1 /**
2  * CANopen LSS Master/Slave protocol.
3  *
4  * @file        CO_LSSmaster.h
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 
28 #ifndef CO_LSSmaster_H
29 #define CO_LSSmaster_H
30 
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34 
35 #if CO_NO_LSS_CLIENT == 1
36 
37 #include "CO_LSS.h"
38 
39 /**
40  * @addtogroup CO_LSS
41  * @defgroup CO_LSSmaster LSS Master
42  * @ingroup CO_LSS
43  * @{
44  *
45  * CANopen Layer Setting Service - client protocol
46  *
47  * The client/master can use the following services
48  * - node selection via LSS address
49  * - node selection via LSS fastscan
50  * - Inquire LSS address of currently selected node
51  * - Inquire node ID
52  * - Configure bit timing
53  * - Configure node ID
54  * - Activate bit timing parameters
55  * - Store configuration
56  *
57  * The LSS master is initalized during the CANopenNode initialization process.
58  * Except for enabling the LSS master in the configurator, no further
59  * run-time configuration is needed for basic operation.
60  * The LSS master does basic checking of commands and command sequence.
61  *
62  * ###Usage
63  *
64  * Usage of the CANopen LSS master is demonstrated in CANopenSocket application,
65  * see CO_LSS_master.c / CO_LSS_master.h files.
66  *
67  * It essentially is always as following:
68  * - select node(s)
69  * - call master command(s)
70  * - evaluate return value
71  * - deselect nodes
72  *
73  * All commands need to be run cyclically, e.g. like this
74  * \code{.c}
75 
76     interval = 0;
77     do {
78         ret = CO_LSSmaster_InquireNodeId(LSSmaster, interval, &outval);
79 
80         interval = 1; ms
81         sleep(interval);
82     } while (ret == CO_LSSmaster_WAIT_SLAVE);
83 
84  * \endcode
85  *
86  * A more advanced implementation can make use of the callback function to
87  * shorten waiting times.
88  */
89 
90 /**
91  * Return values of LSS master functions.
92  */
93 typedef enum {
94     CO_LSSmaster_SCAN_FINISHED       = 2,    /**< Scanning finished successful */
95     CO_LSSmaster_WAIT_SLAVE          = 1,    /**< No response arrived from server yet */
96     CO_LSSmaster_OK                  = 0,    /**< Success, end of communication */
97     CO_LSSmaster_TIMEOUT             = -1,   /**< No reply received */
98     CO_LSSmaster_ILLEGAL_ARGUMENT    = -2,   /**< Invalid argument */
99     CO_LSSmaster_INVALID_STATE       = -3,   /**< State machine not ready or already processing a request */
100     CO_LSSmaster_SCAN_NOACK          = -4,   /**< No node found that matches scan request */
101     CO_LSSmaster_SCAN_FAILED         = -5,   /**< An error occurred while scanning. Try again */
102     CO_LSSmaster_OK_ILLEGAL_ARGUMENT = -101, /**< LSS success, node rejected argument because of non-supported value */
103     CO_LSSmaster_OK_MANUFACTURER     = -102, /**< LSS success, node rejected argument with manufacturer error code */
104 } CO_LSSmaster_return_t;
105 
106 
107 /**
108  * LSS master object.
109  */
110 typedef struct{
111     uint16_t         timeout;          /**< LSS response timeout in ms */
112 
113     uint8_t          state;            /**< Node is currently selected */
114     uint8_t          command;          /**< Active command */
115     uint16_t         timeoutTimer;     /**< Timeout timer for LSS communication */
116 
117     uint8_t          fsState;          /**< Current state of fastscan master state machine */
118     uint8_t          fsLssSub;         /**< Current state of node state machine */
119     uint8_t          fsBitChecked;     /**< Current scan bit position */
120     uint32_t         fsIdNumber;       /**< Current scan result */
121 
122     volatile void   *CANrxNew;         /**< Indication if new LSS message is received from CAN bus. It needs to be cleared when received message is completely processed. */
123     uint8_t          CANrxData[8];     /**< 8 data bytes of the received message */
124 
125     void           (*pFunctSignal)(void *object); /**< From CO_LSSmaster_initCallback() or NULL */
126     void            *functSignalObject;/**< Pointer to object */
127 
128     CO_CANmodule_t  *CANdevTx;         /**< From #CO_LSSslave_init() */
129     CO_CANtx_t      *TXbuff;           /**< CAN transmit buffer */
130 }CO_LSSmaster_t;
131 
132 
133 /**
134  * Default timeout for LSS slave in ms. This is the same as for SDO. For more
135  * info about LSS timeout see #CO_LSSmaster_changeTimeout()
136  */
137 #define CO_LSSmaster_DEFAULT_TIMEOUT 1000U /* ms */
138 
139 
140 /**
141  * Initialize LSS object.
142  *
143  * Function must be called in the communication reset section.
144  *
145  * @param LSSmaster This object will be initialized.
146  * @param timeout_ms slave response timeout in ms, for more detail see
147  * #CO_LSSmaster_changeTimeout()
148  * @param CANdevRx CAN device for LSS master reception.
149  * @param CANdevRxIdx Index of receive buffer in the above CAN device.
150  * @param CANidLssSlave COB ID for reception.
151  * @param CANdevTx CAN device for LSS master transmission.
152  * @param CANdevTxIdx Index of transmit buffer in the above CAN device.
153  * @param CANidLssMaster COB ID for transmission.
154  * @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT.
155  */
156 CO_ReturnError_t CO_LSSmaster_init(
157         CO_LSSmaster_t         *LSSmaster,
158         uint16_t                timeout_ms,
159         CO_CANmodule_t         *CANdevRx,
160         uint16_t                CANdevRxIdx,
161         uint32_t                CANidLssSlave,
162         CO_CANmodule_t         *CANdevTx,
163         uint16_t                CANdevTxIdx,
164         uint32_t                CANidLssMaster);
165 
166 /**
167  * Change LSS master timeout
168  *
169  * On LSS, a "negative ack" is signaled by the slave not answering. Because of
170  * that, a low timeout value can significantly increase protocol speed in some
171  * cases (e.g. fastscan). However, as soon as there is activity on the bus,
172  * LSS messages can be delayed because of their low CAN network priority (see
173  * #CO_Default_CAN_ID_t).
174  *
175  * @remark Be aware that a "late response" will seriously mess up LSS, so this
176  * value must be selected "as high as necessary and as low as possible". CiA does
177  * neither specify nor recommend a value.
178  *
179  * @remark This timeout is per-transfer. If a command internally needs multiple
180  * transfers to complete, this timeout is applied on each transfer.
181  *
182  * @param LSSmaster This object.
183  * @param timeout_ms timeout value in ms
184  */
185 void CO_LSSmaster_changeTimeout(
186         CO_LSSmaster_t         *LSSmaster,
187         uint16_t                timeout_ms);
188 
189 
190 /**
191  * Initialize LSSserverRx callback function.
192  *
193  * Function initializes optional callback function, which is called after new
194  * message is received from the CAN bus. Function may wake up external task,
195  * which processes mainline CANopen functions.
196  *
197  * @param LSSmaster This object.
198  * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL
199  * @param pFunctSignal Pointer to the callback function. Not called if NULL.
200  */
201 void CO_LSSmaster_initCallback(
202         CO_LSSmaster_t         *LSSmaster,
203         void                   *object,
204         void                  (*pFunctSignal)(void *object));
205 
206 
207 /**
208  * Request LSS switch state select
209  *
210  * This function can select one specific or all nodes.
211  *
212  * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE
213  * Function is non-blocking.
214  *
215  * @remark Only one selection can be active at any time.
216  *
217  * @param LSSmaster This object.
218  * @param timeDifference_ms Time difference from previous function call in
219  * [milliseconds]. Zero when request is started.
220  * @param lssAddress LSS target address. If NULL, all nodes are selected
221  * @return #CO_LSSmaster_ILLEGAL_ARGUMENT,  #CO_LSSmaster_INVALID_STATE,
222  * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT
223  */
224 CO_LSSmaster_return_t CO_LSSmaster_switchStateSelect(
225         CO_LSSmaster_t         *LSSmaster,
226         uint16_t                timeDifference_ms,
227         CO_LSS_address_t       *lssAddress);
228 
229 
230 /**
231  * Request LSS switch state deselect
232  *
233  * This function deselects all nodes, so it doesn't matter if a specific
234  * node is selected.
235  *
236  * This function also resets the LSS master state machine to a clean state
237  *
238  * @param LSSmaster This object.
239  * @return #CO_LSSmaster_ILLEGAL_ARGUMENT,  #CO_LSSmaster_INVALID_STATE,
240  * #CO_LSSmaster_OK
241  */
242 CO_LSSmaster_return_t CO_LSSmaster_switchStateDeselect(
243         CO_LSSmaster_t         *LSSmaster);
244 
245 
246 /**
247  * Request LSS configure Bit Timing
248  *
249  * The new bit rate is set as new pending value.
250  *
251  * This function needs one specific node to be selected.
252  *
253  * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE.
254  * Function is non-blocking.
255  *
256  * @param LSSmaster This object.
257  * @param timeDifference_ms Time difference from previous function call in
258  * [milliseconds]. Zero when request is started.
259  * @param bit new bit rate
260  * @return #CO_LSSmaster_ILLEGAL_ARGUMENT,  #CO_LSSmaster_INVALID_STATE,
261  * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT,
262  * #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT
263  */
264 CO_LSSmaster_return_t CO_LSSmaster_configureBitTiming(
265         CO_LSSmaster_t         *LSSmaster,
266         uint16_t                timeDifference_ms,
267         uint16_t                bit);
268 
269 
270 /**
271  * Request LSS configure node ID
272  *
273  * The new node id is set as new pending node ID.
274  *
275  * This function needs one specific node to be selected.
276  *
277  * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE.
278  * Function is non-blocking.
279  *
280  * @param LSSmaster This object.
281  * @param timeDifference_ms Time difference from previous function call in
282  * [milliseconds]. Zero when request is started.
283  * @param nodeId new node ID. Special value #CO_LSS_NODE_ID_ASSIGNMENT can be
284  * used to invalidate node ID.
285  * @return #CO_LSSmaster_ILLEGAL_ARGUMENT,  #CO_LSSmaster_INVALID_STATE,
286  * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT,
287  * #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT
288  */
289 CO_LSSmaster_return_t CO_LSSmaster_configureNodeId(
290         CO_LSSmaster_t         *LSSmaster,
291         uint16_t                timeDifference_ms,
292         uint8_t                 nodeId);
293 
294 
295 /**
296  * Request LSS store configuration
297  *
298  * The current "pending" values for bit rate and node ID in LSS slave are
299  * stored as "permanent" values.
300  *
301  * This function needs one specific node to be selected.
302  *
303  * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE.
304  * Function is non-blocking.
305  *
306  * @param LSSmaster This object.
307  * @param timeDifference_ms Time difference from previous function call in
308  * [milliseconds]. Zero when request is started.
309  * @return #CO_LSSmaster_ILLEGAL_ARGUMENT,  #CO_LSSmaster_INVALID_STATE,
310  * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT,
311  * #CO_LSSmaster_OK_MANUFACTURER, #CO_LSSmaster_OK_ILLEGAL_ARGUMENT
312  */
313 CO_LSSmaster_return_t CO_LSSmaster_configureStore(
314         CO_LSSmaster_t         *LSSmaster,
315         uint16_t                timeDifference_ms);
316 
317 
318 /**
319  * Request LSS activate bit timing
320  *
321  * The current "pending" bit rate in LSS slave is applied.
322  *
323  * Be aware that changing the bit rate is a critical step for the network. A
324  * failure will render the network unusable! Therefore, this function only
325  * should be called if the following conditions are met:
326  * - all nodes support changing bit timing
327  * - new bit timing is successfully set as "pending" in all nodes
328  * - all nodes have to activate the new bit timing roughly at the same time.
329  *   Therefore this function needs all nodes to be selected.
330  *
331  * @param LSSmaster This object.
332  * @param switchDelay_ms delay that is applied by the slave once before and
333  * once after switching in ms.
334  * @return #CO_LSSmaster_ILLEGAL_ARGUMENT,  #CO_LSSmaster_INVALID_STATE,
335  * #CO_LSSmaster_OK
336  */
337 CO_LSSmaster_return_t CO_LSSmaster_ActivateBit(
338         CO_LSSmaster_t         *LSSmaster,
339         uint16_t                switchDelay_ms);
340 
341 
342 /**
343  * Request LSS inquire LSS address
344  *
345  * The LSS address value is read from the node. This is useful when the node
346  * was selected by fastscan.
347  *
348  * This function needs one specific node to be selected.
349  *
350  * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE.
351  * Function is non-blocking.
352  *
353  * @param LSSmaster This object.
354  * @param timeDifference_ms Time difference from previous function call in
355  * [milliseconds]. Zero when request is started.
356  * @param lssAddress [out] read result when function returns successfully
357  * @return #CO_LSSmaster_ILLEGAL_ARGUMENT,  #CO_LSSmaster_INVALID_STATE,
358  * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT
359  */
360 CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress(
361         CO_LSSmaster_t         *LSSmaster,
362         uint16_t                timeDifference_ms,
363         CO_LSS_address_t       *lssAddress);
364 
365 
366 /**
367  * Request LSS inquire node ID
368  *
369  * The node ID value is read from the node.
370  *
371  * This function needs one specific node to be selected.
372  *
373  * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE.
374  * Function is non-blocking.
375  *
376  * @param LSSmaster This object.
377  * @param timeDifference_ms Time difference from previous function call in
378  * [milliseconds]. Zero when request is started.
379  * @param nodeId [out] read result when function returns successfully
380  * @return #CO_LSSmaster_ILLEGAL_ARGUMENT,  #CO_LSSmaster_INVALID_STATE,
381  * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT
382  */
383 CO_LSSmaster_return_t CO_LSSmaster_InquireNodeId(
384         CO_LSSmaster_t         *LSSmaster,
385         uint16_t                timeDifference_ms,
386         uint8_t                *nodeId);
387 
388 
389 /**
390  * Scan type for #CO_LSSmaster_fastscan_t scan
391  */
392 typedef enum {
393     CO_LSSmaster_FS_SCAN  = 0,    /**< Do full 32 bit scan */
394     CO_LSSmaster_FS_SKIP  = 1,    /**< Skip this value */
395     CO_LSSmaster_FS_MATCH = 2,    /**< Full 32 bit value is given as argument, just verify */
396 } CO_LSSmaster_scantype_t;
397 
398 /**
399  * Parameters for LSS fastscan #CO_LSSmaster_IdentifyFastscan
400  */
401 typedef struct{
402     CO_LSSmaster_scantype_t scan[4];  /**< Scan type for each part of the LSS address */
403     CO_LSS_address_t        match;    /**< Value to match in case of #CO_LSSmaster_FS_MATCH */
404     CO_LSS_address_t        found;    /**< Scan result */
405 } CO_LSSmaster_fastscan_t;
406 
407 /**
408  * Select a node by LSS identify fastscan
409  *
410  * This initiates searching for a unconfigured node by the means of LSS fastscan
411  * mechanism. When this function is finished
412  * - a (more or less) arbitrary node is selected and ready for node ID assingment
413  * - no node is selected because the given criteria do not match a node
414  * - no node is selected because all nodes are already configured
415  *
416  * There are multiple ways to scan for a node. Depending on those, the scan
417  * will take different amounts of time:
418  * - full scan
419  * - partial scan
420  * - verification
421  *
422  * Most of the time, those are used in combination. Consider the following example:
423  * - Vendor ID and product code are known
424  * - Software version doesn't matter
425  * - Serial number is unknown
426  *
427  * In this case, the fastscan structure should be set up as following:
428  * \code{.c}
429 CO_LSSmaster_fastscan_t fastscan;
430 fastscan.scan[CO_LSS_FASTSCAN_VENDOR_ID] = CO_LSSmaster_FS_MATCH;
431 fastscan.match.vendorID = YOUR_VENDOR_ID;
432 fastscan.scan[CO_LSS_FASTSCAN_PRODUCT] = CO_LSSmaster_FS_MATCH;
433 fastscan.match.productCode = YOUR_PRODUCT_CODE;
434 fastscan.scan[CO_LSS_FASTSCAN_REV] = CO_LSSmaster_FS_SKIP;
435 fastscan.scan[CO_LSS_FASTSCAN_SERIAL] = CO_LSSmaster_FS_SCAN;
436  * \endcode
437  *
438  * This example will take 2 scan cyles for verifying vendor ID and product code
439  * and 33 scan cycles to find the serial number.
440  *
441  * For scanning, the following limitations apply:
442  * - No more than two values can be skipped
443  * - Vendor ID cannot be skipped
444  *
445  * @remark When doing partial scans, it is in the responsibility of the user
446  * that the LSS address is unique.
447  *
448  * This function needs that no node is selected when starting the scan process.
449  *
450  * Function must be called cyclically until it returns != #CO_LSSmaster_WAIT_SLAVE.
451  * Function is non-blocking.
452  *
453  * @param LSSmaster This object.
454  * @param timeDifference_ms Time difference from previous function call in
455  * [milliseconds]. Zero when request is started.
456  * @param fastscan struct according to #CO_LSSmaster_fastscan_t.
457  * @return #CO_LSSmaster_ILLEGAL_ARGUMENT,  #CO_LSSmaster_INVALID_STATE,
458  * #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_SCAN_FINISHED, #CO_LSSmaster_SCAN_NOACK,
459  * #CO_LSSmaster_SCAN_FAILED
460  */
461 CO_LSSmaster_return_t CO_LSSmaster_IdentifyFastscan(
462         CO_LSSmaster_t                  *LSSmaster,
463         uint16_t                         timeDifference_ms,
464         CO_LSSmaster_fastscan_t         *fastscan);
465 
466 
467 #else /* CO_NO_LSS_CLIENT == 1 */
468 
469 /**
470  * @addtogroup CO_LSS
471  * @{
472  * If you need documetation for LSS master usage, add "CO_NO_LSS_CLIENT=1" to doxygen
473  * "PREDEFINED" variable.
474  *
475  */
476 
477 #endif /* CO_NO_LSS_CLIENT == 1 */
478 
479 #ifdef __cplusplus
480 }
481 #endif /*__cplusplus*/
482 
483 /** @} */
484 #endif
485