refactor: let one RadioScheduler own the radio job queue

The order radio jobs go out in was spread across callers, file statics and
the radio task: each remote tracked its last back job so a stop could decide
whether it may jump the queue, and the task kept a separate count of the back
jobs it had taken.  RadioScheduler now owns the waiting jobs, their tickets,
the stop-goes-first rule, delayed jobs, flush and suspend, and the outcome of
every job.  It is plain C++, with the time passed in and the caller locking,
so all of it is covered by native tests.  Transceiver keeps the FreeRTOS task,
the locks and the CC1101.

sendCommandAfter returns the job's ticket instead of leaving it in lastTxSeq.

Two stops for the same remote now go out in the order they were sent; queued
to the front they used to come out reversed, putting the rolling codes out of
order.

Adds GLOSSARY.md for the radio terms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-12 20:36:32 +02:00
parent 1962778912
commit 4135f21ee7
11 changed files with 862 additions and 410 deletions

View file

@ -58,10 +58,10 @@ struct somfy_tx_job_t {
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; // Repeater frame. Waits for the receiver to be idle.
// Set by RadioScheduler::submit().
bool priority = false; // May use the reserved slots.
bool front = false; // Goes to the front of the queue. Only for priority jobs.
uint32_t gen = 0; // Flush generation when queued. Stale jobs are dropped.
uint32_t seq = 0; // Assigned when queued so the job's events can be matched up.
bool front = false; // Queued ahead of the back. Only for priority jobs.
uint32_t seq = 0; // Ticket the job's events are matched up by.
uint32_t notBefore = 0; // millis() before which the job must not go on air (0 = none).
};
enum class tx_event_t : uint8_t {