CO_HBconsumer.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. /*
  2. * CANopen Heartbeat consumer object.
  3. *
  4. * @file CO_HBconsumer.c
  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. #include "301/CO_driver.h"
  26. #include "301/CO_SDOserver.h"
  27. #include "301/CO_Emergency.h"
  28. #include "301/CO_NMT_Heartbeat.h"
  29. #include "301/CO_HBconsumer.h"
  30. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE
  31. /* Verify HB consumer configuration *******************************************/
  32. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \
  33. && (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI
  34. #error CO_CONFIG_HB_CONS_CALLBACK_CHANGE and CO_CONFIG_HB_CONS_CALLBACK_MULTI cannot be set simultaneously!
  35. #endif
  36. /*
  37. * Read received message from CAN module.
  38. *
  39. * Function will be called (by CAN receive interrupt) every time, when CAN
  40. * message with correct identifier will be received. For more information and
  41. * description of parameters see file CO_driver.h.
  42. */
  43. static void CO_HBcons_receive(void *object, void *msg){
  44. CO_HBconsNode_t *HBconsNode;
  45. uint8_t DLC = CO_CANrxMsg_readDLC(msg);
  46. uint8_t *data = CO_CANrxMsg_readData(msg);
  47. HBconsNode = (CO_HBconsNode_t*) object; /* this is the correct pointer type of the first argument */
  48. /* verify message length */
  49. if (DLC == 1){
  50. /* copy data and set 'new message' flag. */
  51. HBconsNode->NMTstate = (CO_NMT_internalState_t)data[0];
  52. CO_FLAG_SET(HBconsNode->CANrxNew);
  53. }
  54. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE
  55. /* Optional signal to RTOS, which can resume task, which handles HBcons. */
  56. if (HBconsNode->pFunctSignalPre != NULL) {
  57. HBconsNode->pFunctSignalPre(HBconsNode->functSignalObjectPre);
  58. }
  59. #endif
  60. }
  61. /*
  62. * OD function for accessing _Consumer Heartbeat Time_ (index 0x1016) from SDO server.
  63. *
  64. * For more information see file CO_SDOserver.h.
  65. */
  66. static CO_SDO_abortCode_t CO_ODF_1016(CO_ODF_arg_t *ODF_arg)
  67. {
  68. CO_HBconsumer_t *HBcons;
  69. uint8_t NodeID;
  70. uint16_t HBconsTime;
  71. uint32_t value;
  72. CO_ReturnError_t ret;
  73. if (ODF_arg->reading){
  74. return CO_SDO_AB_NONE;
  75. }
  76. HBcons = (CO_HBconsumer_t*) ODF_arg->object;
  77. value = CO_getUint32(ODF_arg->data);
  78. NodeID = (value >> 16U) & 0xFFU;
  79. HBconsTime = value & 0xFFFFU;
  80. if ((value & 0xFF800000U) != 0){
  81. return CO_SDO_AB_PRAM_INCOMPAT;
  82. }
  83. ret = CO_HBconsumer_initEntry(HBcons, ODF_arg->subIndex-1U, NodeID, HBconsTime);
  84. if (ret != CO_ERROR_NO) {
  85. return CO_SDO_AB_PRAM_INCOMPAT;
  86. }
  87. return CO_SDO_AB_NONE;
  88. }
  89. /******************************************************************************/
  90. CO_ReturnError_t CO_HBconsumer_init(
  91. CO_HBconsumer_t *HBcons,
  92. CO_EM_t *em,
  93. CO_SDO_t *SDO,
  94. const uint32_t HBconsTime[],
  95. CO_HBconsNode_t monitoredNodes[],
  96. uint8_t numberOfMonitoredNodes,
  97. CO_CANmodule_t *CANdevRx,
  98. uint16_t CANdevRxIdxStart)
  99. {
  100. uint8_t i;
  101. CO_ReturnError_t ret = CO_ERROR_NO;
  102. /* verify arguments */
  103. if (HBcons==NULL || em==NULL || SDO==NULL || HBconsTime==NULL ||
  104. monitoredNodes==NULL || CANdevRx==NULL){
  105. return CO_ERROR_ILLEGAL_ARGUMENT;
  106. }
  107. /* Configure object variables */
  108. HBcons->em = em;
  109. HBcons->HBconsTime = HBconsTime;
  110. HBcons->monitoredNodes = monitoredNodes;
  111. HBcons->numberOfMonitoredNodes = numberOfMonitoredNodes;
  112. HBcons->allMonitoredActive = false;
  113. HBcons->allMonitoredOperational = CO_NMT_UNKNOWN;
  114. HBcons->NMTisPreOrOperationalPrev = false;
  115. HBcons->CANdevRx = CANdevRx;
  116. HBcons->CANdevRxIdxStart = CANdevRxIdxStart;
  117. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE
  118. HBcons->pFunctSignalNmtChanged = NULL;
  119. #endif
  120. for(i=0; i<HBcons->numberOfMonitoredNodes; i++) {
  121. uint8_t nodeId = (HBcons->HBconsTime[i] >> 16U) & 0xFFU;
  122. uint16_t time = HBcons->HBconsTime[i] & 0xFFFFU;
  123. ret = CO_HBconsumer_initEntry(HBcons, i, nodeId, time);
  124. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE
  125. HBcons->monitoredNodes[i].pFunctSignalPre = NULL;
  126. #endif
  127. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI
  128. HBcons->monitoredNodes[i].pFunctSignalNmtChanged = NULL;
  129. HBcons->monitoredNodes[i].pFunctSignalHbStarted = NULL;
  130. HBcons->monitoredNodes[i].pFunctSignalTimeout = NULL;
  131. HBcons->monitoredNodes[i].pFunctSignalRemoteReset = NULL;
  132. #endif
  133. }
  134. /* Configure Object dictionary entry at index 0x1016 */
  135. CO_OD_configure(SDO, OD_H1016_CONSUMER_HB_TIME, CO_ODF_1016, (void*)HBcons, 0, 0);
  136. return ret;
  137. }
  138. /******************************************************************************/
  139. CO_ReturnError_t CO_HBconsumer_initEntry(
  140. CO_HBconsumer_t *HBcons,
  141. uint8_t idx,
  142. uint8_t nodeId,
  143. uint16_t consumerTime_ms)
  144. {
  145. CO_ReturnError_t ret = CO_ERROR_NO;
  146. /* verify arguments */
  147. if (HBcons == NULL || idx >= HBcons->numberOfMonitoredNodes) {
  148. return CO_ERROR_ILLEGAL_ARGUMENT;
  149. }
  150. if ((consumerTime_ms != 0) && (nodeId != 0)){
  151. uint8_t i;
  152. /* there must not be more entries with same index and time different than zero */
  153. for(i = 0U; i<HBcons->numberOfMonitoredNodes; i++){
  154. uint32_t objectCopy = HBcons->HBconsTime[i];
  155. uint8_t NodeIDObj = (objectCopy >> 16U) & 0xFFU;
  156. uint16_t HBconsTimeObj = objectCopy & 0xFFFFU;
  157. if ((idx != i) && (HBconsTimeObj != 0) && (nodeId == NodeIDObj)){
  158. ret = CO_ERROR_ILLEGAL_ARGUMENT;
  159. }
  160. }
  161. }
  162. /* Configure one monitored node */
  163. if (ret == CO_ERROR_NO) {
  164. uint16_t COB_ID;
  165. CO_HBconsNode_t * monitoredNode = &HBcons->monitoredNodes[idx];
  166. monitoredNode->nodeId = nodeId;
  167. monitoredNode->time_us = (int32_t)consumerTime_ms * 1000;
  168. monitoredNode->NMTstate = CO_NMT_UNKNOWN;
  169. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \
  170. || (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI
  171. monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN;
  172. #endif
  173. CO_FLAG_CLEAR(monitoredNode->CANrxNew);
  174. /* is channel used */
  175. if (monitoredNode->nodeId && monitoredNode->time_us) {
  176. COB_ID = monitoredNode->nodeId + CO_CAN_ID_HEARTBEAT;
  177. monitoredNode->HBstate = CO_HBconsumer_UNKNOWN;
  178. }
  179. else {
  180. COB_ID = 0;
  181. monitoredNode->time_us = 0;
  182. monitoredNode->HBstate = CO_HBconsumer_UNCONFIGURED;
  183. }
  184. /* configure Heartbeat consumer CAN reception */
  185. if (monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED) {
  186. ret = CO_CANrxBufferInit(HBcons->CANdevRx,
  187. HBcons->CANdevRxIdxStart + idx,
  188. COB_ID,
  189. 0x7FF,
  190. 0,
  191. (void*)&HBcons->monitoredNodes[idx],
  192. CO_HBcons_receive);
  193. }
  194. }
  195. return ret;
  196. }
  197. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_CALLBACK_PRE
  198. /******************************************************************************/
  199. void CO_HBconsumer_initCallbackPre(
  200. CO_HBconsumer_t *HBcons,
  201. void *object,
  202. void (*pFunctSignal)(void *object))
  203. {
  204. if (HBcons != NULL) {
  205. uint8_t i;
  206. for(i=0; i<HBcons->numberOfMonitoredNodes; i++) {
  207. HBcons->monitoredNodes[i].pFunctSignalPre = pFunctSignal;
  208. HBcons->monitoredNodes[i].functSignalObjectPre = object;
  209. }
  210. }
  211. }
  212. #endif
  213. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE
  214. /******************************************************************************/
  215. void CO_HBconsumer_initCallbackNmtChanged(
  216. CO_HBconsumer_t *HBcons,
  217. void *object,
  218. void (*pFunctSignal)(uint8_t nodeId, uint8_t idx,
  219. CO_NMT_internalState_t NMTstate,
  220. void *object))
  221. {
  222. if (HBcons==NULL) {
  223. return;
  224. }
  225. HBcons->pFunctSignalNmtChanged = pFunctSignal;
  226. HBcons->pFunctSignalObjectNmtChanged = object;
  227. }
  228. #endif
  229. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI
  230. /******************************************************************************/
  231. void CO_HBconsumer_initCallbackNmtChanged(
  232. CO_HBconsumer_t *HBcons,
  233. uint8_t idx,
  234. void *object,
  235. void (*pFunctSignal)(uint8_t nodeId, uint8_t idx,
  236. CO_NMT_internalState_t NMTstate,
  237. void *object))
  238. {
  239. if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) {
  240. return;
  241. }
  242. CO_HBconsNode_t * const monitoredNode = &HBcons->monitoredNodes[idx];
  243. monitoredNode->pFunctSignalNmtChanged = pFunctSignal;
  244. monitoredNode->pFunctSignalObjectNmtChanged = object;
  245. }
  246. /******************************************************************************/
  247. void CO_HBconsumer_initCallbackHeartbeatStarted(
  248. CO_HBconsumer_t *HBcons,
  249. uint8_t idx,
  250. void *object,
  251. void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object))
  252. {
  253. CO_HBconsNode_t *monitoredNode;
  254. if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) {
  255. return;
  256. }
  257. monitoredNode = &HBcons->monitoredNodes[idx];
  258. monitoredNode->pFunctSignalHbStarted = pFunctSignal;
  259. monitoredNode->functSignalObjectHbStarted = object;
  260. }
  261. /******************************************************************************/
  262. void CO_HBconsumer_initCallbackTimeout(
  263. CO_HBconsumer_t *HBcons,
  264. uint8_t idx,
  265. void *object,
  266. void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object))
  267. {
  268. CO_HBconsNode_t *monitoredNode;
  269. if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) {
  270. return;
  271. }
  272. monitoredNode = &HBcons->monitoredNodes[idx];
  273. monitoredNode->pFunctSignalTimeout = pFunctSignal;
  274. monitoredNode->functSignalObjectTimeout = object;
  275. }
  276. /******************************************************************************/
  277. void CO_HBconsumer_initCallbackRemoteReset(
  278. CO_HBconsumer_t *HBcons,
  279. uint8_t idx,
  280. void *object,
  281. void (*pFunctSignal)(uint8_t nodeId, uint8_t idx, void *object))
  282. {
  283. CO_HBconsNode_t *monitoredNode;
  284. if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) {
  285. return;
  286. }
  287. monitoredNode = &HBcons->monitoredNodes[idx];
  288. monitoredNode->pFunctSignalRemoteReset = pFunctSignal;
  289. monitoredNode->functSignalObjectRemoteReset = object;
  290. }
  291. #endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI */
  292. /******************************************************************************/
  293. void CO_HBconsumer_process(
  294. CO_HBconsumer_t *HBcons,
  295. bool_t NMTisPreOrOperational,
  296. uint32_t timeDifference_us,
  297. uint32_t *timerNext_us)
  298. {
  299. (void)timerNext_us; /* may be unused */
  300. bool_t allMonitoredActiveCurrent = true;
  301. uint8_t allMonitoredOperationalCurrent = CO_NMT_OPERATIONAL;
  302. if (NMTisPreOrOperational && HBcons->NMTisPreOrOperationalPrev) {
  303. for (uint8_t i=0; i<HBcons->numberOfMonitoredNodes; i++) {
  304. uint32_t timeDifference_us_copy = timeDifference_us;
  305. CO_HBconsNode_t * const monitoredNode = &HBcons->monitoredNodes[i];
  306. if (monitoredNode->HBstate == CO_HBconsumer_UNCONFIGURED) {
  307. /* continue, if node is not monitored */
  308. continue;
  309. }
  310. /* Verify if received message is heartbeat or bootup */
  311. if (CO_FLAG_READ(monitoredNode->CANrxNew)) {
  312. if (monitoredNode->NMTstate == CO_NMT_INITIALIZING) {
  313. /* bootup message*/
  314. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI
  315. if (monitoredNode->pFunctSignalRemoteReset != NULL) {
  316. monitoredNode->pFunctSignalRemoteReset(
  317. monitoredNode->nodeId, i,
  318. monitoredNode->functSignalObjectRemoteReset);
  319. }
  320. #endif
  321. if (monitoredNode->HBstate == CO_HBconsumer_ACTIVE) {
  322. CO_errorReport(HBcons->em,
  323. CO_EM_HB_CONSUMER_REMOTE_RESET,
  324. CO_EMC_HEARTBEAT, i);
  325. }
  326. monitoredNode->HBstate = CO_HBconsumer_UNKNOWN;
  327. }
  328. else {
  329. /* heartbeat message */
  330. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI
  331. if (monitoredNode->HBstate != CO_HBconsumer_ACTIVE &&
  332. monitoredNode->pFunctSignalHbStarted != NULL) {
  333. monitoredNode->pFunctSignalHbStarted(
  334. monitoredNode->nodeId, i,
  335. monitoredNode->functSignalObjectHbStarted);
  336. }
  337. #endif
  338. monitoredNode->HBstate = CO_HBconsumer_ACTIVE;
  339. /* reset timer */
  340. monitoredNode->timeoutTimer = 0;
  341. timeDifference_us_copy = 0;
  342. }
  343. CO_FLAG_CLEAR(monitoredNode->CANrxNew);
  344. }
  345. /* Verify timeout */
  346. if (monitoredNode->HBstate == CO_HBconsumer_ACTIVE) {
  347. monitoredNode->timeoutTimer += timeDifference_us_copy;
  348. if (monitoredNode->timeoutTimer >= monitoredNode->time_us) {
  349. /* timeout expired */
  350. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI
  351. if (monitoredNode->pFunctSignalTimeout!=NULL) {
  352. monitoredNode->pFunctSignalTimeout(
  353. monitoredNode->nodeId, i,
  354. monitoredNode->functSignalObjectTimeout);
  355. }
  356. #endif
  357. CO_errorReport(HBcons->em, CO_EM_HEARTBEAT_CONSUMER,
  358. CO_EMC_HEARTBEAT, i);
  359. monitoredNode->NMTstate = CO_NMT_UNKNOWN;
  360. monitoredNode->HBstate = CO_HBconsumer_TIMEOUT;
  361. }
  362. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_FLAG_TIMERNEXT
  363. else if (timerNext_us != NULL) {
  364. /* Calculate timerNext_us for next timeout checking. */
  365. uint32_t diff = monitoredNode->time_us
  366. - monitoredNode->timeoutTimer;
  367. if (*timerNext_us > diff) {
  368. *timerNext_us = diff;
  369. }
  370. }
  371. #endif
  372. }
  373. if (monitoredNode->HBstate != CO_HBconsumer_ACTIVE) {
  374. allMonitoredActiveCurrent = false;
  375. }
  376. if (monitoredNode->NMTstate != CO_NMT_OPERATIONAL) {
  377. allMonitoredOperationalCurrent = CO_NMT_UNKNOWN;
  378. }
  379. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \
  380. || (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI
  381. /* Verify, if NMT state of monitored node changed */
  382. if (monitoredNode->NMTstate != monitoredNode->NMTstatePrev) {
  383. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE
  384. if (HBcons->pFunctSignalNmtChanged != NULL) {
  385. HBcons->pFunctSignalNmtChanged(
  386. monitoredNode->nodeId, i, monitoredNode->NMTstate,
  387. HBcons->pFunctSignalObjectNmtChanged);
  388. #else
  389. if (monitoredNode->pFunctSignalNmtChanged != NULL) {
  390. monitoredNode->pFunctSignalNmtChanged(
  391. monitoredNode->nodeId, i, monitoredNode->NMTstate,
  392. monitoredNode->pFunctSignalObjectNmtChanged);
  393. #endif
  394. }
  395. monitoredNode->NMTstatePrev = monitoredNode->NMTstate;
  396. }
  397. #endif
  398. }
  399. }
  400. else if (NMTisPreOrOperational || HBcons->NMTisPreOrOperationalPrev) {
  401. /* (pre)operational state changed, clear variables */
  402. for(uint8_t i=0; i<HBcons->numberOfMonitoredNodes; i++) {
  403. CO_HBconsNode_t * const monitoredNode = &HBcons->monitoredNodes[i];
  404. monitoredNode->NMTstate = CO_NMT_UNKNOWN;
  405. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_CHANGE \
  406. || (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_CALLBACK_MULTI
  407. monitoredNode->NMTstatePrev = CO_NMT_UNKNOWN;
  408. #endif
  409. CO_FLAG_CLEAR(monitoredNode->CANrxNew);
  410. if (monitoredNode->HBstate != CO_HBconsumer_UNCONFIGURED) {
  411. monitoredNode->HBstate = CO_HBconsumer_UNKNOWN;
  412. }
  413. }
  414. allMonitoredActiveCurrent = false;
  415. allMonitoredOperationalCurrent = CO_NMT_UNKNOWN;
  416. }
  417. /* Clear emergencies when all monitored nodes becomes active.
  418. * We only have one emergency index for all monitored nodes! */
  419. if (!HBcons->allMonitoredActive && allMonitoredActiveCurrent) {
  420. CO_errorReset(HBcons->em, CO_EM_HEARTBEAT_CONSUMER, 0);
  421. CO_errorReset(HBcons->em, CO_EM_HB_CONSUMER_REMOTE_RESET, 0);
  422. }
  423. HBcons->allMonitoredActive = allMonitoredActiveCurrent;
  424. HBcons->allMonitoredOperational = allMonitoredOperationalCurrent;
  425. HBcons->NMTisPreOrOperationalPrev = NMTisPreOrOperational;
  426. }
  427. #if (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT
  428. /******************************************************************************/
  429. int8_t CO_HBconsumer_getIdxByNodeId(
  430. CO_HBconsumer_t *HBcons,
  431. uint8_t nodeId)
  432. {
  433. uint8_t i;
  434. CO_HBconsNode_t *monitoredNode;
  435. if (HBcons == NULL) {
  436. return -1;
  437. }
  438. /* linear search for the node */
  439. monitoredNode = &HBcons->monitoredNodes[0];
  440. for(i=0; i<HBcons->numberOfMonitoredNodes; i++){
  441. if (monitoredNode->nodeId == nodeId) {
  442. return i;
  443. }
  444. monitoredNode ++;
  445. }
  446. /* not found */
  447. return -1;
  448. }
  449. /******************************************************************************/
  450. CO_HBconsumer_state_t CO_HBconsumer_getState(
  451. CO_HBconsumer_t *HBcons,
  452. uint8_t idx)
  453. {
  454. CO_HBconsNode_t *monitoredNode;
  455. if (HBcons==NULL || idx>=HBcons->numberOfMonitoredNodes) {
  456. return CO_HBconsumer_UNCONFIGURED;
  457. }
  458. monitoredNode = &HBcons->monitoredNodes[idx];
  459. return monitoredNode->HBstate;
  460. }
  461. /******************************************************************************/
  462. int8_t CO_HBconsumer_getNmtState(
  463. CO_HBconsumer_t *HBcons,
  464. uint8_t idx,
  465. CO_NMT_internalState_t *nmtState)
  466. {
  467. CO_HBconsNode_t *monitoredNode;
  468. if (HBcons==NULL || nmtState==NULL || idx>=HBcons->numberOfMonitoredNodes) {
  469. return -1;
  470. }
  471. *nmtState = CO_NMT_INITIALIZING;
  472. monitoredNode = &HBcons->monitoredNodes[idx];
  473. if (monitoredNode->HBstate == CO_HBconsumer_ACTIVE) {
  474. *nmtState = monitoredNode->NMTstate;
  475. return 0;
  476. }
  477. return -1;
  478. }
  479. #endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_QUERY_FUNCT */
  480. #endif /* (CO_CONFIG_HB_CONS) & CO_CONFIG_HB_CONS_ENABLE */