Lely core libraries 2.3.4
gw.c
Go to the documentation of this file.
1
24#include "co.h"
25
26#if !LELY_NO_CO_GW
27
28#include <lely/co/csdo.h>
29#include <lely/co/dev.h>
30#include <lely/util/errnum.h>
31#if !LELY_NO_CO_EMCY
32#include <lely/co/emcy.h>
33#endif
34#include <lely/co/gw.h>
35#if !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
36#include <lely/co/lss.h>
37#endif
38#include <lely/co/nmt.h>
39#include <lely/co/obj.h>
40#if !LELY_NO_CO_RPDO
41#include <lely/co/rpdo.h>
42#endif
43#include <lely/co/sdo.h>
44#if !LELY_NO_CO_SYNC
45#include <lely/co/sync.h>
46#endif
47#if !LELY_NO_CO_TIME
48#include <lely/co/time.h>
49#endif
50#if !LELY_NO_CO_TPDO
51#include <lely/co/tpdo.h>
52#endif
53
54#include <assert.h>
55#include <stdlib.h>
56
57struct co_gw_job;
58
60struct co_gw_net {
64 co_unsigned16_t id;
68 co_unsigned8_t def;
69#if !LELY_NO_CO_CSDO
72#endif
77 unsigned bootup_ind : 1;
78#if !LELY_NO_CO_CSDO
81#endif
82#if !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
84 struct co_gw_job *lss;
85#endif
89 void *cs_data;
90#if !LELY_NO_CO_NG
91#if !LELY_NO_CO_MASTER
95 void *ng_data;
96#endif
100 void *lg_data;
101#endif
105 void *hb_data;
109 void *st_data;
110#if !LELY_NO_CO_MASTER
118 void *dn_data;
122 void *up_data;
123#endif
124};
125
127static struct co_gw_net *co_gw_net_create(
128 co_gw_t *gw, co_unsigned16_t id, co_nmt_t *nmt);
129
131static void co_gw_net_destroy(struct co_gw_net *net);
132
139static void co_gw_net_cs_ind(co_nmt_t *nmt, co_unsigned8_t cs, void *data);
140#if !LELY_NO_CO_NG
141#if !LELY_NO_CO_MASTER
148static void co_gw_net_ng_ind(co_nmt_t *nmt, co_unsigned8_t id, int state,
149 int reason, void *data);
150#endif
157static void co_gw_net_lg_ind(co_nmt_t *nmt, int state, void *data);
158#endif // !LELY_NO_CO_NG
165static void co_gw_net_hb_ind(co_nmt_t *nmt, co_unsigned8_t id, int state,
166 int reason, void *data);
173static void co_gw_net_st_ind(co_nmt_t *nmt, co_unsigned8_t id,
174 co_unsigned8_t st, void *data);
175#if !LELY_NO_CO_NMT_BOOT
182static void co_gw_net_boot_ind(co_nmt_t *nmt, co_unsigned8_t id,
183 co_unsigned8_t st, char es, void *data);
184#endif
185#if !LELY_NO_CO_NMT_BOOT || !LELY_NO_CO_NMT_CFG
193static void co_gw_net_dn_ind(co_nmt_t *nmt, co_unsigned8_t id,
194 co_unsigned16_t idx, co_unsigned8_t subidx, size_t size,
195 size_t nbyte, void *data);
203static void co_gw_net_up_ind(co_nmt_t *nmt, co_unsigned8_t id,
204 co_unsigned16_t idx, co_unsigned8_t subidx, size_t size,
205 size_t nbyte, void *data);
206#endif
207#if !LELY_NO_CO_SYNC
212static void co_gw_net_sync_ind(co_sync_t *sync, co_unsigned8_t cnt, void *data);
213#endif
214#if !LELY_NO_CO_TIME
219static void co_gw_net_time_ind(
220 co_time_t *time, const struct timespec *tp, void *data);
221#endif
222#if !LELY_NO_CO_EMCY
227static void co_gw_net_emcy_ind(co_emcy_t *emcy, co_unsigned8_t id,
228 co_unsigned16_t ec, co_unsigned8_t er, co_unsigned8_t msef[5],
229 void *data);
230#endif
231#if !LELY_NO_CO_RPDO
236static void co_gw_net_rpdo_ind(co_rpdo_t *pdo, co_unsigned32_t ac,
237 const void *ptr, size_t n, void *data);
238#endif
239
241struct co_gw_job {
243 struct co_gw_job **pself;
245 struct co_gw_net *net;
247 void *data;
249 void (*dtor)(void *data);
252};
253
255#define CO_GW_JOB_SIZE offsetof(struct co_gw_job, req)
256
258static struct co_gw_job *co_gw_job_create(struct co_gw_job **pself,
259 struct co_gw_net *net, void *data, void (*dtor)(void *data),
260 const struct co_gw_req *req);
262static void co_gw_job_destroy(struct co_gw_job *job);
263
265static void co_gw_job_remove(struct co_gw_job *job);
266
267#if !LELY_NO_CO_CSDO
269static struct co_gw_job *co_gw_job_create_sdo(struct co_gw_job **pself,
270 struct co_gw_net *net, co_unsigned8_t id,
271 const struct co_gw_req *req);
273static void co_gw_job_sdo_dtor(void *data);
275static void co_gw_job_sdo_up_con(co_csdo_t *sdo, co_unsigned16_t idx,
276 co_unsigned8_t subidx, co_unsigned32_t ac, const void *ptr,
277 size_t n, void *data);
279static void co_gw_job_sdo_dn_con(co_csdo_t *sdo, co_unsigned16_t idx,
280 co_unsigned8_t subidx, co_unsigned32_t ac, void *data);
282static void co_gw_job_sdo_ind(const co_csdo_t *sdo, co_unsigned16_t idx,
283 co_unsigned8_t subidx, size_t size, size_t nbyte, void *data);
284#endif
285
286#if !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
288static struct co_gw_job *co_gw_job_create_lss(struct co_gw_job **pself,
289 struct co_gw_net *net, const struct co_gw_req *req);
294static void co_gw_job_lss_cs_ind(co_lss_t *lss, co_unsigned8_t cs, void *data);
299static void co_gw_job_lss_err_ind(co_lss_t *lss, co_unsigned8_t cs,
300 co_unsigned8_t err, co_unsigned8_t spec, void *data);
302static void co_gw_job_lss_lssid_ind(co_lss_t *lss, co_unsigned8_t cs,
303 co_unsigned32_t id, void *data);
305static void co_gw_job_lss_nid_ind(co_lss_t *lss, co_unsigned8_t cs,
306 co_unsigned8_t id, void *data);
308static void co_gw_job_lss_scan_ind(co_lss_t *lss, co_unsigned8_t cs,
309 const struct co_id *id, void *data);
310#endif
311
335
336#if !LELY_NO_CO_CSDO
338static int co_gw_recv_sdo_up(co_gw_t *gw, co_unsigned16_t net,
339 co_unsigned8_t node, const struct co_gw_req *req);
341static int co_gw_recv_sdo_dn(co_gw_t *gw, co_unsigned16_t net,
342 co_unsigned8_t node, const struct co_gw_req *req);
345 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
346#endif
347
348#if !LELY_NO_CO_RPDO
350static int co_gw_recv_set_rpdo(
351 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
352#endif
353#if !LELY_NO_CO_TPDO
355static int co_gw_recv_set_tpdo(
356 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
357#endif
358#if !LELY_NO_CO_RPDO
360static int co_gw_recv_pdo_read(
361 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
362#endif
363#if !LELY_NO_CO_TPDO
365static int co_gw_recv_pdo_write(
366 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
367#endif
368
369#if !LELY_NO_CO_MASTER
371static int co_gw_recv_nmt_cs(co_gw_t *gw, co_unsigned16_t net,
372 co_unsigned8_t node, co_unsigned8_t cs,
373 const struct co_gw_req *req);
374#if !LELY_NO_CO_NG
376static int co_gw_recv_nmt_set_ng(co_gw_t *gw, co_unsigned16_t net,
377 co_unsigned8_t node, const struct co_gw_req *req);
378#endif
379#endif // !LELY_NO_CO_MASTER
381static int co_gw_recv_nmt_set_hb(co_gw_t *gw, co_unsigned16_t net,
382 co_unsigned8_t node, const struct co_gw_req *req);
383
385static int co_gw_recv_init(
386 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
388static int co_gw_recv_set_hb(
389 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
391static int co_gw_recv_set_id(
392 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
393#if !LELY_NO_CO_EMCY
395static int co_gw_recv_set_emcy(co_gw_t *gw, co_unsigned16_t net,
396 co_unsigned8_t node, const struct co_gw_req *req);
397#endif
399static int co_gw_recv_set_cmd_timeout(co_gw_t *gw, const struct co_gw_req *req);
402 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
403
405static int co_gw_recv_set_net(co_gw_t *gw, const struct co_gw_req *req);
407static int co_gw_recv_set_node(
408 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
410static int co_gw_recv_get_version(
411 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
412
413#if !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
415static int co_gw_recv_lss_switch(
416 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
419 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
421static int co_gw_recv_lss_set_id(
422 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
424static int co_gw_recv_lss_set_rate(
425 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
428 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
430static int co_gw_recv_lss_store(
431 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
433static int co_gw_recv_lss_get_lssid(
434 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
436static int co_gw_recv_lss_get_id(
437 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
439static int co_gw_recv_lss_id_slave(
440 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
443 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
444
446static int co_gw_recv__lss_slowscan(
447 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
449static int co_gw_recv__lss_fastscan(
450 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req);
451#endif
452
454static int co_gw_send_con(co_gw_t *gw, const struct co_gw_req *req, int iec,
455 co_unsigned32_t ac);
457static int co_gw_send_ec(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
458 co_unsigned8_t st, int iec);
460static int co_gw_send_srv(co_gw_t *gw, const struct co_gw_srv *srv);
461
463static inline int errnum2iec(errnum_t errnum);
464
465const char *
467{
468 switch (iec) {
469 case CO_GW_IEC_BAD_SRV: return "Request not supported";
470 case CO_GW_IEC_SYNTAX: return "Syntax error";
471 case CO_GW_IEC_INTERN:
472 return "Request not processed due to internal state";
473 case CO_GW_IEC_TIMEOUT: return "Time-out";
474 case CO_GW_IEC_NO_DEF_NET: return "No default net set";
475 case CO_GW_IEC_NO_DEF_NODE: return "No default node set";
476 case CO_GW_IEC_BAD_NET: return "Unsupported net";
477 case CO_GW_IEC_BAD_NODE: return "Unsupported node";
478 case CO_GW_IEC_NG_OCCURRED: return "Lost guarding message";
479 case CO_GW_IEC_LG_OCCURRED: return "Lost connection";
480 case CO_GW_IEC_HB_RESOLVED: return "Heartbeat started";
481 case CO_GW_IEC_HB_OCCURRED: return "Heartbeat lost";
482 case CO_GW_IEC_ST_OCCURRED: return "Wrong NMT state";
483 case CO_GW_IEC_BOOTUP: return "Boot-up";
484 case CO_GW_IEC_CAN_PASSIVE: return "Error passive";
485 case CO_GW_IEC_CAN_BUSOFF: return "Bus off";
486 case CO_GW_IEC_CAN_OVERFLOW: return "CAN buffer overflow";
487 case CO_GW_IEC_CAN_INIT: return "CAN init";
488 case CO_GW_IEC_CAN_ACTIVE: return "CAN active";
489 case CO_GW_IEC_PDO_INUSE: return "PDO already used";
490 case CO_GW_IEC_PDO_LEN: return "PDO length exceeded";
491 case CO_GW_IEC_LSS: return "LSS error";
492 case CO_GW_IEC_LSS_ID: return "LSS node-ID not supported";
493 case CO_GW_IEC_LSS_RATE: return "LSS bit-rate not supported";
494 case CO_GW_IEC_LSS_PARAM: return "LSS parameter storing failed";
496 return "LSS command failed because of media error";
497 case CO_GW_IEC_NO_MEM: return "Running out of memory";
498 default: return "Unknown error code";
499 }
500}
501
502void *
503__co_gw_alloc(void)
504{
505 void *ptr = malloc(sizeof(struct __co_gw));
506#if !LELY_NO_ERRNO
507 if (!ptr)
508 set_errc(errno2c(errno));
509#endif
510 return ptr;
511}
512
513void
514__co_gw_free(void *ptr)
515{
516 free(ptr);
517}
518
519struct __co_gw *
520__co_gw_init(struct __co_gw *gw)
521{
522 assert(gw);
523
524 for (co_unsigned16_t id = 1; id <= CO_GW_NUM_NET; id++)
525 gw->net[id - 1] = NULL;
526
527 gw->timeout = 0;
528 gw->def = 0;
529
530 gw->send_func = NULL;
531 gw->send_data = NULL;
532
533 gw->rate_func = NULL;
534 gw->rate_data = NULL;
535
536 return gw;
537}
538
539void
540__co_gw_fini(struct __co_gw *gw)
541{
542 assert(gw);
543
544 for (co_unsigned16_t id = 1; id <= CO_GW_NUM_NET; id++)
545 co_gw_net_destroy(gw->net[id - 1]);
546}
547
548co_gw_t *
550{
551 int errc = 0;
552
553 co_gw_t *gw = __co_gw_alloc();
554 if (!gw) {
555 errc = get_errc();
556 goto error_alloc_gw;
557 }
558
559 if (!__co_gw_init(gw)) {
560 errc = get_errc();
561 goto error_init_gw;
562 }
563
564 return gw;
565
566error_init_gw:
567 __co_gw_free(gw);
568error_alloc_gw:
569 set_errc(errc);
570 return NULL;
571}
572
573void
575{
576 if (gw) {
577 __co_gw_fini(gw);
578 __co_gw_free(gw);
579 }
580}
581
582int
583co_gw_init_net(co_gw_t *gw, co_unsigned16_t id, co_nmt_t *nmt)
584{
585 assert(gw);
586
587 if (!id)
589
590 if (co_gw_fini_net(gw, id) == -1)
591 return -1;
592
593 gw->net[id - 1] = co_gw_net_create(gw, id, nmt);
594 return gw->net[id - 1] ? 0 : -1;
595}
596
597int
598co_gw_fini_net(co_gw_t *gw, co_unsigned16_t id)
599{
600 assert(gw);
601
602 if (!id || id > CO_GW_NUM_NET) {
604 return -1;
605 }
606
607 co_gw_net_destroy(gw->net[id - 1]);
608 gw->net[id - 1] = NULL;
609
610 return 0;
611}
612
613int
614co_gw_recv(co_gw_t *gw, const struct co_gw_req *req)
615{
616 assert(gw);
617 assert(req);
618
619 if (req->size < sizeof(*req)) {
621 return -1;
622 }
623
624 int iec = 0;
625
626 // Obtain the network-ID for node- and network-level requests. If the
627 // network-ID is 0, use the default ID.
628 co_unsigned16_t net = gw->def;
629 switch (req->srv) {
630#if !LELY_NO_CO_CSDO
631 case CO_GW_SRV_SDO_UP:
632 case CO_GW_SRV_SDO_DN:
634#endif
635#if !LELY_NO_CO_RPDO
637#endif
638#if !LELY_NO_CO_TPDO
640#endif
641#if !LELY_NO_CO_RPDO
643#endif
644#if !LELY_NO_CO_TPDO
646#endif
647#if !LELY_NO_CO_MASTER
655#endif
658 case CO_GW_SRV_INIT:
659 case CO_GW_SRV_SET_HB:
660 case CO_GW_SRV_SET_ID:
661#if !LELY_NO_CO_EMCY
664#endif
668#if !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
681#endif
682 if (req->size < sizeof(struct co_gw_req_net)) {
684 return -1;
685 }
686 struct co_gw_req_net *par = (struct co_gw_req_net *)req;
687 if (par->net)
688 net = par->net;
689 if (!net) {
691 goto error;
692 } else if (net > CO_GW_NUM_NET || !gw->net[net - 1]) {
693 iec = CO_GW_IEC_BAD_NET;
694 goto error;
695 }
696 break;
697 }
698 assert(net <= CO_GW_NUM_NET);
699 assert(!net || gw->net[net - 1]);
700
701 // Obtain the node-ID for node-level requests. If the node-ID is 0xff,
702 // use the default ID.
703 co_unsigned8_t node = net ? gw->net[net - 1]->def : 0;
704 switch (req->srv) {
705#if !LELY_NO_CO_CSDO
706 case CO_GW_SRV_SDO_UP:
707 case CO_GW_SRV_SDO_DN:
708#endif
709#if !LELY_NO_CO_MASTER
717#endif
720#if !LELY_NO_CO_EMCY
723#endif
724 if (req->size < sizeof(struct co_gw_req_node)) {
726 return -1;
727 }
728 struct co_gw_req_node *par = (struct co_gw_req_node *)req;
729 if (par->node != 0xff)
730 node = par->node;
731 if (node > CO_NUM_NODES) {
732 iec = CO_GW_IEC_BAD_NODE;
733 goto error;
734 }
735 break;
736 }
737
738 // Except for the NMT commands, node-level request require a non-zero
739 // node-ID.
740 switch (req->srv) {
741#if !LELY_NO_CO_CSDO
742 case CO_GW_SRV_SDO_UP:
743 case CO_GW_SRV_SDO_DN:
744#endif
745#if !LELY_NO_CO_MASTER
748#endif
751#if !LELY_NO_CO_EMCY
754#endif
755 if (!node) {
757 goto error;
758 }
759 }
760
761 switch (req->srv) {
762#if !LELY_NO_CO_CSDO
763 case CO_GW_SRV_SDO_UP:
764 trace("gateway: received 'SDO upload' request");
765 return co_gw_recv_sdo_up(gw, net, node, req);
766 case CO_GW_SRV_SDO_DN:
767 trace("gateway: received 'SDO download' request");
768 return co_gw_recv_sdo_dn(gw, net, node, req);
770 trace("gateway: received 'Configure SDO time-out' request");
771 return co_gw_recv_set_sdo_timeout(gw, net, req);
772#endif
773#if !LELY_NO_CO_RPDO
775 trace("gateway: received 'Configure RPDO' request");
776 return co_gw_recv_set_rpdo(gw, net, req);
777#endif
778#if !LELY_NO_CO_TPDO
780 trace("gateway: received 'Configure TPDO' request");
781 return co_gw_recv_set_tpdo(gw, net, req);
782#endif
783#if !LELY_NO_CO_RPDO
785 trace("gateway: received 'Read PDO data' request");
786 return co_gw_recv_pdo_read(gw, net, req);
787#endif
788#if !LELY_NO_CO_TPDO
790 trace("gateway: received 'Write PDO data' request");
791 return co_gw_recv_pdo_write(gw, net, req);
792#endif
793#if !LELY_NO_CO_MASTER
795 trace("gateway: received 'Start node' request");
796 return co_gw_recv_nmt_cs(gw, net, node, CO_NMT_CS_START, req);
798 trace("gateway: received 'Stop node' request");
799 return co_gw_recv_nmt_cs(gw, net, node, CO_NMT_CS_STOP, req);
801 trace("gateway: received 'Set node to pre-operational' request");
802 return co_gw_recv_nmt_cs(
803 gw, net, node, CO_NMT_CS_ENTER_PREOP, req);
805 trace("gateway: received 'Reset node' request");
806 return co_gw_recv_nmt_cs(
807 gw, net, node, CO_NMT_CS_RESET_NODE, req);
809 trace("gateway: received 'Reset communication' request");
810 return co_gw_recv_nmt_cs(
811 gw, net, node, CO_NMT_CS_RESET_COMM, req);
812#if !LELY_NO_CO_NG
815 trace("gateway: received '%s node guarding' request",
817 ? "Enable"
818 : "Disable");
819 return co_gw_recv_nmt_set_ng(gw, net, node, req);
820#endif
821#endif // !LELY_NO_CO_MASTER
824 trace("gateway: received '%s heartbeat consumer' request",
826 ? "Start"
827 : "Disable");
828 return co_gw_recv_nmt_set_hb(gw, net, node, req);
829 case CO_GW_SRV_INIT:
830 trace("gateway: received 'Initialize gateway' request");
831 return co_gw_recv_init(gw, net, req);
832 case CO_GW_SRV_SET_HB:
833 trace("gateway: received 'Set heartbeat producer' request");
834 return co_gw_recv_set_hb(gw, net, req);
835 case CO_GW_SRV_SET_ID:
836 trace("gateway: received 'Set node-ID' request");
837 return co_gw_recv_set_id(gw, net, req);
838#if !LELY_NO_CO_EMCY
841 trace("gateway: received '%s emergency consumer' request",
842 // clang-format off
844 ? "Start" : "Stop");
845 // clang-format on
846 return co_gw_recv_set_emcy(gw, net, node, req);
847#endif
849 trace("gateway: received 'Set command time-out' request");
850 return co_gw_recv_set_cmd_timeout(gw, req);
852 trace("gateway: received 'Boot-up forwarding' request");
853 return co_gw_recv_set_bootup_ind(gw, net, req);
855 trace("gateway: received 'Set default network' request");
856 return co_gw_recv_set_net(gw, req);
858 trace("gateway: received 'Set default node-ID' request");
859 return co_gw_recv_set_node(gw, net, req);
861 trace("gateway: received 'Get version' request");
862 return co_gw_recv_get_version(gw, net, req);
864 trace("gateway: received 'Set command size' request");
865 // We cannot guarantee a lack of memory resources will never
866 // occur.
867 return co_gw_send_con(gw, req, CO_GW_IEC_NO_MEM, 0);
868#if !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
870 trace("gateway: received 'LSS switch state global' request");
871 return co_gw_recv_lss_switch(gw, net, req);
873 trace("gateway: received 'LSS switch state selective' request");
874 return co_gw_recv_lss_switch_sel(gw, net, req);
876 trace("gateway: received 'LSS configure node-ID' request");
877 return co_gw_recv_lss_set_id(gw, net, req);
879 trace("gateway: received 'LSS configure bit-rate' request");
880 return co_gw_recv_lss_set_rate(gw, net, req);
882 trace("gateway: received 'LSS activate new bit-rate' request");
883 return co_gw_recv_lss_switch_rate(gw, net, req);
885 trace("gateway: received 'LSS store configuration' request");
886 return co_gw_recv_lss_store(gw, net, req);
888 trace("gateway: received 'Inquire LSS address' request");
889 return co_gw_recv_lss_get_lssid(gw, net, req);
891 trace("gateway: received 'LSS inquire node-ID' request");
892 return co_gw_recv_lss_get_id(gw, net, req);
894 trace("gateway: received 'LSS identify remote slave' request");
895 return co_gw_recv_lss_id_slave(gw, net, req);
897 trace("gateway: received 'LSS identify non-configure remote slaves' request");
898 return co_gw_recv_lss_id_non_cfg_slave(gw, net, req);
900 trace("gateway: received 'LSS Slowscan' request");
901 return co_gw_recv__lss_slowscan(gw, net, req);
903 trace("gateway: received 'LSS Fastscan' request");
904 return co_gw_recv__lss_fastscan(gw, net, req);
905#endif
906 default: iec = CO_GW_IEC_BAD_SRV; goto error;
907 }
908
909error:
910 return co_gw_send_con(gw, req, iec, 0);
911}
912
913void
914co_gw_get_send_func(const co_gw_t *gw, co_gw_send_func_t **pfunc, void **pdata)
915{
916 assert(gw);
917
918 if (pfunc)
919 *pfunc = gw->send_func;
920 if (pdata)
921 *pdata = gw->send_data;
922}
923
924void
926{
927 assert(gw);
928
929 gw->send_func = func;
930 gw->send_data = data;
931}
932
933void
934co_gw_get_rate_func(const co_gw_t *gw, co_gw_rate_func_t **pfunc, void **pdata)
935{
936 assert(gw);
937
938 if (pfunc)
939 *pfunc = gw->rate_func;
940 if (pdata)
941 *pdata = gw->rate_data;
942}
943
944void
946{
947 assert(gw);
948
949 gw->rate_func = func;
950 gw->rate_data = data;
951}
952
953static struct co_gw_net *
954co_gw_net_create(co_gw_t *gw, co_unsigned16_t id, co_nmt_t *nmt)
955{
956 assert(gw);
957 assert(nmt);
958
959 struct co_gw_net *net = malloc(sizeof(*net));
960 if (!net) {
961#if !LELY_NO_ERRNO
962 set_errc(errno2c(errno));
963#endif
964 return NULL;
965 }
966
967 net->gw = gw;
968 net->id = id;
969 net->nmt = nmt;
970
971 net->def = 0;
972#if !LELY_NO_CO_CSDO
973 net->timeout = 0;
974#endif
975 net->bootup_ind = 1;
976
977#if !LELY_NO_CO_CSDO
978 for (co_unsigned8_t id = 1; id <= CO_NUM_NODES; id++)
979 net->sdo[id - 1] = NULL;
980#endif
981#if !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
982 net->lss = NULL;
983#endif
984
985 co_nmt_get_cs_ind(net->nmt, &net->cs_ind, &net->cs_data);
987#if !LELY_NO_CO_NG
988#if !LELY_NO_CO_MASTER
989 co_nmt_get_ng_ind(net->nmt, &net->ng_ind, &net->ng_data);
991#endif
992 co_nmt_get_lg_ind(net->nmt, &net->lg_ind, &net->lg_data);
994#endif
995 co_nmt_get_hb_ind(net->nmt, &net->hb_ind, &net->hb_data);
997 co_nmt_get_st_ind(net->nmt, &net->st_ind, &net->st_data);
999#if !LELY_NO_CO_NMT_BOOT
1000 co_nmt_get_boot_ind(net->nmt, &net->boot_ind, &net->boot_data);
1002#endif
1003#if !LELY_NO_CO_NMT_BOOT || !LELY_NO_CO_NMT_CFG
1004 co_nmt_get_dn_ind(net->nmt, &net->dn_ind, &net->dn_data);
1006 co_nmt_get_dn_ind(net->nmt, &net->up_ind, &net->up_data);
1008#endif
1009
1010#if !LELY_NO_CO_SYNC
1011 co_sync_t *sync = co_nmt_get_sync(nmt);
1012 if (sync)
1014#endif
1015
1016#if !LELY_NO_CO_TIME
1017 co_time_t *time = co_nmt_get_time(nmt);
1018 if (time)
1020#endif
1021
1022#if !LELY_NO_CO_EMCY
1023 co_emcy_t *emcy = co_nmt_get_emcy(nmt);
1024 if (emcy)
1026#endif
1027
1028#if !LELY_NO_CO_RPDO
1029 if (co_nmt_get_st(net->nmt) == CO_NMT_ST_START) {
1030 for (co_unsigned16_t i = 1; i <= 512; i++) {
1031 co_rpdo_t *pdo = co_nmt_get_rpdo(nmt, i);
1032 if (pdo)
1034 }
1035 }
1036#endif
1037
1038 return net;
1039}
1040
1041static void
1043{
1044 if (net) {
1045#if !LELY_NO_CO_RPDO
1046 for (co_unsigned16_t i = 1; i <= 512; i++) {
1047 co_rpdo_t *pdo = co_nmt_get_rpdo(net->nmt, i);
1048 if (pdo)
1049 co_rpdo_set_ind(pdo, NULL, NULL);
1050 }
1051#endif
1052
1053#if !LELY_NO_CO_EMCY
1054 co_emcy_t *emcy = co_nmt_get_emcy(net->nmt);
1055 if (emcy)
1056 co_emcy_set_ind(emcy, NULL, NULL);
1057#endif
1058
1059#if !LELY_NO_CO_TIME
1060 co_time_t *time = co_nmt_get_time(net->nmt);
1061 if (time)
1062 co_time_set_ind(time, NULL, NULL);
1063#endif
1064
1065#if !LELY_NO_CO_SYNC
1066 co_sync_t *sync = co_nmt_get_sync(net->nmt);
1067 if (sync)
1068 co_sync_set_ind(sync, NULL, NULL);
1069#endif
1070
1071#if !LELY_NO_CO_NMT_BOOT
1072 co_nmt_set_boot_ind(net->nmt, net->boot_ind, net->boot_data);
1073#endif
1074 co_nmt_set_st_ind(net->nmt, net->st_ind, net->st_data);
1075 co_nmt_set_hb_ind(net->nmt, net->hb_ind, net->hb_data);
1076#if !LELY_NO_CO_NG
1077 co_nmt_set_lg_ind(net->nmt, net->lg_ind, net->lg_data);
1078#if !LELY_NO_CO_MASTER
1079 co_nmt_set_ng_ind(net->nmt, net->ng_ind, net->ng_data);
1080#endif
1081#endif
1082 co_nmt_set_cs_ind(net->nmt, net->cs_ind, net->cs_data);
1083
1084#if !LELY_NO_CO_CSDO
1085 for (co_unsigned8_t id = 1; id <= CO_NUM_NODES; id++)
1086 co_gw_job_destroy(net->sdo[id - 1]);
1087#endif
1088#if !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
1089 co_gw_job_destroy(net->lss);
1090#endif
1091
1092 free(net);
1093 }
1094}
1095
1096static void
1097co_gw_net_cs_ind(co_nmt_t *nmt, co_unsigned8_t cs, void *data)
1098{
1099 struct co_gw_net *net = data;
1100 assert(net);
1101
1102 switch (cs) {
1103 case CO_NMT_CS_START: {
1104#if !LELY_NO_CO_SYNC
1105 co_sync_t *sync = co_nmt_get_sync(nmt);
1106 if (sync)
1108#endif
1109
1110#if !LELY_NO_CO_TIME
1111 co_time_t *time = co_nmt_get_time(nmt);
1112 if (time)
1114#endif
1115
1116#if !LELY_NO_CO_EMCY
1117 co_emcy_t *emcy = co_nmt_get_emcy(nmt);
1118 if (emcy)
1120#endif
1121
1122#if !LELY_NO_CO_RPDO
1123 for (co_unsigned16_t i = 1; i <= 512; i++) {
1124 co_rpdo_t *pdo = co_nmt_get_rpdo(nmt, i);
1125 if (pdo)
1127 }
1128#endif
1129
1130 break;
1131 }
1132 case CO_NMT_CS_ENTER_PREOP: {
1133#if !LELY_NO_CO_SYNC
1134 co_sync_t *sync = co_nmt_get_sync(nmt);
1135 if (sync)
1137#endif
1138
1139#if !LELY_NO_CO_TIME
1140 co_time_t *time = co_nmt_get_time(nmt);
1141 if (time)
1143#endif
1144
1145#if !LELY_NO_CO_EMCY
1146 co_emcy_t *emcy = co_nmt_get_emcy(nmt);
1147 if (emcy)
1149#endif
1150
1151 break;
1152 }
1153 }
1154
1155 if (net->cs_ind)
1156 net->cs_ind(nmt, cs, net->cs_data);
1157}
1158
1159#if !LELY_NO_CO_NG
1160
1161#if !LELY_NO_CO_MASTER
1162static void
1163co_gw_net_ng_ind(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason,
1164 void *data)
1165{
1166 struct co_gw_net *net = data;
1167 assert(net);
1168
1169 if (state == CO_NMT_EC_OCCURRED) {
1170 int iec = 0;
1171 switch (reason) {
1172 case CO_NMT_EC_TIMEOUT: iec = CO_GW_IEC_NG_OCCURRED; break;
1173 case CO_NMT_EC_STATE: iec = CO_GW_IEC_ST_OCCURRED; break;
1174 }
1175 co_gw_send_ec(net->gw, net->id, id, 0, iec);
1176 }
1177
1178 if (net->ng_ind)
1179 net->ng_ind(nmt, id, state, reason, net->ng_data);
1180}
1181#endif
1182
1183static void
1184co_gw_net_lg_ind(co_nmt_t *nmt, int state, void *data)
1185{
1186 struct co_gw_net *net = data;
1187 assert(net);
1188
1189 co_dev_t *dev = co_nmt_get_dev(nmt);
1190
1191 co_unsigned8_t id = co_dev_get_id(dev);
1192 co_gw_send_ec(net->gw, net->id, id, 0, CO_GW_IEC_LG_OCCURRED);
1193
1194 if (net->lg_ind)
1195 net->lg_ind(nmt, state, net->lg_data);
1196}
1197
1198#endif // !LELY_NO_CO_NG
1199
1200static void
1201co_gw_net_hb_ind(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason,
1202 void *data)
1203{
1204 struct co_gw_net *net = data;
1205 assert(net);
1206
1207 if (reason == CO_NMT_EC_TIMEOUT) {
1208 int iec = 0;
1209 switch (state) {
1210 case CO_NMT_EC_OCCURRED: iec = CO_GW_IEC_HB_OCCURRED; break;
1211 case CO_NMT_EC_RESOLVED: iec = CO_GW_IEC_HB_RESOLVED; break;
1212 }
1213 co_gw_send_ec(net->gw, net->id, id, 0, iec);
1214 }
1215
1216 if (net->hb_ind)
1217 net->hb_ind(nmt, id, state, reason, net->hb_data);
1218}
1219
1220static void
1222 co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, void *data)
1223{
1224 struct co_gw_net *net = data;
1225 assert(net);
1226
1227 co_dev_t *dev = co_nmt_get_dev(nmt);
1228
1229 // Ignore state change indications of the gateway itself.
1230 if (id == co_dev_get_id(dev))
1231 return;
1232
1233 if (st == CO_NMT_ST_BOOTUP && !net->bootup_ind)
1234 return;
1235
1236 co_gw_send_ec(net->gw, net->id, id, st,
1238
1239 if (net->st_ind)
1240 net->st_ind(nmt, id, st, net->st_data);
1241}
1242
1243#if !LELY_NO_CO_NMT_BOOT
1244static void
1245co_gw_net_boot_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, char es,
1246 void *data)
1247{
1248 struct co_gw_net *net = data;
1249 assert(net);
1250
1251 struct co_gw_ind__boot ind = { .size = sizeof(ind),
1253 .net = net->id,
1254 .node = id,
1255 .st = st,
1256 .es = es };
1257 co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1258
1259 if (net->boot_ind)
1260 net->boot_ind(nmt, id, st, es, net->boot_data);
1261}
1262#endif
1263
1264#if !LELY_NO_CO_NMT_BOOT || !LELY_NO_CO_NMT_CFG
1265
1266static void
1267co_gw_net_dn_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t idx,
1268 co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
1269{
1270 struct co_gw_net *net = data;
1271 assert(net);
1272
1273 struct co_gw_ind_sdo ind = { .size = sizeof(ind),
1274 .srv = CO_GW_SRV_SDO,
1275 .net = net->id,
1276 .node = id,
1277 .nbyte = nbyte,
1278 .up = 0,
1279 .data = NULL,
1280 ._size = size };
1281 co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1282
1283 if (net->dn_ind)
1284 net->dn_ind(nmt, id, idx, subidx, size, nbyte, net->dn_data);
1285}
1286
1287static void
1288co_gw_net_up_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t idx,
1289 co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
1290{
1291 struct co_gw_net *net = data;
1292 assert(net);
1293
1294 struct co_gw_ind_sdo ind = { .size = sizeof(ind),
1295 .srv = CO_GW_SRV_SDO,
1296 .net = net->id,
1297 .node = id,
1298 .nbyte = nbyte,
1299 .up = 1,
1300 .data = NULL,
1301 ._size = size };
1302 co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1303
1304 if (net->up_ind)
1305 net->up_ind(nmt, id, idx, subidx, size, nbyte, net->up_data);
1306}
1307
1308#endif // !LELY_NO_CO_NMT_BOOT || !LELY_NO_CO_NMT_CFG
1309
1310#if !LELY_NO_CO_SYNC
1311static void
1312co_gw_net_sync_ind(co_sync_t *sync, co_unsigned8_t cnt, void *data)
1313{
1314 (void)sync;
1315 struct co_gw_net *net = data;
1316 assert(net);
1317
1318 struct co_gw_ind__sync ind = { .size = sizeof(ind),
1320 .net = net->id,
1321 .cnt = cnt };
1322 co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1323
1324 co_nmt_on_sync(net->nmt, cnt);
1325}
1326#endif
1327
1328#if !LELY_NO_CO_TIME
1329static void
1330co_gw_net_time_ind(co_time_t *time, const struct timespec *tp, void *data)
1331{
1332 (void)time;
1333 struct co_gw_net *net = data;
1334 assert(net);
1335
1336 struct co_gw_ind__time ind = { .size = sizeof(ind),
1338 .net = net->id,
1339 .ts = *tp };
1340 co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1341}
1342#endif
1343
1344#if !LELY_NO_CO_EMCY
1345static void
1346co_gw_net_emcy_ind(co_emcy_t *emcy, co_unsigned8_t id, co_unsigned16_t ec,
1347 co_unsigned8_t er, co_unsigned8_t msef[5], void *data)
1348{
1349 (void)emcy;
1350 struct co_gw_net *net = data;
1351 assert(net);
1352
1353 struct co_gw_ind_emcy ind = { .size = sizeof(ind),
1355 .net = net->id,
1356 .node = id,
1357 .ec = ec,
1358 .er = er,
1359 .msef = { msef[0], msef[1], msef[2], msef[3], msef[4] } };
1360 co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1361}
1362#endif
1363
1364static struct co_gw_job *
1366 void (*dtor)(void *data), const struct co_gw_req *req)
1367{
1368 assert(pself);
1369 assert(req);
1370
1371 if (*pself)
1373
1374 *pself = malloc(CO_GW_JOB_SIZE + req->size);
1375 if (!*pself) {
1376#if !LELY_NO_ERRNO
1377 set_errc(errno2c(errno));
1378#endif
1379 return NULL;
1380 }
1381
1382 (*pself)->pself = pself;
1383 (*pself)->net = net;
1384 (*pself)->data = data;
1385 (*pself)->dtor = dtor;
1386 memcpy(&(*pself)->req, req, req->size);
1387
1388 return *pself;
1389}
1390
1391static void
1393{
1394 if (job) {
1395 co_gw_job_remove(job);
1396
1397 if (job->dtor)
1398 job->dtor(job->data);
1399
1400 free(job);
1401 }
1402}
1403
1404static void
1406{
1407 assert(job);
1408
1409 if (job->pself && *job->pself == job)
1410 *job->pself = NULL;
1411}
1412
1413#if !LELY_NO_CO_CSDO
1414
1415static struct co_gw_job *
1417 co_unsigned8_t id, const struct co_gw_req *req)
1418{
1419 assert(pself);
1420 assert(net);
1421
1422 co_gw_t *gw = net->gw;
1423
1424 int errc = 0;
1425
1426 if (*pself) {
1427 errc = errnum2c(ERRNUM_BUSY);
1428 goto error_param;
1429 }
1430
1431 co_csdo_t *sdo = co_csdo_create(co_nmt_get_net(net->nmt), NULL, id);
1432 if (!sdo) {
1433 errc = get_errc();
1434 goto error_create_sdo;
1435 }
1436
1437 // The actual SDO timeout is limited by the global gateway command
1438 // timeout.
1439 int timeout = net->timeout;
1440 if (gw->timeout)
1441 timeout = timeout ? MIN(timeout, gw->timeout) : gw->timeout;
1442 co_csdo_set_timeout(sdo, timeout);
1443
1444 struct co_gw_job *job = co_gw_job_create(
1445 pself, net, sdo, &co_gw_job_sdo_dtor, req);
1446 if (!job) {
1447 errc = get_errc();
1448 goto error_create_job;
1449 }
1450
1451 return job;
1452
1453error_create_job:
1454 co_csdo_destroy(sdo);
1455error_create_sdo:
1456error_param:
1457 set_errc(errc);
1458 return NULL;
1459}
1460
1461static void
1463{
1464 co_csdo_t *sdo = data;
1465
1466 co_csdo_destroy(sdo);
1467}
1468
1469static void
1470co_gw_job_sdo_up_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1471 co_unsigned32_t ac, const void *ptr, size_t n, void *data)
1472{
1473 (void)sdo;
1474 (void)idx;
1475 (void)subidx;
1476 struct co_gw_job *job = data;
1477 assert(job);
1478 assert(job->net);
1479
1480 co_gw_job_remove(job);
1481
1482 if (job->req.srv != CO_GW_SRV_SDO_UP)
1483 goto done;
1484 struct co_gw_req_sdo_up *req = (struct co_gw_req_sdo_up *)&job->req;
1485
1486 if (ac) {
1487 co_gw_send_con(job->net->gw, &job->req, 0, ac);
1488 } else {
1489 size_t size = MAX(CO_GW_CON_SDO_UP_SIZE + n,
1490 sizeof(struct co_gw_con_sdo_up));
1491 int errc = get_errc();
1492 struct co_gw_con_sdo_up *con = malloc(size);
1493 if (con) {
1494 *con = (struct co_gw_con_sdo_up){ .size = size,
1495 .srv = req->srv,
1496 .data = req->data,
1497 .type = req->type,
1498 .len = n };
1499 memcpy(con->val, ptr, n);
1500 co_gw_send_srv(job->net->gw, (struct co_gw_srv *)con);
1501
1502 free(con);
1503 } else {
1504 set_errc(errc);
1505 co_gw_send_con(job->net->gw, &job->req,
1506 CO_GW_IEC_NO_MEM, 0);
1507 }
1508 }
1509
1510done:
1511 co_gw_job_destroy(job);
1512}
1513
1514static void
1515co_gw_job_sdo_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
1516 co_unsigned32_t ac, void *data)
1517{
1518 (void)sdo;
1519 (void)idx;
1520 (void)subidx;
1521 struct co_gw_job *job = data;
1522 assert(job);
1523 assert(job->net);
1524
1525 co_gw_job_remove(job);
1526
1527 if (job->req.srv == CO_GW_SRV_SDO_DN)
1528 co_gw_send_con(job->net->gw, &job->req, 0, ac);
1529
1530 co_gw_job_destroy(job);
1531}
1532
1533static void
1534co_gw_job_sdo_ind(const co_csdo_t *sdo, co_unsigned16_t idx,
1535 co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
1536{
1537 (void)sdo;
1538 (void)idx;
1539 (void)subidx;
1540 struct co_gw_job *job = data;
1541 assert(job);
1542 assert(job->net);
1543
1544 struct co_gw_ind_sdo ind = { .size = sizeof(ind),
1545 .srv = CO_GW_SRV_SDO,
1546 .net = job->net->id,
1547 .node = co_csdo_get_num(job->data),
1548 .nbyte = nbyte,
1549 .up = job->req.srv == CO_GW_SRV_SDO_UP,
1550 .data = job->req.data,
1551 ._size = size };
1552 co_gw_send_srv(job->net->gw, (struct co_gw_srv *)&ind);
1553}
1554
1555#endif // !LELY_NO_CO_CSDO
1556
1557#if !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
1558
1559static struct co_gw_job *
1561 const struct co_gw_req *req)
1562{
1563 assert(pself);
1564 assert(net);
1565
1566 co_gw_t *gw = net->gw;
1567
1568 if (*pself) {
1570 return NULL;
1571 }
1572
1573 co_lss_t *lss = co_nmt_get_lss(net->nmt);
1574 if (!lss) {
1576 return NULL;
1577 }
1578
1579 // The LSS timeout is limited by the global gateway command timeout.
1580 int timeout = LELY_CO_LSS_TIMEOUT;
1581 if (gw->timeout)
1582 timeout = MIN(timeout, gw->timeout);
1583 co_lss_set_timeout(lss, timeout);
1584
1585 return co_gw_job_create(pself, net, lss, NULL, req);
1586}
1587
1588static void
1589co_gw_job_lss_cs_ind(co_lss_t *lss, co_unsigned8_t cs, void *data)
1590{
1591 (void)lss;
1592 struct co_gw_job *job = data;
1593 assert(job);
1594 assert(job->net);
1595
1596 co_gw_job_remove(job);
1597
1598 int iec = CO_GW_IEC_TIMEOUT;
1599 if (cs) {
1600 iec = CO_GW_IEC_LSS;
1601 switch (job->req.srv) {
1603 if (cs == 0x44)
1604 iec = 0;
1605 break;
1607 if (cs == 0x4f)
1608 iec = 0;
1609 break;
1611 if (cs == 0x50)
1612 iec = 0;
1613 break;
1614 }
1615 }
1616 co_gw_send_con(job->net->gw, &job->req, iec, 0);
1617
1618 co_gw_job_destroy(job);
1619}
1620
1621static void
1622co_gw_job_lss_err_ind(co_lss_t *lss, co_unsigned8_t cs, co_unsigned8_t err,
1623 co_unsigned8_t spec, void *data)
1624{
1625 (void)lss;
1626 (void)spec;
1627 struct co_gw_job *job = data;
1628 assert(job);
1629 assert(job->net);
1630
1631 co_gw_job_remove(job);
1632
1633 int iec = CO_GW_IEC_TIMEOUT;
1634 if (cs) {
1635 iec = CO_GW_IEC_LSS;
1636 switch (job->req.srv) {
1638 if (cs == 0x11)
1639 iec = err ? CO_GW_IEC_LSS_ID : 0;
1640 break;
1642 if (cs == 0x13)
1643 iec = err ? CO_GW_IEC_LSS_RATE : 0;
1644 break;
1646 if (cs == 0x17)
1647 iec = err ? CO_GW_IEC_LSS_PARAM : 0;
1648 break;
1649 }
1650 }
1651 co_gw_send_con(job->net->gw, &job->req, iec, 0);
1652
1653 co_gw_job_destroy(job);
1654}
1655
1656static void
1657co_gw_job_lss_lssid_ind(co_lss_t *lss, co_unsigned8_t cs, co_unsigned32_t id,
1658 void *data)
1659{
1660 (void)lss;
1661 struct co_gw_job *job = data;
1662 assert(job);
1663 assert(job->net);
1664 assert(job->req.srv == CO_GW_SRV_LSS_GET_LSSID);
1665 assert(job->req.size >= sizeof(struct co_gw_req_lss_get_lssid));
1666
1667 struct co_gw_req_lss_get_lssid *req =
1668 (struct co_gw_req_lss_get_lssid *)&job->req;
1669
1670 co_gw_job_remove(job);
1671
1672 int iec = 0;
1673 if (!cs)
1674 iec = CO_GW_IEC_TIMEOUT;
1675 else if (cs != req->cs)
1676 iec = CO_GW_IEC_LSS;
1677
1678 if (iec) {
1679 co_gw_send_con(job->net->gw, &job->req, iec, 0);
1680 } else {
1681 struct co_gw_con_lss_get_lssid con = { .size = sizeof(con),
1682 .srv = req->srv,
1683 .data = req->data,
1684 .id = id };
1685 co_gw_send_srv(job->net->gw, (struct co_gw_srv *)&con);
1686 }
1687
1688 co_gw_job_destroy(job);
1689}
1690
1691static void
1693 co_lss_t *lss, co_unsigned8_t cs, co_unsigned8_t id, void *data)
1694{
1695 (void)lss;
1696 struct co_gw_job *job = data;
1697 assert(job);
1698 assert(job->net);
1699 assert(job->req.srv == CO_GW_SRV_LSS_GET_ID);
1700
1701 co_gw_job_remove(job);
1702
1703 int iec = 0;
1704 if (!cs)
1705 iec = CO_GW_IEC_TIMEOUT;
1706 else if (cs != 0x5e)
1707 iec = CO_GW_IEC_LSS;
1708
1709 if (iec) {
1710 co_gw_send_con(job->net->gw, &job->req, iec, 0);
1711 } else {
1712 struct co_gw_con_lss_get_id con = { .size = sizeof(con),
1713 .srv = job->req.srv,
1714 .data = job->req.data,
1715 .id = id };
1716 co_gw_send_srv(job->net->gw, (struct co_gw_srv *)&con);
1717 }
1718
1719 co_gw_job_destroy(job);
1720}
1721
1722static void
1723co_gw_job_lss_scan_ind(co_lss_t *lss, co_unsigned8_t cs, const struct co_id *id,
1724 void *data)
1725{
1726 (void)lss;
1727 struct co_gw_job *job = data;
1728 assert(job);
1729 assert(job->net);
1730
1731 co_gw_job_remove(job);
1732
1733 int iec = CO_GW_IEC_TIMEOUT;
1734 if (cs) {
1735 iec = CO_GW_IEC_LSS;
1736 switch (job->req.srv) {
1738 if (cs == 0x44)
1739 iec = 0;
1740 break;
1742 if (cs == 0x4f)
1743 iec = 0;
1744 break;
1745 }
1746 }
1747
1748 if (iec) {
1749 co_gw_send_con(job->net->gw, &job->req, iec, 0);
1750 } else {
1751 assert(id);
1752 struct co_gw_con__lss_scan con = { .size = sizeof(con),
1753 .srv = job->req.srv,
1754 .data = job->req.data,
1755 .id = *id };
1756 co_gw_send_srv(job->net->gw, (struct co_gw_srv *)&con);
1757 }
1758
1759 co_gw_job_destroy(job);
1760}
1761
1762#endif // !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
1763
1764#if !LELY_NO_CO_RPDO
1765static void
1766co_gw_net_rpdo_ind(co_rpdo_t *pdo, co_unsigned32_t ac, const void *ptr,
1767 size_t n, void *data)
1768{
1769 struct co_gw_net *net = data;
1770 assert(net);
1771
1772 if (ac)
1773 return;
1774
1775 struct co_gw_ind_rpdo ind = { .size = CO_GW_IND_RPDO_SIZE,
1776 .srv = CO_GW_SRV_RPDO,
1777 .net = net->id,
1778 .num = co_rpdo_get_num(pdo),
1779 .n = 0x40 };
1780
1781 const struct co_pdo_map_par *par = co_rpdo_get_map_par(pdo);
1782 if (co_pdo_unmap(par, ptr, n, ind.val, &ind.n))
1783 return;
1784 ind.size += ind.n * sizeof(*ind.val);
1785
1786 co_gw_send_srv(net->gw, (struct co_gw_srv *)&ind);
1787}
1788#endif
1789
1790#if !LELY_NO_CO_CSDO
1791
1792static int
1793co_gw_recv_sdo_up(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
1794 const struct co_gw_req *req)
1795{
1796 assert(gw);
1797 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
1798 assert(req);
1799 assert(req->srv == CO_GW_SRV_SDO_UP);
1800 assert(node && node <= CO_NUM_NODES);
1801
1802 co_nmt_t *nmt = gw->net[net - 1]->nmt;
1803 co_dev_t *dev = co_nmt_get_dev(nmt);
1804
1805 if (req->size < sizeof(struct co_gw_req_sdo_up)) {
1807 return -1;
1808 }
1809
1810 int iec = 0;
1811 int errc = get_errc();
1812
1813 struct co_gw_job *job = NULL;
1814 if (node == co_dev_get_id(dev)) {
1815 job = co_gw_job_create(&gw->net[net - 1]->sdo[node - 1],
1816 gw->net[net - 1], NULL, NULL, req);
1817 if (!job) {
1818 iec = errnum2iec(get_errnum());
1819 goto error_create_job;
1820 }
1821 const struct co_gw_req_sdo_up *par =
1822 (const struct co_gw_req_sdo_up *)&job->req;
1823
1824 // clang-format off
1825 if (co_dev_up_req(dev, par->idx, par->subidx,
1826 &co_gw_job_sdo_up_con, job) == -1) {
1827 // clang-format on
1828 iec = errnum2iec(get_errnum());
1829 goto error_up_req;
1830 }
1831 } else {
1832 if (!co_nmt_is_master(gw->net[net - 1]->nmt)) {
1833 // TODO: Add client-SDO support for slaves where
1834 // possible.
1835 iec = CO_GW_IEC_BAD_NODE;
1836 goto error_srv;
1837 }
1838
1839 job = co_gw_job_create_sdo(&gw->net[net - 1]->sdo[node - 1],
1840 gw->net[net - 1], node, req);
1841 if (!job) {
1842 iec = errnum2iec(get_errnum());
1843 goto error_create_job;
1844 }
1845 const struct co_gw_req_sdo_up *par =
1846 (const struct co_gw_req_sdo_up *)&job->req;
1847
1849 // clang-format off
1850 if (co_csdo_up_req(job->data, par->idx, par->subidx,
1851 &co_gw_job_sdo_up_con, job) == -1) {
1852 // clang-format on
1853 iec = errnum2iec(get_errnum());
1854 goto error_up_req;
1855 }
1856 }
1857
1858 return 0;
1859
1860error_up_req:
1861 co_gw_job_destroy(job);
1862error_create_job:
1863 set_errc(errc);
1864error_srv:
1865 return co_gw_send_con(gw, req, iec, 0);
1866}
1867
1868static int
1869co_gw_recv_sdo_dn(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
1870 const struct co_gw_req *req)
1871{
1872 assert(gw);
1873 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
1874 assert(req);
1875 assert(req->srv == CO_GW_SRV_SDO_DN);
1876
1877 co_nmt_t *nmt = gw->net[net - 1]->nmt;
1878 co_dev_t *dev = co_nmt_get_dev(nmt);
1879
1880 if (req->size < CO_GW_REQ_SDO_DN_SIZE) {
1882 return -1;
1883 }
1884 const struct co_gw_req_sdo_dn *par =
1885 (const struct co_gw_req_sdo_dn *)req;
1886 if (par->size < CO_GW_REQ_SDO_DN_SIZE + par->len) {
1888 return -1;
1889 }
1890
1891 int iec = 0;
1892 int errc = get_errc();
1893
1894 struct co_gw_job *job = NULL;
1895 if (node == co_dev_get_id(dev)) {
1896 job = co_gw_job_create(&gw->net[net - 1]->sdo[node - 1],
1897 gw->net[net - 1], NULL, NULL, req);
1898 if (!job) {
1899 iec = errnum2iec(get_errnum());
1900 goto error_create_job;
1901 }
1902 par = (const struct co_gw_req_sdo_dn *)&job->req;
1903
1904 // clang-format off
1905 if (co_dev_dn_req(dev, par->idx, par->subidx, par->val,
1906 par->len, &co_gw_job_sdo_dn_con, job) == -1) {
1907 // clang-format on
1908 iec = errnum2iec(get_errnum());
1909 goto error_dn_req;
1910 }
1911 } else {
1912 if (!co_nmt_is_master(gw->net[net - 1]->nmt)) {
1913 // TODO: Add client-SDO support for slaves where
1914 // possible.
1915 iec = CO_GW_IEC_BAD_NODE;
1916 goto error_srv;
1917 }
1918
1919 job = co_gw_job_create_sdo(&gw->net[net - 1]->sdo[node - 1],
1920 gw->net[net - 1], node, req);
1921 if (!job) {
1922 iec = errnum2iec(get_errnum());
1923 goto error_create_job;
1924 }
1925 par = (const struct co_gw_req_sdo_dn *)&job->req;
1926
1928 // clang-format off
1929 if (co_csdo_dn_req(job->data, par->idx, par->subidx, par->val,
1930 par->len, &co_gw_job_sdo_dn_con, job) == -1) {
1931 // clang-format on
1932 iec = errnum2iec(get_errnum());
1933 goto error_dn_req;
1934 }
1935 }
1936
1937 return 0;
1938
1939error_dn_req:
1940 co_gw_job_destroy(job);
1941error_create_job:
1942 set_errc(errc);
1943error_srv:
1944 return co_gw_send_con(gw, req, iec, 0);
1945}
1946
1947static int
1949 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
1950{
1951 assert(gw);
1952 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
1953 assert(req);
1954 assert(req->srv == CO_GW_SRV_SET_SDO_TIMEOUT);
1955
1956#if !LELY_NO_CO_MASTER
1957 co_nmt_t *nmt = gw->net[net - 1]->nmt;
1958#endif
1959
1960 if (req->size < sizeof(struct co_gw_req_set_sdo_timeout)) {
1962 return -1;
1963 }
1964 const struct co_gw_req_set_sdo_timeout *par =
1965 (const struct co_gw_req_set_sdo_timeout *)req;
1966
1967 gw->net[net - 1]->timeout = par->timeout;
1968
1969#if !LELY_NO_CO_MASTER
1970 // The actual NMT SDO timeout is limited by the global gateway command
1971 // timeout.
1972 int timeout = par->timeout;
1973 if (gw->timeout)
1974 timeout = timeout ? MIN(timeout, gw->timeout) : gw->timeout;
1976#endif
1977
1978 return co_gw_send_con(gw, req, 0, 0);
1979}
1980
1981#endif
1982
1983#if !LELY_NO_CO_RPDO
1984static int
1986 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
1987{
1988 assert(gw);
1989 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
1990 assert(req);
1991 assert(req->srv == CO_GW_SRV_SET_RPDO);
1992
1993 co_nmt_t *nmt = gw->net[net - 1]->nmt;
1994 co_dev_t *dev = co_nmt_get_dev(nmt);
1995
1996 if (req->size < CO_GW_REQ_SET_RPDO_SIZE) {
1998 return -1;
1999 }
2000 const struct co_gw_req_set_rpdo *par =
2001 (const struct co_gw_req_set_rpdo *)req;
2002 // clang-format off
2003 if (par->n > 0x40 || par->size < CO_GW_REQ_SET_RPDO_SIZE
2004 + par->n * sizeof(*par->map)) {
2005 // clang-format on
2007 return -1;
2008 }
2009
2010 struct co_pdo_comm_par comm = {
2011 .n = 2, .cobid = par->cobid, .trans = par->trans
2012 };
2013
2015 map.n = par->n;
2016 for (co_unsigned8_t i = 0; i < par->n; i++)
2017 map.map[i] = par->map[i];
2018
2019 co_unsigned32_t ac = co_dev_cfg_rpdo(dev, par->num, &comm, &map);
2020
2021 return co_gw_send_con(gw, req, 0, ac);
2022}
2023#endif
2024
2025#if !LELY_NO_CO_TPDO
2026static int
2028 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2029{
2030 assert(gw);
2031 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2032 assert(req);
2033 assert(req->srv == CO_GW_SRV_SET_TPDO);
2034
2035 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2036 co_dev_t *dev = co_nmt_get_dev(nmt);
2037
2038 if (req->size < CO_GW_REQ_SET_TPDO_SIZE) {
2040 return -1;
2041 }
2042 const struct co_gw_req_set_tpdo *par =
2043 (const struct co_gw_req_set_tpdo *)req;
2044 // clang-format off
2045 if (par->n > 0x40 || par->size < CO_GW_REQ_SET_TPDO_SIZE
2046 + par->n * sizeof(*par->map)) {
2047 // clang-format on
2049 return -1;
2050 }
2051
2052 struct co_pdo_comm_par comm = { .n = 6,
2053 .cobid = par->cobid,
2054 .trans = par->trans,
2055 .inhibit = par->inhibit,
2056 .event = par->event,
2057 .sync = par->sync };
2058
2060 map.n = par->n;
2061 for (co_unsigned8_t i = 0; i < par->n; i++)
2062 map.map[i] = par->map[i];
2063
2064 co_unsigned32_t ac = co_dev_cfg_tpdo(dev, par->num, &comm, &map);
2065
2066 return co_gw_send_con(gw, req, 0, ac);
2067}
2068#endif
2069
2070#if !LELY_NO_CO_RPDO
2071static int
2073 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2074{
2075 assert(gw);
2076 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2077 assert(req);
2078 assert(req->srv == CO_GW_SRV_PDO_READ);
2079
2080 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2081 co_dev_t *dev = co_nmt_get_dev(nmt);
2082
2083 if (req->size < sizeof(struct co_gw_req_pdo_read)) {
2085 return -1;
2086 }
2087 const struct co_gw_req_pdo_read *par =
2088 (const struct co_gw_req_pdo_read *)req;
2089
2090 int iec = 0;
2091 co_unsigned32_t ac = 0;
2092
2093 co_rpdo_t *pdo = co_nmt_get_rpdo(nmt, par->num);
2094 if (!pdo) {
2095 iec = CO_GW_IEC_INTERN;
2096 goto error;
2097 }
2098 const struct co_pdo_comm_par *comm = co_rpdo_get_comm_par(pdo);
2099 if (comm->trans == 0xfc || comm->trans == 0xfd) {
2100 // TODO(jseldenthuis@lely.com): Send an RTR and wait for the
2101 // result.
2102 iec = CO_GW_IEC_INTERN;
2103 goto error;
2104 }
2105 const struct co_pdo_map_par *map = co_rpdo_get_map_par(pdo);
2106
2107 // Read the mapped values from the object dictionary.
2108 struct co_sdo_req sdo_req = CO_SDO_REQ_INIT;
2109 uint_least8_t buf[CAN_MAX_LEN];
2110 size_t n = sizeof(buf);
2111 ac = co_pdo_up(map, dev, &sdo_req, buf, &n, 0);
2112 co_sdo_req_fini(&sdo_req);
2113 if (ac)
2114 goto error;
2115
2116 struct co_gw_con_pdo_read con = { .size = sizeof(con),
2117 .srv = req->srv,
2118 .data = req->data,
2119 .net = net,
2120 .num = par->num };
2121
2122 // Unmap the PDO values.
2123 ac = co_pdo_unmap(map, buf, n, con.val, &con.n);
2124 if (ac)
2125 goto error;
2126
2127 con.size += con.n * sizeof(*con.val);
2128 return co_gw_send_srv(gw, (struct co_gw_srv *)&con);
2129
2130error:
2131 return co_gw_send_con(gw, req, iec, ac);
2132}
2133#endif
2134
2135#if !LELY_NO_CO_TPDO
2136static int
2138 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2139{
2140 assert(gw);
2141 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2142 assert(req);
2143 assert(req->srv == CO_GW_SRV_PDO_WRITE);
2144
2145 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2146 co_dev_t *dev = co_nmt_get_dev(nmt);
2147
2148 if (req->size < CO_GW_REQ_PDO_WRITE_SIZE) {
2150 return -1;
2151 }
2152 const struct co_gw_req_pdo_write *par =
2153 (const struct co_gw_req_pdo_write *)req;
2154 // clang-format off
2155 if (par->n > 0x40 || par->size < CO_GW_REQ_PDO_WRITE_SIZE
2156 + par->n * sizeof(*par->val)) {
2157 // clang-format on
2159 return -1;
2160 }
2161
2162 int iec = 0;
2163 co_unsigned32_t ac = 0;
2164
2165 co_tpdo_t *pdo = co_nmt_get_tpdo(nmt, par->num);
2166 if (!pdo) {
2167 iec = CO_GW_IEC_INTERN;
2168 goto error;
2169 }
2170 const struct co_pdo_map_par *map = co_tpdo_get_map_par(pdo);
2171
2172 // Map the values into a PDO.
2173 uint_least8_t buf[CAN_MAX_LEN] = { 0 };
2174 size_t n = sizeof(buf);
2175 ac = co_pdo_map(map, par->val, par->n, buf, &n);
2176 if (ac)
2177 goto error;
2178
2179 // Write the mapped values to the object dictionary.
2180 struct co_sdo_req sdo_req = CO_SDO_REQ_INIT;
2181 ac = co_pdo_dn(map, dev, &sdo_req, buf, n, 0);
2182 co_sdo_req_fini(&sdo_req);
2183 if (ac)
2184 goto error;
2185
2186 // Trigger the event-based TPDO, if necessary.
2187 int errc = get_errc();
2188 if (co_tpdo_event(pdo) == -1) {
2189 iec = errnum2iec(get_errnum());
2190 set_errc(errc);
2191 }
2192
2193error:
2194 return co_gw_send_con(gw, req, iec, ac);
2195}
2196#endif
2197
2198#if !LELY_NO_CO_MASTER
2199
2200static int
2201co_gw_recv_nmt_cs(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
2202 co_unsigned8_t cs, const struct co_gw_req *req)
2203{
2204 assert(gw);
2205 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2206 assert(req);
2207
2208 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2209
2210 int iec = 0;
2211
2212 int errc = get_errc();
2213 if (co_nmt_cs_req(nmt, cs, node) == -1) {
2214 iec = errnum2iec(get_errnum());
2215 set_errc(errc);
2216 }
2217
2218 return co_gw_send_con(gw, req, iec, 0);
2219}
2220
2221#if !LELY_NO_CO_NG
2222static int
2223co_gw_recv_nmt_set_ng(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
2224 const struct co_gw_req *req)
2225{
2226 assert(gw);
2227 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2228 assert(req);
2229
2230 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2231
2232 co_unsigned16_t gt = 0;
2233 co_unsigned8_t ltf = 0;
2234 if (req->srv == CO_GW_SRV_NMT_NG_ENABLE) {
2235 if (req->size < sizeof(struct co_gw_req_nmt_set_ng)) {
2237 return -1;
2238 }
2239 const struct co_gw_req_nmt_set_ng *par =
2240 (const struct co_gw_req_nmt_set_ng *)req;
2241
2242 gt = par->gt;
2243 ltf = par->ltf;
2244 }
2245
2246 int iec = 0;
2247
2248 int errc = get_errc();
2249 if (co_nmt_ng_req(nmt, node, gt, ltf) == -1) {
2250 iec = errnum2iec(get_errnum());
2251 set_errc(errc);
2252 }
2253
2254 return co_gw_send_con(gw, req, iec, 0);
2255}
2256#endif // !LELY_NO_CO_NG
2257
2258#endif // !LELY_NO_CO_MASTER
2259
2260static int
2261co_gw_recv_nmt_set_hb(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
2262 const struct co_gw_req *req)
2263{
2264 assert(gw);
2265 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2266 assert(req);
2267
2268 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2269 co_dev_t *dev = co_nmt_get_dev(nmt);
2270
2271 co_unsigned16_t ms = 0;
2272 if (req->srv == CO_GW_SRV_NMT_HB_ENABLE) {
2273 if (req->size < sizeof(struct co_gw_req_nmt_set_hb)) {
2275 return -1;
2276 }
2277 const struct co_gw_req_nmt_set_hb *par =
2278 (const struct co_gw_req_nmt_set_hb *)req;
2279
2280 ms = par->ms;
2281 }
2282
2283 co_unsigned32_t ac = co_dev_cfg_hb(dev, node, ms);
2284
2285 return co_gw_send_con(gw, req, 0, ac);
2286}
2287
2288static int
2289co_gw_recv_init(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2290{
2291 assert(gw);
2292 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2293 assert(req);
2294 assert(req->srv == CO_GW_SRV_INIT);
2295
2296 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2297 co_dev_t *dev = co_nmt_get_dev(nmt);
2298
2299 if (req->size < sizeof(struct co_gw_req_init)) {
2301 return -1;
2302 }
2303 const struct co_gw_req_init *par = (const struct co_gw_req_init *)req;
2304
2305 int iec = 0;
2306
2307 unsigned int baud = co_dev_get_baud(dev);
2308 co_unsigned16_t rate;
2309 switch (par->bitidx) {
2310 case 0:
2311 if (!(baud & CO_BAUD_1000)) {
2312 iec = CO_GW_IEC_LSS_RATE;
2313 goto error;
2314 }
2315 rate = 1000;
2316 break;
2317 case 1:
2318 if (!(baud & CO_BAUD_800)) {
2319 iec = CO_GW_IEC_LSS_RATE;
2320 goto error;
2321 }
2322 rate = 800;
2323 break;
2324 case 2:
2325 if (!(baud & CO_BAUD_500)) {
2326 iec = CO_GW_IEC_LSS_RATE;
2327 goto error;
2328 }
2329 rate = 500;
2330 break;
2331 case 3:
2332 if (!(baud & CO_BAUD_250)) {
2333 iec = CO_GW_IEC_LSS_RATE;
2334 goto error;
2335 }
2336 rate = 250;
2337 break;
2338 case 4:
2339 if (!(baud & CO_BAUD_125)) {
2340 iec = CO_GW_IEC_LSS_RATE;
2341 goto error;
2342 }
2343 rate = 125;
2344 break;
2345 case 6:
2346 if (!(baud & CO_BAUD_50)) {
2347 iec = CO_GW_IEC_LSS_RATE;
2348 goto error;
2349 }
2350 rate = 50;
2351 break;
2352 case 7:
2353 if (!(baud & CO_BAUD_20)) {
2354 iec = CO_GW_IEC_LSS_RATE;
2355 goto error;
2356 }
2357 rate = 20;
2358 break;
2359 case 8:
2360 if (!(baud & CO_BAUD_10)) {
2361 iec = CO_GW_IEC_LSS_RATE;
2362 goto error;
2363 }
2364 rate = 10;
2365 break;
2366 case 9:
2367 if (!(baud & CO_BAUD_AUTO)) {
2368 iec = CO_GW_IEC_LSS_RATE;
2369 goto error;
2370 }
2371 rate = 0;
2372 break;
2373 default: iec = CO_GW_IEC_LSS_RATE; goto error;
2374 }
2375 if (gw->rate_func)
2376 gw->rate_func(net, rate, gw->rate_data);
2377
2378 int errc = get_errc();
2379 if (co_nmt_cs_ind(nmt, CO_NMT_CS_RESET_NODE) == -1) {
2380 iec = errnum2iec(get_errnum());
2381 set_errc(errc);
2382 }
2383
2384error:
2385 return co_gw_send_con(gw, req, iec, 0);
2386}
2387
2388static int
2389co_gw_recv_set_hb(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2390{
2391 assert(gw);
2392 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2393 assert(req);
2394 assert(req->srv == CO_GW_SRV_SET_HB);
2395
2396 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2397 co_dev_t *dev = co_nmt_get_dev(nmt);
2398
2399 if (req->size < sizeof(struct co_gw_req_set_hb)) {
2401 return -1;
2402 }
2403 const struct co_gw_req_set_hb *par =
2404 (const struct co_gw_req_set_hb *)req;
2405
2406 co_unsigned32_t ac = 0;
2407
2408 co_obj_t *obj = co_dev_find_obj(dev, 0x1017);
2409 if (!obj) {
2410 ac = CO_SDO_AC_NO_OBJ;
2411 goto error;
2412 }
2413 co_sub_t *sub = co_obj_find_sub(obj, 0x00);
2414 if (!sub) {
2415 ac = CO_SDO_AC_NO_SUB;
2416 goto error;
2417 }
2418 ac = co_sub_dn_ind_val(sub, CO_DEFTYPE_UNSIGNED16, &par->ms);
2419
2420error:
2421 return co_gw_send_con(gw, req, 0, ac);
2422}
2423
2424static int
2425co_gw_recv_set_id(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2426{
2427 assert(gw);
2428 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2429 assert(req);
2430 assert(req->srv == CO_GW_SRV_SET_ID);
2431
2432 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2433
2434 if (req->size < sizeof(struct co_gw_req_node)) {
2436 return -1;
2437 }
2438 const struct co_gw_req_node *par = (const struct co_gw_req_node *)req;
2439
2440 int iec = 0;
2441
2442 if (!par->node || (par->node > CO_NUM_NODES && par->node != 0xff)) {
2443 iec = CO_GW_IEC_BAD_NODE;
2444 goto error;
2445 }
2446
2447 co_nmt_set_id(nmt, par->node);
2448
2449error:
2450 return co_gw_send_con(gw, req, iec, 0);
2451}
2452
2453#if !LELY_NO_CO_EMCY
2454static int
2455co_gw_recv_set_emcy(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
2456 const struct co_gw_req *req)
2457{
2458 assert(gw);
2459 assert(req);
2460
2461 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2462 co_dev_t *dev = co_nmt_get_dev(nmt);
2463
2464 if (req->size < sizeof(struct co_gw_req_set_emcy)) {
2466 return -1;
2467 }
2468 const struct co_gw_req_set_emcy *par =
2469 (const struct co_gw_req_set_emcy *)req;
2470
2471 co_unsigned32_t ac = 0;
2472
2473 co_unsigned32_t cobid = par->cobid;
2474 if (par->srv == CO_GW_SRV_EMCY_START)
2475 cobid &= ~CO_EMCY_COBID_VALID;
2476 else
2478
2479 co_obj_t *obj = co_dev_find_obj(dev, 0x1028);
2480 if (!obj) {
2481 ac = CO_SDO_AC_NO_OBJ;
2482 goto error;
2483 }
2484 co_sub_t *sub = co_obj_find_sub(obj, node);
2485 if (!sub) {
2486 ac = CO_SDO_AC_NO_SUB;
2487 goto error;
2488 }
2490
2491error:
2492 return co_gw_send_con(gw, req, 0, ac);
2493}
2494#endif
2495
2496static int
2498{
2499 assert(gw);
2500 assert(req);
2501 assert(req->srv == CO_GW_SRV_SET_CMD_TIMEOUT);
2502
2503 if (req->size < sizeof(struct co_gw_req_set_cmd_timeout)) {
2505 return -1;
2506 }
2507 const struct co_gw_req_set_cmd_timeout *par =
2508 (const struct co_gw_req_set_cmd_timeout *)req;
2509
2510 gw->timeout = par->timeout;
2511
2512#if !LELY_NO_CO_MASTER
2513 for (co_unsigned16_t id = 1; id <= CO_GW_NUM_NET; id++) {
2514 if (!gw->net[id - 1])
2515 continue;
2516 // Limit the NMT SDO timeout for each network by the global
2517 // gateway command timeout.
2518 int timeout = gw->net[id - 1]->timeout;
2519 if (gw->timeout)
2520 // clang-format off
2522 ? MIN(timeout, gw->timeout)
2523 : gw->timeout;
2524 // clang-format on
2525 co_nmt_set_timeout(gw->net[id - 1]->nmt, timeout);
2526 }
2527#endif
2528
2529 return co_gw_send_con(gw, req, 0, 0);
2530}
2531
2532static int
2534 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2535{
2536 assert(gw);
2537 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2538 assert(req);
2539 assert(req->srv == CO_GW_SRV_SET_BOOTUP_IND);
2540
2541 if (req->size < sizeof(struct co_gw_req_set_bootup_ind)) {
2543 return -1;
2544 }
2545 const struct co_gw_req_set_bootup_ind *par =
2546 (const struct co_gw_req_set_bootup_ind *)req;
2547
2548 gw->net[net - 1]->bootup_ind = par->cs;
2549
2550 return co_gw_send_con(gw, req, 0, 0);
2551}
2552
2553static int
2554co_gw_recv_set_net(co_gw_t *gw, const struct co_gw_req *req)
2555{
2556 assert(gw);
2557 assert(req);
2558 assert(req->srv == CO_GW_SRV_SET_NET);
2559
2560 if (req->size < sizeof(struct co_gw_req_net)) {
2562 return -1;
2563 }
2564 const struct co_gw_req_net *par = (const struct co_gw_req_net *)req;
2565
2566 int iec = 0;
2567
2568 if (par->net > CO_GW_NUM_NET) {
2569 iec = CO_GW_IEC_BAD_NET;
2570 goto error;
2571 }
2572
2573 gw->def = par->net;
2574
2575error:
2576 return co_gw_send_con(gw, req, iec, 0);
2577}
2578
2579static int
2581 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2582{
2583 assert(gw);
2584 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2585 assert(req);
2586 assert(req->srv == CO_GW_SRV_SET_NODE);
2587
2588 if (req->size < sizeof(struct co_gw_req_node)) {
2590 return -1;
2591 }
2592 const struct co_gw_req_node *par = (const struct co_gw_req_node *)req;
2593
2594 int iec = 0;
2595
2596 if (par->node > CO_NUM_NODES) {
2597 iec = CO_GW_IEC_BAD_NODE;
2598 goto error;
2599 }
2600
2601 gw->net[net - 1]->def = par->node;
2602
2603error:
2604 return co_gw_send_con(gw, req, iec, 0);
2605}
2606
2607static int
2609 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2610{
2611 assert(gw);
2612 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2613 assert(req);
2614 assert(req->srv == CO_GW_SRV_GET_VERSION);
2615
2616 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2617 co_dev_t *dev = co_nmt_get_dev(nmt);
2618
2619 struct co_gw_con_get_version con = { .size = sizeof(con),
2620 .srv = req->srv,
2621 .data = req->data,
2622 .vendor_id = co_dev_get_val_u32(dev, 0x1018, 0x01),
2623 .product_code = co_dev_get_val_u32(dev, 0x1018, 0x02),
2624 .revision = co_dev_get_val_u32(dev, 0x1018, 0x03),
2625 .serial_nr = co_dev_get_val_u32(dev, 0x1018, 0x04),
2626 .gw_class = co_nmt_is_master(gw->net[net - 1]->nmt) ? 3 : 1,
2627 .prot_hi = CO_GW_PROT_HI,
2628 .prot_lo = CO_GW_PROT_LO };
2629 return co_gw_send_srv(gw, (struct co_gw_srv *)&con);
2630}
2631
2632#if !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
2633
2634static int
2636 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2637{
2638 assert(gw);
2639 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2640 assert(req);
2641 assert(req->srv == CO_GW_SRV_LSS_SWITCH);
2642
2643 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2644 co_lss_t *lss = co_nmt_get_lss(nmt);
2645
2646 if (req->size < sizeof(struct co_gw_req_lss_switch)) {
2648 return -1;
2649 }
2650 const struct co_gw_req_lss_switch *par =
2651 (const struct co_gw_req_lss_switch *)req;
2652
2653 int iec = 0;
2654
2655 if (!lss) {
2656 iec = CO_GW_IEC_BAD_SRV;
2657 goto error;
2658 }
2659
2660 int errc = get_errc();
2661 if (co_lss_switch_req(lss, par->mode) == -1) {
2662 iec = errnum2iec(get_errnum());
2663 set_errc(errc);
2664 }
2665
2666error:
2667 return co_gw_send_con(gw, req, iec, 0);
2668}
2669
2670static int
2672 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2673{
2674 assert(gw);
2675 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2676 assert(req);
2677 assert(req->srv == CO_GW_SRV_LSS_SWITCH_SEL);
2678
2679 if (req->size < sizeof(struct co_gw_req_lss_switch_sel)) {
2681 return -1;
2682 }
2683 const struct co_gw_req_lss_switch_sel *par =
2684 (const struct co_gw_req_lss_switch_sel *)req;
2685
2686 int iec = 0;
2687 int errc = get_errc();
2688
2689 struct co_gw_job *job = co_gw_job_create_lss(
2690 &gw->net[net - 1]->lss, gw->net[net - 1], req);
2691 if (!job) {
2692 iec = errnum2iec(get_errnum());
2693 goto error_create_job;
2694 }
2695
2696 // clang-format off
2698 job) == -1) {
2699 // clang-format on
2700 iec = errnum2iec(get_errnum());
2701 goto error_switch_sel_req;
2702 }
2703
2704 return 0;
2705
2706error_switch_sel_req:
2707 co_gw_job_destroy(job);
2708error_create_job:
2709 set_errc(errc);
2710 return co_gw_send_con(gw, req, iec, 0);
2711}
2712
2713static int
2715 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2716{
2717 assert(gw);
2718 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2719 assert(req);
2720 assert(req->srv == CO_GW_SRV_LSS_SET_ID);
2721
2722 if (req->size < sizeof(struct co_gw_req_node)) {
2724 return -1;
2725 }
2726 const struct co_gw_req_node *par = (const struct co_gw_req_node *)req;
2727
2728 int iec = 0;
2729 int errc = get_errc();
2730
2731 struct co_gw_job *job = co_gw_job_create_lss(
2732 &gw->net[net - 1]->lss, gw->net[net - 1], req);
2733 if (!job) {
2734 iec = errnum2iec(get_errnum());
2735 goto error_create_job;
2736 }
2737
2738 if (co_lss_set_id_req(job->data, par->node, &co_gw_job_lss_err_ind, job)
2739 == -1) {
2740 iec = errnum2iec(get_errnum());
2741 goto error_set_id_req;
2742 }
2743
2744 return 0;
2745
2746error_set_id_req:
2747 co_gw_job_destroy(job);
2748error_create_job:
2749 set_errc(errc);
2750 return co_gw_send_con(gw, req, iec, 0);
2751}
2752
2753static int
2755 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2756{
2757 assert(gw);
2758 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2759 assert(req);
2760 assert(req->srv == CO_GW_SRV_LSS_SET_RATE);
2761
2762 if (req->size < sizeof(struct co_gw_req_lss_set_rate)) {
2764 return -1;
2765 }
2766 const struct co_gw_req_lss_set_rate *par =
2767 (const struct co_gw_req_lss_set_rate *)req;
2768
2769 int iec = 0;
2770
2771 if (par->bitsel) {
2772 iec = CO_GW_IEC_LSS_RATE;
2773 goto error_srv;
2774 }
2775
2776 co_unsigned16_t rate;
2777 switch (par->bitidx) {
2778 case 0: rate = 1000; break;
2779 case 1: rate = 800; break;
2780 case 2: rate = 500; break;
2781 case 3: rate = 250; break;
2782 case 4: rate = 125; break;
2783 case 6: rate = 50; break;
2784 case 7: rate = 20; break;
2785 case 8: rate = 10; break;
2786 case 9: rate = 0; break;
2787 default: iec = CO_GW_IEC_LSS_RATE; goto error_srv;
2788 }
2789
2790 int errc = get_errc();
2791
2792 struct co_gw_job *job = co_gw_job_create_lss(
2793 &gw->net[net - 1]->lss, gw->net[net - 1], req);
2794 if (!job) {
2795 iec = errnum2iec(get_errnum());
2796 goto error_create_job;
2797 }
2798
2799 if (co_lss_set_rate_req(job->data, rate, &co_gw_job_lss_err_ind, job)
2800 == -1) {
2801 iec = errnum2iec(get_errnum());
2802 goto error_set_rate_req;
2803 }
2804
2805 return 0;
2806
2807error_set_rate_req:
2808 co_gw_job_destroy(job);
2809error_create_job:
2810 set_errc(errc);
2811error_srv:
2812 return co_gw_send_con(gw, req, iec, 0);
2813}
2814
2815static int
2817 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2818{
2819 assert(gw);
2820 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2821 assert(req);
2822 assert(req->srv == CO_GW_SRV_LSS_SWITCH_RATE);
2823
2824 co_nmt_t *nmt = gw->net[net - 1]->nmt;
2825 co_lss_t *lss = co_nmt_get_lss(nmt);
2826
2827 if (req->size < sizeof(struct co_gw_req_lss_switch_rate)) {
2829 return -1;
2830 }
2831 const struct co_gw_req_lss_switch_rate *par =
2832 (const struct co_gw_req_lss_switch_rate *)req;
2833
2834 int iec = 0;
2835
2836 if (!lss) {
2837 iec = CO_GW_IEC_BAD_SRV;
2838 goto error;
2839 }
2840
2841 int errc = get_errc();
2842 if (co_lss_switch_rate_req(lss, par->delay) == -1) {
2843 iec = errnum2iec(get_errnum());
2844 set_errc(errc);
2845 }
2846
2847error:
2848 return co_gw_send_con(gw, req, iec, 0);
2849}
2850
2851static int
2853 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2854{
2855 assert(gw);
2856 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2857 assert(req);
2858 assert(req->srv == CO_GW_SRV_LSS_STORE);
2859
2860 int iec = 0;
2861 int errc = get_errc();
2862
2863 struct co_gw_job *job = co_gw_job_create_lss(
2864 &gw->net[net - 1]->lss, gw->net[net - 1], req);
2865 if (!job) {
2866 iec = errnum2iec(get_errnum());
2867 goto error_create_job;
2868 }
2869
2870 if (co_lss_store_req(job->data, &co_gw_job_lss_err_ind, job) == -1) {
2871 iec = errnum2iec(get_errnum());
2872 goto error_store_req;
2873 }
2874
2875 return 0;
2876
2877error_store_req:
2878 co_gw_job_destroy(job);
2879error_create_job:
2880 set_errc(errc);
2881 return co_gw_send_con(gw, req, iec, 0);
2882}
2883
2884static int
2886 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2887{
2888 assert(gw);
2889 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2890 assert(req);
2891 assert(req->srv == CO_GW_SRV_LSS_GET_LSSID);
2892
2893 if (req->size < sizeof(struct co_gw_req_lss_get_lssid)) {
2895 return -1;
2896 }
2897 const struct co_gw_req_lss_get_lssid *par =
2898 (const struct co_gw_req_lss_get_lssid *)req;
2899
2900 int iec = 0;
2901 int errc = get_errc();
2902
2903 struct co_gw_job *job = co_gw_job_create_lss(
2904 &gw->net[net - 1]->lss, gw->net[net - 1], req);
2905 if (!job) {
2906 iec = errnum2iec(get_errnum());
2907 goto error_create_job;
2908 }
2909
2910 switch (par->cs) {
2911 case 0x5a:
2912 // clang-format off
2914 &co_gw_job_lss_lssid_ind, job) == -1) {
2915 // clang-format on
2916 iec = errnum2iec(get_errnum());
2917 goto error_switch_sel_req;
2918 }
2919 break;
2920 case 0x5b:
2921 // clang-format off
2923 &co_gw_job_lss_lssid_ind, job) == -1) {
2924 // clang-format on
2925 iec = errnum2iec(get_errnum());
2926 goto error_switch_sel_req;
2927 }
2928 break;
2929 case 0x5c:
2930 // clang-format off
2932 job) == -1) {
2933 // clang-format on
2934 iec = errnum2iec(get_errnum());
2935 goto error_switch_sel_req;
2936 }
2937 break;
2938 case 0x5d:
2939 // clang-format off
2941 &co_gw_job_lss_lssid_ind, job) == -1) {
2942 // clang-format on
2943 iec = errnum2iec(get_errnum());
2944 goto error_switch_sel_req;
2945 }
2946 break;
2947 default: iec = CO_GW_IEC_LSS; goto error_cs;
2948 }
2949
2950 return 0;
2951
2952error_switch_sel_req:
2953error_cs:
2954 co_gw_job_destroy(job);
2955error_create_job:
2956 set_errc(errc);
2957 return co_gw_send_con(gw, req, iec, 0);
2958}
2959
2960static int
2962 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2963{
2964 assert(gw);
2965 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2966 assert(req);
2967 assert(req->srv == CO_GW_SRV_LSS_GET_ID);
2968
2969 int iec = 0;
2970 int errc = get_errc();
2971
2972 struct co_gw_job *job = co_gw_job_create_lss(
2973 &gw->net[net - 1]->lss, gw->net[net - 1], req);
2974 if (!job) {
2975 iec = errnum2iec(get_errnum());
2976 goto error_create_job;
2977 }
2978
2979 if (co_lss_get_id_req(job->data, &co_gw_job_lss_nid_ind, job) == -1) {
2980 iec = errnum2iec(get_errnum());
2981 goto error_get_id_req;
2982 }
2983
2984 return 0;
2985
2986error_get_id_req:
2987 co_gw_job_destroy(job);
2988error_create_job:
2989 set_errc(errc);
2990 return co_gw_send_con(gw, req, iec, 0);
2991}
2992
2993static int
2995 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
2996{
2997 assert(gw);
2998 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
2999 assert(req);
3000 assert(req->srv == CO_GW_SRV_LSS_ID_SLAVE);
3001
3002 if (req->size < sizeof(struct co_gw_req_lss_id_slave)) {
3004 return -1;
3005 }
3006 const struct co_gw_req_lss_id_slave *par =
3007 (const struct co_gw_req_lss_id_slave *)req;
3008
3009 int iec = 0;
3010 int errc = get_errc();
3011
3012 struct co_gw_job *job = co_gw_job_create_lss(
3013 &gw->net[net - 1]->lss, gw->net[net - 1], req);
3014 if (!job) {
3015 iec = errnum2iec(get_errnum());
3016 goto error_create_job;
3017 }
3018
3019 // clang-format off
3020 if (co_lss_id_slave_req(job->data, &par->lo, &par->hi,
3021 &co_gw_job_lss_cs_ind, job) == -1) {
3022 // clang-format on
3023 iec = errnum2iec(get_errnum());
3024 goto error_id_slave_req;
3025 }
3026
3027 return 0;
3028
3029error_id_slave_req:
3030 co_gw_job_destroy(job);
3031error_create_job:
3032 set_errc(errc);
3033 return co_gw_send_con(gw, req, iec, 0);
3034}
3035
3036static int
3038 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
3039{
3040 assert(gw);
3041 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
3042 assert(req);
3044
3045 int iec = 0;
3046 int errc = get_errc();
3047
3048 struct co_gw_job *job = co_gw_job_create_lss(
3049 &gw->net[net - 1]->lss, gw->net[net - 1], req);
3050 if (!job) {
3051 iec = errnum2iec(get_errnum());
3052 goto error_create_job;
3053 }
3054
3056 == -1) {
3057 iec = errnum2iec(get_errnum());
3058 goto error_id_non_cfg_slave_req;
3059 }
3060
3061 return 0;
3062
3063error_id_non_cfg_slave_req:
3064 co_gw_job_destroy(job);
3065error_create_job:
3066 set_errc(errc);
3067 return co_gw_send_con(gw, req, iec, 0);
3068}
3069
3070static int
3072 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
3073{
3074 assert(gw);
3075 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
3076 assert(req);
3077 assert(req->srv == CO_GW_SRV__LSS_SLOWSCAN);
3078
3079 if (req->size < sizeof(struct co_gw_req__lss_scan)) {
3081 return -1;
3082 }
3083 const struct co_gw_req__lss_scan *par =
3084 (const struct co_gw_req__lss_scan *)req;
3085
3086 int iec = 0;
3087 int errc = get_errc();
3088
3089 struct co_gw_job *job = co_gw_job_create_lss(
3090 &gw->net[net - 1]->lss, gw->net[net - 1], req);
3091 if (!job) {
3092 iec = errnum2iec(get_errnum());
3093 goto error_create_job;
3094 }
3095
3096 // clang-format off
3097 if (co_lss_slowscan_req(job->data, &par->id_1, &par->id_2,
3098 &co_gw_job_lss_scan_ind, job) == -1) {
3099 // clang-format on
3100 iec = errnum2iec(get_errnum());
3101 goto error_slowscan_req;
3102 }
3103
3104 return 0;
3105
3106error_slowscan_req:
3107 co_gw_job_destroy(job);
3108error_create_job:
3109 set_errc(errc);
3110 return co_gw_send_con(gw, req, iec, 0);
3111}
3112
3113static int
3115 co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
3116{
3117 assert(gw);
3118 assert(net && net <= CO_GW_NUM_NET && gw->net[net - 1]);
3119 assert(req);
3120 assert(req->srv == CO_GW_SRV__LSS_FASTSCAN);
3121
3122 if (req->size < sizeof(struct co_gw_req__lss_scan)) {
3124 return -1;
3125 }
3126 const struct co_gw_req__lss_scan *par =
3127 (const struct co_gw_req__lss_scan *)req;
3128
3129 int iec = 0;
3130 int errc = get_errc();
3131
3132 struct co_gw_job *job = co_gw_job_create_lss(
3133 &gw->net[net - 1]->lss, gw->net[net - 1], req);
3134 if (!job) {
3135 iec = errnum2iec(get_errnum());
3136 goto error_create_job;
3137 }
3138
3139 // clang-format off
3140 if (co_lss_fastscan_req(job->data, &par->id_1, &par->id_2,
3141 &co_gw_job_lss_scan_ind, job) == -1) {
3142 // clang-format on
3143 iec = errnum2iec(get_errnum());
3144 goto error_fastscan_req;
3145 }
3146
3147 return 0;
3148
3149error_fastscan_req:
3150 co_gw_job_destroy(job);
3151error_create_job:
3152 set_errc(errc);
3153 return co_gw_send_con(gw, req, iec, 0);
3154}
3155
3156#endif // !LELY_NO_CO_MASTER && !LELY_NO_CO_LSS
3157
3158static int
3159co_gw_send_con(co_gw_t *gw, const struct co_gw_req *req, int iec,
3160 co_unsigned32_t ac)
3161{
3162 assert(req);
3163
3164 // Convert SDO abort codes to their equivalent internal error codes
3165 // where possible.
3166 switch (ac) {
3167 case CO_SDO_AC_TIMEOUT:
3168 ac = 0;
3169 iec = CO_GW_IEC_TIMEOUT;
3170 break;
3171 case CO_SDO_AC_NO_MEM:
3172 ac = 0;
3173 iec = CO_GW_IEC_NO_MEM;
3174 break;
3175 case CO_SDO_AC_PDO_LEN: ac = 0; iec = CO_GW_IEC_PDO_LEN;
3176 }
3177
3178 // Copy the service number and user-specified data from the request to
3179 // the confirmation.
3180 struct co_gw_con con = { .size = sizeof(con),
3181 .srv = req->srv,
3182 .data = req->data,
3183 .iec = iec,
3184 .ac = ac };
3185 return co_gw_send_srv(gw, (struct co_gw_srv *)&con);
3186}
3187
3188static int
3189co_gw_send_ec(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node,
3190 co_unsigned8_t st, int iec)
3191{
3192 struct co_gw_ind_ec ind = { .size = sizeof(ind),
3193 .srv = CO_GW_SRV_EC,
3194 .net = net,
3195 .node = node,
3196 .st = st,
3197 .iec = iec };
3198 return co_gw_send_srv(gw, (struct co_gw_srv *)&ind);
3199}
3200
3201static int
3203{
3204 assert(gw);
3205 assert(srv);
3206
3207 if (!gw->send_func) {
3209 return -1;
3210 }
3211
3212 return gw->send_func(srv, gw->send_data) ? -1 : 0;
3213}
3214
3215static inline int
3217{
3218 switch (errnum) {
3219 case 0: return 0;
3220 case ERRNUM_INVAL: return CO_GW_IEC_SYNTAX;
3221 case ERRNUM_NOMEM: return CO_GW_IEC_NO_MEM;
3222 case ERRNUM_PERM: return CO_GW_IEC_BAD_SRV;
3223 default: return CO_GW_IEC_INTERN;
3224 }
3225}
3226
3227#endif // !LELY_NO_CO_GW
#define CAN_MAX_LEN
The maximum number of bytes in the payload of a CAN format frame.
Definition msg.h:72
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_unsigned8_t co_dev_get_id(const co_dev_t *dev)
Returns the node-ID of a CANopen device.
Definition dev.c:197
#define CO_BAUD_20
A bit rate of 20 kbit/s.
Definition dev.h:77
#define CO_BAUD_AUTO
Automatic bit rate detection.
Definition dev.h:83
#define CO_BAUD_125
A bit rate of 125 kbit/s.
Definition dev.h:71
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition dev.h:56
#define CO_BAUD_10
A bit rate of 10 kbit/s.
Definition dev.h:80
co_unsigned8_t co_dev_get_netid(const co_dev_t *dev)
Returns the network-ID of a CANopen device.
Definition dev.c:174
#define CO_BAUD_250
A bit rate of 250 kbit/s.
Definition dev.h:68
#define CO_BAUD_1000
A bit rate of 1 Mbit/s.
Definition dev.h:59
#define CO_BAUD_500
A bit rate of 500 kbit/s.
Definition dev.h:65
#define CO_BAUD_800
A bit rate of 800 kbit/s.
Definition dev.h:62
unsigned int co_dev_get_baud(const co_dev_t *dev)
Returns the supported bit rates of a CANopen device (any combination of CO_BAUD_1000,...
Definition dev.c:503
#define CO_BAUD_50
A bit rate of 50 kbit/s.
Definition dev.h:74
This header file is part of the CANopen library; it contains the time stamp (TIME) object declaration...
void co_time_set_ind(co_time_t *time, co_time_ind_t *ind, void *data)
Sets the indication function invoked when a CANopen time stamp is received.
Definition time.c:355
This header file is part of the CANopen library; it contains the Client-SDO declarations.
int co_csdo_up_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_csdo_up_con_t *con, void *data)
Submits an upload request to a remote Server-SDO.
Definition csdo.c:1294
int co_dev_up_req(const co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx, co_csdo_up_con_t *con, void *data)
Submits an upload request to a local device.
Definition csdo.c:812
int co_csdo_dn_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
Submits a download request to a remote Server-SDO.
Definition csdo.c:1219
int co_dev_dn_req(co_dev_t *dev, co_unsigned16_t idx, co_unsigned8_t subidx, const void *ptr, size_t n, co_csdo_dn_con_t *con, void *data)
Submits a download request to a local device.
Definition csdo.c:664
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition csdo.c:1142
void co_csdo_set_up_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO upload reques...
Definition csdo.c:1184
void co_csdo_set_dn_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO download requ...
Definition csdo.c:1164
co_csdo_t * co_csdo_create(can_net_t *net, co_dev_t *dev, co_unsigned8_t num)
Creates a new CANopen Client-SDO service.
Definition csdo.c:997
co_unsigned8_t co_csdo_get_num(const co_csdo_t *sdo)
Returns the SDO number of a Client-SDO.
Definition csdo.c:1118
void co_csdo_destroy(co_csdo_t *sdo)
Destroys a CANopen Client-SDO service.
Definition csdo.c:1024
This header file is part of the CANopen library; it contains the emergency (EMCY) object declarations...
#define CO_EMCY_COBID_VALID
The bit in the EMCY COB-ID specifying whether the EMCY exists and is valid.
Definition emcy.h:29
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:625
This header file is part of the utilities library; it contains the native and platform-independent er...
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition errnum.c:810
errnum
The platform-independent error numbers.
Definition errnum.h:77
@ ERRNUM_NOSYS
Function not supported.
Definition errnum.h:184
@ ERRNUM_BUSY
Device or resource busy.
Definition errnum.h:97
@ ERRNUM_PERM
Operation not permitted.
Definition errnum.h:208
@ ERRNUM_NOMEM
Not enough space.
Definition errnum.h:172
@ ERRNUM_INVAL
Invalid argument.
Definition errnum.h:132
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition errnum.c:932
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition errnum.c:944
enum errnum errnum_t
The platform-independent error number type.
Definition errnum.h:266
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition errnum.c:46
errnum_t get_errnum(void)
Returns the last (thread-specific) platform-independent error number set by a system call or library ...
Definition errnum.h:418
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition errnum.h:424
static void co_gw_net_hb_ind(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason, void *data)
The callback function invoked when a heartbeat event occurs for a node on a CANopen network.
Definition gw.c:1201
static void co_gw_job_sdo_up_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac, const void *ptr, size_t n, void *data)
The confirmation function for an 'SDO upload' request.
Definition gw.c:1470
static void co_gw_net_ng_ind(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason, void *data)
The callback function invoked when a node guarding event occurs for a node on a CANopen network.
Definition gw.c:1163
int co_gw_recv(co_gw_t *gw, const struct co_gw_req *req)
Receives and processes a request with a CANopen gateway.
Definition gw.c:614
static int co_gw_recv__lss_slowscan(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'LSS Slowscan' request.
Definition gw.c:3071
static int co_gw_recv_nmt_set_hb(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, const struct co_gw_req *req)
Processes a 'Start/Disable heartbeat consumer' request.
Definition gw.c:2261
static int co_gw_recv_lss_get_id(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'LSS inquire node-ID' request.
Definition gw.c:2961
static int co_gw_recv_set_hb(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a 'Set heartbeat producer' request.
Definition gw.c:2389
static int co_gw_recv_set_tpdo(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a 'Configure TPDO' request.
Definition gw.c:2027
void co_gw_set_rate_func(co_gw_t *gw, co_gw_rate_func_t *func, void *data)
Sets the callback function invoked when a baudrate switch is needed after an 'Initialize gateway' com...
Definition gw.c:945
co_gw_t * co_gw_create(void)
Creates a new CANopen gateway.
Definition gw.c:549
static int errnum2iec(errnum_t errnum)
Converts an error number to an internal error code.
Definition gw.c:3216
static int co_gw_recv_pdo_write(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a 'Write PDO data' request.
Definition gw.c:2137
static struct co_gw_job * co_gw_job_create_sdo(struct co_gw_job **pself, struct co_gw_net *net, co_unsigned8_t id, const struct co_gw_req *req)
Creates a new SDO upload/download job.
Definition gw.c:1416
static int co_gw_recv_nmt_set_ng(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, const struct co_gw_req *req)
Processes a 'Enable/Disable node guarding' request.
Definition gw.c:2223
static void co_gw_net_time_ind(co_time_t *time, const struct timespec *tp, void *data)
The callback function invoked when a TIME message is received from a node on a CANopen network.
Definition gw.c:1330
int co_gw_init_net(co_gw_t *gw, co_unsigned16_t id, co_nmt_t *nmt)
Registers a CANopen network with a gateway.
Definition gw.c:583
static int co_gw_recv_sdo_dn(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, const struct co_gw_req *req)
Processes an 'SDO download' request.
Definition gw.c:1869
static void co_gw_job_remove(struct co_gw_job *job)
Removes a CANopen gateway network job from its network.
Definition gw.c:1405
static void co_gw_net_rpdo_ind(co_rpdo_t *pdo, co_unsigned32_t ac, const void *ptr, size_t n, void *data)
The callback function invoked when a PDO is received from a node on a CANopen network.
Definition gw.c:1766
static void co_gw_job_lss_cs_ind(co_lss_t *lss, co_unsigned8_t cs, void *data)
The confirmation function for an 'LSS switch state selective', 'LSS identify remote slave' or 'LSS id...
Definition gw.c:1589
static void co_gw_net_up_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The callback function invoked to notify the user of the progress of an SDO upload request during the ...
Definition gw.c:1288
const char * co_gw_iec2str(int iec)
Returns a string describing an internal error code.
Definition gw.c:466
static int co_gw_recv_lss_set_id(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'LSS configure node-ID' request.
Definition gw.c:2714
static int co_gw_recv_set_bootup_ind(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a 'Boot-up forwarding' request.
Definition gw.c:2533
static int co_gw_recv_lss_set_rate(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'LSS configure bit-rate' request.
Definition gw.c:2754
static int co_gw_recv_lss_store(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'LSS store configuration' request.
Definition gw.c:2852
void co_gw_get_rate_func(const co_gw_t *gw, co_gw_rate_func_t **pfunc, void **pdata)
Retrieves the callback function invoked when a baudrate switch is needed after an 'Initialize gateway...
Definition gw.c:934
static int co_gw_recv_set_emcy(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, const struct co_gw_req *req)
Processes a 'Start/Stop emergency consumer' request.
Definition gw.c:2455
static int co_gw_recv_lss_get_lssid(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'Inquire LSS address' request.
Definition gw.c:2885
static void co_gw_net_emcy_ind(co_emcy_t *emcy, co_unsigned8_t id, co_unsigned16_t ec, co_unsigned8_t er, co_unsigned8_t msef[5], void *data)
The callback function invoked when an EMCY message is received from a node on a CANopen network.
Definition gw.c:1346
static int co_gw_recv_lss_id_non_cfg_slave(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'LSS identify non-configured remote slaves' request.
Definition gw.c:3037
static int co_gw_recv_get_version(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a 'Get version' request.
Definition gw.c:2608
static struct co_gw_job * co_gw_job_create(struct co_gw_job **pself, struct co_gw_net *net, void *data, void(*dtor)(void *data), const struct co_gw_req *req)
Creates a new CANopen gateway network job.
Definition gw.c:1365
static void co_gw_job_destroy(struct co_gw_job *job)
Destroys a CANopen gateway network job.
Definition gw.c:1392
static int co_gw_recv_lss_switch_sel(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'LSS switch state selective' request.
Definition gw.c:2671
static void co_gw_net_lg_ind(co_nmt_t *nmt, int state, void *data)
The callback function invoked when a life guarding event occurs for a CANopen gateway.
Definition gw.c:1184
static void co_gw_net_boot_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, char es, void *data)
The callback function invoked when the 'boot slave' process completes for a node on a CANopen network...
Definition gw.c:1245
static void co_gw_net_st_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, void *data)
The callback function invoked when a boot-up event or state change is detected for a node on a CANope...
Definition gw.c:1221
static void co_gw_net_sync_ind(co_sync_t *sync, co_unsigned8_t cnt, void *data)
The callback function invoked when a SYNC message is received from a node on a CANopen network.
Definition gw.c:1312
static void co_gw_net_cs_ind(co_nmt_t *nmt, co_unsigned8_t cs, void *data)
The callback function invoked when an NMT command is received by a CANopen gateway.
Definition gw.c:1097
static void co_gw_net_destroy(struct co_gw_net *net)
Destroys a CANopen network.
Definition gw.c:1042
static int co_gw_recv_set_id(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a 'Set node-ID' request.
Definition gw.c:2425
static int co_gw_send_con(co_gw_t *gw, const struct co_gw_req *req, int iec, co_unsigned32_t ac)
Sends a confirmation with an internal error code or SDO abort code.
Definition gw.c:3159
int co_gw_fini_net(co_gw_t *gw, co_unsigned16_t id)
Unregisters a CANopen network with a gateway.
Definition gw.c:598
static int co_gw_recv_set_node(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a 'Set default node-ID' request.
Definition gw.c:2580
static int co_gw_recv_nmt_cs(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, co_unsigned8_t cs, const struct co_gw_req *req)
Processes an NMT request.
Definition gw.c:2201
static int co_gw_recv_lss_switch_rate(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'LSS activate new bit-rate' request.
Definition gw.c:2816
static int co_gw_recv_set_cmd_timeout(co_gw_t *gw, const struct co_gw_req *req)
Processes a 'Set command time-out' request.
Definition gw.c:2497
static int co_gw_recv_sdo_up(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, const struct co_gw_req *req)
Processes an 'SDO upload' request.
Definition gw.c:1793
static struct co_gw_net * co_gw_net_create(co_gw_t *gw, co_unsigned16_t id, co_nmt_t *nmt)
Creates a new CANopen network.
Definition gw.c:954
static struct co_gw_job * co_gw_job_create_lss(struct co_gw_job **pself, struct co_gw_net *net, const struct co_gw_req *req)
Creates a new LSS job.
Definition gw.c:1560
static int co_gw_recv_set_sdo_timeout(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a 'Configure SDO time-out' request.
Definition gw.c:1948
static int co_gw_recv_set_rpdo(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a 'Configure RPDO' request.
Definition gw.c:1985
static void co_gw_job_sdo_dtor(void *data)
Destroys the Client-SDO service in an SDO upload/download job.
Definition gw.c:1462
#define CO_GW_JOB_SIZE
The minimum size (in bytes) of a CANopen gateway network job.
Definition gw.c:255
static int co_gw_send_srv(co_gw_t *gw, const struct co_gw_srv *srv)
Invokes the callback function to send a confirmation or indication.
Definition gw.c:3202
void co_gw_destroy(co_gw_t *gw)
Destroys a CANopen gateway.
Definition gw.c:574
static void co_gw_job_sdo_ind(const co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The progress indication function for an SDO upload/download job.
Definition gw.c:1534
static int co_gw_recv_set_net(co_gw_t *gw, const struct co_gw_req *req)
Processes a 'Set default network' request.
Definition gw.c:2554
static void co_gw_job_lss_err_ind(co_lss_t *lss, co_unsigned8_t cs, co_unsigned8_t err, co_unsigned8_t spec, void *data)
The confirmation function for an 'LSS configure node-ID', 'LSS configure bit-rate' or 'LSS store conf...
Definition gw.c:1622
static void co_gw_job_lss_nid_ind(co_lss_t *lss, co_unsigned8_t cs, co_unsigned8_t id, void *data)
The confirmation function for an 'LSS inquire node-ID' request.
Definition gw.c:1692
static void co_gw_job_sdo_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac, void *data)
The confirmation function for an 'SDO download' request.
Definition gw.c:1515
static void co_gw_job_lss_scan_ind(co_lss_t *lss, co_unsigned8_t cs, const struct co_id *id, void *data)
The confirmation function for an 'LSS Slowscan/Fastscan' request.
Definition gw.c:1723
static int co_gw_recv_lss_switch(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'LSS switch state global' request.
Definition gw.c:2635
static int co_gw_recv_lss_id_slave(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'LSS identify remote slave' request.
Definition gw.c:2994
static int co_gw_send_ec(co_gw_t *gw, co_unsigned16_t net, co_unsigned8_t node, co_unsigned8_t st, int iec)
Sends an 'Error control event received' indication.
Definition gw.c:3189
static void co_gw_job_lss_lssid_ind(co_lss_t *lss, co_unsigned8_t cs, co_unsigned32_t id, void *data)
The confirmation function for an 'Inquire LSS address' request.
Definition gw.c:1657
static int co_gw_recv_init(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'Initialize gateway' request.
Definition gw.c:2289
static int co_gw_recv_pdo_read(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes a 'Read PDO data' request.
Definition gw.c:2072
void co_gw_get_send_func(const co_gw_t *gw, co_gw_send_func_t **pfunc, void **pdata)
Retrieves the callback function used to send indications and confirmations from a CANopen gateway.
Definition gw.c:914
static int co_gw_recv__lss_fastscan(co_gw_t *gw, co_unsigned16_t net, const struct co_gw_req *req)
Processes an 'LSS Fastscan' request.
Definition gw.c:3114
void co_gw_set_send_func(co_gw_t *gw, co_gw_send_func_t *func, void *data)
Sets the callback function used to send indications and confirmations from a CANopen gateway.
Definition gw.c:925
static void co_gw_net_dn_ind(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The callback function invoked to notify the user of the progress of an SDO download request during th...
Definition gw.c:1267
This header file is part of the CANopen library; it contains the gateway declarations (see CiA 309-1 ...
#define CO_GW_IEC_HB_OCCURRED
CANopen gateway internal error: Heartbeat lost.
Definition gw.h:209
#define CO_GW_SRV_SET_RPDO
CANopen gateway service: Configure RPDO.
Definition gw.h:47
#define CO_GW_IEC_CAN_ACTIVE
CANopen gateway internal error: CAN active.
Definition gw.h:230
#define CO_GW_SRV_SET_CMD_TIMEOUT
CANopen gateway service: Set command time-out.
Definition gw.h:110
#define CO_GW_SRV_NMT_STOP
CANopen gateway service: Start node.
Definition gw.h:65
#define CO_GW_IEC_NG_OCCURRED
CANopen gateway internal error: Lost guarding message.
Definition gw.h:200
#define CO_GW_IEC_NO_DEF_NET
CANopen gateway internal error: No default net set.
Definition gw.h:188
#define CO_GW_SRV_LSS_SET_ID
CANopen gateway service: LSS configure node-ID.
Definition gw.h:134
#define CO_GW_SRV_LSS_SWITCH_RATE
CANopen gateway service: LSS activate new bit-rate.
Definition gw.h:140
#define CO_GW_PROT_HI
The high number of the version of CiA 309-1 implemented by this gateway.
Definition gw.h:32
#define CO_GW_SRV_EMCY_START
CANopen gateway service: Start emergency consumer.
Definition gw.h:104
#define CO_GW_IEC_NO_DEF_NODE
CANopen gateway internal error: No default node set.
Definition gw.h:191
#define CO_GW_SRV_NMT_ENTER_PREOP
CANopen gateway service: Set node to pre-operational.
Definition gw.h:68
#define CO_GW_SRV_SET_TPDO
CANopen gateway service: Configure TPDO.
Definition gw.h:50
#define CO_GW_SRV_LSS_GET_LSSID
CANopen gateway service: Inquire LSS address.
Definition gw.h:146
#define CO_GW_IEC_LSS_PARAM
CANopen gateway internal error: LSS parameter storing failed.
Definition gw.h:248
#define CO_GW_CON_SDO_UP_SIZE
The minimum size (in bytes) of a CANopen gateway 'SDO upload' confirmation.
Definition gw.h:725
#define CO_GW_SRV_LSS_SWITCH
CANopen gateway service: LSS switch state global.
Definition gw.h:128
#define CO_GW_REQ_SDO_DN_SIZE
The minimum size (in bytes) of a CANopen gateway 'SDO download' request.
Definition gw.h:349
#define CO_GW_SRV_SET_SDO_TIMEOUT
CANopen gateway service: Configure SDO time-out.
Definition gw.h:44
#define CO_GW_SRV_LSS_SET_RATE
CANopen gateway service: LSS configure bit-rate.
Definition gw.h:137
#define CO_GW_SRV_RPDO
CANopen gateway service: RPDO received.
Definition gw.h:59
#define CO_GW_SRV__BOOT
Lely-specific gateway service: Boot slave process completed.
Definition gw.h:173
#define CO_GW_IEC_LSS_MEDIA
CANopen gateway internal error: LSS command failed because of media error.
Definition gw.h:251
#define CO_GW_SRV_SDO
CANopen gateway service: CiA 301 progress indication download.
Definition gw.h:158
#define CO_GW_SRV_SET_CMD_SIZE
CANopen gateway service: Set command size.
Definition gw.h:125
#define CO_GW_SRV_SET_BOOTUP_IND
CANopen gateway service: Boot-up forwarding.
Definition gw.h:113
#define CO_GW_SRV_SET_NODE
CANopen gateway service: Set default node-ID.
Definition gw.h:119
#define CO_GW_SRV_NMT_HB_ENABLE
CANopen gateway service: Start heartbeat consumer.
Definition gw.h:83
#define CO_GW_IEC_HB_RESOLVED
CANopen gateway internal error: Heartbeat started.
Definition gw.h:206
#define CO_GW_SRV_LSS_ID_NON_CFG_SLAVE
CANopen gateway service: LSS identify non-configured remote slaves.
Definition gw.h:155
#define CO_GW_SRV_PDO_WRITE
CANopen gateway service: Write PDO data.
Definition gw.h:56
#define CO_GW_IEC_ST_OCCURRED
CANopen gateway internal error: Wrong NMT state.
Definition gw.h:212
int co_gw_send_func_t(const struct co_gw_srv *srv, void *data)
The type of a CANopen gateway send callback function, invoked by a gateway when an indication or conf...
Definition gw.h:976
#define CO_GW_IEC_CAN_BUSOFF
CANopen gateway internal error: Bus off.
Definition gw.h:221
#define CO_GW_SRV_NMT_RESET_COMM
CANopen gateway service: Reset communication.
Definition gw.h:74
#define CO_GW_IEC_PDO_LEN
CANopen gateway internal error: PDO length exceeded.
Definition gw.h:236
#define CO_GW_SRV_SDO_UP
CANopen gateway service: SDO upload.
Definition gw.h:38
#define CO_GW_IEC_LSS_ID
CANopen gateway internal error: LSS node-ID not supported.
Definition gw.h:242
#define CO_GW_SRV_PDO_READ
CANopen gateway service: Read PDO data.
Definition gw.h:53
#define CO_GW_IND_RPDO_SIZE
The minimum size (in bytes) of a CANopen gateway 'RPDO received' indication.
Definition gw.h:851
#define CO_GW_IEC_BAD_SRV
CANopen gateway internal error: Request not supported.
Definition gw.h:176
#define CO_GW_SRV_SET_ID
CANopen gateway service: Set node-ID.
Definition gw.h:101
#define CO_GW_SRV_NMT_START
CANopen gateway service: Start node.
Definition gw.h:62
#define CO_GW_SRV__SYNC
Lely-specific gateway service: Synchronization event received.
Definition gw.h:167
#define CO_GW_IEC_CAN_OVERFLOW
CANopen gateway internal error: CAN buffer overflow.
Definition gw.h:224
#define CO_GW_SRV_EMCY
CANopen gateway service: Emergency event received.
Definition gw.h:92
#define CO_GW_IEC_CAN_INIT
CANopen gateway internal error: CAN init.
Definition gw.h:227
#define CO_GW_IEC_NO_MEM
CANopen gateway internal error: Running out of memory.
Definition gw.h:254
#define CO_GW_IEC_SYNTAX
CANopen gateway internal error: Syntax error.
Definition gw.h:179
#define CO_GW_SRV_EC
CANopen gateway service: Error control event received.
Definition gw.h:89
#define CO_GW_IEC_LSS_RATE
CANopen gateway internal error: LSS bit-rate not supported.
Definition gw.h:245
#define CO_GW_SRV_SET_NET
CANopen gateway service: Set default network.
Definition gw.h:116
#define CO_GW_PROT_LO
The low number of the version of CiA 309-1 implemented by this gateway.
Definition gw.h:35
#define CO_GW_SRV__TIME
Lely-specific gateway service: Time stamp event received.
Definition gw.h:170
#define CO_GW_SRV_NMT_RESET_NODE
CANopen gateway service: Reset node.
Definition gw.h:71
#define CO_GW_REQ_SET_RPDO_SIZE
The minimum size (in bytes) of a CANopen gateway 'Configure RPDO' request.
Definition gw.h:388
#define CO_GW_IEC_BOOTUP
CANopen gateway internal error: Boot-up.
Definition gw.h:215
#define CO_GW_NUM_NET
The maximum number of networks in a CANopen gateway.
Definition gw.h:29
#define CO_GW_IEC_BAD_NODE
CANopen gateway internal error: Unsupported node.
Definition gw.h:197
#define CO_GW_SRV_LSS_ID_SLAVE
CANopen gateway service: LSS identify remote slave.
Definition gw.h:152
#define CO_GW_IEC_PDO_INUSE
CANopen gateway internal error: PDO already used.
Definition gw.h:233
#define CO_GW_SRV_LSS_STORE
CANopen gateway service: LSS store configuration.
Definition gw.h:143
#define CO_GW_SRV__LSS_SLOWSCAN
Lely-specific gateway service: LSS Slowscan.
Definition gw.h:161
void co_gw_rate_func_t(co_unsigned16_t net, co_unsigned16_t rate, void *data)
The type of a CANopen gateway 'set bit timing' function, invoked when a baudrate switch is needed aft...
Definition gw.h:986
#define CO_GW_SRV_LSS_GET_ID
CANopen gateway service: LSS inquire node-ID.
Definition gw.h:149
#define CO_GW_SRV_GET_VERSION
CANopen gateway service: Get version.
Definition gw.h:122
#define CO_GW_REQ_SET_TPDO_SIZE
The minimum size (in bytes) of a CANopen gateway 'Configure TPDO' request.
Definition gw.h:419
#define CO_GW_REQ_PDO_WRITE_SIZE
The minimum size (in bytes) of a CANopen gateway 'Write PDO' request.
Definition gw.h:454
#define CO_GW_IEC_TIMEOUT
CANopen gateway internal error: Time-out.
Definition gw.h:185
#define CO_GW_SRV__LSS_FASTSCAN
Lely-specific gateway service: LSS Fastscan.
Definition gw.h:164
#define CO_GW_SRV_NMT_NG_ENABLE
CANopen gateway service: Enable node guarding.
Definition gw.h:77
#define CO_GW_SRV_NMT_NG_DISABLE
CANopen gateway service: Disable node guarding.
Definition gw.h:80
#define CO_GW_IEC_LSS
CANopen gateway internal error: LSS error.
Definition gw.h:239
#define CO_GW_IEC_INTERN
CANopen gateway internal error: Request not processed due to internal state.
Definition gw.h:182
#define CO_GW_SRV_NMT_HB_DISABLE
CANopen gateway service: Disable heartbeat consumer.
Definition gw.h:86
#define CO_GW_SRV_SET_HB
CANopen gateway service: Set heartbeat producer.
Definition gw.h:98
#define CO_GW_IEC_BAD_NET
CANopen gateway internal error: Unsupported net.
Definition gw.h:194
#define CO_GW_IEC_LG_OCCURRED
CANopen gateway internal error: Lost connection.
Definition gw.h:203
#define CO_GW_SRV_INIT
CANopen gateway service: Initialize gateway.
Definition gw.h:95
#define CO_GW_SRV_SDO_DN
CANopen gateway service: SDO download.
Definition gw.h:41
#define CO_GW_IEC_CAN_PASSIVE
CANopen gateway internal error: Error passive.
Definition gw.h:218
#define CO_GW_SRV_EMCY_STOP
CANopen gateway service: Stop emergency consumer.
Definition gw.h:107
#define CO_GW_SRV_LSS_SWITCH_SEL
CANopen gateway service: LSS switch state selective.
Definition gw.h:131
This header file is part of the CANopen library; it contains the Service Data Object (SDO) declaratio...
#define CO_SDO_REQ_INIT
The static initializer for struct co_sdo_req.
Definition sdo.h:206
void co_sdo_req_fini(struct co_sdo_req *req)
Finalizes a CANopen SDO upload/download request.
Definition sdo.c:121
#define CO_SDO_AC_NO_OBJ
SDO abort code: Object does not exist in the object dictionary.
Definition sdo.h:93
#define CO_SDO_AC_NO_SUB
SDO abort code: Sub-index does not exist.
Definition sdo.h:132
#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
#define CO_SDO_AC_TIMEOUT
SDO abort code: SDO protocol timed out.
Definition sdo.h:66
#define CO_SDO_AC_NO_MEM
SDO abort code: Out of memory.
Definition sdo.h:81
#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
This header file is part of the CANopen library; it contains the Layer Setting Services (LSS) and pro...
int co_lss_get_vendor_id_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the 'inquire identity vendor-ID' service.
Definition lss.c:1142
int co_lss_set_id_req(co_lss_t *lss, co_unsigned8_t id, co_lss_err_ind_t *ind, void *data)
Requests the 'configure node-ID' service.
Definition lss.c:1021
void co_lss_set_timeout(co_lss_t *lss, int timeout)
Sets the timeout of an LSS master service.
Definition lss.c:932
int co_lss_slowscan_req(co_lss_t *lss, const struct co_id *lo, const struct co_id *hi, co_lss_scan_ind_t *ind, void *data)
Requests the 'LSS Slowscan' service.
Definition lss.c:1329
int co_lss_switch_rate_req(co_lss_t *lss, int delay)
Requests the 'activate bit timing parameters' service.
Definition lss.c:1094
int co_lss_get_id_req(co_lss_t *lss, co_lss_nid_ind_t *ind, void *data)
Requests the 'inquire node-ID' service.
Definition lss.c:1244
int co_lss_get_revision_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the 'inquire identity revision-number' service.
Definition lss.c:1192
int co_lss_switch_sel_req(co_lss_t *lss, const struct co_id *id, co_lss_cs_ind_t *ind, void *data)
Requests the 'switch state selective' service.
Definition lss.c:999
int co_lss_switch_req(co_lss_t *lss, co_unsigned8_t mode)
Requests the 'switch state global' service.
Definition lss.c:977
int co_lss_set_rate_req(co_lss_t *lss, co_unsigned16_t rate, co_lss_err_ind_t *ind, void *data)
Requests the 'configure bit timing parameters' service.
Definition lss.c:1053
int co_lss_get_product_code_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the 'inquire identity product-code' service.
Definition lss.c:1167
int co_lss_id_slave_req(co_lss_t *lss, const struct co_id *lo, const struct co_id *hi, co_lss_cs_ind_t *ind, void *data)
Requests the 'LSS identify remote slave' service.
Definition lss.c:1269
int co_lss_store_req(co_lss_t *lss, co_lss_err_ind_t *ind, void *data)
Requests the 'store configuration' service.
Definition lss.c:1117
int co_lss_id_non_cfg_slave_req(co_lss_t *lss, co_lss_cs_ind_t *ind, void *data)
Requests the 'LSS identify non-configured remote slave' service.
Definition lss.c:1303
#define LELY_CO_LSS_TIMEOUT
The default LSS timeout (in milliseconds).
Definition lss.h:35
int co_lss_fastscan_req(co_lss_t *lss, const struct co_id *id, const struct co_id *mask, co_lss_scan_ind_t *ind, void *data)
Requests the 'LSS Fastscan' service.
Definition lss.c:1365
int co_lss_get_serial_nr_req(co_lss_t *lss, co_lss_lssid_ind_t *ind, void *data)
Requests the 'inquire identity serial-number' service.
Definition lss.c:1218
This header file is part of the CANopen library; it contains the network management (NMT) declaration...
int co_nmt_cs_ind(co_nmt_t *nmt, co_unsigned8_t cs)
Processes an NMT command from the master or the application.
Definition nmt.c:2098
void co_nmt_on_sync(co_nmt_t *nmt, co_unsigned8_t cnt)
Implements the default behavior after a SYNC object is received or transmitted.
Definition nmt.c:1610
#define CO_NMT_ST_BOOTUP
The NMT state 'boot-up'.
Definition nmt.h:55
void co_nmt_get_cs_ind(const co_nmt_t *nmt, co_nmt_cs_ind_t **pind, void **pdata)
Retrieves the indication function invoked when an NMT command is received.
Definition nmt.c:1283
#define CO_NMT_CS_START
The NMT command specifier 'start'.
Definition nmt.h:40
void co_nmt_lg_ind_t(co_nmt_t *nmt, int state, void *data)
The type of a CANopen NMT life guarding indication function, invoked when a life guarding event occur...
Definition nmt.h:139
void co_nmt_get_st_ind(const co_nmt_t *nmt, co_nmt_st_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a state change is detected.
Definition nmt.c:1434
void co_nmt_get_dn_ind(const co_nmt_t *nmt, co_nmt_sdo_ind_t **pind, void **pdata)
Retrieves the indication function used to notify the user of the progress of the current SDO download...
Definition nmt.c:1548
void co_nmt_set_hb_ind(co_nmt_t *nmt, co_nmt_hb_ind_t *ind, void *data)
Sets the indication function invoked when a heartbeat event occurs.
Definition nmt.c:1392
co_rpdo_t * co_nmt_get_rpdo(const co_nmt_t *nmt, co_unsigned16_t n)
Returns a pointer to a Receive-PDO service.
Definition nmt.c:2175
#define CO_NMT_CS_ENTER_PREOP
The NMT command specifier 'enter pre-operational'.
Definition nmt.h:46
void co_nmt_ng_ind_t(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason, void *data)
The type of a CANopen NMT node guarding indication function, invoked when a node guarding event occur...
Definition nmt.h:126
void co_nmt_get_ng_ind(const co_nmt_t *nmt, co_nmt_ng_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a node guarding event occurs.
Definition nmt.c:1307
#define CO_NMT_CS_RESET_NODE
The NMT command specifier 'reset node'.
Definition nmt.h:49
void co_nmt_get_boot_ind(const co_nmt_t *nmt, co_nmt_boot_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a CANopen NMT 'boot slave' process completes.
Definition nmt.c:1502
void co_nmt_st_ind_t(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, void *data)
The type of a CANopen NMT state change indication function, invoked when a state change is detected b...
Definition nmt.h:176
co_lss_t * co_nmt_get_lss(const co_nmt_t *nmt)
Returns a pointer to the LSS master/slave service.
Definition nmt.c:2282
#define CO_NMT_CS_STOP
The NMT command specifier 'stop'.
Definition nmt.h:43
void co_nmt_get_lg_ind(const co_nmt_t *nmt, co_nmt_lg_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a life guarding event occurs.
Definition nmt.c:1342
void co_nmt_set_boot_ind(co_nmt_t *nmt, co_nmt_boot_ind_t *ind, void *data)
Sets the indication function invoked when a CANopen NMT 'boot slave' process completes.
Definition nmt.c:1513
can_net_t * co_nmt_get_net(const co_nmt_t *nmt)
Returns a pointer to the CAN network of an NMT master/slave service.
Definition nmt.c:1267
co_dev_t * co_nmt_get_dev(const co_nmt_t *nmt)
Returns a pointer to the CANopen device of an NMT master/slave service.
Definition nmt.c:1275
@ CO_NMT_EC_STATE
An NMT error control state change event.
Definition nmt.h:89
@ CO_NMT_EC_TIMEOUT
An NMT error control timeout event.
Definition nmt.h:87
void co_nmt_boot_ind_t(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned8_t st, char es, void *data)
The type of a CANopen NMT 'boot slave' indication function, invoked when the 'boot slave' process com...
Definition nmt.h:200
#define CO_NMT_ST_START
The NMT state 'operational'.
Definition nmt.h:61
void co_nmt_hb_ind_t(co_nmt_t *nmt, co_unsigned8_t id, int state, int reason, void *data)
The type of a CANopen NMT heartbeat indication function, invoked when a heartbeat event occurs (see s...
Definition nmt.h:155
void co_nmt_cs_ind_t(co_nmt_t *nmt, co_unsigned8_t cs, void *data)
The type of a CANopen NMT command indication function, invoked when an NMT command is received (and a...
Definition nmt.h:110
void co_nmt_set_lg_ind(co_nmt_t *nmt, co_nmt_lg_ind_t *ind, void *data)
Sets the indication function invoked when a life guarding event occurs.
Definition nmt.c:1353
co_unsigned8_t co_nmt_get_st(const co_nmt_t *nmt)
Returns the current state of a CANopen NMT service (one of CO_NMT_ST_BOOTUP, CO_NMT_ST_STOP,...
Definition nmt.c:1766
void co_nmt_set_timeout(co_nmt_t *nmt, int timeout)
Sets the default SDO timeout used during the NMT 'boot slave' and 'check configuration' processes.
Definition nmt.c:1798
co_emcy_t * co_nmt_get_emcy(const co_nmt_t *nmt)
Returns a pointer to the EMCY producer/consumer service.
Definition nmt.c:2268
int co_nmt_ng_req(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t gt, co_unsigned8_t ltf)
Request the node guarding service for the specified node, even if it is not in the network list.
Definition nmt.c:2061
co_unsigned32_t co_dev_cfg_hb(co_dev_t *dev, co_unsigned8_t id, co_unsigned16_t ms)
Configures heartbeat consumption for the specified node by updating CANopen object 1016 (Consumer hea...
Definition nmt.c:744
void co_nmt_set_ng_ind(co_nmt_t *nmt, co_nmt_ng_ind_t *ind, void *data)
Sets the indication function invoked when a node guarding event occurs.
Definition nmt.c:1318
void co_nmt_set_dn_ind(co_nmt_t *nmt, co_nmt_sdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO download requ...
Definition nmt.c:1559
int co_nmt_cs_req(co_nmt_t *nmt, co_unsigned8_t cs, co_unsigned8_t id)
Submits an NMT request to a slave.
Definition nmt.c:1806
void co_nmt_set_cs_ind(co_nmt_t *nmt, co_nmt_cs_ind_t *ind, void *data)
Sets the indication function invoked when an NMT command is received.
Definition nmt.c:1294
int co_nmt_set_id(co_nmt_t *nmt, co_unsigned8_t id)
Sets the pending node-ID.
Definition nmt.c:1751
int co_nmt_is_master(const co_nmt_t *nmt)
Returns 1 if the specified CANopen NMT service is a master, and 0 if not.
Definition nmt.c:1774
void co_nmt_get_hb_ind(const co_nmt_t *nmt, co_nmt_hb_ind_t **pind, void **pdata)
Retrieves the indication function invoked when a heartbeat event occurs.
Definition nmt.c:1381
co_time_t * co_nmt_get_time(const co_nmt_t *nmt)
Returns a pointer to the TIME producer/consumer service.
Definition nmt.c:2254
co_tpdo_t * co_nmt_get_tpdo(const co_nmt_t *nmt, co_unsigned16_t n)
Returns a pointer to a Transmit-PDO service.
Definition nmt.c:2193
co_sync_t * co_nmt_get_sync(const co_nmt_t *nmt)
Returns a pointer to the SYNC producer/consumer service.
Definition nmt.c:2240
@ CO_NMT_EC_OCCURRED
An NMT error control event occurred.
Definition nmt.h:80
@ CO_NMT_EC_RESOLVED
An NMT error control event was resolved.
Definition nmt.h:82
void co_nmt_set_st_ind(co_nmt_t *nmt, co_nmt_st_ind_t *ind, void *data)
Sets the indication function invoked when a state change is detected.
Definition nmt.c:1445
#define CO_NMT_CS_RESET_COMM
The NMT command specifier 'reset communication'.
Definition nmt.h:52
void co_nmt_sdo_ind_t(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The type of an SDO request progress indication function, invoked by a CANopen NMT master to notify th...
Definition nmt.h:246
This header file is part of the CANopen library; it contains the object dictionary declarations.
co_unsigned32_t co_sub_dn_ind_val(co_sub_t *sub, co_unsigned16_t type, const void *val)
Invokes the download indication function of a CANopen sub-object, registered with co_sub_set_dn_ind()...
Definition obj.c:974
co_sub_t * co_obj_find_sub(const co_obj_t *obj, co_unsigned8_t subidx)
Finds a sub-object in a CANopen object.
Definition obj.c:240
co_unsigned32_t co_pdo_unmap(const struct co_pdo_map_par *par, const uint_least8_t *buf, size_t n, co_unsigned64_t *val, co_unsigned8_t *pn)
Unmaps a PDO into its constituent values.
Definition pdo.c:333
co_unsigned32_t co_pdo_up(const struct co_pdo_map_par *par, const co_dev_t *dev, struct co_sdo_req *req, uint_least8_t *buf, size_t *pn, int chk)
Reads mapped PDO values from the object dictionary through a local SDO upload request.
Definition pdo.c:432
#define CO_PDO_MAP_PAR_INIT
The static initializer from struct co_pdo_map_par.
Definition pdo.h:99
co_unsigned32_t co_dev_cfg_rpdo(const co_dev_t *dev, co_unsigned16_t num, const struct co_pdo_comm_par *comm, const struct co_pdo_map_par *map)
Configures the communication and parameters of a Receive-PDO service.
Definition pdo.c:80
co_unsigned32_t co_dev_cfg_tpdo(const co_dev_t *dev, co_unsigned16_t num, const struct co_pdo_comm_par *comm, const struct co_pdo_map_par *map)
Configures the communication and parameters of a Transmit-PDO service.
Definition pdo.c:153
co_unsigned32_t co_pdo_map(const struct co_pdo_map_par *par, const co_unsigned64_t *val, co_unsigned8_t n, uint_least8_t *buf, size_t *pn)
Maps values into a PDO.
Definition pdo.c:299
co_unsigned32_t co_pdo_dn(const struct co_pdo_map_par *par, co_dev_t *dev, struct co_sdo_req *req, const uint_least8_t *buf, size_t n, int chk)
Writes mapped PDO values to the object dictionary through a local SDO download request.
Definition pdo.c:368
This header file is part of the CANopen library; it contains the Receive-PDO declarations.
co_unsigned16_t co_rpdo_get_num(const co_rpdo_t *pdo)
Returns the PDO number of a Receive-PDO.
Definition rpdo.c:408
void co_rpdo_set_ind(co_rpdo_t *pdo, co_rpdo_ind_t *ind, void *data)
Sets the indication function invoked when a Receive-PDO error occurs.
Definition rpdo.c:443
const struct co_pdo_map_par * co_rpdo_get_map_par(const co_rpdo_t *pdo)
Returns a pointer to the PDO mapping parameter record of a Receive-PDO.
Definition rpdo.c:424
const struct co_pdo_comm_par * co_rpdo_get_comm_par(const co_rpdo_t *pdo)
Returns a pointer to the PDO communication parameter record of a Receive-PDO.
Definition rpdo.c:416
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 CANopen Client-SDO.
Definition csdo.c:71
A CANopen device.
Definition dev.h:30
A CANopen EMCY producer/consumer service.
Definition emcy.c:85
A CANopen gateway.
Definition gw.c:313
co_gw_rate_func_t * rate_func
A pointer to the callback function invoked when a baudrate switch is needed after an 'Initialize gate...
Definition gw.c:331
int timeout
The command timeout (in milliseconds).
Definition gw.c:317
struct co_gw_net * net[CO_GW_NUM_NET]
An array of pointers to the CANopen networks.
Definition gw.c:315
void * rate_data
A pointer to the user-specified data for rate_func.
Definition gw.c:333
void * send_data
A pointer to the user-specified data for send_func.
Definition gw.c:326
co_unsigned16_t def
The default network-ID.
Definition gw.c:319
co_gw_send_func_t * send_func
A pointer to the callback function invoked when an indication or confirmation needs to be sent.
Definition gw.c:324
A CANopen LSS master/slave service.
Definition lss.c:44
A CANopen NMT master/slave service.
Definition nmt.c:148
void * up_data
A pointer to user-specified data for up_ind.
Definition nmt.c:275
void * boot_data
A pointer to user-specified data for boot_ind.
Definition nmt.c:260
void * dn_data
A pointer to user-specified data for dn_ind.
Definition nmt.c:271
A CANopen object.
Definition obj.h:31
A CANopen Receive-PDO.
Definition rpdo.c:44
A CANopen sub-object.
Definition obj.h:53
A CANopen SYNC producer/consumer service.
Definition sync.c:40
A CANopen TIME producer/consumer service.
Definition time.c:41
A CANopen Transmit-PDO.
Definition tpdo.c:53
The parameters of a Lely-specific gateway 'LSS Slowscan/Fastscan' confirmation.
Definition gw.h:816
int srv
The service number (CO_GW_SRV__LSS_SLOWSCAN or CO_GW_SRV__LSS_FASTSCAN).
Definition gw.h:823
void * data
A pointer to user-specified data.
Definition gw.h:825
co_unsigned32_t ac
The SDO abort code (0 on success).
Definition gw.h:829
size_t size
The size of this struct (in bytes).
Definition gw.h:818
The parameters of a CANopen gateway 'Get version' confirmation.
Definition gw.h:753
size_t size
The size of this struct (in bytes).
Definition gw.h:755
int srv
The service number (CO_GW_SRV_GET_VERSION).
Definition gw.h:757
The parameters of a CANopen gateway 'LSS inquire node-ID' confirmation.
Definition gw.h:797
void * data
A pointer to user-specified data.
Definition gw.h:803
size_t size
The size of this struct (in bytes).
Definition gw.h:799
int srv
The service number (CO_GW_SRV_LSS_GET_ID).
Definition gw.h:801
The parameters of a CANopen gateway 'Inquire LSS address' confirmation.
Definition gw.h:781
size_t size
The size of this struct (in bytes).
Definition gw.h:783
int srv
The service number (CO_GW_SRV_LSS_GET_LSSID).
Definition gw.h:785
void * data
A pointer to user-specified data.
Definition gw.h:787
The parameters of a CANopen gateway 'Read PDO' confirmation.
Definition gw.h:728
co_unsigned8_t n
Number of mapped objects in PDO.
Definition gw.h:744
co_unsigned16_t net
The network-ID.
Definition gw.h:740
int srv
The service number (CO_GW_SRV_PDO_READ).
Definition gw.h:732
co_unsigned64_t val[0x40]
An array of object values.
Definition gw.h:746
co_unsigned32_t ac
The SDO abort code (0 on success).
Definition gw.h:738
int iec
The internal error code (0 on success).
Definition gw.h:736
size_t size
The size of this struct (in bytes).
Definition gw.h:730
The parameters of a CANopen gateway 'SDO upload' confirmation.
Definition gw.h:705
size_t size
The size of this struct (in bytes).
Definition gw.h:707
uint_least8_t val[1]
The (first byte in the) value.
Definition gw.h:721
The common parameters of a CANopen gateway confirmation.
Definition gw.h:691
int iec
The internal error code (0 on success).
Definition gw.h:699
int srv
The service number.
Definition gw.h:695
size_t size
The size of this struct (in bytes).
Definition gw.h:693
co_unsigned32_t ac
The SDO abort code (0 on success).
Definition gw.h:701
The parameters of a Lely-specific gateway 'Boot slave process completed' indication.
Definition gw.h:947
co_unsigned16_t net
The network-ID.
Definition gw.h:953
char es
The error status (in the range ['A'..'O'], or 0 on success).
Definition gw.h:959
size_t size
The size of this struct (in bytes).
Definition gw.h:949
int srv
The service number (CO_GW_SRV__BOOT).
Definition gw.h:951
co_unsigned8_t st
The the state of the node (including the toggle bit).
Definition gw.h:957
The parameters of a Lely-specific gateway 'Synchronization event received' indication.
Definition gw.h:917
size_t size
The size of this struct (in bytes).
Definition gw.h:919
co_unsigned16_t net
The network-ID.
Definition gw.h:923
co_unsigned8_t cnt
The SYNC counter.
Definition gw.h:925
int srv
The service number (CO_GW_SRV__SYNC).
Definition gw.h:921
The parameters of a Lely-specific gateway 'Time stamp event received' indication.
Definition gw.h:932
size_t size
The size of this struct (in bytes).
Definition gw.h:934
int srv
The service number (CO_GW_SRV__TIME).
Definition gw.h:936
co_unsigned16_t net
The network-ID.
Definition gw.h:938
The parameters of a CANopen gateway 'Error control event received' indication.
Definition gw.h:857
co_unsigned8_t node
The node-ID.
Definition gw.h:865
int iec
The internal error code (0 on success).
Definition gw.h:869
int srv
The service number (CO_GW_SRV_EC).
Definition gw.h:861
co_unsigned16_t net
The network-ID.
Definition gw.h:863
size_t size
The size of this struct (in bytes).
Definition gw.h:859
co_unsigned8_t st
The state of the node, or 0 in case of a boot-up event.
Definition gw.h:867
The parameters of a CANopen gateway 'Emergency event received' indication.
Definition gw.h:873
int srv
The service number (CO_GW_SRV_EMCY).
Definition gw.h:877
co_unsigned16_t net
The network-ID.
Definition gw.h:879
co_unsigned16_t ec
The emergency error code.
Definition gw.h:883
co_unsigned8_t msef[5]
The manufacturer-specific error code.
Definition gw.h:887
co_unsigned8_t er
The error register.
Definition gw.h:885
size_t size
The size of this struct (in bytes).
Definition gw.h:875
The parameters of a CANopen gateway 'RPDO received' indication.
Definition gw.h:835
size_t size
The size of this struct (in bytes).
Definition gw.h:837
co_unsigned16_t net
The network-ID.
Definition gw.h:841
co_unsigned8_t n
Number of mapped objects in PDO.
Definition gw.h:845
co_unsigned64_t val[0x40]
An array of object values.
Definition gw.h:847
The parameters of a CANopen gateway 'CiA 301 progress indication download' indication.
Definition gw.h:894
void * data
A pointer to user-specified data of the SDO upload/download request.
Definition gw.h:908
size_t size
The size of this struct (in bytes).
Definition gw.h:896
co_unsigned32_t nbyte
The transferred bytes.
Definition gw.h:904
co_unsigned16_t net
The network-ID.
Definition gw.h:900
int srv
The service number (CO_GW_SRV_SDO).
Definition gw.h:898
A CANopen gateway network job.
Definition gw.c:241
struct co_gw_job ** pself
The address of the pointer to this job in the network.
Definition gw.c:243
void * data
A pointer to request-specific data.
Definition gw.c:247
struct co_gw_net * net
A pointer to the CANopen network.
Definition gw.c:245
struct co_gw_req req
The service parameters of the request.
Definition gw.c:251
void(* dtor)(void *data)
A pointer to the destructor for data.
Definition gw.c:249
A CANopen network.
Definition gw.c:60
co_nmt_boot_ind_t * boot_ind
A pointer to the original 'boot slave' indication function.
Definition gw.c:112
co_nmt_t * nmt
A pointer to a CANopen NMT master/slave service.
Definition gw.c:66
co_gw_t * gw
A pointer to the CANopen gateway.
Definition gw.c:62
void * cs_data
A pointer to user-specified data for cs_ind.
Definition gw.c:89
void * ng_data
A pointer to user-specified data for ng_ind.
Definition gw.c:95
co_nmt_hb_ind_t * hb_ind
A pointer to the original heartbeat event indication function.
Definition gw.c:103
void * dn_data
A pointer to user-specified data for dn_ind.
Definition gw.c:118
void * st_data
A pointer to user-specified data for st_ind.
Definition gw.c:109
co_nmt_sdo_ind_t * up_ind
A pointer to the original SDO upload progress indication function.
Definition gw.c:120
co_unsigned8_t def
The default node-ID.
Definition gw.c:68
co_unsigned16_t id
The network-ID.
Definition gw.c:64
void * boot_data
A pointer to user-specified data for boot_ind.
Definition gw.c:114
unsigned bootup_ind
A flag indicating whether "boot-up event received" commands should be forwarded (1) or not (0).
Definition gw.c:77
co_nmt_lg_ind_t * lg_ind
A pointer to the original life guarding event indication function.
Definition gw.c:98
co_nmt_ng_ind_t * ng_ind
A pointer to the original node guarding event indication function.
Definition gw.c:93
co_nmt_st_ind_t * st_ind
A pointer to the original state change event indication function.
Definition gw.c:107
struct co_gw_job * lss
A pointer to the LSS job.
Definition gw.c:84
void * hb_data
A pointer to user-specified data for hb_ind.
Definition gw.c:105
int timeout
The SDO timeout (in milliseconds).
Definition gw.c:71
void * lg_data
A pointer to user-specified data for lg_ind.
Definition gw.c:100
void * up_data
A pointer to user-specified data for up_ind.
Definition gw.c:122
struct co_gw_job * sdo[CO_NUM_NODES]
An array of pointers to the SDO upload/download jobs.
Definition gw.c:80
co_nmt_cs_ind_t * cs_ind
A pointer to the original NMT command indication function.
Definition gw.c:87
co_nmt_sdo_ind_t * dn_ind
A pointer to the original SDO download progress indication function.
Definition gw.c:116
The parameters of a Lely-specific gateway 'LSS Slowscan/Fastscan' request.
Definition gw.h:664
struct co_id id_2
In case of an LSS Slowscan request, the upper bound of the LSS address; in case of an LSS Fastscan re...
Definition gw.h:687
struct co_id id_1
In case of an LSS Slowscan request, the lower bound of the LSS address; in case of an LSS Fastscan re...
Definition gw.h:681
The parameters of a CANopen gateway 'Initialize gateway' request.
Definition gw.h:491
co_unsigned16_t net
The network-ID.
Definition gw.h:499
co_unsigned8_t bitidx
The bit timing index (in the range [0..9]).
Definition gw.h:501
The parameters of a CANopen gateway 'Inquire LSS address' request.
Definition gw.h:634
co_unsigned8_t cs
The command specifier (one of 0x5a, 0x5b, 0x5c or 0x5d).
Definition gw.h:644
int srv
The service number (CO_GW_SRV_LSS_GET_LSSID).
Definition gw.h:638
void * data
A pointer to user-specified data.
Definition gw.h:640
The parameters of a CANopen gateway 'LSS identify remote slave' request.
Definition gw.h:648
struct co_id lo
The lower bound of the LSS address.
Definition gw.h:658
struct co_id hi
The upper bound of the LSS address.
Definition gw.h:660
The parameters of a CANopen gateway 'LSS configure bit-rate' request.
Definition gw.h:604
co_unsigned8_t bitsel
The bit timing selector.
Definition gw.h:614
co_unsigned8_t bitidx
The bit timing index.
Definition gw.h:616
The parameters of a CANopen gateway 'LSS activate new bit-rate' request.
Definition gw.h:620
co_unsigned16_t delay
The delay (in milliseconds).
Definition gw.h:630
co_unsigned16_t net
The network-ID.
Definition gw.h:628
The parameters of a CANopen gateway 'LSS switch state selective' request.
Definition gw.h:590
struct co_id id
The LSS address of the slave to be configured.
Definition gw.h:600
The parameters of a CANopen gateway 'LSS switch state global' request.
Definition gw.h:576
co_unsigned8_t mode
0 for waiting state, 1 for configuration state.
Definition gw.h:586
co_unsigned16_t net
The network-ID.
Definition gw.h:584
The common parameters of a CANopen gateway network-level request.
Definition gw.h:281
co_unsigned16_t net
The network-ID.
Definition gw.h:289
The parameters of a CANopen gateway 'Start heartbeat consumer' request.
Definition gw.h:475
co_unsigned16_t net
The network-ID.
Definition gw.h:483
co_unsigned8_t node
The node-ID.
Definition gw.h:485
co_unsigned16_t ms
The heartbeat time (in milliseconds).
Definition gw.h:487
The parameters of a CANopen gateway 'Enable node guarding' request.
Definition gw.h:457
co_unsigned8_t node
The node-ID.
Definition gw.h:467
co_unsigned16_t net
The network-ID.
Definition gw.h:465
co_unsigned8_t ltf
The lifetime factor.
Definition gw.h:471
co_unsigned16_t gt
The guard time (in milliseconds).
Definition gw.h:469
The common parameters of a CANopen gateway node-level request.
Definition gw.h:293
void * data
A pointer to user-specified data.
Definition gw.h:299
co_unsigned16_t net
The network-ID.
Definition gw.h:301
co_unsigned8_t node
The node-ID.
Definition gw.h:303
The parameters of a CANopen gateway 'Read PDO' request.
Definition gw.h:422
co_unsigned16_t num
The PDO number.
Definition gw.h:432
The parameters of a CANopen gateway 'Write PDO' request.
Definition gw.h:436
co_unsigned8_t n
Number of mapped objects in PDO.
Definition gw.h:448
co_unsigned16_t num
The PDO number.
Definition gw.h:446
size_t size
The size of this struct (in bytes).
Definition gw.h:438
co_unsigned64_t val[0x40]
An array of object values.
Definition gw.h:450
The parameters of a CANopen gateway 'SDO download' request.
Definition gw.h:327
co_unsigned16_t net
The network-ID.
Definition gw.h:335
co_unsigned16_t idx
The object index.
Definition gw.h:339
size_t size
The size of this struct (in bytes).
Definition gw.h:329
co_unsigned32_t len
The length of the value (in bytes).
Definition gw.h:343
co_unsigned8_t subidx
The object sub-index.
Definition gw.h:341
co_unsigned8_t node
The node-ID.
Definition gw.h:337
uint_least8_t val[1]
The (first byte in the) value.
Definition gw.h:345
The parameters of a CANopen gateway 'SDO upload' request.
Definition gw.h:307
size_t size
The size of this struct (in bytes).
Definition gw.h:309
co_unsigned8_t node
The node-ID.
Definition gw.h:317
void * data
A pointer to user-specified data.
Definition gw.h:313
co_unsigned8_t subidx
The object sub-index.
Definition gw.h:321
co_unsigned16_t idx
The object index.
Definition gw.h:319
int srv
The service number (CO_GW_SRV_SDO_UP).
Definition gw.h:311
co_unsigned16_t type
The data type.
Definition gw.h:323
co_unsigned16_t net
The network-ID.
Definition gw.h:315
The parameters of a CANopen gateway 'Boot-up forwarding' request.
Definition gw.h:547
co_unsigned16_t net
The network-ID.
Definition gw.h:555
unsigned cs
A flag indicating whether "boot-up event received" commands should be forwarded (1) or not (0).
Definition gw.h:560
The parameters of a CANopen gateway 'Set command time-out' request.
Definition gw.h:535
int timeout
The command timeout (in milliseconds).
Definition gw.h:543
The parameters of a CANopen gateway 'Start/Stop emergency consumer' request.
Definition gw.h:519
int srv
The service number (CO_GW_SRV_EMCY_START or CO_GW_SRV_EMCY_STOP).
Definition gw.h:523
co_unsigned8_t node
The node-ID.
Definition gw.h:529
co_unsigned32_t cobid
The COB-ID.
Definition gw.h:531
The parameters of a CANopen gateway 'Set heartbeat producer' request.
Definition gw.h:505
co_unsigned16_t ms
The heartbeat time (in milliseconds).
Definition gw.h:515
co_unsigned16_t net
The network-ID.
Definition gw.h:513
The parameters of a CANopen gateway 'Configure RPDO' request.
Definition gw.h:366
size_t size
The size of this struct (in bytes).
Definition gw.h:368
co_unsigned8_t n
Number of mapped objects in PDO.
Definition gw.h:382
co_unsigned32_t cobid
The COB-ID.
Definition gw.h:378
co_unsigned32_t map[0x40]
An array of objects to be mapped.
Definition gw.h:384
co_unsigned16_t num
The PDO number.
Definition gw.h:376
co_unsigned8_t trans
The transmission type.
Definition gw.h:380
The parameters of a CANopen gateway 'Configure SDO time-out' request.
Definition gw.h:352
int timeout
The SDO timeout (in milliseconds).
Definition gw.h:362
co_unsigned16_t net
The network-ID.
Definition gw.h:360
The parameters of a CANopen gateway 'Configure TPDO' request.
Definition gw.h:391
co_unsigned8_t n
Number of mapped objects in PDO.
Definition gw.h:413
co_unsigned8_t sync
The SYNC start value.
Definition gw.h:411
co_unsigned32_t map[0x40]
An array of objects to be mapped.
Definition gw.h:415
co_unsigned8_t trans
The transmission type.
Definition gw.h:405
co_unsigned16_t inhibit
The inhibit time.
Definition gw.h:407
co_unsigned32_t cobid
The COB-ID.
Definition gw.h:403
co_unsigned16_t event
The event timer.
Definition gw.h:409
co_unsigned16_t num
The PDO number.
Definition gw.h:401
size_t size
The size of this struct (in bytes).
Definition gw.h:393
The common parameters of a CANopen gateway request.
Definition gw.h:271
void * data
A pointer to user-specified data.
Definition gw.h:277
size_t size
The size of this struct (in bytes).
Definition gw.h:273
int srv
The service number.
Definition gw.h:275
The common parameters of a CANopen gateway service.
Definition gw.h:263
An identity record.
Definition dev.h:33
A PDO communication parameter record.
Definition pdo.h:64
co_unsigned8_t trans
Transmission type.
Definition pdo.h:70
co_unsigned8_t n
Highest sub-index supported.
Definition pdo.h:66
A PDO mapping parameter record.
Definition pdo.h:90
co_unsigned8_t n
Number of mapped objects in PDO.
Definition pdo.h:92
co_unsigned32_t map[CO_PDO_NUM_MAPS]
An array of objects to be mapped.
Definition pdo.h:94
A CANopen SDO upload/download request.
Definition sdo.h:181
const void * buf
A pointer to the next bytes to be uploaded/downloaded.
Definition sdo.h:189
A time type with nanosecond resolution.
Definition time.h:88
This header file is part of the CANopen library; it contains the synchronization (SYNC) object declar...
void co_sync_set_ind(co_sync_t *sync, co_sync_ind_t *ind, void *data)
Sets the indication function invoked after a CANopen SYNC message is received or transmitted.
Definition sync.c:351
This header file is part of the CANopen library; it contains the Transmit-PDO declarations.
int co_tpdo_event(co_tpdo_t *pdo)
Triggers the transmission of an acyclic or event-driven PDO.
Definition tpdo.c:509
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:460
#define CO_DEFTYPE_UNSIGNED16
The data type (and object index) of a 16-bit unsigned integer.
Definition type.h:47
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition type.h:50