Selaa lähdekoodia

Refactor the example a little

Brian Starkey 2 vuotta sitten
vanhempi
commit
f62b584605
1 muutettua tiedostoa jossa 173 lisäystä ja 136 poistoa
  1. 173
    136
      main.c

+ 173
- 136
main.c Näytä tiedosto

@@ -21,97 +21,126 @@ extern const char *wifi_pass;
21 21
 
22 22
 #define TCP_PORT 4242
23 23
 #define DEBUG_printf printf
24
-#define BUF_SIZE 2048
25 24
 #define POLL_TIME_S 5
26 25
 
27
-typedef struct TCP_SERVER_T_ {
28
-	struct tcp_pcb *server_pcb;
29
-	struct tcp_pcb *client_pcb;
30
-	bool complete;
31
-	uint8_t buffer_recv[BUF_SIZE];
32
-	int sent_len;
33
-} TCP_SERVER_T;
34
-
35
-static TCP_SERVER_T* tcp_server_init(void) {
36
-	TCP_SERVER_T *state = calloc(1, sizeof(TCP_SERVER_T));
37
-	if (!state) {
38
-		DEBUG_printf("failed to allocate state\n");
39
-		return NULL;
40
-	}
41
-	return state;
26
+#define MAX_LEN 2048
27
+
28
+enum conn_state {
29
+	CONN_STATE_WAIT_FOR_SYNC,
30
+	CONN_STATE_READ_OPCODE,
31
+	CONN_STATE_READ_ARGS,
32
+	CONN_STATE_READ_DATA,
33
+	CONN_STATE_HANDLE,
34
+	CONN_STATE_WRITE_RESP,
35
+	CONN_STATE_ERROR,
36
+	CONN_STATE_CLOSED,
37
+};
38
+
39
+struct tcp_ctx {
40
+	struct tcp_pcb *serv_pcb;
41
+	volatile bool serv_done;
42
+
43
+	struct tcp_pcb *conn_pcb;
44
+	uint8_t buf[MAX_LEN];
45
+	size_t bytes_remaining;
46
+	enum conn_state conn_state;
47
+};
48
+
49
+static err_t tcp_conn_close(struct tcp_ctx *ctx)
50
+{
51
+	err_t err = ERR_OK;
52
+
53
+	cyw43_arch_gpio_put (0, false);
54
+	ctx->conn_state = CONN_STATE_CLOSED;
55
+
56
+	if (!ctx->conn_pcb) {
57
+		return err;
58
+	}
59
+
60
+	tcp_arg(ctx->conn_pcb, NULL);
61
+	tcp_poll(ctx->conn_pcb, NULL, 0);
62
+	tcp_sent(ctx->conn_pcb, NULL);
63
+	tcp_recv(ctx->conn_pcb, NULL);
64
+	tcp_err(ctx->conn_pcb, NULL);
65
+	err = tcp_close(ctx->conn_pcb);
66
+	if (err != ERR_OK) {
67
+		DEBUG_printf("close failed %d, calling abort\n", err);
68
+		tcp_abort(ctx->conn_pcb);
69
+		err = ERR_ABRT;
70
+	}
71
+
72
+	ctx->conn_pcb = NULL;
73
+
74
+	return err;
42 75
 }
43 76
 
44
-static err_t tcp_server_close(void *arg) {
45
-	TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
77
+static err_t tcp_server_close(void *arg)
78
+{
79
+	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
46 80
 	err_t err = ERR_OK;
47
-	if (state->client_pcb != NULL) {
48
-		tcp_arg(state->client_pcb, NULL);
49
-		tcp_poll(state->client_pcb, NULL, 0);
50
-		tcp_sent(state->client_pcb, NULL);
51
-		tcp_recv(state->client_pcb, NULL);
52
-		tcp_err(state->client_pcb, NULL);
53
-		err = tcp_close(state->client_pcb);
54
-		if (err != ERR_OK) {
55
-			DEBUG_printf("close failed %d, calling abort\n", err);
56
-			tcp_abort(state->client_pcb);
57
-			err = ERR_ABRT;
58
-		}
59
-		state->client_pcb = NULL;
81
+
82
+	err = tcp_conn_close(ctx);
83
+	if ((err != ERR_OK) && ctx->serv_pcb) {
84
+		tcp_arg(ctx->serv_pcb, NULL);
85
+		tcp_abort(ctx->serv_pcb);
86
+		ctx->serv_pcb = NULL;
87
+		return ERR_ABRT;
60 88
 	}
61
-	if (state->server_pcb) {
62
-		tcp_arg(state->server_pcb, NULL);
63
-		tcp_close(state->server_pcb);
64
-		state->server_pcb = NULL;
89
+
90
+	if (!ctx->serv_pcb) {
91
+		return err;
65 92
 	}
93
+
94
+	tcp_arg(ctx->serv_pcb, NULL);
95
+	err = tcp_close(ctx->serv_pcb);
96
+	if (err != ERR_OK) {
97
+		tcp_abort(ctx->serv_pcb);
98
+		err = ERR_ABRT;
99
+	}
100
+	ctx->serv_pcb = NULL;
101
+
66 102
 	return err;
67 103
 }
68 104
 
69
-static err_t tcp_server_result(void *arg, int status) {
70
-	TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
105
+static void tcp_server_complete(void *arg, int status)
106
+{
107
+	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
71 108
 	if (status == 0) {
72
-		DEBUG_printf("completed normally\n");
109
+		DEBUG_printf("server completed normally\n");
73 110
 	} else {
74
-		DEBUG_printf("error %d\n", status);
111
+		DEBUG_printf("server error %d\n", status);
75 112
 	}
76
-	state->complete = true;
77
-	return tcp_server_close(arg);
78
-}
79 113
 
80
-static err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) {
81
-	TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
82
-	DEBUG_printf("tcp_server_sent %u\n", len);
83
-	state->sent_len += len;
114
+	tcp_server_close(ctx);
115
+	ctx->serv_done = true;
116
+}
84 117
 
85
-	if (state->sent_len >= strlen("hello\n")) {
86
-		DEBUG_printf("Sending done\n");
118
+static err_t tcp_conn_complete(void *arg, int status)
119
+{
120
+	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
121
+	if (status == 0) {
122
+		DEBUG_printf("conn completed normally\n");
123
+	} else {
124
+		DEBUG_printf("conn error %d\n", status);
87 125
 	}
88
-
89
-	return ERR_OK;
126
+	return tcp_conn_close(ctx);
90 127
 }
91 128
 
92
-err_t tcp_server_send_data(void *arg, struct tcp_pcb *tpcb)
129
+static err_t tcp_conn_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
93 130
 {
94
-	TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
131
+	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
132
+	DEBUG_printf("tcp_server_sent %u\n", len);
95 133
 
96
-	state->sent_len = 0;
97
-	DEBUG_printf("Writing to client\n");
98
-	// this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you
99
-	// can use this method to cause an assertion in debug mode, if this method is called when
100
-	// cyw43_arch_lwip_begin IS needed
101
-	cyw43_arch_lwip_check();
102
-	err_t err = tcp_write(tpcb, "hello\n", strlen("hello\n"), TCP_WRITE_FLAG_COPY);
103
-	if (err != ERR_OK) {
104
-		DEBUG_printf("Failed to write data %d\n", err);
105
-		return tcp_server_result(arg, -1);
106
-	}
107 134
 	return ERR_OK;
108 135
 }
109 136
 
110
-err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
111
-	TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
137
+static err_t tcp_conn_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
138
+{
139
+	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
112 140
 	if (!p) {
113
-		return tcp_server_result(arg, 0);
141
+		return tcp_conn_complete(ctx, 0);
114 142
 	}
143
+
115 144
 	// this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you
116 145
 	// can use this method to cause an assertion in debug mode, if this method is called when
117 146
 	// cyw43_arch_lwip_begin IS needed
@@ -120,10 +149,10 @@ err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err
120 149
 		DEBUG_printf("tcp_server_recv %d err %d\n", p->tot_len, err);
121 150
 
122 151
 		// Receive the buffer
123
-		pbuf_copy_partial(p, state->buffer_recv, p->tot_len, 0);
152
+		pbuf_copy_partial(p, ctx->buf, p->tot_len, 0);
124 153
 
125
-		state->buffer_recv[p->tot_len] = '\0';
126
-		printf("%s\n", state->buffer_recv);
154
+		ctx->buf[p->tot_len] = '\0';
155
+		printf("%s\n", ctx->buf);
127 156
 		tcp_recved(tpcb, p->tot_len);
128 157
 	}
129 158
 	pbuf_free(p);
@@ -131,102 +160,99 @@ err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err
131 160
 	return ERR_OK;
132 161
 }
133 162
 
134
-static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb) {
163
+static err_t tcp_conn_poll(void *arg, struct tcp_pcb *tpcb)
164
+{
135 165
 	DEBUG_printf("tcp_server_poll_fn\n");
136 166
 	return ERR_OK;
137 167
 }
138 168
 
139
-static void tcp_server_err(void *arg, err_t err) {
140
-	if (err != ERR_ABRT) {
141
-		DEBUG_printf("tcp_client_err_fn %d\n", err);
142
-		tcp_server_result(arg, err);
143
-	} else {
144
-		DEBUG_printf("tcp_client_err_fn abort %d\n", err);
145
-		tcp_server_result(arg, err);
146
-	}
169
+static void tcp_conn_err(void *arg, err_t err)
170
+{
171
+	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
172
+
173
+	DEBUG_printf("tcp_conn_err %d\n", err);
174
+
175
+	ctx->conn_pcb = NULL;
176
+	ctx->conn_state = CONN_STATE_CLOSED;
177
+	ctx->bytes_remaining = 0;
178
+	cyw43_arch_gpio_put (0, false);
179
+}
180
+
181
+static void tcp_conn_wait_for_sync(struct tcp_ctx *ctx)
182
+{
183
+	ctx->conn_state = CONN_STATE_WAIT_FOR_SYNC;
184
+	ctx->bytes_remaining = 4;
185
+}
186
+
187
+static void tcp_conn_init(struct tcp_ctx *ctx, struct tcp_pcb *pcb)
188
+{
189
+	ctx->conn_pcb = pcb;
190
+	tcp_arg(pcb, ctx);
191
+	tcp_sent(pcb, tcp_conn_sent);
192
+	tcp_recv(pcb, tcp_conn_recv);
193
+	tcp_poll(pcb, tcp_conn_poll, POLL_TIME_S * 2);
194
+	tcp_err(pcb, tcp_conn_err);
195
+
196
+	cyw43_arch_gpio_put (0, true);
197
+
198
+	tcp_conn_wait_for_sync(ctx);
147 199
 }
148 200
 
149
-static err_t tcp_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err) {
150
-	TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
201
+static err_t tcp_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err)
202
+{
203
+	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
204
+
151 205
 	if (err != ERR_OK || client_pcb == NULL) {
152 206
 		DEBUG_printf("Failure in accept\n");
153
-		tcp_server_result(arg, err);
207
+		tcp_server_complete(ctx, err);
154 208
 		return ERR_VAL;
155 209
 	}
156
-	DEBUG_printf("Client connected\n");
210
+	DEBUG_printf("Connection opened\n");
157 211
 
158
-	state->client_pcb = client_pcb;
159
-	tcp_arg(client_pcb, state);
160
-	tcp_sent(client_pcb, tcp_server_sent);
161
-	tcp_recv(client_pcb, tcp_server_recv);
162
-	tcp_poll(client_pcb, tcp_server_poll, POLL_TIME_S * 2);
163
-	tcp_err(client_pcb, tcp_server_err);
212
+	if (ctx->conn_pcb) {
213
+		DEBUG_printf("Already have a connection\n");
214
+		tcp_abort(client_pcb);
215
+		return ERR_ABRT;
216
+	}
164 217
 
165
-	return tcp_server_send_data(arg, state->client_pcb);
218
+	tcp_conn_init(ctx, client_pcb);
219
+
220
+	return ERR_OK;
166 221
 }
167 222
 
168
-static bool tcp_server_open(void *arg) {
169
-	TCP_SERVER_T *state = (TCP_SERVER_T*)arg;
223
+static err_t tcp_server_listen(struct tcp_ctx *ctx)
224
+{
170 225
 	DEBUG_printf("Starting server at %s on port %u\n", ip4addr_ntoa(netif_ip4_addr(netif_list)), TCP_PORT);
171 226
 
227
+	ctx->serv_done = false;
228
+
172 229
 	struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
173 230
 	if (!pcb) {
174 231
 		DEBUG_printf("failed to create pcb\n");
175
-		return false;
232
+		return ERR_MEM;
176 233
 	}
177 234
 
178 235
 	err_t err = tcp_bind(pcb, NULL, TCP_PORT);
179 236
 	if (err) {
180
-		DEBUG_printf("failed to bind to port %d\n");
181
-		return false;
237
+		DEBUG_printf("failed to bind to port %d\n", TCP_PORT);
238
+		tcp_abort(pcb);
239
+		return err;
182 240
 	}
183 241
 
184
-	state->server_pcb = tcp_listen_with_backlog(pcb, 1);
185
-	if (!state->server_pcb) {
186
-		DEBUG_printf("failed to listen\n");
187
-		if (pcb) {
188
-			tcp_close(pcb);
189
-		}
190
-		return false;
242
+	ctx->serv_pcb = tcp_listen_with_backlog_and_err(pcb, 1, &err);
243
+	if (!ctx->serv_pcb) {
244
+		DEBUG_printf("failed to listen: %d\n", err);
245
+		return err;
191 246
 	}
192 247
 
193
-	tcp_arg(state->server_pcb, state);
194
-	tcp_accept(state->server_pcb, tcp_server_accept);
248
+	tcp_arg(ctx->serv_pcb, ctx);
249
+	tcp_accept(ctx->serv_pcb, tcp_server_accept);
195 250
 
196
-	return true;
197
-}
198
-
199
-void run_tcp_server(void) {
200
-	TCP_SERVER_T *state = tcp_server_init();
201
-	if (!state) {
202
-		return;
203
-	}
204
-
205
-	if (!tcp_server_open(state)) {
206
-		tcp_server_result(state, -1);
207
-		return;
208
-	}
209
-
210
-	// Block until the connection is closed
211
-	while(!state->complete) {
212
-		// the following #ifdef is only here so this same example can be used in multiple modes;
213
-		// you do not need it in your code
214
-#if PICO_CYW43_ARCH_POLL
215
-		// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
216
-		// main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done.
217
-		cyw43_arch_poll();
218
-		sleep_ms(1);
219
-#else
220
-		// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
221
-		// is done via interrupt in the background. This sleep is just an example of some (blocking)
222
-		// work you might be doing.
223
-		sleep_ms(1000);
224
-#endif
225
-	}
226
-	free(state);
251
+	return ERR_OK;
227 252
 }
228 253
 
229
-int main() {
254
+int main()
255
+{
230 256
 	stdio_init_all();
231 257
 
232 258
 	sleep_ms(1000);
@@ -246,8 +272,19 @@ int main() {
246 272
 		printf("Connected.\n");
247 273
 	}
248 274
 
275
+	struct tcp_ctx tcp = { 0 };
276
+
249 277
 	for ( ; ; ) {
250
-		run_tcp_server();
278
+		err_t err = tcp_server_listen(&tcp);
279
+		if (err != ERR_OK) {
280
+			printf("Failed to start server: %d\n", err);
281
+			sleep_ms(1000);
282
+			continue;
283
+		}
284
+
285
+		while (!tcp.serv_done) {
286
+			sleep_ms(1000);
287
+		}
251 288
 	}
252 289
 
253 290
 	cyw43_arch_deinit();

Loading…
Peruuta
Tallenna