fix: move radio TX to a dedicated task so HA WebSocket stays connected

Web command handlers ran on the async_tcp task and blocked up to 3s
waiting for loop() to bit-bang radio frames. async_tcp also services the
WebSocket on port 8080, so pongs stalled and Home Assistant
(ping_timeout=15) disconnected when several covers were commanded.

- Add a radio_tx FreeRTOS task with a job queue; sendFrame/repeatFrame
  and repeater frames enqueue instead of transmitting inline.
- Serialize CC1101 access with a recursive mutex (TX task, apply, end,
  frequency scan, RSSI read).
- Make Web::queueCommand fire-and-forget; drop the done semaphore.
- Route /setMyPosition and /unpairShade through the command queue.
- Clamp repeats to MAX_TX_REPEATS (40).
- Pin AsyncTCP to core 0 on dual-core targets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-10 20:13:31 +02:00
parent b117c34cb8
commit 9a9afa5e86
5 changed files with 202 additions and 81 deletions

View file

@ -201,6 +201,19 @@ struct somfy_frame_t {
bool isSynonym(somfy_frame_t &f);
void copy(somfy_frame_t &f);
};
// Upper bound on repeats for a single transmission. Each frame is ~140ms of
// radio time so this keeps a single job to roughly 6 seconds.
#define MAX_TX_REPEATS 40
#define TX_JOB_QUEUE_SIZE 32
// A transmission handed off to the radio task. The frame is a copy so the
// radio task never touches the remote's lastFrame.
struct somfy_tx_job_t {
somfy_frame_t frame;
uint8_t repeats = 0; // Number of repeat frames after the first frame.
uint8_t firstRepeat = 1; // 80-bit repeat counter used for the first repeat frame.
bool raw = false; // When true rawTx holds a pre-encoded frame (repeater).
somfy_tx_t rawTx;
};
class SomfyRoom {
public:
@ -488,8 +501,11 @@ struct transceiver_config_t {
class Transceiver {
private:
static void handleReceive();
static void txTask(void *arg);
bool _received = false;
somfy_frame_t frame;
void startTxTask();
void transmitJob(somfy_tx_job_t &job);
public:
transceiver_config_t config;
bool printBuffer = false;
@ -505,6 +521,8 @@ class Transceiver {
void disableReceive();
somfy_frame_t& lastFrame();
void sendFrame(byte *frame, uint8_t sync, uint8_t bitLength = 56);
bool queueTx(const somfy_tx_job_t &job);
void flushTx();
void beginTransmit();
void endTransmit();
void emitFrame(somfy_frame_t *frame, somfy_rx_t *rx = nullptr);