mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 22:02:17 +01:00
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:
parent
1962778912
commit
4135f21ee7
11 changed files with 862 additions and 410 deletions
28
src/Somfy.h
28
src/Somfy.h
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "SomfyFrame.h"
|
||||
#include "TxBuffer.h"
|
||||
#include "RadioScheduler.h"
|
||||
#include "ShadeMotion.h"
|
||||
enum class group_types : byte {
|
||||
channel = 0x00
|
||||
|
|
@ -115,9 +116,6 @@ struct somfy_relay_t {
|
|||
uint8_t sync = 0;
|
||||
byte frame[10] = {0};
|
||||
};
|
||||
// Reasons the radio must not transmit. TX resumes once every reason is cleared.
|
||||
#define TX_SUSPEND_SCAN 0x01
|
||||
#define TX_SUSPEND_OTA 0x02
|
||||
|
||||
class SomfyRoom {
|
||||
public:
|
||||
|
|
@ -133,6 +131,13 @@ class SomfyRoom {
|
|||
void unpublish();
|
||||
};
|
||||
|
||||
// What sending a command did. ticket is the radio job carrying it, 0 when the
|
||||
// command went out over GPIO instead.
|
||||
struct send_result_t {
|
||||
bool sent = false;
|
||||
uint32_t ticket = 0;
|
||||
explicit operator bool() const { return this->sent; }
|
||||
};
|
||||
class SomfyRemote {
|
||||
// These sizes for the data have been
|
||||
// confirmed. The address is actually 24bits
|
||||
|
|
@ -154,8 +159,6 @@ class SomfyRemote {
|
|||
somfy_frame_t lastFrame;
|
||||
bool flipCommands = false;
|
||||
uint16_t lastRollingCode = 0;
|
||||
uint32_t lastTxSeq = 0; // Radio job of the last command sent, 0 if it didn't use the radio.
|
||||
uint32_t lastBackTxSeq = 0; // Last radio job queued at the back of the queue.
|
||||
uint8_t flags = 0;
|
||||
uint8_t bitLength = 0;
|
||||
uint8_t repeats = 1;
|
||||
|
|
@ -176,7 +179,7 @@ class SomfyRemote {
|
|||
// command. Nothing about the remote or shade state has changed in that case.
|
||||
virtual bool sendCommand(somfy_commands cmd);
|
||||
virtual bool sendCommand(somfy_commands cmd, uint8_t repeat, uint8_t stepSize = 0);
|
||||
bool sendCommandAfter(somfy_commands cmd, uint8_t repeat, uint8_t stepSize, uint16_t delayMs, bool priority = false);
|
||||
send_result_t sendCommandAfter(somfy_commands cmd, uint8_t repeat, uint8_t stepSize, uint16_t delayMs, bool priority = false);
|
||||
bool sendSensorCommand(int8_t isWindy, int8_t isSunny, uint8_t repeat);
|
||||
bool repeatFrame(uint8_t repeat);
|
||||
virtual uint16_t p_lastRollingCode(uint16_t code);
|
||||
|
|
@ -426,13 +429,12 @@ class Transceiver {
|
|||
static void txTask(void *arg);
|
||||
bool _received = false;
|
||||
somfy_frame_t frame;
|
||||
// Only touched under the TX queue lock.
|
||||
RadioScheduler sched;
|
||||
void startTxTask();
|
||||
bool transmitJob(somfy_tx_job_t &job);
|
||||
// Sends a job taken off the queue and leaves a frame beat after it.
|
||||
void runJob(somfy_tx_job_t &job);
|
||||
// Holds a delayed job until it is due, sending stops queued at the front
|
||||
// in the meantime.
|
||||
void waitUntilDue(const somfy_tx_job_t &job);
|
||||
public:
|
||||
transceiver_config_t config;
|
||||
bool printBuffer = false;
|
||||
|
|
@ -449,11 +451,12 @@ class Transceiver {
|
|||
void disableReceive();
|
||||
somfy_frame_t& lastFrame();
|
||||
void sendFrame(byte *frame, uint8_t sync, uint8_t bitLength = 56);
|
||||
bool queueTx(somfy_tx_job_t &job);
|
||||
// Hands a job to the radio task, see RadioScheduler::submit(). Returns its
|
||||
// ticket, 0 when the radio can't take it. Safe from any task.
|
||||
uint32_t submitTx(somfy_tx_job_t &job, bool priority = false, uint16_t delayMs = 0);
|
||||
void flushTx();
|
||||
void suspendTx(uint8_t reason);
|
||||
void resumeTx(uint8_t reason);
|
||||
bool isQueued(uint32_t seq);
|
||||
bool txSuspended();
|
||||
bool txHasRoom();
|
||||
void beginTransmit();
|
||||
|
|
@ -511,7 +514,8 @@ class SomfyShadeController {
|
|||
SomfyGroup * getGroupById(uint8_t groupId);
|
||||
SomfyShade * findShadeByRemoteAddress(uint32_t address);
|
||||
SomfyGroup * findGroupByRemoteAddress(uint32_t address);
|
||||
bool sendFrame(somfy_frame_t &frame, uint8_t repeats = 0, uint16_t delayMs = 0, bool priority = false, bool front = false, uint32_t *seq = nullptr);
|
||||
// Returns the radio job's ticket, 0 when the radio can't take it.
|
||||
uint32_t sendFrame(somfy_frame_t &frame, uint8_t repeats = 0, uint16_t delayMs = 0, bool priority = false);
|
||||
void processFrame(somfy_frame_t &frame, bool internal = false);
|
||||
void markTxPending(uint32_t remoteAddress, uint32_t seq);
|
||||
void processTxEvent(const somfy_tx_event_t &evt);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue