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