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