Home2L - C/C++ API  v1.2-2-ga4fe (2023-04-15)
Smart Tools for a Private Home
brownies.H
Go to the documentation of this file.
1 /*
2  * This file is part of the Home2L project.
3  *
4  * (C) 2015-2021 Gundolf Kiefer
5  *
6  * Home2L is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Home2L is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Home2L. If not, see <https://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 #ifndef _BROWNIES_
23 #define _BROWNIES_
24 
25 #include "env.H"
26 #include "resources.H"
27 
28 
29 extern "C" {
30 #include "avr/interface.h"
31 }
32 
33 
81 // *************************** Basics ******************************************
82 
83 
84 #define BR_CONF_DEFAULT_NAME "brownies.conf"
85 
86 
87 extern const char *envBrDatabaseFile;
88 extern const char *envBrLinkDev;
89 
90 
91 const char *BrStatusStr (EBrStatus s);
93 
94 const char *BrMcuStr (int mcuType, const char *unknown = NULL);
97 int BrMcuFromStr (const char *mcuStr);
100 
101 
102 
103 
104 
105 // ***************** Brownie Feature and Config Records ************************
106 
107 
108 // ***** Configuration item descriptor *****
109 
110 
112 typedef enum {
113  ctUint8,
114  ctInt8,
115  ctUint16,
116  ctVersion, // special: Version number (stored in TBrFeatureRecord.version*)
117  ctFeatures, // special: Feature information relevant for resources
118  ctMcu, // special: MCU model
119  ctFw, // special: Firmware name (stored in TBrFeatureRecord.fwName)
120  ctId, // special: ID (stored in EEPROM at BR_EEPROM_ID_BASE)
121  ctShadesDelay, // special: Shades delay (byte displayed as seconds)
122  ctShadesSpeed // special: Shades speed (byte displayed as seconds of 100% movement)
123 } EBrCfgType;
124 
125 
127 struct TBrCfgDescriptor {
128  const char *key; // written key
129  const char *fmt; // format for output
130  EBrCfgType type;
131  int features; // any of these features must be present, otherwise the variable is ignored
132  int ofs; // offset inside the TBrConfigRecord structure
133  const char *help;
134 };
135 
136 
137 extern const TBrCfgDescriptor brCfgDescList[];
138 extern const int brCfgDescs;
139 
140 
141 
142 // ***** Feature record to/from string *****
143 
144 uint32_t BrVersionGet (TBrFeatureRecord *featureRecord);
146 static inline const char *BrVersionGetAsStr (CString *ret, TBrFeatureRecord *featureRecord) { return VersionToStr (ret, BrVersionGet (featureRecord)); }
149 bool BrVersionFromStr (TBrFeatureRecord *featureRecord, const char *str);
151 
152 const char *BrFeaturesToStr (CString *ret, TBrFeatureRecord *featureRecord);
155 bool BrFeaturesFromStr (TBrFeatureRecord *featureRecord, const char *str);
157 
158 
159 
160 
161 
162 // *************************** CBrownie ****************************************
163 
164 
167 class CBrownie {
168  public:
169 
172 
173  CBrownie () { features = 0; Clear (); }
174  ~CBrownie () { Clear (); }
175 
176  void Clear ();
177 
178  void SetId (const char *id) { strncpy (idRecord, id, sizeof (idRecord)); idRecord[sizeof (idRecord) - 1] = '\0'; }
179  void SetFeatureRecord (TBrFeatureRecord *_featureRecord) { featureRecord = *_featureRecord; }
180  void SetConfigRecord (TBrConfigRecord *_configRecord) { configRecord = *_configRecord; }
181  void SetDatabaseString (const char *s) { databaseString.Set (s); }
182 
183  bool SetFromStr (const char *str, CString *ret = NULL);
190  const char *ToStr (CString *ret, bool withIdentification = true, bool withVersionInfo = true);
192 
196 
197  int Adr () { return configRecord.adr; }
199  const char *Id () { return idRecord; }
201  TBrFeatureRecord *FeatureRecord () { return &featureRecord; }
203  TBrConfigRecord *ConfigRecord () { return &configRecord; }
205 
206  const char *DatabaseString () { return databaseString.Get (); }
208 
212 
213  bool IsValid () { return configRecord.adr != 0; }
215  bool HasFeatures () { return featureRecord.features || featureRecord.gpiPresence || featureRecord.gpoPresence; }
217 
218  bool HasDeviceFeatures () { return featureRecord.magic == BR_MAGIC; }
220  bool HasDeviceConfig () { return configRecord.magic == BR_MAGIC; }
222 
226 
227  bool IsCompatible (const char *_databaseString);
230 
231  bool UpdateFromDevice (class CBrownieLink *link);
236 
238 
239  protected:
240  const char *GetOptValue (CString *ret, int optIdx);
241  bool SetOptValue (int optIdx, const char *str);
242  void CheckDeviceForResources (CBrownieLink *link);
243 
244  // Database and hardware info ...
245  TBrIdRecord idRecord;
246  TBrFeatureRecord featureRecord;
247  TBrConfigRecord configRecord;
248  CString databaseString;
249 
250  // Resources (with interface calls for @ref CBrownieSet) ...
251  friend class CBrownieSet;
252  friend class CBrRcDriver;
253 
254  class CBrFeature *featureList[8]; // array of device feature objects (use 'sizeof(featureList)' to avoid buffer overflows)
255  int features; // number of device features
256  bool deviceChecked; // device has been checked, either with or without success:
257  // if true, but HasDeviceFeatures() or HasDeviceConfig() returns false, it should not be checked again but treated as unusable
258  bool unknownChanges; // There was a failure reading the "changed" register, we may have missed changes
259 
260  void RegisterAllResources (class CRcDriver *rcDriver, class CBrownieLink *link = NULL);
261  // Register all resources and create device feature objects;
262  // This is done based on the database, However, later, on the first
263  // invocation of 'Iterate()', the features of the real hardware should be validated against
264  // this for the case the database is out of date.
265  // If 'link != NULL' and the 'features' configuration option is not set in the database,
266  // the device is checked immediately.
267  // If 'link == NULL', the 'features' configuration option must be set in the database,
268  // otherwise, no resources will be registered for the device.
269  unsigned Iterate (class CBrownieLink *link, bool fast);
270  // Check the "changed" register BR_REG_CHANGED and do all necessary actions.
271  //
272  // 'link' may be 'NULL', in which case time-outs should be checked and resources
273  // be invalidated accordingly.
274  //
275  // If 'fast' is 'true', a notification was received for this
276  // subnet. Hence, we must only read registers of time-critical features
277  // (= those with a set "changed" bit) to save time in favour of some other
278  // node that caused the notification.
279  //
280  // Returns the contents of register BR_REG_CHANGED (presently only
281  // relevant for hubs and their BR_CHANGED_CHILD bit, other may return 0).
282  //
283  void CheckExpiration ();
284  // Invalidate all expireable resources on expiration
285  void DriveValue (class CBrownieLink *link, class CResource *rc, class CRcValueState *vs);
286  // Unlike CBrownieSet::DriveValue(), this method is always called from the
287  // Brownie thread, so no care of concurrency is necessary.
288 };
289 
290 
291 
292 
293 
294 // *************************** CBrownieSet *************************************
295 
296 
299 class CBrownieSet {
300  public:
301 
304 
305  CBrownieSet ();
306  ~CBrownieSet () { ResourcesDone (); Clear (); }
307 
308  void Clear ();
309 
310  CBrownie *Get (const char *id) { int *pAdr = adrMap.Get (id); return pAdr ? Get (*pAdr) : NULL; }
311  CBrownie *Get (int adr) { return (adr < 0 || adr > 127) ? NULL : brList[adr]; }
314 
315  void Set (CBrownie *brownie);
316  CBrownie *Unlink (int adr);
317 
318  void Del (int adr);
319 
323 
324  bool ReadDatabase (const char *fileName = NULL);
328  bool WriteDatabase (const char *fileName = NULL);
332 
337 
338  void ResourcesInit (CRcEventDriver *_rcDriver, class CBrownieLink *_rcLink);
346  void ResourcesIterate (bool noLink = false, bool noSleep = false);
360  void ResourcesDone ();
366 
368 
369  protected:
370  CBrownie *brList[128];
371  CDictCompact<int> adrMap;
372 
373  // Resources ...
374  class CRcEventDriver *rcDriver;
375  class CBrownieLink *rcLink;
376  int rcLastCheckedAdr; // next address to be polled normally (not fast)
377  TTicks tLastIterate; // monotonic time of last entry of 'ResourcesIterate ()'
378 };
379 
380 
381 
382 
383 
384 // *************************** CBrownieLink ***********************************
385 
386 
388 typedef enum {
389  ifNone = 0,
393  ifEND
394 } ETwiIfType;
395 
396 
397 const char *TwiIfTypeStr (ETwiIfType type);
398 
399 
401 enum ESocketOp {
402  soSend = 0, // request: head + data (<bytes>), reply: head
403  soFetch, // request: head, reply: head + data <bytes>
404  soStatReset, // request: head, no reply
405  soStatFetch // request: head, reply: head + string without \0 <bytes>
406 };
407 
408 
410 struct TSocketHeader {
411  ESocketOp op : 3; // Socket operation
412  EBrStatus status : 5; // Status (for 'soSend', 'soFetch')
413  int adr : 8; // TWI address (for 'soSend', 'soFetch')
414  int bytes : 16; // amount of the remaining data (exception: 'soFetch' request, where this is the desired reply bytes)
415 };
416 
417 
421  public:
422 
425 
426  CBrownieLink ();
427  ~CBrownieLink () { Close (); }
428 
429  EBrStatus Open (const char *devName = NULL);
433  EBrStatus Reopen () { TwiOpen (false); return status; }
435  void Close () { ServerStop (); TwiClose (); }
436 
437  const char *IfName () { return twiIfName.Get (); }
439  ETwiIfType IfType () { return twiIfType; }
441 
445 
446  TBrRequest *Request () { return &request; }
447  TBrReply *Reply () { return &reply; }
448  EBrStatus Status () { return status; }
449 
458 
459  void ClearBus ();
461  void Flush (int adr);
463 
464  EBrStatus SendRequest (int adr, bool noResend = false);
474 
475  EBrStatus FetchReply (int adr, bool noResend = false);
488 
489  EBrStatus Communicate (int adr, bool noResend = false);
498 
502 
503  EBrStatus CheckDevice (int adr, CBrownie *brownie = NULL);
509 
510  EBrStatus RegRead (int adr, uint8_t reg, uint8_t *retVal, bool noResend = false);
511  EBrStatus RegRead (CBrownie *brownie, uint8_t reg, uint8_t *retVal, bool noResend = false) { return RegRead (brownie->Adr (), reg, retVal, noResend); }
513  uint8_t RegReadNext (EBrStatus *status, int adr, uint8_t reg, bool noResend = false);
514  uint8_t RegReadNext (EBrStatus *status, CBrownie *brownie, uint8_t reg, bool noResend = false) { return RegReadNext (status, brownie->Adr (), reg, noResend); }
521  EBrStatus RegWrite (int adr, uint8_t reg, uint8_t val, bool noResend = false);
522  EBrStatus RegWrite (CBrownie *brownie, uint8_t reg, uint8_t val, bool noResend = false) { return RegWrite (brownie->Adr (), reg, val, noResend); }
524  void RegWriteNext (EBrStatus *status, int adr, uint8_t reg, uint8_t val, bool noResend = false);
525  void RegWriteNext (EBrStatus *status, CBrownie *brownie, uint8_t reg, uint8_t val, bool noResend = false) { return RegWriteNext (status, brownie->Adr (), reg, val, noResend); }
527 
528  EBrStatus MemRead (int adr, unsigned memAdr, int bytes, uint8_t *retData, bool printProgress = false);
530  EBrStatus MemWrite (int adr, unsigned memAdr, int bytes, uint8_t *data, bool printProgress = false);
532 
536 
537  void StatisticsReset (bool local = false);
542  const char *StatisticsStr (CString *ret, bool local = false);
548  void StatisticsAddIterateTimes (TTicks tCycle, TTicks tFastPoll, TTicks tSlowPoll);
550 
554 
555  bool ServerStart ();
561  void ServerStop ();
563  bool ServerIterate (TTicks maxSleepTime = -1);
571 
573 
574  protected:
575  void TwiOpen (bool warn);
576  void TwiClose ();
577  EBrStatus TwiSetAdr (int _twiAdr); // Helper for TwiSend() and TwiFetch()
578  EBrStatus TwiSend (int adr, const void *buf, int bytes);
579  EBrStatus TwiFetch (int adr, void *buf, int bytes);
580 
581  CString twiIfName;
582  ETwiIfType twiIfType;
583  int twiFd, twiAdr;
584 
585  TBrRequest request;
586  TBrReply reply;
587  EBrStatus status;
588 
589  // Statistics ...
590  TTicks tLastStatisticsReset;
591  int requests, requestRetries[brEND], requestFailures[brEND];
592  int replies, replyRetries[brEND], replyFailures[brEND];
593 
594  int rcIterations;
595  TTicks rcTSumCycle, rcTSumFastPoll, rcTSumSlowPoll;
596  TTicks rcTCycleMin, rcTCycleMax, rcTFastPollMin, rcTFastPollMax, rcTSlowPollMin, rcTSlowPollMax;
597 
598  // Socket server ...
599  int sockListenFd; // listening socket (or <0, if none activated)
600  int sockClientFd; // currently connected socket client (or <0, if none is connected)
601  TSocketHeader sockHead; // buffer for received header
602  uint8_t *sockData; // buffer for received data
603  size_t sockRxBytes; // number of received bytes (header + data)
604 };
605 
606 
607 
610 
611 
612 #endif // _BROWNIES_
Set of Brownies
Definition: brownies.H:299
void Del(int adr)
Delete database entry.
void ResourcesInit(CRcEventDriver *_rcDriver, class CBrownieLink *_rcLink)
Register all resources and assign a driver and link to the Brownie set.
void ResourcesDone()
Forget about the driver / link and clean up all resources-related data.
void ResourcesIterate(bool noLink=false, bool noSleep=false)
Query Brownies and report any pending resource changes.
bool WriteDatabase(const char *fileName=NULL)
Write the set as a database file.
CBrownie * Unlink(int adr)
Forget brownie and return it (caller becomes owner of CBrownie object).
void Set(CBrownie *brownie)
Add/Change brownie (takes ownership of CBrownie object).
CBrownie * Get(int adr)
Get a reference to the brownie for reading. To modify a brownie object, it must be first removed and ...
Definition: brownies.H:311
bool ReadDatabase(const char *fileName=NULL)
Read a database file.
Representation of a Brownie device.
Definition: brownies.H:167
bool IsCompatible(const char *_databaseString)
Check if the current object, typically read back from a device, is compatible to the passed database ...
bool IsValid()
Data is generally valid.
Definition: brownies.H:213
bool UpdateFromDevice(class CBrownieLink *link)
Read out device, check for compatibility, and update the feature record and config record on success.
bool HasDeviceConfig()
Config record is valid and comes from the device.
Definition: brownies.H:220
int Adr()
Get the TWI address of the Brownie.
Definition: brownies.H:197
const char * DatabaseString()
Get options set in the database file as a string.
Definition: brownies.H:206
bool HasDeviceFeatures()
Feature record is valid and comes from the device.
Definition: brownies.H:218
const char * Id()
Get the ID record (a null-terminated string).
Definition: brownies.H:199
bool HasFeatures()
Feature record appears to be valid (either set from database or from device).
Definition: brownies.H:215
bool SetFromStr(const char *str, CString *ret=NULL)
Set fields in the feature record or config record according to a text line in database string syntax.
const char * ToStr(CString *ret, bool withIdentification=true, bool withVersionInfo=true)
Return the contents of the feature record and the config record as a string in the database syntax.
TBrConfigRecord * ConfigRecord()
Get the config record.
Definition: brownies.H:203
TBrFeatureRecord * FeatureRecord()
Get the feature record.
Definition: brownies.H:201
Driver for local resources.
Definition: resources.H:2433
Local driver using the event processor mechanism for the 'DriveValue()' functionality.
Definition: resources.H:2549
Typed value tagged with a state and a time stamp.
Definition: resources.H:485
Home2L Resource.
Definition: resources.H:895
Dynamically allocated string.
Definition: base.H:635
char * Get() const
Get the C string. Unless explicitely set by 'SetC', this will never return NULL or an invalid pointer...
Definition: base.H:687
#define BR_MAGIC
Magic byte value to identify this device as a brownie.
Definition: interface.h:321
char TBrIdRecord[32]
Brownie ID (stored in EEPROM).
Definition: interface.h:423
EBrStatus
Definition: interface.h:121
const char * envBrDatabaseFile
Name of the selected database file (read-only).
const char * envBrLinkDev
Name of the selected link device (read-only).
uint32_t BrVersionGet(TBrFeatureRecord *featureRecord)
Retrieve version from feature record.
static const char * BrVersionGetAsStr(CString *ret, TBrFeatureRecord *featureRecord)
Get a readable string of the version fields of the feature record. The result is written to '*ret' an...
Definition: brownies.H:146
bool BrFeaturesFromStr(TBrFeatureRecord *featureRecord, const char *str)
Set the feature-related fields of the feature record according to the given string.
int BrMcuFromStr(const char *mcuStr)
Get the MCU model ID (see BR_MCU_* macros) from a string (for example, "t84"). On error,...
const char * BrFeaturesToStr(CString *ret, TBrFeatureRecord *featureRecord)
Get a readable string of the feature-related fields of the feature record. The result is written to '...
const char * BrMcuStr(int mcuType, const char *unknown=NULL)
Get a readable string (for example, "t84") for an MCU model ID (see BR_MCU_* macros)....
bool BrVersionFromStr(TBrFeatureRecord *featureRecord, const char *str)
Set the version fields of the feature record according to the given version string.
ETwiIfType
Brownie link interface type.
Definition: brownies.H:388
const char * BrStatusStr(EBrStatus s)
Get a readable string for Brownie status codes.
@ ifSocket
Unix domain socket (to connect to already running Brownie driver instance on the local machine)
Definition: brownies.H:390
@ ifElvI2c
ELV USB-i2c.
Definition: brownies.H:392
@ ifNone
(None)
Definition: brownies.H:389
@ ifI2cDev
Linux i2c dev.
Definition: brownies.H:391
int64_t TTicks
Time value (relative, absolute, or monotonic).
Definition: base.H:1376
const char * VersionToStr(class CString *ret, uint32_t ver)
Get a string representation of the version. This may be shorter than an eventual original string pass...
Brownie configuration record (stored in EEPROM).
Definition: interface.h:447
uint8_t adr
Own TWI address.
Definition: interface.h:448
uint8_t magic
Identify as a Brownie (should always be BR_MAGIC)
Definition: interface.h:449
Brownie feature record (stored in VROM).
Definition: interface.h:332
uint8_t magic
Brownie identification (always = BR_MAGIC)
Definition: interface.h:358
uint16_t gpiPresence
GPIO input presence mask (must be disjoint with output presence)
Definition: interface.h:342
uint16_t features
Feature presence (see BR_FEATURE_... masks)
Definition: interface.h:340
uint16_t gpoPresence
GPIO output presence mask (must be disjoint with input presence)
Definition: interface.h:344
Reply message.
Definition: interface.h:160
Request message.
Definition: interface.h:140