From 008904d63e868a134c1bcd6b92f8bcaf6215bd41 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Mon, 22 Dec 2025 16:08:31 +0000 Subject: [PATCH] drivers: can: shell: add can dump subcommand Add "can dump " subcommand for dumping all CAN RX frames of a given CAN controller. Signed-off-by: Henrik Brix Andersen --- drivers/can/can_shell.c | 100 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/drivers/can/can_shell.c b/drivers/can/can_shell.c index 982a790c6ce..38a98ca6512 100644 --- a/drivers/can/can_shell.c +++ b/drivers/can/can_shell.c @@ -25,6 +25,12 @@ struct can_shell_rx_event { const struct device *dev; }; +struct can_shell_dump_context { + int filter_id_std; + int filter_id_ext; + bool started; +}; + struct can_shell_mode_mapping { const char *name; can_mode_t mode; @@ -64,6 +70,8 @@ static struct k_poll_event can_shell_rx_msgq_events[] = { &can_shell_rx_msgq, 0) }; +static struct can_shell_dump_context can_shell_dump_ctx; + /* Forward declarations */ static void can_shell_tx_msgq_triggered_work_handler(struct k_work *work); static void can_shell_rx_msgq_triggered_work_handler(struct k_work *work); @@ -434,6 +442,94 @@ static int cmd_can_show(const struct shell *sh, size_t argc, char **argv) return 0; } +#define ASCII_CTRL_C 0x03 + +static void can_shell_dump_bypass_cb(const struct shell *sh, uint8_t *data, size_t len, + void *user_data) +{ + const struct device *dev = user_data; + int err; + + for (size_t i = 0; i < len; i++) { + if (data[i] == ASCII_CTRL_C) { + if (can_shell_dump_ctx.started) { + err = can_stop(dev); + if (err != 0) { + shell_error(sh, "failed to stop CAN controller (err %d)", + err); + } + } + + if (can_shell_dump_ctx.filter_id_std >= 0) { + can_remove_rx_filter(dev, can_shell_dump_ctx.filter_id_std); + } + + + if (can_shell_dump_ctx.filter_id_ext >= 0) { + can_remove_rx_filter(dev, can_shell_dump_ctx.filter_id_ext); + } + + shell_set_bypass(sh, NULL, NULL); + return; + } + } +} + +static int cmd_can_dump(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev = shell_device_get_binding(argv[1]); + const struct can_filter std_filter = { + .flags = 0U, + .id = 0U, + .mask = 0U + }; + const struct can_filter ext_filter = { + .flags = CAN_FILTER_IDE, + .id = 0U, + .mask = 0U + }; + int err; + + if (!can_device_check(dev)) { + shell_error(sh, "device %s not ready", argv[1]); + return -ENODEV; + } + + err = can_add_rx_filter(dev, can_shell_rx_callback, NULL, &std_filter); + if (err < 0) { + shell_warn(sh, "failed to add standard (11-bit) filter (err %d)", err); + } + can_shell_dump_ctx.filter_id_std = err; + + err = can_add_rx_filter(dev, can_shell_rx_callback, NULL, &ext_filter); + if (err < 0) { + shell_warn(sh, "failed to add extended (29-bit) filter (err %d)", err); + } + can_shell_dump_ctx.filter_id_ext = err; + + err = can_shell_rx_msgq_poll_submit(sh); + if (err != 0) { + shell_error(sh, "failed to start CAN RX message queue polling (err %d)", err); + return err; + } + + can_shell_dump_ctx.started = true; + + err = can_start(dev); + if (err == -EALREADY) { + can_shell_dump_ctx.started = false; + } else if (err != 0) { + shell_error(sh, "failed to start CAN controller (err %d)", err); + return err; + } + + shell_set_bypass(sh, can_shell_dump_bypass_cb, (void *)dev); + + shell_print(sh, "dumping CAN RX frames on device %s, press Ctrl+C to exit", dev->name); + + return 0; +} + static int cmd_can_bitrate_set(const struct shell *sh, size_t argc, char **argv) { const struct device *dev = shell_device_get_binding(argv[1]); @@ -1108,6 +1204,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_can_cmds, "Manually recover CAN controller from bus-off state\n" "Usage: can recover [timeout ms]", cmd_can_recover, 2, 1), + SHELL_CMD_ARG(dump, &dsub_can_device_name, + "Dump all CAN controller RX frames\n" + "Usage: can dump ", + cmd_can_dump, 2, 0), SHELL_SUBCMD_SET_END );