From 6e8aef964470ac1c96fd3e36457aba5d0efe4949 Mon Sep 17 00:00:00 2001 From: Seth Rickard Date: Wed, 9 Aug 2017 11:02:49 -0700 Subject: [PATCH] [cc2652] refactored polling loop and propagated ack frames (#2080) Updated cc2650 and cc2652 platforms to place ieee ack frame types in the RX queue and to propagate those frames to the higher level. Initialize extra RX buffers. --- examples/platforms/cc2650/cc2650_radio.h | 28 +- examples/platforms/cc2650/radio.c | 510 +++++++++++------------ examples/platforms/cc2652/cc2652_radio.h | 28 +- examples/platforms/cc2652/radio.c | 210 +++++----- 4 files changed, 385 insertions(+), 391 deletions(-) diff --git a/examples/platforms/cc2650/cc2650_radio.h b/examples/platforms/cc2650/cc2650_radio.h index 6c28af760..fd8d69f29 100644 --- a/examples/platforms/cc2650/cc2650_radio.h +++ b/examples/platforms/cc2650/cc2650_radio.h @@ -35,7 +35,6 @@ enum { IEEE802154_FRAME_TYPE_MASK = 0x7, ///< (IEEE 802.15.4-2006) PSDU.FCF.frameType IEEE802154_FRAME_TYPE_ACK = 0x2, ///< (IEEE 802.15.4-2006) frame type: ACK - IEEE802154_FRAME_PENDING = (1<<4), ///< (IEEE 802.15.4-2006) PSDU.FCF.bFramePending IEEE802154_ACK_REQUEST = (1<<5), ///< (IEEE 802.15.4-2006) PSDU.FCF.bAR IEEE802154_DSN_OFFSET = 2, ///< (IEEE 802.15.4-2006) PSDU.sequenceNumber IEEE802154_MAC_MIN_BE = 1, ///< (IEEE 802.15.4-2006) macMinBE @@ -155,19 +154,19 @@ typedef enum cc2650_address * The following are valid radio state transitions for the cc2650: * * (Radio ON) - * +----------+ Enable() +-------+ Receive() +---------+ Transmit() +----------+ - * | |----------->| |------------->| |-------------->| | - * | Disabled | | Sleep | | Receive | | Transmit | - * | |<-----------| |<-------------| |<--------------| | - * +----------+ Disable() | | Sleep() | |<-- Receive() +----------+ - * | | (Radio OFF) +---------+ \ | transmit - * | | \-----\ | complete - * | | EnergyScan() +--------+ | V - * | |------------->| | +------------------+ - * | | | EdScan | | | - * | |<-------------| | | TransmitComplete | - * | | signal ED | | | | - * +-------+ scan done +--------+ +------------------+ + * +----------+ Enable() +-------+ Receive() +---------+ Transmit() +----------+ + * | |----------->| |------------->| |--------------->| | + * | Disabled | | Sleep | | Receive | | Transmit | + * | |<-----------| |<-------------| |<---------------| | + * +----------+ Disable() | | Sleep() | | AckFrame RX or +----------+ + * | | (Radio OFF) +---------+ sTxCmdChainDone == true + * | | + * | | EnergyScan() +--------+ + * | |------------->| | + * | | | EdScan | + * | |<-------------| | + * | | signal ED | | + * +-------+ scan done +--------+ * * These states slightly differ from the states in \ref include/platform/radio.h. * The additional states the phy can be in are due to the asynchronous nature @@ -192,7 +191,6 @@ typedef enum cc2650_PhyState cc2650_stateReceive, cc2650_stateEdScan, cc2650_stateTransmit, - cc2650_stateTransmitComplete, } cc2650_PhyState; #endif /* CC2650_RADIO_H_ */ diff --git a/examples/platforms/cc2650/radio.c b/examples/platforms/cc2650/radio.c index 5d51004f3..6a8c1b29a 100644 --- a/examples/platforms/cc2650/radio.c +++ b/examples/platforms/cc2650/radio.c @@ -51,7 +51,6 @@ enum { - IEEE802154_ACK_LENGTH = 5, CC2650_RECEIVE_SENSITIVITY = -100, // dBm }; @@ -77,55 +76,50 @@ static uint32_t sIEEEOverrides[] = }; /* - * status of the pending bit of the last ack packet found by the - * sTransmitRxAckCmd radio command + * Number of retry counts left to the currently transmitting frame. * - * used to pass data from the radio state ISR to the processing loop - */ -static volatile bool sReceivedAckPendingBit = false; - -/* - * number of retry counts left to the currently transmitting frame - * - * initialized when a frame is passed to be sent over the air, and decremented + * Initialized when a frame is passed to be sent over the air, and decremented * by the radio ISR every time the transmit command string fails to receive a - * corresponding ack + * corresponding ack. */ static volatile unsigned int sTransmitRetryCount = 0; /* - * offset of the radio timer from the rtc + * Offset of the radio timer from the rtc. * - * used when we start and stop the RAT + * Used when we start and stop the RAT on enabling and disabling of the rf + * core. */ static uint32_t sRatOffset = 0; /* - * radio command structures that run on the CM0 + * Radio command structures that run on the CM0. */ -static volatile rfc_CMD_SYNC_START_RAT_t sStartRatCmd; -static volatile rfc_CMD_RADIO_SETUP_t sRadioSetupCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_SYNC_START_RAT_t sStartRatCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_RADIO_SETUP_t sRadioSetupCmd; -static volatile rfc_CMD_FS_POWERDOWN_t sFsPowerdownCmd; -static volatile rfc_CMD_SYNC_STOP_RAT_t sStopRatCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_FS_POWERDOWN_t sFsPowerdownCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_SYNC_STOP_RAT_t sStopRatCmd; -static volatile rfc_CMD_CLEAR_RX_t sClearReceiveQueueCmd; -static volatile rfc_CMD_IEEE_MOD_FILT_t sModifyReceiveFilterCmd; -static volatile rfc_CMD_IEEE_MOD_SRC_MATCH_t sModifyReceiveSrcMatchCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_CLEAR_RX_t sClearReceiveQueueCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_IEEE_MOD_FILT_t sModifyReceiveFilterCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_IEEE_MOD_SRC_MATCH_t sModifyReceiveSrcMatchCmd; -static volatile rfc_CMD_IEEE_ED_SCAN_t sEdScanCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_IEEE_ED_SCAN_t sEdScanCmd; -static volatile rfc_CMD_IEEE_RX_t sReceiveCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_IEEE_RX_t sReceiveCmd; -static volatile rfc_CMD_IEEE_CSMA_t sCsmacaBackoffCmd; -static volatile rfc_CMD_IEEE_TX_t sTransmitCmd; -static volatile rfc_CMD_IEEE_RX_ACK_t sTransmitRxAckCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_IEEE_CSMA_t sCsmacaBackoffCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_IEEE_TX_t sTransmitCmd; +static volatile __attribute__((aligned(4))) rfc_CMD_IEEE_RX_ACK_t sTransmitRxAckCmd; -static volatile ext_src_match_data_t sSrcMatchExtData; -static volatile short_src_match_data_t sSrcMatchShortData; +static volatile __attribute__((aligned(4))) ext_src_match_data_t sSrcMatchExtData; +static volatile __attribute__((aligned(4))) short_src_match_data_t sSrcMatchShortData; -/* struct containing radio stats */ -static rfc_ieeeRxOutput_t sRfStats; +/* + * Structure containing radio statistics. + */ +static __attribute__((aligned(4))) rfc_ieeeRxOutput_t sRfStats; #define RX_BUF_SIZE 144 /* two receive buffers entries with room for 1 max IEEE802.15.4 frame in each */ @@ -137,21 +131,20 @@ static dataQueue_t sRxDataQueue = { 0 }; /* openthread data primatives */ static otRadioFrame sTransmitFrame; -static otRadioFrame sReceiveFrame; static otError sTransmitError; -static otError sReceiveError; -static uint8_t sTransmitPsdu[OT_RADIO_FRAME_MAX_SIZE] __attribute__((aligned(4))) ; -static uint8_t sReceivePsdu[OT_RADIO_FRAME_MAX_SIZE] __attribute__((aligned(4))) ; +static __attribute__((aligned(4))) uint8_t sTransmitPsdu[OT_RADIO_FRAME_MAX_SIZE]; -/** - * Interrupt handlers forward declared for register function +static volatile bool sTxCmdChainDone = false; + +/* + * Interrupt handlers forward declared for register functions. */ void RFCCPE0IntHandler(void); void RFCCPE1IntHandler(void); /** - * @brief initialize the RX/TX buffers + * Initialize the RX/TX buffers. * * Zeros out the receive and transmit buffers and sets up the data structures * of the receive queue. @@ -162,24 +155,22 @@ static void rfCoreInitBufs(void) memset(sRxBuf0, 0x00, RX_BUF_SIZE); memset(sRxBuf1, 0x00, RX_BUF_SIZE); - entry = (rfc_dataEntry_t *)sRxBuf0; - entry->pNextEntry = sRxBuf1; + entry = (rfc_dataEntry_t *)sRxBuf0; + entry->pNextEntry = sRxBuf1; entry->config.lenSz = DATA_ENTRY_LENSZ_BYTE; - entry->length = sizeof(sRxBuf0) - sizeof(rfc_dataEntry_t); + entry->length = sizeof(sRxBuf0) - sizeof(rfc_dataEntry_t); - entry = (rfc_dataEntry_t *)sRxBuf1; - entry->pNextEntry = sRxBuf0; + entry = (rfc_dataEntry_t *)sRxBuf1; + entry->pNextEntry = sRxBuf0; entry->config.lenSz = DATA_ENTRY_LENSZ_BYTE; - entry->length = sizeof(sRxBuf0) - sizeof(rfc_dataEntry_t); + entry->length = sizeof(sRxBuf1) - sizeof(rfc_dataEntry_t); - sTransmitFrame.mPsdu = sTransmitPsdu; + sTransmitFrame.mPsdu = sTransmitPsdu; sTransmitFrame.mLength = 0; - sReceiveFrame.mPsdu = sReceivePsdu; - sReceiveFrame.mLength = 0; } /** - * @brief initialize the RX command structure + * Initialize the RX command structure. * * Sets the default values for the receive command structure. */ @@ -227,7 +218,7 @@ static void rfCoreInitReceiveParams(void) { .bAcceptFt0Beacon = 1, .bAcceptFt1Data = 1, - .bAcceptFt2Ack = 0, + .bAcceptFt2Ack = 1, .bAcceptFt3MacCmd = 1, .bAcceptFt4Reserved = 1, .bAcceptFt5Reserved = 1, @@ -263,10 +254,10 @@ static void rfCoreInitReceiveParams(void) } /** - * @brief sends the direct abort command to the radio core + * Sends the direct abort command to the radio core. * - * @return the value from the command status register - * @retval CMDSTA_Done the command completed correctly + * @return The value from the command status register. + * @retval CMDSTA_Done The command completed correctly. */ static uint_fast8_t rfCoreExecuteAbortCmd(void) { @@ -274,12 +265,12 @@ static uint_fast8_t rfCoreExecuteAbortCmd(void) } /** - * @brief sends the direct ping command to the radio core + * Sends the direct ping command to the radio core. * * Check that the Radio core is alive and able to respond to commands. * - * @return the value from the command status register - * @retval CMDSTA_Done the command completed correctly + * @return The value from the command status register. + * @retval CMDSTA_Done The command completed correctly. */ static uint_fast8_t rfCoreExecutePingCmd(void) { @@ -287,16 +278,16 @@ static uint_fast8_t rfCoreExecutePingCmd(void) } /** - * @brief sends the immediate clear rx queue command to the radio core + * Sends the immediate clear rx queue command to the radio core. * * Uses the radio core to mark all of the entries in the receive queue as * pending. This is used instead of clearing the entries manually to avoid race * conditions between the main processor and the radio core. * - * @param [in] aQueue a pointer to the receive queue to be cleared + * @param [in] aQueue A pointer to the receive queue to be cleared. * - * @return the value from the command status register - * @retval CMDSTA_Done the command completed correctly + * @return The value from the command status register. + * @retval CMDSTA_Done The command completed correctly. */ static uint_fast8_t rfCoreClearReceiveQueue(dataQueue_t *aQueue) { @@ -308,7 +299,7 @@ static uint_fast8_t rfCoreClearReceiveQueue(dataQueue_t *aQueue) } /** - * @brief enable/disable filtering + * Enable/disable frame filtering. * * Uses the radio core to alter the current running RX command filtering * options. This ensures there is no access fault between the CM3 and CM0 for @@ -319,10 +310,11 @@ static uint_fast8_t rfCoreClearReceiveQueue(dataQueue_t *aQueue) * * @note An IEEE RX command *must* be running while this command executes. * - * @param [in] aEnable TRUE: enable frame filtering, FALSE: disable frame filtering + * @param [in] aEnable TRUE: enable frame filtering, + * FALSE: disable frame filtering. * - * @return the value from the command status register - * @retval CMDSTA_Done the command completed correctly + * @return The value from the command status register. + * @retval CMDSTA_Done The command completed correctly. */ static uint_fast8_t rfCoreModifyRxFrameFilter(bool aEnable) { @@ -340,7 +332,7 @@ static uint_fast8_t rfCoreModifyRxFrameFilter(bool aEnable) } /** - * @brief enable/disable autoPend + * Enable/disable autoPend feature. * * Uses the radio core to alter the current running RX command filtering * options. This ensures there is no access fault between the CM3 and CM0 for @@ -351,10 +343,11 @@ static uint_fast8_t rfCoreModifyRxFrameFilter(bool aEnable) * * @note An IEEE RX command *must* be running while this command executes. * - * @param [in] aEnable TRUE: enable autoPend, FALSE: disable autoPend + * @param [in] aEnable TRUE: enable autoPend, + * FALSE: disable autoPend. * - * @return the value from the command status register - * @retval CMDSTA_Done the command completed correctly + * @return The value from the command status register. + * @retval CMDSTA_Done The command completed correctly. */ static uint_fast8_t rfCoreModifyRxAutoPend(bool aEnable) { @@ -372,7 +365,7 @@ static uint_fast8_t rfCoreModifyRxAutoPend(bool aEnable) } /** - * @brief sends the immediate modify source matching command to the radio core + * Sends the immediate modify source matching command to the radio core. * * Uses the radio core to alter the current source matching parameters used by * the running RX command. This ensures there is no access fault between the @@ -382,12 +375,13 @@ static uint_fast8_t rfCoreModifyRxAutoPend(bool aEnable) * * @note An IEEE RX command *must* be running while this command executes. * - * @param [in] aEntryNo the index of the entry to alter - * @param [in] aType TRUE: the entry is a short address, FALSE: the entry is an extended address - * @param [in] aEnable whether the given entry is to be enabled or disabled + * @param [in] aEntryNo The index of the entry to alter. + * @param [in] aType TRUE: the entry is a short address, + * FALSE: the entry is an extended address. + * @param [in] aEnable Whether the given entry is to be enabled or disabled. * - * @return the value from the command status register - * @retval CMDSTA_Done the command completed correctly + * @return The value from the command status register. + * @retval CMDSTA_Done The command completed correctly. */ static uint_fast8_t rfCoreModifySourceMatchEntry(uint8_t aEntryNo, cc2650_address_t aType, bool aEnable) { @@ -420,105 +414,113 @@ static uint_fast8_t rfCoreModifySourceMatchEntry(uint8_t aEntryNo, cc2650_addres } /** - * @brief walks the short address source match list to find an address + * Walks the short address source match list to find an address. * - * @param [in] address the short address to search for + * @param [in] aAddress The short address to search for. * - * @return the index where the address was found - * @retval CC2650_SRC_MATCH_NONE the address was not found + * @return The index where the address was found. + * @retval CC2650_SRC_MATCH_NONE The address was not found. */ static uint8_t rfCoreFindShortSrcMatchIdx(const uint16_t aAddress) { uint8_t i; + uint8_t ret = CC2650_SRC_MATCH_NONE; for (i = 0; i < CC2650_SHORTADD_SRC_MATCH_NUM; i++) { if (sSrcMatchShortData.extAddrEnt[i].shortAddr == aAddress) { - return i; + ret = i; + break; } } - return CC2650_SRC_MATCH_NONE; + return ret; } /** - * @brief walks the short address source match list to find an empty slot + * Walks the short address source match list to find an empty slot. * - * @return the index of an unused address slot - * @retval CC2650_SRC_MATCH_NONE no unused slots available + * @return The index of an unused address slot. + * @retval CC2650_SRC_MATCH_NONE No unused slots available. */ static uint8_t rfCoreFindEmptyShortSrcMatchIdx(void) { uint8_t i; + uint8_t ret = CC2650_SRC_MATCH_NONE; for (i = 0; i < CC2650_SHORTADD_SRC_MATCH_NUM; i++) { if ((sSrcMatchShortData.srcMatchEn[i / 32] & (1 << (i % 32))) == 0u) { - return i; + ret = i; + break; } } - return CC2650_SRC_MATCH_NONE; + return ret; } /** - * @brief walks the ext address source match list to find an address + * Walks the extended address source match list to find an address. * - * @param [in] address the ext address to search for + * @param [in] aAddress The extended address to search for. * - * @return the index where the address was found - * @retval CC2650_SRC_MATCH_NONE the address was not found + * @return The index where the address was found. + * @retval CC2650_SRC_MATCH_NONE The address was not found. */ static uint8_t rfCoreFindExtSrcMatchIdx(const uint64_t *aAddress) { uint8_t i; + uint8_t ret = CC2650_SRC_MATCH_NONE; for (i = 0; i < CC2650_EXTADD_SRC_MATCH_NUM; i++) { if (sSrcMatchExtData.extAddrEnt[i] == *aAddress) { - return i; + ret = i; + break; } } - return CC2650_SRC_MATCH_NONE; + return ret; } /** - * @brief walks the ext address source match list to find an empty slot + * Walks the extended address source match list to find an empty slot. * - * @return the index of an unused address slot - * @retval CC2650_SRC_MATCH_NONE no unused slots available + * @return The index of an unused address slot. + * @retval CC2650_SRC_MATCH_NONE No unused slots available. */ static uint8_t rfCoreFindEmptyExtSrcMatchIdx(void) { uint8_t i; + uint8_t ret = CC2650_SRC_MATCH_NONE; for (i = 0; i < CC2650_EXTADD_SRC_MATCH_NUM; i++) { if ((sSrcMatchExtData.srcMatchEn[i / 32] & (1 << (i % 32))) != 0u) { - return i; + ret = i; + break; } } - return CC2650_SRC_MATCH_NONE; + return ret; } /** - * @brief sends the tx command to the radio core + * Sends the tx command to the radio core. * * Sends the packet to the radio core to be sent asynchronously. * - * @param [in] aPsdu a pointer to the data to be sent - * @note this *must* be 4 byte aligned and not include the FCS, that is - * calculated in hardware. - * @param [in] aLen the length in bytes of data pointed to by psdu. + * @note @ref aPsdu *must* be 4 byte aligned and not include the FCS. * - * @return the value from the command status register - * @retval CMDSTA_Done the command completed correctly + * @param [in] aPsdu A pointer to the data to be sent. + * @param [in] aLen The length in bytes of data pointed to by PSDU. + * + * @return The value from the command status register. + * @retval CMDSTA_Done The command completed correctly. */ static uint_fast8_t rfCoreSendTransmitCmd(uint8_t *aPsdu, uint8_t aLen) { @@ -612,7 +614,7 @@ static uint_fast8_t rfCoreSendTransmitCmd(uint8_t *aPsdu, uint8_t aLen) } /** - * @brief sends the rx command to the radio core + * Sends the rx command to the radio core. * * Sends the pre-built receive command to the radio core. This sets up the * radio to receive packets according to the settings in the global rx command. @@ -621,8 +623,8 @@ static uint_fast8_t rfCoreSendTransmitCmd(uint8_t *aPsdu, uint8_t aLen) * It is only concerned with sending the command to the radio core. See @ref * otPlatRadioSetPanId for an example of how the rx settings are set changed. * - * @return the value from the command status register - * @retval CMDSTA_Done the command completed correctly + * @return The value from the command status register. + * @retval CMDSTA_Done The command completed correctly. */ static uint_fast8_t rfCoreSendReceiveCmd(void) { @@ -669,7 +671,7 @@ static uint_fast8_t rfCoreSendEdScanCmd(uint8_t aChannel, uint16_t aDurration) } /** - * @brief enables the cpe0 and cpe1 radio interrupts + * Enables the cpe0 and cpe1 radio interrupts. * * Enables the @ref IRQ_LAST_COMMAND_DONE and @ref IRQ_LAST_FG_COMMAND_DONE to * be handled by the @ref RFCCPE0IntHandler interrupt handler. @@ -678,11 +680,7 @@ static void rfCoreSetupInt(void) { bool interruptsWereDisabled; - /* We are already turned on by the caller, so this should not happen */ - if (!PRCMRfReady()) - { - return; - } + otEXPECT(PRCMRfReady()); interruptsWereDisabled = IntMasterDisable(); @@ -701,10 +699,13 @@ static void rfCoreSetupInt(void) { IntMasterEnable(); } + +exit: + return; } /** - * @brief disables and clears the cpe0 and cpe1 radio interrupts + * Disables and clears the cpe0 and cpe1 radio interrupts. */ static void rfCoreStopInt(void) { @@ -730,7 +731,7 @@ static void rfCoreStopInt(void) } /** - * @brief Sets the mode for the radio core to IEEE 802.15.4 + * Sets the mode for the radio core to IEEE 802.15.4 */ static void rfCoreSetModeSelect(void) { @@ -752,7 +753,7 @@ static void rfCoreSetModeSelect(void) } /** - * @brief turns on the radio core + * Turns on the radio core. * * Sets up the power and resources for the radio core. * - switches the high frequency clock to the xosc crystal @@ -763,8 +764,8 @@ static void rfCoreSetModeSelect(void) * - sets up the interrupts * - sends the ping command to the radio core to make sure it is running * - * @return the value from the ping command to the radio core - * @retval CMDSTA_Done the radio core is alive and responding + * @return The value from the command status register. + * @retval CMDSTA_Done The command was received. */ static uint_fast8_t rfCorePowerOn(void) { @@ -830,7 +831,7 @@ static uint_fast8_t rfCorePowerOn(void) } /** - * @brief turns off the radio core + * Turns off the radio core. * * Switches off the power and resources for the radio core. * - disables the interrupts @@ -861,18 +862,20 @@ static void rfCorePowerOff(void) } /** - * @brief sends the setup command string to the radio core + * Sends the setup command string to the radio core. * * Enables the clock line from the RTC to the RF core RAT. Enables the RAT * timer and sets up the radio in IEEE mode. * - * @return the value from the command status register - * @retval CMDSTA_Done the command was received + * @return The value from the command status register. + * @retval CMDSTA_Done The command was received. */ static uint_fast16_t rfCoreSendEnableCmd(void) { - uint8_t ret; - bool interruptsWereDisabled; + uint8_t doorbellRet; + bool interruptsWereDisabled; + uint_fast16_t ret; + static const rfc_CMD_SYNC_START_RAT_t cStartRatCmd = { .commandNo = CMD_SYNC_START_RAT, @@ -912,41 +915,40 @@ static uint_fast16_t rfCoreSendEnableCmd(void) interruptsWereDisabled = IntMasterDisable(); - if ((ret = (RFCDoorbellSendTo((uint32_t)&sStartRatCmd) & 0xFF)) != CMDSTA_Done) - { - if (!interruptsWereDisabled) - { - IntMasterEnable(); - } - - return ret; - } + doorbellRet = (RFCDoorbellSendTo((uint32_t)&sStartRatCmd) & 0xFF); + otEXPECT_ACTION(CMDSTA_Done == doorbellRet, ret = doorbellRet); /* synchronously wait for the CM0 to stop executing */ while ((HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) & IRQ_LAST_COMMAND_DONE) == 0x00); + ret = sRadioSetupCmd.status; + +exit: + if (!interruptsWereDisabled) { IntMasterEnable(); } - return sRadioSetupCmd.status; + return ret; } /** - * @brief sends the shutdown command string to the radio core + * Sends the shutdown command string to the radio core. * * Powers down the frequency synthesizer and stops the RAT. * * @note synchronously waits until the command string completes. * - * @return the status of the RAT stop command - * @retval DONE_OK the command string executed properly + * @return The status of the RAT stop command. + * @retval DONE_OK The command string executed properly. */ static uint_fast16_t rfCoreSendDisableCmd(void) { - uint8_t doorbellRet; - bool interruptsWereDisabled; + uint8_t doorbellRet; + bool interruptsWereDisabled; + uint_fast16_t ret; + static const rfc_CMD_FS_POWERDOWN_t cFsPowerdownCmd = { .commandNo = CMD_FS_POWERDOWN, @@ -983,35 +985,31 @@ static uint_fast16_t rfCoreSendDisableCmd(void) HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = ~IRQ_LAST_COMMAND_DONE; doorbellRet = (RFCDoorbellSendTo((uint32_t)&sFsPowerdownCmd) & 0xFF); + otEXPECT_ACTION(CMDSTA_Done == doorbellRet, ret = doorbellRet); - if (doorbellRet != CMDSTA_Done) - { - if (!interruptsWereDisabled) - { - IntMasterEnable(); - } - - return doorbellRet; - } /* synchronously wait for the CM0 to stop */ while ((HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) & IRQ_LAST_COMMAND_DONE) == 0x00); - if (!interruptsWereDisabled) - { - IntMasterEnable(); - } + ret = sStopRatCmd.status; if (sStopRatCmd.status == DONE_OK) { sRatOffset = sStopRatCmd.rat0; } - return sStopRatCmd.status; +exit: + + if (!interruptsWereDisabled) + { + IntMasterEnable(); + } + + return ret; } /** - * error interrupt handler + * Error interrupt handler. */ void RFCCPE1IntHandler(void) { @@ -1020,7 +1018,7 @@ void RFCCPE1IntHandler(void) } /** - * command done handler + * Command done handler. */ void RFCCPE0IntHandler(void) { @@ -1063,29 +1061,27 @@ void RFCCPE0IntHandler(void) { sTransmitError = OT_ERROR_NO_ACK; /* signal polling function we are done transmitting, we failed to send the packet */ - sState = cc2650_stateTransmitComplete; + sTxCmdChainDone = true; } break; case IEEE_DONE_ACK: - sReceivedAckPendingBit = false; sTransmitError = OT_ERROR_NONE; /* signal polling function we are done transmitting */ - sState = cc2650_stateTransmitComplete; + sTxCmdChainDone = true; break; case IEEE_DONE_ACKPEND: - sReceivedAckPendingBit = true; sTransmitError = OT_ERROR_NONE; /* signal polling function we are done transmitting */ - sState = cc2650_stateTransmitComplete; + sTxCmdChainDone = true; break; default: sTransmitError = OT_ERROR_FAILED; /* signal polling function we are done transmitting */ - sState = cc2650_stateTransmitComplete; + sTxCmdChainDone = true; break; } } @@ -1096,7 +1092,6 @@ void RFCCPE0IntHandler(void) switch (sTransmitCmd.status) { case IEEE_DONE_OK: - sReceivedAckPendingBit = false; sTransmitError = OT_ERROR_NONE; break; @@ -1115,12 +1110,12 @@ void RFCCPE0IntHandler(void) break; default: - sTransmitError = OT_ERROR_GENERIC; + sTransmitError = OT_ERROR_FAILED; break; } /* signal polling function we are done transmitting */ - sState = cc2650_stateTransmitComplete; + sTxCmdChainDone = true; } } } @@ -1313,11 +1308,11 @@ otError otPlatRadioSleep(otInstance *aInstance) if (rfCoreExecuteAbortCmd() != CMDSTA_Done) { error = OT_ERROR_BUSY; - return error; } - - sState = cc2650_stateSleep; - return error; + else + { + sState = cc2650_stateSleep; + } } return error; @@ -1341,27 +1336,18 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) if (sState == cc2650_stateReceive) { - /* - * This is the easiest way to setup the frequency synthesizer. - * And we are supposed to fall into the receive state afterwards. - */ - error = otPlatRadioReceive(aInstance, aFrame->mChannel); + sState = cc2650_stateTransmit; - if (error == OT_ERROR_NONE) - { - sState = cc2650_stateTransmit; - - /* removing 2 bytes of CRC placeholder because we generate that in hardware */ - otEXPECT_ACTION(rfCoreSendTransmitCmd(aFrame->mPsdu, aFrame->mLength - 2) == CMDSTA_Done, - error = OT_ERROR_FAILED); - error = OT_ERROR_NONE; - - otPlatRadioTxStarted(aInstance, aFrame); - } + /* removing 2 bytes of CRC placeholder because we generate that in hardware */ + otEXPECT_ACTION(rfCoreSendTransmitCmd(aFrame->mPsdu, aFrame->mLength - 2) == CMDSTA_Done, + error = OT_ERROR_FAILED); + error = OT_ERROR_NONE; + sTransmitError = OT_ERROR_NONE; + sTxCmdChainDone = false; + otPlatRadioTxStarted(aInstance, aFrame); } exit: - sTransmitError = error; return error; } @@ -1663,7 +1649,7 @@ void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) * Function documented in platform/radio.h * * @note it is entirely possible for this function to fail, but there is no - * valid way to return that error since the funciton prototype was changed. + * valid way to return that error since the function prototype was changed. */ void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanid) { @@ -1694,7 +1680,7 @@ exit: * Function documented in platform/radio.h * * @note it is entirely possible for this function to fail, but there is no - * valid way to return that error since the funciton prototype was changed. + * valid way to return that error since the function prototype was changed. */ void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress) { @@ -1723,7 +1709,7 @@ exit: * Function documented in platform/radio.h * * @note it is entirely possible for this function to fail, but there is no - * valid way to return that error since the funciton prototype was changed. + * valid way to return that error since the function prototype was changed. */ void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress) { @@ -1747,53 +1733,97 @@ exit: return; } -/** - * @brief search the receive queue for unprocessed messages - * - * Loop through the receive queue structure looking for data entries that the - * radio core has marked as finished. Then place those in @ref sReceiveFrame - * and mark any errors in @ref sReceiveError. - */ -static void readFrame(void) +static void cc2650RadioProcessTransmitDone(otInstance *aInstance, otRadioFrame *aTransmitFrame, otRadioFrame *aAckFrame, + otError aTransmitError) { - rfc_ieeeRxCorrCrc_t *crcCorr; - uint8_t rssi; - rfc_dataEntryGeneral_t *startEntry = (rfc_dataEntryGeneral_t *)sRxDataQueue.pCurrEntry; - rfc_dataEntryGeneral_t *curEntry = startEntry; +#if OPENTHREAD_ENABLE_DIAG + + if (otPlatDiagModeGet()) + { + otPlatDiagRadioTransmitDone(aInstance, aTransmitFrame, aTransmitError); + } + else +#endif /* OPENTHREAD_ENABLE_DIAG */ + { + otPlatRadioTxDone(aInstance, aTransmitFrame, aAckFrame, aTransmitError); + } +} + +static void cc2650RadioProcessReceiveDone(otInstance *aInstance, otRadioFrame *aReceiveFrame, otError aReceiveError) +{ +#if OPENTHREAD_ENABLE_DIAG + + if (otPlatDiagModeGet()) + { + otPlatDiagRadioReceiveDone(aInstance, aReceiveFrame, aReceiveError); + } + else +#endif /* OPENTHREAD_ENABLE_DIAG */ + { + otPlatRadioReceiveDone(aInstance, aReceiveFrame, aReceiveError); + } +} + +static void cc2650RadioProcessReceiveQueue(otInstance *aInstance) +{ + rfc_ieeeRxCorrCrc_t *crcCorr; + rfc_dataEntryGeneral_t *curEntry, *startEntry; + uint8_t rssi; + + startEntry = (rfc_dataEntryGeneral_t *)sRxDataQueue.pCurrEntry; + curEntry = startEntry; /* loop through receive queue */ do { uint8_t *payload = &(curEntry->data); - if (sReceiveFrame.mLength == 0 && curEntry->status == DATA_ENTRY_FINISHED) + if (curEntry->status == DATA_ENTRY_FINISHED) { - uint8_t len = payload[0]; + uint8_t len; + otError receiveError; + otRadioFrame receiveFrame; + /* get the information appended to the end of the frame. * This array access looks like it is a fencepost error, but the * first byte is the number of bytes that follow. */ + len = payload[0]; crcCorr = (rfc_ieeeRxCorrCrc_t *)&payload[len]; - rssi = payload[len - 1]; + rssi = payload[len - 1]; if (crcCorr->status.bCrcErr == 0 && (len - 2) < OT_RADIO_FRAME_MAX_SIZE) { #if OPENTHREAD_ENABLE_RAW_LINK_API - // Timestamp - sReceiveFrame.mMsec = otPlatAlarmMilliGetNow(); - sReceiveFrame.mUsec = 0; // Don't support microsecond timer for now. + // TODO: Propagate CM0 timestamp + receiveFrame.mMsec = otPlatAlarmMilliGetNow(); + receiveFrame.mUsec = 0; // Don't support microsecond timer for now. #endif - sReceiveFrame.mLength = len; - memcpy(sReceiveFrame.mPsdu, &(payload[1]), len - 2); - sReceiveFrame.mChannel = sReceiveCmd.channel; - sReceiveFrame.mPower = rssi; - sReceiveFrame.mLqi = crcCorr->status.corr; - sReceiveError = OT_ERROR_NONE; + receiveFrame.mLength = len; + receiveFrame.mPsdu = &(payload[1]); + receiveFrame.mChannel = sReceiveCmd.channel; + receiveFrame.mPower = rssi; + receiveFrame.mLqi = crcCorr->status.corr; + + receiveError = OT_ERROR_NONE; } else { - sReceiveError = OT_ERROR_FCS; + receiveError = OT_ERROR_FCS; + } + + if ((receiveFrame.mPsdu[0] & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_ACK) + { + if (receiveFrame.mPsdu[IEEE802154_DSN_OFFSET] == sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET]) + { + sState = cc2650_stateReceive; + cc2650RadioProcessTransmitDone(aInstance, &sTransmitFrame, &receiveFrame, receiveError); + } + } + else + { + cc2650RadioProcessReceiveDone(aInstance, &receiveFrame, receiveError); } curEntry->status = DATA_ENTRY_PENDING; @@ -1807,8 +1837,6 @@ static void readFrame(void) curEntry = (rfc_dataEntryGeneral_t *)(curEntry->pNextEntry); } while (curEntry != startEntry); - - return; } /** @@ -1828,59 +1856,23 @@ void cc2650RadioProcess(otInstance *aInstance) } } - if (sState == cc2650_stateTransmitComplete || (sState == cc2650_stateTransmit && sTransmitError != OT_ERROR_NONE)) + if (sState == cc2650_stateReceive + || sState == cc2650_stateTransmit) { - /* we are not looking for an ACK packet, or failed */ - sState = cc2650_stateReceive; -#if OPENTHREAD_ENABLE_DIAG - - if (otPlatDiagModeGet()) - { - otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, sTransmitError); - } - else -#endif /* OPENTHREAD_ENABLE_DIAG */ - { - // TODO: pass received ACK frame instead of generating one. - otRadioFrame ackFrame; - uint8_t psdu[IEEE802154_ACK_LENGTH]; - - ackFrame.mPsdu = psdu; - ackFrame.mLength = IEEE802154_ACK_LENGTH; - ackFrame.mPsdu[0] = IEEE802154_FRAME_TYPE_ACK; - - if (sReceivedAckPendingBit) - { - ackFrame.mPsdu[0] |= IEEE802154_FRAME_PENDING; - } - - ackFrame.mPsdu[1] = 0; - ackFrame.mPsdu[2] = sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET]; - - otPlatRadioTxDone(aInstance, &sTransmitFrame, &ackFrame, sTransmitError); - } + cc2650RadioProcessReceiveQueue(aInstance); } - if (sState == cc2650_stateReceive || sState == cc2650_stateTransmit) + if (sTxCmdChainDone) { - readFrame(); - - if (sReceiveFrame.mLength > 0) + if (sState == cc2650_stateTransmit) { -#if OPENTHREAD_ENABLE_DIAG - - if (otPlatDiagModeGet()) - { - otPlatDiagRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); - } - else -#endif /* OPENTHREAD_ENABLE_DIAG */ - { - otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); - } + /* we are not looking for an ACK packet, or failed */ + sState = cc2650_stateReceive; + cc2650RadioProcessTransmitDone(aInstance, &sTransmitFrame, NULL, sTransmitError); } - sReceiveFrame.mLength = 0; + sTransmitError = OT_ERROR_NONE; + sTxCmdChainDone = false; } } diff --git a/examples/platforms/cc2652/cc2652_radio.h b/examples/platforms/cc2652/cc2652_radio.h index 4d5d2aa5c..c797a3d15 100644 --- a/examples/platforms/cc2652/cc2652_radio.h +++ b/examples/platforms/cc2652/cc2652_radio.h @@ -35,7 +35,6 @@ enum { IEEE802154_FRAME_TYPE_MASK = 0x7, ///< (IEEE 802.15.4-2006) PSDU.FCF.frameType IEEE802154_FRAME_TYPE_ACK = 0x2, ///< (IEEE 802.15.4-2006) frame type: ACK - IEEE802154_FRAME_PENDING = (1<<4), ///< (IEEE 802.15.4-2006) PSDU.FCF.bFramePending IEEE802154_ACK_REQUEST = (1<<5), ///< (IEEE 802.15.4-2006) PSDU.FCF.bAR IEEE802154_DSN_OFFSET = 2, ///< (IEEE 802.15.4-2006) PSDU.sequenceNumber IEEE802154_MAC_MIN_BE = 1, ///< (IEEE 802.15.4-2006) macMinBE @@ -156,19 +155,19 @@ typedef enum cc2652_address * The following are valid radio state transitions for the cc2652: * * (Radio ON) - * +----------+ Enable() +-------+ Receive() +---------+ Transmit() +----------+ - * | |----------->| |------------->| |-------------->| | - * | Disabled | | Sleep | | Receive | | Transmit | - * | |<-----------| |<-------------| |<--------------| | - * +----------+ Disable() | | Sleep() | |<-- Receive() +----------+ - * | | (Radio OFF) +---------+ \ | transmit - * | | \-----\ | complete - * | | EnergyScan() +--------+ | V - * | |------------->| | +------------------+ - * | | | EdScan | | | - * | |<-------------| | | TransmitComplete | - * | | signal ED | | | | - * +-------+ scan done +--------+ +------------------+ + * +----------+ Enable() +-------+ Receive() +---------+ Transmit() +----------+ + * | |----------->| |------------->| |--------------->| | + * | Disabled | | Sleep | | Receive | | Transmit | + * | |<-----------| |<-------------| |<---------------| | + * +----------+ Disable() | | Sleep() | | AckFrame RX or +----------+ + * | | (Radio OFF) +---------+ sTxCmdChainDone == true + * | | + * | | EnergyScan() +--------+ + * | |------------->| | + * | | | EdScan | + * | |<-------------| | + * | | signal ED | | + * +-------+ scan done +--------+ * * These states slightly differ from the states in \ref include/platform/radio.h. * The additional states the phy can be in are due to the asynchronous nature @@ -193,7 +192,6 @@ typedef enum cc2652_PhyState cc2652_stateReceive, cc2652_stateEdScan, cc2652_stateTransmit, - cc2652_stateTransmitComplete, } cc2652_PhyState_t; #endif /* CC2652_RADIO_H_ */ diff --git a/examples/platforms/cc2652/radio.c b/examples/platforms/cc2652/radio.c index c87f3ae46..cd166e1a0 100644 --- a/examples/platforms/cc2652/radio.c +++ b/examples/platforms/cc2652/radio.c @@ -61,7 +61,6 @@ enum { - IEEE802154_ACK_LENGTH = 5, CC2652_RECEIVE_SENSITIVITY = -100, // dBm }; @@ -81,14 +80,6 @@ static uint32_t sIEEEOverrides[] = 0xFFFFFFFF, // END_OVERRIDE }; -/* - * Status of the pending bit of the last ack packet found by the - * sTransmitRxAckCmd radio command. - * - * Used to pass data from the radio state ISR to the processing loop. - */ -static volatile bool sReceivedAckPendingBit = false; - /* * Number of retry counts left to the currently transmitting frame. * @@ -143,6 +134,8 @@ static __attribute__((aligned(4))) rfc_ieeeRxOutput_t sRfStats; #define RX_BUF_SIZE 144 static __attribute__((aligned(4))) uint8_t sRxBuf0[RX_BUF_SIZE]; static __attribute__((aligned(4))) uint8_t sRxBuf1[RX_BUF_SIZE]; +static __attribute__((aligned(4))) uint8_t sRxBuf2[RX_BUF_SIZE]; +static __attribute__((aligned(4))) uint8_t sRxBuf3[RX_BUF_SIZE]; /* * The RX Data Queue used by @ref sReceiveCmd. @@ -153,12 +146,11 @@ static __attribute__((aligned(4))) dataQueue_t sRxDataQueue = { 0 }; * OpenThread data primitives */ static otRadioFrame sTransmitFrame; -static otRadioFrame sReceiveFrame; static otError sTransmitError; -static otError sReceiveError; static __attribute__((aligned(4))) uint8_t sTransmitPsdu[OT_RADIO_FRAME_MAX_SIZE]; -static __attribute__((aligned(4))) uint8_t sReceivePsdu[OT_RADIO_FRAME_MAX_SIZE]; + +static volatile bool sTxCmdChainDone = false; /* * Interrupt handlers forward declared for register functions. @@ -175,8 +167,10 @@ void RFCCPE1IntHandler(void); static void rfCoreInitBufs(void) { rfc_dataEntry_t *entry; - memset(sRxBuf0, 0x00, RX_BUF_SIZE); - memset(sRxBuf1, 0x00, RX_BUF_SIZE); + memset(sRxBuf0, 0x00, sizeof(sRxBuf0)); + memset(sRxBuf1, 0x00, sizeof(sRxBuf1)); + memset(sRxBuf2, 0x00, sizeof(sRxBuf2)); + memset(sRxBuf3, 0x00, sizeof(sRxBuf3)); entry = (rfc_dataEntry_t *)sRxBuf0; entry->pNextEntry = sRxBuf1; @@ -184,14 +178,22 @@ static void rfCoreInitBufs(void) entry->length = sizeof(sRxBuf0) - sizeof(rfc_dataEntry_t); entry = (rfc_dataEntry_t *)sRxBuf1; + entry->pNextEntry = sRxBuf2; + entry->config.lenSz = DATA_ENTRY_LENSZ_BYTE; + entry->length = sizeof(sRxBuf1) - sizeof(rfc_dataEntry_t); + + entry = (rfc_dataEntry_t *)sRxBuf2; + entry->pNextEntry = sRxBuf3; + entry->config.lenSz = DATA_ENTRY_LENSZ_BYTE; + entry->length = sizeof(sRxBuf2) - sizeof(rfc_dataEntry_t); + + entry = (rfc_dataEntry_t *)sRxBuf3; entry->pNextEntry = sRxBuf0; entry->config.lenSz = DATA_ENTRY_LENSZ_BYTE; - entry->length = sizeof(sRxBuf0) - sizeof(rfc_dataEntry_t); + entry->length = sizeof(sRxBuf3) - sizeof(rfc_dataEntry_t); sTransmitFrame.mPsdu = sTransmitPsdu; sTransmitFrame.mLength = 0; - sReceiveFrame.mPsdu = sReceivePsdu; - sReceiveFrame.mLength = 0; } /** @@ -243,7 +245,7 @@ static void rfCoreInitReceiveParams(void) { .bAcceptFt0Beacon = 1, .bAcceptFt1Data = 1, - .bAcceptFt2Ack = 0, + .bAcceptFt2Ack = 1, .bAcceptFt3MacCmd = 1, .bAcceptFt4Reserved = 1, .bAcceptFt5Reserved = 1, @@ -696,7 +698,7 @@ static uint_fast8_t rfCoreSendEdScanCmd(uint8_t aChannel, uint16_t aDurration) } /** - * enables the cpe0 and cpe1 radio interrupts + * Enables the cpe0 and cpe1 radio interrupts. * * Enables the @ref IRQ_LAST_COMMAND_DONE and @ref IRQ_LAST_FG_COMMAND_DONE to * be handled by the @ref RFCCPE0IntHandler interrupt handler. @@ -1067,29 +1069,27 @@ void RFCCPE0IntHandler(void) { sTransmitError = OT_ERROR_NO_ACK; /* signal polling function we are done transmitting, we failed to send the packet */ - sState = cc2652_stateTransmitComplete; + sTxCmdChainDone = true; } break; case IEEE_DONE_ACK: - sReceivedAckPendingBit = false; sTransmitError = OT_ERROR_NONE; /* signal polling function we are done transmitting */ - sState = cc2652_stateTransmitComplete; + sTxCmdChainDone = true; break; case IEEE_DONE_ACKPEND: - sReceivedAckPendingBit = true; sTransmitError = OT_ERROR_NONE; /* signal polling function we are done transmitting */ - sState = cc2652_stateTransmitComplete; + sTxCmdChainDone = true; break; default: sTransmitError = OT_ERROR_FAILED; /* signal polling function we are done transmitting */ - sState = cc2652_stateTransmitComplete; + sTxCmdChainDone = true; break; } } @@ -1100,7 +1100,6 @@ void RFCCPE0IntHandler(void) switch (sTransmitCmd.status) { case IEEE_DONE_OK: - sReceivedAckPendingBit = false; sTransmitError = OT_ERROR_NONE; break; @@ -1124,7 +1123,7 @@ void RFCCPE0IntHandler(void) } /* signal polling function we are done transmitting */ - sState = cc2652_stateTransmitComplete; + sTxCmdChainDone = true; } } } @@ -1344,7 +1343,6 @@ otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) */ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) { - (void)aInstance; otError error = OT_ERROR_BUSY; if (sState == cc2652_stateReceive) @@ -1355,10 +1353,12 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) otEXPECT_ACTION(rfCoreSendTransmitCmd(aFrame->mPsdu, aFrame->mLength - 2) == CMDSTA_Done, error = OT_ERROR_FAILED); error = OT_ERROR_NONE; + sTransmitError = OT_ERROR_NONE; + sTxCmdChainDone = false; + otPlatRadioTxStarted(aInstance, aFrame); } exit: - sTransmitError = error; return error; } @@ -1745,53 +1745,97 @@ exit: return; } -/** - * Search the receive queue for unprocessed messages. - * - * Loop through the receive queue structure looking for data entries that the - * radio core has marked as finished. Then place those in @ref sReceiveFrame - * and mark any errors in @ref sReceiveError. - */ -static void readFrame(void) +static void cc2652RadioProcessTransmitDone(otInstance *aInstance, otRadioFrame *aTransmitFrame, otRadioFrame *aAckFrame, + otError aTransmitError) { - rfc_ieeeRxCorrCrc_t *crcCorr; - uint8_t rssi; - rfc_dataEntryGeneral_t *startEntry = (rfc_dataEntryGeneral_t *)sRxDataQueue.pCurrEntry; - rfc_dataEntryGeneral_t *curEntry = startEntry; +#if OPENTHREAD_ENABLE_DIAG + + if (otPlatDiagModeGet()) + { + otPlatDiagRadioTransmitDone(aInstance, aTransmitFrame, aTransmitError); + } + else +#endif /* OPENTHREAD_ENABLE_DIAG */ + { + otPlatRadioTxDone(aInstance, aTransmitFrame, aAckFrame, aTransmitError); + } +} + +static void cc2652RadioProcessReceiveDone(otInstance *aInstance, otRadioFrame *aReceiveFrame, otError aReceiveError) +{ +#if OPENTHREAD_ENABLE_DIAG + + if (otPlatDiagModeGet()) + { + otPlatDiagRadioReceiveDone(aInstance, aReceiveFrame, aReceiveError); + } + else +#endif /* OPENTHREAD_ENABLE_DIAG */ + { + otPlatRadioReceiveDone(aInstance, aReceiveFrame, aReceiveError); + } +} + +static void cc2652RadioProcessReceiveQueue(otInstance *aInstance) +{ + rfc_ieeeRxCorrCrc_t *crcCorr; + rfc_dataEntryGeneral_t *curEntry, *startEntry; + uint8_t rssi; + + startEntry = (rfc_dataEntryGeneral_t *)sRxDataQueue.pCurrEntry; + curEntry = startEntry; /* loop through receive queue */ do { uint8_t *payload = &(curEntry->data); - if (sReceiveFrame.mLength == 0 && curEntry->status == DATA_ENTRY_FINISHED) + if (curEntry->status == DATA_ENTRY_FINISHED) { - uint8_t len = payload[0]; + uint8_t len; + otError receiveError; + otRadioFrame receiveFrame; + /* get the information appended to the end of the frame. * This array access looks like it is a fencepost error, but the * first byte is the number of bytes that follow. */ + len = payload[0]; crcCorr = (rfc_ieeeRxCorrCrc_t *)&payload[len]; - rssi = payload[len - 1]; + rssi = payload[len - 1]; if (crcCorr->status.bCrcErr == 0 && (len - 2) < OT_RADIO_FRAME_MAX_SIZE) { #if OPENTHREAD_ENABLE_RAW_LINK_API - // Timestamp - sReceiveFrame.mMsec = otPlatAlarmMilliGetNow(); - sReceiveFrame.mUsec = 0; // Don't support microsecond timer for now. + // TODO: Propagate CM0 timestamp + receiveFrame.mMsec = otPlatAlarmMilliGetNow(); + receiveFrame.mUsec = 0; // Don't support microsecond timer for now. #endif - sReceiveFrame.mLength = len; - memcpy(sReceiveFrame.mPsdu, &(payload[1]), len - 2); - sReceiveFrame.mChannel = sReceiveCmd.channel; - sReceiveFrame.mPower = rssi; - sReceiveFrame.mLqi = crcCorr->status.corr; - sReceiveError = OT_ERROR_NONE; + receiveFrame.mLength = len; + receiveFrame.mPsdu = &(payload[1]); + receiveFrame.mChannel = sReceiveCmd.channel; + receiveFrame.mPower = rssi; + receiveFrame.mLqi = crcCorr->status.corr; + + receiveError = OT_ERROR_NONE; } else { - sReceiveError = OT_ERROR_FCS; + receiveError = OT_ERROR_FCS; + } + + if ((receiveFrame.mPsdu[0] & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_ACK) + { + if (receiveFrame.mPsdu[IEEE802154_DSN_OFFSET] == sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET]) + { + sState = cc2652_stateReceive; + cc2652RadioProcessTransmitDone(aInstance, &sTransmitFrame, &receiveFrame, receiveError); + } + } + else + { + cc2652RadioProcessReceiveDone(aInstance, &receiveFrame, receiveError); } curEntry->status = DATA_ENTRY_PENDING; @@ -1805,8 +1849,6 @@ static void readFrame(void) curEntry = (rfc_dataEntryGeneral_t *)(curEntry->pNextEntry); } while (curEntry != startEntry); - - return; } /** @@ -1826,59 +1868,23 @@ void cc2652RadioProcess(otInstance *aInstance) } } - if (sState == cc2652_stateTransmitComplete || (sState == cc2652_stateTransmit && sTransmitError != OT_ERROR_NONE)) + if (sState == cc2652_stateReceive + || sState == cc2652_stateTransmit) { - /* we are not looking for an ACK packet, or failed */ - sState = cc2652_stateReceive; -#if OPENTHREAD_ENABLE_DIAG - - if (otPlatDiagModeGet()) - { - otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, sTransmitError); - } - else -#endif /* OPENTHREAD_ENABLE_DIAG */ - { - // TODO: pass received ACK frame instead of generating one. - otRadioFrame ackFrame; - uint8_t psdu[IEEE802154_ACK_LENGTH]; - - ackFrame.mPsdu = psdu; - ackFrame.mLength = IEEE802154_ACK_LENGTH; - ackFrame.mPsdu[0] = IEEE802154_FRAME_TYPE_ACK; - - if (sReceivedAckPendingBit) - { - ackFrame.mPsdu[0] |= IEEE802154_FRAME_PENDING; - } - - ackFrame.mPsdu[1] = 0; - ackFrame.mPsdu[2] = sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET]; - - otPlatRadioTxDone(aInstance, &sTransmitFrame, &ackFrame, sTransmitError); - } + cc2652RadioProcessReceiveQueue(aInstance); } - if (sState == cc2652_stateReceive || sState == cc2652_stateTransmit) + if (sTxCmdChainDone) { - readFrame(); - - if (sReceiveFrame.mLength > 0) + if (sState == cc2652_stateTransmit) { -#if OPENTHREAD_ENABLE_DIAG - - if (otPlatDiagModeGet()) - { - otPlatDiagRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); - } - else -#endif /* OPENTHREAD_ENABLE_DIAG */ - { - otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); - } + /* we are not looking for an ACK packet, or failed */ + sState = cc2652_stateReceive; + cc2652RadioProcessTransmitDone(aInstance, &sTransmitFrame, NULL, sTransmitError); } - sReceiveFrame.mLength = 0; + sTransmitError = OT_ERROR_NONE; + sTxCmdChainDone = false; } }