samples: driver: Extend CAN sample

This commit adds sample code for bus state checking.
Printing the counter state is moved to own thread because the
ISR was blocking too long (messages were lost)

Signed-off-by: Alexander Wachter <alexander.wachter@student.tugraz.at>
This commit is contained in:
Alexander Wachter 2018-07-03 15:13:07 +02:00 committed by Jukka Rissanen
commit 1b88658f9f

View file

@ -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) {