From 81f7c350d025710d956d2dad9d004cf4c78cb8ae Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 23 Jan 2024 11:53:50 +0100 Subject: [PATCH 01/14] dynamic retries discord version 0.8.6401 --- src/hm/Communication.h | 10 +++++++-- src/hm/Heuristic.h | 48 ++++++++++++++++++++++++++++++++++++++++-- src/hm/HeuristicInv.h | 3 +++ src/hm/hmRadio.h | 12 +++++++++-- src/hm/radio.h | 1 + 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 98dd06e1..60e87918 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -148,6 +148,7 @@ class Communication : public CommQueue<> { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); mWaitTime.startTimeMonitor(1000); } else { + mHeu.setIvRetriesBad(q->iv); if(IV_MI == q->iv->ivGen) q->iv->mIvTxCnt++; @@ -180,8 +181,11 @@ class Communication : public CommQueue<> { q->iv->mDtuRxCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - if(parseFrame(p)) + if(parseFrame(p)) { q->iv->curFrmCnt++; + if(!mIsRetransmit && p->packet[9] == 2 && p->millis < 85) + mHeu.setIvRetriesGood(q->iv,p->millis < 70); + } } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command if(parseDevCtrl(p, q)) closeRequest(q, true); @@ -417,6 +421,8 @@ class Communication : public CommQueue<> { } inline bool parseMiFrame(packet_t *p, const queue_s *q) { + if(!mIsRetransmit && p->packet[9] == 0x00 && p->millis < 35) //first frame is fast? + mHeu.setIvRetriesGood(q->iv,p->millis < 22); if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) @@ -527,7 +533,7 @@ class Communication : public CommQueue<> { len -= 2; - DPRINT_IVID(DBG_INFO, q->iv->id); + //DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("Payload (")); DBGPRINT(String(len)); if(*mPrintWholeTrace) { diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 64c78cc8..642eca13 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -23,8 +23,8 @@ class Heuristic { public: uint8_t getTxCh(Inverter<> *iv) { - if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) - return 0; // not used for these inverter types + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return 0; // not used for other than nRF inverter types HeuristicInv *ih = &iv->heuristics; @@ -66,6 +66,8 @@ class Heuristic { ih->testPeriodFailCnt = 0; } + iv->radio->mTxRetriesNext = getIvRetries(iv); + return id2Ch(ih->txRfChId); } @@ -155,6 +157,48 @@ class Heuristic { DBGPRINTLN(String(iv->config->powerLevel)); } + uint8_t getIvRetries(Inverter<> *iv) { + if(iv->heuristics.rxSpeeds[0]) + return 5; + if(iv->heuristics.rxSpeeds[1]) + return 10; + return 15; + } + + void setIvRetriesGood(Inverter<> *iv, bool veryGood) { + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return; // not used for other than nRF inverter types + + if(iv->heuristics.rxSpeedCnt[veryGood] > 9) + return; + iv->heuristics.rxSpeedCnt[veryGood]++; + iv->heuristics.rxSpeeds[veryGood] = true; + } + + void setIvRetriesBad(Inverter<> *iv) { + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return; // not used for other than nRF inverter types + + if(iv->heuristics.rxSpeedCnt[0]) { + iv->heuristics.rxSpeedCnt[0]--; + return; + } + if(iv->heuristics.rxSpeeds[0]) { + iv->heuristics.rxSpeeds[0] = false; + return; + } + + if(iv->heuristics.rxSpeedCnt[1]) { + iv->heuristics.rxSpeedCnt[1]--; + return; + } + if(iv->heuristics.rxSpeeds[1]) { + iv->heuristics.rxSpeeds[1] = false; + return; + } + return; + } + private: bool isNewTxCh(HeuristicInv *ih) { return ih->txRfChId != ih->lastBestTxChId; diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index e7ad6edd..fc782a7b 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -27,6 +27,9 @@ class HeuristicInv { uint8_t testChId = 0; int8_t saveOldTestQuality = -6; uint8_t lastRxFragments = 0; + bool rxSpeeds[2] = {false,false}; // is inverter responding very fast respective fast? + uint8_t rxSpeedCnt[2] = {0,0}; // count how many messages had been received very fast respective fast (10 max) + }; #endif /*__HEURISTIC_INV_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index ef37e266..d41dc36a 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -161,7 +161,7 @@ class HmRadio : public Radio { rxPendular = false; mNRFloopChannels = (mLastIv->ivGen == IV_MI); - innerLoopTimeout = DURATION_TXFRAME; + innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; } if(rx_ready) { @@ -356,11 +356,14 @@ class HmRadio : public Radio { mTxChIdx = iv->heuristics.txRfChId; if(*mSerialDebug) { + /* remark rejoe2: imo this has no added value here. + As this belongs to the last tx cycle, we should print that info + directly when switching from tx to rx. Otherwise we might confuse users. if(!isRetransmit) { DPRINT(DBG_INFO, "last tx setup: "); DBGPRINT(String(mTxSetupTime)); DBGPRINTLN("ms"); - } + }*/ DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("TX ")); @@ -383,6 +386,10 @@ class HmRadio : public Radio { } mNrf24->stopListening(); + if(!isRetransmit && mTxRetries != mTxRetriesNext) { + mNrf24->setRetries(3, mTxRetriesNext); + mTxRetries = mTxRetriesNext; + } mNrf24->setChannel(mRfChLst[mTxChIdx]); mNrf24->openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24->startWrite(mTxBuf, len, false); // false = request ACK response @@ -425,6 +432,7 @@ class HmRadio : public Radio { bool rxPendular = false; uint32_t innerLoopTimeout = DURATION_LISTEN_MIN; uint8_t mTxSetupTime = 0; + uint8_t mTxRetries = 15; // memorize last setting for mNrf24->setRetries(3, 15); std::unique_ptr mSpi; std::unique_ptr mNrf24; diff --git a/src/hm/radio.h b/src/hm/radio.h index a71e24c7..e11d8682 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -78,6 +78,7 @@ class Radio { std::queue mBufCtrl; uint8_t mIrqOk = IRQ_UNKNOWN; TimeMonitor mRadioWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) + uint8_t mTxRetriesNext = 15; // let heuristics tell us the next reties count (for nRF type radios only) protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; From 8f5310ffd35dd7ea9b48af188ef5e95b1e0dc2fb Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 23 Jan 2024 12:41:41 +0100 Subject: [PATCH 02/14] reduce serial output --- src/hm/Communication.h | 12 +++++++----- src/hm/hmRadio.h | 12 +++++++----- src/hm/radio.h | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 60e87918..b02c03b7 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -134,14 +134,16 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); DBGPRINT(String(q->iv->radio->mRadioWaitTime.getRunTime())); - DBGPRINT(F("ms")); - if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { + DBGPRINTLN(F("ms")); + /*if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { + DBGPRINT(F(", retries ")); + DBGPRINTLN(String(q->iv->radio->mTxRetriesNext)); DBGPRINT(F(", ARC ")); DBGPRINT(String(q->iv->radio->getARC())); DBGPRINT(F(", PLOS ")); DBGPRINTLN(String(q->iv->radio->getPLOS())); } else - DBGPRINTLN(""); + DBGPRINTLN("");*/ } if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { @@ -295,10 +297,10 @@ class Communication : public CommQueue<> { DBGPRINT(String(p->millis)); DBGPRINT(F("ms | ")); DBGPRINT(String(p->len)); - DBGPRINT(F(", ARC ")); + /*DBGPRINT(F(", ARC ")); DBGPRINT(String(p->arc)); DBGPRINT(F(", PLOS ")); - DBGPRINT(String(p->plos)); + DBGPRINT(String(p->plos));*/ DBGPRINT(F(" |")); if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { DBGPRINT(F(" CH")); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index d41dc36a..9915a9a8 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -293,13 +293,13 @@ class HmRadio : public Radio { return mNrf24->isPVariant(); } - uint8_t getARC(void) { + /*uint8_t getARC(void) { return mNrf24->getARC(); } uint8_t getPLOS(void) { return mNrf24->getPLOS(); - } + }*/ private: inline bool getReceived(void) { @@ -315,8 +315,8 @@ class HmRadio : public Radio { p.len = (len > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len; p.rssi = mNrf24->testRPD() ? -64 : -75; p.millis = millis() - mMillis; - p.arc = mNrf24->getARC(); - p.plos = mNrf24->getPLOS(); + //p.arc = mNrf24->getARC(); + //p.plos = mNrf24->getPLOS(); mNrf24->read(p.packet, p.len); if (p.packet[0] != 0x00) { @@ -370,7 +370,9 @@ class HmRadio : public Radio { DBGPRINT(String(len)); DBGPRINT(" CH"); DBGPRINT(String(mRfChLst[mTxChIdx])); - DBGPRINT(F(" | ")); + DBGPRINT(F(", ")); + DBGPRINT(String(mTxRetriesNext)); + DBGPRINT(F(" retries | ")); if(*mPrintWholeTrace) { if(*mPrivacyMode) ah::dumpBuf(mTxBuf, len, 1, 4); diff --git a/src/hm/radio.h b/src/hm/radio.h index e11d8682..e6baf792 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -29,8 +29,8 @@ class Radio { virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } virtual bool isChipConnected(void) { return false; } virtual bool loop(void) = 0; - virtual uint8_t getARC(void) { return 0xff; } - virtual uint8_t getPLOS(void) { return 0xff; } + //virtual uint8_t getARC(void) { return 0xff; } + //virtual uint8_t getPLOS(void) { return 0xff; } void handleIntr(void) { mIrqRcvd = true; From bfedf4f0c23db7161ae3aadd4995f88b5f9c815d Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 23 Jan 2024 16:09:54 +0100 Subject: [PATCH 03/14] fix 2nd frame detection for 2ch HM and add faster exiting CMT wait state --- src/hm/Communication.h | 25 ++++++++++++++-------- src/hm/Heuristic.h | 48 ++++++++++++++++++++++++++++++++++++++++-- src/hm/HeuristicInv.h | 3 +++ src/hm/hmRadio.h | 24 +++++++++++++++------ src/hm/radio.h | 5 +++-- src/hms/hmsRadio.h | 5 +++-- 6 files changed, 88 insertions(+), 22 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 98dd06e1..15ca3d5d 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -86,7 +86,7 @@ class Communication : public CommQueue<> { mIsRetransmit = false; if(NULL == q->iv->radio) cmdDone(false); // can't communicate while radio is not defined! - mFirstTry = q->iv->isAvailable(); + mFirstTry = INV_RADIO_TYPE_NRF == q->iv->ivRadioType && q->iv->isAvailable(); q->iv->mCmd = q->cmd; q->iv->mIsSingleframeReq = false; mFramesExpected = getFramesExpected(q); // function to get expected frame count. @@ -134,20 +134,23 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); DBGPRINT(String(q->iv->radio->mRadioWaitTime.getRunTime())); - DBGPRINT(F("ms")); - if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { + DBGPRINTLN(F("ms")); + /*if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { + DBGPRINT(F(", retries ")); + DBGPRINTLN(String(q->iv->radio->mTxRetriesNext)); DBGPRINT(F(", ARC ")); DBGPRINT(String(q->iv->radio->getARC())); DBGPRINT(F(", PLOS ")); DBGPRINTLN(String(q->iv->radio->getPLOS())); } else - DBGPRINTLN(""); + DBGPRINTLN("");*/ } if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); mWaitTime.startTimeMonitor(1000); } else { + mHeu.setIvRetriesBad(q->iv); if(IV_MI == q->iv->ivGen) q->iv->mIvTxCnt++; @@ -180,8 +183,11 @@ class Communication : public CommQueue<> { q->iv->mDtuRxCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - if(parseFrame(p)) + if(parseFrame(p)) { q->iv->curFrmCnt++; + if(!mIsRetransmit && (p->packet[9] == 0x02 || p->packet[9] == 0x82) && p->millis < 85) + mHeu.setIvRetriesGood(q->iv,p->millis < 70); + } } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command if(parseDevCtrl(p, q)) closeRequest(q, true); @@ -291,10 +297,10 @@ class Communication : public CommQueue<> { DBGPRINT(String(p->millis)); DBGPRINT(F("ms | ")); DBGPRINT(String(p->len)); - DBGPRINT(F(", ARC ")); + /*DBGPRINT(F(", ARC ")); DBGPRINT(String(p->arc)); DBGPRINT(F(", PLOS ")); - DBGPRINT(String(p->plos)); + DBGPRINT(String(p->plos));*/ DBGPRINT(F(" |")); if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { DBGPRINT(F(" CH")); @@ -417,6 +423,8 @@ class Communication : public CommQueue<> { } inline bool parseMiFrame(packet_t *p, const queue_s *q) { + if(!mIsRetransmit && p->packet[9] == 0x00 && p->millis < 35) //first frame is fast? + mHeu.setIvRetriesGood(q->iv,p->millis < 22); if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) @@ -436,7 +444,6 @@ class Communication : public CommQueue<> { record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure rec->ts = q->ts; miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); - //mHeu.setGotFragment(q->iv); only do this when we are through the cycle? } return true; @@ -527,7 +534,7 @@ class Communication : public CommQueue<> { len -= 2; - DPRINT_IVID(DBG_INFO, q->iv->id); + //DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("Payload (")); DBGPRINT(String(len)); if(*mPrintWholeTrace) { diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 64c78cc8..642eca13 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -23,8 +23,8 @@ class Heuristic { public: uint8_t getTxCh(Inverter<> *iv) { - if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) - return 0; // not used for these inverter types + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return 0; // not used for other than nRF inverter types HeuristicInv *ih = &iv->heuristics; @@ -66,6 +66,8 @@ class Heuristic { ih->testPeriodFailCnt = 0; } + iv->radio->mTxRetriesNext = getIvRetries(iv); + return id2Ch(ih->txRfChId); } @@ -155,6 +157,48 @@ class Heuristic { DBGPRINTLN(String(iv->config->powerLevel)); } + uint8_t getIvRetries(Inverter<> *iv) { + if(iv->heuristics.rxSpeeds[0]) + return 5; + if(iv->heuristics.rxSpeeds[1]) + return 10; + return 15; + } + + void setIvRetriesGood(Inverter<> *iv, bool veryGood) { + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return; // not used for other than nRF inverter types + + if(iv->heuristics.rxSpeedCnt[veryGood] > 9) + return; + iv->heuristics.rxSpeedCnt[veryGood]++; + iv->heuristics.rxSpeeds[veryGood] = true; + } + + void setIvRetriesBad(Inverter<> *iv) { + if(iv->ivRadioType != INV_RADIO_TYPE_NRF) + return; // not used for other than nRF inverter types + + if(iv->heuristics.rxSpeedCnt[0]) { + iv->heuristics.rxSpeedCnt[0]--; + return; + } + if(iv->heuristics.rxSpeeds[0]) { + iv->heuristics.rxSpeeds[0] = false; + return; + } + + if(iv->heuristics.rxSpeedCnt[1]) { + iv->heuristics.rxSpeedCnt[1]--; + return; + } + if(iv->heuristics.rxSpeeds[1]) { + iv->heuristics.rxSpeeds[1] = false; + return; + } + return; + } + private: bool isNewTxCh(HeuristicInv *ih) { return ih->txRfChId != ih->lastBestTxChId; diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index e7ad6edd..fc782a7b 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -27,6 +27,9 @@ class HeuristicInv { uint8_t testChId = 0; int8_t saveOldTestQuality = -6; uint8_t lastRxFragments = 0; + bool rxSpeeds[2] = {false,false}; // is inverter responding very fast respective fast? + uint8_t rxSpeedCnt[2] = {0,0}; // count how many messages had been received very fast respective fast (10 max) + }; #endif /*__HEURISTIC_INV_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index ef37e266..9915a9a8 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -161,7 +161,7 @@ class HmRadio : public Radio { rxPendular = false; mNRFloopChannels = (mLastIv->ivGen == IV_MI); - innerLoopTimeout = DURATION_TXFRAME; + innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; } if(rx_ready) { @@ -293,13 +293,13 @@ class HmRadio : public Radio { return mNrf24->isPVariant(); } - uint8_t getARC(void) { + /*uint8_t getARC(void) { return mNrf24->getARC(); } uint8_t getPLOS(void) { return mNrf24->getPLOS(); - } + }*/ private: inline bool getReceived(void) { @@ -315,8 +315,8 @@ class HmRadio : public Radio { p.len = (len > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len; p.rssi = mNrf24->testRPD() ? -64 : -75; p.millis = millis() - mMillis; - p.arc = mNrf24->getARC(); - p.plos = mNrf24->getPLOS(); + //p.arc = mNrf24->getARC(); + //p.plos = mNrf24->getPLOS(); mNrf24->read(p.packet, p.len); if (p.packet[0] != 0x00) { @@ -356,18 +356,23 @@ class HmRadio : public Radio { mTxChIdx = iv->heuristics.txRfChId; if(*mSerialDebug) { + /* remark rejoe2: imo this has no added value here. + As this belongs to the last tx cycle, we should print that info + directly when switching from tx to rx. Otherwise we might confuse users. if(!isRetransmit) { DPRINT(DBG_INFO, "last tx setup: "); DBGPRINT(String(mTxSetupTime)); DBGPRINTLN("ms"); - } + }*/ DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("TX ")); DBGPRINT(String(len)); DBGPRINT(" CH"); DBGPRINT(String(mRfChLst[mTxChIdx])); - DBGPRINT(F(" | ")); + DBGPRINT(F(", ")); + DBGPRINT(String(mTxRetriesNext)); + DBGPRINT(F(" retries | ")); if(*mPrintWholeTrace) { if(*mPrivacyMode) ah::dumpBuf(mTxBuf, len, 1, 4); @@ -383,6 +388,10 @@ class HmRadio : public Radio { } mNrf24->stopListening(); + if(!isRetransmit && mTxRetries != mTxRetriesNext) { + mNrf24->setRetries(3, mTxRetriesNext); + mTxRetries = mTxRetriesNext; + } mNrf24->setChannel(mRfChLst[mTxChIdx]); mNrf24->openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24->startWrite(mTxBuf, len, false); // false = request ACK response @@ -425,6 +434,7 @@ class HmRadio : public Radio { bool rxPendular = false; uint32_t innerLoopTimeout = DURATION_LISTEN_MIN; uint8_t mTxSetupTime = 0; + uint8_t mTxRetries = 15; // memorize last setting for mNrf24->setRetries(3, 15); std::unique_ptr mSpi; std::unique_ptr mNrf24; diff --git a/src/hm/radio.h b/src/hm/radio.h index a71e24c7..e6baf792 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -29,8 +29,8 @@ class Radio { virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } virtual bool isChipConnected(void) { return false; } virtual bool loop(void) = 0; - virtual uint8_t getARC(void) { return 0xff; } - virtual uint8_t getPLOS(void) { return 0xff; } + //virtual uint8_t getARC(void) { return 0xff; } + //virtual uint8_t getPLOS(void) { return 0xff; } void handleIntr(void) { mIrqRcvd = true; @@ -78,6 +78,7 @@ class Radio { std::queue mBufCtrl; uint8_t mIrqOk = IRQ_UNKNOWN; TimeMonitor mRadioWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) + uint8_t mTxRetriesNext = 15; // let heuristics tell us the next reties count (for nRF type radios only) protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 48ff3750..3c569e02 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -166,9 +166,10 @@ class CmtRadio : public Radio { mBufCtrl.push(p); // this code completly stops communication! - //if(p.packet[9] > ALL_FRAMES) // indicates last frame + if(p.packet[9] > ALL_FRAMES) // indicates last frame // mRadioWaitTime.stopTimeMonitor(); // we got everything we expected and can exit rx mode... - //optionally instead: mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first get back to rx mode? + //optionally instead: + mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first get back to rx mode? } CmtType mCmt; From 3fbd2c7c88e933e42af35d84dba243598bceed95 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 23 Jan 2024 17:54:57 +0100 Subject: [PATCH 04/14] fix retransmit counter for secondtry - try to fix "45ms"-Problem --- src/hm/Communication.h | 4 ++-- src/hm/hmRadio.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 15ca3d5d..94cf23ff 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -156,9 +156,9 @@ class Communication : public CommQueue<> { if(mFirstTry) { mFirstTry = false; - setAttempt(); + //setAttempt(); mHeu.evalTxChQuality(q->iv, false, 0, 0); - q->iv->radioStatistics.rxFailNoAnser++; + //q->iv->radioStatistics.rxFailNoAnser++; // should only be one of fail or retransmit. q->iv->radioStatistics.retransmits++; q->iv->radio->mRadioWaitTime.stopTimeMonitor(); mState = States::START; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 9915a9a8..54f099dd 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -167,6 +167,7 @@ class HmRadio : public Radio { if(rx_ready) { if (getReceived()) { // check what we got, returns true for last package mNRFisInRX = false; + rx_ready = false; mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first end his transmissions mNrf24->stopListening(); } else { From 444a7160128b2a6e8d7628b8d940ca14236f31d6 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 24 Jan 2024 10:42:39 +0100 Subject: [PATCH 05/14] partly fix statistics - add more data requests to startup phase --- src/hm/Communication.h | 7 +++++-- src/hm/hmInverter.h | 12 ++++++++---- src/hm/hmRadio.h | 12 +++++++++--- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 94cf23ff..4003c13e 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -159,6 +159,7 @@ class Communication : public CommQueue<> { //setAttempt(); mHeu.evalTxChQuality(q->iv, false, 0, 0); //q->iv->radioStatistics.rxFailNoAnser++; // should only be one of fail or retransmit. + q->iv->radioStatistics.txCnt--; q->iv->radioStatistics.retransmits++; q->iv->radio->mRadioWaitTime.stopTimeMonitor(); mState = States::START; @@ -835,8 +836,9 @@ class Communication : public CommQueue<> { DBGHEXLN(cmd); } - if(q->iv->miMultiParts == 7) - q->iv->radioStatistics.rxSuccess++; + //if(q->iv->miMultiParts > 5) //if(q->iv->miMultiParts == 7) + q->iv->radioStatistics.rxSuccess++; + q->iv->radioStatistics.ivSent++; mFramesExpected = getFramesExpected(q); q->iv->radio->setExpectedFrames(mFramesExpected); @@ -861,6 +863,7 @@ class Communication : public CommQueue<> { } q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); + q->iv->radioStatistics.retransmits++; q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + duration_reserve[q->iv->ivRadioType]); mIsRetransmit = false; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index b28682e5..049b5501 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -200,13 +200,17 @@ class Inverter { cb(devControlCmd, false); // custom command which was received by API devControlCmd = InitDataState; mGetLossInterval = 1; - } else if(0 == getFwVersion()) + } else if(0 == getFwVersion()) { + cb(RealTimeRunData_Debug, false); // get live data cb(InverterDevInform_All, false); // get firmware version - else if(0 == getHwVersion()) + } + else if(0 == getHwVersion()) { + cb(RealTimeRunData_Debug, false); // get live data cb(InverterDevInform_Simple, false); // get hardware version - else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) + } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) { + cb(RealTimeRunData_Debug, false); // get live data cb(AlarmData, false); // get last alarms - else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile + } else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile cb(GridOnProFilePara, false); } else if (mGetLossInterval > AHOY_GET_LOSS_INTERVAL) { // get loss rate mGetLossInterval = 1; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 54f099dd..feb4fde5 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -113,6 +113,7 @@ class HmRadio : public Radio { if (mRadioWaitTime.isTimeout()) { // timeout reached! mNRFisInRX = false; + rx_ready = false; return false; } @@ -165,7 +166,7 @@ class HmRadio : public Radio { } if(rx_ready) { - if (getReceived()) { // check what we got, returns true for last package + if (getReceived()) { // check what we got, returns true for last package or success for single frame request mNRFisInRX = false; rx_ready = false; mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first end his transmissions @@ -183,6 +184,7 @@ class HmRadio : public Radio { mRxChIdx = tempRxChIdx; } } + rx_ready = false; // reset return mNRFisInRX; } /*else if(tx_fail) { mNRFisInRX = false; @@ -305,6 +307,7 @@ class HmRadio : public Radio { private: inline bool getReceived(void) { bool isLastPackage = false; + bool isRetransmitAnswer = false; rx_ready = false; // reset for ACK case while(mNrf24->available()) { @@ -329,8 +332,11 @@ class HmRadio : public Radio { mLastIv->mGotFragment = true; mBufCtrl.push(p); - 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 isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received + if(mLastIv->mIsSingleframeReq) // we only expect one frame here... + isRetransmitAnswer = true; + } if(IV_MI == mLastIv->ivGen) { if (p.packet[0] == (0x0f + ALL_FRAMES)) // response from MI get information command @@ -346,7 +352,7 @@ class HmRadio : public Radio { } if(isLastPackage) mLastIv->mGotLastMsg = true; - return isLastPackage; + return isLastPackage || isRetransmitAnswer; } void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { From d7ea4bcb892b0d63e8875bbc49a1a352d1afc1f8 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 24 Jan 2024 17:31:58 +0100 Subject: [PATCH 06/14] fix 0 attempts in Communication - 45ms-Problem seems to be solved --- src/hm/Communication.h | 4 ++-- src/hm/hmRadio.h | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 4003c13e..38925059 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -129,7 +129,7 @@ class Communication : public CommQueue<> { break; case States::CHECK_FRAMES: { - if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) || (0 == q->attempts)) { // radio buffer empty or no more answers + if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) ) { // || (0 == q->attempts)) { // radio buffer empty or no more answers if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); @@ -259,7 +259,7 @@ class Communication : public CommQueue<> { if(framnr) { if(0 == q->attempts) { DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("no attempts left")); + DBGPRINTLN(F("no attempts left")); closeRequest(q, false); return; } diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index feb4fde5..0df22f5a 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -336,6 +336,8 @@ class HmRadio : public Radio { isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received if(mLastIv->mIsSingleframeReq) // we only expect one frame here... isRetransmitAnswer = true; + if(isLastPackage) + mFramesExpected = p.packet[9] - ALL_FRAMES; } if(IV_MI == mLastIv->ivGen) { @@ -350,8 +352,9 @@ class HmRadio : public Radio { } yield(); } - if(isLastPackage) + if(isLastPackage) { mLastIv->mGotLastMsg = true; + } return isLastPackage || isRetransmitAnswer; } From d8af39820816baa94c919bb8127a5a1c63b758d8 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 25 Jan 2024 08:22:03 +0100 Subject: [PATCH 07/14] pendular version let rx channel change between tx+2 and tx+3 --- src/hm/Communication.h | 10 +++++----- src/hm/Heuristic.h | 4 ++-- src/hm/hmDefines.h | 8 ++++++++ src/hm/hmRadio.h | 13 ++++++------- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 38925059..924356e0 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -186,8 +186,8 @@ class Communication : public CommQueue<> { if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command if(parseFrame(p)) { q->iv->curFrmCnt++; - if(!mIsRetransmit && (p->packet[9] == 0x02 || p->packet[9] == 0x82) && p->millis < 85) - mHeu.setIvRetriesGood(q->iv,p->millis < 70); + if(!mIsRetransmit && (p->packet[9] == 0x02 || p->packet[9] == 0x82) && p->millis < LIMIT_FAST_IV) + mHeu.setIvRetriesGood(q->iv,p->millis < LIMIT_VERYFAST_IV); } } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command if(parseDevCtrl(p, q)) @@ -259,7 +259,7 @@ class Communication : public CommQueue<> { if(framnr) { if(0 == q->attempts) { DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINTLN(F("no attempts left")); + DBGPRINTLN(F("timeout, no attempts left")); closeRequest(q, false); return; } @@ -424,8 +424,8 @@ class Communication : public CommQueue<> { } inline bool parseMiFrame(packet_t *p, const queue_s *q) { - if(!mIsRetransmit && p->packet[9] == 0x00 && p->millis < 35) //first frame is fast? - mHeu.setIvRetriesGood(q->iv,p->millis < 22); + if(!mIsRetransmit && p->packet[9] == 0x00 && p->millis < LIMIT_FAST_IV_MI) //first frame is fast? + mHeu.setIvRetriesGood(q->iv,p->millis < LIMIT_VERYFAST_IV_MI); if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 642eca13..3fb86614 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -159,9 +159,9 @@ class Heuristic { uint8_t getIvRetries(Inverter<> *iv) { if(iv->heuristics.rxSpeeds[0]) - return 5; + return RETRIES_VERYFAST_IV; if(iv->heuristics.rxSpeeds[1]) - return 10; + return RETRIES_FAST_IV; return 15; } diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 969e4e1b..9235b3f9 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -94,6 +94,14 @@ enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT}; #define DURATION_PAUSE_LASTFR 45 // how long to pause after last frame (ms) const uint8_t duration_reserve[2] = {115,115}; +#define LIMIT_FAST_IV 85 // time limit to qualify an inverter as very fast answering inverter +#define LIMIT_VERYFAST_IV 70 // time limit to qualify an inverter as very fast answering inverter +#define LIMIT_FAST_IV_MI 35 // time limit to qualify a MI type inverter as fast answering inverter +#define LIMIT_VERYFAST_IV_MI 22 // time limit to qualify a MI type inverter as very fast answering inverter +#define RETRIES_FAST_IV 11 // how often shall a message be automatically retransmitted by the nRF (fast answering inverter) +#define RETRIES_VERYFAST_IV 7 // how often shall a message be automatically retransmitted by the nRF (very fast answering inverter) + + typedef struct { uint8_t fieldId; // field id uint8_t unitId; // uint id diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 0df22f5a..81b27c57 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -124,7 +124,7 @@ class HmRadio : public Radio { rxPendular = !rxPendular; //innerLoopTimeout = (rxPendular ? 1 : 2)*DURATION_LISTEN_MIN; - innerLoopTimeout = DURATION_LISTEN_MIN; + //innerLoopTimeout = DURATION_LISTEN_MIN; if(mNRFloopChannels) tempRxChIdx = (tempRxChIdx + 4) % RF_CHANNELS; @@ -154,7 +154,8 @@ class HmRadio : public Radio { if(tx_ok) mLastIv->mAckCount++; - mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; + //mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; + mRxChIdx = (mTxChIdx + 3) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); mNrf24->startListening(); mTimeslotStart = millis(); @@ -162,7 +163,8 @@ class HmRadio : public Radio { rxPendular = false; mNRFloopChannels = (mLastIv->ivGen == IV_MI); - innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; + //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; + innerLoopTimeout = DURATION_LISTEN_MIN; } if(rx_ready) { @@ -186,10 +188,7 @@ class HmRadio : public Radio { } rx_ready = false; // reset return mNRFisInRX; - } /*else if(tx_fail) { - mNRFisInRX = false; - return false; - }*/ + } } return false; From 1118407019b7bc543b426a7384dd7828f77c0678 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 25 Jan 2024 11:10:44 +0100 Subject: [PATCH 08/14] retransmit review - look at how many frames are missing first - more "second try" if inverter is available (dependent on attempts) --- src/hm/CommQueue.h | 4 ++-- src/hm/Communication.h | 38 +++++++++++++++++++++++++++++--------- src/hm/hmDefines.h | 2 +- src/hm/hmInverter.h | 28 ++++++++++++++-------------- src/hm/radio.h | 2 +- 5 files changed, 47 insertions(+), 27 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index d3fe1c69..227e8c33 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -12,8 +12,8 @@ #include "../utils/dbg.h" #define DEFAULT_ATTEMPS 5 -#define MORE_ATTEMPS_ALARMDATA 8 -#define MORE_ATTEMPS_GRIDONPROFILEPARA 5 +#define MORE_ATTEMPS_ALARMDATA 0 // 8 +#define MORE_ATTEMPS_GRIDONPROFILEPARA 0 // 5 template class CommQueue { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 924356e0..bc7f7236 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -114,11 +114,11 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.txCnt++; q->iv->radio->mRadioWaitTime.startTimeMonitor(mTimeout); + if(!mIsRetransmit && (q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) + incrAttempt(q->cmd == AlarmData? MORE_ATTEMPS_ALARMDATA : MORE_ATTEMPS_GRIDONPROFILEPARA); mIsRetransmit = false; setAttempt(); - if((q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) - incrAttempt(q->cmd == AlarmData? MORE_ATTEMPS_ALARMDATA : MORE_ATTEMPS_GRIDONPROFILEPARA); mState = States::WAIT; break; @@ -155,7 +155,8 @@ class Communication : public CommQueue<> { q->iv->mIvTxCnt++; if(mFirstTry) { - mFirstTry = false; + if(q->attempts < 3 || !q->iv->isProducing()) + mFirstTry = false; //setAttempt(); mHeu.evalTxChQuality(q->iv, false, 0, 0); //q->iv->radioStatistics.rxFailNoAnser++; // should only be one of fail or retransmit. @@ -209,7 +210,7 @@ class Communication : public CommQueue<> { if(q->iv->ivGen != IV_MI) { mState = States::CHECK_PACKAGE; } else { - bool fastNext = true; + //bool fastNext = true; if(q->iv->miMultiParts < 6) { mState = States::WAIT; if((q->iv->radio->mRadioWaitTime.isTimeout() && mIsRetransmit) || !mIsRetransmit) { @@ -222,11 +223,11 @@ class Communication : public CommQueue<> { || ((q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH)) || ((q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { miComplete(q->iv); - fastNext = false; + //fastNext = false; } - if(fastNext) + /*if(fastNext) miNextRequest(q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, q); - else + else*/ closeRequest(q, true); } } @@ -263,6 +264,25 @@ class Communication : public CommQueue<> { closeRequest(q, false); return; } + //count missing frames + if(!q->iv->mIsSingleframeReq && q->iv->ivRadioType == INV_RADIO_TYPE_NRF) { // already checked? + uint8_t missedFrames = 0; + for(uint8_t i = 0; i < q->iv->radio->mFramesExpected; i++) { + if(mLocalBuf[i].len == 0) + missedFrames++; + } + if(missedFrames > 3 || (q->cmd == RealTimeRunData_Debug && missedFrames > 1) || (missedFrames > 1 && missedFrames + 2 > q->attempts)) { + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(String(missedFrames)); + DBGPRINT(F(" frames missing ")); + DBGPRINTLN(F("-> complete retransmit")); + } + mState = States::RESET; + return; + } + } + setAttempt(); if(*mSerialDebug) { @@ -411,8 +431,8 @@ class Communication : public CommQueue<> { if((*frameId & ALL_FRAMES) == ALL_FRAMES) { mMaxFrameId = (*frameId & 0x7f); - if(mMaxFrameId > 8) // large payloads, e.g. AlarmData - incrAttempt(mMaxFrameId - 6); + /*if(mMaxFrameId > 8) // large payloads, e.g. AlarmData + incrAttempt(mMaxFrameId - 6);*/ } frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 9235b3f9..6bd66e66 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -92,7 +92,7 @@ enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT}; #define DURATION_TXFRAME 85 // timeout parameter for first transmission and first expected frame (time to first channel switch from tx start!) (ms) #define DURATION_LISTEN_MIN 5 // time to stay at least on a listening channel (ms) #define DURATION_PAUSE_LASTFR 45 // how long to pause after last frame (ms) -const uint8_t duration_reserve[2] = {115,115}; +const uint8_t duration_reserve[2] = {65,115}; #define LIMIT_FAST_IV 85 // time limit to qualify an inverter as very fast answering inverter #define LIMIT_VERYFAST_IV 70 // time limit to qualify an inverter as very fast answering inverter diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 049b5501..5ef3752d 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -220,21 +220,21 @@ class Inverter { cb(RealTimeRunData_Debug, false); // get live data } } else { // MI - if(0 == getFwVersion()) { - mIvRxCnt +=2; - cb(0x0f, false); // get firmware version; for MI, this makes part of polling the device software and hardware version number - } else { - record_t<> *rec = getRecordStruct(InverterDevInform_Simple); - if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) { - cb(0x0f, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 + cb(((type == INV_TYPE_4CH) ? MI_REQ_4CH : MI_REQ_CH1), false); + mGetLossInterval++; + if (type != INV_TYPE_4CH) + mIvRxCnt++; // statistics workaround... + if(isAvailable()) { + if(0 == getFwVersion()) { mIvRxCnt +=2; - } else if((getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec) == 0) && generalConfig->readGrid) // read grid profile - cb(0x10, false); // legacy GPF command - else { - cb(((type == INV_TYPE_4CH) ? MI_REQ_4CH : MI_REQ_CH1), false); - mGetLossInterval++; - if (type != INV_TYPE_4CH) - mIvRxCnt++; // statistics workaround... + cb(0x0f, false); // get firmware version; for MI, this makes part of polling the device software and hardware version number + } else { + record_t<> *rec = getRecordStruct(InverterDevInform_Simple); + if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) { + cb(0x0f, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 + mIvRxCnt +=2; + } else if((getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec) == 0) && generalConfig->readGrid) // read grid profile + cb(0x10, false); // legacy GPF command } } } diff --git a/src/hm/radio.h b/src/hm/radio.h index e6baf792..ec087f47 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -79,6 +79,7 @@ class Radio { uint8_t mIrqOk = IRQ_UNKNOWN; TimeMonitor mRadioWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) uint8_t mTxRetriesNext = 15; // let heuristics tell us the next reties count (for nRF type radios only) + uint8_t mFramesExpected = 0x0c; protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; @@ -130,7 +131,6 @@ class Radio { volatile bool mIrqRcvd; bool *mSerialDebug, *mPrivacyMode, *mPrintWholeTrace; uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; - uint8_t mFramesExpected = 0x0c; }; #endif /*__RADIO_H__*/ From 626ca86d0d14a04f4cb1081fd25cabb9539e1636 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 26 Jan 2024 11:31:21 +0100 Subject: [PATCH 09/14] fix statistics - based on 0.8.65! --- src/hm/CommQueue.h | 6 ++---- src/hm/Communication.h | 41 ++++++++++++----------------------------- src/hm/hmRadio.h | 22 +++++----------------- src/hm/radio.h | 10 ++++------ src/hms/hmsRadio.h | 14 ++++++-------- 5 files changed, 29 insertions(+), 64 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 227e8c33..d7cc5642 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -18,8 +18,6 @@ template class CommQueue { public: - CommQueue() {} - void addImportant(Inverter<> *iv, uint8_t cmd) { dec(&mRdPtr); mQueue[mRdPtr] = queue_s(iv, cmd, true); @@ -34,12 +32,12 @@ class CommQueue { mQueue[mWrPtr] = queue_s(iv, cmd, false); } - uint8_t getFillState(void) { + uint8_t getFillState(void) const { //DPRINTLN(DBG_INFO, "wr: " + String(mWrPtr) + ", rd: " + String(mRdPtr)); return abs(mRdPtr - mWrPtr); } - uint8_t getMaxFill(void) { + uint8_t getMaxFill(void) const { return N; } diff --git a/src/hm/Communication.h b/src/hm/Communication.h index bc7f7236..bfb6a4df 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -83,6 +83,7 @@ class Communication : public CommQueue<> { q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; q->iv->curFrmCnt = 0; + q->iv->radioStatistics.txCnt++; mIsRetransmit = false; if(NULL == q->iv->radio) cmdDone(false); // can't communicate while radio is not defined! @@ -112,7 +113,7 @@ class Communication : public CommQueue<> { } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - q->iv->radioStatistics.txCnt++; + //q->iv->radioStatistics.txCnt++; q->iv->radio->mRadioWaitTime.startTimeMonitor(mTimeout); if(!mIsRetransmit && (q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) incrAttempt(q->cmd == AlarmData? MORE_ATTEMPS_ALARMDATA : MORE_ATTEMPS_GRIDONPROFILEPARA); @@ -129,22 +130,13 @@ class Communication : public CommQueue<> { break; case States::CHECK_FRAMES: { - if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) ) { // || (0 == q->attempts)) { // radio buffer empty or no more answers + if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) ) { // || (0 == q->attempts)) { // radio buffer empty. No more answers will be checked later if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); DBGPRINT(String(q->iv->radio->mRadioWaitTime.getRunTime())); DBGPRINTLN(F("ms")); - /*if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { - DBGPRINT(F(", retries ")); - DBGPRINTLN(String(q->iv->radio->mTxRetriesNext)); - DBGPRINT(F(", ARC ")); - DBGPRINT(String(q->iv->radio->getARC())); - DBGPRINT(F(", PLOS ")); - DBGPRINTLN(String(q->iv->radio->getPLOS())); - } else - DBGPRINTLN("");*/ - } + } if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); @@ -157,14 +149,13 @@ class Communication : public CommQueue<> { if(mFirstTry) { if(q->attempts < 3 || !q->iv->isProducing()) mFirstTry = false; - //setAttempt(); mHeu.evalTxChQuality(q->iv, false, 0, 0); + mHeu.getTxCh(q->iv); //q->iv->radioStatistics.rxFailNoAnser++; // should only be one of fail or retransmit. - q->iv->radioStatistics.txCnt--; + //q->iv->radioStatistics.txCnt--; q->iv->radioStatistics.retransmits++; q->iv->radio->mRadioWaitTime.stopTimeMonitor(); mState = States::START; - return; } } @@ -210,7 +201,6 @@ class Communication : public CommQueue<> { if(q->iv->ivGen != IV_MI) { mState = States::CHECK_PACKAGE; } else { - //bool fastNext = true; if(q->iv->miMultiParts < 6) { mState = States::WAIT; if((q->iv->radio->mRadioWaitTime.isTimeout() && mIsRetransmit) || !mIsRetransmit) { @@ -223,12 +213,8 @@ class Communication : public CommQueue<> { || ((q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH)) || ((q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { miComplete(q->iv); - //fastNext = false; } - /*if(fastNext) - miNextRequest(q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, q); - else*/ - closeRequest(q, true); + closeRequest(q, true); } } @@ -278,6 +264,8 @@ class Communication : public CommQueue<> { DBGPRINT(F(" frames missing ")); DBGPRINTLN(F("-> complete retransmit")); } + q->iv->radioStatistics.txCnt--; + q->iv->radioStatistics.retransmits++; mState = States::RESET; return; } @@ -318,11 +306,6 @@ class Communication : public CommQueue<> { DBGPRINT(String(p->millis)); DBGPRINT(F("ms | ")); DBGPRINT(String(p->len)); - /*DBGPRINT(F(", ARC ")); - DBGPRINT(String(p->arc)); - DBGPRINT(F(", PLOS ")); - DBGPRINT(String(p->plos));*/ - DBGPRINT(F(" |")); if(INV_RADIO_TYPE_NRF == q->iv->ivRadioType) { DBGPRINT(F(" CH")); if(3 == p->ch) @@ -555,7 +538,7 @@ class Communication : public CommQueue<> { len -= 2; - //DPRINT_IVID(DBG_INFO, q->iv->id); + //DPRINT_IVID(DBG_INFO, q->iv->id); // it's already above "for"-loop DBGPRINT(F("Payload (")); DBGPRINT(String(len)); if(*mPrintWholeTrace) { @@ -856,8 +839,8 @@ class Communication : public CommQueue<> { DBGHEXLN(cmd); } - //if(q->iv->miMultiParts > 5) //if(q->iv->miMultiParts == 7) - q->iv->radioStatistics.rxSuccess++; + /*if(q->iv->miMultiParts > 5) //if(q->iv->miMultiParts == 7) + q->iv->radioStatistics.rxSuccess++;*/ q->iv->radioStatistics.ivSent++; mFramesExpected = getFramesExpected(q); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 81b27c57..bc1e3652 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -15,7 +15,6 @@ #endif #define SPI_SPEED 1000000 - #define RF_CHANNELS 5 const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; @@ -194,8 +193,7 @@ class HmRadio : public Radio { return false; } - bool isChipConnected(void) { - //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:isChipConnected")); + bool isChipConnected(void) const { return mNrf24->isChipConnected(); } @@ -285,24 +283,16 @@ class HmRadio : public Radio { sendPacket(iv, cnt, isRetransmit, (IV_MI != iv->ivGen)); } - uint8_t getDataRate(void) { + uint8_t getDataRate(void) const { if(!mNrf24->isChipConnected()) return 3; // unknown return mNrf24->getDataRate(); } - bool isPVariant(void) { + bool isPVariant(void) const { return mNrf24->isPVariant(); } - /*uint8_t getARC(void) { - return mNrf24->getARC(); - } - - uint8_t getPLOS(void) { - return mNrf24->getPLOS(); - }*/ - private: inline bool getReceived(void) { bool isLastPackage = false; @@ -318,8 +308,6 @@ class HmRadio : public Radio { p.len = (len > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len; p.rssi = mNrf24->testRPD() ? -64 : -75; p.millis = millis() - mMillis; - //p.arc = mNrf24->getARC(); - //p.plos = mNrf24->getPLOS(); mNrf24->read(p.packet, p.len); if (p.packet[0] != 0x00) { @@ -411,11 +399,11 @@ class HmRadio : public Radio { mNRFisInRX = false; } - uint64_t getIvId(Inverter<> *iv) { + uint64_t getIvId(Inverter<> *iv) const { return iv->radioId.u64; } - uint8_t getIvGen(Inverter<> *iv) { + uint8_t getIvGen(Inverter<> *iv) const { return iv->ivGen; } diff --git a/src/hm/radio.h b/src/hm/radio.h index ec087f47..ea6d8c05 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -27,10 +27,8 @@ class Radio { virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) = 0; virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } - virtual bool isChipConnected(void) { return false; } + virtual bool isChipConnected(void) const { return false; } virtual bool loop(void) = 0; - //virtual uint8_t getARC(void) { return 0xff; } - //virtual uint8_t getPLOS(void) { return 0xff; } void handleIntr(void) { mIrqRcvd = true; @@ -66,7 +64,7 @@ class Radio { sendPacket(iv, 24, isRetransmit); } - uint32_t getDTUSn(void) { + uint32_t getDTUSn(void) const { return mDtuSn; } @@ -83,8 +81,8 @@ class Radio { protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; - virtual uint64_t getIvId(Inverter<> *iv) = 0; - virtual uint8_t getIvGen(Inverter<> *iv) = 0; + virtual uint64_t getIvId(Inverter<> *iv) const = 0; + virtual uint8_t getIvGen(Inverter<> *iv) const = 0; void initPacket(uint64_t ivId, uint8_t mid, uint8_t pid) { mTxBuf[0] = mid; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 3c569e02..33b6a75c 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -14,8 +14,7 @@ class CmtRadio : public Radio { typedef Cmt2300a CmtType; public: CmtRadio() { - mDtuSn = DTU_SN; - mCmtAvail = false; + mDtuSn = DTU_SN; } void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { @@ -38,7 +37,7 @@ class CmtRadio : public Radio { return false; } - bool isChipConnected(void) { + bool isChipConnected(void) const { return mCmtAvail; } @@ -116,11 +115,11 @@ class CmtRadio : public Radio { iv->mDtuTxCnt++; } - uint64_t getIvId(Inverter<> *iv) { + uint64_t getIvId(Inverter<> *iv) const { return iv->radioId.u64; } - uint8_t getIvGen(Inverter<> *iv) { + uint8_t getIvGen(Inverter<> *iv) const { return iv->ivGen; } @@ -165,11 +164,10 @@ class CmtRadio : public Radio { if(CMT_SUCCESS == status) mBufCtrl.push(p); - // this code completly stops communication! if(p.packet[9] > ALL_FRAMES) // indicates last frame - // mRadioWaitTime.stopTimeMonitor(); // we got everything we expected and can exit rx mode... - //optionally instead: mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first get back to rx mode? + // optionally instead: + // mRadioWaitTime.stopTimeMonitor(); // we got everything we expected and can exit rx mode... } CmtType mCmt; From 19184727bc0251c26dc606c7be2e1f10404954a5 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Sat, 27 Jan 2024 09:37:55 +0100 Subject: [PATCH 10/14] add data request to PowerLimit update req. --- src/hm/Communication.h | 11 ++++++++--- src/hm/hmInverter.h | 5 +++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index bfb6a4df..23ffe158 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -264,8 +264,10 @@ class Communication : public CommQueue<> { DBGPRINT(F(" frames missing ")); DBGPRINTLN(F("-> complete retransmit")); } + mHeu.evalTxChQuality(q->iv, false, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt); q->iv->radioStatistics.txCnt--; q->iv->radioStatistics.retransmits++; + mCompleteRetry = true; mState = States::RESET; return; } @@ -511,6 +513,7 @@ class Communication : public CommQueue<> { } else DBGPRINTLN(F("-> complete retransmit")); + mCompleteRetry = true; mState = States::RESET; return; } @@ -611,7 +614,7 @@ class Communication : public CommQueue<> { mHeu.evalTxChQuality(q->iv, crcPass, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt); if(crcPass) q->iv->radioStatistics.rxSuccess++; - else if(q->iv->mGotFragment) + else if(q->iv->mGotFragment || mCompleteRetry) q->iv->radioStatistics.rxFail++; // got no complete payload else q->iv->radioStatistics.rxFailNoAnser++; // got nothing @@ -626,6 +629,7 @@ class Communication : public CommQueue<> { q->iv->mGotLastMsg = false; q->iv->miMultiParts = 0; mIsRetransmit = false; + mCompleteRetry = false; mState = States::RESET; DBGPRINTLN(F("-----")); } @@ -1020,8 +1024,9 @@ class Communication : public CommQueue<> { uint16_t *mInverterGap; TimeMonitor mWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) std::array mLocalBuf; - bool mFirstTry = false; // see, if we should do a second try - bool mIsRetransmit = false; // we already had waited one complete cycle + bool mFirstTry = false; // see, if we should do a second try + bool mCompleteRetry = false; // remember if we did request a complete retransmission + bool mIsRetransmit = false; // we already had waited one complete cycle uint8_t mMaxFrameId; uint8_t mFramesExpected = 12; // 0x8c was highest last frame for alarm data uint16_t mTimeout = 0; // calculating that once should be ok diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 5ef3752d..bcf732ea 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -194,9 +194,10 @@ class Inverter { if(mNextLive) cb(RealTimeRunData_Debug, false); // get live data else { - if(actPowerLimit == 0xffff) + if(actPowerLimit == 0xffff) { cb(SystemConfigPara, false); // power limit info - else if(InitDataState != devControlCmd) { + cb(RealTimeRunData_Debug, false); + } else if(InitDataState != devControlCmd) { cb(devControlCmd, false); // custom command which was received by API devControlCmd = InitDataState; mGetLossInterval = 1; From 1b4b5874df3c7252c2a4b7dd7f681823b07d2f27 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Sat, 27 Jan 2024 17:52:08 +0100 Subject: [PATCH 11/14] Individual rx-channel offset per inverter (based on serial, but unfortunately not working yet) --- src/hm/hmInverter.h | 2 +- src/hm/hmRadio.h | 9 ++++++--- src/hm/hmSystem.h | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index bcf732ea..00f05c79 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -133,6 +133,7 @@ class Inverter { bool isConnected; // shows if inverter was successfully identified (fw version and hardware info) InverterStatus status; // indicates the current inverter status std::array lastAlarm; // holds last 10 alarms + uint8_t rxOffset; // holds the default channel offset between tx and rx channel (nRF only) int8_t rssi; // RSSI uint16_t alarmCnt; // counts the total number of occurred alarms uint16_t alarmLastId; // lastId which was received @@ -179,7 +180,6 @@ class Inverter { tsMaxAcPower = 0; memset(&radioStatistics, 0, sizeof(statistics_t)); - memset(heuristics.txRfQuality, -6, 5); memset(mOffYD, 0, sizeof(float) * 6); memset(mLastYD, 0, sizeof(float) * 6); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index bc1e3652..fbb23b57 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -154,11 +154,11 @@ class HmRadio : public Radio { mLastIv->mAckCount++; //mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; - mRxChIdx = (mTxChIdx + 3) % RF_CHANNELS; + mRxChIdx = (mTxChIdx + mLastIv->rxOffset) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); mNrf24->startListening(); mTimeslotStart = millis(); - tempRxChIdx = mRxChIdx; + tempRxChIdx = mRxChIdx; // might be better to start off with one channel less? rxPendular = false; mNRFloopChannels = (mLastIv->ivGen == IV_MI); @@ -369,7 +369,10 @@ class HmRadio : public Radio { DBGPRINT(String(mRfChLst[mTxChIdx])); DBGPRINT(F(", ")); DBGPRINT(String(mTxRetriesNext)); - DBGPRINT(F(" retries | ")); + //DBGPRINT(F(" retries | ")); + DBGPRINT(F(" ret., rx offset: ")); + DBGPRINT(String(iv->rxOffset)); + DBGPRINT(F(" | ")); if(*mPrintWholeTrace) { if(*mPrivacyMode) ah::dumpBuf(mTxBuf, len, 1, 4); diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 8229378e..1e8641cb 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -28,6 +28,8 @@ class HmSystem { iv->config = &mInverter[0].generalConfig->iv[id]; DPRINT(DBG_VERBOSE, "SERIAL: " + String(iv->config->serial.b[5], HEX)); DPRINTLN(DBG_VERBOSE, " " + String(iv->config->serial.b[4], HEX)); + //iv->rxOffset = 5 - (iv->config->serial.b[2] % 5); //RF_CHANNELS; + iv->rxOffset = (iv->config->serial.b[1] % 5); //RF_CHANNELS; if((iv->config->serial.b[5] == 0x11) || (iv->config->serial.b[5] == 0x10)) { switch(iv->config->serial.b[4]) { case 0x24: // HMS-500 From e5ce1f5094592dd50ae890c440b0806eef6c044b Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Mon, 29 Jan 2024 16:44:26 +0100 Subject: [PATCH 12/14] individualize rx offset for nRF --- src/hm/Communication.h | 7 +- src/hm/HeuristicInv.h | 2 +- src/hm/hmDefines.h | 8 -- src/hm/hmInverter.h | 1 - src/hm/hmRadio.h | 14 ++- src/hm/hmSystem.h | 3 +- src/hm/radio.h | 7 +- src/hms/cmt2300a.h | 259 ++++++++++++++++++++++++++--------------- src/hms/hmsRadio.h | 36 ++++-- 9 files changed, 209 insertions(+), 128 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 23ffe158..9219bb8e 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -139,8 +139,10 @@ class Communication : public CommQueue<> { } if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { - q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); + #if defined(ESP32) + q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000)); mWaitTime.startTimeMonitor(1000); + #endif } else { mHeu.setIvRetriesBad(q->iv); if(IV_MI == q->iv->ivGen) @@ -526,7 +528,6 @@ class Communication : public CommQueue<> { int8_t rssi = -127; uint8_t len = 0; - DPRINT_IVID(DBG_INFO, q->iv->id); for(uint8_t i = 0; i < mMaxFrameId; i++) { if(mLocalBuf[i].len + len > MAX_BUFFER) { DPRINTLN(DBG_ERROR, F("payload buffer to small!")); @@ -541,7 +542,7 @@ class Communication : public CommQueue<> { len -= 2; - //DPRINT_IVID(DBG_INFO, q->iv->id); // it's already above "for"-loop + DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("Payload (")); DBGPRINT(String(len)); if(*mPrintWholeTrace) { diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index fc782a7b..e9c7084e 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -14,7 +14,7 @@ class HeuristicInv { public: HeuristicInv() { - memset(txRfQuality, -6, RF_MAX_CHANNEL_ID); + memset(txRfQuality, 0, RF_MAX_CHANNEL_ID); } public: diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 6bd66e66..4705c061 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -78,14 +78,6 @@ enum {CH0 = 0, CH1, CH2, CH3, CH4, CH5, CH6}; enum {INV_TYPE_1CH = 0, INV_TYPE_2CH, INV_TYPE_4CH, INV_TYPE_6CH}; enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT}; -#define WORK_FREQ_KHZ 865000 // desired work frequency between DTU and - // inverter in kHz -#define HOY_BASE_FREQ_KHZ 860000 // in kHz -#define HOY_MAX_FREQ_KHZ 923500 // 0xFE * 250kHz + Base_freq -#define HOY_BOOT_FREQ_KHZ 868000 // Hoymiles boot/init frequency after power up inverter -#define FREQ_STEP_KHZ 250 // channel step size in kHz -#define FREQ_WARN_MIN_KHZ 863000 // for EU 863 - 870 MHz is allowed -#define FREQ_WARN_MAX_KHZ 870000 // for EU 863 - 870 MHz is allowed #define DURATION_ONEFRAME 50 // timeout parameter for each expected frame (ms) //#define DURATION_RESERVE {90,120} // timeout parameter to still wait after last expected frame (ms) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 00f05c79..a74ad02f 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -180,7 +180,6 @@ class Inverter { tsMaxAcPower = 0; memset(&radioStatistics, 0, sizeof(statistics_t)); - memset(mOffYD, 0, sizeof(float) * 6); memset(mLastYD, 0, sizeof(float) * 6); } diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index fbb23b57..e759576c 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -118,7 +118,7 @@ class HmRadio : public Radio { // otherwise switch to next RX channel mTimeslotStart = millis(); - if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME+DURATION_ONEFRAME))) + if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME))) //(DURATION_TXFRAME+DURATION_ONEFRAME))) mNRFloopChannels = true; rxPendular = !rxPendular; @@ -163,7 +163,7 @@ class HmRadio : public Radio { mNRFloopChannels = (mLastIv->ivGen == IV_MI); //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; - innerLoopTimeout = DURATION_LISTEN_MIN; + innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_LISTEN_MIN : 4; } if(rx_ready) { @@ -324,7 +324,13 @@ class HmRadio : public Radio { if(mLastIv->mIsSingleframeReq) // we only expect one frame here... isRetransmitAnswer = true; if(isLastPackage) - mFramesExpected = p.packet[9] - ALL_FRAMES; + setExpectedFrames(p.packet[9] - ALL_FRAMES); + if(p.packet[9] == 1 && p.millis < DURATION_ONEFRAME) + mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + 1) % RF_CHANNELS; + else if(mNRFloopChannels && mLastIv->rxOffset > RF_CHANNELS) { // unsure setting? + mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + (isLastPackage ? mFramesExpected : p.packet[9])); // make clear it's not sure, start with one more offset + mNRFloopChannels = false; + } } if(IV_MI == mLastIv->ivGen) { @@ -332,6 +338,8 @@ class HmRadio : public Radio { isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received 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 + if(p.packet[9] == 0x00 && p.millis < DURATION_ONEFRAME) + mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx - 1) % RF_CHANNELS; } rx_ready = true; //reset in case we first read messages from other inverter or ACK zero payloads } diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 1e8641cb..26d0ea5d 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -28,8 +28,7 @@ class HmSystem { iv->config = &mInverter[0].generalConfig->iv[id]; DPRINT(DBG_VERBOSE, "SERIAL: " + String(iv->config->serial.b[5], HEX)); DPRINTLN(DBG_VERBOSE, " " + String(iv->config->serial.b[4], HEX)); - //iv->rxOffset = 5 - (iv->config->serial.b[2] % 5); //RF_CHANNELS; - iv->rxOffset = (iv->config->serial.b[1] % 5); //RF_CHANNELS; + iv->rxOffset = 13; // effective 3, but can easily be recognized as default setting if((iv->config->serial.b[5] == 0x11) || (iv->config->serial.b[5] == 0x10)) { switch(iv->config->serial.b[4]) { case 0x24: // HMS-500 diff --git a/src/hm/radio.h b/src/hm/radio.h index ea6d8c05..9702c304 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy +// 2024 Ahoy, https://github.com/lumpapu/ahoy // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- @@ -28,6 +28,9 @@ class Radio { virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } virtual bool isChipConnected(void) const { return false; } + virtual uint16_t getBaseFreqMhz() { return 0; } + virtual uint16_t getBootFreqMhz() { return 0; } + virtual std::pair getFreqRangeMhz(void) { return std::make_pair(0, 0); } virtual bool loop(void) = 0; void handleIntr(void) { @@ -115,6 +118,7 @@ class Radio { chipID = ESP.getChipId(); #endif + mDtuSn = 0; uint8_t t; for(int i = 0; i < (7 << 2); i += 4) { t = (chipID >> i) & 0x0f; @@ -125,6 +129,7 @@ class Radio { mDtuSn |= 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal } + uint32_t mDtuSn; volatile bool mIrqRcvd; bool *mSerialDebug, *mPrivacyMode, *mPrintWholeTrace; diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 1ff112e2..3cdc2660 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy +// 2024 Ahoy, https://github.com/lumpapu/ahoy // Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- @@ -12,8 +12,23 @@ #include "esp32_3wSpi.h" #endif -// detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf +#include + +enum class RegionCfg : uint8_t { + EUROPE, USA, BRAZIL, NUM +}; + +enum class CmtStatus : uint8_t { + SUCCESS = 0, + ERR_SWITCH_STATE, + ERR_TX_PENDING, + FIFO_EMPTY, + ERR_RX_IN_FIFO +}; + +#define FREQ_STEP_KHZ 250 // channel step size in kHz +// detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf #define CMT2300A_MASK_CFG_RETAIN 0x10 #define CMT2300A_MASK_RSTN_IN_EN 0x20 #define CMT2300A_MASK_LOCKING_EN 0x20 @@ -152,67 +167,6 @@ #define CMT2300A_MASK_TX_DONE_FLG 0x08 #define CMT2300A_MASK_PKT_OK_FLG 0x01 -// this list and the TX5, TX10 registers were compiled from the output of -// HopeRF RFPDK Tool v1.54 -static uint8_t paLevelList[31][2] PROGMEM = { - {0x17, 0x01}, // -10dBm - {0x1a, 0x01}, // -09dBm - {0x1d, 0x01}, // -08dBm - {0x21, 0x01}, // -07dBm - {0x25, 0x01}, // -06dBm - {0x29, 0x01}, // -05dBm - {0x2d, 0x01}, // -04dBm - {0x33, 0x01}, // -03dBm - {0x39, 0x02}, // -02dBm - {0x41, 0x02}, // -01dBm - {0x4b, 0x02}, // 00dBm - {0x56, 0x03}, // 01dBm - {0x63, 0x03}, // 02dBm - {0x71, 0x04}, // 03dBm - {0x80, 0x04}, // 04dBm - {0x22, 0x01}, // 05dBm - {0x27, 0x04}, // 06dBm - {0x2c, 0x05}, // 07dBm - {0x31, 0x06}, // 08dBm - {0x38, 0x06}, // 09dBm - {0x3f, 0x07}, // 10dBm - {0x48, 0x08}, // 11dBm - {0x52, 0x09}, // 12dBm - {0x5d, 0x0b}, // 13dBm - {0x6a, 0x0c}, // 14dBm - {0x79, 0x0d}, // 15dBm - {0x46, 0x10}, // 16dBm - {0x51, 0x10}, // 17dBm - {0x60, 0x12}, // 18dBm - {0x71, 0x14}, // 19dBm - {0x8c, 0x1c} // 20dBm -}; - -// default CMT parameters -static uint8_t cmtConfig[0x60] PROGMEM { - // 0x00 - 0x0f -- RSSI offset +- 0 and 13dBm - 0x00, 0x66, 0xEC, 0x1C, 0x70, 0x80, 0x14, 0x08, - 0x11, 0x02, 0x02, 0x00, 0xAE, 0xE0, 0x35, 0x00, - // 0x10 - 0x1f - 0x00, 0xF4, 0x10, 0xE2, 0x42, 0x20, 0x0C, 0x81, - 0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12, // 860MHz as default - // 0x20 - 0x2f - 0xA6, 0xC9, 0x20, 0x20, 0xD2, 0x35, 0x0C, 0x0A, - 0x9F, 0x4B, 0x29, 0x29, 0xC0, 0x14, 0x05, 0x53, - // 0x30 - 0x3f - 0x10, 0x00, 0xB4, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x12, 0x1E, 0x00, 0xAA, 0x06, 0x00, 0x00, 0x00, - // 0x40 - 0x4f - 0x00, 0x48, 0x5A, 0x48, 0x4D, 0x01, 0x1F, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x60, - // 0x50 - 0x5f - 0xFF, 0x00, 0x00, 0x1F, 0x10, 0x70, 0x4D, 0x06, - 0x00, 0x07, 0x50, 0x00, 0x5D, 0x0B, 0x3F, 0x7F // - TX 13dBm -}; - - -enum {CMT_SUCCESS = 0, CMT_ERR_SWITCH_STATE, CMT_ERR_TX_PENDING, CMT_FIFO_EMPTY, CMT_ERR_RX_IN_FIFO}; - class Cmt2300a { public: Cmt2300a() {} @@ -234,12 +188,12 @@ class Cmt2300a { } } - uint8_t goRx(void) { + CmtStatus goRx(void) { if(mTxPending) - return CMT_ERR_TX_PENDING; + return CmtStatus::ERR_TX_PENDING; if(mInRxMode) - return CMT_SUCCESS; + return CmtStatus::SUCCESS; mSpi.readReg(CMT2300A_CUS_INT1_CTL); mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE); @@ -260,47 +214,47 @@ class Cmt2300a { mSpi.writeReg(0x16, 0x0C); // [4:3]: RSSI_DET_SEL, [2:0]: RSSI_AVG_MODE if(!cmtSwitchStatus(CMT2300A_GO_RX, CMT2300A_STA_RX)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; mInRxMode = true; - return CMT_SUCCESS; + return CmtStatus::SUCCESS; } - uint8_t getRx(uint8_t buf[], uint8_t *rxLen, uint8_t maxlen, int8_t *rssi) { + CmtStatus getRx(uint8_t buf[], uint8_t *rxLen, uint8_t maxlen, int8_t *rssi) { if(mTxPending) - return CMT_ERR_TX_PENDING; + return CmtStatus::ERR_TX_PENDING; if(0x1b != (mSpi.readReg(CMT2300A_CUS_INT_FLAG) & 0x1b)) - return CMT_FIFO_EMPTY; + return CmtStatus::FIFO_EMPTY; // receive ok (pream, sync, node, crc) if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; mSpi.readFifo(buf, rxLen, maxlen); *rssi = mSpi.readReg(CMT2300A_CUS_RSSI_DBM) - 128; if(!cmtSwitchStatus(CMT2300A_GO_SLEEP, CMT2300A_STA_SLEEP)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; mInRxMode = false; mCusIntFlag = mSpi.readReg(CMT2300A_CUS_INT_FLAG); - return CMT_SUCCESS; + return CmtStatus::SUCCESS; } - uint8_t tx(uint8_t buf[], uint8_t len) { + CmtStatus tx(uint8_t buf[], uint8_t len) { if(mTxPending) - return CMT_ERR_TX_PENDING; + return CmtStatus::ERR_TX_PENDING; if(mInRxMode) { mInRxMode = false; if(!cmtSwitchStatus(CMT2300A_GO_STBY, CMT2300A_STA_STBY)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; } mSpi.writeReg(CMT2300A_CUS_INT1_CTL, CMT2300A_INT_SEL_TX_DONE); @@ -325,16 +279,17 @@ class Cmt2300a { } if(!cmtSwitchStatus(CMT2300A_GO_TX, CMT2300A_STA_TX)) - return CMT_ERR_SWITCH_STATE; + return CmtStatus::ERR_SWITCH_STATE; // wait for tx done mTxPending = true; - return CMT_SUCCESS; + return CmtStatus::SUCCESS; } // initialize CMT2300A, returns true on success - bool reset(void) { + bool reset(RegionCfg region) { + mRegionCfg = region; mSpi.writeReg(0x7f, 0xff); // soft reset delay(30); @@ -346,10 +301,19 @@ class Cmt2300a { if(mSpi.readReg(0x62) != 0x20) return false; // not connected! - for(uint8_t i = 0; i < 0x60; i++) { + for(uint8_t i = 0; i < 0x18; i++) { + mSpi.writeReg(i, cmtConfig[i]); + } + for(uint8_t i = 0; i < 8; i++) { + mSpi.writeReg(0x18 + i, mBaseFreqCfg[static_cast(region)][i]); + } + for(uint8_t i = 0x20; i < 0x60; i++) { mSpi.writeReg(i, cmtConfig[i]); } + if(RegionCfg::EUROPE != region) + mSpi.writeReg(0x27, 0x0B); + mSpi.writeReg(CMT2300A_CUS_IO_SEL, 0x20); // -> GPIO3_SEL[1:0] = 0x02 @@ -389,23 +353,14 @@ class Cmt2300a { } inline uint8_t freq2Chan(const uint32_t freqKhz) { - if((freqKhz % FREQ_STEP_KHZ) != 0) { - DPRINT(DBG_WARN, F("switch frequency to ")); - DBGPRINT(String(freqKhz)); - DBGPRINT(F("kHz not possible!")); + if((freqKhz % FREQ_STEP_KHZ) != 0) return 0xff; // error - // apply the nearest frequency - //freqKhz = (freqKhz + FREQ_STEP_KHZ/2) / FREQ_STEP_KHZ; - //freqKhz *= FREQ_STEP_KHZ; - } - if((freqKhz < HOY_BASE_FREQ_KHZ) || (freqKhz > HOY_MAX_FREQ_KHZ)) + std::pair range = getFreqRangeMhz(); + if((freqKhz < range.first) || (freqKhz > range.second)) return 0xff; // error - if((freqKhz < FREQ_WARN_MIN_KHZ) || (freqKhz > FREQ_WARN_MAX_KHZ)) - DPRINTLN(DBG_WARN, F("Desired frequency is out of EU legal range! (863 - 870MHz)")); - - return (freqKhz - HOY_BASE_FREQ_KHZ) / FREQ_STEP_KHZ; + return (freqKhz - getBaseFreqMhz() * 1000) / FREQ_STEP_KHZ; } inline void switchChannel(uint8_t ch) { @@ -414,9 +369,9 @@ class Cmt2300a { inline uint32_t getFreqKhz(void) { if(0xff != mRqstCh) - return HOY_BASE_FREQ_KHZ + (mRqstCh * FREQ_STEP_KHZ); + return getBaseFreqMhz() * 1000 + (mRqstCh * FREQ_STEP_KHZ); else - return HOY_BASE_FREQ_KHZ + (mCurCh * FREQ_STEP_KHZ); + return getBaseFreqMhz() * 1000 + (mCurCh * FREQ_STEP_KHZ); } uint8_t getCurrentChannel(void) { @@ -443,6 +398,114 @@ class Cmt2300a { mSpi.writeReg(CMT2300A_CUS_TX9, paLevelList[level][1]); } + public: + uint16_t getBaseFreqMhz(void) { + switch(mRegionCfg) { + default: + [[fallthrough]]; + case RegionCfg::EUROPE: + break; + case RegionCfg::USA: + return 905; + case RegionCfg::BRAZIL: + return 915; + } + return 860; + } + + uint16_t getBootFreqMhz(void) { + switch(mRegionCfg) { + default: + [[fallthrough]]; + case RegionCfg::EUROPE: + break; + case RegionCfg::USA: + return 915; + case RegionCfg::BRAZIL: + return 915; + } + return 868; + } + + std::pair getFreqRangeMhz(void) { + switch(mRegionCfg) { + default: + [[fallthrough]]; + case RegionCfg::EUROPE: + break; + case RegionCfg::USA: + return std::make_pair(905, 925); + case RegionCfg::BRAZIL: + return std::make_pair(915, 928); + } + return std::make_pair(860, 870); // Europe + } + + private: + // this list and the TX5, TX10 registers were compiled from the output of + // HopeRF RFPDK Tool v1.54 + constexpr static uint8_t paLevelList[31][2] PROGMEM = { + {0x17, 0x01}, // -10dBm + {0x1a, 0x01}, // -09dBm + {0x1d, 0x01}, // -08dBm + {0x21, 0x01}, // -07dBm + {0x25, 0x01}, // -06dBm + {0x29, 0x01}, // -05dBm + {0x2d, 0x01}, // -04dBm + {0x33, 0x01}, // -03dBm + {0x39, 0x02}, // -02dBm + {0x41, 0x02}, // -01dBm + {0x4b, 0x02}, // 00dBm + {0x56, 0x03}, // 01dBm + {0x63, 0x03}, // 02dBm + {0x71, 0x04}, // 03dBm + {0x80, 0x04}, // 04dBm + {0x22, 0x01}, // 05dBm + {0x27, 0x04}, // 06dBm + {0x2c, 0x05}, // 07dBm + {0x31, 0x06}, // 08dBm + {0x38, 0x06}, // 09dBm + {0x3f, 0x07}, // 10dBm + {0x48, 0x08}, // 11dBm + {0x52, 0x09}, // 12dBm + {0x5d, 0x0b}, // 13dBm + {0x6a, 0x0c}, // 14dBm + {0x79, 0x0d}, // 15dBm + {0x46, 0x10}, // 16dBm + {0x51, 0x10}, // 17dBm + {0x60, 0x12}, // 18dBm + {0x71, 0x14}, // 19dBm + {0x8c, 0x1c} // 20dBm + }; + + // default CMT parameters + constexpr static uint8_t cmtConfig[0x60] PROGMEM { + // 0x00 - 0x0f -- RSSI offset +- 0 and 13dBm + 0x00, 0x66, 0xEC, 0x1C, 0x70, 0x80, 0x14, 0x08, + 0x11, 0x02, 0x02, 0x00, 0xAE, 0xE0, 0x35, 0x00, + // 0x10 - 0x1f + 0x00, 0xF4, 0x10, 0xE2, 0x42, 0x20, 0x0C, 0x81, + 0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12, // 860MHz as default + // 0x20 - 0x2f + 0xA6, 0xC9, 0x20, 0x20, 0xD2, 0x35, 0x0C, 0x0A, + 0x9F, 0x4B, 0x29, 0x29, 0xC0, 0x14, 0x05, 0x53, + // 0x30 - 0x3f + 0x10, 0x00, 0xB4, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x12, 0x1E, 0x00, 0xAA, 0x06, 0x00, 0x00, 0x00, + // 0x40 - 0x4f + 0x00, 0x48, 0x5A, 0x48, 0x4D, 0x01, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x60, + // 0x50 - 0x5f + 0xFF, 0x00, 0x00, 0x1F, 0x10, 0x70, 0x4D, 0x06, + 0x00, 0x07, 0x50, 0x00, 0x5D, 0x0B, 0x3F, 0x7F // TX 13dBm + }; + + constexpr static uint8_t mBaseFreqCfg[static_cast(RegionCfg::NUM)][8] { + {0x42, 0x32, 0xCF, 0x82, 0x42, 0x27, 0x76, 0x12}, // 860MHz + {0x45, 0xA8, 0x31, 0x8A, 0x45, 0x9D, 0xD8, 0x19}, // 905MHz (USA, Indonesia) + {0x46, 0x6D, 0x80, 0x86, 0x46, 0x62, 0x27, 0x16} // 915MHz (Brazil) + }; + private: void init() { mTxPending = false; @@ -480,6 +543,7 @@ class Cmt2300a { return mSpi.readReg(CMT2300A_CUS_MODE_STA) & CMT2300A_MASK_CHIP_MODE_STA; } + private: #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) cmtHal mSpi; #else @@ -490,6 +554,7 @@ class Cmt2300a { bool mInRxMode; uint8_t mCusIntFlag; uint8_t mRqstCh, mCurCh; + RegionCfg mRegionCfg = RegionCfg::EUROPE; }; #endif /*__CMT2300A_H__*/ diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 33b6a75c..07afd4b8 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -17,9 +17,9 @@ class CmtRadio : public Radio { mDtuSn = DTU_SN; } - void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { + void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, uint8_t region = 0, bool genDtuSn = true) { mCmt.setup(pinSclk, pinSdio, pinCsb, pinFcsb); - reset(genDtuSn); + reset(genDtuSn, static_cast(region)); mPrivacyMode = privacyMode; mSerialDebug = serialDebug; mPrintWholeTrace = printWholeTrace; @@ -30,7 +30,7 @@ class CmtRadio : public Radio { if((!mIrqRcvd) && (!mRqstGetRx)) return false; getRx(); - if(CMT_SUCCESS == mCmt.goRx()) { + if(CmtStatus::SUCCESS == mCmt.goRx()) { mIrqRcvd = false; mRqstGetRx = false; } @@ -76,6 +76,18 @@ class CmtRadio : public Radio { return true; } +uint16_t getBaseFreqMhz(void) override { + return mCmt.getBaseFreqMhz(); + } + + uint16_t getBootFreqMhz(void) override { + return mCmt.getBootFreqMhz(); + } + + std::pair getFreqRangeMhz(void) override { + return mCmt.getFreqRangeMhz(); + } + private: void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { @@ -104,12 +116,12 @@ class CmtRadio : public Radio { } } - uint8_t status = mCmt.tx(mTxBuf, len); + CmtStatus status = mCmt.tx(mTxBuf, len); mMillis = millis(); - if(CMT_SUCCESS != status) { + if(CmtStatus::SUCCESS != status) { DPRINT(DBG_WARN, F("CMT TX failed, code: ")); - DBGPRINTLN(String(status)); - if(CMT_ERR_RX_IN_FIFO == status) + DBGPRINTLN(String(static_cast(status))); + if(CmtStatus::ERR_RX_IN_FIFO == status) mIrqRcvd = true; } iv->mDtuTxCnt++; @@ -123,10 +135,10 @@ class CmtRadio : public Radio { return iv->ivGen; } - inline void reset(bool genDtuSn) { + inline void reset(bool genDtuSn, RegionCfg region) { if(genDtuSn) generateDtuSn(); - if(!mCmt.reset()) { + if(!mCmt.reset(region)) { mCmtAvail = false; DPRINTLN(DBG_WARN, F("Initializing CMT2300A failed!")); } else { @@ -160,8 +172,8 @@ class CmtRadio : public Radio { inline void getRx(void) { packet_t p; p.millis = millis() - mMillis; - uint8_t status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi); - if(CMT_SUCCESS == status) + CmtStatus status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi); + if(CmtStatus::SUCCESS == status) mBufCtrl.push(p); if(p.packet[9] > ALL_FRAMES) // indicates last frame @@ -171,7 +183,7 @@ class CmtRadio : public Radio { } CmtType mCmt; - bool mCmtAvail; + bool mCmtAvail = false; bool mRqstGetRx = false; uint32_t mMillis; }; From bba82d8b3a9a634381dfdf128f1fa11e72b163a8 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 30 Jan 2024 13:32:55 +0100 Subject: [PATCH 13/14] different tx-offests for 4ch HM * discord 0.8.6803 * tx+3 for 4ch-HM, tx+2 for other Inverters --- src/hm/CommQueue.h | 2 +- src/hm/Communication.h | 9 ++++++--- src/hm/HeuristicInv.h | 15 +++++++++++++++ src/hm/hmInverter.h | 21 ++++++++++++++++++--- src/hm/hmRadio.h | 43 ++++++++++++++++++++++++++---------------- src/hm/hmSystem.h | 7 ++++++- src/hms/cmt2300a.h | 6 +++--- 7 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index d7cc5642..acbe9a35 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -12,7 +12,7 @@ #include "../utils/dbg.h" #define DEFAULT_ATTEMPS 5 -#define MORE_ATTEMPS_ALARMDATA 0 // 8 +#define MORE_ATTEMPS_ALARMDATA 3 // 8 #define MORE_ATTEMPS_GRIDONPROFILEPARA 0 // 5 template diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 9219bb8e..8887a4a2 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -140,7 +140,10 @@ class Communication : public CommQueue<> { if(!q->iv->mGotFragment) { if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) { #if defined(ESP32) - q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000)); + if(!q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000))) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINTLN(F("switch frequency failed!")); + } mWaitTime.startTimeMonitor(1000); #endif } else { @@ -418,8 +421,8 @@ class Communication : public CommQueue<> { if((*frameId & ALL_FRAMES) == ALL_FRAMES) { mMaxFrameId = (*frameId & 0x7f); - /*if(mMaxFrameId > 8) // large payloads, e.g. AlarmData - incrAttempt(mMaxFrameId - 6);*/ + if(mMaxFrameId > 8) // large payloads, e.g. AlarmData + incrAttempt(mMaxFrameId - 6); } frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index e9c7084e..505562e3 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -14,7 +14,22 @@ class HeuristicInv { public: HeuristicInv() { + clear(); + } + + void clear() { memset(txRfQuality, 0, RF_MAX_CHANNEL_ID); + txRfChId = 0; + lastBestTxChId = 0; + testPeriodSendCnt = 0; + testPeriodFailCnt = 0; + testChId = 0; + saveOldTestQuality = -6; + lastRxFragments = 0; + } + + bool isTxAtMax(void) const { + return (RF_MAX_QUALITY == txRfQuality[txRfChId]); } public: diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index a74ad02f..e6e22fb7 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -193,6 +193,14 @@ class Inverter { if(mNextLive) cb(RealTimeRunData_Debug, false); // get live data else { + if(INV_RADIO_TYPE_NRF == ivRadioType) { + // get live data until quality reaches maximum + if(!heuristics.isTxAtMax()) { + cb(RealTimeRunData_Debug, false); // get live data + return; + } + } + if(actPowerLimit == 0xffff) { cb(SystemConfigPara, false); // power limit info cb(RealTimeRunData_Debug, false); @@ -201,17 +209,18 @@ class Inverter { devControlCmd = InitDataState; mGetLossInterval = 1; } else if(0 == getFwVersion()) { - cb(RealTimeRunData_Debug, false); // get live data cb(InverterDevInform_All, false); // get firmware version + cb(RealTimeRunData_Debug, false); // get live data } else if(0 == getHwVersion()) { - cb(RealTimeRunData_Debug, false); // get live data cb(InverterDevInform_Simple, false); // get hardware version - } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) { cb(RealTimeRunData_Debug, false); // get live data + } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) { cb(AlarmData, false); // get last alarms + cb(RealTimeRunData_Debug, false); // get live data } else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile cb(GridOnProFilePara, false); + cb(RealTimeRunData_Debug, false); // get live data } else if (mGetLossInterval > AHOY_GET_LOSS_INTERVAL) { // get loss rate mGetLossInterval = 1; cb(RealTimeRunData_Debug, false); // get live data @@ -455,6 +464,12 @@ class Inverter { status = InverterStatus::OFF; actPowerLimit = 0xffff; // power limit will be read once inverter becomes available alarmMesIndex = 0; + if(ivRadioType == INV_RADIO_TYPE_NRF) { + heuristics.clear(); + #ifdef DYNAMIC_OFFSET + rxOffset = ivGen == IV_HM ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting + #endif + } } else status = InverterStatus::WAS_ON; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index e759576c..0dcbccb3 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -121,14 +121,14 @@ class HmRadio : public Radio { if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME))) //(DURATION_TXFRAME+DURATION_ONEFRAME))) mNRFloopChannels = true; - rxPendular = !rxPendular; + mRxPendular = !mRxPendular; //innerLoopTimeout = (rxPendular ? 1 : 2)*DURATION_LISTEN_MIN; - //innerLoopTimeout = DURATION_LISTEN_MIN; + innerLoopTimeout = DURATION_LISTEN_MIN; if(mNRFloopChannels) tempRxChIdx = (tempRxChIdx + 4) % RF_CHANNELS; else - tempRxChIdx = (mRxChIdx + rxPendular*4) % RF_CHANNELS; + tempRxChIdx = (mRxChIdx + mRxPendular*4) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[tempRxChIdx]); isRxInit = false; @@ -142,7 +142,7 @@ class HmRadio : public Radio { if(tx_ok || tx_fail) { // tx related interrupt, basically we should start listening mNrf24->flush_tx(); // empty TX FIFO - mTxSetupTime = millis() - mMillis; + //mTxSetupTime = millis() - mMillis; if(mNRFisInRX) { DPRINTLN(DBG_WARN, F("unexpected tx irq!")); @@ -153,17 +153,21 @@ class HmRadio : public Radio { if(tx_ok) mLastIv->mAckCount++; - //mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; + //#ifdef DYNAMIC_OFFSET mRxChIdx = (mTxChIdx + mLastIv->rxOffset) % RF_CHANNELS; + /*#else + mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; + #endif*/ mNrf24->setChannel(mRfChLst[mRxChIdx]); mNrf24->startListening(); mTimeslotStart = millis(); tempRxChIdx = mRxChIdx; // might be better to start off with one channel less? - rxPendular = false; + mRxPendular = false; mNRFloopChannels = (mLastIv->ivGen == IV_MI); //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; - innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_LISTEN_MIN : 4; + //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_LISTEN_MIN : 4; + innerLoopTimeout = (mLastIv->mIsSingleframeReq || mLastIv->ivGen == IV_MI) ? DURATION_LISTEN_MIN : DURATION_TXFRAME; } if(rx_ready) { @@ -176,7 +180,7 @@ class HmRadio : public Radio { innerLoopTimeout = DURATION_LISTEN_MIN; mTimeslotStart = millis(); if (!mNRFloopChannels) { - //rxPendular = true; // stay longer on the next rx channel + //mRxPendular = true; // stay longer on the next rx channel if (isRxInit) { isRxInit = false; tempRxChIdx = (mRxChIdx + 4) % RF_CHANNELS; @@ -325,12 +329,14 @@ class HmRadio : public Radio { isRetransmitAnswer = true; if(isLastPackage) setExpectedFrames(p.packet[9] - ALL_FRAMES); + #ifdef DYNAMIC_OFFSET if(p.packet[9] == 1 && p.millis < DURATION_ONEFRAME) mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + 1) % RF_CHANNELS; else if(mNRFloopChannels && mLastIv->rxOffset > RF_CHANNELS) { // unsure setting? mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + (isLastPackage ? mFramesExpected : p.packet[9])); // make clear it's not sure, start with one more offset mNRFloopChannels = false; } + #endif } if(IV_MI == mLastIv->ivGen) { @@ -338,8 +344,10 @@ class HmRadio : public Radio { isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received 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 + #ifdef DYNAMIC_OFFSET if(p.packet[9] == 0x00 && p.millis < DURATION_ONEFRAME) mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx - 1) % RF_CHANNELS; + #endif } rx_ready = true; //reset in case we first read messages from other inverter or ACK zero payloads } @@ -347,9 +355,8 @@ class HmRadio : public Radio { } yield(); } - if(isLastPackage) { + if(isLastPackage) mLastIv->mGotLastMsg = true; - } return isLastPackage || isRetransmitAnswer; } @@ -361,10 +368,7 @@ class HmRadio : public Radio { mTxChIdx = iv->heuristics.txRfChId; if(*mSerialDebug) { - /* remark rejoe2: imo this has no added value here. - As this belongs to the last tx cycle, we should print that info - directly when switching from tx to rx. Otherwise we might confuse users. - if(!isRetransmit) { + /*if(!isRetransmit) { DPRINT(DBG_INFO, "last tx setup: "); DBGPRINT(String(mTxSetupTime)); DBGPRINTLN("ms"); @@ -374,13 +378,19 @@ class HmRadio : public Radio { DBGPRINT(F("TX ")); DBGPRINT(String(len)); DBGPRINT(" CH"); + if(mTxChIdx == 0) + DBGPRINT("0"); DBGPRINT(String(mRfChLst[mTxChIdx])); DBGPRINT(F(", ")); DBGPRINT(String(mTxRetriesNext)); //DBGPRINT(F(" retries | ")); + //#ifdef DYNAMIC_OFFSET DBGPRINT(F(" ret., rx offset: ")); DBGPRINT(String(iv->rxOffset)); DBGPRINT(F(" | ")); + /*#else + DBGPRINT(F(" ret. | ")); + #endif*/ if(*mPrintWholeTrace) { if(*mPrivacyMode) ah::dumpBuf(mTxBuf, len, 1, 4); @@ -396,6 +406,7 @@ class HmRadio : public Radio { } mNrf24->stopListening(); + mNrf24->flush_rx(); if(!isRetransmit && mTxRetries != mTxRetriesNext) { mNrf24->setRetries(3, mTxRetriesNext); mTxRetries = mTxRetriesNext; @@ -439,9 +450,9 @@ class HmRadio : public Radio { bool mNRFloopChannels = false; bool mNRFisInRX = false; bool isRxInit = true; - bool rxPendular = false; + bool mRxPendular = false; uint32_t innerLoopTimeout = DURATION_LISTEN_MIN; - uint8_t mTxSetupTime = 0; + //uint8_t mTxSetupTime = 0; uint8_t mTxRetries = 15; // memorize last setting for mNrf24->setRetries(3, 15); std::unique_ptr mSpi; diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 26d0ea5d..b727e0bb 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -28,7 +28,6 @@ class HmSystem { iv->config = &mInverter[0].generalConfig->iv[id]; DPRINT(DBG_VERBOSE, "SERIAL: " + String(iv->config->serial.b[5], HEX)); DPRINTLN(DBG_VERBOSE, " " + String(iv->config->serial.b[4], HEX)); - iv->rxOffset = 13; // effective 3, but can easily be recognized as default setting if((iv->config->serial.b[5] == 0x11) || (iv->config->serial.b[5] == 0x10)) { switch(iv->config->serial.b[4]) { case 0x24: // HMS-500 @@ -96,6 +95,12 @@ class HmSystem { if((iv->config->serial.b[5] == 0x10) && ((iv->config->serial.b[4] & 0x03) == 0x01)) DPRINTLN(DBG_WARN, F("MI Inverter, has some restrictions!")); + #ifdef DYNAMIC_OFFSET + iv->rxOffset = iv->ivGen == IV_HM ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting + #else + iv->rxOffset = (iv->ivGen == IV_HM && iv->type == INV_TYPE_4CH) ? 3 : 2; // effective 3 (or 2), but can easily be recognized as default setting + #endif + cb(iv); } diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 3cdc2660..e6456f5b 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -356,11 +356,11 @@ class Cmt2300a { if((freqKhz % FREQ_STEP_KHZ) != 0) return 0xff; // error - std::pair range = getFreqRangeMhz(); - if((freqKhz < range.first) || (freqKhz > range.second)) + std::pair range = getFreqRangeMhz(); + if((freqKhz < (range.first * 1000)) || (freqKhz > (range.second * 1000))) return 0xff; // error - return (freqKhz - getBaseFreqMhz() * 1000) / FREQ_STEP_KHZ; + return (freqKhz - (getBaseFreqMhz() * 1000)) / FREQ_STEP_KHZ; } inline void switchChannel(uint8_t ch) { From fddd03af6b98f75c73ba1b93a29cec88358ef527 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Tue, 30 Jan 2024 15:37:40 +0100 Subject: [PATCH 14/14] re-flexibilisize rx-channels also for HM 2ch devices --- src/hm/hmDefines.h | 4 ++-- src/hm/hmRadio.h | 5 ++--- src/hm/hmSystem.h | 3 ++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 4705c061..f06c06fe 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -90,8 +90,8 @@ const uint8_t duration_reserve[2] = {65,115}; #define LIMIT_VERYFAST_IV 70 // time limit to qualify an inverter as very fast answering inverter #define LIMIT_FAST_IV_MI 35 // time limit to qualify a MI type inverter as fast answering inverter #define LIMIT_VERYFAST_IV_MI 22 // time limit to qualify a MI type inverter as very fast answering inverter -#define RETRIES_FAST_IV 11 // how often shall a message be automatically retransmitted by the nRF (fast answering inverter) -#define RETRIES_VERYFAST_IV 7 // how often shall a message be automatically retransmitted by the nRF (very fast answering inverter) +#define RETRIES_FAST_IV 12 // how often shall a message be automatically retransmitted by the nRF (fast answering inverter) +#define RETRIES_VERYFAST_IV 9 // how often shall a message be automatically retransmitted by the nRF (very fast answering inverter) typedef struct { diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 0dcbccb3..a88e43c6 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -122,7 +122,6 @@ class HmRadio : public Radio { mNRFloopChannels = true; mRxPendular = !mRxPendular; - //innerLoopTimeout = (rxPendular ? 1 : 2)*DURATION_LISTEN_MIN; innerLoopTimeout = DURATION_LISTEN_MIN; if(mNRFloopChannels) @@ -167,7 +166,8 @@ class HmRadio : public Radio { //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME; //innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_LISTEN_MIN : 4; - innerLoopTimeout = (mLastIv->mIsSingleframeReq || mLastIv->ivGen == IV_MI) ? DURATION_LISTEN_MIN : DURATION_TXFRAME; + //innerLoopTimeout = (mLastIv->mIsSingleframeReq || mLastIv->ivGen == IV_MI) ? DURATION_LISTEN_MIN : DURATION_TXFRAME; + innerLoopTimeout = DURATION_LISTEN_MIN; } if(rx_ready) { @@ -180,7 +180,6 @@ class HmRadio : public Radio { innerLoopTimeout = DURATION_LISTEN_MIN; mTimeslotStart = millis(); if (!mNRFloopChannels) { - //mRxPendular = true; // stay longer on the next rx channel if (isRxInit) { isRxInit = false; tempRxChIdx = (mRxChIdx + 4) % RF_CHANNELS; diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index b727e0bb..aa5d7492 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -98,7 +98,8 @@ class HmSystem { #ifdef DYNAMIC_OFFSET iv->rxOffset = iv->ivGen == IV_HM ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting #else - iv->rxOffset = (iv->ivGen == IV_HM && iv->type == INV_TYPE_4CH) ? 3 : 2; // effective 3 (or 2), but can easily be recognized as default setting + iv->rxOffset = (iv->ivGen == IV_HM && iv->type == INV_TYPE_4CH) ? 3 : 2; + iv->rxOffset = iv->ivGen == IV_HM ? 3 : 2; #endif cb(iv);