From 222bf0e54a4315706bb0d39c38af05b2943c2821 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 14 Dec 2023 23:34:10 +0100 Subject: [PATCH] 0.8.23 * heuristics fix #1269 #1270 * moved `sendInterval` in settings, **important:** *will be reseted to 15s after update to this version* * try to prevent access to radio classes if they are not activated * fixed millis in serial log * changed 'print whole trace' = `false` as default * added communication loop duration in [ms] to serial console * don't print Hex-Payload if 'print whole trace' == `false` --- src/CHANGES.md | 9 +++++++++ src/app.cpp | 14 ++++++++++++-- src/app.h | 6 +++++- src/appInterface.h | 1 + src/config/settings.h | 16 ++++++++++------ src/defines.h | 2 +- src/hm/CommQueue.h | 9 +++++++++ src/hm/Communication.h | 40 +++++++++++++++++++++++++++------------- src/hm/Heuristic.h | 29 +++++++++++++++++++++-------- src/utils/helper.cpp | 6 ++++-- src/utils/helper.h | 2 +- src/utils/scheduler.h | 11 ++++++----- src/web/RestApi.h | 22 ++++++++++++---------- src/web/web.h | 6 ++---- 14 files changed, 120 insertions(+), 53 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 839470fb..85e477e3 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,14 @@ # Development Changes +## 0.8.23 - 2023-12-14 +* heuristics fix #1269 #1270 +* moved `sendInterval` in settings, **important:** *will be reseted to 15s after update to this version* +* try to prevent access to radio classes if they are not activated +* fixed millis in serial log +* changed 'print whole trace' = `false` as default +* added communication loop duration in [ms] to serial console +* don't print Hex-Payload if 'print whole trace' == `false` + ## 0.8.22 - 2023-12-13 * fix communication state-machine regarding zero export #1267 diff --git a/src/app.cpp b/src/app.cpp index cb2e6947..d670c696 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -123,7 +123,7 @@ void app::onNetwork(bool gotIp) { mNetworkConnected = gotIp; ah::Scheduler::resetTicker(); regularTickers(); //reinstall regular tickers - every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval, "tSend"); + every(std::bind(&app::tickSend, this), mConfig->inst.sendInterval, "tSend"); mMqttReconnect = true; mSunrise = 0; // needs to be set to 0, to reinstall sunrise and ivComm tickers! once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2"); @@ -275,7 +275,7 @@ void app::tickIVCommunication(void) { onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig, "ivCom"); if (zeroValues) // at least one inverter - once(std::bind(&app::tickZeroValues, this), mConfig->nrf.sendInterval, "tZero"); + once(std::bind(&app::tickZeroValues, this), mConfig->inst.sendInterval, "tZero"); } //----------------------------------------------------------------------------- @@ -334,6 +334,16 @@ void app::tickMidnight(void) { //----------------------------------------------------------------------------- void app::tickSend(void) { + uint8_t fill = mCommunication.getFillState(); + uint8_t max = mCommunication.getMaxFill(); + if((max-MAX_NUM_INVERTERS) <= fill) { + DPRINT(DBG_WARN, F("send queue almost full, consider to increase interval, ")); + DBGPRINT(String(fill)); + DBGPRINT(F(" of ")); + DBGPRINT(String(max)); + DBGPRINTLN(F("entries used")); + } + for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { Inverter<> *iv = mSys.getInverterByPos(i); if(NULL == iv) diff --git a/src/app.h b/src/app.h index f2b4e548..a71ee03c 100644 --- a/src/app.h +++ b/src/app.h @@ -91,7 +91,11 @@ class app : public IApp, public ah::Scheduler { } uint32_t getTimestamp() { - return Scheduler::getTimestamp(); + return Scheduler::mTimestamp; + } + + uint64_t getTimestampMs() { + return ((uint64_t)Scheduler::mTimestamp * 1000) + (uint64_t)Scheduler::mTsMillis; } bool saveSettings(bool reboot) { diff --git a/src/appInterface.h b/src/appInterface.h index 7814d0e1..34dc5ddc 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -41,6 +41,7 @@ class IApp { virtual uint32_t getUptime() = 0; virtual uint32_t getTimestamp() = 0; + virtual uint64_t getTimestampMs() = 0; virtual uint32_t getSunrise() = 0; virtual uint32_t getSunset() = 0; virtual void setTimestamp(uint32_t newTime) = 0; diff --git a/src/config/settings.h b/src/config/settings.h index 92ad1195..31b5cab4 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -30,7 +30,7 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define CONFIG_VERSION 4 +#define CONFIG_VERSION 5 #define PROT_MASK_INDEX 0x0001 @@ -80,7 +80,6 @@ typedef struct { typedef struct { bool enabled; - uint16_t sendInterval; uint8_t pinCs; uint8_t pinCe; uint8_t pinIrq; @@ -150,6 +149,7 @@ typedef struct { bool enabled; cfgIv_t iv[MAX_NUM_INVERTERS]; + uint16_t sendInterval; bool rstYieldMidNight; bool rstValsNotAvail; bool rstValsCommStop; @@ -388,7 +388,6 @@ class settings { snprintf(mCfg.sys.deviceName, DEVNAME_LEN, DEF_DEVICE_NAME); - mCfg.nrf.sendInterval = SEND_INTERVAL; mCfg.nrf.pinCs = DEF_NRF_CS_PIN; mCfg.nrf.pinCe = DEF_NRF_CE_PIN; mCfg.nrf.pinIrq = DEF_NRF_IRQ_PIN; @@ -433,6 +432,7 @@ class settings { snprintf(mCfg.mqtt.topic, MQTT_TOPIC_LEN, "%s", DEF_MQTT_TOPIC); mCfg.mqtt.interval = 0; // off + mCfg.inst.sendInterval = SEND_INTERVAL; mCfg.inst.rstYieldMidNight = false; mCfg.inst.rstValsNotAvail = false; mCfg.inst.rstValsCommStop = false; @@ -478,11 +478,15 @@ class settings { mCfg.inst.iv[i].add2Total = true; } if(mCfg.configVersion < 3) { - mCfg.serial.printWholeTrace = true; + mCfg.serial.printWholeTrace = false; } if(mCfg.configVersion < 4) { mCfg.inst.gapMs = 2000; } + if(mCfg.configVersion < 5) { + mCfg.inst.sendInterval = SEND_INTERVAL; + mCfg.serial.printWholeTrace = false; + } } } @@ -539,7 +543,6 @@ class settings { void jsonNrf(JsonObject obj, bool set = false) { if(set) { - obj[F("intvl")] = mCfg.nrf.sendInterval; obj[F("cs")] = mCfg.nrf.pinCs; obj[F("ce")] = mCfg.nrf.pinCe; obj[F("irq")] = mCfg.nrf.pinIrq; @@ -548,7 +551,6 @@ class settings { obj[F("miso")] = mCfg.nrf.pinMiso; obj[F("en")] = (bool) mCfg.nrf.enabled; } else { - getVal(obj, F("intvl"), &mCfg.nrf.sendInterval); getVal(obj, F("cs"), &mCfg.nrf.pinCs); getVal(obj, F("ce"), &mCfg.nrf.pinCe); getVal(obj, F("irq"), &mCfg.nrf.pinIrq); @@ -707,6 +709,7 @@ class settings { void jsonInst(JsonObject obj, bool set = false) { if(set) { + obj[F("intvl")] = mCfg.inst.sendInterval; obj[F("en")] = (bool)mCfg.inst.enabled; obj[F("rstMidNight")] = (bool)mCfg.inst.rstYieldMidNight; obj[F("rstNotAvail")] = (bool)mCfg.inst.rstValsNotAvail; @@ -717,6 +720,7 @@ class settings { obj[F("gap")] = mCfg.inst.gapMs; } else { + getVal(obj, F("intvl"), &mCfg.inst.sendInterval); getVal(obj, F("en"), &mCfg.inst.enabled); getVal(obj, F("rstMidNight"), &mCfg.inst.rstYieldMidNight); getVal(obj, F("rstNotAvail"), &mCfg.inst.rstValsNotAvail); diff --git a/src/defines.h b/src/defines.h index 8d5dbfd3..c4559891 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 22 +#define VERSION_PATCH 23 //------------------------------------- typedef struct { diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 9771393d..5d6f9bd0 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -9,6 +9,7 @@ #include #include #include "hmInverter.h" +#include "../utils/dbg.h" template class CommQueue { @@ -29,6 +30,14 @@ class CommQueue { mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop, false); } + uint8_t getFillState(void) { + return abs(mRdPtr - mWrPtr); + } + + uint8_t getMaxFill(void) { + return N; + } + protected: struct queue_s { Inverter<> *iv; diff --git a/src/hm/Communication.h b/src/hm/Communication.h index c72aa45d..51db6418 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -45,8 +45,19 @@ class Communication : public CommQueue<> { void loop() { get([this](bool valid, const queue_s *q) { - if(!valid) + if(!valid) { + if(mPrintSequenceDuration) { + mPrintSequenceDuration = false; + DPRINT(DBG_INFO, F("com loop duration: ")); + DBGPRINT(String(millis() - mLastEmptyQueueMillis)); + DBGPRINTLN(F("ms")); + DBGPRINTLN(F("-----")); + } return; // empty + } + if(!mPrintSequenceDuration) // entry was added to the queue + mLastEmptyQueueMillis = millis(); + mPrintSequenceDuration = true; uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT; uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; @@ -151,7 +162,6 @@ class Communication : public CommQueue<> { mIsRetransmit = false; mFirstTry = false; // for correct reset - States nextState = States::RESET; while(!q->iv->radio->mBufCtrl.empty()) { packet_t *p = &q->iv->radio->mBufCtrl.front(); printRxInfo(q, p); @@ -162,7 +172,6 @@ class Communication : public CommQueue<> { if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command 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 if(parseDevCtrl(p, q)) closeRequest(q, true); @@ -179,16 +188,16 @@ class Communication : public CommQueue<> { yield(); } - if(0 == q->attempts) + if(0 == q->attempts) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("no attempts left")); closeRequest(q, false); - else { + } else { if(q->iv->ivGen != IV_MI) { - mState = nextState; - if(States::RESET == nextState) // no valid package received - closeRequest(q, false); + mState = States::CHECK_PACKAGE; } else { if(q->iv->miMultiParts < 6) { - nextState = States::WAIT; + mState = States::WAIT; } else { if(((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH)) || ((q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH)) @@ -237,7 +246,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(q->attempts)); DBGPRINTLN(F(" attempts left)")); } - sendRetransmit(q, framnr-1); + sendRetransmit(q, (framnr-1)); mIsRetransmit = true; mlastTO_min = timeout_min; return; @@ -425,8 +434,11 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("Payload (")); DBGPRINT(String(len)); - DBGPRINT(F("): ")); - ah::dumpBuf(mPayload, len); + if(*mPrintWholeTrace) { + DBGPRINT(F("): ")); + ah::dumpBuf(mPayload, len); + } else + DBGPRINTLN(F(")")); record_t<> *rec = q->iv->getRecordStruct(q->cmd); if(NULL == rec) { @@ -496,7 +508,7 @@ class Communication : public CommQueue<> { mIsRetransmit = false; mFirstTry = false; // for correct reset mState = States::RESET; - DBGPRINTLN("-----"); + DBGPRINTLN(F("-----")); } inline void miHwDecode(packet_t *p, const queue_s *q) { @@ -852,6 +864,8 @@ class Communication : public CommQueue<> { payloadListenerType mCbPayload = NULL; alarmListenerType mCbAlarm = NULL; Heuristic mHeu; + uint32_t mLastEmptyQueueMillis = 0; + bool mPrintSequenceDuration = false; //States mDebugState = States::START; }; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 4b3705dd..64c78cc8 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -54,7 +54,7 @@ class Heuristic { 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))); + DPRINTLN(DBG_INFO, F("Test CH ") + String(id2Ch(ih->txRfChId))); } // start new test period @@ -72,17 +72,29 @@ class Heuristic { void evalTxChQuality(Inverter<> *iv, bool crcPass, uint8_t retransmits, uint8_t rxFragments) { HeuristicInv *ih = &iv->heuristics; + #if (DBG_DEBUG == DEBUG_LEVEL) + DPRINT(DBG_DEBUG, "eval "); + DBGPRINT(String(crcPass)); + DBGPRINT(", "); + DBGPRINT(String(retransmits)); + DBGPRINT(", "); + DBGPRINT(String(rxFragments)); + DBGPRINT(", "); + DBGPRINTLN(String(ih->lastRxFragments)); + #endif + if(ih->lastRxFragments == rxFragments) { - // nothing received: send probably lost - if(!retransmits || isNewTxCh(ih)) { + if(crcPass) + updateQuality(ih, RF_TX_CHAN_QUALITY_GOOD); + else if(!retransmits || isNewTxCh(ih)) { // nothing received: send probably lost if(RF_TX_TEST_CHAN_1ST_USE == ih->testChId) { // switch back to original quality + DPRINTLN(DBG_INFO, F("Test failed (-2)")); ih->txRfQuality[ih->txRfChId] = ih->saveOldTestQuality; - - updateQuality(ih, RF_TX_CHAN_QUALITY_BAD); - if(ih->testPeriodFailCnt < 0xff) - ih->testPeriodFailCnt++; } + updateQuality(ih, RF_TX_CHAN_QUALITY_BAD); + if(ih->testPeriodFailCnt < 0xff) + ih->testPeriodFailCnt++; } } else if(!ih->lastRxFragments && crcPass) { if(!retransmits || isNewTxCh(ih)) { @@ -103,8 +115,9 @@ class Heuristic { // 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) { + if(RF_TX_TEST_CHAN_1ST_USE == ih->testChId) { // switch back to original quality + DPRINTLN(DBG_INFO, F("Test failed (-1)")); ih->txRfQuality[ih->txRfChId] = ih->saveOldTestQuality; } updateQuality(ih, RF_TX_CHAN_QUALITY_LOW); diff --git a/src/utils/helper.cpp b/src/utils/helper.cpp index e606ad8b..9aea1054 100644 --- a/src/utils/helper.cpp +++ b/src/utils/helper.cpp @@ -70,12 +70,14 @@ namespace ah { return String(str); } - String getTimeStrMs(time_t t) { + String getTimeStrMs(uint64_t t) { char str[13]; if(0 == t) sprintf(str, "n/a"); - else + else { + t = (t + (millis() % 1000)) / 1000; sprintf(str, "%02d:%02d:%02d.%03d", hour(t), minute(t), second(t), millis() % 1000); + } return String(str); } diff --git a/src/utils/helper.h b/src/utils/helper.h index 60721414..1dbba3d9 100644 --- a/src/utils/helper.h +++ b/src/utils/helper.h @@ -44,7 +44,7 @@ namespace ah { String getDateTimeStrShort(time_t t); String getDateTimeStrFile(time_t t); String getTimeStr(time_t t); - String getTimeStrMs(time_t t); + String getTimeStrMs(uint64_t t); uint64_t Serial2u64(const char *val); void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl = 0, uint8_t lastRepl = 0); } diff --git a/src/utils/scheduler.h b/src/utils/scheduler.h index 954ae18a..23af29f8 100644 --- a/src/utils/scheduler.h +++ b/src/utils/scheduler.h @@ -34,6 +34,7 @@ namespace ah { void setup(bool directStart) { mUptime = 0; mTimestamp = (directStart) ? 1 : 0; + mTsMillis = 0; mMax = 0; mPrevMillis = millis(); resetTicker(); @@ -59,8 +60,10 @@ namespace ah { } mUptime += mDiffSeconds; - if(0 != mTimestamp) + if(0 != mTimestamp) { mTimestamp += mDiffSeconds; + mTsMillis = mMillis % 1000; + } checkTicker(); } @@ -77,6 +80,7 @@ namespace ah { virtual void setTimestamp(uint32_t ts) { mTimestamp = ts; + mTsMillis = millis() % 1000; } bool resetEveryById(uint8_t id) { @@ -90,10 +94,6 @@ namespace ah { return mUptime; } - uint32_t getTimestamp(void) { - return mTimestamp; - } - inline void resetTicker(void) { for (uint8_t i = 0; i < MAX_NUM_TICKER; i++) mTickerInUse[i] = false; @@ -118,6 +118,7 @@ namespace ah { protected: uint32_t mTimestamp; uint32_t mUptime; + uint16_t mTsMillis; private: inline uint8_t addTicker(scdCb c, uint32_t timeout, uint32_t reload, bool isTimestamp, const char *name) { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 1524fed4..a60d55b8 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -389,7 +389,7 @@ class RestApi { obj2[F("ch_max_pwr")][j] = iv->config->chMaxPwr[j]; } } - obj[F("interval")] = String(mConfig->nrf.sendInterval); + obj[F("interval")] = String(mConfig->inst.sendInterval); obj[F("max_num_inverters")] = MAX_NUM_INVERTERS; obj[F("rstMid")] = (bool)mConfig->inst.rstYieldMidNight; obj[F("rstNotAvail")] = (bool)mConfig->inst.rstValsNotAvail; @@ -556,16 +556,20 @@ class RestApi { void getRadioCmtInfo(JsonObject obj) { obj[F("en")] = (bool) mConfig->cmt.enabled; - obj[F("isconnected")] = mRadioCmt->isChipConnected(); - obj[F("sn")] = String(mRadioCmt->getDTUSn(), HEX); + if(mConfig->cmt.enabled) { + obj[F("isconnected")] = mRadioCmt->isChipConnected(); + obj[F("sn")] = String(mRadioCmt->getDTUSn(), HEX); + } } #endif void getRadioNrf(JsonObject obj) { - obj[F("en")] = (bool) mConfig->nrf.enabled; - obj[F("isconnected")] = mRadioNrf->isChipConnected(); - obj[F("dataRate")] = mRadioNrf->getDataRate(); - obj[F("sn")] = String(mRadioNrf->getDTUSn(), HEX); + obj[F("en")] = (bool) mConfig->nrf.enabled; + if(mConfig->nrf.enabled) { + obj[F("isconnected")] = mRadioNrf->isChipConnected(); + obj[F("dataRate")] = mRadioNrf->getDataRate(); + obj[F("sn")] = String(mRadioNrf->getDTUSn(), HEX); + } } void getSerial(JsonObject obj) { @@ -639,8 +643,6 @@ class RestApi { JsonArray warn = obj.createNestedArray(F("warnings")); if(!mRadioNrf->isChipConnected() && mConfig->nrf.enabled) warn.add(F("your NRF24 module can't be reached, check the wiring, pinout and enable")); - else if(!mRadioNrf->isPVariant() && mConfig->nrf.enabled) - warn.add(F("your NRF24 module isn't a plus version(+), maybe incompatible")); if(!mApp->getSettingsValid()) warn.add(F("your settings are invalid")); if(mApp->getRebootRequestState()) @@ -674,7 +676,7 @@ class RestApi { void getLive(AsyncWebServerRequest *request, JsonObject obj) { getGeneric(request, obj.createNestedObject(F("generic"))); - obj[F("refresh")] = mConfig->nrf.sendInterval; + obj[F("refresh")] = mConfig->inst.sendInterval; for (uint8_t fld = 0; fld < sizeof(acList); fld++) { obj[F("ch0_fld_units")][fld] = String(units[fieldUnits[acList[fld]]]); diff --git a/src/web/web.h b/src/web/web.h index 7ac0f4ad..9dc7ca8f 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -210,7 +210,7 @@ class Web { if (mSerialAddTime) { if ((13 + mSerialBufFill) < WEB_SERIAL_BUF_SIZE) { if (mApp->getTimestamp() > 0) { - strncpy(&mSerialBuf[mSerialBufFill], ah::getTimeStrMs(mApp->getTimestamp() + mApp->getTimezoneOffset()).c_str(), 12); + strncpy(&mSerialBuf[mSerialBufFill], ah::getTimeStrMs(mApp->getTimestampMs() + mApp->getTimezoneOffset() * 1000).c_str(), 12); mSerialBuf[mSerialBufFill+12] = ' '; mSerialBufFill += 13; } @@ -496,7 +496,7 @@ class Web { ah::ip2Arr(mConfig->sys.ip.gateway, buf); if (request->arg("invInterval") != "") - mConfig->nrf.sendInterval = request->arg("invInterval").toInt(); + mConfig->inst.sendInterval = request->arg("invInterval").toInt(); mConfig->inst.rstYieldMidNight = (request->arg("invRstMid") == "on"); mConfig->inst.rstValsCommStop = (request->arg("invRstComStop") == "on"); mConfig->inst.rstValsNotAvail = (request->arg("invRstNotAvail") == "on"); @@ -529,8 +529,6 @@ class Web { } mConfig->nrf.enabled = (request->arg("nrfEnable") == "on"); - - // cmt mConfig->cmt.enabled = (request->arg("cmtEnable") == "on"); // ntp