mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-19 03:46:11 +02:00
further improved new communication model
This commit is contained in:
parent
5a81a54738
commit
c7f3f21469
3 changed files with 147 additions and 30 deletions
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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…
Add table
Add a link
Reference in a new issue