src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
371 / 388
95.6%
Branches:
170 / 216
78.7%
Functions:
37 / 38
97.4%

ConfigRecords.cpp
Line Branch Exec Source
1 #include "ConfigRecords.h"
2 #include "Utils.h"
3
4 5013 bool ConfigReader::next(uint8_t &val) {
5
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 5012 times.
5013 if(!this->readByte(val)) return false;
6 5012 this->_last = val;
7 5012 return true;
8 }
9 31 void ConfigReader::endRecord() {
10
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 29 times.
31 if(!this->atRecordEnd()) this->seekChar(CFG_REC_END);
11 31 }
12 6 bool ConfigReader::seekChar(const char val) {
13 uint8_t ch;
14 do {
15
3/4
✓ Branch 1 taken 624 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 623 times.
624 if(!this->next(ch)) return false;
16
2/2
✓ Branch 0 taken 618 times.
✓ Branch 1 taken 5 times.
623 } while(ch != static_cast<uint8_t>(val));
17 5 return true;
18 }
19 556 bool ConfigReader::readString(char *buff, size_t len) {
20 556 memset(buff, 0x00, len);
21
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 549 times.
556 if(this->atRecordEnd()) return false;
22 549 size_t i = 0;
23 uint8_t val;
24
2/4
✓ Branch 1 taken 3192 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3192 times.
✗ Branch 4 not taken.
3741 while(this->next(val)) {
25
4/4
✓ Branch 0 taken 3161 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 518 times.
✓ Branch 3 taken 2643 times.
3192 if(val == CFG_REC_END || val == CFG_VALUE_SEP) {
26 549 _rtrim(buff);
27 549 return true;
28 }
29
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2643 times.
2643 if(i < len - 1) buff[i++] = val;
30 }
31 ✗ return false;
32 }
33 20 bool ConfigReader::readFixedString(char *buff, size_t len) {
34 20 memset(buff, 0x00, len);
35
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 if(this->atRecordEnd()) return false;
36 uint8_t val;
37
2/2
✓ Branch 0 taken 400 times.
✓ Branch 1 taken 20 times.
420 for(size_t i = 0; i < len - 1; i++) {
38
2/4
✓ Branch 1 taken 400 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 400 times.
400 if(!this->next(val)) return false;
39
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 400 times.
400 if(val == CFG_REC_END) {
40 ✗ _rtrim(buff);
41 ✗ return true;
42 }
43 400 buff[i] = val;
44 }
45 // The separator after the padding.
46
2/4
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 20 times.
20 if(!this->next(val)) return false;
47 20 _rtrim(buff);
48 20 return true;
49 }
50 46 bool ConfigReader::readVarString(char *buff, size_t len) {
51 46 memset(buff, 0x00, len);
52
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
46 if(this->atRecordEnd()) return false;
53 46 uint8_t quotes = 0;
54 46 size_t i = 0;
55 uint8_t val;
56
2/4
✓ Branch 1 taken 777 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 777 times.
✗ Branch 4 not taken.
777 while(this->next(val)) {
57
6/6
✓ Branch 0 taken 776 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 47 times.
✓ Branch 3 taken 729 times.
✓ Branch 4 taken 45 times.
✓ Branch 5 taken 2 times.
777 if(val == CFG_REC_END || (val == CFG_VALUE_SEP && quotes >= 2)) {
58 46 _rtrim(buff);
59 46 return true;
60 }
61
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 639 times.
731 if(val == CFG_TOK_QUOTE) {
62 92 quotes++;
63 92 continue;
64 }
65
2/2
✓ Branch 0 taken 622 times.
✓ Branch 1 taken 17 times.
639 if(i < len - 1) buff[i++] = val;
66 }
67 ✗ return false;
68 }
69 16 int8_t ConfigReader::readInt8(const int8_t defVal) {
70 char buff[5];
71
3/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 4 times.
16 if(this->readString(buff, sizeof(buff))) return static_cast<int8_t>(atoi(buff));
72 4 return defVal;
73 }
74 359 uint8_t ConfigReader::readUInt8(const uint8_t defVal) {
75 char buff[4];
76
3/4
✓ Branch 1 taken 359 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 356 times.
✓ Branch 4 taken 3 times.
359 if(this->readString(buff, sizeof(buff))) return static_cast<uint8_t>(atoi(buff));
77 3 return defVal;
78 }
79 25 uint16_t ConfigReader::readUInt16(const uint16_t defVal) {
80 char buff[6];
81
2/4
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
✗ Branch 4 not taken.
25 if(this->readString(buff, sizeof(buff))) return static_cast<uint16_t>(atoi(buff));
82 ✗ return defVal;
83 }
84 77 uint32_t ConfigReader::readUInt32(const uint32_t defVal) {
85 char buff[11];
86
2/4
✓ Branch 1 taken 77 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 77 times.
✗ Branch 4 not taken.
77 if(this->readString(buff, sizeof(buff))) return static_cast<uint32_t>(strtoul(buff, nullptr, 10));
87 ✗ return defVal;
88 }
89 38 float ConfigReader::readFloat(const float defVal) {
90 char buff[25];
91
2/4
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
✗ Branch 4 not taken.
38 if(this->readString(buff, sizeof(buff))) return atof(buff);
92 ✗ return defVal;
93 }
94 40 bool ConfigReader::readBool(const bool defVal) {
95 char buff[6];
96
2/4
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
✗ Branch 4 not taken.
40 if(this->readString(buff, sizeof(buff))) {
97
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 8 times.
40 switch(buff[0]) {
98 32 case 't':
99 case 'T':
100 case '1':
101 32 return true;
102 8 default:
103 8 return false;
104 }
105 }
106 ✗ return defVal;
107 }
108
109 1307 bool ConfigWriter::writeChar(const char val) {
110 1307 const uint8_t b = static_cast<uint8_t>(val);
111
1/2
✓ Branch 1 taken 1307 times.
✗ Branch 2 not taken.
2614 return this->writeBytes(&b, 1);
112 }
113 761 bool ConfigWriter::writeString(const char *val, size_t len, const char tok) {
114 761 size_t slen = strlen(val);
115
3/6
✓ Branch 0 taken 761 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 761 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 761 times.
761 if(slen > 0 && !this->writeBytes(reinterpret_cast<const uint8_t *>(val), slen)) return false;
116 // Pad the value to its fixed width.
117
2/2
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 761 times.
1121 while(slen + 1 < len) {
118
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 360 times.
360 if(!this->writeChar(' ')) return false;
119 360 slen++;
120 }
121
1/2
✓ Branch 0 taken 761 times.
✗ Branch 1 not taken.
761 if(tok != CFG_TOK_NONE) return this->writeChar(tok);
122 ✗ return true;
123 }
124 62 bool ConfigWriter::writeVarString(const char *val, const char tok) {
125 62 this->writeChar(CFG_TOK_QUOTE);
126 62 const size_t slen = strlen(val);
127
3/6
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 62 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 62 times.
62 if(slen > 0 && !this->writeBytes(reinterpret_cast<const uint8_t *>(val), slen)) return false;
128 62 this->writeChar(CFG_TOK_QUOTE);
129
1/2
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
62 if(tok != CFG_TOK_NONE) return this->writeChar(tok);
130 ✗ return true;
131 }
132 9 bool ConfigWriter::writeInt8(const int8_t val, const char tok) {
133 char buff[5];
134 9 snprintf(buff, sizeof(buff), "%4d", val);
135
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 return this->writeString(buff, sizeof(buff), tok);
136 }
137 473 bool ConfigWriter::writeUInt8(const uint8_t val, const char tok) {
138 char buff[4];
139 473 snprintf(buff, sizeof(buff), "%3u", val);
140
1/2
✓ Branch 1 taken 473 times.
✗ Branch 2 not taken.
946 return this->writeString(buff, sizeof(buff), tok);
141 }
142 41 bool ConfigWriter::writeUInt16(const uint16_t val, const char tok) {
143 char buff[6];
144 41 snprintf(buff, sizeof(buff), "%5u", val);
145
1/2
✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
82 return this->writeString(buff, sizeof(buff), tok);
146 }
147 108 bool ConfigWriter::writeUInt32(const uint32_t val, const char tok) {
148 char buff[11];
149 108 snprintf(buff, sizeof(buff), "%10u", static_cast<unsigned>(val));
150
1/2
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
216 return this->writeString(buff, sizeof(buff), tok);
151 }
152 49 bool ConfigWriter::writeFloat(const float val, const uint8_t prec, const char tok) {
153 char buff[20];
154 49 snprintf(buff, sizeof(buff), "%*.*f", 7 + prec, prec, val);
155
1/2
✓ Branch 1 taken 49 times.
✗ Branch 2 not taken.
98 return this->writeString(buff, 8 + prec, tok);
156 }
157 54 bool ConfigWriter::writeBool(const bool val, const char tok) {
158
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 11 times.
54 return this->writeString(val ? "true" : "false", 6, tok);
159 }
160
161 2 bool writeConfigHeader(ConfigWriter &w, const config_header_t &header) {
162 2 w.writeUInt8(header.version);
163 2 w.writeUInt8(header.length);
164 2 w.writeUInt16(header.roomRecordSize);
165 2 w.writeUInt8(header.roomRecords);
166 2 w.writeUInt16(header.shadeRecordSize);
167 2 w.writeUInt8(header.shadeRecords);
168 2 w.writeUInt16(header.groupRecordSize);
169 2 w.writeUInt8(header.groupRecords);
170 2 w.writeUInt16(header.repeaterRecordSize);
171 2 w.writeUInt8(header.repeaterRecords);
172 2 w.writeUInt16(header.settingsRecordSize);
173 2 w.writeUInt16(header.netRecordSize);
174 2 w.writeUInt16(header.transRecordSize);
175 2 return w.writeString(header.serverId, sizeof(header.serverId), CFG_REC_END);
176 }
177 2 bool readConfigHeader(ConfigReader &r, config_header_t &header) {
178 2 r.beginRecord();
179 2 header.version = r.readUInt8(header.version);
180 2 header.length = r.readUInt8(0);
181
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if(header.version >= 19) {
182 1 header.roomRecordSize = r.readUInt16(header.roomRecordSize);
183 1 header.roomRecords = r.readUInt8(header.roomRecords);
184 }
185
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if(header.version >= 13) header.shadeRecordSize = r.readUInt16(header.shadeRecordSize);
186 1 else header.shadeRecordSize = r.readUInt8(static_cast<uint8_t>(header.shadeRecordSize));
187 2 header.shadeRecords = r.readUInt8(header.shadeRecords);
188
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(header.version > 10) {
189
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if(header.version >= 13) header.groupRecordSize = r.readUInt16(header.groupRecordSize);
190 1 else header.groupRecordSize = r.readUInt8(header.groupRecordSize);
191 2 header.groupRecords = r.readUInt8(header.groupRecords);
192 }
193
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if(header.version >= 21) {
194 1 header.repeaterRecordSize = r.readUInt16(header.repeaterRecordSize);
195 1 header.repeaterRecords = r.readUInt8(header.repeaterRecords);
196 }
197
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if(header.version > 13) {
198 1 header.settingsRecordSize = r.readUInt16(header.settingsRecordSize);
199 1 header.netRecordSize = r.readUInt16(header.netRecordSize);
200 1 header.transRecordSize = r.readUInt16(header.transRecordSize);
201 1 r.readString(header.serverId, sizeof(header.serverId));
202 }
203 2 return true;
204 }
205
206 8 bool writeRoomRecord(ConfigWriter &w, const room_record_t &rec) {
207 8 w.writeUInt8(rec.roomId);
208 8 w.writeString(rec.name, sizeof(rec.name));
209 8 return w.writeUInt8(static_cast<uint8_t>(rec.sortOrder), CFG_REC_END);
210 }
211 7 bool readRoomRecord(ConfigReader &r, room_record_t &rec) {
212 7 r.beginRecord();
213 7 rec.roomId = r.readUInt8(0);
214 7 r.readFixedString(rec.name, sizeof(rec.name));
215 7 rec.sortOrder = static_cast<int8_t>(r.readUInt8(rec.roomId - 1));
216 7 r.endRecord();
217 7 return true;
218 }
219
220 5 bool writeShadeRecord(ConfigWriter &w, const shade_record_t &rec) {
221 5 w.writeUInt8(rec.shadeId);
222 5 w.writeBool(rec.paired);
223 5 w.writeUInt8(static_cast<uint8_t>(rec.shadeType));
224 5 w.writeUInt32(rec.remoteAddress);
225 5 w.writeString(rec.name, sizeof(rec.name));
226 5 w.writeUInt8(static_cast<uint8_t>(rec.tiltType));
227 5 w.writeUInt8(static_cast<uint8_t>(rec.proto));
228 5 w.writeUInt8(rec.bitLength);
229 5 w.writeUInt32(rec.upTime);
230 5 w.writeUInt32(rec.downTime);
231 5 w.writeUInt32(rec.tiltTime);
232 5 w.writeUInt16(rec.stepSize);
233
2/2
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 5 times.
40 for(uint8_t j = 0; j < SOMFY_MAX_LINKED_REMOTES; j++) w.writeUInt32(rec.linkedRemotes[j]);
234 5 w.writeUInt16(rec.lastRollingCode);
235
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 time.
5 if(rec.shadeId != 255) {
236 4 w.writeUInt8(rec.flags);
237 4 w.writeFloat(rec.myPos, 5);
238 4 w.writeFloat(rec.myTiltPos, 5);
239 4 w.writeFloat(rec.currentPos, 5);
240 4 w.writeFloat(rec.currentTiltPos, 5);
241 }
242 else {
243 // A deleted shade is written cleared.
244 1 w.writeUInt8(0);
245 1 w.writeFloat(-1.0f, 5);
246 1 w.writeFloat(-1.0f, 5);
247 1 w.writeFloat(0.0f, 5);
248 1 w.writeFloat(0.0f, 5);
249 }
250 5 w.writeBool(rec.flipCommands);
251 5 w.writeBool(rec.flipPosition);
252 5 w.writeUInt8(rec.repeats);
253 5 w.writeUInt8(static_cast<uint8_t>(rec.sortOrder));
254 5 w.writeUInt8(rec.gpioUp);
255 5 w.writeUInt8(rec.gpioDown);
256 5 w.writeUInt8(rec.gpioMy);
257 5 w.writeUInt8(rec.gpioFlags);
258 5 return w.writeUInt8(rec.roomId, CFG_REC_END);
259 }
260 7 bool readShadeRecord(ConfigReader &r, const config_header_t &header, shade_record_t &rec) {
261 7 const uint8_t ver = header.version;
262 7 r.beginRecord();
263 7 rec.shadeId = r.readUInt8(255);
264 7 rec.paired = r.readBool(false);
265 7 rec.shadeType = static_cast<shade_types>(r.readUInt8(0));
266 7 rec.remoteAddress = r.readUInt32(0);
267 7 r.readFixedString(rec.name, sizeof(rec.name));
268
3/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
7 if(ver < 3) rec.tiltType = r.readBool(false) ? tilt_types::none : tilt_types::tiltmotor;
269 6 else rec.tiltType = static_cast<tilt_types>(r.readUInt8(0));
270
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if(ver > 6) rec.proto = static_cast<radio_proto>(r.readUInt8(0));
271
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if(ver > 1) rec.bitLength = r.readUInt8(56);
272 7 rec.upTime = r.readUInt32(rec.upTime);
273 7 rec.downTime = r.readUInt32(rec.downTime);
274 7 rec.tiltTime = r.readUInt32(rec.tiltTime);
275
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if(ver > 5) rec.stepSize = r.readUInt16(100);
276 // Before version 5 a shade had 5 linked remotes.
277
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 const uint8_t remotes = ver < 5 ? 5 : SOMFY_MAX_LINKED_REMOTES;
278
2/2
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 7 times.
50 for(uint8_t j = 0; j < remotes; j++) rec.linkedRemotes[j] = r.readUInt32(0);
279 7 rec.lastRollingCode = r.readUInt16(0);
280
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if(ver > 7) rec.flags = r.readUInt8(0);
281
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 6 times.
7 if(ver < 4) rec.myPos = static_cast<float>(r.readUInt8(255));
282 else {
283 6 rec.myPos = r.readFloat(-1);
284 6 rec.myTiltPos = r.readFloat(-1);
285 }
286
3/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5 times.
7 if(rec.myPos > 100 || rec.myPos < 0) rec.myPos = -1;
287
3/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 2 times.
7 if(rec.myTiltPos > 100 || rec.myTiltPos < 0) rec.myTiltPos = -1;
288 7 rec.currentPos = r.readFloat(0);
289 7 rec.currentTiltPos = r.readFloat(0);
290
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 3 times.
7 if(rec.tiltType == tilt_types::none || rec.shadeType != shade_types::blind) {
291 4 rec.myTiltPos = -1;
292 4 rec.currentTiltPos = 0;
293 4 rec.tiltType = tilt_types::none;
294 }
295
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 6 times.
7 if(ver < 3) {
296 // Positions were fractions.
297 1 rec.currentPos = rec.currentPos * 100;
298 1 rec.currentTiltPos = rec.currentTiltPos * 100;
299 }
300
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if(ver >= 9) rec.flipCommands = r.readBool(false);
301
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if(ver >= 10) rec.flipPosition = r.readBool(false);
302
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if(ver >= 12) rec.repeats = r.readUInt8(1);
303
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if(ver >= 13) rec.sortOrder = static_cast<int8_t>(r.readUInt8(rec.shadeId - 1));
304 3 else rec.sortOrder = static_cast<int8_t>(rec.shadeId - 1);
305
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if(ver > 14) {
306 3 rec.gpioUp = r.readUInt8(rec.gpioUp);
307 3 rec.gpioDown = r.readUInt8(rec.gpioDown);
308 }
309
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if(ver > 15) rec.gpioMy = r.readUInt8(rec.gpioMy);
310
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if(ver > 16) rec.gpioFlags = r.readUInt8(rec.gpioFlags);
311
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
7 if(rec.shadeId != 255 && rec.tiltType == tilt_types::tiltonly) {
312 // A tilt only shade is always all the way down.
313 ✗ rec.currentPos = 100.0f;
314 ✗ rec.myPos = 100.0f;
315 }
316
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if(ver >= 19) rec.roomId = r.readUInt8(0);
317 7 r.endRecord();
318 7 return true;
319 }
320
321 5 bool writeGroupRecord(ConfigWriter &w, const group_record_t &rec) {
322 5 w.writeUInt8(rec.groupId);
323 5 w.writeUInt8(static_cast<uint8_t>(rec.groupType));
324 5 w.writeUInt32(rec.remoteAddress);
325 5 w.writeString(rec.name, sizeof(rec.name));
326 5 w.writeUInt8(static_cast<uint8_t>(rec.proto));
327 5 w.writeUInt8(rec.bitLength);
328
2/2
✓ Branch 1 taken 160 times.
✓ Branch 2 taken 5 times.
165 for(uint8_t j = 0; j < SOMFY_MAX_GROUPED_SHADES; j++) w.writeUInt8(rec.linkedShades[j]);
329 5 w.writeUInt8(rec.repeats);
330 5 w.writeUInt8(static_cast<uint8_t>(rec.sortOrder));
331 5 w.writeBool(rec.flipCommands);
332 5 w.writeUInt8(rec.roomId);
333 5 return w.writeUInt16(rec.lastRollingCode, CFG_REC_END);
334 }
335 6 bool readGroupRecord(ConfigReader &r, const config_header_t &header, group_record_t &rec) {
336 6 const uint8_t ver = header.version;
337 6 r.beginRecord();
338 6 rec.groupId = r.readUInt8(255);
339 6 rec.groupType = static_cast<group_types>(r.readUInt8(0));
340 6 rec.remoteAddress = r.readUInt32(0);
341 6 r.readFixedString(rec.name, sizeof(rec.name));
342 6 rec.proto = static_cast<radio_proto>(r.readUInt8(0));
343 6 rec.bitLength = r.readUInt8(56);
344 // Version 23 put the rolling code here, version 24 at the end.
345
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 5 times.
6 if(ver == 23) rec.lastRollingCode = r.readUInt16(0);
346 6 rec.hasRollingCode = ver >= 23;
347 6 memset(rec.linkedShades, 0x00, sizeof(rec.linkedShades));
348 6 uint8_t linked = 0;
349
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 6 times.
198 for(uint8_t j = 0; j < SOMFY_MAX_GROUPED_SHADES; j++) {
350 192 const uint8_t shadeId = r.readUInt8(0);
351
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 181 times.
192 if(shadeId > 0) rec.linkedShades[linked++] = shadeId;
352 }
353
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if(ver >= 12) rec.repeats = r.readUInt8(1);
354
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if(ver >= 13) rec.sortOrder = static_cast<int8_t>(r.readUInt8(rec.groupId - 1));
355 2 else rec.sortOrder = static_cast<int8_t>(rec.groupId - 1);
356
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if(ver >= 18) rec.flipCommands = r.readBool(false);
357
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if(ver >= 19) rec.roomId = r.readUInt8(0);
358
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if(ver >= 24) rec.lastRollingCode = r.readUInt16(0);
359 6 r.endRecord();
360 6 return true;
361 }
362
363 1 bool writeRepeaterRecord(ConfigWriter &w, const uint32_t (&repeaters)[SOMFY_MAX_REPEATERS]) {
364
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 time.
8 for(uint8_t i = 0; i < SOMFY_MAX_REPEATERS; i++)
365
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 6 times.
7 w.writeUInt32(repeaters[i], i == SOMFY_MAX_REPEATERS - 1 ? CFG_REC_END : CFG_VALUE_SEP);
366 1 return true;
367 }
368 ✗ bool readRepeaterRecord(ConfigReader &r, uint32_t (&repeaters)[SOMFY_MAX_REPEATERS]) {
369 ✗ r.beginRecord();
370
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ for(uint8_t i = 0; i < SOMFY_MAX_REPEATERS; i++) repeaters[i] = r.readUInt32(0);
371 ✗ r.endRecord();
372 ✗ return true;
373 }
374
375 2 bool writeSettingsRecord(ConfigWriter &w, const settings_record_t &rec) {
376 2 w.writeVarString(rec.fwVersion);
377 2 w.writeVarString(rec.hostname);
378 2 w.writeVarString(rec.ntpServer);
379 2 w.writeVarString(rec.posixZone);
380 2 w.writeBool(rec.ssdpBroadcast);
381 2 return w.writeBool(rec.checkForUpdate, CFG_REC_END);
382 }
383 3 bool readSettingsRecord(ConfigReader &r, const config_header_t &header, settings_record_t &rec) {
384 3 r.beginRecord();
385 3 r.readVarString(rec.fwVersion, sizeof(rec.fwVersion));
386 3 r.readVarString(rec.hostname, sizeof(rec.hostname));
387 3 r.readVarString(rec.ntpServer, sizeof(rec.ntpServer));
388 3 r.readVarString(rec.posixZone, sizeof(rec.posixZone));
389 3 rec.ssdpBroadcast = r.readBool(false);
390
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 if(header.version >= 20) rec.checkForUpdate = r.readBool(true);
391 3 r.endRecord();
392 3 return true;
393 }
394
395 6 bool writeNetRecord(ConfigWriter &w, const net_record_t &rec, bool withEthernet) {
396 6 w.writeUInt8(rec.connType);
397 6 w.writeBool(rec.dhcp);
398 6 w.writeVarString(rec.ip);
399 6 w.writeVarString(rec.gateway);
400 6 w.writeVarString(rec.subnet);
401 6 w.writeVarString(rec.dns1);
402 6 w.writeVarString(rec.dns2);
403 6 w.writeVarString(rec.mqttProtocol);
404 6 w.writeVarString(rec.mqttHostname);
405 6 w.writeUInt16(rec.mqttPort);
406 6 w.writeBool(rec.mqttPubDisco);
407 6 w.writeVarString(rec.mqttRootTopic);
408 6 w.writeVarString(rec.mqttDiscoTopic);
409
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 time.
6 if(!withEthernet) return w.writeUInt8(0, CFG_REC_END);
410 1 w.writeUInt8(rec.ethBoardType);
411 1 w.writeUInt8(rec.ethPhyType);
412 1 w.writeUInt8(rec.ethClkMode);
413 1 w.writeInt8(rec.ethPhyAddress);
414 1 w.writeInt8(rec.ethPWRPin);
415 1 w.writeInt8(rec.ethMDCPin);
416 1 return w.writeInt8(rec.ethMDIOPin, CFG_REC_END);
417 }
418 4 bool readNetRecord(ConfigReader &r, const config_header_t &header, net_record_t &rec, bool withEthernet) {
419 4 r.beginRecord();
420 4 rec.connType = r.readUInt8(0);
421 4 rec.dhcp = r.readBool(true);
422 4 r.readVarString(rec.ip, sizeof(rec.ip));
423 4 r.readVarString(rec.gateway, sizeof(rec.gateway));
424 4 r.readVarString(rec.subnet, sizeof(rec.subnet));
425 4 r.readVarString(rec.dns1, sizeof(rec.dns1));
426 4 r.readVarString(rec.dns2, sizeof(rec.dns2));
427
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 if(header.version >= 22) {
428 3 r.readVarString(rec.mqttProtocol, sizeof(rec.mqttProtocol));
429 3 r.readVarString(rec.mqttHostname, sizeof(rec.mqttHostname));
430 3 rec.mqttPort = r.readUInt16(1883);
431 3 rec.mqttPubDisco = r.readBool(false);
432 3 r.readVarString(rec.mqttRootTopic, sizeof(rec.mqttRootTopic));
433 3 r.readVarString(rec.mqttDiscoTopic, sizeof(rec.mqttDiscoTopic));
434 }
435
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 if(withEthernet) {
436 3 rec.ethBoardType = r.readUInt8(1);
437 3 rec.ethPhyType = r.readUInt8(0);
438 3 rec.ethClkMode = r.readUInt8(0);
439 3 rec.ethPhyAddress = r.readInt8(1);
440 3 rec.ethPWRPin = r.readInt8(1);
441 3 rec.ethMDCPin = r.readInt8(16);
442 3 rec.ethMDIOPin = r.readInt8(23);
443 }
444 4 r.endRecord();
445 4 return true;
446 }
447
448 5 bool writeTransRecord(ConfigWriter &w, const trans_record_t &rec) {
449 5 w.writeBool(rec.enabled);
450 5 w.writeUInt8(static_cast<uint8_t>(rec.proto));
451 5 w.writeUInt8(rec.type);
452 5 w.writeUInt8(rec.SCKPin);
453 5 w.writeUInt8(rec.CSNPin);
454 5 w.writeUInt8(rec.MOSIPin);
455 5 w.writeUInt8(rec.MISOPin);
456 5 w.writeUInt8(rec.TXPin);
457 5 w.writeUInt8(rec.RXPin);
458 5 w.writeFloat(rec.frequency, 3);
459 5 w.writeFloat(rec.rxBandwidth, 2);
460 5 w.writeFloat(rec.deviation, 2);
461 5 w.writeInt8(rec.txPower);
462 5 return w.writeBool(rec.noiseDetection, CFG_REC_END);
463 }
464 4 bool readTransRecord(ConfigReader &r, trans_record_t &rec) {
465 4 r.beginRecord();
466 4 rec.enabled = r.readBool(false);
467 4 rec.proto = static_cast<radio_proto>(r.readUInt8(0));
468 4 rec.type = r.readUInt8(56);
469 4 rec.SCKPin = r.readUInt8(rec.SCKPin);
470 4 rec.CSNPin = r.readUInt8(rec.CSNPin);
471 4 rec.MOSIPin = r.readUInt8(rec.MOSIPin);
472 4 rec.MISOPin = r.readUInt8(rec.MISOPin);
473 4 rec.TXPin = r.readUInt8(rec.TXPin);
474 4 rec.RXPin = r.readUInt8(rec.RXPin);
475 4 rec.frequency = r.readFloat(rec.frequency);
476 4 rec.rxBandwidth = r.readFloat(rec.rxBandwidth);
477 4 rec.deviation = r.readFloat(rec.deviation);
478 4 rec.txPower = r.readInt8(rec.txPower);
479 4 rec.noiseDetection = r.readBool(false);
480 4 r.endRecord();
481 4 return true;
482 }
483
484 3 bool skipRecords(ConfigReader &r, uint32_t count) {
485
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for(uint32_t i = 0; i < count; i++) {
486 4 r.beginRecord();
487
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 3 times.
4 if(!r.seekChar(CFG_REC_END)) return false;
488 }
489 2 return true;
490 }
491