diff --git a/301/CO_PDO.c b/301/CO_PDO.c index 70596fa..4527d77 100644 --- a/301/CO_PDO.c +++ b/301/CO_PDO.c @@ -741,7 +741,7 @@ CO_RPDO_initCallbackPre(CO_RPDO_t* RPDO, void* object, void (*pFunctSignalPre)(v void CO_RPDO_process(CO_RPDO_t* RPDO, #if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 - uint32_t timeDifference_us, uint32_t* timerNext_us, + uint32_t timeDifference_us, bool_t* timeoutState, uint32_t* timerNext_us, #endif bool_t NMTisOperational, bool_t syncWas) { (void)syncWas; @@ -890,11 +890,6 @@ CO_RPDO_process(CO_RPDO_t* RPDO, #if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 if (RPDO->timeoutTime_us > 0U) { if (rpdoReceived) { - /* Do NOT call CO_errorReset here. CO_EM_RPDO_TIME_OUT is a - * single shared bit for all RPDOs. Resetting it when one RPDO - * recovers would clear the error even if other RPDOs are still - * timed out. The reset is handled in CO_process_RPDO() after - * all RPDOs are processed, only when none remain in timeout. */ /* enable monitoring */ RPDO->timeoutTimer = 1; } else if ((RPDO->timeoutTimer > 0U) && (RPDO->timeoutTimer < RPDO->timeoutTime_us)) { @@ -905,6 +900,11 @@ CO_RPDO_process(CO_RPDO_t* RPDO, } } else { /* MISRA C 2004 14.10 */ } + if ((timeoutState != NULL) && RPDO->timeoutTimer > RPDO->timeoutTime_us) { + /* This output variable indicates that the RPDO has timed out. It can be used across all + * RPDOs to determine if any have timed out. If it remains false, CO_errorReset can be called. */ + *timeoutState = true; + } #if ((CO_CONFIG_PDO)&CO_CONFIG_FLAG_TIMERNEXT) != 0 if ((timerNext_us != NULL) && (RPDO->timeoutTimer < RPDO->timeoutTime_us)) { uint32_t diff = RPDO->timeoutTime_us - RPDO->timeoutTimer; diff --git a/301/CO_PDO.h b/301/CO_PDO.h index 339bda0..e772ef4 100644 --- a/301/CO_PDO.h +++ b/301/CO_PDO.h @@ -278,13 +278,16 @@ void CO_RPDO_initCallbackPre(CO_RPDO_t* RPDO, void* object, void (*pFunctSignalP * * @param RPDO This object. * @param timeDifference_us Time difference from previous function call. + * @param [out] timeoutState Pointer to a boolean variable that will be set to true if a RPDO has timed out. + * It can be used across all RPDOs to determine if any have timed out. If it remains false, CO_errorReset should be + * called. Can be NULL if not needed. * @param [out] timerNext_us info to OS - see CO_process(). * @param NMTisOperational True if this node is in NMT_OPERATIONAL state. * @param syncWas True, if CANopen SYNC message was just received or transmitted. */ void CO_RPDO_process(CO_RPDO_t* RPDO, #if (((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0) || defined CO_DOXYGEN - uint32_t timeDifference_us, uint32_t* timerNext_us, + uint32_t timeDifference_us, bool_t* timeoutState, uint32_t* timerNext_us, #endif bool_t NMTisOperational, bool_t syncWas); #endif /* (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE */ diff --git a/CANopen.c b/CANopen.c index a00620b..aa541ab 100644 --- a/CANopen.c +++ b/CANopen.c @@ -1439,11 +1439,14 @@ CO_process_RPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* } bool_t NMTisOperational = CO_NMT_getInternalState(co->NMT) == CO_NMT_OPERATIONAL; +#if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 + bool_t anyTimeout = false; +#endif for (uint16_t i = 0; i < CO_GET_CNT(RPDO); i++) { CO_RPDO_process(&co->RPDO[i], #if ((CO_CONFIG_PDO)&CO_CONFIG_RPDO_TIMERS_ENABLE) != 0 - timeDifference_us, timerNext_us, + timeDifference_us, &anyTimeout, timerNext_us, #endif NMTisOperational, syncWas); } @@ -1452,14 +1455,6 @@ CO_process_RPDO(CO_t* co, bool_t syncWas, uint32_t timeDifference_us, uint32_t* /* CO_EM_RPDO_TIME_OUT is a single shared bit for all RPDOs. Only reset it * after processing all RPDOs, and only when none remain in timeout. * CO_errorReset() is a no-op when the error bit is already clear. */ - bool_t anyTimeout = false; - for (uint16_t i = 0; i < CO_GET_CNT(RPDO); i++) { - CO_RPDO_t* rpdo = &co->RPDO[i]; - if (rpdo->timeoutTime_us > 0U && rpdo->timeoutTimer > rpdo->timeoutTime_us) { - anyTimeout = true; - break; - } - } if (!anyTimeout) { CO_errorReset(co->em, CO_EM_RPDO_TIME_OUT, 0); }