Added constructors for TLV8 and DATA Characteristics

Conformed all CUSTOM_CHAR macros to allow for these constructors
This commit is contained in:
Gregg 2024-06-29 10:03:07 -05:00
parent 1b93c7e75b
commit 3ed18b3f79
7 changed files with 92 additions and 79 deletions

View File

@ -55,17 +55,6 @@ enum FORMAT { // HAP Table 6-5
/////////////////////////////// ///////////////////////////////
typedef boolean BOOL_t;
typedef uint8_t UINT8_t;
typedef uint16_t UINT16_t;
typedef uint32_t UINT32_t;
typedef uint64_t UINT64_t;
typedef int32_t INT_t;
typedef double FLOAT_t;
typedef char * STRING_t;
///////////////////////////////
struct HapChar { struct HapChar {
const char *type; const char *type;
const char *hapName; const char *hapName;

View File

@ -1867,14 +1867,29 @@ void SpanCharacteristic::uvSet(UVal &dest, UVal &src){
/////////////////////////////// ///////////////////////////////
void SpanCharacteristic::uvSet(UVal &u, const char *val){ void SpanCharacteristic::uvSet(UVal &u, STRING_t val){
u.STRING = (char *)HS_REALLOC(u.STRING, strlen(val) + 1); u.STRING = (char *)HS_REALLOC(u.STRING, strlen(val) + 1);
strcpy(u.STRING, val); strcpy(u.STRING, val);
} }
/////////////////////////////// ///////////////////////////////
void SpanCharacteristic::uvSet(UVal &u, const TLV8 &tlv){ void SpanCharacteristic::uvSet(UVal &u, DATA_t data){
if(data.second>0){
size_t olen;
mbedtls_base64_encode(NULL,0,&olen,NULL,data.second); // get length of string buffer needed (mbedtls includes the trailing null in this size)
value.STRING = (char *)HS_REALLOC(value.STRING,olen); // allocate sufficient size for storing value
mbedtls_base64_encode((uint8_t*)value.STRING,olen,&olen,data.first,data.second ); // encode data into string buf
} else {
value.STRING = (char *)HS_REALLOC(value.STRING,1); // allocate sufficient size for just trailing null character
*value.STRING ='\0';
}
}
///////////////////////////////
void SpanCharacteristic::uvSet(UVal &u, TLV_ENC_t tlv){
const size_t bufSize=36; // maximum size of buffer to store packed TLV bytes before encoding directly into value; must be multiple of 3 const size_t bufSize=36; // maximum size of buffer to store packed TLV bytes before encoding directly into value; must be multiple of 3
size_t nBytes=tlv.pack_size(); // total size of packed TLV in bytes size_t nBytes=tlv.pack_size(); // total size of packed TLV in bytes
@ -1941,17 +1956,7 @@ size_t SpanCharacteristic::getDataGeneric(uint8_t *data, size_t len, UVal &val){
void SpanCharacteristic::setData(uint8_t *data, size_t len, boolean notify){ void SpanCharacteristic::setData(uint8_t *data, size_t len, boolean notify){
setValCheck(); setValCheck();
uvSet(value,{data,len});
if(len>0){
size_t olen;
mbedtls_base64_encode(NULL,0,&olen,NULL,len); // get length of string buffer needed (mbedtls includes the trailing null in this size)
value.STRING = (char *)HS_REALLOC(value.STRING,olen); // allocate sufficient size for storing value
mbedtls_base64_encode((uint8_t*)value.STRING,olen,&olen,data,len ); // encode data into string buf
} else {
value.STRING = (char *)HS_REALLOC(value.STRING,1); // allocate sufficient size for just trailing null character
*value.STRING ='\0';
}
setValFinish(notify); setValFinish(notify);
} }

View File

@ -71,6 +71,20 @@ enum {
GET_STATUS=256 GET_STATUS=256
}; };
typedef boolean BOOL_t;
typedef uint8_t UINT8_t;
typedef uint16_t UINT16_t;
typedef uint32_t UINT32_t;
typedef uint64_t UINT64_t;
typedef int32_t INT_t;
typedef double FLOAT_t;
typedef const char * STRING_t;
typedef const TLV8 & TLV_ENC_t;
typedef std::pair<const uint8_t *, size_t> DATA_t;
static DATA_t NULL_DATA={NULL,0};
static TLV8 NULL_TLV{};
/////////////////////////////// ///////////////////////////////
#define STATUS_UPDATE(LED_UPDATE,MESSAGE_UPDATE) {homeSpan.statusLED->LED_UPDATE;if(homeSpan.statusCallback)homeSpan.statusCallback(MESSAGE_UPDATE);} #define STATUS_UPDATE(LED_UPDATE,MESSAGE_UPDATE) {homeSpan.statusLED->LED_UPDATE;if(homeSpan.statusCallback)homeSpan.statusCallback(MESSAGE_UPDATE);}
@ -485,14 +499,14 @@ class SpanCharacteristic{
friend class SpanService; friend class SpanService;
union UVal { union UVal {
BOOL_t BOOL; boolean BOOL;
UINT8_t UINT8; uint8_t UINT8;
UINT16_t UINT16; uint16_t UINT16;
UINT32_t UINT32; uint32_t UINT32;
UINT64_t UINT64; uint64_t UINT64;
INT_t INT; int32_t INT;
FLOAT_t FLOAT; double FLOAT;
STRING_t STRING = NULL; char * STRING = NULL;
}; };
class EVLIST : public vector<HAPClient *, Mallocator<HAPClient *>>{ // vector of current connections that have subscribed to EV notifications for this Characteristic class EVLIST : public vector<HAPClient *, Mallocator<HAPClient *>>{ // vector of current connections that have subscribed to EV notifications for this Characteristic
@ -534,8 +548,9 @@ class SpanCharacteristic{
String uvPrint(UVal &u); // returns "printable" String for any type of Characteristic String uvPrint(UVal &u); // returns "printable" String for any type of Characteristic
void uvSet(UVal &dest, UVal &src); // copies UVal src into UVal dest void uvSet(UVal &dest, UVal &src); // copies UVal src into UVal dest
void uvSet(UVal &u, const char *val); // copies string val into UVal u void uvSet(UVal &u, STRING_t val); // copies string val into UVal u
void uvSet(UVal &u, const TLV8 &tlv); // copies TLV8 val into UVal u (after transforming to a char *) void uvSet(UVal &u, DATA_t data); // copies DATA data into UVal u (after transforming to a char *)
void uvSet(UVal &u, TLV_ENC_t tlv); // copies TLV8 tlv into UVal u (after transforming to a char *)
template <typename T> void uvSet(UVal &u, T val){ // copies numeric val into UVal u template <typename T> void uvSet(UVal &u, T val){ // copies numeric val into UVal u
switch(format){ switch(format){

View File

@ -513,7 +513,7 @@ namespace Characteristic {
CREATE_CHAR(double,CurrentRelativeHumidity,0,0,100); // current humidity measured as a percentage CREATE_CHAR(double,CurrentRelativeHumidity,0,0,100); // current humidity measured as a percentage
CREATE_CHAR(double,CurrentTemperature,0,0,100); // current temperature measured in Celsius CREATE_CHAR(double,CurrentTemperature,0,0,100); // current temperature measured in Celsius
CREATE_CHAR(int,CurrentTiltAngle,0,-90,90); // current angle (in degrees) of slats from fully up or left (-90) to fully open (0) to fully down or right (90) CREATE_CHAR(int,CurrentTiltAngle,0,-90,90); // current angle (in degrees) of slats from fully up or left (-90) to fully open (0) to fully down or right (90)
CREATE_CHAR(const TLV8 &,DisplayOrder,TLV8::NULL_TLV,TLV8::NULL_TLV,TLV8::NULL_TLV); // specifies the order in which the TV inputs are displayed for selection in the Home App CREATE_CHAR(const TLV8 &,DisplayOrder,NULL_TLV,NULL_TLV,NULL_TLV); // specifies the order in which the TV inputs are displayed for selection in the Home App
CREATE_CHAR(double,FilterLifeLevel,100,0,100); // measured as a percentage of remaining life CREATE_CHAR(double,FilterLifeLevel,100,0,100); // measured as a percentage of remaining life
CREATE_CHAR(uint8_t,FilterChangeIndication,0,0,1,NO_CHANGE_NEEDED,CHANGE_NEEDED); // indicates state of filter CREATE_CHAR(uint8_t,FilterChangeIndication,0,0,1,NO_CHANGE_NEEDED,CHANGE_NEEDED); // indicates state of filter
CREATE_CHAR(const char *,FirmwareRevision,"1.0.0",NULL,NULL); // must be in form x[.y[.z]] - informational only CREATE_CHAR(const char *,FirmwareRevision,"1.0.0",NULL,NULL); // must be in form x[.y[.z]] - informational only
@ -607,46 +607,25 @@ namespace Characteristic {
#define CUSTOM_CHAR(NAME,UUID,PERMISISONS,FORMAT,DEFVAL,MINVAL,MAXVAL,STATIC_RANGE) \ #define CUSTOM_CHAR(NAME,UUID,PERMISISONS,FORMAT,DEFVAL,MINVAL,MAXVAL,STATIC_RANGE) \
HapChar _CUSTOM_##NAME {#UUID,#NAME,(PERMS)(PERMISISONS),FORMAT,STATIC_RANGE}; \ HapChar _CUSTOM_##NAME {#UUID,#NAME,(PERMS)(PERMISISONS),FORMAT,STATIC_RANGE}; \
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(FORMAT##_t val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore,(FORMAT##_t)MINVAL,(FORMAT##_t)MAXVAL); } }; } namespace Characteristic { struct NAME : SpanCharacteristic { NAME(FORMAT##_t val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init<FORMAT##_t>(val,nvsStore,MINVAL,MAXVAL); } }; }
#define CUSTOM_CHAR_STRING(NAME,UUID,PERMISISONS,DEFVAL) \
HapChar _CUSTOM_##NAME {#UUID,#NAME,(PERMS)(PERMISISONS),STRING,true}; \
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(const char * val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore); } }; }
#define CUSTOM_CHAR_DATA(NAME,UUID,PERMISISONS) \
HapChar _CUSTOM_##NAME {#UUID,#NAME,(PERMS)(PERMISISONS),DATA,true}; \
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(const char * val="", boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore); } }; }
#define CUSTOM_CHAR_TLV8(NAME,UUID,PERMISISONS) \
HapChar _CUSTOM_##NAME {#UUID,#NAME,(PERMS)(PERMISISONS),TLV_ENC,true}; \
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(const char * val="", boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore); } }; }
#else #else
#define CUSTOM_CHAR(NAME,UUID,PERMISISONS,FORMAT,DEFVAL,MINVAL,MAXVAL,STATIC_RANGE) \ #define CUSTOM_CHAR(NAME,UUID,PERMISISONS,FORMAT,DEFVAL,MINVAL,MAXVAL,STATIC_RANGE) \
extern HapChar _CUSTOM_##NAME; \ extern HapChar _CUSTOM_##NAME; \
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(FORMAT##_t val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore,(FORMAT##_t)MINVAL,(FORMAT##_t)MAXVAL); } }; } namespace Characteristic { struct NAME : SpanCharacteristic { NAME(FORMAT##_t val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init<FORMAT##_t>(val,nvsStore,MINVAL,MAXVAL); } }; }
#define CUSTOM_CHAR_STRING(NAME,UUID,PERMISISONS,DEFVAL) \ #endif
extern HapChar _CUSTOM_##NAME; \
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(const char * val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore); } }; }
#define CUSTOM_CHAR_DATA(NAME,UUID,PERMISISONS) \ #define CUSTOM_CHAR_STRING(NAME,UUID,PERMISISONS,DEFVAL) CUSTOM_CHAR(NAME,UUID,PERMISISONS,STRING,DEFVAL,NULL,NULL,true);
extern HapChar _CUSTOM_##NAME; \ #define CUSTOM_CHAR_TLV8(NAME,UUID,PERMISISONS) CUSTOM_CHAR(NAME,UUID,PERMISISONS,TLV_ENC,NULL_TLV,NULL_TLV,NULL_TLV,true);
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(const char * val="", boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore); } }; } #define CUSTOM_CHAR_DATA(NAME,UUID,PERMISISONS) CUSTOM_CHAR(NAME,UUID,PERMISISONS,DATA,NULL_DATA,NULL_DATA,NULL_DATA,true);
#define CUSTOM_CHAR_TLV8(NAME,UUID,PERMISISONS) \
extern HapChar _CUSTOM_##NAME; \
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(const char * val="", boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore); } }; }
#endif
#define CUSTOM_SERV(NAME,UUID) \ #define CUSTOM_SERV(NAME,UUID) \
namespace Service { struct NAME : SpanService { NAME() : SpanService{#UUID,#NAME,true}{} }; } namespace Service { struct NAME : SpanService { NAME() : SpanService{#UUID,#NAME,true}{} }; }
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
// MACROS TO ADD A NEW ACCESSORT WITH OPTIONAL NAME // // MACROS TO ADD A NEW ACCESSORY WITH OPTIONAL NAME //
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
#define SPAN_ACCESSORY(...) new SpanAccessory(); new Service::AccessoryInformation(); new Characteristic::Identify(); __VA_OPT__(new Characteristic::Name(__VA_ARGS__)); #define SPAN_ACCESSORY(...) new SpanAccessory(); new Service::AccessoryInformation(); new Characteristic::Identify(); __VA_OPT__(new Characteristic::Name(__VA_ARGS__));

View File

@ -68,7 +68,7 @@ void tlv8_t::osprint(std::ostream& os) const {
///////////////////////////////////// /////////////////////////////////////
TLV8_it TLV8::add(uint8_t tag, size_t len, const uint8_t* val){ TLV8_itc TLV8::add(uint8_t tag, size_t len, const uint8_t* val) {
if(!empty() && back().getTag()==tag) if(!empty() && back().getTag()==tag)
back().update(len,val); back().update(len,val);
@ -80,7 +80,7 @@ TLV8_it TLV8::add(uint8_t tag, size_t len, const uint8_t* val){
///////////////////////////////////// /////////////////////////////////////
TLV8_it TLV8::add(uint8_t tag, TLV8 &subTLV){ TLV8_itc TLV8::add(uint8_t tag, TLV8 &subTLV){
auto it=add(tag,subTLV.pack_size(),NULL); // create space for inserting sub TLV and store iterator to new element auto it=add(tag,subTLV.pack_size(),NULL); // create space for inserting sub TLV and store iterator to new element
subTLV.pack(*it); // pack subTLV into new element subTLV.pack(*it); // pack subTLV into new element
@ -89,7 +89,7 @@ TLV8_it TLV8::add(uint8_t tag, TLV8 &subTLV){
///////////////////////////////////// /////////////////////////////////////
TLV8_it TLV8::add(uint8_t tag, uint64_t val){ TLV8_itc TLV8::add(uint8_t tag, uint64_t val){
uint8_t *p=reinterpret_cast<uint8_t *>(&val); uint8_t *p=reinterpret_cast<uint8_t *>(&val);
size_t nBytes=sizeof(uint64_t); size_t nBytes=sizeof(uint64_t);
@ -227,7 +227,7 @@ int TLV8::unpack(uint8_t *buf, size_t bufSize){
///////////////////////////////////// /////////////////////////////////////
int TLV8::unpack(TLV8_it it){ int TLV8::unpack(TLV8_itc it){
if(it==end()) if(it==end())
return(0); return(0);
@ -297,5 +297,3 @@ void TLV8::osprint(std::ostream& os, TLV8_itc it1, TLV8_itc it2) const {
} }
////////////////////////////////////// //////////////////////////////////////
TLV8 TLV8::NULL_TLV;

View File

@ -79,7 +79,6 @@ class tlv8_t {
///////////////////////////////////// /////////////////////////////////////
typedef std::list<tlv8_t, Mallocator<tlv8_t>>::iterator TLV8_it;
typedef std::list<tlv8_t, Mallocator<tlv8_t>>::const_iterator TLV8_itc; typedef std::list<tlv8_t, Mallocator<tlv8_t>>::const_iterator TLV8_itc;
typedef struct { const uint8_t tag; const char *name; } TLV8_names; typedef struct { const uint8_t tag; const char *name; } TLV8_names;
@ -108,11 +107,11 @@ class TLV8 : public std::list<tlv8_t, Mallocator<tlv8_t>> {
TLV8(){}; TLV8(){};
TLV8(const TLV8_names *names, int nNames) : names{names}, nNames{nNames} {}; TLV8(const TLV8_names *names, int nNames) : names{names}, nNames{nNames} {};
TLV8_it add(uint8_t tag, size_t len, const uint8_t *val); TLV8_itc add(uint8_t tag, size_t len, const uint8_t *val);
TLV8_it add(uint8_t tag, uint64_t val); TLV8_itc add(uint8_t tag, uint64_t val);
TLV8_it add(uint8_t tag, TLV8 &subTLV); TLV8_itc add(uint8_t tag, TLV8 &subTLV);
TLV8_it add(uint8_t tag){return(add(tag, 0, NULL));} TLV8_itc add(uint8_t tag){return(add(tag, 0, NULL));}
TLV8_it add(uint8_t tag, const char *val){return(add(tag, strlen(val), reinterpret_cast<const uint8_t*>(val)));} TLV8_itc add(uint8_t tag, const char *val){return(add(tag, strlen(val), reinterpret_cast<const uint8_t*>(val)));}
TLV8_itc find(uint8_t tag, TLV8_itc it1, TLV8_itc it2) const; TLV8_itc find(uint8_t tag, TLV8_itc it1, TLV8_itc it2) const;
TLV8_itc find(uint8_t tag, TLV8_itc it1) const {return(find(tag, it1, end()));} TLV8_itc find(uint8_t tag, TLV8_itc it1) const {return(find(tag, it1, end()));}
@ -142,9 +141,7 @@ class TLV8 : public std::list<tlv8_t, Mallocator<tlv8_t>> {
void osprint(std::ostream& os) const {osprint(os, begin(), end());} void osprint(std::ostream& os) const {osprint(os, begin(), end());}
int unpack(uint8_t *buf, size_t bufSize); int unpack(uint8_t *buf, size_t bufSize);
int unpack(TLV8_it it); int unpack(TLV8_itc it);
void wipe(){std::list<tlv8_t, Mallocator<tlv8_t>>().swap(*this);} void wipe() {std::list<tlv8_t, Mallocator<tlv8_t>>().swap(*this);}
static TLV8 NULL_TLV;
}; };

View File

@ -27,6 +27,12 @@
#include "HomeSpan.h" #include "HomeSpan.h"
CUSTOM_CHAR(TestChar,3F4F,PR+PW,UINT8,20,0,100,false)
CUSTOM_CHAR_STRING(TestString,3F45,PR+EV,"Hello");
CUSTOM_CHAR_TLV8(TestTLV,4F45,PW+PR);
CUSTOM_CHAR_DATA(TestData,303,PW+PW);
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
@ -43,7 +49,31 @@ void setup() {
new Characteristic::Identify(); new Characteristic::Identify();
new Service::LightBulb(); new Service::LightBulb();
new Characteristic::On(); new Characteristic::On();
new Characteristic::TestChar(30);
new Characteristic::TestString();
new Characteristic::TestString("MyName");
new Characteristic::TestTLV();
Characteristic::TestData *testData = new Characteristic::TestData();
TLV8 myTLV;
myTLV.add(5,0x20);
myTLV.add(5,0x30);
myTLV.add(1);
myTLV.add(5,255);
Characteristic::TestTLV *testTLV = new Characteristic::TestTLV(myTLV);
size_t n=testTLV->getData(NULL,0);
uint8_t buf[n];
testTLV->getData(buf,n);
Serial.printf("\n");
for(int i=0;i<n;i++)
Serial.printf("%d %0X\n",i,buf[i]);
Serial.printf("\n");
testData->setData(buf,0);
} }