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
44 co_unsigned16_t eec;
46 co_unsigned8_t er;
47};
48
54 co_unsigned8_t id;
57};
58
70 co_emcy_t *emcy, co_unsigned8_t id);
71
73static void co_emcy_node_destroy(struct co_emcy_node *node);
74
80static int co_emcy_node_recv(const struct can_msg *msg, void *data);
81
83struct __co_emcy {
93 size_t nmsg;
97 struct can_buf buf;
107 void *data;
108};
109
111struct co_1003 {
113 co_unsigned8_t n;
115 co_unsigned32_t ef[0xfe];
116};
117
124static int co_emcy_set_1003(co_emcy_t *emcy);
125
132static co_unsigned32_t co_1003_dn_ind(
133 co_sub_t *sub, struct co_sdo_req *req, void *data);
134
141static co_unsigned32_t co_1014_dn_ind(
142 co_sub_t *sub, struct co_sdo_req *req, void *data);
143
153static int co_emcy_set_1028(
154 co_emcy_t *emcy, co_unsigned8_t id, co_unsigned32_t cobid);
155
162static co_unsigned32_t co_1028_dn_ind(
163 co_sub_t *sub, struct co_sdo_req *req, void *data);
164
170static int co_emcy_timer(const struct timespec *tp, void *data);
171
182static int co_emcy_send(co_emcy_t *emcy, co_unsigned16_t eec, co_unsigned8_t er,
183 const uint8_t msef[5]);
184
189static void co_emcy_flush(co_emcy_t *emcy);
190
191void *
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
200void
201__co_emcy_free(void *ptr)
202{
203 free(ptr);
204}
205
206struct __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 }
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),
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
279error_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);
287error_create_timer:
288 can_buf_fini(&emcy->buf);
289error_init_buf:
290error_sub_1001_00:
291 set_errc(errc);
292 return NULL;
293}
294
295void
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
320
321 can_buf_fini(&emcy->buf);
322
323 free(emcy->msgs);
324}
325
326co_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
346error_init_emcy:
347 __co_emcy_free(emcy);
348error_alloc_emcy:
349 set_errc(errc);
350 return NULL;
351}
352
353void
355{
356 if (emcy) {
357 trace("destroying EMCY producer service");
358 __co_emcy_fini(emcy);
359 __co_emcy_free(emcy);
360 }
361}
362
363can_net_t *
365{
366 assert(emcy);
367
368 return emcy->net;
369}
370
371co_dev_t *
373{
374 assert(emcy);
375
376 return emcy->dev;
377}
378
379int
380co_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
425int
426co_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
455void
456co_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
466int
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
485void
486co_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
496void
498{
499 assert(emcy);
500
501 emcy->ind = ind;
502 emcy->data = data;
503}
504
505struct co_emcy_node *
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
533error_create_recv:
534 free(node);
535error_alloc_node:
536 set_errc(errc);
537 return NULL;
538}
539
540void
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
550static int
551co_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
586static 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
607static co_unsigned32_t
608co_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))) {
625 goto error;
626 }
627
628 // Only the value 0 is allowed.
629 assert(type == CO_DEFTYPE_UNSIGNED8);
630 if (__unlikely(val.u8)) {
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
643error:
644 co_val_fini(type, &val);
645 return ac;
646}
647
648static co_unsigned32_t
649co_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)) {
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
690 goto error;
691 }
692
693 co_sub_dn(sub, &val);
694error:
695 co_val_fini(type, &val);
696 return ac;
697}
698
699static int
700co_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) {
725 emcy->nodes[id - 1] = NULL;
726 }
727
728 return 0;
729}
730
731static co_unsigned32_t
732co_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)) {
750 goto error;
751 }
752 co_unsigned8_t maxid = MIN(co_obj_get_val_u8(co_sub_get_obj(sub), 0),
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)) {
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
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);
790error:
791 co_val_fini(type, &val);
792 return ac;
793}
794
795static int
796co_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
807static int
808co_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
850static 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
This header file is part of the CAN library; it contains the CAN frame buffer declarations.
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
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
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
int can_buf_init(struct can_buf *buf, size_t size)
Initializes a CAN frame buffer.
Definition: buf.c:39
void can_buf_fini(struct can_buf *buf)
Finalizes a CAN frame buffer.
Definition: buf.c:67
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
This header file is part of the CANopen library; it contains the device description declarations.
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
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
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition: dev.h:56
This header file is part of the utilities library; it contains the diagnostic declarations.
@ DIAG_INFO
An informational message.
Definition: diag.h:45
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Definition: diag.c:156
void co_emcy_destroy(co_emcy_t *emcy)
Destroys a CANopen EMCY producer/consumer service.
Definition: emcy.c:354
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
static int co_emcy_timer(const struct timespec *tp, void *data)
The CAN timer callback function for an EMCY service.
Definition: emcy.c:796
static void co_emcy_node_destroy(struct co_emcy_node *node)
Destroys a remote CANopen EMCY producer node.
Definition: emcy.c:541
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
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
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
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
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 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
int co_emcy_clear(co_emcy_t *emcy)
Clears the CANopen EMCY message stack and broadcasts the 'error reset/no error' message if the EMCY p...
Definition: emcy.c:467
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
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 'error reset' message if t...
Definition: emcy.c:426
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
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
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
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
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_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
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_flush(co_emcy_t *emcy)
Sends any messages in the CAN frame buffer unless the inhibit time has not yet elapsed,...
Definition: emcy.c:851
This header file is part of the CANopen library; it contains the emergency (EMCY) object declarations...
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
#define CO_EMCY_COBID_VALID
The bit in the EMCY COB-ID specifying whether the EMCY exists and is valid.
Definition: emcy.h:29
#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
This header file is part of the utilities library; it contains the byte order (endianness) function d...
void stle_u16(void *ptr, uint_least16_t x)
Stores a 16-bit unsigned integer in little-endian byte order.
Definition: endian.h:480
void stle_u32(void *ptr, uint_least32_t x)
Stores a 32-bit unsigned integer in little-endian byte order.
Definition: endian.h:534
uint_least16_t ldle_u16(const void *ptr)
Loads a 16-bit unsigned integer in little-endian byte order.
Definition: endian.h:487
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:825
@ ERRNUM_NOSYS
Function not supported.
Definition: errnum.h:181
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:129
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
#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 CANopen library; it contains the object dictionary declarations.
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
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
void * co_obj_addressof_val(const co_obj_t *obj)
Returns the address of the value of a CANopen object.
Definition: obj.c:275
co_unsigned16_t co_obj_get_idx(const co_obj_t *obj)
Returns the index of a CANopen object.
Definition: obj.c:136
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
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
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
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
This header file is part of the CANopen library; it contains the Service Data Object (SDO) declaratio...
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
#define CO_SDO_AC_ERROR
SDO abort code: General error.
Definition: sdo.h:150
#define CO_SDO_AC_NO_SUB
SDO abort code: Sub-index does not exist.
Definition: sdo.h:132
#define CO_SDO_AC_PARAM_VAL
SDO abort code: Invalid value for parameter (download only).
Definition: sdo.h:135
#define CO_SDO_AC_NO_WRITE
SDO abort code: Attempt to write a read only object.
Definition: sdo.h:90
#define MIN(a, b)
Returns the minimum of a and b.
Definition: util.h:57
#define MAX(a, b)
Returns the maximum of a and b.
Definition: util.h:65
#define CAN_MASK_EID
The mask used to extract the 29-bit Extended Identifier from a CAN frame.
Definition: msg.h:34
#define CAN_FLAG_RTR
The Remote Transmission Request (RTR) flag (unavailable in CAN FD format frames).
Definition: msg.h:47
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition: msg.h:73
#define CAN_FLAG_IDE
The Identifier Extension (IDE) flag.
Definition: msg.h:41
#define CAN_MASK_BID
The mask used to extract the 11-bit Base Identifier from a CAN frame.
Definition: msg.h:31
#define CAN_MSG_INIT
The static initializer for can_msg.
Definition: msg.h:114
#define CAN_FLAG_EDL
The Extended Data Length (EDL) flag.
Definition: msg.h:55
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
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
can_timer_t * can_timer_create(void)
Creates a new CAN timer.
Definition: net.c:382
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
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 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
void can_recv_destroy(can_recv_t *recv)
Destroys a CAN frame receiver.
Definition: net.c:562
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
can_recv_t * can_recv_create(void)
Creates a new CAN frame receiver.
Definition: net.c:537
void can_timer_destroy(can_timer_t *timer)
Destroys a CAN timer.
Definition: net.c:407
This is the internal header file of the CANopen library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
A CAN network interface.
Definition: net.c:37
A CAN frame receiver.
Definition: net.c:99
A CAN timer.
Definition: net.c:63
A CANopen device.
Definition: dev.c:38
A CANopen EMCY producer/consumer service.
Definition: emcy.c:83
struct can_buf buf
The CAN frame buffer.
Definition: emcy.c:97
co_obj_t * obj_1003
A pointer to the pre-defined error field object.
Definition: emcy.c:91
co_dev_t * dev
A pointer to a CANopen device.
Definition: emcy.c:87
void * data
A pointer to user-specified data for ind.
Definition: emcy.c:107
can_timer_t * timer
A pointer to the CAN timer.
Definition: emcy.c:99
co_sub_t * sub_1001_00
A pointer to the error register object.
Definition: emcy.c:89
size_t nmsg
The number of messages in msgs.
Definition: emcy.c:93
struct co_emcy_node * nodes[CO_NUM_NODES]
An array of pointers to remote nodes.
Definition: emcy.c:103
struct timespec inhibit
The time at which the next EMCY message may be sent.
Definition: emcy.c:101
co_emcy_ind_t * ind
A pointer to the indication function.
Definition: emcy.c:105
can_net_t * net
A pointer to a CAN network interface.
Definition: emcy.c:85
struct co_emcy_msg * msgs
An array of EMCY messages. The first element is the most recent.
Definition: emcy.c:95
A CANopen object.
Definition: obj.h:32
A CANopen sub-object.
Definition: obj.h:54
A CAN frame buffer.
Definition: buf.h:47
A CAN or CAN FD format frame.
Definition: msg.h:88
uint_least8_t data[CAN_MSG_MAX_LEN]
The frame payload (in case of a data frame).
Definition: msg.h:103
uint_least32_t id
The identifier (11 or 29 bits, depending on the CAN_FLAG_IDE flag).
Definition: msg.h:90
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
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
The pre-defined error field.
Definition: emcy.c:111
co_unsigned32_t ef[0xfe]
An array of standard error fields.
Definition: emcy.c:115
co_unsigned8_t n
Number of errors.
Definition: emcy.c:113
An EMCY message.
Definition: emcy.c:42
co_unsigned8_t er
The error register.
Definition: emcy.c:46
co_unsigned16_t eec
The emergency error code.
Definition: emcy.c:44
A remote CANopen EMCY producer node.
Definition: emcy.c:50
can_recv_t * recv
A pointer to the CAN frame receiver.
Definition: emcy.c:56
co_emcy_t * emcy
A pointer to the EMCY service.
Definition: emcy.c:52
co_unsigned8_t id
The node-ID.
Definition: emcy.c:54
A CANopen SDO upload/download request.
Definition: sdo.h:178
A time type with nanosecond resolution.
Definition: time.h:83
#define CO_DEFTYPE_UNSIGNED8
The data type (and object index) of an 8-bit unsigned integer.
Definition: type.h:44
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
A union of the CANopen static data types.
Definition: val.h:163
This header file is part of the utilities library; it contains the time function declarations.
int timespec_cmp(const void *p1, const void *p2)
Compares two times.
Definition: time.h:224
void timespec_add_usec(struct timespec *tp, uint_least64_t usec)
Adds usec microseconds to the time at tp.
Definition: time.h:138
This header file is part of the CANopen library; it contains the CANopen value declarations.
void co_val_fini(co_unsigned16_t type, void *val)
Finalizes a value of the specified data type.
Definition: val.c:273