Browse Source

Refactor the example a little

Brian Starkey 2 years ago
parent
commit
f62b584605
1 changed files with 173 additions and 136 deletions
  1. 173
    136
      main.c

+ 173
- 136
main.c View File

21
 
21
 
22
 #define TCP_PORT 4242
22
 #define TCP_PORT 4242
23
 #define DEBUG_printf printf
23
 #define DEBUG_printf printf
24
-#define BUF_SIZE 2048
25
 #define POLL_TIME_S 5
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
 	err_t err = ERR_OK;
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
 	return err;
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
 	if (status == 0) {
108
 	if (status == 0) {
72
-		DEBUG_printf("completed normally\n");
109
+		DEBUG_printf("server completed normally\n");
73
 	} else {
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
 	return ERR_OK;
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
 	if (!p) {
140
 	if (!p) {
113
-		return tcp_server_result(arg, 0);
141
+		return tcp_conn_complete(ctx, 0);
114
 	}
142
 	}
143
+
115
 	// this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you
144
 	// this method is callback from lwIP, so cyw43_arch_lwip_begin is not required, however you
116
 	// can use this method to cause an assertion in debug mode, if this method is called when
145
 	// can use this method to cause an assertion in debug mode, if this method is called when
117
 	// cyw43_arch_lwip_begin IS needed
146
 	// cyw43_arch_lwip_begin IS needed
120
 		DEBUG_printf("tcp_server_recv %d err %d\n", p->tot_len, err);
149
 		DEBUG_printf("tcp_server_recv %d err %d\n", p->tot_len, err);
121
 
150
 
122
 		// Receive the buffer
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
 		tcp_recved(tpcb, p->tot_len);
156
 		tcp_recved(tpcb, p->tot_len);
128
 	}
157
 	}
129
 	pbuf_free(p);
158
 	pbuf_free(p);
131
 	return ERR_OK;
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
 	DEBUG_printf("tcp_server_poll_fn\n");
165
 	DEBUG_printf("tcp_server_poll_fn\n");
136
 	return ERR_OK;
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
 	if (err != ERR_OK || client_pcb == NULL) {
205
 	if (err != ERR_OK || client_pcb == NULL) {
152
 		DEBUG_printf("Failure in accept\n");
206
 		DEBUG_printf("Failure in accept\n");
153
-		tcp_server_result(arg, err);
207
+		tcp_server_complete(ctx, err);
154
 		return ERR_VAL;
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
 	DEBUG_printf("Starting server at %s on port %u\n", ip4addr_ntoa(netif_ip4_addr(netif_list)), TCP_PORT);
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
 	struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
229
 	struct tcp_pcb *pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
173
 	if (!pcb) {
230
 	if (!pcb) {
174
 		DEBUG_printf("failed to create pcb\n");
231
 		DEBUG_printf("failed to create pcb\n");
175
-		return false;
232
+		return ERR_MEM;
176
 	}
233
 	}
177
 
234
 
178
 	err_t err = tcp_bind(pcb, NULL, TCP_PORT);
235
 	err_t err = tcp_bind(pcb, NULL, TCP_PORT);
179
 	if (err) {
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
 	stdio_init_all();
256
 	stdio_init_all();
231
 
257
 
232
 	sleep_ms(1000);
258
 	sleep_ms(1000);
246
 		printf("Connected.\n");
272
 		printf("Connected.\n");
247
 	}
273
 	}
248
 
274
 
275
+	struct tcp_ctx tcp = { 0 };
276
+
249
 	for ( ; ; ) {
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
 	cyw43_arch_deinit();
290
 	cyw43_arch_deinit();

Loading…
Cancel
Save