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