diff --git a/build-flags/build_flags_stm32-noip b/build-flags/build_flags_stm32-noip index fafe4e8..263c950 100644 --- a/build-flags/build_flags_stm32-noip +++ b/build-flags/build_flags_stm32-noip @@ -15,6 +15,7 @@ -D CANDRV -D THERMOSTAT_CHECK_PERIOD=5000 +-D ULTRASONIC -DENABLE_HWSERIAL1 diff --git a/compiled/lighthub21/firmware.bin b/compiled/lighthub21/firmware.bin index 209394a..e79b6e6 100644 Binary files a/compiled/lighthub21/firmware.bin and b/compiled/lighthub21/firmware.bin differ diff --git a/lighthub/candriver.cpp b/lighthub/candriver.cpp index bf36fe8..bef8e3a 100644 --- a/lighthub/candriver.cpp +++ b/lighthub/candriver.cpp @@ -52,7 +52,7 @@ bool canDriver::upTime(uint32_t ut) packet.metric1=ut; - debugSerial<<("UpTime")<mac); //debugSerial<<"ID requested"<type == aJson_Int)) { - debugSerial<valueint << endl; + debugSerial<valueint << endl; return addrObj->valueint; } @@ -531,7 +531,7 @@ return 0; bool canDriver::write(uint32_t msg_id, datagram_t * buf, uint8_t size) { //return 0; - if (!ready) errorSerial<<"CAN not initialized"<8) size = 8; @@ -542,8 +542,8 @@ bool canDriver::write(uint32_t msg_id, datagram_t * buf, uint8_t size) CAN_TX_msg.id = msg_id; CAN_TX_msg.flags.extended = 1; // To enable extended ID CAN_TX_msg.len=size; - if (res=STMCan.write(CAN_TX_msg)) debugSerial<<("CAN Wrote ")<data,size); //for(uint8_t i=0;idata[i]; res=Can0.sendFrame(CAN_TX_msg); - if (res) debugSerial<<("CAN Wrote ")<type) + { + case aJson_Int: cmd.setSuffix(sfx->valueint); + break; + case aJson_String: + int suffix=txt2subItem(sfx->valuestring); + if (suffix) cmd.setSuffix(suffix); + } debugSerial<valueint << ":" << it->valueint<type == aJson_Int && it->type == aJson_Int) return sendCommand(dev->valueint, it->valueint, cmd, status); @@ -621,8 +631,8 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID, itemCmd cmd, bool st res=write (id.id,&packet,8); - if (res) debugSerial<write (id.id, &writeBuffer, len); writePos=0; @@ -662,37 +672,48 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID, itemCmd cmd, bool st { case canState::StreamOpenedRead: readPos = 0; - res= driver->requestFrame(devId,pType); //Requesting frame; + res= driver->requestFrame(devId,pType,seqNo); //Requesting frame; if (res) state = canState::FrameRequested; else { state = canState::Error; return -1; - } + } + if (seqNo ==0xFFFF) seqNo =0; //continue case canState::FrameRequested: - { - uint32_t timer = millis(); + { int c; - + + uint32_t timer = millis(); do { - debugSerial.print("."); + //debugSerial.print("."); yield(); - if (c=driver->readFrame()>0 && (driver->RXid.deviceId == devId) && (driver ->RXid.payloadType == pType)) + if ((c=driver->readFrame()>0) && (driver->RXid.deviceId == devId) && (driver ->RXid.payloadType == pType) && driver->RXid.status) { state = canState::FrameReceived; - debugSerial<RXlen<< " "<RXpacket.payload<RXlen<< " "<RXpacket.payload<<"#"<RXid.itemId<RXid.itemId; + failedCount=0; return driver->RXlen; } } while((!isTimeOver(timer,millis(),1000UL)) ); + + debugSerial<=3) + { + state = canState::Error; + return -1; + } - debugSerial<RXid.payloadType == pType) && (driver->RXid.status == 0) ) - state = canState::StreamOpenedWrite; + { + debugSerial<RXid.itemId<RXid.itemId) + { + state = canState::StreamOpenedWrite; + seqNo++; + } + else + { + state = canState::Error; + errorSerial<RXlen; @@ -772,7 +808,7 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID, itemCmd cmd, bool st if (isTimeOver(timer,millis(),1000UL)) { state = canState::Error; - errorSerial<=8) { - bool res = send(8); + bool res = send(8,seqNo); if (res) state = canState::waitingConfirm; else state = canState::Error; return res; @@ -791,7 +827,7 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID, itemCmd cmd, bool st void canStream::flush() { - send(writePos); + send(writePos,seqNo); }; diff --git a/lighthub/candriver.h b/lighthub/candriver.h index ff46e24..fbe2878 100644 --- a/lighthub/candriver.h +++ b/lighthub/candriver.h @@ -118,7 +118,7 @@ bool sendCommand(aJsonObject * can,itemCmd cmd, bool status = false); bool upTime(uint32_t ut); bool salt(uint32_t salt); bool lookupMAC(); -bool requestFrame(uint8_t devId, payloadType _payloadType ); +bool requestFrame(uint8_t devId, payloadType _payloadType, uint16_t seqNo ); int readFrame(); bool sendRemoteID(macAddress mac); bool begin(); @@ -161,13 +161,15 @@ extern aJsonObject * topics; class canStream : public Stream { public: - canStream(canDriver * _driver) : readPos(0),writePos(0),devId(0), pType(payloadType::unknown),state(canState::stateUnknown){driver=_driver; } + canStream(canDriver * _driver) : readPos(0),writePos(0),devId(0), pType(payloadType::unknown),state(canState::stateUnknown),seqNo(0),failedCount(0){driver=_driver; } int open(uint8_t controllerID, payloadType _pType, char _mode) { if (mode) close(); devId=controllerID; pType = _pType; mode = _mode; + seqNo=0xFFFF; + failedCount=0; if (mode == 'w') state=canState::StreamOpenedWrite; else state=canState::StreamOpenedRead; return 1; @@ -194,7 +196,7 @@ public: private: - int send(uint8_t len); + int send(uint8_t len, uint16_t _seqNo); int checkState(); canDriver * driver; unsigned int readPos; @@ -203,6 +205,8 @@ private: datagram_t writeBuffer; uint8_t devId; + uint16_t seqNo; + int8_t failedCount; char mode; payloadType pType; canState state; diff --git a/lighthub/flashstream.cpp b/lighthub/flashstream.cpp index 735e627..7b09186 100644 --- a/lighthub/flashstream.cpp +++ b/lighthub/flashstream.cpp @@ -237,7 +237,7 @@ NRFFlashStorage EEPROM; { samBufferPos = 0; EEPROM.write(startPos+pos-sizeof(samBuffer),(byte*)samBuffer,sizeof(samBuffer)); - + } samBuffer[samBufferPos++]=ch; diff --git a/lighthub/inputs.cpp b/lighthub/inputs.cpp index 9ec6d01..6bed6dd 100644 --- a/lighthub/inputs.cpp +++ b/lighthub/inputs.cpp @@ -44,6 +44,14 @@ extern canDriver LHCAN; #include "Adafruit_MCP23X17.h" Adafruit_MCP23X17 mcp; #endif + +#ifdef ULTRASONIC +#define US_TRIG PA_14 //pin49 +#define US_ECHO PA_15 //pin50 +#include "Ultrasonic.h" +Ultrasonic ultrasonic(US_TRIG, US_ECHO); +#endif + #if not defined (NOIP) extern PubSubClient mqttClient; #endif @@ -107,6 +115,7 @@ void Input::Parse(aJsonObject * configObj) store = NULL; inType = 0; pin = 0; + pin2 =0; if (!inputObj || !root) return; if (!configObj) configObj = inputObj; @@ -118,10 +127,25 @@ void Input::Parse(aJsonObject * configObj) if (itemBuffer) inType = static_cast(itemBuffer->valueint); itemBuffer = aJson.getObjectItem(configObj, "#"); - if (itemBuffer) pin = static_cast(itemBuffer->valueint); - else pin = static_cast(atoi(configObj->name)); - } + if (itemBuffer) + switch (itemBuffer->type) + { + case aJson_Int: + pin = static_cast(itemBuffer->valueint); + + break; + case aJson_Array: + if ((itemBuffer->child) && (itemBuffer->child->type == aJson_Int)) + { + pin = static_cast(itemBuffer->child->valueint); + if ((itemBuffer->child->child) && (itemBuffer->child->child->type == aJson_Int)) + pin = static_cast(itemBuffer->child->child->valueint); + } + } //switch + else pin = static_cast(atoi(configObj->name)); + + } // Persistant storage itemBuffer = aJson.getObjectItem(inputObj, "@S"); if (!itemBuffer) { @@ -135,8 +159,10 @@ void Input::Parse(aJsonObject * configObj) void cleanStore(aJsonObject * input) { -if (input->type == aJson_Object) { +if (input && (input->type == aJson_Object)) { // Check for nested inputs + Input in(input); + in.store->aslong = 0; aJsonObject * inputArray = aJson.getObjectItem(input, "act"); if (inputArray && (inputArray->type == aJson_Array)) { @@ -153,9 +179,8 @@ if (input->type == aJson_Object) { } else { - Input in(input); - in.store->aslong = 0; - //in.Poll(CHECK_INPUT); + // Input in(input); + // in.store->aslong = 0; } } } @@ -267,6 +292,14 @@ switch (cause) { break; } break; + case CHECK_ULTRASONIC: + switch (inType) + { + case IN_ULTRASONIC: + analogPoll(cause); + contactPoll(cause); + } + break; case CHECK_SENSOR: //Slow polling switch (inType) { @@ -528,7 +561,8 @@ debugSerial << F("IN:") << pin << F(" DHT22 type. T=") << temp << F("°C H=") << #endif // TODO Polling via timed interrupt with CHECK_INTERRUPT cause -bool Input::changeState(uint8_t newState, short cause) +bool Input:: +changeState(uint8_t newState, short cause) { if (!inputObj || !store) return false; @@ -666,8 +700,11 @@ if (newState!=store->state && cause!=CHECK_INTERRUPT) debugSerial<type == aJson_Array) + if ((isAnalogPin(pin) || (inType == IN_ULTRASONIC)) && (mapObj=aJson.getObjectItem(inputObj, "map")) && mapObj->type == aJson_Array) { - int value = inCache.analogReadCached(pin); + int value = inCache.analogReadCached(pin,pin2,inType); if (value >= aJson.getArrayItem(mapObj, 0)->valueint && value <= aJson.getArrayItem(mapObj, 1)->valueint) currentInputState = true; else currentInputState = false; @@ -801,7 +838,7 @@ if (cause != CHECK_INTERRUPT) switch (store->state) //Timer based transitions // onContactChanged(currentInputState); //Legacy input - to remove later bool res = true; - if (currentInputState) //Button pressed state transitions + if (currentInputState) //Button pressed state transitions switch (store->state) { @@ -896,7 +933,7 @@ void Input::analogPoll(short cause) { pinMode(pin, inputPinMode); */ - inputVal = inCache.analogReadCached(pin); + inputVal = inCache.analogReadCached(pin,pin2,inType); // Mapping if (inputMap && inputMap->type == aJson_Array) { @@ -1110,8 +1147,18 @@ readCache::readCache() cached_data = 0; } -uint16_t readCache::analogReadCached (uint8_t _pin) +uint16_t readCache::analogReadCached (uint8_t _pin, uint8_t trigPin, uint8_t _type ) { +#ifdef ULTRASONIC +if (_type == IN_ULTRASONIC) +{ + if ((_pin==addr) && (IN_ULTRASONIC == type)) return cached_data; + type = IN_ULTRASONIC; + cached_data=ultrasonic.read(); + //debugSerial<=0) cmd.cmdCode = cmdN; + + bool hsvflag=false; + + switch (cmd.cmdCode) { + case CMD_HSV: + hsvflag=true; + case CMD_RGB: + + cmd.cmdCode=CMD_VOID; + //Parsing integers from payload + i = 0; + + while (_cmd && i < 4) + Par[i++] = getIntFromStr((char **) &_cmd); + + if (hsvflag) + { + setSuffix(S_HSV); + cmd.itemArgType=ST_HSV255; + switch (i) //Number of params + { + case 4: + setColorTemp(Par[3]); + case 3: + param.v=Par[2]; + case 2: + setH(Par[0]); + setS(Par[1]); + } + } + else + { + setSuffix(S_RGB); + switch (i) //Number of params + { + case 3: RGB(Par[0],Par[1],Par[2]); + break; + case 4: RGBW(Par[0],Par[1],Par[2],Par[3]); + default:; + } + } + + break; + + // case CMD_UNKNOWN: //Not known command + // case CMD_JSON: //JSON input (not implemented yet + // cmd.cmdCode=CMD_VOID; + // break; + + default: //some known command + //case CMD_VOID: + //case CMD_UP: + //case CMD_DN: + { + itemCmd num =getNumber((char **) &_cmd); + cmd.itemArgType=num.getArgType(); + param.aslong=num.param.aslong; + if (cmd.cmdCode) setSuffix(S_CMD); + } + } //switch + //debugOut(); } itemCmd itemCmd::setChanType(short chanType) diff --git a/lighthub/main.cpp b/lighthub/main.cpp index c3ef630..29c1841 100644 --- a/lighthub/main.cpp +++ b/lighthub/main.cpp @@ -148,6 +148,7 @@ volatile unsigned long timerCount=0; volatile int16_t timerNumber=-1; volatile int8_t timerHandlerBusy=0; volatile uint32_t cryptoSalt=0; +volatile uint32_t ultrasonicInputCheck=0; //uint32_t timerCtr=0; aJsonObject *pollingItem = NULL; @@ -778,14 +779,30 @@ lan_status lanLoop() { lanStatus=READ_RE_CONFIG; break; + case AWAITING_CONFIG: + if (isTimeOver(timerLanCheckTime,millis(),TIMEOUT_REINIT_NOT_CONFIGURED)) + lanStatus=DO_REINIT; + break; + case READ_RE_CONFIG: // Restore config from FLASH, re-init LAN - if (loadConfigFromEEPROM()) lanStatus = IP_READY_CONFIG_LOADED_CONNECTING_TO_BROKER; - else + switch (loadConfigFromEEPROM()) + { + case 1: lanStatus = IP_READY_CONFIG_LOADED_CONNECTING_TO_BROKER; + break; + + case -1: //Temporary busy if (isTimeOver(timerLanCheckTime,millis(),TIMEOUT_RELOAD)) { errorSerial< timerInputCheck) if (isTimeOver(timerInputCheck,millis(),INTERVAL_CHECK_INPUT)) { + if ((cause != CHECK_INTERRUPT) && isTimeOver(ultrasonicInputCheck,millis(),INTERVAL_CHECK_ULTRASONIC)) needCheckUltrasonic=true; + aJsonObject *input = inputs->child; while (input) { if (input->type == aJson_Object) { + + Input in(input); + in.Poll(cause); + if (needCheckUltrasonic) in.Poll(CHECK_ULTRASONIC); + // Check for nested inputs aJsonObject * inputArray = aJson.getObjectItem(input, "act"); if (inputArray && (inputArray->type == aJson_Array)) @@ -2974,6 +2999,7 @@ configLocked++; { Input in(inputObj,input); in.Poll(cause); + if (needCheckUltrasonic) in.Poll(CHECK_ULTRASONIC); //yield(); inputObj = inputObj->next; @@ -2982,14 +3008,16 @@ configLocked++; } else { - Input in(input); - in.Poll(cause); + //Input in(input); + //in.Poll(cause); + //if (needCheckUltrasonic) in.Poll(CHECK_ULTRASONIC); } } //yield(); input = input->next; } - if (cause != CHECK_INTERRUPT) timerInputCheck = millis();// + INTERVAL_CHECK_INPUT; + if (cause != CHECK_INTERRUPT) timerInputCheck = millis(); + if (needCheckUltrasonic) {ultrasonicInputCheck = millis(); needCheckUltrasonic=false;} inCache.invalidateInputCache(); } configLocked--; diff --git a/lighthub/main.h b/lighthub/main.h index 82dde7c..c695af2 100644 --- a/lighthub/main.h +++ b/lighthub/main.h @@ -232,7 +232,8 @@ enum lan_status { DO_NOTHING = -15, DO_GET = -16, GET = -17, - GET_IN_PROGRESS = 18 + GET_IN_PROGRESS = 18, + AWAITING_CONFIG = 19 }; extern lan_status lanStatus; diff --git a/lighthub/options.h b/lighthub/options.h index d117a17..17f65b4 100644 --- a/lighthub/options.h +++ b/lighthub/options.h @@ -77,6 +77,7 @@ #define TIMEOUT_REINIT 5000UL #define TIMEOUT_RELOAD 30000UL #define TIMEOUT_RETAIN 8000UL +#define TIMEOUT_REINIT_NOT_CONFIGURED 120000UL #define INTERVAL_1W 5000UL #define PERIOD_THERMOSTAT_FAILED (600 * 1000UL) @@ -120,6 +121,8 @@ #define INTERVAL_CHECK_INPUT 11 #endif +#define INTERVAL_CHECK_ULTRASONIC 100 + #ifndef TIMER_CHECK_INPUT #define TIMER_CHECK_INPUT 15 #endif diff --git a/lighthub/seekablestream.h b/lighthub/seekablestream.h index e1fdbe1..b8423b2 100644 --- a/lighthub/seekablestream.h +++ b/lighthub/seekablestream.h @@ -22,7 +22,7 @@ virtual unsigned int seek(unsigned int _pos = 0) = 0; virtual int open(String _filename, char mode) = 0; virtual void close() = 0; virtual uint16_t getContentType() {return contentType;}; -virtual void putEOF() {if (textMode) write (EOFchar);}; +virtual void putEOF() {if (textMode) {write (EOFchar);textMode=false;}}; }; #endif \ No newline at end of file diff --git a/lighthub/utils.cpp b/lighthub/utils.cpp index 97ba569..ad4dea6 100644 --- a/lighthub/utils.cpp +++ b/lighthub/utils.cpp @@ -110,7 +110,7 @@ return !err; // chan is pointer to pointer to string // Function return first retrived integer and move pointer to position next after ',' -long getInt(char **chan) { +long getIntFromStr(char **chan) { if (chan && *chan && **chan) { //Skip non-numeric values diff --git a/lighthub/utils.h b/lighthub/utils.h index 1220a66..91a86e8 100644 --- a/lighthub/utils.h +++ b/lighthub/utils.h @@ -53,7 +53,7 @@ void PrintBytes(uint8_t* addr, uint8_t count, bool newline); void SetBytes(uint8_t* addr, uint8_t count, char * out); bool SetAddr(char * in, uint8_t* addr); uint8_t HEX2DEC(char i, bool* err); -long getInt(char ** chan); +long getIntFromStr(char **chan); itemCmd getNumber(char ** chan); unsigned long freeRam (); void parseBytes(const char* str, char separator, byte* bytes, int maxBytes, int base);