From 28fd60f89630fb7d3367a6174a4e52f864dc2c7b Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Sun, 24 Dec 2023 15:26:47 +0100 Subject: [PATCH 01/15] Fix https://github.com/lumapu/ahoy/issues/1288 #1288 --- src/hm/Communication.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 818b396d..07da4311 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -271,7 +271,7 @@ class Communication : public CommQueue<> { compilePayload(q); - if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd)) + if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd) && (GetLossRate != q->cmd)) (mCbPayload)(q->cmd, q->iv); closeRequest(q, true); From e8185b9e809914a9e671addaa32c7efe98ec3ac4 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 12:03:00 +0100 Subject: [PATCH 02/15] discord .2901 - add longer timeout + more retransmits to GridProfile req. - close GridProfile + GetLossRate req. explicitly (also for heuristiscs) --- src/hm/Communication.h | 35 +++++++++++++++++++++++++++++++++-- src/hm/hmRadio.h | 4 ++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 23d20004..a0e593c2 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -59,7 +59,7 @@ 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) ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); + 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))); uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; /*if(mDebugState != mState) { @@ -113,10 +113,35 @@ class Communication : public CommQueue<> { mIsRetransmit = false; mlastTO_min = timeout_min; setAttempt(); + if(q->cmd == AlarmData || q->cmd == GridOnProFilePara) + incrAttempt(q->cmd == AlarmData? 5 : 3); + mState = States::WAIT; break; case States::WAIT: + /*if(millis() > mWaitTimeout_min) { + if(mIsRetransmit) { // we already have been through... + mWaitTimeout = mWaitTimeout_min; + } else if(q->iv->mGotFragment) { // nothing received yet? + if(q->iv->mGotLastMsg) { + //mState = States::CHECK_FRAMES; + mWaitTimeout = mWaitTimeout_min; + } + } else if(mFirstTry) { + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(String(millis() - mWaitTimeout_min + mlastTO_min)); + DBGPRINTLN(F("ms - second try")); + } + mFirstTry = false; + mlastTO_min = timeout_min; + q->iv->radioStatistics.retransmits++; // got nothing + mState = States::START; + break; + } + + }*/ if(millis() < mWaitTimeout) return; mState = States::CHECK_FRAMES; @@ -283,7 +308,7 @@ class Communication : public CommQueue<> { else ah::dumpBuf(p->packet, p->len); } else { - DBGPRINT(F("| ")); + DBGPRINT(F("| 0x")); DHEX(p->packet[0]); DBGPRINT(F(" ")); DBGHEXLN(p->packet[9]); @@ -439,6 +464,9 @@ class Communication : public CommQueue<> { if(GridOnProFilePara == q->cmd) { q->iv->addGridProfile(mPayload, len); + q->iv->radioStatistics.rxSuccess++; + mHeu.evalTxChQuality(q->iv, true, (7 - q->attempts), q->iv->curFrmCnt); + cmdDone(false); return; } @@ -447,6 +475,9 @@ class Communication : public CommQueue<> { if(GetLossRate == q->cmd) { q->iv->parseGetLossRate(mPayload, len); //closeRequest(q, true); //@lumapu: Activating would crash most esp's! + mHeu.evalTxChQuality(q->iv, true, (9 - q->attempts), q->iv->curFrmCnt); + q->iv->radioStatistics.rxSuccess++; + cmdDone(false); return; } else { DPRINTLN(DBG_ERROR, F("record is NULL!")); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 1c4e26e9..2e02e92a 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -121,9 +121,10 @@ class HmRadio : public Radio { uint32_t startMicros = micros(); uint32_t loopMillis = millis(); - uint32_t outerLoopTimeout = (mLastIv->mIsSingleframeReq) ? 100 : ((mLastIv->mCmd != AlarmData) ? 400 : 600); + uint32_t outerLoopTimeout = (mLastIv->mIsSingleframeReq) ? 100 : ((mLastIv->mCmd != AlarmData) && (mLastIv->mCmd != GridOnProFilePara)) ? 400 : 600; while ((millis() - loopMillis) < outerLoopTimeout) { + uint32_t startMicros = micros(); while ((micros() - startMicros) < 5110) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; @@ -137,7 +138,6 @@ class HmRadio : public Radio { // switch to next RX channel mRxChIdx = (mRxChIdx + 1) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); - startMicros = micros(); } // not finished but time is over mRxChIdx = (mRxChIdx + 1) % RF_CHANNELS; From 6ec9561d7a1e99348bfe51fd8d3ae902dd3010b6 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 12:16:02 +0100 Subject: [PATCH 03/15] discord .2902 - disable cmdDone() calls for GridProfile+GetLossRate - Typo --- src/hm/Communication.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index a0e593c2..bc6f9f38 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -308,7 +308,7 @@ class Communication : public CommQueue<> { else ah::dumpBuf(p->packet, p->len); } else { - DBGPRINT(F("| 0x")); + DBGPRINT(F("| ")); DHEX(p->packet[0]); DBGPRINT(F(" ")); DBGHEXLN(p->packet[9]); @@ -466,7 +466,7 @@ class Communication : public CommQueue<> { q->iv->addGridProfile(mPayload, len); q->iv->radioStatistics.rxSuccess++; mHeu.evalTxChQuality(q->iv, true, (7 - q->attempts), q->iv->curFrmCnt); - cmdDone(false); + //cmdDone(false); return; } @@ -477,7 +477,7 @@ class Communication : public CommQueue<> { //closeRequest(q, true); //@lumapu: Activating would crash most esp's! mHeu.evalTxChQuality(q->iv, true, (9 - q->attempts), q->iv->curFrmCnt); q->iv->radioStatistics.rxSuccess++; - cmdDone(false); + //cmdDone(false); return; } else { DPRINTLN(DBG_ERROR, F("record is NULL!")); From f9257934300ab52f45aae6916e389700e143e07e Mon Sep 17 00:00:00 2001 From: you69man Date: Thu, 28 Dec 2023 12:38:22 +0100 Subject: [PATCH 04/15] fix esp8266 pin settings --- src/web/html/setup.html | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 74425185..7ca17005 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -897,10 +897,12 @@ function parsePinout(obj, type, system) { var e = document.getElementById("pinout"); + var pinList = esp8266pins; + /*IF_ESP32*/ var pinList = esp32pins; - if("ESP8266" == type) pinList = esp8266pins; - else if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; + /*ENDIF_ESP32*/ pins = [['led0', 'pinLed0', 'At least one inverter is producing'], ['led1', 'pinLed1', 'MqTT connected']]; for(p of pins) { e.append( @@ -927,10 +929,12 @@ var en = inp("nrfEnable", null, null, ["cb"], "nrfEnable", "checkbox"); en.checked = obj["en"]; + var pinList = esp8266pins; + /*IF_ESP32*/ var pinList = esp32pins; - if("ESP8266" == type) pinList = esp8266pins; - else if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; + /*ENDIF_ESP32*/ e.replaceChildren ( ml("div", {class: "row mb-3"}, [ @@ -992,10 +996,12 @@ } function parseDisplay(obj, type, system) { + var pinList = esp8266pins; + /*IF_ESP32*/ var pinList = esp32pins; - if("ESP8266" == type) pinList = esp8266pirpins; - else if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; + /*ENDIF_ESP32*/ for(var i of ["disp_pwr"]) document.getElementsByName(i)[0].checked = obj[i]; @@ -1061,7 +1067,7 @@ document.getElementById("pirPin").append( ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, "PIR sensor"), - ml("div", {class: "col-12 col-sm-9"}, sel("pir_pin", pinList, obj["pir_pin"])) + ml("div", {class: "col-12 col-sm-9"}, sel("pir_pin", ("ESP8266" == type) ? esp8266pirpins : pinList, obj["pir_pin"])) ]) ); From cf7fa9c3a338918c2bba100272dfc6820a205039 Mon Sep 17 00:00:00 2001 From: you69man Date: Thu, 28 Dec 2023 19:10:03 +0100 Subject: [PATCH 05/15] fix yields for displays 128x64 and 84x48 --- src/plugins/Display/Display_Mono_128X64.h | 20 ++++++++++---------- src/plugins/Display/Display_Mono_84X48.h | 18 +++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index 7b7b7920..afb581dd 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -49,9 +49,9 @@ class DisplayMono128X64 : public DisplayMono { /* mDisplayData->nrSleeping = 10; mDisplayData->nrProducing = 10; - mDisplayData->totalPower = 54321.9; // W - mDisplayData->totalYieldDay = 4321.9; // Wh - mDisplayData->totalYieldTotal = 4321.9; // kWh + mDisplayData->totalPower = 15432.9; // W + mDisplayData->totalYieldDay = 14321.9; // Wh + mDisplayData->totalYieldTotal = 15432.9; // kWh mDisplay->drawPixel(0, 0); mDisplay->drawPixel(mDispWidth-1, 0); mDisplay->drawPixel(0, mDispHeight-1); @@ -63,8 +63,8 @@ class DisplayMono128X64 : public DisplayMono { // print total power if (mDisplayData->nrProducing > 0) { - if (mDisplayData->totalPower > 999) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kW", (mDisplayData->totalPower / 1000.0)); + if (mDisplayData->totalPower > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000.0)); else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower); @@ -120,16 +120,16 @@ class DisplayMono128X64 : public DisplayMono { mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day symbol mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total symbol - if (mDisplayData->totalYieldDay > 999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldDay / 1000.0); + if (mDisplayData->totalYieldDay > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kWh", mDisplayData->totalYieldDay / 1000.0); else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); printText(mFmtText, l_YieldDay, 0xff); - if (mDisplayData->totalYieldTotal > 999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f MWh", mDisplayData->totalYieldTotal / 1000.0); + if (mDisplayData->totalYieldTotal > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f MWh", mDisplayData->totalYieldTotal / 1000.0); else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldTotal); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal); printText(mFmtText, l_YieldTotal, 0xff); // draw dynamic RSSI bars diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index df27a414..7e5c157f 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -36,8 +36,8 @@ class DisplayMono84X48 : public DisplayMono { /* mDisplayData->nrSleeping = 10; mDisplayData->nrProducing = 10; - mDisplayData->totalPower = 111.91; // W - mDisplayData->totalYieldDay = 54321.9; // Wh + mDisplayData->totalPower = 19897.6; // W + mDisplayData->totalYieldDay = 15521.9; // Wh mDisplayData->totalYieldTotal = 654321.9; // kWh mDisplay->drawPixel(0, 0); mDisplay->drawPixel(mDispWidth-1, 0); @@ -47,8 +47,8 @@ class DisplayMono84X48 : public DisplayMono { // print total power if (mDisplayData->nrProducing > 0) { - if (mDisplayData->totalPower > 999) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kW", (mDisplayData->totalPower / 1000)); + if (mDisplayData->totalPower > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000.0)); else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower); @@ -84,16 +84,16 @@ class DisplayMono84X48 : public DisplayMono { printText("\x88", l_YieldDay, 10); // day symbol printText("\x83", l_YieldTotal, 10); // total symbol - if (mDisplayData->totalYieldDay > 999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldDay / 1000.0); + if (mDisplayData->totalYieldDay > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kWh", mDisplayData->totalYieldDay / 1000.0); else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); printText(mFmtText, l_YieldDay, 0xff); - if (mDisplayData->totalYieldTotal > 999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f MWh", mDisplayData->totalYieldTotal / 1000.0); + if (mDisplayData->totalYieldTotal > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f MWh", mDisplayData->totalYieldTotal / 1000.0); else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldTotal); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal); printText(mFmtText, l_YieldTotal, 0xff); // draw dynamic Nokia RSSI bars From f047e31d4b984fdc1de0856ded7ae7e56ac3aa2f Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 20:53:39 +0100 Subject: [PATCH 06/15] fix double success counts --- Communication.h | 930 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 930 insertions(+) create mode 100644 Communication.h diff --git a/Communication.h b/Communication.h new file mode 100644 index 00000000..9cf8fcb7 --- /dev/null +++ b/Communication.h @@ -0,0 +1,930 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __COMMUNICATION_H__ +#define __COMMUNICATION_H__ + +#include "CommQueue.h" +#include +#include "../utils/crc.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; +typedef std::function *)> alarmListenerType; + +class Communication : public CommQueue<> { + public: + void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint16_t *inverterGap) { + mTimestamp = timestamp; + mPrivacyMode = privacyMode; + mSerialDebug = serialDebug; + mPrintWholeTrace = printWholeTrace; + mInverterGap = inverterGap; + } + + void addImportant(Inverter<> *iv, uint8_t cmd) { + mState = States::RESET; // cancel current operation + CommQueue::addImportant(iv, cmd); + } + + void addPayloadListener(payloadListenerType cb) { + mCbPayload = cb; + } + + void addAlarmListener(alarmListenerType cb) { + mCbAlarm = cb; + } + + void loop() { + get([this](bool valid, const queue_s *q) { + 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 : ((q->cmd != AlarmData) && q->cmd != GridOnProFilePara ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); + uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; + + /*if(mDebugState != mState) { + DPRINT(DBG_INFO, F("State: ")); + DBGHEXLN((uint8_t)(mState)); + mDebugState = mState; + }*/ + switch(mState) { + case States::RESET: + if(millis() < mWaitTimeout) + return; + mMaxFrameId = 0; + for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) { + mLocalBuf[i].len = 0; + } + + if(*mSerialDebug) + mHeu.printStatus(q->iv); + mHeu.getTxCh(q->iv); + q->iv->mGotFragment = false; + q->iv->mGotLastMsg = false; + q->iv->curFrmCnt = 0; + mIsRetransmit = false; + if(NULL == q->iv->radio) + cmdDone(false); // can't communicate while radio is not defined! + q->iv->mCmd = q->cmd; + q->iv->mIsSingleframeReq = false; + mState = States::START; + break; + + case States::START: + setTs(mTimestamp); + if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { + // 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)) + q->iv->curCmtFreq = q->iv->config->frequency; + } + } + + if(q->isDevControl) { + if(ActivePowerContr == q->cmd) + q->iv->powerLimitAck = false; + q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); + } else + q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); + + q->iv->radioStatistics.txCnt++; + mWaitTimeout = millis() + timeout; + mWaitTimeout_min = millis() + timeout_min; + mIsRetransmit = false; + mlastTO_min = timeout_min; + setAttempt(); + if(q->cmd == AlarmData || q->cmd == GridOnProFilePara) + incrAttempt(q->cmd == AlarmData? 5 : 3); + + mState = States::WAIT; + break; + + case States::WAIT: + /*if(millis() > mWaitTimeout_min) { + if(mIsRetransmit) { // we already have been through... + mWaitTimeout = mWaitTimeout_min; + } else if(q->iv->mGotFragment) { // nothing received yet? + if(q->iv->mGotLastMsg) { + //mState = States::CHECK_FRAMES; + mWaitTimeout = mWaitTimeout_min; + } + } else if(mFirstTry) { + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(String(millis() - mWaitTimeout_min + mlastTO_min)); + DBGPRINTLN(F("ms - second try")); + } + mFirstTry = false; + mlastTO_min = timeout_min; + q->iv->radioStatistics.retransmits++; // got nothing + mState = States::START; + break; + } + + }*/ + if(millis() < mWaitTimeout) + return; + mState = States::CHECK_FRAMES; + break; + + case States::CHECK_FRAMES: { + 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: ")); + DBGPRINT(String(millis() - mWaitTimeout + timeout)); + DBGPRINTLN(F("ms")); + } + if(!q->iv->mGotFragment) { + if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { + q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); + mWaitTimeout = millis() + 1000; + } + } + closeRequest(q, false); + break; + } + mFirstTry = false; // for correct reset + if((IV_MI != q->iv->ivGen) || (0 == q->attempts)) + mIsRetransmit = false; + + while(!q->iv->radio->mBufCtrl.empty()) { + packet_t *p = &q->iv->radio->mBufCtrl.front(); + printRxInfo(q, p); + + if(validateIvSerial(&p->packet[1], q->iv)) { + q->iv->radioStatistics.frmCnt++; + q->iv->mDtuRxCnt++; + + if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command + if(parseFrame(p)) + q->iv->curFrmCnt++; + } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command + if(parseDevCtrl(p, q)) + closeRequest(q, true); + else + closeRequest(q, false); + q->iv->radio->mBufCtrl.pop(); + return; // don't wait for empty buffer + } else if(IV_MI == q->iv->ivGen) { + if(parseMiFrame(p, q)) + q->iv->curFrmCnt++; + } + } //else -> serial does not match + + q->iv->radio->mBufCtrl.pop(); + 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; + } else { + bool fastNext = true; + if(q->iv->miMultiParts < 6) { + mState = States::WAIT; + if((millis() > mWaitTimeout && mIsRetransmit) || !mIsRetransmit) { + miRepeatRequest(q); + return; + } + } else { + mHeu.evalTxChQuality(q->iv, true, (4 - 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; + + case States::CHECK_PACKAGE: + uint8_t framnr = 0; + if(0 == mMaxFrameId) { + uint8_t i = 0; + while(i < MAX_PAYLOAD_ENTRIES) { + if(mLocalBuf[i].len == 0) { + framnr = i+1; + break; + } + i++; + } + } + + if(!framnr) { + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(mLocalBuf[i].len == 0) { + framnr = i+1; + break; + } + } + } + + if(framnr) { + setAttempt(); + + if(*mSerialDebug) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("frame ")); + DBGPRINT(String(framnr)); + DBGPRINT(F(" missing: request retransmit (")); + DBGPRINT(String(q->attempts)); + DBGPRINTLN(F(" attempts left)")); + } + if (!mIsRetransmit) + q->iv->mIsSingleframeReq = true; + sendRetransmit(q, (framnr-1)); + mIsRetransmit = true; + mlastTO_min = timeout_min; + return; + } + + compilePayload(q); + + if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd) && (GetLossRate != q->cmd)) + (mCbPayload)(q->cmd, q->iv); + + closeRequest(q, true); + break; + } + }); + } + + private: + inline void printRxInfo(const queue_s *q, packet_t *p) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("RX ")); + if(p->millis < 100) + DBGPRINT(F(" ")); + DBGPRINT(String(p->millis)); + DBGPRINT(F("ms | ")); + DBGPRINT(String(p->len)); + if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { + DBGPRINT(F(" CH")); + if(3 == p->ch) + DBGPRINT(F("0")); + DBGPRINT(String(p->ch)); + DBGPRINT(F(" ")); + } else { + DBGPRINT(F(" ")); + DBGPRINT(String(p->rssi)); + DBGPRINT(F("dBm | ")); + } + if(*mPrintWholeTrace) { + if(*mPrivacyMode) + ah::dumpBuf(p->packet, p->len, 1, 8); + else + ah::dumpBuf(p->packet, p->len); + } else { + DBGPRINT(F("| ")); + DHEX(p->packet[0]); + DBGPRINT(F(" ")); + DBGHEXLN(p->packet[9]); + } + } + + inline bool validateIvSerial(uint8_t buf[], Inverter<> *iv) { + uint8_t tmp[4]; + CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); + for(uint8_t i = 0; i < 4; i++) { + if(tmp[i] != buf[i]) { + 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]); + DBGPRINTLN(""); + return false; + } + } + return true; + } + + inline bool checkFrameCrc(uint8_t buf[], uint8_t len) { + return (ah::crc8(buf, len - 1) == buf[len-1]); + } + + inline bool parseFrame(packet_t *p) { + uint8_t *frameId = &p->packet[9]; + if(0x00 == *frameId) { + DPRINTLN(DBG_WARN, F("invalid frameId 0x00")); + return false; // skip current packet + } + if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) { + DPRINTLN(DBG_WARN, F("local buffer to small for payload fragments")); + return false; // local storage is to small for id + } + + if(!checkFrameCrc(p->packet, p->len)) { + DPRINTLN(DBG_WARN, F("frame CRC is wrong")); + return false; // CRC8 is wrong, frame invalid + } + + if((*frameId & ALL_FRAMES) == ALL_FRAMES) { + mMaxFrameId = (*frameId & 0x7f); + if(mMaxFrameId > 8) // large payloads, e.g. AlarmData + incrAttempt(mMaxFrameId - 6); + } + + frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; + memcpy(f->buf, &p->packet[10], p->len-11); + f->len = p->len - 11; + f->rssi = p->rssi; + + return true; + } + + 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)) + && (p->packet[0] < (0x39 + SINGLE_FRAME)) + )) { //&& (p->packet[0] != (0x0f + ALL_FRAMES)))) { + // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 + //mPayload[iv->id].txId = p->packet[0]; + miDataDecode(p, q); + } else if (p->packet[0] == (0x0f + ALL_FRAMES)) + miHwDecode(p, q); + else if ((p->packet[0] == 0x88) || (p->packet[0] == 0x92)) { + 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; + } + + inline bool parseDevCtrl(packet_t *p, const queue_s *q) { + if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) + return false; + bool accepted = true; + if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) + q->iv->powerLimitAck = true; + else + accepted = false; + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("has ")); + if(!accepted) DBGPRINT(F("not ")); + DBGPRINT(F("accepted power limit set point ")); + DBGPRINT(String(q->iv->powerLimit[0])); + DBGPRINT(F(" with PowerLimitControl ")); + DBGPRINTLN(String(q->iv->powerLimit[1])); + q->iv->actPowerLimit = 0xffff; // unknown, readback current value + + return accepted; + } + + inline void compilePayload(const queue_s *q) { + uint16_t crc = 0xffff, crcRcv = 0x0000; + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(i == (mMaxFrameId - 1)) { + crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len - 2, crc); + crcRcv = (mLocalBuf[i].buf[mLocalBuf[i].len-2] << 8); + crcRcv |= mLocalBuf[i].buf[mLocalBuf[i].len-1]; + } else + crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len, crc); + } + + if(crc != crcRcv) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("CRC Error ")); + if(q->attempts == 0) { + DBGPRINTLN(F("-> Fail")); + closeRequest(q, false); + + } else + DBGPRINTLN(F("-> complete retransmit")); + mState = States::RESET; + return; + } + + /*DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("procPyld: cmd: 0x")); + DBGHEXLN(q->cmd);*/ + + memset(mPayload, 0, MAX_BUFFER); + int8_t rssi = -127; + uint8_t len = 0; + + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(mLocalBuf[i].len + len > MAX_BUFFER) { + DPRINTLN(DBG_ERROR, F("payload buffer to small!")); + return; + } + memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); + len += mLocalBuf[i].len; + // get worst RSSI (high value is better) + if(mLocalBuf[i].rssi > rssi) + rssi = mLocalBuf[i].rssi; + } + + len -= 2; + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("Payload (")); + DBGPRINT(String(len)); + if(*mPrintWholeTrace) { + DBGPRINT(F("): ")); + ah::dumpBuf(mPayload, len); + } else + DBGPRINTLN(F(")")); + + if(GridOnProFilePara == q->cmd) { + q->iv->addGridProfile(mPayload, len); + return; + } + + record_t<> *rec = q->iv->getRecordStruct(q->cmd); + if(NULL == rec) { + if(GetLossRate == q->cmd) { + q->iv->parseGetLossRate(mPayload, len); + //closeRequest(q, true); //@lumapu: Activating would crash most esp's! + return; + } else { + DPRINTLN(DBG_ERROR, F("record is NULL!")); + closeRequest(q, false); + } + return; + } + if((rec->pyldLen != len) && (0 != rec->pyldLen)) { + if(*mSerialDebug) { + DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); + DBGPRINT(String(rec->pyldLen)); + DBGPRINTLN(F(" bytes")); + } + /*q->iv->radioStatistics.rxFail++;*/ + closeRequest(q, false); + + return; + } + + rec->ts = q->ts; + for (uint8_t i = 0; i < rec->length; i++) { + q->iv->addValue(i, mPayload, rec); + } + + q->iv->rssi = rssi; + q->iv->doCalculations(); + + if(AlarmData == q->cmd) { + uint8_t i = 0; + while(1) { + if(0 == q->iv->parseAlarmLog(i++, mPayload, len)) + break; + if (NULL != mCbAlarm) + (mCbAlarm)(q->iv); + yield(); + } + } + } + + 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++; + mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout + mState = States::WAIT; + } else { + //add(q, true); + closeRequest(q, false); + } + } + + private: + void closeRequest(const queue_s *q, bool crcPass) { + 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() + *mInverterGap; + + bool keep = false; + if(q->isDevControl) + keep = !crcPass; + + cmdDone(keep); + q->iv->mGotFragment = false; + q->iv->mGotLastMsg = false; + q->iv->miMultiParts = 0; + mIsRetransmit = false; + mFirstTry = false; // for correct reset + mState = States::RESET; + DBGPRINTLN(F("-----")); + } + + inline void miHwDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure + rec->ts = q->ts; + /* + Polling the device software and hardware version number command + start byte Command word routing address target address User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] + 0x7e 0x0f xx xx xx xx YY YY YY YY 0x00 CRC 0x7f + Command Receipt - First Frame + start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] + 0x7e 0x8f YY YY YY YY xx xx xx xx 0x00 USFWBuild_VER APPFWBuild_VER APPFWBuild_YYYY APPFWBuild_MMDD APPFWBuild_HHMM APPFW_PN HW_VER CRC 0x7f + Command Receipt - Second Frame + start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] + 0x7e 0x8f YY YY YY YY xx xx xx xx 0x01 HW_PN HW_FB_TLmValue HW_FB_ReSPRT HW_GridSamp_ResValule HW_ECapValue Matching_APPFW_PN CRC 0x7f + Command receipt - third frame + start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[15] byte[16] byte[17] byte[18] + 0x7e 0x8f YY YY YY YY xx xx xx xx 0x12 APPFW_MINVER HWInfoAddr PNInfoCRC_gusv PNInfoCRC_gusv CRC 0x7f + */ + + /* + case InverterDevInform_All: + rec->length = (uint8_t)(HMINFO_LIST_LEN); + rec->assign = (byteAssign_t *)InfoAssignment; + rec->pyldLen = HMINFO_PAYLOAD_LEN; + break; + const byteAssign_t InfoAssignment[] = { + { FLD_FW_VERSION, UNIT_NONE, CH0, 0, 2, 1 }, + { FLD_FW_BUILD_YEAR, UNIT_NONE, CH0, 2, 2, 1 }, + { FLD_FW_BUILD_MONTH_DAY, UNIT_NONE, CH0, 4, 2, 1 }, + { FLD_FW_BUILD_HOUR_MINUTE, UNIT_NONE, CH0, 6, 2, 1 }, + { FLD_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } + }; + */ + + if ( p->packet[9] == 0x00 ) {//first frame + //FLD_FW_VERSION + for (uint8_t i = 0; i < 5; i++) { + q->iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); + } + q->iv->isConnected = true; + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("HW_VER is ")); + DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); + } + record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec->ts = q->ts; + q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); + q->iv->miMultiParts +=4; + } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 + DPRINT_IVID(DBG_INFO, q->iv->id); + if ( p->packet[9] == 0x01 ) { + DBGPRINTLN(F("got 2nd frame (hw info)")); + /* according to xlsx (different start byte -1!) + byte[11] to byte[14] HW_PN + byte[15] byte[16] HW_FB_TLmValue + byte[17] byte[18] HW_FB_ReSPRT + byte[19] byte[20] HW_GridSamp_ResValule + byte[21] byte[22] HW_ECapValue + byte[23] to byte[26] Matching_APPFW_PN*/ + DPRINT(DBG_INFO,F("HW_PartNo ")); + DBGPRINTLN(String((uint32_t) (((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])); + record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec->ts = q->ts; + q->iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1); + + if(*mSerialDebug) { + DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); + DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); + DBGPRINT(F("HW_FB_ReSPRT ")); + DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); + DBGPRINT(F("HW_GridSamp_ResValule ")); + DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); + DBGPRINT(F("HW_ECapValue ")); + DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); + DBGPRINT(F("Matching_APPFW_PN ")); + DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); + } + if(NULL != mCbPayload) + (mCbPayload)(InverterDevInform_All, q->iv); + q->iv->miMultiParts +=2; + + } else { + DBGPRINTLN(F("3rd gen. inverter!")); + } + + } else if ( p->packet[9] == 0x12 ) {//3rd frame + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINTLN(F("got 3rd frame (hw info)")); + /* according to xlsx (different start byte -1!) + byte[11] byte[12] APPFW_MINVER + byte[13] byte[14] HWInfoAddr + byte[15] byte[16] PNInfoCRC_gusv + byte[15] byte[16] PNInfoCRC_gusv (this really is double mentionned in xlsx...) + */ + if(*mSerialDebug) { + DPRINT(DBG_INFO,F("APPFW_MINVER ")); + DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); + DBGPRINT(F("HWInfoAddr ")); + DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); + DBGPRINT(F("PNInfoCRC_gusv ")); + DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); + } + if(NULL != mCbPayload) + (mCbPayload)(InverterDevInform_Simple, q->iv); + q->iv->miMultiParts++; + } + //if(q->iv->miMultiParts > 5) + //closeRequest(q->iv, true); + //else + //if(q->iv->miMultiParts < 6) + // mState = States::WAIT; + + /*if (mPayload[iv->id].multi_parts > 5) { + iv->setQueuedCmdFinished(); + mPayload[iv->id].complete = true; + mPayload[iv->id].rxTmo = true; + mPayload[iv->id].requested= false; + iv->radioStatistics.rxSuccess++; + } + if (mHighPrioIv == NULL) + mHighPrioIv = iv; + */ + } + + inline void miDataDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser + rec->ts = q->ts; + //mState = States::RESET; + if(q->iv->miMultiParts < 6) + q->iv->miMultiParts += 6; + + uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : + ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : + p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : + CH4; + // count in RF_communication_protocol.xlsx is with offset = -1 + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); + + if (datachan == 1) + q->iv->rssi = p->rssi; + else if(q->iv->rssi > p->rssi) + q->iv->rssi = p->rssi; + + if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { + /*For MI1500: + if (MI1500) { + STAT = (uint8_t)(p->packet[25] ); + FCNT = (uint8_t)(p->packet[26]); + FCODE = (uint8_t)(p->packet[27]); + }*/ + miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); + + if (p->packet[0] < (0x39 + ALL_FRAMES) ) { + mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), 1); + miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); + } else { + q->iv->miMultiParts = 7; // indicate we are ready + //miComplete(q->iv); + } + } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { + //addImportant(q->iv, MI_REQ_CH2); + miNextRequest(MI_REQ_CH2, q); + mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), q->iv->curFrmCnt); + //use also miMultiParts here for better statistics? + //mHeu.setGotFragment(q->iv); + } else { // first data msg for 1ch, 2nd for 2ch + q->iv->miMultiParts += 6; // indicate we are ready + //miComplete(q->iv); + } + } + + void miNextRequest(uint8_t cmd, const queue_s *q) { + incrAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... + if(*mSerialDebug) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("next request (")); + DBGPRINT(String(q->attempts)); + DBGPRINT(F(" attempts left): 0x")); + DBGHEXLN(cmd); + } + + if(q->iv->miMultiParts == 7) { + //mHeu.setGotAll(q->iv); + q->iv->radioStatistics.rxSuccess++; + } else + //mHeu.setGotFragment(q->iv); + /*iv->radioStatistics.rxFail++; // got no complete payload*/ + //q->iv->radioStatistics.retransmits++; + q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); + + mWaitTimeout = millis() + MI_TIMEOUT; + mWaitTimeout_min = mWaitTimeout; + q->iv->miMultiParts = 0; + q->iv->mGotFragment = 0; + mIsRetransmit = true; + chgCmd(cmd); + //mState = States::WAIT; + } + + void miRepeatRequest(const queue_s *q) { + setAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... + if(*mSerialDebug) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("resend request (")); + DBGPRINT(String(q->attempts)); + DBGPRINT(F(" attempts left): 0x")); + DBGHEXLN(q->cmd); + } + + q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); + + mWaitTimeout = millis() + MI_TIMEOUT; + mWaitTimeout_min = mWaitTimeout; + //mState = States::WAIT; + mIsRetransmit = false; + } + + void miStsConsolidate(const queue_s *q, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) { + //uint8_t status = (p->packet[11] << 8) + p->packet[12]; + uint16_t statusMi = 3; // regular status for MI, change to 1 later? + if ( uState == 2 ) { + statusMi = 5050 + stschan; //first approach, needs review! + if (lState) + statusMi += lState*10; + } else if ( uState > 3 ) { + statusMi = uState*1000 + uEnum*10; + if (lState) + statusMi += lState*100; //needs review, esp. for 4ch-8310 state! + //if (lEnum) + statusMi += lEnum; + if (uEnum < 6) { + statusMi += stschan; + } + if (statusMi == 8000) + statusMi = 8310; //trick? + } + + uint16_t prntsts = statusMi == 3 ? 1 : statusMi; + bool stsok = true; + if ( prntsts != rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)] ) { //sth.'s changed? + q->iv->alarmCnt = 1; // minimum... + stsok = false; + //sth is or was wrong? + if ( (q->iv->type != INV_TYPE_1CH) && ( (statusMi != 3) + || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) + ) { + q->iv->lastAlarm[stschan+q->iv->type==INV_TYPE_2CH ? 2: 4] = alarm_t(q->iv->lastAlarm[stschan].code, q->iv->lastAlarm[stschan].start,q->ts); + q->iv->lastAlarm[stschan] = alarm_t(prntsts, q->ts,0); + q->iv->alarmCnt = q->iv->type == INV_TYPE_2CH ? 3 : 5; + } else if ( (q->iv->type == INV_TYPE_1CH) && ( (statusMi != 3) + || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) + ) { + q->iv->lastAlarm[stschan] = alarm_t(q->iv->lastAlarm[0].code, q->iv->lastAlarm[0].start,q->ts); + } else if (q->iv->type == INV_TYPE_1CH) + stsok = true; + + q->iv->alarmLastId = prntsts; //iv->alarmMesIndex; + + if (q->iv->alarmCnt > 1) { //more than one channel + for (uint8_t ch = 0; ch < (q->iv->alarmCnt); ++ch) { //start with 1 + if (q->iv->lastAlarm[ch].code == 1) { + stsok = true; + break; + } + } + } + if(*mSerialDebug) { + DPRINT(DBG_WARN, F("New state on CH")); + DBGPRINT(String(stschan)); DBGPRINT(F(" (")); + DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); + DBGPRINTLN(q->iv->getAlarmStr(prntsts)); + } + if(!q->iv->miMultiParts) + q->iv->miMultiParts = 1; // indicate we got status info (1+2 ch types) + } + + if (!stsok) { + q->iv->setValue(q->iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts); + q->iv->lastAlarm[0] = alarm_t(prntsts, q->ts, 0); + } + + if (q->iv->alarmMesIndex < rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]) { + q->iv->alarmMesIndex = rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? + if (*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("alarm ID incremented to ")); + DBGPRINTLN(String(q->iv->alarmMesIndex)); + } + } + } + + + void miComplete(Inverter<> *iv) { + if (*mSerialDebug) { + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINTLN(F("got all data msgs")); + } + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); + iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); + + //preliminary AC calculation... + float ac_pow = 0; + if (iv->type == INV_TYPE_1CH) { + if ((!iv->lastAlarm[0].code) || (iv->lastAlarm[0].code == 1)) + ac_pow += iv->getValue(iv->getPosByChFld(1, FLD_PDC, rec), rec); + } else { + for(uint8_t i = 1; i <= iv->channels; i++) { + if ((!iv->lastAlarm[i].code) || (iv->lastAlarm[i].code == 1)) { + uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); + ac_pow += iv->getValue(pos, rec); + } + } + } + ac_pow = (int) (ac_pow*9.5); + iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10); + + iv->doCalculations(); + // update status state-machine, + if (ac_pow) + iv->isProducing(); + //closeRequest(iv, iv->miMultiParts > 5); + + //mHeu.setGotAll(iv); + //cmdDone(false); + if(NULL != mCbPayload) + (mCbPayload)(RealTimeRunData_Debug, iv); + + //mState = States::RESET; // everything ok, next request + } + + private: + enum class States : uint8_t { + RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE + }; + + typedef struct { + uint8_t buf[MAX_RF_PAYLOAD_SIZE]; + uint8_t len; + int8_t rssi; + } frame_t; + + private: + States mState = States::RESET; + uint32_t *mTimestamp; + bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; + uint16_t *mInverterGap; + uint32_t mWaitTimeout = 0; + uint32_t mWaitTimeout_min = 0; + std::array mLocalBuf; + bool mFirstTry = false; // see, if we should do a second try + bool mIsRetransmit = false; // we alrady had waited one complete cycle + uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation + uint8_t mMaxFrameId; + uint8_t mPayload[MAX_BUFFER]; + payloadListenerType mCbPayload = NULL; + alarmListenerType mCbAlarm = NULL; + Heuristic mHeu; + uint32_t mLastEmptyQueueMillis = 0; + bool mPrintSequenceDuration = false; + + //States mDebugState = States::START; +}; + +#endif /*__COMMUNICATION_H__*/ From 2ab73d9627930b3d8366558cab27741e9f7c6ad6 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 20:56:08 +0100 Subject: [PATCH 07/15] fix double counts From 8a489ca14c4efc97c41a3457a6c739cbdba2f426 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 20:59:22 +0100 Subject: [PATCH 08/15] Delete Communication.h wrong place... --- Communication.h | 930 ------------------------------------------------ 1 file changed, 930 deletions(-) delete mode 100644 Communication.h diff --git a/Communication.h b/Communication.h deleted file mode 100644 index 9cf8fcb7..00000000 --- a/Communication.h +++ /dev/null @@ -1,930 +0,0 @@ -//----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed -//----------------------------------------------------------------------------- - -#ifndef __COMMUNICATION_H__ -#define __COMMUNICATION_H__ - -#include "CommQueue.h" -#include -#include "../utils/crc.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; -typedef std::function *)> alarmListenerType; - -class Communication : public CommQueue<> { - public: - void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint16_t *inverterGap) { - mTimestamp = timestamp; - mPrivacyMode = privacyMode; - mSerialDebug = serialDebug; - mPrintWholeTrace = printWholeTrace; - mInverterGap = inverterGap; - } - - void addImportant(Inverter<> *iv, uint8_t cmd) { - mState = States::RESET; // cancel current operation - CommQueue::addImportant(iv, cmd); - } - - void addPayloadListener(payloadListenerType cb) { - mCbPayload = cb; - } - - void addAlarmListener(alarmListenerType cb) { - mCbAlarm = cb; - } - - void loop() { - get([this](bool valid, const queue_s *q) { - 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 : ((q->cmd != AlarmData) && q->cmd != GridOnProFilePara ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); - uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; - - /*if(mDebugState != mState) { - DPRINT(DBG_INFO, F("State: ")); - DBGHEXLN((uint8_t)(mState)); - mDebugState = mState; - }*/ - switch(mState) { - case States::RESET: - if(millis() < mWaitTimeout) - return; - mMaxFrameId = 0; - for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) { - mLocalBuf[i].len = 0; - } - - if(*mSerialDebug) - mHeu.printStatus(q->iv); - mHeu.getTxCh(q->iv); - q->iv->mGotFragment = false; - q->iv->mGotLastMsg = false; - q->iv->curFrmCnt = 0; - mIsRetransmit = false; - if(NULL == q->iv->radio) - cmdDone(false); // can't communicate while radio is not defined! - q->iv->mCmd = q->cmd; - q->iv->mIsSingleframeReq = false; - mState = States::START; - break; - - case States::START: - setTs(mTimestamp); - if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { - // 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)) - q->iv->curCmtFreq = q->iv->config->frequency; - } - } - - if(q->isDevControl) { - if(ActivePowerContr == q->cmd) - q->iv->powerLimitAck = false; - q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); - } else - q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - - q->iv->radioStatistics.txCnt++; - mWaitTimeout = millis() + timeout; - mWaitTimeout_min = millis() + timeout_min; - mIsRetransmit = false; - mlastTO_min = timeout_min; - setAttempt(); - if(q->cmd == AlarmData || q->cmd == GridOnProFilePara) - incrAttempt(q->cmd == AlarmData? 5 : 3); - - mState = States::WAIT; - break; - - case States::WAIT: - /*if(millis() > mWaitTimeout_min) { - if(mIsRetransmit) { // we already have been through... - mWaitTimeout = mWaitTimeout_min; - } else if(q->iv->mGotFragment) { // nothing received yet? - if(q->iv->mGotLastMsg) { - //mState = States::CHECK_FRAMES; - mWaitTimeout = mWaitTimeout_min; - } - } else if(mFirstTry) { - if(*mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(String(millis() - mWaitTimeout_min + mlastTO_min)); - DBGPRINTLN(F("ms - second try")); - } - mFirstTry = false; - mlastTO_min = timeout_min; - q->iv->radioStatistics.retransmits++; // got nothing - mState = States::START; - break; - } - - }*/ - if(millis() < mWaitTimeout) - return; - mState = States::CHECK_FRAMES; - break; - - case States::CHECK_FRAMES: { - 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: ")); - DBGPRINT(String(millis() - mWaitTimeout + timeout)); - DBGPRINTLN(F("ms")); - } - if(!q->iv->mGotFragment) { - if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { - q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); - mWaitTimeout = millis() + 1000; - } - } - closeRequest(q, false); - break; - } - mFirstTry = false; // for correct reset - if((IV_MI != q->iv->ivGen) || (0 == q->attempts)) - mIsRetransmit = false; - - while(!q->iv->radio->mBufCtrl.empty()) { - packet_t *p = &q->iv->radio->mBufCtrl.front(); - printRxInfo(q, p); - - if(validateIvSerial(&p->packet[1], q->iv)) { - q->iv->radioStatistics.frmCnt++; - q->iv->mDtuRxCnt++; - - if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - if(parseFrame(p)) - q->iv->curFrmCnt++; - } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command - if(parseDevCtrl(p, q)) - closeRequest(q, true); - else - closeRequest(q, false); - q->iv->radio->mBufCtrl.pop(); - return; // don't wait for empty buffer - } else if(IV_MI == q->iv->ivGen) { - if(parseMiFrame(p, q)) - q->iv->curFrmCnt++; - } - } //else -> serial does not match - - q->iv->radio->mBufCtrl.pop(); - 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; - } else { - bool fastNext = true; - if(q->iv->miMultiParts < 6) { - mState = States::WAIT; - if((millis() > mWaitTimeout && mIsRetransmit) || !mIsRetransmit) { - miRepeatRequest(q); - return; - } - } else { - mHeu.evalTxChQuality(q->iv, true, (4 - 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; - - case States::CHECK_PACKAGE: - uint8_t framnr = 0; - if(0 == mMaxFrameId) { - uint8_t i = 0; - while(i < MAX_PAYLOAD_ENTRIES) { - if(mLocalBuf[i].len == 0) { - framnr = i+1; - break; - } - i++; - } - } - - if(!framnr) { - for(uint8_t i = 0; i < mMaxFrameId; i++) { - if(mLocalBuf[i].len == 0) { - framnr = i+1; - break; - } - } - } - - if(framnr) { - setAttempt(); - - if(*mSerialDebug) { - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("frame ")); - DBGPRINT(String(framnr)); - DBGPRINT(F(" missing: request retransmit (")); - DBGPRINT(String(q->attempts)); - DBGPRINTLN(F(" attempts left)")); - } - if (!mIsRetransmit) - q->iv->mIsSingleframeReq = true; - sendRetransmit(q, (framnr-1)); - mIsRetransmit = true; - mlastTO_min = timeout_min; - return; - } - - compilePayload(q); - - if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd) && (GetLossRate != q->cmd)) - (mCbPayload)(q->cmd, q->iv); - - closeRequest(q, true); - break; - } - }); - } - - private: - inline void printRxInfo(const queue_s *q, packet_t *p) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("RX ")); - if(p->millis < 100) - DBGPRINT(F(" ")); - DBGPRINT(String(p->millis)); - DBGPRINT(F("ms | ")); - DBGPRINT(String(p->len)); - if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { - DBGPRINT(F(" CH")); - if(3 == p->ch) - DBGPRINT(F("0")); - DBGPRINT(String(p->ch)); - DBGPRINT(F(" ")); - } else { - DBGPRINT(F(" ")); - DBGPRINT(String(p->rssi)); - DBGPRINT(F("dBm | ")); - } - if(*mPrintWholeTrace) { - if(*mPrivacyMode) - ah::dumpBuf(p->packet, p->len, 1, 8); - else - ah::dumpBuf(p->packet, p->len); - } else { - DBGPRINT(F("| ")); - DHEX(p->packet[0]); - DBGPRINT(F(" ")); - DBGHEXLN(p->packet[9]); - } - } - - inline bool validateIvSerial(uint8_t buf[], Inverter<> *iv) { - uint8_t tmp[4]; - CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); - for(uint8_t i = 0; i < 4; i++) { - if(tmp[i] != buf[i]) { - 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]); - DBGPRINTLN(""); - return false; - } - } - return true; - } - - inline bool checkFrameCrc(uint8_t buf[], uint8_t len) { - return (ah::crc8(buf, len - 1) == buf[len-1]); - } - - inline bool parseFrame(packet_t *p) { - uint8_t *frameId = &p->packet[9]; - if(0x00 == *frameId) { - DPRINTLN(DBG_WARN, F("invalid frameId 0x00")); - return false; // skip current packet - } - if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) { - DPRINTLN(DBG_WARN, F("local buffer to small for payload fragments")); - return false; // local storage is to small for id - } - - if(!checkFrameCrc(p->packet, p->len)) { - DPRINTLN(DBG_WARN, F("frame CRC is wrong")); - return false; // CRC8 is wrong, frame invalid - } - - if((*frameId & ALL_FRAMES) == ALL_FRAMES) { - mMaxFrameId = (*frameId & 0x7f); - if(mMaxFrameId > 8) // large payloads, e.g. AlarmData - incrAttempt(mMaxFrameId - 6); - } - - frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; - memcpy(f->buf, &p->packet[10], p->len-11); - f->len = p->len - 11; - f->rssi = p->rssi; - - return true; - } - - 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)) - && (p->packet[0] < (0x39 + SINGLE_FRAME)) - )) { //&& (p->packet[0] != (0x0f + ALL_FRAMES)))) { - // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 - //mPayload[iv->id].txId = p->packet[0]; - miDataDecode(p, q); - } else if (p->packet[0] == (0x0f + ALL_FRAMES)) - miHwDecode(p, q); - else if ((p->packet[0] == 0x88) || (p->packet[0] == 0x92)) { - 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; - } - - inline bool parseDevCtrl(packet_t *p, const queue_s *q) { - if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) - return false; - bool accepted = true; - if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) - q->iv->powerLimitAck = true; - else - accepted = false; - - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("has ")); - if(!accepted) DBGPRINT(F("not ")); - DBGPRINT(F("accepted power limit set point ")); - DBGPRINT(String(q->iv->powerLimit[0])); - DBGPRINT(F(" with PowerLimitControl ")); - DBGPRINTLN(String(q->iv->powerLimit[1])); - q->iv->actPowerLimit = 0xffff; // unknown, readback current value - - return accepted; - } - - inline void compilePayload(const queue_s *q) { - uint16_t crc = 0xffff, crcRcv = 0x0000; - for(uint8_t i = 0; i < mMaxFrameId; i++) { - if(i == (mMaxFrameId - 1)) { - crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len - 2, crc); - crcRcv = (mLocalBuf[i].buf[mLocalBuf[i].len-2] << 8); - crcRcv |= mLocalBuf[i].buf[mLocalBuf[i].len-1]; - } else - crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len, crc); - } - - if(crc != crcRcv) { - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("CRC Error ")); - if(q->attempts == 0) { - DBGPRINTLN(F("-> Fail")); - closeRequest(q, false); - - } else - DBGPRINTLN(F("-> complete retransmit")); - mState = States::RESET; - return; - } - - /*DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("procPyld: cmd: 0x")); - DBGHEXLN(q->cmd);*/ - - memset(mPayload, 0, MAX_BUFFER); - int8_t rssi = -127; - uint8_t len = 0; - - for(uint8_t i = 0; i < mMaxFrameId; i++) { - if(mLocalBuf[i].len + len > MAX_BUFFER) { - DPRINTLN(DBG_ERROR, F("payload buffer to small!")); - return; - } - memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); - len += mLocalBuf[i].len; - // get worst RSSI (high value is better) - if(mLocalBuf[i].rssi > rssi) - rssi = mLocalBuf[i].rssi; - } - - len -= 2; - - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("Payload (")); - DBGPRINT(String(len)); - if(*mPrintWholeTrace) { - DBGPRINT(F("): ")); - ah::dumpBuf(mPayload, len); - } else - DBGPRINTLN(F(")")); - - if(GridOnProFilePara == q->cmd) { - q->iv->addGridProfile(mPayload, len); - return; - } - - record_t<> *rec = q->iv->getRecordStruct(q->cmd); - if(NULL == rec) { - if(GetLossRate == q->cmd) { - q->iv->parseGetLossRate(mPayload, len); - //closeRequest(q, true); //@lumapu: Activating would crash most esp's! - return; - } else { - DPRINTLN(DBG_ERROR, F("record is NULL!")); - closeRequest(q, false); - } - return; - } - if((rec->pyldLen != len) && (0 != rec->pyldLen)) { - if(*mSerialDebug) { - DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); - DBGPRINT(String(rec->pyldLen)); - DBGPRINTLN(F(" bytes")); - } - /*q->iv->radioStatistics.rxFail++;*/ - closeRequest(q, false); - - return; - } - - rec->ts = q->ts; - for (uint8_t i = 0; i < rec->length; i++) { - q->iv->addValue(i, mPayload, rec); - } - - q->iv->rssi = rssi; - q->iv->doCalculations(); - - if(AlarmData == q->cmd) { - uint8_t i = 0; - while(1) { - if(0 == q->iv->parseAlarmLog(i++, mPayload, len)) - break; - if (NULL != mCbAlarm) - (mCbAlarm)(q->iv); - yield(); - } - } - } - - 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++; - mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout - mState = States::WAIT; - } else { - //add(q, true); - closeRequest(q, false); - } - } - - private: - void closeRequest(const queue_s *q, bool crcPass) { - 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() + *mInverterGap; - - bool keep = false; - if(q->isDevControl) - keep = !crcPass; - - cmdDone(keep); - q->iv->mGotFragment = false; - q->iv->mGotLastMsg = false; - q->iv->miMultiParts = 0; - mIsRetransmit = false; - mFirstTry = false; // for correct reset - mState = States::RESET; - DBGPRINTLN(F("-----")); - } - - inline void miHwDecode(packet_t *p, const queue_s *q) { - record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure - rec->ts = q->ts; - /* - Polling the device software and hardware version number command - start byte Command word routing address target address User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] - 0x7e 0x0f xx xx xx xx YY YY YY YY 0x00 CRC 0x7f - Command Receipt - First Frame - start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] - 0x7e 0x8f YY YY YY YY xx xx xx xx 0x00 USFWBuild_VER APPFWBuild_VER APPFWBuild_YYYY APPFWBuild_MMDD APPFWBuild_HHMM APPFW_PN HW_VER CRC 0x7f - Command Receipt - Second Frame - start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] - 0x7e 0x8f YY YY YY YY xx xx xx xx 0x01 HW_PN HW_FB_TLmValue HW_FB_ReSPRT HW_GridSamp_ResValule HW_ECapValue Matching_APPFW_PN CRC 0x7f - Command receipt - third frame - start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[15] byte[16] byte[17] byte[18] - 0x7e 0x8f YY YY YY YY xx xx xx xx 0x12 APPFW_MINVER HWInfoAddr PNInfoCRC_gusv PNInfoCRC_gusv CRC 0x7f - */ - - /* - case InverterDevInform_All: - rec->length = (uint8_t)(HMINFO_LIST_LEN); - rec->assign = (byteAssign_t *)InfoAssignment; - rec->pyldLen = HMINFO_PAYLOAD_LEN; - break; - const byteAssign_t InfoAssignment[] = { - { FLD_FW_VERSION, UNIT_NONE, CH0, 0, 2, 1 }, - { FLD_FW_BUILD_YEAR, UNIT_NONE, CH0, 2, 2, 1 }, - { FLD_FW_BUILD_MONTH_DAY, UNIT_NONE, CH0, 4, 2, 1 }, - { FLD_FW_BUILD_HOUR_MINUTE, UNIT_NONE, CH0, 6, 2, 1 }, - { FLD_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } - }; - */ - - if ( p->packet[9] == 0x00 ) {//first frame - //FLD_FW_VERSION - for (uint8_t i = 0; i < 5; i++) { - q->iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); - } - q->iv->isConnected = true; - if(*mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("HW_VER is ")); - DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); - } - record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure - rec->ts = q->ts; - q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); - q->iv->miMultiParts +=4; - } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 - DPRINT_IVID(DBG_INFO, q->iv->id); - if ( p->packet[9] == 0x01 ) { - DBGPRINTLN(F("got 2nd frame (hw info)")); - /* according to xlsx (different start byte -1!) - byte[11] to byte[14] HW_PN - byte[15] byte[16] HW_FB_TLmValue - byte[17] byte[18] HW_FB_ReSPRT - byte[19] byte[20] HW_GridSamp_ResValule - byte[21] byte[22] HW_ECapValue - byte[23] to byte[26] Matching_APPFW_PN*/ - DPRINT(DBG_INFO,F("HW_PartNo ")); - DBGPRINTLN(String((uint32_t) (((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])); - record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure - rec->ts = q->ts; - q->iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1); - - if(*mSerialDebug) { - DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); - DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); - DBGPRINT(F("HW_FB_ReSPRT ")); - DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); - DBGPRINT(F("HW_GridSamp_ResValule ")); - DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); - DBGPRINT(F("HW_ECapValue ")); - DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); - DBGPRINT(F("Matching_APPFW_PN ")); - DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); - } - if(NULL != mCbPayload) - (mCbPayload)(InverterDevInform_All, q->iv); - q->iv->miMultiParts +=2; - - } else { - DBGPRINTLN(F("3rd gen. inverter!")); - } - - } else if ( p->packet[9] == 0x12 ) {//3rd frame - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINTLN(F("got 3rd frame (hw info)")); - /* according to xlsx (different start byte -1!) - byte[11] byte[12] APPFW_MINVER - byte[13] byte[14] HWInfoAddr - byte[15] byte[16] PNInfoCRC_gusv - byte[15] byte[16] PNInfoCRC_gusv (this really is double mentionned in xlsx...) - */ - if(*mSerialDebug) { - DPRINT(DBG_INFO,F("APPFW_MINVER ")); - DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); - DBGPRINT(F("HWInfoAddr ")); - DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); - DBGPRINT(F("PNInfoCRC_gusv ")); - DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); - } - if(NULL != mCbPayload) - (mCbPayload)(InverterDevInform_Simple, q->iv); - q->iv->miMultiParts++; - } - //if(q->iv->miMultiParts > 5) - //closeRequest(q->iv, true); - //else - //if(q->iv->miMultiParts < 6) - // mState = States::WAIT; - - /*if (mPayload[iv->id].multi_parts > 5) { - iv->setQueuedCmdFinished(); - mPayload[iv->id].complete = true; - mPayload[iv->id].rxTmo = true; - mPayload[iv->id].requested= false; - iv->radioStatistics.rxSuccess++; - } - if (mHighPrioIv == NULL) - mHighPrioIv = iv; - */ - } - - inline void miDataDecode(packet_t *p, const queue_s *q) { - record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser - rec->ts = q->ts; - //mState = States::RESET; - if(q->iv->miMultiParts < 6) - q->iv->miMultiParts += 6; - - uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : - ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : - p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : - CH4; - // count in RF_communication_protocol.xlsx is with offset = -1 - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); - - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); - - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); - q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); - - if (datachan == 1) - q->iv->rssi = p->rssi; - else if(q->iv->rssi > p->rssi) - q->iv->rssi = p->rssi; - - if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { - /*For MI1500: - if (MI1500) { - STAT = (uint8_t)(p->packet[25] ); - FCNT = (uint8_t)(p->packet[26]); - FCODE = (uint8_t)(p->packet[27]); - }*/ - miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); - - if (p->packet[0] < (0x39 + ALL_FRAMES) ) { - mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), 1); - miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); - } else { - q->iv->miMultiParts = 7; // indicate we are ready - //miComplete(q->iv); - } - } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { - //addImportant(q->iv, MI_REQ_CH2); - miNextRequest(MI_REQ_CH2, q); - mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), q->iv->curFrmCnt); - //use also miMultiParts here for better statistics? - //mHeu.setGotFragment(q->iv); - } else { // first data msg for 1ch, 2nd for 2ch - q->iv->miMultiParts += 6; // indicate we are ready - //miComplete(q->iv); - } - } - - void miNextRequest(uint8_t cmd, const queue_s *q) { - incrAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... - if(*mSerialDebug) { - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("next request (")); - DBGPRINT(String(q->attempts)); - DBGPRINT(F(" attempts left): 0x")); - DBGHEXLN(cmd); - } - - if(q->iv->miMultiParts == 7) { - //mHeu.setGotAll(q->iv); - q->iv->radioStatistics.rxSuccess++; - } else - //mHeu.setGotFragment(q->iv); - /*iv->radioStatistics.rxFail++; // got no complete payload*/ - //q->iv->radioStatistics.retransmits++; - q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); - - mWaitTimeout = millis() + MI_TIMEOUT; - mWaitTimeout_min = mWaitTimeout; - q->iv->miMultiParts = 0; - q->iv->mGotFragment = 0; - mIsRetransmit = true; - chgCmd(cmd); - //mState = States::WAIT; - } - - void miRepeatRequest(const queue_s *q) { - setAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... - if(*mSerialDebug) { - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("resend request (")); - DBGPRINT(String(q->attempts)); - DBGPRINT(F(" attempts left): 0x")); - DBGHEXLN(q->cmd); - } - - q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); - - mWaitTimeout = millis() + MI_TIMEOUT; - mWaitTimeout_min = mWaitTimeout; - //mState = States::WAIT; - mIsRetransmit = false; - } - - void miStsConsolidate(const queue_s *q, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) { - //uint8_t status = (p->packet[11] << 8) + p->packet[12]; - uint16_t statusMi = 3; // regular status for MI, change to 1 later? - if ( uState == 2 ) { - statusMi = 5050 + stschan; //first approach, needs review! - if (lState) - statusMi += lState*10; - } else if ( uState > 3 ) { - statusMi = uState*1000 + uEnum*10; - if (lState) - statusMi += lState*100; //needs review, esp. for 4ch-8310 state! - //if (lEnum) - statusMi += lEnum; - if (uEnum < 6) { - statusMi += stschan; - } - if (statusMi == 8000) - statusMi = 8310; //trick? - } - - uint16_t prntsts = statusMi == 3 ? 1 : statusMi; - bool stsok = true; - if ( prntsts != rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)] ) { //sth.'s changed? - q->iv->alarmCnt = 1; // minimum... - stsok = false; - //sth is or was wrong? - if ( (q->iv->type != INV_TYPE_1CH) && ( (statusMi != 3) - || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) - ) { - q->iv->lastAlarm[stschan+q->iv->type==INV_TYPE_2CH ? 2: 4] = alarm_t(q->iv->lastAlarm[stschan].code, q->iv->lastAlarm[stschan].start,q->ts); - q->iv->lastAlarm[stschan] = alarm_t(prntsts, q->ts,0); - q->iv->alarmCnt = q->iv->type == INV_TYPE_2CH ? 3 : 5; - } else if ( (q->iv->type == INV_TYPE_1CH) && ( (statusMi != 3) - || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) - ) { - q->iv->lastAlarm[stschan] = alarm_t(q->iv->lastAlarm[0].code, q->iv->lastAlarm[0].start,q->ts); - } else if (q->iv->type == INV_TYPE_1CH) - stsok = true; - - q->iv->alarmLastId = prntsts; //iv->alarmMesIndex; - - if (q->iv->alarmCnt > 1) { //more than one channel - for (uint8_t ch = 0; ch < (q->iv->alarmCnt); ++ch) { //start with 1 - if (q->iv->lastAlarm[ch].code == 1) { - stsok = true; - break; - } - } - } - if(*mSerialDebug) { - DPRINT(DBG_WARN, F("New state on CH")); - DBGPRINT(String(stschan)); DBGPRINT(F(" (")); - DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); - DBGPRINTLN(q->iv->getAlarmStr(prntsts)); - } - if(!q->iv->miMultiParts) - q->iv->miMultiParts = 1; // indicate we got status info (1+2 ch types) - } - - if (!stsok) { - q->iv->setValue(q->iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts); - q->iv->lastAlarm[0] = alarm_t(prntsts, q->ts, 0); - } - - if (q->iv->alarmMesIndex < rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]) { - q->iv->alarmMesIndex = rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? - if (*mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("alarm ID incremented to ")); - DBGPRINTLN(String(q->iv->alarmMesIndex)); - } - } - } - - - void miComplete(Inverter<> *iv) { - if (*mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINTLN(F("got all data msgs")); - } - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - - //preliminary AC calculation... - float ac_pow = 0; - if (iv->type == INV_TYPE_1CH) { - if ((!iv->lastAlarm[0].code) || (iv->lastAlarm[0].code == 1)) - ac_pow += iv->getValue(iv->getPosByChFld(1, FLD_PDC, rec), rec); - } else { - for(uint8_t i = 1; i <= iv->channels; i++) { - if ((!iv->lastAlarm[i].code) || (iv->lastAlarm[i].code == 1)) { - uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); - ac_pow += iv->getValue(pos, rec); - } - } - } - ac_pow = (int) (ac_pow*9.5); - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10); - - iv->doCalculations(); - // update status state-machine, - if (ac_pow) - iv->isProducing(); - //closeRequest(iv, iv->miMultiParts > 5); - - //mHeu.setGotAll(iv); - //cmdDone(false); - if(NULL != mCbPayload) - (mCbPayload)(RealTimeRunData_Debug, iv); - - //mState = States::RESET; // everything ok, next request - } - - private: - enum class States : uint8_t { - RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE - }; - - typedef struct { - uint8_t buf[MAX_RF_PAYLOAD_SIZE]; - uint8_t len; - int8_t rssi; - } frame_t; - - private: - States mState = States::RESET; - uint32_t *mTimestamp; - bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; - uint16_t *mInverterGap; - uint32_t mWaitTimeout = 0; - uint32_t mWaitTimeout_min = 0; - std::array mLocalBuf; - bool mFirstTry = false; // see, if we should do a second try - bool mIsRetransmit = false; // we alrady had waited one complete cycle - uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation - uint8_t mMaxFrameId; - uint8_t mPayload[MAX_BUFFER]; - payloadListenerType mCbPayload = NULL; - alarmListenerType mCbAlarm = NULL; - Heuristic mHeu; - uint32_t mLastEmptyQueueMillis = 0; - bool mPrintSequenceDuration = false; - - //States mDebugState = States::START; -}; - -#endif /*__COMMUNICATION_H__*/ From 0d3bfe371082818c56c1c3f9d0a83a6661b799d6 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 20:59:52 +0100 Subject: [PATCH 09/15] fix some double counts --- src/hm/Communication.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index bc6f9f38..eff60869 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -464,9 +464,6 @@ class Communication : public CommQueue<> { if(GridOnProFilePara == q->cmd) { q->iv->addGridProfile(mPayload, len); - q->iv->radioStatistics.rxSuccess++; - mHeu.evalTxChQuality(q->iv, true, (7 - q->attempts), q->iv->curFrmCnt); - //cmdDone(false); return; } @@ -474,10 +471,6 @@ class Communication : public CommQueue<> { if(NULL == rec) { if(GetLossRate == q->cmd) { q->iv->parseGetLossRate(mPayload, len); - //closeRequest(q, true); //@lumapu: Activating would crash most esp's! - mHeu.evalTxChQuality(q->iv, true, (9 - q->attempts), q->iv->curFrmCnt); - q->iv->radioStatistics.rxSuccess++; - //cmdDone(false); return; } else { DPRINTLN(DBG_ERROR, F("record is NULL!")); From 61ebe3e989a4c1152c804b881924adbdc38fe157 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 28 Dec 2023 21:36:35 +0100 Subject: [PATCH 10/15] 0.8.30 * added info if grid profile was not found --- src/CHANGES.md | 3 +++ src/defines.h | 2 +- src/web/html/grid_info.json | 1 + src/web/html/visualization.html | 19 +++++++++++++------ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index fc8566cc..17d0528c 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.30 - 2023-12-28 +* added info if grid profile was not found + ## 0.8.29 - 2023-12-27 * fix MqTT generic topic `comm_disabled` #1265 #1286 * potential fix of #1285 (reset yield day) diff --git a/src/defines.h b/src/defines.h index 2b304f9f..d3936d62 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 29 +#define VERSION_PATCH 30 //------------------------------------- typedef struct { diff --git a/src/web/html/grid_info.json b/src/web/html/grid_info.json index adb68393..5dcdda65 100644 --- a/src/web/html/grid_info.json +++ b/src/web/html/grid_info.json @@ -159,6 +159,7 @@ { "name": "Nominal Voltage", "div": 10, + "def": 230, "unit": "V" }, { diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index b561d5cc..2c771f5a 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -355,12 +355,19 @@ getJSON("/grid_info.json").then(data => { var glob = {offs:0, grid:obj.grid, info: data} var content = []; - content.push(ml("div", {class: "row"}, - ml("div", {class: "col my-3"}, ml("h5", {}, getGridType(glob.info.type, getGridIdentifier(glob)) + " (Version " + getGridValue(glob).toString(16) + ")")) - )) - - while((glob.offs*3) < glob.grid.length) { - content.push(parseGridGroup(glob)) + var g = getGridType(glob.info.type, getGridIdentifier(glob)) + if(null === g) { + content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("h5", {}, "Unknown Profile")))) + content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("p", {}, "Please open a new issue at https://github.com/lumapu/ahoy and copy the raw data into it.")))) + content.push(ml("div", {class: "row"}, ml("div", {class: "col my-2"}, ml("pre", {}, obj.grid)))) + } else { + content.push(ml("div", {class: "row"}, + ml("div", {class: "col my-3"}, ml("h5", {}, g + " (Version " + getGridValue(glob).toString(16) + ")")) + )) + + while((glob.offs*3) < glob.grid.length) { + content.push(parseGridGroup(glob)) + } } modal("Grid Profile for inverter " + obj.name, ml("div", {}, ml("div", {class: "col mb-2"}, [...content]))) From 9c074b9814831a67a2f9221993aa8447334d4109 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 28 Dec 2023 21:45:37 +0100 Subject: [PATCH 11/15] 0.8.30 * merge PR #1293 * merge PR #1295 fix ESP8266 pin settings --- src/CHANGES.md | 2 ++ src/hm/Communication.h | 26 ++------------------------ src/hm/hmRadio.h | 2 +- src/web/html/setup.html | 6 +++--- 4 files changed, 8 insertions(+), 28 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 17d0528c..a0fa874a 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,8 @@ ## 0.8.30 - 2023-12-28 * added info if grid profile was not found +* merge PR #1293 +* merge PR #1295 fix ESP8266 pin settings ## 0.8.29 - 2023-12-27 * fix MqTT generic topic `comm_disabled` #1265 #1286 diff --git a/src/hm/Communication.h b/src/hm/Communication.h index eff60869..6ed10e9f 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -59,7 +59,7 @@ 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))); + 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))); uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; /*if(mDebugState != mState) { @@ -113,35 +113,13 @@ class Communication : public CommQueue<> { mIsRetransmit = false; mlastTO_min = timeout_min; setAttempt(); - if(q->cmd == AlarmData || q->cmd == GridOnProFilePara) + if((q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) incrAttempt(q->cmd == AlarmData? 5 : 3); mState = States::WAIT; break; case States::WAIT: - /*if(millis() > mWaitTimeout_min) { - if(mIsRetransmit) { // we already have been through... - mWaitTimeout = mWaitTimeout_min; - } else if(q->iv->mGotFragment) { // nothing received yet? - if(q->iv->mGotLastMsg) { - //mState = States::CHECK_FRAMES; - mWaitTimeout = mWaitTimeout_min; - } - } else if(mFirstTry) { - if(*mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(String(millis() - mWaitTimeout_min + mlastTO_min)); - DBGPRINTLN(F("ms - second try")); - } - mFirstTry = false; - mlastTO_min = timeout_min; - q->iv->radioStatistics.retransmits++; // got nothing - mState = States::START; - break; - } - - }*/ if(millis() < mWaitTimeout) return; mState = States::CHECK_FRAMES; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 2e02e92a..d7ae594b 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -124,7 +124,7 @@ class HmRadio : public Radio { uint32_t outerLoopTimeout = (mLastIv->mIsSingleframeReq) ? 100 : ((mLastIv->mCmd != AlarmData) && (mLastIv->mCmd != GridOnProFilePara)) ? 400 : 600; while ((millis() - loopMillis) < outerLoopTimeout) { - uint32_t startMicros = micros(); + startMicros = micros(); while ((micros() - startMicros) < 5110) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 7ca17005..8e415c2c 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -900,7 +900,7 @@ var pinList = esp8266pins; /*IF_ESP32*/ var pinList = esp32pins; - if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system.chip_model) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; /*ENDIF_ESP32*/ pins = [['led0', 'pinLed0', 'At least one inverter is producing'], ['led1', 'pinLed1', 'MqTT connected']]; @@ -932,7 +932,7 @@ var pinList = esp8266pins; /*IF_ESP32*/ var pinList = esp32pins; - if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system.chip_model) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; /*ENDIF_ESP32*/ @@ -999,7 +999,7 @@ var pinList = esp8266pins; /*IF_ESP32*/ var pinList = esp32pins; - if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system.chip_model) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; /*ENDIF_ESP32*/ From c28d051ba480eae120ccdac1448e4c514e423b54 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 28 Dec 2023 21:49:50 +0100 Subject: [PATCH 12/15] 0.8.30 * added info if grid profile was not found * merge PR #1293 * merge PR #1295 fix ESP8266 pin settings * merge PR #1297 fix layout for OLED displays --- src/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CHANGES.md b/src/CHANGES.md index a0fa874a..f09b00a5 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -4,6 +4,7 @@ * added info if grid profile was not found * merge PR #1293 * merge PR #1295 fix ESP8266 pin settings +* merge PR #1297 fix layout for OLED displays ## 0.8.29 - 2023-12-27 * fix MqTT generic topic `comm_disabled` #1265 #1286 From f7e35e440454e7c3450e0f1a63aca55fdc15bcde Mon Sep 17 00:00:00 2001 From: you69man Date: Sun, 24 Dec 2023 05:56:28 +0100 Subject: [PATCH 13/15] implement TimeMonitor Class --- src/hm/Communication.h | 52 ++++++++++------- src/utils/timemonitor.h | 126 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 20 deletions(-) create mode 100644 src/utils/timemonitor.h diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 6ed10e9f..8f9404a1 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -10,6 +10,7 @@ #include #include "../utils/crc.h" #include "Heuristic.h" +#include "../utils/timemonitor.h" #define MI_TIMEOUT 250 // timeout for MI type requests #define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received @@ -60,7 +61,7 @@ class Communication : public CommQueue<> { 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))); - uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; + // uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; // not used /*if(mDebugState != mState) { DPRINT(DBG_INFO, F("State: ")); @@ -69,8 +70,10 @@ class Communication : public CommQueue<> { }*/ switch(mState) { case States::RESET: - if(millis() < mWaitTimeout) + //if(millis() < mWaitTimeout) // replaced by TimeMonitor + if (!mWaitTime.isTimeout()) return; + mMaxFrameId = 0; for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) { mLocalBuf[i].len = 0; @@ -108,10 +111,11 @@ class Communication : public CommQueue<> { q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); q->iv->radioStatistics.txCnt++; - mWaitTimeout = millis() + timeout; - mWaitTimeout_min = millis() + timeout_min; + // mWaitTimeout = millis() + timeout; // replaced by Timemonitor + mWaitTime.startTimeMonitor(timeout); + // mWaitTimeout_min = millis() + timeout_min; // not used mIsRetransmit = false; - mlastTO_min = timeout_min; + // mlastTO_min = timeout_min; // not used setAttempt(); if((q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) incrAttempt(q->cmd == AlarmData? 5 : 3); @@ -120,7 +124,8 @@ class Communication : public CommQueue<> { break; case States::WAIT: - if(millis() < mWaitTimeout) + // if(millis() < mWaitTimeout) // replaced by Timemonitor + if (!mWaitTime.isTimeout()) return; mState = States::CHECK_FRAMES; break; @@ -130,13 +135,15 @@ class Communication : public CommQueue<> { if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); - DBGPRINT(String(millis() - mWaitTimeout + timeout)); + // DBGPRINT(String(millis() - mWaitTimeout + timeout)); // replaced by Timemonitor + DBGPRINT(String(mWaitTime.getRunTime())); DBGPRINTLN(F("ms")); } if(!q->iv->mGotFragment) { if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); - mWaitTimeout = millis() + 1000; + //mWaitTimeout = millis() + 1000; // replaced by Timemonitor + mWaitTime.startTimeMonitor(1000UL); } } closeRequest(q, false); @@ -185,7 +192,8 @@ class Communication : public CommQueue<> { bool fastNext = true; if(q->iv->miMultiParts < 6) { mState = States::WAIT; - if((millis() > mWaitTimeout && mIsRetransmit) || !mIsRetransmit) { + // if((millis() > mWaitTimeout && mIsRetransmit) || !mIsRetransmit) { // replaced by TimeMonitor + if((mWaitTime.isTimeout() && mIsRetransmit) || !mIsRetransmit) { miRepeatRequest(q); return; } @@ -245,7 +253,7 @@ class Communication : public CommQueue<> { q->iv->mIsSingleframeReq = true; sendRetransmit(q, (framnr-1)); mIsRetransmit = true; - mlastTO_min = timeout_min; + // mlastTO_min = timeout_min; // not used return; } @@ -492,7 +500,8 @@ class Communication : public CommQueue<> { if(q->attempts) { q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout + // mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout replaced by Timemonitor + mWaitTime.startTimeMonitor(SINGLEFR_TIMEOUT); // timeout mState = States::WAIT; } else { //add(q, true); @@ -509,7 +518,8 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.rxFail++; // got no complete payload else q->iv->radioStatistics.rxFailNoAnser++; // got nothing - mWaitTimeout = millis() + *mInverterGap; + // mWaitTimeout = millis() + *mInverterGap; // replaced by Timemonitor + mWaitTime.startTimeMonitor(*mInverterGap); bool keep = false; if(q->isDevControl) @@ -731,8 +741,9 @@ class Communication : public CommQueue<> { //q->iv->radioStatistics.retransmits++; q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); - mWaitTimeout = millis() + MI_TIMEOUT; - mWaitTimeout_min = mWaitTimeout; + // mWaitTimeout = millis() + MI_TIMEOUT; // replaced by TimeMonitor + // mWaitTimeout_min = mWaitTimeout; // not used + mWaitTime.startTimeMonitor(MI_TIMEOUT); q->iv->miMultiParts = 0; q->iv->mGotFragment = 0; mIsRetransmit = true; @@ -752,8 +763,9 @@ class Communication : public CommQueue<> { q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); - mWaitTimeout = millis() + MI_TIMEOUT; - mWaitTimeout_min = mWaitTimeout; + // mWaitTimeout = millis() + MI_TIMEOUT; // replaced by TimeMonitor + // mWaitTimeout_min = mWaitTimeout; // not used + mWaitTime.startTimeMonitor(MI_TIMEOUT); //mState = States::WAIT; mIsRetransmit = false; } @@ -887,12 +899,12 @@ class Communication : public CommQueue<> { uint32_t *mTimestamp; bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; uint16_t *mInverterGap; - uint32_t mWaitTimeout = 0; - uint32_t mWaitTimeout_min = 0; + TimeMonitor mWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) + // uint32_t mWaitTimeout_min = 0; // not used std::array mLocalBuf; bool mFirstTry = false; // see, if we should do a second try - bool mIsRetransmit = false; // we alrady had waited one complete cycle - uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation + bool mIsRetransmit = false; // we already had waited one complete cycle + // uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation not used uint8_t mMaxFrameId; uint8_t mPayload[MAX_BUFFER]; payloadListenerType mCbPayload = NULL; diff --git a/src/utils/timemonitor.h b/src/utils/timemonitor.h new file mode 100644 index 00000000..ce44a94d --- /dev/null +++ b/src/utils/timemonitor.h @@ -0,0 +1,126 @@ +//----------------------------------------------------------- +// You69Man, 2023 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// version 2 as published by the Free Software Foundation. +//----------------------------------------------------------- + +/** + * @file timemonitor.h + * + * Class declaration for TimeMonitor + */ + +#ifndef __TIMEMONITOR_H__ +#define __TIMEMONITOR_H__ + +#include + +class TimeMonitor { + public: + /** + * A constructor for initializing a TimeMonitor + * @note TimeMonitor witch default constructor is stopped + */ + TimeMonitor(void) {}; + + /** + * A constructor for initializing a TimeMonitor + * @param timeout timeout in ms + * @param start (optional) if true, start TimeMonitor immediately + * @note TimeMonitor witch default constructor is stopped + */ + TimeMonitor(uint32_t timeout, bool start = false) { + if (start) + startTimeMonitor(timeout); + else + configureTimeMonitor(timeout); + }; + + /** + * Start the TimeMonitor with new timeout configuration + * @param timeout timout in ms + */ + void startTimeMonitor(uint32_t timeout) { + mStartTime = millis(); + mTimeout = timeout; + mStarted = true; + } + + /** + * Restart the TimeMonitor with already set timeout configuration + * @note returns nothing + */ + void reStartTimeMonitor(void) { + mStartTime = millis(); + mStarted = true; + } + + /** + * Configure the TimeMonitor to new timeout configuration + * @param timeout timeout in ms + * @note This doesn't restart an already running TimeMonitor. + * If timer is already running and new timeout is longer that current timeout runtime of the running timer is expanded + * If timer is already running and new timeout is shorter that current timeout this can immediately lead to a timeout + */ + void configureTimeMonitor(uint32_t timeout) { + mTimeout = timeout; + } + + /** + * Stop the TimeMonitor + */ + void stopTimeMonitor(void) { + mStarted = false; + } + + /** + * Get timeout status of the TimeMonitor + * @return bool + * true: TimeMonitor already timed out + * false: TimeMonitor still in time or TimeMonitor was stopped + */ + bool isTimeout(void) { + if ((mStarted) && (millis() - mStartTime >= mTimeout)) + return true; + else + return false; + } + + /** + * Get timeout configuration of the TimeMonitor + * @return uint32_t timeout value in ms + */ + uint32_t getTimeout(void) const { + return mTimeout; + } + + /** + * Get residual time of the TimeMonitor until timeout + * @return uint32_t residual time until timeout in ms + * @note in case of a stopped TimeMonitor residual time is always 0xFFFFFFFFUL + * in case of a timed out TimeMonitor residual time is always 0UL (zero) + */ + uint32_t getResidualTime(void) const { + uint32_t delayed = millis() - mStartTime; + return(mStarted ? (delayed < mTimeout ? mTimeout - delayed : 0UL) : 0xFFFFFFFFUL); + } + + /** + * Get overall run time of the TimeMonitor + * @return uint32_t residual time until timeout in ms + * @note in case of a stopped TimeMonitor residual time is always 0xFFFFFFFFUL + * in case of a timed out TimeMonitor residual time is always 0UL (zero) + */ + uint32_t getRunTime(void) const { + return(mStarted ? millis() - mStartTime : 0UL); + } + + private: + uint32_t mStartTime = 0UL; // start time of the TimeMonitor + uint32_t mTimeout = 0UL; // timeout configuration of the TimeMonitor + bool mStarted = false; // start/stop state of the TimeMonitor +}; + +#endif \ No newline at end of file From bd0c5e3613e118975633b5503c00effb594fdde8 Mon Sep 17 00:00:00 2001 From: you69man Date: Sun, 24 Dec 2023 05:56:58 +0100 Subject: [PATCH 14/15] adapt Display_Mono.h to TimeMonitor --- src/plugins/Display/Display_Mono.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 3fc691c2..5b0d7457 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -19,6 +19,7 @@ #include "../../utils/helper.h" #include "Display_data.h" #include "../../utils/dbg.h" +#include "../../utils/timemonitor.h" class DisplayMono { public: @@ -37,19 +38,19 @@ class DisplayMono { if (mDisplayActive) { if (!dispConditions) { - if ((millis() - mStarttime) > DISP_DEFAULT_TIMEOUT * 1000ul) { // switch display off after timeout + if (mDisplayTime.isTimeout()) { // switch display off after timeout mDisplayActive = false; mDisplay->setPowerSave(true); DBGPRINTLN("**** Display off ****"); } } else - mStarttime = millis(); // keep display on + mDisplayTime.reStartTimeMonitor(); // keep display on } else { if (dispConditions) { - mDisplayActive = true; // switch display on - mStarttime = millis(); + mDisplayActive = true; + mDisplayTime.reStartTimeMonitor(); // switch display on mDisplay->setPowerSave(false); DBGPRINTLN("**** Display on ****"); } @@ -79,7 +80,7 @@ class DisplayMono { uint8_t mExtra; int8_t mPixelshift=0; - uint32_t mStarttime = millis(); + TimeMonitor mDisplayTime = TimeMonitor(1000ul * 15, true); bool mDisplayActive = true; // always start with display on char mFmtText[DISP_FMT_TEXT_LEN]; From 7c08d934a93748b0d7291777990120b3ee8fd563 Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 29 Dec 2023 00:18:55 +0100 Subject: [PATCH 15/15] 0.8.31 * added class to handle timeouts PR #1298 --- src/CHANGES.md | 3 +++ src/defines.h | 2 +- src/hm/Communication.h | 26 ++++---------------------- src/plugins/Display/Display_Mono.h | 2 +- src/utils/timemonitor.h | 10 +++++----- 5 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index f09b00a5..7839d420 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.31 - 2023-12-29 +* added class to handle timeouts PR #1298 + ## 0.8.30 - 2023-12-28 * added info if grid profile was not found * merge PR #1293 diff --git a/src/defines.h b/src/defines.h index d3936d62..b3c5089a 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 30 +#define VERSION_PATCH 31 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 8f9404a1..1ed45831 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -9,8 +9,8 @@ #include "CommQueue.h" #include #include "../utils/crc.h" -#include "Heuristic.h" #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 @@ -61,7 +61,6 @@ class Communication : public CommQueue<> { 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))); - // uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; // not used /*if(mDebugState != mState) { DPRINT(DBG_INFO, F("State: ")); @@ -70,7 +69,6 @@ class Communication : public CommQueue<> { }*/ switch(mState) { case States::RESET: - //if(millis() < mWaitTimeout) // replaced by TimeMonitor if (!mWaitTime.isTimeout()) return; @@ -111,11 +109,8 @@ class Communication : public CommQueue<> { q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); q->iv->radioStatistics.txCnt++; - // mWaitTimeout = millis() + timeout; // replaced by Timemonitor mWaitTime.startTimeMonitor(timeout); - // mWaitTimeout_min = millis() + timeout_min; // not used mIsRetransmit = false; - // mlastTO_min = timeout_min; // not used setAttempt(); if((q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) incrAttempt(q->cmd == AlarmData? 5 : 3); @@ -124,7 +119,6 @@ class Communication : public CommQueue<> { break; case States::WAIT: - // if(millis() < mWaitTimeout) // replaced by Timemonitor if (!mWaitTime.isTimeout()) return; mState = States::CHECK_FRAMES; @@ -135,15 +129,13 @@ class Communication : public CommQueue<> { if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); - // DBGPRINT(String(millis() - mWaitTimeout + timeout)); // replaced by Timemonitor DBGPRINT(String(mWaitTime.getRunTime())); DBGPRINTLN(F("ms")); } if(!q->iv->mGotFragment) { if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); - //mWaitTimeout = millis() + 1000; // replaced by Timemonitor - mWaitTime.startTimeMonitor(1000UL); + mWaitTime.startTimeMonitor(1000); } } closeRequest(q, false); @@ -192,7 +184,6 @@ class Communication : public CommQueue<> { bool fastNext = true; if(q->iv->miMultiParts < 6) { mState = States::WAIT; - // if((millis() > mWaitTimeout && mIsRetransmit) || !mIsRetransmit) { // replaced by TimeMonitor if((mWaitTime.isTimeout() && mIsRetransmit) || !mIsRetransmit) { miRepeatRequest(q); return; @@ -253,7 +244,6 @@ class Communication : public CommQueue<> { q->iv->mIsSingleframeReq = true; sendRetransmit(q, (framnr-1)); mIsRetransmit = true; - // mlastTO_min = timeout_min; // not used return; } @@ -500,7 +490,6 @@ class Communication : public CommQueue<> { if(q->attempts) { q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - // mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout replaced by Timemonitor mWaitTime.startTimeMonitor(SINGLEFR_TIMEOUT); // timeout mState = States::WAIT; } else { @@ -518,7 +507,6 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.rxFail++; // got no complete payload else q->iv->radioStatistics.rxFailNoAnser++; // got nothing - // mWaitTimeout = millis() + *mInverterGap; // replaced by Timemonitor mWaitTime.startTimeMonitor(*mInverterGap); bool keep = false; @@ -741,8 +729,6 @@ class Communication : public CommQueue<> { //q->iv->radioStatistics.retransmits++; q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); - // mWaitTimeout = millis() + MI_TIMEOUT; // replaced by TimeMonitor - // mWaitTimeout_min = mWaitTimeout; // not used mWaitTime.startTimeMonitor(MI_TIMEOUT); q->iv->miMultiParts = 0; q->iv->mGotFragment = 0; @@ -763,8 +749,6 @@ class Communication : public CommQueue<> { q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); - // mWaitTimeout = millis() + MI_TIMEOUT; // replaced by TimeMonitor - // mWaitTimeout_min = mWaitTimeout; // not used mWaitTime.startTimeMonitor(MI_TIMEOUT); //mState = States::WAIT; mIsRetransmit = false; @@ -900,11 +884,9 @@ class Communication : public CommQueue<> { bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; uint16_t *mInverterGap; TimeMonitor mWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) - // uint32_t mWaitTimeout_min = 0; // not used std::array mLocalBuf; - bool mFirstTry = false; // see, if we should do a second try - bool mIsRetransmit = false; // we already had waited one complete cycle - // uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation not used + 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 mPayload[MAX_BUFFER]; payloadListenerType mCbPayload = NULL; diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 5b0d7457..3e998b6d 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -80,7 +80,7 @@ class DisplayMono { uint8_t mExtra; int8_t mPixelshift=0; - TimeMonitor mDisplayTime = TimeMonitor(1000ul * 15, true); + TimeMonitor mDisplayTime = TimeMonitor(1000 * 15, true); bool mDisplayActive = true; // always start with display on char mFmtText[DISP_FMT_TEXT_LEN]; diff --git a/src/utils/timemonitor.h b/src/utils/timemonitor.h index ce44a94d..798077d5 100644 --- a/src/utils/timemonitor.h +++ b/src/utils/timemonitor.h @@ -23,7 +23,7 @@ class TimeMonitor { * A constructor for initializing a TimeMonitor * @note TimeMonitor witch default constructor is stopped */ - TimeMonitor(void) {}; + TimeMonitor(void) {} /** * A constructor for initializing a TimeMonitor @@ -36,7 +36,7 @@ class TimeMonitor { startTimeMonitor(timeout); else configureTimeMonitor(timeout); - }; + } /** * Start the TimeMonitor with new timeout configuration @@ -118,9 +118,9 @@ class TimeMonitor { } private: - uint32_t mStartTime = 0UL; // start time of the TimeMonitor - uint32_t mTimeout = 0UL; // timeout configuration of the TimeMonitor - bool mStarted = false; // start/stop state of the TimeMonitor + uint32_t mStartTime = 0UL; // start time of the TimeMonitor + uint32_t mTimeout = 0UL; // timeout configuration of the TimeMonitor + bool mStarted = false; // start/stop state of the TimeMonitor }; #endif \ No newline at end of file