Massive kernel logic refaktoring & critical memory issues fixes. HomeRemote compatibility, Modbus command retrying, MQTT Status async/submission optimization

This commit is contained in:
2018-04-01 22:13:13 +03:00
parent a936240d14
commit 66d6445967
7 changed files with 174 additions and 83 deletions

View File

@@ -35,10 +35,10 @@ e-mail anklimov@gmail.com
#define fmPar SERIAL_8N1
short modbusBusy = 0;
extern aJsonObject *modbusItem;
extern aJsonObject *pollingItem;
int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value);
//int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value);
extern PubSubClient mqttClient;
//extern char outprefix[];
@@ -83,13 +83,14 @@ void Item::Parse() {
itemArg = aJson.getArrayItem(itemArr, I_ARG);
itemVal = aJson.getArrayItem(itemArr, I_VAL);
/*
Serial.print(F(" Item:"));
Serial.print(itemArr->name);
Serial.print(F(" T:"));
Serial.print(itemType);
Serial.print(F(" ="));
Serial.println(getArg());
*/
}
}
@@ -163,9 +164,9 @@ void Item::setVal(short n, int par) // Only store if VAL is array defined in c
void Item::setVal(long int par) // Only store if VAL is int (autogenerated or config-defined)
{
if (!itemVal || itemVal->type != aJson_Int) return;
Serial.print(F(" Store "));
Serial.print(F(" Val="));
Serial.println(par);
// Serial.print(F(" Store "));
// Serial.print(F(" Val="));
// Serial.println(par);
itemVal->valueint = par;
}
@@ -193,7 +194,7 @@ void analogWrite(int pin, int val)
boolean Item::getEnableCMD(int delta) {
return ((millis() - lastctrl > (unsigned long) delta));//|| (itemArr!=lastobj));
return ((millis() - lastctrl > (unsigned long) delta));// || ((void *)itemArr != (void *) lastobj));
}
int Item::Ctrl(short cmd, short n, int *Par, boolean send) {
@@ -246,14 +247,14 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) {
st.s = Par[1];
st.v = Par[2];
setVal(st.aslong);
if (send) SendCmd(0,3,Par); // Send back triplet ?
if (send) SendStatus(0,3,Par,true); // Send back triplet ?
break;
case CH_PWM:
case CH_VC:
case CH_DIMMER:
case CH_MODBUS:
if (send) SendCmd(0, 1, Par); // Send back parameter for channel above this line
if (send) SendStatus(0, 1, Par,true); // Send back parameter for channel above this line
case CH_THERMO:
case CH_VCTEMP:
setVal(Par[0]); // Store value
@@ -280,8 +281,9 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) {
Par[1] = st.s;
Par[2] = st.v;
if (!Par[2]) Par[2]=80; //If RGB value==0 set to 80%
setVal(st.aslong);
params = 3;
SendCmd(0, params, Par); // Send restored triplet. In any cases
SendStatus(0, params, Par,true); // Send restored triplet. In any cases
break;
case CH_VCTEMP:
@@ -293,15 +295,15 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) {
Par[0] = st.aslong;
params = 1;
SendCmd(0, params, Par); // Send restored parameter, even if send=false - no problem, loop will be supressed at next hop
SendStatus(0, params, Par, true); // Send restored parameter, even if send=false - no problem, loop will be supressed at next hop
break;
case CH_THERMO:
Par[0] = st.aslong;
params = 0;
if (send) SendCmd(CMD_ON); // Just ON (switch)
if (send) SendStatus(CMD_ON); // Just ON (switch)
break;
default:
if (send) SendCmd(cmd); // Just send ON
if (send) SendStatus(cmd); // Just send ON
}//itemtype
else {// Default settings
Serial.print(st.aslong);
@@ -329,7 +331,7 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) {
if (send) setCmd(cmd);
} else { //Double ON - apply special preset - clean white full power
switch (itemType) {
if (getEnableCMD(500)) switch (itemType) {
case CH_RGBW:
Serial.println(F("Force White"));
itemType = CH_WHITE;
@@ -343,7 +345,7 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) {
setVal(st.aslong);
//Send to OH
if (send) SendCmd(0, 3, Par);
if (send) SendStatus(0, 3, Par);
break;
} //itemtype
} //else
@@ -361,7 +363,7 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) {
Par[1] = 0;
Par[2] = 0;
setCmd(cmd);
if (send) SendCmd(cmd); ///?
if (send) SendStatus(cmd);
}
break;
@@ -372,7 +374,7 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) {
Par[1] = 0;
Par[2] = 0;
setCmd(cmd);
SendCmd(CMD_OFF); //HALT to OFF mapping - send in any cases
SendStatus(CMD_OFF); //HALT to OFF mapping - send in any cases
Serial.println(F(" Halted"));
}
@@ -433,7 +435,7 @@ int Item::Ctrl(short cmd, short n, int *Par, boolean send) {
int _reg = aJson.getArrayItem(itemArg, 1)->valueint;
int _mask = aJson.getArrayItem(itemArg, 2)->valueint;
modbusSet(_addr, _reg, _mask, map(Par[0], 0, 100, 0, 0x3f));
modbusDimmerSet(_addr, _reg, _mask, map(Par[0], 0, 100, 0, 0x3f));
}
break;
}
@@ -655,9 +657,12 @@ POLL 2101x10
*/
void mb_fail(short addr, short op, int val, int cmd) {
void Item::mb_fail(short addr, short op, int val, int cmd) {
Serial.println(F("Modbus op failed"));
// int cmd = getCmd();
// if (cmd<0) return;
setCmd(cmd | CMD_RETRY);
setVal(val);
}
extern ModbusMaster node;
@@ -731,16 +736,24 @@ int Item::VacomSetHeat(int addr, int8_t val, int8_t cmd) {
}
int Item::SendCmd(short cmd, short n, int *Par) {
int Item::SendStatus(short cmd, short n, int *Par, boolean deffered) {
/// ToDo: relative patches, configuration
if (deffered) {
setCmd(cmd | CMD_REPORT);
Serial.println(F("Status deffered"));
// mqttClient.publish("/push", "1");
return 0;
// Todo: Parameters? Now expected that parameters already stored by setVal()
}
else { //publush to MQTT
char addrstr[32];
//char addrbuf[17];
char valstr[16] = "";
strcpy_P(addrstr, outprefix);
strncat(addrstr, itemArr->name, sizeof(addrstr)); ////
strncat(addrstr, itemArr->name, sizeof(addrstr));
switch (cmd) {
@@ -766,21 +779,24 @@ int Item::SendCmd(short cmd, short n, int *Par) {
}
break;
default:
Serial.println(F("Unknown cmd "));
return -1;
}
Serial.print(F("Pub: "));
Serial.print(addrstr);
Serial.print(F("->"));
Serial.println(valstr);
mqttClient.publish(addrstr, valstr,true);
return 0;
}
}
int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value) {
int Item::modbusDimmerSet(int addr, uint16_t _reg, int _mask, uint16_t value) {
if (modbusBusy) {
mb_fail(3, addr, value, 0);
return -1;
};
modbusBusy = 1;
@@ -810,6 +826,7 @@ int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value) {
int Item::checkFM() {
if (modbusBusy) return -1;
if (checkModbusRetry()) return -2;
modbusBusy = 1;
uint8_t j, result;
@@ -888,13 +905,19 @@ int Item::checkFM() {
}
int set = node.getResponseBuffer(0);
if (set) aJson.addNumberToObject(out, "set", set * a + b);
aJson.addNumberToObject(out, "t", (int) node.getResponseBuffer(1) * a + b);
float fset;
float ftemp;
if (set) aJson.addNumberToObject(out, "set", fset =set * a + b);
aJson.addNumberToObject(out, "t", ftemp =(int) node.getResponseBuffer(1) * a + b);
// aJson.addNumberToObject(out,"d", (int) node.getResponseBuffer(2)*a+b);
int pwr = node.getResponseBuffer(3);
if (pwr > 0) aJson.addNumberToObject(out, "pwr", pwr / 10.); else aJson.addNumberToObject(out, "pwr", 0);
if (ftemp>fset+FM_OVERHEAT_CELSIUS)
{
mqttClient.publish("/alarm/ovrht", itemArr->name);
Ctrl(CMD_OFF); //Shut down
}
Serial.println();
} else {
Serial.print(F("Modbus polling error="));
@@ -910,9 +933,21 @@ int Item::checkFM() {
modbusBusy = 0;
}
boolean Item::checkModbusRetry() {
int cmd = getCmd();
if (cmd & CMD_RETRY) { // if last sending attempt of command was failed
int val = getVal();
Serial.println(F("Retrying CMD"));
cmd &= ~CMD_RETRY; // Clean retry flag
Ctrl(cmd,1,&val); // Execute command again
return true;
}
return false;
}
int Item::checkModbus() {
int Item::checkModbusDimmer() {
if (modbusBusy) return -1;
if (checkModbusRetry()) return -2;
modbusBusy = 1;
uint8_t result;
@@ -933,9 +968,11 @@ int Item::checkModbus() {
if (result == node.ku8MBSuccess) {
data = node.getResponseBuffer(0);
Serial.print(F("Modbus Val: "));
Serial.print(F("MB: "));
Serial.print(itemArr->name);
Serial.print(F(" Val: "));
Serial.println(data, HEX);
checkModbus(data);
checkModbusDimmer(data);
} else {
Serial.print(F("Modbus polling error="));
Serial.println(result, HEX);
@@ -944,18 +981,18 @@ int Item::checkModbus() {
modbusBusy = 0;
// Looking 1 step ahead for modbus item, which uses same register
Item nextItem(modbusItem->next);
if (modbusItem && nextItem.isValid() && nextItem.itemType == CH_MODBUS && nextItem.getArg(0) == addr &&
Item nextItem(pollingItem->next);
if (pollingItem && nextItem.isValid() && nextItem.itemType == CH_MODBUS && nextItem.getArg(0) == addr &&
nextItem.getArg(1) == reg) {
nextItem.checkModbus(data);
modbusItem = modbusItem->next;
if (!modbusItem) modbusItem = items->child;
nextItem.checkModbusDimmer(data);
pollingItem = pollingItem->next;
if (!pollingItem) pollingItem = items->child;
}
}
int Item::checkModbus(int data) {
int Item::checkModbusDimmer(int data) {
short mask = getArg(2);
int d = data;
if (mask) d >>= 8;
@@ -966,14 +1003,14 @@ int Item::checkModbus(int data) {
if (getVal() != d || d && cmd == CMD_OFF || d && cmd == CMD_HALT) //volume changed or turned on manualy
{
if (d) { // Actually turned on
if (cmd == CMD_OFF || cmd == CMD_HALT) SendCmd(CMD_ON); //update OH with ON if it was turned off before
SendCmd(0, 1, &d); //update OH with value
if (cmd == CMD_OFF || cmd == CMD_HALT) SendStatus(CMD_ON); //update OH with ON if it was turned off before
SendStatus(0, 1, &d); //update OH with value
setCmd(CMD_ON); //store command
setVal(d); //store value
} else {
if (cmd != CMD_HALT && cmd != CMD_OFF) {
setCmd(CMD_OFF); // store command (not value)
SendCmd(CMD_OFF);// update OH
SendStatus(CMD_OFF);// update OH
}
}
} //if data changed
@@ -982,10 +1019,60 @@ int Item::checkModbus(int data) {
int Item::Poll() {
switch (itemType) {
case CH_MODBUS:
checkModbus();
checkModbusDimmer();
sendDelayedStatus();
return INTERVAL_CHECK_MODBUS;
break;
case CH_VC:
checkFM();
return INTERVAL_CHECK_MODBUS;
break;
case CH_RGB: //All channels with slider generate too many updates
case CH_RGBW:
case CH_DIMMER:
case CH_PWM:
sendDelayedStatus();
}
return INTERVAL_POLLING;
}
void Item::sendDelayedStatus(){
HSVstore st;
int cmd=getCmd();
short params = 0;
int Par[3];
if (cmd & CMD_REPORT)
{
//retrive stored values
st.aslong = getVal();
switch (itemType) {
//case CH_GROUP:
case CH_RGBW:
case CH_RGB:
Par[0] = st.h;
Par[1] = st.s;
Par[2] = st.v;
params = 3;
SendStatus(0, params, Par); // Send restored triplet.
break;
case CH_VCTEMP:
case CH_PWM:
case CH_DIMMER: //Everywhere, in flat VAL
case CH_MODBUS:
case CH_VC:
case CH_THERMO:
Par[0] = st.aslong;
params = 1;
SendStatus(0, params, Par); // Send restored parameter
break;
default:
SendStatus(cmd); // Just send CMD
}//itemtype
cmd &= ~CMD_REPORT; // Clean report flag
setCmd(cmd);
}
}