1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file implements the OpenThread platform abstraction for radio communication.
32  *
33  */
34 
35 #include <openthread/config.h>
36 #include <openthread/platform/alarm-milli.h>
37 #include <openthread/platform/diag.h>
38 #include <openthread/platform/radio.h>
39 
40 #include "platform-cc2538.h"
41 #include "common/logging.hpp"
42 #include "utils/code_utils.h"
43 
44 #define RFCORE_XREG_RFIRQM0 0x4008868C // RF interrupt masks
45 #define RFCORE_XREG_RFIRQM1 0x40088690 // RF interrupt masks
46 #define RFCORE_XREG_RFERRM 0x40088694  // RF error interrupt mask
47 
48 #define RFCORE_SFR_RFIRQF0_RXMASKZERO 0x00000080      // RXENABLE is now completely clear
49 #define RFCORE_SFR_RFIRQF0_RXPKTDONE 0x00000040       // A complete frame has been received
50 #define RFCORE_SFR_RFIRQF0_FRAME_ACCEPTED 0x00000020  // Frame has passed frame filtering
51 #define RFCORE_SFR_RFIRQF0_SRC_MATCH_FOUND 0x00000010 // Source match is found
52 #define RFCORE_SFR_RFIRQF0_SRC_MATCH_DONE 0x00000008  // Source matching is complete
53 #define RFCORE_SFR_RFIRQF0_FIFOP 0x00000004           // The number of bytes in the RX fifo is above threshold
54 #define RFCORE_SFR_RFIRQF0_SFD 0x00000002             // SFD has been received or transmitted
55 #define RFCORE_SFR_RFIRQF0_ACT_UNUSED 0x00000001      // Reserved
56 
57 #define RFCORE_XREG_RFIRQM0_RXMASKZERO 0x00000080
58 #define RFCORE_XREG_RFIRQM0_RXPKTDONE 0x00000040
59 #define RFCORE_XREG_RFIRQM0_FRAME_ACCEPTED 0x00000020
60 #define RFCORE_XREG_RFIRQM0_SRC_MATCH_FOUND 0x00000010
61 #define RFCORE_XREG_RFIRQM0_SRC_MATCH_DONE 0x00000008
62 #define RFCORE_XREG_RFIRQM0_FIFOP 0x00000004
63 #define RFCORE_XREG_RFIRQM0_SFD 0x00000002
64 #define RFCORE_XREG_RFIRQM0_ACT_UNUSED 0x00000001
65 
66 #define RFCORE_SFR_RFIRQF1_CSP_WAIT 0x00000020
67 #define RFCORE_SFR_RFIRQF1_CSP_STOP 0x00000010
68 #define RFCORE_SFR_RFIRQF1_CSP_MANINT 0x00000008
69 #define RFCORE_SFR_RFIRQF1_RF_IDLE 0x00000004
70 #define RFCORE_SFR_RFIRQF1_TXDONE 0x00000002
71 #define RFCORE_SFR_RFIRQF1_TXACKDONE 0x00000001
72 
73 #define RFCORE_XREG_RFIRQM1_CSP_WAIT 0x00000020
74 #define RFCORE_XREG_RFIRQM1_CSP_STOP 0x00000010
75 #define RFCORE_XREG_RFIRQM1_CSP_MANINT 0x00000008
76 #define RFCORE_XREG_RFIRQM1_RF_IDLE 0x00000004
77 #define RFCORE_XREG_RFIRQM1_TXDONE 0x00000002
78 #define RFCORE_XREG_RFIRQM1_TXACKDONE 0x00000001
79 
80 #define RFCORE_XREG_RFERRM_STROBE_ERR 0x00000040
81 #define RFCORE_XREG_RFERRM_TXUNDERF 0x00000020
82 #define RFCORE_XREG_RFERRM_TXOVERF 0x00000010
83 #define RFCORE_XREG_RFERRM_RXUNDERF 0x00000008
84 #define RFCORE_XREG_RFERRM_RXOVERF 0x00000004
85 #define RFCORE_XREG_RFERRM_RXABO 0x00000002
86 #define RFCORE_XREG_RFERRM_NLOCK 0x00000001
87 
88 enum
89 {
90     IEEE802154_MIN_LENGTH      = 5,
91     IEEE802154_MAX_LENGTH      = 127,
92     IEEE802154_ACK_LENGTH      = 5,
93     IEEE802154_FRAME_TYPE_MASK = 0x7,
94     IEEE802154_FRAME_TYPE_ACK  = 0x2,
95     IEEE802154_FRAME_PENDING   = 1 << 4,
96     IEEE802154_ACK_REQUEST     = 1 << 5,
97     IEEE802154_DSN_OFFSET      = 2,
98 };
99 
100 enum
101 {
102     CC2538_RSSI_OFFSET = OPENTHREAD_CONFIG_CC2538_RSSI_OFFSET,
103     // TI AN130 (SWRA447) Table 4 (bottom of page 3)
104     CC2592_RSSI_OFFSET_HGM = 85,
105     CC2592_RSSI_OFFSET_LGM = 81,
106     CC2538_CRC_BIT_MASK    = 0x80,
107     CC2538_LQI_BIT_MASK    = 0x7f,
108 };
109 
110 // All values in dBm
111 enum
112 {
113     CC2538_RECEIVE_SENSITIVITY = OPENTHREAD_CONFIG_CC2538_RECEIVE_SENSITIVITY,
114     // TI AN130 (SWRA447) Table 3 (middle of page 3)
115     CC2592_RECEIVE_SENSITIVITY_LGM = -99,
116     CC2592_RECEIVE_SENSITIVITY_HGM = -101,
117 };
118 
119 typedef struct TxPowerTable
120 {
121     int8_t  mTxPowerVal;
122     uint8_t mTxPowerReg;
123 } TxPowerTable;
124 
125 // The transmit power table.
126 static const TxPowerTable sTxPowerTable[] = {
127 #if OPENTHREAD_CONFIG_CC2538_WITH_CC2592
128     // CC2538 using CC2592 PA
129     // Values are from AN130 table 6 (page 4)
130     {22, 0xFF}, // 22.0dBm =~ 158.5mW
131     {21, 0xD5}, // 20.9dBm =~ 123.0mW
132     {20, 0xC5}, // 20.1dBm =~ 102.3mW
133     {19, 0xB0}, // 19.0dBm =~  79.4mW
134     {18, 0xA1}, // 17.8dBm =~  60.3mW
135     {16, 0x91}, // 16.4dBm =~  43.7mW
136     {15, 0x88}, // 14.9dBm =~  30.9mW
137     {13, 0x72}, // 13.0dBm =~  20.0mW
138     {11, 0x62}, // 11.0dBm =~  12.6mW
139     {10, 0x58}, //  9.5dBm =~   8.9mW
140     {8, 0x42},  //  7.5dBm =~   5.6mW
141 #else
142     // CC2538 operating "bare foot"
143     // Values are from SmartRF Studio 2.4.0
144     {7, 0xFF},   //
145     {5, 0xED},   //
146     {3, 0xD5},   //
147     {1, 0xC5},   //
148     {0, 0xB6},   //
149     {-1, 0xB0},  //
150     {-3, 0xA1},  //
151     {-5, 0x91},  //
152     {-7, 0x88},  //
153     {-9, 0x72},  //
154     {-11, 0x62}, //
155     {-13, 0x58}, //
156     {-15, 0x42}, //
157     {-24, 0x00}, //
158 #endif
159 };
160 
161 static otRadioFrame sTransmitFrame;
162 static otRadioFrame sReceiveFrame;
163 static otError      sTransmitError;
164 static otError      sReceiveError;
165 
166 static uint8_t sTransmitPsdu[IEEE802154_MAX_LENGTH];
167 static uint8_t sReceivePsdu[IEEE802154_MAX_LENGTH];
168 static uint8_t sChannel = 0;
169 static int8_t  sTxPower = 0;
170 
171 static otRadioState sState             = OT_RADIO_STATE_DISABLED;
172 static bool         sIsReceiverEnabled = false;
173 
174 #if OPENTHREAD_CONFIG_LOG_PLATFORM && OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
175 // Debugging _and_ logging are enabled, so if there's a dropped frame
176 // we'll need to store the length here as using snprintf from an interrupt
177 // handler is not a good idea.
178 static uint8_t sDroppedFrameLength = 0;
179 #endif
180 
181 static int8_t cc2538RadioGetRssiOffset(void);
182 
enableReceiver(void)183 void enableReceiver(void)
184 {
185     if (!sIsReceiverEnabled)
186     {
187         otLogInfoPlat("Enabling receiver", NULL);
188 
189         // flush rxfifo
190         HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
191         HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
192 
193         // enable receiver
194         HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_RXON;
195         sIsReceiverEnabled     = true;
196     }
197 }
198 
disableReceiver(void)199 void disableReceiver(void)
200 {
201     if (sIsReceiverEnabled)
202     {
203         otLogInfoPlat("Disabling receiver", NULL);
204 
205         while (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)
206             ;
207 
208         // flush rxfifo
209         HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
210         HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
211 
212         if (HWREG(RFCORE_XREG_RXENABLE) != 0)
213         {
214             // disable receiver
215             HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_RFOFF;
216         }
217 
218         sIsReceiverEnabled = false;
219     }
220 }
221 
setChannel(uint8_t aChannel)222 void setChannel(uint8_t aChannel)
223 {
224     if (sChannel != aChannel)
225     {
226         bool enabled = false;
227 
228         if (sIsReceiverEnabled)
229         {
230             disableReceiver();
231             enabled = true;
232         }
233 
234         otLogInfoPlat("Channel=%d", aChannel);
235 
236         HWREG(RFCORE_XREG_FREQCTRL) = 11 + (aChannel - 11) * 5;
237         sChannel                    = aChannel;
238 
239         if (enabled)
240         {
241             enableReceiver();
242         }
243     }
244 }
245 
setTxPower(int8_t aTxPower)246 void setTxPower(int8_t aTxPower)
247 {
248     uint8_t i = 0;
249 
250     if (sTxPower != aTxPower)
251     {
252         otLogInfoPlat("TxPower=%d", aTxPower);
253 
254         for (i = sizeof(sTxPowerTable) / sizeof(TxPowerTable) - 1; i > 0; i--)
255         {
256             if (aTxPower < sTxPowerTable[i].mTxPowerVal)
257             {
258                 break;
259             }
260         }
261 
262         HWREG(RFCORE_XREG_TXPOWER) = sTxPowerTable[i].mTxPowerReg;
263         sTxPower                   = aTxPower;
264     }
265 }
266 
cc2538SrcMatchEnabled(void)267 static bool cc2538SrcMatchEnabled(void)
268 {
269     return (HWREG(RFCORE_XREG_FRMCTRL1) & RFCORE_XREG_FRMCTRL1_PENDING_OR) == 0;
270 }
271 
cc2538GetSrcMatchFoundIntFlag(void)272 static bool cc2538GetSrcMatchFoundIntFlag(void)
273 {
274     bool flag = (HWREG(RFCORE_SFR_RFIRQF0) & RFCORE_SFR_RFIRQF0_SRC_MATCH_FOUND) != 0;
275     if (flag)
276     {
277         HWREG(RFCORE_SFR_RFIRQF0) &= ~RFCORE_SFR_RFIRQF0_SRC_MATCH_FOUND;
278     }
279     return flag;
280 }
281 
otPlatRadioGetIeeeEui64(otInstance * aInstance,uint8_t * aIeeeEui64)282 void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
283 {
284     OT_UNUSED_VARIABLE(aInstance);
285 
286     // EUI64 is in a mixed-endian format.  Split in two halves, each 32-bit
287     // half is in little-endian format (machine endian).  However, the
288     // most significant part of the EUI64 comes first, so we can't cheat
289     // with a uint64_t!
290     //
291     // See https://e2e.ti.com/support/wireless_connectivity/low_power_rf_tools/f/155/p/307344/1072252
292 
293     volatile uint32_t *eui64 = &HWREG(IEEE_EUI64);
294 
295     // Read first 32-bits
296     uint32_t part = eui64[0];
297     for (uint8_t i = 0; i < (OT_EXT_ADDRESS_SIZE / 2); i++)
298     {
299         aIeeeEui64[3 - i] = part;
300         part >>= 8;
301     }
302 
303     // Read the last 32-bits
304     part = eui64[1];
305     for (uint8_t i = 0; i < (OT_EXT_ADDRESS_SIZE / 2); i++)
306     {
307         aIeeeEui64[7 - i] = part;
308         part >>= 8;
309     }
310 }
311 
otPlatRadioSetPanId(otInstance * aInstance,uint16_t aPanid)312 void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanid)
313 {
314     OT_UNUSED_VARIABLE(aInstance);
315 
316     otLogInfoPlat("PANID=%X", aPanid);
317 
318     HWREG(RFCORE_FFSM_PAN_ID0) = aPanid & 0xFF;
319     HWREG(RFCORE_FFSM_PAN_ID1) = aPanid >> 8;
320 }
321 
otPlatRadioSetExtendedAddress(otInstance * aInstance,const otExtAddress * aAddress)322 void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress)
323 {
324     OT_UNUSED_VARIABLE(aInstance);
325 
326     otLogInfoPlat("ExtAddr=%X%X%X%X%X%X%X%X", aAddress->m8[7], aAddress->m8[6], aAddress->m8[5], aAddress->m8[4],
327                   aAddress->m8[3], aAddress->m8[2], aAddress->m8[1], aAddress->m8[0]);
328 
329     for (int i = 0; i < 8; i++)
330     {
331         ((volatile uint32_t *)RFCORE_FFSM_EXT_ADDR0)[i] = aAddress->m8[i];
332     }
333 }
334 
otPlatRadioSetShortAddress(otInstance * aInstance,uint16_t aAddress)335 void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress)
336 {
337     OT_UNUSED_VARIABLE(aInstance);
338 
339     otLogInfoPlat("ShortAddr=%X", aAddress);
340 
341     HWREG(RFCORE_FFSM_SHORT_ADDR0) = aAddress & 0xFF;
342     HWREG(RFCORE_FFSM_SHORT_ADDR1) = aAddress >> 8;
343 }
344 
cc2538RadioInit(void)345 void cc2538RadioInit(void)
346 {
347     sTransmitFrame.mLength = 0;
348     sTransmitFrame.mPsdu   = sTransmitPsdu;
349     sReceiveFrame.mLength  = 0;
350     sReceiveFrame.mPsdu    = sReceivePsdu;
351 
352 #if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
353     // Enable interrupts for RX/TX, interrupt 26.
354     // That's NVIC index 0 (26 >> 5) bit 26 (26 & 0x1f).
355     HWREG(NVIC_EN0 + (0 * 4)) = (1 << 26);
356     HWREG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_RXPKTDONE;
357 #endif
358 
359     // enable clock
360     HWREG(SYS_CTRL_RCGCRFC) = SYS_CTRL_RCGCRFC_RFC0;
361     HWREG(SYS_CTRL_SCGCRFC) = SYS_CTRL_SCGCRFC_RFC0;
362     HWREG(SYS_CTRL_DCGCRFC) = SYS_CTRL_DCGCRFC_RFC0;
363 
364     // Table 23-7.
365     HWREG(RFCORE_XREG_AGCCTRL1)              = 0x15;
366     HWREG(RFCORE_XREG_TXFILTCFG)             = 0x09;
367     HWREG(ANA_REGS_BASE + ANA_REGS_O_IVCTRL) = 0x0b;
368 
369     HWREG(RFCORE_XREG_CCACTRL0)  = 0xf8;
370     HWREG(RFCORE_XREG_FIFOPCTRL) = IEEE802154_MAX_LENGTH;
371 
372     HWREG(RFCORE_XREG_FRMCTRL0) = RFCORE_XREG_FRMCTRL0_AUTOCRC | RFCORE_XREG_FRMCTRL0_AUTOACK;
373 
374     // default: SRCMATCH.SRC_MATCH_EN(1), SRCMATCH.AUTOPEND(1),
375     // SRCMATCH.PEND_DATAREQ_ONLY(1), RFCORE_XREG_FRMCTRL1_PENDING_OR(0)
376 
377     HWREG(RFCORE_XREG_TXPOWER) = sTxPowerTable[0].mTxPowerReg;
378     sTxPower                   = sTxPowerTable[0].mTxPowerVal;
379 
380 #if OPENTHREAD_CONFIG_CC2538_WITH_CC2592
381     // PA_EN pin configuration.
382     // Step 1. make it an output
383     HWREG(GPIO_C_BASE | GPIO_O_DIR) |= GPIO_PIN(OPENTHREAD_CONFIG_CC2592_PA_EN_PIN);
384     // Step 2. Route PA_PD to OBS0 and invert it to produce PA_EN
385     HWREG_ARR(RFCORE_XREG_RFC_OBS_CTRL, 0) = RFCORE_XREG_RFC_OBS_POL_INV      // Invert the output
386                                              | RFCORE_XREG_RFC_OBS_MUX_PA_PD; // PA "power down" signal
387     // Step 3. Connect the selected pin to OBS0 and enable OBS0.
388     HWREG_ARR(CCTEST_OBSSEL, OPENTHREAD_CONFIG_CC2592_PA_EN_PIN) = CCTEST_OBSSEL_EN          // Enable the output
389                                                                    | CCTEST_OBSSEL_SEL_OBS0; // Select OBS0
390 
391     // LNA_EN pin configuration.
392     HWREG(GPIO_C_BASE | GPIO_O_DIR) |= GPIO_PIN(OPENTHREAD_CONFIG_CC2592_LNA_EN_PIN);
393     HWREG_ARR(RFCORE_XREG_RFC_OBS_CTRL, 1) = RFCORE_XREG_RFC_OBS_POL_INV | RFCORE_XREG_RFC_OBS_MUX_LNA_PD;
394     HWREG_ARR(CCTEST_OBSSEL, OPENTHREAD_CONFIG_CC2592_LNA_EN_PIN) = CCTEST_OBSSEL_EN | CCTEST_OBSSEL_SEL_OBS1;
395 
396 #if OPENTHREAD_CONFIG_CC2592_USE_HGM
397     // HGM pin configuration.  Set the pin state first so we don't glitch.
398     cc2538RadioSetHgm(OPENTHREAD_CONFIG_CC2592_HGM_DEFAULT_STATE);
399     HWREG(OPENTHREAD_CONFIG_CC2592_HGM_PORT | GPIO_O_DIR) |= GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN);
400 #endif // OPENTHREAD_CONFIG_CC2592_USE_HGM
401 #endif // OPENTHREAD_CONFIG_CC2538_WITH_CC2592
402 
403     otLogInfoPlat("Initialized", NULL);
404 }
405 
406 #if OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM
cc2538RadioSetHgm(bool aState)407 void cc2538RadioSetHgm(bool aState)
408 {
409     if (aState)
410     {
411         HWREG_ARR(OPENTHREAD_CONFIG_CC2592_HGM_PORT, GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN)) =
412             GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN);
413     }
414     else
415     {
416         HWREG_ARR(OPENTHREAD_CONFIG_CC2592_HGM_PORT, GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN)) = 0;
417     }
418 }
419 
cc2538RadioGetHgm(void)420 bool cc2538RadioGetHgm(void)
421 {
422     if (HWREG_ARR(OPENTHREAD_CONFIG_CC2592_HGM_PORT, GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN)) &
423         GPIO_PIN(OPENTHREAD_CONFIG_CC2592_HGM_PIN))
424     {
425         return true;
426     }
427     else
428     {
429         return false;
430     }
431 }
432 #endif // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM
433 
otPlatRadioIsEnabled(otInstance * aInstance)434 bool otPlatRadioIsEnabled(otInstance *aInstance)
435 {
436     OT_UNUSED_VARIABLE(aInstance);
437 
438     return (sState != OT_RADIO_STATE_DISABLED) ? true : false;
439 }
440 
otPlatRadioEnable(otInstance * aInstance)441 otError otPlatRadioEnable(otInstance *aInstance)
442 {
443     if (!otPlatRadioIsEnabled(aInstance))
444     {
445         otLogDebgPlat("State=OT_RADIO_STATE_SLEEP", NULL);
446         sState = OT_RADIO_STATE_SLEEP;
447     }
448 
449     return OT_ERROR_NONE;
450 }
451 
otPlatRadioDisable(otInstance * aInstance)452 otError otPlatRadioDisable(otInstance *aInstance)
453 {
454     if (otPlatRadioIsEnabled(aInstance))
455     {
456         otLogDebgPlat("State=OT_RADIO_STATE_DISABLED", NULL);
457         sState = OT_RADIO_STATE_DISABLED;
458     }
459 
460     return OT_ERROR_NONE;
461 }
462 
otPlatRadioSleep(otInstance * aInstance)463 otError otPlatRadioSleep(otInstance *aInstance)
464 {
465     OT_UNUSED_VARIABLE(aInstance);
466 
467     otError error = OT_ERROR_INVALID_STATE;
468 
469     if (sState == OT_RADIO_STATE_SLEEP || sState == OT_RADIO_STATE_RECEIVE)
470     {
471         otLogDebgPlat("State=OT_RADIO_STATE_SLEEP", NULL);
472         error  = OT_ERROR_NONE;
473         sState = OT_RADIO_STATE_SLEEP;
474         disableReceiver();
475     }
476 
477     return error;
478 }
479 
otPlatRadioReceive(otInstance * aInstance,uint8_t aChannel)480 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
481 {
482     OT_UNUSED_VARIABLE(aInstance);
483 
484     otError error = OT_ERROR_INVALID_STATE;
485 
486     if (sState != OT_RADIO_STATE_DISABLED)
487     {
488         otLogDebgPlat("State=OT_RADIO_STATE_RECEIVE", NULL);
489 
490         error  = OT_ERROR_NONE;
491         sState = OT_RADIO_STATE_RECEIVE;
492         setChannel(aChannel);
493         sReceiveFrame.mChannel = aChannel;
494         enableReceiver();
495     }
496 
497     return error;
498 }
499 
setupTransmit(otRadioFrame * aFrame)500 static void setupTransmit(otRadioFrame *aFrame)
501 {
502     int i;
503 
504     // wait for current TX operation to complete, if any.
505     while (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)
506         ;
507 
508     // flush txfifo
509     HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHTX;
510     HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHTX;
511 
512     // frame length
513     HWREG(RFCORE_SFR_RFDATA) = aFrame->mLength;
514 
515     // frame data
516     for (i = 0; i < aFrame->mLength; i++)
517     {
518         HWREG(RFCORE_SFR_RFDATA) = aFrame->mPsdu[i];
519     }
520 
521     setChannel(aFrame->mChannel);
522 }
523 
otPlatRadioTransmit(otInstance * aInstance,otRadioFrame * aFrame)524 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
525 {
526     OT_UNUSED_VARIABLE(aInstance);
527 
528     otError error = OT_ERROR_INVALID_STATE;
529 
530     if (sState == OT_RADIO_STATE_RECEIVE)
531     {
532         int i;
533 
534         error          = OT_ERROR_NONE;
535         sState         = OT_RADIO_STATE_TRANSMIT;
536         sTransmitError = OT_ERROR_NONE;
537 
538         setupTransmit(aFrame);
539 
540         // Set up a counter to inform us if we get stuck.
541         i = 1000000;
542 
543         // Wait for radio to enter receive state.
544         while ((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_RX_ACTIVE) == 0)
545         {
546             // Count down the cycles, and emit a message if we get to zero.
547             // Ideally, we should never get there!
548             if (i)
549             {
550                 i--;
551             }
552             else
553             {
554                 otLogCritPlat("Radio is stuck!!! FSMSTAT0=0x%08x FSMSTAT1=0x%08x RFERRF=0x%08x",
555                               HWREG(RFCORE_XREG_FSMSTAT0), HWREG(RFCORE_XREG_FSMSTAT1), HWREG(RFCORE_SFR_RFERRF));
556                 i = 1000000;
557             }
558 
559             // Ensure we haven't overflowed the RX buffer in the mean time, as this
560             // will cause a deadlock here otherwise.  Similarly, if we see an aborted
561             // RX, handle that here too to prevent deadlock.
562             if (HWREG(RFCORE_SFR_RFERRF) & (RFCORE_SFR_RFERRF_RXOVERF | RFCORE_SFR_RFERRF_RXABO))
563             {
564                 if (HWREG(RFCORE_SFR_RFERRF) & RFCORE_SFR_RFERRF_RXOVERF)
565                 {
566                     otLogCritPlat("RX Buffer Overflow detected", NULL);
567                 }
568 
569                 if (HWREG(RFCORE_SFR_RFERRF) & RFCORE_SFR_RFERRF_RXABO)
570                 {
571                     otLogCritPlat("Aborted RX detected", NULL);
572                 }
573 
574                 // Flush the RX buffer
575                 HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
576                 HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
577             }
578 
579             // Check for idle state.  After flushing the RX buffer, we may wind up here.
580             if (!(HWREG(RFCORE_XREG_FSMSTAT1) & (RFCORE_XREG_FSMSTAT1_TX_ACTIVE | RFCORE_XREG_FSMSTAT1_RX_ACTIVE)))
581             {
582                 otLogCritPlat("Idle state detected", NULL);
583 
584                 // In this case, the state of our driver mis-matches our state.  So force
585                 // matters by clearing our channel variable and calling setChannel.  This
586                 // should bring our radio into the RX state, which should allow us to go
587                 // into TX.
588                 sChannel = 0;
589                 setupTransmit(aFrame);
590             }
591         }
592 
593         // wait for valid rssi
594         while ((HWREG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0)
595             ;
596 
597         otEXPECT_ACTION(((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_CCA) &&
598                          !((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_SFD))),
599                         sTransmitError = OT_ERROR_CHANNEL_ACCESS_FAILURE);
600 
601         // begin transmit
602         HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_TXON;
603 
604         otPlatRadioTxStarted(aInstance, aFrame);
605 
606         while (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE)
607             ;
608 
609         otLogDebgPlat("Transmitted %d bytes", aFrame->mLength);
610     }
611 
612 exit:
613     return error;
614 }
615 
otPlatRadioGetTransmitBuffer(otInstance * aInstance)616 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
617 {
618     OT_UNUSED_VARIABLE(aInstance);
619 
620     return &sTransmitFrame;
621 }
622 
otPlatRadioGetRssi(otInstance * aInstance)623 int8_t otPlatRadioGetRssi(otInstance *aInstance)
624 {
625     OT_UNUSED_VARIABLE(aInstance);
626 
627     int8_t rssi = OT_RADIO_RSSI_INVALID;
628 
629     if ((HWREG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) != 0)
630     {
631         rssi = HWREG(RFCORE_XREG_RSSI) & 0xff;
632 
633         if (rssi > cc2538RadioGetRssiOffset() - 128)
634         {
635             rssi -= cc2538RadioGetRssiOffset();
636         }
637         else
638         {
639             rssi = -128;
640         }
641     }
642 
643     return rssi;
644 }
645 
otPlatRadioGetCaps(otInstance * aInstance)646 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
647 {
648     OT_UNUSED_VARIABLE(aInstance);
649 
650     return OT_RADIO_CAPS_ENERGY_SCAN;
651 }
652 
cc2538RadioGetPromiscuous(void)653 static bool cc2538RadioGetPromiscuous(void)
654 {
655     return (HWREG(RFCORE_XREG_FRMFILT0) & RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN) == 0;
656 }
657 
otPlatRadioGetPromiscuous(otInstance * aInstance)658 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
659 {
660     OT_UNUSED_VARIABLE(aInstance);
661 
662     return cc2538RadioGetPromiscuous();
663 }
664 
cc2538RadioGetRssiOffset(void)665 static int8_t cc2538RadioGetRssiOffset(void)
666 {
667 #if OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM
668     if (cc2538RadioGetHgm())
669     {
670         return CC2592_RSSI_OFFSET_HGM;
671     }
672     else
673     {
674         return CC2592_RSSI_OFFSET_LGM;
675     }
676 #else  // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM
677     return CC2538_RSSI_OFFSET;
678 #endif // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM
679 }
680 
otPlatRadioSetPromiscuous(otInstance * aInstance,bool aEnable)681 void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
682 {
683     OT_UNUSED_VARIABLE(aInstance);
684 
685     otLogInfoPlat("PromiscuousMode=%d", aEnable ? 1 : 0);
686 
687     if (aEnable)
688     {
689         HWREG(RFCORE_XREG_FRMFILT0) &= ~RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN;
690     }
691     else
692     {
693         HWREG(RFCORE_XREG_FRMFILT0) |= RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN;
694     }
695 }
696 
readFrame(void)697 static void readFrame(void)
698 {
699     uint8_t length;
700     uint8_t crcCorr;
701     int     i;
702 
703     /*
704      * There is already a frame present in the buffer, return early so
705      * we do not overwrite it (hopefully we'll catch it on the next run).
706      */
707     otEXPECT(sReceiveFrame.mLength == 0);
708 
709     otEXPECT(sState == OT_RADIO_STATE_RECEIVE || sState == OT_RADIO_STATE_TRANSMIT);
710     otEXPECT((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) != 0);
711 
712     // read length
713     length = HWREG(RFCORE_SFR_RFDATA);
714     otEXPECT(IEEE802154_MIN_LENGTH <= length && length <= IEEE802154_MAX_LENGTH);
715 
716 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
717 #error Time sync requires the timestamp of SFD rather than that of rx done!
718 #else
719     // Timestamp
720     if (cc2538RadioGetPromiscuous())
721 #endif
722     {
723         // The current driver only supports milliseconds resolution.
724         sReceiveFrame.mInfo.mRxInfo.mTimestamp = otPlatAlarmMilliGetNow() * 1000;
725     }
726 
727     // read psdu
728     for (i = 0; i < length - 2; i++)
729     {
730         sReceiveFrame.mPsdu[i] = HWREG(RFCORE_SFR_RFDATA);
731     }
732 
733     sReceiveFrame.mInfo.mRxInfo.mRssi = (int8_t)HWREG(RFCORE_SFR_RFDATA) - cc2538RadioGetRssiOffset();
734     crcCorr                           = HWREG(RFCORE_SFR_RFDATA);
735 
736     if (crcCorr & CC2538_CRC_BIT_MASK)
737     {
738         sReceiveFrame.mLength            = length;
739         sReceiveFrame.mInfo.mRxInfo.mLqi = crcCorr & CC2538_LQI_BIT_MASK;
740 
741         if (length > IEEE802154_ACK_LENGTH)
742         {
743             // Set ACK FP flag for the received frame according to whether SRC_MATCH_FOUND was triggered just before
744             // if SRC MATCH is not enabled, SRC_MATCH_FOUND is not triggered and all ACK FP is always set
745             sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending =
746                 cc2538SrcMatchEnabled() ? cc2538GetSrcMatchFoundIntFlag() : true;
747         }
748     }
749     else
750     {
751         // resets rxfifo
752         HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
753         HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
754 #if OPENTHREAD_CONFIG_LOG_PLATFORM && OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
755         // Debugging _and_ logging are enabled, it may not be safe to do
756         // logging if we're in the interrupt context, so just stash the
757         // length and do the logging later.
758         sDroppedFrameLength = length;
759 #else
760         otLogDebgPlat("Dropping %d received bytes (Invalid CRC)", length);
761 #endif
762     }
763 
764     // check for rxfifo overflow
765     if ((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) != 0 &&
766         (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFO) == 0)
767     {
768         HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
769         HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
770     }
771 
772 exit:
773     return;
774 }
775 
cc2538RadioProcess(otInstance * aInstance)776 void cc2538RadioProcess(otInstance *aInstance)
777 {
778 #if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
779     // Disable the receive interrupt so that sReceiveFrame doesn't get
780     // blatted by the interrupt handler while we're polling.
781     HWREG(RFCORE_XREG_RFIRQM0) &= ~RFCORE_XREG_RFIRQM0_RXPKTDONE;
782 #endif
783 
784     readFrame();
785 
786 #if OPENTHREAD_CONFIG_LOG_PLATFORM && OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
787     if (sDroppedFrameLength != 0)
788     {
789         otLogDebgPlat("Dropping %d received bytes (Invalid CRC)", sDroppedFrameLength);
790         sDroppedFrameLength = 0;
791     }
792 #endif
793 
794     if ((sState == OT_RADIO_STATE_RECEIVE && sReceiveFrame.mLength > 0) ||
795         (sState == OT_RADIO_STATE_TRANSMIT && sReceiveFrame.mLength > IEEE802154_ACK_LENGTH))
796     {
797 #if OPENTHREAD_CONFIG_DIAG_ENABLE
798 
799         if (otPlatDiagModeGet())
800         {
801             otPlatDiagRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError);
802         }
803         else
804 #endif
805         {
806             // signal MAC layer for each received frame if promiscuous is enabled
807             // otherwise only signal MAC layer for non-ACK frame
808             if (((HWREG(RFCORE_XREG_FRMFILT0) & RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN) == 0) ||
809                 (sReceiveFrame.mLength > IEEE802154_ACK_LENGTH))
810             {
811                 otLogDebgPlat("Received %d bytes", sReceiveFrame.mLength);
812                 otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError);
813             }
814         }
815     }
816 
817     if (sState == OT_RADIO_STATE_TRANSMIT)
818     {
819         if (sTransmitError != OT_ERROR_NONE || (sTransmitFrame.mPsdu[0] & IEEE802154_ACK_REQUEST) == 0)
820         {
821             if (sTransmitError != OT_ERROR_NONE)
822             {
823                 otLogDebgPlat("Transmit failed ErrorCode=%d", sTransmitError);
824             }
825 
826             sState = OT_RADIO_STATE_RECEIVE;
827 
828 #if OPENTHREAD_CONFIG_DIAG_ENABLE
829 
830             if (otPlatDiagModeGet())
831             {
832                 otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, sTransmitError);
833             }
834             else
835 #endif
836             {
837                 otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, sTransmitError);
838             }
839         }
840         else if (sReceiveFrame.mLength == IEEE802154_ACK_LENGTH &&
841                  (sReceiveFrame.mPsdu[0] & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_ACK &&
842                  (sReceiveFrame.mPsdu[IEEE802154_DSN_OFFSET] == sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET]))
843         {
844             sState = OT_RADIO_STATE_RECEIVE;
845 
846             otPlatRadioTxDone(aInstance, &sTransmitFrame, &sReceiveFrame, sTransmitError);
847         }
848     }
849 
850     sReceiveFrame.mLength = 0;
851 
852 #if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
853     // Turn the receive interrupt handler back on now the buffer is clear.
854     HWREG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_RXPKTDONE;
855 #endif
856 }
857 
RFCoreRxTxIntHandler(void)858 void RFCoreRxTxIntHandler(void)
859 {
860 #if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
861     if (HWREG(RFCORE_SFR_RFIRQF0) & RFCORE_SFR_RFIRQF0_RXPKTDONE)
862     {
863         readFrame();
864 
865         if (sReceiveFrame.mLength > 0)
866         {
867             // A frame has been received, disable the interrupt handler
868             // until the main loop has dealt with this previous frame,
869             // otherwise we might overwrite it whilst it is being read.
870             HWREG(RFCORE_XREG_RFIRQM0) &= ~RFCORE_XREG_RFIRQM0_RXPKTDONE;
871         }
872     }
873 #endif
874 
875     HWREG(RFCORE_SFR_RFIRQF0) = 0;
876 }
877 
RFCoreErrIntHandler(void)878 void RFCoreErrIntHandler(void)
879 {
880     HWREG(RFCORE_SFR_RFERRF) = 0;
881 }
882 
getSrcMatchEntriesEnableStatus(bool aShort)883 uint32_t getSrcMatchEntriesEnableStatus(bool aShort)
884 {
885     uint32_t  status = 0;
886     uint32_t *addr   = aShort ? (uint32_t *)RFCORE_XREG_SRCSHORTEN0 : (uint32_t *)RFCORE_XREG_SRCEXTEN0;
887 
888     for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++)
889     {
890         status |= HWREG(addr++) << (i * 8);
891     }
892 
893     return status;
894 }
895 
findSrcMatchShortEntry(uint16_t aShortAddress)896 int8_t findSrcMatchShortEntry(uint16_t aShortAddress)
897 {
898     int8_t    entry = -1;
899     uint16_t  shortAddr;
900     uint32_t  bitMask;
901     uint32_t *addr   = NULL;
902     uint32_t  status = getSrcMatchEntriesEnableStatus(true);
903 
904     for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_SHORT_ENTRIES; i++)
905     {
906         bitMask = 0x00000001 << i;
907 
908         if ((status & bitMask) == 0)
909         {
910             continue;
911         }
912 
913         addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE + (i * RFCORE_XREG_SRCMATCH_SHORT_ENTRY_OFFSET);
914 
915         shortAddr = HWREG(addr + 2);
916         shortAddr |= HWREG(addr + 3) << 8;
917 
918         if ((shortAddr == aShortAddress))
919         {
920             entry = i;
921             break;
922         }
923     }
924 
925     return entry;
926 }
927 
findSrcMatchExtEntry(const otExtAddress * aExtAddress)928 int8_t findSrcMatchExtEntry(const otExtAddress *aExtAddress)
929 {
930     int8_t    entry = -1;
931     uint32_t  bitMask;
932     uint32_t *addr   = NULL;
933     uint32_t  status = getSrcMatchEntriesEnableStatus(false);
934 
935     for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_EXT_ENTRIES; i++)
936     {
937         uint8_t j = 0;
938         bitMask   = 0x00000001 << 2 * i;
939 
940         if ((status & bitMask) == 0)
941         {
942             continue;
943         }
944 
945         addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE + (i * RFCORE_XREG_SRCMATCH_EXT_ENTRY_OFFSET);
946 
947         for (j = 0; j < sizeof(otExtAddress); j++)
948         {
949             if (HWREG(addr + j) != aExtAddress->m8[j])
950             {
951                 break;
952             }
953         }
954 
955         if (j == sizeof(otExtAddress))
956         {
957             entry = i;
958             break;
959         }
960     }
961 
962     return entry;
963 }
964 
setSrcMatchEntryEnableStatus(bool aShort,uint8_t aEntry,bool aEnable)965 void setSrcMatchEntryEnableStatus(bool aShort, uint8_t aEntry, bool aEnable)
966 {
967     uint8_t   entry          = aShort ? aEntry : (2 * aEntry);
968     uint8_t   index          = entry / 8;
969     uint32_t *addrEn         = aShort ? (uint32_t *)RFCORE_XREG_SRCSHORTEN0 : (uint32_t *)RFCORE_XREG_SRCEXTEN0;
970     uint32_t *addrAutoPendEn = aShort ? (uint32_t *)RFCORE_FFSM_SRCSHORTPENDEN0 : (uint32_t *)RFCORE_FFSM_SRCEXTPENDEN0;
971     uint32_t  bitMask        = 0x00000001;
972 
973     if (aEnable)
974     {
975         HWREG(addrEn + index) |= (bitMask) << (entry % 8);
976         HWREG(addrAutoPendEn + index) |= (bitMask) << (entry % 8);
977     }
978     else
979     {
980         HWREG(addrEn + index) &= ~((bitMask) << (entry % 8));
981         HWREG(addrAutoPendEn + index) &= ~((bitMask) << (entry % 8));
982     }
983 }
984 
findSrcMatchAvailEntry(bool aShort)985 int8_t findSrcMatchAvailEntry(bool aShort)
986 {
987     int8_t   entry = -1;
988     uint32_t bitMask;
989     uint32_t shortEnableStatus = getSrcMatchEntriesEnableStatus(true);
990     uint32_t extEnableStatus   = getSrcMatchEntriesEnableStatus(false);
991 
992     otLogDebgPlat("Short enable status: 0x%x", shortEnableStatus);
993     otLogDebgPlat("Ext enable status: 0x%x", extEnableStatus);
994 
995     if (aShort)
996     {
997         bitMask = 0x00000001;
998 
999         for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_SHORT_ENTRIES; i++)
1000         {
1001             if ((extEnableStatus & bitMask) == 0)
1002             {
1003                 if ((shortEnableStatus & bitMask) == 0)
1004                 {
1005                     entry = i;
1006                     break;
1007                 }
1008             }
1009 
1010             if (i % 2 == 1)
1011             {
1012                 extEnableStatus = extEnableStatus >> 2;
1013             }
1014 
1015             shortEnableStatus = shortEnableStatus >> 1;
1016         }
1017     }
1018     else
1019     {
1020         bitMask = 0x00000003;
1021 
1022         for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_EXT_ENTRIES; i++)
1023         {
1024             if (((extEnableStatus | shortEnableStatus) & bitMask) == 0)
1025             {
1026                 entry = i;
1027                 break;
1028             }
1029 
1030             extEnableStatus   = extEnableStatus >> 2;
1031             shortEnableStatus = shortEnableStatus >> 2;
1032         }
1033     }
1034 
1035     return entry;
1036 }
1037 
cc2538EnergyScanTimerHandler(void)1038 void cc2538EnergyScanTimerHandler(void)
1039 {
1040     int8_t rssi = otPlatRadioGetRssi(sInstance);
1041 
1042     disableReceiver();
1043 
1044     HWREG(RFCORE_XREG_FRMCTRL0) &= ~RFCORE_XREG_FRMCTRL0_ENERGY_SCAN;
1045     HWREG(RFCORE_XREG_FREQCTRL) = 11 + (sChannel - 11) * 5;
1046 
1047     if (sIsReceiverEnabled)
1048     {
1049         enableReceiver();
1050     }
1051 
1052     otPlatRadioEnergyScanDone(sInstance, rssi);
1053 }
1054 
otPlatRadioEnableSrcMatch(otInstance * aInstance,bool aEnable)1055 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
1056 {
1057     OT_UNUSED_VARIABLE(aInstance);
1058 
1059     otLogInfoPlat("EnableSrcMatch=%d", aEnable ? 1 : 0);
1060 
1061     if (aEnable)
1062     {
1063         // only set FramePending when ack for data poll if there are queued messages
1064         // for entries in the source match table.
1065         HWREG(RFCORE_XREG_FRMCTRL1) &= ~RFCORE_XREG_FRMCTRL1_PENDING_OR;
1066     }
1067     else
1068     {
1069         // set FramePending for all ack.
1070         HWREG(RFCORE_XREG_FRMCTRL1) |= RFCORE_XREG_FRMCTRL1_PENDING_OR;
1071     }
1072 }
1073 
otPlatRadioAddSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)1074 otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
1075 {
1076     OT_UNUSED_VARIABLE(aInstance);
1077 
1078     otError   error = OT_ERROR_NONE;
1079     int8_t    entry = findSrcMatchAvailEntry(true);
1080     uint32_t *addr  = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE;
1081 
1082     otLogDebgPlat("Add ShortAddr entry: %d", entry);
1083 
1084     otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_BUFS);
1085 
1086     addr += (entry * RFCORE_XREG_SRCMATCH_SHORT_ENTRY_OFFSET);
1087 
1088     HWREG(addr++) = HWREG(RFCORE_FFSM_PAN_ID0);
1089     HWREG(addr++) = HWREG(RFCORE_FFSM_PAN_ID1);
1090     HWREG(addr++) = aShortAddress & 0xFF;
1091     HWREG(addr++) = aShortAddress >> 8;
1092 
1093     setSrcMatchEntryEnableStatus(true, (uint8_t)(entry), true);
1094 
1095 exit:
1096     return error;
1097 }
1098 
otPlatRadioAddSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)1099 otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
1100 {
1101     OT_UNUSED_VARIABLE(aInstance);
1102 
1103     otError   error = OT_ERROR_NONE;
1104     int8_t    entry = findSrcMatchAvailEntry(false);
1105     uint32_t *addr  = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE;
1106 
1107     otLogDebgPlat("Add ExtAddr entry: %d", entry);
1108 
1109     otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_BUFS);
1110 
1111     addr += (entry * RFCORE_XREG_SRCMATCH_EXT_ENTRY_OFFSET);
1112 
1113     for (uint8_t i = 0; i < sizeof(otExtAddress); i++)
1114     {
1115         HWREG(addr++) = aExtAddress->m8[i];
1116     }
1117 
1118     setSrcMatchEntryEnableStatus(false, (uint8_t)(entry), true);
1119 
1120 exit:
1121     return error;
1122 }
1123 
otPlatRadioClearSrcMatchShortEntry(otInstance * aInstance,uint16_t aShortAddress)1124 otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, uint16_t aShortAddress)
1125 {
1126     OT_UNUSED_VARIABLE(aInstance);
1127 
1128     otError error = OT_ERROR_NONE;
1129     int8_t  entry = findSrcMatchShortEntry(aShortAddress);
1130 
1131     otLogDebgPlat("Clear ShortAddr entry: %d", entry);
1132 
1133     otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_ADDRESS);
1134 
1135     setSrcMatchEntryEnableStatus(true, (uint8_t)(entry), false);
1136 
1137 exit:
1138     return error;
1139 }
1140 
otPlatRadioClearSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)1141 otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
1142 {
1143     OT_UNUSED_VARIABLE(aInstance);
1144 
1145     otError error = OT_ERROR_NONE;
1146     int8_t  entry = findSrcMatchExtEntry(aExtAddress);
1147 
1148     otLogDebgPlat("Clear ExtAddr entry: %d", entry);
1149 
1150     otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_ADDRESS);
1151 
1152     setSrcMatchEntryEnableStatus(false, (uint8_t)(entry), false);
1153 
1154 exit:
1155     return error;
1156 }
1157 
otPlatRadioClearSrcMatchShortEntries(otInstance * aInstance)1158 void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
1159 {
1160     OT_UNUSED_VARIABLE(aInstance);
1161 
1162     uint32_t *addrEn         = (uint32_t *)RFCORE_XREG_SRCSHORTEN0;
1163     uint32_t *addrAutoPendEn = (uint32_t *)RFCORE_FFSM_SRCSHORTPENDEN0;
1164 
1165     otLogDebgPlat("Clear ShortAddr entries", NULL);
1166 
1167     for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++)
1168     {
1169         HWREG(addrEn++)         = 0;
1170         HWREG(addrAutoPendEn++) = 0;
1171     }
1172 }
1173 
otPlatRadioClearSrcMatchExtEntries(otInstance * aInstance)1174 void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
1175 {
1176     OT_UNUSED_VARIABLE(aInstance);
1177 
1178     uint32_t *addrEn         = (uint32_t *)RFCORE_XREG_SRCEXTEN0;
1179     uint32_t *addrAutoPendEn = (uint32_t *)RFCORE_FFSM_SRCEXTPENDEN0;
1180 
1181     otLogDebgPlat("Clear ExtAddr entries", NULL);
1182 
1183     for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++)
1184     {
1185         HWREG(addrEn++)         = 0;
1186         HWREG(addrAutoPendEn++) = 0;
1187     }
1188 }
1189 
otPlatRadioEnergyScan(otInstance * aInstance,uint8_t aScanChannel,uint16_t aScanDuration)1190 otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
1191 {
1192     OT_UNUSED_VARIABLE(aInstance);
1193 
1194     otLogInfoPlat("ScanChannel=%d", aScanChannel);
1195 
1196     if (aScanChannel != sChannel)
1197     {
1198         if (sIsReceiverEnabled)
1199         {
1200             disableReceiver();
1201         }
1202 
1203         HWREG(RFCORE_XREG_FREQCTRL) = 11 + (aScanChannel - 11) * 5;
1204 
1205         enableReceiver();
1206     }
1207     else if (!sIsReceiverEnabled)
1208     {
1209         enableReceiver();
1210     }
1211 
1212     // Collect peak signal strength
1213     HWREG(RFCORE_XREG_FRMCTRL0) |= RFCORE_XREG_FRMCTRL0_ENERGY_SCAN;
1214 
1215     cc2538SetTimer(OT_CC2538_TIMER_ENERGY_SCAN, aScanDuration);
1216 
1217     return OT_ERROR_NONE;
1218 }
1219 
otPlatRadioGetTransmitPower(otInstance * aInstance,int8_t * aPower)1220 otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
1221 {
1222     OT_UNUSED_VARIABLE(aInstance);
1223 
1224     otError error = OT_ERROR_NONE;
1225 
1226     otEXPECT_ACTION(aPower != NULL, error = OT_ERROR_INVALID_ARGS);
1227     *aPower = sTxPower;
1228 
1229 exit:
1230     return error;
1231 }
1232 
otPlatRadioSetTransmitPower(otInstance * aInstance,int8_t aPower)1233 otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
1234 {
1235     OT_UNUSED_VARIABLE(aInstance);
1236 
1237     setTxPower(aPower);
1238     return OT_ERROR_NONE;
1239 }
1240 
otPlatRadioGetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t * aThreshold)1241 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold)
1242 {
1243     OT_UNUSED_VARIABLE(aInstance);
1244     OT_UNUSED_VARIABLE(aThreshold);
1245 
1246     return OT_ERROR_NOT_IMPLEMENTED;
1247 }
1248 
otPlatRadioSetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t aThreshold)1249 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold)
1250 {
1251     OT_UNUSED_VARIABLE(aInstance);
1252     OT_UNUSED_VARIABLE(aThreshold);
1253 
1254     return OT_ERROR_NOT_IMPLEMENTED;
1255 }
1256 
otPlatRadioGetReceiveSensitivity(otInstance * aInstance)1257 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
1258 {
1259     OT_UNUSED_VARIABLE(aInstance);
1260 
1261 #if OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM
1262     if (cc2538RadioGetHgm())
1263     {
1264         return CC2592_RECEIVE_SENSITIVITY_HGM;
1265     }
1266     else
1267     {
1268         return CC2592_RECEIVE_SENSITIVITY_LGM;
1269     }
1270 #else  // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM
1271     return CC2538_RECEIVE_SENSITIVITY;
1272 #endif // OPENTHREAD_CONFIG_CC2538_WITH_CC2592 && OPENTHREAD_CONFIG_CC2592_USE_HGM
1273 }
1274