Lely core libraries  1.9.2
tpdo.c
Go to the documentation of this file.
1 
24 #include "co.h"
25 
26 #ifndef LELY_NO_CO_TPDO
27 
28 #include <lely/can/buf.h>
29 #include <lely/co/dev.h>
30 #include <lely/co/obj.h>
31 #include <lely/co/sdo.h>
32 #include <lely/co/tpdo.h>
33 #include <lely/co/val.h>
34 #include <lely/util/errnum.h>
35 #include <lely/util/time.h>
36 
37 #include <assert.h>
38 #include <stdlib.h>
39 
41 struct __co_tpdo {
47  co_unsigned16_t num;
59  struct can_buf *buf;
61  struct timespec inhibit;
63  unsigned int event : 1;
65  unsigned int swnd : 1;
67  co_unsigned8_t sync;
69  co_unsigned8_t cnt;
71  struct co_sdo_req req;
75  void *data;
76 };
77 
85 static int co_tpdo_init_recv(co_tpdo_t *pdo);
86 
94 static int co_tpdo_init_timer_event(co_tpdo_t *pdo);
95 
102 static int co_tpdo_init_timer_swnd(co_tpdo_t *pdo);
103 
111 static int co_tpdo_init_buf(co_tpdo_t *pdo);
112 
119 static co_unsigned32_t co_1800_dn_ind(
120  co_sub_t *sub, struct co_sdo_req *req, void *data);
121 
128 static co_unsigned32_t co_1a00_dn_ind(
129  co_sub_t *sub, struct co_sdo_req *req, void *data);
130 
136 static int co_tpdo_recv(const struct can_msg *msg, void *data);
137 
143 static int co_tpdo_timer_event(const struct timespec *tp, void *data);
144 
151 static int co_tpdo_timer_swnd(const struct timespec *tp, void *data);
152 
161 static co_unsigned32_t co_tpdo_init_frame(co_tpdo_t *pdo, struct can_msg *msg);
162 
163 void *
164 __co_tpdo_alloc(void)
165 {
166  void *ptr = malloc(sizeof(struct __co_tpdo));
167  if (__unlikely(!ptr))
168  set_errc(errno2c(errno));
169  return ptr;
170 }
171 
172 void
173 __co_tpdo_free(void *ptr)
174 {
175  free(ptr);
176 }
177 
178 struct __co_tpdo *
179 __co_tpdo_init(struct __co_tpdo *pdo, can_net_t *net, co_dev_t *dev,
180  co_unsigned16_t num)
181 {
182  assert(pdo);
183  assert(net);
184  assert(dev);
185 
186  int errc = 0;
187 
188  if (__unlikely(!num || num > 512)) {
189  errc = errnum2c(ERRNUM_INVAL);
190  goto error_param;
191  }
192 
193  // Find the PDO parameters in the object dictionary.
194  co_obj_t *obj_1800 = co_dev_find_obj(dev, 0x1800 + num - 1);
195  co_obj_t *obj_1a00 = co_dev_find_obj(dev, 0x1a00 + num - 1);
196  if (__unlikely(!obj_1800 || !obj_1a00)) {
197  errc = errnum2c(ERRNUM_INVAL);
198  goto error_param;
199  }
200 
201  pdo->net = net;
202  pdo->dev = dev;
203  pdo->num = num;
204 
205  // Copy the PDO communication parameter record.
206  memset(&pdo->comm, 0, sizeof(pdo->comm));
207  memcpy(&pdo->comm, co_obj_addressof_val(obj_1800),
208  MIN(co_obj_sizeof_val(obj_1800), sizeof(pdo->comm)));
209 
210  // Copy the PDO mapping parameter record.
211  memset(&pdo->map, 0, sizeof(pdo->map));
212  memcpy(&pdo->map, co_obj_addressof_val(obj_1a00),
213  MIN(co_obj_sizeof_val(obj_1a00), sizeof(pdo->map)));
214 
215  pdo->recv = NULL;
216 
217  pdo->timer_event = NULL;
218  pdo->timer_swnd = NULL;
219 
220  pdo->buf = NULL;
221 
222  can_net_get_time(pdo->net, &pdo->inhibit);
223  pdo->event = 0;
224  pdo->swnd = 0;
225  pdo->sync = pdo->comm.sync;
226  pdo->cnt = 0;
227 
228  co_sdo_req_init(&pdo->req);
229 
230  pdo->ind = NULL;
231  pdo->data = NULL;
232 
233  // Set the download indication functions PDO communication parameter
234  // record.
235  co_obj_set_dn_ind(obj_1800, &co_1800_dn_ind, pdo);
236 
237  // Set the download indication functions PDO mapping parameter record.
238  co_obj_set_dn_ind(obj_1a00, &co_1a00_dn_ind, pdo);
239 
240  if (__unlikely(co_tpdo_init_recv(pdo) == -1)) {
241  errc = get_errc();
242  goto error_init_recv;
243  }
244 
245  if (__unlikely(co_tpdo_init_timer_event(pdo) == -1)) {
246  errc = get_errc();
247  goto error_init_timer_event;
248  }
249 
250  if (__unlikely(co_tpdo_init_buf(pdo) == -1)) {
251  errc = get_errc();
252  goto error_init_buf;
253  }
254 
255  return pdo;
256 
257 error_init_buf:
259 error_init_timer_event:
260  can_recv_destroy(pdo->recv);
261 error_init_recv:
262  co_obj_set_dn_ind(obj_1a00, NULL, NULL);
263  co_obj_set_dn_ind(obj_1800, NULL, NULL);
264 error_param:
265  set_errc(errc);
266  return NULL;
267 }
268 
269 void
270 __co_tpdo_fini(struct __co_tpdo *pdo)
271 {
272  assert(pdo);
273  assert(pdo->num >= 1 && pdo->num <= 512);
274 
275  // Remove the download indication functions PDO mapping parameter
276  // record.
277  co_obj_t *obj_1a00 = co_dev_find_obj(pdo->dev, 0x1a00 + pdo->num - 1);
278  assert(obj_1a00);
279  co_obj_set_dn_ind(obj_1a00, NULL, NULL);
280 
281  // Remove the download indication functions PDO communication parameter
282  // record.
283  co_obj_t *obj_1800 = co_dev_find_obj(pdo->dev, 0x1800 + pdo->num - 1);
284  assert(obj_1800);
285  co_obj_set_dn_ind(obj_1800, NULL, NULL);
286 
287  co_sdo_req_fini(&pdo->req);
288 
289  can_buf_destroy(pdo->buf);
290 
293 
294  can_recv_destroy(pdo->recv);
295 }
296 
297 co_tpdo_t *
299 {
300  trace("creating Transmit-PDO %d", num);
301 
302  int errc = 0;
303 
304  co_tpdo_t *pdo = __co_tpdo_alloc();
305  if (__unlikely(!pdo)) {
306  errc = get_errc();
307  goto error_alloc_pdo;
308  }
309 
310  if (__unlikely(!__co_tpdo_init(pdo, net, dev, num))) {
311  errc = get_errc();
312  goto error_init_pdo;
313  }
314 
315  return pdo;
316 
317 error_init_pdo:
318  __co_tpdo_free(pdo);
319 error_alloc_pdo:
320  set_errc(errc);
321  return NULL;
322 }
323 
324 void
326 {
327  if (tpdo) {
328  trace("destroying Transmit-PDO %d", tpdo->num);
329  __co_tpdo_fini(tpdo);
330  __co_tpdo_free(tpdo);
331  }
332 }
333 
334 can_net_t *
336 {
337  assert(pdo);
338 
339  return pdo->net;
340 }
341 
342 co_dev_t *
344 {
345  assert(pdo);
346 
347  return pdo->dev;
348 }
349 
350 co_unsigned16_t
352 {
353  assert(pdo);
354 
355  return pdo->num;
356 }
357 
358 const struct co_pdo_comm_par *
360 {
361  assert(pdo);
362 
363  return &pdo->comm;
364 }
365 
366 const struct co_pdo_map_par *
368 {
369  assert(pdo);
370 
371  return &pdo->map;
372 }
373 
374 void
375 co_tpdo_get_ind(const co_tpdo_t *pdo, co_tpdo_ind_t **pind, void **pdata)
376 {
377  assert(pdo);
378 
379  if (pind)
380  *pind = pdo->ind;
381  if (pdata)
382  *pdata = pdo->data;
383 }
384 
385 void
386 co_tpdo_set_ind(co_tpdo_t *pdo, co_tpdo_ind_t *ind, void *data)
387 {
388  assert(pdo);
389 
390  pdo->ind = ind;
391  pdo->data = data;
392 }
393 
394 int
396 {
397  assert(pdo);
398 
399  // Ignore events if the transmission type is synchronous.
400  if (pdo->comm.trans && pdo->comm.trans < 0xfd)
401  return 0;
402 
403  if (!pdo->comm.trans) {
404  // Ignore events occurring after the synchronous time window has
405  // expired.
406  if (!pdo->event)
407  pdo->event = !pdo->swnd;
408  } else if (pdo->comm.trans >= 0xfe) {
409  if (pdo->comm.inhibit) {
410  // Check whether the inhibit time has passed.
411  struct timespec now;
412  can_net_get_time(pdo->net, &now);
413  if (timespec_cmp(&now, &pdo->inhibit) < 0) {
415  return -1;
416  }
417  pdo->inhibit = now;
418  }
419 
420  // In case of an event-driven TPDO, send the frame right away.
421  struct can_msg msg;
422  if (__unlikely(co_tpdo_init_frame(pdo, &msg)))
423  return -1;
424  if (__unlikely(can_net_send(pdo->net, &msg) == -1))
425  return -1;
426 
427  if (pdo->comm.inhibit)
429  &pdo->inhibit, pdo->comm.inhibit * 100);
430  }
431 
432  return co_tpdo_init_timer_event(pdo);
433 }
434 
435 int
436 co_tpdo_sync(co_tpdo_t *pdo, co_unsigned8_t cnt)
437 {
438  assert(pdo);
439 
440  if (__unlikely(cnt > 240)) {
442  return -1;
443  }
444 
445  // Check whether the PDO exists and is valid.
446  if (pdo->comm.cobid & CO_PDO_COBID_VALID)
447  return 0;
448 
449  // Ignore SYNC objects if the transmission type is not synchronous.
450  if (pdo->comm.trans > 0xf0 && pdo->comm.trans != 0xfc)
451  return 0;
452 
453  // Reset the time window for synchronous PDOs.
454  pdo->swnd = 0;
456 
457  // Wait for the SYNC counter to equal the SYNC start value.
458  if (pdo->sync && cnt) {
459  if (pdo->sync != cnt)
460  return 0;
461  pdo->sync = 0;
462  pdo->cnt = 0;
463  }
464 
465  if (!pdo->comm.trans) {
466  // In case of a synchronous (acyclic) TPDO, do nothing unless an
467  // event occurred.
468  if (!pdo->event)
469  return 0;
470  pdo->event = 0;
471  } else if (pdo->comm.trans <= 0xf0) {
472  // In case of a synchronous (cyclic) TPDO, do nothing unless the
473  // n-th SYNC object has been received.
474  if (++pdo->cnt < pdo->comm.trans)
475  return 0;
476  pdo->cnt = 0;
477  }
478 
479  struct can_msg msg;
480  if (__unlikely(co_tpdo_init_frame(pdo, &msg)))
481  return -1;
482 
483  if (pdo->comm.trans <= 0xf0) {
484  if (__unlikely(can_net_send(pdo->net, &msg) == -1))
485  return -1;
486  } else if (pdo->comm.trans == 0xfc) {
487  if (__unlikely(!pdo->buf)) {
489  return -1;
490  }
491  // In case of an RTR-only (synchronous) TPDO, buffer the frame
492  // instead of sending it right away.
493  if (__unlikely(!can_buf_write(pdo->buf, &msg, 1))) {
494  if (__unlikely(!can_buf_reserve(pdo->buf, 1)))
495  return -1;
496  can_buf_write(pdo->buf, &msg, 1);
497  }
498  }
499 
500  return 0;
501 }
502 
503 void
504 co_tpdo_get_next(const co_tpdo_t *pdo, struct timespec *tp)
505 {
506  assert(pdo);
507 
508  if (tp)
509  *tp = pdo->inhibit;
510 }
511 
512 static int
514 {
515  assert(pdo);
516 
517  // clang-format off
518  if (!(pdo->comm.cobid & CO_PDO_COBID_VALID) && (pdo->comm.trans == 0xfc
519  || pdo->comm.trans == 0xfd)) {
520  // clang-format on
521  if (!pdo->recv) {
522  pdo->recv = can_recv_create();
523  if (__unlikely(!pdo->recv))
524  return -1;
525  can_recv_set_func(pdo->recv, &co_tpdo_recv, pdo);
526  }
527  // Register the receiver under the specified CAN-ID.
528  uint32_t id = pdo->comm.cobid;
529  uint8_t flags = 0;
530  if (id & CO_PDO_COBID_FRAME) {
531  id &= CAN_MASK_EID;
532  flags |= CAN_FLAG_IDE;
533  } else {
534  id &= CAN_MASK_BID;
535  }
536  can_recv_start(pdo->recv, pdo->net, id, flags);
537  } else if (pdo->recv) {
538  can_recv_destroy(pdo->recv);
539  pdo->recv = NULL;
540  }
541 
542  return 0;
543 }
544 
545 static int
547 {
548  assert(pdo);
549 
550  if (!(pdo->comm.cobid & CO_PDO_COBID_VALID)
551  && (!pdo->comm.trans || pdo->comm.trans >= 0xfe)
552  && pdo->comm.event) {
553  if (!pdo->timer_event) {
554  pdo->timer_event = can_timer_create();
555  if (__unlikely(!pdo->timer_event))
556  return -1;
558  &co_tpdo_timer_event, pdo);
559  }
560  // Reset the event timer.
561  can_timer_timeout(pdo->timer_event, pdo->net, pdo->comm.event);
562  } else if (pdo->timer_event) {
564  pdo->timer_event = NULL;
565  }
566 
567  return 0;
568 }
569 
570 static int
572 {
573  assert(pdo);
574 
575  // Ignore the synchronous window length unless the TPDO is valid and
576  // synchronous.
577  co_unsigned32_t swnd = co_dev_get_val_u32(pdo->dev, 0x1007, 0x00);
578  if (!(pdo->comm.cobid & CO_PDO_COBID_VALID)
579  && (pdo->comm.trans <= 0xf0 || pdo->comm.trans == 0xfc)
580  && swnd) {
581  if (!pdo->timer_swnd) {
582  pdo->timer_swnd = can_timer_create();
583  if (__unlikely(!pdo->timer_swnd))
584  return -1;
586  pdo);
587  }
588  can_timer_timeout(pdo->timer_swnd, pdo->net, swnd);
589  } else if (pdo->timer_swnd) {
591  pdo->timer_swnd = NULL;
592  }
593 
594  return 0;
595 }
596 
597 static int
599 {
600  assert(pdo);
601 
602  if (!(pdo->comm.cobid & CO_PDO_COBID_VALID)
603  && (pdo->comm.trans == 0xfd)) {
604  if (!pdo->buf) {
605  pdo->buf = can_buf_create(0);
606  if (__unlikely(!pdo->buf))
607  return -1;
608  }
609  } else if (pdo->buf) {
610  can_buf_destroy(pdo->buf);
611  pdo->buf = NULL;
612  }
613 
614  return 0;
615 }
616 
617 static co_unsigned32_t
618 co_1800_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
619 {
620  assert(sub);
621  assert(req);
622  co_tpdo_t *pdo = data;
623  assert(pdo);
624  assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1800 + pdo->num - 1);
625 
626  co_unsigned32_t ac = 0;
627 
628  co_unsigned16_t type = co_sub_get_type(sub);
629  union co_val val;
630  if (__unlikely(co_sdo_req_dn_val(req, type, &val, &ac) == -1))
631  return ac;
632 
633  switch (co_sub_get_subidx(sub)) {
634  case 0: ac = CO_SDO_AC_NO_WRITE; goto error;
635  case 1: {
636  assert(type == CO_DEFTYPE_UNSIGNED32);
637  co_unsigned32_t cobid = val.u32;
638  co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
639  if (cobid == cobid_old)
640  goto error;
641 
642  // The CAN-ID cannot be changed when the PDO is and remains
643  // valid.
644  int valid = !(cobid & CO_PDO_COBID_VALID);
645  int valid_old = !(cobid_old & CO_PDO_COBID_VALID);
646  uint32_t canid = cobid & CAN_MASK_EID;
647  uint32_t canid_old = cobid_old & CAN_MASK_EID;
648  if (__unlikely(valid && valid_old && canid != canid_old)) {
649  ac = CO_SDO_AC_PARAM_VAL;
650  goto error;
651  }
652 
653  // A 29-bit CAN-ID is only valid if the frame bit is set.
654  // clang-format off
655  if (__unlikely(!(cobid & CO_PDO_COBID_FRAME)
656  && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))) {
657  // clang-format on
658  ac = CO_SDO_AC_PARAM_VAL;
659  goto error;
660  }
661 
662  pdo->comm.cobid = cobid;
663 
664  if (valid && !valid_old) {
665  can_net_get_time(pdo->net, &pdo->inhibit);
666  pdo->event = 0;
667  pdo->sync = pdo->comm.sync;
668  pdo->cnt = 0;
669  }
670 
671  co_tpdo_init_recv(pdo);
674  co_tpdo_init_buf(pdo);
675  break;
676  }
677  case 2: {
678  assert(type == CO_DEFTYPE_UNSIGNED8);
679  co_unsigned8_t trans = val.u8;
680  co_unsigned8_t trans_old = co_sub_get_val_u8(sub);
681  if (trans == trans_old)
682  goto error;
683 
684  // Transmission types 0xF1..0xFB are reserved.
685  if (__unlikely(trans > 0xf0 && trans < 0xfc)) {
686  ac = CO_SDO_AC_PARAM_VAL;
687  goto error;
688  }
689 
690  // Check whether RTR is allowed on this PDO.
691  // clang-format off
692  if (__unlikely((trans == 0xfc || trans == 0xfd)
693  && (pdo->comm.cobid & CO_PDO_COBID_RTR))) {
694  // clang-format on
695  ac = CO_SDO_AC_PARAM_VAL;
696  goto error;
697  }
698 
699  pdo->comm.trans = trans;
700 
701  pdo->event = 0;
702 
703  co_tpdo_init_recv(pdo);
706  co_tpdo_init_buf(pdo);
707  break;
708  }
709  case 3: {
710  assert(type == CO_DEFTYPE_UNSIGNED16);
711  co_unsigned16_t inhibit = val.u16;
712  co_unsigned16_t inhibit_old = co_sub_get_val_u16(sub);
713  if (inhibit == inhibit_old)
714  goto error;
715 
716  // The inhibit time cannot be changed while the PDO exists and
717  // is valid.
718  if (__unlikely(!(pdo->comm.cobid & CO_PDO_COBID_VALID))) {
719  ac = CO_SDO_AC_PARAM_VAL;
720  goto error;
721  }
722 
723  pdo->comm.inhibit = inhibit;
724  break;
725  }
726  case 5: {
727  assert(type == CO_DEFTYPE_UNSIGNED16);
728  co_unsigned16_t event = val.u16;
729  co_unsigned16_t event_old = co_sub_get_val_u16(sub);
730  if (event == event_old)
731  goto error;
732 
733  pdo->comm.event = event;
734 
736  break;
737  }
738  case 6: {
739  assert(type == CO_DEFTYPE_UNSIGNED8);
740  co_unsigned8_t sync = val.u8;
741  co_unsigned8_t sync_old = co_sub_get_val_u8(sub);
742  if (sync == sync_old)
743  goto error;
744 
745  // The SYNC start value cannot be changed while the PDO exists
746  // and is valid.
747  if (__unlikely(!(pdo->comm.cobid & CO_PDO_COBID_VALID))) {
748  ac = CO_SDO_AC_PARAM_VAL;
749  goto error;
750  }
751 
752  pdo->comm.sync = sync;
753  break;
754  }
755  default: ac = CO_SDO_AC_NO_SUB; goto error;
756  }
757 
758  co_sub_dn(sub, &val);
759 error:
760  co_val_fini(type, &val);
761  return ac;
762 }
763 
764 static co_unsigned32_t
765 co_1a00_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
766 {
767  assert(sub);
768  assert(req);
769  co_tpdo_t *pdo = data;
770  assert(pdo);
771  assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1a00 + pdo->num - 1);
772 
773  co_unsigned32_t ac = 0;
774 
775  co_unsigned16_t type = co_sub_get_type(sub);
776  union co_val val;
777  if (__unlikely(co_sdo_req_dn_val(req, type, &val, &ac) == -1))
778  return ac;
779 
780  int valid = !(pdo->comm.cobid & CO_PDO_COBID_VALID);
781 
782  if (!co_sub_get_subidx(sub)) {
783  assert(type == CO_DEFTYPE_UNSIGNED8);
784  co_unsigned8_t n = val.u8;
785  co_unsigned8_t n_old = co_sub_get_val_u8(sub);
786  if (n == n_old)
787  goto error;
788 
789  // The PDO mapping cannot be changed when the PDO is valid.
790  if (__unlikely(valid || n > 0x40)) {
791  ac = CO_SDO_AC_PARAM_VAL;
792  goto error;
793  }
794 
795  size_t bits = 0;
796  for (size_t i = 1; i <= n; i++) {
797  co_unsigned32_t map = pdo->map.map[i - 1];
798  co_unsigned16_t idx = (map >> 16) & 0xffff;
799  co_unsigned8_t subidx = (map >> 8) & 0xff;
800  co_unsigned8_t len = map & 0xff;
801 
802  // Check the PDO length.
803  if (__unlikely((bits += len) > CAN_MAX_LEN * 8)) {
804  ac = CO_SDO_AC_PDO_LEN;
805  goto error;
806  }
807 
808  // Check whether the sub-object exists and can be mapped
809  // into a PDO.
810  ac = co_dev_chk_tpdo(pdo->dev, idx, subidx);
811  if (__unlikely(ac))
812  goto error;
813  }
814 
815  pdo->map.n = n;
816  } else {
817  assert(type == CO_DEFTYPE_UNSIGNED32);
818  co_unsigned32_t map = val.u32;
819  co_unsigned32_t map_old = co_sub_get_val_u32(sub);
820  if (map == map_old)
821  goto error;
822 
823  // The PDO mapping cannot be changed when the PDO is valid or
824  // sub-index 0x00 is non-zero.
825  if (__unlikely(valid || pdo->map.n)) {
826  ac = CO_SDO_AC_PARAM_VAL;
827  goto error;
828  }
829 
830  co_unsigned16_t idx = (map >> 16) & 0xffff;
831  co_unsigned8_t subidx = (map >> 8) & 0xff;
832  // Check whether the sub-object exists and can be mapped into a
833  // PDO.
834  ac = co_dev_chk_tpdo(pdo->dev, idx, subidx);
835  if (__unlikely(ac))
836  goto error;
837 
838  pdo->map.map[co_sub_get_subidx(sub) - 1] = map;
839  }
840 
841  co_sub_dn(sub, &val);
842 error:
843  co_val_fini(type, &val);
844  return ac;
845 }
846 
847 static int
848 co_tpdo_recv(const struct can_msg *_msg, void *data)
849 {
850  assert(_msg);
851  co_tpdo_t *pdo = data;
852  assert(pdo);
853 
854  if (__unlikely(!(_msg->flags & CAN_FLAG_RTR)))
855  return 0;
856 
857  struct can_msg msg;
858  switch (pdo->comm.trans) {
859  case 0xfc:
860  // Send a CAN frame from the buffer if available, otherwise
861  // fall through to the event-driven case.
862  if (pdo->buf && can_buf_read(pdo->buf, &msg, 1)) {
863  can_net_send(pdo->net, &msg);
864  break;
865  }
866  // ... falls through ...
867  case 0xfd: {
868  co_unsigned32_t ac = co_tpdo_init_frame(pdo, &msg);
869  if (__likely(!ac))
870  can_net_send(pdo->net, &msg);
871  if (pdo->ind)
872  pdo->ind(pdo, ac, ac ? NULL : msg.data,
873  ac ? 0 : msg.len, pdo->data);
874  }
875  default: break;
876  }
877 
878  return 0;
879 }
880 
881 static int
882 co_tpdo_timer_event(const struct timespec *tp, void *data)
883 {
884  (void)tp;
885  co_tpdo_t *pdo = data;
886  assert(pdo);
887 
888  co_tpdo_event(pdo);
889 
890  return 0;
891 }
892 
893 static int
894 co_tpdo_timer_swnd(const struct timespec *tp, void *data)
895 {
896  (void)tp;
897  co_tpdo_t *pdo = data;
898  assert(pdo);
899 
900  trace("TPDO %d: no event occurred in synchronous window", pdo->num);
901 
902  if (pdo->ind)
903  pdo->ind(pdo, CO_SDO_AC_TIMEOUT, NULL, 0, pdo->data);
904 
905  return 0;
906 }
907 
908 static co_unsigned32_t
910 {
911  assert(pdo);
912  assert(msg);
913 
914  *msg = (struct can_msg)CAN_MSG_INIT;
915  msg->id = pdo->comm.cobid;
916  if (pdo->comm.cobid & CO_PDO_COBID_FRAME) {
917  msg->id &= CAN_MASK_EID;
918  msg->id |= CAN_FLAG_IDE;
919  } else {
920  msg->id &= CAN_MASK_BID;
921  }
922 
923  size_t n = CAN_MAX_LEN;
924  co_unsigned32_t ac = co_pdo_up(
925  &pdo->map, pdo->dev, &pdo->req, msg->data, &n);
926  if (__unlikely(ac))
927  return ac;
928  msg->len = n;
929 
930  return 0;
931 }
932 
933 #endif // !LELY_NO_CO_TPDO
A CANopen SDO upload/download request.
Definition: sdo.h:178
static co_unsigned32_t co_1800_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen objects 1800..19FF (TPDO communicat...
Definition: tpdo.c:618
int co_tpdo_event(co_tpdo_t *pdo)
Triggers the transmission of an event-driven (asynchronous) PDO.
Definition: tpdo.c:395
A PDO mapping parameter record.
Definition: pdo.h:69
static int co_tpdo_init_timer_swnd(co_tpdo_t *pdo)
Initializes the CAN timer for the synchronous time window of a Transmit-PDO service.
Definition: tpdo.c:571
A CAN or CAN FD format frame.
Definition: msg.h:88
co_unsigned8_t sync
SYNC start value.
Definition: pdo.h:56
struct can_buf * buf
A CAN frame buffer.
Definition: tpdo.c:59
void co_tpdo_destroy(co_tpdo_t *tpdo)
Destroys a CANopen Transmit-PDO service.
Definition: tpdo.c:325
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 co_tpdo_get_next(const co_tpdo_t *pdo, struct timespec *tp)
Retrieves the time at which the next event-driven TPDO may be sent.
Definition: tpdo.c:504
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
static int co_tpdo_recv(const struct can_msg *msg, void *data)
The CAN receive callback function for a Transmit-PDO service.
Definition: tpdo.c:848
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
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_PDO_COBID_RTR
The bit in the PDO COB-ID specifying whether RTR is allowed.
Definition: pdo.h:31
A CANopen sub-object.
Definition: obj.h:54
This header file is part of the CANopen library; it contains the Transmit-PDO declarations.
A CAN frame buffer.
Definition: buf.h:47
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
co_tpdo_ind_t * ind
A pointer to the indication function.
Definition: tpdo.c:73
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:825
can_timer_t * timer_event
A pointer to the CAN timer for events.
Definition: tpdo.c:55
A CANopen Transmit-PDO.
Definition: tpdo.c:41
#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
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: tpdo.c:53
co_unsigned8_t sync
The SYNC start value.
Definition: tpdo.c:67
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
A PDO communication parameter record.
Definition: pdo.h:43
#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
void co_tpdo_ind_t(co_tpdo_t *pdo, co_unsigned32_t ac, const void *ptr, size_t n, void *data)
The type of a CANopen Transmit-PDO indication function, invoked when a PDO is sent or an error occurs...
Definition: tpdo.h:45
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...
static int co_tpdo_timer_swnd(const struct timespec *tp, void *data)
The CAN timer callback function for the synchronous time window of a Transmit-PDO service...
Definition: tpdo.c:894
void co_tpdo_set_ind(co_tpdo_t *pdo, co_tpdo_ind_t *ind, void *data)
Sets the indication function invoked when a Transmit-PDO error occurs.
Definition: tpdo.c:386
This header file is part of the CANopen library; it contains the CANopen value declarations.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
const struct co_pdo_comm_par * co_tpdo_get_comm_par(const co_tpdo_t *pdo)
Returns a pointer to the PDO communication parameter record of a Transmit-PDO.
Definition: tpdo.c:359
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
static int co_tpdo_init_recv(co_tpdo_t *pdo)
Initializes the CAN frame receiver of a Transmit-PDO service.
Definition: tpdo.c:513
void * data
A pointer to user-specified data for ind.
Definition: tpdo.c:75
#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:138
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition: msg.h:103
co_unsigned16_t num
The PDO number.
Definition: tpdo.c:47
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
#define __likely(x)
Indicates to the compiler that the expression is most-likely true.
Definition: features.h:273
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_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
struct co_pdo_comm_par comm
The PDO communication parameter.
Definition: tpdo.c:49
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition: type.h:47
const struct co_pdo_map_par * co_tpdo_get_map_par(const co_tpdo_t *pdo)
Returns a pointer to the PDO mapping parameter record of a Transmit-PDO.
Definition: tpdo.c:367
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition: net.c:562
#define CO_SDO_AC_TIMEOUT
SDO abort code: SDO protocol timed out.
Definition: sdo.h:66
can_net_t * net
A pointer to a CAN network interface.
Definition: tpdo.c:43
This is the internal header file of the CANopen library.
size_t can_buf_reserve(struct can_buf *buf, size_t n)
Resizes a CAN frame buffer, if necessary, to make room for at least n additional frames.
Definition: buf.c:111
This header file is part of the CAN library; it contains the CAN frame buffer declarations.
void co_tpdo_get_ind(const co_tpdo_t *pdo, co_tpdo_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a Transmit-PDO error occurs.
Definition: tpdo.c:375
#define CO_PDO_COBID_VALID
The bit in the PDO COB-ID specifying whether the PDO exists and is valid.
Definition: pdo.h:28
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
Resource unavailable, try again.
Definition: errnum.h:86
#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
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
co_dev_t * co_tpdo_get_dev(const co_tpdo_t *pdo)
Returns a pointer to the CANopen device of a Transmit-PDO.
Definition: tpdo.c:343
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition: type.h:44
unsigned int event
A flag indicating the occurrence of an event.
Definition: tpdo.c:63
int co_tpdo_sync(co_tpdo_t *pdo, co_unsigned8_t cnt)
Triggers the transmission of a synchronous PDO.
Definition: tpdo.c:436
Invalid argument.
Definition: errnum.h:129
co_tpdo_t * co_tpdo_create(can_net_t *net, co_dev_t *dev, co_unsigned16_t num)
Creates a new CANopen Transmit-PDO service.
Definition: tpdo.c:298
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
int timespec_cmp(const void *p1, const void *p2)
Compares two times.
Definition: time.h:224
A CANopen device.
Definition: dev.c:38
size_t can_buf_read(struct can_buf *buf, struct can_msg *ptr, size_t n)
Reads, and removes, frames from a CAN frame buffer.
Definition: buf.h:268
struct timespec inhibit
The time at which the next event-driven TPDO may be sent.
Definition: tpdo.c:61
co_unsigned8_t cnt
The SYNC counter value.
Definition: tpdo.c:69
co_unsigned32_t co_pdo_up(const struct co_pdo_map_par *par, const co_dev_t *dev, struct co_sdo_req *req, uint8_t *buf, size_t *pn)
Reads mapped PDO values from the object dictionary through a local SDO upload request.
Definition: pdo.c:305
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
struct can_buf * can_buf_create(size_t size)
Allocates and initializes a CAN frame buffer.
Definition: buf.c:75
This header file is part of the CANopen library; it contains the device description declarations...
static int co_tpdo_init_buf(co_tpdo_t *pdo)
Initializes the CAN frame buffer of a Transmit-PDO service.
Definition: tpdo.c:598
static co_unsigned32_t co_1a00_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen objects 1A00..1BFF (TPDO mapping pa...
Definition: tpdo.c:765
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
struct co_pdo_map_par map
The PDO mapping parameter.
Definition: tpdo.c:51
unsigned int swnd
A flag indicating the synchronous time window has expired.
Definition: tpdo.c:65
#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
size_t can_buf_write(struct can_buf *buf, const struct can_msg *ptr, size_t n)
Writes frames to a CAN frame buffer.
Definition: buf.h:300
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
co_dev_t * dev
A pointer to a CANopen device.
Definition: tpdo.c:45
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
co_unsigned16_t co_tpdo_get_num(const co_tpdo_t *pdo)
Returns the PDO number of a Transmit-PDO.
Definition: tpdo.c:351
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition: obj.c:136
can_timer_t * timer_swnd
A pointer to the CAN timer for the synchronous time window.
Definition: tpdo.c:57
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_unsigned32_t co_dev_chk_tpdo(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 Transmit-PDO.
Definition: pdo.c:120
struct co_sdo_req req
The CANopen SDO upload request used for reading sub-objects.
Definition: tpdo.c:71
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
static int co_tpdo_timer_event(const struct timespec *tp, void *data)
The CAN timer callback function for events of a Transmit-PDO service.
Definition: tpdo.c:882
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
static co_unsigned32_t co_tpdo_init_frame(co_tpdo_t *pdo, struct can_msg *msg)
Initializes a CAN frame to be sent by a Transmit-PDO service.
Definition: tpdo.c:909
can_net_t * co_tpdo_get_net(const co_tpdo_t *pdo)
Returns a pointer to the CAN network of a Transmit-PDO.
Definition: tpdo.c:335
static int co_tpdo_init_timer_event(co_tpdo_t *pdo)
Initializes the CAN timer for events of a Transmit-PDO service.
Definition: tpdo.c:546