1 /** 2 * CANopen Heartbeat consumer protocol. 3 * 4 * @file CO_HBconsumer.h 5 * @ingroup CO_HBconsumer 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_HB_CONS_H 28 #define CO_HB_CONS_H 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 /** 35 * @defgroup CO_HBconsumer Heartbeat consumer 36 * @ingroup CO_CANopen 37 * @{ 38 * 39 * CANopen Heartbeat consumer protocol. 40 * 41 * Heartbeat consumer monitors Heartbeat messages from remote nodes. If any 42 * monitored node don't send his Heartbeat in specified time, Heartbeat consumer 43 * sends emergency message. If all monitored nodes are operational, then 44 * variable _allMonitoredOperational_ inside CO_HBconsumer_t is set to true. 45 * Monitoring starts after the reception of the first HeartBeat (not bootup). 46 * 47 * Heartbeat set up is done by writing to the OD registers 0x1016 or by using 48 * the function _CO_HBconsumer_initEntry()_ 49 * 50 * @see @ref CO_NMT_Heartbeat 51 */ 52 53 /** 54 * Heartbeat state of a node 55 */ 56 typedef enum { 57 CO_HBconsumer_UNCONFIGURED = 0x00U, /**< Consumer entry inactive */ 58 CO_HBconsumer_UNKNOWN = 0x01U, /**< Consumer enabled, but no heartbeat received yet */ 59 CO_HBconsumer_ACTIVE = 0x02U, /**< Heartbeat received within set time */ 60 CO_HBconsumer_TIMEOUT = 0x03U, /**< No heatbeat received for set time */ 61 } CO_HBconsumer_state_t; 62 63 64 /** 65 * One monitored node inside CO_HBconsumer_t. 66 */ 67 typedef struct{ 68 uint8_t nodeId; /**< Node Id of the monitored node */ 69 CO_NMT_internalState_t NMTstate; /**< Of the remote node (Heartbeat payload) */ 70 CO_HBconsumer_state_t HBstate; /**< Current heartbeat state */ 71 uint16_t timeoutTimer; /**< Time since last heartbeat received */ 72 uint16_t time; /**< Consumer heartbeat time from OD */ 73 volatile void *CANrxNew; /**< Indication if new Heartbeat message received from the CAN bus */ 74 /** Callback for heartbeat state change to active event */ 75 void (*pFunctSignalHbStarted)(uint8_t nodeId, uint8_t idx, void *object); /**< From CO_HBconsumer_initTimeoutCallback() or NULL */ 76 void *functSignalObjectHbStarted;/**< Pointer to object */ 77 /** Callback for consumer timeout event */ 78 void (*pFunctSignalTimeout)(uint8_t nodeId, uint8_t idx, void *object); /**< From CO_HBconsumer_initTimeoutCallback() or NULL */ 79 void *functSignalObjectTimeout;/**< Pointer to object */ 80 /** Callback for remote reset event */ 81 void (*pFunctSignalRemoteReset)(uint8_t nodeId, uint8_t idx, void *object); /**< From CO_HBconsumer_initRemoteResetCallback() or NULL */ 82 void *functSignalObjectRemoteReset;/**< Pointer to object */ 83 }CO_HBconsNode_t; 84 85 86 /** 87 * Heartbeat consumer object. 88 * 89 * Object is initilaized by CO_HBconsumer_init(). It contains an array of 90 * CO_HBconsNode_t objects. 91 */ 92 typedef struct{ 93 CO_EM_t *em; /**< From CO_HBconsumer_init() */ 94 const uint32_t *HBconsTime; /**< From CO_HBconsumer_init() */ 95 CO_HBconsNode_t *monitoredNodes; /**< From CO_HBconsumer_init() */ 96 uint8_t numberOfMonitoredNodes; /**< From CO_HBconsumer_init() */ 97 /** True, if all monitored nodes are NMT operational or no node is 98 monitored. Can be read by the application */ 99 uint8_t allMonitoredOperational; 100 CO_CANmodule_t *CANdevRx; /**< From CO_HBconsumer_init() */ 101 uint16_t CANdevRxIdxStart; /**< From CO_HBconsumer_init() */ 102 }CO_HBconsumer_t; 103 104 105 /** 106 * Initialize Heartbeat consumer object. 107 * 108 * Function must be called in the communication reset section. 109 * 110 * @param HBcons This object will be initialized. 111 * @param em Emergency object. 112 * @param SDO SDO server object. 113 * @param HBconsTime Pointer to _Consumer Heartbeat Time_ array 114 * from Object Dictionary (index 0x1016). Size of array is equal to numberOfMonitoredNodes. 115 * @param monitoredNodes Pointer to the externaly defined array of the same size 116 * as numberOfMonitoredNodes. 117 * @param numberOfMonitoredNodes Total size of the above arrays. 118 * @param CANdevRx CAN device for Heartbeat reception. 119 * @param CANdevRxIdxStart Starting index of receive buffer in the above CAN device. 120 * Number of used indexes is equal to numberOfMonitoredNodes. 121 * 122 * @return #CO_ReturnError_t CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT. 123 */ 124 CO_ReturnError_t CO_HBconsumer_init( 125 CO_HBconsumer_t *HBcons, 126 CO_EM_t *em, 127 CO_SDO_t *SDO, 128 const uint32_t HBconsTime[], 129 CO_HBconsNode_t monitoredNodes[], 130 uint8_t numberOfMonitoredNodes, 131 CO_CANmodule_t *CANdevRx, 132 uint16_t CANdevRxIdxStart); 133 134 /** 135 * Initialize one Heartbeat consumer entry 136 * 137 * Calling this function has the same affect as writing to the corresponding 138 * entries in the Object Dictionary (index 0x1016) 139 * @remark The values in the Object Dictionary must be set manually by the 140 * calling function so that heartbeat consumer behaviour matches the OD value. 141 * 142 * @param HBcons This object. 143 * @param idx index of the node in HBcons object 144 * @param nodeId see OD 0x1016 description 145 * @param consumerTime see OD 0x1016 description 146 * @return 147 */ 148 CO_ReturnError_t CO_HBconsumer_initEntry( 149 CO_HBconsumer_t *HBcons, 150 uint8_t idx, 151 uint8_t nodeId, 152 uint16_t consumerTime); 153 154 /** 155 * Initialize Heartbeat consumer started callback function. 156 * 157 * Function initializes optional callback function, which is called for the 158 * first received heartbeat after activating hb consumer or timeout. 159 * Function may wake up external task, which handles this event. 160 * 161 * @param HBcons This object. 162 * @param idx index of the node in HBcons object 163 * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL 164 * @param pFunctSignal Pointer to the callback function. Not called if NULL. 165 */ 166 void CO_HBconsumer_initCallbackHeartbeatStarted( 167 CO_HBconsumer_t *HBcons, 168 uint8_t idx, 169 void *object, 170 void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)); 171 172 173 /** 174 * Initialize Heartbeat consumer timeout callback function. 175 * 176 * Function initializes optional callback function, which is called when the node 177 * state changes from active to timeout. Function may wake up external task, 178 * which handles this event. 179 * 180 * @param HBcons This object. 181 * @param idx index of the node in HBcons object 182 * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL 183 * @param pFunctSignal Pointer to the callback function. Not called if NULL. 184 */ 185 void CO_HBconsumer_initCallbackTimeout( 186 CO_HBconsumer_t *HBcons, 187 uint8_t idx, 188 void *object, 189 void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)); 190 191 /** 192 * Initialize Heartbeat consumer remote reset detected callback function. 193 * 194 * Function initializes optional callback function, which is called when a bootup 195 * message is received from the remote node. Function may wake up external task, 196 * which handles this event. 197 * 198 * @param HBcons This object. 199 * @param idx index of the node in HBcons object 200 * @param object Pointer to object, which will be passed to pFunctSignal(). Can be NULL 201 * @param pFunctSignal Pointer to the callback function. Not called if NULL. 202 */ 203 void CO_HBconsumer_initCallbackRemoteReset( 204 CO_HBconsumer_t *HBcons, 205 uint8_t idx, 206 void *object, 207 void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object)); 208 209 /** 210 * Process Heartbeat consumer object. 211 * 212 * Function must be called cyclically. 213 * 214 * @param HBcons This object. 215 * @param NMTisPreOrOperational True if this node is NMT_PRE_OPERATIONAL or NMT_OPERATIONAL. 216 * @param timeDifference_ms Time difference from previous function call in [milliseconds]. 217 */ 218 void CO_HBconsumer_process( 219 CO_HBconsumer_t *HBcons, 220 bool_t NMTisPreOrOperational, 221 uint16_t timeDifference_ms); 222 223 /** 224 * Get the heartbeat producer object index by node ID 225 * 226 * @param HBcons This object. 227 * @param nodeId producer node ID 228 * @return index. -1 if not found 229 */ 230 int8_t CO_HBconsumer_getIdxByNodeId( 231 CO_HBconsumer_t *HBcons, 232 uint8_t nodeId); 233 234 /** 235 * Get the current state of a heartbeat producer by the index in OD 0x1016 236 * 237 * @param HBcons This object. 238 * @param idx object sub index 239 * @return #CO_HBconsumer_state_t 240 */ 241 CO_HBconsumer_state_t CO_HBconsumer_getState( 242 CO_HBconsumer_t *HBcons, 243 uint8_t idx); 244 245 /** 246 * Get the current NMT state of a heartbeat producer by the index in OD 0x1016 247 * 248 * NMT state is only available when heartbeat is enabled for this index! 249 * 250 * @param HBcons This object. 251 * @param idx object sub index 252 * @param [out] #CO_NMT_internalState_t of this index 253 * @retval 0 NMT state has been received and is valid 254 * @retval -1 not valid 255 */ 256 int8_t CO_HBconsumer_getNmtState( 257 CO_HBconsumer_t *HBcons, 258 uint8_t idx, 259 CO_NMT_internalState_t *nmtState); 260 261 262 #ifdef __cplusplus 263 } 264 #endif /*__cplusplus*/ 265 266 /** @} */ 267 #endif 268