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