Browse Source

Implement "comm", a fairly close port of M0o+'s version

Brian Starkey 2 years ago
parent
commit
3bdad9eb2b
2 changed files with 325 additions and 32 deletions
  1. 1
    1
      CMakeLists.txt
  2. 324
    31
      main.c

+ 1
- 1
CMakeLists.txt View File

@@ -19,6 +19,6 @@ pico_add_extra_outputs(picowota)
19 19
 target_include_directories(picowota PRIVATE ${CMAKE_CURRENT_LIST_DIR})
20 20
 
21 21
 target_link_libraries(picowota
22
-	pico_cyw43_arch_lwip_threadsafe_background
22
+	pico_cyw43_arch_lwip_poll
23 23
 	pico_stdlib
24 24
 )

+ 324
- 31
main.c View File

@@ -25,6 +25,22 @@ extern const char *wifi_pass;
25 25
 
26 26
 #define MAX_LEN 2048
27 27
 
28
+#define COMM_MAX_NARG     5
29
+#define COMM_MAX_DATA_LEN 1024
30
+
31
+#define COMM_RSP_OK       (('O' << 0) | ('K' << 8) | ('O' << 16) | ('K' << 24))
32
+#define COMM_RSP_ERR      (('E' << 0) | ('R' << 8) | ('R' << 16) | ('!' << 24))
33
+#define CMD_SYNC          (('S' << 0) | ('Y' << 8) | ('N' << 16) | ('C' << 24))
34
+#define RSP_SYNC          (('W' << 0) | ('O' << 8) | ('T' << 16) | ('A' << 24))
35
+
36
+struct comm_command {
37
+	uint32_t opcode;
38
+	uint32_t nargs;
39
+	uint32_t resp_nargs;
40
+	uint32_t (*size)(uint32_t *args_in, uint32_t *data_len_out, uint32_t *resp_data_len_out);
41
+	uint32_t (*handle)(uint32_t *args_in, uint8_t *data_in, uint32_t *resp_args_out, uint8_t *resp_data_out);
42
+};
43
+
28 44
 enum conn_state {
29 45
 	CONN_STATE_WAIT_FOR_SYNC,
30 46
 	CONN_STATE_READ_OPCODE,
@@ -32,21 +48,240 @@ enum conn_state {
32 48
 	CONN_STATE_READ_DATA,
33 49
 	CONN_STATE_HANDLE,
34 50
 	CONN_STATE_WRITE_RESP,
35
-	CONN_STATE_ERROR,
51
+	CONN_STATE_WRITE_ERROR,
36 52
 	CONN_STATE_CLOSED,
37 53
 };
38 54
 
39
-struct tcp_ctx {
55
+struct tcp_comm_ctx {
40 56
 	struct tcp_pcb *serv_pcb;
41 57
 	volatile bool serv_done;
58
+	enum conn_state conn_state;
42 59
 
43 60
 	struct tcp_pcb *conn_pcb;
44
-	uint8_t buf[MAX_LEN];
45
-	size_t bytes_remaining;
46
-	enum conn_state conn_state;
61
+	uint8_t buf[(sizeof(uint32_t) * (1 + COMM_MAX_NARG)) + COMM_MAX_DATA_LEN];
62
+	uint16_t rx_bytes_received;
63
+	uint16_t rx_bytes_remaining;
64
+
65
+	uint16_t tx_bytes_sent;
66
+	uint16_t tx_bytes_remaining;
67
+
68
+	uint32_t resp_data_len;
69
+
70
+	const struct comm_command *cmd;
71
+	const struct comm_command *const *cmds;
72
+	unsigned int n_cmds;
73
+	uint32_t sync_opcode;
47 74
 };
48 75
 
49
-static err_t tcp_conn_close(struct tcp_ctx *ctx)
76
+#define COMM_BUF_OPCODE(_buf)       ((uint32_t *)((uint8_t *)(_buf)))
77
+#define COMM_BUF_ARGS(_buf)         ((uint32_t *)((uint8_t *)(_buf) + sizeof(uint32_t)))
78
+#define COMM_BUF_BODY(_buf, _nargs) ((uint8_t *)(_buf) + (sizeof(uint32_t) * ((_nargs) + 1)))
79
+
80
+static const struct comm_command *find_command_desc(struct tcp_comm_ctx *ctx, uint32_t opcode)
81
+{
82
+	unsigned int i;
83
+
84
+	for (i = 0; i < ctx->n_cmds; i++) {
85
+		if (ctx->cmds[i]->opcode == opcode) {
86
+			return ctx->cmds[i];
87
+		}
88
+	}
89
+
90
+	return NULL;
91
+}
92
+
93
+static bool is_error(uint32_t status)
94
+{
95
+	return status == COMM_RSP_ERR;
96
+}
97
+
98
+static int tcp_conn_sync_begin(struct tcp_comm_ctx *ctx);
99
+static int tcp_conn_sync_complete(struct tcp_comm_ctx *ctx);
100
+static int tcp_conn_opcode_begin(struct tcp_comm_ctx *ctx);
101
+static int tcp_conn_opcode_complete(struct tcp_comm_ctx *ctx);
102
+static int tcp_conn_args_begin(struct tcp_comm_ctx *ctx);
103
+static int tcp_conn_args_complete(struct tcp_comm_ctx *ctx);
104
+static int tcp_conn_data_begin(struct tcp_comm_ctx *ctx, uint32_t data_len);
105
+static int tcp_conn_data_complete(struct tcp_comm_ctx *ctx);
106
+static int tcp_conn_response_begin(struct tcp_comm_ctx *ctx);
107
+static int tcp_conn_response_complete(struct tcp_comm_ctx *ctx);
108
+static int tcp_conn_error_begin(struct tcp_comm_ctx *ctx);
109
+
110
+static int tcp_conn_sync_begin(struct tcp_comm_ctx *ctx)
111
+{
112
+	ctx->conn_state = CONN_STATE_WAIT_FOR_SYNC;
113
+	ctx->rx_bytes_received = 0;
114
+	ctx->rx_bytes_remaining = sizeof(uint32_t);
115
+
116
+	DEBUG_printf("sync_begin %d\n", ctx->rx_bytes_remaining);
117
+}
118
+
119
+static int tcp_conn_sync_complete(struct tcp_comm_ctx *ctx)
120
+{
121
+	if (ctx->sync_opcode != *COMM_BUF_OPCODE(ctx->buf)) {
122
+		DEBUG_printf("sync not correct: %c%c%c%c\n", ctx->buf[0], ctx->buf[1], ctx->buf[2], ctx->buf[3]);
123
+		return tcp_conn_error_begin(ctx);
124
+	}
125
+
126
+	return tcp_conn_opcode_complete(ctx);
127
+}
128
+
129
+static int tcp_conn_opcode_begin(struct tcp_comm_ctx *ctx)
130
+{
131
+	ctx->conn_state = CONN_STATE_READ_OPCODE;
132
+	ctx->rx_bytes_received = 0;
133
+	ctx->rx_bytes_remaining = sizeof(uint32_t);
134
+
135
+	return 0;
136
+}
137
+
138
+static int tcp_conn_opcode_complete(struct tcp_comm_ctx *ctx)
139
+{
140
+	ctx->cmd = find_command_desc(ctx, *COMM_BUF_OPCODE(ctx->buf));
141
+	if (!ctx->cmd) {
142
+		DEBUG_printf("no command for '%c%c%c%c'\n", ctx->buf[0], ctx->buf[1], ctx->buf[2], ctx->buf[3]);
143
+		return tcp_conn_error_begin(ctx);
144
+	} else {
145
+		DEBUG_printf("got command '%c%c%c%c'\n", ctx->buf[0], ctx->buf[1], ctx->buf[2], ctx->buf[3]);
146
+	}
147
+
148
+	return tcp_conn_args_begin(ctx);
149
+}
150
+
151
+static int tcp_conn_args_begin(struct tcp_comm_ctx *ctx)
152
+{
153
+	ctx->conn_state = CONN_STATE_READ_ARGS;
154
+	ctx->rx_bytes_received = 0;
155
+	ctx->rx_bytes_remaining = ctx->cmd->nargs * sizeof(uint32_t);
156
+
157
+	if (ctx->cmd->nargs == 0) {
158
+		return tcp_conn_args_complete(ctx);
159
+	}
160
+
161
+	return 0;
162
+}
163
+
164
+static int tcp_conn_args_complete(struct tcp_comm_ctx *ctx)
165
+{
166
+	const struct comm_command *cmd = ctx->cmd;
167
+
168
+	uint32_t data_len = 0;
169
+
170
+	if (cmd->size) {
171
+		uint32_t status = cmd->size(COMM_BUF_ARGS(ctx->buf),
172
+					    &data_len,
173
+					    &ctx->resp_data_len);
174
+		if (is_error(status)) {
175
+			return tcp_conn_error_begin(ctx);
176
+		}
177
+	}
178
+
179
+	return tcp_conn_data_begin(ctx, data_len);
180
+}
181
+
182
+static int tcp_conn_data_begin(struct tcp_comm_ctx *ctx, uint32_t data_len)
183
+{
184
+	const struct comm_command *cmd = ctx->cmd;
185
+
186
+	ctx->conn_state = CONN_STATE_READ_DATA;
187
+	ctx->rx_bytes_received = 0;
188
+	ctx->rx_bytes_remaining = data_len;
189
+
190
+	if (data_len == 0) {
191
+		return tcp_conn_data_complete(ctx);
192
+	}
193
+
194
+
195
+	return 0;
196
+}
197
+
198
+static int tcp_conn_data_complete(struct tcp_comm_ctx *ctx)
199
+{
200
+	const struct comm_command *cmd = ctx->cmd;
201
+
202
+	if (cmd->handle) {
203
+		uint32_t status = cmd->handle(COMM_BUF_ARGS(ctx->buf),
204
+					      COMM_BUF_BODY(ctx->buf, cmd->nargs),
205
+					      COMM_BUF_ARGS(ctx->buf),
206
+					      COMM_BUF_BODY(ctx->buf, cmd->resp_nargs));
207
+		if (is_error(status)) {
208
+			return tcp_conn_error_begin(ctx);
209
+		}
210
+
211
+		*COMM_BUF_OPCODE(ctx->buf) = status;
212
+	} else {
213
+		// TODO: Should we just assert(desc->handle)?
214
+		*COMM_BUF_OPCODE(ctx->buf) = COMM_RSP_OK;
215
+	}
216
+
217
+	return tcp_conn_response_begin(ctx);
218
+}
219
+
220
+static int tcp_conn_response_begin(struct tcp_comm_ctx *ctx)
221
+{
222
+	ctx->conn_state = CONN_STATE_WRITE_RESP;
223
+	ctx->tx_bytes_sent = 0;
224
+	ctx->tx_bytes_remaining = ctx->resp_data_len + ((ctx->cmd->resp_nargs + 1) * sizeof(uint32_t));
225
+
226
+	err_t err = tcp_write(ctx->conn_pcb, ctx->buf, ctx->tx_bytes_remaining, 0);
227
+	if (err != ERR_OK) {
228
+		return -1;
229
+	}
230
+
231
+	return 0;
232
+}
233
+
234
+static int tcp_conn_error_begin(struct tcp_comm_ctx *ctx)
235
+{
236
+	ctx->conn_state = CONN_STATE_WRITE_ERROR;
237
+	ctx->tx_bytes_sent = 0;
238
+	ctx->tx_bytes_remaining = sizeof(uint32_t);
239
+
240
+	*COMM_BUF_OPCODE(ctx->buf) = COMM_RSP_ERR;
241
+
242
+	err_t err = tcp_write(ctx->conn_pcb, ctx->buf, ctx->tx_bytes_remaining, 0);
243
+	if (err != ERR_OK) {
244
+		return -1;
245
+	}
246
+
247
+	return 0;
248
+}
249
+
250
+
251
+static int tcp_conn_response_complete(struct tcp_comm_ctx *ctx)
252
+{
253
+	return tcp_conn_opcode_begin(ctx);
254
+}
255
+
256
+static int tcp_conn_rx_complete(struct tcp_comm_ctx *ctx)
257
+{
258
+	switch (ctx->conn_state) {
259
+	case CONN_STATE_WAIT_FOR_SYNC:
260
+		return tcp_conn_sync_complete(ctx);
261
+	case CONN_STATE_READ_OPCODE:
262
+		return tcp_conn_opcode_complete(ctx);
263
+	case CONN_STATE_READ_ARGS:
264
+		return tcp_conn_args_complete(ctx);
265
+	case CONN_STATE_READ_DATA:
266
+		return tcp_conn_data_complete(ctx);
267
+	default:
268
+		return -1;
269
+	}
270
+}
271
+
272
+static int tcp_conn_tx_complete(struct tcp_comm_ctx *ctx)
273
+{
274
+	switch (ctx->conn_state) {
275
+	case CONN_STATE_WRITE_RESP:
276
+		return tcp_conn_response_complete(ctx);
277
+	case CONN_STATE_WRITE_ERROR:
278
+		return -1;
279
+	default:
280
+		return -1;
281
+	}
282
+}
283
+
284
+static err_t tcp_conn_close(struct tcp_comm_ctx *ctx)
50 285
 {
51 286
 	err_t err = ERR_OK;
52 287
 
@@ -76,7 +311,7 @@ static err_t tcp_conn_close(struct tcp_ctx *ctx)
76 311
 
77 312
 static err_t tcp_server_close(void *arg)
78 313
 {
79
-	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
314
+	struct tcp_comm_ctx *ctx = (struct tcp_comm_ctx *)arg;
80 315
 	err_t err = ERR_OK;
81 316
 
82 317
 	err = tcp_conn_close(ctx);
@@ -104,7 +339,7 @@ static err_t tcp_server_close(void *arg)
104 339
 
105 340
 static void tcp_server_complete(void *arg, int status)
106 341
 {
107
-	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
342
+	struct tcp_comm_ctx *ctx = (struct tcp_comm_ctx *)arg;
108 343
 	if (status == 0) {
109 344
 		DEBUG_printf("server completed normally\n");
110 345
 	} else {
@@ -117,7 +352,7 @@ static void tcp_server_complete(void *arg, int status)
117 352
 
118 353
 static err_t tcp_conn_complete(void *arg, int status)
119 354
 {
120
-	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
355
+	struct tcp_comm_ctx *ctx = (struct tcp_comm_ctx *)arg;
121 356
 	if (status == 0) {
122 357
 		DEBUG_printf("conn completed normally\n");
123 358
 	} else {
@@ -128,16 +363,33 @@ static err_t tcp_conn_complete(void *arg, int status)
128 363
 
129 364
 static err_t tcp_conn_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
130 365
 {
131
-	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
366
+	struct tcp_comm_ctx *ctx = (struct tcp_comm_ctx *)arg;
132 367
 	DEBUG_printf("tcp_server_sent %u\n", len);
133 368
 
369
+	cyw43_arch_lwip_check();
370
+	if (len > ctx->tx_bytes_remaining) {
371
+		DEBUG_printf("tx len %d > remaining %d\n", len, ctx->tx_bytes_remaining);
372
+		return tcp_conn_complete(ctx, ERR_ARG);
373
+	}
374
+
375
+	ctx->tx_bytes_remaining -= len;
376
+	ctx->tx_bytes_sent += len;
377
+
378
+	if (ctx->tx_bytes_remaining == 0) {
379
+		int res = tcp_conn_tx_complete(ctx);
380
+		if (res) {
381
+			return tcp_conn_complete(ctx, ERR_ARG);
382
+		}
383
+	}
384
+
134 385
 	return ERR_OK;
135 386
 }
136 387
 
137 388
 static err_t tcp_conn_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
138 389
 {
139
-	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
390
+	struct tcp_comm_ctx *ctx = (struct tcp_comm_ctx *)arg;
140 391
 	if (!p) {
392
+		DEBUG_printf("no pbuf\n");
141 393
 		return tcp_conn_complete(ctx, 0);
142 394
 	}
143 395
 
@@ -148,12 +400,24 @@ static err_t tcp_conn_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_
148 400
 	if (p->tot_len > 0) {
149 401
 		DEBUG_printf("tcp_server_recv %d err %d\n", p->tot_len, err);
150 402
 
403
+		size_t to_copy = p->tot_len > ctx->rx_bytes_remaining ? ctx->rx_bytes_remaining : p->tot_len;
404
+
151 405
 		// Receive the buffer
152
-		pbuf_copy_partial(p, ctx->buf, p->tot_len, 0);
406
+		if (pbuf_copy_partial(p, ctx->buf + ctx->rx_bytes_received, to_copy, 0) != to_copy) {
407
+			DEBUG_printf("wrong copy len\n");
408
+			return tcp_conn_complete(ctx, ERR_ARG);
409
+		}
153 410
 
154
-		ctx->buf[p->tot_len] = '\0';
155
-		printf("%s\n", ctx->buf);
411
+		ctx->rx_bytes_received += to_copy;
412
+		ctx->rx_bytes_remaining -= to_copy;
156 413
 		tcp_recved(tpcb, p->tot_len);
414
+
415
+		if (ctx->rx_bytes_remaining == 0) {
416
+			int res = tcp_conn_rx_complete(ctx);
417
+			if (res) {
418
+				return tcp_conn_complete(ctx, ERR_ARG);
419
+			}
420
+		}
157 421
 	}
158 422
 	pbuf_free(p);
159 423
 
@@ -168,39 +432,34 @@ static err_t tcp_conn_poll(void *arg, struct tcp_pcb *tpcb)
168 432
 
169 433
 static void tcp_conn_err(void *arg, err_t err)
170 434
 {
171
-	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
435
+	struct tcp_comm_ctx *ctx = (struct tcp_comm_ctx *)arg;
172 436
 
173 437
 	DEBUG_printf("tcp_conn_err %d\n", err);
174 438
 
175 439
 	ctx->conn_pcb = NULL;
176 440
 	ctx->conn_state = CONN_STATE_CLOSED;
177
-	ctx->bytes_remaining = 0;
441
+	ctx->rx_bytes_remaining = 0;
178 442
 	cyw43_arch_gpio_put (0, false);
179 443
 }
180 444
 
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)
445
+static void tcp_conn_init(struct tcp_comm_ctx *ctx, struct tcp_pcb *pcb)
188 446
 {
189 447
 	ctx->conn_pcb = pcb;
190 448
 	tcp_arg(pcb, ctx);
449
+
450
+	cyw43_arch_gpio_put (0, true);
451
+
452
+	tcp_conn_sync_begin(ctx);
453
+
191 454
 	tcp_sent(pcb, tcp_conn_sent);
192 455
 	tcp_recv(pcb, tcp_conn_recv);
193 456
 	tcp_poll(pcb, tcp_conn_poll, POLL_TIME_S * 2);
194 457
 	tcp_err(pcb, tcp_conn_err);
195
-
196
-	cyw43_arch_gpio_put (0, true);
197
-
198
-	tcp_conn_wait_for_sync(ctx);
199 458
 }
200 459
 
201 460
 static err_t tcp_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err)
202 461
 {
203
-	struct tcp_ctx *ctx = (struct tcp_ctx *)arg;
462
+	struct tcp_comm_ctx *ctx = (struct tcp_comm_ctx *)arg;
204 463
 
205 464
 	if (err != ERR_OK || client_pcb == NULL) {
206 465
 		DEBUG_printf("Failure in accept\n");
@@ -220,7 +479,7 @@ static err_t tcp_server_accept(void *arg, struct tcp_pcb *client_pcb, err_t err)
220 479
 	return ERR_OK;
221 480
 }
222 481
 
223
-static err_t tcp_server_listen(struct tcp_ctx *ctx)
482
+static err_t tcp_server_listen(struct tcp_comm_ctx *ctx)
224 483
 {
225 484
 	DEBUG_printf("Starting server at %s on port %u\n", ip4addr_ntoa(netif_ip4_addr(netif_list)), TCP_PORT);
226 485
 
@@ -251,6 +510,34 @@ static err_t tcp_server_listen(struct tcp_ctx *ctx)
251 510
 	return ERR_OK;
252 511
 }
253 512
 
513
+static uint32_t handle_sync(uint32_t *args_in, uint8_t *data_in, uint32_t *resp_args_out, uint8_t *resp_data_out)
514
+{
515
+	return RSP_SYNC;
516
+}
517
+
518
+const struct comm_command util_sync_cmd = {
519
+	.opcode = CMD_SYNC,
520
+	.nargs = 0,
521
+	.resp_nargs = 0,
522
+	.size = NULL,
523
+	.handle = &handle_sync,
524
+};
525
+
526
+static void tcp_comm_init(struct tcp_comm_ctx *ctx, const struct comm_command *const *cmds,
527
+		unsigned int n_cmds, uint32_t sync_opcode)
528
+{
529
+	unsigned int i;
530
+	for (i = 0; i < n_cmds; i++) {
531
+		assert(cmds[i]->nargs <= MAX_NARG);
532
+		assert(cmds[i]->resp_nargs <= MAX_NARG);
533
+	}
534
+
535
+	memset(ctx, 0, sizeof(*ctx));
536
+	ctx->cmds = cmds;
537
+	ctx->n_cmds = n_cmds;
538
+	ctx->sync_opcode = sync_opcode;
539
+}
540
+
254 541
 int main()
255 542
 {
256 543
 	stdio_init_all();
@@ -272,7 +559,12 @@ int main()
272 559
 		printf("Connected.\n");
273 560
 	}
274 561
 
275
-	struct tcp_ctx tcp = { 0 };
562
+	struct tcp_comm_ctx tcp;
563
+	const struct comm_command *cmds[] = {
564
+		&util_sync_cmd,
565
+	};
566
+
567
+	tcp_comm_init(&tcp, cmds, 1, CMD_SYNC);
276 568
 
277 569
 	for ( ; ; ) {
278 570
 		err_t err = tcp_server_listen(&tcp);
@@ -283,7 +575,8 @@ int main()
283 575
 		}
284 576
 
285 577
 		while (!tcp.serv_done) {
286
-			sleep_ms(1000);
578
+			cyw43_arch_poll();
579
+			sleep_ms(10);
287 580
 		}
288 581
 	}
289 582
 

Loading…
Cancel
Save