From 0dedf388da7b6a4aab0bd72541f3cb8dd76a5f9a Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Wed, 13 May 2020 13:03:12 +0300 Subject: [PATCH] interim commit: universal Modbus driver --- build-flags/build_flags_esp32-wifi | 2 +- lighthub/abstractch.h | 1 + lighthub/abstractout.h | 1 + lighthub/item.cpp | 38 ++- lighthub/item.h | 3 + lighthub/lighthub.ino.cpp | 17 -- lighthub/main.cpp | 8 +- lighthub/modules/out_modbus.cpp | 360 +++++++++++++++++++++++++++++ lighthub/modules/out_modbus.h | 42 ++++ 9 files changed, 447 insertions(+), 25 deletions(-) delete mode 100644 lighthub/lighthub.ino.cpp create mode 100644 lighthub/modules/out_modbus.cpp create mode 100644 lighthub/modules/out_modbus.h diff --git a/build-flags/build_flags_esp32-wifi b/build-flags/build_flags_esp32-wifi index 21b4c8b..39146e8 100644 --- a/build-flags/build_flags_esp32-wifi +++ b/build-flags/build_flags_esp32-wifi @@ -1,6 +1,6 @@ -DDMX_DISABLE -DMODBUS_DISABLE --DOWIRE_DISABLE +#-DOWIRE_DISABLE -DDHT_DISABLE -DCOUNTER_DISABLE -DSPILED_DISABLE diff --git a/lighthub/abstractch.h b/lighthub/abstractch.h index 7276fdf..bc0ee11 100644 --- a/lighthub/abstractch.h +++ b/lighthub/abstractch.h @@ -3,6 +3,7 @@ #define CST_UNKNOWN 0 #define CST_INITIALIZED 1 +#define CST_FAILED 2 class abstractCh { public: diff --git a/lighthub/abstractout.h b/lighthub/abstractout.h index a4e8ac6..dfd0c03 100644 --- a/lighthub/abstractout.h +++ b/lighthub/abstractout.h @@ -3,6 +3,7 @@ #include "abstractch.h" class Item; +class chPersistent {}; class abstractOut : public abstractCh{ public: abstractOut(Item * _item):abstractCh(){item=_item;}; diff --git a/lighthub/item.cpp b/lighthub/item.cpp index c35c9bc..e66f983 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -43,6 +43,7 @@ e-mail anklimov@gmail.com #include "modules/out_spiled.h" #include "modules/out_ac.h" #include "modules/out_motor.h" +#include "modules/out_modbus.h" short modbusBusy = 0; extern aJsonObject *pollingItem; @@ -174,6 +175,13 @@ void Item::Parse() { // debugSerial<name << F(" T:") << itemType << F(" =") << getArg() << endl; @@ -350,16 +358,40 @@ void Item::setExt(long int par) // Only store if VAL is int (autogenerated or c if (!itemExt) { for (int i = aJson.getArraySize(itemArr); i <= 4; i++) - aJson.addItemToArray(itemArr, aJson.createItem(0)); - itemExt = aJson.getArrayItem(itemArr, I_EXT); + aJson.addItemToArray(itemArr, itemExt=aJson.createItem(0)); + //itemExt = aJson.getArrayItem(itemArr, I_EXT); }; - if(itemExt->type != aJson_Int) return; + if(!itemExt || itemExt->type != aJson_Int) return; itemExt->valueint = par; debugSerial<type == aJson_Int) return (chPersistent *) itemExt->child; + else return NULL; +} + +chPersistent * Item::setPersistent(chPersistent * par) +{ + if (!itemExt) + { + for (int i = aJson.getArraySize(itemArr); i <= 4; i++) + aJson.addItemToArray(itemArr, itemExt = aJson.createItem(0)); + //itemExt = aJson.getArrayItem(itemArr, I_EXT); + }; + + if(!itemExt || (itemExt->type != aJson_Int)) return NULL; + itemExt->child = (aJsonObject *) par; + // debugSerial<type == aJson_Array)); } diff --git a/lighthub/item.h b/lighthub/item.h index 1e1f55a..3298bda 100644 --- a/lighthub/item.h +++ b/lighthub/item.h @@ -50,6 +50,7 @@ e-mail anklimov@gmail.com #define CH_AC 10 //AC Haier #define CH_SPILED 11 #define CH_MOTOR 12 +#define CH_MBUS 14 //#define CHANNEL_TYPES 13 //static uint32_t pollInterval[CHANNEL_TYPES] = {0,0,0,0,MODB}; @@ -172,6 +173,8 @@ class Item uint8_t getCmd(); long int getExt(); //From int val OR array void setExt(long int par); + chPersistent * getPersistent(); + chPersistent * setPersistent(chPersistent * par); void setCmd(uint8_t cmdValue); short getFlag (short flag=FLAG_MASK); void setFlag (short flag); diff --git a/lighthub/lighthub.ino.cpp b/lighthub/lighthub.ino.cpp deleted file mode 100644 index 9f8c3a2..0000000 --- a/lighthub/lighthub.ino.cpp +++ /dev/null @@ -1,17 +0,0 @@ -# 1 "/var/folders/kt/8psth65x03v6tw_phdhbj12r0000gn/T/tmpzcgFX2" -#include -# 1 "/Users/andrey/Documents/Arduino/lighthub/lighthub/lighthub.ino" -#include "main.h" -void setup(); -void loop(); -#line 2 "/Users/andrey/Documents/Arduino/lighthub/lighthub/lighthub.ino" -void setup(){ - - setup_main(); - - -} -void loop(){ - - loop_main(); -} \ No newline at end of file diff --git a/lighthub/main.cpp b/lighthub/main.cpp index 671edf1..573c904 100644 --- a/lighthub/main.cpp +++ b/lighthub/main.cpp @@ -134,7 +134,7 @@ aJsonObject *inputs = NULL; aJsonObject *mqttArr = NULL; #ifndef MODBUS_DISABLE -aJsonObject *modbusArr = NULL; +aJsonObject *modbusObj = NULL; #endif #ifdef _owire aJsonObject *owArr = NULL; @@ -210,7 +210,7 @@ debugSerial< + +extern aJsonObject *modbusObj; +extern ModbusMaster node; +extern short modbusBusy; +extern void modbusIdle(void) ; + +/* +const char float_P[] PROGMEM = "i16"; +const char hsv_P[] PROGMEM = "i32"; +const char int_P[] PROGMEM = "u16"; +const char enum_P[] PROGMEM = "u32"; +const char format_P[] PROGMEM = "i8h"; +const char true_P[] PROGMEM = "i8l"; +const char false_P[] PROGMEM = "false"; + +const char 8E1_P[] PROGMEM = "8E1"; +const char 8N1_P[] PROGMEM = "8N1"; +const char int_P[] PROGMEM = "8O1"; +const char enum_P[] PROGMEM = "u32"; +const char format_P[] PROGMEM = "$i8h"; +const char true_P[] PROGMEM = "i8l"; +const char false_P[] PROGMEM = "false"; +*/ +struct reg_t +{ + const char verb[4]; + const uint8_t id; +}; + +struct serial_t +{ + const char verb[4]; + const int mode; +}; + +#define PAR_I16 1 +#define PAR_I32 2 +#define PAR_U16 3 +#define PAR_U32 4 +#define PAR_I8H 5 +#define PAR_I8L 6 +#define PAR_U8H 7 +#define PAR_U8L 8 + + +const reg_t regSize_P[] PROGMEM = +{ + { "i16", (int) PAR_I16 }, + { "i32", (int) PAR_I32 }, + { "u16", (int) PAR_U16 }, + { "u32", (int) PAR_U32 }, + { "i8h", (int) PAR_I8H }, + { "i8l", (int) PAR_I8L }, + { "u8h", (int) PAR_U8H }, + { "u8l", (int) PAR_U8L } +} ; +#define regSizeNum sizeof(regSize_P)/sizeof(reg_t) + +const serial_t serialModes_P[] PROGMEM = +{ + { "8E1", SERIAL_8E1 }, + { "8N1", SERIAL_8N1 }, + { "8O1", SERIAL_8O1 }, + { "8M1", SERIAL_8M1 }, + { "8S1", SERIAL_8S1 } +} ; + +#define serialModesNum sizeof(serialModes_P)/sizeof(serial_t) + +int str2SerialParam(char * str) +{ + for(uint8_t i=0; iitemArg || (item->itemArg->type != aJson_Array) || aJson.getArraySize(item->itemArg)<2) return false; + + aJsonObject * templateIdObj = aJson.getArrayItem(item->itemArg, 1); + if (templateIdObj->type != aJson_String || !templateIdObj->valuestring) return false; + + aJsonObject * templateObj = aJson.getObjectItem(modbusObj, templateIdObj->valuestring); + if (! templateObj) + { + debugSerial<valuestring<type == aJson_String && serialParamObj->valuestring) store->serialParam = (UARTClass::UARTModes) str2SerialParam(serialParamObj->valuestring); + else store->serialParam = SERIAL_8N1; + + aJsonObject * baudObj=aJson.getObjectItem(templateObj, "baud"); + if (baudObj && baudObj->type == aJson_Int && baudObj->valueint) store->baud = baudObj->valueint; + else store->baud = 9600; + aJsonObject * pollObj=aJson.getObjectItem(templateObj, "poll"); + if (pollObj && pollObj->type == aJson_Object) + { + store->pollingRegisters=aJson.getObjectItem(pollObj, "regs"); + store->pollingInterval =aJson.getObjectItem(pollObj, "delay")->valueint; + } + else {store->pollingRegisters=NULL;store->pollingInterval = 1000;} + + store->parameters=aJson.getObjectItem(templateObj, "par"); + + //store->addr=item->getArg(0); + } + + +int out_Modbus::Setup() +{ +Serial.println("Modbus Init"); +if (!store) store= (mbPersistent *)item->setPersistent(new mbPersistent); +if (!store) return 0; +store->timestamp=millis(); +if (getConfig()) + { + //item->clearFlag(ACTION_NEEDED); + //item->clearFlag(ACTION_IN_PROCESS); + debugSerial<driverStatus = CST_INITIALIZED; + return 1; + } +else + { debugSerial<driverStatus = CST_FAILED; + return 0; + } + +} + +int out_Modbus::Stop() +{ +Serial.println("Modbus De-Init"); + +delete store; +item->setPersistent(NULL); +store = NULL; + +//driverStatus = CST_UNKNOWN; +return 1; +} + +int out_Modbus::Status() +{ +if (store) + return store->driverStatus; +return CST_UNKNOWN; +} + +int out_Modbus::isActive() +{ +return item->getVal(); +} + + +bool readModbus(uint16_t reg, int regType, int count) +{ +uint8_t result; +switch (regType) { + case MODBUS_HOLDING_REG_TYPE: + result = node.readHoldingRegisters(reg, count); + break; + case MODBUS_COIL_REG_TYPE: + result = node.readCoils(reg, count); + break; + case MODBUS_DISCRETE_REG_TYPE: + result = node.readDiscreteInputs(reg, count); + break; + case MODBUS_INPUT_REG_TYPE: + result = node.readInputRegisters(reg, count); + break; + default: + debugSerial<parameters->child; + while (paramObj) + { + aJsonObject *regObj = aJson.getObjectItem(paramObj, "reg"); + if (regObj && regObj->valueint ==registerNum) + { + aJsonObject *typeObj = aJson.getObjectItem(paramObj, "type"); + aJsonObject *mapObj = aJson.getObjectItem(paramObj, "map"); + uint16_t data = node.getResponseBuffer(posInBuffer); + debugSerial << F("MB got ")<name<next; + } +return 0; +} + +int out_Modbus::Poll(short cause) +{ +if (store->pollingRegisters && !modbusBusy && (Status() == CST_INITIALIZED) && isTimeOver(store->timestamp,millis(),store->pollingInterval)) + { + debugSerial<itemArr->name << endl; + modbusBusy=1; + modbusSerial.begin(store->baud, store->serialParam); + node.begin(item->getArg(0), modbusSerial); + + aJsonObject * reg = store->pollingRegisters->child; + while (reg) + { + switch (reg->type) + { + case aJson_Int: + { + int registerNum = reg->valueint; + if (readModbus(registerNum,MODBUS_HOLDING_REG_TYPE,1)) + { + findRegister(registerNum,0); + // data = node.getResponseBuffer(j); + } + } + break; + case aJson_Array: + if (aJson.getArraySize(reg)==2) + { + int registerFrom=aJson.getArrayItem(reg, 0)->valueint; + int registerTo=aJson.getArrayItem(reg, 1)->valueint; + + if (readModbus(registerFrom,MODBUS_HOLDING_REG_TYPE,registerTo-registerFrom+1)) + { + for(int i=registerFrom;i<=registerTo;i++) + { + findRegister(i,i-registerFrom); + } + //data = node.getResponseBuffer(j); + } + + } + + } + reg = reg->next; + } + + store->timestamp=millis(); + debugSerial<itemArr->name << endl; + + //Non blocking waiting to release line + uint32_t time = millis()+50; + while (millis()pollingInterval; +}; + +int out_Modbus::getChanType() +{ + return CH_MODBUS; +} + + + +int out_Modbus::Ctrl(short cmd, short n, int * Parameters, boolean send, int suffixCode, char* subItem) +{ +int chActive = item->isActive(); +bool toExecute = (chActive>0); +long st; +if (cmd>0 && !suffixCode) suffixCode=S_CMD; //if some known command find, but w/o correct suffix - got it + +//item->setFlag(ACTION_NEEDED); + +switch(suffixCode) +{ +case S_NOTFOUND: + // turn on and set +toExecute = true; +debugSerial<setVal(st=Parameters[0]); //Store + if (!suffixCode) + { + if (chActive>0 && !st) item->setCmd(CMD_OFF); + if (chActive==0 && st) item->setCmd(CMD_ON); + item->SendStatus(SEND_COMMAND | SEND_PARAMETERS | SEND_DEFFERED); +// if (item->getExt()) item->setExt(millis()+maxOnTime); //Extend motor time + } + else item->SendStatus(SEND_PARAMETERS | SEND_DEFFERED); + + return 1; + //break; + +case S_CMD: + item->setCmd(cmd); + switch (cmd) + { + case CMD_ON: + //retrive stored values + st = item->getVal(); + + + if (st && (stsetVal(st); + + if (st) //Stored smthng + { + if (send) item->SendStatus(SEND_COMMAND | SEND_PARAMETERS); + debugSerial<setVal(st); + if (send) item->SendStatus(SEND_COMMAND | SEND_PARAMETERS ); + } + // if (item->getExt()) item->setExt(millis()+maxOnTime); //Extend motor time + return 1; + + case CMD_OFF: + if (send) item->SendStatus(SEND_COMMAND); + // if (item->getExt()) item->setExt(millis()+maxOnTime); //Extend motor time + return 1; + +} //switch cmd + +break; +} //switch suffix +debugSerial< +#include + + +class mbPersistent : public chPersistent { + +public: +// int addr + int8_t driverStatus; + int baud; + UARTClass::UARTModes serialParam; + uint16_t pollingInterval; + uint32_t timestamp; + aJsonObject * pollingRegisters; + aJsonObject * parameters; + +}; + + + +class out_Modbus : public abstractOut { +public: + + out_Modbus(Item * _item):abstractOut(_item){store = (mbPersistent *) item->getPersistent();}; + int Setup() override; + int Poll(short cause) override; + int Stop() override; + int Status() override; + int isActive() override; + int getChanType() override; + int Ctrl(short cmd, short n=0, int * Parameters=NULL, boolean send=true, int suffixCode=0, char* subItem=NULL) override; + + +protected: + mbPersistent * store; + bool getConfig(); + int findRegister(int registerNum, int posInBuffer); +}; +#endif