From df2e8407510871a13459c84a7e5eb3f0aa4fc939 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 10 Dec 2023 22:40:46 +0100 Subject: [PATCH] 0.8.18 * copied even more from the original heuristic code #1259 --- src/CHANGES.md | 3 ++ src/defines.h | 2 +- src/hm/Communication.h | 82 ++++++++++++++++++++++------------------- src/hm/Heuristic.h | 84 +++++++++++++++++++++++++++++------------- src/hm/HeuristicInv.h | 11 ++++-- src/hm/hmInverter.h | 1 + 6 files changed, 116 insertions(+), 67 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index e7fbefcc..a36e0769 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.18 - 2023-12-10 +* copied even more from the original heuristic code #1259 + ## 0.8.17 - 2023-12-10 * possible fix of NRF with opendtufusion (without ETH) * small fix in heuristics (if conditions made assignment not comparisson) diff --git a/src/defines.h b/src/defines.h index 351810fa..ffd3c6ae 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 17 +#define VERSION_PATCH 18 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 9d92992f..bf95d44c 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -65,6 +65,7 @@ class Communication : public CommQueue<> { mHeu.getTxCh(q->iv); q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; + q->iv->curFrmCnt = 0; mIsResend = false; if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! @@ -140,7 +141,7 @@ class Communication : public CommQueue<> { mWaitTimeout = millis() + 1000; } } - closeRequest(q->iv, false, false); + closeRequest(q, false, false); break; } @@ -182,17 +183,18 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.frmCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - parseFrame(p); + if(parseFrame(p)) + q->iv->curFrmCnt++; nextState = States::CHECK_PACKAGE; } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command parseDevCtrl(p, q); - closeRequest(q->iv, true); + closeRequest(q, true, true); } else if(IV_MI == q->iv->ivGen) { - parseMiFrame(p, q); + if(parseMiFrame(p, q)) + q->iv->curFrmCnt++; } } else { q->iv->radioStatistics.rxFail++; // got no complete payload - DPRINTLN(DBG_WARN, F("Inverter serial does not match")); mWaitTimeout = millis() + timeout; } @@ -200,7 +202,7 @@ class Communication : public CommQueue<> { yield(); } if((0 == q->attempts) && (!q->iv->mGotFragment)) - closeRequest(q->iv, false); + closeRequest(q, false, true); else { if(q->iv->ivGen != IV_MI) mState = nextState; @@ -212,9 +214,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); - //closeRequest(q->iv, q->iv->miMultiParts > 5); } - closeRequest(q->iv, true); + closeRequest(q, true, true); } } @@ -267,7 +268,7 @@ class Communication : public CommQueue<> { if(NULL != mCbPayload) (mCbPayload)(q->cmd, q->iv); - closeRequest(q->iv); + closeRequest(q, true, true); break; } }); @@ -278,8 +279,13 @@ class Communication : public CommQueue<> { 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(tmp[i] != buf[i]) { + DPRINT(DBG_WARN, F("Inverter serial does not match, got: 0x")); + DHEX(buf[0]);DHEX(buf[1]);DHEX(buf[2]);DHEX(buf[3]); + DBGPRINT(F(", expected: 0x")); + DHEX(tmp[0]);DHEX(tmp[1]);DHEX(tmp[2]);DHEX(tmp[3]); return false; + } } return true; } @@ -288,20 +294,20 @@ class Communication : public CommQueue<> { return (ah::crc8(buf, len - 1) == buf[len-1]); } - inline void parseFrame(packet_t *p) { + inline bool parseFrame(packet_t *p) { uint8_t *frameId = &p->packet[9]; if(0x00 == *frameId) { DPRINTLN(DBG_WARN, F("invalid frameId 0x00")); - return; // skip current packet + return false; // skip current packet } if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) { DPRINTLN(DBG_WARN, F("local buffer to small for payload fragments")); - return; // local storage is to small for id + return false; // local storage is to small for id } if(!checkFrameCrc(p->packet, p->len)) { DPRINTLN(DBG_WARN, F("frame CRC is wrong")); - return; // CRC8 is wrong, frame invalid + return false; // CRC8 is wrong, frame invalid } if((*frameId & ALL_FRAMES) == ALL_FRAMES) @@ -311,9 +317,11 @@ class Communication : public CommQueue<> { memcpy(f->buf, &p->packet[10], p->len-11); f->len = p->len - 11; f->rssi = p->rssi; + + return true; } - inline void parseMiFrame(packet_t *p, const queue_s *q) { + inline bool parseMiFrame(packet_t *p, const queue_s *q) { 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)) @@ -330,6 +338,8 @@ class Communication : public CommQueue<> { 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; } inline void parseDevCtrl(packet_t *p, const queue_s *q) { @@ -369,7 +379,7 @@ class Communication : public CommQueue<> { DBGPRINTLN(F("-> Fail")); /*q->iv->radioStatistics.rxFail++; // got fragments but not complete response cmdDone();*/ - closeRequest(q->iv, false, false); + closeRequest(q, false, false); } else DBGPRINTLN(F("-> complete retransmit")); @@ -417,7 +427,7 @@ class Communication : public CommQueue<> { DBGPRINTLN(F(" bytes")); } /*q->iv->radioStatistics.rxFail++;*/ - closeRequest(q->iv, false, false); + closeRequest(q, false, false); return; } @@ -450,31 +460,29 @@ class Communication : public CommQueue<> { mState = States::WAIT; } else { add(q, true); - closeRequest(q->iv, false); + closeRequest(q, false, true); } } private: - void closeRequest(Inverter<> *iv, bool succeeded = true, bool delCmd = true) { - // ordering of lines is relevant for statistics - if(succeeded) { - mHeu.setGotAll(iv); - iv->radioStatistics.rxSuccess++; - } else if(iv->mGotFragment) { - mHeu.setGotFragment(iv); - iv->radioStatistics.rxFail++; // got no complete payload - } else { - iv->radioStatistics.rxFailNoAnser++; // got nothing - mHeu.setGotNothing(iv); + void closeRequest(const queue_s *q, bool crcPass, bool delCmd) { + mHeu.evalTxChQuality(q->iv, crcPass, (4 - q->attempts), q->iv->curFrmCnt); + if(crcPass) + q->iv->radioStatistics.rxSuccess++; + else if(q->iv->mGotFragment) + q->iv->radioStatistics.rxFail++; // got no complete payload + else { + q->iv->radioStatistics.rxFailNoAnser++; // got nothing mWaitTimeout = millis() + WAIT_GAP_TIMEOUT; } + cmdDone(delCmd); - iv->mGotFragment = false; - iv->mGotLastMsg = false; - iv->miMultiParts = 0; - mIsResend = false; - mFirstTry = false; // for correct reset - mState = States::RESET; + q->iv->mGotFragment = false; + q->iv->mGotLastMsg = false; + q->iv->miMultiParts = 0; + mIsResend = false; + mFirstTry = false; // for correct reset + mState = States::RESET; } inline void miHwDecode(packet_t *p, const queue_s *q) { @@ -673,10 +681,10 @@ class Communication : public CommQueue<> { } if(q->iv->miMultiParts == 7) { - mHeu.setGotAll(q->iv); + //mHeu.setGotAll(q->iv); q->iv->radioStatistics.rxSuccess++; } else - mHeu.setGotFragment(q->iv); + //mHeu.setGotFragment(q->iv); /*iv->radioStatistics.rxFail++; // got no complete payload*/ //q->iv->radioStatistics.retransmits++; q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 6b28f216..a30436f7 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -15,6 +15,11 @@ #define RF_TX_TEST_CHAN_1ST_USE 0xff +#define RF_TX_CHAN_QUALITY_GOOD 2 +#define RF_TX_CHAN_QUALITY_OK 1 +#define RF_TX_CHAN_QUALITY_LOW -1 +#define RF_TX_CHAN_QUALITY_BAD -2 + class Heuristic { public: uint8_t getTxCh(Inverter<> *iv) { @@ -25,7 +30,7 @@ class Heuristic { // start with the next index: round robbin in case of same 'best' quality uint8_t curId = (ih->txRfChId + 1) % RF_MAX_CHANNEL_ID; - uint8_t lastBestId = ih->txRfChId; + ih->lastBestTxChId = ih->txRfChId; ih->txRfChId = curId; curId = (curId + 1) % RF_MAX_CHANNEL_ID; for(uint8_t i = 1; i < RF_MAX_CHANNEL_ID; i++) { @@ -37,14 +42,16 @@ class Heuristic { if(ih->testPeriodSendCnt < 0xff) ih->testPeriodSendCnt++; - if((ih->txRfChId == lastBestId) && (ih->testPeriodSendCnt >= RF_TEST_PERIOD_MAX_SEND_CNT)) { + if((ih->txRfChId == ih->lastBestTxChId) && (ih->testPeriodSendCnt >= RF_TEST_PERIOD_MAX_SEND_CNT)) { if(ih->testPeriodFailCnt > RF_TEST_PERIOD_MAX_FAIL_CNT) { - // try round robbin another chan and see if it works even better + // try round robbin another chan and see if it works even better ih->testChId = (ih->testChId + 1) % RF_MAX_CHANNEL_ID; if(ih->testChId == ih->txRfChId) ih->testChId = (ih->testChId + 1) % RF_MAX_CHANNEL_ID; // give it a fair chance but remember old status in case of immediate fail + ih->saveOldTestQuality = ih->txRfQuality[ih->testChId]; + ih->txRfQuality[ih->testChId] = ih->txRfQuality[ih->txRfChId]; ih->txRfChId = ih->testChId; ih->testChId = RF_TX_TEST_CHAN_1ST_USE; // mark the chan as a test and as 1st use during new test period DPRINTLN(DBG_INFO, "Test CH " + String(id2Ch(ih->txRfChId))); @@ -53,7 +60,7 @@ class Heuristic { // start new test period ih->testPeriodSendCnt = 0; ih->testPeriodFailCnt = 0; - } else if(ih->txRfChId != lastBestId) { + } else if(ih->txRfChId != ih->lastBestTxChId) { // start new test period ih->testPeriodSendCnt = 0; ih->testPeriodFailCnt = 0; @@ -62,27 +69,52 @@ class Heuristic { return id2Ch(ih->txRfChId); } - void setGotAll(Inverter<> *iv) { - updateQuality(iv, 2); // GOOD - } - - void setGotFragment(Inverter<> *iv) { - updateQuality(iv, 1); // OK - } - - void setGotNothing(Inverter<> *iv) { + void evalTxChQuality(Inverter<> *iv, bool crcPass, uint8_t retransmits, uint8_t rxFragments) { HeuristicInv *ih = &iv->heuristics; - if(RF_TX_TEST_CHAN_1ST_USE == ih->testChId) { - // immediate fail - ih->testChId = ih->txRfChId; // reset to best - return; - } - - if(ih->testPeriodFailCnt < 0xff) - ih->testPeriodFailCnt++; - - updateQuality(iv, -2); // BAD + if(ih->lastRxFragments == rxFragments) { + // nothing received: send probably lost + if(!retransmits || isNewTxCh(ih)) { + if(RF_TX_TEST_CHAN_1ST_USE == ih->testChId) { + // switch back to original quality + ih->txRfQuality[ih->txRfChId] = ih->saveOldTestQuality; + + updateQuality(ih, RF_TX_CHAN_QUALITY_BAD); + if(ih->testPeriodFailCnt < 0xff) + ih->testPeriodFailCnt++; + } + } + } else if(!ih->lastRxFragments && crcPass) { + if(!retransmits || isNewTxCh(ih)) { + // every fragment received successfull immediately + updateQuality(ih, RF_TX_CHAN_QUALITY_GOOD); + } else { + // every fragment received successfully + updateQuality(ih, RF_TX_CHAN_QUALITY_OK); + } + } else if(crcPass) { + if(isNewTxCh(ih)) { + // last Fragment successfully received on new send channel + updateQuality(ih, RF_TX_CHAN_QUALITY_OK); + } + } else if(!retransmits || isNewTxCh(ih)) { + // no complete receive for this send channel + if((rxFragments - ih->lastRxFragments) > 2) { + // graceful evaluation for big inverters that have to send 4 answer packets + updateQuality(ih, RF_TX_CHAN_QUALITY_OK); + } else if((rxFragments - ih->lastRxFragments) < 2) { + if(RF_TX_TEST_CHAN_1ST_USE == ih->txRfChId) { + // switch back to original quality + ih->txRfQuality[ih->txRfChId] = ih->saveOldTestQuality; + } + updateQuality(ih, RF_TX_CHAN_QUALITY_LOW); + if(ih->testPeriodFailCnt < 0xff) + ih->testPeriodFailCnt++; + } // else: _QUALITY_NEUTRAL, keep any test channel + } // else: dont overestimate burst distortion + + ih->testChId = ih->txRfChId; // reset to best + ih->lastRxFragments = rxFragments; } void printStatus(Inverter<> *iv) { @@ -105,9 +137,11 @@ class Heuristic { } private: - void updateQuality(Inverter<> *iv, uint8_t quality) { - HeuristicInv *ih = &iv->heuristics; + bool isNewTxCh(HeuristicInv *ih) { + return ih->txRfChId != ih->lastBestTxChId; + } + void updateQuality(HeuristicInv *ih, uint8_t quality) { ih->txRfQuality[ih->txRfChId] += quality; if(ih->txRfQuality[ih->txRfChId] > RF_MAX_QUALITY) ih->txRfQuality[ih->txRfChId] = RF_MAX_QUALITY; diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index d3c2cdf0..e7ad6edd 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -19,11 +19,14 @@ class HeuristicInv { public: int8_t txRfQuality[RF_MAX_CHANNEL_ID]; // heuristics tx quality (check 'Heuristics.h') - uint8_t txRfChId = 0; // RF TX channel id + uint8_t txRfChId = 0; // RF TX channel id + uint8_t lastBestTxChId = 0; - uint8_t testPeriodSendCnt = 0; - uint8_t testPeriodFailCnt = 0; - uint8_t testChId = 0; + uint8_t testPeriodSendCnt = 0; + uint8_t testPeriodFailCnt = 0; + uint8_t testChId = 0; + int8_t saveOldTestQuality = -6; + uint8_t lastRxFragments = 0; }; #endif /*__HEURISTIC_INV_H__*/ diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 72bbb7fd..3e3e1c08 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -129,6 +129,7 @@ class Inverter { 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 + uint8_t curFrmCnt; // count received frames in current loop 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