From 4749b5ef3d3a9f69330af07fd8b9c7271fabd371 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 18 Jan 2024 14:15:44 +0100 Subject: [PATCH 1/3] non blocking version - shorten hms waiting times after last frame es well (might be too short to immedately stop timer!) - timings still need review... --- src/app.cpp | 2 - src/app.h | 1 + src/hm/Communication.h | 145 +++++++++++++++++++++++++--------------- src/hm/hmDefines.h | 6 ++ src/hm/hmInverter.h | 10 ++- src/hm/hmRadio.h | 148 ++++++++++++++++++++++++++--------------- src/hm/radio.h | 11 ++- src/hms/hmsRadio.h | 5 +- 8 files changed, 214 insertions(+), 114 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index c2a1fd6e..97abc790 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -7,8 +7,6 @@ #include "app.h" #include "utils/sun.h" -#define WDT_TIMEOUT_SECONDS 8 // Watchdog Timeout 8s - #if !defined(ESP32) void esp_task_wdt_reset() {} #endif diff --git a/src/app.h b/src/app.h index e6630219..a5438777 100644 --- a/src/app.h +++ b/src/app.h @@ -10,6 +10,7 @@ #include #if defined(ESP32) #include +#define WDT_TIMEOUT_SECONDS 8 // Watchdog Timeout 8s #endif #include "config/settings.h" diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 7b5c84f9..efcb69f8 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -12,10 +12,6 @@ #include "../utils/timemonitor.h" #include "Heuristic.h" -#define MI_TIMEOUT 250 // timeout for MI type requests -#define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received -#define DEFAULT_TIMEOUT 500 // timeout for regular requests -#define SINGLEFR_TIMEOUT 100 // timeout for single frame requests #define MAX_BUFFER 250 typedef std::function *)> payloadListenerType; @@ -65,8 +61,6 @@ class Communication : public CommQueue<> { mLastEmptyQueueMillis = millis(); mPrintSequenceDuration = true; - uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : (((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : ((q->cmd != AlarmData) && (q->cmd != GridOnProFilePara) ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); - /*if(mDebugState != mState) { DPRINT(DBG_INFO, F("State: ")); DBGHEXLN((uint8_t)(mState)); @@ -94,6 +88,9 @@ class Communication : public CommQueue<> { mFirstTry = q->iv->isAvailable(); q->iv->mCmd = q->cmd; q->iv->mIsSingleframeReq = false; + mFramesExpected = getFramesExpected(q); // function to get expected frame count. + mTimeout = DURATION_TXFRAME + mFramesExpected*DURATION_ONEFRAME + DURATION_RESERVE; + mState = States::START; break; @@ -115,7 +112,8 @@ class Communication : public CommQueue<> { q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); q->iv->radioStatistics.txCnt++; - mWaitTime.startTimeMonitor(timeout); + q->iv->radio->mRadioWaitTime.startTimeMonitor(mTimeout); + mIsRetransmit = false; setAttempt(); if((q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) @@ -124,7 +122,7 @@ class Communication : public CommQueue<> { break; case States::WAIT: - if (!mWaitTime.isTimeout()) + if (!q->iv->radio->mRadioWaitTime.isTimeout()) return; mState = States::CHECK_FRAMES; break; @@ -134,7 +132,7 @@ class Communication : public CommQueue<> { if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); - DBGPRINT(String(mWaitTime.getRunTime())); + DBGPRINT(String(q->iv->radio->mRadioWaitTime.getRunTime())); DBGPRINTLN(F("ms")); } if(!q->iv->mGotFragment) { @@ -150,13 +148,9 @@ class Communication : public CommQueue<> { mHeu.evalTxChQuality(q->iv, false, 0, 0); //q->iv->radioStatistics.rxFailNoAnser++; q->iv->radioStatistics.retransmits++; - mWaitTime.stopTimeMonitor(); + q->iv->radio->mRadioWaitTime.stopTimeMonitor(); mState = States::START; - /*if(*mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINTLN(F("second try")); - }*/ return; } } @@ -196,36 +190,30 @@ class Communication : public CommQueue<> { yield(); } - /*if(0 == q->attempts) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("no attempts left")); - closeRequest(q, false); - } else {*/ - if(q->iv->ivGen != IV_MI) { - mState = States::CHECK_PACKAGE; + 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) { + miRepeatRequest(q); + return; + } } else { - bool fastNext = true; - if(q->iv->miMultiParts < 6) { - mState = States::WAIT; - if((mWaitTime.isTimeout() && mIsRetransmit) || !mIsRetransmit) { - miRepeatRequest(q); - return; - } - } else { - mHeu.evalTxChQuality(q->iv, true, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt); - if(((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH)) - || ((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); + mHeu.evalTxChQuality(q->iv, true, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt); + if(((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH)) + || ((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); } - //} + } } break; @@ -321,6 +309,56 @@ class Communication : public CommQueue<> { } } + + inline uint8_t getFramesExpected(const queue_s *q) { + if(q->isDevControl) + return 1; + + if(q->iv->ivGen != IV_MI) { + if (q->cmd == RealTimeRunData_Debug) { + switch (q->iv->type) { // breaks are intentionally missing! + case INV_TYPE_1CH: return 2; + case INV_TYPE_2CH: return 3; + case INV_TYPE_4CH: return 4; + case INV_TYPE_6CH: return 7; + default: return 7; + } + } + + switch (q->cmd) { + case InverterDevInform_All: + case GetLossRate: + case SystemConfigPara: + return 1; + case AlarmData: return 0x0c; + case GridOnProFilePara: return 6; + + /*HardWareConfig = 3, // 0x03 + SimpleCalibrationPara = 4, // 0x04 + RealTimeRunData_Reality = 12, // 0x0c + RealTimeRunData_A_Phase = 13, // 0x0d + RealTimeRunData_B_Phase = 14, // 0x0e + RealTimeRunData_C_Phase = 15, // 0x0f + AlarmUpdate = 18, // 0x12, Alarm data - all pending alarms + RecordData = 19, // 0x13 + InternalData = 20, // 0x14 + GetSelfCheckState = 30, // 0x1e + */ + + default: return 8; // for the moment, this should result in sth. like a default timeout of 500ms + } + + } else { //MI + switch (q->cmd) { + case 0x09: + case 0x11: + return 2; + case 0x0f: return 3; + default: return 1; + } + } + } + inline bool validateIvSerial(uint8_t buf[], Inverter<> *iv) { uint8_t tmp[4]; CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); @@ -540,15 +578,13 @@ class Communication : public CommQueue<> { } void sendRetransmit(const queue_s *q, uint8_t i) { - //if(q->attempts) { - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); - q->iv->radioStatistics.retransmits++; - mWaitTime.startTimeMonitor(SINGLEFR_TIMEOUT); // timeout - mState = States::WAIT; - /*} else { - //add(q, true); - closeRequest(q, false); - }*/ + mFramesExpected = 1; + q->iv->radio->setExpectedFrames(mFramesExpected); + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); + q->iv->radioStatistics.retransmits++; + q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + DURATION_RESERVE); + + mState = States::WAIT; } private: @@ -787,9 +823,11 @@ class Communication : public CommQueue<> { if(q->iv->miMultiParts == 7) q->iv->radioStatistics.rxSuccess++; + mFramesExpected = getFramesExpected(q); + q->iv->radio->setExpectedFrames(mFramesExpected); q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); - mWaitTime.startTimeMonitor(MI_TIMEOUT); + q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + DURATION_RESERVE); q->iv->miMultiParts = 0; q->iv->mGotFragment = 0; mIsRetransmit = true; @@ -809,8 +847,7 @@ class Communication : public CommQueue<> { q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); - mWaitTime.startTimeMonitor(MI_TIMEOUT); - //mState = States::WAIT; + q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + DURATION_RESERVE); mIsRetransmit = false; } @@ -965,6 +1002,8 @@ class Communication : public CommQueue<> { bool mFirstTry = false; // see, if we should do a second try 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 uint8_t mPayload[MAX_BUFFER]; payloadListenerType mCbPayload = NULL; powerLimitAckListenerType mCbPwrAck = NULL; diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index a2a2d6b4..bee67bb8 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -86,6 +86,12 @@ enum {INV_TYPE_1CH = 0, INV_TYPE_2CH, INV_TYPE_4CH, INV_TYPE_6CH}; #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 // timeout parameter to still wait after last expected frame (ms) +#define DURATION_TXFRAME 60 // 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) + typedef struct { uint8_t fieldId; // field id diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 7bbf1019..ff3343fb 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -639,7 +639,13 @@ class Inverter { DBGPRINT(F(", DTU loss: ")); DBGPRINT(String(radioStatistics.dtuLoss)); DBGPRINT(F(" of ")); - DBGPRINTLN(String(radioStatistics.dtuSent)); + if(mAckCount) { + DBGPRINT(String(radioStatistics.dtuSent)); + DBGPRINT(F(". ACKs: ")); + DBGPRINTLN(String(mAckCount)); + mAckCount = 0; + } else + DBGPRINTLN(String(radioStatistics.dtuSent)); } mIvRxCnt = rxCnt; @@ -849,7 +855,7 @@ class Inverter { uint8_t mGetLossInterval = 0; // request iv every AHOY_GET_LOSS_INTERVAL RealTimeRunData_Debug uint16_t mIvRxCnt = 0; uint16_t mIvTxCnt = 0; - + uint16_t mAckCount = 0; }; template diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 6539dd21..0ef24477 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -105,61 +105,88 @@ class HmRadio : public Radio { } void loop(void) { - if (!mIrqRcvd) - return; // nothing to do - mIrqRcvd = false; - bool tx_ok, tx_fail, rx_ready; - mNrf24->whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH - mNrf24->flush_tx(); // empty TX FIFO - - // start listening - uint8_t chOffset = 2; - mRxChIdx = (mTxChIdx + chOffset) % RF_CHANNELS; - mNrf24->setChannel(mRfChLst[mRxChIdx]); - mNrf24->startListening(); + if (!mIrqRcvd && !mNRFisInRX) + return; // first quick check => nothing to do at all here if(NULL == mLastIv) // prevent reading on NULL object! return; - uint32_t innerLoopTimeout = 55000; - uint32_t loopMillis = millis(); - uint32_t outerLoopTimeout = (mLastIv->mIsSingleframeReq) ? 100 : ((mLastIv->mCmd != AlarmData) && (mLastIv->mCmd != GridOnProFilePara)) ? 400 : 600; - bool isRxInit = true; + if(!mIrqRcvd) { // no news from nRF, check timers + if (mRadioWaitTime.isTimeout()) { // timeout reached! + mNRFisInRX = false; + // add stop listening? + return; + } + yield(); - while ((millis() - loopMillis) < outerLoopTimeout) { - uint32_t startMicros = micros(); - while ((micros() - startMicros) < innerLoopTimeout) { // listen (4088us or?) 5110us to each channel - if (mIrqRcvd) { - mIrqRcvd = false; + if (millis() - mTimeslotStart < innerLoopTimeout) + return; // nothing to do - if (getReceived()) { // everything received - return; - } + // otherwise switch to next RX channel + mTimeslotStart = millis(); + rxPendular = !rxPendular; + //innerLoopTimeout = (rxPendular ? 1 : 2)*DURATION_LISTEN_MIN; + innerLoopTimeout = DURATION_LISTEN_MIN; - innerLoopTimeout = 4088*5; - if (isRxInit) { - isRxInit = false; - if (micros() - startMicros < 42000) { - innerLoopTimeout = 4088*12; - mRxChIdx = (mRxChIdx + 4) % RF_CHANNELS; - mNrf24->setChannel(mRfChLst[mRxChIdx]); - } - } + tempRxChIdx = (mRxChIdx + rxPendular*chOffset2) % RF_CHANNELS; + mNrf24->setChannel(mRfChLst[tempRxChIdx]); + isRxInit = false; - startMicros = micros(); - } - yield(); + return; + } + + // here we got news from the nRF + + mNrf24->whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH + mIrqRcvd = false; + + if(tx_ok || tx_fail) { // tx related interrupt, basically we should start listening + mNrf24->flush_tx(); // empty TX FIFO + + if(mNRFisInRX) { + DPRINTLN(DBG_WARN, F("unexpected tx irq!")); + return; } - // switch to next RX channel - mRxChIdx = (mRxChIdx + 4) % RF_CHANNELS; + + mNRFisInRX = true; + if(tx_ok) + mLastIv->mAckCount++; + + // start listening + mRxChIdx = (mTxChIdx + chOffset) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); - innerLoopTimeout = 4088; - isRxInit = false; + mNrf24->startListening(); + mTimeslotStart = millis(); + tempRxChIdx = mRxChIdx; + chOffset2 = mLastIv->ivGen == IV_HM ? 4 : (mLastIv->mCmd == MI_REQ_CH1 || mLastIv->mCmd == MI_REQ_CH2) ? 1 :4; // reversed channel order for everything apart from 1/2ch MI Data requests + rxPendular = false; + + innerLoopTimeout = DURATION_TXFRAME; + } + + if(rx_ready) { + + if (getReceived()) { // check what we got, returns true for last package + mNRFisInRX = false; + mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first end his transmissions + // add stop listening? + } else { + //rxPendular = true; // stay longer on the next rx channel + + if (isRxInit) { + isRxInit = false; + tempRxChIdx = (mRxChIdx + chOffset2) % RF_CHANNELS; + mNrf24->setChannel(mRfChLst[tempRxChIdx]); + } else { + mRxChIdx = tempRxChIdx; + } + innerLoopTimeout = DURATION_LISTEN_MIN; + mTimeslotStart = millis(); + } + return; } - // not finished but time is over - return; } bool isChipConnected(void) { @@ -264,16 +291,15 @@ class HmRadio : public Radio { private: inline bool getReceived(void) { - bool tx_ok, tx_fail, rx_ready; - mNrf24->whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH bool isLastPackage = false; + rx_ready = false; // reset for ACK case while(mNrf24->available()) { uint8_t len; len = mNrf24->getDynamicPayloadSize(); // if payload size > 32, corrupt payload has been flushed if (len > 0) { packet_t p; - p.ch = mRfChLst[mRxChIdx]; + p.ch = mRfChLst[tempRxChIdx]; p.len = (len > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len; p.rssi = mNrf24->testRPD() ? -64 : -75; p.millis = millis() - mMillis; @@ -285,16 +311,18 @@ class HmRadio : public Radio { ah::dumpBuf(p.packet, p.len, 1, 4); else ah::dumpBuf(p.packet, p.len); - return false; + //return false; + } else { + mLastIv->mGotFragment = true; + mBufCtrl.push(p); + if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command + isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received + else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command + isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received + else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 && + isLastPackage = true; // response from dev control command + rx_ready = true; //reset in case we first read messages from other inverter or ACK zero payloads } - mLastIv->mGotFragment = true; - mBufCtrl.push(p); - if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command - isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received - else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command - isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received - else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 && - isLastPackage = true; // response from dev control command } } yield(); @@ -340,6 +368,8 @@ class HmRadio : public Radio { mLastIv = iv; iv->mDtuTxCnt++; + mNRFisInRX = false; + mRqstGetRx = true; // preparation only } uint64_t getIvId(Inverter<> *iv) { @@ -362,8 +392,18 @@ class HmRadio : public Radio { uint8_t mRfChLst[RF_CHANNELS] = {03, 23, 40, 61, 75}; // channel List:2403, 2423, 2440, 2461, 2475MHz uint8_t mTxChIdx = 0; uint8_t mRxChIdx = 0; + uint8_t tempRxChIdx = mRxChIdx; bool mGotLastMsg = false; uint32_t mMillis; + bool tx_ok, tx_fail, rx_ready = false; + uint8_t chOffset = 2; + uint8_t chOffset2 = 4; + unsigned long mTimeslotStart = 0; + bool mNRFisInRX = false; + bool isRxInit = true; + bool rxPendular = false; + uint32_t innerLoopTimeout = DURATION_LISTEN_MIN; + //uint32_t outerLoopTimeout = 400; std::unique_ptr mSpi; std::unique_ptr mNrf24; diff --git a/src/hm/radio.h b/src/hm/radio.h index 1422b285..1db0b361 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -13,6 +13,7 @@ #include "../utils/dbg.h" #include "../utils/crc.h" +#include "../utils/timemonitor.h" enum { IRQ_UNKNOWN = 0, IRQ_OK, IRQ_ERROR }; @@ -68,9 +69,14 @@ class Radio { return mDtuSn; } + void setExpectedFrames(uint8_t framesExpected) { + mFramesExpected = framesExpected; + } + public: std::queue mBufCtrl; uint8_t mIrqOk = IRQ_UNKNOWN; + TimeMonitor mRadioWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; @@ -116,13 +122,14 @@ class Radio { mDtuSn |= (t << i); } 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 mRqstGetRx; bool *mSerialDebug, *mPrivacyMode, *mPrintWholeTrace; uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; - + uint8_t mFramesExpected = 0x0c; }; #endif /*__RADIO_H__*/ diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 6b502816..443a7d89 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -163,10 +163,13 @@ class CmtRadio : public Radio { uint8_t status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi); if(CMT_SUCCESS == status) mBufCtrl.push(p); + 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? } CmtType mCmt; - bool mRqstGetRx; + //bool mRqstGetRx; bool mCmtAvail; uint32_t mMillis; }; From 5b3b9ca88e43492a15d37076aec91e20b5f91416 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 18 Jan 2024 18:20:18 +0100 Subject: [PATCH 2/3] Disable stopping timer for CMT breaks communication when enabled. Maybe there's another solution or some bug? --- src/hms/hmsRadio.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 443a7d89..aab8a6a7 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -163,8 +163,8 @@ class CmtRadio : public Radio { uint8_t status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi); if(CMT_SUCCESS == status) mBufCtrl.push(p); - if(p.packet[9] > ALL_FRAMES) // indicates last frame - mRadioWaitTime.stopTimeMonitor(); // we got everything we expected and can exit rx mode... + //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? } From ac0c93cb408521899e4c6c406c8136b9eb720d98 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Sat, 20 Jan 2024 10:03:57 +0100 Subject: [PATCH 3/3] non blocking - first review - discord 0.8.5902 - stay longer on expected rx channel to wait for first frame - stick to looping over 5 channels for MI (after first frame or timeout) --- src/app.cpp | 21 +++++++++++++++++++-- src/app.h | 4 +++- src/hm/CommQueue.h | 4 ++-- src/hm/Communication.h | 27 +++++++++++---------------- src/hm/hmDefines.h | 7 ++++--- src/hm/hmInverter.h | 1 + src/hm/hmRadio.h | 36 +++++++++++++++++++++--------------- src/hm/hmSystem.h | 16 +++++++++++----- 8 files changed, 72 insertions(+), 44 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 97abc790..c53efa3b 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -106,7 +106,7 @@ void app::setup() { #endif // Plugins #if defined(PLUGIN_DISPLAY) - if (mConfig->plugin.display.type != 0) + if (DISP_TYPE_T0_NONE != mConfig->plugin.display.type) #if defined(ESP32) mDisplay.setup(this, &mConfig->plugin.display, &mSys, &mNrfRadio, &mCmtRadio, &mTimestamp); #else @@ -184,7 +184,7 @@ void app::regularTickers(void) { everySec(std::bind(&WebType::tickSecond, &mWeb), "webSc"); // Plugins #if defined(PLUGIN_DISPLAY) - if (mConfig->plugin.display.type != 0) + if (DISP_TYPE_T0_NONE != mConfig->plugin.display.type) everySec(std::bind(&DisplayType::tickerSecond, &mDisplay), "disp"); #endif every(std::bind(&PubSerialType::tick, &mPubSerial), 5, "uart"); @@ -350,6 +350,14 @@ void app::tickSunrise(void) { #endif } +//----------------------------------------------------------------------------- +void app::notAvailChanged(void) { + #if defined(ENABLE_MQTT) + if (mMqttEnabled) + mMqtt.notAvailChanged(mAllIvNotAvail); + #endif +} + //----------------------------------------------------------------------------- void app::tickZeroValues(void) { zeroIvValues(!CHECK_AVAIL, SKIP_YIELD_DAY); @@ -401,6 +409,7 @@ void app::tickMidnight(void) { //----------------------------------------------------------------------------- void app::tickSend(void) { + bool notAvail = true; uint8_t fill = mCommunication.getFillState(); uint8_t max = mCommunication.getMaxFill(); if((max-MAX_NUM_INVERTERS) <= fill) { @@ -426,6 +435,9 @@ void app::tickSend(void) { if(!iv->radio->isChipConnected()) continue; + if(InverterStatus::OFF != iv->status) + notAvail = false; + iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { if(isDevControl) mCommunication.addImportant(iv, cmd); @@ -435,6 +447,10 @@ void app::tickSend(void) { } } + if(mAllIvNotAvail != notAvail) + once(std::bind(&app::notAvailChanged, this), 1, "avail"); + mAllIvNotAvail = notAvail; + updateLed(); } @@ -533,6 +549,7 @@ void app::resetSystem(void) { #endif mSendFirst = true; + mAllIvNotAvail = true; mSunrise = 0; mSunset = 0; diff --git a/src/app.h b/src/app.h index a5438777..4d9aae79 100644 --- a/src/app.h +++ b/src/app.h @@ -320,7 +320,7 @@ class app : public IApp, public ah::Scheduler { #endif /*ENABLE_MQTT*/ #endif #if defined(PLUGIN_DISPLAY) - if(mConfig->plugin.display.type != 0) + if(DISP_TYPE_T0_NONE != mConfig->plugin.display.type) mDisplay.payloadEventListener(cmd); #endif updateLed(); @@ -367,6 +367,7 @@ class app : public IApp, public ah::Scheduler { void tickMinute(void); void tickZeroValues(void); void tickMidnight(void); + void notAvailChanged(void); HmSystemType mSys; HmRadio<> mNrfRadio; @@ -403,6 +404,7 @@ class app : public IApp, public ah::Scheduler { uint8_t mSendLastIvId; bool mSendFirst; + bool mAllIvNotAvail; bool mNetworkConnected; diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 13decc01..d3fe1c69 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 15 -#define MORE_ATTEMPS_GRIDONPROFILEPARA 15 +#define MORE_ATTEMPS_ALARMDATA 8 +#define MORE_ATTEMPS_GRIDONPROFILEPARA 5 template class CommQueue { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index efcb69f8..8874a87a 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -89,14 +89,14 @@ class Communication : public CommQueue<> { q->iv->mCmd = q->cmd; q->iv->mIsSingleframeReq = false; mFramesExpected = getFramesExpected(q); // function to get expected frame count. - mTimeout = DURATION_TXFRAME + mFramesExpected*DURATION_ONEFRAME + DURATION_RESERVE; + mTimeout = DURATION_TXFRAME + mFramesExpected*DURATION_ONEFRAME + duration_reserve[q->iv->ivRadioType]; mState = States::START; break; case States::START: setTs(mTimestamp); - if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { + if(q->iv->ivRadioType == INV_RADIO_TYPE_CMT) { // frequency was changed during runtime if(q->iv->curCmtFreq != q->iv->config->frequency) { if(q->iv->radio->switchFrequencyCh(q->iv, q->iv->curCmtFreq, q->iv->config->frequency)) @@ -136,7 +136,7 @@ class Communication : public CommQueue<> { DBGPRINTLN(F("ms")); } if(!q->iv->mGotFragment) { - if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { + if(q->iv->ivRadioType == INV_RADIO_TYPE_CMT) { 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 { @@ -284,7 +284,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(p->millis)); DBGPRINT(F("ms | ")); DBGPRINT(String(p->len)); - if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { + if(q->iv->ivRadioType == INV_RADIO_TYPE_NRF) { DBGPRINT(F(" CH")); if(3 == p->ch) DBGPRINT(F("0")); @@ -316,13 +316,8 @@ class Communication : public CommQueue<> { if(q->iv->ivGen != IV_MI) { if (q->cmd == RealTimeRunData_Debug) { - switch (q->iv->type) { // breaks are intentionally missing! - case INV_TYPE_1CH: return 2; - case INV_TYPE_2CH: return 3; - case INV_TYPE_4CH: return 4; - case INV_TYPE_6CH: return 7; - default: return 7; - } + uint8_t framecnt[4] = {2, 3, 4, 7}; + return framecnt[q->iv->type]; } switch (q->cmd) { @@ -350,8 +345,8 @@ class Communication : public CommQueue<> { } else { //MI switch (q->cmd) { - case 0x09: - case 0x11: + case MI_REQ_CH1: + case MI_REQ_CH2: return 2; case 0x0f: return 3; default: return 1; @@ -582,7 +577,7 @@ class Communication : public CommQueue<> { q->iv->radio->setExpectedFrames(mFramesExpected); q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + DURATION_RESERVE); + q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + duration_reserve[q->iv->ivRadioType]); mState = States::WAIT; } @@ -827,7 +822,7 @@ class Communication : public CommQueue<> { q->iv->radio->setExpectedFrames(mFramesExpected); q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); - q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + DURATION_RESERVE); + q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + duration_reserve[q->iv->ivRadioType]); q->iv->miMultiParts = 0; q->iv->mGotFragment = 0; mIsRetransmit = true; @@ -847,7 +842,7 @@ class Communication : public CommQueue<> { q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); - q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + DURATION_RESERVE); + q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + duration_reserve[q->iv->ivRadioType]); mIsRetransmit = false; } diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index bee67bb8..969e4e1b 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -76,6 +76,7 @@ enum {CMD_CALC = 0xffff}; 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 @@ -87,11 +88,11 @@ enum {INV_TYPE_1CH = 0, INV_TYPE_2CH, INV_TYPE_4CH, INV_TYPE_6CH}; #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 // timeout parameter to still wait after last expected frame (ms) -#define DURATION_TXFRAME 60 // timeout parameter for first transmission and first expected frame (time to first channel switch from tx start!) (ms) +//#define DURATION_RESERVE {90,120} // timeout parameter to still wait after last expected frame (ms) +#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}; typedef struct { uint8_t fieldId; // field id diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index ff3343fb..2c1c6362 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -114,6 +114,7 @@ template class Inverter { public: uint8_t ivGen; // generation of inverter (HM / MI) + uint8_t ivRadioType; // refers to used radio (nRF24 / CMT) cfgIv_t *config; // stored settings uint8_t id; // unique id uint8_t type; // integer which refers to inverter type diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 0ef24477..54dc0121 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -125,11 +125,16 @@ class HmRadio : public Radio { // otherwise switch to next RX channel mTimeslotStart = millis(); + if(!mNRFloopChannels && (mTimeslotStart - mLastIrqTime > (DURATION_TXFRAME+DURATION_ONEFRAME))) + mNRFloopChannels = true; + rxPendular = !rxPendular; //innerLoopTimeout = (rxPendular ? 1 : 2)*DURATION_LISTEN_MIN; innerLoopTimeout = DURATION_LISTEN_MIN; - tempRxChIdx = (mRxChIdx + rxPendular*chOffset2) % RF_CHANNELS; + tempRxChIdx = mNRFloopChannels ? + (tempRxChIdx + 4) % RF_CHANNELS : + (mRxChIdx + rxPendular*4) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[tempRxChIdx]); isRxInit = false; @@ -140,6 +145,7 @@ class HmRadio : public Radio { mNrf24->whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH mIrqRcvd = false; + mLastIrqTime = millis(); if(tx_ok || tx_fail) { // tx related interrupt, basically we should start listening mNrf24->flush_tx(); // empty TX FIFO @@ -154,13 +160,13 @@ class HmRadio : public Radio { mLastIv->mAckCount++; // start listening - mRxChIdx = (mTxChIdx + chOffset) % RF_CHANNELS; + mRxChIdx = (mTxChIdx + 2 ) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); mNrf24->startListening(); mTimeslotStart = millis(); tempRxChIdx = mRxChIdx; - chOffset2 = mLastIv->ivGen == IV_HM ? 4 : (mLastIv->mCmd == MI_REQ_CH1 || mLastIv->mCmd == MI_REQ_CH2) ? 1 :4; // reversed channel order for everything apart from 1/2ch MI Data requests rxPendular = false; + mNRFloopChannels = mLastIv->ivGen == IV_MI; innerLoopTimeout = DURATION_TXFRAME; } @@ -172,17 +178,18 @@ class HmRadio : public Radio { mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first end his transmissions // add stop listening? } else { - //rxPendular = true; // stay longer on the next rx channel - - if (isRxInit) { - isRxInit = false; - tempRxChIdx = (mRxChIdx + chOffset2) % RF_CHANNELS; - mNrf24->setChannel(mRfChLst[tempRxChIdx]); - } else { - mRxChIdx = tempRxChIdx; - } innerLoopTimeout = DURATION_LISTEN_MIN; mTimeslotStart = millis(); + if (!mNRFloopChannels) { + //rxPendular = true; // stay longer on the next rx channel + if (isRxInit) { + isRxInit = false; + tempRxChIdx = (mRxChIdx + 4) % RF_CHANNELS; + mNrf24->setChannel(mRfChLst[tempRxChIdx]); + } else + mRxChIdx = tempRxChIdx; + + } } return; } @@ -396,14 +403,13 @@ class HmRadio : public Radio { bool mGotLastMsg = false; uint32_t mMillis; bool tx_ok, tx_fail, rx_ready = false; - uint8_t chOffset = 2; - uint8_t chOffset2 = 4; unsigned long mTimeslotStart = 0; + unsigned long mLastIrqTime = 0; + bool mNRFloopChannels = false; bool mNRFisInRX = false; bool isRxInit = true; bool rxPendular = false; uint32_t innerLoopTimeout = DURATION_LISTEN_MIN; - //uint32_t outerLoopTimeout = 400; std::unique_ptr mSpi; std::unique_ptr mNrf24; diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 8f997104..8229378e 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -51,15 +51,21 @@ class HmSystem { } if(iv->config->serial.b[5] == 0x11) { - if((iv->config->serial.b[4] & 0x0f) == 0x04) + if((iv->config->serial.b[4] & 0x0f) == 0x04) { iv->ivGen = IV_HMS; - else + iv->ivRadioType = INV_RADIO_TYPE_CMT; + } else { iv->ivGen = IV_HM; + iv->ivRadioType = INV_RADIO_TYPE_NRF; + } } - else if((iv->config->serial.b[4] & 0x03) == 0x02) // MI 3rd Gen -> same as HM + else if((iv->config->serial.b[4] & 0x03) == 0x02) { // MI 3rd Gen -> same as HM iv->ivGen = IV_HM; - else // MI 2nd Gen + iv->ivRadioType = INV_RADIO_TYPE_NRF; + } else { // MI 2nd Gen iv->ivGen = IV_MI; + iv->ivRadioType = INV_RADIO_TYPE_NRF; + } } else if(iv->config->serial.b[5] == 0x13) { iv->ivGen = IV_HMT; iv->type = INV_TYPE_6CH; @@ -87,7 +93,7 @@ class HmSystem { DBGPRINTLN(String(iv->config->serial.u64, HEX)); if((iv->config->serial.b[5] == 0x10) && ((iv->config->serial.b[4] & 0x03) == 0x01)) - DPRINTLN(DBG_WARN, F("MI Inverter are not fully supported now!!!")); + DPRINTLN(DBG_WARN, F("MI Inverter, has some restrictions!")); cb(iv); }