Skip to content

Commit

Permalink
Merge branch 'release/v17.6.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
valeros committed Sep 26, 2024
2 parents e4c0f8b + e437655 commit e2078e6
Show file tree
Hide file tree
Showing 10 changed files with 434 additions and 509 deletions.
342 changes: 86 additions & 256 deletions examples/zephyr-drivers-can/src/main.c
Original file line number Diff line number Diff line change
@@ -1,309 +1,139 @@
/*
* Copyright (c) 2018 Alexander Wachter
* Copyright (c) 2021-2022 Henrik Brix Andersen <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdio.h>

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/can.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/byteorder.h>

#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
#define RESET_LED 0
#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);

const struct device *const can_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus));
struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, {0});

struct k_thread rx_thread_data;
struct k_thread poll_state_thread_data;
struct k_work_poll change_led_work;
struct k_work state_change_work;
enum can_state current_state;
struct can_bus_err_cnt current_err_cnt;
#include <zephyr/kernel.h>

CAN_MSGQ_DEFINE(change_led_msgq, 2);
CAN_MSGQ_DEFINE(counter_msgq, 2);
/* Devicetree */
#define CANBUS_NODE DT_CHOSEN(zephyr_canbus)
#define BUTTON_NODE DT_ALIAS(sw0)
#define BUTTON_NAME DT_PROP_OR(BUTTON_NODE, label, "sw0")

static struct k_poll_event change_led_events[1] = {
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_MSGQ_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&change_led_msgq, 0)
#if DT_NODE_EXISTS(BUTTON_NODE)
struct button_callback_context {
struct gpio_callback callback;
struct k_sem sem;
};

void tx_irq_callback(const struct device *dev, int error, void *arg)
static void button_callback(const struct device *port, struct gpio_callback *cb,
gpio_port_pins_t pins)
{
char *sender = (char *)arg;

ARG_UNUSED(dev);
struct button_callback_context *ctx =
CONTAINER_OF(cb, struct button_callback_context, callback);

if (error != 0) {
printf("Callback! error-code: %d\nSender: %s\n",
error, sender);
}
k_sem_give(&ctx->sem);
}
#endif /* DT_NODE_EXISTS(BUTTON_NODE) */

void rx_thread(void *arg1, void *arg2, void *arg3)
static void can_tx_callback(const struct device *dev, int error, void *user_data)
{
ARG_UNUSED(arg1);
ARG_UNUSED(arg2);
ARG_UNUSED(arg3);
const struct can_filter filter = {
.flags = CAN_FILTER_IDE,
.id = COUNTER_MSG_ID,
.mask = CAN_EXT_ID_MASK
};
struct can_frame frame;
int filter_id;

filter_id = can_add_rx_filter_msgq(can_dev, &counter_msgq, &filter);
printf("Counter filter id: %d\n", filter_id);

while (1) {
k_msgq_get(&counter_msgq, &frame, K_FOREVER);

if (IS_ENABLED(CONFIG_CAN_ACCEPT_RTR) && (frame.flags & CAN_FRAME_RTR) != 0U) {
continue;
}

if (frame.dlc != 2U) {
printf("Wrong data length: %u\n", frame.dlc);
continue;
}
struct k_sem *tx_queue_sem = user_data;

printf("Counter received: %u\n",
sys_be16_to_cpu(UNALIGNED_GET((uint16_t *)&frame.data)));
}
k_sem_give(tx_queue_sem);
}

void change_led_work_handler(struct k_work *work)
int main(void)
{
struct can_frame frame;
int ret;

while (k_msgq_get(&change_led_msgq, &frame, K_NO_WAIT) == 0) {
if (IS_ENABLED(CONFIG_CAN_ACCEPT_RTR) && (frame.flags & CAN_FRAME_RTR) != 0U) {
continue;
}
#if DT_NODE_EXISTS(BUTTON_NODE)
const struct gpio_dt_spec btn = GPIO_DT_SPEC_GET(BUTTON_NODE, gpios);
struct button_callback_context btn_cb_ctx;
#endif /* DT_NODE_EXISTS(BUTTON_NODE) */
const struct device *dev = DEVICE_DT_GET(CANBUS_NODE);
struct k_sem tx_queue_sem;
struct can_frame frame = {0};
int err;

if (led.port == NULL) {
printf("LED %s\n", frame.data[0] == SET_LED ? "ON" : "OFF");
} else {
gpio_pin_set(led.port, led.pin, frame.data[0] == SET_LED ? 1 : 0);
}
}
k_sem_init(&tx_queue_sem, CONFIG_SAMPLE_CAN_BABBLING_TX_QUEUE_SIZE,
CONFIG_SAMPLE_CAN_BABBLING_TX_QUEUE_SIZE);

ret = k_work_poll_submit(&change_led_work, change_led_events,
ARRAY_SIZE(change_led_events), K_FOREVER);
if (ret != 0) {
printf("Failed to resubmit msgq polling: %d", ret);
}
}

char *state_to_str(enum can_state state)
{
switch (state) {
case CAN_STATE_ERROR_ACTIVE:
return "error-active";
case CAN_STATE_ERROR_WARNING:
return "error-warning";
case CAN_STATE_ERROR_PASSIVE:
return "error-passive";
case CAN_STATE_BUS_OFF:
return "bus-off";
case CAN_STATE_STOPPED:
return "stopped";
default:
return "unknown";
if (!device_is_ready(dev)) {
printk("CAN device not ready");
return 0;
}
}

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_STATE_ERROR_ACTIVE;
enum can_state state;
int err;

while (1) {
err = can_get_state(can_dev, &state, &err_cnt);
if (IS_ENABLED(CONFIG_SAMPLE_CAN_BABBLING_FD_MODE)) {
err = can_set_mode(dev, CAN_MODE_FD);
if (err != 0) {
printf("Failed to get CAN controller state: %d", err);
k_sleep(K_MSEC(100));
continue;
}

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;
printf("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));
printk("Error setting CAN FD mode (err %d)", err);
return 0;
}
}
}

void state_change_work_handler(struct k_work *work)
{
printf("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_BUS_OFF_RECOVERY
if (current_state == CAN_STATE_BUS_OFF) {
printf("Recover from bus-off\n");

if (can_recover(can_dev, K_MSEC(100)) != 0) {
printf("Recovery timed out\n");
}
err = can_start(dev);
if (err != 0) {
printk("Error starting CAN controller (err %d)", err);
return 0;
}
#endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */
}

void state_change_callback(const struct device *dev, enum can_state state,
struct can_bus_err_cnt err_cnt, void *user_data)
{
struct k_work *work = (struct k_work *)user_data;

ARG_UNUSED(dev);

current_state = state;
current_err_cnt = err_cnt;
k_work_submit(work);
}
#if DT_NODE_EXISTS(BUTTON_NODE)
k_sem_init(&btn_cb_ctx.sem, 0, 1);

int main(void)
{
const struct can_filter change_led_filter = {
.flags = 0U,
.id = LED_MSG_ID,
.mask = CAN_STD_ID_MASK
};
struct can_frame change_led_frame = {
.flags = 0,
.id = LED_MSG_ID,
.dlc = 1
};
struct can_frame counter_frame = {
.flags = CAN_FRAME_IDE,
.id = COUNTER_MSG_ID,
.dlc = 2
};
uint8_t toggle = 1;
uint16_t counter = 0;
k_tid_t rx_tid, get_state_tid;
int ret;

if (!device_is_ready(can_dev)) {
printf("CAN: Device %s not ready.\n", can_dev->name);
if (!gpio_is_ready_dt(&btn)) {
printk("button device not ready\n");
return 0;
}

#ifdef CONFIG_LOOPBACK_MODE
ret = can_set_mode(can_dev, CAN_MODE_LOOPBACK);
if (ret != 0) {
printf("Error setting CAN mode [%d]", ret);
return 0;
}
#endif
ret = can_start(can_dev);
if (ret != 0) {
printf("Error starting CAN controller [%d]", ret);
err = gpio_pin_configure_dt(&btn, GPIO_INPUT);
if (err != 0) {
printk("failed to configure button GPIO (err %d)\n", err);
return 0;
}

if (led.port != NULL) {
if (!gpio_is_ready_dt(&led)) {
printf("LED: Device %s not ready.\n",
led.port->name);
return 0;
}
ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_HIGH);
if (ret < 0) {
printf("Error setting LED pin to output mode [%d]",
ret);
led.port = NULL;
}
}

k_work_init(&state_change_work, state_change_work_handler);
k_work_poll_init(&change_led_work, change_led_work_handler);

ret = can_add_rx_filter_msgq(can_dev, &change_led_msgq, &change_led_filter);
if (ret == -ENOSPC) {
printf("Error, no filter available!\n");
err = gpio_pin_interrupt_configure_dt(&btn, GPIO_INT_EDGE_TO_ACTIVE);
if (err != 0) {
printk("failed to configure button interrupt (err %d)\n", err);
return 0;
}

printf("Change LED filter ID: %d\n", ret);
gpio_init_callback(&btn_cb_ctx.callback, button_callback, BIT(btn.pin));
gpio_add_callback(btn.port, &btn_cb_ctx.callback);
#endif /* DT_NODE_EXISTS(BUTTON_NODE) */

ret = k_work_poll_submit(&change_led_work, change_led_events,
ARRAY_SIZE(change_led_events), K_FOREVER);
if (ret != 0) {
printf("Failed to submit msgq polling: %d", ret);
return 0;
if (IS_ENABLED(CONFIG_SAMPLE_CAN_BABBLING_EXT_ID)) {
frame.flags |= CAN_FRAME_IDE;
}

rx_tid = k_thread_create(&rx_thread_data, rx_thread_stack,
K_THREAD_STACK_SIZEOF(rx_thread_stack),
rx_thread, NULL, NULL, NULL,
RX_THREAD_PRIORITY, 0, K_NO_WAIT);
if (!rx_tid) {
printf("ERROR spawning rx thread\n");
if (IS_ENABLED(CONFIG_SAMPLE_CAN_BABBLING_RTR)) {
frame.flags |= CAN_FRAME_RTR;
}

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) {
printf("ERROR spawning poll_state_thread\n");
if (IS_ENABLED(CONFIG_SAMPLE_CAN_BABBLING_FD_MODE)) {
frame.flags |= CAN_FRAME_FDF;
}

can_set_state_change_callback(can_dev, state_change_callback, &state_change_work);
frame.id = CONFIG_SAMPLE_CAN_BABBLING_CAN_ID;

printf("Finished init.\n");
printk("babbling on %s with %s (%d-bit) CAN ID 0x%0*x, RTR %d, CAN FD %d\n",
dev->name,
(frame.flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard",
(frame.flags & CAN_FRAME_IDE) != 0 ? 29 : 11,
(frame.flags & CAN_FRAME_IDE) != 0 ? 8 : 3, frame.id,
(frame.flags & CAN_FRAME_RTR) != 0 ? 1 : 0,
(frame.flags & CAN_FRAME_FDF) != 0 ? 1 : 0);

while (1) {
change_led_frame.data[0] = toggle++ & 0x01 ? SET_LED : RESET_LED;
/* This sending call is none blocking. */
can_send(can_dev, &change_led_frame, K_FOREVER,
tx_irq_callback,
"LED change");
k_sleep(SLEEP_TIME);
#if DT_NODE_EXISTS(BUTTON_NODE)
printk("abort by pressing %s button\n", BUTTON_NAME);
#endif /* DT_NODE_EXISTS(BUTTON_NODE) */

UNALIGNED_PUT(sys_cpu_to_be16(counter),
(uint16_t *)&counter_frame.data[0]);
counter++;
/* This sending call is blocking until the message is sent. */
can_send(can_dev, &counter_frame, K_MSEC(100), NULL, NULL);
k_sleep(SLEEP_TIME);
while (true) {
if (k_sem_take(&tx_queue_sem, K_MSEC(100)) == 0) {
err = can_send(dev, &frame, K_NO_WAIT, can_tx_callback, &tx_queue_sem);
if (err != 0) {
printk("failed to enqueue CAN frame (err %d)\n", err);
}
}

#if DT_NODE_EXISTS(BUTTON_NODE)
if (k_sem_take(&btn_cb_ctx.sem, K_NO_WAIT) == 0) {
printk("button press detected, babbling stopped\n");
return 0;
}
#endif /* DT_NODE_EXISTS(BUTTON_NODE) */
}
}
Loading

0 comments on commit e2078e6

Please sign in to comment.