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