Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /**
  2. * Copyright (c) 2022 Brian Starkey <stark3y@gmail.com>
  3. *
  4. * Based on the Pico W tcp_server example:
  5. * Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
  6. *
  7. * SPDX-License-Identifier: BSD-3-Clause
  8. */
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include "pico/stdlib.h"
  12. #include "pico/cyw43_arch.h"
  13. #include "lwip/pbuf.h"
  14. #include "lwip/tcp.h"
  15. extern const char *wifi_ssid;
  16. extern const char *wifi_pass;
  17. #define TCP_PORT 4242
  18. #define DEBUG_printf printf
  19. #define BUF_SIZE 2048
  20. #define POLL_TIME_S 5
  21. typedef struct TCP_SERVER_T_ {
  22. struct tcp_pcb *server_pcb;
  23. struct tcp_pcb *client_pcb;
  24. bool complete;
  25. uint8_t buffer_recv[BUF_SIZE];
  26. int sent_len;
  27. } TCP_SERVER_T;
  28. static TCP_SERVER_T* tcp_server_init(void) {
  29. TCP_SERVER_T *state = calloc(1, sizeof(TCP_SERVER_T));
  30. if (!state) {
  31. DEBUG_printf("failed to allocate state\n");
  32. return NULL;
  33. }
  34. return state;
  35. }
  36. static err_t tcp_server_close(void *arg) {
  37. TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
  38. err_t err = ERR_OK;
  39. if (state->client_pcb != NULL) {
  40. tcp_arg(state->client_pcb, NULL);
  41. tcp_poll(state->client_pcb, NULL, 0);
  42. tcp_sent(state->client_pcb, NULL);
  43. tcp_recv(state->client_pcb, NULL);
  44. tcp_err(state->client_pcb, NULL);
  45. err = tcp_close(state->client_pcb);
  46. if (err != ERR_OK) {
  47. DEBUG_printf("close failed %d, calling abort\n", err);
  48. tcp_abort(state->client_pcb);
  49. err = ERR_ABRT;
  50. }
  51. state->client_pcb = NULL;
  52. }
  53. if (state->server_pcb) {
  54. tcp_arg(state->server_pcb, NULL);
  55. tcp_close(state->server_pcb);
  56. state->server_pcb = NULL;
  57. }
  58. return err;
  59. }
  60. static err_t tcp_server_result(void *arg, int status) {
  61. TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
  62. if (status == 0) {
  63. DEBUG_printf("completed normally\n");
  64. } else {
  65. DEBUG_printf("error %d\n", status);
  66. }
  67. state->complete = true;
  68. return tcp_server_close(arg);
  69. }
  70. static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) {
  71. TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
  72. DEBUG_printf("tcp_server_sent %u\n", len);
  73. state->sent_len += len;
  74. if (state->sent_len >= strlen("hello\n")) {
  75. DEBUG_printf("Sending done\n");
  76. }
  77. return ERR_OK;
  78. }
  79. err_t tcp_server_send_data(void *arg, struct tcp_pcb *tpcb)
  80. {
  81. TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
  82. state->sent_len = 0;
  83. DEBUG_printf("Writing to client\n");
  84. // this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you
  85. // can use this method to cause an assertion in debug mode, if this method is called when
  86. // cyw43_arch_lwip_begin IS needed
  87. cyw43_arch_lwip_check();
  88. err_t err = tcp_write(tpcb, "hello\n", strlen("hello\n"), TCP_WRITE_FLAG_COPY);
  89. if (err != ERR_OK) {
  90. DEBUG_printf("Failed to write data %d\n", err);
  91. return tcp_server_result(arg, -1);
  92. }
  93. return ERR_OK;
  94. }
  95. err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
  96. TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
  97. if (!p) {
  98. return tcp_server_result(arg, 0);
  99. }
  100. // this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you
  101. // can use this method to cause an assertion in debug mode, if this method is called when
  102. // cyw43_arch_lwip_begin IS needed
  103. cyw43_arch_lwip_check();
  104. if (p->tot_len > 0) {
  105. DEBUG_printf("tcp_server_recv %d err %d\n", p->tot_len, err);
  106. // Receive the buffer
  107. pbuf_copy_partial(p, state->buffer_recv, p->tot_len, 0);
  108. state->buffer_recv[p->tot_len] = '\0';
  109. printf("%s\n", state->buffer_recv);
  110. tcp_recved(tpcb, p->tot_len);
  111. }
  112. pbuf_free(p);
  113. return ERR_OK;
  114. }
  115. static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb) {
  116. DEBUG_printf("tcp_server_poll_fn\n");
  117. return ERR_OK;
  118. }
  119. static void tcp_server_err(void *arg, err_t err) {
  120. if (err != ERR_ABRT) {
  121. DEBUG_printf("tcp_client_err_fn %d\n", err);
  122. tcp_server_result(arg, err);
  123. } else {
  124. DEBUG_printf("tcp_client_err_fn abort %d\n", err);
  125. tcp_server_result(arg, err);
  126. }
  127. }
  128. static err_t tcp_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err) {
  129. TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
  130. if (err != ERR_OK || client_pcb == NULL) {
  131. DEBUG_printf("Failure in accept\n");
  132. tcp_server_result(arg, err);
  133. return ERR_VAL;
  134. }
  135. DEBUG_printf("Client connected\n");
  136. state->client_pcb = client_pcb;
  137. tcp_arg(client_pcb, state);
  138. tcp_sent(client_pcb, tcp_server_sent);
  139. tcp_recv(client_pcb, tcp_server_recv);
  140. tcp_poll(client_pcb, tcp_server_poll, POLL_TIME_S * 2);
  141. tcp_err(client_pcb, tcp_server_err);
  142. return tcp_server_send_data(arg, state->client_pcb);
  143. }
  144. static bool tcp_server_open(void *arg) {
  145. TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
  146. DEBUG_printf("Starting server at %s on port %u\n", ip4addr_ntoa(netif_ip4_addr(netif_list)), TCP_PORT);
  147. struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
  148. if (!pcb) {
  149. DEBUG_printf("failed to create pcb\n");
  150. return false;
  151. }
  152. err_t err = tcp_bind(pcb, NULL, TCP_PORT);
  153. if (err) {
  154. DEBUG_printf("failed to bind to port %d\n");
  155. return false;
  156. }
  157. state->server_pcb = tcp_listen_with_backlog(pcb, 1);
  158. if (!state->server_pcb) {
  159. DEBUG_printf("failed to listen\n");
  160. if (pcb) {
  161. tcp_close(pcb);
  162. }
  163. return false;
  164. }
  165. tcp_arg(state->server_pcb, state);
  166. tcp_accept(state->server_pcb, tcp_server_accept);
  167. return true;
  168. }
  169. void run_tcp_server(void) {
  170. TCP_SERVER_T *state = tcp_server_init();
  171. if (!state) {
  172. return;
  173. }
  174. if (!tcp_server_open(state)) {
  175. tcp_server_result(state, -1);
  176. return;
  177. }
  178. // Block until the connection is closed
  179. while(!state->complete) {
  180. // the following #ifdef is only here so this same example can be used in multiple modes;
  181. // you do not need it in your code
  182. #if PICO_CYW43_ARCH_POLL
  183. // if you are using pico_cyw43_arch_poll, then you must poll periodically from your
  184. // main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done.
  185. cyw43_arch_poll();
  186. sleep_ms(1);
  187. #else
  188. // if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
  189. // is done via interrupt in the background. This sleep is just an example of some (blocking)
  190. // work you might be doing.
  191. sleep_ms(1000);
  192. #endif
  193. }
  194. free(state);
  195. }
  196. int main() {
  197. stdio_init_all();
  198. sleep_ms(1000);
  199. if (cyw43_arch_init()) {
  200. printf("failed to initialise\n");
  201. return 1;
  202. }
  203. cyw43_arch_enable_sta_mode();
  204. printf("Connecting to WiFi...\n");
  205. if (cyw43_arch_wifi_connect_timeout_ms(wifi_ssid, wifi_pass, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
  206. printf("failed to connect.\n");
  207. return 1;
  208. } else {
  209. printf("Connected.\n");
  210. }
  211. for ( ; ; ) {
  212. run_tcp_server();
  213. }
  214. cyw43_arch_deinit();
  215. return 0;
  216. }