Home2L - C/C++ API v1.4-0-g38cc (2024-05-25)
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-2024 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
29extern "C" {
30#include "avr/interface.h"
31}
32
33
81// *************************** Basics ******************************************
82
83
84#define BR_CONF_DEFAULT_NAME "brownies.conf"
85
86
87extern const char *envBrDatabaseFile;
88extern const char *envBrLinkDev;
89
90
91const char *BrStatusStr (EBrStatus s);
93
94const char *BrMcuStr (int mcuType, const char *unknown = NULL);
97int BrMcuFromStr (const char *mcuStr);
100
101
102
103
104
105// ***************** Brownie Feature and Config Records ************************
106
107
108// ***** Configuration item descriptor *****
109
110
112typedef 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
127struct 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
137extern const TBrCfgDescriptor brCfgDescList[];
138extern const int brCfgDescs;
139
140
141
142// ***** Feature record to/from string *****
143
144uint32_t BrVersionGet (TBrFeatureRecord *featureRecord);
146static inline const char *BrVersionGetAsStr (CString *ret, TBrFeatureRecord *featureRecord) { return VersionToStr (ret, BrVersionGet (featureRecord)); }
149bool BrVersionFromStr (TBrFeatureRecord *featureRecord, const char *str);
151
152const char *BrFeaturesToStr (CString *ret, TBrFeatureRecord *featureRecord);
155bool BrFeaturesFromStr (TBrFeatureRecord *featureRecord, const char *str);
157
158
159
160
161
162// *************************** CBrownie ****************************************
163
164
167class 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
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);
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
388typedef enum {
389 ifNone = 0,
393 ifEND
394} ETwiIfType;
395
396
397const char *TwiIfTypeStr (ETwiIfType type);
398
399
401enum 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
410struct 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 * 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
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).
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 ...
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
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
bool HasDeviceFeatures()
Feature record is valid and comes from the device.
Definition: brownies.H:218
bool HasFeatures()
Feature record appears to be valid (either set from database or from device).
Definition: brownies.H:215
const char * Id()
Get the ID record (a null-terminated string).
Definition: brownies.H:199
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 * DatabaseString()
Get options set in the database file as a string.
Definition: brownies.H:206
TBrFeatureRecord * FeatureRecord()
Get the feature record.
Definition: brownies.H:201
Driver for local resources.
Definition: resources.H:2460
Local driver using the event processor mechanism for the 'DriveValue()' functionality.
Definition: resources.H:2576
Typed value tagged with a state and a time stamp.
Definition: resources.H:488
Home2L Resource.
Definition: resources.H:909
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).
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
const char * envBrLinkDev
Name of the selected link device (read-only).
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)....
uint32_t BrVersionGet(TBrFeatureRecord *featureRecord)
Retrieve version from feature record.
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 * BrStatusStr(EBrStatus s)
Get a readable string for Brownie status codes.
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
@ 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:1378
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