42#include "pa_conversions_efr32.h"
43#include "sl_rail_util_dma.h"
44#include "sl_rail_util_pti.h"
45#include "sl_rail_util_rf_path.h"
46#include "sl_rail_util_rssi.h"
48#include <ieee802154/rail_ieee802154.h>
52#define LOG_MODULE "EFR32"
53#define LOG_LEVEL LOG_LEVEL_NONE
56 IEEE802154_ACK_REQUEST = 1 << 5,
70#define PTI_ENABLED false
72extern const RAIL_ChannelConfig_t *
const RAIL_IEEE802154_Phy2p4GHz;
74static void rail_events_cb(RAIL_Handle_t rail_handle, RAIL_Events_t events);
75static RAILSched_Config_t rail_sched_config;
76static RAIL_Config_t rail_config = {
77 .eventsCallback = &rail_events_cb,
78 .scheduler = &rail_sched_config,
81 RAIL_FIFO_ALIGNMENT_TYPE align[RAIL_FIFO_SIZE / RAIL_FIFO_ALIGNMENT];
82 uint8_t fifo[RAIL_FIFO_SIZE];
84static RAIL_Handle_t sRailHandle = NULL;
85static RAIL_Time_t last_rx_time = 0;
86static int16_t last_rssi;
87static int16_t last_lqi;
89PROCESS(efr32_radio_process,
"efr32 radio driver");
90static uint8_t send_on_cca = 1;
91static uint8_t poll_mode = 0;
92static RAIL_DataConfig_t data_config = {
93 .txSource = TX_PACKET_DATA,
94 .rxSource = RX_PACKET_DATA,
95 .txMethod = PACKET_MODE,
96 .rxMethod = PACKET_MODE,
98static RAIL_IEEE802154_Config_t rail_ieee802154_config = {
104 .success = RAIL_RF_STATE_RX,
105 .error = RAIL_RF_STATE_IDLE
108 .success = RAIL_RF_STATE_RX,
109 .error = RAIL_RF_STATE_IDLE
117 .rxSearchTimeout = 0,
118 .txToRxSearchTimeout = 0,
120 .framesMask = RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES
121 | RAIL_IEEE802154_ACCEPT_ACK_FRAMES,
122 .promiscuousMode = 0,
123 .isPanCoordinator = 0,
124 .defaultFramePendingInOutgoingAcks = 0,
127 RAIL_FIFO_ALIGNMENT_TYPE align[RAIL_FIFO_SIZE / RAIL_FIFO_ALIGNMENT];
128 uint8_t fifo[RAIL_FIFO_SIZE];
130static uint16_t panid = 0xabcd;
132static int cca_threshold = -85;
133static RAIL_TxOptions_t txOptions = RAIL_TX_OPTIONS_DEFAULT;
134volatile tx_status_t tx_status;
135volatile bool is_receiving =
false;
138RAILCb_SetupRxFifo(RAIL_Handle_t railHandle)
140 uint16_t rxFifoSize = RAIL_FIFO_SIZE;
141 RAIL_Status_t status = RAIL_SetRxFifo(railHandle, sRailRxFifo.fifo, &rxFifoSize);
142 if(rxFifoSize != RAIL_FIFO_SIZE) {
144 return RAIL_STATUS_INVALID_PARAMETER;
146 if(status == RAIL_STATUS_INVALID_STATE) {
148 return RAIL_STATUS_NO_ERROR;
154configure_radio_interrupts(
void)
156 RAIL_Status_t rail_status;
158 rail_status = RAIL_ConfigEvents(sRailHandle, RAIL_EVENTS_ALL,
159 RAIL_EVENT_RX_SYNC1_DETECT |
160 RAIL_EVENT_RX_SYNC2_DETECT |
161 RAIL_EVENT_RX_ACK_TIMEOUT |
162 RAIL_EVENT_RX_FRAME_ERROR |
163 RAIL_EVENT_RX_PACKET_RECEIVED |
164 RAIL_EVENT_RX_FIFO_OVERFLOW |
165 RAIL_EVENT_RX_ADDRESS_FILTERED |
166 RAIL_EVENT_RX_PACKET_ABORTED |
167 RAIL_EVENT_TX_PACKET_SENT |
168 RAIL_EVENT_TX_CHANNEL_BUSY |
169 RAIL_EVENT_TX_ABORTED |
170 RAIL_EVENT_TX_BLOCKED |
171 RAIL_EVENT_TX_UNDERFLOW |
172 RAIL_EVENT_CAL_NEEDED);
174 if(rail_status != RAIL_STATUS_NO_ERROR) {
175 LOG_ERR(
"RAIL_ConfigEvents failed, return value: %d", rail_status);
185 RAIL_RxPacketHandle_t rx_packet_handle;
186 RAIL_RxPacketDetails_t packet_details;
187 RAIL_RxPacketInfo_t packet_info;
188 RAIL_Status_t rail_status;
192 rx_packet_handle = RAIL_GetRxPacketInfo(sRailHandle, RAIL_RX_PACKET_HANDLE_OLDEST_COMPLETE, &packet_info);
194 if(rx_packet_handle == RAIL_RX_PACKET_HANDLE_INVALID) {
198 packet_details.isAck =
false;
199 packet_details.timeReceived.timePosition = RAIL_PACKET_TIME_AT_SYNC_END;
200 packet_details.timeReceived.totalPacketBytes = 0;
202 rail_status = RAIL_GetRxPacketDetails(sRailHandle, rx_packet_handle, &packet_details);
203 if(rail_status != RAIL_STATUS_NO_ERROR) {
204 LOG_ERR(
"Failed to get packet details\n");
208 length = packet_info.packetBytes - 1;
209 LOG_INFO(
"EFR32 Radio: rcv:%d\n", length);
212 packet_info.firstPortionData++;
213 packet_info.firstPortionBytes--;
214 packet_info.packetBytes--;
216 rx_buf = get_empty_rx_buf();
218 rx_buf->len = length;
221 memcpy(rx_buf->buf, packet_info.firstPortionData,
222 packet_info.firstPortionBytes);
223 if(packet_info.lastPortionData != NULL) {
224 memcpy(rx_buf->buf + packet_info.firstPortionBytes,
225 packet_info.lastPortionData,
226 packet_info.packetBytes - packet_info.firstPortionBytes);
228 rx_buf->rssi = packet_details.rssi;
229 rx_buf->lqi = packet_details.lqi;
230 rx_buf->timestamp = packet_details.timeReceived.packetTime;
232 LOG_INFO(
"EFR32 Radio: Could not allocate rx_buf\n");
236 rail_status = RAIL_ReleaseRxPacket(sRailHandle, rx_packet_handle);
237 if(rail_status != RAIL_STATUS_NO_ERROR) {
238 LOG_WARN(
"RAIL_ReleaseRxPacket() result:%d", rail_status);
243rail_events_cb(RAIL_Handle_t rail_handle, RAIL_Events_t events)
245 if(events & (RAIL_EVENT_TX_ABORTED | RAIL_EVENT_TX_BLOCKED | RAIL_EVENT_TX_UNDERFLOW)) {
246 tx_status = TX_ERROR;
249 if(events & RAIL_EVENT_RX_ACK_TIMEOUT) {
250 tx_status = TX_NO_ACK;
253 if(events & (RAIL_EVENT_RX_FIFO_OVERFLOW
254 | RAIL_EVENT_RX_ADDRESS_FILTERED
255 | RAIL_EVENT_RX_PACKET_ABORTED
256 | RAIL_EVENT_RX_FRAME_ERROR
257 | RAIL_EVENT_RX_PACKET_RECEIVED)) {
258 is_receiving =
false;
259 if(events & RAIL_EVENT_RX_PACKET_RECEIVED) {
260 RAIL_HoldRxPacket(rail_handle);
262 LOG_INFO(
"EFR32 Radio: Receive event - poll.\n");
268 if(events & RAIL_EVENT_TX_PACKET_SENT) {
269 LOG_INFO(
"EFR32 Radio: packet sent\n");
273 if(events & RAIL_EVENT_TX_CHANNEL_BUSY) {
274 tx_status = TX_CHANNEL_BUSY;
277 if(events & (RAIL_EVENT_RX_SYNC1_DETECT | RAIL_EVENT_RX_SYNC2_DETECT)) {
281 if(events & RAIL_EVENT_CAL_NEEDED) {
282 (void)RAIL_Calibrate(rail_handle, NULL, RAIL_CAL_ALL_PENDING);
289 RAIL_Status_t status;
292 uint16_t allocated_tx_fifo_size;
293 uint64_t system_number;
295 NVIC_SetPriority(FRC_PRI_IRQn, CORE_INTERRUPT_HIGHEST_PRIORITY);
296 NVIC_SetPriority(FRC_IRQn, CORE_INTERRUPT_HIGHEST_PRIORITY);
297 NVIC_SetPriority(MODEM_IRQn, CORE_INTERRUPT_HIGHEST_PRIORITY);
298 NVIC_SetPriority(RAC_SEQ_IRQn, CORE_INTERRUPT_HIGHEST_PRIORITY);
299 NVIC_SetPriority(RAC_RSM_IRQn, CORE_INTERRUPT_HIGHEST_PRIORITY);
300 NVIC_SetPriority(BUFC_IRQn, CORE_INTERRUPT_HIGHEST_PRIORITY);
301 NVIC_SetPriority(AGC_IRQn, CORE_INTERRUPT_HIGHEST_PRIORITY);
302 NVIC_SetPriority(PROTIMER_IRQn, CORE_INTERRUPT_HIGHEST_PRIORITY);
303 NVIC_SetPriority(SYNTH_IRQn, CORE_INTERRUPT_HIGHEST_PRIORITY);
304 NVIC_SetPriority(RFSENSE_IRQn, CORE_INTERRUPT_HIGHEST_PRIORITY);
306 sl_rail_util_dma_init();
307 sl_rail_util_pa_init();
308 sl_rail_util_pti_init();
309 sl_rail_util_rf_path_init();
310 sl_rail_util_rssi_init();
313 sRailHandle = RAIL_Init(&rail_config,
316 if(sRailHandle == NULL) {
317 LOG_ERR(
"RAIL_Init failed, return value: NULL");
321 status = RAIL_InitPowerManager();
322 if(status != RAIL_STATUS_NO_ERROR) {
323 LOG_ERR(
"RAIL_InitPowerManager failed, return value: %d", status);
327 status = RAIL_ConfigData(sRailHandle, &data_config);
329 if(status != RAIL_STATUS_NO_ERROR) {
330 LOG_ERR(
"RAIL_ConfigData failed, return value: %d", status);
335 (void)RAIL_ConfigChannels(sRailHandle,
336 RAIL_IEEE802154_Phy2p4GHz,
337 &sl_rail_util_pa_on_channel_config_change);
339 status = RAIL_IEEE802154_Init(sRailHandle, &rail_ieee802154_config);
340 if(status != RAIL_STATUS_NO_ERROR) {
341 LOG_ERR(
"RAIL_IEEE802154_Init failed, return value: %d", status);
345 status = RAIL_IEEE802154_Config2p4GHzRadio(sRailHandle);
346 if(status != RAIL_STATUS_NO_ERROR) {
347 (void)RAIL_IEEE802154_Deinit(sRailHandle);
348 LOG_ERR(
"RAIL_IEEE802154_Config2p4GHzRadio failed, return value: %d", status);
352 status = RAIL_IEEE802154_ConfigEOptions(sRailHandle,
353 (RAIL_IEEE802154_E_OPTION_GB868
354 | RAIL_IEEE802154_E_OPTION_ENH_ACK
355 | RAIL_IEEE802154_E_OPTION_IMPLICIT_BROADCAST),
356 (RAIL_IEEE802154_E_OPTION_GB868
357 | RAIL_IEEE802154_E_OPTION_ENH_ACK
358 | RAIL_IEEE802154_E_OPTION_IMPLICIT_BROADCAST));
360 if(status != RAIL_STATUS_NO_ERROR) {
361 LOG_ERR(
"RAIL_IEEE802154_ConfigEOptions failed, return value: %d", status);
365 status = RAIL_ConfigCal(sRailHandle,
368 ? RAIL_CAL_TEMP : 0U)
370 ? RAIL_CAL_ONETIME : 0U));
372 if(status != RAIL_STATUS_NO_ERROR) {
373 LOG_ERR(
"RAIL_ConfigCal failed, return value: %d", status);
377 if(!configure_radio_interrupts()) {
381 system_number = SYSTEM_GetUnique();
383 ext_addr = (uint8_t *)&system_number;
384 short_addr = ext_addr[7];
385 short_addr |= ext_addr[6] << 8;
391 allocated_tx_fifo_size = RAIL_SetTxFifo(sRailHandle, sRailTxFifo.fifo,
394 if(allocated_tx_fifo_size != RAIL_FIFO_SIZE) {
395 LOG_ERR(
"RAIL_SetTxFifo() failed to allocate a large enough fifo"
396 " (%d bytes instead of %d bytes)\n",
397 allocated_tx_fifo_size, RAIL_FIFO_SIZE);
402 status = RAIL_SetPtiProtocol(sRailHandle, RAIL_PTI_PROTOCOL_802154);
403 if(status != RAIL_STATUS_NO_ERROR) {
404 LOG_ERR(
"RAIL_SetPtiProtocol() status: %d failed", status);
407 status = RAIL_EnablePti(sRailHandle, PTI_ENABLED);
408 if(status != RAIL_STATUS_NO_ERROR) {
409 LOG_ERR(
"RAIL_EnablePti() status: %d failed", status);
433 case RADIO_CONST_MAX_PAYLOAD_LEN:
434 *value = RAIL_FIFO_SIZE;
438 if(!rail_ieee802154_config.promiscuousMode) {
441 if(rail_ieee802154_config.ackConfig.enable) {
462 int16_t rssi_value = RAIL_GetRssi(sRailHandle,
true);
463 if(rssi_value != RAIL_RSSI_INVALID) {
465 *value = rssi_value / 4;
479 if(value < CHANNEL_MIN ||
480 value > CHANNEL_MAX) {
485 const RAIL_Status_t status = RAIL_StartRx(sRailHandle, channel, NULL);
486 if(status != RAIL_STATUS_NO_ERROR) {
487 LOG_ERR(
"Could not start RX on channel %d\n", channel);
492 panid = value & 0xffff;
493 RAIL_IEEE802154_SetPanId(sRailHandle, panid, 0);
496 (void)RAIL_IEEE802154_SetShortAddress(sRailHandle, value & 0xFFFF, 0);
509 if(!rail_ieee802154_config.ackConfig.enable) {
510 RAIL_StateTransitions_t transitions = {
511 .error = RAIL_RF_STATE_RX,
512 .success = RAIL_RF_STATE_RX,
514 RAIL_SetTxTransitions(sRailHandle, &transitions);
515 RAIL_SetRxTransitions(sRailHandle, &transitions);
517 (void)RAIL_ConfigAutoAck(sRailHandle, &rail_ieee802154_config.ackConfig);
518 (void)RAIL_IEEE802154_SetPromiscuousMode(sRailHandle, rail_ieee802154_config.promiscuousMode);
519 (void)configure_radio_interrupts();
534get_object(radio_param_t param,
void *dest,
size_t size)
537 if(size !=
sizeof(rtimer_clock_t) || !dest) {
540 *(rtimer_clock_t *)dest = last_rx_time;
548set_object(radio_param_t param,
const void *src,
size_t size)
551 if(size != 8 || src == NULL) {
554 (void)RAIL_IEEE802154_SetLongAddress(sRailHandle, src, 0);
563 if(RAIL_GetRssi(sRailHandle,
true) / 4 > cca_threshold) {
570prepare(
const void *payload,
unsigned short payload_len)
572 uint8_t plen = (uint8_t)payload_len + 2;
573 uint8_t *data = (uint8_t *)payload;
576 written += RAIL_WriteTxFifo(sRailHandle, &plen, 1,
true);
578 written += RAIL_WriteTxFifo(sRailHandle, payload, payload_len,
false);
580 LOG_INFO(
"EFR32 Radio - wrote %d bytes to TX fifo\n", written);
582 if(!(poll_mode) && (data[0] & IEEE802154_ACK_REQUEST)) {
583 txOptions = RAIL_TX_OPTION_WAIT_FOR_ACK;
585 txOptions = RAIL_TX_OPTIONS_DEFAULT;
592transmit(
unsigned short transmit_len)
595 RAIL_CsmaConfig_t csmaConfig =
596 RAIL_CSMA_CONFIG_802_15_4_2003_2p4_GHz_OQPSK_CSMA;
597 RAIL_Status_t status;
599 LOG_INFO(
"EFR32 Radio: Sending packet %d bytes\n", transmit_len);
601 tx_status = TX_SENDING;
604 status = RAIL_StartCcaCsmaTx(sRailHandle,
610 status = RAIL_StartTx(sRailHandle,
616 if(status != RAIL_STATUS_NO_ERROR) {
617 LOG_ERR(
"RAIL_Start***Tx status: %d failed", status);
624 const uint16_t frame_length = transmit_len + RADIO_PHY_HEADER_LEN + RADIO_PHY_OVERHEAD;
626 US_TO_RTIMERTICKS(RADIO_BYTE_AIR_TIME * frame_length + 300));
629 while(tx_status == TX_SENDING);
632 if(tx_status == TX_SENT) {
633 LOG_INFO(
"EFR32: OK - packet sent.\n");
635 LOG_INFO(
"EFR32: TX error %d\n", tx_status);
645send(
const void *payload,
unsigned short payload_len)
648 ret = prepare(payload, payload_len);
652 return transmit(payload_len);
668receiving_packet(
void)
674read(
void *buf,
unsigned short bufsize)
681 rx_buf = get_full_rx_buf();
685 LOG_INFO(
"EFR32 Radio Read: %d\n", rx_buf->len);
688 last_rx_time =
RTIMER_NOW() - US_TO_RTIMERTICKS(RAIL_GetTime() - rx_buf->timestamp);
689 memcpy(buf, rx_buf->buf, len);
690 last_rssi = rx_buf->rssi;
691 last_lqi = rx_buf->lqi;
693 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rx_buf->rssi);
694 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, rx_buf->lqi);
717 if(pending_packet()) {
723 NETSTACK_MAC.
input();
GPIO HAL header file for the gecko.
802.15.4 frame creation and parsing functions
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
void packetbuf_clear(void)
Clear and reset the packetbuf.
#define PROCESS(name, strname)
Declare a process.
#define PROCESS_BEGIN()
Define the beginning of a process.
#define PROCESS_END()
Define the end of a process.
void process_start(struct process *p, process_data_t data)
Start a process.
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
void process_poll(struct process *p)
Request a process to be polled.
#define RADIO_RX_MODE_ADDRESS_FILTER
Enable address-based frame filtering.
#define RADIO_RX_MODE_POLL_MODE
Enable/disable/get the state of radio driver poll mode operation.
#define RADIO_TX_MODE_SEND_ON_CCA
Radio TX mode control / retrieval.
enum radio_result_e radio_result_t
Radio return values when setting or getting radio parameters.
int radio_value_t
Each radio has a set of parameters that designate the current configuration and state of the radio.
#define RADIO_RX_MODE_AUTOACK
Enable automatic transmission of ACK frames.
@ RADIO_RESULT_ERROR
An error occurred when getting/setting the parameter, but the arguments were otherwise correct.
@ RADIO_RESULT_NOT_SUPPORTED
The parameter is not supported.
@ RADIO_RESULT_INVALID_VALUE
The value argument was incorrect.
@ RADIO_RESULT_OK
The parameter was set/read successfully.
@ RADIO_PARAM_RSSI
Received signal strength indicator in dBm.
@ RADIO_PARAM_LAST_PACKET_TIMESTAMP
Last packet timestamp, of type rtimer_clock_t.
@ RADIO_PARAM_LAST_RSSI
The RSSI value of the last received packet.
@ RADIO_PARAM_RX_MODE
Radio receiver mode determines if the radio has address filter (RADIO_RX_MODE_ADDRESS_FILTER) and aut...
@ RADIO_PARAM_CHANNEL
Channel used for radio communication.
@ RADIO_PARAM_LAST_LINK_QUALITY
Link quality indicator of the last received packet.
@ RADIO_PARAM_64BIT_ADDR
Long (64 bits) address for the radio, which is used by the address filter.
@ RADIO_PARAM_PAN_ID
The personal area network identifier (PAN ID), which is used by the h/w frame filtering functionality...
@ RADIO_PARAM_16BIT_ADDR
The short address (16 bits) for the radio, which is used by the h/w filter.
@ RADIO_PARAM_TX_MODE
Radio transmission mode determines if the radio has send on CCA (RADIO_TX_MODE_SEND_ON_CCA) enabled o...
@ RADIO_TX_ERR
An error occurred during transmission.
@ RADIO_TX_OK
TX was successful and where an ACK was requested one was received.
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time)
Busy-wait until a condition for at most max_time.
#define RTIMER_NOW()
Get the current clock time.
Header file for the logging system.
#define IEEE802154_DEFAULT_CHANNEL
The default channel for IEEE 802.15.4 networks.
Include file for the Contiki low-layer network stack (NETSTACK)
Header file for the Packet buffer (packetbuf) management.
Header file for the radio API.
void(* input)(void)
Callback for getting notified of incoming packet.
The structure of a Contiki-NG radio device driver.
radio_result_t(* get_object)(radio_param_t param, void *dest, size_t size)
Get a radio parameter object.
int(* read)(void *buf, unsigned short buf_len)
Read a received packet into a buffer.
int(* prepare)(const void *payload, unsigned short payload_len)
Prepare the radio with a packet to be sent.
radio_result_t(* set_value)(radio_param_t param, radio_value_t value)
Set a radio parameter value.
int(* off)(void)
Turn the radio off.
int(* init)(void)
Initialise the radio hardware.
int(* send)(const void *payload, unsigned short payload_len)
Prepare & transmit a packet.
int(* receiving_packet)(void)
Check if the radio driver is currently receiving a packet.
radio_result_t(* set_object)(radio_param_t param, const void *src, size_t size)
Set a radio parameter object.
int(* on)(void)
Turn the radio on.
int(* transmit)(unsigned short transmit_len)
Send the packet that has previously been prepared.
int(* pending_packet)(void)
Check if a packet has been received and is available in the radio driver's buffers.
radio_result_t(* get_value)(radio_param_t param, radio_value_t *value)
Get a radio parameter value.
int(* channel_clear)(void)
Perform a Clear-Channel Assessment (CCA) to find out if there is a packet in the air or not.