diff --git a/src/app.cpp b/src/app.cpp index 9cbe06a1..5570af54 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -205,8 +205,8 @@ void app::onNetwork(bool gotIp) { every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval, "tSend"); mMqttReconnect = true; mSunrise = 0; // needs to be set to 0, to reinstall sunrise and ivComm tickers! - //once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2"); - tickNtpUpdate(); + once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2"); + //tickNtpUpdate(); #if !defined(ETHERNET) if (WIFI_AP == WiFi.getMode()) { mMqttEnabled = false; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h new file mode 100644 index 00000000..3080e8df --- /dev/null +++ b/src/hm/Heuristic.h @@ -0,0 +1,147 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __HEURISTIC_H__ +#define __HEURISTIC_H__ + +#include "../utils/dbg.h" + +#define RF_MAX_CHANNEL_ID 5 +#define RF_MAX_QUALITY 4 +#define RF_MIN_QUALTIY -6 + +class Heuristic { + public: + void setup() { + uint8_t j; + for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { + mTxQuality[i] = -6; // worst + for(j = 0; j < 10; j++) { + mRxCh[i][j] = 3; + } + } + } + + /*uint8_t getRxCh(void) { + + }*/ + + uint8_t getTxCh(void) { + if(++mCycleCnt > RF_MAX_CHANNEL_ID) { + bool ok = false; + for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { + if(mTxQuality[i] > -4) { + ok = true; + mState = States::RUNNING; + } + } + if(!ok) { // restart + mCycleCnt = 0; + mState = States::TRAINING; + } + } + + if(States::TRAINING == mState) { + mTxChId = (mTxChId + 1) % RF_MAX_CHANNEL_ID; + return id2Ch(mTxChId); + } else { + int8_t bestQuality = -6; + uint8_t id = 0; + for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { + if((mCycleCnt % 50) == 0) { + if(mTxQuality[(i + mTxChId) % RF_MAX_CHANNEL_ID] != -6) { + id = i; + break; + } + + } + if(mTxQuality[(i + mTxChId) % RF_MAX_CHANNEL_ID] == 4) { + id = i; + break; + } + if(mTxQuality[i] > bestQuality) { + bestQuality = mTxQuality[i]; + id = i; + } + } + mTxChId = id; + return id2Ch(mTxChId); + } + } + + void setGotAll(void) { + updateQuality(2); // GOOD + } + + void setGotFragment(void) { + updateQuality(1); // OK + } + + void setGotNothing(void) { + updateQuality(-2); // BAD + } + + void printStatus(void) { + DPRINT(DBG_INFO, F("Status: #")); + DBGPRINT(String(mCycleCnt)); + DBGPRINT(F(" |")); + for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { + DBGPRINT(F(" ")); + DBGPRINT(String(mTxQuality[i])); + } + DBGPRINTLN(""); + } + + private: + void updateQuality(uint8_t quality) { + mTxQuality[mTxChId] += quality; + if(mTxQuality[mTxChId] > RF_MAX_QUALITY) + mTxQuality[mTxChId] = RF_MAX_QUALITY; + else if(mTxQuality[mTxChId] < RF_MIN_QUALTIY) + mTxQuality[mTxChId] = RF_MIN_QUALTIY; + } + + uint8_t ch2Id(uint8_t ch) { + switch(ch) { + case 3: return 0; + case 23: return 1; + case 40: return 2; + case 61: return 3; + case 75: return 4; + } + return 0; // standard + } + + uint8_t id2Ch(uint8_t id) { + switch(id) { + case 0: return 3; + case 1: return 23; + case 2: return 40; + case 3: return 61; + case 4: return 75; + } + return 0; // standard + } + + private: + enum class States : uint8_t { + TRAINING, RUNNING + }; + + private: + uint8_t mChList[5] = {03, 23, 40, 61, 75}; + + int8_t mTxQuality[RF_MAX_CHANNEL_ID]; + uint8_t mTxChId = 0; + + uint8_t mRxCh[RF_MAX_CHANNEL_ID][10]; + uint8_t mRxChId = 0; + + uint32_t mCycleCnt = 0; + States mState = States::TRAINING; +}; + + +#endif /*__HEURISTIC_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 3d74222d..fc4f2069 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -9,6 +9,7 @@ #include #include "SPI.h" #include "radio.h" +#include "heuristic.h" #define SPI_SPEED 1000000 @@ -76,6 +77,9 @@ class HmRadio : public Radio { mSpi = new SPIClass(); mSpi->begin(); #endif + + mHeu.setup(); + mNrf24.begin(mSpi, ce, cs); mNrf24.setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms @@ -114,6 +118,8 @@ class HmRadio : public Radio { mNrf24.flush_tx(); // empty TX FIFO // start listening + //mNrf24.setChannel(23); + //mRxChIdx = 0; mNrf24.setChannel(mRfChLst[mRxChIdx]); mNrf24.startListening(); @@ -124,8 +130,11 @@ class HmRadio : public Radio { if (mIrqRcvd) { mIrqRcvd = false; - if (getReceived()) // everything received + if (getReceived()) { // everything received + mHeu.setGotAll(); return; + } else + mHeu.setGotFragment(); } yield(); @@ -134,9 +143,15 @@ class HmRadio : public Radio { if(++mRxChIdx >= RF_CHANNELS) mRxChIdx = 0; mNrf24.setChannel(mRfChLst[mRxChIdx]); - startMicros = micros() + 5000; + startMicros = micros() + 5110; } // not finished but time is over + if(++mRxChIdx >= RF_CHANNELS) + mRxChIdx = 0; + if(mBufCtrl.empty()) + mHeu.setGotNothing(); + + mHeu.printStatus(); return; } @@ -275,21 +290,20 @@ class HmRadio : public Radio { updateCrcs(&len, appendCrc16); // set TX and RX channels - mTxChIdx = (mTxChIdx + 1) % RF_CHANNELS; - mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; + mTxChIdx = mHeu.getTxCh(); if(mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("TX ")); DBGPRINT(String(len)); DBGPRINT(" CH"); - DBGPRINT(String(mRfChLst[mTxChIdx])); + DBGPRINT(String(mTxChIdx)); DBGPRINT(F(" | ")); ah::dumpBuf(mTxBuf, len); } mNrf24.stopListening(); - mNrf24.setChannel(mRfChLst[mTxChIdx]); + mNrf24.setChannel(mTxChIdx); mNrf24.openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response mMillis = millis(); @@ -311,6 +325,7 @@ class HmRadio : public Radio { SPIClass* mSpi; RF24 mNrf24; + Heuristic mHeu; }; #endif /*__HM_RADIO_H__*/