STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
radio_task.cpp
Go to the documentation of this file.
1#include "radio_task.h"
2
3#include <string.h>
4
5#include "board.h"
6#include "board_exti.h"
7#include "board_spi.h"
8#include "cmsis_os2.h"
9#include "frame.h"
10#include "link.h"
11#include "main.h"
12#include "sx1262.h"
13#include "sx1262_setup.h"
14
15namespace {
16
17using namespace radio_link;
18
19constexpr uint32_t kEvDio1 = 1u << 0;
20constexpr uint32_t kBusyTimeoutMs = 20; // > calibrate 3.5 ms + TCXO 5 ms
21constexpr uint32_t kFrameTimeoutMs = 10;
22constexpr uint32_t kSetupRetryMs = 5000;
23// Proposal pending review, like the key and window in arm_gate.h.
24constexpr uint8_t kTargetId = 0x01;
25
26// Ryan's SpiBus over board_spi (SPI1, CS PC4, BUSY PC5).
27class BoardBus : public SpiBus {
28public:
29 bool wait_busy() override {
30 const uint32_t deadline = board_now_ms() + kBusyTimeoutMs;
33 if (board_deadline_passed(deadline)) {
34 return false;
35 }
36 }
37 return true;
38 }
39 void transfer(const uint8_t* tx, uint8_t* rx, uint16_t len) override {
40 if (board_spi_transfer(BOARD_SPI_RADIO, tx, rx, len,
43 // All zeros decode as "no chip" in sx1262_status_ok(), so a
44 // failed transfer is reported, never mistaken for data.
45 memset(rx, 0, len);
46 }
47 }
48};
49
50// RF_SW (PB1) and waiting, for Sx1262Setup.
51class BoardControl : public RadioControl {
52public:
53 void set_rx_switch(bool receive) override {
55 receive ? GPIO_PIN_SET : GPIO_PIN_RESET);
56 }
57 void delay_ms(uint32_t ms) override {
58 osDelay(ms);
59 }
60};
61
64// The flight settings, except a bench build may lower the transmit power
65// (STAR_RADIO_POWER_DBM, -9..+22 on the high-power PA, datasheet p.84).
66#ifdef STAR_RADIO_POWER_DBM
67constexpr LoraConfig kLora = {kDefaultLora.freq_hz, kDefaultLora.sf,
69 kDefaultLora.preamble, STAR_RADIO_POWER_DBM,
70 kDefaultLora.sync_word};
71static_assert(STAR_RADIO_POWER_DBM >= -9 && STAR_RADIO_POWER_DBM <= 22,
72 "SX1262 high-power PA range is -9..+22 dBm");
73#else
75#endif
79
82uint16_t tx_seq;
85// The RX mode last asked for (mode.c), kept so it survives a late start-up.
90
91void take() {
93}
94void give() {
95 (void)osMutexRelease(mutex);
96}
97
98void try_setup() {
99 take();
100 status.setup_attempts++;
101 const SetupStep step = setup.configure();
102 status.setup_step = static_cast<uint8_t>(step);
103 status.device_errors = setup.device_errors();
104 configured = step == SetupStep::Ok;
105 // A mode asked for before start-up finished (Idle can begin first).
106 if (configured && want_sniff) {
107 (void)setup.start_rx_duty_cycle(want_rx_ms, want_sleep_ms);
108 }
109 give();
110}
111
112void radio_task(void*) {
114 try_setup();
115 uint32_t last_setup = board_now_ms();
116 for (;;) {
117 const uint32_t flags = osThreadFlagsWait(kEvDio1, osFlagsWaitAny, 1000);
118 if (!configured) {
119 if (board_now_ms() - last_setup >= kSetupRetryMs) {
120 try_setup();
121 last_setup = board_now_ms();
122 }
123 continue;
124 }
125 take();
126 const uint32_t ok_before = link.frames_ok();
127 const ArmAction action = link.poll(board_now_ms());
128 if (link.frames_ok() != ok_before) {
129 // Read the signal quality now, before the next packet lands.
130 PacketStatus ps = {0, 0, 0};
131 const Frame& f = link.last_frame();
132 last_rx.quality_ok = receiver.packet_status(ps);
133 last_rx.rssi_x2 = ps.rssi_x2;
134 last_rx.snr_x4 = ps.snr_x4;
135 last_rx.signal_rssi_x2 = ps.signal_rssi_x2;
136 last_rx.type = static_cast<uint8_t>(f.type);
137 last_rx.seq = f.seq;
138 last_rx.payload_len = f.payload_len;
139 memcpy(last_rx.payload, f.payload,
140 f.payload_len < sizeof last_rx.payload
141 ? f.payload_len
142 : sizeof last_rx.payload);
143 last_rx.at_ms = board_now_ms();
144 last_rx.count++;
145 }
146 // In sniff mode the chip returns to STDBY_RC after any DIO1 event
147 // (RxDone, HeaderErr, CrcErr, p.71); restart the duty cycle so the
148 // radio does not go deaf. Skip the 1-second fallback poll: the chip
149 // is still cycling on its own and must not be interrupted.
150 if (flags == kEvDio1) {
151 setup.rearm_rx();
152 }
153 status.frames_ok = link.frames_ok();
154 status.frames_dropped = link.frames_dropped();
155 status.radio_errors = link.radio_errors();
156 status.crc_errors = receiver.crc_errors();
157 give();
158 if (action == ArmAction::Arm) {
159 status.arms++;
160 if (on_command)
162 } else if (action == ArmAction::Disarm) {
163 status.disarms++;
164 if (on_command)
166 }
167 }
168}
169
170} // namespace
171
172// Ryan's seam (src/radio/radio.h), on the real chip. Callers hold the mutex:
173// link.poll() inside the task, radio_send() inside radio_task_send_frame().
174namespace radio_link {
178RadioStatus radio_receive(uint8_t* buf, uint8_t max_len, uint8_t& len) {
179 return receiver.receive(buf, max_len, len);
180}
181RadioStatus radio_send(const uint8_t* bytes, uint8_t len) {
182 return setup.send(bytes, len);
183}
184} // namespace radio_link
185
186extern "C" {
187
188void radio_task_on_command(void (*callback)(radio_command_t)) {
189 on_command = callback;
190}
191
193 static const osMutexAttr_t mutex_attr = {"radio", osMutexPrioInherit,
194 nullptr, 0};
195 mutex = osMutexNew(&mutex_attr);
196 static const osThreadAttr_t attr = {
197 .name = "radio",
198 .attr_bits = 0,
199 .cb_mem = nullptr,
200 .cb_size = 0,
201 .stack_mem = nullptr,
202 .stack_size = 1024,
203 .priority = osPriorityAboveNormal, /* an Arm should not wait */
204 .tz_module = 0,
205 .reserved = 0,
206 };
207 return mutex && osThreadNew(radio_task, nullptr, &attr) != nullptr;
208}
209
211 uint8_t len) {
212 if (!mutex) {
213 return RADIO_SEND_NO_RADIO;
214 }
215 take();
216 if (!configured) {
217 give();
218 return RADIO_SEND_NO_RADIO;
219 }
220 size_t n = 0;
221 if (encode_frame(static_cast<FrameType>(type), tx_seq, payload, len,
222 frame_buf, sizeof frame_buf, n) != FrameStatus::Ok) {
223 give();
225 }
226 tx_seq++;
227 const RadioStatus rs = radio_send(frame_buf, static_cast<uint8_t>(n));
228 status.tx_ok = setup.tx_ok();
229 status.tx_timeouts = setup.tx_timeouts();
230 give();
231 if (rs == RadioStatus::Ok)
232 return RADIO_SEND_OK;
233 if (rs == RadioStatus::ErrTimeout)
234 return RADIO_SEND_TIMEOUT;
235 return RADIO_SEND_NO_RADIO;
236}
237
239 *out = status;
240}
241
242void radio_task_start_sniff(uint32_t rx_ms, uint32_t sleep_ms) {
243 if (!mutex)
244 return;
245 take();
246 want_sniff = true;
247 want_rx_ms = rx_ms;
248 want_sleep_ms = sleep_ms;
249 if (configured)
250 setup.start_rx_duty_cycle(rx_ms, sleep_ms);
251 give();
252}
253
255 if (!mutex)
256 return;
257 take();
258 want_sniff = false;
259 if (configured)
260 setup.start_rx_continuous();
261 give();
262}
263
265 if (!mutex) {
266 *out = last_rx;
267 return;
268 }
269 take();
270 *out = last_rx;
271 give();
272}
273
274} // extern "C"
#define RADIO_RF_SW_GPIO_Port
Definition main.h:110
#define RADIO_BUSY_GPIO_Port
Definition main.h:106
#define RADIO_RF_SW_Pin
Definition main.h:109
#define RADIO_BUSY_Pin
Definition main.h:105
#define RADIO_DIO1_Pin
Definition main.h:111
uint32_t board_now_ms(void)
Definition board.c:24
static bool board_deadline_passed(uint32_t deadline_ms)
Definition board.h:42
bool board_exti_route(uint16_t pin, osThreadId_t thread, uint32_t flags)
Definition board_exti.c:29
board_spi_status_t board_spi_transfer(board_spi_device_t device, const uint8_t *tx, uint8_t *rx, uint16_t len, uint32_t deadline_ms)
Definition board_spi.c:178
@ BOARD_SPI_RADIO
Definition board_spi.h:31
@ BOARD_SPI_OK
Definition board_spi.h:37
void transfer(const uint8_t *tx, uint8_t *rx, uint16_t len) override
#define osFlagsWaitAny
Wait for any flag (default).
Definition cmsis_os2.h:176
void * osMutexId_t
Definition cmsis_os2.h:220
#define osMutexPrioInherit
Priority inherit protocol.
Definition cmsis_os2.h:194
osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)
Create a thread and add it to Active Threads.
Definition cmsis_os2.c:577
osThreadId_t osThreadGetId(void)
Return the thread ID of the current running thread.
Definition cmsis_os2.c:669
#define osWaitForever
Wait forever timeout value.
Definition cmsis_os2.h:173
osMutexId_t osMutexNew(const osMutexAttr_t *attr)
Create and Initialize a Mutex object.
osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout)
Acquire a Mutex or timeout if it is locked.
uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout)
Wait for one or more Thread Flags of the current running thread to become signaled.
@ osPriorityAboveNormal
Priority: above normal.
Definition cmsis_os2.h:131
osStatus_t osMutexRelease(osMutexId_t mutex_id)
Release a Mutex that was acquired by osMutexAcquire.
osStatus_t osDelay(uint32_t ticks)
Wait for Timeout (Time Delay).
Definition cmsis_os2.c:1094
void setup()
Definition main.cpp:571
Over-the-air frame format for the LoRa command link.
GPIO_PinState HAL_GPIO_ReadPin(const GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
@ GPIO_PIN_SET
@ GPIO_PIN_RESET
void(* on_command)(radio_command_t)
uint8_t frame_buf[kFrameMaxLen]
Sx1262Setup setup(bus, control, kLora)
*brief user defined string literal for JSON values *sa std::size_t n
Definition json.hpp:24474
void radio_task_start_sniff(uint32_t rx_ms, uint32_t sleep_ms)
void radio_task_status(radio_status_t *out)
void radio_task_start_continuous_rx(void)
bool radio_task_start(void)
void radio_task_on_command(void(*callback)(radio_command_t))
void radio_task_last_rx(radio_rx_t *out)
radio_send_result_t radio_task_send_frame(uint8_t type, const uint8_t *payload, uint8_t len)
radio_send_result_t
Definition radio_task.h:25
@ RADIO_SEND_BAD_FRAME
Definition radio_task.h:29
@ RADIO_SEND_TIMEOUT
Definition radio_task.h:27
@ RADIO_SEND_NO_RADIO
Definition radio_task.h:28
@ RADIO_SEND_OK
Definition radio_task.h:26
radio_command_t
Definition radio_task.h:32
@ RADIO_CMD_DISARM
Definition radio_task.h:32
@ RADIO_CMD_ARM
Definition radio_task.h:32
Attributes structure for mutex.
Definition cmsis_os2.h:269
Attributes structure for thread.
Definition cmsis_os2.h:240
uint32_t tx_ok
Definition radio_task.h:39
uint32_t tx_timeouts
Definition radio_task.h:39