From c7f3f21469869bee4ec8d74854952eeaf29d4452 Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 10 Oct 2023 23:53:59 +0200 Subject: [PATCH] further improved new communication model --- src/app.cpp | 4 +- src/hm/CommQueue.h | 24 ++++--- src/hm/Communication.h | 149 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 147 insertions(+), 30 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index a834d091..684914e2 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -70,7 +70,9 @@ void app::setup() { else if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) iv->radio = &mCmtRadio; #endif - mCommunication.add(iv, 0x01, false); + mCommunication.add(iv, 0x01); + mCommunication.add(iv, 0x05); + mCommunication.add(iv, 0x0b); }); } diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 3f0e2da8..d9745eb1 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -15,13 +15,13 @@ class CommQueue { public: CommQueue() {} - void addImportant(Inverter<> *iv, uint8_t cmd, bool delIfFailed = true) { + void addImportant(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { dec(&mRdPtr); - mQueue[mRdPtr] = queue_s(iv, cmd, delIfFailed); + mQueue[mRdPtr] = queue_s(iv, cmd, delOnPop); } - void add(Inverter<> *iv, uint8_t cmd, bool delIfFailed = true) { - mQueue[mWrPtr] = queue_s(iv, cmd, delIfFailed); + void add(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { + mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop); inc(&mWrPtr); } @@ -30,12 +30,11 @@ class CommQueue { Inverter<> *iv; uint8_t cmd; uint8_t attempts; - bool delIfFailed; - bool done; + bool delOnPop; uint32_t ts; queue_s() {} queue_s(Inverter<> *i, uint8_t c, bool d) : - iv(i), cmd(c), attempts(5), done(false), ts(0), delIfFailed(d) {} + iv(i), cmd(c), attempts(5), ts(0), delOnPop(d) {} }; protected: @@ -52,9 +51,11 @@ class CommQueue { cb(true, &mQueue[mRdPtr]); } - void pop(void) { - if(!mQueue[mRdPtr].delIfFailed) + void pop(bool force = false) { + if(!mQueue[mRdPtr].delOnPop && !force) { + mQueue[mRdPtr].attempts = 5; add(mQueue[mRdPtr]); // add to the end again + } inc(&mRdPtr); } @@ -62,8 +63,9 @@ class CommQueue { mQueue[mRdPtr].ts = *ts; } - void setDone(void) { - mQueue[mRdPtr].done = true; + void setAttempt(void) { + if(mQueue[mRdPtr].attempts) + mQueue[mRdPtr].attempts--; } void inc(uint8_t *ptr) { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 1d165186..65dd2d5c 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -22,49 +22,106 @@ class Communication : public CommQueue<> { return; // empty switch(mState) { - case States::IDLE: + case States::RESET: + lastFound = false; + for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) { + mLocalBuf[i].len = 0; + } + mState = States::START; + break; + + case States::START: setTs(mTimestamp); q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - lastMillis = millis(); - lastFound = false; + mWaitTimeout = millis() + 500; + setAttempt(); mState = States::WAIT; break; case States::WAIT: - if((millis()-lastMillis) < 500) + if(millis() < mWaitTimeout) return; mState = States::CHECK_FRAMES; break; - case States::CHECK_FRAMES: - if(!q->iv->radio->loop()) + case States::CHECK_FRAMES: { + if(!q->iv->radio->loop()) { + pop(); + q->iv->radioStatistics.rxFailNoAnser++; // got nothing + mState = States::RESET; break; // radio buffer empty + } + States nextState = States::RESET; while(!q->iv->radio->mBufCtrl.empty()) { packet_t *p = &q->iv->radio->mBufCtrl.front(); q->iv->radio->mBufCtrl.pop(); + DPRINT_IVID(DBG_INFO, q->iv->id); + DPRINT(DBG_INFO, F("RX ")); + DBGPRINT(String(p->len)); + DBGPRINT(F(" CH")); + DBGPRINT(String(p->ch)); + DBGPRINT(F(", ")); + DBGPRINT(String(p->rssi)); + DBGPRINT(F("dBm | ")); + ah::dumpBuf(p->packet, p->len); + if(!checkIvSerial(&p->packet[1], q->iv)) continue; // inverter ID incorrect q->iv->radioStatistics.frmCnt++; - if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command + if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command parseFrame(p); - else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command + nextState = States::CHECK_PACKAGE; + } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command parseDevCtrl(p); yield(); } + mState = nextState; + } + break; + + case States::CHECK_PACKAGE: + if(!lastFound) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("last frame ")); + DBGPRINT(String(mMaxFrameId+1)); + DBGPRINTLN(F(" missing: Request Retransmit")); + + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + mMaxFrameId + 1), true); + setAttempt(); + mWaitTimeout = millis() + 100; + mState = States::WAIT; + break; + } + + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(mLocalBuf[i].len == 0) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("frame ")); + DBGPRINT(String(i + 1)); + DBGPRINTLN(F(" missing: Request Retransmit")); + + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); + setAttempt(); + mWaitTimeout = millis() + 100; + mState = States::WAIT; + return; + } + } + + compilePayload(q); + + pop(true); // remove done request + mState = States::RESET; // everything ok, next request break; } }); } - void gotData() { - setDone(); - } - private: inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { uint8_t tmp[4]; @@ -84,14 +141,16 @@ class Communication : public CommQueue<> { uint8_t *frameId = &p->packet[9]; if(0x00 == *frameId) return; // skip current packet - if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) + if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) { + DPRINTLN(DBG_WARN, F("local buffer to small for payload fragments!")); return; // local storage is to small for id + } if(!checkFrameCrc(p->packet, p->len)) return; // CRC8 is wrong, frame invalid if((*frameId & ALL_FRAMES) == ALL_FRAMES) { - maxFrameId = (*frameId & 0x7f); + mMaxFrameId = (*frameId & 0x7f); if(*frameId > 0x81) lastFound = true; } @@ -106,9 +165,62 @@ class Communication : public CommQueue<> { //if((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) } + inline void compilePayload(const queue_s *q) { + uint16_t crc = 0xffff, crcRcv = 0x0000; + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(i == (mMaxFrameId - 1)) { + crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len - 2, crc); + crcRcv = (mLocalBuf[i].buf[mLocalBuf[i].len-2] << 8); + crcRcv |= mLocalBuf[i].buf[mLocalBuf[i].len-1]; + } else + crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len, crc); + } + + if(crc != crcRcv) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("CRC Error ")); + if(q->attempts == 0) { + DBGPRINTLN(F("-> Fail")); + q->iv->radioStatistics.rxFail++; // got fragments but not complete response + pop(); + } else + DBGPRINTLN(F("-> complete retransmit")); + mState = States::RESET; + return; + } + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("procPyld: cmd: 0x")); + DBGHEXLN(q->cmd); + + memset(mPayload, 0, 150); + int8_t rssi = -127; + uint8_t len = 0; + + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(mLocalBuf[i].len + len > 150) { + DPRINTLN(DBG_ERROR, F("payload buffer to small!")); + return; + } + memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); + len += mLocalBuf[i].len; + // get worst RSSI + if(mLocalBuf[i].rssi > rssi) + rssi = mLocalBuf[i].rssi; + } + + len -= 2; + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("Payload (")); + DBGPRINT(String(len)); + DBGPRINT(F("): ")); + ah::dumpBuf(mPayload, len); + } + private: enum class States : uint8_t { - IDLE, WAIT, CHECK_FRAMES + RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE }; typedef struct { @@ -118,12 +230,13 @@ class Communication : public CommQueue<> { } frame_t; private: - States mState = States::IDLE; + States mState = States::RESET; uint32_t *mTimestamp; - uint32_t lastMillis; + uint32_t mWaitTimeout; std::array mLocalBuf; bool lastFound; - uint8_t maxFrameId; + uint8_t mMaxFrameId; + uint8_t mPayload[150]; }; #endif /*__COMMUNICATION_H__*/