20#include "nrf_802154.h"
21#include "nrf_802154_config.h"
29#define LOG_MODULE "nrf54l15-radio"
30#define LOG_LEVEL LOG_CONF_LEVEL_RADIO
34#define MAX_PAYLOAD_LEN 125
36#define FRAME_ACK_REQUEST_BIT 0x20
39#define DEFAULT_CHANNEL 26
40#define DEFAULT_TX_POWER 0
45#define TX_DONE_TIMEOUT_US 250000ULL
46#define TX_ABORT_TIMEOUT_US 10000ULL
47#define CCA_DONE_TIMEOUT_US 50000ULL
51static uint8_t tx_buf[1 + MAX_PAYLOAD_LEN + 2];
52static volatile uint8_t tx_buf_len;
58#define RX_BUF_COUNT NRF_802154_RX_BUFFERS
59static uint8_t *rx_bufs[RX_BUF_COUNT];
60static int8_t rx_rssi[RX_BUF_COUNT];
61static uint8_t rx_lqi[RX_BUF_COUNT];
62static volatile uint8_t rx_head;
63static volatile uint8_t rx_tail;
66static volatile bool tx_done;
67static volatile bool tx_success;
68static volatile nrf_802154_tx_error_t tx_error;
71static volatile bool cca_done;
72static volatile bool cca_free;
75static volatile uint32_t rx_fail_count;
76static volatile uint32_t tx_fail_count;
79static uint8_t current_channel = DEFAULT_CHANNEL;
80static int8_t current_tx_power = DEFAULT_TX_POWER;
81static bool radio_is_on;
84PROCESS(nrf54l15_radio_process,
"nRF54L15 radio driver");
87tx_error_name(nrf_802154_tx_error_t error)
90 case NRF_802154_TX_ERROR_NONE:
92 case NRF_802154_TX_ERROR_BUSY_CHANNEL:
93 return "busy_channel";
94 case NRF_802154_TX_ERROR_INVALID_ACK:
96 case NRF_802154_TX_ERROR_NO_MEM:
98 case NRF_802154_TX_ERROR_TIMESLOT_ENDED:
99 return "timeslot_ended";
100 case NRF_802154_TX_ERROR_NO_ACK:
102 case NRF_802154_TX_ERROR_ABORTED:
104 case NRF_802154_TX_ERROR_TIMESLOT_DENIED:
105 return "timeslot_denied";
106 case NRF_802154_TX_ERROR_KEY_ID_INVALID:
107 return "key_id_invalid";
108 case NRF_802154_TX_ERROR_FRAME_COUNTER_ERROR:
109 return "frame_counter_error";
110 case NRF_802154_TX_ERROR_TIMESTAMP_ENCODING_ERROR:
111 return "timestamp_encoding_error";
112 case NRF_802154_TX_ERROR_INVALID_REQUEST:
113 return "invalid_request";
120wait_for_flag(
volatile bool *flag, uint64_t timeout_us)
122 uint64_t deadline = nrf_802154_time_get() + timeout_us;
124 while(!*flag && nrf_802154_time_get() < deadline) {
132recover_to_receive_state(
void)
138 if(nrf_802154_sleep()) {
139 (void)wait_for_flag(&tx_done, TX_ABORT_TIMEOUT_US);
142 if(!nrf_802154_receive()) {
143 LOG_WARN(
"Failed to restore receive state\n");
150 LOG_INFO(
"Initializing nrf_802154 radio driver\n");
155 nrf_802154_channel_set(current_channel);
156 nrf_802154_tx_power_set(current_tx_power);
159 nrf_802154_auto_ack_set(
true);
160 nrf_802154_rx_on_when_idle_set(
true);
163 uint8_t pan_id[2] = {
164 (uint8_t)(IEEE802154_PANID & 0xFF),
165 (uint8_t)(IEEE802154_PANID >> 8)
167 nrf_802154_pan_id_set(pan_id);
170 uint8_t short_addr[2] = {
174 nrf_802154_short_address_set(short_addr);
178 for(
int i = 0; i < 8; i++) {
179 if(i < LINKADDR_SIZE) {
185 nrf_802154_extended_address_set(ext_addr);
196 LOG_INFO(
"Radio initialized, channel %u, PAN 0x%04x\n",
197 current_channel, IEEE802154_PANID);
206 LOG_DBG(
"Radio ON\n");
207 ENERGEST_ON(ENERGEST_TYPE_LISTEN);
208 if(!nrf_802154_receive()) {
209 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
210 LOG_WARN(
"Failed to enter receive state\n");
213 LOG_DBG(
"receive() returned, ticks=%lu\n", (
unsigned long)
clock_time());
223 LOG_DBG(
"Radio OFF\n");
225 ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
232prepare(
const void *payload,
unsigned short payload_len)
234 if(payload_len > MAX_PAYLOAD_LEN) {
235 LOG_WARN(
"TX payload too long: %u\n", payload_len);
240 tx_buf[0] = payload_len + 2;
241 memcpy(&tx_buf[1], payload, payload_len);
242 tx_buf_len = payload_len;
248transmit(
unsigned short transmit_len)
250 nrf_802154_transmit_metadata_t metadata = {
251 .frame_props = NRF_802154_TRANSMITTED_FRAME_PROPS_DEFAULT_INIT,
253 .tx_power = { .use_metadata_value =
false },
254 .tx_channel = { .use_metadata_value =
false },
255 .tx_timestamp_encode =
false,
263 LOG_DBG(
"TX %u bytes, ch=%u\n", tx_buf[0], nrf_802154_channel_get());
267 tx_error = NRF_802154_TX_ERROR_NONE;
269 ENERGEST_SWITCH(ENERGEST_TYPE_LISTEN, ENERGEST_TYPE_TRANSMIT);
273 nrf_802154_tx_error_t tx_err = nrf_802154_transmit_raw(tx_buf, &metadata);
275 LOG_DBG(
"TX result=%u\n", tx_err);
277 if(tx_err != NRF_802154_TX_ERROR_NONE) {
278 LOG_WARN(
"TX request rejected: %s (%u)\n", tx_error_name(tx_err), tx_err);
279 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
281 if(tx_err == NRF_802154_TX_ERROR_BUSY_CHANNEL) {
282 recover_to_receive_state();
286 if(tx_err == NRF_802154_TX_ERROR_INVALID_ACK ||
287 tx_err == NRF_802154_TX_ERROR_NO_ACK) {
295 if(!wait_for_flag(&tx_done, TX_DONE_TIMEOUT_US)) {
300 LOG_WARN(
"TX timeout\n");
301 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
302 tx_error = NRF_802154_TX_ERROR_ABORTED;
306 ENERGEST_SWITCH(ENERGEST_TYPE_TRANSMIT, ENERGEST_TYPE_LISTEN);
309 LOG_DBG(
"TX OK %u bytes on ch %u\n", tx_buf[0], current_channel);
313 if(tx_error == NRF_802154_TX_ERROR_NO_ACK) {
314 LOG_WARN(
"TX failed: no ACK\n");
318 if(tx_error == NRF_802154_TX_ERROR_INVALID_ACK) {
319 LOG_WARN(
"TX failed: invalid ACK\n");
323 if(tx_error == NRF_802154_TX_ERROR_BUSY_CHANNEL) {
324 LOG_WARN(
"TX failed: busy channel\n");
328 LOG_WARN(
"TX failed: %s (%u)\n", tx_error_name(tx_error), tx_error);
333send(
const void *payload,
unsigned short payload_len)
335 prepare(payload, payload_len);
336 return transmit(payload_len);
340radio_read(
void *buf,
unsigned short buf_len)
342 if(rx_tail == rx_head) {
346 uint8_t idx = rx_tail % RX_BUF_COUNT;
347 uint8_t *p_data = rx_bufs[idx];
356 uint8_t frame_len = p_data[0];
357 uint8_t payload_len = frame_len - 2;
359 if(payload_len > buf_len) {
360 payload_len = buf_len;
363 memcpy(buf, &p_data[1], payload_len);
366 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rx_rssi[idx]);
367 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, rx_lqi[idx]);
370 nrf_802154_buffer_free_raw(p_data);
374 LOG_DBG(
"RX %u bytes, RSSI %d, LQI %u\n", payload_len,
375 rx_rssi[idx], rx_lqi[idx]);
392 if(!nrf_802154_cca()) {
393 LOG_WARN(
"CCA could not start\n");
398 if(!wait_for_flag(&cca_done, CCA_DONE_TIMEOUT_US)) {
399 LOG_WARN(
"CCA timeout\n");
400 recover_to_receive_state();
404 return cca_free ? 1 : 0;
408receiving_packet(
void)
418 return (rx_head != rx_tail) ? 1 : 0;
474 case RADIO_CONST_MAX_PAYLOAD_LEN:
475 *value = MAX_PAYLOAD_LEN;
496 if(value < 11 || value > 26) {
499 current_channel = (uint8_t)value;
500 nrf_802154_channel_set(current_channel);
504 current_tx_power = (int8_t)value;
505 nrf_802154_tx_power_set(current_tx_power);
520get_object(radio_param_t param,
void *dest,
size_t size)
526set_object(radio_param_t param,
const void *src,
size_t size)
535 const uint8_t *
addr = (
const uint8_t *)src;
536 for(
int i = 0; i < 8; i++) {
537 ext_addr[i] =
addr[7 - i];
539 nrf_802154_extended_address_set(ext_addr);
546 nrf_802154_pan_id_set((
const uint8_t *)src);
553 nrf_802154_short_address_set((
const uint8_t *)src);
563nrf_802154_received_timestamp_raw(uint8_t *p_data, int8_t power,
564 uint8_t lqi, uint64_t time)
566 uint8_t idx = rx_head % RX_BUF_COUNT;
568 if(((rx_head - rx_tail) & 0xFF) >= RX_BUF_COUNT) {
570 if(rx_bufs[rx_tail % RX_BUF_COUNT] != NULL) {
571 nrf_802154_buffer_free_raw(rx_bufs[rx_tail % RX_BUF_COUNT]);
572 rx_bufs[rx_tail % RX_BUF_COUNT] = NULL;
575 idx = rx_head % RX_BUF_COUNT;
578 rx_bufs[idx] = p_data;
579 rx_rssi[idx] = power;
588nrf_802154_receive_failed(nrf_802154_rx_error_t error, uint32_t
id)
597nrf_802154_transmitted_raw(uint8_t *p_frame,
598 const nrf_802154_transmit_done_metadata_t *p_metadata)
600 bool ack_requested =
false;
602 if(p_frame != NULL) {
604 ack_requested = (p_frame[1] & FRAME_ACK_REQUEST_BIT) != 0;
607 if(p_metadata->data.transmitted.p_ack != NULL) {
608 uint8_t *ack = p_metadata->data.transmitted.p_ack;
609 uint8_t ack_len = p_metadata->data.transmitted.length;
614 nrf_802154_buffer_free_raw(ack);
616 }
else if(ack_requested) {
617 tx_error = NRF_802154_TX_ERROR_NO_ACK;
628nrf_802154_transmit_failed(uint8_t *p_frame,
629 nrf_802154_tx_error_t error,
630 const nrf_802154_transmit_done_metadata_t *p_metadata)
643nrf_802154_cca_done(
bool channel_free)
645 cca_free = channel_free;
651nrf_802154_cca_failed(nrf_802154_cca_error_t error)
660nrf_802154_energy_detected(
const nrf_802154_energy_detected_t *p_result)
666nrf_802154_energy_detection_failed(nrf_802154_ed_error_t error)
680 if(rx_fail_count > 0) {
681 if(rx_fail_count > 16) {
682 LOG_WARN(
"RX failed %" PRIu32
" times\n", rx_fail_count);
686 if(tx_fail_count > 0) {
687 LOG_WARN(
"TX failed %" PRIu32
" times\n", tx_fail_count);
692 while(pending_packet()) {
697 NETSTACK_MAC.
input();
Header file for the energy estimation mechanism.
802.15.4 frame creation and parsing functions
clock_time_t clock_time(void)
Get the current clock time.
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.
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.
@ 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_PARAM_CCA_THRESHOLD
Clear channel assessment threshold in dBm.
@ 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.
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(* 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.
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.