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
38
50 co_unsigned8_t id;
52 co_unsigned32_t assignment;
56 co_unsigned32_t ac;
57};
58
65static 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
72static void co_nmt_cfg_enter(co_nmt_cfg_t *cfg, co_nmt_cfg_state_t *next);
73
83static 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
93static 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
138LELY_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
144
146
147// clang-format off
148LELY_CO_DEFINE_STATE(co_nmt_cfg_abort_state,
149 .on_enter = &co_nmt_cfg_abort_on_enter
150)
151// clang-format on
152
153
155
161 co_unsigned16_t idx, co_unsigned8_t subidx, co_unsigned32_t ac);
162
163// clang-format off
164LELY_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
172void *
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
181void
182__co_nmt_cfg_free(void *ptr)
183{
184 free(ptr);
185}
186
187struct __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
212void
213__co_nmt_cfg_fini(struct __co_nmt_cfg *cfg)
214{
215 assert(cfg);
216
217 co_csdo_destroy(cfg->sdo);
218}
219
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
238error_init_cfg:
239 __co_nmt_cfg_free(cfg);
240error_alloc_cfg:
241 set_errc(errc);
242 return NULL;
243}
244
245void
247{
248 if (cfg) {
249 __co_nmt_cfg_fini(cfg);
250 __co_nmt_cfg_free(cfg);
251 }
252}
253
254int
255co_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
285int
286co_nmt_cfg_cfg_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
287{
288 assert(cfg);
289
291
292 return 0;
293}
294
295static void
296co_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
306static 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
322static inline void
323co_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
333static inline void
334co_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
343static 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
363static co_nmt_cfg_state_t *
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
380static 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
390static 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
417static co_nmt_cfg_state_t *
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
void co_csdo_set_timeout(co_csdo_t *sdo, int timeout)
Sets the timeout of a Client-SDO.
Definition: csdo.c:944
void co_csdo_set_up_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO upload reques...
Definition: csdo.c:986
void co_csdo_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
void co_csdo_set_dn_ind(co_csdo_t *sdo, co_csdo_ind_t *ind, void *data)
Sets the indication function used to notify the user of the progress of the current SDO download requ...
Definition: csdo.c:966
co_csdo_t * co_csdo_create(can_net_t *net, co_dev_t *dev, co_unsigned8_t num)
Creates a new CANopen Client-SDO service.
Definition: csdo.c:867
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 co_csdo_destroy(co_csdo_t *sdo)
Destroys a CANopen Client-SDO service.
Definition: csdo.c:894
This header file is part of the CANopen library; it contains the device description declarations.
#define CO_NUM_NODES
The maximum number of nodes in a CANopen network.
Definition: dev.h:56
This header file is part of the utilities library; it contains the native and platform-independent er...
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:129
@ ERRNUM_INPROGRESS
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
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
Definition: errnum.c:43
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
#define CO_SDO_AC_ERROR
SDO abort code: General error.
Definition: sdo.h:150
void co_nmt_cfg_ind(co_nmt_t *nmt, co_unsigned8_t id, co_csdo_t *sdo)
The CANopen NMT 'update configuration' indication function, invoked when a configuration request is r...
Definition: nmt.c:1934
void co_nmt_cfg_con(co_nmt_t *nmt, co_unsigned8_t id, co_unsigned32_t ac)
The CANopen NMT 'configuration request' confirmation function, invoked when a configuration request c...
Definition: nmt.c:1950
#define CO_NMT_CS_RESET_NODE
The NMT command specifier 'reset node'.
Definition: nmt.h:49
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
#define CO_NMT_CS_RESET_COMM
The NMT command specifier 'reset communication'.
Definition: nmt.h:52
static void co_nmt_cfg_enter(co_nmt_cfg_t *cfg, co_nmt_cfg_state_t *next)
Enters the specified state of a 'configuration request; and invokes the exit and entry functions.
Definition: nmt_cfg.c:307
static co_nmt_cfg_state_t * co_nmt_cfg_abort_on_enter(co_nmt_cfg_t *cfg)
The entry function of the 'abort' state.
Definition: nmt_cfg.c:381
void co_nmt_cfg_destroy(co_nmt_cfg_t *cfg)
Destroys a CANopen NMT 'configuration request'.
Definition: nmt_cfg.c:246
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 'configuration request'.
Definition: nmt_cfg.c:255
static co_nmt_cfg_state_t * co_nmt_cfg_init_on_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
The 'result received' function of the 'initialization' state.
Definition: nmt_cfg.c:364
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 'SDO download confirmation' transition function of the 'restore configuration' state.
Definition: nmt_cfg.c:418
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 'configuration request'.
Definition: nmt_cfg.c:221
int co_nmt_cfg_cfg_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
Indicates the result of the 'update configuration' step of an NMT 'configuration request'.
Definition: nmt_cfg.c:286
static co_nmt_cfg_state_t * co_nmt_cfg_restore_on_enter(co_nmt_cfg_t *cfg)
The entry function of the 'restore configuration' state.
Definition: nmt_cfg.c:391
static co_nmt_cfg_state_t * co_nmt_cfg_init_on_enter(co_nmt_cfg_t *cfg)
The entry function of the 'initialization' state.
Definition: nmt_cfg.c:344
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 'configuration request'.
Definition: nmt_cfg.c:296
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 'SDO download confirmation' transition function of the current state of a 'boot slave' se...
Definition: nmt_cfg.c:323
static void co_nmt_cfg_emit_res(co_nmt_cfg_t *cfg, co_unsigned32_t ac)
Invokes the 'result received' transition function of the current state of a 'configuration request'.
Definition: nmt_cfg.c:334
This is the internal header file of the NMT 'configuration request' declarations.
This is the internal header file of the CANopen library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
A CAN network interface.
Definition: net.c:37
A CANopen Client-SDO.
Definition: csdo.c:45
A CANopen device.
Definition: dev.c:38
A CANopen NMT 'configuration request' state.
Definition: nmt_cfg.c:96
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
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
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
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'update configuration' step completes.
Definition: nmt_cfg.c:108
A CANopen NMT 'configuration request' service.
Definition: nmt_cfg.c:40
co_nmt_t * nmt
A pointer to an NMT master service.
Definition: nmt_cfg.c:46
co_nmt_cfg_state_t * state
A pointer to the current state.
Definition: nmt_cfg.c:48
co_unsigned32_t ac
The SDO abort code.
Definition: nmt_cfg.c:56
co_dev_t * dev
A pointer to a CANopen device.
Definition: nmt_cfg.c:44
co_unsigned32_t assignment
The NMT slave assignment (object 1F81).
Definition: nmt_cfg.c:52
can_net_t * net
A pointer to a CAN network interface.
Definition: nmt_cfg.c:42
co_unsigned8_t id
The node-ID.
Definition: nmt_cfg.c:50
co_csdo_t * sdo
A pointer to the Client-SDO used to access slave objects.
Definition: nmt_cfg.c:54
A CANopen NMT master/slave service.
Definition: nmt.c:104
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition: type.h:50