Lely core libraries  1.9.2
emcy.c
Go to the documentation of this file.
1 
24 #include "co.h"
25 
26 #ifndef LELY_NO_CO_EMCY
27 
28 #include <lely/can/buf.h>
29 #include <lely/co/dev.h>
30 #include <lely/co/emcy.h>
31 #include <lely/co/obj.h>
32 #include <lely/co/sdo.h>
33 #include <lely/co/val.h>
34 #include <lely/util/diag.h>
35 #include <lely/util/endian.h>
36 #include <lely/util/time.h>
37 
38 #include <assert.h>
39 #include <stdlib.h>
40 
42 struct co_emcy_msg {
44  co_unsigned16_t eec;
46  co_unsigned8_t er;
47 };
48 
50 struct co_emcy_node {
54  co_unsigned8_t id;
57 };
58 
69 static struct co_emcy_node *co_emcy_node_create(
70  co_emcy_t *emcy, co_unsigned8_t id);
71 
73 static void co_emcy_node_destroy(struct co_emcy_node *node);
74 
80 static int co_emcy_node_recv(const struct can_msg *msg, void *data);
81 
83 struct __co_emcy {
93  size_t nmsg;
95  struct co_emcy_msg *msgs;
97  struct can_buf buf;
101  struct timespec inhibit;
107  void *data;
108 };
109 
111 struct co_1003 {
113  co_unsigned8_t n;
115  co_unsigned32_t ef[0xfe];
116 };
117 
124 static int co_emcy_set_1003(co_emcy_t *emcy);
125 
132 static co_unsigned32_t co_1003_dn_ind(
133  co_sub_t *sub, struct co_sdo_req *req, void *data);
134 
141 static co_unsigned32_t co_1014_dn_ind(
142  co_sub_t *sub, struct co_sdo_req *req, void *data);
143 
153 static int co_emcy_set_1028(
154  co_emcy_t *emcy, co_unsigned8_t id, co_unsigned32_t cobid);
155 
162 static co_unsigned32_t co_1028_dn_ind(
163  co_sub_t *sub, struct co_sdo_req *req, void *data);
164 
170 static int co_emcy_timer(const struct timespec *tp, void *data);
171 
182 static int co_emcy_send(co_emcy_t *emcy, co_unsigned16_t eec, co_unsigned8_t er,
183  const uint8_t msef[5]);
184 
189 static void co_emcy_flush(co_emcy_t *emcy);
190 
191 void *
192 __co_emcy_alloc(void)
193 {
194  void *ptr = malloc(sizeof(struct __co_emcy));
195  if (__unlikely(!ptr))
196  set_errc(errno2c(errno));
197  return ptr;
198 }
199 
200 void
201 __co_emcy_free(void *ptr)
202 {
203  free(ptr);
204 }
205 
206 struct __co_emcy *
207 __co_emcy_init(struct __co_emcy *emcy, can_net_t *net, co_dev_t *dev)
208 {
209  assert(emcy);
210  assert(net);
211  assert(dev);
212 
213  int errc = 0;
214 
215  emcy->net = net;
216  emcy->dev = dev;
217 
218  emcy->sub_1001_00 = co_dev_find_sub(emcy->dev, 0x1001, 0x00);
219  if (__unlikely(!emcy->sub_1001_00)) {
220  errc = errnum2c(ERRNUM_NOSYS);
221  goto error_sub_1001_00;
222  }
223  emcy->obj_1003 = co_dev_find_obj(emcy->dev, 0x1003);
224 
225  emcy->nmsg = 0;
226  emcy->msgs = NULL;
227 
228  if (__unlikely(can_buf_init(&emcy->buf, 0) == -1)) {
229  errc = get_errc();
230  goto error_init_buf;
231  }
232 
233  emcy->timer = can_timer_create();
234  if (__unlikely(!emcy->timer)) {
235  errc = get_errc();
236  goto error_create_timer;
237  }
238  can_timer_set_func(emcy->timer, &co_emcy_timer, emcy);
239 
240  can_net_get_time(emcy->net, &emcy->inhibit);
241 
242  memset(emcy->nodes, 0, CO_NUM_NODES * sizeof(struct co_emcy_node *));
243 
244  emcy->ind = NULL;
245  emcy->data = NULL;
246 
247  // Set the download indication function for the pre-defined error field.
248  if (emcy->obj_1003)
250 
251  // Set the download indication function for the EMCY COB-ID object.
252  co_obj_t *obj_1014 = co_dev_find_obj(emcy->dev, 0x1014);
253  if (obj_1014)
254  co_obj_set_dn_ind(obj_1014, &co_1014_dn_ind, emcy);
255 
256  co_obj_t *obj_1028 = co_dev_find_obj(emcy->dev, 0x1028);
257  if (obj_1028) {
258  // Set the download indication function for the emergency
259  // consumer object.
260  co_obj_set_dn_ind(obj_1028, &co_1028_dn_ind, emcy);
261  // Initialize the nodes.
262  co_unsigned8_t maxid = MIN(co_obj_get_val_u8(obj_1028, 0x00),
263  CO_NUM_NODES);
264  for (co_unsigned8_t id = 1; id <= maxid; id++) {
265  co_unsigned32_t cobid =
266  co_obj_get_val_u32(obj_1028, id);
267  // clang-format off
268  if (__unlikely(co_emcy_set_1028(emcy, id, cobid)
269  == -1)) {
270  // clang-format on
271  errc = get_errc();
272  goto error_set_1028;
273  }
274  }
275  }
276 
277  return emcy;
278 
279 error_set_1028:
280  if (obj_1028)
281  co_obj_set_dn_ind(obj_1028, NULL, NULL);
282  if (obj_1014)
283  co_obj_set_dn_ind(obj_1014, NULL, NULL);
284  if (emcy->obj_1003)
285  co_obj_set_dn_ind(emcy->obj_1003, NULL, NULL);
286  can_timer_destroy(emcy->timer);
287 error_create_timer:
288  can_buf_fini(&emcy->buf);
289 error_init_buf:
290 error_sub_1001_00:
291  set_errc(errc);
292  return NULL;
293 }
294 
295 void
296 __co_emcy_fini(struct __co_emcy *emcy)
297 {
298  assert(emcy);
299 
300  // Remove the download indication function for the emergency consumer
301  // object.
302  co_obj_t *obj_1028 = co_dev_find_obj(emcy->dev, 0x1028);
303  if (obj_1028)
304  co_obj_set_dn_ind(obj_1028, NULL, NULL);
305 
306  // Remove the download indication function for the EMCY COB-ID object.
307  co_obj_t *obj_1014 = co_dev_find_obj(emcy->dev, 0x1014);
308  if (obj_1014)
309  co_obj_set_dn_ind(obj_1014, NULL, NULL);
310 
311  // Remove the download indication function for the pre-defined error
312  // field.
313  if (emcy->obj_1003)
314  co_obj_set_dn_ind(emcy->obj_1003, NULL, NULL);
315 
316  for (co_unsigned8_t id = 1; id <= CO_NUM_NODES; id++)
317  co_emcy_node_destroy(emcy->nodes[id - 1]);
318 
319  can_timer_destroy(emcy->timer);
320 
321  can_buf_fini(&emcy->buf);
322 
323  free(emcy->msgs);
324 }
325 
326 co_emcy_t *
328 {
329  trace("creating EMCY producer service");
330 
331  int errc = 0;
332 
333  co_emcy_t *emcy = __co_emcy_alloc();
334  if (__unlikely(!emcy)) {
335  errc = get_errc();
336  goto error_alloc_emcy;
337  }
338 
339  if (__unlikely(!__co_emcy_init(emcy, net, dev))) {
340  errc = get_errc();
341  goto error_init_emcy;
342  }
343 
344  return emcy;
345 
346 error_init_emcy:
347  __co_emcy_free(emcy);
348 error_alloc_emcy:
349  set_errc(errc);
350  return NULL;
351 }
352 
353 void
355 {
356  if (emcy) {
357  trace("destroying EMCY producer service");
358  __co_emcy_fini(emcy);
359  __co_emcy_free(emcy);
360  }
361 }
362 
363 can_net_t *
365 {
366  assert(emcy);
367 
368  return emcy->net;
369 }
370 
371 co_dev_t *
373 {
374  assert(emcy);
375 
376  return emcy->dev;
377 }
378 
379 int
380 co_emcy_push(co_emcy_t *emcy, co_unsigned16_t eec, co_unsigned8_t er,
381  const uint8_t msef[5])
382 {
383  assert(emcy);
384 
385  if (__unlikely(!eec)) {
387  return -1;
388  }
389  // Bit 0 (generic error) shall be signaled at any error situation.
390  er |= 0x01;
391 
392  if (msef)
393  diag(DIAG_INFO, 0, "EMCY: %04X %02X %u %u %u %u %u", eec, er,
394  msef[0], msef[1], msef[2], msef[3], msef[4]);
395  else
396  diag(DIAG_INFO, 0, "EMCY: %04X %02X", eec, er);
397 
398  // Make room on the stack.
399  struct co_emcy_msg *msgs = realloc(emcy->msgs,
400  (emcy->nmsg + 1) * sizeof(struct co_emcy_msg));
401  if (__unlikely(!msgs)) {
402  set_errc(errno2c(errno));
403  return -1;
404  }
405  emcy->msgs = msgs;
406  if (emcy->nmsg) {
407  // Copy the current error register.
408  er |= emcy->msgs[0].er;
409  // Move the older messages.
410  memmove(emcy->msgs + 1, emcy->msgs,
411  emcy->nmsg * sizeof(struct co_emcy_msg));
412  }
413  emcy->nmsg++;
414  // Push the error to the stack.
415  emcy->msgs[0].eec = eec;
416  emcy->msgs[0].er = er;
417 
418  // Update the pre-defined error field.
419  if (emcy->obj_1003)
420  co_emcy_set_1003(emcy);
421 
422  return co_emcy_send(emcy, eec, er, msef);
423 }
424 
425 int
426 co_emcy_pop(co_emcy_t *emcy, co_unsigned16_t *peec, co_unsigned8_t *per)
427 {
428  assert(emcy);
429 
430  co_emcy_peek(emcy, peec, per);
431 
432  if (!emcy->nmsg)
433  return 0;
434 
435  // Move the older messages.
436  if (--emcy->nmsg)
437  memmove(emcy->msgs, emcy->msgs + 1,
438  emcy->nmsg * sizeof(struct co_emcy_msg));
439 
440  // Update the pre-defined error field.
441  if (emcy->obj_1003)
442  co_emcy_set_1003(emcy);
443 
444  if (emcy->nmsg) {
445  // Store the next error in the error register and the
446  // manufacturer-specific field.
447  uint8_t msef[5] = { 0 };
448  stle_u16(msef, emcy->msgs[0].eec);
449  return co_emcy_send(emcy, 0, emcy->msgs[0].er, msef);
450  } else {
451  return co_emcy_send(emcy, 0, 0, NULL);
452  }
453 }
454 
455 void
456 co_emcy_peek(const co_emcy_t *emcy, co_unsigned16_t *peec, co_unsigned8_t *per)
457 {
458  assert(emcy);
459 
460  if (peec)
461  *peec = emcy->nmsg ? emcy->msgs[0].eec : 0;
462  if (per)
463  *per = emcy->nmsg ? emcy->msgs[0].er : 0;
464 }
465 
466 int
468 {
469  assert(emcy);
470 
471  if (!emcy->nmsg)
472  return 0;
473 
474  // Clear the stack.
475  emcy->nmsg = 0;
476 
477  // Clear the pre-defined error field.
478  if (emcy->obj_1003)
479  co_emcy_set_1003(emcy);
480 
481  // Send the 'error reset/no error' message.
482  return co_emcy_send(emcy, 0, 0, NULL);
483 }
484 
485 void
486 co_emcy_get_ind(const co_emcy_t *emcy, co_emcy_ind_t **pind, void **pdata)
487 {
488  assert(emcy);
489 
490  if (pind)
491  *pind = emcy->ind;
492  if (pdata)
493  *pdata = emcy->data;
494 }
495 
496 void
497 co_emcy_set_ind(co_emcy_t *emcy, co_emcy_ind_t *ind, void *data)
498 {
499  assert(emcy);
500 
501  emcy->ind = ind;
502  emcy->data = data;
503 }
504 
505 struct co_emcy_node *
506 co_emcy_node_create(co_emcy_t *emcy, co_unsigned8_t id)
507 {
508  assert(emcy);
509  assert(id && id <= CO_NUM_NODES);
510 
511  trace("creating EMCY consumer service for node %d", id);
512 
513  int errc = 0;
514 
515  struct co_emcy_node *node = malloc(sizeof(*node));
516  if (__unlikely(!node)) {
517  errc = errno2c(errno);
518  goto error_alloc_node;
519  }
520 
521  node->emcy = emcy;
522  node->id = id;
523 
524  node->recv = can_recv_create();
525  if (__unlikely(!node->recv)) {
526  errc = get_errc();
527  goto error_create_recv;
528  }
530 
531  return node;
532 
533 error_create_recv:
534  free(node);
535 error_alloc_node:
536  set_errc(errc);
537  return NULL;
538 }
539 
540 void
542 {
543  if (node) {
544  trace("destroying EMCY consumer service for node %d", node->id);
545  can_recv_destroy(node->recv);
546  free(node);
547  }
548 }
549 
550 static int
551 co_emcy_node_recv(const struct can_msg *msg, void *data)
552 {
553  assert(msg);
554  struct co_emcy_node *node = data;
555  assert(node);
556  co_emcy_t *emcy = node->emcy;
557  assert(emcy);
558 
559  // Ignore remote frames.
560  if (__unlikely(msg->flags & CAN_FLAG_RTR))
561  return 0;
562 
563 #ifndef LELY_NO_CANFD
564  // Ignore CAN FD format frames.
565  if (__unlikely(msg->flags & CAN_FLAG_EDL))
566  return 0;
567 #endif
568 
569  // Extract the parameters from the frame.
570  co_unsigned16_t eec = 0;
571  if (msg->len >= 2)
572  eec = ldle_u16(msg->data);
573  co_unsigned8_t er = msg->len >= 3 ? msg->data[2] : 0;
574  co_unsigned8_t msef[5] = { 0 };
575  if (msg->len >= 4)
576  memcpy(msef, msg->data + 3, MAX((uint8_t)(msg->len - 3), 5));
577 
578  // Notify the user.
579  trace("EMCY: received %04X %02X", eec, er);
580  if (emcy->ind)
581  emcy->ind(emcy, node->id, eec, er, msef, emcy->data);
582 
583  return 0;
584 }
585 
586 static int
588 {
589  assert(emcy);
590  assert(emcy->obj_1003);
591 
592  struct co_1003 *val_1003 = co_obj_addressof_val(emcy->obj_1003);
593  co_unsigned8_t nsubidx = co_obj_get_subidx(emcy->obj_1003, 0, NULL);
594  if (__unlikely(!nsubidx))
595  return 0;
596 
597  // Copy the emergency error codes.
598  val_1003->n = MIN((co_unsigned8_t)emcy->nmsg, nsubidx - 1);
599  for (int i = 0; i < val_1003->n; i++)
600  val_1003->ef[i] = emcy->msgs[i].eec;
601  for (int i = val_1003->n; i < nsubidx - 1; i++)
602  val_1003->ef[i] = 0;
603 
604  return 0;
605 }
606 
607 static co_unsigned32_t
608 co_1003_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
609 {
610  assert(sub);
611  assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1003);
612  assert(req);
613  co_emcy_t *emcy = data;
614  assert(emcy);
615 
616  co_unsigned32_t ac = 0;
617 
618  co_unsigned16_t type = co_sub_get_type(sub);
619  union co_val val;
620  if (__unlikely(co_sdo_req_dn_val(req, type, &val, &ac) == -1))
621  return ac;
622 
623  if (__unlikely(co_sub_get_subidx(sub))) {
624  ac = CO_SDO_AC_NO_WRITE;
625  goto error;
626  }
627 
628  // Only the value 0 is allowed.
629  assert(type == CO_DEFTYPE_UNSIGNED8);
630  if (__unlikely(val.u8)) {
631  ac = CO_SDO_AC_PARAM_VAL;
632  goto error;
633  }
634 
635  emcy->nmsg = 0;
636 
637  co_sub_dn(sub, &val);
638  co_val_fini(type, &val);
639 
640  co_emcy_set_1003(emcy);
641  return 0;
642 
643 error:
644  co_val_fini(type, &val);
645  return ac;
646 }
647 
648 static co_unsigned32_t
649 co_1014_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
650 {
651  assert(sub);
652  assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1014);
653  assert(req);
654  (void)data;
655 
656  co_unsigned32_t ac = 0;
657 
658  co_unsigned16_t type = co_sub_get_type(sub);
659  union co_val val;
660  if (__unlikely(co_sdo_req_dn_val(req, type, &val, &ac) == -1))
661  return ac;
662 
663  if (__unlikely(co_sub_get_subidx(sub))) {
664  ac = CO_SDO_AC_NO_SUB;
665  goto error;
666  }
667 
668  assert(type == CO_DEFTYPE_UNSIGNED32);
669  co_unsigned32_t cobid = val.u32;
670  co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
671  if (cobid == cobid_old)
672  goto error;
673 
674  // The CAN-ID cannot be changed when the EMCY is and remains valid.
675  int valid = !(cobid & CO_EMCY_COBID_VALID);
676  int valid_old = !(cobid_old & CO_EMCY_COBID_VALID);
677  uint32_t canid = cobid & CAN_MASK_EID;
678  uint32_t canid_old = cobid_old & CAN_MASK_EID;
679  if (__unlikely(valid && valid_old && canid != canid_old)) {
680  ac = CO_SDO_AC_PARAM_VAL;
681  goto error;
682  }
683 
684  // A 29-bit CAN-ID is only valid if the frame bit is set.
685  // clang-format off
686  if (__unlikely(!(cobid & CO_EMCY_COBID_FRAME)
687  && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))) {
688  // clang-format on
689  ac = CO_SDO_AC_PARAM_VAL;
690  goto error;
691  }
692 
693  co_sub_dn(sub, &val);
694 error:
695  co_val_fini(type, &val);
696  return ac;
697 }
698 
699 static int
700 co_emcy_set_1028(co_emcy_t *emcy, co_unsigned8_t id, co_unsigned32_t cobid)
701 {
702  assert(emcy);
703  assert(id && id <= CO_NUM_NODES);
704  struct co_emcy_node *node = emcy->nodes[id - 1];
705 
706  if (!(cobid & CO_EMCY_COBID_VALID)) {
707  if (!node) {
708  node = co_emcy_node_create(emcy, id);
709  if (__unlikely(!node))
710  return -1;
711  emcy->nodes[id - 1] = node;
712  }
713  // Register the receiver under the specified CAN-ID.
714  uint32_t id = cobid;
715  uint8_t flags = 0;
716  if (id & CO_EMCY_COBID_FRAME) {
717  id &= CAN_MASK_EID;
718  flags |= CAN_FLAG_IDE;
719  } else {
720  id &= CAN_MASK_BID;
721  }
722  can_recv_start(node->recv, emcy->net, id, flags);
723  } else if (node) {
724  co_emcy_node_destroy(node);
725  emcy->nodes[id - 1] = NULL;
726  }
727 
728  return 0;
729 }
730 
731 static co_unsigned32_t
732 co_1028_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
733 {
734  assert(sub);
735  assert(co_obj_get_idx(co_sub_get_obj(sub)) == 0x1028);
736  assert(req);
737  co_emcy_t *emcy = data;
738  assert(emcy);
739 
740  co_unsigned32_t ac = 0;
741 
742  co_unsigned16_t type = co_sub_get_type(sub);
743  union co_val val;
744  if (__unlikely(co_sdo_req_dn_val(req, type, &val, &ac) == -1))
745  return ac;
746 
747  co_unsigned8_t id = co_sub_get_subidx(sub);
748  if (__unlikely(!id)) {
749  ac = CO_SDO_AC_NO_WRITE;
750  goto error;
751  }
752  co_unsigned8_t maxid = MIN(co_obj_get_val_u8(co_sub_get_obj(sub), 0),
753  CO_NUM_NODES);
754  if (__unlikely(id > maxid)) {
755  ac = CO_SDO_AC_NO_SUB;
756  goto error;
757  }
758 
759  assert(type == CO_DEFTYPE_UNSIGNED32);
760  co_unsigned32_t cobid = val.u32;
761  co_unsigned32_t cobid_old = co_sub_get_val_u32(sub);
762  if (cobid == cobid_old)
763  goto error;
764 
765  // The CAN-ID cannot be changed when the EMCY is and remains valid.
766  int valid = !(cobid & CO_EMCY_COBID_VALID);
767  int valid_old = !(cobid_old & CO_EMCY_COBID_VALID);
768  uint32_t canid = cobid & CAN_MASK_EID;
769  uint32_t canid_old = cobid_old & CAN_MASK_EID;
770  if (__unlikely(valid && valid_old && canid != canid_old)) {
771  ac = CO_SDO_AC_PARAM_VAL;
772  goto error;
773  }
774 
775  // A 29-bit CAN-ID is only valid if the frame bit is set.
776  // clang-format off
777  if (__unlikely(!(cobid & CO_EMCY_COBID_FRAME)
778  && (cobid & (CAN_MASK_EID ^ CAN_MASK_BID)))) {
779  // clang-format on
780  ac = CO_SDO_AC_PARAM_VAL;
781  goto error;
782  }
783 
784  if (__unlikely(co_emcy_set_1028(emcy, id, cobid) == -1)) {
785  ac = CO_SDO_AC_ERROR;
786  goto error;
787  }
788 
789  co_sub_dn(sub, &val);
790 error:
791  co_val_fini(type, &val);
792  return ac;
793 }
794 
795 static int
796 co_emcy_timer(const struct timespec *tp, void *data)
797 {
798  (void)tp;
799  co_emcy_t *emcy = data;
800  assert(emcy);
801 
802  co_emcy_flush(emcy);
803 
804  return 0;
805 }
806 
807 static int
808 co_emcy_send(co_emcy_t *emcy, co_unsigned16_t eec, co_unsigned8_t er,
809  const uint8_t msef[5])
810 {
811  assert(emcy);
812 
813  // Update the error register in the object dictionary.
814  co_sub_set_val_u8(emcy->sub_1001_00, er);
815 
816  // Check whether the EMCY COB-ID exists and is valid.
817  co_obj_t *obj_1014 = co_dev_find_obj(emcy->dev, 0x1014);
818  if (!obj_1014)
819  return 0;
820  co_unsigned32_t cobid = co_obj_get_val_u32(obj_1014, 0x00);
821  if (cobid & CO_EMCY_COBID_VALID)
822  return 0;
823 
824  // Create the frame.
825  struct can_msg msg = CAN_MSG_INIT;
826  msg.id = cobid;
827  if (cobid & CO_EMCY_COBID_FRAME) {
828  msg.id &= CAN_MASK_EID;
829  msg.flags |= CAN_FLAG_IDE;
830  } else {
831  msg.id &= CAN_MASK_BID;
832  }
833  msg.len = CAN_MAX_LEN;
834  stle_u32(msg.data, eec);
835  msg.data[2] = er;
836  if (msef)
837  memcpy(msg.data + 3, msef, 5);
838 
839  // Add the frame to the buffer.
840  if (__unlikely(!can_buf_write(&emcy->buf, &msg, 1))) {
841  if (__unlikely(!can_buf_reserve(&emcy->buf, 1)))
842  return -1;
843  can_buf_write(&emcy->buf, &msg, 1);
844  }
845 
846  co_emcy_flush(emcy);
847  return 0;
848 }
849 
850 static void
852 {
853  assert(emcy);
854 
855  co_unsigned16_t inhibit = co_dev_get_val_u16(emcy->dev, 0x1015, 0x00);
856 
857  struct timespec now = { 0, 0 };
858  can_net_get_time(emcy->net, &now);
859 
860  while (can_buf_size(&emcy->buf)) {
861  if (timespec_cmp(&now, &emcy->inhibit) < 0) {
862  can_timer_start(emcy->timer, emcy->net, &emcy->inhibit,
863  NULL);
864  return;
865  }
866  // Update the inhibit time.
867  emcy->inhibit = now;
868  timespec_add_usec(&emcy->inhibit, inhibit * 100);
869  // Send the frame.
870  struct can_msg msg;
871  if (__likely(can_buf_read(&emcy->buf, &msg, 1)))
872  can_net_send(emcy->net, &msg);
873  }
874 }
875 
876 #endif // !LELY_NO_CO_EMCY
A CANopen SDO upload/download request.
Definition: sdo.h:178
A CAN or CAN FD format frame.
Definition: msg.h:88
void stle_u32(void *ptr, uint_least32_t x)
Stores a 32-bit unsigned integer in little-endian byte order.
Definition: endian.h:534
void can_buf_fini(struct can_buf *buf)
Finalizes a CAN frame buffer.
Definition: buf.c:67
#define CO_EMCY_COBID_VALID
The bit in the EMCY COB-ID specifying whether the EMCY exists and is valid.
Definition: emcy.h:29
size_t can_buf_size(const struct can_buf *buf)
Returns the number of frames available for reading in a CAN buffer.
Definition: buf.h:210
static co_unsigned32_t co_1014_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen object 1014 (COB-ID emergency messa...
Definition: emcy.c:649
void co_emcy_ind_t(co_emcy_t *emcy, co_unsigned8_t id, co_unsigned16_t eec, co_unsigned8_t er, uint8_t msef[5], void *data)
The type of a CANopen EMCY indication function, invoked when an EMCY message is received.
Definition: emcy.h:52
static co_unsigned32_t co_1003_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen object 1003 (Pre-defined error fiel...
Definition: emcy.c:608
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
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition: msg.h:90
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
A CANopen sub-object.
Definition: obj.h:54
co_emcy_t * emcy
A pointer to the EMCY service.
Definition: emcy.c:52
static void co_emcy_flush(co_emcy_t *emcy)
Sends any messages in the CAN frame buffer unless the inhibit time has not yet elapsed, in which case it sets the CAN timer.
Definition: emcy.c:851
A CAN frame buffer.
Definition: buf.h:47
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:825
#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
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
#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
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
can_timer_t * timer
A pointer to the CAN timer.
Definition: emcy.c:99
uint_least16_t ldle_u16(const void *ptr)
Loads a 16-bit unsigned integer in little-endian byte order.
Definition: endian.h:487
#define CO_SDO_AC_ERROR
SDO abort code: General error.
Definition: sdo.h:150
static int co_emcy_node_recv(const struct can_msg *msg, void *data)
The CAN receive callback function for a remote CANopen EMCY producer node.
Definition: emcy.c:551
static int co_emcy_set_1003(co_emcy_t *emcy)
Sets the value of CANopen object 1003 (Pre-defined error field).
Definition: emcy.c:587
#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 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
int can_buf_init(struct can_buf *buf, size_t size)
Initializes a CAN frame buffer.
Definition: buf.c:39
An EMCY message.
Definition: emcy.c:42
This header file is part of the CANopen library; it contains the Service Data Object (SDO) declaratio...
co_unsigned8_t er
The error register.
Definition: emcy.c:46
struct co_emcy_node * nodes[CO_NUM_NODES]
An array of pointers to remote nodes.
Definition: emcy.c:103
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
struct timespec inhibit
The time at which the next EMCY message may be sent.
Definition: emcy.c:101
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
void co_emcy_peek(const co_emcy_t *emcy, co_unsigned16_t *peec, co_unsigned8_t *per)
Retrieves, but does not pop, the most recent CANopen EMCY message from the stack. ...
Definition: emcy.c:456
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition: net.c:537
#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
void co_emcy_set_ind(co_emcy_t *emcy, co_emcy_ind_t *ind, void *data)
Sets the indication function invoked when a CANopen EMCY message is received.
Definition: emcy.c:497
static void co_emcy_node_destroy(struct co_emcy_node *node)
Destroys a remote CANopen EMCY producer node.
Definition: emcy.c:541
#define __likely(x)
Indicates to the compiler that the expression is most-likely true.
Definition: features.h:273
co_unsigned8_t n
Number of errors.
Definition: emcy.c:113
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
This header file is part of the CANopen library; it contains the emergency (EMCY) object declarations...
#define CAN_FLAG_EDL
The Extended Data Length (EDL) flag.
Definition: msg.h:55
co_emcy_ind_t * ind
A pointer to the indication function.
Definition: emcy.c:105
co_unsigned16_t eec
The emergency error code.
Definition: emcy.c:44
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition: net.c:562
void * data
A pointer to user-specified data for ind.
Definition: emcy.c:107
This header file is part of the utilities library; it contains the byte order (endianness) function d...
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.
co_emcy_t * co_emcy_create(can_net_t *net, co_dev_t *dev)
Creates a new CANopen EMCY producer/consumer service.
Definition: emcy.c:327
void co_emcy_destroy(co_emcy_t *emcy)
Destroys a CANopen EMCY producer/consumer service.
Definition: emcy.c:354
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
#define MAX(a, b)
Returns the maximum of a and b.
Definition: util.h:65
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
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition: type.h:44
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: emcy.c:56
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition: dev.h:56
#define CO_EMCY_COBID_FRAME
The bit in the EMCY COB-ID specifying whether to use an 11-bit (0) or 29-bit (1) CAN-ID.
Definition: emcy.h:35
Invalid argument.
Definition: errnum.h:129
void stle_u16(void *ptr, uint_least16_t x)
Stores a 16-bit unsigned integer in little-endian byte order.
Definition: endian.h:480
size_t nmsg
The number of messages in msgs.
Definition: emcy.c:93
co_unsigned8_t co_obj_get_subidx(const co_obj_t *obj, co_unsigned8_t maxsubidx, co_unsigned8_t *subidx)
Retrieves a list of sub-indices in a CANopen object.
Definition: obj.c:144
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
This header file is part of the utilities library; it contains the diagnostic declarations.
#define 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 co_emcy_push(co_emcy_t *emcy, co_unsigned16_t eec, co_unsigned8_t er, const uint8_t msef[5])
Pushes a CANopen EMCY message to the stack and broadcasts it if the EMCY producer service is active...
Definition: emcy.c:380
void co_emcy_get_ind(const co_emcy_t *emcy, co_emcy_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a CANopen EMCY message is received.
Definition: emcy.c:486
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
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...
A remote CANopen EMCY producer node.
Definition: emcy.c:50
struct co_emcy_msg * msgs
An array of EMCY messages. The first element is the most recent.
Definition: emcy.c:95
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_unsigned8_t id
The node-ID.
Definition: emcy.c:54
#define CO_SDO_AC_NO_SUB
SDO abort code: Sub-index does not exist.
Definition: sdo.h:132
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
struct can_buf buf
The CAN frame buffer.
Definition: emcy.c:97
A CANopen EMCY producer/consumer service.
Definition: emcy.c:83
int co_emcy_clear(co_emcy_t *emcy)
Clears the CANopen EMCY message stack and broadcasts the &#39;error reset/no error&#39; message if the EMCY p...
Definition: emcy.c:467
static int co_emcy_send(co_emcy_t *emcy, co_unsigned16_t eec, co_unsigned8_t er, const uint8_t msef[5])
Adds an EMCY message to the CAN frame buffer and sends it if possible.
Definition: emcy.c:808
#define CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames). ...
Definition: msg.h:47
static co_unsigned32_t co_1028_dn_ind(co_sub_t *sub, struct co_sdo_req *req, void *data)
The download indication function for (all sub-objects of) CANopen object 1028 (Emergency consumer obj...
Definition: emcy.c:732
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
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
can_net_t * net
A pointer to a CAN network interface.
Definition: emcy.c:85
can_net_t * co_emcy_get_net(const co_emcy_t *emcy)
Returns a pointer to the CAN network of an EMCY producer/consumer service.
Definition: emcy.c:364
co_sub_t * sub_1001_00
A pointer to the error register object.
Definition: emcy.c:89
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition: msg.h:73
static struct co_emcy_node * co_emcy_node_create(co_emcy_t *emcy, co_unsigned8_t id)
Creates a new remote CANopen EMCY producer node.
Definition: emcy.c:506
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition: obj.c:136
A CANopen object.
Definition: obj.h:32
This header file is part of the CANopen library; it contains the object dictionary declarations...
co_obj_t * obj_1003
A pointer to the pre-defined error field object.
Definition: emcy.c:91
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
Function not supported.
Definition: errnum.h:181
co_unsigned32_t ef[0xfe]
An array of standard error fields.
Definition: emcy.c:115
static int co_emcy_set_1028(co_emcy_t *emcy, co_unsigned8_t id, co_unsigned32_t cobid)
Sets the value of CANopen object 1028 (Emergency consumer object).
Definition: emcy.c:700
co_dev_t * dev
A pointer to a CANopen device.
Definition: emcy.c:87
void * co_obj_addressof_val(const co_obj_t *obj)
Returns the address of the value of a CANopen object.
Definition: obj.c:275
int co_emcy_pop(co_emcy_t *emcy, co_unsigned16_t *peec, co_unsigned8_t *per)
Pops the most recent CANopen EMCY message from the stack and broadcasts an &#39;error reset&#39; message if t...
Definition: emcy.c:426
static int co_emcy_timer(const struct timespec *tp, void *data)
The CAN timer callback function for an EMCY service.
Definition: emcy.c:796
co_sub_t * co_dev_find_sub(const co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx)
Finds a sub-object in the object dictionary of a CANopen device.
Definition: dev.c:290
The pre-defined error field.
Definition: emcy.c:111
co_dev_t * co_emcy_get_dev(const co_emcy_t *emcy)
Returns a pointer to the CANopen device of an EMCY producer/consumer service.
Definition: emcy.c:372
An informational message.
Definition: diag.h:45