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