1 /*
2 * Copyright (c) 2021-2022 Henrik Brix Andersen <henrik@brixandersen.dk>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/device.h>
8 #include <zephyr/devicetree.h>
9 #include <zephyr/drivers/can.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/kernel.h>
12
13 /* Devicetree */
14 #define CANBUS_NODE DT_CHOSEN(zephyr_canbus)
15 #define BUTTON_NODE DT_ALIAS(sw0)
16 #define BUTTON_NAME DT_PROP_OR(BUTTON_NODE, label, "sw0")
17
18 #if DT_NODE_EXISTS(BUTTON_NODE)
19 struct button_callback_context {
20 struct gpio_callback callback;
21 struct k_sem sem;
22 };
23
button_callback(const struct device * port,struct gpio_callback * cb,gpio_port_pins_t pins)24 static void button_callback(const struct device *port, struct gpio_callback *cb,
25 gpio_port_pins_t pins)
26 {
27 struct button_callback_context *ctx =
28 CONTAINER_OF(cb, struct button_callback_context, callback);
29
30 k_sem_give(&ctx->sem);
31 }
32 #endif /* DT_NODE_EXISTS(BUTTON_NODE) */
33
can_tx_callback(const struct device * dev,int error,void * user_data)34 static void can_tx_callback(const struct device *dev, int error, void *user_data)
35 {
36 struct k_sem *tx_queue_sem = user_data;
37
38 k_sem_give(tx_queue_sem);
39 }
40
main(void)41 int main(void)
42 {
43 #if DT_NODE_EXISTS(BUTTON_NODE)
44 const struct gpio_dt_spec btn = GPIO_DT_SPEC_GET(BUTTON_NODE, gpios);
45 struct button_callback_context btn_cb_ctx;
46 #endif /* DT_NODE_EXISTS(BUTTON_NODE) */
47 const struct device *dev = DEVICE_DT_GET(CANBUS_NODE);
48 struct k_sem tx_queue_sem;
49 struct can_frame frame = {0};
50 int err;
51
52 k_sem_init(&tx_queue_sem, CONFIG_SAMPLE_CAN_BABBLING_TX_QUEUE_SIZE,
53 CONFIG_SAMPLE_CAN_BABBLING_TX_QUEUE_SIZE);
54
55 if (!device_is_ready(dev)) {
56 printk("CAN device not ready");
57 return 0;
58 }
59
60 if (IS_ENABLED(CONFIG_SAMPLE_CAN_BABBLING_FD_MODE)) {
61 err = can_set_mode(dev, CAN_MODE_FD);
62 if (err != 0) {
63 printk("Error setting CAN FD mode (err %d)", err);
64 return 0;
65 }
66 }
67
68 err = can_start(dev);
69 if (err != 0) {
70 printk("Error starting CAN controller (err %d)", err);
71 return 0;
72 }
73
74 #if DT_NODE_EXISTS(BUTTON_NODE)
75 k_sem_init(&btn_cb_ctx.sem, 0, 1);
76
77 if (!gpio_is_ready_dt(&btn)) {
78 printk("button device not ready\n");
79 return 0;
80 }
81
82 err = gpio_pin_configure_dt(&btn, GPIO_INPUT);
83 if (err != 0) {
84 printk("failed to configure button GPIO (err %d)\n", err);
85 return 0;
86 }
87
88 err = gpio_pin_interrupt_configure_dt(&btn, GPIO_INT_EDGE_TO_ACTIVE);
89 if (err != 0) {
90 printk("failed to configure button interrupt (err %d)\n", err);
91 return 0;
92 }
93
94 gpio_init_callback(&btn_cb_ctx.callback, button_callback, BIT(btn.pin));
95 gpio_add_callback(btn.port, &btn_cb_ctx.callback);
96 #endif /* DT_NODE_EXISTS(BUTTON_NODE) */
97
98 if (IS_ENABLED(CONFIG_SAMPLE_CAN_BABBLING_EXT_ID)) {
99 frame.flags |= CAN_FRAME_IDE;
100 }
101
102 if (IS_ENABLED(CONFIG_SAMPLE_CAN_BABBLING_RTR)) {
103 frame.flags |= CAN_FRAME_RTR;
104 }
105
106 if (IS_ENABLED(CONFIG_SAMPLE_CAN_BABBLING_FD_MODE)) {
107 frame.flags |= CAN_FRAME_FDF;
108 }
109
110 frame.id = CONFIG_SAMPLE_CAN_BABBLING_CAN_ID;
111
112 printk("babbling on %s with %s (%d-bit) CAN ID 0x%0*x, RTR %d, CAN FD %d\n",
113 dev->name,
114 (frame.flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard",
115 (frame.flags & CAN_FRAME_IDE) != 0 ? 29 : 11,
116 (frame.flags & CAN_FRAME_IDE) != 0 ? 8 : 3, frame.id,
117 (frame.flags & CAN_FRAME_RTR) != 0 ? 1 : 0,
118 (frame.flags & CAN_FRAME_FDF) != 0 ? 1 : 0);
119
120 #if DT_NODE_EXISTS(BUTTON_NODE)
121 printk("abort by pressing %s button\n", BUTTON_NAME);
122 #endif /* DT_NODE_EXISTS(BUTTON_NODE) */
123
124 while (true) {
125 if (k_sem_take(&tx_queue_sem, K_MSEC(100)) == 0) {
126 err = can_send(dev, &frame, K_NO_WAIT, can_tx_callback, &tx_queue_sem);
127 if (err != 0) {
128 printk("failed to enqueue CAN frame (err %d)\n", err);
129 }
130 }
131
132 #if DT_NODE_EXISTS(BUTTON_NODE)
133 if (k_sem_take(&btn_cb_ctx.sem, K_NO_WAIT) == 0) {
134 printk("button press detected, babbling stopped\n");
135 return 0;
136 }
137 #endif /* DT_NODE_EXISTS(BUTTON_NODE) */
138 }
139 }
140