1 /*
2  * Copyright (c) 2019 Vestas Wind Systems A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/drivers/can.h>
9 #include <zephyr/init.h>
10 #include <zephyr/sys/util.h>
11 
12 #include <canopennode.h>
13 
14 #define LOG_LEVEL CONFIG_CANOPEN_LOG_LEVEL
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(canopen_driver);
17 
18 K_KERNEL_STACK_DEFINE(canopen_tx_workq_stack,
19 		      CONFIG_CANOPENNODE_TX_WORKQUEUE_STACK_SIZE);
20 
21 struct k_work_q canopen_tx_workq;
22 
23 struct canopen_tx_work_container {
24 	struct k_work work;
25 	CO_CANmodule_t *CANmodule;
26 };
27 
28 struct canopen_tx_work_container canopen_tx_queue;
29 
30 K_MUTEX_DEFINE(canopen_send_mutex);
31 K_MUTEX_DEFINE(canopen_emcy_mutex);
32 K_MUTEX_DEFINE(canopen_co_mutex);
33 
34 static canopen_rxmsg_callback_t rxmsg_callback;
35 
canopen_send_lock(void)36 inline void canopen_send_lock(void)
37 {
38 	k_mutex_lock(&canopen_send_mutex, K_FOREVER);
39 }
40 
canopen_send_unlock(void)41 inline void canopen_send_unlock(void)
42 {
43 	k_mutex_unlock(&canopen_send_mutex);
44 }
45 
canopen_emcy_lock(void)46 inline void canopen_emcy_lock(void)
47 {
48 	k_mutex_lock(&canopen_emcy_mutex, K_FOREVER);
49 }
50 
canopen_emcy_unlock(void)51 inline void canopen_emcy_unlock(void)
52 {
53 	k_mutex_unlock(&canopen_emcy_mutex);
54 }
55 
canopen_od_lock(void)56 inline void canopen_od_lock(void)
57 {
58 	k_mutex_lock(&canopen_co_mutex, K_FOREVER);
59 }
60 
canopen_od_unlock(void)61 inline void canopen_od_unlock(void)
62 {
63 	k_mutex_unlock(&canopen_co_mutex);
64 }
65 
canopen_set_rxmsg_callback(canopen_rxmsg_callback_t callback)66 void canopen_set_rxmsg_callback(canopen_rxmsg_callback_t callback)
67 {
68 	rxmsg_callback = callback;
69 }
70 
canopen_detach_all_rx_filters(CO_CANmodule_t * CANmodule)71 static void canopen_detach_all_rx_filters(CO_CANmodule_t *CANmodule)
72 {
73 	uint16_t i;
74 
75 	if (!CANmodule || !CANmodule->rx_array || !CANmodule->configured) {
76 		return;
77 	}
78 
79 	for (i = 0U; i < CANmodule->rx_size; i++) {
80 		if (CANmodule->rx_array[i].filter_id != -ENOSPC) {
81 			can_remove_rx_filter(CANmodule->dev,
82 					     CANmodule->rx_array[i].filter_id);
83 			CANmodule->rx_array[i].filter_id = -ENOSPC;
84 		}
85 	}
86 }
87 
canopen_rx_callback(const struct device * dev,struct can_frame * frame,void * user_data)88 static void canopen_rx_callback(const struct device *dev, struct can_frame *frame, void *user_data)
89 {
90 	CO_CANmodule_t *CANmodule = (CO_CANmodule_t *)user_data;
91 	CO_CANrxMsg_t rxMsg;
92 	CO_CANrx_t *buffer;
93 	canopen_rxmsg_callback_t callback = rxmsg_callback;
94 	int i;
95 
96 	ARG_UNUSED(dev);
97 
98 	/* Loop through registered rx buffers in priority order */
99 	for (i = 0; i < CANmodule->rx_size; i++) {
100 		buffer = &CANmodule->rx_array[i];
101 
102 		if (buffer->filter_id == -ENOSPC || buffer->pFunct == NULL) {
103 			continue;
104 		}
105 
106 		if (((frame->id ^ buffer->ident) & buffer->mask) == 0U) {
107 #ifdef CONFIG_CAN_ACCEPT_RTR
108 			if (buffer->rtr && ((frame->flags & CAN_FRAME_RTR) == 0U)) {
109 				continue;
110 			}
111 #endif /* CONFIG_CAN_ACCEPT_RTR */
112 			rxMsg.ident = frame->id;
113 			rxMsg.DLC = frame->dlc;
114 			memcpy(rxMsg.data, frame->data, frame->dlc);
115 			buffer->pFunct(buffer->object, &rxMsg);
116 			if (callback != NULL) {
117 				callback();
118 			}
119 			break;
120 		}
121 	}
122 }
123 
canopen_tx_callback(const struct device * dev,int error,void * arg)124 static void canopen_tx_callback(const struct device *dev, int error, void *arg)
125 {
126 	CO_CANmodule_t *CANmodule = arg;
127 
128 	ARG_UNUSED(dev);
129 
130 	if (!CANmodule) {
131 		LOG_ERR("failed to process CAN tx callback");
132 		return;
133 	}
134 
135 	if (error == 0) {
136 		CANmodule->first_tx_msg = false;
137 	}
138 
139 	k_work_submit_to_queue(&canopen_tx_workq, &canopen_tx_queue.work);
140 }
141 
canopen_tx_retry(struct k_work * item)142 static void canopen_tx_retry(struct k_work *item)
143 {
144 	struct canopen_tx_work_container *container =
145 		CONTAINER_OF(item, struct canopen_tx_work_container, work);
146 	CO_CANmodule_t *CANmodule = container->CANmodule;
147 	struct can_frame frame;
148 	CO_CANtx_t *buffer;
149 	int err;
150 	uint16_t i;
151 
152 	memset(&frame, 0, sizeof(frame));
153 
154 	CO_LOCK_CAN_SEND();
155 
156 	for (i = 0; i < CANmodule->tx_size; i++) {
157 		buffer = &CANmodule->tx_array[i];
158 		if (buffer->bufferFull) {
159 			frame.id = buffer->ident;
160 			frame.dlc = buffer->DLC;
161 			frame.flags |= (buffer->rtr ? CAN_FRAME_RTR : 0);
162 			memcpy(frame.data, buffer->data, buffer->DLC);
163 
164 			err = can_send(CANmodule->dev, &frame, K_NO_WAIT,
165 				       canopen_tx_callback, CANmodule);
166 			if (err == -EAGAIN) {
167 				break;
168 			} else if (err != 0) {
169 				LOG_ERR("failed to send CAN frame (err %d)",
170 					err);
171 				CO_errorReport(CANmodule->em,
172 					       CO_EM_GENERIC_SOFTWARE_ERROR,
173 					       CO_EMC_COMMUNICATION, 0);
174 
175 			}
176 
177 			buffer->bufferFull = false;
178 		}
179 	}
180 
181 	CO_UNLOCK_CAN_SEND();
182 }
183 
CO_CANsetConfigurationMode(void * CANdriverState)184 void CO_CANsetConfigurationMode(void *CANdriverState)
185 {
186 	struct canopen_context *ctx = (struct canopen_context *)CANdriverState;
187 	int err;
188 
189 	err = can_stop(ctx->dev);
190 	if (err != 0 && err != -EALREADY) {
191 		LOG_ERR("failed to stop CAN interface (err %d)", err);
192 	}
193 }
194 
CO_CANsetNormalMode(CO_CANmodule_t * CANmodule)195 void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule)
196 {
197 	int err;
198 
199 	err = can_start(CANmodule->dev);
200 	if (err != 0 && err != -EALREADY) {
201 		LOG_ERR("failed to start CAN interface (err %d)", err);
202 		return;
203 	}
204 
205 	CANmodule->CANnormal = true;
206 }
207 
CO_CANmodule_init(CO_CANmodule_t * CANmodule,void * CANdriverState,CO_CANrx_t rxArray[],uint16_t rxSize,CO_CANtx_t txArray[],uint16_t txSize,uint16_t CANbitRate)208 CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule,
209 				   void *CANdriverState,
210 				   CO_CANrx_t rxArray[], uint16_t rxSize,
211 				   CO_CANtx_t txArray[], uint16_t txSize,
212 				   uint16_t CANbitRate)
213 {
214 	struct canopen_context *ctx = (struct canopen_context *)CANdriverState;
215 	uint16_t i;
216 	int err;
217 	int max_filters;
218 
219 	LOG_DBG("rxSize = %d, txSize = %d", rxSize, txSize);
220 
221 	if (!CANmodule || !rxArray || !txArray || !CANdriverState) {
222 		LOG_ERR("failed to initialize CAN module");
223 		return CO_ERROR_ILLEGAL_ARGUMENT;
224 	}
225 
226 	max_filters = can_get_max_filters(ctx->dev, false);
227 	if (max_filters != -ENOSYS) {
228 		if (max_filters < 0) {
229 			LOG_ERR("unable to determine number of CAN RX filters");
230 			return CO_ERROR_SYSCALL;
231 		}
232 
233 		if (rxSize > max_filters) {
234 			LOG_ERR("insufficient number of concurrent CAN RX filters"
235 				" (needs %d, %d available)", rxSize, max_filters);
236 			return CO_ERROR_OUT_OF_MEMORY;
237 		} else if (rxSize < max_filters) {
238 			LOG_DBG("excessive number of concurrent CAN RX filters enabled"
239 				" (needs %d, %d available)", rxSize, max_filters);
240 		}
241 	}
242 
243 	canopen_detach_all_rx_filters(CANmodule);
244 	canopen_tx_queue.CANmodule = CANmodule;
245 
246 	CANmodule->dev = ctx->dev;
247 	CANmodule->rx_array = rxArray;
248 	CANmodule->rx_size = rxSize;
249 	CANmodule->tx_array = txArray;
250 	CANmodule->tx_size = txSize;
251 	CANmodule->CANnormal = false;
252 	CANmodule->first_tx_msg = true;
253 	CANmodule->errors = 0;
254 	CANmodule->em = NULL;
255 
256 	for (i = 0U; i < rxSize; i++) {
257 		rxArray[i].ident = 0U;
258 		rxArray[i].pFunct = NULL;
259 		rxArray[i].filter_id = -ENOSPC;
260 	}
261 
262 	for (i = 0U; i < txSize; i++) {
263 		txArray[i].bufferFull = false;
264 	}
265 
266 	err = can_set_bitrate(CANmodule->dev, KHZ(CANbitRate));
267 	if (err) {
268 		LOG_ERR("failed to configure CAN bitrate (err %d)", err);
269 		return CO_ERROR_ILLEGAL_ARGUMENT;
270 	}
271 
272 	err = can_set_mode(CANmodule->dev, CAN_MODE_NORMAL);
273 	if (err) {
274 		LOG_ERR("failed to configure CAN interface (err %d)", err);
275 		return CO_ERROR_ILLEGAL_ARGUMENT;
276 	}
277 
278 	CANmodule->configured = true;
279 
280 	return CO_ERROR_NO;
281 }
282 
CO_CANmodule_disable(CO_CANmodule_t * CANmodule)283 void CO_CANmodule_disable(CO_CANmodule_t *CANmodule)
284 {
285 	int err;
286 
287 	if (!CANmodule || !CANmodule->dev) {
288 		return;
289 	}
290 
291 	canopen_detach_all_rx_filters(CANmodule);
292 
293 	err = can_stop(CANmodule->dev);
294 	if (err != 0 && err != -EALREADY) {
295 		LOG_ERR("failed to disable CAN interface (err %d)", err);
296 	}
297 }
298 
CO_CANrxMsg_readIdent(const CO_CANrxMsg_t * rxMsg)299 uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg)
300 {
301 	return rxMsg->ident;
302 }
303 
CO_CANrxBufferInit(CO_CANmodule_t * CANmodule,uint16_t index,uint16_t ident,uint16_t mask,bool_t rtr,void * object,CO_CANrxBufferCallback_t pFunct)304 CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index,
305 				uint16_t ident, uint16_t mask, bool_t rtr,
306 				void *object,
307 				CO_CANrxBufferCallback_t pFunct)
308 {
309 	struct can_filter filter;
310 	CO_CANrx_t *buffer;
311 
312 	if (CANmodule == NULL) {
313 		return CO_ERROR_ILLEGAL_ARGUMENT;
314 	}
315 
316 	if (!pFunct || (index >= CANmodule->rx_size)) {
317 		LOG_ERR("failed to initialize CAN rx buffer, illegal argument");
318 		CO_errorReport(CANmodule->em, CO_EM_GENERIC_SOFTWARE_ERROR,
319 			       CO_EMC_SOFTWARE_INTERNAL, 0);
320 		return CO_ERROR_ILLEGAL_ARGUMENT;
321 	}
322 
323 	buffer = &CANmodule->rx_array[index];
324 	buffer->object = object;
325 	buffer->pFunct = pFunct;
326 	buffer->ident = ident;
327 	buffer->mask = mask;
328 
329 #ifndef CONFIG_CAN_ACCEPT_RTR
330 	if (rtr) {
331 		LOG_ERR("request for RTR frames, but RTR frames are rejected");
332 		CO_errorReport(CANmodule->em, CO_EM_GENERIC_SOFTWARE_ERROR,
333 			       CO_EMC_SOFTWARE_INTERNAL, 0);
334 		return CO_ERROR_ILLEGAL_ARGUMENT;
335 	}
336 #else /* !CONFIG_CAN_ACCEPT_RTR */
337 	buffer->rtr = rtr;
338 #endif /* CONFIG_CAN_ACCEPT_RTR */
339 
340 	filter.flags = 0U;
341 	filter.id = ident;
342 	filter.mask = mask;
343 
344 	if (buffer->filter_id != -ENOSPC) {
345 		can_remove_rx_filter(CANmodule->dev, buffer->filter_id);
346 	}
347 
348 	buffer->filter_id = can_add_rx_filter(CANmodule->dev,
349 					      canopen_rx_callback,
350 					      CANmodule, &filter);
351 	if (buffer->filter_id == -ENOSPC) {
352 		LOG_ERR("failed to add CAN rx callback, no free filter");
353 		CO_errorReport(CANmodule->em, CO_EM_MEMORY_ALLOCATION_ERROR,
354 			       CO_EMC_SOFTWARE_INTERNAL, 0);
355 		return CO_ERROR_OUT_OF_MEMORY;
356 	}
357 
358 	return CO_ERROR_NO;
359 }
360 
CO_CANtxBufferInit(CO_CANmodule_t * CANmodule,uint16_t index,uint16_t ident,bool_t rtr,uint8_t noOfBytes,bool_t syncFlag)361 CO_CANtx_t *CO_CANtxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index,
362 			       uint16_t ident, bool_t rtr, uint8_t noOfBytes,
363 			       bool_t syncFlag)
364 {
365 	CO_CANtx_t *buffer;
366 
367 	if (CANmodule == NULL) {
368 		return NULL;
369 	}
370 
371 	if (index >= CANmodule->tx_size) {
372 		LOG_ERR("failed to initialize CAN rx buffer, illegal argument");
373 		CO_errorReport(CANmodule->em, CO_EM_GENERIC_SOFTWARE_ERROR,
374 			       CO_EMC_SOFTWARE_INTERNAL, 0);
375 		return NULL;
376 	}
377 
378 	buffer = &CANmodule->tx_array[index];
379 	buffer->ident = ident;
380 	buffer->rtr = rtr;
381 	buffer->DLC = noOfBytes;
382 	buffer->bufferFull = false;
383 	buffer->syncFlag = syncFlag;
384 
385 	return buffer;
386 }
387 
CO_CANsend(CO_CANmodule_t * CANmodule,CO_CANtx_t * buffer)388 CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer)
389 {
390 	CO_ReturnError_t ret = CO_ERROR_NO;
391 	struct can_frame frame;
392 	int err;
393 
394 	if (!CANmodule || !CANmodule->dev || !buffer) {
395 		return CO_ERROR_ILLEGAL_ARGUMENT;
396 	}
397 
398 	memset(&frame, 0, sizeof(frame));
399 
400 	CO_LOCK_CAN_SEND();
401 
402 	if (buffer->bufferFull) {
403 		if (!CANmodule->first_tx_msg) {
404 			CO_errorReport(CANmodule->em, CO_EM_CAN_TX_OVERFLOW,
405 				       CO_EMC_CAN_OVERRUN, buffer->ident);
406 		}
407 		buffer->bufferFull = false;
408 		ret = CO_ERROR_TX_OVERFLOW;
409 	}
410 
411 	frame.id = buffer->ident;
412 	frame.dlc = buffer->DLC;
413 	frame.flags = (buffer->rtr ? CAN_FRAME_RTR : 0);
414 	memcpy(frame.data, buffer->data, buffer->DLC);
415 
416 	err = can_send(CANmodule->dev, &frame, K_NO_WAIT, canopen_tx_callback,
417 		       CANmodule);
418 	if (err == -EAGAIN) {
419 		buffer->bufferFull = true;
420 	} else if (err != 0) {
421 		LOG_ERR("failed to send CAN frame (err %d)", err);
422 		CO_errorReport(CANmodule->em, CO_EM_GENERIC_SOFTWARE_ERROR,
423 			       CO_EMC_COMMUNICATION, 0);
424 		ret = CO_ERROR_TX_UNCONFIGURED;
425 	}
426 
427 	CO_UNLOCK_CAN_SEND();
428 
429 	return ret;
430 }
431 
CO_CANclearPendingSyncPDOs(CO_CANmodule_t * CANmodule)432 void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule)
433 {
434 	bool_t tpdoDeleted = false;
435 	CO_CANtx_t *buffer;
436 	uint16_t i;
437 
438 	if (!CANmodule) {
439 		return;
440 	}
441 
442 	CO_LOCK_CAN_SEND();
443 
444 	for (i = 0; i < CANmodule->tx_size; i++) {
445 		buffer = &CANmodule->tx_array[i];
446 		if (buffer->bufferFull && buffer->syncFlag) {
447 			buffer->bufferFull = false;
448 			tpdoDeleted = true;
449 		}
450 	}
451 
452 	CO_UNLOCK_CAN_SEND();
453 
454 	if (tpdoDeleted) {
455 		CO_errorReport(CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW,
456 			       CO_EMC_COMMUNICATION, 0);
457 	}
458 }
459 
CO_CANverifyErrors(CO_CANmodule_t * CANmodule)460 void CO_CANverifyErrors(CO_CANmodule_t *CANmodule)
461 {
462 	CO_EM_t *em = (CO_EM_t *)CANmodule->em;
463 	struct can_bus_err_cnt err_cnt;
464 	enum can_state state;
465 	uint8_t rx_overflows;
466 	uint32_t errors;
467 	int err;
468 
469 	/*
470 	 * TODO: Zephyr lacks an API for reading the rx mailbox
471 	 * overflow counter.
472 	 */
473 	rx_overflows  = 0;
474 
475 	err = can_get_state(CANmodule->dev, &state, &err_cnt);
476 	if (err != 0) {
477 		LOG_ERR("failed to get CAN controller state (err %d)", err);
478 		return;
479 	}
480 
481 	errors = ((uint32_t)err_cnt.tx_err_cnt << 16) |
482 		 ((uint32_t)err_cnt.rx_err_cnt << 8) |
483 		 rx_overflows;
484 
485 	if (errors != CANmodule->errors) {
486 		CANmodule->errors = errors;
487 
488 		if (state == CAN_STATE_BUS_OFF) {
489 			/* Bus off */
490 			CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF,
491 				       CO_EMC_BUS_OFF_RECOVERED, errors);
492 		} else {
493 			/* Bus not off */
494 			CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, errors);
495 
496 			if ((err_cnt.rx_err_cnt >= 96U) ||
497 			    (err_cnt.tx_err_cnt >= 96U)) {
498 				/* Bus warning */
499 				CO_errorReport(em, CO_EM_CAN_BUS_WARNING,
500 					       CO_EMC_NO_ERROR, errors);
501 			} else {
502 				/* Bus not warning */
503 				CO_errorReset(em, CO_EM_CAN_BUS_WARNING,
504 					      errors);
505 			}
506 
507 			if (err_cnt.rx_err_cnt >= 128U) {
508 				/* Bus rx passive */
509 				CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE,
510 					       CO_EMC_CAN_PASSIVE, errors);
511 			} else {
512 				/* Bus not rx passive */
513 				CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE,
514 					      errors);
515 			}
516 
517 			if (err_cnt.tx_err_cnt >= 128U &&
518 			    !CANmodule->first_tx_msg) {
519 				/* Bus tx passive */
520 				CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE,
521 					       CO_EMC_CAN_PASSIVE, errors);
522 			} else if (CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE)) {
523 				/* Bus not tx passive */
524 				CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE,
525 					      errors);
526 				CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW,
527 					      errors);
528 			}
529 		}
530 
531 		/* This code can be activated if we can read the overflows*/
532 		if (false && rx_overflows != 0U) {
533 			CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW,
534 				       CO_EMC_CAN_OVERRUN, errors);
535 		}
536 	}
537 }
538 
canopen_init(void)539 static int canopen_init(void)
540 {
541 
542 	k_work_queue_start(&canopen_tx_workq, canopen_tx_workq_stack,
543 			   K_KERNEL_STACK_SIZEOF(canopen_tx_workq_stack),
544 			   CONFIG_CANOPENNODE_TX_WORKQUEUE_PRIORITY, NULL);
545 
546 	k_thread_name_set(&canopen_tx_workq.thread, "canopen_tx_workq");
547 
548 	k_work_init(&canopen_tx_queue.work, canopen_tx_retry);
549 
550 	return 0;
551 }
552 
553 SYS_INIT(canopen_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
554