1 /*
2 * CANopen LSS Master protocol.
3 *
4 * @file CO_LSSmaster.c
5 * @ingroup CO_LSS
6 * @author Martin Wagner
7 * @copyright 2017 - 2020 Neuberger Gebaeudeautomation GmbH
8 *
9 *
10 * This file is part of CANopenNode, an opensource CANopen Stack.
11 * Project home page is <https://github.com/CANopenNode/CANopenNode>.
12 * For more information on CANopen see <http://www.can-cia.org/>.
13 *
14 * Licensed under the Apache License, Version 2.0 (the "License");
15 * you may not use this file except in compliance with the License.
16 * You may obtain a copy of the License at
17 *
18 * http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing, software
21 * distributed under the License is distributed on an "AS IS" BASIS,
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 * See the License for the specific language governing permissions and
24 * limitations under the License.
25 */
26
27 #include "CANopen.h"
28 #include "CO_LSSmaster.h"
29
30 #if CO_NO_LSS_CLIENT == 1
31
32 /*
33 * LSS master slave select state machine. Compared to #CO_LSS_state_t this
34 * has information if we currently have selected one or all slaves. This
35 * allows for some basic error checking.
36 */
37 typedef enum {
38 CO_LSSmaster_STATE_WAITING = 0,
39 CO_LSSmaster_STATE_CFG_SLECTIVE,
40 CO_LSSmaster_STATE_CFG_GLOBAL,
41 } CO_LSSmaster_state_t;
42
43 /*
44 * LSS master slave command state machine
45 */
46 typedef enum {
47 CO_LSSmaster_COMMAND_WAITING = 0,
48 CO_LSSmaster_COMMAND_SWITCH_STATE,
49 CO_LSSmaster_COMMAND_CFG_BIT_TIMING,
50 CO_LSSmaster_COMMAND_CFG_NODE_ID,
51 CO_LSSmaster_COMMAND_CFG_STORE,
52 CO_LSSmaster_COMMAND_INQUIRE_VENDOR,
53 CO_LSSmaster_COMMAND_INQUIRE_PRODUCT,
54 CO_LSSmaster_COMMAND_INQUIRE_REV,
55 CO_LSSmaster_COMMAND_INQUIRE_SERIAL,
56 CO_LSSmaster_COMMAND_INQUIRE_NODE_ID,
57 CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN,
58 } CO_LSSmaster_command_t;
59
60 /*
61 * LSS master fastscan state machine
62 */
63 typedef enum {
64 CO_LSSmaster_FS_STATE_CHECK,
65 CO_LSSmaster_FS_STATE_SCAN,
66 CO_LSSmaster_FS_STATE_VERIFY
67 } CO_LSSmaster_fs_t;
68
69 /*
70 * Read received message from CAN module.
71 *
72 * Function will be called (by CAN receive interrupt) every time, when CAN
73 * message with correct identifier will be received. For more information and
74 * description of parameters see file CO_driver.h.
75 */
CO_LSSmaster_receive(void * object,const CO_CANrxMsg_t * msg)76 static void CO_LSSmaster_receive(void *object, const CO_CANrxMsg_t *msg)
77 {
78 CO_LSSmaster_t *LSSmaster;
79
80 LSSmaster = (CO_LSSmaster_t*)object; /* this is the correct pointer type of the first argument */
81
82 /* verify message length and message overflow (previous message was not processed yet) */
83 if(msg->DLC==8 && !IS_CANrxNew(LSSmaster->CANrxNew) &&
84 LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING){
85
86 /* copy data and set 'new message' flag */
87 LSSmaster->CANrxData[0] = msg->data[0];
88 LSSmaster->CANrxData[1] = msg->data[1];
89 LSSmaster->CANrxData[2] = msg->data[2];
90 LSSmaster->CANrxData[3] = msg->data[3];
91 LSSmaster->CANrxData[4] = msg->data[4];
92 LSSmaster->CANrxData[5] = msg->data[5];
93 LSSmaster->CANrxData[6] = msg->data[6];
94 LSSmaster->CANrxData[7] = msg->data[7];
95
96 SET_CANrxNew(LSSmaster->CANrxNew);
97
98 /* Optional signal to RTOS, which can resume task, which handles SDO client. */
99 if(LSSmaster->pFunctSignal != NULL) {
100 LSSmaster->pFunctSignal(LSSmaster->functSignalObject);
101 }
102 }
103 }
104
105 /*
106 * Check LSS timeout.
107 *
108 * Generally, we do not really care if the message has been received before
109 * or after the timeout expired. Only if no message has been received we have
110 * to check for timeouts
111 */
CO_LSSmaster_check_timeout(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms)112 static CO_LSSmaster_return_t CO_LSSmaster_check_timeout(
113 CO_LSSmaster_t *LSSmaster,
114 uint16_t timeDifference_ms)
115 {
116 CO_LSSmaster_return_t ret = CO_LSSmaster_WAIT_SLAVE;
117
118 LSSmaster->timeoutTimer += timeDifference_ms;
119 if (LSSmaster->timeoutTimer >= LSSmaster->timeout) {
120 LSSmaster->timeoutTimer = 0;
121 ret = CO_LSSmaster_TIMEOUT;
122 }
123
124 return ret;
125 }
126
127
128 /******************************************************************************/
CO_LSSmaster_init(CO_LSSmaster_t * LSSmaster,uint16_t timeout_ms,CO_CANmodule_t * CANdevRx,uint16_t CANdevRxIdx,uint32_t CANidLssSlave,CO_CANmodule_t * CANdevTx,uint16_t CANdevTxIdx,uint32_t CANidLssMaster)129 CO_ReturnError_t CO_LSSmaster_init(
130 CO_LSSmaster_t *LSSmaster,
131 uint16_t timeout_ms,
132 CO_CANmodule_t *CANdevRx,
133 uint16_t CANdevRxIdx,
134 uint32_t CANidLssSlave,
135 CO_CANmodule_t *CANdevTx,
136 uint16_t CANdevTxIdx,
137 uint32_t CANidLssMaster)
138 {
139 /* verify arguments */
140 if (LSSmaster==NULL || CANdevRx==NULL || CANdevTx==NULL){
141 return CO_ERROR_ILLEGAL_ARGUMENT;
142 }
143
144 LSSmaster->timeout = timeout_ms;
145 LSSmaster->state = CO_LSSmaster_STATE_WAITING;
146 LSSmaster->command = CO_LSSmaster_COMMAND_WAITING;
147 LSSmaster->timeoutTimer = 0;
148 CLEAR_CANrxNew(LSSmaster->CANrxNew);
149 CO_memset(LSSmaster->CANrxData, 0, sizeof(LSSmaster->CANrxData));
150 LSSmaster->pFunctSignal = NULL;
151 LSSmaster->functSignalObject = NULL;
152
153 /* configure LSS CAN Slave response message reception */
154 CO_CANrxBufferInit(
155 CANdevRx, /* CAN device */
156 CANdevRxIdx, /* rx buffer index */
157 CANidLssSlave, /* CAN identifier */
158 0x7FF, /* mask */
159 0, /* rtr */
160 (void*)LSSmaster, /* object passed to receive function */
161 CO_LSSmaster_receive);/* this function will process received message */
162
163 /* configure LSS CAN Master message transmission */
164 LSSmaster->CANdevTx = CANdevTx;
165 LSSmaster->TXbuff = CO_CANtxBufferInit(
166 CANdevTx, /* CAN device */
167 CANdevTxIdx, /* index of specific buffer inside CAN module */
168 CANidLssMaster, /* CAN identifier */
169 0, /* rtr */
170 8, /* number of data bytes */
171 0); /* synchronous message flag bit */
172
173 return CO_ERROR_NO;
174 }
175
176
177 /******************************************************************************/
CO_LSSmaster_changeTimeout(CO_LSSmaster_t * LSSmaster,uint16_t timeout_ms)178 void CO_LSSmaster_changeTimeout(
179 CO_LSSmaster_t *LSSmaster,
180 uint16_t timeout_ms)
181 {
182 if (LSSmaster != NULL) {
183 LSSmaster->timeout = timeout_ms;
184 }
185 }
186
187
188 /******************************************************************************/
CO_LSSmaster_initCallback(CO_LSSmaster_t * LSSmaster,void * object,void (* pFunctSignal)(void * object))189 void CO_LSSmaster_initCallback(
190 CO_LSSmaster_t *LSSmaster,
191 void *object,
192 void (*pFunctSignal)(void *object))
193 {
194 if(LSSmaster != NULL){
195 LSSmaster->functSignalObject = object;
196 LSSmaster->pFunctSignal = pFunctSignal;
197 }
198 }
199
200 /*
201 * Helper function - initiate switch state
202 */
CO_LSSmaster_switchStateSelectInitiate(CO_LSSmaster_t * LSSmaster,CO_LSS_address_t * lssAddress)203 static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectInitiate(
204 CO_LSSmaster_t *LSSmaster,
205 CO_LSS_address_t *lssAddress)
206 {
207 CO_LSSmaster_return_t ret;
208
209 if (lssAddress != NULL) {
210 /* switch state select specific using LSS address */
211 LSSmaster->state = CO_LSSmaster_STATE_CFG_SLECTIVE;
212 LSSmaster->command = CO_LSSmaster_COMMAND_SWITCH_STATE;
213 LSSmaster->timeoutTimer = 0;
214
215 CLEAR_CANrxNew(LSSmaster->CANrxNew);
216 CO_memset(&LSSmaster->TXbuff->data[6], 0, 2);
217 LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_VENDOR;
218 CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.vendorID);
219 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
220 LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_PRODUCT;
221 CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.productCode);
222 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
223 LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_REV;
224 CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.revisionNumber);
225 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
226 LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_SEL_SERIAL;
227 CO_setUint32(&LSSmaster->TXbuff->data[1], lssAddress->identity.serialNumber);
228 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
229
230 ret = CO_LSSmaster_WAIT_SLAVE;
231 }
232 else {
233 /* switch state global */
234 LSSmaster->state = CO_LSSmaster_STATE_CFG_GLOBAL;
235
236 CLEAR_CANrxNew(LSSmaster->CANrxNew);
237 LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL;
238 LSSmaster->TXbuff->data[1] = CO_LSS_STATE_CONFIGURATION;
239 CO_memset(&LSSmaster->TXbuff->data[2], 0, 6);
240 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
241
242 /* This is non-confirmed service! */
243 ret = CO_LSSmaster_OK;
244 }
245 return ret;
246 }
247
248 /*
249 * Helper function - wait for confirmation
250 */
CO_LSSmaster_switchStateSelectWait(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms)251 static CO_LSSmaster_return_t CO_LSSmaster_switchStateSelectWait(
252 CO_LSSmaster_t *LSSmaster,
253 uint16_t timeDifference_ms)
254 {
255 CO_LSSmaster_return_t ret;
256
257 if (IS_CANrxNew(LSSmaster->CANrxNew)) {
258 uint8_t cs = LSSmaster->CANrxData[0];
259 CLEAR_CANrxNew(LSSmaster->CANrxNew);
260
261 if (cs == CO_LSS_SWITCH_STATE_SEL) {
262 /* confirmation received */
263 ret = CO_LSSmaster_OK;
264 }
265 else {
266 ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms);
267 }
268 }
269 else {
270 ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms);
271 }
272
273 return ret;
274 }
275
276 /******************************************************************************/
CO_LSSmaster_switchStateSelect(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,CO_LSS_address_t * lssAddress)277 CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect(
278 CO_LSSmaster_t *LSSmaster,
279 uint16_t timeDifference_ms,
280 CO_LSS_address_t *lssAddress)
281 {
282 CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE;
283
284 if (LSSmaster == NULL){
285 return CO_LSSmaster_ILLEGAL_ARGUMENT;
286 }
287
288 /* Initiate select */
289 if (LSSmaster->state==CO_LSSmaster_STATE_WAITING &&
290 LSSmaster->command==CO_LSSmaster_COMMAND_WAITING){
291
292 ret = CO_LSSmaster_switchStateSelectInitiate(LSSmaster, lssAddress);
293 }
294 /* Wait for confirmation */
295 else if (LSSmaster->command == CO_LSSmaster_COMMAND_SWITCH_STATE) {
296 ret = CO_LSSmaster_switchStateSelectWait(LSSmaster, timeDifference_ms);
297 }
298
299 if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) {
300 /* finished */
301 LSSmaster->command = CO_LSSmaster_COMMAND_WAITING;
302 }
303 if (ret < CO_LSSmaster_OK) {
304 /* switching failed, go back to waiting */
305 LSSmaster->state=CO_LSSmaster_STATE_WAITING;
306 LSSmaster->command = CO_LSSmaster_COMMAND_WAITING;
307 }
308 return ret;
309 }
310
311
312 /******************************************************************************/
CO_LSSmaster_switchStateDeselect(CO_LSSmaster_t * LSSmaster)313 CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect(
314 CO_LSSmaster_t *LSSmaster)
315 {
316 CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE;
317
318 if (LSSmaster == NULL){
319 return CO_LSSmaster_ILLEGAL_ARGUMENT;
320 }
321
322 /* We can always send this command to get into a clean state on the network.
323 * If no slave is selected, this command is ignored. */
324 LSSmaster->state = CO_LSSmaster_STATE_WAITING;
325 LSSmaster->command = CO_LSSmaster_COMMAND_WAITING;
326 LSSmaster->timeoutTimer = 0;
327
328 /* switch state global */
329 CLEAR_CANrxNew(LSSmaster->CANrxNew);
330 LSSmaster->TXbuff->data[0] = CO_LSS_SWITCH_STATE_GLOBAL;
331 LSSmaster->TXbuff->data[1] = CO_LSS_STATE_WAITING;
332 CO_memset(&LSSmaster->TXbuff->data[2], 0, 6);
333 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
334
335 /* This is non-confirmed service! */
336 ret = CO_LSSmaster_OK;
337
338 return ret;
339 }
340
341
342 /*
343 * Helper function - wait for confirmation, check for returned error code
344 *
345 * This uses the nature of the configure confirmation message design:
346 * - byte 0 -> cs
347 * - byte 1 -> Error Code, where
348 * - 0 = OK
349 * - 1 .. FE = Values defined by CiA. All currently defined values
350 * are slave rejects. No further distinction on why the
351 * slave did reject the request.
352 * - FF = Manufacturer Error Code in byte 2
353 * - byte 2 -> Manufacturer Error, currently not used
354 *
355 * enums for the errorCode are
356 * - CO_LSS_cfgNodeId_t
357 * - CO_LSS_cfgBitTiming_t
358 * - CO_LSS_cfgStore_t
359 */
CO_LSSmaster_configureCheckWait(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,uint8_t csWait)360 static CO_LSSmaster_return_t CO_LSSmaster_configureCheckWait(
361 CO_LSSmaster_t *LSSmaster,
362 uint16_t timeDifference_ms,
363 uint8_t csWait)
364 {
365 CO_LSSmaster_return_t ret;
366
367 if (IS_CANrxNew(LSSmaster->CANrxNew)) {
368 uint8_t cs = LSSmaster->CANrxData[0];
369 uint8_t errorCode = LSSmaster->CANrxData[1];
370 CLEAR_CANrxNew(LSSmaster->CANrxNew);
371
372 if (cs == csWait) {
373 if (errorCode == 0) {
374 ret = CO_LSSmaster_OK;
375 }
376 else if (errorCode == 0xff) {
377 ret = CO_LSSmaster_OK_MANUFACTURER;
378 }
379 else {
380 ret = CO_LSSmaster_OK_ILLEGAL_ARGUMENT;
381 }
382 }
383 else {
384 ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms);
385 }
386 }
387 else {
388 ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms);
389 }
390
391 if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) {
392 /* finished */
393 LSSmaster->command = CO_LSSmaster_COMMAND_WAITING;
394 }
395 return ret;
396 }
397
398
399 /******************************************************************************/
CO_LSSmaster_configureBitTiming(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,uint16_t bit)400 CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming(
401 CO_LSSmaster_t *LSSmaster,
402 uint16_t timeDifference_ms,
403 uint16_t bit)
404 {
405 CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE;
406 uint8_t bitTiming;
407
408 if (LSSmaster == NULL){
409 return CO_LSSmaster_ILLEGAL_ARGUMENT;
410 }
411
412 switch (bit) {
413 case 1000: bitTiming = CO_LSS_BIT_TIMING_1000; break;
414 case 800: bitTiming = CO_LSS_BIT_TIMING_800; break;
415 case 500: bitTiming = CO_LSS_BIT_TIMING_500; break;
416 case 250: bitTiming = CO_LSS_BIT_TIMING_250; break;
417 case 125: bitTiming = CO_LSS_BIT_TIMING_125; break;
418 case 50: bitTiming = CO_LSS_BIT_TIMING_50; break;
419 case 20: bitTiming = CO_LSS_BIT_TIMING_20; break;
420 case 10: bitTiming = CO_LSS_BIT_TIMING_10; break;
421 case 0: bitTiming = CO_LSS_BIT_TIMING_AUTO; break;
422 default: return CO_LSSmaster_ILLEGAL_ARGUMENT;
423 }
424
425 /* Initiate config bit */
426 if (LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE &&
427 LSSmaster->command==CO_LSSmaster_COMMAND_WAITING){
428
429 LSSmaster->command = CO_LSSmaster_COMMAND_CFG_BIT_TIMING;
430 LSSmaster->timeoutTimer = 0;
431
432 CLEAR_CANrxNew(LSSmaster->CANrxNew);
433 LSSmaster->TXbuff->data[0] = CO_LSS_CFG_BIT_TIMING;
434 LSSmaster->TXbuff->data[1] = 0;
435 LSSmaster->TXbuff->data[2] = bitTiming;
436 CO_memset(&LSSmaster->TXbuff->data[3], 0, 5);
437 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
438
439 ret = CO_LSSmaster_WAIT_SLAVE;
440 }
441 /* Wait for confirmation */
442 else if (LSSmaster->command == CO_LSSmaster_COMMAND_CFG_BIT_TIMING) {
443
444 ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_ms,
445 CO_LSS_CFG_BIT_TIMING);
446 }
447
448 if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) {
449 /* finished */
450 LSSmaster->command = CO_LSSmaster_COMMAND_WAITING;
451 }
452 return ret;
453 }
454
455
456 /******************************************************************************/
CO_LSSmaster_configureNodeId(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,uint8_t nodeId)457 CO_LSSmaster_return_t CO_LSSmaster_configureNodeId(
458 CO_LSSmaster_t *LSSmaster,
459 uint16_t timeDifference_ms,
460 uint8_t nodeId)
461 {
462 CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE;
463
464 if (LSSmaster==NULL || !CO_LSS_NODE_ID_VALID(nodeId)){
465 return CO_LSSmaster_ILLEGAL_ARGUMENT;
466 }
467
468 /* Initiate config node ID */
469 if ((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE ||
470 /* Let un-config node ID also be run in global mode for unconfiguring all nodes */
471 (LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL &&
472 nodeId == CO_LSS_NODE_ID_ASSIGNMENT)) &&
473 LSSmaster->command==CO_LSSmaster_COMMAND_WAITING) {
474
475 LSSmaster->command = CO_LSSmaster_COMMAND_CFG_NODE_ID;
476 LSSmaster->timeoutTimer = 0;
477
478 CLEAR_CANrxNew(LSSmaster->CANrxNew);
479 LSSmaster->TXbuff->data[0] = CO_LSS_CFG_NODE_ID;
480 LSSmaster->TXbuff->data[1] = nodeId;
481 CO_memset(&LSSmaster->TXbuff->data[2], 0, 6);
482 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
483
484 ret = CO_LSSmaster_WAIT_SLAVE;
485 }
486 /* Wait for confirmation */
487 else if (LSSmaster->command == CO_LSSmaster_COMMAND_CFG_NODE_ID) {
488
489 ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_ms,
490 CO_LSS_CFG_NODE_ID);
491 }
492
493 if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) {
494 /* finished */
495 LSSmaster->command = CO_LSSmaster_COMMAND_WAITING;
496 }
497 return ret;
498 }
499
500
501 /******************************************************************************/
CO_LSSmaster_configureStore(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms)502 CO_LSSmaster_return_t CO_LSSmaster_configureStore(
503 CO_LSSmaster_t *LSSmaster,
504 uint16_t timeDifference_ms)
505 {
506 CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE;
507
508 if (LSSmaster == NULL){
509 return CO_LSSmaster_ILLEGAL_ARGUMENT;
510 }
511
512 /* Initiate config store */
513 if (LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE &&
514 LSSmaster->command==CO_LSSmaster_COMMAND_WAITING){
515
516 LSSmaster->command = CO_LSSmaster_COMMAND_CFG_STORE;
517 LSSmaster->timeoutTimer = 0;
518
519 CLEAR_CANrxNew(LSSmaster->CANrxNew);
520 LSSmaster->TXbuff->data[0] = CO_LSS_CFG_STORE;
521 CO_memset(&LSSmaster->TXbuff->data[1], 0, 7);
522 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
523
524 ret = CO_LSSmaster_WAIT_SLAVE;
525 }
526 /* Wait for confirmation */
527 else if (LSSmaster->command == CO_LSSmaster_COMMAND_CFG_STORE) {
528
529 ret = CO_LSSmaster_configureCheckWait(LSSmaster, timeDifference_ms,
530 CO_LSS_CFG_STORE);
531 }
532
533 if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) {
534 /* finished */
535 LSSmaster->command = CO_LSSmaster_COMMAND_WAITING;
536 }
537 return ret;
538 }
539
540
541 /******************************************************************************/
CO_LSSmaster_ActivateBit(CO_LSSmaster_t * LSSmaster,uint16_t switchDelay_ms)542 CO_LSSmaster_return_t CO_LSSmaster_ActivateBit(
543 CO_LSSmaster_t *LSSmaster,
544 uint16_t switchDelay_ms)
545 {
546 CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE;
547
548 if (LSSmaster == NULL){
549 return CO_LSSmaster_ILLEGAL_ARGUMENT;
550 }
551
552 /* for activating bit timing, we need to have all slaves set to config
553 * state. This check makes it a bit harder to shoot ourselves in the foot */
554 if (LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL &&
555 LSSmaster->command==CO_LSSmaster_COMMAND_WAITING){
556
557 CLEAR_CANrxNew(LSSmaster->CANrxNew);
558 LSSmaster->TXbuff->data[0] = CO_LSS_CFG_ACTIVATE_BIT_TIMING;
559 CO_setUint16(&LSSmaster->TXbuff->data[1], switchDelay_ms);
560 CO_memset(&LSSmaster->TXbuff->data[3], 0, 5);
561 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
562
563 /* This is non-confirmed service! */
564 ret = CO_LSSmaster_OK;
565 }
566
567 return ret;
568 }
569
570 /*
571 * Helper function - send request
572 */
CO_LSSmaster_inquireInitiate(CO_LSSmaster_t * LSSmaster,uint8_t cs)573 static CO_LSSmaster_return_t CO_LSSmaster_inquireInitiate(
574 CO_LSSmaster_t *LSSmaster,
575 uint8_t cs)
576 {
577 CLEAR_CANrxNew(LSSmaster->CANrxNew);
578 LSSmaster->TXbuff->data[0] = cs;
579 CO_memset(&LSSmaster->TXbuff->data[1], 0, 7);
580 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
581
582 return CO_LSSmaster_WAIT_SLAVE;
583 }
584
585 /*
586 * Helper function - wait for confirmation
587 */
CO_LSSmaster_inquireCheckWait(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,uint8_t csWait,uint32_t * value)588 static CO_LSSmaster_return_t CO_LSSmaster_inquireCheckWait(
589 CO_LSSmaster_t *LSSmaster,
590 uint16_t timeDifference_ms,
591 uint8_t csWait,
592 uint32_t *value)
593 {
594 CO_LSSmaster_return_t ret;
595
596 if (IS_CANrxNew(LSSmaster->CANrxNew)) {
597 uint8_t cs = LSSmaster->CANrxData[0];
598 *value = CO_getUint32(&LSSmaster->CANrxData[1]);
599 CLEAR_CANrxNew(LSSmaster->CANrxNew);
600
601 if (cs == csWait) {
602 ret = CO_LSSmaster_OK;
603 }
604 else {
605 ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms);
606 }
607 }
608 else {
609 ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms);
610 }
611
612 return ret;
613 }
614
615 /******************************************************************************/
CO_LSSmaster_InquireLssAddress(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,CO_LSS_address_t * lssAddress)616 CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress(
617 CO_LSSmaster_t *LSSmaster,
618 uint16_t timeDifference_ms,
619 CO_LSS_address_t *lssAddress)
620 {
621 CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE;
622 CO_LSSmaster_command_t next = CO_LSSmaster_COMMAND_WAITING;
623
624 if (LSSmaster==NULL || lssAddress==NULL){
625 return CO_LSSmaster_ILLEGAL_ARGUMENT;
626 }
627
628 /* Check for reply */
629 if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_VENDOR) {
630
631 ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_ms,
632 CO_LSS_INQUIRE_VENDOR, &lssAddress->identity.vendorID);
633 if (ret == CO_LSSmaster_OK) {
634 /* Start next request */
635 next = CO_LSSmaster_COMMAND_INQUIRE_PRODUCT;
636 ret = CO_LSSmaster_WAIT_SLAVE;
637 }
638 }
639 else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_PRODUCT) {
640
641 ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_ms,
642 CO_LSS_INQUIRE_PRODUCT, &lssAddress->identity.productCode);
643 if (ret == CO_LSSmaster_OK) {
644 /* Start next request */
645 next = CO_LSSmaster_COMMAND_INQUIRE_REV;
646 ret = CO_LSSmaster_WAIT_SLAVE;
647 }
648 }
649 else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_REV) {
650
651 ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_ms,
652 CO_LSS_INQUIRE_REV, &lssAddress->identity.revisionNumber);
653 if (ret == CO_LSSmaster_OK) {
654 /* Start next request */
655 next = CO_LSSmaster_COMMAND_INQUIRE_SERIAL;
656 ret = CO_LSSmaster_WAIT_SLAVE;
657 }
658 }
659 else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_SERIAL) {
660
661 ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_ms,
662 CO_LSS_INQUIRE_SERIAL, &lssAddress->identity.serialNumber);
663 }
664 /* Check for next request */
665 if (LSSmaster->state == CO_LSSmaster_STATE_CFG_SLECTIVE ||
666 LSSmaster->state == CO_LSSmaster_STATE_CFG_GLOBAL) {
667 if (LSSmaster->command == CO_LSSmaster_COMMAND_WAITING) {
668
669 LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_VENDOR;
670 LSSmaster->timeoutTimer = 0;
671
672 ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_VENDOR);
673 }
674 else if (next == CO_LSSmaster_COMMAND_INQUIRE_PRODUCT) {
675 LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_PRODUCT;
676 LSSmaster->timeoutTimer = 0;
677
678 ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_PRODUCT);
679 }
680 else if (next == CO_LSSmaster_COMMAND_INQUIRE_REV) {
681 LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_REV;
682 LSSmaster->timeoutTimer = 0;
683
684 ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_REV);
685 }
686 else if (next == CO_LSSmaster_COMMAND_INQUIRE_SERIAL) {
687 LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_SERIAL;
688 LSSmaster->timeoutTimer = 0;
689
690 ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_SERIAL);
691 }
692 }
693
694 if (ret!=CO_LSSmaster_INVALID_STATE && ret!=CO_LSSmaster_WAIT_SLAVE) {
695 /* finished */
696 LSSmaster->command = CO_LSSmaster_COMMAND_WAITING;
697 }
698 return ret;
699 }
700
701
702 /******************************************************************************/
CO_LSSmaster_InquireNodeId(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,uint8_t * nodeId)703 CO_LSSmaster_return_t CO_LSSmaster_InquireNodeId(
704 CO_LSSmaster_t *LSSmaster,
705 uint16_t timeDifference_ms,
706 uint8_t *nodeId)
707 {
708 CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE;
709
710 if (LSSmaster==NULL || nodeId==NULL){
711 return CO_LSSmaster_ILLEGAL_ARGUMENT;
712 }
713
714 /* send request */
715 if ((LSSmaster->state==CO_LSSmaster_STATE_CFG_SLECTIVE ||
716 LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL) &&
717 LSSmaster->command == CO_LSSmaster_COMMAND_WAITING) {
718
719 LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_NODE_ID;
720 LSSmaster->timeoutTimer = 0;
721
722 ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_NODE_ID);
723 }
724 /* Check for reply */
725 else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_NODE_ID) {
726 uint32_t tmp = 0;
727
728 ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_ms,
729 CO_LSS_INQUIRE_NODE_ID, &tmp);
730
731 *nodeId = tmp & 0xff;
732 }
733
734 if (ret != CO_LSSmaster_WAIT_SLAVE) {
735 LSSmaster->command = CO_LSSmaster_COMMAND_WAITING;
736 }
737 return ret;
738 }
739
740 /*
741 * Helper function - send request
742 */
CO_LSSmaster_FsSendMsg(CO_LSSmaster_t * LSSmaster,uint32_t idNumber,uint8_t bitCheck,uint8_t lssSub,uint8_t lssNext)743 static void CO_LSSmaster_FsSendMsg(
744 CO_LSSmaster_t *LSSmaster,
745 uint32_t idNumber,
746 uint8_t bitCheck,
747 uint8_t lssSub,
748 uint8_t lssNext)
749 {
750 LSSmaster->timeoutTimer = 0;
751
752 CLEAR_CANrxNew(LSSmaster->CANrxNew);
753 LSSmaster->TXbuff->data[0] = CO_LSS_IDENT_FASTSCAN;
754 CO_setUint32(&LSSmaster->TXbuff->data[1], idNumber);
755 LSSmaster->TXbuff->data[5] = bitCheck;
756 LSSmaster->TXbuff->data[6] = lssSub;
757 LSSmaster->TXbuff->data[7] = lssNext;
758
759 CO_CANsend(LSSmaster->CANdevTx, LSSmaster->TXbuff);
760 }
761
762 /*
763 * Helper function - wait for confirmation
764 */
CO_LSSmaster_FsCheckWait(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms)765 static CO_LSSmaster_return_t CO_LSSmaster_FsCheckWait(
766 CO_LSSmaster_t *LSSmaster,
767 uint16_t timeDifference_ms)
768 {
769 CO_LSSmaster_return_t ret;
770
771 ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms);
772 if (ret == CO_LSSmaster_TIMEOUT) {
773 ret = CO_LSSmaster_SCAN_NOACK;
774
775 if (IS_CANrxNew(LSSmaster->CANrxNew)) {
776 uint8_t cs = LSSmaster->CANrxData[0];
777 CLEAR_CANrxNew(LSSmaster->CANrxNew);
778
779 if (cs == CO_LSS_IDENT_SLAVE) {
780 /* At least one node is waiting for fastscan */
781 ret = CO_LSSmaster_SCAN_FINISHED;
782 }
783 }
784 }
785
786 return ret;
787 }
788
789 /*
790 * Helper function - initiate scan for 32 bit part of LSS address
791 */
CO_LSSmaster_FsScanInitiate(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,CO_LSSmaster_scantype_t scan,CO_LSS_fastscan_lss_sub_next lssSub)792 static CO_LSSmaster_return_t CO_LSSmaster_FsScanInitiate(
793 CO_LSSmaster_t *LSSmaster,
794 uint16_t timeDifference_ms,
795 CO_LSSmaster_scantype_t scan,
796 CO_LSS_fastscan_lss_sub_next lssSub)
797 {
798 LSSmaster->fsLssSub = lssSub;
799 LSSmaster->fsIdNumber = 0;
800
801 switch (scan) {
802 case CO_LSSmaster_FS_SCAN:
803 break;
804 case CO_LSSmaster_FS_MATCH:
805 /* No scanning requested */
806 return CO_LSSmaster_SCAN_FINISHED;
807 case CO_LSSmaster_FS_SKIP:
808 default:
809 return CO_LSSmaster_SCAN_FAILED;
810 }
811
812 LSSmaster->fsBitChecked = CO_LSS_FASTSCAN_BIT31;
813
814 /* trigger scan procedure by sending first message */
815 CO_LSSmaster_FsSendMsg(LSSmaster, LSSmaster->fsIdNumber,
816 LSSmaster->fsBitChecked, LSSmaster->fsLssSub, LSSmaster->fsLssSub);
817
818 return CO_LSSmaster_WAIT_SLAVE;
819 }
820
821 /*
822 * Helper function - scan for 32 bits of LSS address, one by one
823 */
CO_LSSmaster_FsScanWait(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,CO_LSSmaster_scantype_t scan)824 static CO_LSSmaster_return_t CO_LSSmaster_FsScanWait(
825 CO_LSSmaster_t *LSSmaster,
826 uint16_t timeDifference_ms,
827 CO_LSSmaster_scantype_t scan)
828 {
829 CO_LSSmaster_return_t ret;
830
831 switch (scan) {
832 case CO_LSSmaster_FS_SCAN:
833 break;
834 case CO_LSSmaster_FS_MATCH:
835 /* No scanning requested */
836 return CO_LSSmaster_SCAN_FINISHED;
837 case CO_LSSmaster_FS_SKIP:
838 default:
839 return CO_LSSmaster_SCAN_FAILED;
840 }
841
842 ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms);
843 if (ret == CO_LSSmaster_TIMEOUT) {
844
845 ret = CO_LSSmaster_WAIT_SLAVE;
846
847 if (IS_CANrxNew(LSSmaster->CANrxNew)) {
848 uint8_t cs = LSSmaster->CANrxData[0];
849 CLEAR_CANrxNew(LSSmaster->CANrxNew);
850
851 if (cs != CO_LSS_IDENT_SLAVE) {
852 /* wrong response received. Can not continue */
853 return CO_LSSmaster_SCAN_FAILED;
854 }
855 }
856 else {
857 /* no response received, assumption is wrong */
858 LSSmaster->fsIdNumber |= 1UL << LSSmaster->fsBitChecked;
859 }
860
861 if (LSSmaster->fsBitChecked == CO_LSS_FASTSCAN_BIT0) {
862 /* Scanning cycle is finished, we now have 32 bit address data */
863 ret = CO_LSSmaster_SCAN_FINISHED;
864 }
865 else {
866 LSSmaster->fsBitChecked --;
867
868 CO_LSSmaster_FsSendMsg(LSSmaster,
869 LSSmaster->fsIdNumber, LSSmaster->fsBitChecked,
870 LSSmaster->fsLssSub, LSSmaster->fsLssSub);
871 }
872 }
873
874 return ret;
875 }
876
877 /*
878 * Helper function - initiate check for 32 bit part of LSS address
879 */
CO_LSSmaster_FsVerifyInitiate(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,CO_LSSmaster_scantype_t scan,uint32_t idNumberCheck,CO_LSS_fastscan_lss_sub_next lssNext)880 static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyInitiate(
881 CO_LSSmaster_t *LSSmaster,
882 uint16_t timeDifference_ms,
883 CO_LSSmaster_scantype_t scan,
884 uint32_t idNumberCheck,
885 CO_LSS_fastscan_lss_sub_next lssNext)
886 {
887 switch (scan) {
888 case CO_LSSmaster_FS_SCAN:
889 /* ID obtained by scan */
890 break;
891 case CO_LSSmaster_FS_MATCH:
892 /* ID given by user */
893 LSSmaster->fsIdNumber = idNumberCheck;
894 break;
895 case CO_LSSmaster_FS_SKIP:
896 default:
897 return CO_LSSmaster_SCAN_FAILED;
898 }
899
900 LSSmaster->fsBitChecked = CO_LSS_FASTSCAN_BIT0;
901
902 /* send request */
903 CO_LSSmaster_FsSendMsg(LSSmaster, LSSmaster->fsIdNumber,
904 LSSmaster->fsBitChecked, LSSmaster->fsLssSub, lssNext);
905
906 return CO_LSSmaster_WAIT_SLAVE;
907 }
908
909 /*
910 * Helper function - verify 32 bit LSS address, request node(s) to switch
911 * their state machine to the next state
912 */
CO_LSSmaster_FsVerifyWait(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,CO_LSSmaster_scantype_t scan,uint32_t * idNumberRet)913 static CO_LSSmaster_return_t CO_LSSmaster_FsVerifyWait(
914 CO_LSSmaster_t *LSSmaster,
915 uint16_t timeDifference_ms,
916 CO_LSSmaster_scantype_t scan,
917 uint32_t *idNumberRet)
918 {
919 CO_LSSmaster_return_t ret;
920
921 if (scan == CO_LSSmaster_FS_SKIP) {
922 return CO_LSSmaster_SCAN_FAILED;
923 }
924
925 ret = CO_LSSmaster_check_timeout(LSSmaster, timeDifference_ms);
926 if (ret == CO_LSSmaster_TIMEOUT) {
927
928 *idNumberRet = 0;
929 ret = CO_LSSmaster_SCAN_NOACK;
930
931 if (IS_CANrxNew(LSSmaster->CANrxNew)) {
932 uint8_t cs = LSSmaster->CANrxData[0];
933 CLEAR_CANrxNew(LSSmaster->CANrxNew);
934
935 if (cs == CO_LSS_IDENT_SLAVE) {
936 *idNumberRet = LSSmaster->fsIdNumber;
937 ret = CO_LSSmaster_SCAN_FINISHED;
938 } else {
939 ret = CO_LSSmaster_SCAN_FAILED;
940 }
941 }
942 }
943
944 return ret;
945 }
946
947 /*
948 * Helper function - check which 32 bit to scan for next, if any
949 */
CO_LSSmaster_FsSearchNext(CO_LSSmaster_t * LSSmaster,const CO_LSSmaster_fastscan_t * fastscan)950 static CO_LSS_fastscan_lss_sub_next CO_LSSmaster_FsSearchNext(
951 CO_LSSmaster_t *LSSmaster,
952 const CO_LSSmaster_fastscan_t *fastscan)
953 {
954 int i;
955
956 /* we search for the next LSS address part to scan for, beginning with the
957 * one after the current one. If there is none remaining, scanning is
958 * finished */
959 for (i = LSSmaster->fsLssSub + 1; i <= CO_LSS_FASTSCAN_SERIAL; i++) {
960 if (fastscan->scan[i] != CO_LSSmaster_FS_SKIP) {
961 return (CO_LSS_fastscan_lss_sub_next)i;
962 }
963 }
964 /* node selection is triggered by switching node state machine back
965 * to initial state */
966 return CO_LSS_FASTSCAN_VENDOR_ID;
967 }
968
969 /******************************************************************************/
CO_LSSmaster_IdentifyFastscan(CO_LSSmaster_t * LSSmaster,uint16_t timeDifference_ms,CO_LSSmaster_fastscan_t * fastscan)970 CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan(
971 CO_LSSmaster_t *LSSmaster,
972 uint16_t timeDifference_ms,
973 CO_LSSmaster_fastscan_t *fastscan)
974 {
975 uint8_t i;
976 uint8_t count;
977 CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE;
978 CO_LSS_fastscan_lss_sub_next next;
979
980 /* parameter validation */
981 if (LSSmaster==NULL || fastscan==NULL){
982 return CO_LSSmaster_ILLEGAL_ARGUMENT;
983 }
984 if (fastscan->scan[0] == CO_LSSmaster_FS_SKIP) {
985 /* vendor ID scan cannot be skipped */
986 return CO_LSSmaster_ILLEGAL_ARGUMENT;
987 }
988 count = 0;
989 for (i = 0; i < (sizeof(fastscan->scan) / sizeof(fastscan->scan[0])); i++) {
990 if (fastscan->scan[i] == CO_LSSmaster_FS_SKIP) {
991 count ++;
992 }
993 if (count > 2) {
994 /* Node selection needs the Vendor ID and at least one other value */
995 return CO_LSSmaster_ILLEGAL_ARGUMENT;
996 }
997 }
998
999 /* state machine validation */
1000 if (LSSmaster->state!=CO_LSSmaster_STATE_WAITING ||
1001 (LSSmaster->command!=CO_LSSmaster_COMMAND_WAITING &&
1002 LSSmaster->command!=CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN)) {
1003 /* state machine not ready, other command is already processed */
1004 return CO_LSSmaster_INVALID_STATE;
1005 }
1006
1007 /* evaluate LSS state machine */
1008 switch (LSSmaster->command) {
1009 case CO_LSSmaster_COMMAND_WAITING:
1010 /* start fastscan */
1011 LSSmaster->command = CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN;
1012
1013 /* check if any nodes are waiting, if yes fastscan is reset */
1014 LSSmaster->fsState = CO_LSSmaster_FS_STATE_CHECK;
1015 CO_LSSmaster_FsSendMsg(LSSmaster, 0, CO_LSS_FASTSCAN_CONFIRM, 0, 0);
1016
1017 return CO_LSSmaster_WAIT_SLAVE;
1018 default:
1019 /* continue with evaluating fastscan state machine */
1020 break;
1021 }
1022
1023 /* evaluate fastscan state machine. The state machine is evaluated as following
1024 * - check for non-configured nodes
1025 * - scan for vendor ID
1026 * - verify vendor ID, switch node state
1027 * - scan for product code
1028 * - verify product code, switch node state
1029 * - scan for revision number
1030 * - verify revision number, switch node state
1031 * - scan for serial number
1032 * - verify serial number, switch node to LSS configuration mode
1033 * Certain steps can be skipped as mentioned in the function description.
1034 * If one step is not ack'ed by a node, the scanning process is terminated
1035 * and the correspondign error is returned. */
1036 switch (LSSmaster->fsState) {
1037 case CO_LSSmaster_FS_STATE_CHECK:
1038 ret = CO_LSSmaster_FsCheckWait(LSSmaster, timeDifference_ms);
1039 if (ret == CO_LSSmaster_SCAN_FINISHED) {
1040 CO_memset((uint8_t*)&fastscan->found, 0, sizeof(fastscan->found));
1041
1042 /* start scanning procedure by triggering vendor ID scan */
1043 CO_LSSmaster_FsScanInitiate(LSSmaster, timeDifference_ms,
1044 fastscan->scan[CO_LSS_FASTSCAN_VENDOR_ID],
1045 CO_LSS_FASTSCAN_VENDOR_ID);
1046 ret = CO_LSSmaster_WAIT_SLAVE;
1047
1048 LSSmaster->fsState = CO_LSSmaster_FS_STATE_SCAN;
1049 }
1050 break;
1051 case CO_LSSmaster_FS_STATE_SCAN:
1052 ret = CO_LSSmaster_FsScanWait(LSSmaster, timeDifference_ms,
1053 fastscan->scan[LSSmaster->fsLssSub]);
1054 if (ret == CO_LSSmaster_SCAN_FINISHED) {
1055 /* scanning finished, initiate verifcation. The verification
1056 * message also contains the node state machine "switch to
1057 * next state" request */
1058 next = CO_LSSmaster_FsSearchNext(LSSmaster, fastscan);
1059 ret = CO_LSSmaster_FsVerifyInitiate(LSSmaster, timeDifference_ms,
1060 fastscan->scan[LSSmaster->fsLssSub],
1061 fastscan->match.addr[LSSmaster->fsLssSub], next);
1062
1063 LSSmaster->fsState = CO_LSSmaster_FS_STATE_VERIFY;
1064 }
1065 break;
1066 case CO_LSSmaster_FS_STATE_VERIFY:
1067 ret = CO_LSSmaster_FsVerifyWait(LSSmaster, timeDifference_ms,
1068 fastscan->scan[LSSmaster->fsLssSub],
1069 &fastscan->found.addr[LSSmaster->fsLssSub]);
1070 if (ret == CO_LSSmaster_SCAN_FINISHED) {
1071 /* verification successful:
1072 * - assumed node id is correct
1073 * - node state machine has switched to the requested state,
1074 * mirror that in the local copy */
1075 next = CO_LSSmaster_FsSearchNext(LSSmaster, fastscan);
1076 if (next == CO_LSS_FASTSCAN_VENDOR_ID) {
1077 /* fastscan finished, one node is now in LSS configuration
1078 * mode */
1079 LSSmaster->state = CO_LSSmaster_STATE_CFG_SLECTIVE;
1080 }
1081 else {
1082 /* initiate scan for next part of LSS address */
1083 ret = CO_LSSmaster_FsScanInitiate(LSSmaster,
1084 timeDifference_ms, fastscan->scan[next], next);
1085 if (ret == CO_LSSmaster_SCAN_FINISHED) {
1086 /* Scanning is not requested. Initiate verification
1087 * step in next function call */
1088 ret = CO_LSSmaster_WAIT_SLAVE;
1089 }
1090
1091 LSSmaster->fsState = CO_LSSmaster_FS_STATE_SCAN;
1092 }
1093 }
1094 break;
1095 default:
1096 break;
1097 }
1098
1099 if (ret != CO_LSSmaster_WAIT_SLAVE) {
1100 /* finished */
1101 LSSmaster->command = CO_LSSmaster_COMMAND_WAITING;
1102 }
1103 return ret;
1104 }
1105
1106
1107 #endif
1108