From 163a9e485ef7f01cd85548d41aeb575fbc15146b Mon Sep 17 00:00:00 2001
From: lumapu <lp@lufami.de>
Date: Mon, 29 Jan 2024 21:51:49 +0100
Subject: [PATCH] 0.8.68 * fix HMS / HMT startup * added `flush_rx` to NRF on
 TX * start with heuristics set to `0` * added warning for WiFi channel 12-14
 (ESP8266 only) #1381

---
 src/CHANGES.md         |  6 ++++++
 src/app.h              |  4 ++++
 src/appInterface.h     |  1 +
 src/defines.h          |  2 +-
 src/hm/Communication.h |  5 ++++-
 src/hm/HeuristicInv.h  | 19 +++++++++++++++++--
 src/hm/hmInverter.h    |  9 +++++++++
 src/hm/hmRadio.h       | 26 ++++++++++++++------------
 src/hms/cmt2300a.h     |  6 +++---
 src/web/RestApi.h      |  6 ++++++
 src/web/lang.h         |  6 ++++++
 src/wifi/ahoywifi.cpp  |  2 ++
 src/wifi/ahoywifi.h    |  5 +++++
 13 files changed, 78 insertions(+), 19 deletions(-)

diff --git a/src/CHANGES.md b/src/CHANGES.md
index 651d068d..f690b192 100644
--- a/src/CHANGES.md
+++ b/src/CHANGES.md
@@ -1,5 +1,11 @@
 # Development Changes
 
+## 0.8.68 - 2024-01-29
+* fix HMS / HMT startup
+* added `flush_rx` to NRF on TX
+* start with heuristics set to `0`
+* added warning for WiFi channel 12-14 (ESP8266 only) #1381
+
 ## 0.8.67 - 2024-01-29
 * fix HMS frequency
 * fix display of inverter id in serial log (was displayed twice)
diff --git a/src/app.h b/src/app.h
index 851ad3c8..ccf46297 100644
--- a/src/app.h
+++ b/src/app.h
@@ -182,6 +182,10 @@ class app : public IApp, public ah::Scheduler {
             return mWifi.getStationIp();
         }
 
+        bool getWasInCh12to14(void) const {
+            return mWifi.getWasInCh12to14();
+        }
+
         #endif /* !defined(ETHERNET) */
 
         void setRebootFlag() {
diff --git a/src/appInterface.h b/src/appInterface.h
index ad38f756..f98fb0cb 100644
--- a/src/appInterface.h
+++ b/src/appInterface.h
@@ -35,6 +35,7 @@ class IApp {
         virtual void setupStation(void) = 0;
         virtual void setStopApAllowedMode(bool allowed) = 0;
         virtual String getStationIp(void) = 0;
+        virtual bool getWasInCh12to14(void) const = 0;
         #endif /* defined(ETHERNET) */
 
         virtual uint32_t getUptime() = 0;
diff --git a/src/defines.h b/src/defines.h
index 4ff2fc1e..442008ff 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -13,7 +13,7 @@
 //-------------------------------------
 #define VERSION_MAJOR       0
 #define VERSION_MINOR       8
-#define VERSION_PATCH       67
+#define VERSION_PATCH       68
 
 //-------------------------------------
 typedef struct {
diff --git a/src/hm/Communication.h b/src/hm/Communication.h
index 396a98a5..b74f689d 100644
--- a/src/hm/Communication.h
+++ b/src/hm/Communication.h
@@ -139,7 +139,10 @@ class Communication : public CommQueue<> {
                         if(!q->iv->mGotFragment) {
                             if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) {
                                 #if defined(ESP32)
-                                q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000));
+                                if(!q->iv->radio->switchFrequency(q->iv, q->iv->radio->getBootFreqMhz() * 1000, (q->iv->config->frequency*FREQ_STEP_KHZ + q->iv->radio->getBaseFreqMhz() * 1000))) {
+                                    DPRINT_IVID(DBG_INFO, q->iv->id);
+                                    DBGPRINTLN(F("switch frequency failed!"));
+                                }
                                 mWaitTime.startTimeMonitor(1000);
                                 #endif
                             } else {
diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h
index e7ad6edd..0391e758 100644
--- a/src/hm/HeuristicInv.h
+++ b/src/hm/HeuristicInv.h
@@ -1,5 +1,5 @@
 //-----------------------------------------------------------------------------
-// 2023 Ahoy, https://github.com/lumpapu/ahoy
+// 2024 Ahoy, https://github.com/lumpapu/ahoy
 // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
 //-----------------------------------------------------------------------------
 
@@ -14,7 +14,22 @@
 class HeuristicInv {
     public:
         HeuristicInv() {
-            memset(txRfQuality, -6, RF_MAX_CHANNEL_ID);
+            clear();
+        }
+
+        void clear() {
+            memset(txRfQuality, 0, RF_MAX_CHANNEL_ID);
+            txRfChId           = 0;
+            lastBestTxChId     = 0;
+            testPeriodSendCnt  = 0;
+            testPeriodFailCnt  = 0;
+            testChId           = 0;
+            saveOldTestQuality = -6;
+            lastRxFragments    = 0;
+        }
+
+        bool isTxAtMax(void) const {
+            return (RF_MAX_QUALITY == txRfQuality[txRfChId]);
         }
 
     public:
diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h
index cc73cb0b..f63fa688 100644
--- a/src/hm/hmInverter.h
+++ b/src/hm/hmInverter.h
@@ -192,6 +192,14 @@ class Inverter {
                 if(mNextLive)
                     cb(RealTimeRunData_Debug, false);    // get live data
                 else {
+                    if(INV_RADIO_TYPE_NRF == ivRadioType) {
+                        // get live data until quility reaches maximum
+                        if(!heuristics.isTxAtMax()) {
+                            cb(RealTimeRunData_Debug, false);    // get live data
+                            return;
+                        }
+                    }
+
                     if(actPowerLimit == 0xffff)
                         cb(SystemConfigPara, false);         // power limit info
                     else if(InitDataState != devControlCmd) {
@@ -449,6 +457,7 @@ class Inverter {
                     status = InverterStatus::OFF;
                     actPowerLimit = 0xffff; // power limit will be read once inverter becomes available
                     alarmMesIndex = 0;
+                    heuristics.clear();
                 }
                 else
                     status = InverterStatus::WAS_ON;
diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h
index d73b2b0e..5730c492 100644
--- a/src/hm/hmRadio.h
+++ b/src/hm/hmRadio.h
@@ -77,7 +77,7 @@ class HmRadio : public Radio {
             #else
                 mNrf24->begin(mSpi.get(), ce, cs);
             #endif
-            mNrf24->setRetries(3, 15); // wait 3*250 = 750us, 16 * 250us -> 4000us = 4ms
+            mNrf24->setRetries(3, 9); // wait 3*250 = 750us, 16 * 250us -> 4000us = 4ms
 
             mNrf24->setDataRate(RF24_250KBPS);
             //mNrf24->setAutoAck(true); // enabled by default
@@ -120,14 +120,14 @@ class HmRadio : public Radio {
                 if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME+DURATION_ONEFRAME)))
                     mNRFloopChannels = true;
 
-                rxPendular = !rxPendular;
-                //innerLoopTimeout = (rxPendular ? 1 : 2)*DURATION_LISTEN_MIN;
+                mRxPendular = !mRxPendular;
+                //innerLoopTimeout = (mRxPendular ? 1 : 2)*DURATION_LISTEN_MIN;
                 innerLoopTimeout = DURATION_LISTEN_MIN;
 
                 if(mNRFloopChannels)
                     tempRxChIdx = (tempRxChIdx + 4) % RF_CHANNELS;
                 else
-                    tempRxChIdx = (mRxChIdx + rxPendular*4) % RF_CHANNELS;
+                    tempRxChIdx = (mRxChIdx + mRxPendular*4) % RF_CHANNELS;
 
                 mNrf24->setChannel(mRfChLst[tempRxChIdx]);
                 isRxInit = false;
@@ -141,7 +141,7 @@ class HmRadio : public Radio {
 
                 if(tx_ok || tx_fail) { // tx related interrupt, basically we should start listening
                     mNrf24->flush_tx();                         // empty TX FIFO
-                    mTxSetupTime = millis() - mMillis;
+                    //mTxSetupTime = millis() - mMillis;
 
                     if(mNRFisInRX) {
                         DPRINTLN(DBG_WARN, F("unexpected tx irq!"));
@@ -157,7 +157,7 @@ class HmRadio : public Radio {
                     mNrf24->startListening();
                     mTimeslotStart = millis();
                     tempRxChIdx = mRxChIdx;
-                    rxPendular  = false;
+                    mRxPendular = false;
                     mNRFloopChannels = (mLastIv->ivGen == IV_MI);
 
                     innerLoopTimeout = DURATION_TXFRAME;
@@ -168,11 +168,12 @@ class HmRadio : public Radio {
                         mNRFisInRX = false;
                         mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first end his transmissions
                         mNrf24->stopListening();
+                        return false;
                     } else {
                         innerLoopTimeout = DURATION_LISTEN_MIN;
                         mTimeslotStart = millis();
                         if (!mNRFloopChannels) {
-                            //rxPendular = true; // stay longer on the next rx channel
+                            //mRxPendular = true; // stay longer on the next rx channel
                             if (isRxInit) {
                                 isRxInit = false;
                                 tempRxChIdx = (mRxChIdx + 4) % RF_CHANNELS;
@@ -180,8 +181,8 @@ class HmRadio : public Radio {
                             } else
                                 mRxChIdx = tempRxChIdx;
                         }
+                        return true;
                     }
-                    return mNRFisInRX;
                 }
             }
 
@@ -341,11 +342,11 @@ class HmRadio : public Radio {
             mTxChIdx = iv->heuristics.txRfChId;
 
             if(*mSerialDebug) {
-                if(!isRetransmit) {
+                /*if(!isRetransmit) {
                     DPRINT(DBG_INFO, "last tx setup: ");
                     DBGPRINT(String(mTxSetupTime));
                     DBGPRINTLN("ms");
-                }
+                }*/
 
                 DPRINT_IVID(DBG_INFO, iv->id);
                 DBGPRINT(F("TX "));
@@ -368,6 +369,7 @@ class HmRadio : public Radio {
             }
 
             mNrf24->stopListening();
+            mNrf24->flush_rx();
             mNrf24->setChannel(mRfChLst[mTxChIdx]);
             mNrf24->openWritingPipe(reinterpret_cast<uint8_t*>(&iv->radioId.u64));
             mNrf24->startWrite(mTxBuf, len, false); // false = request ACK response
@@ -407,9 +409,9 @@ class HmRadio : public Radio {
         bool mNRFloopChannels = false;
         bool mNRFisInRX = false;
         bool isRxInit = true;
-        bool rxPendular = false;
+        bool mRxPendular = false;
         uint32_t innerLoopTimeout = DURATION_LISTEN_MIN;
-        uint8_t mTxSetupTime = 0;
+        //uint8_t mTxSetupTime = 0;
 
         std::unique_ptr<SPIClass> mSpi;
         std::unique_ptr<RF24> mNrf24;
diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h
index 3cdc2660..e6456f5b 100644
--- a/src/hms/cmt2300a.h
+++ b/src/hms/cmt2300a.h
@@ -356,11 +356,11 @@ class Cmt2300a {
             if((freqKhz % FREQ_STEP_KHZ) != 0)
                 return 0xff; // error
 
-            std::pair<uint8_t, uint8_t> range = getFreqRangeMhz();
-            if((freqKhz < range.first) || (freqKhz > range.second))
+            std::pair<uint16_t, uint16_t> range = getFreqRangeMhz();
+            if((freqKhz < (range.first * 1000)) || (freqKhz > (range.second * 1000)))
                 return 0xff; // error
 
-            return (freqKhz - getBaseFreqMhz() * 1000) / FREQ_STEP_KHZ;
+            return (freqKhz - (getBaseFreqMhz() * 1000)) / FREQ_STEP_KHZ;
         }
 
         inline void switchChannel(uint8_t ch) {
diff --git a/src/web/RestApi.h b/src/web/RestApi.h
index 9ec717c1..ccdc8747 100644
--- a/src/web/RestApi.h
+++ b/src/web/RestApi.h
@@ -754,6 +754,12 @@ class RestApi {
                 warn.add(F(REBOOT_ESP_APPLY_CHANGES));
             if(0 == mApp->getTimestamp())
                 warn.add(F(TIME_NOT_SET));
+            #if !defined(ETHERNET)
+                #if !defined(ESP32)
+                if(mApp->getWasInCh12to14())
+                    warn.add(F(WAS_IN_CH_12_TO_14));
+                #endif
+            #endif
         }
 
         void getSetup(AsyncWebServerRequest *request, JsonObject obj) {
diff --git a/src/web/lang.h b/src/web/lang.h
index 546399aa..e55493eb 100644
--- a/src/web/lang.h
+++ b/src/web/lang.h
@@ -18,6 +18,12 @@
     #define TIME_NOT_SET "time not set. No communication to inverter possible"
 #endif
 
+#ifdef LANG_DE
+    #define WAS_IN_CH_12_TO_14 "Der ESP war in WLAN Kanal 12 bis 14, was uU. zu Abstürzen führt"
+#else /*LANG_EN*/
+    #define WAS_IN_CH_12_TO_14 "Your ESP was in wifi channel 12 to 14. It may cause reboots of your AhoyDTU"
+#endif
+
 #ifdef LANG_DE
     #define INV_INDEX_INVALID "Wechselrichterindex ungültig; "
 #else /*LANG_EN*/
diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp
index defca5bc..9bcbdadc 100644
--- a/src/wifi/ahoywifi.cpp
+++ b/src/wifi/ahoywifi.cpp
@@ -92,6 +92,8 @@ void ahoywifi::tickWifiLoop() {
             }
             #if !defined(ESP32)
             MDNS.update();
+            if(WiFi.channel() > 11)
+                mWasInCh12to14 = true;
             #endif
             return;
         case IN_AP_MODE:
diff --git a/src/wifi/ahoywifi.h b/src/wifi/ahoywifi.h
index 7fb62a20..709c08c4 100644
--- a/src/wifi/ahoywifi.h
+++ b/src/wifi/ahoywifi.h
@@ -37,6 +37,10 @@ class ahoywifi {
         }
         void setupStation(void);
 
+        bool getWasInCh12to14() const {
+            return mWasInCh12to14;
+        }
+
     private:
         typedef enum WiFiStatus {
             DISCONNECTED = 0,
@@ -86,6 +90,7 @@ class ahoywifi {
         bool mGotDisconnect;
         std::list<uint8_t> mBSSIDList;
         bool mStopApAllowed;
+        bool mWasInCh12to14 = false;
 };
 
 #endif /*__AHOYWIFI_H__*/