TxBuffer.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef TX_BUFFER_H | ||
| 2 | #define TX_BUFFER_H | ||
| 3 | #include <Arduino.h> | ||
| 4 | #include "SomfyFrame.h" | ||
| 5 | |||
| 6 | // Repeater frames waiting to be handed to the radio task, and the jobs and | ||
| 7 | // events passed to and from it. Kept free of the radio and timers so it can be | ||
| 8 | // unit tested on the PC (pio test -e native). | ||
| 9 | |||
| 10 | #define MAX_TX_BUFFER 5 | ||
| 11 | #define TX_JOB_QUEUE_SIZE 32 | ||
| 12 | // Slots only priority jobs (stops) may use so a stop always fits in the queue. | ||
| 13 | #define TX_RESERVED_SLOTS 4 | ||
| 14 | // The radio task bit-bangs a whole job on loop()'s core at a higher priority | ||
| 15 | // so loop() only runs between jobs. A frame takes about 140ms so this keeps a | ||
| 16 | // job around 7s, well inside the 15s task watchdog loop() is subscribed to. | ||
| 17 | #define TX_MAX_REPEATS 50 | ||
| 18 | |||
| 19 | struct somfy_tx_t { | ||
| 20 | 72 | void clear() { | |
| 21 | 72 | this->hwsync = 0; | |
| 22 | 72 | this->bit_length = 0; | |
| 23 | 72 | memset(this->payload, 0x00, sizeof(this->payload)); | |
| 24 | 72 | } | |
| 25 | uint8_t hwsync = 0; | ||
| 26 | uint8_t bit_length = 0; | ||
| 27 | uint8_t payload[10] = {}; | ||
| 28 | }; | ||
| 29 | struct somfy_tx_queue_t { | ||
| 30 | 7 | somfy_tx_queue_t() { this->clear(); } | |
| 31 | 8 | void clear() { | |
| 32 | 48 | for (uint8_t i = 0; i < MAX_TX_BUFFER; i++) { | |
| 33 | 40 | this->index[i] = 255; | |
| 34 | 40 | this->items[i].clear(); | |
| 35 | } | ||
| 36 | 8 | this->length = 0; | |
| 37 | 8 | } | |
| 38 | unsigned long delay_time = 0; // Set by the caller, not before this millis(). | ||
| 39 | uint8_t length = 0; | ||
| 40 | uint8_t index[MAX_TX_BUFFER] = {255}; | ||
| 41 | somfy_tx_t items[MAX_TX_BUFFER]; | ||
| 42 | // The oldest frame without removing it, so it can stay queued until the radio | ||
| 43 | // takes it. | ||
| 44 | bool peek(somfy_tx_t *tx) const; | ||
| 45 | bool pop(somfy_tx_t *tx); | ||
| 46 | // When full the oldest frame is thrown away. | ||
| 47 | void push(uint8_t hwsync, byte *payload, uint8_t bit_length); | ||
| 48 | private: | ||
| 49 | // Position in index of the oldest frame, -1 when empty. | ||
| 50 | int8_t oldest() const; | ||
| 51 | }; | ||
| 52 | // A transmission handed off to the radio task. The first frame is encoded by | ||
| 53 | // the producer into tx. The frame is a copy so the radio task never touches the | ||
| 54 | // remote's lastFrame and is only used to re-encode 80-bit repeat frames. | ||
| 55 | struct somfy_tx_job_t { | ||
| 56 | somfy_tx_t tx; // Encoded first frame with its hw sync count and bit length. | ||
| 57 | somfy_frame_t frame; | ||
| 58 | uint8_t repeats = 0; // Number of repeat frames after the first frame. | ||
| 59 | uint8_t firstRepeat = 1; // 80-bit repeat counter used for the first repeat frame. | ||
| 60 | bool repeater = false; // Repeater frame. Waits for the receiver to be idle. | ||
| 61 | // Set by RadioScheduler::submit(). | ||
| 62 | bool priority = false; // May use the reserved slots. | ||
| 63 | bool front = false; // Queued ahead of the back. Only for priority jobs. | ||
| 64 | uint32_t ticket = 0; // Matches the job's events up with it. | ||
| 65 | uint32_t queuedAt = 0; // millis() when it was submitted. | ||
| 66 | uint16_t delayMs = 0; // How long it waits after it was queued and after the job ahead of it ended. | ||
| 67 | }; | ||
| 68 | enum class tx_event_t : uint8_t { | ||
| 69 | started, // The job is going on air. | ||
| 70 | finished, // Every frame of the job went on air. | ||
| 71 | aborted, // The job was cut short by a flush or a radio reconfiguration. | ||
| 72 | dropped // The job was flushed and will never go on air. | ||
| 73 | }; | ||
| 74 | // Reported by the radio task for every queued non-repeater job. | ||
| 75 | struct somfy_tx_event_t { | ||
| 76 | tx_event_t type = tx_event_t::started; | ||
| 77 | somfy_commands cmd = somfy_commands::My; | ||
| 78 | uint32_t remoteAddress = 0; | ||
| 79 | uint32_t ticket = 0; | ||
| 80 | uint32_t at = 0; // millis() when the job started or was dropped. | ||
| 81 | }; | ||
| 82 | // Encodes the first frame of a transmission into the job. Encoding here keeps | ||
| 83 | // its side effects on the frame (valid flag, default step size) visible to the | ||
| 84 | // caller and the radio task only re-encodes the 80-bit repeat frames. More | ||
| 85 | // than TX_MAX_REPEATS repeats are cut down to it. | ||
| 86 | void encodeTxJob(somfy_tx_job_t &job, somfy_frame_t &frame, uint8_t repeat); | ||
| 87 | // Encodes a repeat of the frame last sent. The first frame carries the | ||
| 88 | // frame's current repeat counter and the radio task counts up from there. | ||
| 89 | void encodeRepeatJob(somfy_tx_job_t &job, somfy_frame_t &frame, uint8_t repeat); | ||
| 90 | // Advances the frame's repeat counter past a repeat job the radio took. | ||
| 91 | void noteRepeatQueued(somfy_frame_t &frame, const somfy_tx_job_t &job); | ||
| 92 | #endif | ||
| 93 |