diff --git a/samples/drivers/CAN/src/main.c b/samples/drivers/CAN/src/main.c index 0aa3caae42b..b315c1bd137 100644 --- a/samples/drivers/CAN/src/main.c +++ b/samples/drivers/CAN/src/main.c @@ -14,6 +14,8 @@ #define RX_THREAD_STACK_SIZE 512 #define RX_THREAD_PRIORITY 2 +#define STATE_POLL_THREAD_STACK_SIZE 512 +#define STATE_POLL_THREAD_PRIORITY 2 #define LED_MSG_ID 0x10 #define COUNTER_MSG_ID 0x12345 #define SET_LED 1 @@ -21,9 +23,16 @@ #define SLEEP_TIME K_MSEC(250) K_THREAD_STACK_DEFINE(rx_thread_stack, RX_THREAD_STACK_SIZE); +K_THREAD_STACK_DEFINE(poll_state_stack, STATE_POLL_THREAD_STACK_SIZE); + +struct device *can_dev; struct k_thread rx_thread_data; +struct k_thread poll_state_thread_data; struct zcan_work rx_work; +struct k_work state_change_work; +enum can_state current_state; +struct can_bus_err_cnt current_err_cnt; CAN_DEFINE_MSGQ(counter_msgq, 2); @@ -37,10 +46,11 @@ void tx_irq_callback(u32_t error_flags, void *arg) } } -void rx_thread(void *can_dev_param, void *arg1, void *arg2) +void rx_thread(void *arg1, void *arg2, void *arg3) { ARG_UNUSED(arg1); ARG_UNUSED(arg2); + ARG_UNUSED(arg3); const struct zcan_filter filter = { .id_type = CAN_EXTENDED_IDENTIFIER, .rtr = CAN_DATAFRAME, @@ -48,7 +58,6 @@ void rx_thread(void *can_dev_param, void *arg1, void *arg2) .rtr_mask = 1, .ext_id_mask = CAN_EXT_ID_MASK }; - struct device *can_dev = can_dev_param; struct zcan_frame msg; int filter_id; @@ -92,6 +101,73 @@ void change_led(struct zcan_frame *msg, void *led_dev_param) #endif } +char *state_to_str(enum can_state state) +{ + switch (state) { + case CAN_ERROR_ACTIVE: + return "error-active"; + case CAN_ERROR_PASSIVE: + return "error-passive"; + case CAN_BUS_OFF: + return "bus-off"; + default: + return "unknown"; + } +} + +void poll_state_thread(void *unused1, void *unused2, void *unused3) +{ + struct can_bus_err_cnt err_cnt = {0, 0}; + struct can_bus_err_cnt err_cnt_prev = {0, 0}; + enum can_state state_prev = CAN_ERROR_ACTIVE; + enum can_state state; + + while (1) { + state = can_get_state(can_dev, &err_cnt); + if (err_cnt.tx_err_cnt != err_cnt_prev.tx_err_cnt || + err_cnt.rx_err_cnt != err_cnt_prev.rx_err_cnt || + state_prev != state) { + + err_cnt_prev.tx_err_cnt = err_cnt.tx_err_cnt; + err_cnt_prev.rx_err_cnt = err_cnt.rx_err_cnt; + state_prev = state; + printk("state: %s\n" + "rx error count: %d\n" + "tx error count: %d\n", + state_to_str(state), + err_cnt.rx_err_cnt, err_cnt.tx_err_cnt); + } else { + k_sleep(K_MSEC(100)); + } + } +} + +void state_change_work_handler(struct k_work *work) +{ + printk("State Change ISR\nstate: %s\n" + "rx error count: %d\n" + "tx error count: %d\n", + state_to_str(current_state), + current_err_cnt.rx_err_cnt, current_err_cnt.tx_err_cnt); + +#ifndef CONFIG_CAN_AUTO_BOFF_RECOVERY + if (current_state == CAN_BUS_OFF) { + printk("Recover from bus-off\n"); + + if (can_recover(can_dev, K_MSEC(100) != 0)) { + printk("Recovery timed out\n"); + } + } +#endif /* CONFIG_CAN_AUTO_BOFF_RECOVERY */ +} + +void state_change_isr(enum can_state state, struct can_bus_err_cnt err_cnt) +{ + current_state = state; + current_err_cnt = err_cnt; + k_work_submit(&state_change_work); +} + void main(void) { const struct zcan_filter change_led_filter = { @@ -116,8 +192,7 @@ void main(void) u8_t toggle = 1; u16_t counter = 0; struct device *led_gpio_dev = NULL; - struct device *can_dev; - k_tid_t rx_tid; + k_tid_t rx_tid, get_state_tid; int ret; /* Usually the CAN device is either called CAN_0 or CAN_1, depending @@ -151,6 +226,8 @@ void main(void) } #endif + k_work_init(&state_change_work, state_change_work_handler); + ret = can_attach_workq(can_dev, &k_sys_work_q, &rx_work, change_led, led_gpio_dev, &change_led_filter); if (ret == CAN_NO_FREE_FILTER) { @@ -162,12 +239,25 @@ void main(void) rx_tid = k_thread_create(&rx_thread_data, rx_thread_stack, K_THREAD_STACK_SIZEOF(rx_thread_stack), - rx_thread, can_dev, NULL, NULL, + rx_thread, NULL, NULL, NULL, RX_THREAD_PRIORITY, 0, K_NO_WAIT); if (!rx_tid) { printk("ERROR spawning rx thread\n"); } + + get_state_tid = k_thread_create(&poll_state_thread_data, + poll_state_stack, + K_THREAD_STACK_SIZEOF(poll_state_stack), + poll_state_thread, NULL, NULL, NULL, + STATE_POLL_THREAD_PRIORITY, 0, + K_NO_WAIT); + if (!get_state_tid) { + printk("ERROR spawning poll_state_thread\n"); + } + + can_register_state_change_isr(can_dev, state_change_isr); + printk("Finished init.\n"); while (1) {