From eb15ce5dba8b5b576a493b39e0519e4957040217 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Nov 2023 11:33:53 +0100 Subject: [PATCH 1/4] 0.8.0707 --- src/defines.h | 2 +- src/hm/CommQueue.h | 4 ++ src/hm/Communication.h | 148 +++++++++++++++++++++++------------------ src/hm/Heuristic.h | 6 +- src/hm/hmInverter.h | 5 ++ src/hm/hmRadio.h | 7 +- src/hm/radio.h | 4 ++ src/utils/helper.cpp | 7 +- src/utils/helper.h | 2 +- 9 files changed, 113 insertions(+), 72 deletions(-) diff --git a/src/defines.h b/src/defines.h index fe9acf95..21c583b0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 7 +#define VERSION_PATCH 0707 //------------------------------------- typedef struct { diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 8d0bb0f8..9771393d 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -85,6 +85,10 @@ class CommQueue { mQueue[mRdPtr].attempts--; } + void incrAttempt(void) { + mQueue[mRdPtr].attempts++; + } + void inc(uint8_t *ptr) { if(++(*ptr) >= N) *ptr = 0; diff --git a/src/hm/Communication.h b/src/hm/Communication.h index a4eb43eb..f23fe416 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -11,9 +11,10 @@ #include "../utils/crc.h" #include "Heuristic.h" -#define MI_TIMEOUT 250 -#define DEFAULT_TIMEOUT 500 -#define SINGLEFR_TIMEOUT 60 +#define MI_TIMEOUT 250 // timeout for MI type requests +#define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received +#define DEFAULT_TIMEOUT 500 // timeout for regular requests +#define SINGLEFR_TIMEOUT 60 // timeout for single frame requests #define MAX_BUFFER 250 typedef std::function *)> payloadListenerType; @@ -43,7 +44,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty - uint16_t timeout = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT; + uint16_t timeout = q->iv->ivGen != IV_MI ? (mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT : MI_TIMEOUT; + uint16_t timeout_min = q->iv->ivGen != IV_MI ? mGotFragment ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT : MI_TIMEOUT; bool testMode = false; switch(mState) { @@ -55,11 +57,13 @@ class Communication : public CommQueue<> { mLocalBuf[i].len = 0; } - mHeu.printStatus(q->iv); + if(q->iv->radio->isSerialDebug()) + mHeu.printStatus(q->iv); mHeu.getTxCh(q->iv); testMode = mHeu.getTestModeEnabled(); mGotFragment = false; - mFirstTry = mFirstTry ? false : ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()); //) || (millis() < 120000));} + q->iv->mGotLastMsg = false; + mFirstTry = mFirstTry ? false : ( ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()) || (millis() < 120000) ); if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! mState = States::START; @@ -83,12 +87,33 @@ class Communication : public CommQueue<> { q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); if(!testMode) q->iv->radioStatistics.txCnt++; - mWaitTimeout = millis() + timeout; + mWaitTimeout = millis() + timeout; + mWaitTimeout_min = millis() + timeout_min; setAttempt(); mState = States::WAIT; break; case States::WAIT: + if(millis() > mWaitTimeout_min) { + if(!mGotFragment) { // nothing received yet? + if(q->iv->radio->get()) { // radio received sth.? + mGotFragment = true; + if(q->iv->mGotLastMsg) { + //mState = States::CHECK_FRAMES; + mWaitTimeout = mWaitTimeout_min; + } + } + } else if(mFirstTry) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINTLN(F("second try")); + mFirstTry = false; + if(!testMode) + q->iv->radioStatistics.retransmits++; // got nothing + mState = States::START; + break; + } + + } if(millis() < mWaitTimeout) return; mState = States::CHECK_FRAMES; @@ -102,7 +127,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(millis() - mWaitTimeout + timeout)); DBGPRINTLN(F("ms")); - if(!mGotFragment && !mFirstTry) { + if(!mGotFragment) { // && !mFirstTry) { if(!testMode) q->iv->radioStatistics.rxFailNoAnser++; // got nothing mHeu.setGotNothing(q->iv); @@ -140,7 +165,7 @@ class Communication : public CommQueue<> { DBGPRINT(F(", ")); DBGPRINT(String(p->rssi)); DBGPRINT(F("dBm | ")); - ah::dumpBuf(p->packet, p->len); + ah::dumpBuf(p->packet, p->len, 1, 8, "#"+String(q->iv->id)); if(checkIvSerial(&p->packet[1], q->iv)) { if(!testMode) @@ -178,39 +203,37 @@ class Communication : public CommQueue<> { break; case States::CHECK_PACKAGE: + uint8_t framnr = 0; if(0 == mMaxFrameId) { - setAttempt(); - - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("frame missing: request retransmit (")); - DBGPRINT(String(q->attempts)); - DBGPRINTLN(F(" attempts left)")); - uint8_t i = 0; while(i < MAX_PAYLOAD_ENTRIES) { if(mLocalBuf[i].len == 0) + framnr = i+1; break; i++; } - - sendRetransmit(q, i); - return; } - for(uint8_t i = 0; i < mMaxFrameId; i++) { - if(mLocalBuf[i].len == 0) { - setAttempt(); + if(!framnr) { + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(mLocalBuf[i].len == 0) { + framnr = i+1; + break; + } + } + } - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("frame ")); - DBGPRINT(String(i + 1)); - DBGPRINT(F(" missing: request retransmit (")); - DBGPRINT(String(q->attempts)); - DBGPRINTLN(F(" attempts left)")); + if(framnr) { + setAttempt(); - sendRetransmit(q, i); - return; - } + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("frame ")); + DBGPRINT(String(framnr)); + DBGPRINT(F(" missing: request retransmit (")); + DBGPRINT(String(q->attempts)); + DBGPRINTLN(F(" attempts left)")); + sendRetransmit(q, framnr-1); + return; } mHeu.setGotAll(q->iv); @@ -257,8 +280,9 @@ class Communication : public CommQueue<> { return; // CRC8 is wrong, frame invalid } - if((*frameId & ALL_FRAMES) == ALL_FRAMES) + if((*frameId & ALL_FRAMES) == ALL_FRAMES) { mMaxFrameId = (*frameId & 0x7f); + } frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; memcpy(f->buf, &p->packet[10], p->len-11); @@ -413,9 +437,6 @@ class Communication : public CommQueue<> { inline void miHwDecode(packet_t *p, const queue_s *q) { record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure rec->ts = q->ts; - //mPayload[iv->id].gotFragment = true; - uint8_t multi_parts = 0; - /* Polling the device software and hardware version number command start byte Command word routing address target address User data check end byte @@ -458,14 +479,13 @@ class Communication : public CommQueue<> { q->iv->isConnected = true; //if(mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); - DPRINT(DBG_INFO,F("HW_VER is ")); + DBGPRINT(F("HW_VER is ")); DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); //} record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure rec->ts = q->ts; q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); - //mPayload[iv->id].multi_parts +=4; - multi_parts +=4; + q->iv->miMultiParts +=4; } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 DPRINT_IVID(DBG_INFO, q->iv->id); if ( p->packet[9] == 0x01 ) { @@ -486,19 +506,19 @@ class Communication : public CommQueue<> { //if(mSerialDebug) { DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); - DPRINT(DBG_INFO,F("HW_FB_ReSPRT ")); + DBGPRINT(F("HW_FB_ReSPRT ")); DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); - DPRINT(DBG_INFO,F("HW_GridSamp_ResValule ")); + DBGPRINT(F("HW_GridSamp_ResValule ")); DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); - DPRINT(DBG_INFO,F("HW_ECapValue ")); + DBGPRINT(F("HW_ECapValue ")); DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); - DPRINT(DBG_INFO,F("Matching_APPFW_PN ")); + DBGPRINT(F("Matching_APPFW_PN ")); DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); //} - //notify(InverterDevInform_Simple, iv); - //mPayload[iv->id].multi_parts +=2; - multi_parts +=2; - //notify(InverterDevInform_All, iv); + if(NULL != mCbPayload) + (mCbPayload)(InverterDevInform_All, q->iv); + q->iv->miMultiParts +=2; + } else { DBGPRINTLN(F("3rd gen. inverter!")); } @@ -515,21 +535,24 @@ class Communication : public CommQueue<> { //if(mSerialDebug) { DPRINT(DBG_INFO,F("APPFW_MINVER ")); DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); - DPRINT(DBG_INFO,F("HWInfoAddr ")); + DBGPRINT(F("HWInfoAddr ")); DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); - DPRINT(DBG_INFO,F("PNInfoCRC_gusv ")); + DBGPRINT(F("PNInfoCRC_gusv ")); DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); //} - //mPayload[iv->id].multi_parts++; - multi_parts++; + if(NULL != mCbPayload) + (mCbPayload)(InverterDevInform_Simple, q->iv); + q->iv->miMultiParts++; } - if(multi_parts > 5) { + if(q->iv->miMultiParts > 5) { cmdDone(true); mState = States::RESET; q->iv->radioStatistics.rxSuccess++; mHeu.setGotAll(q->iv); + q->iv->miMultiParts = 0; } else { mHeu.setGotFragment(q->iv); + mState = States::WAIT; } /*if (mPayload[iv->id].multi_parts > 5) { @@ -568,9 +591,8 @@ class Communication : public CommQueue<> { q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); - //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; - if (datachan == 1) //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + if (datachan == 1) q->iv->rssi = p->rssi; else if(q->iv->rssi > p->rssi) q->iv->rssi = p->rssi; @@ -597,6 +619,7 @@ class Communication : public CommQueue<> { } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { //addImportant(q->iv, MI_REQ_CH2); miNextRequest(MI_REQ_CH2, q); + //use also miMultiParts here for better statistics? mHeu.setGotFragment(q->iv); } else { // first data msg for 1ch, 2nd for 2ch miComplete(q->iv); @@ -604,25 +627,24 @@ class Communication : public CommQueue<> { } inline void miNextRequest(uint8_t cmd, const queue_s *q) { - //setAttempt(); + incrAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... DPRINT_IVID(DBG_WARN, q->iv->id); DBGPRINT(F("next request (")); DBGPRINT(String(q->attempts)); DBGPRINT(F(" attempts left): 0x")); DBGHEXLN(cmd); - if(q->attempts) { + //if(q->attempts) { q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); q->iv->radioStatistics.retransmits++; mWaitTimeout = millis() + MI_TIMEOUT; - //chgCmd(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) chgCmd(cmd); mState = States::WAIT; - } else { + /*} else { add(q, true); cmdDone(); mState = States::RESET; - } + }*/ } inline void miStsConsolidate(const queue_s *q, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) { @@ -699,13 +721,10 @@ class Communication : public CommQueue<> { inline void miComplete(Inverter<> *iv) { - //if ( mPayload[iv->id].complete ) - // return; //if we got second message as well in repreated attempt - //mPayload[iv->id].complete = true; - //if (mSerialDebug) { + if (iv->radio->isSerialDebug()) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("got all data msgs")); - //} + } record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); @@ -751,7 +770,8 @@ class Communication : public CommQueue<> { private: States mState = States::RESET; uint32_t *mTimestamp; - uint32_t mWaitTimeout = 0; + uint32_t mWaitTimeout = 0; + uint32_t mWaitTimeout_min = 0; std::array mLocalBuf; bool mGotFragment = false; bool mFirstTry = false; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 7bf9f4a9..3ad249b9 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -62,7 +62,7 @@ class Heuristic { void printStatus(Inverter<> *iv) { DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("CH qualities:")); + DBGPRINT(F("Radio infos:")); for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { DBGPRINT(F(" ")); DBGPRINT(String(iv->txRfQuality[i])); @@ -74,7 +74,9 @@ class Heuristic { DBGPRINT(F(", f: ")); DBGPRINT(String(iv->radioStatistics.rxFail)); DBGPRINT(F(", n: ")); - DBGPRINTLN(String(iv->radioStatistics.rxFailNoAnser)); + DBGPRINT(String(iv->radioStatistics.rxFailNoAnser)); + DBGPRINT(F(" | p: ")); // better debugging for helpers... + DBGPRINTLN(String(iv->config->powerLevel)); } bool getTestModeEnabled(void) { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index f3d149c4..88a19a1b 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -125,6 +125,8 @@ class Inverter { uint16_t alarmCnt; // counts the total number of occurred alarms uint16_t alarmLastId; // lastId which was received int8_t rssi; // RSSI + uint8_t miMultiParts; // helper info for MI multiframe msgs + bool mGotLastMsg; // shows if inverter has already finished transmission cycle Radio *radio; // pointer to associated radio class statistics_t radioStatistics; // information about transmitted, failed, ... packets int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h') @@ -150,8 +152,11 @@ class Inverter { alarmCnt = 0; alarmLastId = 0; rssi = -127; + miMultiParts = 0; + mGotLastMsg = false; radio = NULL; commEnabled = true; + memset(&radioStatistics, 0, sizeof(statistics_t)); memset(txRfQuality, -6, 5); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index a55c7d3c..a51504df 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -257,12 +257,14 @@ class HmRadio : public Radio { isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received - else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore fragment number zero and MI status messages //#0 was p.packet[0] != 0x00 && + else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 && isLastPackage = true; // response from dev control command } } yield(); } + if(isLastPackage) + mLastIv->mGotLastMsg = true; return isLastPackage; } @@ -280,7 +282,7 @@ class HmRadio : public Radio { DBGPRINT(" CH"); DBGPRINT(String(mTxChIdx)); DBGPRINT(F(" | ")); - ah::dumpBuf(mTxBuf, len); + ah::dumpBuf(mTxBuf, len, 1, 4, "#"+String(iv->id)); } mNrf24.stopListening(); @@ -304,6 +306,7 @@ class HmRadio : public Radio { uint8_t mRfChLst[RF_CHANNELS] = {03, 23, 40, 61, 75}; // channel List:2403, 2423, 2440, 2461, 2475MHz uint8_t mTxChIdx = 0; uint8_t mRxChIdx = 0; + bool mGotLastMsg = false; uint32_t mMillis; SPIClass* mSpi; diff --git a/src/hm/radio.h b/src/hm/radio.h index 07317e8c..e4beb071 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -38,6 +38,10 @@ class Radio { mSerialDebug = true; } + bool isSerialDebug() { + return mSerialDebug; + } + void sendCmdPacket(Inverter<> *iv, uint8_t mid, uint8_t pid, bool isRetransmit, bool appendCrc16=true) { initPacket(getIvId(iv), mid, pid); sendPacket(iv, 10, isRetransmit, appendCrc16); diff --git a/src/utils/helper.cpp b/src/utils/helper.cpp index 4050c999..c7aefc1c 100644 --- a/src/utils/helper.cpp +++ b/src/utils/helper.cpp @@ -86,9 +86,12 @@ namespace ah { return ret; } - void dumpBuf(uint8_t buf[], uint8_t len) { + void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl, uint8_t lastRepl, String repl) { for(uint8_t i = 0; i < len; i++) { - DHEX(buf[i]); + if(i < firstRepl || i > lastRepl) + DHEX(buf[i]); + else + DBGPRINT(repl); DBGPRINT(" "); } DBGPRINTLN(""); diff --git a/src/utils/helper.h b/src/utils/helper.h index 252ca9fe..296729db 100644 --- a/src/utils/helper.h +++ b/src/utils/helper.h @@ -45,7 +45,7 @@ namespace ah { String getDateTimeStrFile(time_t t); String getTimeStr(time_t t); uint64_t Serial2u64(const char *val); - void dumpBuf(uint8_t buf[], uint8_t len); + void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl = 0, uint8_t lastRepl = 0, String repl = ""); } #endif /*__HELPER_H__*/ From 08fcbb4e73e9d879f9ca633d87e9d190f12622e5 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 17 Nov 2023 10:49:03 +0100 Subject: [PATCH 2/4] Partly fix retransmit errors * move gotFragment flag --- src/hm/Communication.h | 26 +++++++++++--------------- src/hm/hmInverter.h | 2 ++ src/hm/hmRadio.h | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index f23fe416..ce2a7175 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -14,7 +14,7 @@ #define MI_TIMEOUT 250 // timeout for MI type requests #define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received #define DEFAULT_TIMEOUT 500 // timeout for regular requests -#define SINGLEFR_TIMEOUT 60 // timeout for single frame requests +#define SINGLEFR_TIMEOUT 65 // timeout for single frame requests #define MAX_BUFFER 250 typedef std::function *)> payloadListenerType; @@ -44,8 +44,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty - uint16_t timeout = q->iv->ivGen != IV_MI ? (mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT : MI_TIMEOUT; - uint16_t timeout_min = q->iv->ivGen != IV_MI ? mGotFragment ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT : MI_TIMEOUT; + uint16_t timeout = q->iv->ivGen != IV_MI ? (q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT : MI_TIMEOUT; + uint16_t timeout_min = q->iv->ivGen != IV_MI ? q->iv->mGotFragment ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT : MI_TIMEOUT; bool testMode = false; switch(mState) { @@ -61,7 +61,7 @@ class Communication : public CommQueue<> { mHeu.printStatus(q->iv); mHeu.getTxCh(q->iv); testMode = mHeu.getTestModeEnabled(); - mGotFragment = false; + q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; mFirstTry = mFirstTry ? false : ( ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()) || (millis() < 120000) ); if(NULL == q->iv->radio) @@ -95,13 +95,10 @@ class Communication : public CommQueue<> { case States::WAIT: if(millis() > mWaitTimeout_min) { - if(!mGotFragment) { // nothing received yet? - if(q->iv->radio->get()) { // radio received sth.? - mGotFragment = true; - if(q->iv->mGotLastMsg) { + if(!q->iv->mGotFragment) { // nothing received yet? + if(q->iv->mGotLastMsg) { //mState = States::CHECK_FRAMES; mWaitTimeout = mWaitTimeout_min; - } } } else if(mFirstTry) { DPRINT_IVID(DBG_INFO, q->iv->id); @@ -127,7 +124,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(millis() - mWaitTimeout + timeout)); DBGPRINTLN(F("ms")); - if(!mGotFragment) { // && !mFirstTry) { + if(!q->iv->mGotFragment) { if(!testMode) q->iv->radioStatistics.rxFailNoAnser++; // got nothing mHeu.setGotNothing(q->iv); @@ -143,7 +140,6 @@ class Communication : public CommQueue<> { break; } - mGotFragment = true; mFirstTry = false; // for correct reset States nextState = States::RESET; while(!q->iv->radio->mBufCtrl.empty()) { @@ -207,9 +203,10 @@ class Communication : public CommQueue<> { if(0 == mMaxFrameId) { uint8_t i = 0; while(i < MAX_PAYLOAD_ENTRIES) { - if(mLocalBuf[i].len == 0) + if(mLocalBuf[i].len == 0) { framnr = i+1; break; + } i++; } } @@ -280,9 +277,8 @@ class Communication : public CommQueue<> { return; // CRC8 is wrong, frame invalid } - if((*frameId & ALL_FRAMES) == ALL_FRAMES) { + if((*frameId & ALL_FRAMES) == ALL_FRAMES) mMaxFrameId = (*frameId & 0x7f); - } frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; memcpy(f->buf, &p->packet[10], p->len-11); @@ -773,7 +769,7 @@ class Communication : public CommQueue<> { uint32_t mWaitTimeout = 0; uint32_t mWaitTimeout_min = 0; std::array mLocalBuf; - bool mGotFragment = false; + //bool mGotFragment = false; bool mFirstTry = false; uint8_t mMaxFrameId; uint8_t mPayload[MAX_BUFFER]; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 88a19a1b..0b87fbb1 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -126,6 +126,8 @@ class Inverter { uint16_t alarmLastId; // lastId which was received int8_t rssi; // RSSI uint8_t miMultiParts; // helper info for MI multiframe msgs + uint8_t outstandingFrames; // helper info to count difference between expected and received frames + bool mGotFragment; // shows if inverter has sent at least one fragment bool mGotLastMsg; // shows if inverter has already finished transmission cycle Radio *radio; // pointer to associated radio class statistics_t radioStatistics; // information about transmitted, failed, ... packets diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index a51504df..d0a7b250 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -252,6 +252,12 @@ class HmRadio : public Radio { p.millis = millis() - mMillis; mNrf24.read(p.packet, p.len); if (p.packet[0] != 0x00) { + if(!checkIvSerial(&p.packet[1], mLastIv)) { + DPRINT(DBG_WARN, "RX other inverter: "); + ah::dumpBuf(p.packet, p.len); + return false; + } + mLastIv->mGotFragment = true; mBufCtrl.push(p); if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received @@ -302,6 +308,16 @@ class HmRadio : public Radio { return iv->ivGen; } + inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { + uint8_t tmp[4]; + CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); + for(uint8_t i = 0; i < 4; i++) { + if(tmp[i] != buf[i]) + return false; + } + return true; + } + uint64_t DTU_RADIO_ID; uint8_t mRfChLst[RF_CHANNELS] = {03, 23, 40, 61, 75}; // channel List:2403, 2423, 2440, 2461, 2475MHz uint8_t mTxChIdx = 0; From b57e463b92327fa393aa8de984db7161ba00094c Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Nov 2023 00:25:27 +0100 Subject: [PATCH 3/4] improved changes from PR #1234 --- src/defines.h | 2 +- src/hm/Communication.h | 10 +++++----- src/hm/hmRadio.h | 4 +--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/defines.h b/src/defines.h index 4d95b022..72f2887f 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 8 +#define VERSION_PATCH 9 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index ce2a7175..c599cadc 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -44,8 +44,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty - uint16_t timeout = q->iv->ivGen != IV_MI ? (q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT : MI_TIMEOUT; - uint16_t timeout_min = q->iv->ivGen != IV_MI ? q->iv->mGotFragment ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT : MI_TIMEOUT; + uint16_t timeout = q->iv->ivGen != IV_MI ? ((q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT) : MI_TIMEOUT; + uint16_t timeout_min = q->iv->ivGen != IV_MI ? ((q->iv->mGotFragment) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT) : MI_TIMEOUT; bool testMode = false; switch(mState) { @@ -63,7 +63,7 @@ class Communication : public CommQueue<> { testMode = mHeu.getTestModeEnabled(); q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; - mFirstTry = mFirstTry ? false : ( ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()) || (millis() < 120000) ); + mFirstTry = mFirstTry ? false : (((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()) || (millis() < 120000)); if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! mState = States::START; @@ -97,8 +97,8 @@ class Communication : public CommQueue<> { if(millis() > mWaitTimeout_min) { if(!q->iv->mGotFragment) { // nothing received yet? if(q->iv->mGotLastMsg) { - //mState = States::CHECK_FRAMES; - mWaitTimeout = mWaitTimeout_min; + //mState = States::CHECK_FRAMES; + mWaitTimeout = mWaitTimeout_min; } } else if(mFirstTry) { DPRINT_IVID(DBG_INFO, q->iv->id); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index d0a7b250..88e62f8f 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -309,10 +309,8 @@ class HmRadio : public Radio { } inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { - uint8_t tmp[4]; - CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); for(uint8_t i = 0; i < 4; i++) { - if(tmp[i] != buf[i]) + if(buf[3-i] != iv->radioId.b[i]) return false; } return true; From 49ef94cb7a1435821816807697addb0108e1d00e Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Nov 2023 01:38:54 +0100 Subject: [PATCH 4/4] 0.8.9 * merged PR #1234 * added new alarm codes * removed serial interval, was not in use anymore --- src/CHANGES.md | 5 +++ src/app.cpp | 2 +- src/config/config.h | 3 -- src/config/settings.h | 4 -- src/hm/hmInverter.h | 82 ++++++++++++++++++++++++++++++++--------- src/platformio.ini | 18 ++++----- src/web/RestApi.h | 1 - src/web/html/setup.html | 5 --- src/web/web.h | 10 +---- 9 files changed, 82 insertions(+), 48 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 380458fc..9ea5ff5d 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.9 - 2023-11-19 +* merged PR #1234 +* added new alarm codes +* removed serial interval, was not in use anymore + ## 0.8.8 - 2023-11-16 * fix ESP8266 save inverter #1232 diff --git a/src/app.cpp b/src/app.cpp index edd58306..5226f5ac 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -142,7 +142,7 @@ void app::regularTickers(void) { if (mConfig->plugin.display.type != 0) everySec(std::bind(&DisplayType::tickerSecond, &mDisplay), "disp"); #endif - every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval, "uart"); + every(std::bind(&PubSerialType::tick, &mPubSerial), 5, "uart"); #if !defined(ETHERNET) //everySec([this]() { mImprov.tickSerial(); }, "impro"); #endif diff --git a/src/config/config.h b/src/config/config.h index e9d3adec..5b17ca9d 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -142,9 +142,6 @@ #define MAX_NUM_INVERTERS 4 #endif -// default serial interval -#define SERIAL_INTERVAL 5 - // default send interval #define SEND_INTERVAL 15 diff --git a/src/config/settings.h b/src/config/settings.h index 76a42e23..50632d0a 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -114,7 +114,6 @@ typedef struct { } cfgSun_t; typedef struct { - uint16_t interval; bool showIv; bool debug; } cfgSerial_t; @@ -423,7 +422,6 @@ class settings { mCfg.sun.lon = 0.0; mCfg.sun.offsetSec = 0; - mCfg.serial.interval = SERIAL_INTERVAL; mCfg.serial.showIv = false; mCfg.serial.debug = false; @@ -617,11 +615,9 @@ class settings { void jsonSerial(JsonObject obj, bool set = false) { if(set) { - obj[F("intvl")] = mCfg.serial.interval; obj[F("show")] = mCfg.serial.showIv; obj[F("debug")] = mCfg.serial.debug; } else { - getVal(obj, F("intvl"), &mCfg.serial.interval); getVal(obj, F("show"), &mCfg.serial.showIv); getVal(obj, F("debug"), &mCfg.serial.debug); } diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 0b87fbb1..eddf0664 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -594,14 +594,40 @@ class Inverter { static String getAlarmStr(uint16_t alarmCode) { switch (alarmCode) { // breaks are intentionally missing! case 1: return String(F("Inverter start")); - case 2: return String(F("DTU command failed")); - case 73: return String(F("Temperature >80°C")); // https://github.com/tbnobody/OpenDTU/discussions/590#discussioncomment-6049750 + case 2: return String(F("Time calibration")); + case 3: return String(F("EEPROM reading and writing error during operation")); + case 4: return String(F("Offline")); + case 11: return String(F("Grid voltage surge")); + case 12: return String(F("Grid voltage sharp drop")); + case 13: return String(F("Grid frequency mutation")); + case 14: return String(F("Grid phase mutation")); + case 15: return String(F("Grid transient fluctuation")); + case 36: return String(F("INV overvoltage or overcurrent")); + case 46: return String(F("FB overvoltage")); + case 47: return String(F("FB overcurrent")); + case 48: return String(F("FB clamp overvoltage")); + case 49: return String(F("FB clamp overvoltage")); + case 61: return String(F("Calibration parameter error")); + case 62: return String(F("System configuration parameter error")); + case 63: return String(F("Abnormal power generation data")); + + case 71: return String(F("Grid overvoltage load reduction (VW) function enable")); + case 72: return String(F("Power grid over-frequency load reduction (FW) function enable")); + case 73: return String(F("Over-temperature load reduction (TW) function enable")); + + case 95: return String(F("PV-1: Module in suspected shadow")); + case 96: return String(F("PV-2: Module in suspected shadow")); + case 97: return String(F("PV-3: Module in suspected shadow")); + case 98: return String(F("PV-4: Module in suspected shadow")); + case 121: return String(F("Over temperature protection")); + case 122: return String(F("Microinverter is suspected of being stolen")); + case 123: return String(F("Locked by remote control")); case 124: return String(F("Shut down by remote control")); case 125: return String(F("Grid configuration parameter error")); - case 126: return String(F("Software error code 126")); + case 126: return String(F("EEPROM reading and writing error")); case 127: return String(F("Firmware error")); - case 128: return String(F("Software error code 128")); + case 128: return String(F("Hardware configuration error")); case 129: return String(F("Abnormal bias")); case 130: return String(F("Offline")); case 141: return String(F("Grid: Grid overvoltage")); @@ -613,7 +639,12 @@ class Inverter { case 147: return String(F("Grid: Power grid outage")); case 148: return String(F("Grid: Grid disconnection")); case 149: return String(F("Grid: Island detected")); + + case 150: return String(F("DCI exceeded")); + case 171: return String(F("Grid: Abnormal phase difference between phase to phase")); + case 181: return String(F("Abnormal insulation impedance")); + case 182: return String(F("Abnormal grounding")); case 205: return String(F("MPPT-A: Input overvoltage")); case 206: return String(F("MPPT-B: Input overvoltage")); case 207: return String(F("MPPT-A: Input undervoltage")); @@ -632,24 +663,33 @@ class Inverter { case 220: return String(F("PV-3: Input undervoltage")); case 221: return String(F("PV-4: Input overvoltage")); case 222: return String(F("PV-4: Input undervoltage")); - case 301: return String(F("Hardware error code 301")); - case 302: return String(F("Hardware error code 302")); - case 303: return String(F("Hardware error code 303")); - case 304: return String(F("Hardware error code 304")); - case 305: return String(F("Hardware error code 305")); - case 306: return String(F("Hardware error code 306")); - case 307: return String(F("Hardware error code 307")); - case 308: return String(F("Hardware error code 308")); + + case 301: return String(F("FB short circuit failure")); + case 302: return String(F("FB short circuit failure")); + case 303: return String(F("FB overcurrent protection failure")); + case 304: return String(F("FB overcurrent protection failure")); + case 305: return String(F("FB clamp circuit failure")); + case 306: return String(F("FB clamp circuit failure")); + case 307: return String(F("INV power device failure")); + case 308: return String(F("INV overcurrent or overvoltage protection failure")); case 309: return String(F("Hardware error code 309")); case 310: return String(F("Hardware error code 310")); case 311: return String(F("Hardware error code 311")); case 312: return String(F("Hardware error code 312")); case 313: return String(F("Hardware error code 313")); case 314: return String(F("Hardware error code 314")); - case 5041: return String(F("Error code-04 Port 1")); - case 5042: return String(F("Error code-04 Port 2")); - case 5043: return String(F("Error code-04 Port 3")); - case 5044: return String(F("Error code-04 Port 4")); + + case 5011: return String(F("PV-1: MOSFET overcurrent (II)")); + case 5012: return String(F("PV-2: MOSFET overcurrent (II)")); + case 5013: return String(F("PV-3: MOSFET overcurrent (II)")); + case 5014: return String(F("PV-4: MOSFET overcurrent (II)")); + case 5020: return String(F("H-bridge MOSFET overcurrent or H-bridge overvoltage")); + + case 5041: return String(F("PV-1: current overcurrent (II)")); + case 5042: return String(F("PV-2: current overcurrent (II)")); + case 5043: return String(F("PV-3: current overcurrent (II)")); + case 5044: return String(F("PV-4: current overcurrent (II)")); + case 5051: return String(F("PV Input 1 Overvoltage/Undervoltage")); case 5052: return String(F("PV Input 2 Overvoltage/Undervoltage")); case 5053: return String(F("PV Input 3 Overvoltage/Undervoltage")); @@ -659,10 +699,18 @@ class Inverter { case 5080: return String(F("Grid Overvoltage/Undervoltage")); case 5090: return String(F("Grid Overfrequency/Underfrequency")); case 5100: return String(F("Island detected")); + case 5110: return String(F("GFDI")); case 5120: return String(F("EEPROM reading and writing error")); + case 5141: + case 5142: + case 5143: + case 5144: + return String(F("FB clamp overvoltage")); case 5150: return String(F("10 min value grid overvoltage")); + case 5160: return String(F("Grid transient fluctuation")); case 5200: return String(F("Firmware error")); - case 8310: return String(F("Shut down")); + case 8310: return String(F("Shut down by remote control")); + case 8320: return String(F("Locked by remote control")); case 9000: return String(F("Microinverter is suspected of being stolen")); default: return String(F("Unknown")); } diff --git a/src/platformio.ini b/src/platformio.ini index d3c3c43c..e7c87979 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -25,9 +25,9 @@ extra_scripts = lib_deps = https://github.com/yubox-node-org/ESPAsyncWebServer - nrf24/RF24 @ 1.4.7 + nrf24/RF24 @ 1.4.8 paulstoffregen/Time @ ^1.6.1 - https://github.com/bertmelis/espMqttClient#v1.4.5 + https://github.com/bertmelis/espMqttClient#v1.5.0 bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.7 @@ -71,7 +71,7 @@ monitor_filters = esp8266_exception_decoder [env:esp32-wroom32] -platform = espressif32@6.3.2 +platform = espressif32@6.4.0 board = lolin_d32 build_flags = ${env.build_flags} -DUSE_HSPI_FOR_EPD @@ -79,7 +79,7 @@ monitor_filters = esp32_exception_decoder [env:esp32-wroom32-prometheus] -platform = espressif32@6.3.2 +platform = espressif32@6.4.0 board = lolin_d32 build_flags = ${env.build_flags} -DUSE_HSPI_FOR_EPD @@ -93,9 +93,9 @@ board = esp32dev lib_deps = khoih-prog/AsyncWebServer_ESP32_W5500 khoih-prog/AsyncUDP_ESP32_W5500 - nrf24/RF24 @ ^1.4.7 + nrf24/RF24 @ ^1.4.8 paulstoffregen/Time @ ^1.6.1 - https://github.com/bertmelis/espMqttClient#v1.4.4 + https://github.com/bertmelis/espMqttClient#v1.5.0 bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.7 @@ -110,7 +110,7 @@ monitor_filters = esp32_exception_decoder [env:esp32-s2-mini] -platform = espressif32@6.3.2 +platform = espressif32@6.4.0 board = lolin_s2_mini build_flags = ${env.build_flags} -DUSE_HSPI_FOR_EPD @@ -124,7 +124,7 @@ monitor_filters = esp32_exception_decoder [env:opendtufusion] -platform = espressif32@6.3.2 +platform = espressif32@6.4.0 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin build_flags = ${env.build_flags} @@ -147,7 +147,7 @@ monitor_filters = esp32_exception_decoder, colorize [env:opendtufusion-dev] -platform = espressif32@6.3.2 +platform = espressif32@6.4.0 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin build_flags = ${env.build_flags} diff --git a/src/web/RestApi.h b/src/web/RestApi.h index d44e0f1e..2378819c 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -559,7 +559,6 @@ class RestApi { } void getSerial(JsonObject obj) { - obj[F("interval")] = (uint16_t)mConfig->serial.interval; obj[F("show_live_data")] = mConfig->serial.showIv; obj[F("debug")] = mConfig->serial.debug; } diff --git a/src/web/html/setup.html b/src/web/html/setup.html index c1c1c841..aa0f5435 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -48,10 +48,6 @@
Serial Debug
-
-
Interval [s]
-
-
@@ -939,7 +935,6 @@ function parseSerial(obj) { for(var i of [["serEn", "show_live_data"], ["serDbg", "debug"]]) document.getElementsByName(i[0])[0].checked = obj[i[1]]; - document.getElementsByName("serIntvl")[0].value = obj["interval"]; } function parseDisplay(obj, type, system) { diff --git a/src/web/web.h b/src/web/web.h index ae2fc091..a795d5ed 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -558,14 +558,8 @@ class Web { mConfig->mqtt.interval = request->arg("mqttInterval").toInt(); // serial console - if (request->arg("serIntvl") != "") { - mConfig->serial.interval = request->arg("serIntvl").toInt() & 0xffff; - - mConfig->serial.debug = (request->arg("serDbg") == "on"); - mConfig->serial.showIv = (request->arg("serEn") == "on"); - // Needed to log TX buffers to serial console - // mSys->Radio.mSerialDebug = mConfig->serial.debug; - } + mConfig->serial.debug = (request->arg("serDbg") == "on"); + mConfig->serial.showIv = (request->arg("serEn") == "on"); // display mConfig->plugin.display.pwrSaveAtIvOffline = (request->arg("disp_pwr") == "on");