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