Lely core libraries 1.9.2
nmt_cfg.c
Go to the documentation of this file.
1
23
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
struct __co_csdo co_csdo_t
An opaque CANopen Client-SDO service type.
Definition co.h:79
struct __co_nmt co_nmt_t
An opaque CANopen NMT master/slave service type.
Definition co.h:145
struct __co_dev co_dev_t
An opaque CANopen device type.
Definition co.h:35
#define CO_SDO_AC_ERROR
SDO abort code: General error.
Definition sdo.h:150
struct __can_net can_net_t
An opaque CAN network interface type.
Definition net.h:31
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
const struct __co_nmt_cfg_state co_nmt_cfg_state_t
An opaque CANopen NMT 'configuration request' state type.
Definition nmt_cfg.c:37
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.
struct __co_nmt_cfg co_nmt_cfg_t
An opaque CANopen NMT 'configuration request' type.
Definition nmt_cfg.h:34
This is the internal header file of the CANopen library.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
A CANopen 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
#define CO_DEFTYPE_UNSIGNED32
The data type (and object index) of a 32-bit unsigned integer.
Definition type.h:50