Lely core libraries 1.9.2
wtm.c
Go to the documentation of this file.
1
24#include "co.h"
25
26#ifndef LELY_NO_CO_WTM
27
28#include <lely/co/crc.h>
29#include <lely/co/wtm.h>
30#include <lely/util/diag.h>
31#include <lely/util/endian.h>
32#include <lely/util/time.h>
33
34#include <assert.h>
35#include <inttypes.h>
36#include <stdlib.h>
37#include <string.h>
38
40#define CO_WTM_MAX_NIF 127
41
43struct co_wtm_can {
49 uint8_t st;
56 uint8_t err;
61 uint8_t load;
67 uint16_t ec;
72 uint16_t foc;
77 uint16_t coc;
84};
85
87struct __co_wtm {
89 uint8_t nif;
94 uint8_t quality;
145 uint8_t recv_nseq;
151 uint8_t send_nseq;
152};
153
155static int co_wtm_send_diag_can_res(co_wtm_t *wtm, uint8_t nif);
156
158static int co_wtm_send_diag_wtm_res(co_wtm_t *wtm);
159
161static void co_wtm_diag_ac(co_wtm_t *wtm, uint32_t ac);
162
164static void default_wtm_diag_ac_ind(co_wtm_t *wtm, uint32_t ac, void *data);
165
175static uint32_t co_wtm_recv_can(co_wtm_t *wtm, const void *buf, size_t nbytes);
176
177const char *
178co_wtm_ac_str(uint32_t ac)
179{
180 switch (ac) {
181 case CO_WTM_AC_ERROR: return "General error";
183 return "Diagnostic protocol timed out limit reached";
184 case CO_WTM_AC_NO_MEM: return "Out of memory";
185 case CO_WTM_AC_HARDWARE: return "Access failed due to a hardware error";
186 case CO_WTM_AC_DATA:
187 return "Data cannot be transferred or stored to the application";
189 return "Data cannot be transferred or stored to the application because of local control";
191 return "Data cannot be transferred or stored to the application because of the present device state";
192 case CO_WTM_AC_NO_DATA: return "No data available";
193 case CO_WTM_AC_NO_IF: return "Requested interface not implemented";
194 case CO_WTM_AC_IF_DOWN: return "Requested interface disabled";
195 case CO_WTM_AC_DIAG: return "Diagnostic data generation not supported";
197 return "Diagnostic data generation for requested CAN interface not supported";
199 return "Diagnostic data generation for requested WTM interface not supported";
200 case CO_WTM_AC_FRAME: return "General generic frame error";
201 case CO_WTM_AC_PREAMBLE: return "Invalid generic frame preamble";
202 case CO_WTM_AC_SEQ: return "Invalid sequence counter in generic frame";
203 case CO_WTM_AC_TYPE: return "Message type not valid or unknown";
204 case CO_WTM_AC_PAYLOAD: return "Payload field in generic frame invalid";
205 case CO_WTM_AC_CRC: return "CRC error (Generic frame)";
206 case CO_WTM_AC_CAN: return "CAN telegram essentials invalid";
207 default: return "Unknown abort code";
208 }
209}
210
211void *
212__co_wtm_alloc(void)
213{
214 void *ptr = malloc(sizeof(struct __co_wtm));
215 if (__unlikely(!ptr))
216 set_errc(errno2c(errno));
217 return ptr;
218}
219
220void
221__co_wtm_free(void *ptr)
222{
223 free(ptr);
224}
225
226struct __co_wtm *
227__co_wtm_init(struct __co_wtm *wtm)
228{
229 assert(wtm);
230
231 wtm->nif = 1;
232
233 wtm->quality = 0xff;
234
235 for (uint8_t nif = 1; nif <= CO_WTM_MAX_NIF; nif++) {
236 struct co_wtm_can *can = &wtm->can[nif - 1];
237
238 can->st = 0xf;
239 can->err = 0xf;
240 can->load = 0xff;
241 can->ec = 0xffff;
242 can->foc = 0xffff;
243 can->coc = 0xffff;
244
245 can->recv_time = (struct timespec){ 0, 0 };
246 can->send_time = (struct timespec){ 0, 0 };
247 can->send_next = (struct timespec){ 0, 0 };
248 }
249
250 wtm->diag_can_con = NULL;
251 wtm->diag_can_con_data = NULL;
252
253 wtm->diag_wtm_con = NULL;
254 wtm->diag_wtm_con_data = NULL;
255
256 wtm->diag_can_ind = NULL;
257 wtm->diag_can_ind_data = NULL;
258
259 wtm->diag_wtm_ind = NULL;
260 wtm->diag_wtm_ind_data = NULL;
261
263 wtm->diag_ac_data = NULL;
264
265 wtm->recv_func = NULL;
266 wtm->recv_data = NULL;
267
268 wtm->send_func = NULL;
269 wtm->send_data = NULL;
270
271 wtm->recv_nbytes = 0;
272 wtm->recv_nseq = 0;
273
274 wtm->send_nbytes = 0;
275 wtm->send_nseq = 0;
276
277 return wtm;
278}
279
280void
281__co_wtm_fini(struct __co_wtm *wtm)
282{
283 (void)wtm;
284}
285
286co_wtm_t *
288{
289 int errc = 0;
290
291 co_wtm_t *wtm = __co_wtm_alloc();
292 if (__unlikely(!wtm)) {
293 errc = get_errc();
294 goto error_alloc_wtm;
295 }
296
297 if (__unlikely(!__co_wtm_init(wtm))) {
298 errc = get_errc();
299 goto error_init_wtm;
300 }
301
302 return wtm;
303
304error_init_wtm:
305 __co_wtm_free(wtm);
306error_alloc_wtm:
307 set_errc(errc);
308 return NULL;
309}
310
311void
313{
314 if (wtm) {
315 __co_wtm_fini(wtm);
316 __co_wtm_free(wtm);
317 }
318}
319
320uint8_t
322{
323 assert(wtm);
324
325 return wtm->nif;
326}
327
328int
329co_wtm_set_nif(co_wtm_t *wtm, uint8_t nif)
330{
331 assert(wtm);
332
333 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
335 return -1;
336 }
337
338 wtm->nif = nif;
339
340 return 0;
341}
342
343int
344co_wtm_set_diag_can(co_wtm_t *wtm, uint8_t nif, uint8_t st, uint8_t err,
345 uint8_t load, uint16_t ec, uint16_t foc, uint16_t coc)
346{
347 assert(wtm);
348
349 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
351 return -1;
352 }
353 struct co_wtm_can *can = &wtm->can[nif - 1];
354
355 switch (st) {
356 case CAN_STATE_ACTIVE: st = 0; break;
357 case CAN_STATE_PASSIVE: st = 1; break;
358 case CAN_STATE_BUSOFF: st = 2; break;
359 case 0xf: break;
360 default: set_errnum(ERRNUM_INVAL); return -1;
361 }
362
363 if (err == 0xf) {
364 } else if (err & CAN_ERROR_BIT) {
365 err = 1;
366 } else if (err & CAN_ERROR_STUFF) {
367 err = 2;
368 } else if (err & CAN_ERROR_CRC) {
369 err = 3;
370 } else if (err & CAN_ERROR_FORM) {
371 err = 4;
372 } else if (err & CAN_ERROR_ACK) {
373 err = 5;
374 } else if (err) {
375 err = 0xf;
376 }
377
378 if (__unlikely(load > 100 && load != 0xff)) {
380 return -1;
381 }
382
383 can->st = st;
384 can->err = err;
385 can->load = load;
386 can->ec = ec;
387 can->foc = foc;
388 can->coc = coc;
389
390 return 0;
391}
392
393int
394co_wtm_set_diag_wtm(co_wtm_t *wtm, uint8_t quality)
395{
396 assert(wtm);
397
398 if (__unlikely(quality > 100 && quality != 0xff)) {
400 return -1;
401 }
402
403 wtm->quality = quality;
404
405 return 0;
406}
407
408void
410 const co_wtm_t *wtm, co_wtm_diag_can_con_t **pcon, void **pdata)
411{
412 assert(wtm);
413
414 if (pcon)
415 *pcon = wtm->diag_can_con;
416 if (pdata)
417 *pdata = wtm->diag_can_con_data;
418}
419
420void
422{
423 assert(wtm);
424
425 wtm->diag_can_con = con;
426 wtm->diag_can_con_data = data;
427}
428
429void
431 const co_wtm_t *wtm, co_wtm_diag_wtm_con_t **pcon, void **pdata)
432{
433 assert(wtm);
434
435 if (pcon)
436 *pcon = wtm->diag_wtm_con;
437 if (pdata)
438 *pdata = wtm->diag_wtm_con_data;
439}
440
441void
443{
444 assert(wtm);
445
446 wtm->diag_wtm_con = con;
447 wtm->diag_wtm_con_data = data;
448}
449
450void
452 const co_wtm_t *wtm, co_wtm_diag_can_ind_t **pcon, void **pdata)
453{
454 assert(wtm);
455
456 if (pcon)
457 *pcon = wtm->diag_can_ind;
458 if (pdata)
459 *pdata = wtm->diag_can_ind_data;
460}
461
462void
464{
465 assert(wtm);
466
467 wtm->diag_can_ind = con;
468 wtm->diag_can_ind_data = data;
469}
470
471void
473 const co_wtm_t *wtm, co_wtm_diag_wtm_ind_t **pcon, void **pdata)
474{
475 assert(wtm);
476
477 if (pcon)
478 *pcon = wtm->diag_wtm_ind;
479 if (pdata)
480 *pdata = wtm->diag_wtm_ind_data;
481}
482
483void
485{
486 assert(wtm);
487
488 wtm->diag_wtm_ind = con;
489 wtm->diag_wtm_ind_data = data;
490}
491
492void
494 const co_wtm_t *wtm, co_wtm_diag_ac_ind_t **pind, void **pdata)
495{
496 assert(wtm);
497
498 if (pind)
499 *pind = wtm->diag_ac_ind;
500 if (pdata)
501 *pdata = wtm->diag_ac_data;
502}
503
504void
506{
507 assert(wtm);
508
509 wtm->diag_ac_ind = ind ? ind : &default_wtm_diag_ac_ind;
510 wtm->diag_ac_data = ind ? data : NULL;
511}
512
513void
514co_wtm_recv(co_wtm_t *wtm, const void *buf, size_t nbytes)
515{
516 assert(wtm);
517 assert(wtm->diag_ac_ind);
518 assert(buf);
519
520 for (const char *bp = buf; nbytes;) {
521 uint32_t ac = 0;
522 // Search for the preamble (see section 5.2 in CiA 315 version
523 // 1.0.0).
524 size_t size = 1;
525 if (wtm->recv_nbytes < size) {
526 wtm->recv_buf[wtm->recv_nbytes] = *bp;
527 wtm->recv_nbytes++;
528 bp++;
529 nbytes--;
530 }
531 if (__unlikely(wtm->recv_buf[0] != 0x55)) {
533 goto error;
534 }
535 // Copy the rest of the header (plus the CRC checksum if there
536 // is no payload).
537 size += 5;
538 if (wtm->recv_nbytes < size) {
539 size_t n = MIN(nbytes, size - wtm->recv_nbytes);
540 memcpy(wtm->recv_buf + wtm->recv_nbytes, bp, n);
541 wtm->recv_nbytes += n;
542 bp += n;
543 nbytes -= n;
544 if (wtm->recv_nbytes < size)
545 continue;
546 }
547 // Copy the payload (plus the CRC checksum).
548 uint8_t len = wtm->recv_buf[1];
549 size += len;
550 if (wtm->recv_nbytes < size) {
551 size_t n = MIN(nbytes, size - wtm->recv_nbytes);
552 memcpy(wtm->recv_buf + wtm->recv_nbytes, bp, n);
553 wtm->recv_nbytes += n;
554 bp += n;
555 nbytes -= n;
556 if (wtm->recv_nbytes < size)
557 continue;
558 }
559 // Check the CRC checksum (see section 5.7 in CiA 315 version
560 // 1.0.0).
561 uint16_t crc = co_crc(0xffff, wtm->recv_buf, 4 + len);
562 if (__unlikely(crc != ldle_u16(wtm->recv_buf + 4 + len))) {
563 ac = CO_WTM_AC_CRC;
564 goto error;
565 }
566 // Check the sequence counter (see section 5.4 in CiA 315
567 // version 1.0.0).
568 uint8_t seq = wtm->recv_buf[2];
569 if (__unlikely(seq != wtm->recv_nseq))
570 // Generate an error, but do not abort processing the
571 // message.
573 wtm->recv_nseq = seq + 1;
574 // Process message payload based on its type (see Table 2 in CiA
575 // 315 version 1.0.0).
576 uint8_t type = wtm->recv_buf[3];
577 uint8_t nif;
578 switch (type) {
579 // CAN messages forwarding (see section 6 in CiA 315 version
580 // 1.0.0).
581 case 0x00:
582 // Process the CAN frames.
583 // clang-format off
584 if (__unlikely((ac = co_wtm_recv_can(wtm,
585 wtm->recv_buf + 4, len)) != 0))
586 // clang-format on
587 goto error;
588 break;
589 // Keep-alive (see section 7.3 in CiA 315 version 1.0.0).
590 case 0x10:
591 if (__unlikely(len < 1)) {
593 goto error;
594 }
595 // Obtain the WTM interface indicator.
596 nif = wtm->recv_buf[4];
597 if (__unlikely(nif <= 0x80)) {
599 goto error;
600 }
601 // Ignore keep-alive messages for other WTM interfaces.
602 if (__unlikely(nif != 0x80 + wtm->nif))
603 break;
604 // TODO: handle keep-alive message.
605 break;
606 // Timer-overrun (see section 7.4 in CiA 315 version 1.0.0).
607 case 0x11:
608 if (__unlikely(len < 1)) {
610 goto error;
611 }
612 // Obtain the CAN interface indicator.
613 nif = wtm->recv_buf[4];
614 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
616 goto error;
617 }
618 // Add 6553.5 ms to the CAN interface timer.
620 &wtm->can[nif - 1].recv_time, 6553500);
621 break;
622 // Communication quality request.
623 case 0x12:
624 if (__unlikely(len < 1)) {
626 goto error;
627 }
628 // Obtain the interface indicator.
629 nif = wtm->recv_buf[4];
630 if (nif <= 0x80) {
631 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
633 wtm, CO_WTM_AC_NO_IF);
634 break;
635 }
636 // Send the communication quality response.
637 co_wtm_send_diag_can_res(wtm, nif);
638 } else {
639 // Only accept communication quality requests
640 // for this WTM interface.
641 if (__unlikely(nif != 0x80 + wtm->nif)) {
643 wtm, CO_WTM_AC_NO_IF);
644 break;
645 }
646 // Send the communication quality response.
648 }
649 break;
650 // Communication quality response.
651 case 0x13:
652 if (__unlikely(len < 2)) {
654 goto error;
655 }
656 // Obtain the interface indicator.
657 nif = wtm->recv_buf[4];
658 if (__unlikely(!nif || nif == 0x80)) {
660 goto error;
661 }
662 if (nif < 0x80) {
663 if (__unlikely(len < 9)) {
665 goto error;
666 }
667 if (!wtm->diag_can_con)
668 continue;
669 uint8_t st = 0xf;
670 switch ((wtm->recv_buf[5] >> 4) & 0xf) {
671 case 0: st = CAN_STATE_ACTIVE; break;
672 case 1: st = CAN_STATE_PASSIVE; break;
673 case 2: st = CAN_STATE_BUSOFF; break;
674 }
675 uint8_t err = 0xf;
676 switch (wtm->recv_buf[5] & 0xf) {
677 case 1: err = CAN_ERROR_BIT; break;
678 case 2: err = CAN_ERROR_STUFF; break;
679 case 3: err = CAN_ERROR_CRC; break;
680 case 4: err = CAN_ERROR_FORM; break;
681 case 5: err = CAN_ERROR_ACK; break;
682 }
683 uint8_t load = wtm->recv_buf[6];
684 uint16_t ec = ldle_u16(wtm->recv_buf + 7);
685 uint16_t foc = ldle_u16(wtm->recv_buf + 9);
686 uint16_t coc = ldle_u16(wtm->recv_buf + 11);
687 wtm->diag_can_con(wtm, nif, st, err, load, ec,
688 foc, coc,
689 wtm->diag_can_con_data);
690 } else {
691 if (!wtm->diag_wtm_con)
692 continue;
693 uint8_t quality = wtm->recv_buf[5];
694 wtm->diag_wtm_con(wtm, nif - 0x80, quality,
695 wtm->diag_wtm_con_data);
696 }
697 break;
698 // Communication quality reset.
699 case 0x14:
700 if (__unlikely(len < 1)) {
702 goto error;
703 }
704 // Obtain the interface indicator.
705 nif = wtm->recv_buf[4];
706 if (nif <= 0x80) {
707 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
709 wtm, CO_WTM_AC_NO_IF);
710 break;
711 }
712 struct co_wtm_can *can = &wtm->can[nif - 1];
713 can->st = 0xf;
714 can->err = 0xf;
715 can->load = 0xff;
716 can->ec = 0xffff;
717 can->foc = 0xffff;
718 can->coc = 0xffff;
719 if (wtm->diag_can_ind)
720 wtm->diag_can_ind(wtm, nif,
721 wtm->diag_can_ind_data);
722 } else {
723 // Only accept communication quality reset
724 // messages for this WTM interface.
725 if (__unlikely(nif != 0x80 + wtm->nif)) {
727 wtm, CO_WTM_AC_NO_IF);
728 break;
729 }
730 wtm->quality = 0xff;
731 if (wtm->diag_wtm_ind)
732 wtm->diag_wtm_ind(wtm,
733 wtm->diag_wtm_ind_data);
734 }
735 break;
736 // Diagnostic abort message.
737 case 0x15:
738 if (__unlikely(len < 5)) {
740 goto error;
741 }
742 // Obtain the WTM interface indicator.
743 nif = wtm->recv_buf[4];
744 if (__unlikely(nif <= 0x80)) {
746 goto error;
747 }
748 // Ignore diagnostic abort messages for other WTM
749 // interfaces.
750 if (__unlikely(nif != 0x80 + wtm->nif))
751 break;
752 ac = ldle_u32(wtm->recv_buf + 5);
753 break;
754 default: ac = CO_WTM_AC_TYPE; goto error;
755 }
756 error:
757 if (__unlikely(ac))
758 co_wtm_diag_ac(wtm, ac);
759 // Empty the buffer for the next message.
760 wtm->recv_nbytes = 0;
761 }
762}
763
764void
766 const co_wtm_t *wtm, co_wtm_recv_func_t **pfunc, void **pdata)
767{
768 assert(wtm);
769
770 if (pfunc)
771 *pfunc = wtm->recv_func;
772 if (pdata)
773 *pdata = wtm->recv_data;
774}
775
776void
778{
779 assert(wtm);
780
781 wtm->recv_func = func;
782 wtm->recv_data = data;
783}
784
785int
786co_wtm_get_time(const co_wtm_t *wtm, uint8_t nif, struct timespec *tp)
787{
788 assert(wtm);
789
790 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
792 return -1;
793 }
794
795 if (tp)
796 *tp = wtm->can[nif - 1].send_next;
797
798 return 0;
799}
800
801int
802co_wtm_set_time(co_wtm_t *wtm, uint8_t nif, const struct timespec *tp)
803{
804 assert(wtm);
805 assert(tp);
806
807 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
809 return -1;
810 }
811 struct co_wtm_can *can = &wtm->can[nif - 1];
812
813 // Since the time stamp is relative, store the absolute time on the
814 // first invocation.
815 if (!can->send_time.tv_sec && !can->send_time.tv_nsec)
816 can->send_time = *tp;
817 // Update the time stamp for the next CAN frame.
818 can->send_next = *tp;
819
820 // If the difference between the current (reference) and next time is
821 // larger than 6553.5 ms, send a timer-overrun message.
822 while (timespec_diff_usec(&can->send_next, &can->send_time) > 6553500) {
823 if (__unlikely(co_wtm_flush(wtm) == -1))
824 return -1;
825 wtm->send_buf[3] = 0x11;
826 wtm->send_buf[4] = nif;
827 wtm->send_nbytes = 5;
828 // Update the current (reference) time.
829 timespec_add_usec(&can->send_time, 6553500);
830 }
831
832 return 0;
833}
834
835int
836co_wtm_send(co_wtm_t *wtm, uint8_t nif, const struct can_msg *msg)
837{
838 assert(wtm);
839 assert(msg);
840
841 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
843 return -1;
844 }
845 struct co_wtm_can *can = &wtm->can[nif - 1];
846
847#ifndef LELY_NO_CANFD
848 // CAN FD frames are not supported.
849 if (__unlikely(msg->flags & CAN_FLAG_EDL)) {
851 return -1;
852 }
853#endif
854
855 if (__unlikely(msg->len > CAN_MAX_LEN)) {
857 return -1;
858 }
859
860 // Compute the length of the CAN frame.
861 size_t len = 1 + (nif != 1) + ((msg->flags & CAN_FLAG_IDE) ? 4 : 2)
862 + msg->len + 2;
863 // Flush the buffer if necessary.
864 if ((wtm->send_nbytes > 3 && wtm->send_buf[3] != 0x00)
865 || wtm->send_nbytes + len + 2 > CO_WTM_MAX_LEN) {
866 if (__unlikely(co_wtm_flush(wtm) == -1))
867 return -1;
868 }
869 wtm->send_buf[3] = 0x00;
870 wtm->send_nbytes = MAX(wtm->send_nbytes, 4);
871 uint8_t *bp = wtm->send_buf + wtm->send_nbytes;
872 size_t nbytes = wtm->send_nbytes;
873
874 // Write the data length code.
875 uint8_t dlc = msg->len | 0x40;
876 if (msg->flags & CAN_FLAG_RTR)
877 dlc |= 0x10;
878 if (msg->flags & CAN_FLAG_IDE)
879 dlc |= 0x20;
880 if (nif != 1)
881 dlc |= 0x80;
882 *bp = dlc;
883 bp++;
884 nbytes++;
885 // Write the interface indicator.
886 if (nif != 1) {
887 *bp = nif;
888 bp++;
889 nbytes++;
890 }
891 // Write the CAN identifier.
892 if (msg->flags & CAN_FLAG_IDE) {
893 stle_u32(bp, msg->id & CAN_MASK_EID);
894 bp += 4;
895 nbytes += 4;
896 } else {
897 stle_u16(bp, msg->id & CAN_MASK_BID);
898 bp += 2;
899 nbytes += 2;
900 }
901 // Copy the frame payload.
902 memcpy(bp, msg->data, msg->len);
903 bp += msg->len;
904 nbytes += msg->len;
905 // Write the time stamp.
906 int64_t usec = timespec_diff_usec(&can->send_next, &can->send_time);
907 stle_u16(bp, (uint16_t)(usec / 100));
908 nbytes += 2;
909
910 assert(nbytes + 2 <= CO_WTM_MAX_LEN);
911 wtm->send_nbytes = nbytes;
912
913 return 0;
914}
915
916int
918{
919 assert(wtm);
920 assert(wtm->nif && wtm->nif <= CO_WTM_MAX_NIF);
921
922 if (__unlikely(co_wtm_flush(wtm) == -1))
923 return -1;
924 wtm->send_buf[3] = 0x10;
925 wtm->send_buf[4] = 0x80 + wtm->nif;
926 wtm->send_nbytes = 5;
927 return co_wtm_flush(wtm);
928}
929
930int
932{
933 assert(wtm);
934
935 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
937 return -1;
938 }
939
940 if (__unlikely(co_wtm_flush(wtm) == -1))
941 return -1;
942 wtm->send_buf[3] = 0x12;
943 wtm->send_buf[4] = nif;
944 wtm->send_nbytes = 5;
945 return co_wtm_flush(wtm);
946}
947
948int
950{
951 assert(wtm);
952
953 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
955 return -1;
956 }
957
958 if (__unlikely(co_wtm_flush(wtm) == -1))
959 return -1;
960 wtm->send_buf[3] = 0x12;
961 wtm->send_buf[4] = 0x80 + nif;
962 wtm->send_nbytes = 5;
963 return co_wtm_flush(wtm);
964}
965
966int
968{
969 assert(wtm);
970
971 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
973 return -1;
974 }
975
976 if (__unlikely(co_wtm_flush(wtm) == -1))
977 return -1;
978 wtm->send_buf[3] = 0x14;
979 wtm->send_buf[4] = nif;
980 wtm->send_nbytes = 5;
981 return co_wtm_flush(wtm);
982}
983
984int
986{
987 assert(wtm);
988
989 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF)) {
991 return -1;
992 }
993
994 if (__unlikely(co_wtm_flush(wtm) == -1))
995 return -1;
996 wtm->send_buf[3] = 0x14;
997 wtm->send_buf[4] = 0x80 + nif;
998 wtm->send_nbytes = 5;
999 return co_wtm_flush(wtm);
1000}
1001
1002int
1004{
1005 assert(wtm);
1006 assert(wtm->nif && wtm->nif <= CO_WTM_MAX_NIF);
1007
1008 if (__unlikely(co_wtm_flush(wtm) == -1))
1009 return -1;
1010 wtm->send_buf[3] = 0x15;
1011 wtm->send_buf[4] = 0x80 + wtm->nif;
1012 stle_u32(wtm->send_buf + 5, ac);
1013 wtm->send_nbytes = 9;
1014 return co_wtm_flush(wtm);
1015}
1016
1017int
1019{
1020 assert(wtm);
1021
1022 // Do not flush if there is no header.
1023 if (wtm->send_nbytes < 4)
1024 return 0;
1025 uint8_t len = (uint8_t)(wtm->send_nbytes - 4);
1026 wtm->send_nbytes = 0;
1027
1028 // Fill in the header fields.
1029 wtm->send_buf[0] = 0x55;
1030 wtm->send_buf[1] = len;
1031 wtm->send_buf[2] = wtm->send_nseq++;
1032 // Compute the CRC checksum.
1033 uint16_t crc = co_crc(0xffff, wtm->send_buf, 4 + len);
1034 stle_u16(wtm->send_buf + 4 + len, crc);
1035
1036 // Invoke the user-specified callback function to send the generic
1037 // frame.
1038 if (__unlikely(!wtm->send_func)) {
1040 return -1;
1041 }
1042 return wtm->send_func(wtm, wtm->send_buf, 4 + len + 2, wtm->send_data)
1043 ? -1
1044 : 0;
1045}
1046
1047void
1049 const co_wtm_t *wtm, co_wtm_send_func_t **pfunc, void **pdata)
1050{
1051 assert(wtm);
1052
1053 if (pfunc)
1054 *pfunc = wtm->send_func;
1055 if (pdata)
1056 *pdata = wtm->send_data;
1057}
1058
1059void
1061{
1062 assert(wtm);
1063
1064 wtm->send_func = func;
1065 wtm->send_data = data;
1066}
1067
1068static int
1070{
1071 assert(wtm);
1072 assert(nif && nif <= CO_WTM_MAX_NIF);
1073 struct co_wtm_can *can = &wtm->can[nif - 1];
1074
1075 if (__unlikely(co_wtm_flush(wtm) == -1))
1076 return -1;
1077 wtm->send_buf[3] = 0x13;
1078 wtm->send_buf[4] = nif;
1079 wtm->send_buf[5] = ((can->st & 0xf) << 4) | (can->err & 0xf);
1080 wtm->send_buf[6] = can->load;
1081 stle_u16(wtm->send_buf + 7, can->ec);
1082 stle_u16(wtm->send_buf + 9, can->foc);
1083 stle_u16(wtm->send_buf + 11, can->coc);
1084 wtm->send_nbytes = 13;
1085 return co_wtm_flush(wtm);
1086}
1087
1088static int
1090{
1091 assert(wtm);
1092
1093 if (__unlikely(co_wtm_flush(wtm) == -1))
1094 return -1;
1095 wtm->send_buf[3] = 0x13;
1096 wtm->send_buf[4] = 0x80 + wtm->nif;
1097 wtm->send_buf[5] = wtm->quality;
1098 wtm->send_nbytes = 6;
1099 return co_wtm_flush(wtm);
1100}
1101
1102static void
1103co_wtm_diag_ac(co_wtm_t *wtm, uint32_t ac)
1104{
1105 assert(wtm);
1106 assert(wtm->diag_ac_ind);
1107
1108 wtm->diag_ac_ind(wtm, ac, wtm->diag_ac_data);
1109}
1110
1111static void
1112default_wtm_diag_ac_ind(co_wtm_t *wtm, uint32_t ac, void *data)
1113{
1114 (void)wtm;
1115 (void)data;
1116
1117 diag(DIAG_WARNING, 0, "received WTM abort code %08" PRIX32 ": %s", ac,
1118 co_wtm_ac_str(ac));
1119}
1120
1121static uint32_t
1122co_wtm_recv_can(co_wtm_t *wtm, const void *buf, size_t nbytes)
1123{
1124 assert(wtm);
1125 assert(buf);
1126 assert(nbytes);
1127
1128 uint32_t ac = 0;
1129 for (const char *bp = buf; nbytes;) {
1130 struct can_msg msg = CAN_MSG_INIT;
1131 // Obtain the data length code.
1132 uint8_t dlc = *bp;
1133 bp++;
1134 nbytes--;
1135 msg.len = dlc & 0x0f;
1136 if (__unlikely(msg.len > CAN_MAX_LEN)) {
1137 ac = CO_WTM_AC_CAN;
1138 goto error;
1139 }
1140 if (dlc & 0x10)
1141 msg.flags |= CAN_FLAG_RTR;
1142 // Obtain the CAN interface indicator.
1143 uint8_t nif = 1;
1144 if (dlc & 0x80) {
1145 if (__unlikely(nbytes < 1)) {
1146 ac = CO_WTM_AC_CAN;
1147 goto error;
1148 }
1149 nif = *bp;
1150 bp++;
1151 nbytes--;
1152 }
1153 // Obtain the CAN identifier.
1154 if (dlc & 0x20) {
1155 if (__unlikely(nbytes < 4)) {
1156 ac = CO_WTM_AC_CAN;
1157 goto error;
1158 }
1159 msg.id = ldle_u32(bp) & CAN_MASK_EID;
1160 bp += 4;
1161 nbytes -= 4;
1162 msg.flags |= CAN_FLAG_IDE;
1163 } else {
1164 if (__unlikely(nbytes < 2)) {
1165 ac = CO_WTM_AC_CAN;
1166 goto error;
1167 }
1168 msg.id = ldle_u16(bp) & CAN_MASK_BID;
1169 bp += 2;
1170 nbytes -= 2;
1171 }
1172 // Obtain the frame payload.
1173 if (__unlikely(nbytes < msg.len)) {
1174 ac = CO_WTM_AC_CAN;
1175 goto error;
1176 }
1177 memcpy(msg.data, bp, msg.len);
1178 bp += msg.len;
1179 nbytes -= msg.len;
1180 // Obtain the time stamp.
1181 uint16_t ts = 0;
1182 if (dlc & 0x40) {
1183 if (__unlikely(nbytes < 2)) {
1184 ac = CO_WTM_AC_CAN;
1185 goto error;
1186 }
1187 ts = ldle_u16(bp);
1188 bp += 2;
1189 nbytes -= 2;
1190 }
1191 // Ignore CAN frames with an invalid interface indicator.
1192 if (__unlikely(!nif || nif > CO_WTM_MAX_NIF))
1193 continue;
1194 // Update the CAN interface timer.
1195 struct timespec *tp = NULL;
1196 if (dlc & 0x40) {
1197 tp = &wtm->can[nif - 1].recv_time;
1198 timespec_add_usec(tp, ts * 100);
1199 }
1200 // Invoke the user-specified callback function.
1201 if (wtm->recv_func) {
1202 int errc = get_errc();
1203 // clang-format off
1204 if (__unlikely(wtm->recv_func(wtm, nif, tp, &msg,
1205 wtm->recv_data))) {
1206 // clang-format on
1207 // Convert the error number to a WTM abort code.
1208 if (!ac) {
1209 ac = get_errnum() == ERRNUM_NOMEM
1212 }
1213 set_errc(errc);
1214 }
1215 }
1216 }
1217
1218error:
1219 return ac;
1220}
1221
1222#endif // !LELY_NO_CO_WTM
This header file is part of the CANopen library; it contains the Cyclic Redundancy Check (CRC) declar...
uint16_t co_crc(uint16_t crc, const void *ptr, size_t n)
Computes a CRC-16 checksum.
Definition: crc.c:28
This header file is part of the utilities library; it contains the diagnostic declarations.
@ DIAG_WARNING
A warning.
Definition: diag.h:47
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
This header file is part of the utilities library; it contains the byte order (endianness) function d...
void stle_u16(void *ptr, uint_least16_t x)
Stores a 16-bit unsigned integer in little-endian byte order.
Definition: endian.h:480
void stle_u32(void *ptr, uint_least32_t x)
Stores a 32-bit unsigned integer in little-endian byte order.
Definition: endian.h:534
uint_least32_t ldle_u32(const void *ptr)
Loads a 32-bit unsigned integer in little-endian byte order.
Definition: endian.h:541
uint_least16_t ldle_u16(const void *ptr)
Loads a 16-bit unsigned integer in little-endian byte order.
Definition: endian.h:487
@ ERRNUM_NOSYS
Function not supported.
Definition: errnum.h:181
@ ERRNUM_NOMEM
Not enough space.
Definition: errnum.h:169
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:129
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
errnum_t get_errnum(void)
Returns the last (thread-specific) platform-independent error number set by a system call or library ...
Definition: errnum.h:369
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
@ CAN_STATE_BUSOFF
The bus off state (TX/RX error count >= 256).
Definition: can.h:33
@ CAN_STATE_PASSIVE
The error passive state (TX/RX error count < 256).
Definition: can.h:31
@ CAN_STATE_ACTIVE
The error active state (TX/RX error count < 128).
Definition: can.h:29
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
#define MAX(a, b)
Returns the maximum of a and b.
Definition: util.h:65
#define CAN_MASK_EID
The mask used to extract the 29-bit Extended Identifier from a CAN frame.
Definition: msg.h:34
#define CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames).
Definition: msg.h:47
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition: msg.h:73
#define CAN_FLAG_IDE
The Identifier Extension (IDE) flag.
Definition: msg.h:41
#define CAN_MASK_BID
The mask used to extract the 11-bit Base Identifier from a CAN frame.
Definition: msg.h:31
#define CAN_MSG_INIT
The static initializer for can_msg.
Definition: msg.h:114
#define CAN_FLAG_EDL
The Extended Data Length (EDL) flag.
Definition: msg.h:55
This is the internal header file of the CANopen library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
This header file is part of the C11 and POSIX compatibility library; it includes <string....
A CANopen Wireless Transmission Media (WTM) interface.
Definition: wtm.c:87
co_wtm_diag_can_ind_t * diag_can_ind
A pointer to the indication function invoked when a CAN communication quality reset message is receiv...
Definition: wtm.c:115
uint8_t send_nseq
The sequence number for sent generic frames.
Definition: wtm.c:151
size_t send_nbytes
The number of bytes in send_buf.
Definition: wtm.c:149
void * diag_wtm_con_data
A pointer to the user-specified data for diag_wtm_con.
Definition: wtm.c:110
uint8_t nif
The WTM interface indicator.
Definition: wtm.c:89
co_wtm_diag_ac_ind_t * diag_ac_ind
A pointer to the callback function invoked when an abort code is generated or received.
Definition: wtm.c:129
co_wtm_diag_can_con_t * diag_can_con
A pointer to the confirmation function invoked when a CAN communication quality response is received.
Definition: wtm.c:101
struct co_wtm_can can[CO_WTM_MAX_NIF]
The CAN interfaces.
Definition: wtm.c:96
uint8_t recv_buf[CO_WTM_MAX_LEN]
The buffer used to receive byte streams.
Definition: wtm.c:141
void * diag_ac_data
A pointer to the user-specified data for diag_ac_ind.
Definition: wtm.c:131
uint8_t recv_nseq
The sequence number for received generic frames.
Definition: wtm.c:145
void * recv_data
A pointer to the user-specified data for recv_func.
Definition: wtm.c:135
size_t recv_nbytes
The number of bytes in recv_buf.
Definition: wtm.c:143
void * diag_can_ind_data
A pointer to the user-specified data for diag_can_ind.
Definition: wtm.c:117
co_wtm_recv_func_t * recv_func
A pointer to the callback function invoked by co_wtm_recv().
Definition: wtm.c:133
co_wtm_diag_wtm_con_t * diag_wtm_con
A pointer to the confirmation function invoked when a WTM communication quality response is received.
Definition: wtm.c:108
uint8_t send_buf[CO_WTM_MAX_LEN]
The buffer used to send byte streams.
Definition: wtm.c:147
void * send_data
A pointer to the user-specified data for send_func.
Definition: wtm.c:139
co_wtm_diag_wtm_ind_t * diag_wtm_ind
A pointer to the indication function invoked when a WTM communication quality reset message is receiv...
Definition: wtm.c:122
co_wtm_send_func_t * send_func
A pointer to the callback function invoked by co_wtm_send().
Definition: wtm.c:137
uint8_t quality
The link quality percentage (in the range [0..100], or 0xff if the information is not available).
Definition: wtm.c:94
void * diag_wtm_ind_data
A pointer to the user-specified data for diag_wtm_ind.
Definition: wtm.c:124
void * diag_can_con_data
A pointer to the user-specified data for diag_can_con.
Definition: wtm.c:103
A CAN or CAN FD format frame.
Definition: msg.h:88
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition: msg.h:103
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition: msg.h:90
uint_least8_t flags
The flags (any combination of CAN_FLAG_IDE, CAN_FLAG_RTR, CAN_FLAG_EDL, CAN_FLAG_BRS and CAN_FLAG_ESI...
Definition: msg.h:95
uint_least8_t len
The number of bytes in data (or the requested number of bytes in case of a remote frame).
Definition: msg.h:101
A CAN device.
Definition: can.c:53
A CANopen WTM CAN interface.
Definition: wtm.c:43
uint8_t st
The current CAN controller status (one of CAN_STATE_ACTIVE, CAN_STATE_PASSIVE or CAN_STATE_BUSOFF,...
Definition: wtm.c:49
uint16_t coc
The CAN controller overrun counter (in the range [0..0xfffe], or 0xffff if the information is not ava...
Definition: wtm.c:77
struct timespec send_time
The current time of the CAN frame sender.
Definition: wtm.c:81
uint16_t foc
The FIFO overrun counter (in the range [0..0xfffe], or 0xffff if the information is not available).
Definition: wtm.c:72
struct timespec recv_time
The current time of the CAN frame receiver.
Definition: wtm.c:79
struct timespec send_next
The time at which the next frame is sent.
Definition: wtm.c:83
uint16_t ec
The number of detected errors that led to the increase of one of the CAN controller internal error co...
Definition: wtm.c:67
uint8_t load
The current busload percentage (in the range [0..100], or 0xff if the information is not available).
Definition: wtm.c:61
uint8_t err
The last detected error (0 if no error was detected, one of CAN_ERROR_BIT, CAN_ERROR_STUFF,...
Definition: wtm.c:56
A time type with nanosecond resolution.
Definition: time.h:83
This header file is part of the utilities library; it contains the time function declarations.
void timespec_add_usec(struct timespec *tp, uint_least64_t usec)
Adds usec microseconds to the time at tp.
Definition: time.h:138
int_least64_t timespec_diff_usec(const struct timespec *t1, const struct timespec *t2)
Returns the time difference (in microseconds) between *t1 and *t2.
Definition: time.h:210
void co_wtm_get_diag_ac_ind(const co_wtm_t *wtm, co_wtm_diag_ac_ind_t **pind, void **pdata)
Retrieves the indication function invoked when an abort code is generated or received by a CANopen WT...
Definition: wtm.c:493
void co_wtm_get_diag_can_ind(const co_wtm_t *wtm, co_wtm_diag_can_ind_t **pcon, void **pdata)
Retrieves the indication function invoked when a CAN communication quality reset message is received ...
Definition: wtm.c:451
const char * co_wtm_ac_str(uint32_t ac)
Returns a string describing a CANopen WTM abort code.
Definition: wtm.c:178
void co_wtm_set_diag_wtm_ind(co_wtm_t *wtm, co_wtm_diag_wtm_ind_t *con, void *data)
Sets the indication function invoked when a WTM communication quality reset message is received by a ...
Definition: wtm.c:484
int co_wtm_set_time(co_wtm_t *wtm, uint8_t nif, const struct timespec *tp)
Sets the current time of a CANopen WTM interface.
Definition: wtm.c:802
int co_wtm_send_diag_can_req(co_wtm_t *wtm, uint8_t nif)
Sends a CAN communication quality request.
Definition: wtm.c:931
void co_wtm_destroy(co_wtm_t *wtm)
Destroys a CANopen Wireless Transmission Media (WTM) interface.
Definition: wtm.c:312
int co_wtm_send_alive(co_wtm_t *wtm)
Sends a keep-alive message from a CANopen WTM interface.
Definition: wtm.c:917
void co_wtm_get_diag_wtm_con(const co_wtm_t *wtm, co_wtm_diag_wtm_con_t **pcon, void **pdata)
Retrieves the confirmation function invoked when a WTM communication quality response is received by ...
Definition: wtm.c:430
void co_wtm_get_diag_wtm_ind(const co_wtm_t *wtm, co_wtm_diag_wtm_ind_t **pcon, void **pdata)
Retrieves the indication function invoked when a WTM communication quality reset message is received ...
Definition: wtm.c:472
int co_wtm_send_diag_wtm_rst(co_wtm_t *wtm, uint8_t nif)
Sends a WTM communication quality reset message.
Definition: wtm.c:985
void co_wtm_set_diag_can_ind(co_wtm_t *wtm, co_wtm_diag_can_ind_t *con, void *data)
Sets the indication function invoked when a CAN communication quality reset message is received by a ...
Definition: wtm.c:463
co_wtm_t * co_wtm_create(void)
Creates a new CANopen Wireless Transmission Media (WTM) interface.
Definition: wtm.c:287
void co_wtm_set_diag_ac_ind(co_wtm_t *wtm, co_wtm_diag_ac_ind_t *ind, void *data)
Sets the indication function invoked when an abort code is generated or received by a CANopen WTM int...
Definition: wtm.c:505
void co_wtm_set_recv_func(co_wtm_t *wtm, co_wtm_recv_func_t *func, void *data)
Sets the callback function invoked when a CAN frame is received by a CANopen WTM interface.
Definition: wtm.c:777
static int co_wtm_send_diag_wtm_res(co_wtm_t *wtm)
Sends a communication quality response for a WTM interface.
Definition: wtm.c:1089
int co_wtm_set_diag_can(co_wtm_t *wtm, uint8_t nif, uint8_t st, uint8_t err, uint8_t load, uint16_t ec, uint16_t foc, uint16_t coc)
Sets the diagnostic parameters of a CAN interface.
Definition: wtm.c:344
void co_wtm_set_send_func(co_wtm_t *wtm, co_wtm_send_func_t *func, void *data)
Sets the callback function used to send byte streams from a CANopen WTM interface.
Definition: wtm.c:1060
static uint32_t co_wtm_recv_can(co_wtm_t *wtm, const void *buf, size_t nbytes)
Processes a generic frame containing CAN messages.
Definition: wtm.c:1122
void co_wtm_recv(co_wtm_t *wtm, const void *buf, size_t nbytes)
Receives and processes a byte stream with a CANopen WTM interface.
Definition: wtm.c:514
int co_wtm_send(co_wtm_t *wtm, uint8_t nif, const struct can_msg *msg)
Sends a CAN frame from a CANopen WTM interface.
Definition: wtm.c:836
static int co_wtm_send_diag_can_res(co_wtm_t *wtm, uint8_t nif)
Sends a communication quality response for a CAN interface.
Definition: wtm.c:1069
int co_wtm_send_diag_ac(co_wtm_t *wtm, uint32_t ac)
Sends a diagnostic abort message from a CANopen WTM interface.
Definition: wtm.c:1003
int co_wtm_get_time(const co_wtm_t *wtm, uint8_t nif, struct timespec *tp)
Retrieves the current time of a CANopen WTM interface.
Definition: wtm.c:786
#define CO_WTM_MAX_NIF
The maximum value of a CAN/WTM interface indicator.
Definition: wtm.c:40
static void co_wtm_diag_ac(co_wtm_t *wtm, uint32_t ac)
Invokes the diagnostic indication function.
Definition: wtm.c:1103
static void default_wtm_diag_ac_ind(co_wtm_t *wtm, uint32_t ac, void *data)
The default diagnostic indication function.
Definition: wtm.c:1112
void co_wtm_get_diag_can_con(const co_wtm_t *wtm, co_wtm_diag_can_con_t **pcon, void **pdata)
Retrieves the confirmation function invoked when a CAN communication quality response is received by ...
Definition: wtm.c:409
void co_wtm_get_recv_func(const co_wtm_t *wtm, co_wtm_recv_func_t **pfunc, void **pdata)
Retrieves the callback function invoked when a CAN frame is received by a CANopen WTM interface.
Definition: wtm.c:765
int co_wtm_set_nif(co_wtm_t *wtm, uint8_t nif)
Sets the interface indicator of a CANopen WTM interface.
Definition: wtm.c:329
int co_wtm_send_diag_wtm_req(co_wtm_t *wtm, uint8_t nif)
Sends a WTM communication quality request.
Definition: wtm.c:949
int co_wtm_flush(co_wtm_t *wtm)
Flushes the current send buffer of a CANopen WTM interface.
Definition: wtm.c:1018
void co_wtm_set_diag_can_con(co_wtm_t *wtm, co_wtm_diag_can_con_t *con, void *data)
Sets the confirmation function invoked when a CAN communication quality response is received by a CAN...
Definition: wtm.c:421
void co_wtm_get_send_func(const co_wtm_t *wtm, co_wtm_send_func_t **pfunc, void **pdata)
Retrieves the callback function used to send byte streams from a CANopen WTM interface.
Definition: wtm.c:1048
int co_wtm_send_diag_can_rst(co_wtm_t *wtm, uint8_t nif)
Sends a CAN communication quality reset message.
Definition: wtm.c:967
uint8_t co_wtm_get_nif(const co_wtm_t *wtm)
Returns the interface indicator of a CANopen WTM interface.
Definition: wtm.c:321
int co_wtm_set_diag_wtm(co_wtm_t *wtm, uint8_t quality)
Sets the diagnostic parameters of a WTM interface.
Definition: wtm.c:394
void co_wtm_set_diag_wtm_con(co_wtm_t *wtm, co_wtm_diag_wtm_con_t *con, void *data)
Sets the confirmation function invoked when a WTM communication quality response is received by a CAN...
Definition: wtm.c:442
This header file is part of the CANopen library; it contains the Wireless Transmission Media (WTM) de...
#define CO_WTM_AC_DATA_CTL
CANopen WTM abort code: Data cannot be transferred or stored to the application because of local cont...
Definition: wtm.h:57
#define CO_WTM_AC_DATA
CANopen WTM abort code: Data cannot be transferred or stored to the application.
Definition: wtm.h:51
void co_wtm_diag_wtm_ind_t(co_wtm_t *wtm, void *data)
The type of a CANopen WTM diagnostic indication function, invoked when a WTM communication quality re...
Definition: wtm.h:178
void co_wtm_diag_can_con_t(co_wtm_t *wtm, uint8_t nif, uint8_t st, uint8_t err, uint8_t load, uint16_t ec, uint16_t foc, uint16_t coc, void *data)
The type of a CANopen WTM diagnostic confirmation function, invoked when a CAN communication quality ...
Definition: wtm.h:144
#define CO_WTM_AC_TYPE
CANopen WTM abort code: Message type not valid or unknown.
Definition: wtm.h:99
#define CO_WTM_AC_DATA_DEV
CANopen WTM abort code: Data cannot be transferred or stored to the application because of the presen...
Definition: wtm.h:63
#define CO_WTM_AC_DIAG_CAN
CANopen WTM abort code: Diagnostic data generation for requested CAN interface not supported.
Definition: wtm.h:81
#define CO_WTM_AC_DIAG
CANopen WTM abort code: Diagnostic data generation not supported.
Definition: wtm.h:75
#define CO_WTM_AC_DIAG_WTM
CANopen WTM abort code: Diagnostic data generation for requested WTM interface not supported.
Definition: wtm.h:87
int co_wtm_send_func_t(co_wtm_t *wtm, const void *buf, size_t nbytes, void *data)
The type of a CANopen WTM send callback function, invoked when a byte stream needs to be sent.
Definition: wtm.h:220
#define CO_WTM_AC_HARDWARE
CANopen WTM abort code: Access failed due to a hardware error.
Definition: wtm.h:45
#define CO_WTM_AC_NO_DATA
CANopen WTM abort code: No data available.
Definition: wtm.h:66
#define CO_WTM_AC_IF_DOWN
CANopen WTM abort code: Requested interface disabled.
Definition: wtm.h:72
#define CO_WTM_AC_NO_IF
CANopen WTM abort code: Requested interface not implemented.
Definition: wtm.h:69
#define CO_WTM_AC_ERROR
CANopen WTM abort code: General error.
Definition: wtm.h:36
#define CO_WTM_AC_PREAMBLE
CANopen WTM abort code: Invalid generic frame preamble.
Definition: wtm.h:93
void co_wtm_diag_ac_ind_t(co_wtm_t *wtm, uint32_t ac, void *data)
The type of a CANopen WTM diagnostic indication function, invoked when an abort code is generated or ...
Definition: wtm.h:188
#define CO_WTM_AC_SEQ
CANopen WTM abort code: Invalid sequence counter in generic frame.
Definition: wtm.h:96
#define CO_WTM_AC_NO_MEM
CANopen WTM abort code: Out of memory.
Definition: wtm.h:42
#define CO_WTM_AC_CRC
CANopen WTM abort code: CRC error (Generic frame).
Definition: wtm.h:105
#define CO_WTM_AC_CAN
CANopen WTM abort code: CAN telegram essentials invalid.
Definition: wtm.h:108
int co_wtm_recv_func_t(co_wtm_t *wtm, uint8_t nif, const struct timespec *tp, const struct can_msg *msg, void *data)
The type of a CANopen WTM receive callback function, invoked when a CAN frame is received.
Definition: wtm.h:204
#define CO_WTM_AC_TIMEOUT
CANopen WTM abort code: Diagnostic protocol timed out limit reached.
Definition: wtm.h:39
void co_wtm_diag_wtm_con_t(co_wtm_t *wtm, uint8_t nif, uint8_t quality, void *data)
The type of a CANopen WTM diagnostic confirmation function, invoked when a WTM communication quality ...
Definition: wtm.h:158
#define CO_WTM_AC_FRAME
CANopen WTM abort code: General generic frame error.
Definition: wtm.h:90
void co_wtm_diag_can_ind_t(co_wtm_t *wtm, uint8_t nif, void *data)
The type of a CANopen WTM diagnostic indication function, invoked when a CAN communication quality re...
Definition: wtm.h:169
#define CO_WTM_AC_PAYLOAD
CANopen WTM abort code: Payload field in generic frame invalid.
Definition: wtm.h:102
#define CO_WTM_MAX_LEN
The maximum size of a CANopen WTM generic frame (4 (header) + 255 (payload) + 2 (CRC checksum) = 261)...
Definition: wtm.h:33