diff --git a/examples/platforms/cc2538/radio.c b/examples/platforms/cc2538/radio.c index d203f1656..70293b4f5 100644 --- a/examples/platforms/cc2538/radio.c +++ b/examples/platforms/cc2538/radio.c @@ -369,6 +369,8 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) // begin transmit HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_TXON; + otPlatRadioTxStarted(aInstance, aFrame); + while (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE); otLogDebgPlat(sInstance, "Transmitted %d bytes", aFrame->mLength); diff --git a/examples/platforms/cc2650/radio.c b/examples/platforms/cc2650/radio.c index 7ac31b654..cec51aad5 100644 --- a/examples/platforms/cc2650/radio.c +++ b/examples/platforms/cc2650/radio.c @@ -1353,6 +1353,8 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) otEXPECT_ACTION(rfCoreSendTransmitCmd(aFrame->mPsdu, aFrame->mLength - 2) == CMDSTA_Done, error = OT_ERROR_FAILED); error = OT_ERROR_NONE; + + otPlatRadioTxStarted(aInstance, aFrame); } } diff --git a/examples/platforms/da15000/radio.c b/examples/platforms/da15000/radio.c index cf4acafed..9365fb954 100644 --- a/examples/platforms/da15000/radio.c +++ b/examples/platforms/da15000/radio.c @@ -411,6 +411,8 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) ad_ftdf_send_frame_simple(aFrame->mLength, aFrame->mPsdu, aFrame->mChannel, 0, csmaSuppress); //Prio 0 for all. sRadioState = OT_RADIO_STATE_TRANSMIT; + otPlatRadioTxStarted(aInstance, aFrame); + exit: return error; } diff --git a/examples/platforms/efr32/radio.c b/examples/platforms/efr32/radio.c index 5e82f856c..7a598d6c3 100644 --- a/examples/platforms/efr32/radio.c +++ b/examples/platforms/efr32/radio.c @@ -345,6 +345,8 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) otEXPECT_ACTION(RAIL_TxStartWithOptions(aFrame->mChannel, &txOption, RAIL_CcaCsma, &csmaConfig) == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED); + otPlatRadioTxStarted(aInstance, aFrame); + exit: CORE_EXIT_CRITICAL(); return error; diff --git a/examples/platforms/emsk/radio.c b/examples/platforms/emsk/radio.c index 18b775b26..14681deb2 100644 --- a/examples/platforms/emsk/radio.c +++ b/examples/platforms/emsk/radio.c @@ -473,7 +473,6 @@ exit: void radioTransmitMessage(otInstance *aInstance) { - (void)aInstance; uint8_t header_len = 0; sTransmitError = OT_ERROR_NONE; @@ -506,6 +505,8 @@ void radioTransmitMessage(otInstance *aInstance) mrf24j40_write_short_ctrl_reg(MRF24J40_TXNCON, reg | MRF24J40_TXNTRIG); + otPlatRadioTxStarted(aInstance, &sTransmitFrame); + int16_t tx_timeout = 500; Mrf24StatusTx = 0; diff --git a/examples/platforms/kw41z/radio.c b/examples/platforms/kw41z/radio.c index 0ca156303..a0bc0ab0c 100644 --- a/examples/platforms/kw41z/radio.c +++ b/examples/platforms/kw41z/radio.c @@ -335,8 +335,6 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) otError status = OT_ERROR_NONE; uint32_t timeout; - (void) aInstance; - otEXPECT_ACTION(((sState != OT_RADIO_STATE_TRANSMIT) && (sState != OT_RADIO_STATE_DISABLED)), status = OT_ERROR_INVALID_STATE); @@ -379,6 +377,8 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) /* Unmask SEQ interrupt */ ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_SEQMSK_MASK; + otPlatRadioTxStarted(aInstance, aFrame); + exit: return status; } diff --git a/examples/platforms/nrf52840/radio.c b/examples/platforms/nrf52840/radio.c index e531399b7..f71918291 100644 --- a/examples/platforms/nrf52840/radio.c +++ b/examples/platforms/nrf52840/radio.c @@ -92,6 +92,7 @@ static int8_t sEnergyDetected; typedef enum { kPendingEventSleep, // Requested to enter Sleep state. + kPendingEventTransmit, // Frame is queued for transmission. kPendingEventFrameTransmitted, // Transmitted frame and received ACK (if requested). kPendingEventChannelAccessFailure, // Failed to transmit frame (channel busy). kPendingEventEnergyDetectionStart, // Requested to start Energy Detection procedure. @@ -327,11 +328,12 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) if (nrf_drv_radio802154_transmit(&aFrame->mPsdu[-1], aFrame->mChannel, aFrame->mPower, true)) { clearPendingEvents(); + otPlatRadioTxStarted(aInstance, aFrame); } else { clearPendingEvents(); - setPendingEvent(kPendingEventChannelAccessFailure); + setPendingEvent(kPendingEventTransmit); } return OT_ERROR_NONE; @@ -523,6 +525,15 @@ void nrf5RadioProcess(otInstance *aInstance) } } + if (isPendingEventSet(kPendingEventTransmit)) + { + if (nrf_drv_radio802154_transmit(sTransmitPsdu, sTransmitFrame.mChannel, sTransmitFrame.mPower, true)) + { + resetPendingEvent(kPendingEventTransmit); + otPlatRadioTxStarted(aInstance, &sTransmitFrame); + } + } + if (isPendingEventSet(kPendingEventFrameTransmitted)) { #if OPENTHREAD_ENABLE_DIAG @@ -592,6 +603,13 @@ void nrf_drv_radio802154_received(uint8_t *p_data, int8_t power, int8_t lqi) { otRadioFrame *receivedFrame = NULL; + if (isPendingEventSet(kPendingEventTransmit)) + { + nrf_drv_radio802154_buffer_free(p_data); + + return; + } + for (uint32_t i = 0; i < RADIO_RX_BUFFERS; i++) { if (sReceivedFrames[i].mPsdu == NULL) diff --git a/examples/platforms/posix/radio.c b/examples/platforms/posix/radio.c index e47d17c2a..1b314861b 100644 --- a/examples/platforms/posix/radio.c +++ b/examples/platforms/posix/radio.c @@ -508,6 +508,7 @@ void radioSendMessage(otInstance *aInstance) { sTransmitMessage.mChannel = sTransmitFrame.mChannel; + otPlatRadioTxStarted(aInstance, &sTransmitFrame); radioTransmit(&sTransmitMessage, &sTransmitFrame); sAckWait = isAckRequested(sTransmitFrame.mPsdu); diff --git a/include/openthread/platform/radio.h b/include/openthread/platform/radio.h index b81cd64bc..01eb57f6f 100644 --- a/include/openthread/platform/radio.h +++ b/include/openthread/platform/radio.h @@ -388,6 +388,18 @@ otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance); */ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame); +/** + * The radio driver calls this method to notify OpenThread that the transmission has started. + * + * @note This function should be called by the same thread that executes all of the other OpenThread code. It should + * not be called by ISR or any other task. + * + * @param[in] aInstance A pointer to the OpenThread instance structure. + * @param[in] aFrame A pointer to the frame that is being transmitted. + * + */ +extern void otPlatRadioTxStarted(otInstance *aInstance, otRadioFrame *aFrame); + /** * The radio driver calls this method to notify OpenThread that the transmission has completed, * this callback pass up the ACK frame, new add platforms should use this callback function. diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index 131fbf807..384cc2acc 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -832,12 +832,6 @@ void Mac::HandleBeginTransmit(void) assert(error == OT_ERROR_NONE); - if (sendFrame.GetAckRequest() && !(otPlatRadioGetCaps(GetInstance()) & OT_RADIO_CAPS_ACK_TIMEOUT)) - { - mMacTimer.Start(kAckTimeout); - otLogDebgMac(GetInstance(), "Ack timer start"); - } - if (mPcapCallback) { sendFrame.mDidTX = true; @@ -856,6 +850,26 @@ exit: } } +extern "C" void otPlatRadioTxStarted(otInstance *aInstance, otRadioFrame *aFrame) +{ + otLogFuncEntry(); + + aInstance->mThreadNetif.GetMac().TransmitStartedTask(aFrame); + + otLogFuncExit(); +} + +void Mac::TransmitStartedTask(otRadioFrame *aFrame) +{ + Frame *frame = static_cast(aFrame); + + if (frame->GetAckRequest() && !(otPlatRadioGetCaps(GetInstance()) & OT_RADIO_CAPS_ACK_TIMEOUT)) + { + mMacTimer.Start(kAckTimeout); + otLogDebgMac(GetInstance(), "Ack timer start"); + } +} + #if OPENTHREAD_CONFIG_LEGACY_TRANSMIT_DONE extern "C" void otPlatRadioTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, bool aRxPending, otError aError) diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 90a233413..21caf3d8f 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -501,6 +501,13 @@ public: */ void ReceiveDoneTask(Frame *aFrame, otError aError); + /** + * This method is called to handle transmission start events. + * + * @param[in] aFrame A pointer to the frame that is transmitted. + */ + void TransmitStartedTask(otRadioFrame *aFrame); + #if OPENTHREAD_CONFIG_LEGACY_TRANSMIT_DONE /** * This method is called to handle transmit events. diff --git a/tests/unit/test_diag.cpp b/tests/unit/test_diag.cpp index e881bc946..45cb14576 100644 --- a/tests/unit/test_diag.cpp +++ b/tests/unit/test_diag.cpp @@ -70,6 +70,11 @@ extern "C" void otPlatRadioReceiveDone(otInstance *, otRadioFrame *aFrame, otErr (void)aError; } +extern "C" void otPlatRadioTxStarted(otInstance *, otRadioFrame *aFrame) +{ + (void) aFrame; +} + /** * diagnostics module tests