Skip to content

Commit c77657e

Browse files
committed
sys/nrf_sf_radio: add synchronous flooding module
sys/nrf_sf_radio: add synchronous flooding physical layer and link layer module tests/nrf_sf_radio/: add test for sys/nrf_sf_radio tests/sys/nrf_sf_radio: move test module refresh
1 parent 2cc98da commit c77657e

10 files changed

Lines changed: 723 additions & 0 deletions

File tree

sys/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ endif
131131
ifneq (,$(filter netutils,$(USEMODULE)))
132132
DIRS += net/netutils
133133
endif
134+
ifneq (,$(filter nrf_sf_radio,$(USEMODULE)))
135+
DIRS += nrf_sf_radio
136+
endif
134137
ifneq (,$(filter sema,$(USEMODULE)))
135138
DIRS += sema
136139
endif
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright (C) 2026 Xin He
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
9+
/**
10+
* @ingroup sys_nrf_sf_radio
11+
* @{
12+
*
13+
* @file link_radio.h
14+
* @brief Link layer radio TX/RX startup interface
15+
*
16+
* @author Xin He <xin.he@mailbox.tu-dresden.de>
17+
*
18+
* @}
19+
*/
20+
21+
#ifndef NRF_SF_RADIO_LINK_RADIO_H
22+
#define NRF_SF_RADIO_LINK_RADIO_H
23+
24+
#include <stdbool.h>
25+
#include <stdint.h>
26+
27+
#ifdef __cplusplus
28+
extern "C" {
29+
#endif
30+
31+
/**
32+
* @name BLE-like packet header field lengths
33+
* @{
34+
*/
35+
36+
/**
37+
* @brief Length of the S0 field in bytes.
38+
*/
39+
#define NRF_SF_RADIO_S0_LEN (1U)
40+
41+
/**
42+
* @brief Length of the LENGTH field in bytes.
43+
*/
44+
#define NRF_SF_RADIO_LENGTH_LEN (1U)
45+
46+
/**
47+
* @brief Length of the advertising address field in bytes.
48+
*/
49+
#define NRF_SF_RADIO_ADV_ADDR_LEN (6U)
50+
51+
/**
52+
* @brief Total length of the link-layer packet header in bytes.
53+
*/
54+
#define NRF_SF_RADIO_HDR_LEN (NRF_SF_RADIO_S0_LEN + \
55+
NRF_SF_RADIO_LENGTH_LEN + \
56+
NRF_SF_RADIO_ADV_ADDR_LEN)
57+
58+
/** @} */
59+
60+
/**
61+
* @brief Remove the link-layer header from the received packet
62+
*
63+
* @param[in] packet Received radio packet
64+
*
65+
* @return Pointer to the payload after the link-layer header
66+
*/
67+
const uint8_t *nrf_sf_radio_payload(const uint8_t *packet);
68+
69+
/**
70+
* @brief Send one payload at a scheduled radio start time
71+
*
72+
* @param[in] payload Payload to be transmitted
73+
* @param[in] txen_ticks Absolute timer tick for starting radio ramp-up
74+
* @param[in] event_end_ticks Absolute timer tick by which END is expected
75+
* @param[in] payload_length Payload length in bytes
76+
*
77+
* @return true if the transmission completed before the end time
78+
* @return false if the transmission failed or timed out
79+
*/
80+
bool nrf_sf_radio_tx_start(uint8_t *payload, uint32_t txen_ticks,
81+
uint32_t event_end_ticks,
82+
uint8_t payload_length);
83+
84+
/**
85+
* @brief Start radio reception at a scheduled radio start time
86+
*
87+
* @param[out] rx_buffer Buffer for the received radio packet
88+
* @param[in] rxen_ticks Absolute timer tick for starting radio ramp-up
89+
* @param[in] rx_window_end_ticks Absolute timer tick for ADDRESS timeout
90+
* @param[in] rx_end_ticks Absolute timer tick by which END is expected
91+
*
92+
* @return true if a valid packet was received before the end time
93+
* @return false if no valid packet was received or reception timed out
94+
*/
95+
uint8_t nrf_sf_radio_rx_start(uint8_t *rx_buffer, uint32_t rxen_ticks,
96+
uint32_t rx_window_end_ticks,
97+
uint32_t rx_end_ticks);
98+
99+
/**
100+
* @brief Start radio reception immediately and wait for one packet
101+
*
102+
* @param[out] rx_buffer Buffer for the received radio packet
103+
* @param[in] rx_end_ticks Relative timeout for END after ADDRESS
104+
* @param[in] runtimeout_us Relative timeout for ADDRESS in microseconds
105+
*
106+
* @return Corrected ADDRESS timestamp in timer ticks on success
107+
* @return 0 on timeout or CRC failure
108+
*/
109+
uint32_t nrf_sf_radio_rx_listen_until_packet(uint8_t *rx_buffer,
110+
uint32_t rx_end_ticks,
111+
uint32_t runtimeout_us);
112+
113+
#ifdef __cplusplus
114+
}
115+
#endif
116+
117+
#endif /* NRF_SF_RADIO_LINK_RADIO_H */
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright (C) 2026 Xin He
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
9+
/**
10+
* @defgroup sys_nrf_sf_radio nRF synchronous flooding radio
11+
* @ingroup sys
12+
* @{
13+
*
14+
* @file radio_driver.h
15+
* @brief Physical layer radio, timer and PPI configuration interface
16+
*
17+
* @author Xin He <xin.he@mailbox.tu-dresden.de>
18+
*/
19+
20+
#ifndef NRF_SF_RADIO_RADIO_DRIVER_H
21+
#define NRF_SF_RADIO_RADIO_DRIVER_H
22+
23+
#include <stdbool.h>
24+
#include <stdint.h>
25+
26+
#include "cpu.h"
27+
28+
#ifdef __cplusplus
29+
extern "C" {
30+
#endif
31+
32+
/**
33+
* @brief 16 MHz timer: 1 microsecond equals 16 ticks
34+
*/
35+
#define NRF_SF_RADIO_TIMER_TICKS_PER_US (16U)
36+
37+
/**
38+
* @brief Convert microseconds to ticks
39+
*/
40+
#define NRF_SF_RADIO_US_TO_TIMER_TICKS(us) ((uint32_t)(us) << 4U)
41+
42+
/**
43+
* @brief Convert ticks to microseconds
44+
*/
45+
#define NRF_SF_RADIO_TIMER_TICKS_TO_US(tk) ((uint32_t)(tk) >> 4U)
46+
47+
/**
48+
* @brief ramp-up time ticks
49+
*/
50+
#define NRF_SF_RADIO_RAMPUP_TIME_TICKS NRF_SF_RADIO_US_TO_TIMER_TICKS(40U)
51+
52+
/**
53+
* @brief Initialize the radio timer and PPI
54+
*/
55+
void nrf_sf_radio_start(void);
56+
57+
/**
58+
* @brief Busy-wait for a time interval or condition
59+
*
60+
* @param[in] event Required condition
61+
* @param[in] timeout_ticks Time interval to wait
62+
*/
63+
void nrf_sf_radio_wait_until(volatile uint32_t *event,
64+
uint32_t timeout_ticks);
65+
66+
/**
67+
* @brief Busy-wait to a time point or condition
68+
*
69+
* @param[in] event Required condition
70+
* @param[in] deadline_ticks Time point to wait
71+
*/
72+
void nrf_sf_radio_wait_until_abs(volatile uint32_t *event,
73+
uint32_t deadline_ticks);
74+
75+
/**
76+
* @brief Get the timestamp of the last radio READY event
77+
*
78+
* @return Timestamp of the last radio READY event
79+
*/
80+
uint32_t nrf_sf_radio_get_last_ready_time_ticks(void);
81+
82+
/**
83+
* @brief Get the timestamp of the last radio END event
84+
*
85+
* @return Timestamp of the last radio END event
86+
*/
87+
uint32_t nrf_sf_radio_get_last_end_time_ticks(void);
88+
89+
/**
90+
* @brief Get the timestamp of the last radio ADDRESS event
91+
*
92+
* @return Timestamp of the last radio ADDRESS event
93+
*/
94+
uint32_t nrf_sf_radio_get_last_address_time_ticks(void);
95+
96+
/**
97+
* @brief Get the current timestamp
98+
*
99+
* @return Current timestamp
100+
*/
101+
uint32_t nrf_sf_radio_now_ticks(void);
102+
103+
/**
104+
* @brief Start radio transmission at the scheduled time
105+
*
106+
* @param[in] buf Buffer for the transmitted radio packet
107+
* @param[in] deadline_ticks Scheduled radio start time
108+
*/
109+
void nrf_sf_radio_tx_arm(uint8_t *buf, uint32_t deadline_ticks);
110+
111+
/**
112+
* @brief Start radio reception at the scheduled time
113+
*
114+
* @param[out] buf Buffer for the received radio packet
115+
* @param[in] deadline_ticks Scheduled radio start time
116+
*/
117+
void nrf_sf_radio_rx_arm(uint8_t *buf, uint32_t deadline_ticks);
118+
119+
/**
120+
* @brief Start radio reception immediately
121+
*
122+
* @param[out] buf Buffer for the received radio packet
123+
*/
124+
void nrf_sf_radio_try_rx_enable(uint8_t *buf);
125+
126+
#ifdef __cplusplus
127+
}
128+
#endif
129+
130+
#endif /* NRF_SF_RADIO_RADIO_DRIVER_H */
131+
132+
/** @} */

sys/nrf_sf_radio/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include $(RIOTBASE)/Makefile.base

sys/nrf_sf_radio/link_radio.c

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright (C) 2026 Xin He
3+
*
4+
* This file is subject to the terms and conditions of the GNU Lesser
5+
* General Public License v2.1. See the file LICENSE in the top level
6+
* directory for more details.
7+
*/
8+
9+
/**
10+
* @ingroup sys_nrf_sf_radio
11+
* @{
12+
*
13+
* @file
14+
* @brief Link layer radio TX/RX startup implementation
15+
*
16+
* @author Xin He <xin.he@mailbox.tu-dresden.de>
17+
*
18+
* @}
19+
*/
20+
21+
#include <string.h>
22+
#include <stdio.h>
23+
#include "nrf_sf_radio/link_radio.h"
24+
#include "nrf_sf_radio/radio_driver.h"
25+
26+
#define NRF_SF_RADIO_TX_CHAIN_DELAY_US (10U)
27+
#define NRF_SF_RADIO_ADV_ADDR_LO (0xABABABUL)
28+
#define NRF_SF_RADIO_ADV_ADDR_HI (0xABABC0UL)
29+
30+
static void _encode_packet_header(uint8_t *dst, const uint8_t *payload,
31+
uint8_t length);
32+
33+
const uint8_t *nrf_sf_radio_payload(const uint8_t *packet)
34+
{
35+
return &packet[NRF_SF_RADIO_HDR_LEN];
36+
}
37+
38+
static void _encode_packet_header(uint8_t *dst, const uint8_t *payload,
39+
uint8_t length)
40+
{
41+
dst[0] = 0x42;
42+
dst[1] = (uint8_t)(NRF_SF_RADIO_ADV_ADDR_LEN + length);
43+
dst[2] = (uint8_t)(NRF_SF_RADIO_ADV_ADDR_LO & 0xFFu);
44+
dst[3] = (uint8_t)((NRF_SF_RADIO_ADV_ADDR_LO >> 8) & 0xFFu);
45+
dst[4] = (uint8_t)((NRF_SF_RADIO_ADV_ADDR_LO >> 16) & 0xFFu);
46+
dst[5] = (uint8_t)(NRF_SF_RADIO_ADV_ADDR_HI & 0xFFu);
47+
dst[6] = (uint8_t)((NRF_SF_RADIO_ADV_ADDR_HI >> 8) & 0xFFu);
48+
dst[7] = (uint8_t)((NRF_SF_RADIO_ADV_ADDR_HI >> 16) & 0xFFu);
49+
memcpy(&dst[8], payload, length);
50+
}
51+
52+
bool nrf_sf_radio_tx_start(uint8_t *payload, uint32_t txen_ticks,
53+
uint32_t event_end_ticks, uint8_t payload_length)
54+
{
55+
uint8_t dst[NRF_SF_RADIO_HDR_LEN + payload_length];
56+
57+
_encode_packet_header(dst, payload, payload_length);
58+
nrf_sf_radio_tx_arm(dst, txen_ticks);
59+
60+
nrf_sf_radio_wait_until_abs(&NRF_RADIO->EVENTS_ADDRESS,
61+
txen_ticks +
62+
NRF_SF_RADIO_RAMPUP_TIME_TICKS +
63+
NRF_SF_RADIO_US_TO_TIMER_TICKS(40));
64+
if (NRF_RADIO->EVENTS_ADDRESS != 0) {
65+
nrf_sf_radio_wait_until_abs(&NRF_RADIO->EVENTS_END,
66+
event_end_ticks +
67+
NRF_SF_RADIO_US_TO_TIMER_TICKS(1));
68+
if (NRF_RADIO->EVENTS_END == 0) {
69+
return false;
70+
}
71+
return true;
72+
}
73+
74+
return false;
75+
}
76+
77+
uint8_t nrf_sf_radio_rx_start(uint8_t *rx_buffer, uint32_t rxen_ticks,
78+
uint32_t rx_window_end_ticks,
79+
uint32_t rx_end_ticks)
80+
{
81+
nrf_sf_radio_rx_arm(rx_buffer, rxen_ticks);
82+
83+
nrf_sf_radio_wait_until_abs(&NRF_RADIO->EVENTS_ADDRESS,
84+
rx_window_end_ticks);
85+
86+
if (NRF_RADIO->EVENTS_ADDRESS != 0) {
87+
nrf_sf_radio_wait_until_abs(&NRF_RADIO->EVENTS_END,
88+
rx_end_ticks +
89+
NRF_SF_RADIO_US_TO_TIMER_TICKS(
90+
NRF_SF_RADIO_TX_CHAIN_DELAY_US));
91+
if ((NRF_RADIO->EVENTS_END != 0) && (NRF_RADIO->CRCSTATUS != 0)) {
92+
return 0;
93+
}else if (NRF_RADIO->EVENTS_END == 0){
94+
return 2;
95+
}else {
96+
return 3;
97+
}
98+
}
99+
else {
100+
NRF_RADIO->TASKS_DISABLE = 1;
101+
return 1;
102+
}
103+
104+
}
105+
106+
uint32_t nrf_sf_radio_rx_listen_until_packet(uint8_t *rx_buffer,
107+
uint32_t rx_end_ticks,
108+
uint32_t runtimeout_us)
109+
{
110+
uint32_t rx_ticks;
111+
112+
nrf_sf_radio_try_rx_enable(rx_buffer);
113+
114+
nrf_sf_radio_wait_until(&NRF_RADIO->EVENTS_ADDRESS,
115+
NRF_SF_RADIO_US_TO_TIMER_TICKS(runtimeout_us));
116+
if (NRF_RADIO->EVENTS_ADDRESS != 0) {
117+
rx_ticks = nrf_sf_radio_get_last_address_time_ticks();
118+
nrf_sf_radio_wait_until(&NRF_RADIO->EVENTS_END, rx_end_ticks);
119+
if ((NRF_RADIO->EVENTS_END != 0) && (NRF_RADIO->CRCSTATUS == 1)) {
120+
return rx_ticks -
121+
NRF_SF_RADIO_US_TO_TIMER_TICKS(
122+
NRF_SF_RADIO_TX_CHAIN_DELAY_US);
123+
}
124+
}
125+
126+
return 0;
127+
}

0 commit comments

Comments
 (0)