Lely core libraries  1.9.2
rpdo.c
Go to the documentation of this file.
1 
24 #include "co.h"
25 
26 #ifndef LELY_NO_CO_RPDO
27 
28 #include <lely/co/dev.h>
29 #include <lely/co/obj.h>
30 #include <lely/co/rpdo.h>
31 #include <lely/co/sdo.h>
32 #include <lely/co/val.h>
33 #include <lely/util/errnum.h>
34 
35 #include <assert.h>
36 #include <inttypes.h>
37 #include <stdlib.h>
38 
40 struct __co_rpdo {
46  co_unsigned16_t num;
58  unsigned int sync : 1;
60  unsigned int swnd : 1;
62  struct can_msg msg;
64  struct co_sdo_req req;
68  void *ind_data;
72  void *err_data;
73 };
74 
82 static int co_rpdo_init_recv(co_rpdo_t *pdo);
83 
90 static int co_rpdo_init_timer_event(co_rpdo_t *pdo);
91 
99 static int co_rpdo_init_timer_swnd(co_rpdo_t *pdo);
100 
107 static co_unsigned32_t co_1400_dn_ind(
108  co_sub_t *sub, struct co_sdo_req *req, void *data);
109 
116 static co_unsigned32_t co_1600_dn_ind(
117  co_sub_t *sub, struct co_sdo_req *req, void *data);
118 
124 static int co_rpdo_recv(const struct can_msg *msg, void *data);
125 
132 static int co_rpdo_timer_event(const struct timespec *tp, void *data);
133 
140 static int co_rpdo_timer_swnd(const struct timespec *tp, void *data);
141 
151 static co_unsigned32_t co_rpdo_read_frame(
152  co_rpdo_t *pdo, const struct can_msg *msg);
153 
154 void *
155 __co_rpdo_alloc(void)
156 {
157  void *ptr = malloc(sizeof(struct __co_rpdo));
158  if (__unlikely(!ptr))
159  set_errc(errno2c(errno));
160  return ptr;
161 }
162 
163 void
164 __co_rpdo_free(void *ptr)
165 {
166  free(ptr);
167 }
168 
169 struct __co_rpdo *
170 __co_rpdo_init(struct __co_rpdo *pdo, can_net_t *net, co_dev_t *dev,
171  co_unsigned16_t num)
172 {
173  assert(pdo);
174  assert(net);
175  assert(dev);
176 
177  int errc = 0;
178 
179  if (__unlikely(!num || num > 512)) {
180  errc = errnum2c(ERRNUM_INVAL);
181  goto error_param;
182  }
183 
184  // Find the PDO parameters in the object dictionary.
185  co_obj_t *obj_1400 = co_dev_find_obj(dev, 0x1400 + num - 1);
186  co_obj_t *obj_1600 = co_dev_find_obj(dev, 0x1600 + num - 1);
187  if (__unlikely(!obj_1400 || !obj_1600)) {
188  errc = errnum2c(ERRNUM_INVAL);
189  goto error_param;
190  }
191 
192  pdo->net = net;
193  pdo->dev = dev;
194  pdo->num = num;
195 
196  // Copy the PDO communication parameter record.
197  memset(&pdo->comm, 0, sizeof(pdo->comm));
198  memcpy(&pdo->comm, co_obj_addressof_val(obj_1400),
199  MIN(co_obj_sizeof_val(obj_1400), sizeof(pdo->comm)));
200 
201  // Copy the PDO mapping parameter record.
202  memset(&pdo->map, 0, sizeof(pdo->map));
203  memcpy(&pdo->map, co_obj_addressof_val(obj_1600),
204  MIN(co_obj_sizeof_val(obj_1600), sizeof(pdo->map)));
205 
206  pdo->recv = NULL;
207 
208  pdo->timer_event = NULL;
209  pdo->timer_swnd = NULL;
210 
211  pdo->sync = 0;
212  pdo->swnd = 0;
213  pdo->msg = (struct can_msg)CAN_MSG_INIT;
214 
215  co_sdo_req_init(&pdo->req);
216 
217  pdo->ind = NULL;
218  pdo->ind_data = NULL;
219  pdo->err = NULL;
220  pdo->err_data = NULL;
221 
222  // Set the download indication functions PDO communication parameter
223  // record.
224  co_obj_set_dn_ind(obj_1400, &co_1400_dn_ind, pdo);
225 
226  // Set the download indication functions PDO mapping parameter record.
227  co_obj_set_dn_ind(obj_1600, &co_1600_dn_ind, pdo);
228 
229  if (__unlikely(co_rpdo_init_recv(pdo) == -1)) {
230  errc = get_errc();
231  goto error_init_recv;
232  }
233 
234  if (__unlikely(co_rpdo_init_timer_swnd(pdo) == -1)) {
235  errc = get_errc();
236  goto error_init_timer_swnd;
237  }
238 
239  return pdo;
240 
241 error_init_timer_swnd:
242  can_recv_destroy(pdo->recv);
243 error_init_recv:
244  co_obj_set_dn_ind(obj_1600, NULL, NULL);
245  co_obj_set_dn_ind(obj_1400, NULL, NULL);
246 error_param:
247  set_errc(errc);
248  return NULL;
249 }
250 
251 void
252 __co_rpdo_fini(struct __co_rpdo *pdo)
253 {
254  assert(pdo);
255  assert(pdo->num >= 1 && pdo->num <= 512);
256 
257  // Remove the download indication functions PDO mapping parameter
258  // record.
259  co_obj_t *obj_1600 = co_dev_find_obj(pdo->dev, 0x1600 + pdo->num - 1);
260  assert(obj_1600);
261  co_obj_set_dn_ind(obj_1600, NULL, NULL);
262 
263  // Remove the download indication functions PDO communication parameter
264  // record.
265  co_obj_t *obj_1400 = co_dev_find_obj(pdo->dev, 0x1400 + pdo->num - 1);
266  assert(obj_1400);
267  co_obj_set_dn_ind(obj_1400, NULL, NULL);
268 
269  co_sdo_req_fini(&pdo->req);
270 
273 
274  can_recv_destroy(pdo->recv);
275 }
276 
277 co_rpdo_t *
278 co_rpdo_create(can_net_t *net, co_dev_t *dev, co_unsigned16_t num)
279 {
280  trace("creating Receive-PDO %d", num);
281 
282  int errc = 0;
283 
284  co_rpdo_t *pdo = __co_rpdo_alloc();
285  if (__unlikely(!pdo)) {
286  errc = get_errc();
287  goto error_alloc_pdo;
288  }
289 
290  if (__unlikely(!__co_rpdo_init(pdo, net, dev, num))) {
291  errc = get_errc();
292  goto error_init_pdo;
293  }
294 
295  return pdo;
296 
297 error_init_pdo:
298  __co_rpdo_free(pdo);
299 error_alloc_pdo:
300  set_errc(errc);
301  return NULL;
302 }
303 
304 void
306 {
307  if (rpdo) {
308  trace("destroying Receive-PDO %d", rpdo->num);
309  __co_rpdo_fini(rpdo);
310  __co_rpdo_free(rpdo);
311  }
312 }
313 
314 can_net_t *
316 {
317  assert(pdo);
318 
319  return pdo->net;
320 }
321 
322 co_dev_t *
324 {
325  assert(pdo);
326 
327  return pdo->dev;
328 }
329 
330 co_unsigned16_t
332 {
333  assert(pdo);
334 
335  return pdo->num;
336 }
337 
338 const struct co_pdo_comm_par *
340 {
341  assert(pdo);
342 
343  return &pdo->comm;
344 }
345 
346 const struct co_pdo_map_par *
348 {
349  assert(pdo);
350 
351  return &pdo->map;
352 }
353 
354 void
355 co_rpdo_get_ind(const co_rpdo_t *pdo, co_rpdo_ind_t **pind, void **pdata)
356 {
357  assert(pdo);
358 
359  if (pind)
360  *pind = pdo->ind;
361  if (pdata)
362  *pdata = pdo->ind_data;
363 }
364 
365 void
366 co_rpdo_set_ind(co_rpdo_t *pdo, co_rpdo_ind_t *ind, void *data)
367 {
368  assert(pdo);
369 
370  pdo->ind = ind;
371  pdo->ind_data = data;
372 }
373 
374 void
375 co_rpdo_get_err(const co_rpdo_t *pdo, co_rpdo_err_t **perr, void **pdata)
376 {
377  assert(pdo);
378 
379  if (perr)
380  *perr = pdo->err;
381  if (pdata)
382  *pdata = pdo->err_data;
383 }
384 
385 void
386 co_rpdo_set_err(co_rpdo_t *pdo, co_rpdo_err_t *err, void *data)
387 {
388  assert(pdo);
389 
390  pdo->err = err;
391  pdo->err_data = data;
392 }
393 
394 int
396 {
397  assert(pdo);
398 
399  // Check whether the PDO exists and is valid.
400  if (pdo->comm.cobid & CO_PDO_COBID_VALID)
401  return 0;
402 
403  struct can_msg msg = CAN_MSG_INIT;
404  msg.id = pdo->comm.cobid;
405  if (pdo->comm.cobid & CO_PDO_COBID_FRAME) {
406  msg.id &= CAN_MASK_EID;
407  msg.flags |= CAN_FLAG_IDE;
408  } else {
409  msg.id &= CAN_MASK_BID;
410  }
411  msg.flags |= CAN_FLAG_RTR;
412  return can_net_send(pdo->net, &msg);
413 }
414 
415 int
416 co_rpdo_sync(co_rpdo_t *pdo, co_unsigned8_t cnt)
417 {
418  assert(pdo);
419 
420  if (__unlikely(cnt > 240)) {
422  return -1;
423  }
424 
425  // Ignore SYNC objects if the transmission type is not synchronous.
426  if (pdo->comm.trans > 0xf0)
427  return 0;
428 
429  // Reset the time window for synchronous PDOs.
430  pdo->swnd = 0;
432 
433  // Check if we have a CAN frame waiting for a SYNC object.
434  if (!pdo->sync)
435  return 0;
436  pdo->sync = 0;
437 
438  return co_rpdo_read_frame(pdo, &pdo->msg) ? -1 : 0;
439 }
440 
441 static int
443 {
444  assert(pdo);
445 
446  if (!(pdo->comm.cobid & CO_PDO_COBID_VALID)) {
447  if (!pdo->recv) {
448  pdo->recv = can_recv_create();
449  if (__unlikely(!pdo->recv))
450  return -1;
451  can_recv_set_func(pdo->recv, co_rpdo_recv, pdo);
452  }
453  // Register the receiver under the specified CAN-ID.
454  uint32_t id = pdo->comm.cobid;
455  uint8_t flags = 0;
456  if (id & CO_PDO_COBID_FRAME) {
457  id &= CAN_MASK_EID;
458  flags |= CAN_FLAG_IDE;
459  } else {
460  id &= CAN_MASK_BID;
461  }
462  can_recv_start(pdo->recv, pdo->net, id, flags);
463  } else if (pdo->recv) {
464  can_recv_destroy(pdo->recv);
465  pdo->recv = NULL;
466  }
467 
468  return 0;
469 }
470 
471 static int
473 {
474  assert(pdo);
475 
476  if (!(pdo->comm.cobid & CO_PDO_COBID_VALID) && pdo->comm.event) {
477  if (!pdo->timer_event) {
478  pdo->timer_event = can_timer_create();
479  if (__unlikely(!pdo->timer_event))
480  return -1;
482  co_rpdo_timer_event, pdo);
483  }
484  can_timer_timeout(pdo->timer_event, pdo->net, pdo->comm.event);
485  } else if (pdo->timer_event) {
487  pdo->timer_event = NULL;
488  }
489 
490  return 0;
491 }
492 
493 static int
495 {
496  assert(pdo);
497 
498  // Ignore the synchronous window length unless the RPDO is valid and
499  // synchronous.
500  co_unsigned32_t swnd = co_dev_get_val_u32(pdo->dev, 0x1007, 0x00);
501  if (!(pdo->comm.cobid & CO_PDO_COBID_VALID) && pdo->comm.trans <= 0xf0
502  && swnd) {
503  if (!pdo->timer_swnd) {
504  pdo->timer_swnd = can_timer_create();
505  if (__unlikely(!pdo->timer_swnd))
506  return -1;
508  pdo);
509  }
510  can_timer_timeout(pdo->timer_swnd, pdo->net, swnd);
511  } else if (pdo->timer_swnd) {
513  pdo->timer_swnd = NULL;
514  }
515 
516  return 0;
517 }
518 
519 static co_unsigned32_t
520 co_1400_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
521 {
522  assert(sub);
523  assert(req);
524  co_rpdo_t *pdo = data;
525  assert(pdo);
526  assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1400 + pdo->num - 1);
527 
528  co_unsigned32_t ac = 0;
529 
530  co_unsigned16_t type = co_sub_get_type(sub);
531  union co_val val;
532  if (__unlikely(co_sdo_req_dn_val(req, type, &val, &ac) == -1))
533  return ac;
534 
535  switch (co_sub_get_subidx(sub)) {
536  case 0: ac = CO_SDO_AC_NO_WRITE; goto error;
537  case 1: {
538  assert(type == CO_DEFTYPE_UNSIGNED32);
539  co_unsigned32_t cobid = val.u32;
540  co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
541  if (cobid == cobid_old)
542  goto error;
543 
544  // The CAN-ID cannot be changed when the PDO is and remains
545  // valid.
546  int valid = !(cobid & CO_PDO_COBID_VALID);
547  int valid_old = !(cobid_old & CO_PDO_COBID_VALID);
548  uint32_t canid = cobid & CAN_MASK_EID;
549  uint32_t canid_old = cobid_old & CAN_MASK_EID;
550  if (__unlikely(valid && valid_old && canid != canid_old)) {
551  ac = CO_SDO_AC_PARAM_VAL;
552  goto error;
553  }
554 
555  // A 29-bit CAN-ID is only valid if the frame bit is set.
556  // clang-format off
557  if (__unlikely(!(cobid & CO_PDO_COBID_FRAME)
558  && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))) {
559  // clang-format on
560  ac = CO_SDO_AC_PARAM_VAL;
561  goto error;
562  }
563 
564  pdo->comm.cobid = cobid;
565 
566  pdo->sync = 0;
567  pdo->swnd = 0;
568 
569  co_rpdo_init_recv(pdo);
571  break;
572  }
573  case 2: {
574  assert(type == CO_DEFTYPE_UNSIGNED8);
575  co_unsigned8_t trans = val.u8;
576  co_unsigned8_t trans_old = co_sub_get_val_u8(sub);
577  if (trans == trans_old)
578  goto error;
579 
580  // Transmission types 0xF1..0xFD are reserved.
581  if (__unlikely(trans > 0xf0 && trans < 0xfe)) {
582  ac = CO_SDO_AC_PARAM_VAL;
583  goto error;
584  }
585 
586  pdo->comm.trans = trans;
587 
588  pdo->swnd = 0;
589 
591  break;
592  }
593  case 3: {
594  assert(type == CO_DEFTYPE_UNSIGNED16);
595  co_unsigned16_t inhibit = val.u16;
596  co_unsigned16_t inhibit_old = co_sub_get_val_u16(sub);
597  if (inhibit == inhibit_old)
598  goto error;
599 
600  // The inhibit time cannot be changed while the PDO exists and
601  // is valid.
602  if (__unlikely(!(pdo->comm.cobid & CO_PDO_COBID_VALID))) {
603  ac = CO_SDO_AC_PARAM_VAL;
604  goto error;
605  }
606 
607  pdo->comm.inhibit = inhibit;
608  break;
609  }
610  case 5: {
611  assert(type == CO_DEFTYPE_UNSIGNED16);
612  co_unsigned16_t event = val.u16;
613  co_unsigned16_t event_old = co_sub_get_val_u16(sub);
614  if (event == event_old)
615  goto error;
616 
617  pdo->comm.event = event;
618  break;
619  }
620  default: ac = CO_SDO_AC_NO_SUB; goto error;
621  }
622 
623  co_sub_dn(sub, &val);
624 error:
625  co_val_fini(type, &val);
626  return ac;
627 }
628 
629 static co_unsigned32_t
630 co_1600_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
631 {
632  assert(sub);
633  assert(req);
634  co_rpdo_t *pdo = data;
635  assert(pdo);
636  assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1600 + pdo->num - 1);
637 
638  co_unsigned32_t ac = 0;
639 
640  co_unsigned16_t type = co_sub_get_type(sub);
641  union co_val val;
642  if (__unlikely(co_sdo_req_dn_val(req, type, &val, &ac) == -1))
643  return ac;
644 
645  int valid = !(pdo->comm.cobid & CO_PDO_COBID_VALID);
646 
647  if (!co_sub_get_subidx(sub)) {
648  assert(type == CO_DEFTYPE_UNSIGNED8);
649  co_unsigned8_t n = val.u8;
650  co_unsigned8_t n_old = co_sub_get_val_u8(sub);
651  if (n == n_old)
652  goto error;
653 
654  // The PDO mapping cannot be changed when the PDO is valid.
655  if (__unlikely(valid || n > 0x40)) {
656  ac = CO_SDO_AC_PARAM_VAL;
657  goto error;
658  }
659 
660  size_t bits = 0;
661  for (size_t i = 1; i <= n; i++) {
662  co_unsigned32_t map = pdo->map.map[i - 1];
663  co_unsigned16_t idx = (map >> 16) & 0xffff;
664  co_unsigned8_t subidx = (map >> 8) & 0xff;
665  co_unsigned8_t len = map & 0xff;
666 
667  // Check the PDO length.
668  if (__unlikely((bits += len) > CAN_MAX_LEN * 8)) {
669  ac = CO_SDO_AC_PDO_LEN;
670  goto error;
671  }
672 
673  // Check whether the sub-object exists and can be mapped
674  // into a PDO (or is a valid dummy entry).
675  ac = co_dev_chk_rpdo(pdo->dev, idx, subidx);
676  if (__unlikely(ac))
677  goto error;
678  }
679 
680  pdo->map.n = n;
681  } else {
682  assert(type == CO_DEFTYPE_UNSIGNED32);
683  co_unsigned32_t map = val.u32;
684  co_unsigned32_t map_old = co_sub_get_val_u32(sub);
685  if (map == map_old)
686  goto error;
687 
688  // The PDO mapping cannot be changed when the PDO is valid or
689  // sub-index 0x00 is non-zero.
690  if (__unlikely(valid || pdo->map.n)) {
691  ac = CO_SDO_AC_PARAM_VAL;
692  goto error;
693  }
694 
695  co_unsigned16_t idx = (map >> 16) & 0xffff;
696  co_unsigned8_t subidx = (map >> 8) & 0xff;
697  // Check whether the sub-object exists and can be mapped into a
698  // PDO (or is a valid dummy entry).
699  ac = co_dev_chk_rpdo(pdo->dev, idx, subidx);
700  if (__unlikely(ac))
701  goto error;
702 
703  pdo->map.map[co_sub_get_subidx(sub) - 1] = map;
704  }
705 
706  co_sub_dn(sub, &val);
707 error:
708  co_val_fini(type, &val);
709  return ac;
710 }
711 
712 static int
713 co_rpdo_recv(const struct can_msg *msg, void *data)
714 {
715  assert(msg);
716  co_rpdo_t *pdo = data;
717  assert(pdo);
718 
719  // Ignore remote frames.
720  if (__unlikely(msg->flags & CAN_FLAG_RTR))
721  return 0;
722 
723 #ifndef LELY_NO_CANFD
724  // Ignore CAN FD format frames.
725  if (__unlikely(msg->flags & CAN_FLAG_EDL))
726  return 0;
727 #endif
728 
729  // Reset the event timer.
731 
732  if (pdo->comm.trans <= 0xf0) {
733  // In case of a synchronous RPDO, save the frame to be processed
734  // after the next SYNC object.
735  if (!pdo->swnd) {
736  pdo->sync = 1;
737  pdo->msg = *msg;
738  }
739  } else if (pdo->comm.trans >= 0xfe) {
740  // In case of an event-driven RPDO, process the frame directly.
741  co_rpdo_read_frame(pdo, msg);
742  }
743 
744  return 0;
745 }
746 
747 static int
748 co_rpdo_timer_event(const struct timespec *tp, void *data)
749 {
750  (void)tp;
751  co_rpdo_t *pdo = data;
752  assert(pdo);
753 
754  trace("RPDO %d: no PDO received in synchronous window", pdo->num);
755 
756  // Generate an error if an RPDO timeout occurred.
757  if (pdo->err)
758  pdo->err(pdo, 0x8250, 0x10, pdo->err_data);
759 
760  return 0;
761 }
762 
763 static int
764 co_rpdo_timer_swnd(const struct timespec *tp, void *data)
765 {
766  (void)tp;
767  co_rpdo_t *pdo = data;
768  assert(pdo);
769 
770  // The synchronous time window has expired.
771  pdo->swnd = 1;
772 
773  return 0;
774 }
775 
776 static co_unsigned32_t
777 co_rpdo_read_frame(co_rpdo_t *pdo, const struct can_msg *msg)
778 {
779  assert(pdo);
780  assert(msg);
781 
782  size_t n = MIN(msg->len, CAN_MAX_LEN);
783  co_unsigned32_t ac =
784  co_pdo_dn(&pdo->map, pdo->dev, &pdo->req, msg->data, n);
785 
786 #ifndef NDEBUG
787  if (ac)
788  trace("RPDO %d: PDO error %08" PRIX32 " (%s)", pdo->num, ac,
789  co_sdo_ac2str(ac));
790 #endif
791 
792  // Invoke the user-defined callback function.
793  if (pdo->ind)
794  pdo->ind(pdo, ac, msg->data, n, pdo->ind_data);
795 
796  if (pdo->err) {
797  if (ac == CO_SDO_AC_PDO_LEN) {
798  // Generate an error message if the PDO was not
799  // processed because too few bytes were available.
800  pdo->err(pdo, 0x8210, 0x10, pdo->err_data);
801  } else if (!ac) {
802  size_t offset = 0;
803  for (size_t i = 0; i < MIN(pdo->map.n, 0x40u); i++)
804  offset += (pdo->map.map[i]) & 0xff;
805  if (__unlikely((offset + 7) / 8 < n))
806  // Generate an error message if the PDO length
807  // exceeds the mapping.
808  pdo->err(pdo, 0x8220, 0x10, pdo->err_data);
809  }
810  }
811 
812  return ac;
813 }
814 
815 #endif // !LELY_NO_CO_RPDO
A CANopen SDO upload/download request.
Definition: sdo.h:178
A PDO mapping parameter record.
Definition: pdo.h:69
A CAN or CAN FD format frame.
Definition: msg.h:88
can_net_t * co_rpdo_get_net(const co_rpdo_t *pdo)
Returns a pointer to the CAN network of a Receive-PDO.
Definition: rpdo.c:315
void co_obj_set_dn_ind(co_obj_t *obj, co_sub_dn_ind_t *ind, void *data)
Sets the download indication function for a CANopen object.
Definition: obj.c:336
void * err_data
A pointer to user-specified data for err.
Definition: rpdo.c:72
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition: msg.h:90
size_t co_obj_sizeof_val(const co_obj_t *obj)
Returns size (in bytes) of the value of a CANopen object.
Definition: obj.c:281
A CAN network interface.
Definition: net.c:37
#define CAN_MASK_EID
The mask used to extract the 29-bit Extended Identifier from a CAN frame.
Definition: msg.h:34
can_timer_t * timer_swnd
A pointer to the CAN timer for the synchronous time window.
Definition: rpdo.c:56
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
unsigned int swnd
A flag indicating the synchronous time window has expired.
Definition: rpdo.c:60
A CANopen sub-object.
Definition: obj.h:54
A CANopen Receive-PDO.
Definition: rpdo.c:40
unsigned int sync
A flag indicating we&#39;re waiting for a SYNC object to process msg.
Definition: rpdo.c:58
void can_timer_timeout(can_timer_t *timer, can_net_t *net, int timeout)
Starts a CAN timer and registers it with a network interface.
Definition: net.c:484
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:825
void co_rpdo_err_t(co_rpdo_t *pdo, co_unsigned16_t eec, co_unsigned8_t er, void *data)
The type of a CANopen Receive-PDO error handling function, invoked in case of a timeout or length mis...
Definition: rpdo.h:56
#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
co_unsigned8_t n
Number of mapped objects in PDO.
Definition: pdo.h:71
#define CO_SDO_AC_PARAM_VAL
SDO abort code: Invalid value for parameter (download only).
Definition: sdo.h:135
A union of the CANopen static data types.
Definition: val.h:163
co_rpdo_err_t * err
A pointer to the error handling function.
Definition: rpdo.c:70
co_unsigned16_t co_rpdo_get_num(const co_rpdo_t *pdo)
Returns the PDO number of a Receive-PDO.
Definition: rpdo.c:331
A PDO communication parameter record.
Definition: pdo.h:43
const struct co_pdo_map_par * co_rpdo_get_map_par(const co_rpdo_t *pdo)
Returns a pointer to the PDO mapping parameter record of a Receive-PDO.
Definition: rpdo.c:347
void co_rpdo_set_ind(co_rpdo_t *pdo, co_rpdo_ind_t *ind, void *data)
Sets the indication function invoked when a Receive-PDO error occurs.
Definition: rpdo.c:366
co_rpdo_t * co_rpdo_create(can_net_t *net, co_dev_t *dev, co_unsigned16_t num)
Creates a new CANopen Receive-PDO service.
Definition: rpdo.c:278
#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
static int co_rpdo_init_timer_event(co_rpdo_t *pdo)
Initializes the CAN timer for deadline monitoring of a Receive-PDO service.
Definition: rpdo.c:472
co_unsigned32_t cobid
COB-ID.
Definition: pdo.h:47
This header file is part of the CANopen library; it contains the Service Data Object (SDO) declaratio...
struct co_pdo_map_par map
The PDO mapping parameter.
Definition: rpdo.c:50
static int co_rpdo_init_timer_swnd(co_rpdo_t *pdo)
Initializes the CAN timer for the synchronous time window of a Receive-PDO service.
Definition: rpdo.c:494
This header file is part of the CANopen library; it contains the CANopen value declarations.
struct can_msg msg
A CAN frame waiting for a SYNC object to be processed.
Definition: rpdo.c:62
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
void can_timer_set_func(can_timer_t *timer, can_timer_func_t *func, void *data)
Sets the callback function invoked when a CAN timer is triggered.
Definition: net.c:428
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition: net.c:537
void co_rpdo_destroy(co_rpdo_t *rpdo)
Destroys a CANopen Receive-PDO service.
Definition: rpdo.c:305
static int co_rpdo_init_recv(co_rpdo_t *pdo)
Initializes the CAN frame receiver of a Receive-PDO service.
Definition: rpdo.c:442
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition: msg.h:103
int co_rpdo_rtr(co_rpdo_t *pdo)
Requests the transmission of a PDO.
Definition: rpdo.c:395
static co_unsigned32_t co_1600_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen objects 1600..17FF (RPDO mapping pa...
Definition: rpdo.c:630
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: rpdo.c:52
This header file is part of the utilities library; it contains the native and platform-independent er...
co_unsigned16_t event
Event timer.
Definition: pdo.h:54
co_unsigned32_t co_dev_chk_rpdo(const co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx)
Checks if the specified object is valid and can be mapped into a Receive-PDO.
Definition: pdo.c:42
struct co_pdo_comm_par comm
The PDO communication parameter.
Definition: rpdo.c:48
struct co_sdo_req req
The CANopen SDO download request used for writing sub-objects.
Definition: rpdo.c:64
#define CAN_FLAG_IDE
The Identifier Extension (IDE) flag.
Definition: msg.h:41
#define CO_PDO_COBID_FRAME
The bit in the PDO COB-ID specifying whether to use an 11-bit (0) or 29-bit (1) CAN-ID.
Definition: pdo.h:37
#define CAN_FLAG_EDL
The Extended Data Length (EDL) flag.
Definition: msg.h:55
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition: type.h:47
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition: net.c:562
This is the internal header file of the CANopen library.
const struct co_pdo_comm_par * co_rpdo_get_comm_par(const co_rpdo_t *pdo)
Returns a pointer to the PDO communication parameter record of a Receive-PDO.
Definition: rpdo.c:339
void co_rpdo_ind_t(co_rpdo_t *pdo, co_unsigned32_t ac, const void *ptr, size_t n, void *data)
The type of a CANopen Receive-PDO indication function, invoked when a PDO is received or an error occ...
Definition: rpdo.h:44
#define CO_PDO_COBID_VALID
The bit in the PDO COB-ID specifying whether the PDO exists and is valid.
Definition: pdo.h:28
can_timer_t * timer_event
A pointer to the CAN timer for deadline monitoring.
Definition: rpdo.c:54
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function...
Definition: errnum.c:947
A CAN timer.
Definition: net.c:63
int co_rpdo_sync(co_rpdo_t *pdo, co_unsigned8_t cnt)
Triggers the actuation of a received synchronous PDO.
Definition: rpdo.c:416
#define CO_SDO_AC_PDO_LEN
SDO abort code: The number and length of the objects to be mapped would exceed the PDO length...
Definition: sdo.h:102
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition: net.c:407
void co_rpdo_set_err(co_rpdo_t *pdo, co_rpdo_err_t *err, void *data)
Sets the error handling function of a Receive-PDO service.
Definition: rpdo.c:386
int co_sub_dn(co_sub_t *sub, void *val)
Downloads (moves) a value into a CANopen sub-object if the refuse-write-on-download flag (CO_OBJ_FLAG...
Definition: obj.c:832
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition: type.h:44
This header file is part of the CANopen library; it contains the Receive-PDO declarations.
void co_rpdo_get_err(const co_rpdo_t *pdo, co_rpdo_err_t **perr, void **pdata)
Retrieves the error handling function of a Receive-PDO service.
Definition: rpdo.c:375
void co_rpdo_get_ind(const co_rpdo_t *pdo, co_rpdo_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a Receive-PDO error occurs.
Definition: rpdo.c:355
Invalid argument.
Definition: errnum.h:129
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
#define CO_SDO_AC_NO_WRITE
SDO abort code: Attempt to write a read only object.
Definition: sdo.h:90
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
co_dev_t * dev
A pointer to a CANopen device.
Definition: rpdo.c:44
co_unsigned32_t co_pdo_dn(const struct co_pdo_map_par *par, co_dev_t *dev, struct co_sdo_req *req, const uint8_t *buf, size_t n)
Writes mapped PDO values to the object dictionary through a local SDO download request.
Definition: pdo.c:254
can_net_t * net
A pointer to a CAN network interface.
Definition: rpdo.c:42
A CANopen device.
Definition: dev.c:38
const char * co_sdo_ac2str(co_unsigned32_t ac)
Returns a string describing an SDO abort code.
Definition: sdo.c:57
void can_recv_set_func(can_recv_t *recv, can_recv_func_t *func, void *data)
Sets the callback function used to process CAN frames with a receiver.
Definition: net.c:582
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
co_obj_t * co_sub_get_obj(const co_sub_t *sub)
Returns the a pointer to the CANopen object containing the specified sub-object.
Definition: obj.c:458
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition: net.c:382
This header file is part of the CANopen library; it contains the device description declarations...
static int co_rpdo_timer_swnd(const struct timespec *tp, void *data)
The CAN timer callback function for the synchronous time window of a Receive-PDO service.
Definition: rpdo.c:764
void co_val_fini(co_unsigned16_t type, void *val)
Finalizes a value of the specified data type.
Definition: val.c:273
int can_net_send(can_net_t *net, const struct can_msg *msg)
Sends a CAN frame from a network interface.
Definition: net.c:308
co_dev_t * co_rpdo_get_dev(const co_rpdo_t *pdo)
Returns a pointer to the CANopen device of a Receive-PDO.
Definition: rpdo.c:323
#define CO_SDO_AC_NO_SUB
SDO abort code: Sub-index does not exist.
Definition: sdo.h:132
void co_sdo_req_init(struct co_sdo_req *req)
Initializes a CANopen SDO upload/download request.
Definition: sdo.c:109
static co_unsigned32_t co_rpdo_read_frame(co_rpdo_t *pdo, const struct can_msg *msg)
Parses a CAN frame received by a Receive-PDO service and updates the corresponding objects in the obj...
Definition: rpdo.c:777
static int co_rpdo_recv(const struct can_msg *msg, void *data)
The CAN receive callback function for a Receive-PDO service.
Definition: rpdo.c:713
int co_sdo_req_dn_val(struct co_sdo_req *req, co_unsigned16_t type, void *val, co_unsigned32_t *pac)
Copies the next segment of the specified CANopen SDO download request to the internal buffer and...
Definition: sdo.c:165
static int co_rpdo_timer_event(const struct timespec *tp, void *data)
The CAN timer callback function for deadline monitoring of a Receive-PDO service. ...
Definition: rpdo.c:748
co_unsigned32_t map[0x40]
An array of objects to be mapped.
Definition: pdo.h:73
#define CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames). ...
Definition: msg.h:47
co_unsigned8_t co_sub_get_subidx(const co_sub_t *sub)
Returns the sub-index of a CANopen sub-object.
Definition: obj.c:466
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
co_obj_t * co_dev_find_obj(const co_dev_t *dev, co_unsigned16_t idx)
Finds an object in the object dictionary of a CANopen device.
Definition: dev.c:279
A CAN frame receiver.
Definition: net.c:99
void co_sdo_req_fini(struct co_sdo_req *req)
Finalizes a CANopen SDO upload/download request.
Definition: sdo.c:121
co_unsigned16_t co_sub_get_type(const co_sub_t *sub)
Returns the data type of a CANopen sub-object.
Definition: obj.c:508
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition: msg.h:73
static co_unsigned32_t co_1400_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen objects 1400..15FF (RPDO communicat...
Definition: rpdo.c:520
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition: obj.c:136
void * ind_data
A pointer to user-specified data for ind.
Definition: rpdo.c:68
co_unsigned16_t inhibit
Inhibit time.
Definition: pdo.h:51
A CANopen object.
Definition: obj.h:32
This header file is part of the CANopen library; it contains the object dictionary declarations...
co_rpdo_ind_t * ind
A pointer to the indication function.
Definition: rpdo.c:66
void can_recv_start(can_recv_t *recv, can_net_t *net, uint_least32_t id, uint_least8_t flags)
Registers a CAN frame receiver with a network interface and starts processing frames.
Definition: net.c:591
co_unsigned8_t trans
Transmission type.
Definition: pdo.h:49
void * co_obj_addressof_val(const co_obj_t *obj)
Returns the address of the value of a CANopen object.
Definition: obj.c:275
co_unsigned16_t num
The PDO number.
Definition: rpdo.c:46