1 /**
2  * CANopen Network management and Heartbeat producer protocol.
3  *
4  * @file        CO_NMT_Heartbeat.h
5  * @ingroup     CO_NMT_Heartbeat
6  * @author      Janez Paternoster
7  * @copyright   2004 - 2020 Janez Paternoster
8  *
9  * This file is part of CANopenNode, an opensource CANopen Stack.
10  * Project home page is <https://github.com/CANopenNode/CANopenNode>.
11  * For more information on CANopen see <http://www.can-cia.org/>.
12  *
13  * Licensed under the Apache License, Version 2.0 (the "License");
14  * you may not use this file except in compliance with the License.
15  * You may obtain a copy of the License at
16  *
17  *     http://www.apache.org/licenses/LICENSE-2.0
18  *
19  * Unless required by applicable law or agreed to in writing, software
20  * distributed under the License is distributed on an "AS IS" BASIS,
21  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  * See the License for the specific language governing permissions and
23  * limitations under the License.
24  */
25 
26 
27 #ifndef CO_NMT_HEARTBEAT_H
28 #define CO_NMT_HEARTBEAT_H
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
34 /**
35  * @defgroup CO_NMT_Heartbeat NMT and Heartbeat
36  * @ingroup CO_CANopen
37  * @{
38  *
39  * CANopen Network management and Heartbeat producer protocol.
40  *
41  * CANopen device can be in one of the #CO_NMT_internalState_t
42  *  - Initializing. It is active before CANopen is initialized.
43  *  - Pre-operational. All CANopen objects are active, except PDOs.
44  *  - Operational. Process data objects (PDOs) are active too.
45  *  - Stopped. Only Heartbeat producer and NMT consumer are active.
46  *
47  * NMT master can change the internal state of the devices by sending
48  * #CO_NMT_command_t.
49  *
50  * ###NMT message contents:
51  *
52  *   Byte | Description
53  *   -----|-----------------------------------------------------------
54  *     0  | #CO_NMT_command_t
55  *     1  | Node ID. If zero, command addresses all nodes.
56  *
57  * ###Heartbeat message contents:
58  *
59  *   Byte | Description
60  *   -----|-----------------------------------------------------------
61  *     0  | #CO_NMT_internalState_t
62  *
63  * @see #CO_Default_CAN_ID_t
64  *
65  * ###Status LED diodes
66  * Macros for @ref CO_NMT_statusLEDdiodes are also implemented in this object.
67  */
68 
69 
70 /**
71  * @defgroup CO_NMT_statusLEDdiodes Status LED diodes
72  * @{
73  *
74  * Macros for status LED diodes.
75  *
76  * Helper macros for implementing status LED diodes are used by stack and can
77  * also be used by the application. If macro returns 1 LED should be ON,
78  * otherwise OFF. Function CO_NMT_blinkingProcess50ms() must be called cyclically
79  * to update the variables.
80  */
81     #define LED_FLICKERING(NMT)     (((NMT)->LEDflickering>=0)     ? 1 : 0) /**< 10HZ (100MS INTERVAL) */
82     #define LED_BLINKING(NMT)       (((NMT)->LEDblinking>=0)       ? 1 : 0) /**< 2.5HZ (400MS INTERVAL) */
83     #define LED_SINGLE_FLASH(NMT)   (((NMT)->LEDsingleFlash>=0)    ? 1 : 0) /**< 200MS ON, 1000MS OFF */
84     #define LED_DOUBLE_FLASH(NMT)   (((NMT)->LEDdoubleFlash>=0)    ? 1 : 0) /**< 200MS ON, 200MS OFF, 200MS ON, 1000MS OFF */
85     #define LED_TRIPLE_FLASH(NMT)   (((NMT)->LEDtripleFlash>=0)    ? 1 : 0) /**< 200MS ON, 200MS OFF, 200MS ON, 200MS OFF, 200MS ON, 1000MS OFF */
86     #define LED_QUADRUPLE_FLASH(NMT)(((NMT)->LEDquadrupleFlash>=0) ? 1 : 0) /**< 200MS ON, 200MS OFF, 200MS ON, 200MS OFF, 200MS ON, 200MS OFF, 200MS ON, 1000MS OFF */
87     #define LED_GREEN_RUN(NMT)      (((NMT)->LEDgreenRun>=0)       ? 1 : 0) /**< CANOPEN RUN LED ACCORDING TO CIA DR 303-3 */
88     #define LED_RED_ERROR(NMT)      (((NMT)->LEDredError>=0)       ? 1 : 0) /**< CANopen error LED according to CiA DR 303-3 */
89 /** @} */
90 
91 
92 /**
93  * Internal network state of the CANopen node
94  */
95 typedef enum{
96     CO_NMT_INITIALIZING             = 0,    /**< Device is initializing */
97     CO_NMT_PRE_OPERATIONAL          = 127,  /**< Device is in pre-operational state */
98     CO_NMT_OPERATIONAL              = 5,    /**< Device is in operational state */
99     CO_NMT_STOPPED                  = 4     /**< Device is stopped */
100 }CO_NMT_internalState_t;
101 
102 
103 /**
104  * Commands from NMT master.
105  */
106 typedef enum{
107     CO_NMT_ENTER_OPERATIONAL        = 1,    /**< Start device */
108     CO_NMT_ENTER_STOPPED            = 2,    /**< Stop device */
109     CO_NMT_ENTER_PRE_OPERATIONAL    = 128,  /**< Put device into pre-operational */
110     CO_NMT_RESET_NODE               = 129,  /**< Reset device */
111     CO_NMT_RESET_COMMUNICATION      = 130   /**< Reset CANopen communication on device */
112 }CO_NMT_command_t;
113 
114 
115 /**
116  * Return code for CO_NMT_process() that tells application code what to
117  * reset.
118  */
119 typedef enum{
120     CO_RESET_NOT  = 0,/**< Normal return, no action */
121     CO_RESET_COMM = 1,/**< Application must provide communication reset. */
122     CO_RESET_APP  = 2,/**< Application must provide complete device reset */
123     CO_RESET_QUIT = 3 /**< Application must quit, no reset of microcontroller (command is not requested by the stack.) */
124 }CO_NMT_reset_cmd_t;
125 
126 
127 /**
128  * NMT consumer and Heartbeat producer object. It includes also variables for
129  * @ref CO_NMT_statusLEDdiodes. Object is initialized by CO_NMT_init().
130  */
131 typedef struct{
132     uint8_t             operatingState; /**< See @ref CO_NMT_internalState_t */
133 #ifdef CO_USE_LEDS
134     int8_t              LEDflickering;  /**< See @ref CO_NMT_statusLEDdiodes */
135     int8_t              LEDblinking;    /**< See @ref CO_NMT_statusLEDdiodes */
136     int8_t              LEDsingleFlash; /**< See @ref CO_NMT_statusLEDdiodes */
137     int8_t              LEDdoubleFlash; /**< See @ref CO_NMT_statusLEDdiodes */
138     int8_t              LEDtripleFlash; /**< See @ref CO_NMT_statusLEDdiodes */
139     int8_t              LEDquadrupleFlash; /**< See @ref CO_NMT_statusLEDdiodes */
140     int8_t              LEDgreenRun;    /**< See @ref CO_NMT_statusLEDdiodes */
141     int8_t              LEDredError;    /**< See @ref CO_NMT_statusLEDdiodes */
142 #endif /* CO_USE_LEDS */
143 
144     uint8_t             resetCommand;   /**< If different than zero, device will reset */
145     uint8_t             nodeId;         /**< CANopen Node ID of this device */
146     uint16_t            HBproducerTimer;/**< Internal timer for HB producer */
147     uint16_t            firstHBTime;    /**< From CO_NMT_init() */
148     CO_EMpr_t          *emPr;           /**< From CO_NMT_init() */
149     CO_CANmodule_t     *HB_CANdev;      /**< From CO_NMT_init() */
150     void              (*pFunctNMT)(CO_NMT_internalState_t state); /**< From CO_NMT_initCallback() or NULL */
151     CO_CANtx_t         *HB_TXbuff;      /**< CAN transmit buffer */
152 }CO_NMT_t;
153 
154 
155 /**
156  * Initialize NMT and Heartbeat producer object.
157  *
158  * Function must be called in the communication reset section.
159  *
160  * @param NMT This object will be initialized.
161  * @param emPr Emergency main object.
162  * @param nodeId CANopen Node ID of this device.
163  * @param firstHBTime Time between bootup and first heartbeat message in milliseconds.
164  * If firstHBTime is greater than _Producer Heartbeat time_
165  * (object dictionary, index 0x1017), latter is used instead.
166  * @param NMT_CANdev CAN device for NMT reception.
167  * @param NMT_rxIdx Index of receive buffer in above CAN device.
168  * @param CANidRxNMT CAN identifier for NMT message.
169  * @param HB_CANdev CAN device for HB transmission.
170  * @param HB_txIdx Index of transmit buffer in the above CAN device.
171  * @param CANidTxHB CAN identifier for HB message.
172  *
173  * @return #CO_ReturnError_t CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT.
174  */
175 CO_ReturnError_t CO_NMT_init(
176         CO_NMT_t               *NMT,
177         CO_EMpr_t              *emPr,
178         uint8_t                 nodeId,
179         uint16_t                firstHBTime,
180         CO_CANmodule_t         *NMT_CANdev,
181         uint16_t                NMT_rxIdx,
182         uint16_t                CANidRxNMT,
183         CO_CANmodule_t         *HB_CANdev,
184         uint16_t                HB_txIdx,
185         uint16_t                CANidTxHB);
186 
187 /**
188  * Initialize NMT callback function.
189  *
190  * Function initializes optional callback function, which is called after
191  * NMT State change has occured. Function may wake up external task which
192  * handles NMT events.
193  * The first call is made immediately to give the consumer the current NMT state.
194  *
195  * @remark Be aware that the callback function is run inside the CAN receive
196  * function context. Depending on the driver, this might be inside an interrupt!
197  *
198  * @param NMT This object.
199  * @param pFunctNMT Pointer to the callback function. Not called if NULL.
200  */
201 void CO_NMT_initCallback(
202         CO_NMT_t               *NMT,
203         void                  (*pFunctNMT)(CO_NMT_internalState_t state));
204 
205 
206 /**
207  * Calculate blinking bytes.
208  *
209  * Function must be called cyclically every 50 milliseconds. See @ref CO_NMT_statusLEDdiodes.
210  *
211  * @param NMT NMT object.
212  */
213 #ifdef CO_USE_LEDS
214 void CO_NMT_blinkingProcess50ms(CO_NMT_t *NMT);
215 #endif /* CO_USE_LEDS */
216 
217 
218 /**
219  * Process received NMT and produce Heartbeat messages.
220  *
221  * Function must be called cyclically.
222  *
223  * @param NMT This object.
224  * @param timeDifference_ms Time difference from previous function call in [milliseconds].
225  * @param HBtime _Producer Heartbeat time_ (object dictionary, index 0x1017).
226  * @param NMTstartup _NMT startup behavior_ (object dictionary, index 0x1F80).
227  * @param errorRegister _Error register_ (object dictionary, index 0x1001).
228  * @param errorBehavior pointer to _Error behavior_ array (object dictionary, index 0x1029).
229  *        Object controls, if device should leave NMT operational state.
230  *        Length of array must be 6. If pointer is NULL, no calculation is made.
231  * @param timerNext_ms Return value - info to OS - see CO_process().
232  *
233  * @return #CO_NMT_reset_cmd_t
234  */
235 CO_NMT_reset_cmd_t CO_NMT_process(
236         CO_NMT_t               *NMT,
237         uint16_t                timeDifference_ms,
238         uint16_t                HBtime,
239         uint32_t                NMTstartup,
240         uint8_t                 errorRegister,
241         const uint8_t           errorBehavior[],
242         uint16_t               *timerNext_ms);
243 
244 
245 /**
246  * Query current NMT state
247  *
248  * @param NMT This object.
249  *
250  * @return #CO_NMT_internalState_t
251  */
252 CO_NMT_internalState_t CO_NMT_getInternalState(
253         CO_NMT_t               *NMT);
254 
255 /**
256  * Set current NMT state
257  *
258  * @param NMT This object.
259  * @param CO_NMT_internalState_t State to set
260  *
261  */
262 void CO_NMT_setInternalState(
263         CO_NMT_t               *NMT,
264         CO_NMT_internalState_t state);
265 
266 
267 #ifdef __cplusplus
268 }
269 #endif /*__cplusplus*/
270 
271 /** @} */
272 #endif
273