RadioScheduler.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef RADIO_SCHEDULER_H | ||
| 2 | #define RADIO_SCHEDULER_H | ||
| 3 | #include <stdint.h> | ||
| 4 | #include "TxBuffer.h" | ||
| 5 | |||
| 6 | // Reasons the radio must not transmit. TX resumes once every reason is cleared. | ||
| 7 | #define TX_SUSPEND_SCAN 0x01 | ||
| 8 | #define TX_SUSPEND_OTA 0x02 | ||
| 9 | // No job is waiting so the radio task sleeps until it is woken. | ||
| 10 | #define RADIO_WAIT_FOREVER 0xFFFFFFFFu | ||
| 11 | |||
| 12 | // The radio jobs waiting for, or on, the air (see GLOSSARY.md). It decides | ||
| 13 | // their order, when a delayed job is due, what a flush or suspend drops, and | ||
| 14 | // reports the outcome of every job. Kept free of FreeRTOS and the radio so it | ||
| 15 | // can be unit tested on the PC (pio test -e native). | ||
| 16 | // | ||
| 17 | // Not thread safe. The caller serializes every call and passes the time in. | ||
| 18 | class RadioScheduler { | ||
| 19 | public: | ||
| 20 | // Queues a job. Its ticket comes back and is also set in job.ticket, 0 when | ||
| 21 | // the queue is full or suspended, or when outcomes aren't collected with | ||
| 22 | // popEvent() fast enough to leave room for its own. A priority job (a stop) may use the | ||
| 23 | // reserved slots and goes ahead of every job queued at the back, unless a | ||
| 24 | // job of its remote is already waiting: overtaking that would put the | ||
| 25 | // rolling codes out of order. A delayed job doesn't go on air until | ||
| 26 | // delayMs after it was queued and after the job ahead of it ended, and holds | ||
| 27 | // up the jobs queued behind it. | ||
| 28 | uint32_t submit(somfy_tx_job_t &job, bool priority, uint16_t delayMs, uint32_t now); | ||
| 29 | // Whether a normal (not priority) job would be taken right now. | ||
| 30 | bool hasRoom() const; | ||
| 31 | // For the radio task: takes the job to send next. False when there is | ||
| 32 | // none due, waitMs then says how long until there is (RADIO_WAIT_FOREVER | ||
| 33 | // when nothing waits). A job taken goes on air through start() and | ||
| 34 | // ended(). | ||
| 35 | bool next(uint32_t now, somfy_tx_job_t &job, uint32_t &waitMs); | ||
| 36 | // The job taken is about to go on air. False when it was flushed since, | ||
| 37 | // it is then dropped and must not be sent. | ||
| 38 | bool start(uint32_t ticket, uint32_t now); | ||
| 39 | // Whether the job on air should send its next frame. A flush cuts it | ||
| 40 | // short. | ||
| 41 | bool keepSending(uint32_t ticket) const; | ||
| 42 | // The job on air stopped, after every frame when complete. | ||
| 43 | void ended(uint32_t ticket, bool complete, uint32_t now); | ||
| 44 | // Drops every waiting job and cuts short the one on air. | ||
| 45 | void flush(uint32_t now); | ||
| 46 | // Refuses new jobs until every reason (TX_SUSPEND_*) is resumed. Flushes. | ||
| 47 | void suspend(uint8_t reason, uint32_t now); | ||
| 48 | void resume(uint8_t reason); | ||
| 49 | 3 | bool suspended() const { return this->suspendMask != 0; } | |
| 50 | // Takes the oldest job outcome not yet handed out. Every job submitted | ||
| 51 | // that isn't a repeater frame is started and then finished or aborted, or | ||
| 52 | // dropped. | ||
| 53 | bool popEvent(somfy_tx_event_t &evt); | ||
| 54 | private: | ||
| 55 | somfy_tx_job_t jobs[TX_JOB_QUEUE_SIZE]; | ||
| 56 | uint8_t count = 0; | ||
| 57 | uint32_t lastTicket = 0; | ||
| 58 | uint8_t suspendMask = 0; | ||
| 59 | // The job taken by next() and not yet ended (0 for none), kept for its | ||
| 60 | // events. | ||
| 61 | uint32_t taken = 0; | ||
| 62 | somfy_tx_job_t takenJob; | ||
| 63 | bool takenFlushed = false; | ||
| 64 | // When a job last went off air, for the delay of the job after it. | ||
| 65 | uint32_t lastEnded = 0; | ||
| 66 | bool endedOnce = false; | ||
| 67 | somfy_tx_event_t events[TX_JOB_QUEUE_SIZE * 3]; | ||
| 68 | uint8_t eventHead = 0; | ||
| 69 | uint8_t eventCount = 0; | ||
| 70 | // Whether the outcomes of every job not yet ended, and of one more, still | ||
| 71 | // fit in events. A job is refused otherwise so no outcome is ever lost. | ||
| 72 | bool outcomesFit() const; | ||
| 73 | // Whether a job of the remote is still waiting. | ||
| 74 | bool waitingFor(uint32_t remoteAddress) const; | ||
| 75 | void remove(uint8_t i); | ||
| 76 | void post(tx_event_t type, const somfy_tx_job_t &job, uint32_t at); | ||
| 77 | }; | ||
| 78 | #endif | ||
| 79 |