mirror of https://github.com/lumapu/ahoy.git
8 changed files with 246 additions and 12 deletions
@ -0,0 +1,87 @@ |
|||
//-----------------------------------------------------------------------------
|
|||
// 2023 Ahoy, https://github.com/lumpapu/ahoy
|
|||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
|||
//-----------------------------------------------------------------------------
|
|||
|
|||
#ifndef __COMM_QUEUE_H__ |
|||
#define __COMM_QUEUE_H__ |
|||
|
|||
#include <array> |
|||
#include <functional> |
|||
#include "hmInverter.h" |
|||
|
|||
template <uint8_t N=100> |
|||
class CommQueue { |
|||
public: |
|||
CommQueue() {} |
|||
|
|||
void addImportant(Inverter<> *iv, uint8_t cmd, bool delIfFailed = true) { |
|||
dec(&mRdPtr); |
|||
mQueue[mRdPtr] = queue_s(iv, cmd, delIfFailed); |
|||
} |
|||
|
|||
void add(Inverter<> *iv, uint8_t cmd, bool delIfFailed = true) { |
|||
mQueue[mWrPtr] = queue_s(iv, cmd, delIfFailed); |
|||
inc(&mWrPtr); |
|||
} |
|||
|
|||
protected: |
|||
struct queue_s { |
|||
Inverter<> *iv; |
|||
uint8_t cmd; |
|||
uint8_t attempts; |
|||
bool delIfFailed; |
|||
bool done; |
|||
uint32_t ts; |
|||
queue_s() {} |
|||
queue_s(Inverter<> *i, uint8_t c, bool d) : |
|||
iv(i), cmd(c), attempts(5), done(false), ts(0), delIfFailed(d) {} |
|||
}; |
|||
|
|||
protected: |
|||
void add(queue_s q) { |
|||
mQueue[mWrPtr] = q; |
|||
inc(&mWrPtr); |
|||
} |
|||
|
|||
void get(std::function<void(bool valid, const queue_s *q)> cb) { |
|||
if(mRdPtr == mWrPtr) { |
|||
cb(false, &mQueue[mRdPtr]); // empty
|
|||
return; |
|||
} |
|||
cb(true, &mQueue[mRdPtr]); |
|||
} |
|||
|
|||
void pop(void) { |
|||
if(!mQueue[mRdPtr].delIfFailed) |
|||
add(mQueue[mRdPtr]); // add to the end again
|
|||
inc(&mRdPtr); |
|||
} |
|||
|
|||
void setTs(uint32_t *ts) { |
|||
mQueue[mRdPtr].ts = *ts; |
|||
} |
|||
|
|||
void setDone(void) { |
|||
mQueue[mRdPtr].done = true; |
|||
} |
|||
|
|||
void inc(uint8_t *ptr) { |
|||
if(++(*ptr) >= N) |
|||
*ptr = 0; |
|||
} |
|||
void dec(uint8_t *ptr) { |
|||
if((*ptr) == 0) |
|||
*ptr = N-1; |
|||
else |
|||
--(*ptr); |
|||
} |
|||
|
|||
protected: |
|||
std::array<queue_s, N> mQueue; |
|||
uint8_t mWrPtr = 0; |
|||
uint8_t mRdPtr = 0; |
|||
}; |
|||
|
|||
|
|||
#endif /*__COMM_QUEUE_H__*/ |
@ -0,0 +1,129 @@ |
|||
//-----------------------------------------------------------------------------
|
|||
// 2023 Ahoy, https://github.com/lumpapu/ahoy
|
|||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
|||
//-----------------------------------------------------------------------------
|
|||
|
|||
#ifndef __COMMUNICATION_H__ |
|||
#define __COMMUNICATION_H__ |
|||
|
|||
#include "CommQueue.h" |
|||
#include <Arduino.h> |
|||
#include "../utils/crc.h" |
|||
|
|||
class Communication : public CommQueue<> { |
|||
public: |
|||
void setup(uint32_t *timestamp) { |
|||
mTimestamp = timestamp; |
|||
} |
|||
|
|||
void loop() { |
|||
get([this](bool valid, const queue_s *q) { |
|||
if(!valid) |
|||
return; // empty
|
|||
|
|||
switch(mState) { |
|||
case States::IDLE: |
|||
setTs(mTimestamp); |
|||
q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); |
|||
lastMillis = millis(); |
|||
lastFound = false; |
|||
mState = States::WAIT; |
|||
break; |
|||
|
|||
case States::WAIT: |
|||
if((millis()-lastMillis) < 500) |
|||
return; |
|||
mState = States::CHECK_FRAMES; |
|||
break; |
|||
|
|||
case States::CHECK_FRAMES: |
|||
if(!q->iv->radio->loop()) |
|||
break; // radio buffer empty
|
|||
|
|||
while(!q->iv->radio->mBufCtrl.empty()) { |
|||
packet_t *p = &q->iv->radio->mBufCtrl.front(); |
|||
q->iv->radio->mBufCtrl.pop(); |
|||
|
|||
if(!checkIvSerial(&p->packet[1], q->iv)) |
|||
continue; // inverter ID incorrect
|
|||
|
|||
q->iv->radioStatistics.frmCnt++; |
|||
|
|||
if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command
|
|||
parseFrame(p); |
|||
else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command
|
|||
parseDevCtrl(p); |
|||
|
|||
yield(); |
|||
} |
|||
break; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
void gotData() { |
|||
setDone(); |
|||
} |
|||
|
|||
private: |
|||
inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { |
|||
uint8_t tmp[4]; |
|||
CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); |
|||
for(uint8_t i = 0; i < 4; i++) { |
|||
if(tmp[i] != buf[i]) |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
inline bool checkFrameCrc(uint8_t buf[], uint8_t len) { |
|||
return (ah::crc8(buf, len - 1) == buf[len-1]); |
|||
} |
|||
|
|||
inline void parseFrame(packet_t *p) { |
|||
uint8_t *frameId = &p->packet[9]; |
|||
if(0x00 == *frameId) |
|||
return; // skip current packet
|
|||
if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) |
|||
return; // local storage is to small for id
|
|||
|
|||
if(!checkFrameCrc(p->packet, p->len)) |
|||
return; // CRC8 is wrong, frame invalid
|
|||
|
|||
if((*frameId & ALL_FRAMES) == ALL_FRAMES) { |
|||
maxFrameId = (*frameId & 0x7f); |
|||
if(*frameId > 0x81) |
|||
lastFound = true; |
|||
} |
|||
|
|||
frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; |
|||
memcpy(f->buf, &p->packet[10], p->len-11); |
|||
f->len = p->len - 11; |
|||
f->rssi = p->rssi; |
|||
} |
|||
|
|||
inline void parseDevCtrl(packet_t *p) { |
|||
//if((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00))
|
|||
} |
|||
|
|||
private: |
|||
enum class States : uint8_t { |
|||
IDLE, WAIT, CHECK_FRAMES |
|||
}; |
|||
|
|||
typedef struct { |
|||
uint8_t buf[MAX_RF_PAYLOAD_SIZE]; |
|||
uint8_t len; |
|||
int8_t rssi; |
|||
} frame_t; |
|||
|
|||
private: |
|||
States mState = States::IDLE; |
|||
uint32_t *mTimestamp; |
|||
uint32_t lastMillis; |
|||
std::array<frame_t, MAX_PAYLOAD_ENTRIES> mLocalBuf; |
|||
bool lastFound; |
|||
uint8_t maxFrameId; |
|||
}; |
|||
|
|||
#endif /*__COMMUNICATION_H__*/ |
Loading…
Reference in new issue