mirror of
https://github.com/lumapu/ahoy.git
synced 2025-07-23 11:17:11 +02:00
started to improve communication (from scratch)
This commit is contained in:
parent
111c683faf
commit
5a81a54738
8 changed files with 246 additions and 12 deletions
25
src/app.cpp
25
src/app.cpp
|
@ -59,26 +59,29 @@ void app::setup() {
|
|||
#endif
|
||||
#endif /* defined(ETHERNET) */
|
||||
|
||||
mCommunication.setup(&mTimestamp);
|
||||
mSys.setup(&mTimestamp, &mConfig->inst);
|
||||
for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) {
|
||||
mSys.addInverter(i, [this](Inverter<> *iv) {
|
||||
// will be only called for valid inverters
|
||||
if((IV_MI == iv->ivGen) || (IV_HM == iv->ivGen))
|
||||
iv->radio = &mNrfRadio;
|
||||
#if defined(ESP32)
|
||||
else if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen))
|
||||
iv->radio = &mCmtRadio;
|
||||
#endif
|
||||
mCommunication.add(iv, 0x01, false);
|
||||
});
|
||||
}
|
||||
|
||||
mPayload.setup(this, &mSys, &mTimestamp);
|
||||
/*mPayload.setup(this, &mSys, &mTimestamp);
|
||||
mPayload.enableSerialDebug(mConfig->serial.debug);
|
||||
mPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2));
|
||||
if (mConfig->nrf.enabled) {
|
||||
mMiPayload.setup(this, &mSys, &mTimestamp);
|
||||
mMiPayload.enableSerialDebug(mConfig->serial.debug);
|
||||
mMiPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
}*/
|
||||
|
||||
if(mConfig->nrf.enabled) {
|
||||
if (!mNrfRadio.isChipConnected())
|
||||
|
@ -91,8 +94,8 @@ void app::setup() {
|
|||
if (mMqttEnabled) {
|
||||
mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, &mSys, &mTimestamp, &mUptime);
|
||||
mMqtt.setSubscriptionCb(std::bind(&app::mqttSubRxCb, this, std::placeholders::_1));
|
||||
mPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); });
|
||||
mMiPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); });
|
||||
//mPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); });
|
||||
//mMiPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); });
|
||||
}
|
||||
#endif
|
||||
setupLed();
|
||||
|
@ -103,8 +106,10 @@ void app::setup() {
|
|||
mApi.setup(this, &mSys, mWeb.getWebSrvPtr(), mConfig);
|
||||
|
||||
// Plugins
|
||||
#if defined(PLUGIN_DISPLAY)
|
||||
if (mConfig->plugin.display.type != 0)
|
||||
mDisplay.setup(this, &mConfig->plugin.display, &mSys, &mNrfRadio, &mTimestamp);
|
||||
#endif
|
||||
|
||||
mPubSerial.setup(mConfig, &mSys, &mTimestamp);
|
||||
|
||||
|
@ -120,7 +125,9 @@ void app::loop(void) {
|
|||
ah::Scheduler::loop();
|
||||
bool processPayload = false;
|
||||
|
||||
if (mNrfRadio.loop() && mConfig->nrf.enabled) {
|
||||
mCommunication.loop();
|
||||
|
||||
/*if (mNrfRadio.loop() && mConfig->nrf.enabled) {
|
||||
while (!mNrfRadio.mBufCtrl.empty()) {
|
||||
packet_t *p = &mNrfRadio.mBufCtrl.front();
|
||||
if (mConfig->serial.debug) {
|
||||
|
@ -178,7 +185,7 @@ void app::loop(void) {
|
|||
mPayload.process(true);
|
||||
|
||||
mPayload.loop();
|
||||
mMiPayload.loop();
|
||||
mMiPayload.loop();*/
|
||||
|
||||
if (mMqttEnabled && mNetworkConnected)
|
||||
mMqtt.loop();
|
||||
|
@ -208,8 +215,10 @@ void app::regularTickers(void) {
|
|||
DPRINTLN(DBG_DEBUG, F("regularTickers"));
|
||||
everySec(std::bind(&WebType::tickSecond, &mWeb), "webSc");
|
||||
// Plugins
|
||||
#if defined(PLUGIN_DISPLAY)
|
||||
if (mConfig->plugin.display.type != 0)
|
||||
everySec(std::bind(&DisplayType::tickerSecond, &mDisplay), "disp");
|
||||
#endif
|
||||
every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval, "uart");
|
||||
#if !defined(ETHERNET)
|
||||
//everySec([this]() { mImprov.tickSerial(); }, "impro");
|
||||
|
@ -391,7 +400,7 @@ void app::tickMidnight(void) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::tickSend(void) {
|
||||
if(mConfig->nrf.enabled) {
|
||||
/*if(mConfig->nrf.enabled) {
|
||||
if(!mNrfRadio.isChipConnected()) {
|
||||
DPRINTLN(DBG_WARN, F("NRF24 not connected!"));
|
||||
}
|
||||
|
@ -437,7 +446,7 @@ void app::tickSend(void) {
|
|||
if (mConfig->serial.debug)
|
||||
DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!"));
|
||||
}
|
||||
yield();
|
||||
yield();*/
|
||||
|
||||
updateLed();
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "utils/scheduler.h"
|
||||
#include "web/RestApi.h"
|
||||
#include "web/web.h"
|
||||
#include "hm/Communication.h"
|
||||
#if defined(ETHERNET)
|
||||
#include "eth/ahoyeth.h"
|
||||
#else /* defined(ETHERNET) */
|
||||
|
@ -52,9 +53,11 @@ typedef PubMqtt<HmSystemType> PubMqttType;
|
|||
typedef PubSerial<HmSystemType> PubSerialType;
|
||||
|
||||
// PLUGINS
|
||||
#if defined(PLUGIN_DISPLAY)
|
||||
#include "plugins/Display/Display.h"
|
||||
#include "plugins/Display/Display_data.h"
|
||||
typedef Display<HmSystemType, HmRadio<>> DisplayType;
|
||||
#endif
|
||||
|
||||
class app : public IApp, public ah::Scheduler {
|
||||
public:
|
||||
|
@ -258,8 +261,10 @@ class app : public IApp, public ah::Scheduler {
|
|||
if (mMqttEnabled)
|
||||
mMqtt.payloadEventListener(cmd, iv);
|
||||
#endif
|
||||
#if defined(PLUGIN_DISPLAY)
|
||||
if(mConfig->plugin.display.type != 0)
|
||||
mDisplay.payloadEventListener(cmd);
|
||||
#endif
|
||||
updateLed();
|
||||
}
|
||||
|
||||
|
@ -302,6 +307,7 @@ class app : public IApp, public ah::Scheduler {
|
|||
|
||||
HmSystemType mSys;
|
||||
HmRadio<> mNrfRadio;
|
||||
Communication mCommunication;
|
||||
|
||||
bool mShowRebootRequest;
|
||||
bool mIVCommunicationOn;
|
||||
|
@ -344,8 +350,10 @@ class app : public IApp, public ah::Scheduler {
|
|||
uint32_t mSunrise, mSunset;
|
||||
|
||||
// plugins
|
||||
#if defined(PLUGIN_DISPLAY)
|
||||
DisplayType mDisplay;
|
||||
DisplayData mDispData;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /*__APP_H__*/
|
||||
|
|
|
@ -21,6 +21,7 @@ typedef struct {
|
|||
uint8_t len;
|
||||
int8_t rssi;
|
||||
uint8_t packet[MAX_RF_PAYLOAD_SIZE];
|
||||
//uint32_t millis;
|
||||
} packet_t;
|
||||
|
||||
typedef enum {
|
||||
|
|
87
src/hm/CommQueue.h
Normal file
87
src/hm/CommQueue.h
Normal file
|
@ -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__*/
|
129
src/hm/Communication.h
Normal file
129
src/hm/Communication.h
Normal file
|
@ -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__*/
|
|
@ -238,8 +238,6 @@ class HmRadio : public Radio {
|
|||
return mNrf24.isPVariant();
|
||||
}
|
||||
|
||||
std::queue<packet_t> mBufCtrl;
|
||||
|
||||
private:
|
||||
inline bool getReceived(void) {
|
||||
bool tx_ok, tx_fail, rx_ready;
|
||||
|
|
|
@ -23,6 +23,7 @@ class Radio {
|
|||
public:
|
||||
virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) = 0;
|
||||
virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; }
|
||||
virtual bool loop(void) = 0;
|
||||
|
||||
void handleIntr(void) {
|
||||
mIrqRcvd = true;
|
||||
|
@ -52,6 +53,9 @@ class Radio {
|
|||
sendPacket(iv, 24, isRetransmit);
|
||||
}
|
||||
|
||||
public:
|
||||
std::queue<packet_t> mBufCtrl;
|
||||
|
||||
protected:
|
||||
virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0;
|
||||
virtual uint64_t getIvId(Inverter<> *iv) = 0;
|
||||
|
|
|
@ -78,8 +78,6 @@ class CmtRadio : public Radio {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::queue<packet_t> mBufCtrl;
|
||||
|
||||
private:
|
||||
void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) {
|
||||
updateCrcs(&len, appendCrc16);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue