14 Commits

Author SHA1 Message Date
fae1bd4dcc pre-rel bins 2024-08-23 18:59:58 +03:00
e5e24943a6 critical relability fix 2024-08-23 18:35:39 +03:00
f672878873 pre-release-binaries 2024-08-23 00:30:59 +03:00
ff8997fb02 post-refactoring fixes: $command, Items-Parse 2024-08-23 00:12:12 +03:00
96a9c59add nrf bin 2024-08-22 00:56:21 +03:00
7759d51b31 Cross comp & binaries 2024-08-22 00:55:31 +03:00
e21541aa7a cleanup and odd cleanConf fix 2024-08-22 00:35:47 +03:00
806e99eb92 NO-IP devices persistence
STM Flash cfg fix
 CAN GROUP chan fix
 CRC16 fix
2024-08-21 14:01:06 +03:00
2b638b1310 MQTT->CAN proxy. CRC16 for CAN config 2024-08-19 22:35:20 +03:00
82f729216e mapping constrain fix & more mbus relability 2024-08-16 21:41:13 +03:00
dc6e310b10 MBUS fix for requrent def# reg less main reg
Now it can working for empty action for def# reg
2024-08-15 00:36:14 +03:00
baad75fde7 bins 2024-08-14 20:04:11 +03:00
7040d9bf93 MBUS no write if prefetched value == target
Removed constrain 255 for mapping
2024-08-14 19:43:24 +03:00
0a4e70479b Modbus attempts counter reset & silence timer fix 2024-08-14 00:00:22 +03:00
31 changed files with 54373 additions and 53950 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
#!/bin/sh
../tools/mac/arduinoOTA -address 192.168.11.10 -port 80 -username arduino -password password -sketch firmware.bin -b -upload /sketch

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1 @@
../tools/mac/tool-avrdude/avrdude -C ../tools/mac/tool-avrdude/avrdude.conf -P net:192.168.88.2:23000 -v -V -patmega2560 -cwiring -b115200 -D -Uflash:w:firmware.hex:i
avrdude -P net:192.168.88.2:23000 -v -V -patmega2560 -cwiring -b115200 -D -Uflash:w:firmware.hex:i

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -132,14 +132,18 @@ bool canDriver::sendRemoteID(macAddress mac)
canid_t id;
//datagram_t packet;
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")<<endl;
res = write (id.id,(datagram_t*)mac,6);
@@ -152,7 +156,21 @@ return res;
bool canDriver::begin()
{
if (root)
{
canConfigObj = aJson.getObjectItem(root, "can");
if (canConfigObj)
{
canRemoteConfigObj= aJson.getObjectItem(canConfigObj, "conf");
controllerId = getMyId();
}
confCRC=getCRC(root);
}
#ifndef NOIP
if (!canConfigObj) return false;
#endif
if (!ready) // not reInitialization
{
@@ -304,8 +322,8 @@ switch (state)
if (CANConfStream.peek() == '{') {
debugSerial<<F("CAN: JSON detected")<<endl;
cleanConf(1);
aJsonStream as = aJsonStream(&CANConfStream);
cleanConf(false);
root = aJson.parse(&as);
CANConfStream.close();
if (!root) {
@@ -318,7 +336,9 @@ switch (state)
}
infoSerial<<F("CAN: config Loaded")<<endl;
configLocked--;
applyConfig();
cmdFunctionSave(0,NULL);
if (applyConfig()) ;
// debugSerial.print(aJson.print(root,false));
sysConf.loadETAG();
state = canState::Idle;
return ;
@@ -419,7 +439,7 @@ if (id.status){
case payloadType::itemCommand:
{
if (len!=8) return false;
aJsonObject *confObj = findConfbyID(id.deviceId);
aJsonObject *confObj = getConfbyID(id.deviceId);
if (confObj)
{
debugSerial<<F("CAN: status received for dev ")<<id.deviceId<<endl;
@@ -434,13 +454,15 @@ if (id.status){
ic.cmd = packet->cmd;
ic.param = packet->param;
debugSerial<<F("CAN: item ")<<it.itemArr->name;
debugSerial<<F("CAN: item ")<<it.itemArr->name<<" ";
ic.debugOut();
if (ic.isCommand()) flags |= FLAG_COMMAND;
if (ic.isValue()) flags |= FLAG_PARAMETERS;
if (ic.getSuffix()==S_DELAYED) flags |= FLAG_SEND_DELAYED;
else if (ic.isCommand()) flags |= FLAG_COMMAND;
ic.saveItem(&it,flags);
it.SendStatusImmediate(ic,flags | FLAG_NOT_SEND_CAN,it.getSubItemStrById(id.subItemId));
it.SendStatusImmediate(ic,flags | FLAG_NOT_SEND_CAN, it.getSubItemStrById(id.subItemId));
return true;
}
@@ -456,9 +478,17 @@ if (id.status){
case canState::MACLookup:
if ((id.payloadType == payloadType::lookupMAC))
{
debugSerial<<"\nCAN: Got Controller addr: "<<id.deviceId<<endl;
controllerId=id.deviceId;
if (root && (id.subjId == confCRC)) ///?
{
infoSerial << (F("Valid config already onboard")) << endl;
state = canState::Idle;
}
else
{
infoSerial<<"\nCAN: Got Controller addr: "<<id.deviceId<<endl;
state = canState::ReadConfig;
controllerId=id.deviceId;
}
}
return true;
@@ -511,7 +541,7 @@ else //Requests
else if ((id.payloadType == payloadType::configFrame) && (id.subjId == 0xFFFF))
{
debugSerial<<F("CAN: Requested conf for dev#")<<id.deviceId<<endl;
aJsonObject * remoteConfObj = findConfbyID(id.deviceId);
aJsonObject * remoteConfObj = getConfbyID(id.deviceId);
if (remoteConfObj)
{
infoSerial<<F("CAN: Sending conf for dev#")<<id.deviceId<<endl;
@@ -531,26 +561,17 @@ return false;
uint8_t canDriver::getMyId()
{
if (!root) return 0;
aJsonObject * canObj = aJson.getObjectItem(root, "can");
if (!canObj) return 0;
aJsonObject * addrObj = aJson.getObjectItem(canObj, "addr");
if (!canConfigObj) return 0;
aJsonObject * addrObj = aJson.getObjectItem(canConfigObj, "addr");
if (addrObj && (addrObj->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 || canRemoteConfigObj->type != aJson_Object) return NULL;
aJsonObject * remoteConfObj=canRemoteConfigObj->child;
while (remoteConfObj)
{
aJsonObject * remoteCanObj = aJson.getObjectItem(remoteConfObj, "can");
@@ -564,30 +585,77 @@ while (remoteConfObj)
return NULL;
}
aJsonObject * canDriver::findConfbyName(char* devName, int * devAddr)
{
if (!canRemoteConfigObj || canRemoteConfigObj->type != aJson_Object || !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 || canRemoteConfigObj->type != aJson_Object) 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;
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';
char macStr[19];
uint8_t strptr = 0;
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<<F("CAN: Searching devId for ")<<macStr<<endl;
aJsonObject * remoteConfObj = aJson.getObjectItem(confObj, macStr);
aJsonObject * remoteConfObj = aJson.getObjectItem(canRemoteConfigObj, macStr);
if (!remoteConfObj) return 0;
@@ -606,8 +674,11 @@ return 0;
}
bool canDriver::write(uint32_t msg_id, datagram_t * buf, uint8_t size)
{ //return 0;
if (!ready) errorSerial<<"CAN: not initialized"<<endl;
{ //
if (!ready) {
errorSerial<<"CAN: not initialized"<<endl;
return false;
}
bool res;
if (size>8) size = 8;

View File

@@ -119,7 +119,7 @@ Error
class canDriver
{
public:
canDriver(){ready=false; controllerId=0; responseTimer=0; state=canState::stateUnknown;};
canDriver(){ready=false; controllerId=0; responseTimer=0; state=canState::stateUnknown;canConfigObj=NULL;canRemoteConfigObj=NULL;confCRC=0xFFFF;};
uint8_t getMyId();
bool sendStatus(uint16_t itemNum, itemCmd cmd, int subItem = NO_SUBITEM);
bool sendCommand(uint8_t devID, uint16_t itemID, itemCmd cmd, bool status=false, int subItemID=NO_SUBITEM );
@@ -134,15 +134,22 @@ bool begin();
void Poll();
bool processPacket(canid_t id, datagram_t *packet, uint8_t len, bool rtr=false);
bool write(uint32_t msg_id, datagram_t * buf = NULL, uint8_t size=0);
aJsonObject * findConfbyName(char* devName, int * devAddr=NULL);
#if not defined (NOIP)
bool subscribeTopics(char * root, size_t buflen);
#endif
uint8_t getControllerID(){return controllerId;};
uint8_t getIdByMac(macAddress mac);
aJsonObject * canConfigObj;
aJsonObject * canRemoteConfigObj;
uint16_t confCRC;
datagram_t RXpacket;
canid_t RXid;
uint8_t RXlen;
private:
aJsonObject * findConfbyID(uint8_t devId);
aJsonObject * getConfbyID(uint8_t devId);
#if defined(ARDUINO_ARCH_STM32)
CAN_message_t CAN_RX_msg;

View File

@@ -287,6 +287,10 @@ NRFFlashStorage EEPROM;
putEOF();
debugSerial<<F("EOF")<<endl;
}
#if defined (ARDUINO_ARCH_STM32)
eeprom_buffer_flush();
#endif
#if defined(__SAM3X8E__)
if (samBufferPos) flush();
#endif

View File

@@ -156,13 +156,23 @@ void Item::Parse() {
if (isValid()) {
// Todo - avoid static enlarge for every types
for (int i = aJson.getArraySize(itemArr); i < 4; i++)
aJson.addItemToArray(itemArr, aJson.createNull());//( (long int) 0));
// int(defval[i]) )); //Enlarge item to 4 elements. VAL=int if no other definition in conf
//itemType = aJson.getArrayItem(itemArr, I_TYPE)->valueint;
aJson.addItemToArray(itemArr, aJson.createNull());
/*
itemType = replaceTypeToInt (aJson.getArrayItem(itemArr, I_TYPE));
itemArg = aJson.getArrayItem(itemArr, I_ARG);
itemVal = aJson.getArrayItem(itemArr, I_VAL);
itemExt = aJson.getArrayItem(itemArr, I_EXT);
itemExt = aJson.getArrayItem(itemArr, I_EXT); */
aJsonObject * cmdObj = NULL;
aJsonObject * itemTypeObj = itemArr->child;
if (itemTypeObj) itemArg = itemTypeObj->next;
if (itemArg) itemVal = itemArg->next;
if (itemVal) cmdObj = itemVal->next;
if (cmdObj) itemExt = cmdObj->next;
itemType = replaceTypeToInt (itemTypeObj);
switch (itemType)
{
#ifndef PWM_DISABLE
@@ -331,13 +341,13 @@ uint16_t getCanNum(aJsonObject* verb)
case aJson_Array:
{
aJsonObject *canNumObj=aJson.getArrayItem(verb,1);
if (canNumObj->type == aJson_Int) return canNumObj->valueint;
if (canNumObj && canNumObj->type == aJson_Int) return canNumObj->valueint;
return 0;
}
case aJson_Object:
{
aJsonObject *canNumObj=aJson.getObjectItem(verb, "can");
if (canNumObj->type == aJson_Int) return canNumObj->valueint;
if (canNumObj && canNumObj->type == aJson_Int) return canNumObj->valueint;
return 0;
}
}
@@ -649,7 +659,7 @@ if (suffix = strrchr(*psubItem, '/')) //Trying to retrieve right part
*suffix= 0; //Truncate subItem string
suffix++;
suffixCode = txt2subItem(suffix);
debugSerial<<F("suffixCode:")<<suffixCode<<endl;
// debugSerial<<F("suffixCode:")<<suffixCode<<endl;
// myhome/dev/item/sub.....Item/suffix
}
else
@@ -684,7 +694,7 @@ long int Item::limitSetValue()
// myhome/dev/item/subItem
int Item::Ctrl(char * payload, char * subItem)
int Item::Ctrl(char * payload, char * subItem, int remoteID)
{
if (!payload) return 0;
int fr = freeRam();
@@ -709,13 +719,16 @@ if (suffixCode == S_RAW)
{ itemCmd ic;
ic.Str(payload);
ic.setSuffix(suffixCode);
if (remoteID) return remoteCtrl(ic,remoteID,subItem);
return Ctrl(ic,subItem);
}
bool authorized = false;
char * authPos = strchr(payload,'@');
char * authToken = NULL;
char * authPos = strchr(payload,'@'); //token@command
if (authPos)
{
authToken = payload;
*authPos=0;
authorized = checkToken(payload,authPos+1);
payload=authPos+1;
@@ -782,7 +795,7 @@ st.setSuffix(suffixCode);
default: errorSerial<<F("Wrong paylad")<<endl;
}
}
if (remoteID) return remoteCtrl(st,remoteID,subItem,authToken);
return Ctrl(st,subItem,true,authorized);
} //Void command
break;
@@ -806,7 +819,7 @@ st.setSuffix(suffixCode);
case 4: st.RGBW(Par[0],Par[1],Par[2],Par[3]);
default:;
}
if (remoteID) return remoteCtrl(st,remoteID,subItem,authToken);
return Ctrl(st,subItem,true,authorized);
}
case CMD_UP:
@@ -815,18 +828,40 @@ st.setSuffix(suffixCode);
itemCmd Par0 = getNumber((char **) &payload);
Par0.Cmd(cmd);
Par0.setSuffix(suffixCode);
if (remoteID) return remoteCtrl(Par0,remoteID,subItem,authToken);
return Ctrl(Par0, subItem,true,authorized);
}
default: //some known command
{
int32_t intParam = getIntFromStr((char **) &payload);
if (intParam) st.Int(intParam);
if (remoteID) return remoteCtrl(st,remoteID,NULL,authToken);
return Ctrl(st,NULL, true, authorized);
}
} //ctrl
return 0;
}
int Item::remoteCtrl(itemCmd cmd, int remoteID, char* subItem, char * authToken)
{
#ifdef CANDRV
// Retrieve remote item id
if (!itemArr) return 0;
aJsonObject * itemHandler = itemArr->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
@@ -836,7 +871,9 @@ bool Item::digGroup (aJsonObject *itemArr, itemCmd *cmd, char* subItem, bool aut
aJsonObject *i = itemArr->child;
configLocked++;
while (i) {
if (i->type == aJson_String)
switch (i->type)
{
case aJson_String:
{ //debugSerial<< i->valuestring<<endl;
aJsonObject *nextItem = aJson.getObjectItem(rootItems, i->valuestring);
if (nextItem && nextItem->type == aJson_Array) //nextItem is correct item
@@ -844,8 +881,9 @@ bool Item::digGroup (aJsonObject *itemArr, itemCmd *cmd, char* subItem, bool aut
Item it(nextItem);
if (cmd && it.isValid()) it.Ctrl(*cmd,subItem,false,authorized); //Execute (non recursive)
//Retrieve itemType
aJsonObject * itemtype = aJson.getArrayItem(nextItem,0);
if (itemtype && itemtype->type == aJson_Int && itemtype->valueint == CH_GROUP)
//aJsonObject * itemtype = aJson.getArrayItem(nextItem,0);
//if (itemtype && itemtype->type == aJson_Int && itemtype->valueint == CH_GROUP)
if (it.itemType == CH_GROUP)
{ //is Group
aJsonObject * itemSubArray = aJson.getArrayItem(nextItem,1);
short res = digGroup(itemSubArray,cmd,subItem,authorized);
@@ -863,6 +901,11 @@ bool Item::digGroup (aJsonObject *itemArr, itemCmd *cmd, char* subItem, bool aut
}
}
}
break;
case aJson_Object:
case aJson_Array:
executeCommand(i,-1,*cmd);
}//switch
i = i->next;
} //while
configLocked--;
@@ -1663,7 +1706,7 @@ int Item::isActive() {
itemCmd st;
int val = 0;
debugSerial<<itemArr->name<<F(" ");
debugSerial<<F("ACTIVE:")<<itemArr->name<<F(" ");
if (!isValid())
{
debugSerial<<F(" invalid")<<endl;
@@ -1841,7 +1884,8 @@ int Item::SendStatus(int sendFlags) {
st.debugOut();
#ifdef CANDRV
if (!(sendFlags & FLAG_NOT_SEND_CAN)) LHCAN.sendStatus(getCanNum(itemArr->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)

View File

@@ -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();

View File

@@ -1454,7 +1454,9 @@ if (valMapping && valMapping->type == aJson_Array && aJson.getArraySize(valMappi
if (getInt()<aJson.getArrayItem(valMapping,2)->valueint) return itemCmd().Int((uint32_t) 0);
int diff = ((b-a)/(d-c))/2;
return itemCmd().Int((uint32_t) constrain(map(getInt(),c,d,a,b)+diff,0,255));
//return itemCmd().Int((uint32_t) constrain(map(getInt(),c,d,a,b)+diff,0,255));
return itemCmd().Int((uint32_t) constrain(map(getInt(),c,d,a,b)+diff,0,b));
//return itemCmd().Int((uint32_t) map(getInt(),c,d,a,b)+diff);
}
if (valMapping && valMapping->type == aJson_NULL) return itemCmd();
return *this;

View File

@@ -115,24 +115,24 @@ UID UniqueID;
#endif
uint8_t brokers = 0;
char *deviceName = NULL;
aJsonObject *topics = NULL;
aJsonObject *root = NULL;
aJsonObject *items = NULL;
aJsonObject *inputs = NULL;
aJsonObject *brokersArr = NULL;
aJsonObject *mqttArr = NULL;
aJsonObject *topics = NULL;
aJsonObject *root = NULL;
aJsonObject *items = NULL;
aJsonObject *inputs = NULL;
aJsonObject *brokersArr = NULL;
aJsonObject *mqttArr = NULL;
#ifdef _modbus
aJsonObject *modbusObj = NULL;
aJsonObject *modbusObj = NULL;
#endif
#ifdef _owire
aJsonObject *owArr = NULL;
aJsonObject *owArr = NULL;
#endif
#ifdef _dmxout
aJsonObject *dmxArr = NULL;
aJsonObject *dmxArr = NULL;
#endif
#ifdef SYSLOG_ENABLE
bool syslogInitialized = false;
volatile bool syslogInitialized = false;
#endif
#ifdef WIFI_ENABLE
@@ -153,11 +153,11 @@ volatile uint32_t ultrasonicInputCheck=0;
aJsonObject *pollingItem = NULL;
bool owReady = false;
bool configOk = false; // At least once connected to MQTT
bool configLoaded = false;
bool initializedListeners = false;
uint8_t DHCP_failures = 0;
volatile bool owReady = false;
volatile bool configOk = false; // At least once connected to MQTT
volatile bool configLoaded = false;
volatile bool initializedListeners = false;
volatile uint8_t DHCP_failures = 0;
volatile int8_t ethernetIdleCount =0;
volatile int8_t configLocked = 0;
@@ -177,45 +177,19 @@ int8_t mqttErrorRate=0;
void watchdogSetup(void) {} //Do not remove - strong re-definition WDT Init for DUE
#endif
bool cleanConf(bool wait)
bool cleanConf(short locksAlowed )
{
if (!root) return true;
bool clean = true;
if (configLocked)
if (!root)
{
//debugSerial<<F("No root")<<endl;
return true;
}
if (configLocked>locksAlowed)
{
errorSerial<<F("Can not clean - locked")<<endl;
return false;
}
/*
No more unsafe operations
if (wait)
{
debugSerial<<F("Unlocking config ...")<<endl;
uint32_t stamp=millis();
while (configLocked && !isTimeOver(stamp,millis(),10000))
{
//wdt_res();
cmdPoll();
#ifdef _owire
if (owReady && owArr) owLoop();
#endif
#ifdef _dmxin
DMXCheck();
#endif
if (isNotRetainingStatus()) pollingLoop();
thermoLoop();
inputLoop(CHECK_INPUT);
yield();
}
if (configLocked)
{
errorSerial<<F("Not unlocked in 10s - continue ...")<<endl;
clean = false;
}
} //wait
*/
debugSerial<<F("Stopping channels ...")<<endl;
timerHandlerBusy++;
//Stoping the channels
@@ -265,7 +239,7 @@ debugSerial<<F("Deleting conf. RAM was:")<<freeRam();
configOk=false;
timerHandlerBusy--;
return clean;
return true;
}
bool isNotRetainingStatus() {
@@ -434,8 +408,11 @@ 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;
bool forBcast=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 +432,53 @@ if (lanStatus == RETAINING_COLLECTING)
}
return;
}
else forLocal = true;
}
else
{
pfxlen=inTopic(topic,T_DEV);
/* 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
*/
pfxlen=inTopic(topic,T_DEV);
if (pfxlen)
{
strncpy(savedTopic,topic,sizeof(savedTopic)-1); //Save topic to delete after exec
forLocal=true;
}
else
{
pfxlen = inTopic(topic,T_BCST);
if (pfxlen) forBcast = true;
}
//if (pfxlen) forLocal=true;
#ifdef CANDRV
// else //Nor local or bcst name, try can names
if (!forLocal && !forBcast)
{
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<<F("MQTT: remote command Item:")<<topic+pfxlen<<endl;
strncpy(savedTopic,topic,sizeof(savedTopic)-1); //Save topic to delete after exec
}
else pfxlen=0;
}
}
#endif
}
if (!pfxlen) {
debugSerial<<F("Skipping..")<<endl;
// debugSerial<<F("Skipping..")<<endl;
return;// -3;
}
@@ -473,12 +486,15 @@ else
// debugSerial<<itemName<<endl;
if(!strcmp_P(itemName,CMDTOPIC_P) && payload && (strlen((char*) payload)>1)) {
mqttClient.deleteTopic(topic);
cmd_parse((char *)payload);
if (forLocal || forBcast) cmd_parse ((char *)payload);
//TODO implement for remote
return;// -4;
}
//if (itemName[0]=='$') return;// -6; //Skipping homie stuff
if (strrchr(topic,'$')) return;
/*
Item item(itemName);
if (item.isValid() && (item.Ctrl((char *)payload)>0) && savedTopic[0] && lanStatus != RETAINING_COLLECTING)
@@ -487,7 +503,37 @@ else
debugSerial<<F("MQTT: Complete. Remove topic ")<<savedTopic<<endl;
mqttClient.deleteTopic(savedTopic);
}
*/
bool succeeded = false;
if (forLocal || forBcast)
{
Item item(itemName);
if (item.isValid()) //Local item
{
if (item.Ctrl((char *)payload)>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;
}
}
/// TODO bcast - scan CAN
#endif
if (succeeded && savedTopic[0] && lanStatus != RETAINING_COLLECTING)
{
debugSerial<<F("MQTT: Complete. Remove topic ")<<savedTopic<<endl;
mqttClient.deleteTopic(savedTopic);
}
return;// -7;
}
@@ -714,11 +760,16 @@ lan_status lanLoop() {
strncat(buf, "+/+/#", sizeof(buf)); // Subscribing only on separated command/parameters topics
mqttClient.unsubscribe(buf);
#ifdef CANDRV
setTopic(buf,sizeof(buf),T_ROOT);
LHCAN.subscribeTopics(buf,sizeof(buf));
#endif
onMQTTConnect();
#ifdef CRYPT
//setTopic(buf,sizeof(buf),T_OUT);
strncpy(buf, "+/+/$salt", sizeof(buf)); // Only on separated cmd/val topics
setTopic(buf,sizeof(buf),T_ROOT);
strncat(buf, "+/$salt", sizeof(buf)); // Only on separated cmd/val topics
mqttClient.subscribe(buf);
#endif
@@ -1385,8 +1436,8 @@ return 200;
}
#endif
void applyConfig() {
if (!root || configLocked) return;
bool applyConfig() {
if (!root || configLocked) return false;
configLocked++;
infoSerial<<F("Applying config")<<endl;
items = aJson.getObjectItem(root, "items");
@@ -1532,6 +1583,7 @@ lanStatus=IP_READY_CONFIG_LOADED_CONNECTING_TO_BROKER; ///change
if (lanStatus == OPERATION_NO_MQTT) lanStatus=IP_READY_CONFIG_LOADED_CONNECTING_TO_BROKER;
configLocked--;
return configLoaded;
}
void printConfigSummary() {
@@ -1593,8 +1645,9 @@ int loadConfigFromEEPROM()
if (sysConfStream.peek() == '{') {
debugSerial<<F("JSON detected")<<endl;
if (root) cleanConf(1);
aJsonStream as = aJsonStream(&sysConfStream);
cleanConf(false);
root = aJson.parse(&as);
sysConfStream.close();
if (!root) {
@@ -1605,6 +1658,7 @@ int loadConfigFromEEPROM()
return 0;
}
infoSerial<<F("Loaded from EEPROM")<<endl;
// debugSerial.print(aJson.print(root));
configLocked--;
applyConfig();
sysConf.loadETAG();
@@ -1895,7 +1949,7 @@ if (!sysConf.getServer(configServer,sizeof(configServer)))
infoSerial<<F("got Config\n"); delay(500);
aJsonFileStream as = aJsonFileStream(configStream);
noInterrupts();
if (!cleanConf(true))
if (!cleanConf(0))
{
errorSerial<<F("Get aborted")<<endl;
hclient.closeStream(configStream);
@@ -1972,7 +2026,7 @@ if (!sysConf.getServer(configServer,sizeof(configServer)))
if (responseStatusCode == 200) {
aJsonStream socketStream = aJsonStream(&htclient);
debugSerial<<F("Free:")<<freeRam()<<endl;
if (!cleanConf(true))
if (!cleanConf(0))
{
errorSerial<<F("Get aborted")<<endl;
htclient.stop();
@@ -2051,7 +2105,7 @@ if (!sysConf.getServer(configServer,sizeof(configServer)))
sysConf.setETAG(httpClient.header("ETag"));
//String response = httpClient.getString();
//debugSerial<<response;
if (!cleanConf(true))
if (!cleanConf(0))
{
errorSerial<<F("Get aborted")<<endl;
httpClient.end();
@@ -2458,10 +2512,14 @@ WiFi.onEvent(WiFiEvent);
#endif
#endif //NOIP
loadConfigFromEEPROM();
#ifdef CANDRV
LHCAN.begin();
#endif
loadConfigFromEEPROM();
#ifdef CANDRV
LHCAN.lookupMAC();
#endif
}
@@ -2659,6 +2717,18 @@ infoSerial<<F("\n(+)CAN");
#else
infoSerial<<F("\n(-)CAN");
#endif
#ifdef PULSEPIN12
infoSerial<<F("\n(+)PULSE on PIN12");
#else
infoSerial<<F("\n(-)PULSE on PIN12");
#endif
#ifdef CRYPT
infoSerial<<F("\n(+)CRYPT");
#else
infoSerial<<F("\n(-)CRYPT");
#endif
//#ifdef IPMODBUS
//infoSerial<<F("\n(+)IPMODBUS");
//#endif
@@ -2733,7 +2803,6 @@ LHCAN.upTime(ut);
#endif
}
//#if not defined (NOIP)
void setupMacAddress() {
//Check MAC, stored in NVRAM
@@ -2765,12 +2834,7 @@ if (!sysConf.getMAC()) {
#endif
}
printMACAddress();
#ifdef CANDRV
// LHCAN.lookupMAC();
#endif
}
//#endif //NOIP
void setupCmdArduino() {
//cmdInit(uint32_t(SERIAL_BAUD));

View File

@@ -268,7 +268,7 @@ int cmdFunctionHelp(int arg_cnt, char **args);
int cmdFunctionKill(int arg_cnt, char **args);
void applyConfig();
bool applyConfig();
int cmdFunctionLoad(int arg_cnt, char **args);
@@ -283,6 +283,8 @@ int cmdFunctionGet(int arg_cnt, char **args);
int cmdFunctionLoglevel(int arg_cnt, char **args);
void printBool(bool arg);
int cmdFunctionSave(int arg_cnt, char **args);
/*
void saveFlash(short n, char *str);
@@ -333,7 +335,7 @@ bool disabledDisconnected(const aJsonObject *thermoExtensionArray, int thermoLat
void resetHard();
bool cleanConf(bool wait);
bool cleanConf(short locksAlowed=0);
void printCurentLanConfig();

View File

@@ -303,11 +303,12 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
switch (defMappingObj->type)
{
case aJson_Int: //register/coil/.. number
traceSerial<<F("Searching reg#")<<defMappingObj->valueint<<endl;
traceSerial<<F("MBUSD: Searching reg#")<<defMappingObj->valueint<<endl;
if ((defMappingObj->valueint>= registerFrom) && (defMappingObj->valueint<=registerTo))
{
mappedParam = findRegister(defMappingObj->valueint,defMappingObj->valueint-registerFrom,regType,registerFrom,registerTo,false,&submitRecurrentOut);
executeWithoutCheck=true;
debugSerial<<"MBUSD: recurrent check res: "<<"SRO:"<<submitRecurrentOut<<endl;
}
else
{
@@ -410,8 +411,30 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,paramObj->name);
if (execObj)
{
bool storeLastValue = true;
if (doExecution)
{
storeLastValue=false;
// Check - if no action configured for object - not need to store last value - let requrent process do it
aJsonObject * i = execObj->child;
while (i && !storeLastValue)
{
if (i->name && *i->name && (*i->name != '@')) storeLastValue = true;
i=i->next;
}
}
aJsonObject * markObj = execObj;
if (execObj->type == aJson_Array) markObj = execObj->child;
if (execObj->type == aJson_Array)
{
markObj = execObj->child;
storeLastValue = true;
}
if (storeLastValue)
{
//Retrive previous data
aJsonObject *lastMeasured = aJson.getObjectItem(markObj,"@S");
if (lastMeasured)
@@ -433,13 +456,14 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
debugSerial<<F("MBUS: Add @S: ")<<paramObj->name<<endl;
aJson.addNumberToObject(markObj, "@S", (long) param);
}
}
if (executeWithoutCheck)
{
if (doExecution && (submitRecurrentOut || *submitParam))
{
//debugSerial<<F("MBUS: exec ");mappedParam.debugOut();
executeCommand(execObj, -1, mappedParam);
*submitParam=true; //if requrrent check has submit smth - report it.
}
@@ -447,7 +471,7 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
return mappedParam;
}
if (*submitParam)
if (*submitParam && doExecution)
{
// Compare with last submitted val (if @V NOT marked as NULL in config)
aJsonObject *settedValue = aJson.getObjectItem(markObj,"@V");
@@ -458,7 +482,11 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
}
else
{
if (doExecution) executeCommand(execObj, -1, mappedParam);
if (doExecution)
{
//debugSerial<<F("MBUS: exec ");mappedParam.debugOut();
executeCommand(execObj, -1, mappedParam);
}
// if param updated by device and no new value queued to send - update @V to avoid "Ignored - equal with setted val"
if (settedValue && !(execObj->subtype & MB_NEED_SEND))
settedValue->valueint=param;
@@ -556,13 +584,14 @@ int out_Modbus::sendModbus(char * paramName, aJsonObject * outValue)
if (prefetchObj && (prefetchObj->type == aJson_Boolean) && prefetchObj->valuebool)
{
int modbusRegType = (outValue->subtype == PAR_COIL) ? MODBUS_COIL_REG_TYPE:MODBUS_HOLDING_REG_TYPE;
debugSerial<<F("\nMBUS: prefetching ")<<paramName<<F(" #") <<regObj->valueint << " type:" << modbusRegType << " ";
debugSerial<<F(" prefetch ")<<paramName<<F(" #") <<regObj->valueint << " type:" << modbusRegType << " ";
/// to prevent CORRUPTIOIN if using same buffer
uint16_t localBuffer;
node.setResponseBuffer(&localBuffer,1);
bool successRead = readModbus(regObj->valueint,modbusRegType,1);
mbusSlenceTimer = millisNZ();
if (successRead)
@@ -607,6 +636,13 @@ if (prefetchObj && (prefetchObj->type == aJson_Boolean) && prefetchObj->valueboo
}
else
{
if (outValue->valueint == localBuffer)
{
debugSerial << F("MBUS:")<<paramName<< F("=")<<localBuffer<<F(": equal targert.")<<endl;
node.setDefaultResponseBuffer();
return -4;
}
debugSerial << F("MBUS:")<<paramName<< F(" val not changed. Continue")<<endl;
}
}
@@ -664,7 +700,7 @@ int out_Modbus::Poll(short cause)
if (cause==POLLING_SLOW) return 0;
bool lineInitialized = false;
if (modbusBusy || (Status() != CST_INITIALIZED) || ( mbusSlenceTimer && !isTimeOver(mbusSlenceTimer,millis(),100))) return 0;
if (modbusBusy || (Status() != CST_INITIALIZED) || ( mbusSlenceTimer && !isTimeOver(mbusSlenceTimer,millis(),200))) return 0;
aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
if (itemParametersObj && itemParametersObj->type ==aJson_Object)
@@ -692,18 +728,23 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
int sendRes;
int savedValue;
bool needResend;
do
{
savedValue = outValue->valueint;
debugSerial<<"MBUS: SEND "<<item->itemArr->name<<" ";
sendRes = sendModbus(execObj->name,outValue);
needResend = (savedValue != outValue->valueint);
while(needResend && mbusSlenceTimer && !isTimeOver(mbusSlenceTimer,millis(),200)) modbusIdle();
}
while (savedValue != outValue->valueint); //repeat sending if target value changed while we're waited for mbus responce
while (needResend); //repeat sending if target value changed while we're waited for mbus responce
switch (sendRes)
{
case 1: //success
execObj->subtype&=~ MB_NEED_SEND;
case -4: //equal tatget
//execObj->subtype&=~ MB_NEED_SEND;
execObj->subtype = 0;
onceSendOk=true;
///return 1; //relax
break;
@@ -716,7 +757,8 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
case -3:
errorSerial<<F("MBUS: param ")<<execObj->name<<F(" sending cancelled")<<endl;
//outValue->valueint=
execObj->subtype&=~ MB_NEED_SEND;
//execObj->subtype&=~ MB_NEED_SEND;
execObj->subtype = 0;
break;
default: //param not found
errorSerial<<F("MBUS: param ")<<execObj->name<<F(" not found")<<endl;
@@ -730,7 +772,7 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
}
if (isTimeOver(store->timestamp,millis(),store->pollingInterval) && ( !mbusSlenceTimer || isTimeOver(mbusSlenceTimer,millis(),100)))
if (isTimeOver(store->timestamp,millis(),store->pollingInterval) && ( !mbusSlenceTimer || isTimeOver(mbusSlenceTimer,millis(),200)))
{
// Clean_up FLAG_SEND_ERROR flag

View File

@@ -531,9 +531,12 @@ if (_l2 && _l2->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;
}
@@ -974,7 +977,19 @@ return true;
}
#ifdef CANDRV
uint16_t getCRC(aJsonObject * in)
{
if (!in) return 0;
CRCStream crcStream;
aJsonStream aJsonCrcStream = aJsonStream(&crcStream);
//debugSerial<<"CRC: in";
//debugSerial.print(aJson.print(in));
aJson.print(in,&aJsonCrcStream,false);
//debugSerial<<"\nCRC:"<<crcStream.getCRC16();
return crcStream.getCRC16();
}
#endif
#pragma message(VAR_NAME_VALUE(debugSerial))
#pragma message(VAR_NAME_VALUE(SERIAL_BAUD))

View File

@@ -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,26 @@ int str2regSize(char * str);
bool checkToken(char * token, char * data);
bool isProtectedPin(short pin);
bool i2cReset();
uint16_t getCRC(aJsonObject * in);
#ifdef CANDRV
#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);return 1;};
virtual int availableForWrite(){return 1;};
};
#endif

View File

@@ -359,6 +359,8 @@ lib_ignore =
ModbusMaster
ClosedCube HDC1080
SparkFun CCS811 Arduino Library
;ArduinoOTA
ArduinoMDNS
;Adafruit BusIO
;Adafruit MCP23017 Arduino Library
;Adafruit Unified Sensor
@@ -388,7 +390,7 @@ lib_deps =
Adafruit MCP23017 Arduino Library
Adafruit BusIO
br3ttb/PID@^1.2.1
ArduinoMDNS
;ArduinoMDNS
;https://github.com/khoih-prog/TimerInterrupt_Generic.git
monitor_speed = 115200
@@ -820,7 +822,6 @@ lib_ignore =
DallasTemperature
Adafruit Unified Sensor
DS2482_OneWire
ModbusMaster
Syslog
;EEPROM
ClosedCube HDC1080
@@ -843,6 +844,7 @@ lib_deps =
br3ttb/PID@^1.2.1
ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git
https://github.com/anklimov/ModbusMaster
monitor_speed = 115200
@@ -888,7 +890,6 @@ lib_ignore =
DallasTemperature
Adafruit Unified Sensor
DS2482_OneWire
ModbusMaster
Syslog
NRFFlashStorage
ClosedCube HDC1080
@@ -911,7 +912,8 @@ lib_deps =
br3ttb/PID@^1.2.1
ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git
;https://github.com/anklimov/ModbusMaster
https://github.com/anklimov/ModbusMaster
https://github.com/anklimov/ModbusMaster
monitor_speed = 115200
@@ -957,7 +959,6 @@ lib_ignore =
DallasTemperature
Adafruit Unified Sensor
DS2482_OneWire
ModbusMaster
Syslog
NRFFlashStorage
ClosedCube HDC1080
@@ -980,7 +981,7 @@ lib_deps =
br3ttb/PID@^1.2.1
; ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git
;https://github.com/anklimov/ModbusMaster
https://github.com/anklimov/ModbusMaster
pazi88/STM32_CAN
ericksimoes/Ultrasonic