ether2ser 0.1.0
Ethernet <-> synchronous V.24 bridge firmware for RP2040 + W5500
Loading...
Searching...
No Matches
cli_commands.c
Go to the documentation of this file.
1/*
2 * ether2ser — Ethernet <-> synchronous V.24 (RS-232/V.28) bridge
3 *
4 * File: src/system/cli_commands.c
5 * Purpose: CLI command handlers and dispatch.
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 *
9 * Copyright (c) 2026 Florian <f.leuze@outlook.de>
10 */
11
12// Related headers
13#include "cli_commands.h"
14
15// Standard library headers
16#include <stdbool.h>
17#include <stddef.h>
18#include <stdint.h>
19#include <stdio.h>
20#include <string.h>
21
22// Library Headers
23#include "hardware/gpio.h"
24#include "hardware/structs/io_bank0.h"
25#include "hardware/watchdog.h"
26#include "wizchip_conf.h"
27#include "wizchip_qspi_pio.h"
28
29// Project Headers
30#include "drivers/v24_config.h"
31#include "platform/watchdog.h"
32#include "system/cli_parser.h"
33#include "system/common.h"
34#include "system/error.h"
35#include "system/event_queue.h"
36// Generated headers
37
38#define MAX_CMD_BUFFER_LEN 16
39#define MAX_PIN_NAME_LEN 16
40#define MAX_ARG_BUFFER_LEN 64
41
42// Command handler type
43typedef void (*cmd_handler_t)(const char* args);
44
45typedef struct
46{
47 const char* name;
49 const char* help;
50} command_t;
51
52typedef void (*category_set_handler_t)(const char* args);
53typedef void (*category_get_handler_t)(const char* args);
54
62
63typedef void (*subcmd_set_handler_t)(const char* args);
64typedef void (*subcmd_get_handler_t)(const char* args);
65
73
74// Forward declarations for lookup tables
75static void cmd_help(const char* args);
76static void cmd_status(const char* args);
77static void cmd_mem(const char* args);
78static void cmd_net(const char* args);
79static void cmd_set(const char* args);
80static void cmd_get(const char* args);
81static void cmd_pininfo(const char* args);
82static void cmd_save(const char* args);
83static void cmd_wipe(const char* args);
84static void cmd_reboot(const char* args);
85static void cat_gpio_set(const char* args);
86static void cat_gpio_get(const char* args);
87static void cat_net_set(const char* args);
88static void cat_net_get(const char* args);
89static void cat_v24_set(const char* args);
90static void cat_v24_get(const char* args);
91static void cat_loglevel_set(const char* args);
92static void cat_loglevel_get(const char* args);
93static void subcmd_set_ip_local(const char* args);
94static void subcmd_get_ip_local(const char* args);
95static void subcmd_set_ip_remote(const char* args);
96static void subcmd_get_ip_remote(const char* args);
97static void subcmd_set_ip_gateway(const char* args);
98static void subcmd_get_ip_gateway(const char* args);
99static void subcmd_set_udp_port_local(const char* args);
100static void subcmd_get_udp_port_local(const char* args);
101static void subcmd_set_udp_port_remote(const char* args);
102static void subcmd_get_udp_port_remote(const char* args);
103static void subcmd_set_v24_baudrate(const char* args);
104static void subcmd_get_v24_baudrate(const char* args);
105static void subcmd_set_v24_inverted(const char* args);
106static void subcmd_get_v24_inverted(const char* args);
107static void subcmd_set_v24_clockmode(const char* args);
108static void subcmd_get_v24_clockmode(const char* args);
109
110// Lookup tables
111static const command_t commands[] = {
112 {"help", cmd_help, "Show available commands"},
113 {"status", cmd_status, "Show system status and RXC estimate"},
114 {"mem", cmd_mem, "Show RAM/flash memory usage"},
115 {"save", cmd_save, "Persist current configuration to flash"},
116 {"wipe", cmd_wipe, "Erase persistent configuration from flash"},
117 {"net", cmd_net, "Show current network status (W5500)"},
118 {"set", cmd_set, "Set values (e.g. set gpio <pin> <0|1>, set net ip.local <addr>/<cidr>)"},
119 {"get", cmd_get, "Get values (e.g. get gpio <pin>, get net ip.local)"},
120 {"pininfo", cmd_pininfo, "Show pin details: pininfo <pin>"},
121 {"reboot", cmd_reboot, "Reboot the device"},
122};
123
124static const category_t categories[] = {
125 {"gpio", cat_gpio_set, cat_gpio_get, "GPIO controls and queries"},
126 {"net", cat_net_set, cat_net_get, "Network configuration and queries"},
127 {"v24", cat_v24_set, cat_v24_get, "V.24 config (inverted pins, baudrate)"},
128 {"loglevel", cat_loglevel_set, cat_loglevel_get, "Runtime logging level"}};
129
130static const subcmd_t net_subcmds[] = {
131 {"ip.local", subcmd_set_ip_local, subcmd_get_ip_local, "Local IP address (CIDR)"},
132 {"ip.remote", subcmd_set_ip_remote, subcmd_get_ip_remote, "Remote IP address"},
133 {"ip.gateway", subcmd_set_ip_gateway, subcmd_get_ip_gateway, "Gateway IP address"},
134 {"udp.port.local", subcmd_set_udp_port_local, subcmd_get_udp_port_local, "Local UDP port"},
135 {"udp.port.remote", subcmd_set_udp_port_remote, subcmd_get_udp_port_remote, "Remote UDP port"},
136};
137#define INVERT_HELP "Invert pins (comma-separated, e.g. set v24 invert txd,rxd)"
138static const subcmd_t v24_subcmds[] = {
140 {"baudrate", subcmd_set_v24_baudrate, subcmd_get_v24_baudrate, "Baudrate"},
142 "<0|1> Internal or external tx clock"}};
143
144#define NUM_COMMANDS (sizeof(commands) / sizeof(commands[0]))
145#define NUM_CATEGORIES ARRAY_LEN(categories)
146#define NUM_NET_SUBCMDS ARRAY_LEN(net_subcmds)
147#define NUM_V24_SUBCMDS ARRAY_LEN(v24_subcmds)
148#define NUM_PINS get_num_pins()
149
154#define NUM_V24_BAUDRATES ARRAY_LEN(v24_baudrates)
155
156typedef struct
157{
158 const char* name;
161
162static const loglevel_entry_t loglevels[] = {
163 {"error", LOG_LEVEL_ERROR}, {"info", LOG_LEVEL_INFO}, {"debug", LOG_LEVEL_DEBUG},
164 {"trace", LOG_LEVEL_TRACE}, {"tracea", LOG_LEVEL_TRACE},
165};
166#define NUM_LOGLEVELS ARRAY_LEN(loglevels)
167
168static void dispatch_v24_polarities(const V24_POLARITIES_T* polarities)
169{
170 event_queue_data_t event_data = {.id = V24_POLARITIES};
171 memcpy(&event_data.value.polarities, polarities, sizeof(V24_POLARITIES_T));
172
173 event_t event = {
175 .data_len = sizeof(event_data),
176 .is_inline = true,
177 };
178 memcpy(event.data.bytes, &event_data, sizeof(event_data));
179 event_queue_push(&event);
180}
181
183{
184 event_queue_data_t get_request = {.id = type};
185
186 event_t event = {
187 .type = event_type,
188 .data_len = sizeof(get_request),
189 .is_inline = true,
190 };
191 memcpy(event.data.bytes, &get_request, sizeof(get_request));
192 event_queue_push(&event);
193}
194static void subcmd_set_v24_inverted(const char* args)
195{
196 V24_POLARITIES_T polarities;
197 if (parse_set_v24_polarities(args, &polarities) != E2S_OK)
198 {
199 LOG_PLAIN("usage: set v24 polarities txd,rxd,rts\r\n");
200 return;
201 }
202 dispatch_v24_polarities(&polarities);
203}
204
205static void subcmd_get_v24_inverted(const char* args)
206{
207 (void)args;
209}
210
211static void dispatch_v24_baudrate(const V24_BAUDRATE_T* baudrate)
212{
213 event_queue_data_t event_data = {.id = V24_BAUDRATE};
214 memcpy(&event_data.value.baudrate, baudrate, sizeof(V24_BAUDRATE_T));
215
216 event_t event = {
218 .data_len = sizeof(event_data),
219 .is_inline = true,
220 };
221 memcpy(event.data.bytes, &event_data, sizeof(event_data));
222 event_queue_push(&event);
223}
224static void subcmd_set_v24_clockmode(const char* args)
225{
226 bool clockmode;
227 if (parse_set_v24_clockmode(args, &clockmode) != E2S_OK)
228 {
229 LOG_PLAIN("usage: set v24 txclock <0|1> \r\n");
230 return;
231 }
232 event_queue_data_t event_data = {.id = V24_CLOCK_MODE};
233 memcpy(&event_data.value.v24_clock_mode, &clockmode, sizeof(bool));
234
235 event_t event = {
237 .data_len = sizeof(event_data),
238 .is_inline = true,
239 };
240 memcpy(event.data.bytes, &event_data, sizeof(event_data));
241 event_queue_push(&event);
242}
243
244static void subcmd_set_v24_baudrate(const char* args)
245{
246 V24_BAUDRATE_T baudrate;
247 if (parse_set_v24_baudrate(args, &baudrate) != E2S_OK)
248 {
249 LOG_PLAIN("usage: set v24 baudrate 9600\r\n");
250 return;
251 }
252 dispatch_v24_baudrate(&baudrate);
253}
254static void subcmd_get_v24_clockmode(const char* args)
255{
256 (void)args;
258}
259
260static void subcmd_get_v24_baudrate(const char* args)
261{
262 (void)args;
264}
265
266static void cat_v24_set(const char* args)
267{
268 LOG_DEBUG("set v24: args='%s'\r\n", args);
269 if (args == NULL || args[0] == '\0')
270 {
271 LOG_PLAIN("usage: set v24 <subcmd> <args>\r\n");
272 LOG_PLAIN("available v24 subcmds:\r\n");
273 for (size_t i = 0; i < NUM_V24_SUBCMDS; i++)
274 {
275 LOG_PLAIN(" %s - %s\r\n", v24_subcmds[i].name, v24_subcmds[i].help);
276 }
277 return;
278 }
279 for (size_t i = 0; i < NUM_V24_SUBCMDS; i++)
280 {
281 size_t len = strlen(v24_subcmds[i].name);
282 if (strncmp(args, v24_subcmds[i].name, len) == 0 && (args[len] == ' ' || args[len] == '\0'))
283 {
284 const char* sub_args = args[len] == ' ' ? args + len + 1 : "";
285 v24_subcmds[i].set_handler(sub_args);
286 return;
287 }
288 }
289 LOG_PLAIN("unknown v24 subcmd: '%s'\r\n", args);
290}
291
292static void cat_v24_get(const char* args)
293{
294 LOG_DEBUG("get v24: args='%s'\r\n", args);
295 if (args == NULL || args[0] == '\0')
296 {
297 LOG_PLAIN("usage: get v24 <subcmd>\r\n");
298 LOG_PLAIN("available v24 subcmds:\r\n");
299 for (size_t i = 0; i < NUM_V24_SUBCMDS; i++)
300 {
301 LOG_PLAIN(" %s - %s\r\n", v24_subcmds[i].name, v24_subcmds[i].help);
302 }
303 return;
304 }
305 for (size_t i = 0; i < NUM_V24_SUBCMDS; i++)
306 {
307 size_t len = strlen(v24_subcmds[i].name);
308 if (strncmp(args, v24_subcmds[i].name, len) == 0 && (args[len] == ' ' || args[len] == '\0'))
309 {
310 const char* sub_args = args[len] == ' ' ? args + len + 1 : "";
311 v24_subcmds[i].get_handler(sub_args);
312 return;
313 }
314 }
315 LOG_PLAIN("unknown v24 subcmd: '%s'\r\n", args);
316}
317
318static void cat_loglevel_set(const char* args)
319{
320 if (args == NULL || args[0] == '\0')
321 {
322 LOG_PLAIN("usage: set loglevel <error|info|debug|trace>\r\n");
323 return;
324 }
325
326 char level_name[16];
327 if (sscanf(args, "%15s", level_name) != 1)
328 {
329 LOG_PLAIN("usage: set loglevel <error|info|debug|trace>\r\n");
330 return;
331 }
332
333 for (size_t i = 0; i < NUM_LOGLEVELS; i++)
334 {
335 if (strcmp(level_name, loglevels[i].name) == 0)
336 {
337 set_loglevel(loglevels[i].value);
338 LOG_PLAIN("LOG_LEVEL: %s\r\n", log_level_tag(get_loglevel()));
339 return;
340 }
341 }
342
343 LOG_PLAIN("unknown loglevel: '%s'\r\n", level_name);
344 LOG_PLAIN("available loglevels: error, info, debug, trace\r\n");
345}
346
347static void cat_loglevel_get(const char* args)
348{
349 if (args != NULL && args[0] != '\0')
350 {
351 LOG_PLAIN("usage: get loglevel\r\n");
352 return;
353 }
354 LOG_PLAIN("LOG_LEVEL: %s\r\n", log_level_tag(get_loglevel()));
355}
356
357static void cmd_reboot(const char* args)
358{
359 (void)args;
360
361 (void)args;
362 event_t status_event = {.type = EV_REBOOT, .data.ptr = NULL, .data_len = 0, .is_inline = false};
363 event_queue_push(&status_event);
364}
365
366static void dispatch_ip(const uint8_t* ip_addr, const event_queue_data_types_t type)
367{
368 event_queue_data_t ip_event_data = {.id = type};
369 memcpy(ip_event_data.value.ip, ip_addr, 4); //
370
371 event_t ip_event = {
373 .data_len = sizeof(ip_event_data),
374 .is_inline = true,
375 };
376 memcpy(ip_event.data.bytes, &ip_event_data, sizeof(ip_event_data));
377 event_queue_push(&ip_event);
378}
379
380static void subcmd_get_ip_local(const char* args)
381{
382 if (args != NULL && args[0] != '\0')
383 {
384 LOG_PLAIN("usage: get net ip.local\r\n");
385 return;
386 }
388}
389
390static void subcmd_set_ip_local(const char* args)
391{
392 uint8_t ip_addr[4];
393 uint8_t mask[4];
394 if (parse_set_ip_args(args, ip_addr, mask) != E2S_OK)
395 {
396 LOG_PLAIN("usage: set net ip 192.168.29.2/24\r\n");
397 return;
398 }
399 dispatch_ip(ip_addr, NET_IP_LOCAL);
401}
402
403static void subcmd_get_ip_remote(const char* args)
404{
405 if (args != NULL && args[0] != '\0')
406 {
407 LOG_PLAIN("usage: get net ip.remote\r\n");
408 return;
409 }
411}
412
413static void subcmd_set_ip_remote(const char* args)
414{
415 uint8_t ip_addr[4];
416 if (parse_set_ip_remote_args(args, ip_addr) != E2S_OK)
417 {
418 LOG_PLAIN("usage: set net ip.remote 192.168.29.2\r\n");
419 return;
420 }
421 dispatch_ip(ip_addr, NET_IP_REMOTE);
422}
423
424static void subcmd_get_ip_gateway(const char* args)
425{
426 if (args != NULL && args[0] != '\0')
427 {
428 LOG_PLAIN("usage: get net ip.gateway\r\n");
429 return;
430 }
432}
433
434static void subcmd_set_ip_gateway(const char* args)
435{
436 uint8_t ip_addr[4];
437 if (parse_set_ip_remote_args(args, ip_addr) != E2S_OK)
438 {
439 LOG_PLAIN("usage: set net ip.gateway 192.168.29.1\r\n");
440 return;
441 }
442 dispatch_ip(ip_addr, NET_IP_GATEWAY);
443}
444
446{
447 event_queue_data_t get_request = {.id = type};
448
449 event_t event = {
451 .data_len = sizeof(get_request),
452 .is_inline = true,
453 };
454 memcpy(event.data.bytes, &get_request, sizeof(get_request));
455 event_queue_push(&event);
456}
457
458static void dispatch_set_udp_port(const event_queue_data_types_t type, uint16_t port)
459{
460 event_queue_data_t set_request = {.id = type, .value.port = port};
461
462 event_t event = {
464 .data_len = sizeof(set_request),
465 .is_inline = true,
466 };
467 memcpy(event.data.bytes, &set_request, sizeof(set_request));
468 event_queue_push(&event);
469}
470
471static void subcmd_get_udp_port_local(const char* args)
472{
473 if (args != NULL && args[0] != '\0')
474 {
475 LOG_PLAIN("usage: get net udp.port.local\r\n");
476 return;
477 }
479}
480
481static void subcmd_set_udp_port_local(const char* args)
482{
483 uint16_t port = 0;
484 if (parse_set_udp_port_local_args(args, &port) != E2S_OK)
485 {
486 LOG_PLAIN("usage: set net udp.port.local 6969\r\n");
487 return;
488 }
490}
491
492static void subcmd_get_udp_port_remote(const char* args)
493{
494 if (args != NULL && args[0] != '\0')
495 {
496 LOG_PLAIN("usage: get net udp.port.remote\r\n");
497 return;
498 }
499
501}
502
503static void subcmd_set_udp_port_remote(const char* args)
504{
505 uint16_t port = 0;
506 if (parse_set_udp_port_remote_args(args, &port) != E2S_OK)
507 {
508 LOG_PLAIN("usage: set net udp.port.remote 6969\r\n");
509 return;
510 }
512}
513
514static void cat_net_get(const char* args)
515{
516 LOG_DEBUG("get net: args='%s'\r\n", args);
517 if (args == NULL || args[0] == '\0')
518 {
519 LOG_PLAIN("usage: get net <subcmd>\r\n");
520 LOG_PLAIN("available net subcmds:\r\n");
521 for (size_t i = 0; i < NUM_NET_SUBCMDS; i++)
522 {
523 LOG_PLAIN(" %s - %s\r\n", net_subcmds[i].name, net_subcmds[i].help);
524 }
525 return;
526 }
527 for (size_t i = 0; i < NUM_NET_SUBCMDS; i++)
528 {
529 size_t len = strlen(net_subcmds[i].name);
530 if (strncmp(args, net_subcmds[i].name, len) == 0 && (args[len] == ' ' || args[len] == '\0'))
531 {
532 const char* sub_args = args[len] == ' ' ? args + len + 1 : "";
533 net_subcmds[i].get_handler(sub_args);
534 return;
535 }
536 }
537 LOG_PLAIN("unknown net subcmd: '%s'\r\n", args);
538}
539
540static void cat_gpio_set(const char* args)
541{
542 char pin_name[MAX_PIN_NAME_LEN];
543 int value;
544 const pin_info_t* pin = NULL;
545 e2s_error_t parser_result = parse_set_gpio_args(args, pin_name, &value, &pin);
546
547 switch (parser_result)
548 {
550 LOG_PLAIN("usage:\r\n");
551 LOG_PLAIN(" set gpio <pin> <0|1>\r\n");
552 return;
554 LOG_PLAIN("unknown pin: '%s'\r\n", pin_name);
555 return;
557 LOG_PLAIN("pin '%s' is input-only\r\n", pin_name);
558 return;
559 case E2S_OK:
560 break;
561 default:
562 // Unreachable
563 return;
564 }
565
566 if (pin == NULL)
567 {
568 return;
569 }
570
571 gpio_init(pin->gpio_num);
572 gpio_set_dir(pin->gpio_num, GPIO_OUT);
573 gpio_put(pin->gpio_num, value);
574
575 LOG_PLAIN("set %s (pin %u) = %d\r\n", pin_name, pin->gpio_num, value);
576}
577
578static void cat_net_set(const char* args)
579{
580 if (args == NULL || args[0] == '\0')
581 {
582 LOG_PLAIN("usage: set net <subcmd> <args>\r\n");
583 LOG_PLAIN("available net subcmds:\r\n");
584 for (size_t i = 0; i < NUM_NET_SUBCMDS; i++)
585 {
586 LOG_PLAIN(" %s - %s\r\n", net_subcmds[i].name, net_subcmds[i].help);
587 }
588 return;
589 }
590 for (size_t i = 0; i < NUM_NET_SUBCMDS; i++)
591 {
592 size_t len = strlen(net_subcmds[i].name);
593 if (strncmp(args, net_subcmds[i].name, len) == 0 && (args[len] == ' ' || args[len] == '\0'))
594 {
595 const char* sub_args = args[len] == ' ' ? args + len + 1 : "";
596 net_subcmds[i].set_handler(sub_args);
597 return;
598 }
599 }
600 LOG_PLAIN("unknown net subcmd: '%s'\r\n", args);
601}
602
603static void cat_gpio_get(const char* args)
604{
605 char pin_name[MAX_PIN_NAME_LEN];
606 const pin_info_t* pin = NULL;
607
608 e2s_error_t parser_result = parse_get_args(args, pin_name, &pin);
609
610 switch (parser_result)
611 {
613 LOG_PLAIN("usage: get <pin>\r\n");
614 return;
616 LOG_PLAIN("unknown pin: '%s'\r\n", pin_name);
617 return;
618 case E2S_OK:
619 break;
620 default:
621 // Unreachable
622 return;
623 }
624
625 if (pin == NULL)
626 {
627 return;
628 }
629
630 // Only initialize if not already a GPIO function
631 if (gpio_get_function(pin->gpio_num) != GPIO_FUNC_SIO)
632 {
633 gpio_init(pin->gpio_num);
634 gpio_set_dir(pin->gpio_num, GPIO_IN);
635 }
636 // If already GPIO but not configured as input/output, set as input
637 else if (!gpio_is_dir_out(pin->gpio_num))
638 {
639 // Already initialized as GPIO input, no change needed
640 }
641
642 int value = gpio_get(pin->gpio_num);
643 bool is_output = gpio_is_dir_out(pin->gpio_num);
644
645 LOG_PLAIN("get %s (pin %u) = %d [%s]\r\n", pin_name, pin->gpio_num, value,
646 is_output ? "OUT" : "IN");
647}
648
649static void cmd_set(const char* args)
650{
651 if (args == NULL || args[0] == '\0')
652 {
653 LOG_PLAIN("usage: set <category> <args>\r\n");
654 LOG_PLAIN("available categories:\r\n");
655 for (size_t i = 0; i < NUM_CATEGORIES; i++)
656 {
657 LOG_PLAIN(" %s - %s\r\n", categories[i].name, categories[i].help);
658 }
659 return;
660 }
661 for (size_t i = 0; i < NUM_CATEGORIES; i++)
662 {
663 size_t len = strlen(categories[i].name);
664 if (strncmp(args, categories[i].name, len) == 0 && args[len] == ' ')
665 {
666 categories[i].set_handler(args + len + 1);
667 return;
668 }
669 }
670 LOG_PLAIN("unknown set category: '%s'\r\n", args);
671}
672
673static void cmd_get(const char* args)
674{
675 if (args == NULL || args[0] == '\0')
676 {
677 LOG_PLAIN("usage: get <category> <args>\r\n");
678 LOG_PLAIN("available categories:\r\n");
679 for (size_t i = 0; i < NUM_CATEGORIES; i++)
680 {
681 LOG_PLAIN(" %s - %s\r\n", categories[i].name, categories[i].help);
682 }
683 return;
684 }
685 for (size_t i = 0; i < NUM_CATEGORIES; i++)
686 {
687 size_t len = strlen(categories[i].name);
688 if (strncmp(args, categories[i].name, len) == 0 && (args[len] == ' ' || args[len] == '\0'))
689 {
690 const char* cat_args = args[len] == ' ' ? args + len + 1 : "";
691 categories[i].get_handler(cat_args);
692 return;
693 }
694 }
695 LOG_PLAIN("unknown get category: '%s'\r\n", args);
696}
697
698static void cmd_wipe(const char* args)
699{
700 (void)args;
701 event_t wipe_event = {
702 .type = EV_WIPE_CONFIG, .data.ptr = NULL, .data_len = 0, .is_inline = false};
703 event_queue_push(&wipe_event);
704}
705
706static void cmd_save(const char* args)
707{
708 (void)args;
709 event_t save_event = {
710 .type = EV_SAVE_CONFIG, .data.ptr = NULL, .data_len = 0, .is_inline = false};
711 event_queue_push(&save_event);
712}
713
714// Command handlers
715static void cmd_help(const char* args)
716{
717 (void)args;
718
719 size_t max_cmd = 0;
720 for (size_t i = 0; i < NUM_COMMANDS; i++)
721 {
722 size_t len = strlen(commands[i].name);
723 if (len > max_cmd)
724 {
725 max_cmd = len;
726 }
727 }
728
729 LOG_PLAIN("\r\nCommands:\r\n");
730 for (size_t i = 0; i < NUM_COMMANDS; i++)
731 {
732 LOG_PLAIN(" %-*s %s\r\n", (int)max_cmd, commands[i].name, commands[i].help);
733 }
734
735 LOG_PLAIN("\r\nSet/Get Categories:\r\n");
736 for (size_t i = 0; i < NUM_CATEGORIES; i++)
737 {
738 LOG_PLAIN(" %s - %s\r\n", categories[i].name, categories[i].help);
739 }
740
741 LOG_PLAIN("\r\nNet Subcommands:\r\n");
742 for (size_t i = 0; i < NUM_NET_SUBCMDS; i++)
743 {
744 LOG_PLAIN(" %s - %s\r\n", net_subcmds[i].name, net_subcmds[i].help);
745 }
746
747 LOG_PLAIN("\r\nV24 Subcommands:\r\n");
748 for (size_t i = 0; i < NUM_V24_SUBCMDS; i++)
749 {
750 LOG_PLAIN(" %s - %s\r\n", v24_subcmds[i].name, v24_subcmds[i].help);
751 }
752
753 LOG_PLAIN("\r\nPins:\r\n");
755 for (size_t i = 0; i < NUM_PINS; i++)
756 {
757 LOG_PLAIN(" %-10s %s\r\n", pin_table[i].name, pin_table[i].is_output ? "OUT" : "IN");
758 }
759
760 LOG_PLAIN("\r\nBaudrates:\r\n");
761 LOG_PLAIN(" ");
762 for (size_t i = 0; i < NUM_V24_BAUDRATES; i++)
763 {
764 LOG_PLAIN("%u", (unsigned)v24_baudrates[i]);
765 if (i < NUM_V24_BAUDRATES - 1)
766 {
767 LOG_PLAIN(", ");
768 }
769 }
770 LOG_PLAIN("\r\n");
771
772 LOG_PLAIN("\r\nLoglevels:\r\n");
773 LOG_PLAIN(" error, info, debug, trace\r\n");
774}
775
776static void cmd_status(const char* args)
777{
778 (void)args;
779 event_t status_event = {.type = EV_STATUS, .data.ptr = NULL, .data_len = 0, .is_inline = false};
780 event_queue_push(&status_event);
781}
782
783static void cmd_mem(const char* args)
784{
785 if (args != NULL && args[0] != '\0')
786 {
787 LOG_PLAIN("usage: mem\r\n");
788 return;
789 }
790 event_t mem_event = {.type = EV_MEM, .data.ptr = NULL, .data_len = 0, .is_inline = false};
791 event_queue_push(&mem_event);
792}
793
794static void cmd_net(const char* args)
795{
796 if (args != NULL && args[0] != '\0')
797 {
798 LOG_PLAIN("usage: net\r\n");
799 return;
800 }
801 wiz_NetInfo net_info;
802 wizchip_getnetinfo(&net_info);
803 LOG_PLAIN("ip=%u.%u.%u.%u gw=%u.%u.%u.%u\r\n", net_info.ip[0], net_info.ip[1], net_info.ip[2],
804 net_info.ip[3], net_info.gw[0], net_info.gw[1], net_info.gw[2], net_info.gw[3]);
805}
806
807static void cmd_pininfo(const char* args)
808{
809 char pin_name[MAX_PIN_NAME_LEN];
810
811 if (sscanf(args, "%15s", pin_name) != 1)
812 {
813 LOG_PLAIN("usage: pininfo <pin>\r\n");
814 return;
815 }
816
817 const pin_info_t* pin = find_pin(pin_name);
818 if (!pin)
819 {
820 LOG_PLAIN("unknown pin: '%s'\r\n", pin_name);
821 return;
822 }
823
824 uint8_t gpio_num = pin->gpio_num;
825 bool is_output = gpio_is_dir_out(gpio_num);
826 int value = gpio_get(gpio_num);
827
828 LOG_PLAIN("Pin %s (GPIO %u):\r\n", pin_name, gpio_num);
829 LOG_PLAIN(" Direction: %s\r\n", is_output ? "OUTPUT" : "INPUT");
830 LOG_PLAIN(" Value: %d\r\n", value);
831 LOG_PLAIN(" Function: %d\r\n", gpio_get_function(gpio_num));
832}
833
834const char* get_command_name(int index)
835{
836 return commands[index].name;
837}
838
839void handle_cli_line(const char* line)
840{
841 char cmd[MAX_CMD_BUFFER_LEN] = {0};
842 char args[MAX_ARG_BUFFER_LEN] = {0};
843
844 e2s_error_t parse_result = cli_parse(line, cmd, sizeof(cmd), args, sizeof(args));
845 if (parse_result == E2S_ERR_CLI_EMPTY_LINE)
846 {
847 return;
848 }
849 if (parse_result == E2S_ERR_CLI_LINE_TRUNCATED)
850 {
851 LOG_PLAIN("error: command too long\r\n");
852 return;
853 }
854 if (parse_result != E2S_OK)
855 {
856 LOG_PLAIN("error: invalid command line\r\n");
857 return;
858 }
859
860 for (size_t i = 0; i < NUM_COMMANDS; i++)
861 {
862 if (strcmp(cmd, commands[i].name) == 0)
863 {
864 commands[i].handler(args);
865 return;
866 }
867 }
868
869 LOG_PLAIN("unknown: '%s' (try 'help')\r\n", cmd);
870}
static const V24_BAUDRATE_T v24_baudrates[]
static void cat_v24_set(const char *args)
static void dispatch_v24_polarities(const V24_POLARITIES_T *polarities)
static void subcmd_get_udp_port_local(const char *args)
static void cmd_reboot(const char *args)
static void dispatch_set_udp_port(const event_queue_data_types_t type, uint16_t port)
static void subcmd_get_udp_port_remote(const char *args)
static void subcmd_get_ip_gateway(const char *args)
static void subcmd_set_udp_port_remote(const char *args)
void(* category_set_handler_t)(const char *args)
static void cmd_help(const char *args)
void handle_cli_line(const char *line)
Parse and execute one CLI input line.
static const loglevel_entry_t loglevels[]
const char * get_command_name(int index)
Return command name by table index.
static void cmd_mem(const char *args)
static void subcmd_get_v24_clockmode(const char *args)
static void subcmd_set_ip_gateway(const char *args)
#define MAX_PIN_NAME_LEN
static void subcmd_set_v24_baudrate(const char *args)
#define NUM_PINS
static void cmd_status(const char *args)
static void subcmd_get_ip_remote(const char *args)
#define NUM_V24_BAUDRATES
static void cmd_set(const char *args)
static void dispatch_get_request(event_queue_data_types_t type, event_type_t event_type)
static void cat_gpio_get(const char *args)
#define NUM_NET_SUBCMDS
#define NUM_CATEGORIES
static void cat_net_get(const char *args)
#define MAX_ARG_BUFFER_LEN
static const category_t categories[]
static void cmd_save(const char *args)
static void cat_loglevel_get(const char *args)
static void subcmd_set_ip_local(const char *args)
#define NUM_LOGLEVELS
void(* subcmd_set_handler_t)(const char *args)
static void cmd_net(const char *args)
static void cmd_get(const char *args)
void(* category_get_handler_t)(const char *args)
static void cmd_pininfo(const char *args)
static void dispatch_get_udp_port(const event_queue_data_types_t type)
static const subcmd_t v24_subcmds[]
void(* subcmd_get_handler_t)(const char *args)
#define MAX_CMD_BUFFER_LEN
static const command_t commands[]
static void dispatch_ip(const uint8_t *ip_addr, const event_queue_data_types_t type)
static void subcmd_get_v24_baudrate(const char *args)
static void dispatch_v24_baudrate(const V24_BAUDRATE_T *baudrate)
static const subcmd_t net_subcmds[]
static void subcmd_get_v24_inverted(const char *args)
static void subcmd_set_ip_remote(const char *args)
static void cat_v24_get(const char *args)
static void cat_net_set(const char *args)
#define NUM_COMMANDS
static void cmd_wipe(const char *args)
static void subcmd_set_v24_clockmode(const char *args)
static void subcmd_set_v24_inverted(const char *args)
static void subcmd_get_ip_local(const char *args)
#define INVERT_HELP
static void subcmd_set_udp_port_local(const char *args)
void(* cmd_handler_t)(const char *args)
static void cat_gpio_set(const char *args)
#define NUM_V24_SUBCMDS
static void cat_loglevel_set(const char *args)
e2s_error_t parse_set_v24_baudrate(const char *args, V24_BAUDRATE_T *baudrate)
Parse V.24 baudrate argument.
Definition cli_parser.c:417
e2s_error_t cli_parse(const char *line, char *cmd, size_t cmd_cap, char *args, size_t args_cap)
Split one CLI line into command and argument string.
Definition cli_parser.c:531
e2s_error_t parse_set_ip_args(const char *args, uint8_t ip_addr[4], uint8_t netmask[4])
Parse ip_addr and optional netmask values.
Definition cli_parser.c:187
e2s_error_t parse_get_args(const char *args, char *pin_name, const pin_info_t **pin)
Parse get command arguments and resolve pin metadata.
Definition cli_parser.c:515
e2s_error_t parse_set_v24_clockmode(const char *args, bool *clockmode)
Parse V.24 tx clock mode argument.
Definition cli_parser.c:462
const pin_info_t * find_pin(const char *name)
Lookup pin metadata by name.
Definition cli_parser.c:503
static const pin_info_t pin_table[]
Definition cli_parser.c:33
e2s_error_t parse_set_udp_port_remote_args(const char *args, uint16_t *port)
Parse remote UDP port argument.
Definition cli_parser.c:307
e2s_error_t parse_set_gpio_args(const char *args, char *pin_name, int *value, const pin_info_t **pin)
Parse GPIO set command arguments.
Definition cli_parser.c:231
const pin_info_t * get_pin_table(void)
Return pointer to static pin metadata table.
Definition cli_parser.c:497
e2s_error_t parse_set_udp_port_local_args(const char *args, uint16_t *port)
Parse local UDP port argument.
Definition cli_parser.c:302
e2s_error_t parse_set_ip_remote_args(const char *args, uint8_t ip_addr[4])
Parse remote ip_addr argument.
Definition cli_parser.c:292
e2s_error_t parse_set_v24_polarities(const char *args, V24_POLARITIES_T *polarities)
Parse V.24 polarities argument list.
Definition cli_parser.c:312
log_level_t get_loglevel(void)
Get current global log level.
Definition log.c:61
static const char * log_level_tag(log_level_t level)
Get printable tag for a log level.
Definition common.h:125
#define LOG_DEBUG(...)
Definition common.h:165
#define LOG_PLAIN(...)
Definition common.h:162
void set_loglevel(log_level_t level)
Set current global log level.
Definition log.c:66
log_level_t
Log verbosity levels.
Definition common.h:87
@ LOG_LEVEL_DEBUG
Definition common.h:91
@ LOG_LEVEL_ERROR
Definition common.h:89
@ LOG_LEVEL_TRACE
Definition common.h:92
@ LOG_LEVEL_INFO
Definition common.h:90
e2s_error_t
Common error codes returned by ether2ser modules.
Definition error.h:27
@ E2S_ERR_CLI_EMPTY_LINE
Definition error.h:32
@ E2S_ERR_CLI_UNKNOWN_PIN
Definition error.h:37
@ E2S_OK
Definition error.h:28
@ E2S_ERR_CLI_USAGE_SET
Definition error.h:34
@ E2S_ERR_CLI_LINE_TRUNCATED
Definition error.h:40
@ E2S_ERR_CLI_PIN_INPUT_ONLY
Definition error.h:38
@ E2S_ERR_CLI_USAGE_GET
Definition error.h:35
bool event_queue_push(const event_t *event_entry)
Enqueue an event.
Definition event_queue.c:49
event_queue_data_types_t
Typed payload selector for configuration-oriented events.
Definition event_queue.h:56
@ NET_PORT_REMOTE
Definition event_queue.h:62
@ NET_IP_MASK
Definition event_queue.h:60
@ V24_POLARITIES
Definition event_queue.h:64
@ V24_CLOCK_MODE
Definition event_queue.h:65
@ V24_BAUDRATE
Definition event_queue.h:63
@ NET_PORT_LOCAL
Definition event_queue.h:61
@ NET_IP_LOCAL
Definition event_queue.h:59
@ NET_IP_REMOTE
Definition event_queue.h:57
@ NET_IP_GATEWAY
Definition event_queue.h:58
event_type_t
Event type identifiers.
Definition event_queue.h:35
@ EV_STATUS
Definition event_queue.h:42
@ EV_SET_V24_SETTINGS
Definition event_queue.h:47
@ EV_GET_NET_SETTINGS
Definition event_queue.h:46
@ EV_MEM
Definition event_queue.h:43
@ EV_WIPE_CONFIG
Definition event_queue.h:44
@ EV_SET_NET_SETTINGS
Definition event_queue.h:45
@ EV_GET_V24_SETTINGS
Definition event_queue.h:48
@ EV_REBOOT
Definition event_queue.h:49
@ EV_SAVE_CONFIG
Definition event_queue.h:41
Combined TX and RX polarity configuration.
Definition v24_config.h:78
category_set_handler_t set_handler
category_get_handler_t get_handler
const char * help
const char * name
cmd_handler_t handler
const char * name
const char * help
Generic event payload wrapper for network/V.24 config operations.
Definition event_queue.h:73
V24_BAUDRATE_T baudrate
Definition event_queue.h:82
V24_POLARITIES_T polarities
Definition event_queue.h:81
event_queue_data_types_t id
Definition event_queue.h:75
union event_queue_data_t::@0 value
Event queue entry.
Definition event_queue.h:91
event_type_t type
Definition event_queue.h:93
union event_t::@1 data
uint8_t bytes[16]
log_level_t value
const char * name
Pin metadata entry used by CLI lookup and validation.
Definition cli_parser.h:33
uint8_t gpio_num
Definition cli_parser.h:37
subcmd_set_handler_t set_handler
const char * help
const char * name
subcmd_get_handler_t get_handler
V24_BAUDRATE_T
Supported synchronous V.24 baudrates.
Definition v24_config.h:32
@ V24_BAUD_1200
Definition v24_config.h:33
@ V24_BAUD_2400
Definition v24_config.h:34
@ V24_BAUD_115200
Definition v24_config.h:41
@ V24_BAUD_19200
Definition v24_config.h:38
@ V24_BAUD_57600
Definition v24_config.h:40
@ V24_BAUD_38400
Definition v24_config.h:39
@ V24_BAUD_4800
Definition v24_config.h:35
@ V24_BAUD_9600
Definition v24_config.h:36
@ V24_BAUD_16000
Definition v24_config.h:37