From 5a81a54738b3f1ec1231e4130520e256b843eeb7 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 9 Oct 2023 23:59:04 +0200 Subject: [PATCH] started to improve communication (from scratch) --- src/app.cpp | 25 +++++--- src/app.h | 8 +++ src/defines.h | 1 + src/hm/CommQueue.h | 87 +++++++++++++++++++++++++++ src/hm/Communication.h | 129 +++++++++++++++++++++++++++++++++++++++++ src/hm/hmRadio.h | 2 - src/hm/radio.h | 4 ++ src/hms/hmsRadio.h | 2 - 8 files changed, 246 insertions(+), 12 deletions(-) create mode 100644 src/hm/CommQueue.h create mode 100644 src/hm/Communication.h diff --git a/src/app.cpp b/src/app.cpp index 84423d4c..a834d091 100644 --- a/src/app.cpp +++ b/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(); } diff --git a/src/app.h b/src/app.h index ac516302..9cc90100 100644 --- a/src/app.h +++ b/src/app.h @@ -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 PubMqttType; typedef PubSerial PubSerialType; // PLUGINS +#if defined(PLUGIN_DISPLAY) #include "plugins/Display/Display.h" #include "plugins/Display/Display_data.h" typedef Display> 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__*/ diff --git a/src/defines.h b/src/defines.h index c7d5700a..860231ba 100644 --- a/src/defines.h +++ b/src/defines.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 { diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h new file mode 100644 index 00000000..3f0e2da8 --- /dev/null +++ b/src/hm/CommQueue.h @@ -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 +#include +#include "hmInverter.h" + +template +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 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 mQueue; + uint8_t mWrPtr = 0; + uint8_t mRdPtr = 0; +}; + + +#endif /*__COMM_QUEUE_H__*/ diff --git a/src/hm/Communication.h b/src/hm/Communication.h new file mode 100644 index 00000000..1d165186 --- /dev/null +++ b/src/hm/Communication.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 +#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 mLocalBuf; + bool lastFound; + uint8_t maxFrameId; +}; + +#endif /*__COMMUNICATION_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index a3368c0f..45278e6b 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -238,8 +238,6 @@ class HmRadio : public Radio { return mNrf24.isPVariant(); } - std::queue mBufCtrl; - private: inline bool getReceived(void) { bool tx_ok, tx_fail, rx_ready; diff --git a/src/hm/radio.h b/src/hm/radio.h index e2112586..8e9f5ef4 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -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 mBufCtrl; + protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; virtual uint64_t getIvId(Inverter<> *iv) = 0; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 42eee1bc..5cee324b 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -78,8 +78,6 @@ class CmtRadio : public Radio { return true; } - std::queue mBufCtrl; - private: void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { updateCrcs(&len, appendCrc16);