ConfigRecords.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef CONFIG_RECORDS_H | ||
| 2 | #define CONFIG_RECORDS_H | ||
| 3 | #include <Arduino.h> | ||
| 4 | #include "ConfigHeader.h" | ||
| 5 | #include "ShadeTypes.h" | ||
| 6 | #include "SomfyFrame.h" | ||
| 7 | |||
| 8 | // The records of shades.cfg and of a backup, and how they are written and | ||
| 9 | // read. The file is text: each value is padded to a fixed width and followed | ||
| 10 | // by a comma, strings that vary in length are quoted, and each record ends | ||
| 11 | // with a newline. Older versions of the file lack the values added since, | ||
| 12 | // and read as their defaults. Kept free of the file system and the shade | ||
| 13 | // model so every version can be unit tested on the PC (pio test -e native). | ||
| 14 | |||
| 15 | #define CFG_VALUE_SEP ',' | ||
| 16 | #define CFG_REC_END '\n' | ||
| 17 | #define CFG_TOK_NONE 0x00 | ||
| 18 | #define CFG_TOK_QUOTE '"' | ||
| 19 | |||
| 20 | #define SHADE_HDR_VER 24 | ||
| 21 | #define SHADE_HDR_SIZE 76 | ||
| 22 | #define SHADE_REC_SIZE 276 | ||
| 23 | #define GROUP_REC_SIZE 200 | ||
| 24 | #define ROOM_REC_SIZE 29 | ||
| 25 | #define REPEATER_REC_SIZE 77 | ||
| 26 | // Files written before 4.0 declare the transceiver record 74 bytes: it was | ||
| 27 | // left there when noiseDetection was added. | ||
| 28 | #define TRANS_REC_SIZE 80 | ||
| 29 | |||
| 30 | // The sizes of the strings, which are those of the fields they are read into. | ||
| 31 | #define CFG_NAME_LEN 21 | ||
| 32 | #define CFG_VERSION_LEN 24 | ||
| 33 | #define CFG_HOSTNAME_LEN 32 | ||
| 34 | #define CFG_NTP_SERVER_LEN 65 | ||
| 35 | #define CFG_POSIX_ZONE_LEN 64 | ||
| 36 | #define CFG_IP_LEN 24 | ||
| 37 | #define CFG_MQTT_PROTOCOL_LEN 10 | ||
| 38 | #define CFG_MQTT_HOSTNAME_LEN 65 | ||
| 39 | #define CFG_MQTT_TOPIC_LEN 65 | ||
| 40 | |||
| 41 | // Reads the values of a file. A record's values past its end read as their | ||
| 42 | // defaults, so a record shorter than expected never reads into the next one. | ||
| 43 | class ConfigReader { | ||
| 44 | private: | ||
| 45 | uint8_t _last = 0; | ||
| 46 | bool next(uint8_t &val); | ||
| 47 | public: | ||
| 48 | 31 | virtual ~ConfigReader() {} | |
| 49 | // The next byte of the file; false at its end. | ||
| 50 | virtual bool readByte(uint8_t &val) = 0; | ||
| 51 | virtual uint32_t position() = 0; | ||
| 52 | 39 | void beginRecord() { _last = 0; } | |
| 53 | // Moves past the rest of the record: the values a newer version added. | ||
| 54 | void endRecord(); | ||
| 55 | 653 | bool atRecordEnd() const { return _last == CFG_REC_END; } | |
| 56 | bool seekChar(const char val); | ||
| 57 | // A value up to the next separator, cut to fit buff. | ||
| 58 | bool readString(char *buff, size_t len); | ||
| 59 | // A value padded to len - 1 bytes, read whole so it may hold commas: a | ||
| 60 | // name. | ||
| 61 | bool readFixedString(char *buff, size_t len); | ||
| 62 | // A quoted value of any length, cut to fit buff. | ||
| 63 | bool readVarString(char *buff, size_t len); | ||
| 64 | int8_t readInt8(const int8_t defVal = 0); | ||
| 65 | uint8_t readUInt8(const uint8_t defVal = 0); | ||
| 66 | uint16_t readUInt16(const uint16_t defVal = 0); | ||
| 67 | uint32_t readUInt32(const uint32_t defVal = 0); | ||
| 68 | bool readBool(const bool defVal = false); | ||
| 69 | float readFloat(const float defVal = 0.00); | ||
| 70 | }; | ||
| 71 | class ConfigWriter { | ||
| 72 | public: | ||
| 73 | 30 | virtual ~ConfigWriter() {} | |
| 74 | virtual bool writeBytes(const uint8_t *buf, size_t len) = 0; | ||
| 75 | bool writeChar(const char val); | ||
| 76 | bool writeString(const char *val, size_t len, const char tok = CFG_VALUE_SEP); | ||
| 77 | bool writeVarString(const char *val, const char tok = CFG_VALUE_SEP); | ||
| 78 | bool writeInt8(const int8_t val, const char tok = CFG_VALUE_SEP); | ||
| 79 | bool writeUInt8(const uint8_t val, const char tok = CFG_VALUE_SEP); | ||
| 80 | bool writeUInt16(const uint16_t val, const char tok = CFG_VALUE_SEP); | ||
| 81 | bool writeUInt32(const uint32_t val, const char tok = CFG_VALUE_SEP); | ||
| 82 | bool writeBool(const bool val, const char tok = CFG_VALUE_SEP); | ||
| 83 | bool writeFloat(const float val, const uint8_t prec, const char tok = CFG_VALUE_SEP); | ||
| 84 | }; | ||
| 85 | // Counts what would be written: the size of a record that varies in length. | ||
| 86 | class ConfigCounter : public ConfigWriter { | ||
| 87 | public: | ||
| 88 | uint32_t bytes = 0; | ||
| 89 | 47 | bool writeBytes(const uint8_t *buf, size_t len) override { (void)buf; bytes += len; return true; } | |
| 90 | }; | ||
| 91 | |||
| 92 | struct room_record_t { | ||
| 93 | uint8_t roomId = 0; | ||
| 94 | char name[CFG_NAME_LEN] = ""; | ||
| 95 | int8_t sortOrder = 0; | ||
| 96 | }; | ||
| 97 | struct shade_record_t { | ||
| 98 | uint8_t shadeId = 255; | ||
| 99 | bool paired = false; | ||
| 100 | shade_types shadeType = shade_types::roller; | ||
| 101 | uint32_t remoteAddress = 0; | ||
| 102 | char name[CFG_NAME_LEN] = ""; | ||
| 103 | tilt_types tiltType = tilt_types::none; | ||
| 104 | radio_proto proto = radio_proto::RTS; | ||
| 105 | uint8_t bitLength = 56; | ||
| 106 | uint32_t upTime = 10000; | ||
| 107 | uint32_t downTime = 10000; | ||
| 108 | uint32_t tiltTime = 7000; | ||
| 109 | uint16_t stepSize = 100; | ||
| 110 | uint32_t linkedRemotes[SOMFY_MAX_LINKED_REMOTES] = {}; | ||
| 111 | uint16_t lastRollingCode = 0; | ||
| 112 | uint8_t flags = 0; | ||
| 113 | float myPos = -1; | ||
| 114 | float myTiltPos = -1; | ||
| 115 | float currentPos = 0; | ||
| 116 | float currentTiltPos = 0; | ||
| 117 | bool flipCommands = false; | ||
| 118 | bool flipPosition = false; | ||
| 119 | uint8_t repeats = 1; | ||
| 120 | int8_t sortOrder = 0; | ||
| 121 | uint8_t gpioUp = 0; | ||
| 122 | uint8_t gpioDown = 0; | ||
| 123 | uint8_t gpioMy = 0; | ||
| 124 | uint8_t gpioFlags = 0; | ||
| 125 | uint8_t roomId = 0; | ||
| 126 | }; | ||
| 127 | struct group_record_t { | ||
| 128 | uint8_t groupId = 255; | ||
| 129 | group_types groupType = group_types::channel; | ||
| 130 | uint32_t remoteAddress = 0; | ||
| 131 | char name[CFG_NAME_LEN] = ""; | ||
| 132 | radio_proto proto = radio_proto::RTS; | ||
| 133 | uint8_t bitLength = 56; | ||
| 134 | // Read without the gaps the file may have. | ||
| 135 | uint8_t linkedShades[SOMFY_MAX_GROUPED_SHADES] = {}; | ||
| 136 | uint8_t repeats = 1; | ||
| 137 | int8_t sortOrder = 0; | ||
| 138 | bool flipCommands = false; | ||
| 139 | uint8_t roomId = 0; | ||
| 140 | uint16_t lastRollingCode = 0; | ||
| 141 | // Versions before 23 have none. | ||
| 142 | bool hasRollingCode = false; | ||
| 143 | }; | ||
| 144 | struct settings_record_t { | ||
| 145 | // The firmware that wrote the backup. Not restored. | ||
| 146 | char fwVersion[CFG_VERSION_LEN] = ""; | ||
| 147 | char hostname[CFG_HOSTNAME_LEN] = ""; | ||
| 148 | char ntpServer[CFG_NTP_SERVER_LEN] = ""; | ||
| 149 | char posixZone[CFG_POSIX_ZONE_LEN] = ""; | ||
| 150 | bool ssdpBroadcast = false; | ||
| 151 | bool checkForUpdate = true; | ||
| 152 | }; | ||
| 153 | struct net_record_t { | ||
| 154 | uint8_t connType = 0; | ||
| 155 | bool dhcp = true; | ||
| 156 | char ip[CFG_IP_LEN] = ""; | ||
| 157 | char gateway[CFG_IP_LEN] = ""; | ||
| 158 | char subnet[CFG_IP_LEN] = ""; | ||
| 159 | char dns1[CFG_IP_LEN] = ""; | ||
| 160 | char dns2[CFG_IP_LEN] = ""; | ||
| 161 | char mqttProtocol[CFG_MQTT_PROTOCOL_LEN] = ""; | ||
| 162 | char mqttHostname[CFG_MQTT_HOSTNAME_LEN] = ""; | ||
| 163 | uint16_t mqttPort = 1883; | ||
| 164 | bool mqttPubDisco = false; | ||
| 165 | char mqttRootTopic[CFG_MQTT_TOPIC_LEN] = ""; | ||
| 166 | char mqttDiscoTopic[CFG_MQTT_TOPIC_LEN] = ""; | ||
| 167 | // Only boards with Ethernet write these, and only the board that wrote | ||
| 168 | // them reads them back. | ||
| 169 | uint8_t ethBoardType = 1; | ||
| 170 | uint8_t ethPhyType = 0; | ||
| 171 | uint8_t ethClkMode = 0; | ||
| 172 | int8_t ethPhyAddress = 1; | ||
| 173 | int8_t ethPWRPin = 1; | ||
| 174 | int8_t ethMDCPin = 16; | ||
| 175 | int8_t ethMDIOPin = 23; | ||
| 176 | }; | ||
| 177 | struct trans_record_t { | ||
| 178 | bool enabled = false; | ||
| 179 | radio_proto proto = radio_proto::RTS; | ||
| 180 | uint8_t type = 56; | ||
| 181 | uint8_t SCKPin = 18; | ||
| 182 | uint8_t CSNPin = 5; | ||
| 183 | uint8_t MOSIPin = 23; | ||
| 184 | uint8_t MISOPin = 19; | ||
| 185 | uint8_t TXPin = 13; | ||
| 186 | uint8_t RXPin = 35; | ||
| 187 | float frequency = 433.42; | ||
| 188 | float rxBandwidth = 99.97; | ||
| 189 | float deviation = 47.60; | ||
| 190 | int8_t txPower = 10; | ||
| 191 | bool noiseDetection = false; | ||
| 192 | }; | ||
| 193 | |||
| 194 | // The readers leave alone what the record's version lacks, so a record that | ||
| 195 | // starts as the shade, group or settings it is read into keeps their values. | ||
| 196 | bool writeConfigHeader(ConfigWriter &w, const config_header_t &header); | ||
| 197 | bool readConfigHeader(ConfigReader &r, config_header_t &header); | ||
| 198 | bool writeRoomRecord(ConfigWriter &w, const room_record_t &rec); | ||
| 199 | bool readRoomRecord(ConfigReader &r, room_record_t &rec); | ||
| 200 | bool writeShadeRecord(ConfigWriter &w, const shade_record_t &rec); | ||
| 201 | bool readShadeRecord(ConfigReader &r, const config_header_t &header, shade_record_t &rec); | ||
| 202 | bool writeGroupRecord(ConfigWriter &w, const group_record_t &rec); | ||
| 203 | bool readGroupRecord(ConfigReader &r, const config_header_t &header, group_record_t &rec); | ||
| 204 | bool writeRepeaterRecord(ConfigWriter &w, const uint32_t (&repeaters)[SOMFY_MAX_REPEATERS]); | ||
| 205 | bool readRepeaterRecord(ConfigReader &r, uint32_t (&repeaters)[SOMFY_MAX_REPEATERS]); | ||
| 206 | bool writeSettingsRecord(ConfigWriter &w, const settings_record_t &rec); | ||
| 207 | bool readSettingsRecord(ConfigReader &r, const config_header_t &header, settings_record_t &rec); | ||
| 208 | // withEthernet: the Ethernet settings, which a board without Ethernet leaves out. | ||
| 209 | bool writeNetRecord(ConfigWriter &w, const net_record_t &rec, bool withEthernet); | ||
| 210 | bool readNetRecord(ConfigReader &r, const config_header_t &header, net_record_t &rec, bool withEthernet); | ||
| 211 | bool writeTransRecord(ConfigWriter &w, const trans_record_t &rec); | ||
| 212 | bool readTransRecord(ConfigReader &r, trans_record_t &rec); | ||
| 213 | // Moves past count records without reading them. | ||
| 214 | bool skipRecords(ConfigReader &r, uint32_t count); | ||
| 215 | |||
| 216 | #endif | ||
| 217 |