From 2b638b1310656e06f3a04e0137ebd1e552f40ee2 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 19 Aug 2024 22:35:20 +0300 Subject: [PATCH] MQTT->CAN proxy. CRC16 for CAN config --- lighthub/candriver.cpp | 139 ++++++++++++++++++++++++++++------------- lighthub/candriver.h | 14 +++-- lighthub/item.cpp | 40 +++++++++--- lighthub/item.h | 4 +- lighthub/main.cpp | 83 +++++++++++++++++++----- lighthub/utils.cpp | 15 ++++- lighthub/utils.h | 21 +++++++ 7 files changed, 245 insertions(+), 71 deletions(-) diff --git a/lighthub/candriver.cpp b/lighthub/candriver.cpp index f3baea9..2f38da5 100644 --- a/lighthub/candriver.cpp +++ b/lighthub/candriver.cpp @@ -131,15 +131,19 @@ bool canDriver::sendRemoteID(macAddress mac) { canid_t id; //datagram_t packet; - bool res=false; + bool res=false; + id.subjId=0; id.deviceId=getIdByMac(mac); //Retrieved controllerID if (!id.deviceId) return false; + aJsonObject * config=getConfbyID(id.deviceId); + if (config) id.subjId=getCRC(config); //CRC16 of remote config id.reserve=0; id.status=1; //response id.payloadType=payloadType::lookupMAC; - id.subjId=200; //CRC16 of remote config + + debugSerial<<("CAN: Send remote ID")<cmd; ic.param = packet->param; - debugSerial<name; + debugSerial<name<<" "; ic.debugOut(); if (ic.isCommand()) flags |= FLAG_COMMAND; @@ -456,9 +465,17 @@ if (id.status){ case canState::MACLookup: if ((id.payloadType == payloadType::lookupMAC)) { - debugSerial<<"\nCAN: Got Controller addr: "<type == aJson_Int)) return addrObj->valueint; - return 0; } -aJsonObject * canDriver::findConfbyID(uint8_t devId) +aJsonObject * canDriver::getConfbyID(uint8_t devId) { -if (!root) return NULL; -aJsonObject * canObj = aJson.getObjectItem(root, "can"); -if (!canObj) return NULL; - -aJsonObject * remoteConfObj = aJson.getObjectItem(canObj, "conf"); - -if (!remoteConfObj) return NULL; -remoteConfObj=remoteConfObj->child; +if (!canConfigObj) return NULL; +if (!canRemoteConfigObj) return NULL; +aJsonObject * remoteConfObj=canRemoteConfigObj->child; while (remoteConfObj) { aJsonObject * remoteCanObj = aJson.getObjectItem(remoteConfObj, "can"); @@ -564,30 +572,77 @@ while (remoteConfObj) return NULL; } +aJsonObject * canDriver::findConfbyName(char* devName, int * devAddr) +{ +if (!canRemoteConfigObj && !devName) return NULL; +aJsonObject * remoteConfObj=canRemoteConfigObj->child; +while (remoteConfObj) + { + aJsonObject * remoteCanObj = aJson.getObjectItem(remoteConfObj, "can"); + if (remoteCanObj) + { + aJsonObject * nameObj = aJson.getObjectItem(remoteCanObj, "name"); + if (nameObj && (nameObj->type == aJson_String) && nameObj->valuestring && (strncasecmp(nameObj->valuestring,devName,strlen(nameObj->valuestring)) == 0)) + { + if (devAddr) + { + aJsonObject * addrObj = aJson.getObjectItem(remoteCanObj, "addr"); + if (addrObj && (addrObj->type == aJson_Int)) *devAddr=addrObj->valueint; + } + return remoteConfObj; + } + } + remoteConfObj=remoteConfObj->next; + } +return NULL; +} + +#if not defined (NOIP) +extern PubSubClient mqttClient; + +bool canDriver::subscribeTopics(char * root, size_t buflen) +{ + if (!root) return false; + if (!canRemoteConfigObj) return false; + + int rootLen = strlen(root); + +aJsonObject * remoteConfObj=canRemoteConfigObj->child; +while (remoteConfObj) + { + aJsonObject * remoteCanObj = aJson.getObjectItem(remoteConfObj, "can"); + if (remoteCanObj) + { + aJsonObject * addrObj = aJson.getObjectItem(remoteCanObj, "name"); + if (addrObj && (addrObj->type == aJson_String) && addrObj->valuestring) + { + strncpy(root+rootLen, addrObj->valuestring, buflen-rootLen-1); + strncat(root+rootLen, "/", buflen-rootLen-1); + strncat(root+rootLen, "#", buflen-rootLen-1); + debugSerial.println(root); + mqttClient.subscribe(root); + } + } + remoteConfObj=remoteConfObj->next; + } +} +#endif uint8_t canDriver::getIdByMac(macAddress mac) { - char macStr[19]; - uint8_t strptr = 0; +char macStr[19]; +uint8_t strptr = 0; - if (!root) return 0; - aJsonObject * canObj = aJson.getObjectItem(root, "can"); - if (!canObj) return 0; - aJsonObject * confObj = aJson.getObjectItem(canObj, "conf"); - if (!confObj) return 0; - - memset(macStr,0,sizeof(macStr)); - for (byte i = 0; i < 6; i++) -{ - // if (mac[i]<16) macStr[strptr++]='0'; - - SetBytes(&mac[i],1,&macStr[strptr]); - strptr+=2; - - if (i < 5) macStr[strptr++]=':'; -} +if (!canRemoteConfigObj) return 0; +memset(macStr,0,sizeof(macStr)); +for (byte i = 0; i < 6; i++) + { + SetBytes(&mac[i],1,&macStr[strptr]); + strptr+=2; + if (i < 5) macStr[strptr++]=':'; + } debugSerial<child; + if (!itemHandler || itemHandler->type!=aJson_Array) return 0; + aJsonObject * itemIdObj=aJson.getArrayItem(itemHandler,1); + if (itemIdObj->type != aJson_Int) return 0; + + //Retrieve target controller ID + if (!remoteID) return 0; + +//TODO - translate subItem & auth token + short subitemNum = NO_SUBITEM; + return LHCAN.sendCommand(remoteID,itemIdObj->valueint,cmd,false,subitemNum); + #endif + return 0; +} + // Recursive function with small stack consumption // if cmd defined - execute Ctrl for any group members recursively // else performs Activity check for group members and return true if any member is active @@ -1663,7 +1688,7 @@ int Item::isActive() { itemCmd st; int val = 0; - debugSerial<name<name<child),st, getSubitemId(subItem)); + if (!(sendFlags & FLAG_NOT_SEND_CAN)) + LHCAN.sendStatus(getCanNum(itemArr->child),(sendFlags & FLAG_SEND_DELAYED)?st.setSuffix(S_DELAYED):st, getSubitemId(subItem)); #endif if (sendFlags & FLAG_COMMAND) diff --git a/lighthub/item.h b/lighthub/item.h index c3922ed..deeca5a 100644 --- a/lighthub/item.h +++ b/lighthub/item.h @@ -117,8 +117,8 @@ class Item void Stop(); //int Ctrl(short cmd, short n=0, int * Parameters=NULL, int suffixCode=0, char* subItem=NULL); int Ctrl(itemCmd cmd, char* subItem=NULL, bool allowRecursion = true, bool authorized=false); - int Ctrl(char * payload, char * subItem=NULL); - + int Ctrl(char * payload, char * subItem=NULL, int remoteID = 0); + int remoteCtrl(itemCmd cmd, int remoteID, char* subItem=NULL, char * authToken=NULL); int getArg(short n=0); float getFloatArg(short n=0); short getArgCount(); diff --git a/lighthub/main.cpp b/lighthub/main.cpp index bc331e3..b49dfde 100644 --- a/lighthub/main.cpp +++ b/lighthub/main.cpp @@ -434,8 +434,10 @@ void mqttCallback(char *topic, byte *payload, unsigned int length) short pfxlen = 0; char * itemName = NULL; - char * subItem = NULL; char savedTopic[MQTT_TOPIC_LENGTH] = ""; + bool forLocal=false; + aJsonObject * remoteConfig = NULL; + int remoteID=0; // in Retaining status - trying to restore previous state from retained output topic. Retained input topics are not relevant. if (lanStatus == RETAINING_COLLECTING) @@ -455,17 +457,39 @@ if (lanStatus == RETAINING_COLLECTING) } return; } + else forLocal = true; } else { pfxlen=inTopic(topic,T_DEV); if (!pfxlen) pfxlen = inTopic(topic,T_BCST); else // Personal device topic - strncpy(savedTopic,topic,sizeof(savedTopic)-1); + strncpy(savedTopic,topic,sizeof(savedTopic)-1); //Save topic to delete after exec + + if (pfxlen) forLocal=true; + + #ifdef CANDRV + else //Nor local or bcst name, try can names + { + pfxlen=inTopic(topic,T_ROOT); //check root + if (pfxlen) + { + remoteConfig = LHCAN.findConfbyName(topic+pfxlen,&remoteID); + if (remoteConfig) + { + while(*(topic+pfxlen) && *(topic+pfxlen)!='/') pfxlen++; //skip controller name + if (*(topic+pfxlen)=='/') pfxlen++; + debugSerial<1)) { mqttClient.deleteTopic(topic); - cmd_parse((char *)payload); + if (forLocal)((char *)payload); + //TODO implement for remote return;// -4; } //if (itemName[0]=='$') return;// -6; //Skipping homie stuff if (strrchr(topic,'$')) return; - Item item(itemName); + +/* + Item item(itemName); if (item.isValid() && (item.Ctrl((char *)payload)>0) && savedTopic[0] && lanStatus != RETAINING_COLLECTING) //if (lanStatus != RETAINING_COLLECTING && (mqttClient.isRetained())) @@ -487,7 +514,36 @@ else debugSerial<0) succeeded = true; + } + } + + #ifdef CANDRV + if (remoteConfig) + { + aJsonObject * remoteItems = aJson.getObjectItem(remoteConfig,"items"); + if (remoteItems) + { + Item remoteItem(itemName,remoteItems); + if (remoteItem.Ctrl((char *)payload,NULL,remoteID)>0) succeeded = true; + } + } + #endif + +if (succeeded && savedTopic[0] && lanStatus != RETAINING_COLLECTING) +{ + debugSerial<type == aJson_String) strncat(buf,_l2->valuestring,buflen); strncat_P(buf,inTopic,buflen); ///// break; } -strncat(buf,"/",buflen); -if (suffix) strncat(buf,suffix,buflen); +if (tt!=T_ROOT) +{ + strncat(buf,"/",buflen); + if (suffix) strncat(buf,suffix,buflen); +} return buf; } @@ -975,6 +978,14 @@ return true; +uint16_t getCRC(aJsonObject * in) +{ +if (!in) return 0; +CRCStream crcStream; +aJsonStream aJsonCrcStream = aJsonStream(&crcStream); +aJson.print(in,&aJsonCrcStream); +return crcStream.getCRC16(); +} #pragma message(VAR_NAME_VALUE(debugSerial)) #pragma message(VAR_NAME_VALUE(SERIAL_BAUD)) diff --git a/lighthub/utils.h b/lighthub/utils.h index 91a86e8..8a55cc2 100644 --- a/lighthub/utils.h +++ b/lighthub/utils.h @@ -38,6 +38,7 @@ using namespace ios; #endif enum topicType { + T_ROOT = 4, T_DEV = 1, T_BCST= 2, T_OUT = 3 @@ -80,4 +81,24 @@ int str2regSize(char * str); bool checkToken(char * token, char * data); bool isProtectedPin(short pin); bool i2cReset(); + uint16_t getCRC(aJsonObject * in); + +#include "util/crc16_.h" +class CRCStream : public Stream +{ +public: + CRCStream() : CRC16(0xFFFF){} + uint16_t CRC16; + uint16_t getCRC16() {return CRC16;} + // Stream methods + virtual int available(){return 0;}; + virtual int read(){return 0;}; + virtual int peek(){return 0;}; + + virtual void flush(){}; + // Print methods + virtual size_t write(uint8_t c) {CRC16 = crc16_update(CRC16, c);}; + virtual int availableForWrite(){return 1;}; + +};