mirror of
https://github.com/lumapu/ahoy.git
synced 2025-07-27 05:07:18 +02:00
0.8.6
* merged PR #1225 * improved heuristics (prevent update of statitistic during testing)
This commit is contained in:
parent
e8dbe02e4f
commit
a82777b2a1
5 changed files with 77 additions and 31 deletions
|
@ -1,5 +1,9 @@
|
||||||
# Development Changes
|
# Development Changes
|
||||||
|
|
||||||
|
## 0.8.6 - 2023-11-12
|
||||||
|
* merged PR #1225
|
||||||
|
* improved heuristics (prevent update of statitistic during testing)
|
||||||
|
|
||||||
## 0.8.5 - 2023-11-12
|
## 0.8.5 - 2023-11-12
|
||||||
* fixed endless loop while switching CMT frequency
|
* fixed endless loop while switching CMT frequency
|
||||||
* removed obsolete "retries" field from settings #1224
|
* removed obsolete "retries" field from settings #1224
|
||||||
|
|
|
@ -44,6 +44,7 @@ class Communication : public CommQueue<> {
|
||||||
return; // empty
|
return; // empty
|
||||||
|
|
||||||
uint16_t timeout = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT;
|
uint16_t timeout = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT;
|
||||||
|
bool testMode = false;
|
||||||
|
|
||||||
switch(mState) {
|
switch(mState) {
|
||||||
case States::RESET:
|
case States::RESET:
|
||||||
|
@ -56,6 +57,7 @@ class Communication : public CommQueue<> {
|
||||||
|
|
||||||
mHeu.printStatus(q->iv);
|
mHeu.printStatus(q->iv);
|
||||||
mHeu.getTxCh(q->iv);
|
mHeu.getTxCh(q->iv);
|
||||||
|
testMode = mHeu.getTestModeEnabled();
|
||||||
mGotFragment = false;
|
mGotFragment = false;
|
||||||
mFirstTry = mFirstTry ? false : ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()); //) || (millis() < 120000));}
|
mFirstTry = mFirstTry ? false : ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()); //) || (millis() < 120000));}
|
||||||
if(NULL == q->iv->radio)
|
if(NULL == q->iv->radio)
|
||||||
|
@ -79,7 +81,8 @@ class Communication : public CommQueue<> {
|
||||||
q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false);
|
q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false);
|
||||||
} else
|
} else
|
||||||
q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false);
|
q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false);
|
||||||
q->iv->radioStatistics.txCnt++;
|
if(!testMode)
|
||||||
|
q->iv->radioStatistics.txCnt++;
|
||||||
mWaitTimeout = millis() + timeout;
|
mWaitTimeout = millis() + timeout;
|
||||||
setAttempt();
|
setAttempt();
|
||||||
mState = States::WAIT;
|
mState = States::WAIT;
|
||||||
|
@ -100,14 +103,17 @@ class Communication : public CommQueue<> {
|
||||||
DBGPRINTLN(F("ms"));
|
DBGPRINTLN(F("ms"));
|
||||||
|
|
||||||
if(!mGotFragment && !mFirstTry) {
|
if(!mGotFragment && !mFirstTry) {
|
||||||
q->iv->radioStatistics.rxFailNoAnser++; // got nothing
|
if(!testMode)
|
||||||
|
q->iv->radioStatistics.rxFailNoAnser++; // got nothing
|
||||||
mHeu.setGotNothing(q->iv);
|
mHeu.setGotNothing(q->iv);
|
||||||
if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) {
|
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));
|
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;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
q->iv->radioStatistics.rxFail++;
|
if(!testMode)
|
||||||
|
q->iv->radioStatistics.rxFail++;
|
||||||
|
}
|
||||||
mState = States::RESET;
|
mState = States::RESET;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +143,8 @@ class Communication : public CommQueue<> {
|
||||||
ah::dumpBuf(p->packet, p->len);
|
ah::dumpBuf(p->packet, p->len);
|
||||||
|
|
||||||
if(checkIvSerial(&p->packet[1], q->iv)) {
|
if(checkIvSerial(&p->packet[1], q->iv)) {
|
||||||
q->iv->radioStatistics.frmCnt++;
|
if(!testMode)
|
||||||
|
q->iv->radioStatistics.frmCnt++;
|
||||||
|
|
||||||
if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command
|
if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command
|
||||||
parseFrame(p);
|
parseFrame(p);
|
||||||
|
@ -149,7 +156,8 @@ class Communication : public CommQueue<> {
|
||||||
parseMiFrame(p, q);
|
parseMiFrame(p, q);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
q->iv->radioStatistics.rxFail++; // got no complete payload
|
if(!testMode)
|
||||||
|
q->iv->radioStatistics.rxFail++; // got no complete payload
|
||||||
DPRINTLN(DBG_WARN, F("Inverter serial does not match"));
|
DPRINTLN(DBG_WARN, F("Inverter serial does not match"));
|
||||||
mWaitTimeout = millis() + timeout;
|
mWaitTimeout = millis() + timeout;
|
||||||
}
|
}
|
||||||
|
@ -158,8 +166,9 @@ class Communication : public CommQueue<> {
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
if(0 == q->attempts) {
|
if(0 == q->attempts) {
|
||||||
|
if(!testMode)
|
||||||
|
q->iv->radioStatistics.rxFail++; // got no complete payload
|
||||||
mHeu.setGotFragment(q->iv);
|
mHeu.setGotFragment(q->iv);
|
||||||
q->iv->radioStatistics.rxFail++; // got no complete payload
|
|
||||||
cmdDone(true);
|
cmdDone(true);
|
||||||
mState = States::RESET;
|
mState = States::RESET;
|
||||||
} else
|
} else
|
||||||
|
@ -205,7 +214,7 @@ class Communication : public CommQueue<> {
|
||||||
}
|
}
|
||||||
|
|
||||||
mHeu.setGotAll(q->iv);
|
mHeu.setGotAll(q->iv);
|
||||||
compilePayload(q);
|
compilePayload(q, testMode);
|
||||||
|
|
||||||
if(NULL != mCbPayload)
|
if(NULL != mCbPayload)
|
||||||
(mCbPayload)(q->cmd, q->iv);
|
(mCbPayload)(q->cmd, q->iv);
|
||||||
|
@ -295,7 +304,7 @@ class Communication : public CommQueue<> {
|
||||||
q->iv->actPowerLimit = 0xffff; // unknown, readback current value
|
q->iv->actPowerLimit = 0xffff; // unknown, readback current value
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void compilePayload(const queue_s *q) {
|
inline void compilePayload(const queue_s *q, bool testMode) {
|
||||||
uint16_t crc = 0xffff, crcRcv = 0x0000;
|
uint16_t crc = 0xffff, crcRcv = 0x0000;
|
||||||
for(uint8_t i = 0; i < mMaxFrameId; i++) {
|
for(uint8_t i = 0; i < mMaxFrameId; i++) {
|
||||||
if(i == (mMaxFrameId - 1)) {
|
if(i == (mMaxFrameId - 1)) {
|
||||||
|
@ -311,7 +320,8 @@ class Communication : public CommQueue<> {
|
||||||
DBGPRINT(F("CRC Error "));
|
DBGPRINT(F("CRC Error "));
|
||||||
if(q->attempts == 0) {
|
if(q->attempts == 0) {
|
||||||
DBGPRINTLN(F("-> Fail"));
|
DBGPRINTLN(F("-> Fail"));
|
||||||
q->iv->radioStatistics.rxFail++; // got fragments but not complete response
|
if(!testMode)
|
||||||
|
q->iv->radioStatistics.rxFail++; // got fragments but not complete response
|
||||||
cmdDone();
|
cmdDone();
|
||||||
} else
|
} else
|
||||||
DBGPRINTLN(F("-> complete retransmit"));
|
DBGPRINTLN(F("-> complete retransmit"));
|
||||||
|
@ -356,11 +366,13 @@ class Communication : public CommQueue<> {
|
||||||
DPRINT(DBG_ERROR, F("plausibility check failed, expected "));
|
DPRINT(DBG_ERROR, F("plausibility check failed, expected "));
|
||||||
DBGPRINT(String(rec->pyldLen));
|
DBGPRINT(String(rec->pyldLen));
|
||||||
DBGPRINTLN(F(" bytes"));
|
DBGPRINTLN(F(" bytes"));
|
||||||
q->iv->radioStatistics.rxFail++;
|
if(!testMode)
|
||||||
|
q->iv->radioStatistics.rxFail++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
q->iv->radioStatistics.rxSuccess++;
|
if(!testMode)
|
||||||
|
q->iv->radioStatistics.rxSuccess++;
|
||||||
|
|
||||||
rec->ts = q->ts;
|
rec->ts = q->ts;
|
||||||
for (uint8_t i = 0; i < rec->length; i++) {
|
for (uint8_t i = 0; i < rec->length; i++) {
|
||||||
|
|
|
@ -19,6 +19,13 @@ class Heuristic {
|
||||||
if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen))
|
if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen))
|
||||||
return 0; // not used for these inverter types
|
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 id = 0;
|
||||||
int8_t bestQuality = -6;
|
int8_t bestQuality = -6;
|
||||||
for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) {
|
for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) {
|
||||||
|
@ -37,14 +44,20 @@ class Heuristic {
|
||||||
|
|
||||||
void setGotAll(Inverter<> *iv) {
|
void setGotAll(Inverter<> *iv) {
|
||||||
updateQuality(iv, 2); // GOOD
|
updateQuality(iv, 2); // GOOD
|
||||||
|
mTestEn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setGotFragment(Inverter<> *iv) {
|
void setGotFragment(Inverter<> *iv) {
|
||||||
updateQuality(iv, 1); // OK
|
updateQuality(iv, 1); // OK
|
||||||
|
mTestEn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setGotNothing(Inverter<> *iv) {
|
void setGotNothing(Inverter<> *iv) {
|
||||||
updateQuality(iv, -2); // BAD
|
if(!mTestEn) {
|
||||||
|
updateQuality(iv, -2); // BAD
|
||||||
|
mTestEn = true;
|
||||||
|
iv->txRfChId = (iv->txRfChId + 1) % RF_MAX_CHANNEL_ID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printStatus(Inverter<> *iv) {
|
void printStatus(Inverter<> *iv) {
|
||||||
|
@ -54,7 +67,18 @@ class Heuristic {
|
||||||
DBGPRINT(F(" "));
|
DBGPRINT(F(" "));
|
||||||
DBGPRINT(String(iv->txRfQuality[i]));
|
DBGPRINT(String(iv->txRfQuality[i]));
|
||||||
}
|
}
|
||||||
DBGPRINTLN("");
|
DBGPRINT(F(" | t: "));
|
||||||
|
DBGPRINT(String(iv->radioStatistics.txCnt));
|
||||||
|
DBGPRINT(F(", s: "));
|
||||||
|
DBGPRINT(String(iv->radioStatistics.rxSuccess));
|
||||||
|
DBGPRINT(F(", f: "));
|
||||||
|
DBGPRINT(String(iv->radioStatistics.rxFail));
|
||||||
|
DBGPRINT(F(", n: "));
|
||||||
|
DBGPRINTLN(String(iv->radioStatistics.rxFailNoAnser));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getTestModeEnabled(void) {
|
||||||
|
return mTestEn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -66,17 +90,6 @@ class Heuristic {
|
||||||
iv->txRfQuality[iv->txRfChId] = RF_MIN_QUALTIY;
|
iv->txRfQuality[iv->txRfChId] = 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
|
|
||||||
}*/
|
|
||||||
|
|
||||||
inline uint8_t id2Ch(uint8_t id) {
|
inline uint8_t id2Ch(uint8_t id) {
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case 0: return 3;
|
case 0: return 3;
|
||||||
|
@ -90,6 +103,8 @@ class Heuristic {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t mChList[5] = {03, 23, 40, 61, 75};
|
uint8_t mChList[5] = {03, 23, 40, 61, 75};
|
||||||
|
bool mTestEn = false;
|
||||||
|
uint8_t mCycle = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,19 @@ function tr(val1, val2) {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function tr2(cols) {
|
||||||
|
var t = [];
|
||||||
|
for(val of cols) {
|
||||||
|
if(typeof val == "number")
|
||||||
|
val = String(val);
|
||||||
|
if(t.length == 0)
|
||||||
|
t.push(ml("th", {}, val));
|
||||||
|
else
|
||||||
|
t.push(ml("td", {}, val));
|
||||||
|
}
|
||||||
|
return ml("tr", {}, t);
|
||||||
|
}
|
||||||
|
|
||||||
function badge(success, text, second="error") {
|
function badge(success, text, second="error") {
|
||||||
return ml("span", {class: "badge badge-" + ((success) ? "success" : second)}, text);
|
return ml("span", {class: "badge badge-" + ((success) ? "success" : second)}, text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -296,15 +296,17 @@
|
||||||
modal("Info for inverter " + obj.name, ml("div", {}, html));
|
modal("Info for inverter " + obj.name, ml("div", {}, html));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function parseIvRadioStats(obj) {
|
function parseIvRadioStats(obj) {
|
||||||
var html = ml("table", {class: "table"}, [
|
var html = ml("table", {class: "table"}, [
|
||||||
ml("tbody", {}, [
|
ml("tbody", {}, [
|
||||||
tr("TX count", obj.tx_cnt),
|
tr2(["TX count", obj.tx_cnt, ""]),
|
||||||
tr("RX success", obj.rx_success),
|
tr2(["RX success", obj.rx_success, String(Math.round(obj.rx_success / obj.tx_cnt * 10000) / 100) + "%"]),
|
||||||
tr("RX fail", obj.rx_fail),
|
tr2(["RX fail", obj.rx_fail, String(Math.round(obj.rx_fail / obj.tx_cnt * 10000) / 100) + "%"]),
|
||||||
tr("RX no answer", obj.rx_fail_answer),
|
tr2(["RX no answer", obj.rx_fail_answer, String(Math.round(obj.rx_fail_answer / obj.tx_cnt * 10000) / 100) + "%"]),
|
||||||
tr("RX fragments", obj.frame_cnt),
|
tr2(["RX fragments", obj.frame_cnt, ""]),
|
||||||
tr("TX retransmits", obj.retransmits)
|
tr2(["TX retransmits", obj.retransmits, ""])
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
modal("Radio statistics for inverter " + obj.name, ml("div", {}, html));
|
modal("Radio statistics for inverter " + obj.name, ml("div", {}, html));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue