Fix formatting and comments in bwm_forward.c

Signed-off-by: Niel Nielsen <nieldk@gmail.com>
This commit is contained in:
Niel Nielsen
2026-08-27 20:03:15 +02:00
committed by Philippe Teuwen
parent 426c9f11fd
commit 5fa3ac2446
+48 -13
View File
@@ -14,13 +14,15 @@
#include "bwm_forward.h"
#include "bwm_uart_at32.h"
#include "pm3_cmd.h"
#include "pm3_cmd.h" // PM3_CMD_DATA_SIZE, PM3_* return codes
#include "string.h"
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
// CRC-16/CCITT-FALSE, byte-identical to the BWM firmware's crc16_ccitt()
// (poly 0x1021, init 0xFFFF, MSB-first, no reflection, no xorout).
static uint16_t bwm_crc16(const uint8_t *data, size_t len, uint16_t crc) {
for (size_t i = 0; i < len; i++) {
crc ^= (uint16_t)data[i] << 8;
@@ -35,28 +37,43 @@ static uint16_t bwm_crc16(const uint8_t *data, size_t len, uint16_t crc) {
return crc;
}
// ---------------------------------------------------------------------------
// TX: wrap one reply frame into a SEND_FORWARD_DATA app_com frame.
// A full NG/OLD frame is <= PM3_CMD_DATA_SIZE + a small header/postamble, well
// under the BWM 4096-byte payload cap, so a single frame always suffices.
// ---------------------------------------------------------------------------
#define BWM_TX_OVERHEAD (2 + 2 + 2 + 2) // hdr + cmd + len + crc
#define BWM_TX_MAX_PAYLOAD (PM3_CMD_DATA_SIZE + 64) // NG/OLD frame ceiling
#define BWM_TX_BUFSZ (BWM_TX_OVERHEAD + BWM_TX_MAX_PAYLOAD)
static void bwm_pump(void);
static void bwm_pump(void); // fwd decl: TX gate pumps RX to collect forward-frame acks
// --- Flow control (ack window) ---------------------------------------------
// s_fwd_inflight: forward frames sent but not yet acked by the ESP. Bumped on
// send, decremented when a SLAVE_RESP echoing cmd=SEND_FORWARD_DATA arrives.
// We may send while it is below BWM_FC_WINDOW; at the cap we wait for an ack.
static volatile int16_t s_fwd_inflight = 0;
int bwm_fwd_writebuffer_sync(const uint8_t *data, size_t len) {
static uint8_t frame[BWM_TX_BUFSZ];
static uint8_t frame[BWM_TX_BUFSZ]; // single-threaded bare-metal: static OK
if (len > BWM_TX_MAX_PAYLOAD) {
len = BWM_TX_MAX_PAYLOAD;
len = BWM_TX_MAX_PAYLOAD; // defensive; should never trigger
}
size_t idx = 0;
// Flow control: block while the in-flight window is full, waiting for the
// ESP to ack an earlier forward frame. bwm_pump() drains the IRQ-filled RX
// ring, so acks are collected even while we sit inside a tight download loop
// (the reply_old firehose). The spin cap is a safety valve so a dead or
// disconnected ESP can't hard-hang us. A window >= 1 means single command
// replies never block - only sustained bursts hit the cap.
{
uint32_t spins = 0;
while (s_fwd_inflight >= BWM_FC_WINDOW) {
bwm_pump();
if (++spins > BWM_FC_ACK_TIMEOUT_SPINS) {
s_fwd_inflight = 0;
s_fwd_inflight = 0; // best-effort: assume the pipe cleared
break;
}
}
@@ -77,10 +94,16 @@ int bwm_fwd_writebuffer_sync(const uint8_t *data, size_t len) {
frame[idx++] = (uint8_t)((crc >> 8) & 0xFF);
int wr = bwm_uart_write(frame, idx);
s_fwd_inflight++;
s_fwd_inflight++; // one more forward frame awaiting its ack
return wr;
}
// ---------------------------------------------------------------------------
// RX: persistent app_com de-framer. Feeds raw FPC bytes through a state machine
// and pushes the payloads of valid DATA_FORWARD (0xD2 0xD3 / cmd 8089) frames
// into a byte FIFO that bwm_read_ng() drains. Non-DATA_FORWARD frames (slave
// responses, forwarded logs, cmd-error reports) are validated and discarded.
// ---------------------------------------------------------------------------
#define BWM_DEFIFO_SZ 2048 // >= one full NG frame's payload
#define BWM_RXFRAME_MAX (PM3_CMD_DATA_SIZE + 64)
@@ -91,27 +114,28 @@ typedef enum {
typedef struct {
bwm_state_t state;
uint8_t hdr1;
bool is_bcast;
bool is_bcast; // header pair is 0xD2 0xD3
uint16_t cmd;
uint16_t len;
uint16_t got;
uint16_t crc_calc;
uint16_t got; // payload bytes received
uint16_t crc_calc; // running CRC over hdr..payload
uint16_t crc_recv;
uint8_t payload[BWM_RXFRAME_MAX];
} bwm_parser_t;
static bwm_parser_t s_p = { .state = S_IDLE };
// De-framed payload ring
static uint8_t s_fifo[BWM_DEFIFO_SZ];
static volatile uint16_t s_fifo_head = 0;
static volatile uint16_t s_fifo_tail = 0;
static volatile uint16_t s_fifo_head = 0; // write
static volatile uint16_t s_fifo_tail = 0; // read
static uint16_t fifo_count(void) {
return (uint16_t)((s_fifo_head - s_fifo_tail) & (BWM_DEFIFO_SZ - 1));
}
static void fifo_push(uint8_t b) {
uint16_t next = (uint16_t)((s_fifo_head + 1) & (BWM_DEFIFO_SZ - 1));
if (next != s_fifo_tail) {
if (next != s_fifo_tail) { // drop on overflow rather than corrupt
s_fifo[s_fifo_head] = b;
s_fifo_head = next;
}
@@ -126,6 +150,8 @@ static void bwm_reset_frame(bwm_parser_t *p) {
p->state = S_IDLE;
}
// Update running CRC one byte at a time (mirrors the streaming update in the
// BWM firmware parser).
static void crc_step(bwm_parser_t *p, uint8_t byte) {
p->crc_calc = bwm_crc16(&byte, 1, p->crc_calc);
}
@@ -138,12 +164,14 @@ static void bwm_feed_byte(bwm_parser_t *p, uint8_t byte) {
} else if (byte == BWM_HDR_SLAVE_RESP_1) {
p->hdr1 = byte; p->is_bcast = false; p->state = S_HDR2;
}
// any other byte: stay idle (resync)
break;
case S_HDR2: {
bool ok = (p->is_bcast && byte == BWM_HDR_SLAVE_BCAST_2) ||
(!p->is_bcast && byte == BWM_HDR_SLAVE_RESP_2);
if (!ok) {
// header mismatch: reset and re-examine this byte as a potential SOF
p->state = S_IDLE;
bwm_feed_byte(p, byte);
return;
@@ -161,7 +189,7 @@ static void bwm_feed_byte(bwm_parser_t *p, uint8_t byte) {
p->len |= (uint16_t)byte << 8;
crc_step(p, byte);
p->got = 0;
if (p->len > BWM_RXFRAME_MAX) {
if (p->len > BWM_RXFRAME_MAX) { // oversized -> drop frame
bwm_reset_frame(p);
} else {
p->state = (p->len == 0) ? S_CRC_LO : S_PAYLOAD;
@@ -185,11 +213,13 @@ static void bwm_feed_byte(bwm_parser_t *p, uint8_t byte) {
fifo_push(p->payload[i]);
}
} else if ((p->is_bcast == false) && p->cmd == BWM_CMD_SEND_FORWARD_DATA) {
// SLAVE_RESP ack for a forward frame -> one slot freed
if (s_fwd_inflight > 0) {
s_fwd_inflight--;
}
}
}
// valid non-DATA_FORWARD frames and CRC failures alike: just resync
bwm_reset_frame(p);
break;
@@ -199,6 +229,7 @@ static void bwm_feed_byte(bwm_parser_t *p, uint8_t byte) {
}
}
// Pull whatever raw framed bytes are waiting and run them through the parser.
static void bwm_pump(void) {
uint8_t scratch[64];
uint16_t avail = bwm_uart_rx_available();
@@ -218,6 +249,8 @@ uint16_t bwm_fwd_rxdata_available(void) {
if (fifo_count() > 0) {
return fifo_count();
}
// No de-framed payload yet, but raw frame bytes may be waiting; pump once so
// receive_ng()'s gate reflects real forward data.
bwm_pump();
return fifo_count();
}
@@ -227,6 +260,8 @@ uint32_t bwm_read_ng(uint8_t *data, size_t len) {
return 0;
}
// Same bounded-retry budget shape as bwm_uart_read(); USART_SLOW_LINK (set
// for the BWM/BLE link) widens it so a slow round-trip doesn't time out.
uint32_t tryconstant = 0;
#ifdef USART_SLOW_LINK
tryconstant = 50000;