Lely core libraries  2.2.5
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 #include <lely/util/time.h>
35 
36 #include <assert.h>
37 #include <inttypes.h>
38 #include <stdlib.h>
39 
41 struct __co_rpdo {
47  co_unsigned16_t num;
59  unsigned int sync : 1;
61  unsigned int swnd : 1;
63  struct can_msg msg;
65  struct co_sdo_req req;
69  void *ind_data;
73  void *err_data;
74 };
75 
83 static int co_rpdo_init_recv(co_rpdo_t *pdo);
84 
91 static int co_rpdo_init_timer_event(co_rpdo_t *pdo);
92 
100 static int co_rpdo_init_timer_swnd(co_rpdo_t *pdo);
101 
108 static co_unsigned32_t co_1400_dn_ind(
109  co_sub_t *sub, struct co_sdo_req *req, void *data);
110 
117 static co_unsigned32_t co_1600_dn_ind(
118  co_sub_t *sub, struct co_sdo_req *req, void *data);
119 
125 static int co_rpdo_recv(const struct can_msg *msg, void *data);
126 
133 static int co_rpdo_timer_event(const struct timespec *tp, void *data);
134 
141 static int co_rpdo_timer_swnd(const struct timespec *tp, void *data);
142 
152 static co_unsigned32_t co_rpdo_read_frame(
153  co_rpdo_t *pdo, const struct can_msg *msg);
154 
155 void *
156 __co_rpdo_alloc(void)
157 {
158  void *ptr = malloc(sizeof(struct __co_rpdo));
159  if (!ptr)
160  set_errc(errno2c(errno));
161  return ptr;
162 }
163 
164 void
165 __co_rpdo_free(void *ptr)
166 {
167  free(ptr);
168 }
169 
170 struct __co_rpdo *
171 __co_rpdo_init(struct __co_rpdo *pdo, can_net_t *net, co_dev_t *dev,
172  co_unsigned16_t num)
173 {
174  assert(pdo);
175  assert(net);
176  assert(dev);
177 
178  int errc = 0;
179 
180  if (!num || num > 512) {
181  errc = errnum2c(ERRNUM_INVAL);
182  goto error_param;
183  }
184 
185  // Find the PDO parameters in the object dictionary.
186  co_obj_t *obj_1400 = co_dev_find_obj(dev, 0x1400 + num - 1);
187  co_obj_t *obj_1600 = co_dev_find_obj(dev, 0x1600 + num - 1);
188  if (!obj_1400 || !obj_1600) {
189  errc = errnum2c(ERRNUM_INVAL);
190  goto error_param;
191  }
192 
193  pdo->net = net;
194  pdo->dev = dev;
195  pdo->num = num;
196 
197  // Copy the PDO communication parameter record.
198  memset(&pdo->comm, 0, sizeof(pdo->comm));
199  memcpy(&pdo->comm, co_obj_addressof_val(obj_1400),
200  MIN(co_obj_sizeof_val(obj_1400), sizeof(pdo->comm)));
201 
202  // Copy the PDO mapping parameter record.
203  memset(&pdo->map, 0, sizeof(pdo->map));
204  memcpy(&pdo->map, co_obj_addressof_val(obj_1600),
205  MIN(co_obj_sizeof_val(obj_1600), sizeof(pdo->map)));
206 
207  pdo->recv = NULL;
208 
209  pdo->timer_event = NULL;
210  pdo->timer_swnd = NULL;
211 
212  pdo->sync = 0;
213  pdo->swnd = 0;
214  pdo->msg = (struct can_msg)CAN_MSG_INIT;
215 
216  co_sdo_req_init(&pdo->req);
217 
218  pdo->ind = NULL;
219  pdo->ind_data = NULL;
220  pdo->err = NULL;
221  pdo->err_data = NULL;
222 
223  // Set the download indication functions PDO communication parameter
224  // record.
225  co_obj_set_dn_ind(obj_1400, &co_1400_dn_ind, pdo);
226 
227  // Set the download indication functions PDO mapping parameter record.
228  co_obj_set_dn_ind(obj_1600, &co_1600_dn_ind, pdo);
229 
230  if (co_rpdo_init_recv(pdo) == -1) {
231  errc = get_errc();
232  goto error_init_recv;
233  }
234 
235  return pdo;
236 
237  // can_recv_destroy(pdo->recv);
238 error_init_recv:
239  co_obj_set_dn_ind(obj_1600, NULL, NULL);
240  co_obj_set_dn_ind(obj_1400, NULL, NULL);
241 error_param:
242  set_errc(errc);
243  return NULL;
244 }
245 
246 void
247 __co_rpdo_fini(struct __co_rpdo *pdo)
248 {
249  assert(pdo);
250  assert(pdo->num >= 1 && pdo->num <= 512);
251 
252  // Remove the download indication functions PDO mapping parameter
253  // record.
254  co_obj_t *obj_1600 = co_dev_find_obj(pdo->dev, 0x1600 + pdo->num - 1);
255  assert(obj_1600);
256  co_obj_set_dn_ind(obj_1600, NULL, NULL);
257 
258  // Remove the download indication functions PDO communication parameter
259  // record.
260  co_obj_t *obj_1400 = co_dev_find_obj(pdo->dev, 0x1400 + pdo->num - 1);
261  assert(obj_1400);
262  co_obj_set_dn_ind(obj_1400, NULL, NULL);
263 
264  co_sdo_req_fini(&pdo->req);
265 
268 
269  can_recv_destroy(pdo->recv);
270 }
271 
272 co_rpdo_t *
273 co_rpdo_create(can_net_t *net, co_dev_t *dev, co_unsigned16_t num)
274 {
275  trace("creating Receive-PDO %d", num);
276 
277  int errc = 0;
278 
279  co_rpdo_t *pdo = __co_rpdo_alloc();
280  if (!pdo) {
281  errc = get_errc();
282  goto error_alloc_pdo;
283  }
284 
285  if (!__co_rpdo_init(pdo, net, dev, num)) {
286  errc = get_errc();
287  goto error_init_pdo;
288  }
289 
290  return pdo;
291 
292 error_init_pdo:
293  __co_rpdo_free(pdo);
294 error_alloc_pdo:
295  set_errc(errc);
296  return NULL;
297 }
298 
299 void
301 {
302  if (rpdo) {
303  trace("destroying Receive-PDO %d", rpdo->num);
304  __co_rpdo_fini(rpdo);
305  __co_rpdo_free(rpdo);
306  }
307 }
308 
309 can_net_t *
311 {
312  assert(pdo);
313 
314  return pdo->net;
315 }
316 
317 co_dev_t *
319 {
320  assert(pdo);
321 
322  return pdo->dev;
323 }
324 
325 co_unsigned16_t
327 {
328  assert(pdo);
329 
330  return pdo->num;
331 }
332 
333 const struct co_pdo_comm_par *
335 {
336  assert(pdo);
337 
338  return &pdo->comm;
339 }
340 
341 const struct co_pdo_map_par *
343 {
344  assert(pdo);
345 
346  return &pdo->map;
347 }
348 
349 void
350 co_rpdo_get_ind(const co_rpdo_t *pdo, co_rpdo_ind_t **pind, void **pdata)
351 {
352  assert(pdo);
353 
354  if (pind)
355  *pind = pdo->ind;
356  if (pdata)
357  *pdata = pdo->ind_data;
358 }
359 
360 void
362 {
363  assert(pdo);
364 
365  pdo->ind = ind;
366  pdo->ind_data = data;
367 }
368 
369 void
370 co_rpdo_get_err(const co_rpdo_t *pdo, co_rpdo_err_t **perr, void **pdata)
371 {
372  assert(pdo);
373 
374  if (perr)
375  *perr = pdo->err;
376  if (pdata)
377  *pdata = pdo->err_data;
378 }
379 
380 void
382 {
383  assert(pdo);
384 
385  pdo->err = err;
386  pdo->err_data = data;
387 }
388 
389 int
391 {
392  assert(pdo);
393 
394  // Check whether the PDO exists and is valid.
395  if (pdo->comm.cobid & CO_PDO_COBID_VALID)
396  return 0;
397 
398  struct can_msg msg = CAN_MSG_INIT;
399  msg.id = pdo->comm.cobid;
400  if (pdo->comm.cobid & CO_PDO_COBID_FRAME) {
401  msg.id &= CAN_MASK_EID;
402  msg.flags |= CAN_FLAG_IDE;
403  } else {
404  msg.id &= CAN_MASK_BID;
405  }
406  msg.flags |= CAN_FLAG_RTR;
407  return can_net_send(pdo->net, &msg);
408 }
409 
410 int
411 co_rpdo_sync(co_rpdo_t *pdo, co_unsigned8_t cnt)
412 {
413  assert(pdo);
414 
415  if (cnt > 240) {
417  return -1;
418  }
419 
420  // Ignore SYNC objects if the transmission type is not synchronous.
421  if (pdo->comm.trans > 0xf0)
422  return 0;
423 
424  // Reset the time window for synchronous PDOs.
425  pdo->swnd = 0;
427 
428  // Check if we have a CAN frame waiting for a SYNC object.
429  if (!pdo->sync)
430  return 0;
431  pdo->sync = 0;
432 
433  return co_rpdo_read_frame(pdo, &pdo->msg) ? -1 : 0;
434 }
435 
436 static int
438 {
439  assert(pdo);
440 
441  if (!(pdo->comm.cobid & CO_PDO_COBID_VALID)) {
442  if (!pdo->recv) {
443  pdo->recv = can_recv_create();
444  if (!pdo->recv)
445  return -1;
446  can_recv_set_func(pdo->recv, co_rpdo_recv, pdo);
447  }
448  // Register the receiver under the specified CAN-ID.
449  uint_least32_t id = pdo->comm.cobid;
450  uint_least8_t flags = 0;
451  if (id & CO_PDO_COBID_FRAME) {
452  id &= CAN_MASK_EID;
453  flags |= CAN_FLAG_IDE;
454  } else {
455  id &= CAN_MASK_BID;
456  }
457  can_recv_start(pdo->recv, pdo->net, id, flags);
458  } else if (pdo->recv) {
459  can_recv_destroy(pdo->recv);
460  pdo->recv = NULL;
461  }
462 
463  return 0;
464 }
465 
466 static int
468 {
469  assert(pdo);
470 
471  if (!(pdo->comm.cobid & CO_PDO_COBID_VALID) && pdo->comm.event) {
472  if (!pdo->timer_event) {
473  pdo->timer_event = can_timer_create();
474  if (!pdo->timer_event)
475  return -1;
477  co_rpdo_timer_event, pdo);
478  }
479  can_timer_timeout(pdo->timer_event, pdo->net, pdo->comm.event);
480  } else if (pdo->timer_event) {
482  pdo->timer_event = NULL;
483  }
484 
485  return 0;
486 }
487 
488 static int
490 {
491  assert(pdo);
492 
493  // Ignore the synchronous window length unless the RPDO is valid and
494  // synchronous.
495  co_unsigned32_t swnd = co_dev_get_val_u32(pdo->dev, 0x1007, 0x00);
496  if (!(pdo->comm.cobid & CO_PDO_COBID_VALID) && pdo->comm.trans <= 0xf0
497  && swnd) {
498  if (!pdo->timer_swnd) {
499  pdo->timer_swnd = can_timer_create();
500  if (!pdo->timer_swnd)
501  return -1;
503  pdo);
504  }
505  struct timespec start = { 0, 0 };
506  can_net_get_time(pdo->net, &start);
507  timespec_add_usec(&start, swnd);
508  can_timer_start(pdo->timer_swnd, pdo->net, &start, NULL);
509  } else if (pdo->timer_swnd) {
511  pdo->timer_swnd = NULL;
512  }
513 
514  return 0;
515 }
516 
517 static co_unsigned32_t
518 co_1400_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
519 {
520  assert(sub);
521  assert(req);
522  co_rpdo_t *pdo = data;
523  assert(pdo);
524  assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1400 + pdo->num - 1);
525 
526  co_unsigned32_t ac = 0;
527 
528  co_unsigned16_t type = co_sub_get_type(sub);
529  union co_val val;
530  if (co_sdo_req_dn_val(req, type, &val, &ac) == -1)
531  return ac;
532 
533  switch (co_sub_get_subidx(sub)) {
534  case 0: ac = CO_SDO_AC_NO_WRITE; goto error;
535  case 1: {
536  assert(type == CO_DEFTYPE_UNSIGNED32);
537  co_unsigned32_t cobid = val.u32;
538  co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
539  if (cobid == cobid_old)
540  goto error;
541 
542  // The CAN-ID cannot be changed when the PDO is and remains
543  // valid.
544  int valid = !(cobid & CO_PDO_COBID_VALID);
545  int valid_old = !(cobid_old & CO_PDO_COBID_VALID);
546  uint_least32_t canid = cobid & CAN_MASK_EID;
547  uint_least32_t canid_old = cobid_old & CAN_MASK_EID;
548  if (valid && valid_old && canid != canid_old) {
549  ac = CO_SDO_AC_PARAM_VAL;
550  goto error;
551  }
552 
553  // A 29-bit CAN-ID is only valid if the frame bit is set.
554  if (!(cobid & CO_PDO_COBID_FRAME)
555  && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID))) {
556  ac = CO_SDO_AC_PARAM_VAL;
557  goto error;
558  }
559 
560  pdo->comm.cobid = cobid;
561 
562  pdo->sync = 0;
563  pdo->swnd = 0;
564 
565  co_rpdo_init_recv(pdo);
566  if (pdo->timer_swnd) {
568  pdo->timer_swnd = NULL;
569  }
570  break;
571  }
572  case 2: {
573  assert(type == CO_DEFTYPE_UNSIGNED8);
574  co_unsigned8_t trans = val.u8;
575  co_unsigned8_t trans_old = co_sub_get_val_u8(sub);
576  if (trans == trans_old)
577  goto error;
578 
579  // Transmission types 0xF1..0xFD are reserved.
580  if (trans > 0xf0 && trans < 0xfe) {
581  ac = CO_SDO_AC_PARAM_VAL;
582  goto error;
583  }
584 
585  pdo->comm.trans = trans;
586  break;
587  }
588  case 3: {
589  assert(type == CO_DEFTYPE_UNSIGNED16);
590  co_unsigned16_t inhibit = val.u16;
591  co_unsigned16_t inhibit_old = co_sub_get_val_u16(sub);
592  if (inhibit == inhibit_old)
593  goto error;
594 
595  // The inhibit time cannot be changed while the PDO exists and
596  // is valid.
597  if (!(pdo->comm.cobid & CO_PDO_COBID_VALID)) {
598  ac = CO_SDO_AC_PARAM_VAL;
599  goto error;
600  }
601 
602  pdo->comm.inhibit = inhibit;
603  break;
604  }
605  case 5: {
606  assert(type == CO_DEFTYPE_UNSIGNED16);
607  co_unsigned16_t event = val.u16;
608  co_unsigned16_t event_old = co_sub_get_val_u16(sub);
609  if (event == event_old)
610  goto error;
611 
612  pdo->comm.event = event;
613  break;
614  }
615  default: ac = CO_SDO_AC_NO_SUB; goto error;
616  }
617 
618  co_sub_dn(sub, &val);
619 error:
620  co_val_fini(type, &val);
621  return ac;
622 }
623 
624 static co_unsigned32_t
625 co_1600_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
626 {
627  assert(sub);
628  assert(req);
629  co_rpdo_t *pdo = data;
630  assert(pdo);
631  assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1600 + pdo->num - 1);
632 
633  co_unsigned32_t ac = 0;
634 
635  co_unsigned16_t type = co_sub_get_type(sub);
636  union co_val val;
637  if (co_sdo_req_dn_val(req, type, &val, &ac) == -1)
638  return ac;
639 
640  int valid = !(pdo->comm.cobid & CO_PDO_COBID_VALID);
641 
642  if (!co_sub_get_subidx(sub)) {
643  assert(type == CO_DEFTYPE_UNSIGNED8);
644  co_unsigned8_t n = val.u8;
645  co_unsigned8_t n_old = co_sub_get_val_u8(sub);
646  if (n == n_old)
647  goto error;
648 
649  // The PDO mapping cannot be changed when the PDO is valid.
650  if (valid || n > 0x40) {
651  ac = CO_SDO_AC_PARAM_VAL;
652  goto error;
653  }
654 
655  size_t bits = 0;
656  for (size_t i = 1; i <= n; i++) {
657  co_unsigned32_t map = pdo->map.map[i - 1];
658  if (!map)
659  continue;
660 
661  co_unsigned16_t idx = (map >> 16) & 0xffff;
662  co_unsigned8_t subidx = (map >> 8) & 0xff;
663  co_unsigned8_t len = map & 0xff;
664 
665  // Check the PDO length.
666  if ((bits += len) > CAN_MAX_LEN * 8) {
667  ac = CO_SDO_AC_PDO_LEN;
668  goto error;
669  }
670 
671  // Check whether the sub-object exists and can be mapped
672  // into a PDO (or is a valid dummy entry).
673  ac = co_dev_chk_rpdo(pdo->dev, idx, subidx);
674  if (ac)
675  goto error;
676  }
677 
678  pdo->map.n = n;
679  } else {
680  assert(type == CO_DEFTYPE_UNSIGNED32);
681  co_unsigned32_t map = val.u32;
682  co_unsigned32_t map_old = co_sub_get_val_u32(sub);
683  if (map == map_old)
684  goto error;
685 
686  // The PDO mapping cannot be changed when the PDO is valid or
687  // sub-index 0x00 is non-zero.
688  if (valid || pdo->map.n) {
689  ac = CO_SDO_AC_PARAM_VAL;
690  goto error;
691  }
692 
693  if (map) {
694  co_unsigned16_t idx = (map >> 16) & 0xffff;
695  co_unsigned8_t subidx = (map >> 8) & 0xff;
696  // Check whether the sub-object exists and can be mapped
697  // into a PDO (or is a valid dummy entry).
698  ac = co_dev_chk_rpdo(pdo->dev, idx, subidx);
699  if (ac)
700  goto error;
701  }
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 (msg->flags & CAN_FLAG_RTR)
721  return 0;
722 
723 #ifndef LELY_NO_CANFD
724  // Ignore CAN FD format frames.
725  if (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
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 ((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:87
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:310
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:372
void * err_data
A pointer to user-specified data for err.
Definition: rpdo.c:73
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition: msg.h:89
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:317
A CAN network interface.
Definition: net.c:37
can_timer_t * timer_swnd
A pointer to the CAN timer for the synchronous time window.
Definition: rpdo.c:57
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
unsigned int swnd
A flag indicating the synchronous time window has expired.
Definition: rpdo.c:61
co_unsigned32_t co_pdo_dn(const struct co_pdo_map_par *par, co_dev_t *dev, struct co_sdo_req *req, const uint_least8_t *buf, size_t n)
Writes mapped PDO values to the object dictionary through a local SDO download request.
Definition: pdo.c:254
A CANopen sub-object.
Definition: obj.h:54
A CANopen Receive-PDO.
Definition: rpdo.c:41
unsigned int sync
A flag indicating we&#39;re waiting for a SYNC object to process msg.
Definition: rpdo.c:59
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
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:71
void can_net_get_time(const can_net_t *net, struct timespec *tp)
Retrieves the current time of a CAN network interface.
Definition: net.c:204
co_unsigned16_t co_rpdo_get_num(const co_rpdo_t *pdo)
Returns the PDO number of a Receive-PDO.
Definition: rpdo.c:326
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:342
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:361
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:273
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
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:467
co_unsigned32_t cobid
COB-ID.
Definition: pdo.h:47
void can_timer_start(can_timer_t *timer, can_net_t *net, const struct timespec *start, const struct timespec *interval)
Starts a CAN timer and registers it with a network interface.
Definition: net.c:437
#define CAN_MASK_BID
The mask used to extract the 11-bit Base Identifier from a CAN frame.
Definition: msg.h:31
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:51
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:489
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:63
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:300
static int co_rpdo_init_recv(co_rpdo_t *pdo)
Initializes the CAN frame receiver of a Receive-PDO service.
Definition: rpdo.c:437
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
void timespec_add_usec(struct timespec *tp, uint_least64_t usec)
Adds usec microseconds to the time at tp.
Definition: time.h:143
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition: msg.h:102
int co_rpdo_rtr(co_rpdo_t *pdo)
Requests the transmission of a PDO.
Definition: rpdo.c:390
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:625
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: rpdo.c:53
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:49
struct co_sdo_req req
The CANopen SDO download request used for writing sub-objects.
Definition: rpdo.c:65
This header file is part of the utilities library; it contains the time function declarations.
#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 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
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames). ...
Definition: msg.h:48
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:334
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 CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition: msg.h:72
#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:55
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:411
#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:381
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:954
#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:370
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:350
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
co_dev_t * dev
A pointer to a CANopen device.
Definition: rpdo.c:45
can_net_t * net
A pointer to a CAN network interface.
Definition: rpdo.c:43
A CANopen device.
Definition: dev.c:41
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_FDF, CAN_FLAG_BRS and CAN_FLAG_ESI...
Definition: msg.h:94
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:520
The Identifier Extension (IDE) flag.
Definition: msg.h:43
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition: net.c:382
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:275
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:318
#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
This header file is part of the CANopen library; it contains the device description declarations...
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
co_unsigned8_t co_sub_get_subidx(const co_sub_t *sub)
Returns the sub-index of a CANopen sub-object.
Definition: obj.c:528
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
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:570
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:518
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition: obj.c:154
void * ind_data
A pointer to user-specified data for ind.
Definition: rpdo.c:69
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:67
#define CAN_MSG_INIT
The static initializer for can_msg.
Definition: msg.h:113
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_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:288
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:311
#define CAN_MASK_EID
The mask used to extract the 29-bit Extended Identifier from a CAN frame.
Definition: msg.h:34
co_unsigned16_t num
The PDO number.
Definition: rpdo.c:47