LoopQueue.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef LOOP_QUEUE_H | ||
| 2 | #define LOOP_QUEUE_H | ||
| 3 | #include <stdint.h> | ||
| 4 | #include "ShadeRequests.h" | ||
| 5 | #include "ProtoFrame.h" | ||
| 6 | |||
| 7 | // The one queue through which other tasks hand work to loop(), which alone | ||
| 8 | // changes the shade model (docs/adr/0002-loop-task-is-the-only-writer-of-the-shade-model.md). | ||
| 9 | // The items and the hold rule are kept free of FreeRTOS so they can be unit | ||
| 10 | // tested on the PC (pio test -e native). | ||
| 11 | |||
| 12 | // Big enough for Home Assistant firing a command at every shade at once. | ||
| 13 | #define LOOP_QUEUE_SIZE 32 | ||
| 14 | |||
| 15 | // What a restore_shades item restores, as bits of restoreParts. | ||
| 16 | #define RESTORE_SETTINGS 0x01 | ||
| 17 | #define RESTORE_SHADES 0x02 | ||
| 18 | #define RESTORE_NETWORK 0x04 | ||
| 19 | #define RESTORE_TRANSCEIVER 0x08 | ||
| 20 | #define RESTORE_REPEATERS 0x10 | ||
| 21 | #define RESTORE_MQTT 0x20 | ||
| 22 | |||
| 23 | enum class loop_item_type_t : uint8_t { | ||
| 24 | shade_request, // run by ShadeRequests | ||
| 25 | restore_shades, // restore from /shades.tmp, then reboot | ||
| 26 | model_edit, // apply an edit with ModelEditor | ||
| 27 | proto_read, // answer a protocol 2 read op from the shade model | ||
| 28 | proto_device // run a protocol 2 settings op or the WiFi scan (DeviceOps) | ||
| 29 | }; | ||
| 30 | struct model_edit_t; | ||
| 31 | struct settings_save_t; | ||
| 32 | struct loop_item_t { | ||
| 33 | loop_item_type_t type = loop_item_type_t::shade_request; | ||
| 34 | shade_request_t request; // shade_request | ||
| 35 | uint8_t restoreParts = 0; // restore_shades: RESTORE_* bits | ||
| 36 | model_edit_t *edit = nullptr; // model_edit: loop() runs and frees it | ||
| 37 | // shade_request, proto_read and proto_device from a protocol 2 client: | ||
| 38 | // loop() replies once it has run. | ||
| 39 | proto_reply_to_t replyTo; | ||
| 40 | uint8_t op = 0; // proto_read and proto_device: the op's type | ||
| 41 | uint8_t groupId = 0; // proto_read: groupOptions' group | ||
| 42 | uint8_t section = 0; // proto_device: getSettings' settings_section_t | ||
| 43 | settings_save_t *save = nullptr; // proto_device: saveSettings' save, which loop() frees | ||
| 44 | }; | ||
| 45 | |||
| 46 | // Whether the item sends anything on air. | ||
| 47 | 30 | inline bool loopItemUsesRadio(const loop_item_t &item) { | |
| 48 | 30 | return item.type == loop_item_type_t::shade_request && shadeRequestUsesRadio(item.request.type); | |
| 49 | } | ||
| 50 | // Whether the item at the head of the queue waits for the radio. An HTTP or | ||
| 51 | // MQTT client was already told it was accepted, so it stays queued until the | ||
| 52 | // radio has room rather than have the radio drop it; a protocol 2 client gets | ||
| 53 | // its reply once it has run. While TX is suspended nothing gets through | ||
| 54 | // anyway so nothing is held back then, except an unpair, which waits until TX | ||
| 55 | // resumes rather than leave the shade paired. Everything queued | ||
| 56 | // behind it waits too, protocol 2 replies included, so a frequency scan | ||
| 57 | // started after an unpair delays them until it ends. | ||
| 58 | 48 | inline bool holdLoopItem(const loop_item_t &item, bool txSuspended, bool txHasRoom) { | |
| 59 | 48 | if(txSuspended) return item.type == loop_item_type_t::shade_request && item.request.type == shade_request_type_t::unpair; | |
| 60 | 24 | return loopItemUsesRadio(item) && !txHasRoom; | |
| 61 | } | ||
| 62 | |||
| 63 | class LoopQueue { | ||
| 64 | public: | ||
| 65 | void begin(); | ||
| 66 | // Hands the item to loop() without waiting, so it is safe from any task, | ||
| 67 | // including async_tcp. False when the queue is full. first puts it | ||
| 68 | // ahead of everything waiting: an item that ends a frequency scan, which | ||
| 69 | // an unpair at the head waits for (holdLoopItem). | ||
| 70 | bool submit(const loop_item_t &item, bool first = false); | ||
| 71 | // Runs the waiting items in order. Only from loop(). | ||
| 72 | void drain(); | ||
| 73 | private: | ||
| 74 | void *queue = nullptr; | ||
| 75 | }; | ||
| 76 | #endif | ||
| 77 |