diff --git a/examples/platforms/cc2538/alarm.c b/examples/platforms/cc2538/alarm.c index dd6cc206b..7deefda0c 100644 --- a/examples/platforms/cc2538/alarm.c +++ b/examples/platforms/cc2538/alarm.c @@ -52,6 +52,17 @@ static uint32_t sAlarmT0 = 0; static uint32_t sAlarmDt = 0; static bool sIsRunning = false; +static uint8_t sTimersIsRunning = 0; +static uint32_t sTimersExpireAt[OT_CC2538_TIMERS_COUNT]; + +extern void cc2538EnergyScanTimerHandler(void); + +void cc2538SetTimer(otCC2538Timer aTimer, uint32_t aDelay) +{ + sTimersIsRunning |= (1 << aTimer); + sTimersExpireAt[aTimer] = sCounter + aDelay; +} + void cc2538AlarmInit(void) { HWREG(NVIC_ST_RELOAD) = kSystemClock / kTicksPerSec; @@ -84,6 +95,15 @@ void cc2538AlarmProcess(otInstance *aInstance) uint32_t expires; bool fire = false; + if (sTimersIsRunning) + { + if ((int32_t)(sTimersExpireAt[OT_CC2538_TIMER_ENERGY_SCAN] - sCounter) < 0) + { + sTimersIsRunning &= ~(1 << OT_CC2538_TIMER_ENERGY_SCAN); + cc2538EnergyScanTimerHandler(); + } + } + if (sIsRunning) { expires = sAlarmT0 + sAlarmDt; diff --git a/examples/platforms/cc2538/cc2538-reg.h b/examples/platforms/cc2538/cc2538-reg.h index 0da810b8a..54972fbea 100644 --- a/examples/platforms/cc2538/cc2538-reg.h +++ b/examples/platforms/cc2538/cc2538-reg.h @@ -95,6 +95,7 @@ #define RFCORE_XREG_FSMSTAT1 0x4008864C // Radio status register #define RFCORE_XREG_FIFOPCTRL 0x40088650 // FIFOP threshold #define RFCORE_XREG_CCACTRL0 0x40088658 // CCA threshold +#define RFCORE_XREG_RSSI 0x40088660 // RSSI status register #define RFCORE_XREG_RSSISTAT 0x40088664 // RSSI valid status register #define RFCORE_XREG_AGCCTRL1 0x400886C8 // AGC reference level #define RFCORE_XREG_RFC_OBS_CTRL 0x400887AC // RF Core observable output @@ -109,6 +110,7 @@ #define RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN 0x00000001 // Enables frame filtering #define RFCORE_XREG_FRMCTRL0_AUTOACK 0x00000020 +#define RFCORE_XREG_FRMCTRL0_ENERGY_SCAN 0x00000010 #define RFCORE_XREG_FRMCTRL0_AUTOCRC 0x00000040 #define RFCORE_XREG_FRMCTRL0_INFINITY_RX 0x00000008 diff --git a/examples/platforms/cc2538/platform-cc2538.h b/examples/platforms/cc2538/platform-cc2538.h index 5fee64710..f89b01bbb 100644 --- a/examples/platforms/cc2538/platform-cc2538.h +++ b/examples/platforms/cc2538/platform-cc2538.h @@ -104,4 +104,19 @@ void cc2538RadioSetHgm(bool aState); bool cc2538RadioGetHgm(void); #endif // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM +typedef enum +{ + OT_CC2538_TIMER_ENERGY_SCAN, ///< Internal timer for energy scan + OT_CC2538_TIMERS_COUNT, ///< Number of internal timers +} otCC2538Timer; + +/** + * This function sets the internal timer. + * + * @param[in] aTimer The timer identifier. + * @param[in] aDelay The delay to trigger the timer, and must be no more than `INT32_MAX`. + * + */ +void cc2538SetTimer(otCC2538Timer aTimer, uint32_t aDelay); + #endif // PLATFORM_CC2538_H_ diff --git a/examples/platforms/cc2538/radio.c b/examples/platforms/cc2538/radio.c index cd2b35125..f93366ab5 100644 --- a/examples/platforms/cc2538/radio.c +++ b/examples/platforms/cc2538/radio.c @@ -178,6 +178,8 @@ static bool sIsReceiverEnabled = false; static uint8_t sDroppedFrameLength = 0; #endif +static int8_t cc2538RadioGetRssiOffset(void); + void enableReceiver(void) { if (!sIsReceiverEnabled) @@ -622,14 +624,30 @@ int8_t otPlatRadioGetRssi(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); - return 0; + int8_t rssi = OT_RADIO_RSSI_INVALID; + + if ((HWREG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) != 0) + { + rssi = HWREG(RFCORE_XREG_RSSI) & 0xff; + + if (rssi <= cc2538RadioGetRssiOffset() - 128) + { + rssi -= cc2538RadioGetRssiOffset(); + } + else + { + rssi = -128; + } + } + + return rssi; } otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); - return OT_RADIO_CAPS_NONE; + return OT_RADIO_CAPS_ENERGY_SCAN; } static bool cc2538RadioGetPromiscuous(void) @@ -1017,6 +1035,23 @@ int8_t findSrcMatchAvailEntry(bool aShort) return entry; } +void cc2538EnergyScanTimerHandler(void) +{ + int8_t rssi = otPlatRadioGetRssi(sInstance); + + disableReceiver(); + + HWREG(RFCORE_XREG_FRMCTRL0) &= ~RFCORE_XREG_FRMCTRL0_ENERGY_SCAN; + HWREG(RFCORE_XREG_FREQCTRL) = 11 + (sChannel - 11) * 5; + + if (sIsReceiverEnabled) + { + enableReceiver(); + } + + otPlatRadioEnergyScanDone(sInstance, rssi); +} + void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) { OT_UNUSED_VARIABLE(aInstance); @@ -1155,10 +1190,31 @@ void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) 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; + otLogInfoPlat("ScanChannel=%d", aScanChannel); + + if (aScanChannel != sChannel) + { + if (sIsReceiverEnabled) + { + disableReceiver(); + } + + HWREG(RFCORE_XREG_FREQCTRL) = 11 + (aScanChannel - 11) * 5; + + enableReceiver(); + } + else if (!sIsReceiverEnabled) + { + enableReceiver(); + } + + // Collect peak signal strength + HWREG(RFCORE_XREG_FRMCTRL0) |= RFCORE_XREG_FRMCTRL0_ENERGY_SCAN; + + cc2538SetTimer(OT_CC2538_TIMER_ENERGY_SCAN, aScanDuration); + + return OT_ERROR_NONE; } otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)