| /* |
| * Copyright (c) 2016, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /** |
| * @file |
| * This file implements the OpenThread platform abstraction for radio communication. |
| * |
| */ |
| |
| #include <openthread/config.h> |
| #include <openthread/platform/alarm-milli.h> |
| #include <openthread/platform/diag.h> |
| #include <openthread/platform/radio.h> |
| |
| #include "platform-cc2538.h" |
| #include "common/logging.hpp" |
| #include "utils/code_utils.h" |
| |
| #define RFCORE_XREG_RFIRQM0 0x4008868C // RF interrupt masks |
| #define RFCORE_XREG_RFIRQM1 0x40088690 // RF interrupt masks |
| #define RFCORE_XREG_RFERRM 0x40088694 // RF error interrupt mask |
| |
| #define RFCORE_SFR_RFIRQF0_RXMASKZERO 0x00000080 // RXENABLE is now completely clear |
| #define RFCORE_SFR_RFIRQF0_RXPKTDONE 0x00000040 // A complete frame has been received |
| #define RFCORE_SFR_RFIRQF0_FRAME_ACCEPTED 0x00000020 // Frame has passed frame filtering |
| #define RFCORE_SFR_RFIRQF0_SRC_MATCH_FOUND 0x00000010 // Source match is found |
| #define RFCORE_SFR_RFIRQF0_SRC_MATCH_DONE 0x00000008 // Source matching is complete |
| #define RFCORE_SFR_RFIRQF0_FIFOP 0x00000004 // The number of bytes in the RX fifo is above threshold |
| #define RFCORE_SFR_RFIRQF0_SFD 0x00000002 // SFD has been received or transmitted |
| #define RFCORE_SFR_RFIRQF0_ACT_UNUSED 0x00000001 // Reserved |
| |
| #define RFCORE_XREG_RFIRQM0_RXMASKZERO 0x00000080 |
| #define RFCORE_XREG_RFIRQM0_RXPKTDONE 0x00000040 |
| #define RFCORE_XREG_RFIRQM0_FRAME_ACCEPTED 0x00000020 |
| #define RFCORE_XREG_RFIRQM0_SRC_MATCH_FOUND 0x00000010 |
| #define RFCORE_XREG_RFIRQM0_SRC_MATCH_DONE 0x00000008 |
| #define RFCORE_XREG_RFIRQM0_FIFOP 0x00000004 |
| #define RFCORE_XREG_RFIRQM0_SFD 0x00000002 |
| #define RFCORE_XREG_RFIRQM0_ACT_UNUSED 0x00000001 |
| |
| #define RFCORE_SFR_RFIRQF1_CSP_WAIT 0x00000020 |
| #define RFCORE_SFR_RFIRQF1_CSP_STOP 0x00000010 |
| #define RFCORE_SFR_RFIRQF1_CSP_MANINT 0x00000008 |
| #define RFCORE_SFR_RFIRQF1_RF_IDLE 0x00000004 |
| #define RFCORE_SFR_RFIRQF1_TXDONE 0x00000002 |
| #define RFCORE_SFR_RFIRQF1_TXACKDONE 0x00000001 |
| |
| #define RFCORE_XREG_RFIRQM1_CSP_WAIT 0x00000020 |
| #define RFCORE_XREG_RFIRQM1_CSP_STOP 0x00000010 |
| #define RFCORE_XREG_RFIRQM1_CSP_MANINT 0x00000008 |
| #define RFCORE_XREG_RFIRQM1_RF_IDLE 0x00000004 |
| #define RFCORE_XREG_RFIRQM1_TXDONE 0x00000002 |
| #define RFCORE_XREG_RFIRQM1_TXACKDONE 0x00000001 |
| |
| #define RFCORE_XREG_RFERRM_STROBE_ERR 0x00000040 |
| #define RFCORE_XREG_RFERRM_TXUNDERF 0x00000020 |
| #define RFCORE_XREG_RFERRM_TXOVERF 0x00000010 |
| #define RFCORE_XREG_RFERRM_RXUNDERF 0x00000008 |
| #define RFCORE_XREG_RFERRM_RXOVERF 0x00000004 |
| #define RFCORE_XREG_RFERRM_RXABO 0x00000002 |
| #define RFCORE_XREG_RFERRM_NLOCK 0x00000001 |
| |
| enum |
| { |
| IEEE802154_MIN_LENGTH = 5, |
| IEEE802154_MAX_LENGTH = 127, |
| IEEE802154_ACK_LENGTH = 5, |
| IEEE802154_FRAME_TYPE_MASK = 0x7, |
| IEEE802154_FRAME_TYPE_ACK = 0x2, |
| IEEE802154_FRAME_PENDING = 1 << 4, |
| IEEE802154_ACK_REQUEST = 1 << 5, |
| IEEE802154_DSN_OFFSET = 2, |
| }; |
| |
| enum |
| { |
| CC2538_RSSI_OFFSET = OPENTHREAD_CONFIG_CC2538_RSSI_OFFSET, |
| // TI AN130 (SWRA447) Table 4 (bottom of page 3) |
| CC2592_RSSI_OFFSET_HGM = 85, |
| CC2592_RSSI_OFFSET_LGM = 81, |
| CC2538_CRC_BIT_MASK = 0x80, |
| CC2538_LQI_BIT_MASK = 0x7f, |
| }; |
| |
| // All values in dBm |
| enum |
| { |
| CC2538_RECEIVE_SENSITIVITY = OPENTHREAD_CONFIG_CC2538_RECEIVE_SENSITIVITY, |
| // TI AN130 (SWRA447) Table 3 (middle of page 3) |
| CC2592_RECEIVE_SENSITIVITY_LGM = -99, |
| CC2592_RECEIVE_SENSITIVITY_HGM = -101, |
| }; |
| |
| typedef struct TxPowerTable |
| { |
| int8_t mTxPowerVal; |
| uint8_t mTxPowerReg; |
| } TxPowerTable; |
| |
| // The transmit power table. |
| static const TxPowerTable sTxPowerTable[] = { |
| #if OPENTHREAD_CONFIG_CC2538_WITH_CC2592 |
| // CC2538 using CC2592 PA |
| // Values are from AN130 table 6 (page 4) |
| {22, 0xFF}, // 22.0dBm =~ 158.5mW |
| {21, 0xD5}, // 20.9dBm =~ 123.0mW |
| {20, 0xC5}, // 20.1dBm =~ 102.3mW |
| {19, 0xB0}, // 19.0dBm =~ 79.4mW |
| {18, 0xA1}, // 17.8dBm =~ 60.3mW |
| {16, 0x91}, // 16.4dBm =~ 43.7mW |
| {15, 0x88}, // 14.9dBm =~ 30.9mW |
| {13, 0x72}, // 13.0dBm =~ 20.0mW |
| {11, 0x62}, // 11.0dBm =~ 12.6mW |
| {10, 0x58}, // 9.5dBm =~ 8.9mW |
| {8, 0x42}, // 7.5dBm =~ 5.6mW |
| #else |
| // CC2538 operating "bare foot" |
| // Values are from SmartRF Studio 2.4.0 |
| {7, 0xFF}, // |
| {5, 0xED}, // |
| {3, 0xD5}, // |
| {1, 0xC5}, // |
| {0, 0xB6}, // |
| {-1, 0xB0}, // |
| {-3, 0xA1}, // |
| {-5, 0x91}, // |
| {-7, 0x88}, // |
| {-9, 0x72}, // |
| {-11, 0x62}, // |
| {-13, 0x58}, // |
| {-15, 0x42}, // |
| {-24, 0x00}, // |
| #endif |
| }; |
| |
| static otRadioFrame sTransmitFrame; |
| static otRadioFrame sReceiveFrame; |
| static otError sTransmitError; |
| static otError sReceiveError; |
| |
| static uint8_t sTransmitPsdu[IEEE802154_MAX_LENGTH]; |
| static uint8_t sReceivePsdu[IEEE802154_MAX_LENGTH]; |
| static uint8_t sChannel = 0; |
| static int8_t sTxPower = 0; |
| |
| static otRadioState sState = OT_RADIO_STATE_DISABLED; |
| static bool sIsReceiverEnabled = false; |
| |
| #if OPENTHREAD_CONFIG_LOG_PLATFORM && OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT |
| // Debugging _and_ logging are enabled, so if there's a dropped frame |
| // we'll need to store the length here as using snprintf from an interrupt |
| // handler is not a good idea. |
| static uint8_t sDroppedFrameLength = 0; |
| #endif |
| |
| void enableReceiver(void) |
| { |
| if (!sIsReceiverEnabled) |
| { |
| otLogInfoPlat("Enabling receiver", NULL); |
| |
| // flush rxfifo |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; |
| |
| // enable receiver |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_RXON; |
| sIsReceiverEnabled = true; |
| } |
| } |
| |
| void disableReceiver(void) |
| { |
| if (sIsReceiverEnabled) |
| { |
| otLogInfoPlat("Disabling receiver", NULL); |
| |
| while (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE) |
| ; |
| |
| // flush rxfifo |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; |
| |
| if (HWREG(RFCORE_XREG_RXENABLE) != 0) |
| { |
| // disable receiver |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_RFOFF; |
| } |
| |
| sIsReceiverEnabled = false; |
| } |
| } |
| |
| void setChannel(uint8_t aChannel) |
| { |
| if (sChannel != aChannel) |
| { |
| bool enabled = false; |
| |
| if (sIsReceiverEnabled) |
| { |
| disableReceiver(); |
| enabled = true; |
| } |
| |
| otLogInfoPlat("Channel=%d", aChannel); |
| |
| HWREG(RFCORE_XREG_FREQCTRL) = 11 + (aChannel - 11) * 5; |
| sChannel = aChannel; |
| |
| if (enabled) |
| { |
| enableReceiver(); |
| } |
| } |
| } |
| |
| void setTxPower(int8_t aTxPower) |
| { |
| uint8_t i = 0; |
| |
| if (sTxPower != aTxPower) |
| { |
| otLogInfoPlat("TxPower=%d", aTxPower); |
| |
| for (i = sizeof(sTxPowerTable) / sizeof(TxPowerTable) - 1; i > 0; i--) |
| { |
| if (aTxPower < sTxPowerTable[i].mTxPowerVal) |
| { |
| break; |
| } |
| } |
| |
| HWREG(RFCORE_XREG_TXPOWER) = sTxPowerTable[i].mTxPowerReg; |
| sTxPower = aTxPower; |
| } |
| } |
| |
| static bool cc2538SrcMatchEnabled(void) |
| { |
| return (HWREG(RFCORE_XREG_FRMCTRL1) & RFCORE_XREG_FRMCTRL1_PENDING_OR) == 0; |
| } |
| |
| static bool cc2538GetSrcMatchFoundIntFlag(void) |
| { |
| bool flag = (HWREG(RFCORE_SFR_RFIRQF0) & RFCORE_SFR_RFIRQF0_SRC_MATCH_FOUND) != 0; |
| if (flag) |
| { |
| HWREG(RFCORE_SFR_RFIRQF0) &= ~RFCORE_SFR_RFIRQF0_SRC_MATCH_FOUND; |
| } |
| return flag; |
| } |
| |
| void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| // EUI64 is in a mixed-endian format. Split in two halves, each 32-bit |
| // half is in little-endian format (machine endian). However, the |
| // most significant part of the EUI64 comes first, so we can't cheat |
| // with a uint64_t! |
| // |
| // See https://e2e.ti.com/support/wireless_connectivity/low_power_rf_tools/f/155/p/307344/1072252 |
| |
| volatile uint32_t *eui64 = &HWREG(IEEE_EUI64); |
| |
| // Read first 32-bits |
| uint32_t part = eui64[0]; |
| for (uint8_t i = 0; i < (OT_EXT_ADDRESS_SIZE / 2); i++) |
| { |
| aIeeeEui64[3 - i] = part; |
| part >>= 8; |
| } |
| |
| // Read the last 32-bits |
| part = eui64[1]; |
| for (uint8_t i = 0; i < (OT_EXT_ADDRESS_SIZE / 2); i++) |
| { |
| aIeeeEui64[7 - i] = part; |
| part >>= 8; |
| } |
| } |
| |
| void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanid) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otLogInfoPlat("PANID=%X", aPanid); |
| |
| HWREG(RFCORE_FFSM_PAN_ID0) = aPanid & 0xFF; |
| HWREG(RFCORE_FFSM_PAN_ID1) = aPanid >> 8; |
| } |
| |
| void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otLogInfoPlat("ExtAddr=%X%X%X%X%X%X%X%X", aAddress->m8[7], aAddress->m8[6], aAddress->m8[5], aAddress->m8[4], |
| aAddress->m8[3], aAddress->m8[2], aAddress->m8[1], aAddress->m8[0]); |
| |
| for (int i = 0; i < 8; i++) |
| { |
| ((volatile uint32_t *)RFCORE_FFSM_EXT_ADDR0)[i] = aAddress->m8[i]; |
| } |
| } |
| |
| void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otLogInfoPlat("ShortAddr=%X", aAddress); |
| |
| HWREG(RFCORE_FFSM_SHORT_ADDR0) = aAddress & 0xFF; |
| HWREG(RFCORE_FFSM_SHORT_ADDR1) = aAddress >> 8; |
| } |
| |
| void cc2538RadioInit(void) |
| { |
| sTransmitFrame.mLength = 0; |
| sTransmitFrame.mPsdu = sTransmitPsdu; |
| sReceiveFrame.mLength = 0; |
| sReceiveFrame.mPsdu = sReceivePsdu; |
| |
| #if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT |
| // Enable interrupts for RX/TX, interrupt 26. |
| // That's NVIC index 0 (26 >> 5) bit 26 (26 & 0x1f). |
| HWREG(NVIC_EN0 + (0 * 4)) = (1 << 26); |
| HWREG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_RXPKTDONE; |
| #endif |
| |
| // enable clock |
| HWREG(SYS_CTRL_RCGCRFC) = SYS_CTRL_RCGCRFC_RFC0; |
| HWREG(SYS_CTRL_SCGCRFC) = SYS_CTRL_SCGCRFC_RFC0; |
| HWREG(SYS_CTRL_DCGCRFC) = SYS_CTRL_DCGCRFC_RFC0; |
| |
| // Table 23-7. |
| HWREG(RFCORE_XREG_AGCCTRL1) = 0x15; |
| HWREG(RFCORE_XREG_TXFILTCFG) = 0x09; |
| HWREG(ANA_REGS_BASE + ANA_REGS_O_IVCTRL) = 0x0b; |
| |
| HWREG(RFCORE_XREG_CCACTRL0) = 0xf8; |
| HWREG(RFCORE_XREG_FIFOPCTRL) = IEEE802154_MAX_LENGTH; |
| |
| HWREG(RFCORE_XREG_FRMCTRL0) = RFCORE_XREG_FRMCTRL0_AUTOCRC | RFCORE_XREG_FRMCTRL0_AUTOACK; |
| |
| // default: SRCMATCH.SRC_MATCH_EN(1), SRCMATCH.AUTOPEND(1), |
| // SRCMATCH.PEND_DATAREQ_ONLY(1), RFCORE_XREG_FRMCTRL1_PENDING_OR(0) |
| |
| HWREG(RFCORE_XREG_TXPOWER) = sTxPowerTable[0].mTxPowerReg; |
| sTxPower = sTxPowerTable[0].mTxPowerVal; |
| |
| #if OPENTHREAD_CONFIG_CC2538_WITH_CC2592 |
| // PA_EN pin configuration. |
| // Step 1. make it an output |
| HWREG(GPIO_C_BASE | GPIO_O_DIR) |= GPIO_PIN(OPENTHREAD_CONFIG_CC2592_PA_EN_PIN); |
| // Step 2. Route PA_PD to OBS0 and invert it to produce PA_EN |
| HWREG_ARR(RFCORE_XREG_RFC_OBS_CTRL, 0) = RFCORE_XREG_RFC_OBS_POL_INV // Invert the output |
| | RFCORE_XREG_RFC_OBS_MUX_PA_PD; // PA "power down" signal |
| // Step 3. Connect the selected pin to OBS0 and enable OBS0. |
| HWREG_ARR(CCTEST_OBSSEL, OPENTHREAD_CONFIG_CC2592_PA_EN_PIN) = CCTEST_OBSSEL_EN // Enable the output |
| | CCTEST_OBSSEL_SEL_OBS0; // Select OBS0 |
| |
| // LNA_EN pin configuration. |
| HWREG(GPIO_C_BASE | GPIO_O_DIR) |= GPIO_PIN(OPENTHREAD_CONFIG_CC2592_LNA_EN_PIN); |
| HWREG_ARR(RFCORE_XREG_RFC_OBS_CTRL, 1) = RFCORE_XREG_RFC_OBS_POL_INV | RFCORE_XREG_RFC_OBS_MUX_LNA_PD; |
| HWREG_ARR(CCTEST_OBSSEL, OPENTHREAD_CONFIG_CC2592_LNA_EN_PIN) = CCTEST_OBSSEL_EN | CCTEST_OBSSEL_SEL_OBS1; |
| |
| #if OPENTHREAD_CONFIG_CC2592_USE_HGM |
| // HGM pin configuration. Set the pin state first so we don't glitch. |
| cc2538RadioSetHgm(OPENTHREAD_CONFIG_CC2592_HGM_DEFAULT_STATE); |
| HWREG(OPENTHREAD_CONFIG_CC2592_HGM_PORT | GPIO_O_DIR) |= GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN); |
| #endif // OPENTHREAD_CONFIG_CC2592_USE_HGM |
| #endif // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 |
| |
| otLogInfoPlat("Initialized", NULL); |
| } |
| |
| #if OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM |
| void cc2538RadioSetHgm(bool aState) |
| { |
| if (aState) |
| { |
| HWREG_ARR(OPENTHREAD_CONFIG_CC2592_HGM_PORT, GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN)) = |
| GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN); |
| } |
| else |
| { |
| HWREG_ARR(OPENTHREAD_CONFIG_CC2592_HGM_PORT, GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN)) = 0; |
| } |
| } |
| |
| bool cc2538RadioGetHgm(void) |
| { |
| if (HWREG_ARR(OPENTHREAD_CONFIG_CC2592_HGM_PORT, GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN)) & |
| GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN)) |
| { |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| #endif // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM |
| |
| bool otPlatRadioIsEnabled(otInstance *aInstance) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| return (sState != OT_RADIO_STATE_DISABLED) ? true : false; |
| } |
| |
| otError otPlatRadioEnable(otInstance *aInstance) |
| { |
| if (!otPlatRadioIsEnabled(aInstance)) |
| { |
| otLogDebgPlat("State=OT_RADIO_STATE_SLEEP", NULL); |
| sState = OT_RADIO_STATE_SLEEP; |
| } |
| |
| return OT_ERROR_NONE; |
| } |
| |
| otError otPlatRadioDisable(otInstance *aInstance) |
| { |
| if (otPlatRadioIsEnabled(aInstance)) |
| { |
| otLogDebgPlat("State=OT_RADIO_STATE_DISABLED", NULL); |
| sState = OT_RADIO_STATE_DISABLED; |
| } |
| |
| return OT_ERROR_NONE; |
| } |
| |
| otError otPlatRadioSleep(otInstance *aInstance) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otError error = OT_ERROR_INVALID_STATE; |
| |
| if (sState == OT_RADIO_STATE_SLEEP || sState == OT_RADIO_STATE_RECEIVE) |
| { |
| otLogDebgPlat("State=OT_RADIO_STATE_SLEEP", NULL); |
| error = OT_ERROR_NONE; |
| sState = OT_RADIO_STATE_SLEEP; |
| disableReceiver(); |
| } |
| |
| return error; |
| } |
| |
| otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otError error = OT_ERROR_INVALID_STATE; |
| |
| if (sState != OT_RADIO_STATE_DISABLED) |
| { |
| otLogDebgPlat("State=OT_RADIO_STATE_RECEIVE", NULL); |
| |
| error = OT_ERROR_NONE; |
| sState = OT_RADIO_STATE_RECEIVE; |
| setChannel(aChannel); |
| sReceiveFrame.mChannel = aChannel; |
| enableReceiver(); |
| } |
| |
| return error; |
| } |
| |
| static void setupTransmit(otRadioFrame *aFrame) |
| { |
| int i; |
| |
| // wait for current TX operation to complete, if any. |
| while (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE) |
| ; |
| |
| // flush txfifo |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHTX; |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHTX; |
| |
| // frame length |
| HWREG(RFCORE_SFR_RFDATA) = aFrame->mLength; |
| |
| // frame data |
| for (i = 0; i < aFrame->mLength; i++) |
| { |
| HWREG(RFCORE_SFR_RFDATA) = aFrame->mPsdu[i]; |
| } |
| |
| setChannel(aFrame->mChannel); |
| } |
| |
| otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otError error = OT_ERROR_INVALID_STATE; |
| |
| if (sState == OT_RADIO_STATE_RECEIVE) |
| { |
| int i; |
| |
| error = OT_ERROR_NONE; |
| sState = OT_RADIO_STATE_TRANSMIT; |
| sTransmitError = OT_ERROR_NONE; |
| |
| setupTransmit(aFrame); |
| |
| // Set up a counter to inform us if we get stuck. |
| i = 1000000; |
| |
| // Wait for radio to enter receive state. |
| while ((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_RX_ACTIVE) == 0) |
| { |
| // Count down the cycles, and emit a message if we get to zero. |
| // Ideally, we should never get there! |
| if (i) |
| { |
| i--; |
| } |
| else |
| { |
| otLogCritPlat("Radio is stuck!!! FSMSTAT0=0x%08x FSMSTAT1=0x%08x RFERRF=0x%08x", |
| HWREG(RFCORE_XREG_FSMSTAT0), HWREG(RFCORE_XREG_FSMSTAT1), HWREG(RFCORE_SFR_RFERRF)); |
| i = 1000000; |
| } |
| |
| // Ensure we haven't overflowed the RX buffer in the mean time, as this |
| // will cause a deadlock here otherwise. Similarly, if we see an aborted |
| // RX, handle that here too to prevent deadlock. |
| if (HWREG(RFCORE_SFR_RFERRF) & (RFCORE_SFR_RFERRF_RXOVERF | RFCORE_SFR_RFERRF_RXABO)) |
| { |
| if (HWREG(RFCORE_SFR_RFERRF) & RFCORE_SFR_RFERRF_RXOVERF) |
| { |
| otLogCritPlat("RX Buffer Overflow detected", NULL); |
| } |
| |
| if (HWREG(RFCORE_SFR_RFERRF) & RFCORE_SFR_RFERRF_RXABO) |
| { |
| otLogCritPlat("Aborted RX detected", NULL); |
| } |
| |
| // Flush the RX buffer |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; |
| } |
| |
| // Check for idle state. After flushing the RX buffer, we may wind up here. |
| if (!(HWREG(RFCORE_XREG_FSMSTAT1) & (RFCORE_XREG_FSMSTAT1_TX_ACTIVE | RFCORE_XREG_FSMSTAT1_RX_ACTIVE))) |
| { |
| otLogCritPlat("Idle state detected", NULL); |
| |
| // In this case, the state of our driver mis-matches our state. So force |
| // matters by clearing our channel variable and calling setChannel. This |
| // should bring our radio into the RX state, which should allow us to go |
| // into TX. |
| sChannel = 0; |
| setupTransmit(aFrame); |
| } |
| } |
| |
| // wait for valid rssi |
| while ((HWREG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0) |
| ; |
| |
| otEXPECT_ACTION(((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_CCA) && |
| !((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_SFD))), |
| sTransmitError = OT_ERROR_CHANNEL_ACCESS_FAILURE); |
| |
| // 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("Transmitted %d bytes", aFrame->mLength); |
| } |
| |
| exit: |
| return error; |
| } |
| |
| otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| return &sTransmitFrame; |
| } |
| |
| int8_t otPlatRadioGetRssi(otInstance *aInstance) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| return 0; |
| } |
| |
| otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| return OT_RADIO_CAPS_NONE; |
| } |
| |
| static bool cc2538RadioGetPromiscuous(void) |
| { |
| return (HWREG(RFCORE_XREG_FRMFILT0) & RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN) == 0; |
| } |
| |
| bool otPlatRadioGetPromiscuous(otInstance *aInstance) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| return cc2538RadioGetPromiscuous(); |
| } |
| |
| static int8_t cc2538RadioGetRssiOffset(void) |
| { |
| #if OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM |
| if (cc2538RadioGetHgm()) |
| { |
| return CC2592_RSSI_OFFSET_HGM; |
| } |
| else |
| { |
| return CC2592_RSSI_OFFSET_LGM; |
| } |
| #else // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM |
| return CC2538_RSSI_OFFSET; |
| #endif // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM |
| } |
| |
| void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otLogInfoPlat("PromiscuousMode=%d", aEnable ? 1 : 0); |
| |
| if (aEnable) |
| { |
| HWREG(RFCORE_XREG_FRMFILT0) &= ~RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN; |
| } |
| else |
| { |
| HWREG(RFCORE_XREG_FRMFILT0) |= RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN; |
| } |
| } |
| |
| static void readFrame(void) |
| { |
| uint8_t length; |
| uint8_t crcCorr; |
| int i; |
| |
| /* |
| * There is already a frame present in the buffer, return early so |
| * we do not overwrite it (hopefully we'll catch it on the next run). |
| */ |
| otEXPECT(sReceiveFrame.mLength == 0); |
| |
| otEXPECT(sState == OT_RADIO_STATE_RECEIVE || sState == OT_RADIO_STATE_TRANSMIT); |
| otEXPECT((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) != 0); |
| |
| // read length |
| length = HWREG(RFCORE_SFR_RFDATA); |
| otEXPECT(IEEE802154_MIN_LENGTH <= length && length <= IEEE802154_MAX_LENGTH); |
| |
| #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE |
| #error Time sync requires the timestamp of SFD rather than that of rx done! |
| #else |
| // Timestamp |
| if (cc2538RadioGetPromiscuous()) |
| #endif |
| { |
| // The current driver only supports milliseconds resolution. |
| sReceiveFrame.mInfo.mRxInfo.mTimestamp = otPlatAlarmMilliGetNow() * 1000; |
| } |
| |
| // read psdu |
| for (i = 0; i < length - 2; i++) |
| { |
| sReceiveFrame.mPsdu[i] = HWREG(RFCORE_SFR_RFDATA); |
| } |
| |
| sReceiveFrame.mInfo.mRxInfo.mRssi = (int8_t)HWREG(RFCORE_SFR_RFDATA) - cc2538RadioGetRssiOffset(); |
| crcCorr = HWREG(RFCORE_SFR_RFDATA); |
| |
| if (crcCorr & CC2538_CRC_BIT_MASK) |
| { |
| sReceiveFrame.mLength = length; |
| sReceiveFrame.mInfo.mRxInfo.mLqi = crcCorr & CC2538_LQI_BIT_MASK; |
| |
| if (length > IEEE802154_ACK_LENGTH) |
| { |
| // Set ACK FP flag for the received frame according to whether SRC_MATCH_FOUND was triggered just before |
| // if SRC MATCH is not enabled, SRC_MATCH_FOUND is not triggered and all ACK FP is always set |
| sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending = |
| cc2538SrcMatchEnabled() ? cc2538GetSrcMatchFoundIntFlag() : true; |
| } |
| } |
| else |
| { |
| // resets rxfifo |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; |
| #if OPENTHREAD_CONFIG_LOG_PLATFORM && OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT |
| // Debugging _and_ logging are enabled, it may not be safe to do |
| // logging if we're in the interrupt context, so just stash the |
| // length and do the logging later. |
| sDroppedFrameLength = length; |
| #else |
| otLogDebgPlat("Dropping %d received bytes (Invalid CRC)", length); |
| #endif |
| } |
| |
| // check for rxfifo overflow |
| if ((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) != 0 && |
| (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFO) == 0) |
| { |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; |
| HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; |
| } |
| |
| exit: |
| return; |
| } |
| |
| void cc2538RadioProcess(otInstance *aInstance) |
| { |
| #if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT |
| // Disable the receive interrupt so that sReceiveFrame doesn't get |
| // blatted by the interrupt handler while we're polling. |
| HWREG(RFCORE_XREG_RFIRQM0) &= ~RFCORE_XREG_RFIRQM0_RXPKTDONE; |
| #endif |
| |
| readFrame(); |
| |
| #if OPENTHREAD_CONFIG_LOG_PLATFORM && OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT |
| if (sDroppedFrameLength != 0) |
| { |
| otLogDebgPlat("Dropping %d received bytes (Invalid CRC)", sDroppedFrameLength); |
| sDroppedFrameLength = 0; |
| } |
| #endif |
| |
| if ((sState == OT_RADIO_STATE_RECEIVE && sReceiveFrame.mLength > 0) || |
| (sState == OT_RADIO_STATE_TRANSMIT && sReceiveFrame.mLength > IEEE802154_ACK_LENGTH)) |
| { |
| #if OPENTHREAD_CONFIG_DIAG_ENABLE |
| |
| if (otPlatDiagModeGet()) |
| { |
| otPlatDiagRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); |
| } |
| else |
| #endif |
| { |
| // signal MAC layer for each received frame if promiscuous is enabled |
| // otherwise only signal MAC layer for non-ACK frame |
| if (((HWREG(RFCORE_XREG_FRMFILT0) & RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN) == 0) || |
| (sReceiveFrame.mLength > IEEE802154_ACK_LENGTH)) |
| { |
| otLogDebgPlat("Received %d bytes", sReceiveFrame.mLength); |
| otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); |
| } |
| } |
| } |
| |
| if (sState == OT_RADIO_STATE_TRANSMIT) |
| { |
| if (sTransmitError != OT_ERROR_NONE || (sTransmitFrame.mPsdu[0] & IEEE802154_ACK_REQUEST) == 0) |
| { |
| if (sTransmitError != OT_ERROR_NONE) |
| { |
| otLogDebgPlat("Transmit failed ErrorCode=%d", sTransmitError); |
| } |
| |
| sState = OT_RADIO_STATE_RECEIVE; |
| |
| #if OPENTHREAD_CONFIG_DIAG_ENABLE |
| |
| if (otPlatDiagModeGet()) |
| { |
| otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, sTransmitError); |
| } |
| else |
| #endif |
| { |
| otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, sTransmitError); |
| } |
| } |
| else if (sReceiveFrame.mLength == IEEE802154_ACK_LENGTH && |
| (sReceiveFrame.mPsdu[0] & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_ACK && |
| (sReceiveFrame.mPsdu[IEEE802154_DSN_OFFSET] == sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET])) |
| { |
| sState = OT_RADIO_STATE_RECEIVE; |
| |
| otPlatRadioTxDone(aInstance, &sTransmitFrame, &sReceiveFrame, sTransmitError); |
| } |
| } |
| |
| sReceiveFrame.mLength = 0; |
| |
| #if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT |
| // Turn the receive interrupt handler back on now the buffer is clear. |
| HWREG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_RXPKTDONE; |
| #endif |
| } |
| |
| void RFCoreRxTxIntHandler(void) |
| { |
| #if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT |
| if (HWREG(RFCORE_SFR_RFIRQF0) & RFCORE_SFR_RFIRQF0_RXPKTDONE) |
| { |
| readFrame(); |
| |
| if (sReceiveFrame.mLength > 0) |
| { |
| // A frame has been received, disable the interrupt handler |
| // until the main loop has dealt with this previous frame, |
| // otherwise we might overwrite it whilst it is being read. |
| HWREG(RFCORE_XREG_RFIRQM0) &= ~RFCORE_XREG_RFIRQM0_RXPKTDONE; |
| } |
| } |
| #endif |
| |
| HWREG(RFCORE_SFR_RFIRQF0) = 0; |
| } |
| |
| void RFCoreErrIntHandler(void) |
| { |
| HWREG(RFCORE_SFR_RFERRF) = 0; |
| } |
| |
| uint32_t getSrcMatchEntriesEnableStatus(bool aShort) |
| { |
| uint32_t status = 0; |
| uint32_t *addr = aShort ? (uint32_t *)RFCORE_XREG_SRCSHORTEN0 : (uint32_t *)RFCORE_XREG_SRCEXTEN0; |
| |
| for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++) |
| { |
| status |= HWREG(addr++) << (i * 8); |
| } |
| |
| return status; |
| } |
| |
| int8_t findSrcMatchShortEntry(const uint16_t aShortAddress) |
| { |
| int8_t entry = -1; |
| uint16_t shortAddr; |
| uint32_t bitMask; |
| uint32_t *addr = NULL; |
| uint32_t status = getSrcMatchEntriesEnableStatus(true); |
| |
| for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_SHORT_ENTRIES; i++) |
| { |
| bitMask = 0x00000001 << i; |
| |
| if ((status & bitMask) == 0) |
| { |
| continue; |
| } |
| |
| addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE + (i * RFCORE_XREG_SRCMATCH_SHORT_ENTRY_OFFSET); |
| |
| shortAddr = HWREG(addr + 2); |
| shortAddr |= HWREG(addr + 3) << 8; |
| |
| if ((shortAddr == aShortAddress)) |
| { |
| entry = i; |
| break; |
| } |
| } |
| |
| return entry; |
| } |
| |
| int8_t findSrcMatchExtEntry(const otExtAddress *aExtAddress) |
| { |
| int8_t entry = -1; |
| uint32_t bitMask; |
| uint32_t *addr = NULL; |
| uint32_t status = getSrcMatchEntriesEnableStatus(false); |
| |
| for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_EXT_ENTRIES; i++) |
| { |
| uint8_t j = 0; |
| bitMask = 0x00000001 << 2 * i; |
| |
| if ((status & bitMask) == 0) |
| { |
| continue; |
| } |
| |
| addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE + (i * RFCORE_XREG_SRCMATCH_EXT_ENTRY_OFFSET); |
| |
| for (j = 0; j < sizeof(otExtAddress); j++) |
| { |
| if (HWREG(addr + j) != aExtAddress->m8[j]) |
| { |
| break; |
| } |
| } |
| |
| if (j == sizeof(otExtAddress)) |
| { |
| entry = i; |
| break; |
| } |
| } |
| |
| return entry; |
| } |
| |
| void setSrcMatchEntryEnableStatus(bool aShort, uint8_t aEntry, bool aEnable) |
| { |
| uint8_t entry = aShort ? aEntry : (2 * aEntry); |
| uint8_t index = entry / 8; |
| uint32_t *addrEn = aShort ? (uint32_t *)RFCORE_XREG_SRCSHORTEN0 : (uint32_t *)RFCORE_XREG_SRCEXTEN0; |
| uint32_t *addrAutoPendEn = aShort ? (uint32_t *)RFCORE_FFSM_SRCSHORTPENDEN0 : (uint32_t *)RFCORE_FFSM_SRCEXTPENDEN0; |
| uint32_t bitMask = 0x00000001; |
| |
| if (aEnable) |
| { |
| HWREG(addrEn + index) |= (bitMask) << (entry % 8); |
| HWREG(addrAutoPendEn + index) |= (bitMask) << (entry % 8); |
| } |
| else |
| { |
| HWREG(addrEn + index) &= ~((bitMask) << (entry % 8)); |
| HWREG(addrAutoPendEn + index) &= ~((bitMask) << (entry % 8)); |
| } |
| } |
| |
| int8_t findSrcMatchAvailEntry(bool aShort) |
| { |
| int8_t entry = -1; |
| uint32_t bitMask; |
| uint32_t shortEnableStatus = getSrcMatchEntriesEnableStatus(true); |
| uint32_t extEnableStatus = getSrcMatchEntriesEnableStatus(false); |
| |
| otLogDebgPlat("Short enable status: 0x%x", shortEnableStatus); |
| otLogDebgPlat("Ext enable status: 0x%x", extEnableStatus); |
| |
| if (aShort) |
| { |
| bitMask = 0x00000001; |
| |
| for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_SHORT_ENTRIES; i++) |
| { |
| if ((extEnableStatus & bitMask) == 0) |
| { |
| if ((shortEnableStatus & bitMask) == 0) |
| { |
| entry = i; |
| break; |
| } |
| } |
| |
| if (i % 2 == 1) |
| { |
| extEnableStatus = extEnableStatus >> 2; |
| } |
| |
| shortEnableStatus = shortEnableStatus >> 1; |
| } |
| } |
| else |
| { |
| bitMask = 0x00000003; |
| |
| for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_EXT_ENTRIES; i++) |
| { |
| if (((extEnableStatus | shortEnableStatus) & bitMask) == 0) |
| { |
| entry = i; |
| break; |
| } |
| |
| extEnableStatus = extEnableStatus >> 2; |
| shortEnableStatus = shortEnableStatus >> 2; |
| } |
| } |
| |
| return entry; |
| } |
| |
| void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otLogInfoPlat("EnableSrcMatch=%d", aEnable ? 1 : 0); |
| |
| if (aEnable) |
| { |
| // only set FramePending when ack for data poll if there are queued messages |
| // for entries in the source match table. |
| HWREG(RFCORE_XREG_FRMCTRL1) &= ~RFCORE_XREG_FRMCTRL1_PENDING_OR; |
| } |
| else |
| { |
| // set FramePending for all ack. |
| HWREG(RFCORE_XREG_FRMCTRL1) |= RFCORE_XREG_FRMCTRL1_PENDING_OR; |
| } |
| } |
| |
| otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otError error = OT_ERROR_NONE; |
| int8_t entry = findSrcMatchAvailEntry(true); |
| uint32_t *addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE; |
| |
| otLogDebgPlat("Add ShortAddr entry: %d", entry); |
| |
| otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_BUFS); |
| |
| addr += (entry * RFCORE_XREG_SRCMATCH_SHORT_ENTRY_OFFSET); |
| |
| HWREG(addr++) = HWREG(RFCORE_FFSM_PAN_ID0); |
| HWREG(addr++) = HWREG(RFCORE_FFSM_PAN_ID1); |
| HWREG(addr++) = aShortAddress & 0xFF; |
| HWREG(addr++) = aShortAddress >> 8; |
| |
| setSrcMatchEntryEnableStatus(true, (uint8_t)(entry), true); |
| |
| exit: |
| return error; |
| } |
| |
| otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otError error = OT_ERROR_NONE; |
| int8_t entry = findSrcMatchAvailEntry(false); |
| uint32_t *addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE; |
| |
| otLogDebgPlat("Add ExtAddr entry: %d", entry); |
| |
| otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_BUFS); |
| |
| addr += (entry * RFCORE_XREG_SRCMATCH_EXT_ENTRY_OFFSET); |
| |
| for (uint8_t i = 0; i < sizeof(otExtAddress); i++) |
| { |
| HWREG(addr++) = aExtAddress->m8[i]; |
| } |
| |
| setSrcMatchEntryEnableStatus(false, (uint8_t)(entry), true); |
| |
| exit: |
| return error; |
| } |
| |
| otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otError error = OT_ERROR_NONE; |
| int8_t entry = findSrcMatchShortEntry(aShortAddress); |
| |
| otLogDebgPlat("Clear ShortAddr entry: %d", entry); |
| |
| otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_ADDRESS); |
| |
| setSrcMatchEntryEnableStatus(true, (uint8_t)(entry), false); |
| |
| exit: |
| return error; |
| } |
| |
| otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otError error = OT_ERROR_NONE; |
| int8_t entry = findSrcMatchExtEntry(aExtAddress); |
| |
| otLogDebgPlat("Clear ExtAddr entry: %d", entry); |
| |
| otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_ADDRESS); |
| |
| setSrcMatchEntryEnableStatus(false, (uint8_t)(entry), false); |
| |
| exit: |
| return error; |
| } |
| |
| void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| uint32_t *addrEn = (uint32_t *)RFCORE_XREG_SRCSHORTEN0; |
| uint32_t *addrAutoPendEn = (uint32_t *)RFCORE_FFSM_SRCSHORTPENDEN0; |
| |
| otLogDebgPlat("Clear ShortAddr entries", NULL); |
| |
| for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++) |
| { |
| HWREG(addrEn++) = 0; |
| HWREG(addrAutoPendEn++) = 0; |
| } |
| } |
| |
| void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| uint32_t *addrEn = (uint32_t *)RFCORE_XREG_SRCEXTEN0; |
| uint32_t *addrAutoPendEn = (uint32_t *)RFCORE_FFSM_SRCEXTPENDEN0; |
| |
| otLogDebgPlat("Clear ExtAddr entries", NULL); |
| |
| for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++) |
| { |
| HWREG(addrEn++) = 0; |
| HWREG(addrAutoPendEn++) = 0; |
| } |
| } |
| |
| otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| OT_UNUSED_VARIABLE(aScanChannel); |
| OT_UNUSED_VARIABLE(aScanDuration); |
| |
| return OT_ERROR_NOT_IMPLEMENTED; |
| } |
| |
| otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| otError error = OT_ERROR_NONE; |
| |
| otEXPECT_ACTION(aPower != NULL, error = OT_ERROR_INVALID_ARGS); |
| *aPower = sTxPower; |
| |
| exit: |
| return error; |
| } |
| |
| otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| setTxPower(aPower); |
| return OT_ERROR_NONE; |
| } |
| |
| otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| OT_UNUSED_VARIABLE(aThreshold); |
| |
| return OT_ERROR_NOT_IMPLEMENTED; |
| } |
| |
| otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| OT_UNUSED_VARIABLE(aThreshold); |
| |
| return OT_ERROR_NOT_IMPLEMENTED; |
| } |
| |
| int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| #if OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM |
| if (cc2538RadioGetHgm()) |
| { |
| return CC2592_RECEIVE_SENSITIVITY_HGM; |
| } |
| else |
| { |
| return CC2592_RECEIVE_SENSITIVITY_LGM; |
| } |
| #else // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM |
| return CC2538_RECEIVE_SENSITIVITY; |
| #endif // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM |
| } |