From 75539c5daf968598c7e336b78ae31e61bdf00fba Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 6 Feb 2023 23:37:05 +0100 Subject: [PATCH] started implementation of MI inverters (setup.html, own processing `MiPayload.h`) --- src/CHANGES.md | 3 + src/app.cpp | 65 ++++--- src/app.h | 8 +- src/defines.h | 2 +- src/hm/hmDefines.h | 3 + src/hm/hmInverter.h | 2 + src/hm/hmPayload.h | 17 +- src/hm/hmRadio.h | 8 +- src/hm/hmSystem.h | 39 +++-- src/hm/miPayload.h | 298 ++++++++++++++++++++++++++++++++ src/web/html/index.html | 2 +- src/web/html/login.html | 2 +- src/web/html/serial.html | 2 +- src/web/html/setup.html | 17 +- src/web/html/system.html | 2 +- src/web/html/update.html | 2 +- src/web/html/visualization.html | 2 +- 17 files changed, 408 insertions(+), 66 deletions(-) create mode 100644 src/hm/miPayload.h diff --git a/src/CHANGES.md b/src/CHANGES.md index ae341ba6..2e31c0e1 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,9 @@ (starting from release version `0.5.66`) +## 0.5.81 +* started implementation of MI inverters (setup.html, own processing `MiPayload.h`) + ## 0.5.80 * fixed communication #656 diff --git a/src/app.cpp b/src/app.cpp index 2f1bd58d..d64eefdb 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -13,7 +13,6 @@ app::app() : ah::Scheduler() {} //----------------------------------------------------------------------------- void app::setup() { - mSys = NULL; Serial.begin(115200); while (!Serial) yield(); @@ -26,9 +25,8 @@ void app::setup() { mSettings.getPtr(mConfig); DPRINTLN(DBG_INFO, F("Settings valid: ") + String((mSettings.getValid()) ? F("true") : F("false"))); - mSys = new HmSystemType(); - mSys->enableDebug(); - mSys->setup(mConfig->nrf.amplifierPower, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs); + mSys.enableDebug(); + mSys.setup(mConfig->nrf.amplifierPower, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs); mPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1)); #if defined(AP_ONLY) @@ -42,34 +40,37 @@ void app::setup() { everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL"); #endif - mSys->addInverters(&mConfig->inst); - mPayload.setup(this, mSys, &mStat, mConfig->nrf.maxRetransPerPyld, &mTimestamp); + mSys.addInverters(&mConfig->inst); + mPayload.setup(this, &mSys, &mStat, mConfig->nrf.maxRetransPerPyld, &mTimestamp); mPayload.enableSerialDebug(mConfig->serial.debug); - if(!mSys->Radio.isChipConnected()) + mMiPayload.setup(this, &mSys, &mStat, mConfig->nrf.maxRetransPerPyld, &mTimestamp); + mMiPayload.enableSerialDebug(mConfig->serial.debug); + + if(!mSys.Radio.isChipConnected()) DPRINTLN(DBG_WARN, F("WARNING! your NRF24 module can't be reached, check the wiring")); // when WiFi is in client mode, then enable mqtt broker #if !defined(AP_ONLY) mMqttEnabled = (mConfig->mqtt.broker[0] > 0); if (mMqttEnabled) { - mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, mSys, &mTimestamp); + mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, &mSys, &mTimestamp); mMqtt.setSubscriptionCb(std::bind(&app::mqttSubRxCb, this, std::placeholders::_1)); mPayload.addAlarmListener(std::bind(&PubMqttType::alarmEventListener, &mMqtt, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); } #endif setupLed(); - mWeb.setup(this, mSys, mConfig); + mWeb.setup(this, &mSys, mConfig); mWeb.setProtection(strlen(mConfig->sys.adminPwd) != 0); - mApi.setup(this, mSys, mWeb.getWebSrvPtr(), mConfig); + mApi.setup(this, &mSys, mWeb.getWebSrvPtr(), mConfig); // Plugins if(mConfig->plugin.display.type != 0) - mMonoDisplay.setup(&mConfig->plugin.display, mSys, &mTimestamp, 0xff, mVersion); + mMonoDisplay.setup(&mConfig->plugin.display, &mSys, &mTimestamp, 0xff, mVersion); - mPubSerial.setup(mConfig, mSys, &mTimestamp); + mPubSerial.setup(mConfig, &mSys, &mTimestamp); regularTickers(); } @@ -83,23 +84,31 @@ void app::loop(void) { void app::loopStandard(void) { ah::Scheduler::loop(); - if (mSys->Radio.loop()) { - while (!mSys->Radio.mBufCtrl.empty()) { - packet_t *p = &mSys->Radio.mBufCtrl.front(); + if (mSys.Radio.loop()) { + while (!mSys.Radio.mBufCtrl.empty()) { + packet_t *p = &mSys.Radio.mBufCtrl.front(); if (mConfig->serial.debug) { DPRINT(DBG_INFO, "RX " + String(p->len) + "B Ch" + String(p->ch) + " | "); - mSys->Radio.dumpBuf(p->packet, p->len); + mSys.Radio.dumpBuf(p->packet, p->len); } mStat.frmCnt++; - mPayload.add(p); - mSys->Radio.mBufCtrl.pop(); + Inverter<> *iv = mSys.findInverter(&p->packet[1]); + if(NULL == iv) { + if(IV_HM == iv->ivGen) + mPayload.add(iv, p); + else + mMiPayload.add(iv, p); + } + mSys.Radio.mBufCtrl.pop(); yield(); } mPayload.process(true); + mMiPayload.process(true); } mPayload.loop(); + mMiPayload.loop(); if(mMqttEnabled) mMqtt.loop(); @@ -232,26 +241,30 @@ void app::tickMidnight(void) { //----------------------------------------------------------------------------- void app::tickSend(void) { - if(!mSys->Radio.isChipConnected()) { + if(!mSys.Radio.isChipConnected()) { DPRINTLN(DBG_WARN, "NRF24 not connected!"); return; } if (mIVCommunicationOn) { - if (!mSys->Radio.mBufCtrl.empty()) { + if (!mSys.Radio.mBufCtrl.empty()) { if (mConfig->serial.debug) - DPRINTLN(DBG_DEBUG, F("recbuf not empty! #") + String(mSys->Radio.mBufCtrl.size())); + DPRINTLN(DBG_DEBUG, F("recbuf not empty! #") + String(mSys.Radio.mBufCtrl.size())); } int8_t maxLoop = MAX_NUM_INVERTERS; - Inverter<> *iv = mSys->getInverterByPos(mSendLastIvId); + Inverter<> *iv = mSys.getInverterByPos(mSendLastIvId); do { mSendLastIvId = ((MAX_NUM_INVERTERS - 1) == mSendLastIvId) ? 0 : mSendLastIvId + 1; - iv = mSys->getInverterByPos(mSendLastIvId); + iv = mSys.getInverterByPos(mSendLastIvId); } while ((NULL == iv) && ((maxLoop--) > 0)); if (NULL != iv) { - if(iv->config->enabled) - mPayload.ivSend(iv); + if(iv->config->enabled) { + if(iv->ivGen == IV_HM) + mPayload.ivSend(iv); + else + mMiPayload.ivSend(iv); + } } } else { if (mConfig->serial.debug) @@ -307,7 +320,7 @@ void app::setupLed(void) { //----------------------------------------------------------------------------- void app::updateLed(void) { if(mConfig->led.led0 != 0xff) { - Inverter<> *iv = mSys->getInverterByPos(0); + Inverter<> *iv = mSys.getInverterByPos(0); if (NULL != iv) { if(iv->isProducing(mTimestamp)) digitalWrite(mConfig->led.led0, LOW); // LED on diff --git a/src/app.h b/src/app.h index c60bb295..7e9499b7 100644 --- a/src/app.h +++ b/src/app.h @@ -22,6 +22,7 @@ #include "hm/hmSystem.h" #include "hm/hmPayload.h" +#include "hm/miPayload.h" #include "wifi/ahoywifi.h" #include "web/web.h" #include "web/RestApi.h" @@ -38,6 +39,7 @@ typedef HmSystem HmSystemType; typedef HmPayload PayloadType; +typedef MiPayload MiPayloadType; typedef Web WebType; typedef RestApi RestApiType; typedef PubMqtt PubMqttType; @@ -61,8 +63,7 @@ class app : public IApp, public ah::Scheduler { void regularTickers(void); void handleIntr(void) { - if(NULL != mSys) - mSys->Radio.handleIntr(); + mSys.Radio.handleIntr(); } uint32_t getUptime() { @@ -187,7 +188,7 @@ class app : public IApp, public ah::Scheduler { Scheduler::setTimestamp(newTime); } - HmSystemType *mSys; + HmSystemType mSys; private: typedef std::function innerLoopCb; @@ -246,6 +247,7 @@ class app : public IApp, public ah::Scheduler { WebType mWeb; RestApiType mApi; PayloadType mPayload; + MiPayloadType mMiPayload; PubSerialType mPubSerial; char mVersion[12]; diff --git a/src/defines.h b/src/defines.h index 9dfb7884..cf16e86b 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 80 +#define VERSION_PATCH 81 //------------------------------------- typedef struct { diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index fa7e08b2..aa9fe24f 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -9,6 +9,9 @@ #include "../utils/dbg.h" #include +// inverter generations +enum {IV_HM = 0, IV_MI}; + // units enum {UNIT_V = 0, UNIT_A, UNIT_W, UNIT_WH, UNIT_KWH, UNIT_HZ, UNIT_C, UNIT_PCT, UNIT_VAR, UNIT_NONE}; const char* const units[] = {"V", "A", "W", "Wh", "kWh", "Hz", "°C", "%", "var", ""}; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 640aeae3..d50f341a 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -105,6 +105,7 @@ const calcFunc_t calcFunctions[] = { template class Inverter { public: + uint8_t ivGen; // generation of inverter (HM / MI) cfgIv_t *config; // stored settings uint8_t id; // unique id uint8_t type; // integer which refers to inverter type @@ -123,6 +124,7 @@ class Inverter { bool isConnected; // shows if inverter was successfully identified (fw version and hardware info) Inverter() { + ivGen = IV_HM; powerLimit[0] = 0xffff; // 65535 W Limit -> unlimited powerLimit[1] = AbsolutNonPersistent; // default power limit setting actPowerLimit = 0xffff; // init feedback from inverter to -1 diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 2e599a6c..a85f24e3 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -3,8 +3,8 @@ // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ //----------------------------------------------------------------------------- -#ifndef __PAYLOAD_H__ -#define __PAYLOAD_H__ +#ifndef __HM_PAYLOAD_H__ +#define __HM_PAYLOAD_H__ #include "../utils/dbg.h" #include "../utils/crc.h" @@ -48,6 +48,7 @@ class HmPayload { mSerialDebug = false; mHighPrioIv = NULL; mCbAlarm = NULL; + mCbPayload = NULL; } void enableSerialDebug(bool enable) { @@ -118,12 +119,7 @@ class HmPayload { } } - void add(packet_t *p) { - Inverter<> *iv = mSys->findInverter(&p->packet[1]); - - if(NULL == iv) - return; - + void add(Inverter<> *iv, packet_t *p) { if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command mPayload[iv->id].txId = p->packet[0]; DPRINTLN(DBG_DEBUG, F("Response from info request received")); @@ -289,7 +285,8 @@ class HmPayload { private: void notify(uint8_t val) { - (mCbPayload)(val); + if(NULL != mCbPayload) + (mCbPayload)(val); } void notify(uint16_t code, uint32_t start, uint32_t endTime) { @@ -352,4 +349,4 @@ class HmPayload { payloadListenerType mCbPayload; }; -#endif /*__PAYLOAD_H_*/ +#endif /*__HM_PAYLOAD_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index b3466d00..5a6edb0e 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -291,16 +291,16 @@ class HmRadio { mTxBuf[len++] = (crc ) & 0xff; } // crc over all - mTxBuf[len++] = ah::crc8(mTxBuf, len); + mTxBuf[len+1] = ah::crc8(mTxBuf, len); if(mSerialDebug) { - DPRINT(DBG_INFO, "TX " + String(len) + "B Ch" + String(mRfChLst[mTxChIdx]) + " | "); - dumpBuf(mTxBuf, len); + DPRINT(DBG_INFO, "TX " + String(len+1) + "B Ch" + String(mRfChLst[mTxChIdx]) + " | "); + dumpBuf(mTxBuf, len+1); } mNrf24.setChannel(mRfChLst[mTxChIdx]); mNrf24.openWritingPipe(reinterpret_cast(&invId)); - mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response + mNrf24.startWrite(mTxBuf, len+1, false); // false = request ACK response // switch TX channel for next packet if(++mTxChIdx >= RF_CHANNELS) diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 58099d40..3f3b29a7 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -14,18 +14,15 @@ class HmSystem { public: HmRadio<> Radio; - HmSystem() { - mNumInv = 0; - } - ~HmSystem() { - // TODO: cleanup - } + HmSystem() {} void setup() { + mNumInv = 0; Radio.setup(); } void setup(uint8_t ampPwr, uint8_t irqPin, uint8_t cePin, uint8_t csPin) { + mNumInv = 0; Radio.setup(ampPwr, irqPin, cePin, csPin); } @@ -34,8 +31,19 @@ class HmSystem { for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { iv = addInverter(&config->iv[i]); if (0ULL != config->iv[i].serial.u64) { - if (NULL != iv) - DPRINTLN(DBG_INFO, "added inverter " + String(iv->config->serial.u64, HEX)); + if (NULL != iv) { + DPRINT(DBG_INFO, "added inverter "); + if(iv->config->serial.b[5] == 0x11) + DBGPRINT("HM"); + else { + DBGPRINT(((iv->config->serial.b[4] & 0x03) == 0x01) ? " (2nd Gen) " : " (3rd Gen) "); + } + + DBGPRINTLN(String(iv->config->serial.u64, HEX)); + + if((iv->config->serial.b[5] == 0x10) && ((iv->config->serial.b[4] & 0x03) == 0x01)) + DPRINTLN(DBG_WARN, F("MI Inverter are not fully supported now!!!")); + } } } } @@ -51,16 +59,25 @@ class HmSystem { p->config = config; DPRINT(DBG_VERBOSE, "SERIAL: " + String(p->config->serial.b[5], HEX)); DPRINTLN(DBG_VERBOSE, " " + String(p->config->serial.b[4], HEX)); - if(p->config->serial.b[5] == 0x11) { + if((p->config->serial.b[5] == 0x11) || (p->config->serial.b[5] == 0x10)) { switch(p->config->serial.b[4]) { + case 0x22: case 0x21: p->type = INV_TYPE_1CH; break; + case 0x42: case 0x41: p->type = INV_TYPE_2CH; break; + case 0x62: case 0x61: p->type = INV_TYPE_4CH; break; default: - DPRINT(DBG_ERROR, F("unknown inverter type: 11")); - DPRINTLN(DBG_ERROR, String(p->config->serial.b[4], HEX)); + DPRINTLN(DBG_ERROR, F("unknown inverter type")); break; } + + if(p->config->serial.b[5] == 0x11) + p->ivGen = IV_HM; + else if((p->config->serial.b[4] & 0x03) == 0x02) // MI 3rd Gen -> same as HM + p->ivGen = IV_HM; + else // MI 2nd Gen + p->ivGen = IV_MI; } else if(p->config->serial.u64 != 0ULL) DPRINTLN(DBG_ERROR, F("inverter type can't be detected!")); diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h new file mode 100644 index 00000000..f578652c --- /dev/null +++ b/src/hm/miPayload.h @@ -0,0 +1,298 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://ahoydtu.de +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + +#ifndef __MI_PAYLOAD_H__ +#define __MI_PAYLOAD_H__ + +#include "../utils/dbg.h" +#include "../utils/crc.h" +#include "../config/config.h" +#include + +typedef struct { + uint32_t ts; + bool requested; + uint8_t txCmd; + uint8_t len[MAX_PAYLOAD_ENTRIES]; + /* + uint8_t txId; + uint8_t invId; + uint8_t data[MAX_PAYLOAD_ENTRIES][MAX_RF_PAYLOAD_SIZE]; + bool complete; + uint8_t maxPackId; + bool lastFound; + uint8_t retransmits; + bool gotFragment;*/ +} miPayload_t; + + +typedef std::function miPayloadListenerType; + + +template +class MiPayload { + public: + MiPayload() {} + + void setup(IApp *app, HMSYSTEM *sys, statistics_t *stat, uint8_t maxRetransmits, uint32_t *timestamp) { + mApp = app; + mSys = sys; + mStat = stat; + mMaxRetrans = maxRetransmits; + mTimestamp = timestamp; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + reset(i); + } + mSerialDebug = false; + mCbMiPayload = NULL; + } + + void enableSerialDebug(bool enable) { + mSerialDebug = enable; + } + + void addPayloadListener(miPayloadListenerType cb) { + mCbMiPayload = cb; + } + + void loop() {} + + + void ivSend(Inverter<> *iv) { + reset(iv->id); + mPayload[iv->id].requested = true; + + yield(); + if (mSerialDebug) + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Requesting Inv SN ") + String(iv->config->serial.u64, HEX)); + + uint8_t cmd = 0x09; //iv->getQueuedCmd(); + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket")); + mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false); + mPayload[iv->id].txCmd = cmd; + } + + void add(Inverter<> *iv, packet_t *p) { + DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX)); + + /*if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command + mPayload[iv->id].txId = p->packet[0]; + DPRINTLN(DBG_DEBUG, F("Response from info request received")); + uint8_t *pid = &p->packet[9]; + if (*pid == 0x00) { + DPRINT(DBG_DEBUG, F("fragment number zero received and ignored")); + } else { + DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX)); + if ((*pid & 0x7F) < MAX_PAYLOAD_ENTRIES) { + memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], p->len - 11); + mPayload[iv->id].len[(*pid & 0x7F) - 1] = p->len - 11; + mPayload[iv->id].gotFragment = true; + } + + if ((*pid & ALL_FRAMES) == ALL_FRAMES) { + // Last packet + if (((*pid & 0x7f) > mPayload[iv->id].maxPackId) || (MAX_PAYLOAD_ENTRIES == mPayload[iv->id].maxPackId)) { + mPayload[iv->id].maxPackId = (*pid & 0x7f); + if (*pid > 0x81) + mPayload[iv->id].lastFound = true; + } + } + } + } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command + DPRINTLN(DBG_DEBUG, F("Response from devcontrol request received")); + + mPayload[iv->id].txId = p->packet[0]; + iv->clearDevControlRequest(); + + if ((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) { + String msg = ""; + if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) + mApp->setMqttPowerLimitAck(iv); + else + msg = "NOT "; + DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + iv->clearCmdQueue(); + iv->enqueCommand(SystemConfigPara); // read back power limit + } + iv->devControlCmd = Init; + }*/ + } + + void process(bool retransmit) { + for (uint8_t id = 0; id < mSys->getNumInverters(); id++) { + Inverter<> *iv = mSys->getInverterByPos(id); + if (NULL == iv) + continue; // skip to next inverter + + /*if ((mPayload[iv->id].txId != (TX_REQ_INFO + ALL_FRAMES)) && (0 != mPayload[iv->id].txId)) { + // no processing needed if txId is not 0x95 + mPayload[iv->id].complete = true; + continue; // skip to next inverter + } + + if (!mPayload[iv->id].complete) { + bool crcPass, pyldComplete; + crcPass = build(iv->id, &pyldComplete); + if (!crcPass && !pyldComplete) { // payload not complete + if ((mPayload[iv->id].requested) && (retransmit)) { + if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { + // This is required to prevent retransmissions without answer. + DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); + mPayload[iv->id].retransmits = mMaxRetrans; + } else if(iv->devControlCmd == ActivePowerContr) { + DPRINTLN(DBG_INFO, F("retransmit power limit")); + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); + } else { + if (mPayload[iv->id].retransmits < mMaxRetrans) { + mPayload[iv->id].retransmits++; + if(false == mPayload[iv->id].gotFragment) { + DPRINTLN(DBG_WARN, F("(#") + String(iv->id) + F(") nothing received")); + mPayload[iv->id].retransmits = mMaxRetrans; + } else { + for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) { + if (mPayload[iv->id].len[i] == 0) { + DPRINTLN(DBG_WARN, F("Frame ") + String(i + 1) + F(" missing: Request Retransmit")); + mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME + i), true); + break; // only request retransmit one frame per loop + } + yield(); + } + } + } + } + } + } else if(!crcPass && pyldComplete) { // crc error on complete Payload + if (mPayload[iv->id].retransmits < mMaxRetrans) { + mPayload[iv->id].retransmits++; + DPRINTLN(DBG_WARN, F("CRC Error: Request Complete Retransmit")); + mPayload[iv->id].txCmd = iv->getQueuedCmd(); + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") sendTimePacket 0x") + String(mPayload[iv->id].txCmd, HEX)); + mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); + } + } else { // payload complete + DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); + DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); + DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); + record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser + mPayload[iv->id].complete = true; + + uint8_t payload[128]; + uint8_t payloadLen = 0; + + memset(payload, 0, 128); + + for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { + memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); + payloadLen += (mPayload[iv->id].len[i]); + yield(); + } + payloadLen -= 2; + + if (mSerialDebug) { + DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): "); + mSys->Radio.dumpBuf(payload, payloadLen); + } + + if (NULL == rec) { + DPRINTLN(DBG_ERROR, F("record is NULL!")); + } else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { + if (mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) + mStat->rxSuccess++; + + rec->ts = mPayload[iv->id].ts; + for (uint8_t i = 0; i < rec->length; i++) { + iv->addValue(i, payload, rec); + yield(); + } + iv->doCalculations(); + notify(mPayload[iv->id].txCmd); + + if(AlarmData == mPayload[iv->id].txCmd) { + uint8_t i = 0; + uint16_t code; + uint32_t start, end; + while(1) { + code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); + if(0 == code) + break; + if (NULL != mCbAlarm) + (mCbAlarm)(code, start, end); + yield(); + } + } + } else { + DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); + mStat->rxFail++; + } + + iv->setQueuedCmdFinished(); + } + }*/ + yield(); + } + } + + private: + void notify(uint8_t val) { + if(NULL != mCbMiPayload) + (mCbMiPayload)(val); + } + + bool build(uint8_t id, bool *complete) { + /*DPRINTLN(DBG_VERBOSE, F("build")); + uint16_t crc = 0xffff, crcRcv = 0x0000; + if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) + mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; + + // check if all fragments are there + *complete = true; + for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) { + if(mPayload[id].len[i] == 0) + *complete = false; + } + if(!*complete) + return false; + + for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) { + if (mPayload[id].len[i] > 0) { + if (i == (mPayload[id].maxPackId - 1)) { + crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i] - 2, crc); + crcRcv = (mPayload[id].data[i][mPayload[id].len[i] - 2] << 8) | (mPayload[id].data[i][mPayload[id].len[i] - 1]); + } else + crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i], crc); + } + yield(); + } + + return (crc == crcRcv) ? true : false;*/ + return true; + } + + void reset(uint8_t id) { + DPRINTLN(DBG_INFO, "resetPayload: id: " + String(id)); + memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); + /* + mPayload[id].gotFragment = false; + mPayload[id].retransmits = 0; + mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; + mPayload[id].lastFound = false; + mPayload[id].complete = false;*/ + mPayload[id].txCmd = 0; + mPayload[id].requested = false; + mPayload[id].ts = *mTimestamp; + } + + IApp *mApp; + HMSYSTEM *mSys; + statistics_t *mStat; + uint8_t mMaxRetrans; + uint32_t *mTimestamp; + miPayload_t mPayload[MAX_NUM_INVERTERS]; + bool mSerialDebug; + + payloadListenerType mCbMiPayload; +}; + +#endif /*__MI_PAYLOAD_H__*/ diff --git a/src/web/html/index.html b/src/web/html/index.html index 6634197e..0e71fcf7 100644 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -62,7 +62,7 @@