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