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