Browse Source

Merge branch 'rejoe2-dynamic-retries-offset' into development03

pull/1402/head
lumapu 8 months ago
parent
commit
ac58f2f078
  1. 4
      src/hm/CommQueue.h
  2. 77
      src/hm/Communication.h
  3. 48
      src/hm/Heuristic.h
  4. 3
      src/hm/HeuristicInv.h
  5. 10
      src/hm/hmDefines.h
  6. 56
      src/hm/hmInverter.h
  7. 59
      src/hm/hmRadio.h
  8. 7
      src/hm/hmSystem.h
  9. 4
      src/hm/radio.h
  10. 6
      src/hms/hmsRadio.h

4
src/hm/CommQueue.h

@ -12,8 +12,8 @@
#include "../utils/dbg.h"
#define DEFAULT_ATTEMPS 5
#define MORE_ATTEMPS_ALARMDATA 8
#define MORE_ATTEMPS_GRIDONPROFILEPARA 5
#define MORE_ATTEMPS_ALARMDATA 3 // 8
#define MORE_ATTEMPS_GRIDONPROFILEPARA 0 // 5
template <uint8_t N=100>
class CommQueue {

77
src/hm/Communication.h

@ -83,10 +83,11 @@ class Communication : public CommQueue<> {
q->iv->mGotFragment = false;
q->iv->mGotLastMsg = false;
q->iv->curFrmCnt = 0;
q->iv->radioStatistics.txCnt++;
mIsRetransmit = false;
if(NULL == q->iv->radio)
cmdDone(false); // can't communicate while radio is not defined!
mFirstTry = q->iv->isAvailable();
mFirstTry = INV_RADIO_TYPE_NRF == q->iv->ivRadioType && q->iv->isAvailable();
q->iv->mCmd = q->cmd;
q->iv->mIsSingleframeReq = false;
mFramesExpected = getFramesExpected(q); // function to get expected frame count.
@ -112,13 +113,13 @@ class Communication : public CommQueue<> {
} else
q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false);
q->iv->radioStatistics.txCnt++;
//q->iv->radioStatistics.txCnt++;
q->iv->radio->mRadioWaitTime.startTimeMonitor(mTimeout);
if(!mIsRetransmit && (q->cmd == AlarmData) || (q->cmd == GridOnProFilePara))
incrAttempt(q->cmd == AlarmData? MORE_ATTEMPS_ALARMDATA : MORE_ATTEMPS_GRIDONPROFILEPARA);
mIsRetransmit = false;
setAttempt();
if((q->cmd == AlarmData) || (q->cmd == GridOnProFilePara))
incrAttempt(q->cmd == AlarmData? MORE_ATTEMPS_ALARMDATA : MORE_ATTEMPS_GRIDONPROFILEPARA);
mState = States::WAIT;
break;
@ -129,13 +130,14 @@ class Communication : public CommQueue<> {
break;
case States::CHECK_FRAMES: {
if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) || (0 == q->attempts)) { // radio buffer empty or no more answers
if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) ) { // || (0 == q->attempts)) { // radio buffer empty. No more answers will be checked later
if(*mSerialDebug) {
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("request timeout: "));
DBGPRINT(String(q->iv->radio->mRadioWaitTime.getRunTime()));
DBGPRINTLN(F("ms"));
}
if(!q->iv->mGotFragment) {
if(INV_RADIO_TYPE_CMT == q->iv->ivRadioType) {
#if defined(ESP32)
@ -146,18 +148,20 @@ class Communication : public CommQueue<> {
mWaitTime.startTimeMonitor(1000);
#endif
} else {
mHeu.setIvRetriesBad(q->iv);
if(IV_MI == q->iv->ivGen)
q->iv->mIvTxCnt++;
if(mFirstTry) {
mFirstTry = false;
setAttempt();
if(q->attempts < 3 || !q->iv->isProducing())
mFirstTry = false;
mHeu.evalTxChQuality(q->iv, false, 0, 0);
q->iv->radioStatistics.rxFailNoAnser++;
mHeu.getTxCh(q->iv);
//q->iv->radioStatistics.rxFailNoAnser++; // should only be one of fail or retransmit.
//q->iv->radioStatistics.txCnt--;
q->iv->radioStatistics.retransmits++;
q->iv->radio->mRadioWaitTime.stopTimeMonitor();
mState = States::START;
return;
}
}
@ -178,8 +182,11 @@ class Communication : public CommQueue<> {
q->iv->mDtuRxCnt++;
if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command
if(parseFrame(p))
if(parseFrame(p)) {
q->iv->curFrmCnt++;
if(!mIsRetransmit && (p->packet[9] == 0x02 || p->packet[9] == 0x82) && p->millis < LIMIT_FAST_IV)
mHeu.setIvRetriesGood(q->iv,p->millis < LIMIT_VERYFAST_IV);
}
} else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command
if(parseDevCtrl(p, q))
closeRequest(q, true);
@ -200,7 +207,6 @@ class Communication : public CommQueue<> {
if(q->iv->ivGen != IV_MI) {
mState = States::CHECK_PACKAGE;
} else {
bool fastNext = true;
if(q->iv->miMultiParts < 6) {
mState = States::WAIT;
if((q->iv->radio->mRadioWaitTime.isTimeout() && mIsRetransmit) || !mIsRetransmit) {
@ -213,12 +219,8 @@ class Communication : public CommQueue<> {
|| ((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);
closeRequest(q, true);
}
}
@ -250,10 +252,33 @@ class Communication : public CommQueue<> {
if(framnr) {
if(0 == q->attempts) {
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("no attempts left"));
DBGPRINTLN(F("timeout, no attempts left"));
closeRequest(q, false);
return;
}
//count missing frames
if(!q->iv->mIsSingleframeReq && q->iv->ivRadioType == INV_RADIO_TYPE_NRF) { // already checked?
uint8_t missedFrames = 0;
for(uint8_t i = 0; i < q->iv->radio->mFramesExpected; i++) {
if(mLocalBuf[i].len == 0)
missedFrames++;
}
if(missedFrames > 3 || (q->cmd == RealTimeRunData_Debug && missedFrames > 1) || (missedFrames > 1 && missedFrames + 2 > q->attempts)) {
if(*mSerialDebug) {
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(String(missedFrames));
DBGPRINT(F(" frames missing "));
DBGPRINTLN(F("-> complete retransmit"));
}
mHeu.evalTxChQuality(q->iv, false, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt);
q->iv->radioStatistics.txCnt--;
q->iv->radioStatistics.retransmits++;
mCompleteRetry = true;
mState = States::RESET;
return;
}
}
setAttempt();
if(*mSerialDebug) {
@ -410,6 +435,8 @@ class Communication : public CommQueue<> {
}
inline bool parseMiFrame(packet_t *p, const queue_s *q) {
if(!mIsRetransmit && p->packet[9] == 0x00 && p->millis < LIMIT_FAST_IV_MI) //first frame is fast?
mHeu.setIvRetriesGood(q->iv,p->millis < LIMIT_VERYFAST_IV_MI);
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))
@ -429,7 +456,6 @@ class Communication : public CommQueue<> {
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;
@ -493,6 +519,7 @@ class Communication : public CommQueue<> {
} else
DBGPRINTLN(F("-> complete retransmit"));
mCompleteRetry = true;
mState = States::RESET;
return;
}
@ -592,7 +619,7 @@ class Communication : public CommQueue<> {
mHeu.evalTxChQuality(q->iv, crcPass, (q->attemptsMax - 1 - q->attempts), q->iv->curFrmCnt);
if(crcPass)
q->iv->radioStatistics.rxSuccess++;
else if(q->iv->mGotFragment)
else if(q->iv->mGotFragment || mCompleteRetry)
q->iv->radioStatistics.rxFail++; // got no complete payload
else
q->iv->radioStatistics.rxFailNoAnser++; // got nothing
@ -607,6 +634,7 @@ class Communication : public CommQueue<> {
q->iv->mGotLastMsg = false;
q->iv->miMultiParts = 0;
mIsRetransmit = false;
mCompleteRetry = false;
mState = States::RESET;
DBGPRINTLN(F("-----"));
}
@ -820,8 +848,9 @@ class Communication : public CommQueue<> {
DBGHEXLN(cmd);
}
if(q->iv->miMultiParts == 7)
q->iv->radioStatistics.rxSuccess++;
/*if(q->iv->miMultiParts > 5) //if(q->iv->miMultiParts == 7)
q->iv->radioStatistics.rxSuccess++;*/
q->iv->radioStatistics.ivSent++;
mFramesExpected = getFramesExpected(q);
q->iv->radio->setExpectedFrames(mFramesExpected);
@ -846,6 +875,7 @@ class Communication : public CommQueue<> {
}
q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true);
q->iv->radioStatistics.retransmits++;
q->iv->radio->mRadioWaitTime.startTimeMonitor(DURATION_TXFRAME + DURATION_ONEFRAME + duration_reserve[q->iv->ivRadioType]);
mIsRetransmit = false;
@ -999,8 +1029,9 @@ class Communication : public CommQueue<> {
uint16_t *mInverterGap;
TimeMonitor mWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state)
std::array<frame_t, MAX_PAYLOAD_ENTRIES> mLocalBuf;
bool mFirstTry = false; // see, if we should do a second try
bool mIsRetransmit = false; // we already had waited one complete cycle
bool mFirstTry = false; // see, if we should do a second try
bool mCompleteRetry = false; // remember if we did request a complete retransmission
bool mIsRetransmit = false; // we already had waited one complete cycle
uint8_t mMaxFrameId;
uint8_t mFramesExpected = 12; // 0x8c was highest last frame for alarm data
uint16_t mTimeout = 0; // calculating that once should be ok

48
src/hm/Heuristic.h

@ -23,8 +23,8 @@
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
if(iv->ivRadioType != INV_RADIO_TYPE_NRF)
return 0; // not used for other than nRF inverter types
HeuristicInv *ih = &iv->heuristics;
@ -66,6 +66,8 @@ class Heuristic {
ih->testPeriodFailCnt = 0;
}
iv->radio->mTxRetriesNext = getIvRetries(iv);
return id2Ch(ih->txRfChId);
}
@ -155,6 +157,48 @@ class Heuristic {
DBGPRINTLN(String(iv->config->powerLevel));
}
uint8_t getIvRetries(Inverter<> *iv) {
if(iv->heuristics.rxSpeeds[0])
return RETRIES_VERYFAST_IV;
if(iv->heuristics.rxSpeeds[1])
return RETRIES_FAST_IV;
return 15;
}
void setIvRetriesGood(Inverter<> *iv, bool veryGood) {
if(iv->ivRadioType != INV_RADIO_TYPE_NRF)
return; // not used for other than nRF inverter types
if(iv->heuristics.rxSpeedCnt[veryGood] > 9)
return;
iv->heuristics.rxSpeedCnt[veryGood]++;
iv->heuristics.rxSpeeds[veryGood] = true;
}
void setIvRetriesBad(Inverter<> *iv) {
if(iv->ivRadioType != INV_RADIO_TYPE_NRF)
return; // not used for other than nRF inverter types
if(iv->heuristics.rxSpeedCnt[0]) {
iv->heuristics.rxSpeedCnt[0]--;
return;
}
if(iv->heuristics.rxSpeeds[0]) {
iv->heuristics.rxSpeeds[0] = false;
return;
}
if(iv->heuristics.rxSpeedCnt[1]) {
iv->heuristics.rxSpeedCnt[1]--;
return;
}
if(iv->heuristics.rxSpeeds[1]) {
iv->heuristics.rxSpeeds[1] = false;
return;
}
return;
}
private:
bool isNewTxCh(HeuristicInv *ih) {
return ih->txRfChId != ih->lastBestTxChId;

3
src/hm/HeuristicInv.h

@ -42,6 +42,9 @@ class HeuristicInv {
uint8_t testChId = 0;
int8_t saveOldTestQuality = -6;
uint8_t lastRxFragments = 0;
bool rxSpeeds[2] = {false,false}; // is inverter responding very fast respective fast?
uint8_t rxSpeedCnt[2] = {0,0}; // count how many messages had been received very fast respective fast (10 max)
};
#endif /*__HEURISTIC_INV_H__*/

10
src/hm/hmDefines.h

@ -84,7 +84,15 @@ enum {INV_RADIO_TYPE_NRF = 0, INV_RADIO_TYPE_CMT};
#define DURATION_TXFRAME 85 // timeout parameter for first transmission and first expected frame (time to first channel switch from tx start!) (ms)
#define DURATION_LISTEN_MIN 5 // time to stay at least on a listening channel (ms)
#define DURATION_PAUSE_LASTFR 45 // how long to pause after last frame (ms)
const uint8_t duration_reserve[2] = {115,115};
const uint8_t duration_reserve[2] = {65,115};
#define LIMIT_FAST_IV 85 // time limit to qualify an inverter as very fast answering inverter
#define LIMIT_VERYFAST_IV 70 // time limit to qualify an inverter as very fast answering inverter
#define LIMIT_FAST_IV_MI 35 // time limit to qualify a MI type inverter as fast answering inverter
#define LIMIT_VERYFAST_IV_MI 22 // time limit to qualify a MI type inverter as very fast answering inverter
#define RETRIES_FAST_IV 12 // how often shall a message be automatically retransmitted by the nRF (fast answering inverter)
#define RETRIES_VERYFAST_IV 9 // how often shall a message be automatically retransmitted by the nRF (very fast answering inverter)
typedef struct {
uint8_t fieldId; // field id

56
src/hm/hmInverter.h

@ -133,6 +133,7 @@ class Inverter {
bool isConnected; // shows if inverter was successfully identified (fw version and hardware info)
InverterStatus status; // indicates the current inverter status
std::array<alarm_t, 10> lastAlarm; // holds last 10 alarms
uint8_t rxOffset; // holds the default channel offset between tx and rx channel (nRF only)
int8_t rssi; // RSSI
uint16_t alarmCnt; // counts the total number of occurred alarms
uint16_t alarmLastId; // lastId which was received
@ -193,27 +194,33 @@ class Inverter {
cb(RealTimeRunData_Debug, false); // get live data
else {
if(INV_RADIO_TYPE_NRF == ivRadioType) {
// get live data until quility reaches maximum
// get live data until quality reaches maximum
if(!heuristics.isTxAtMax()) {
cb(RealTimeRunData_Debug, false); // get live data
return;
}
}
if(actPowerLimit == 0xffff)
if(actPowerLimit == 0xffff) {
cb(SystemConfigPara, false); // power limit info
else if(InitDataState != devControlCmd) {
cb(RealTimeRunData_Debug, false);
} else if(InitDataState != devControlCmd) {
cb(devControlCmd, false); // custom command which was received by API
devControlCmd = InitDataState;
mGetLossInterval = 1;
} else if(0 == getFwVersion())
} else if(0 == getFwVersion()) {
cb(InverterDevInform_All, false); // get firmware version
else if(0 == getHwVersion())
cb(RealTimeRunData_Debug, false); // get live data
}
else if(0 == getHwVersion()) {
cb(InverterDevInform_Simple, false); // get hardware version
else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0))
cb(RealTimeRunData_Debug, false); // get live data
} else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) {
cb(AlarmData, false); // get last alarms
else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile
cb(RealTimeRunData_Debug, false); // get live data
} else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile
cb(GridOnProFilePara, false);
cb(RealTimeRunData_Debug, false); // get live data
} else if (mGetLossInterval > AHOY_GET_LOSS_INTERVAL) { // get loss rate
mGetLossInterval = 1;
cb(RealTimeRunData_Debug, false); // get live data
@ -222,21 +229,21 @@ class Inverter {
cb(RealTimeRunData_Debug, false); // get live data
}
} else { // MI
if(0 == getFwVersion()) {
mIvRxCnt +=2;
cb(0x0f, false); // get firmware version; for MI, this makes part of polling the device software and hardware version number
} else {
record_t<> *rec = getRecordStruct(InverterDevInform_Simple);
if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) {
cb(0x0f, false); // hard- and firmware version for missing HW part nr, delivered by frame 1
cb(((type == INV_TYPE_4CH) ? MI_REQ_4CH : MI_REQ_CH1), false);
mGetLossInterval++;
if (type != INV_TYPE_4CH)
mIvRxCnt++; // statistics workaround...
if(isAvailable()) {
if(0 == getFwVersion()) {
mIvRxCnt +=2;
} else if((getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec) == 0) && generalConfig->readGrid) // read grid profile
cb(0x10, false); // legacy GPF command
else {
cb(((type == INV_TYPE_4CH) ? MI_REQ_4CH : MI_REQ_CH1), false);
mGetLossInterval++;
if (type != INV_TYPE_4CH)
mIvRxCnt++; // statistics workaround...
cb(0x0f, false); // get firmware version; for MI, this makes part of polling the device software and hardware version number
} else {
record_t<> *rec = getRecordStruct(InverterDevInform_Simple);
if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) {
cb(0x0f, false); // hard- and firmware version for missing HW part nr, delivered by frame 1
mIvRxCnt +=2;
} else if((getChannelFieldValue(CH0, FLD_GRID_PROFILE_CODE, rec) == 0) && generalConfig->readGrid) // read grid profile
cb(0x10, false); // legacy GPF command
}
}
}
@ -457,7 +464,12 @@ class Inverter {
status = InverterStatus::OFF;
actPowerLimit = 0xffff; // power limit will be read once inverter becomes available
alarmMesIndex = 0;
heuristics.clear();
if(ivRadioType == INV_RADIO_TYPE_NRF) {
heuristics.clear();
#ifdef DYNAMIC_OFFSET
rxOffset = ivGen == IV_HM ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting
#endif
}
}
else
status = InverterStatus::WAS_ON;

59
src/hm/hmRadio.h

@ -112,16 +112,16 @@ class HmRadio : public Radio {
if (mRadioWaitTime.isTimeout()) { // timeout reached!
mNRFisInRX = false;
rx_ready = false;
return false;
}
// otherwise switch to next RX channel
mTimeslotStart = millis();
if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME+DURATION_ONEFRAME)))
if(!mNRFloopChannels && ((mTimeslotStart - mLastIrqTime) > (DURATION_TXFRAME))) //(DURATION_TXFRAME+DURATION_ONEFRAME)))
mNRFloopChannels = true;
mRxPendular = !mRxPendular;
//innerLoopTimeout = (mRxPendular ? 1 : 2)*DURATION_LISTEN_MIN;
innerLoopTimeout = DURATION_LISTEN_MIN;
if(mNRFloopChannels)
@ -152,20 +152,28 @@ class HmRadio : public Radio {
if(tx_ok)
mLastIv->mAckCount++;
//#ifdef DYNAMIC_OFFSET
mRxChIdx = (mTxChIdx + mLastIv->rxOffset) % RF_CHANNELS;
/*#else
mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS;
#endif*/
mNrf24->setChannel(mRfChLst[mRxChIdx]);
mNrf24->startListening();
mTimeslotStart = millis();
tempRxChIdx = mRxChIdx;
tempRxChIdx = mRxChIdx; // might be better to start off with one channel less?
mRxPendular = false;
mNRFloopChannels = (mLastIv->ivGen == IV_MI);
innerLoopTimeout = DURATION_TXFRAME;
//innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_TXFRAME : DURATION_ONEFRAME;
//innerLoopTimeout = mLastIv->ivGen != IV_MI ? DURATION_LISTEN_MIN : 4;
//innerLoopTimeout = (mLastIv->mIsSingleframeReq || mLastIv->ivGen == IV_MI) ? DURATION_LISTEN_MIN : DURATION_TXFRAME;
innerLoopTimeout = DURATION_LISTEN_MIN;
}
if(rx_ready) {
if (getReceived()) { // check what we got, returns true for last package
if (getReceived()) { // check what we got, returns true for last package or success for single frame request
mNRFisInRX = false;
rx_ready = false;
mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first end his transmissions
mNrf24->stopListening();
return false;
@ -173,7 +181,6 @@ class HmRadio : public Radio {
innerLoopTimeout = DURATION_LISTEN_MIN;
mTimeslotStart = millis();
if (!mNRFloopChannels) {
//mRxPendular = true; // stay longer on the next rx channel
if (isRxInit) {
isRxInit = false;
tempRxChIdx = (mRxChIdx + 4) % RF_CHANNELS;
@ -183,6 +190,8 @@ class HmRadio : public Radio {
}
return true;
}
rx_ready = false; // reset
return mNRFisInRX;
}
}
@ -292,6 +301,7 @@ class HmRadio : public Radio {
private:
inline bool getReceived(void) {
bool isLastPackage = false;
bool isRetransmitAnswer = false;
rx_ready = false; // reset for ACK case
while(mNrf24->available()) {
@ -314,14 +324,31 @@ class HmRadio : public Radio {
mLastIv->mGotFragment = true;
mBufCtrl.push(p);
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
isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received
if(mLastIv->mIsSingleframeReq) // we only expect one frame here...
isRetransmitAnswer = true;
if(isLastPackage)
setExpectedFrames(p.packet[9] - ALL_FRAMES);
#ifdef DYNAMIC_OFFSET
if(p.packet[9] == 1 && p.millis < DURATION_ONEFRAME)
mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + 1) % RF_CHANNELS;
else if(mNRFloopChannels && mLastIv->rxOffset > RF_CHANNELS) { // unsure setting?
mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx + (isLastPackage ? mFramesExpected : p.packet[9])); // make clear it's not sure, start with one more offset
mNRFloopChannels = false;
}
#endif
}
if(IV_MI == mLastIv->ivGen) {
if (p.packet[0] == (0x0f + ALL_FRAMES)) // response from MI get information command
isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received
else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 &&
isLastPackage = true; // response from dev control command
#ifdef DYNAMIC_OFFSET
if(p.packet[9] == 0x00 && p.millis < DURATION_ONEFRAME)
mLastIv->rxOffset = (RF_CHANNELS + mTxChIdx - tempRxChIdx - 1) % RF_CHANNELS;
#endif
}
rx_ready = true; //reset in case we first read messages from other inverter or ACK zero payloads
}
@ -331,7 +358,7 @@ class HmRadio : public Radio {
}
if(isLastPackage)
mLastIv->mGotLastMsg = true;
return isLastPackage;
return isLastPackage || isRetransmitAnswer;
}
void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) {
@ -352,8 +379,19 @@ class HmRadio : public Radio {
DBGPRINT(F("TX "));
DBGPRINT(String(len));
DBGPRINT(" CH");
if(mTxChIdx == 0)
DBGPRINT("0");
DBGPRINT(String(mRfChLst[mTxChIdx]));
DBGPRINT(F(", "));
DBGPRINT(String(mTxRetriesNext));
//DBGPRINT(F(" retries | "));
//#ifdef DYNAMIC_OFFSET
DBGPRINT(F(" ret., rx offset: "));
DBGPRINT(String(iv->rxOffset));
DBGPRINT(F(" | "));
/*#else
DBGPRINT(F(" ret. | "));
#endif*/
if(*mPrintWholeTrace) {
if(*mPrivacyMode)
ah::dumpBuf(mTxBuf, len, 1, 4);
@ -370,6 +408,10 @@ class HmRadio : public Radio {
mNrf24->stopListening();
mNrf24->flush_rx();
if(!isRetransmit && mTxRetries != mTxRetriesNext) {
mNrf24->setRetries(3, mTxRetriesNext);
mTxRetries = mTxRetriesNext;
}
mNrf24->setChannel(mRfChLst[mTxChIdx]);
mNrf24->openWritingPipe(reinterpret_cast<uint8_t*>(&iv->radioId.u64));
mNrf24->startWrite(mTxBuf, len, false); // false = request ACK response
@ -412,6 +454,7 @@ class HmRadio : public Radio {
bool mRxPendular = false;
uint32_t innerLoopTimeout = DURATION_LISTEN_MIN;
//uint8_t mTxSetupTime = 0;
uint8_t mTxRetries = 15; // memorize last setting for mNrf24->setRetries(3, 15);
std::unique_ptr<SPIClass> mSpi;
std::unique_ptr<RF24> mNrf24;

7
src/hm/hmSystem.h

@ -95,6 +95,13 @@ class HmSystem {
if((iv->config->serial.b[5] == 0x10) && ((iv->config->serial.b[4] & 0x03) == 0x01))
DPRINTLN(DBG_WARN, F("MI Inverter, has some restrictions!"));
#ifdef DYNAMIC_OFFSET
iv->rxOffset = iv->ivGen == IV_HM ? 13 : 12; // effective 3 (or 2), but can easily be recognized as default setting
#else
iv->rxOffset = (iv->ivGen == IV_HM && iv->type == INV_TYPE_4CH) ? 3 : 2;
iv->rxOffset = iv->ivGen == IV_HM ? 3 : 2;
#endif
cb(iv);
}

4
src/hm/radio.h

@ -79,6 +79,8 @@ class Radio {
std::queue<packet_t> mBufCtrl;
uint8_t mIrqOk = IRQ_UNKNOWN;
TimeMonitor mRadioWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state)
uint8_t mTxRetriesNext = 15; // let heuristics tell us the next reties count (for nRF type radios only)
uint8_t mFramesExpected = 0x0c;
protected:
virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0;
@ -128,11 +130,11 @@ class Radio {
}
uint32_t mDtuSn;
volatile bool mIrqRcvd;
bool *mSerialDebug, *mPrivacyMode, *mPrintWholeTrace;
uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE];
uint8_t mFramesExpected = 0x0c;
};
#endif /*__RADIO_H__*/

6
src/hms/hmsRadio.h

@ -176,10 +176,10 @@ class CmtRadio : public Radio {
if(CmtStatus::SUCCESS == status)
mBufCtrl.push(p);
// this code completly stops communication!
//if(p.packet[9] > ALL_FRAMES) // indicates last frame
if(p.packet[9] > ALL_FRAMES) // indicates last frame
mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first get back to rx mode?
// optionally instead:
// mRadioWaitTime.stopTimeMonitor(); // we got everything we expected and can exit rx mode...
//optionally instead: mRadioWaitTime.startTimeMonitor(DURATION_PAUSE_LASTFR); // let the inverter first get back to rx mode?
}
CmtType mCmt;

Loading…
Cancel
Save