Lely core libraries  1.9.2
nmt_cfg.c
Go to the documentation of this file.
1 
24 #include "co.h"
25 
26 #ifndef LELY_NO_CO_MASTER
27 
28 #include "nmt_cfg.h"
29 #include <lely/co/dev.h>
30 #include <lely/util/errnum.h>
31 
32 #include <assert.h>
33 #include <stdlib.h>
34 
35 struct __co_nmt_cfg_state;
38 
40 struct __co_nmt_cfg {
50  co_unsigned8_t id;
52  co_unsigned32_t assignment;
56  co_unsigned32_t ac;
57 };
58 
65 static void co_nmt_cfg_dn_con(co_csdo_t *sdo, co_unsigned16_t idx,
66  co_unsigned8_t subidx, co_unsigned32_t ac, void *data);
67 
72 static void co_nmt_cfg_enter(co_nmt_cfg_t *cfg, co_nmt_cfg_state_t *next);
73 
83 static inline void co_nmt_cfg_emit_dn_con(co_nmt_cfg_t *cfg,
84  co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac);
85 
93 static inline void co_nmt_cfg_emit_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac);
94 
98  co_nmt_cfg_state_t *(*on_enter)(co_nmt_cfg_t *cfg);
108  co_nmt_cfg_state_t *(*on_res)(co_nmt_cfg_t *cfg, co_unsigned32_t ac);
120  co_nmt_cfg_state_t *(*on_dn_con)(co_nmt_cfg_t *cfg, co_unsigned16_t idx,
121  co_unsigned8_t subidx, co_unsigned32_t ac);
123  void (*on_leave)(co_nmt_cfg_t *cfg);
124 };
125 
126 #define LELY_CO_DEFINE_STATE(name, ...) \
127  static co_nmt_cfg_state_t *const name = \
128  &(co_nmt_cfg_state_t){ __VA_ARGS__ };
129 
132 
135  co_nmt_cfg_t *cfg, co_unsigned32_t ac);
136 
137 // clang-format off
138 LELY_CO_DEFINE_STATE(co_nmt_cfg_init_state,
139  .on_enter = &co_nmt_cfg_init_on_enter,
140  .on_res = &co_nmt_cfg_init_on_res
141 )
142 // clang-format on
143 
146 
147 // clang-format off
148 LELY_CO_DEFINE_STATE(co_nmt_cfg_abort_state,
149  .on_enter = &co_nmt_cfg_abort_on_enter
150 )
151 // clang-format on
152 
155 
161  co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac);
162 
163 // clang-format off
164 LELY_CO_DEFINE_STATE(co_nmt_cfg_restore_state,
165  .on_enter = &co_nmt_cfg_restore_on_enter,
166  .on_dn_con = &co_nmt_cfg_restore_on_dn_con
167 )
168 // clang-format on
169 
170 #undef LELY_CO_DEFINE_STATE
171 
172 void *
173 __co_nmt_cfg_alloc(void)
174 {
175  void *ptr = malloc(sizeof(struct __co_nmt_cfg));
176  if (__unlikely(!ptr))
177  set_errc(errno2c(errno));
178  return ptr;
179 }
180 
181 void
182 __co_nmt_cfg_free(void *ptr)
183 {
184  free(ptr);
185 }
186 
187 struct __co_nmt_cfg *
188 __co_nmt_cfg_init(struct __co_nmt_cfg *cfg, can_net_t *net, co_dev_t *dev,
189  co_nmt_t *nmt)
190 {
191  assert(cfg);
192  assert(net);
193  assert(dev);
194  assert(nmt);
195 
196  cfg->net = net;
197  cfg->dev = dev;
198  cfg->nmt = nmt;
199 
200  cfg->state = NULL;
201 
202  cfg->id = 0;
203  cfg->assignment = 0;
204 
205  cfg->sdo = NULL;
206 
207  cfg->ac = 0;
208 
209  return cfg;
210 }
211 
212 void
213 __co_nmt_cfg_fini(struct __co_nmt_cfg *cfg)
214 {
215  assert(cfg);
216 
217  co_csdo_destroy(cfg->sdo);
218 }
219 
220 co_nmt_cfg_t *
222 {
223  int errc = 0;
224 
225  co_nmt_cfg_t *cfg = __co_nmt_cfg_alloc();
226  if (__unlikely(!cfg)) {
227  errc = get_errc();
228  goto error_alloc_cfg;
229  }
230 
231  if (__unlikely(!__co_nmt_cfg_init(cfg, net, dev, nmt))) {
232  errc = get_errc();
233  goto error_init_cfg;
234  }
235 
236  return cfg;
237 
238 error_init_cfg:
239  __co_nmt_cfg_free(cfg);
240 error_alloc_cfg:
241  set_errc(errc);
242  return NULL;
243 }
244 
245 void
247 {
248  if (cfg) {
249  __co_nmt_cfg_fini(cfg);
250  __co_nmt_cfg_free(cfg);
251  }
252 }
253 
254 int
255 co_nmt_cfg_cfg_req(co_nmt_cfg_t *cfg, co_unsigned8_t id, int timeout,
256  co_csdo_ind_t *dn_ind, co_csdo_ind_t *up_ind, void *data)
257 {
258  assert(cfg);
259 
260  if (__unlikely(!id || id > CO_NUM_NODES)) {
262  return -1;
263  }
264 
265  if (__unlikely(cfg->state)) {
267  return -1;
268  }
269 
270  cfg->id = id;
271 
272  co_csdo_destroy(cfg->sdo);
273  cfg->sdo = co_csdo_create(cfg->net, NULL, cfg->id);
274  if (__unlikely(!cfg->sdo))
275  return -1;
276  co_csdo_set_timeout(cfg->sdo, timeout);
277  co_csdo_set_dn_ind(cfg->sdo, dn_ind, data);
278  co_csdo_set_up_ind(cfg->sdo, up_ind, data);
279 
280  co_nmt_cfg_enter(cfg, co_nmt_cfg_init_state);
281 
282  return 0;
283 }
284 
285 int
286 co_nmt_cfg_cfg_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
287 {
288  assert(cfg);
289 
290  co_nmt_cfg_emit_res(cfg, ac);
291 
292  return 0;
293 }
294 
295 static void
296 co_nmt_cfg_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx,
297  co_unsigned32_t ac, void *data)
298 {
299  (void)sdo;
300  co_nmt_cfg_t *cfg = data;
301  assert(cfg);
302 
303  co_nmt_cfg_emit_dn_con(cfg, idx, subidx, ac);
304 }
305 
306 static void
308 {
309  assert(cfg);
310 
311  while (next) {
312  co_nmt_cfg_state_t *prev = cfg->state;
313  cfg->state = next;
314 
315  if (prev && prev->on_leave)
316  prev->on_leave(cfg);
317 
318  next = next->on_enter ? next->on_enter(cfg) : NULL;
319  }
320 }
321 
322 static inline void
323 co_nmt_cfg_emit_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx,
324  co_unsigned8_t subidx, co_unsigned32_t ac)
325 {
326  assert(cfg);
327  assert(cfg->state);
328  assert(cfg->state->on_dn_con);
329 
330  co_nmt_cfg_enter(cfg, cfg->state->on_dn_con(cfg, idx, subidx, ac));
331 }
332 
333 static inline void
334 co_nmt_cfg_emit_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
335 {
336  assert(cfg);
337  assert(cfg->state);
338  assert(cfg->state->on_res);
339 
340  co_nmt_cfg_enter(cfg, cfg->state->on_res(cfg, ac));
341 }
342 
343 static co_nmt_cfg_state_t *
345 {
346  assert(cfg);
347 
348  cfg->ac = 0;
349 
350  // Retrieve the slave assignment for the node.
351  cfg->assignment = co_dev_get_val_u32(cfg->dev, 0x1f81, cfg->id);
352 
353  // Abort the configuration request if the slave is not in the network
354  // list.
355  if (!(cfg->assignment & 0x01))
356  return co_nmt_cfg_abort_state;
357 
358  co_nmt_cfg_ind(cfg->nmt, cfg->id, cfg->sdo);
359 
360  return NULL;
361 }
362 
363 static co_nmt_cfg_state_t *
364 co_nmt_cfg_init_on_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
365 {
366  assert(cfg);
367 
368  if (__unlikely(ac)) {
369  cfg->ac = ac;
370  return co_nmt_cfg_abort_state;
371  }
372 
373  // We are done if the slave can be used without prior resetting (bit 7).
374  if (!(cfg->assignment & 0x80))
375  return co_nmt_cfg_abort_state;
376 
377  return co_nmt_cfg_restore_state;
378 }
379 
380 static co_nmt_cfg_state_t *
382 {
383  assert(cfg);
384 
385  co_nmt_cfg_con(cfg->nmt, cfg->id, cfg->ac);
386 
387  return NULL;
388 }
389 
390 static co_nmt_cfg_state_t *
392 {
393  assert(cfg);
394 
395  // Retrieve the sub-index of object 1011 of the slave that is used to
396  // initiate the restore operation.
397  co_unsigned8_t subidx = co_dev_get_val_u8(cfg->dev, 0x1f8a, cfg->id);
398 
399  // If the sub-index is 0, no restore is sent to the slave.
400  if (!subidx)
401  return co_nmt_cfg_abort_state;
402 
403  // Write the value 'load' to sub-index of object 1011 on the slave.
404  // clang-format off
405  if (__unlikely(co_csdo_dn_val_req(cfg->sdo, 0x1011, subidx,
407  &(co_unsigned32_t){ UINT32_C(0x64616f6c) },
408  &co_nmt_cfg_dn_con, cfg) == -1)) {
409  // clang-format on
410  cfg->ac = CO_SDO_AC_ERROR;
411  return co_nmt_cfg_abort_state;
412  }
413 
414  return NULL;
415 }
416 
417 static co_nmt_cfg_state_t *
418 co_nmt_cfg_restore_on_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx,
419  co_unsigned8_t subidx, co_unsigned32_t ac)
420 {
421  assert(cfg);
422  (void)idx;
423 
424  if (__unlikely(ac)) {
425  cfg->ac = ac;
426  return co_nmt_cfg_abort_state;
427  }
428 
429  switch (subidx) {
430  case 0x02:
431  // Issue the NMT reset communication command after restoring
432  // communication related parameters.
434  break;
435  default:
436  // Issue the NMT reset node command after restoring application
437  // or manufacturer-specific parameters.
439  break;
440  }
441 
442  return co_nmt_cfg_abort_state;
443 }
444 
445 #endif // !LELY_NO_CO_MASTER
int co_nmt_cs_req(co_nmt_t *nmt, co_unsigned8_t cs, co_unsigned8_t id)
Submits an NMT request to a slave.
Definition: nmt.c:1455
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition: csdo.c:944
static void co_nmt_cfg_emit_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
Invokes the &#39;result received&#39; transition function of the current state of a &#39;configuration request&#39;...
Definition: nmt_cfg.c:334
A CAN network interface.
Definition: net.c:37
void co_nmt_cfg_destroy(co_nmt_cfg_t *cfg)
Destroys a CANopen NMT &#39;configuration request&#39;.
Definition: nmt_cfg.c:246
static void co_nmt_cfg_dn_con(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac, void *data)
The CANopen SDO download confirmation callback function for a &#39;configuration request&#39;.
Definition: nmt_cfg.c:296
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
void(* on_leave)(co_nmt_cfg_t *cfg)
A pointer to the function invoked when the current state is left.
Definition: nmt_cfg.c:123
void co_nmt_cfg_ind(co_nmt_t *nmt, co_unsigned8_t id, co_csdo_t *sdo)
The CANopen NMT &#39;update configuration&#39; indication function, invoked when a configuration request is r...
Definition: nmt.c:1934
static co_nmt_cfg_state_t * co_nmt_cfg_restore_on_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac)
The &#39;SDO download confirmation&#39; transition function of the &#39;restore configuration&#39; state...
Definition: nmt_cfg.c:418
#define CO_SDO_AC_ERROR
SDO abort code: General error.
Definition: sdo.h:150
int co_csdo_dn_val_req(co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned16_t type, const void *val, co_csdo_dn_con_t *con, void *data)
Submits a download request to a remote Server-SDO.
Definition: csdo.c:1036
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
co_unsigned32_t ac
The SDO abort code.
Definition: nmt_cfg.c:56
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50
This header file is part of the utilities library; it contains the native and platform-independent er...
static co_nmt_cfg_state_t * co_nmt_cfg_init_on_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
The &#39;result received&#39; function of the &#39;initialization&#39; state.
Definition: nmt_cfg.c:364
co_nmt_cfg_state_t *(* on_enter)(co_nmt_cfg_t *cfg)
A pointer to the function invoked when a new state is entered.
Definition: nmt_cfg.c:98
This is the internal header file of the CANopen library.
#define CO_NMT_CS_RESET_NODE
The NMT command specifier &#39;reset node&#39;.
Definition: nmt.h:49
Operation in progress.
Definition: errnum.h:125
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function...
Definition: errnum.c:947
static void co_nmt_cfg_emit_dn_con(co_nmt_cfg_t *cfg, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac)
Invokes the &#39;SDO download confirmation&#39; transition function of the current state of a &#39;boot slave&#39; se...
Definition: nmt_cfg.c:323
A CANopen Client-SDO.
Definition: csdo.c:45
void co_csdo_set_dn_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO download requ...
Definition: csdo.c:966
A CANopen NMT master/slave service.
Definition: nmt.c:104
co_nmt_cfg_t * co_nmt_cfg_create(can_net_t *net, co_dev_t *dev, co_nmt_t *nmt)
Creates a new CANopen NMT &#39;configuration request&#39;.
Definition: nmt_cfg.c:221
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition: dev.h:56
Invalid argument.
Definition: errnum.h:129
co_dev_t * dev
A pointer to a CANopen device.
Definition: nmt_cfg.c:44
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
A CANopen NMT &#39;configuration request&#39; service.
Definition: nmt_cfg.c:40
void co_csdo_ind_t(const co_csdo_t *sdo, co_unsigned16_t idx, co_unsigned8_t subidx, size_t size, size_t nbyte, void *data)
The type of a CANopen Client-SDO request progress indication function, used to notify the user of the...
Definition: csdo.h:79
co_unsigned32_t assignment
The NMT slave assignment (object 1F81).
Definition: nmt_cfg.c:52
A CANopen device.
Definition: dev.c:38
co_csdo_t * co_csdo_create(can_net_t *net, co_dev_t *dev, co_unsigned8_t num)
Creates a new CANopen Client-SDO service.
Definition: csdo.c:867
This is the internal header file of the NMT &#39;configuration request&#39; declarations. ...
void co_csdo_destroy(co_csdo_t *sdo)
Destroys a CANopen Client-SDO service.
Definition: csdo.c:894
co_nmt_cfg_state_t * state
A pointer to the current state.
Definition: nmt_cfg.c:48
This header file is part of the CANopen library; it contains the device description declarations...
A CANopen NMT &#39;configuration request&#39; state.
Definition: nmt_cfg.c:96
co_nmt_t * nmt
A pointer to an NMT master service.
Definition: nmt_cfg.c:46
can_net_t * net
A pointer to a CAN network interface.
Definition: nmt_cfg.c:42
co_nmt_cfg_state_t *(* on_res)(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
A pointer to the transition function invoked when an NMT&#39;update configuration&#39; step completes...
Definition: nmt_cfg.c:108
co_csdo_t * sdo
A pointer to the Client-SDO used to access slave objects.
Definition: nmt_cfg.c:54
static co_nmt_cfg_state_t * co_nmt_cfg_restore_on_enter(co_nmt_cfg_t *cfg)
The entry function of the &#39;restore configuration&#39; state.
Definition: nmt_cfg.c:391
void co_nmt_cfg_con(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned32_t ac)
The CANopen NMT &#39;configuration request&#39; confirmation function, invoked when a configuration request c...
Definition: nmt.c:1950
co_nmt_cfg_state_t *(* on_dn_con)(co_nmt_cfg_t *cfg, co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac)
A pointer to the transition function invoked when an SDO download request completes.
Definition: nmt_cfg.c:120
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
static void co_nmt_cfg_enter(co_nmt_cfg_t *cfg, co_nmt_cfg_state_t *next)
Enters the specified state of a &#39;configuration request; and invokes the exit and entry functions...
Definition: nmt_cfg.c:307
int co_nmt_cfg_cfg_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
Indicates the result of the &#39;update configuration&#39; step of an NMT &#39;configuration request&#39;.
Definition: nmt_cfg.c:286
static co_nmt_cfg_state_t * co_nmt_cfg_init_on_enter(co_nmt_cfg_t *cfg)
The entry function of the &#39;initialization&#39; state.
Definition: nmt_cfg.c:344
co_unsigned8_t id
The node-ID.
Definition: nmt_cfg.c:50
#define CO_NMT_CS_RESET_COMM
The NMT command specifier &#39;reset communication&#39;.
Definition: nmt.h:52
static co_nmt_cfg_state_t * co_nmt_cfg_abort_on_enter(co_nmt_cfg_t *cfg)
The entry function of the &#39;abort&#39; state.
Definition: nmt_cfg.c:381
void co_csdo_set_up_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO upload reques...
Definition: csdo.c:986
int co_nmt_cfg_cfg_req(co_nmt_cfg_t *cfg, co_unsigned8_t id, int timeout, co_csdo_ind_t *dn_ind, co_csdo_ind_t *up_ind, void *data)
Starts a CANopen NMT &#39;configuration request&#39;.
Definition: nmt_cfg.c:255