Browse Source

further improved new communication model

pull/1219/head
lumapu 1 year ago
parent
commit
c7f3f21469
  1. 4
      src/app.cpp
  2. 24
      src/hm/CommQueue.h
  3. 149
      src/hm/Communication.h

4
src/app.cpp

@ -70,7 +70,9 @@ void app::setup() {
else if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) else if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen))
iv->radio = &mCmtRadio; iv->radio = &mCmtRadio;
#endif #endif
mCommunication.add(iv, 0x01, false); mCommunication.add(iv, 0x01);
mCommunication.add(iv, 0x05);
mCommunication.add(iv, 0x0b);
}); });
} }

24
src/hm/CommQueue.h

@ -15,13 +15,13 @@ class CommQueue {
public: public:
CommQueue() {} CommQueue() {}
void addImportant(Inverter<> *iv, uint8_t cmd, bool delIfFailed = true) { void addImportant(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) {
dec(&mRdPtr); dec(&mRdPtr);
mQueue[mRdPtr] = queue_s(iv, cmd, delIfFailed); mQueue[mRdPtr] = queue_s(iv, cmd, delOnPop);
} }
void add(Inverter<> *iv, uint8_t cmd, bool delIfFailed = true) { void add(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) {
mQueue[mWrPtr] = queue_s(iv, cmd, delIfFailed); mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop);
inc(&mWrPtr); inc(&mWrPtr);
} }
@ -30,12 +30,11 @@ class CommQueue {
Inverter<> *iv; Inverter<> *iv;
uint8_t cmd; uint8_t cmd;
uint8_t attempts; uint8_t attempts;
bool delIfFailed; bool delOnPop;
bool done;
uint32_t ts; uint32_t ts;
queue_s() {} queue_s() {}
queue_s(Inverter<> *i, uint8_t c, bool d) : queue_s(Inverter<> *i, uint8_t c, bool d) :
iv(i), cmd(c), attempts(5), done(false), ts(0), delIfFailed(d) {} iv(i), cmd(c), attempts(5), ts(0), delOnPop(d) {}
}; };
protected: protected:
@ -52,9 +51,11 @@ class CommQueue {
cb(true, &mQueue[mRdPtr]); cb(true, &mQueue[mRdPtr]);
} }
void pop(void) { void pop(bool force = false) {
if(!mQueue[mRdPtr].delIfFailed) if(!mQueue[mRdPtr].delOnPop && !force) {
mQueue[mRdPtr].attempts = 5;
add(mQueue[mRdPtr]); // add to the end again add(mQueue[mRdPtr]); // add to the end again
}
inc(&mRdPtr); inc(&mRdPtr);
} }
@ -62,8 +63,9 @@ class CommQueue {
mQueue[mRdPtr].ts = *ts; mQueue[mRdPtr].ts = *ts;
} }
void setDone(void) { void setAttempt(void) {
mQueue[mRdPtr].done = true; if(mQueue[mRdPtr].attempts)
mQueue[mRdPtr].attempts--;
} }
void inc(uint8_t *ptr) { void inc(uint8_t *ptr) {

149
src/hm/Communication.h

@ -22,49 +22,106 @@ class Communication : public CommQueue<> {
return; // empty return; // empty
switch(mState) { switch(mState) {
case States::IDLE: case States::RESET:
lastFound = false;
for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) {
mLocalBuf[i].len = 0;
}
mState = States::START;
break;
case States::START:
setTs(mTimestamp); setTs(mTimestamp);
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);
lastMillis = millis(); mWaitTimeout = millis() + 500;
lastFound = false; setAttempt();
mState = States::WAIT; mState = States::WAIT;
break; break;
case States::WAIT: case States::WAIT:
if((millis()-lastMillis) < 500) if(millis() < mWaitTimeout)
return; return;
mState = States::CHECK_FRAMES; mState = States::CHECK_FRAMES;
break; break;
case States::CHECK_FRAMES: case States::CHECK_FRAMES: {
if(!q->iv->radio->loop()) if(!q->iv->radio->loop()) {
pop();
q->iv->radioStatistics.rxFailNoAnser++; // got nothing
mState = States::RESET;
break; // radio buffer empty break; // radio buffer empty
}
States nextState = States::RESET;
while(!q->iv->radio->mBufCtrl.empty()) { while(!q->iv->radio->mBufCtrl.empty()) {
packet_t *p = &q->iv->radio->mBufCtrl.front(); packet_t *p = &q->iv->radio->mBufCtrl.front();
q->iv->radio->mBufCtrl.pop(); q->iv->radio->mBufCtrl.pop();
DPRINT_IVID(DBG_INFO, q->iv->id);
DPRINT(DBG_INFO, F("RX "));
DBGPRINT(String(p->len));
DBGPRINT(F(" CH"));
DBGPRINT(String(p->ch));
DBGPRINT(F(", "));
DBGPRINT(String(p->rssi));
DBGPRINT(F("dBm | "));
ah::dumpBuf(p->packet, p->len);
if(!checkIvSerial(&p->packet[1], q->iv)) if(!checkIvSerial(&p->packet[1], q->iv))
continue; // inverter ID incorrect continue; // inverter ID incorrect
q->iv->radioStatistics.frmCnt++; 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);
else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command nextState = States::CHECK_PACKAGE;
} else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command
parseDevCtrl(p); parseDevCtrl(p);
yield(); yield();
} }
mState = nextState;
}
break;
case States::CHECK_PACKAGE:
if(!lastFound) {
DPRINT_IVID(DBG_WARN, q->iv->id);
DBGPRINT(F("last frame "));
DBGPRINT(String(mMaxFrameId+1));
DBGPRINTLN(F(" missing: Request Retransmit"));
q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + mMaxFrameId + 1), true);
setAttempt();
mWaitTimeout = millis() + 100;
mState = States::WAIT;
break;
}
for(uint8_t i = 0; i < mMaxFrameId; i++) {
if(mLocalBuf[i].len == 0) {
DPRINT_IVID(DBG_WARN, q->iv->id);
DBGPRINT(F("frame "));
DBGPRINT(String(i + 1));
DBGPRINTLN(F(" missing: Request Retransmit"));
q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true);
setAttempt();
mWaitTimeout = millis() + 100;
mState = States::WAIT;
return;
}
}
compilePayload(q);
pop(true); // remove done request
mState = States::RESET; // everything ok, next request
break; break;
} }
}); });
} }
void gotData() {
setDone();
}
private: private:
inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) {
uint8_t tmp[4]; uint8_t tmp[4];
@ -84,14 +141,16 @@ class Communication : public CommQueue<> {
uint8_t *frameId = &p->packet[9]; uint8_t *frameId = &p->packet[9];
if(0x00 == *frameId) if(0x00 == *frameId)
return; // skip current packet return; // skip current packet
if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) {
DPRINTLN(DBG_WARN, F("local buffer to small for payload fragments!"));
return; // local storage is to small for id return; // local storage is to small for id
}
if(!checkFrameCrc(p->packet, p->len)) if(!checkFrameCrc(p->packet, p->len))
return; // CRC8 is wrong, frame invalid return; // CRC8 is wrong, frame invalid
if((*frameId & ALL_FRAMES) == ALL_FRAMES) { if((*frameId & ALL_FRAMES) == ALL_FRAMES) {
maxFrameId = (*frameId & 0x7f); mMaxFrameId = (*frameId & 0x7f);
if(*frameId > 0x81) if(*frameId > 0x81)
lastFound = true; lastFound = true;
} }
@ -106,9 +165,62 @@ class Communication : public CommQueue<> {
//if((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) //if((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00))
} }
inline void compilePayload(const queue_s *q) {
uint16_t crc = 0xffff, crcRcv = 0x0000;
for(uint8_t i = 0; i < mMaxFrameId; i++) {
if(i == (mMaxFrameId - 1)) {
crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len - 2, crc);
crcRcv = (mLocalBuf[i].buf[mLocalBuf[i].len-2] << 8);
crcRcv |= mLocalBuf[i].buf[mLocalBuf[i].len-1];
} else
crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len, crc);
}
if(crc != crcRcv) {
DPRINT_IVID(DBG_WARN, q->iv->id);
DBGPRINT(F("CRC Error "));
if(q->attempts == 0) {
DBGPRINTLN(F("-> Fail"));
q->iv->radioStatistics.rxFail++; // got fragments but not complete response
pop();
} else
DBGPRINTLN(F("-> complete retransmit"));
mState = States::RESET;
return;
}
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("procPyld: cmd: 0x"));
DBGHEXLN(q->cmd);
memset(mPayload, 0, 150);
int8_t rssi = -127;
uint8_t len = 0;
for(uint8_t i = 0; i < mMaxFrameId; i++) {
if(mLocalBuf[i].len + len > 150) {
DPRINTLN(DBG_ERROR, F("payload buffer to small!"));
return;
}
memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len);
len += mLocalBuf[i].len;
// get worst RSSI
if(mLocalBuf[i].rssi > rssi)
rssi = mLocalBuf[i].rssi;
}
len -= 2;
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("Payload ("));
DBGPRINT(String(len));
DBGPRINT(F("): "));
ah::dumpBuf(mPayload, len);
}
private: private:
enum class States : uint8_t { enum class States : uint8_t {
IDLE, WAIT, CHECK_FRAMES RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE
}; };
typedef struct { typedef struct {
@ -118,12 +230,13 @@ class Communication : public CommQueue<> {
} frame_t; } frame_t;
private: private:
States mState = States::IDLE; States mState = States::RESET;
uint32_t *mTimestamp; uint32_t *mTimestamp;
uint32_t lastMillis; uint32_t mWaitTimeout;
std::array<frame_t, MAX_PAYLOAD_ENTRIES> mLocalBuf; std::array<frame_t, MAX_PAYLOAD_ENTRIES> mLocalBuf;
bool lastFound; bool lastFound;
uint8_t maxFrameId; uint8_t mMaxFrameId;
uint8_t mPayload[150];
}; };
#endif /*__COMMUNICATION_H__*/ #endif /*__COMMUNICATION_H__*/

Loading…
Cancel
Save