Skip to content

Commit

Permalink
* optimized heuristic
Browse files Browse the repository at this point in the history
* added option to reduce log size (strip frame payload to relevant field)
thx @oberfritze, @rejoe2
  • Loading branch information
lumapu committed Nov 20, 2023
1 parent bac4301 commit f417717
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 69 deletions.
6 changes: 3 additions & 3 deletions src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ void app::setup() {
DBGPRINTLN(F("false"));

if(mConfig->nrf.enabled) {
mNrfRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso);
mNrfRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso);
}
#if defined(ESP32)
if(mConfig->cmt.enabled) {
mCmtRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb, false);
mCmtRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb, false);
}
#endif
#ifdef ETHERNET
Expand All @@ -55,7 +55,7 @@ void app::setup() {
#endif
#endif /* defined(ETHERNET) */

mCommunication.setup(&mTimestamp, &mConfig->serial.debug, &mConfig->serial.privacyLog);
mCommunication.setup(&mTimestamp, &mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace);
mCommunication.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2));
mSys.setup(&mTimestamp, &mConfig->inst);
for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) {
Expand Down
9 changes: 8 additions & 1 deletion src/config/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
* https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout
* */

#define CONFIG_VERSION 2
#define CONFIG_VERSION 3


#define PROT_MASK_INDEX 0x0001
Expand Down Expand Up @@ -117,6 +117,7 @@ typedef struct {
bool showIv;
bool debug;
bool privacyLog;
bool printWholeTrace;
} cfgSerial_t;

typedef struct {
Expand Down Expand Up @@ -426,6 +427,7 @@ class settings {
mCfg.serial.showIv = false;
mCfg.serial.debug = false;
mCfg.serial.privacyLog = true;
mCfg.serial.printWholeTrace = true;

mCfg.mqtt.port = DEF_MQTT_PORT;
snprintf(mCfg.mqtt.broker, MQTT_ADDR_LEN, "%s", DEF_MQTT_BROKER);
Expand Down Expand Up @@ -476,6 +478,9 @@ class settings {
mCfg.inst.iv[i].disNightCom = false;
mCfg.inst.iv[i].add2Total = true;
}
if(mCfg.configVersion < 3) {
mCfg.serial.printWholeTrace = true;
}
}
}

Expand Down Expand Up @@ -620,10 +625,12 @@ class settings {
obj[F("show")] = mCfg.serial.showIv;
obj[F("debug")] = mCfg.serial.debug;
obj[F("prv")] = (bool) mCfg.serial.privacyLog;
obj[F("trc")] = (bool) mCfg.serial.printWholeTrace;
} else {
getVal<bool>(obj, F("show"), &mCfg.serial.showIv);
getVal<bool>(obj, F("debug"), &mCfg.serial.debug);
getVal<bool>(obj, F("prv"), &mCfg.serial.privacyLog);
getVal<bool>(obj, F("trc"), &mCfg.serial.printWholeTrace);
}
}

Expand Down
86 changes: 50 additions & 36 deletions src/hm/Communication.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,23 @@
#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 65 // timeout for single frame requests
#define MAX_BUFFER 250
#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 65 // timeout for single frame requests
#define WAIT_GAP_TIMEOUT 200 // timeout after no complete payload
#define MAX_BUFFER 250

typedef std::function<void(uint8_t, Inverter<> *)> payloadListenerType;
typedef std::function<void(Inverter<> *)> alarmListenerType;

class Communication : public CommQueue<> {
public:
void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode) {
void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode, bool *printWholeTrace) {
mTimestamp = timestamp;
mPrivacyMode = privacyMode;
mSerialDebug = serialDebug;
mPrintWholeTrace = printWholeTrace;
}

void addImportant(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) {
Expand All @@ -47,7 +49,7 @@ class Communication : public CommQueue<> {
return; // empty

uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsResend) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT;
uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT);
uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsResend)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT;

switch(mState) {
case States::RESET:
Expand All @@ -63,6 +65,7 @@ class Communication : public CommQueue<> {
mHeu.getTxCh(q->iv);
q->iv->mGotFragment = false;
q->iv->mGotLastMsg = false;
mIsResend = false;
if(NULL == q->iv->radio)
cmdDone(true); // can't communicate while radio is not defined!
mState = States::START;
Expand Down Expand Up @@ -97,7 +100,9 @@ class Communication : public CommQueue<> {

case States::WAIT:
if(millis() > mWaitTimeout_min) {
if(q->iv->mGotFragment) { // nothing received yet?
if(mIsResend) { // 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;
Expand All @@ -123,8 +128,7 @@ class Communication : public CommQueue<> {
break;

case States::CHECK_FRAMES: {
if((!q->iv->radio->get() && !mIsResend) || ((q->iv->mGotFragment) && (0 == q->attempts))) { // radio buffer empty
//cmdDone();
if((!q->iv->radio->get() && !mIsResend) || (((q->iv->mGotFragment) || (mIsResend)) && (0 == q->attempts))) { // radio buffer empty or no more answers
if(*mSerialDebug) {
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("request timeout: "));
Expand Down Expand Up @@ -153,21 +157,26 @@ class Communication : public CommQueue<> {
if(p->millis < 100)
DBGPRINT(F(" "));
DBGPRINT(String(p->millis));
DBGPRINT(F("ms "));
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));
} else {
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("frm "));
DBGHEXLN(p->packet[9]);
}
DBGPRINT(F(", "));
DBGPRINT(String(p->rssi));
DBGPRINT(F("dBm | "));
if(*mPrivacyMode)
ah::dumpBuf(p->packet, p->len, 1, 8);
else
ah::dumpBuf(p->packet, p->len);

if(checkIvSerial(&p->packet[1], q->iv)) {
if(!mHeu.getTestModeEnabled())
Expand All @@ -178,7 +187,7 @@ class Communication : public CommQueue<> {
nextState = States::CHECK_PACKAGE;
} else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command
parseDevCtrl(p, q);
cmdDone(true); // remove done request
closeRequest(q->iv, true);
} else if(IV_MI == q->iv->ivGen) {
parseMiFrame(p, q);
}
Expand All @@ -198,19 +207,20 @@ class Communication : public CommQueue<> {
if(q->iv->ivGen != IV_MI)
mState = nextState;
else {
if( q->iv->miMultiParts > 5 &&
((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))) {
if(q->iv->miMultiParts < 6) {
nextState = States::WAIT;
} else {
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);
//closeRequest(q->iv, q->iv->miMultiParts > 5);
} else if (q->iv->miMultiParts > 5)
closeRequest(q->iv, true);
else {
nextState = States::WAIT;
}
closeRequest(q->iv, true);
}

}
}

}
break;
Expand Down Expand Up @@ -240,12 +250,14 @@ class Communication : public CommQueue<> {
if(framnr) {
setAttempt();

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(*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)"));
}
sendRetransmit(q, framnr-1);
mIsResend = true;
mlastTO_min = timeout_min;
Expand Down Expand Up @@ -448,7 +460,7 @@ class Communication : public CommQueue<> {

private:
void closeRequest(Inverter<> *iv, bool succeeded = true, bool delCmd = true) {
// ordering of lines is relevant for statistics
// ordering of lines is relevant for statistics
if(succeeded) {
mHeu.setGotAll(iv);
if(!mHeu.getTestModeEnabled())
Expand All @@ -461,11 +473,13 @@ class Communication : public CommQueue<> {
if(!mHeu.getTestModeEnabled())
iv->radioStatistics.rxFailNoAnser++; // got nothing
mHeu.setGotNothing(iv);
mWaitTimeout = millis() + WAIT_GAP_TIMEOUT;
}
cmdDone(delCmd);
iv->mGotFragment = false;
iv->mGotLastMsg = false;
iv->miMultiParts = 0;
mIsResend = false;
mFirstTry = false; // for correct reset
mState = States::RESET;
}
Expand Down Expand Up @@ -788,7 +802,7 @@ class Communication : public CommQueue<> {
// update status state-machine,
if (ac_pow)
iv->isProducing();
closeRequest(iv, iv->miMultiParts > 5);
//closeRequest(iv, iv->miMultiParts > 5);

//mHeu.setGotAll(iv);
//cmdDone(true);
Expand All @@ -812,7 +826,7 @@ class Communication : public CommQueue<> {
private:
States mState = States::RESET;
uint32_t *mTimestamp;
bool *mPrivacyMode, *mSerialDebug;
bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace;
uint32_t mWaitTimeout = 0;
uint32_t mWaitTimeout_min = 0;
std::array<frame_t, MAX_PAYLOAD_ENTRIES> mLocalBuf;
Expand Down
43 changes: 27 additions & 16 deletions src/hm/Heuristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,37 @@
#define RF_MAX_CHANNEL_ID 5
#define RF_MAX_QUALITY 4
#define RF_MIN_QUALTIY -6
#define RF_NA -99

class Heuristic {
public:
uint8_t getTxCh(Inverter<> *iv) {
if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen))
return 0; // not used for these inverter types

mCycle++; // intended to overflow from time to time
if(mTestEn) {
iv->txRfChId = mCycle % RF_MAX_CHANNEL_ID;
DPRINTLN(DBG_INFO, F("heuristic test mode"));
return id2Ch(iv->txRfChId);
}

uint8_t id = 0;
uint8_t bestId = 0;
int8_t bestQuality = -6;
for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) {
if(iv->txRfQuality[i] > bestQuality) {
bestQuality = iv->txRfQuality[i];
id = i;
bestId = i;
}
}
if(bestQuality == -6)
iv->txRfChId = (iv->txRfChId + 1) % RF_MAX_CHANNEL_ID; // next channel
else
iv->txRfChId = id; // best quality channel

if(mTestEn) {
DPRINTLN(DBG_INFO, F("heuristic test mode"));
mTestIdx = (mTestIdx + 1) % RF_MAX_CHANNEL_ID;

if (mTestIdx == bestId)
mTestIdx = (mTestIdx + 1) % RF_MAX_CHANNEL_ID;

// test channel get's quality of best channel (maybe temporarily, see in 'setGotNothing')
mStoredIdx = iv->txRfQuality[mTestIdx];
iv->txRfQuality[mTestIdx] = bestQuality;

iv->txRfChId = mTestIdx;
} else
iv->txRfChId = bestId;

return id2Ch(iv->txRfChId);
}
Expand All @@ -53,10 +58,15 @@ class Heuristic {
}

void setGotNothing(Inverter<> *iv) {
if(RF_NA != mStoredIdx) {
// if communication fails on first try with temporarily good level, revert it back to its original level
iv->txRfQuality[iv->txRfChId] = mStoredIdx;
mStoredIdx = RF_NA;
}

if(!mTestEn) {
updateQuality(iv, -2); // BAD
mTestEn = true;
iv->txRfChId = mCycle % RF_MAX_CHANNEL_ID;
}
}

Expand Down Expand Up @@ -100,13 +110,14 @@ class Heuristic {
case 3: return 61;
case 4: return 75;
}
return 0; // standard
return 3; // standard
}

private:
uint8_t mChList[5] = {03, 23, 40, 61, 75};
bool mTestEn = false;
uint8_t mCycle = 0;
uint8_t mTestIdx = 0;
int8_t mStoredIdx = RF_NA;
};


Expand Down
14 changes: 9 additions & 5 deletions src/hm/hmRadio.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ class HmRadio : public Radio {
}
~HmRadio() {}

void setup(bool *serialDebug, bool *privacyMode, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) {
void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) {
DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup"));
pinMode(irq, INPUT_PULLUP);

mSerialDebug = serialDebug;
mPrivacyMode = privacyMode;
mPrintWholeTrace = printWholeTrace;

if(*mSerialDebug) {
DPRINT(DBG_VERBOSE, F("hmRadio.h : HmRadio():mNrf24(CE_PIN: "));
Expand Down Expand Up @@ -293,10 +294,13 @@ class HmRadio : public Radio {
DBGPRINT(" CH");
DBGPRINT(String(mTxChIdx));
DBGPRINT(F(" | "));
if(*mPrivacyMode)
ah::dumpBuf(mTxBuf, len, 1, 4);
else
ah::dumpBuf(mTxBuf, len);
if(*mPrintWholeTrace) {
if(*mPrivacyMode)
ah::dumpBuf(mTxBuf, len, 1, 4);
else
ah::dumpBuf(mTxBuf, len);
} else
DBGHEXLN(mTxBuf[9]);
}

mNrf24.stopListening();
Expand Down
Loading

0 comments on commit f417717

Please sign in to comment.