1 /*
2 * Copyright (c) 2018 Alexander Wachter
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdio.h>
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/sys/printk.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/can.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/sys/byteorder.h>
15
16 #define RX_THREAD_STACK_SIZE 512
17 #define RX_THREAD_PRIORITY 2
18 #define STATE_POLL_THREAD_STACK_SIZE 512
19 #define STATE_POLL_THREAD_PRIORITY 2
20 #define LED_MSG_ID 0x10
21 #define COUNTER_MSG_ID 0x12345
22 #define SET_LED 1
23 #define RESET_LED 0
24 #define SLEEP_TIME K_MSEC(250)
25
26 K_THREAD_STACK_DEFINE(rx_thread_stack, RX_THREAD_STACK_SIZE);
27 K_THREAD_STACK_DEFINE(poll_state_stack, STATE_POLL_THREAD_STACK_SIZE);
28
29 const struct device *const can_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus));
30 struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, {0});
31
32 struct k_thread rx_thread_data;
33 struct k_thread poll_state_thread_data;
34 struct k_work_poll change_led_work;
35 struct k_work state_change_work;
36 enum can_state current_state;
37 struct can_bus_err_cnt current_err_cnt;
38
39 CAN_MSGQ_DEFINE(change_led_msgq, 2);
40 CAN_MSGQ_DEFINE(counter_msgq, 2);
41
42 static struct k_poll_event change_led_events[1] = {
43 K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_MSGQ_DATA_AVAILABLE,
44 K_POLL_MODE_NOTIFY_ONLY,
45 &change_led_msgq, 0)
46 };
47
tx_irq_callback(const struct device * dev,int error,void * arg)48 void tx_irq_callback(const struct device *dev, int error, void *arg)
49 {
50 char *sender = (char *)arg;
51
52 ARG_UNUSED(dev);
53
54 if (error != 0) {
55 printf("Callback! error-code: %d\nSender: %s\n",
56 error, sender);
57 }
58 }
59
rx_thread(void * arg1,void * arg2,void * arg3)60 void rx_thread(void *arg1, void *arg2, void *arg3)
61 {
62 ARG_UNUSED(arg1);
63 ARG_UNUSED(arg2);
64 ARG_UNUSED(arg3);
65 const struct can_filter filter = {
66 .flags = CAN_FILTER_IDE,
67 .id = COUNTER_MSG_ID,
68 .mask = CAN_EXT_ID_MASK
69 };
70 struct can_frame frame;
71 int filter_id;
72
73 filter_id = can_add_rx_filter_msgq(can_dev, &counter_msgq, &filter);
74 printf("Counter filter id: %d\n", filter_id);
75
76 while (1) {
77 k_msgq_get(&counter_msgq, &frame, K_FOREVER);
78
79 if (IS_ENABLED(CONFIG_CAN_ACCEPT_RTR) && (frame.flags & CAN_FRAME_RTR) != 0U) {
80 continue;
81 }
82
83 if (frame.dlc != 2U) {
84 printf("Wrong data length: %u\n", frame.dlc);
85 continue;
86 }
87
88 printf("Counter received: %u\n",
89 sys_be16_to_cpu(UNALIGNED_GET((uint16_t *)&frame.data)));
90 }
91 }
92
change_led_work_handler(struct k_work * work)93 void change_led_work_handler(struct k_work *work)
94 {
95 struct can_frame frame;
96 int ret;
97
98 while (k_msgq_get(&change_led_msgq, &frame, K_NO_WAIT) == 0) {
99 if (IS_ENABLED(CONFIG_CAN_ACCEPT_RTR) && (frame.flags & CAN_FRAME_RTR) != 0U) {
100 continue;
101 }
102
103 if (led.port == NULL) {
104 printf("LED %s\n", frame.data[0] == SET_LED ? "ON" : "OFF");
105 } else {
106 gpio_pin_set(led.port, led.pin, frame.data[0] == SET_LED ? 1 : 0);
107 }
108 }
109
110 ret = k_work_poll_submit(&change_led_work, change_led_events,
111 ARRAY_SIZE(change_led_events), K_FOREVER);
112 if (ret != 0) {
113 printf("Failed to resubmit msgq polling: %d", ret);
114 }
115 }
116
state_to_str(enum can_state state)117 char *state_to_str(enum can_state state)
118 {
119 switch (state) {
120 case CAN_STATE_ERROR_ACTIVE:
121 return "error-active";
122 case CAN_STATE_ERROR_WARNING:
123 return "error-warning";
124 case CAN_STATE_ERROR_PASSIVE:
125 return "error-passive";
126 case CAN_STATE_BUS_OFF:
127 return "bus-off";
128 case CAN_STATE_STOPPED:
129 return "stopped";
130 default:
131 return "unknown";
132 }
133 }
134
poll_state_thread(void * unused1,void * unused2,void * unused3)135 void poll_state_thread(void *unused1, void *unused2, void *unused3)
136 {
137 struct can_bus_err_cnt err_cnt = {0, 0};
138 struct can_bus_err_cnt err_cnt_prev = {0, 0};
139 enum can_state state_prev = CAN_STATE_ERROR_ACTIVE;
140 enum can_state state;
141 int err;
142
143 while (1) {
144 err = can_get_state(can_dev, &state, &err_cnt);
145 if (err != 0) {
146 printf("Failed to get CAN controller state: %d", err);
147 k_sleep(K_MSEC(100));
148 continue;
149 }
150
151 if (err_cnt.tx_err_cnt != err_cnt_prev.tx_err_cnt ||
152 err_cnt.rx_err_cnt != err_cnt_prev.rx_err_cnt ||
153 state_prev != state) {
154
155 err_cnt_prev.tx_err_cnt = err_cnt.tx_err_cnt;
156 err_cnt_prev.rx_err_cnt = err_cnt.rx_err_cnt;
157 state_prev = state;
158 printf("state: %s\n"
159 "rx error count: %d\n"
160 "tx error count: %d\n",
161 state_to_str(state),
162 err_cnt.rx_err_cnt, err_cnt.tx_err_cnt);
163 } else {
164 k_sleep(K_MSEC(100));
165 }
166 }
167 }
168
state_change_work_handler(struct k_work * work)169 void state_change_work_handler(struct k_work *work)
170 {
171 printf("State Change ISR\nstate: %s\n"
172 "rx error count: %d\n"
173 "tx error count: %d\n",
174 state_to_str(current_state),
175 current_err_cnt.rx_err_cnt, current_err_cnt.tx_err_cnt);
176 }
177
state_change_callback(const struct device * dev,enum can_state state,struct can_bus_err_cnt err_cnt,void * user_data)178 void state_change_callback(const struct device *dev, enum can_state state,
179 struct can_bus_err_cnt err_cnt, void *user_data)
180 {
181 struct k_work *work = (struct k_work *)user_data;
182
183 ARG_UNUSED(dev);
184
185 current_state = state;
186 current_err_cnt = err_cnt;
187 k_work_submit(work);
188 }
189
main(void)190 int main(void)
191 {
192 const struct can_filter change_led_filter = {
193 .flags = 0U,
194 .id = LED_MSG_ID,
195 .mask = CAN_STD_ID_MASK
196 };
197 struct can_frame change_led_frame = {
198 .flags = 0,
199 .id = LED_MSG_ID,
200 .dlc = 1
201 };
202 struct can_frame counter_frame = {
203 .flags = CAN_FRAME_IDE,
204 .id = COUNTER_MSG_ID,
205 .dlc = 2
206 };
207 uint8_t toggle = 1;
208 uint16_t counter = 0;
209 k_tid_t rx_tid, get_state_tid;
210 int ret;
211
212 if (!device_is_ready(can_dev)) {
213 printf("CAN: Device %s not ready.\n", can_dev->name);
214 return 0;
215 }
216
217 #ifdef CONFIG_LOOPBACK_MODE
218 ret = can_set_mode(can_dev, CAN_MODE_LOOPBACK);
219 if (ret != 0) {
220 printf("Error setting CAN mode [%d]", ret);
221 return 0;
222 }
223 #endif
224 ret = can_start(can_dev);
225 if (ret != 0) {
226 printf("Error starting CAN controller [%d]", ret);
227 return 0;
228 }
229
230 if (led.port != NULL) {
231 if (!gpio_is_ready_dt(&led)) {
232 printf("LED: Device %s not ready.\n",
233 led.port->name);
234 return 0;
235 }
236 ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_HIGH);
237 if (ret < 0) {
238 printf("Error setting LED pin to output mode [%d]",
239 ret);
240 led.port = NULL;
241 }
242 }
243
244 k_work_init(&state_change_work, state_change_work_handler);
245 k_work_poll_init(&change_led_work, change_led_work_handler);
246
247 ret = can_add_rx_filter_msgq(can_dev, &change_led_msgq, &change_led_filter);
248 if (ret == -ENOSPC) {
249 printf("Error, no filter available!\n");
250 return 0;
251 }
252
253 printf("Change LED filter ID: %d\n", ret);
254
255 ret = k_work_poll_submit(&change_led_work, change_led_events,
256 ARRAY_SIZE(change_led_events), K_FOREVER);
257 if (ret != 0) {
258 printf("Failed to submit msgq polling: %d", ret);
259 return 0;
260 }
261
262 rx_tid = k_thread_create(&rx_thread_data, rx_thread_stack,
263 K_THREAD_STACK_SIZEOF(rx_thread_stack),
264 rx_thread, NULL, NULL, NULL,
265 RX_THREAD_PRIORITY, 0, K_NO_WAIT);
266 if (!rx_tid) {
267 printf("ERROR spawning rx thread\n");
268 }
269
270 get_state_tid = k_thread_create(&poll_state_thread_data,
271 poll_state_stack,
272 K_THREAD_STACK_SIZEOF(poll_state_stack),
273 poll_state_thread, NULL, NULL, NULL,
274 STATE_POLL_THREAD_PRIORITY, 0,
275 K_NO_WAIT);
276 if (!get_state_tid) {
277 printf("ERROR spawning poll_state_thread\n");
278 }
279
280 can_set_state_change_callback(can_dev, state_change_callback, &state_change_work);
281
282 printf("Finished init.\n");
283
284 while (1) {
285 change_led_frame.data[0] = toggle++ & 0x01 ? SET_LED : RESET_LED;
286 /* This sending call is none blocking. */
287 can_send(can_dev, &change_led_frame, K_FOREVER,
288 tx_irq_callback,
289 "LED change");
290 k_sleep(SLEEP_TIME);
291
292 UNALIGNED_PUT(sys_cpu_to_be16(counter),
293 (uint16_t *)&counter_frame.data[0]);
294 counter++;
295 /* This sending call is blocking until the message is sent. */
296 can_send(can_dev, &counter_frame, K_MSEC(100), NULL, NULL);
297 k_sleep(SLEEP_TIME);
298 }
299 }
300