ACwing FC firmware
STM32WB55: attitude IEKF, altitude Kalman filter, flight core, protocol v2
Loading...
Searching...
No Matches
usb_link.c
Go to the documentation of this file.
1
5#include "usb_link.h"
6#include "proto_v2.h"
7#include "telemetry.h"
8#include "spsc.h"
9#include <string.h>
10
11static uint8_t s_rx[USBL_RX_SIZE];
12static volatile uint32_t s_rx_h, s_rx_t;
13
14typedef struct {
15 uint8_t b[USBL_TX_SIZE];
16 volatile uint32_t h, t;
17 uint32_t dropped;
18} ring_t;
20
21/* consumer: ring being drained and the bytes left of the snapshot taken when it
22 * was chosen (whole frames only: producers publish whole frames) */
23static uint8_t s_cur;
24static uint32_t s_cur_left;
25
26/* host state */
27static volatile uint8_t s_cfgd, s_dtr, s_ever;
28static volatile uint32_t s_cmd_ms;
29
30/* parser */
31static uint8_t s_acc[4 + 255 + 2];
32static uint32_t s_na;
33static uint32_t s_err;
34
35void usbl_reset(void)
36{
37 s_rx_h = s_rx_t = 0;
38 memset(s_tx, 0, sizeof s_tx);
39 s_cur = 0; s_cur_left = 0;
40 s_na = 0; s_err = 0;
41 s_cfgd = s_dtr = s_ever = 0; s_cmd_ms = 0;
42}
43
44/* ------------------------------------------------------------------ host state */
45void usbl_set_configured(uint8_t on) { s_cfgd = on ? 1u : 0u; if (!on) s_dtr = 0u; }
46void usbl_set_dtr(uint8_t on) { s_dtr = on ? 1u : 0u; }
47uint8_t usbl_host(void) { return s_cfgd; }
48
49uint8_t usbl_open(uint32_t now)
50{
51 if (!s_cfgd) return 0u;
52 if (s_dtr) return 1u;
53 return (uint8_t)(s_ever && (now - s_cmd_ms) < USBL_OPEN_MS);
54}
55
56/* ------------------------------------------------------------------ RX */
57void usbl_rx_isr(const uint8_t *p, uint32_t n)
58{
59 uint32_t h = s_rx_h;
60 const uint32_t t = s_rx_t;
61 for (uint32_t k = 0; k < n; ++k) {
62 if (h - t >= USBL_RX_SIZE) break;
63 s_rx[h % USBL_RX_SIZE] = p[k];
64 h++;
65 }
67 s_rx_h = h;
68}
69
70static int rx_byte(uint8_t *b)
71{
72 const uint32_t t = s_rx_t;
73 if (t == s_rx_h) return 0;
75 *b = s_rx[t % USBL_RX_SIZE];
76 s_rx_t = t + 1u;
77 return 1;
78}
79
80uint32_t usbl_rx_errors(void) { return s_err; }
81
82/* drops the first byte of s_acc and moves to the next possible "A5 5A" */
83static void resync(void)
84{
85 uint32_t j = 1;
86 while (j < s_na) {
87 if (s_acc[j] == 0xA5u && (j + 1u >= s_na || s_acc[j + 1u] == 0x5Au)) break;
88 j++;
89 }
90 memmove(s_acc, &s_acc[j], s_na - j);
91 s_na -= j;
92}
93
94/* a complete frame at the start of s_acc: 1 valid, 0 need more bytes, -1 bad (resynced) */
95static int frame_ready(void)
96{
97 if (s_na < 4u) return 0;
98 const uint32_t len = s_acc[3];
99 if (s_na < len + 6u) return 0;
100 const uint16_t crc = tlm_crc16(&s_acc[2], len + 2u);
101 if ((uint16_t)(s_acc[4u + len] | (s_acc[5u + len] << 8)) != crc) { s_err++; resync(); return -1; }
102 return 1;
103}
104
105uint32_t usbl_poll(uint8_t *cmd, uint32_t cap, uint32_t now)
106{
107 for (;;) {
108 /* bytes left over after a resync may already hold the next frame */
109 int r;
110 while ((r = frame_ready()) == -1) {}
111 if (r == 1) {
112 const uint32_t len = s_acc[3];
113 const uint8_t type = s_acc[2];
114 uint32_t n = 0;
115 if (type == PV2_FT_CMD && len >= 2u) { /* only commands come this way */
116 n = len > cap ? cap : len;
117 memcpy(cmd, &s_acc[4], n);
118 }
119 memmove(s_acc, &s_acc[len + 6u], s_na - (len + 6u));
120 s_na -= len + 6u;
121 if (n) { s_cmd_ms = now; s_ever = 1u; return n; }
122 continue;
123 }
124 uint8_t b;
125 if (!rx_byte(&b)) return 0;
126 /* resynchronise on A5 5A */
127 if (s_na == 0u && b != 0xA5u) continue;
128 if (s_na == 1u && b != 0x5Au) { s_na = (b == 0xA5u) ? 1u : 0u; continue; }
129 s_acc[s_na++] = b;
130 }
131}
132
133/* ------------------------------------------------------------------ TX producers */
134uint32_t usbl_tx_free_src(uint8_t src)
135{
136 if (src >= USBL_SRC_COUNT) return 0u;
137 return USBL_TX_SIZE - (s_tx[src].h - s_tx[src].t);
138}
139
140uint32_t usbl_tx_dropped(uint8_t src) { return src < USBL_SRC_COUNT ? s_tx[src].dropped : 0u; }
141
142int usbl_put_frame(uint8_t src, const uint8_t *f, uint32_t n)
143{
144 if (src >= USBL_SRC_COUNT || !n) return -1;
145 ring_t *r = &s_tx[src];
146 if (usbl_tx_free_src(src) < n) { r->dropped++; return -1; }
147 const uint32_t h = r->h;
148 for (uint32_t k = 0; k < n; ++k) r->b[(h + k) % USBL_TX_SIZE] = f[k];
149 SPSC_BARRIER();
150 r->h = h + n; /* published whole */
151 return 0;
152}
153
154int usbl_send_src(uint8_t src, uint8_t type, const void *payload, uint8_t len)
155{
156 uint8_t f[4 + 255 + 2];
157 const size_t n = pv2_frame(type, payload, len, f, sizeof f);
158 if (!n) return -1;
159 return usbl_put_frame(src, f, (uint32_t)n);
160}
161
162/* ------------------------------------------------------------------ TX consumer */
163/* picks the next ring with data when the current snapshot is used up */
164static void choose(void)
165{
166 if (s_cur_left) return;
167 for (uint8_t k = 1; k <= USBL_SRC_COUNT; ++k) {
168 const uint8_t c = (uint8_t)((s_cur + k) % USBL_SRC_COUNT);
169 const uint32_t n = s_tx[c].h - s_tx[c].t;
170 if (n) { SPSC_BARRIER(); s_cur = c; s_cur_left = n; return; }
171 }
172}
173
174uint32_t usbl_tx_peek(uint8_t *buf, uint32_t cap)
175{
176 choose();
177 if (!s_cur_left) return 0u;
178 const ring_t *r = &s_tx[s_cur];
179 uint32_t n = s_cur_left;
180 if (n > cap) n = cap;
181 for (uint32_t k = 0; k < n; ++k) buf[k] = r->b[(r->t + k) % USBL_TX_SIZE];
182 return n;
183}
184
185void usbl_tx_consume(uint32_t n)
186{
187 if (n > s_cur_left) n = s_cur_left;
188 s_tx[s_cur].t += n;
189 s_cur_left -= n;
190}
191
193{
194 for (uint8_t c = 0; c < USBL_SRC_COUNT; ++c) s_tx[c].t = s_tx[c].h;
195 s_cur_left = 0u;
196}
double b[6]
Definition calib_mgr.c:53
uint32_t n
Definition calib_mgr.c:35
float cap[6][3]
Definition calib_mgr.c:36
static void cmd(uint8_t port, const uint8_t *c, uint32_t n, uint8_t armed, uint32_t now)
Definition log_task.c:222
uint8_t on
Definition log_task.c:48
size_t pv2_frame(uint8_t type, const void *payload, uint8_t len, uint8_t *out, size_t cap)
Definition proto_v2.c:9
ACwing Pilot app protocol v2: identifiers and frame layouts.
#define PV2_FT_CMD
PC -> drone: payload = op, seq, args (as a BLE CMD write)
Definition proto_v2.h:44
Lock-free single-producer single-consumer queue of fixed-size items.
#define SPSC_BARRIER()
Definition spsc.h:18
uint32_t dropped
Definition usb_link.c:17
volatile uint32_t t
Definition usb_link.c:16
volatile uint32_t h
Definition usb_link.c:16
uint8_t b[USBL_TX_SIZE]
Definition usb_link.c:15
uint16_t tlm_crc16(const uint8_t *data, size_t len)
Definition telemetry.c:7
Telemetry packet format (shared with 02 - Tools/00 - Matlab/Telemetry/parseTelemetry....