AceTime  2.3.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>
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>
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>
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>
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 {
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>
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>
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>
463  const {
464  ace_common::printReplaceCharTo(
465  printer, zoneinfo::findShortName(name()), '_', ' ');
466 }
467 
468 //-----------------------------------------------------------------------------
469 
476 template <typename ZI>
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>
511  public:
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
Helper functions are used in both Basic brokers and Extended brokers.
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
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
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
Data broker for accessing a ZoneContext.
Definition: BrokersLow.h:91
Data broker for accessing ZoneEra.
Definition: BrokersLow.h:297
Data broker for accessing ZoneInfo.
Definition: BrokersLow.h:384
bool equals(uintptr_t zoneKey) const
Definition: BrokersLow.h:399
void printNameTo(Print &printer) const
Print a human-readable identifier (e.g.
Definition: BrokersLow.h:455
void printShortNameTo(Print &printer) const
Print a short human-readable identifier (e.g.
Definition: BrokersLow.h:462
A storage object that creates an ZoneInfoBroker from a key that identifies the ZoneInfo.
Definition: BrokersLow.h:510
ZoneInfoBroker< ZC, ZI, ZE, ZP, ZR > createZoneInfoBroker(uintptr_t zoneKey) const
Definition: BrokersLow.h:517
Data broker for accessing ZonePolicy.
Definition: BrokersLow.h:255
Data broker for accessing the ZoneRegistry.
Definition: BrokersLow.h:477
Data broker for accessing ZoneRule.
Definition: BrokersLow.h:169
Macros and definitions that provide a consistency layer among the various Arduino boards for compatib...