ACwing FC firmware
STM32WB55: attitude IEKF, altitude Kalman filter, flight core, protocol v2
Loading...
Searching...
No Matches
tlm_ble.c
Go to the documentation of this file.
1
5#include "tlm_ble.h"
6#include "proto_v2.h"
7#include <string.h>
8
9#ifndef APP_BLE_STATE_DECIM_DEFAULT
10#include "app_config.h"
11#define APP_BLE_STATE_DECIM_DEFAULT APP_BLE_STATE_DECIM
12#endif
13
14#if defined(__arm__)
15#define TLM_BARRIER() __asm volatile ("dmb" ::: "memory")
16#else
17#define TLM_BARRIER() __sync_synchronize()
18#endif
19
20#define RING_MASK (TLM_BLE_RING_SIZE - 1u)
21#if (TLM_BLE_RING_SIZE & RING_MASK) != 0
22#error "TLM_BLE_RING_SIZE must be a power of 2"
23#endif
24
25enum { RHI = 0, RLO = 1, NRING = 2 };
26
27typedef struct {
28 uint8_t buf[TLM_BLE_RING_SIZE];
29 volatile uint32_t head; /* written only by the producer */
30 volatile uint32_t tail; /* written only by the consumer */
31} ring_t;
32
34static volatile uint32_t s_dropped;
35static volatile uint8_t s_state;
36static volatile uint16_t s_mtu = TLM_BLE_MTU_DEFAULT;
37static volatile uint8_t s_err;
38static volatile uint8_t s_initReq, s_subReq, s_open;
39static volatile uint8_t s_decim = APP_BLE_STATE_DECIM_DEFAULT;
40static uint16_t s_lastSeq;
41static uint8_t s_haveSeq;
42
43volatile uint8_t g_dbg_ble_stall;
44
45/* consumer: frame being sent across notifications, and the pending plan */
46static int8_t s_cur = -1; /* ring of a partially sent frame, -1 none */
47static uint16_t s_curRem;
48static uint32_t s_planTail[NRING];
49static int8_t s_planCur;
50static uint16_t s_planRem, s_planTotal;
51static uint8_t s_planValid;
52
53void tlm_ble_reset(void)
54{
55 for (int i = 0; i < NRING; ++i) s_r[i].head = s_r[i].tail = 0u;
56 s_dropped = 0u;
59 s_err = 0u;
60 s_initReq = s_subReq = s_open = 0u;
62 s_haveSeq = 0u;
63 s_cur = -1; s_curRem = 0u; s_planValid = 0u;
64 g_dbg_ble_stall = 0u;
65}
66
67/* ------------------------------------------------------------ producers */
68/* fill level (out of 100) up to which a frame type may be queued */
69static uint32_t level_pct(uint8_t type)
70{
71 switch (type) {
72 case PV2_FT_ACK: case PV2_FT_EVENT: case PV2_FT_CAPS: return 100u;
73 case PV2_FT_CALIB: case PV2_FT_PARAM: case PV2_FT_INIT:
74 case PV2_FT_STATUS: return 85u;
75 case PV2_FT_FLIGHT: case PV2_FT_CHECKS: return 70u;
76 case PV2_FT_LOG_ENTRY: case PV2_FT_LOG_DATA: return 60u; /* log download (disarmed) */
77 case PV2_FT_POWER: case PV2_FT_NAV: return 55u;
78 case PV2_FT_STATE: return 50u;
79 default: return 45u; /* MOTORS, SYSTEM */
80 }
81}
82
83static int push(ring_t *r, const uint8_t *frame, uint16_t len)
84{
85 if (len < 6u || frame[0] != 0xA5u || frame[1] != 0x5Au || frame[3] + 6u != len) { s_dropped++; return -1; }
86 const uint32_t head = r->head;
87 const uint32_t used = head - r->tail;
88 if (used + len > (TLM_BLE_RING_SIZE * level_pct(frame[2])) / 100u) { s_dropped++; return -1; }
89 const uint32_t pos = head & RING_MASK;
90 const uint32_t first = (len < TLM_BLE_RING_SIZE - pos) ? len : (TLM_BLE_RING_SIZE - pos);
91 memcpy(&r->buf[pos], frame, first);
92 memcpy(&r->buf[0], frame + first, len - first);
93 TLM_BARRIER(); /* data visible before the new head */
94 r->head = head + len; /* only whole frames become visible */
95 return 0;
96}
97
98int tlm_ble_push(const uint8_t *frame, uint16_t len)
99{
100 if (s_state != TLM_BLE_STREAMING || !s_open) return 1;
101 return push(&s_r[RLO], frame, len);
102}
103
104int tlm_ble_push_hi(const uint8_t *frame, uint16_t len)
105{
106 if (s_state != TLM_BLE_STREAMING) return 1;
107 return push(&s_r[RHI], frame, len);
108}
109
110uint16_t tlm_ble_hi_free(void)
111{
112 return (uint16_t)(TLM_BLE_RING_SIZE - (s_r[RHI].head - s_r[RHI].tail));
113}
114
116{
117 if (s_state != TLM_BLE_STREAMING || !s_open) return 0;
118 const uint16_t n = s_decim ? s_decim : 1u;
119 if (s_haveSeq) {
120 const uint16_t d = (uint16_t)(seq - s_lastSeq); /* wrap-safe; a reboot gives a large d */
121 if (d == 0u || d < n) return 0;
122 }
123 s_lastSeq = seq;
124 s_haveSeq = 1u;
125 return 1;
126}
127
129{
130 if (!s_initReq) return 0;
131 s_initReq = 0u;
132 return 1;
133}
134
136{
137 if (!s_subReq) return 0;
138 s_subReq = 0u;
139 return 1;
140}
141
142void tlm_ble_open_streams(void) { s_open = 1u; }
143
144/* ------------------------------------------------------------ consumer */
145static uint32_t avail(int i, const uint32_t *t) { return s_r[i].head - t[i]; }
146
147uint16_t tlm_ble_queued(void)
148{
149 return (uint16_t)((s_r[RHI].head - s_r[RHI].tail) + (s_r[RLO].head - s_r[RLO].tail));
150}
151
152uint16_t tlm_ble_peek(uint8_t *dst, uint16_t max)
153{
154 uint32_t t[NRING] = { s_r[RHI].tail, s_r[RLO].tail };
155 int8_t cur = s_cur;
156 uint16_t rem = s_curRem, n = 0;
157 TLM_BARRIER(); /* heads read before the data */
158 while (n < max) {
159 if (cur < 0) { /* frame boundary: HI first */
160 if (avail(RHI, t)) cur = RHI;
161 else if (avail(RLO, t)) cur = RLO;
162 else break;
163 rem = (uint16_t)(s_r[cur].buf[(t[cur] + 3u) & RING_MASK] + 6u);
164 }
165 ring_t *r = &s_r[cur];
166 uint16_t take = (uint16_t)(max - n);
167 if (take > rem) take = rem;
168 const uint32_t pos = t[cur] & RING_MASK;
169 const uint32_t first = (take < TLM_BLE_RING_SIZE - pos) ? take : (TLM_BLE_RING_SIZE - pos);
170 memcpy(dst + n, &r->buf[pos], first);
171 memcpy(dst + n + first, &r->buf[0], take - first);
172 t[cur] += take; n = (uint16_t)(n + take); rem = (uint16_t)(rem - take);
173 if (rem == 0u) cur = -1;
174 }
175 s_planTail[RHI] = t[RHI]; s_planTail[RLO] = t[RLO];
176 s_planCur = cur; s_planRem = rem; s_planTotal = n; s_planValid = 1u;
177 return n;
178}
179
180void tlm_ble_consume(uint16_t n)
181{
182 if (!s_planValid || n != s_planTotal) return; /* only the last peek, whole */
183 TLM_BARRIER(); /* data read before freeing */
187 s_planValid = 0u;
188}
189
191{
192 s_r[RHI].tail = s_r[RHI].head;
193 s_r[RLO].tail = s_r[RLO].head;
194 s_cur = -1; s_curRem = 0u; s_planValid = 0u;
195}
196
197/* ------------------------------------------------------------ link events */
199{
200 const uint8_t prev = s_state;
201 if (st == TLM_BLE_STREAMING && prev != TLM_BLE_STREAMING) {
202 s_haveSeq = 0u;
203 s_open = 0u; /* LO closed until CAPS, INIT, CHECKS are queued */
204 s_subReq = 1u;
205 }
206 if (st != TLM_BLE_STREAMING) s_open = 0u;
208 s_state = (uint8_t)st;
209}
210
211void tlm_ble_set_mtu(uint16_t att_mtu)
212{
213 if (att_mtu < TLM_BLE_MTU_DEFAULT) att_mtu = TLM_BLE_MTU_DEFAULT;
214 s_mtu = att_mtu;
215}
216
217void tlm_ble_set_error(uint8_t ble_status) { s_err = ble_status; }
218
219void tlm_ble_on_command(const uint8_t *data, uint16_t len)
220{
221 if (!data || len == 0u) return;
222 switch (data[0]) {
224 s_initReq = 1u;
225 break;
227 if (len >= 2u && data[1] >= 1u) { s_decim = data[1]; s_haveSeq = 0u; }
228 break;
229 default:
230 break; /* protocol v2: app_link.c */
231 }
232}
233
234/* ------------------------------------------------------------ diagnostics */
236uint16_t tlm_ble_mtu(void) { return s_mtu; }
237uint16_t tlm_ble_chunk_max(void) { return (uint16_t)(s_mtu - 3u); }
238uint32_t tlm_ble_dropped(void) { return s_dropped; }
239uint8_t tlm_ble_error(void) { return s_err; }
240uint8_t tlm_ble_state_decim(void) { return s_decim; }
Phase-1 configuration: P-NUCLEO-WB55 (NUCLEO-WB55RG) + X-NUCLEO-IKS4A1 in Mode 3 (LSM6DSV16X is the s...
uint8_t pos
Definition calib_mgr.c:34
uint32_t n
Definition calib_mgr.c:35
float used
Definition calib_mgr.c:50
uint8_t seq
Definition log_task.c:48
ACwing Pilot app protocol v2: identifiers and frame layouts.
#define PV2_FT_CAPS
Definition proto_v2.h:30
#define PV2_FT_ACK
Definition proto_v2.h:39
#define PV2_FT_LOG_ENTRY
answer to LOG_LIST, one per log
Definition proto_v2.h:42
#define PV2_FT_STATE
Definition proto_v2.h:26
#define PV2_FT_EVENT
Definition proto_v2.h:36
#define PV2_FT_POWER
Definition proto_v2.h:32
#define PV2_FT_STATUS
Definition proto_v2.h:28
#define PV2_FT_LOG_DATA
answer to LOG_READ
Definition proto_v2.h:43
#define PV2_FT_CHECKS
Definition proto_v2.h:40
#define PV2_FT_PARAM
Definition proto_v2.h:37
#define PV2_FT_NAV
Definition proto_v2.h:33
#define PV2_FT_FLIGHT
Definition proto_v2.h:31
#define PV2_FT_CALIB
Definition proto_v2.h:38
#define PV2_FT_INIT
Definition proto_v2.h:27
volatile uint32_t head
Definition tlm_ble.c:29
uint8_t buf[TLM_BLE_RING_SIZE]
Definition tlm_ble.c:28
volatile uint32_t tail
Definition tlm_ble.c:30
void tlm_ble_set_state(tlm_ble_state_t st)
Definition tlm_ble.c:198
static volatile uint32_t s_dropped
Definition tlm_ble.c:34
int tlm_ble_push(const uint8_t *frame, uint16_t len)
Queue a whole frame or nothing.
Definition tlm_ble.c:98
uint16_t tlm_ble_peek(uint8_t *dst, uint16_t max)
Copies up to max bytes of the next notification into dst without removing them; tlm_ble_consume(n) wi...
Definition tlm_ble.c:152
static uint32_t level_pct(uint8_t type)
Definition tlm_ble.c:69
static uint8_t s_haveSeq
Definition tlm_ble.c:41
int tlm_ble_want_state(uint16_t seq)
1 if a STATE frame with this sequence number must go over BLE (decimation)
Definition tlm_ble.c:115
static ring_t s_r[NRING]
Definition tlm_ble.c:33
static uint16_t s_planRem
Definition tlm_ble.c:50
static uint32_t s_planTail[NRING]
Definition tlm_ble.c:48
static volatile uint8_t s_decim
Definition tlm_ble.c:39
static uint16_t s_curRem
Definition tlm_ble.c:47
volatile uint8_t g_dbg_ble_stall
Bench test of HANDOVER_FW.md §6 / §16.12 (debugger Live Expression): 1 = the BLE path stops on purpos...
Definition tlm_ble.c:43
static int8_t s_planCur
Definition tlm_ble.c:49
void tlm_ble_consume(uint16_t n)
Definition tlm_ble.c:180
static uint16_t s_lastSeq
Definition tlm_ble.c:40
void tlm_ble_on_command(const uint8_t *data, uint16_t len)
legacy 0x01/0x02
Definition tlm_ble.c:219
static int push(ring_t *r, const uint8_t *frame, uint16_t len)
Definition tlm_ble.c:83
uint16_t tlm_ble_hi_free(void)
bytes free in HI
Definition tlm_ble.c:110
static uint16_t s_planTotal
Definition tlm_ble.c:50
int tlm_ble_take_subscribe(void)
1 once after a client enabled notifications (AppTask: CAPS, INIT, CHECKS)
Definition tlm_ble.c:135
void tlm_ble_reset(void)
Definition tlm_ble.c:53
static int8_t s_cur
Definition tlm_ble.c:46
uint16_t tlm_ble_mtu(void)
Definition tlm_ble.c:236
int tlm_ble_push_hi(const uint8_t *frame, uint16_t len)
HI: AppTask
Definition tlm_ble.c:104
static volatile uint8_t s_state
Definition tlm_ble.c:35
uint8_t tlm_ble_state_decim(void)
Definition tlm_ble.c:240
#define RING_MASK
Definition tlm_ble.c:20
#define TLM_BARRIER()
Definition tlm_ble.c:17
uint16_t tlm_ble_chunk_max(void)
ATT_MTU - 3.
Definition tlm_ble.c:237
uint32_t tlm_ble_dropped(void)
Definition tlm_ble.c:238
@ RHI
Definition tlm_ble.c:25
@ RLO
Definition tlm_ble.c:25
@ NRING
Definition tlm_ble.c:25
void tlm_ble_discard(void)
drop everything queued (consumer side)
Definition tlm_ble.c:190
uint16_t tlm_ble_queued(void)
Definition tlm_ble.c:147
tlm_ble_state_t tlm_ble_state(void)
Definition tlm_ble.c:235
void tlm_ble_set_mtu(uint16_t att_mtu)
Definition tlm_ble.c:211
void tlm_ble_set_error(uint8_t ble_status)
last non-recoverable stack error
Definition tlm_ble.c:217
static volatile uint8_t s_err
Definition tlm_ble.c:37
static volatile uint8_t s_initReq
Definition tlm_ble.c:38
void tlm_ble_open_streams(void)
Definition tlm_ble.c:142
uint8_t tlm_ble_error(void)
Definition tlm_ble.c:239
static volatile uint8_t s_subReq
Definition tlm_ble.c:38
static uint32_t avail(int i, const uint32_t *t)
Definition tlm_ble.c:145
#define APP_BLE_STATE_DECIM_DEFAULT
Definition tlm_ble.c:11
static uint8_t s_planValid
Definition tlm_ble.c:51
static volatile uint8_t s_open
Definition tlm_ble.c:38
int tlm_ble_take_init_request(void)
1 once after the legacy [0x01] command: send INIT now (TelemetryTask)
Definition tlm_ble.c:128
static volatile uint16_t s_mtu
Definition tlm_ble.c:36
BLE telemetry, transport-independent part (phase 2 + protocol v2).
#define TLM_BLE_CMD_STATE_DECIM
[0x02, N] STATE every N acc updates
Definition tlm_ble.h:53
tlm_ble_state_t
Definition tlm_ble.h:44
@ TLM_BLE_STREAMING
Definition tlm_ble.h:48
@ TLM_BLE_OFF
BLE not compiled in or stack not started
Definition tlm_ble.h:45
@ TLM_BLE_CONNECTED
central connected, notifications not enabled
Definition tlm_ble.h:47
#define TLM_BLE_MTU_DEFAULT
ATT_MTU before any exchange
Definition tlm_ble.h:43
#define TLM_BLE_RING_SIZE
per queue, power of 2
Definition tlm_ble.h:42
#define TLM_BLE_CMD_SEND_INIT
[0x01] resend INIT now
Definition tlm_ble.h:52
static USBD_StatusTypeDef st(HAL_StatusTypeDef h)
Definition usbd_conf.c:86