From f4fbac12542b8b7456456a8450931d39ba435611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hubert=20Mi=C5=9B?= Date: Wed, 12 Jul 2017 20:22:05 +0200 Subject: [PATCH] [radio] delayed transmission support (#1976) * [radio] Add call from radio to MAC layer to indicate transmission start. This call is used to start ACK timer. When transmission requested by the MAC layer is delayed by the radio layer (e.g. due to BLE activity) ACK timer should not be started when MAC requests transmission but when tranmission is started. This commit provides required functions. * [nRF52840] Queue transmission in radio platform to allow delayed transmission after BLE activity. * Add note that otPlatRadioTxStarted() should be called by main OpenThread thread. --- examples/platforms/cc2538/radio.c | 2 ++ examples/platforms/cc2650/radio.c | 2 ++ examples/platforms/da15000/radio.c | 2 ++ examples/platforms/efr32/radio.c | 2 ++ examples/platforms/emsk/radio.c | 3 ++- examples/platforms/kw41z/radio.c | 4 ++-- examples/platforms/nrf52840/radio.c | 20 +++++++++++++++++++- examples/platforms/posix/radio.c | 1 + include/openthread/platform/radio.h | 12 ++++++++++++ src/core/mac/mac.cpp | 26 ++++++++++++++++++++------ src/core/mac/mac.hpp | 7 +++++++ tests/unit/test_diag.cpp | 5 +++++ 12 files changed, 76 insertions(+), 10 deletions(-) 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