50#include "nrf_802154.h"
51#include "nrf_802154_config.h"
58#ifndef LOG_CONF_LEVEL_RADIO
59#define LOG_CONF_LEVEL_RADIO LOG_LEVEL_INFO
61#define LOG_MODULE "nrf53-radio"
62#define LOG_LEVEL LOG_CONF_LEVEL_RADIO
64#define MAX_PAYLOAD_LEN 125
65#define FRAME_ACK_REQUEST_BIT 0x20
75#define DEFAULT_CHANNEL IEEE802154_DEFAULT_CHANNEL
76#define DEFAULT_TX_POWER 0
80#define TX_DONE_TIMEOUT_US 250000ULL
81#define TX_ABORT_TIMEOUT_US 10000ULL
82#define CCA_DONE_TIMEOUT_US 50000ULL
85static uint8_t tx_buf[1 + MAX_PAYLOAD_LEN + 2];
95#define RX_BUF_COUNT 32
96#define RX_BUF_MASK (RX_BUF_COUNT - 1)
97#if (RX_BUF_COUNT & RX_BUF_MASK) != 0
98#error RX_BUF_COUNT must be a power of two
100#if RX_BUF_COUNT < NRF_802154_RX_BUFFERS
101#error RX_BUF_COUNT must be >= NRF_802154_RX_BUFFERS
103static uint8_t *rx_bufs[RX_BUF_COUNT];
104static int8_t rx_rssi[RX_BUF_COUNT];
105static uint8_t rx_lqi[RX_BUF_COUNT];
106static volatile uint8_t rx_head;
107static volatile uint8_t rx_tail;
109static volatile bool tx_done;
110static volatile bool tx_success;
111static volatile nrf_802154_tx_error_t tx_error;
113static volatile bool cca_done;
114static volatile bool cca_free;
116static volatile uint32_t rx_fail_count;
117static volatile uint32_t rx_drop_count;
118static volatile uint32_t tx_fail_count;
120static uint8_t current_channel = DEFAULT_CHANNEL;
121static int8_t current_tx_power = DEFAULT_TX_POWER;
122static bool radio_is_on;
131PROCESS(nrf53_radio_process,
"nRF53 radio driver");
134tx_error_name(nrf_802154_tx_error_t error)
137 case NRF_802154_TX_ERROR_NONE:
139 case NRF_802154_TX_ERROR_BUSY_CHANNEL:
140 return "busy_channel";
141 case NRF_802154_TX_ERROR_INVALID_ACK:
142 return "invalid_ack";
143 case NRF_802154_TX_ERROR_NO_MEM:
145 case NRF_802154_TX_ERROR_TIMESLOT_ENDED:
146 return "timeslot_ended";
147 case NRF_802154_TX_ERROR_NO_ACK:
149 case NRF_802154_TX_ERROR_ABORTED:
151 case NRF_802154_TX_ERROR_TIMESLOT_DENIED:
152 return "timeslot_denied";
159wait_for_flag(
volatile bool *flag, uint64_t timeout_us)
161 uint64_t deadline = nrf_802154_time_get() + timeout_us;
163 while(!*flag && nrf_802154_time_get() < deadline) {
171recover_to_receive_state(
void)
186 (void)wait_for_flag(&tx_done, TX_ABORT_TIMEOUT_US);
188 if(!nrf_802154_receive()) {
189 LOG_WARN(
"Failed to restore receive state\n");
197 uint8_t short_addr[2];
201 LOG_INFO(
"Initializing nrf_802154 radio driver\n");
205 nrf_802154_channel_set(current_channel);
206 nrf_802154_tx_power_set(current_tx_power);
208 nrf_802154_auto_ack_set(
true);
209 nrf_802154_rx_on_when_idle_set(
true);
220 pan_id[0] = (uint8_t)(IEEE802154_PANID & 0xFF);
221 pan_id[1] = (uint8_t)(IEEE802154_PANID >> 8);
222 nrf_802154_pan_id_set(pan_id);
226 nrf_802154_short_address_set(short_addr);
229 for(i = 0; i < 8; i++) {
230 ext_addr[i] = (i < LINKADDR_SIZE) ?
233 nrf_802154_extended_address_set(ext_addr);
244 LOG_INFO(
"Radio initialized, channel %u, PAN 0x%04x\n",
245 current_channel, IEEE802154_PANID);
259 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
260 if(!nrf_802154_receive()) {
261 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
262 LOG_WARN(
"Failed to enter receive state\n");
275 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
282prepare(
const void *payload,
unsigned short payload_len)
284 if(payload_len > MAX_PAYLOAD_LEN) {
285 LOG_WARN(
"TX payload too long: %u\n", payload_len);
289 tx_buf[0] = payload_len + 2;
290 memcpy(&tx_buf[1], payload, payload_len);
296transmit(
unsigned short transmit_len)
298 nrf_802154_transmit_metadata_t metadata = {
299 .frame_props = NRF_802154_TRANSMITTED_FRAME_PROPS_DEFAULT_INIT,
301 .tx_power = { .use_metadata_value =
false },
302 .tx_channel = { .use_metadata_value =
false },
304 nrf_802154_tx_error_t tx_err;
312 if(transmit_len > MAX_PAYLOAD_LEN || transmit_len + 2 != tx_buf[0]) {
313 LOG_WARN(
"TX length mismatch: %u vs PHR %u\n", transmit_len, tx_buf[0]);
323 tx_error = NRF_802154_TX_ERROR_NONE;
325 ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
327 tx_err = nrf_802154_transmit_raw(tx_buf, &metadata);
329 if(tx_err != NRF_802154_TX_ERROR_NONE) {
330 LOG_WARN(
"TX request rejected: %s (%u)\n", tx_error_name(tx_err), tx_err);
331 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
333 if(tx_err == NRF_802154_TX_ERROR_BUSY_CHANNEL) {
334 recover_to_receive_state();
337 if(tx_err == NRF_802154_TX_ERROR_INVALID_ACK ||
338 tx_err == NRF_802154_TX_ERROR_NO_ACK) {
344 if(!wait_for_flag(&tx_done, TX_DONE_TIMEOUT_US)) {
345 LOG_WARN(
"TX timeout\n");
346 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
350 recover_to_receive_state();
354 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
359 if(tx_error == NRF_802154_TX_ERROR_NO_ACK ||
360 tx_error == NRF_802154_TX_ERROR_INVALID_ACK) {
363 if(tx_error == NRF_802154_TX_ERROR_BUSY_CHANNEL) {
367 LOG_WARN(
"TX failed: %s (%u)\n", tx_error_name(tx_error), tx_error);
372send(
const void *payload,
unsigned short payload_len)
374 if(
prepare(payload, payload_len) != 0) {
382radio_read(
void *buf,
unsigned short buf_len)
388 if(rx_tail == rx_head) {
392 idx = rx_tail & RX_BUF_MASK;
393 p_data = rx_bufs[idx];
403 nrf_802154_buffer_free_raw(p_data);
410 payload_len = p_data[0] - 2;
411 if(payload_len > buf_len) {
412 payload_len = buf_len;
415 memcpy(buf, &p_data[1], payload_len);
417 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rx_rssi[idx]);
418 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, rx_lqi[idx]);
420 nrf_802154_buffer_free_raw(p_data);
437 if(!nrf_802154_cca()) {
438 LOG_WARN(
"CCA could not start\n");
442 if(!wait_for_flag(&cca_done, CCA_DONE_TIMEOUT_US)) {
443 LOG_WARN(
"CCA timeout\n");
444 recover_to_receive_state();
448 return cca_free ? 1 : 0;
452receiving_packet(
void)
460 return (rx_head != rx_tail) ? 1 : 0;
498 case RADIO_CONST_MAX_PAYLOAD_LEN:
499 *
value = MAX_PAYLOAD_LEN;
521 current_channel = (uint8_t)
value;
522 nrf_802154_channel_set(current_channel);
528 current_tx_power = (int8_t)
value;
529 nrf_802154_tx_power_set(current_tx_power);
554get_object(radio_param_t param,
void *dest,
size_t size)
563set_object(radio_param_t param,
const void *src,
size_t size)
575 addr = (
const uint8_t *)src;
576 for(i = 0; i < 8; i++) {
577 ext_addr[i] =
addr[7 - i];
579 nrf_802154_extended_address_set(ext_addr);
585 nrf_802154_pan_id_set((
const uint8_t *)src);
591 nrf_802154_short_address_set((
const uint8_t *)src);
600nrf_802154_received_timestamp_raw(uint8_t *p_data, int8_t power,
601 uint8_t lqi, uint64_t time)
607 if(((uint8_t)(rx_head - rx_tail)) >= RX_BUF_COUNT) {
616 nrf_802154_buffer_free_raw(p_data);
622 idx = rx_head & RX_BUF_MASK;
623 rx_bufs[idx] = p_data;
624 rx_rssi[idx] = power;
632nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t
id)
641nrf_802154_transmitted_raw(uint8_t *p_frame,
642 const nrf_802154_transmit_done_metadata_t *p_metadata)
644 bool ack_requested =
false;
646 if(p_frame != NULL) {
647 ack_requested = (p_frame[1] & FRAME_ACK_REQUEST_BIT) != 0;
650 if(p_metadata->data.transmitted.p_ack != NULL) {
651 nrf_802154_buffer_free_raw(p_metadata->data.transmitted.p_ack);
653 }
else if(ack_requested) {
654 tx_error = NRF_802154_TX_ERROR_NO_ACK;
665nrf_802154_transmit_failed(uint8_t *p_frame,
666 nrf_802154_tx_error_t error,
667 const nrf_802154_transmit_done_metadata_t *p_metadata)
677 if(error != NRF_802154_TX_ERROR_NO_ACK &&
678 error != NRF_802154_TX_ERROR_BUSY_CHANNEL) {
688nrf_802154_cca_done(
bool channel_free)
690 cca_free = channel_free;
696nrf_802154_cca_failed(nrf_802154_cca_error_t error)
705nrf_802154_energy_detected(
const nrf_802154_energy_detected_t *p_result)
711nrf_802154_energy_detection_failed(nrf_802154_ed_error_t error)
723 if(rx_fail_count > 0) {
724 if(rx_fail_count > 16) {
725 LOG_WARN(
"RX failed %" PRIu32
" times\n", rx_fail_count);
729 if(rx_drop_count > 0) {
730 LOG_WARN(
"RX ring full, dropped %" PRIu32
" frames\n", rx_drop_count);
733 if(tx_fail_count > 0) {
734 LOG_WARN(
"TX failed %" PRIu32
" times\n", tx_fail_count);
738 while(pending_packet()) {
744 NETSTACK_MAC.input();
Header file for the energy estimation mechanism.
802.15.4 frame creation and parsing functions
static int transmit(unsigned short transmit_len)
static radio_result_t get_object(radio_param_t param, void *dest, size_t size)
static int prepare(const void *payload, unsigned short payload_len)
static radio_result_t set_object(radio_param_t param, const void *src, size_t size)
static int value(int type)
linkaddr_t linkaddr_node_addr
The link-layer address of the node.
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_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_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_POWER_MODE
When getting the value of this parameter, the radio driver should indicate whether the radio is on or...
@ RADIO_PARAM_RSSI
Received signal strength indicator in dBm.
@ 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_TXPOWER
Transmission power in dBm.
@ RADIO_PARAM_64BIT_ADDR
Long (64 bits) address for the radio, which is used by the address filter.
@ RADIO_CONST_CHANNEL_MAX
The highest radio channel number.
@ RADIO_PARAM_PAN_ID
The personal area network identifier (PAN ID), which is used by the h/w frame filtering functionality...
@ RADIO_CONST_TXPOWER_MIN
The minimum transmission power in dBm.
@ RADIO_CONST_CHANNEL_MIN
The lowest radio channel number.
@ RADIO_CONST_TXPOWER_MAX
The maximum transmission power in dBm.
@ 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_POWER_MODE_OFF
Radio powered off and in the lowest possible power consumption state.
@ RADIO_POWER_MODE_ON
Radio powered on and able to receive frames.
@ RADIO_TX_NOACK
A unicast frame was sent OK but an ACK was not received.
@ RADIO_TX_COLLISION
TX failed due to a collision.
@ RADIO_TX_ERR
An error occurred during transmission.
@ RADIO_TX_OK
TX was successful and where an ACK was requested one was received.
Header file for the link-layer address representation.
Header file for the logging system.
Include file for the Contiki low-layer network stack (NETSTACK).
Header file for the Packet buffer (packetbuf) management.
Header file for the radio API.
The structure of a Contiki-NG radio device driver.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.