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