#include "usb_console.h" #include #include #include #include "esp_console.h" #include "esp_err.h" #include "session_broker.h" #include "usb_cdc_transport.h" static const char *yes_no(bool value) { return value ? "yes" : "no"; } static const char *stop_bits_name(uint8_t stop_bits) { switch (stop_bits) { case USB_CDC_TRANSPORT_STOP_BITS_1: return "1"; case USB_CDC_TRANSPORT_STOP_BITS_1_5: return "1.5"; case USB_CDC_TRANSPORT_STOP_BITS_2: return "2"; default: return "unknown"; } } static const char *parity_name(uint8_t parity) { switch (parity) { case USB_CDC_TRANSPORT_PARITY_NONE: return "none"; case USB_CDC_TRANSPORT_PARITY_ODD: return "odd"; case USB_CDC_TRANSPORT_PARITY_EVEN: return "even"; case USB_CDC_TRANSPORT_PARITY_MARK: return "mark"; case USB_CDC_TRANSPORT_PARITY_SPACE: return "space"; default: return "unknown"; } } static int show_status(void) { usb_cdc_transport_snapshot_t snapshot; esp_err_t err = usb_cdc_transport_get_snapshot(&snapshot); if (err != ESP_OK) { printf("Could not read USB CDC status: %s\n", esp_err_to_name(err)); return 1; } bool host_open = snapshot.attached && snapshot.dtr; printf("USB CDC: initialized=%s attached=%s host-open=%s DTR=%s RTS=%s\n", yes_no(snapshot.initialized), yes_no(snapshot.attached), yes_no(host_open), yes_no(snapshot.dtr), yes_no(snapshot.rts)); if (snapshot.broker_client_id == SESSION_BROKER_NO_CLIENT) { printf("Broker: disconnected\n"); } else { printf("Broker: client=%" PRIu32 " role=%s\n", snapshot.broker_client_id, snapshot.writer ? "writer" : "observer"); } printf("Last host line coding: baud=%" PRIu32 " data=%u parity=%s stop=%s\n", snapshot.line_coding.baud_rate, (unsigned int)snapshot.line_coding.data_bits, parity_name(snapshot.line_coding.parity), stop_bits_name(snapshot.line_coding.stop_bits)); printf("Host line coding is reported only; UART1 uses the serial configuration.\n"); return 0; } static int show_counters(void) { usb_cdc_transport_snapshot_t snapshot; esp_err_t err = usb_cdc_transport_get_snapshot(&snapshot); if (err != ESP_OK) { printf("Could not read USB CDC counters: %s\n", esp_err_to_name(err)); return 1; } const usb_cdc_transport_counters_t *counter = &snapshot.counters; printf("Host RX: received=%" PRIu64 " stream-dropped=%" PRIu64 " broker-accepted=%" PRIu64 " discarded=%" PRIu64 "\n", counter->host_rx_bytes, counter->host_rx_stream_dropped_bytes, counter->broker_accepted_bytes, counter->broker_rejected_bytes); printf("Host TX: broker-read=%" PRIu64 " USB-queued=%" PRIu64 " local-dropped=%" PRIu64 "\n", counter->broker_to_usb_bytes, counter->usb_tx_queued_bytes, counter->usb_tx_dropped_bytes); printf("Sessions: connect=%" PRIu64 " disconnect=%" PRIu64 " grants=%" PRIu64 " denials=%" PRIu64 " revocations=%" PRIu64 " writer-events=%" PRIu64 "\n", counter->connections, counter->disconnections, counter->writer_grants, counter->writer_denials, counter->writer_revocations, counter->writer_events); printf("Service start failures=%" PRIu64 "\n", counter->service_start_failures); printf("Control/callback drops: control=%" PRIu64 " callback=%" PRIu64 "\n", counter->control_drops, counter->callback_drops); return 0; } static int queue_writer_request(bool request) { esp_err_t err = request ? usb_cdc_transport_request_writer() : usb_cdc_transport_release_writer(); if (err != ESP_OK) { printf("Could not queue USB writer %s: %s\n", request ? "request" : "release", esp_err_to_name(err)); return 1; } printf("USB writer %s queued; use 'usb status' to observe the result.\n", request ? "request" : "release"); return 0; } static void print_usage(void) { printf("Usage:\n"); printf(" usb status\n"); printf(" usb counters|clear-counters\n"); printf(" usb request-writer|release-writer\n"); } static int command_usb(int argc, char **argv) { if (argc == 1 || (argc == 2 && strcmp(argv[1], "help") == 0)) { print_usage(); return 0; } if (argc == 2 && strcmp(argv[1], "status") == 0) { return show_status(); } if (argc == 2 && strcmp(argv[1], "counters") == 0) { return show_counters(); } if (argc == 2 && strcmp(argv[1], "clear-counters") == 0) { esp_err_t err = usb_cdc_transport_clear_counters(); if (err != ESP_OK) { printf("Could not clear USB CDC counters: %s\n", esp_err_to_name(err)); return 1; } printf("USB CDC counters cleared.\n"); return 0; } if (argc == 2 && strcmp(argv[1], "request-writer") == 0) { return queue_writer_request(true); } if (argc == 2 && strcmp(argv[1], "release-writer") == 0) { return queue_writer_request(false); } print_usage(); return 1; } esp_err_t usb_console_register_commands(void) { const esp_console_cmd_t command = { .command = "usb", .help = "Inspect native USB CDC and manage writer ownership; run 'usb' for subcommands", .hint = NULL, .func = &command_usb, .argtable = NULL, }; return esp_console_cmd_register(&command); }