AceTime 2.4.0 Date and time classes for Arduino that support timezones from the TZ Database.

BrokersLow.h
Go to the documentation of this file.
1 /*
2 * MIT License
3 * Copyright (c) 2023 Brian T. Park
4 */
5
6 #ifndef ACE_TIME_BROKERS_LOW_H
7 #define ACE_TIME_BROKERS_LOW_H
8
24 #include <stdint.h> // uintptr_t, uint32_t, etc
25 #include <Arduino.h> // pgm_read_xxx()
26 #include <AceCommon.h> // KString
27 #include "compat.h" // ACE_TIME_USE_PROGMEM
28 #include "BrokerCommon.h"
29 #include "ZoneInfoLow.h"
30
31 class __FlashStringHelper;
32 class Print;
33
34 namespace ace_time {
35 namespace zoneinfolow {
36
37 //-----------------------------------------------------------------------------
38
49 inline int16_t toDeltaMinutes(uint8_t deltaCode) {
50 return ((int16_t)(deltaCode & 0x0f) - 4) * 15;
51 }
52
59 inline int16_t toOffsetMinutes(uint8_t offsetCode, uint8_t deltaCode) {
60 return ((int8_t)offsetCode * 15) + ((deltaCode & 0xf0) >> 4);
61 }
62
63
70 inline uint16_t timeCodeToMinutes(uint8_t code, uint8_t modifier) {
71 return code * (uint16_t) 15 + (modifier & 0x0f);
72 }
73
79 inline uint8_t toSuffix(uint8_t modifier) {
80 return modifier & 0xf0;
81 }
82
83 //-----------------------------------------------------------------------------
84
90 template <typename ZC>
91 class ZoneContextBroker {
92 public:
93 explicit ZoneContextBroker(const ZC* zoneContext = nullptr)
94 : mZoneContext(zoneContext)
95 {}
96
97 // use the default copy constructor
98 ZoneContextBroker(const ZoneContextBroker&) = default;
99
100 // use the default assignment operator
101 ZoneContextBroker& operator=(const ZoneContextBroker&) = default;
102
103 bool isNull() const { return mZoneContext == nullptr; }
104
105 const ZC* raw() const { return mZoneContext; }
106
107 int16_t startYear() const {
108 return (int16_t) pgm_read_word(&mZoneContext->startYear);
109 }
110
111 int16_t untilYear() const {
112 return (int16_t) pgm_read_word(&mZoneContext->untilYear);
113 }
114
115 int16_t startYearAccurate() const {
116 return (int16_t) pgm_read_word(&mZoneContext->startYearAccurate);
117 }
118
119 int16_t untilYearAccurate() const {
120 return (int16_t) pgm_read_word(&mZoneContext->untilYearAccurate);
121 }
122
123 int16_t baseYear() const {
124 return (int16_t) pgm_read_word(&mZoneContext->baseYear);
125 }
126
127 int16_t maxTransitions() const {
128 return (int16_t) pgm_read_word(&mZoneContext->maxTransitions);
129 }
130
131 const __FlashStringHelper* tzVersion() const {
132 return (const __FlashStringHelper*)
133 pgm_read_ptr(&mZoneContext->tzVersion);
134 }
135
136 uint8_t numFragments() const {
137 return (uint8_t) pgm_read_byte(&mZoneContext->numFragments);
138 }
139
140 uint8_t numLetters() const {
141 return (uint8_t) pgm_read_byte(&mZoneContext->numLetters);
142 }
143
144 const __FlashStringHelper* const* fragments() const {
145 return (const __FlashStringHelper* const*)
146 pgm_read_ptr(&mZoneContext->fragments);
147 }
148
149 const __FlashStringHelper* letter(uint8_t i) const {
150 const char * const* letters = (const char* const*)
151 pgm_read_ptr(&mZoneContext->letters);
152 const char* letter = (const char*) pgm_read_ptr(letters + i);
153 return (const __FlashStringHelper*) letter;
154 }
155
156 private:
157 const ZC* mZoneContext;
158 };
159
160 //-----------------------------------------------------------------------------
161
168 template <typename ZC, typename ZR>
169 class ZoneRuleBroker {
170 public:
171 explicit ZoneRuleBroker(
172 const ZC* zoneContext = nullptr,
173 const ZR* zoneRule = nullptr)
174 : mZoneContext(zoneContext)
175 , mZoneRule(zoneRule)
176 {}
177
178 // use the default copy constructor
179 ZoneRuleBroker(const ZoneRuleBroker&) = default;
180
181 // use the default assignment operator
182 ZoneRuleBroker& operator=(const ZoneRuleBroker&) = default;
183
184 bool isNull() const { return mZoneRule == nullptr; }
185
186 int16_t fromYear() const {
187 int8_t yearTiny = (int8_t) pgm_read_byte(&mZoneRule->fromYear);
188 int16_t baseYear = ZoneContextBroker<ZC>(mZoneContext).baseYear();
189 return toYearFromTiny(yearTiny, baseYear);
190 }
191
192 int16_t toYear() const {
193 int8_t yearTiny = (int8_t) pgm_read_byte(&mZoneRule->toYear);
194 int16_t baseYear = ZoneContextBroker<ZC>(mZoneContext).baseYear();
195 return toYearFromTiny(yearTiny, baseYear);
196 }
197
198 static int16_t toYearFromTiny(int8_t yearTiny, int16_t baseYear) {
199 if (yearTiny == ZC::kInvalidYearTiny) return ZC::kInvalidYear;
200 if (yearTiny == ZC::kMinYearTiny) return ZC::kMinYear;
201
202 // yearTiny should be a maximum of 126, and should never be as high as
203 // 127. But if it does have this value, what should we do? Let's peg the
204 // return value at 32766, so that it's always less than the 32767 maximum
205 // returned by untilYear().
206 if (yearTiny >= ZC::kMaxYearTiny) return ZC::kMaxYear;
207
208 return baseYear + yearTiny;
209 }
210
211 uint8_t inMonth() const {
212 return pgm_read_byte(&mZoneRule->inMonth);
213 }
214
215 uint8_t onDayOfWeek() const {
216 return pgm_read_byte(&mZoneRule->onDayOfWeek);
217 }
218
219 int8_t onDayOfMonth() const {
220 return pgm_read_byte(&mZoneRule->onDayOfMonth);
221 }
222
223 uint32_t atTimeSeconds() const {
224 return 60 * timeCodeToMinutes(
225 pgm_read_byte(&mZoneRule->atTimeCode),
226 pgm_read_byte(&mZoneRule->atTimeModifier));
227 }
228
229 uint8_t atTimeSuffix() const {
230 return toSuffix(pgm_read_byte(&mZoneRule->atTimeModifier));
231 }
232
233 int32_t deltaSeconds() const {
234 return 60 * toDeltaMinutes(pgm_read_byte(&mZoneRule->deltaCode));
235 }
236
237 const __FlashStringHelper* letter() const {
238 uint8_t index = pgm_read_byte(&mZoneRule->letterIndex);
239 return ZoneContextBroker<ZC>(mZoneContext).letter(index);
240 }
241
242 private:
243 const ZC* mZoneContext;
244 const ZR* mZoneRule;
245 };
246
254 template <typename ZC, typename ZP, typename ZR>
255 class ZonePolicyBroker {
256 public:
257 explicit ZonePolicyBroker(
258 const ZC* zoneContext,
259 const ZP* zonePolicy)
260 : mZoneContext(zoneContext)
261 , mZonePolicy(zonePolicy)
262 {}
263
264 // use default copy constructor
265 ZonePolicyBroker(const ZonePolicyBroker&) = default;
266
267 // use default assignment operator
268 ZonePolicyBroker& operator=(const ZonePolicyBroker&) = default;
269
270 bool isNull() const { return mZonePolicy == nullptr; }
271
272 uint8_t numRules() const {
273 return pgm_read_byte(&mZonePolicy->numRules);
274 }
275
276 const ZoneRuleBroker<ZC, ZR> rule(uint8_t i) const {
277 const ZR* rules = (const ZR*) pgm_read_ptr(&mZonePolicy->rules);
278 return ZoneRuleBroker<ZC, ZR>(mZoneContext, &rules[i]);
279 }
280
281 private:
282 const ZC* mZoneContext;
283 const ZP* mZonePolicy;
284 };
285
286 //-----------------------------------------------------------------------------
287
296 template <typename ZC, typename ZE, typename ZP, typename ZR>
297 class ZoneEraBroker {
298 public:
299 explicit ZoneEraBroker(
300 const ZC* zoneContext = nullptr,
301 const ZE* zoneEra = nullptr)
302 : mZoneContext(zoneContext)
303 , mZoneEra(zoneEra)
304 {}
305
306 // use default copy constructor
307 ZoneEraBroker(const ZoneEraBroker&) = default;
308
309 // use default assignment operator
310 ZoneEraBroker& operator=(const ZoneEraBroker&) = default;
311
312 bool isNull() const { return mZoneEra == nullptr; }
313
314 bool equals(const ZoneEraBroker& other) const {
315 return mZoneEra == other.mZoneEra;
316 }
317
318 const ZonePolicyBroker<ZC, ZP, ZR> zonePolicy() const {
319 return ZonePolicyBroker<ZC, ZP, ZR>(
320 mZoneContext,
321 (const ZP*) pgm_read_ptr(&mZoneEra->zonePolicy));
322 }
323
324 int32_t offsetSeconds() const {
325 return 60 * toOffsetMinutes(
326 pgm_read_byte(&mZoneEra->offsetCode),
327 pgm_read_byte(&mZoneEra->deltaCode));
328 }
329
330 int32_t deltaSeconds() const {
331 return 60 * toDeltaMinutes(pgm_read_byte(&mZoneEra->deltaCode));
332 }
333
334 const char* format() const {
335 return (const char*) pgm_read_ptr(&mZoneEra->format);
336 }
337
338 int16_t untilYear() const {
339 int8_t yearTiny = (int8_t) pgm_read_byte(&mZoneEra->untilYear);
340 int16_t baseYear = ZoneContextBroker<ZC>(mZoneContext).baseYear();
341 return toUntilYearFromTiny(yearTiny, baseYear);
342 }
343
344 static int16_t toUntilYearFromTiny(int8_t yearTiny, int16_t baseYear) {
345 if (yearTiny == ZC::kInvalidYearTiny) return ZC::kInvalidYear;
346 if (yearTiny == ZC::kMinYearTiny) return ZC::kMinYear;
347 if (yearTiny == ZC::kMaxUntilYearTiny) return ZC::kMaxUntilYear;
348 return baseYear + yearTiny;
349 }
350
351 uint8_t untilMonth() const {
352 return pgm_read_byte(&mZoneEra->untilMonth);
353 }
354
355 uint8_t untilDay() const {
356 return pgm_read_byte(&mZoneEra->untilDay);
357 }
358
359 uint32_t untilTimeSeconds() const {
360 return 60 * timeCodeToMinutes(
361 pgm_read_byte(&mZoneEra->untilTimeCode),
362 pgm_read_byte(&mZoneEra->untilTimeModifier));
363 }
364
365 uint8_t untilTimeSuffix() const {
366 return toSuffix(pgm_read_byte(&mZoneEra->untilTimeModifier));
367 }
368
369 private:
370 const ZC* mZoneContext;
371 const ZE* mZoneEra;
372 };
373
383 template <typename ZC, typename ZI, typename ZE, typename ZP, typename ZR>
384 class ZoneInfoBroker {
385 public:
386 explicit ZoneInfoBroker(const ZI* zoneInfo = nullptr):
387 mZoneInfo(zoneInfo) {}
388
389 // use default copy constructor
390 ZoneInfoBroker(const ZoneInfoBroker&) = default;
391
392 // use default assignment operator
393 ZoneInfoBroker& operator=(const ZoneInfoBroker&) = default;
394
399 bool equals(uintptr_t zoneKey) const {
400 return mZoneInfo == (const ZI*) zoneKey;
401 }
402
403 bool equals(const ZoneInfoBroker& zoneInfoBroker) const {
404 return mZoneInfo == zoneInfoBroker.mZoneInfo;
405 }
406
407 bool isNull() const { return mZoneInfo == nullptr; }
408
409 const ZoneContextBroker<ZC> zoneContext() const {
410 const ZC* context = (const ZC*) pgm_read_ptr(&mZoneInfo->zoneContext);
411 return ZoneContextBroker<ZC>(context);
412 }
413
414 const __FlashStringHelper* name() const {
415 return FPSTR(pgm_read_ptr(&mZoneInfo->name));
416 }
417
418 uint32_t zoneId() const {
419 return pgm_read_dword(&mZoneInfo->zoneId);
420 }
421
422 uint8_t numEras() const {
423 return pgm_read_byte(&mZoneInfo->numEras);
424 }
425
426 const ZoneEraBroker<ZC, ZE, ZP, ZR> era(uint8_t i) const {
427 auto eras = (const ZE*) pgm_read_ptr(&mZoneInfo->eras);
428 return ZoneEraBroker<ZC, ZE, ZP, ZR>(zoneContext().raw(), &eras[i]);
429 }
430
431 bool isLink() const {
432 return mZoneInfo->targetInfo != nullptr;
433 }
434
435 ZoneInfoBroker targetInfo() const {
436 return ZoneInfoBroker(
437 (const ZI*) pgm_read_ptr(&mZoneInfo->targetInfo));
438 }
439
441 void printNameTo(Print& printer) const;
442
447 void printShortNameTo(Print& printer) const;
448
449 private:
450 const ZI* mZoneInfo;
451 };
452
453
454 template <typename ZC, typename ZI, typename ZE, typename ZP, typename ZR>
455 void ZoneInfoBroker<ZC, ZI, ZE, ZP, ZR>::printNameTo(Print& printer) const {
456 ZoneContextBroker<ZC> zc = zoneContext();
457 ace_common::KString kname(name(), zc.fragments(), zc.numFragments());
458 kname.printTo(printer);
459 }
460
461 template <typename ZC, typename ZI, typename ZE, typename ZP, typename ZR>
462 void ZoneInfoBroker<ZC, ZI, ZE, ZP, ZR>::printShortNameTo(Print& printer)
463 const {
464 ace_common::printReplaceCharTo(
465 printer, zoneinfo::findShortName(name()), '_', ' ');
466 }
467
468 //-----------------------------------------------------------------------------
469
476 template <typename ZI>
477 class ZoneRegistryBroker {
478 public:
479 ZoneRegistryBroker(const ZI* const* zoneRegistry):
480 mZoneRegistry(zoneRegistry) {}
481
482 // use default copy constructor
483 ZoneRegistryBroker(const ZoneRegistryBroker&) = default;
484
485 // use default assignment operator
486 ZoneRegistryBroker& operator=(const ZoneRegistryBroker&) = default;
487
488 const ZI* zoneInfo(uint16_t i) const {
489 return (const ZI*) pgm_read_ptr(&mZoneRegistry[i]);
490 }
491
492 private:
493 const ZI* const* mZoneRegistry;
494 };
495
496 //-----------------------------------------------------------------------------
497
509 template <typename ZC, typename ZI, typename ZE, typename ZP, typename ZR>
510 class ZoneInfoStore {
511 public:
516 ZoneInfoBroker<ZC, ZI, ZE, ZP, ZR>
517 createZoneInfoBroker(uintptr_t zoneKey) const {
518 return ZoneInfoBroker<ZC, ZI, ZE, ZP, ZR>((const ZI*) zoneKey);
519 }
520 };
521
522 } // zoneinfolow
523 } // ace_time
524
525 #endif
BrokerCommon.h
Helper functions are used in both Basic brokers and Extended brokers.
ace_time::zoneinfolow::toOffsetMinutes
int16_t toOffsetMinutes(uint8_t offsetCode, uint8_t deltaCode)
Convert the offsetCode and deltaCode holding the STDOFF field of the ZoneEra into minutes.
Definition: BrokersLow.h:59
ace_time::zoneinfolow::timeCodeToMinutes
uint16_t timeCodeToMinutes(uint8_t code, uint8_t modifier)
Convert (code, modifier) fields representing the UNTIL time in ZoneInfo or AT time in ZoneRule in one...
Definition: BrokersLow.h:70
ace_time::zoneinfolow::toDeltaMinutes
int16_t toDeltaMinutes(uint8_t deltaCode)
Convert the deltaCode holding the RULES/DSTOFF field in ZoneEra or the SAVE field in ZoneRule to the ...
Definition: BrokersLow.h:49
ZoneInfoLow.h
Data structures describe the low resolution zoneinfo persistence format.
ace_time::zoneinfolow::ZoneContextBroker
Data broker for accessing a ZoneContext.
Definition: BrokersLow.h:91
ace_time::zoneinfolow::ZoneEraBroker
Data broker for accessing ZoneEra.
Definition: BrokersLow.h:297
ace_time::zoneinfolow::ZoneInfoBroker
Data broker for accessing ZoneInfo.
Definition: BrokersLow.h:384
ace_time::zoneinfolow::ZoneInfoBroker::equals
bool equals(uintptr_t zoneKey) const
Definition: BrokersLow.h:399
ace_time::zoneinfolow::ZoneInfoBroker::printNameTo
void printNameTo(Print &printer) const
Print a human-readable identifier (e.g.
Definition: BrokersLow.h:455
ace_time::zoneinfolow::ZoneInfoBroker::printShortNameTo
void printShortNameTo(Print &printer) const
Print a short human-readable identifier (e.g.
Definition: BrokersLow.h:462
ace_time::zoneinfolow::ZoneInfoStore
A storage object that creates an ZoneInfoBroker from a key that identifies the ZoneInfo.
Definition: BrokersLow.h:510
ace_time::zoneinfolow::ZoneInfoStore::createZoneInfoBroker
ZoneInfoBroker< ZC, ZI, ZE, ZP, ZR > createZoneInfoBroker(uintptr_t zoneKey) const
Definition: BrokersLow.h:517
ace_time::zoneinfolow::ZonePolicyBroker
Data broker for accessing ZonePolicy.
Definition: BrokersLow.h:255
ace_time::zoneinfolow::ZoneRegistryBroker
Data broker for accessing the ZoneRegistry.
Definition: BrokersLow.h:477
ace_time::zoneinfolow::ZoneRuleBroker
Data broker for accessing ZoneRule.
Definition: BrokersLow.h:169
compat.h
Macros and definitions that provide a consistency layer among the various Arduino boards for compatib...