From 53ae7fe7f5e6e98793972eb21e1c6db1e6fb9bb1 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 08:02:36 +0100 Subject: [PATCH 1/9] Mi dev control (#3) * MI - add devControl path to ivSend() * MI - review AC calc II Additionally code restructured to prepare for dev control (limitation, not working yet) --- src/hm/miPayload.h | 131 +++++++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 52 deletions(-) diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 62e7450e..a90b845d 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -68,49 +68,93 @@ class MiPayload { } void loop() { - /*if(NULL != mHighPrioIv) { - iv->ivSend(mHighPrioIv, true); // should request firmware version etc.? + if(NULL != mHighPrioIv) { + ivSend(mHighPrioIv, true); // for devcontrol commands? mHighPrioIv = NULL; - }*/ + } } void ivSendHighPrio(Inverter<> *iv) { mHighPrioIv = iv; } - void ivSend(Inverter<> *iv) { + void ivSend(Inverter<> *iv, bool highPrio = false) { + if(!highPrio) { + if (mPayload[iv->id].requested) { + if (!mPayload[iv->id].complete) + process(false); // no retransmit + + if (!mPayload[iv->id].complete) { + if (!mPayload[iv->id].gotFragment) + mStat->rxFailNoAnser++; // got nothing + else + mStat->rxFail++; // got fragments but not complete response + + iv->setQueuedCmdFinished(); // command failed + if (mSerialDebug) + DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); + if (mSerialDebug) { + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") no Payload received! (retransmits: ")); + DBGPRINT(String(mPayload[iv->id].retransmits)); + DBGPRINTLN(F(")")); + } + } + } + } + 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 = iv->getQueuedCmd(); - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") prepareDevInformCmd 0x")); - DBGPRINTLN(String(cmd, HEX)); - uint8_t cmd2 = cmd; - if (cmd == 0x1 ) { //0x1 - cmd = 0x0f; - cmd2 = 0x00; - mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); - } else { - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); - }; - - mPayload[iv->id].txCmd = cmd; - if (iv->type == INV_TYPE_1CH || iv->type == INV_TYPE_2CH) { - mPayload[iv->id].dataAB[CH1] = false; - mPayload[iv->id].stsAB[CH1] = false; - mPayload[iv->id].dataAB[CH0] = false; - mPayload[iv->id].stsAB[CH0] = false; + if (mSerialDebug){ + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") Requesting Inv SN ")); + DBGPRINTLN(String(iv->config->serial.u64, HEX)); } - if (iv->type == INV_TYPE_2CH) { - mPayload[iv->id].dataAB[CH2] = false; - mPayload[iv->id].stsAB[CH2] = false; + if (iv->getDevControlRequest()) { + if (mSerialDebug) { + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") Devcontrol request 0x")); + DBGPRINT(String(iv->devControlCmd, HEX)); + DBGPRINT(F(" power limit ")); + DBGPRINTLN(String(iv->powerLimit[0])); + } + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false); + mPayload[iv->id].txCmd = iv->devControlCmd; + //iv->clearCmdQueue(); + //iv->enqueCommand(SystemConfigPara); // read back power limit + } else { + uint8_t cmd = iv->getQueuedCmd(); + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") prepareDevInformCmd 0x")); + DBGPRINTLN(String(cmd, HEX)); + uint8_t cmd2 = cmd; + if (cmd == 0x1 ) { //0x1 + cmd = 0x0f; + cmd2 = 0x00; + mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); + } else { + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); + }; + + mPayload[iv->id].txCmd = cmd; + if (iv->type == INV_TYPE_1CH || iv->type == INV_TYPE_2CH) { + mPayload[iv->id].dataAB[CH1] = false; + mPayload[iv->id].stsAB[CH1] = false; + mPayload[iv->id].dataAB[CH0] = false; + mPayload[iv->id].stsAB[CH0] = false; + } + + if (iv->type == INV_TYPE_2CH) { + mPayload[iv->id].dataAB[CH2] = false; + mPayload[iv->id].stsAB[CH2] = false; + } } } @@ -118,7 +162,7 @@ class MiPayload { //DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX)); if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09 - miStsDecode(iv, p), CH1; + miStsDecode(iv, p); } else if (p->packet[0] == (0x11 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 @@ -573,27 +617,11 @@ const byteAssign_t InfoAssignment[] = { } - - if ( mPayload[iv->id].complete || //4ch device (iv->type != INV_TYPE_4CH //other devices && mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].stsAB[CH0])) { miComplete(iv); - /*mPayload[iv->id].complete = true; // For 2 CH devices, this might be too short... - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); - iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - //preliminary AC calculation... - uint8_t ac_pow = 0; - //if (mPayload[iv->id].sts[0] == 3) { - ac_pow = calcPowerDcCh0(iv, 0)*9.5; - //} - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); - iv->doCalculations(); - iv->setQueuedCmdFinished(); - mStat->rxSuccess++; - yield(); - notify(mPayload[iv->id].txCmd);*/ } @@ -619,18 +647,18 @@ const byteAssign_t InfoAssignment[] = { DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - //preliminary AC calculation... - uint8_t ac_pow = 0; + //preliminary AC calculation... + float ac_pow = 0; for(uint8_t i = 1; i <= iv->channels; i++) { if (mPayload[iv->id].sts[i] == 3) { uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); ac_pow += iv->getValue(pos, rec); } } - ac_pow = ac_pow*9.5; + ac_pow = (int) (ac_pow*9.5); + iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10); - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); iv->doCalculations(); iv->setQueuedCmdFinished(); mStat->rxSuccess++; @@ -695,7 +723,6 @@ const byteAssign_t InfoAssignment[] = { } - IApp *mApp; HMSYSTEM *mSys; statistics_t *mStat; From 12f37c2cb08129259036362cea216b7109bb314f Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 09:35:42 +0100 Subject: [PATCH 2/9] MI - add some multiframe handling --- src/hm/hmRadio.h | 5 ++++- src/hm/miPayload.h | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index f0236362..8f528784 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -253,7 +253,10 @@ class HmRadio { mBufCtrl.push(p); if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command isLastPackage = (p.packet[9] > 0x81); // > 0x81 indicates last packet received - else if (p.packet[0] != 0x00) // ignore fragment number zero + else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command + isLastPackage = (p.packet[9] > 0x11); // > 0x11 indicates last packet received + else if (p.packet[0] != 0x00 && p.packet[0] != 0x88 && p.packet[0] != 0x92) + // ignore fragment number zero and MI status messages isLastPackage = true; // response from dev control command yield(); } diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index a90b845d..931c9657 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -221,14 +221,16 @@ const byteAssign_t InfoAssignment[] = { for (uint8_t i = 0; i < 5; i++) { iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); } - iv->setQueuedCmdFinished(); + /*iv->setQueuedCmdFinished(); mStat->rxSuccess++; - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false); + mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ } else if ( p->packet[9] == 0x01 ) {//second frame DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got 2nd frame (hw info)")); - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); + //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); } else if ( p->packet[9] == 0x12 ) {//3rd frame DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got 3rd frame (hw info)")); + iv->setQueuedCmdFinished(); + mStat->rxSuccess++; } } else if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command @@ -723,6 +725,7 @@ const byteAssign_t InfoAssignment[] = { } + IApp *mApp; HMSYSTEM *mSys; statistics_t *mStat; From 3317265783e6a308c46cb4b46849892532caea88 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 16:48:57 +0100 Subject: [PATCH 3/9] MI - optimize serial output and resending logic --- hmRadio.h | 335 +++++++++++++++++++++++ miPayload.h | 757 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1092 insertions(+) create mode 100644 hmRadio.h create mode 100644 miPayload.h diff --git a/hmRadio.h b/hmRadio.h new file mode 100644 index 00000000..8f528784 --- /dev/null +++ b/hmRadio.h @@ -0,0 +1,335 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + +#ifndef __RADIO_H__ +#define __RADIO_H__ + +#include "../utils/dbg.h" +#include +#include "../utils/crc.h" +#include "../config/config.h" + +#define SPI_SPEED 1000000 + +#define RF_CHANNELS 5 + +#define TX_REQ_INFO 0x15 +#define TX_REQ_DEVCONTROL 0x51 +#define ALL_FRAMES 0x80 +#define SINGLE_FRAME 0x81 + +const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; + + +//----------------------------------------------------------------------------- +// MACROS +//----------------------------------------------------------------------------- +#define CP_U32_LittleEndian(buf, v) ({ \ + uint8_t *b = buf; \ + b[0] = ((v >> 24) & 0xff); \ + b[1] = ((v >> 16) & 0xff); \ + b[2] = ((v >> 8) & 0xff); \ + b[3] = ((v ) & 0xff); \ +}) + +#define CP_U32_BigEndian(buf, v) ({ \ + uint8_t *b = buf; \ + b[3] = ((v >> 24) & 0xff); \ + b[2] = ((v >> 16) & 0xff); \ + b[1] = ((v >> 8) & 0xff); \ + b[0] = ((v ) & 0xff); \ +}) + +#define BIT_CNT(x) ((x)<<3) + +//----------------------------------------------------------------------------- +// HM Radio class +//----------------------------------------------------------------------------- +template +class HmRadio { + public: + HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) { + DPRINT(DBG_VERBOSE, F("hmRadio.h : HmRadio():mNrf24(CE_PIN: ")); + DPRINT(DBG_VERBOSE, String(CE_PIN)); + DPRINT(DBG_VERBOSE, F(", CS_PIN: ")); + DPRINT(DBG_VERBOSE, String(CS_PIN)); + DPRINT(DBG_VERBOSE, F(", SPI_SPEED: ")); + DPRINTLN(DBG_VERBOSE, String(SPI_SPEED) + ")"); + + // Depending on the program, the module can work on 2403, 2423, 2440, 2461 or 2475MHz. + // Channel List 2403, 2423, 2440, 2461, 2475MHz + mRfChLst[0] = 03; + mRfChLst[1] = 23; + mRfChLst[2] = 40; + mRfChLst[3] = 61; + mRfChLst[4] = 75; + + // default channels + mTxChIdx = 2; // Start TX with 40 + mRxChIdx = 0; // Start RX with 03 + + mSendCnt = 0; + mRetransmits = 0; + + mSerialDebug = false; + mIrqRcvd = false; + } + ~HmRadio() {} + + void setup(uint8_t ampPwr = RF24_PA_LOW, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN) { + DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); + pinMode(irq, INPUT_PULLUP); + + uint32_t dtuSn = 0x87654321; + uint32_t chipID = 0; // will be filled with last 3 bytes of MAC + #ifdef ESP32 + uint64_t MAC = ESP.getEfuseMac(); + chipID = ((MAC >> 8) & 0xFF0000) | ((MAC >> 24) & 0xFF00) | ((MAC >> 40) & 0xFF); + #else + chipID = ESP.getChipId(); + #endif + if(chipID) { + dtuSn = 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal + for(int i = 0; i < 7; i++) { + dtuSn |= (chipID % 10) << (i * 4); + chipID /= 10; + } + } + // change the byte order of the DTU serial number and append the required 0x01 at the end + DTU_RADIO_ID = ((uint64_t)(((dtuSn >> 24) & 0xFF) | ((dtuSn >> 8) & 0xFF00) | ((dtuSn << 8) & 0xFF0000) | ((dtuSn << 24) & 0xFF000000)) << 8) | 0x01; + + mNrf24.begin(ce, cs); + mNrf24.setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms + + mNrf24.setChannel(mRfChLst[mRxChIdx]); + mNrf24.startListening(); + mNrf24.setDataRate(RF24_250KBPS); + mNrf24.setAutoAck(true); + mNrf24.enableDynamicPayloads(); + mNrf24.setCRCLength(RF24_CRC_16); + mNrf24.setAddressWidth(5); + mNrf24.openReadingPipe(1, DTU_RADIO_ID); + + // enable all receiving interrupts + mNrf24.maskIRQ(false, false, false); + + DPRINT(DBG_INFO, F("RF24 Amp Pwr: RF24_PA_")); + DPRINTLN(DBG_INFO, String(rf24AmpPowerNames[ampPwr])); + mNrf24.setPALevel(ampPwr & 0x03); + + if(mNrf24.isChipConnected()) { + DPRINTLN(DBG_INFO, F("Radio Config:")); + mNrf24.printPrettyDetails(); + } + else + DPRINTLN(DBG_WARN, F("WARNING! your NRF24 module can't be reached, check the wiring")); + } + + bool loop(void) { + if (!mIrqRcvd) + return false; // nothing to do + mIrqRcvd = false; + bool tx_ok, tx_fail, rx_ready; + mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH + mNrf24.flush_tx(); // empty TX FIFO + //DBGPRINTLN("TX whatHappened Ch" + String(mRfChLst[mTxChIdx]) + " " + String(tx_ok) + String(tx_fail) + String(rx_ready)); + + // start listening on the default RX channel + mRxChIdx = 0; + mNrf24.setChannel(mRfChLst[mRxChIdx]); + mNrf24.startListening(); + + //uint32_t debug_ms = millis(); + uint16_t cnt = 300; // that is 60 times 5 channels + while (0 < cnt--) { + uint32_t startMillis = millis(); + while (millis()-startMillis < 4) { // listen 4ms to each channel + if (mIrqRcvd) { + mIrqRcvd = false; + if (getReceived()) { // everything received + //DBGPRINTLN("RX finished Cnt: " + String(300-cnt) + " time used: " + String(millis()-debug_ms)+ " ms"); + return true; + } + } + yield(); + } + switchRxCh(); // switch to next RX channel + yield(); + } + // not finished but time is over + //DBGPRINTLN("RX not finished: 300 time used: " + String(millis()-debug_ms)+ " ms"); + return true; + } + + void handleIntr(void) { + mIrqRcvd = true; + } + + bool isChipConnected(void) { + //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:isChipConnected")); + return mNrf24.isChipConnected(); + } + void enableDebug() { + mSerialDebug = true; + } + + void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data, bool isRetransmit) { + DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); + DBGPRINTLN(String(cmd, HEX)); + initPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME); + uint8_t cnt = 10; + mTxBuf[cnt++] = cmd; // cmd -> 0 on, 1 off, 2 restart, 11 active power, 12 reactive power, 13 power factor + mTxBuf[cnt++] = 0x00; + if(cmd >= ActivePowerContr && cmd <= PFSet) { // ActivePowerContr, ReactivePowerContr, PFSet + mTxBuf[cnt++] = ((data[0] * 10) >> 8) & 0xff; // power limit + mTxBuf[cnt++] = ((data[0] * 10) ) & 0xff; // power limit + mTxBuf[cnt++] = ((data[1] ) >> 8) & 0xff; // setting for persistens handlings + mTxBuf[cnt++] = ((data[1] ) ) & 0xff; // setting for persistens handling + } + sendPacket(invId, cnt, isRetransmit, true); + } + + void prepareDevInformCmd(uint64_t invId, uint8_t cmd, uint32_t ts, uint16_t alarmMesId, bool isRetransmit, uint8_t reqfld=TX_REQ_INFO) { // might not be necessary to add additional arg. + DPRINTLN(DBG_DEBUG, F("prepareDevInformCmd 0x") + String(cmd, HEX)); + initPacket(invId, reqfld, ALL_FRAMES); + mTxBuf[10] = cmd; // cid + mTxBuf[11] = 0x00; + CP_U32_LittleEndian(&mTxBuf[12], ts); + if (cmd == RealTimeRunData_Debug || cmd == AlarmData ) { + mTxBuf[18] = (alarmMesId >> 8) & 0xff; + mTxBuf[19] = (alarmMesId ) & 0xff; + } + sendPacket(invId, 24, isRetransmit, true); + } + + void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t pid, bool isRetransmit) { + initPacket(invId, mid, pid); + sendPacket(invId, 10, isRetransmit, false); + } + + void dumpBuf(uint8_t buf[], uint8_t len) { + //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:dumpBuf")); + for(uint8_t i = 0; i < len; i++) { + DHEX(buf[i]); + DBGPRINT(" "); + } + DBGPRINTLN(""); + } + + uint8_t getDataRate(void) { + if(!mNrf24.isChipConnected()) + return 3; // unkown + return mNrf24.getDataRate(); + } + + bool isPVariant(void) { + return mNrf24.isPVariant(); + } + + std::queue mBufCtrl; + + uint32_t mSendCnt; + uint32_t mRetransmits; + + bool mSerialDebug; + + private: + bool getReceived(void) { + bool tx_ok, tx_fail, rx_ready; + mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH + //DBGPRINTLN("RX whatHappened Ch" + String(mRfChLst[mRxChIdx]) + " " + String(tx_ok) + String(tx_fail) + String(rx_ready)); + + bool isLastPackage = false; + while(mNrf24.available()) { + uint8_t len; + len = mNrf24.getDynamicPayloadSize(); // if payload size > 32, corrupt payload has been flushed + if (len > 0) { + packet_t p; + p.ch = mRfChLst[mRxChIdx]; + p.len = len; + mNrf24.read(p.packet, len); + mBufCtrl.push(p); + if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command + isLastPackage = (p.packet[9] > 0x81); // > 0x81 indicates last packet received + else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command + isLastPackage = (p.packet[9] > 0x11); // > 0x11 indicates last packet received + else if (p.packet[0] != 0x00 && p.packet[0] != 0x88 && p.packet[0] != 0x92) + // ignore fragment number zero and MI status messages + isLastPackage = true; // response from dev control command + yield(); + } + } + return isLastPackage; + } + + void switchRxCh() { + mNrf24.stopListening(); + // get next channel index + if(++mRxChIdx >= RF_CHANNELS) + mRxChIdx = 0; + mNrf24.setChannel(mRfChLst[mRxChIdx]); + mNrf24.startListening(); + } + + void initPacket(uint64_t invId, uint8_t mid, uint8_t pid) { + DPRINTLN(DBG_VERBOSE, F("initPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX)); + memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE); + mTxBuf[0] = mid; // message id + CP_U32_BigEndian(&mTxBuf[1], (invId >> 8)); + CP_U32_BigEndian(&mTxBuf[5], (DTU_RADIO_ID >> 8)); + mTxBuf[9] = pid; + } + + void sendPacket(uint64_t invId, uint8_t len, bool isRetransmit, bool clear=false) { + //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:sendPacket")); + //DPRINTLN(DBG_VERBOSE, "sent packet: #" + String(mSendCnt)); + + // append crc's + if (len > 10) { + // crc control data + uint16_t crc = ah::crc16(&mTxBuf[10], len - 10); + mTxBuf[len++] = (crc >> 8) & 0xff; + mTxBuf[len++] = (crc ) & 0xff; + } + // crc over all + mTxBuf[len] = ah::crc8(mTxBuf, len); + len++; + + if(mSerialDebug) { + DPRINT(DBG_INFO, F("TX ")); + DBGPRINT(String(len)); + DBGPRINT("B Ch"); + DBGPRINT(String(mRfChLst[mTxChIdx])); + DBGPRINT(F(" | ")); + dumpBuf(mTxBuf, len); + } + + mNrf24.stopListening(); + mNrf24.setChannel(mRfChLst[mTxChIdx]); + mNrf24.openWritingPipe(reinterpret_cast(&invId)); + mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response + + // switch TX channel for next packet + if(++mTxChIdx >= RF_CHANNELS) + mTxChIdx = 0; + + if(isRetransmit) + mRetransmits++; + else + mSendCnt++; + } + + volatile bool mIrqRcvd; + uint64_t DTU_RADIO_ID; + + uint8_t mRfChLst[RF_CHANNELS]; + uint8_t mTxChIdx; + uint8_t mRxChIdx; + + RF24 mNrf24; + uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; +}; + +#endif /*__RADIO_H__*/ diff --git a/miPayload.h b/miPayload.h new file mode 100644 index 00000000..7e32ea92 --- /dev/null +++ b/miPayload.h @@ -0,0 +1,757 @@ +//----------------------------------------------------------------------------- +// 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 "hmInverter.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]; + bool complete; + bool dataAB[3]; + bool stsAB[3]; + uint8_t sts[5]; + uint8_t txId; + uint8_t invId; + uint8_t retransmits; + uint8_t skipfirstrepeat; + bool gotFragment; + /* + uint8_t data[MAX_PAYLOAD_ENTRIES][MAX_RF_PAYLOAD_SIZE]; + uint8_t maxPackId; + bool lastFound;*/ +} 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; + mHighPrioIv = NULL; + mCbMiPayload = NULL; + } + + void enableSerialDebug(bool enable) { + mSerialDebug = enable; + } + + void addPayloadListener(miPayloadListenerType cb) { + mCbMiPayload = cb; + } + + void addAlarmListener(alarmListenerType cb) { + mCbMiAlarm = cb; + } + + void loop() { + if(NULL != mHighPrioIv) { + ivSend(mHighPrioIv, true); // for devcontrol commands? + mHighPrioIv = NULL; + } + } + + void ivSendHighPrio(Inverter<> *iv) { + mHighPrioIv = iv; + } + + void ivSend(Inverter<> *iv, bool highPrio = false) { + if(!highPrio) { + if (mPayload[iv->id].requested) { + if (!mPayload[iv->id].complete) + process(false); // no retransmit + + if (!mPayload[iv->id].complete) { + if (!mPayload[iv->id].gotFragment) + mStat->rxFailNoAnser++; // got nothing + else + mStat->rxFail++; // got fragments but not complete response + + iv->setQueuedCmdFinished(); // command failed + if (mSerialDebug) + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("enqueued cmd failed/timeout")); + if (mSerialDebug) { + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("no Payload received! (retransmits: ")); + DBGPRINT(String(mPayload[iv->id].retransmits)); + DBGPRINTLN(F(")")); + } + } + } + } + + reset(iv->id); + mPayload[iv->id].requested = true; + + yield(); + if (mSerialDebug){ + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("Requesting Inv SN ")); + DBGPRINTLN(String(iv->config->serial.u64, HEX)); + } + + if (iv->getDevControlRequest()) { + if (mSerialDebug) { + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("Devcontrol request 0x")); + DBGPRINT(String(iv->devControlCmd, HEX)); + DBGPRINT(F(" power limit ")); + DBGPRINTLN(String(iv->powerLimit[0])); + } + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false); + mPayload[iv->id].txCmd = iv->devControlCmd; + //iv->clearCmdQueue(); + //iv->enqueCommand(SystemConfigPara); // read back power limit + } else { + uint8_t cmd = iv->getQueuedCmd(); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("prepareDevInformCmd 0x")); + DBGPRINTLN(String(cmd, HEX)); + uint8_t cmd2 = cmd; + if (cmd == 0x1 ) { //0x1 + cmd = 0x0f; + cmd2 = 0x00; + mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); + } else { + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); + }; + + mPayload[iv->id].txCmd = cmd; + if (iv->type == INV_TYPE_1CH || iv->type == INV_TYPE_2CH) { + mPayload[iv->id].dataAB[CH1] = false; + mPayload[iv->id].stsAB[CH1] = false; + mPayload[iv->id].dataAB[CH0] = false; + mPayload[iv->id].stsAB[CH0] = false; + } + + if (iv->type == INV_TYPE_2CH) { + mPayload[iv->id].dataAB[CH2] = false; + mPayload[iv->id].stsAB[CH2] = false; + } + } + } + + void add(Inverter<> *iv, packet_t *p) { + //DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX)); + + if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09 + miStsDecode(iv, p); + } + + else if (p->packet[0] == (0x11 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 + miStsDecode(iv, p, CH2); + } + + else if ( p->packet[0] == 0x09 + ALL_FRAMES || + p->packet[0] == 0x11 + ALL_FRAMES || + ( p->packet[0] >= (0x36 + ALL_FRAMES) && p->packet[0] < (0x39 + SINGLE_FRAME) ) ) { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 + mPayload[iv->id].txId = p->packet[0]; + miDataDecode(iv,p); + } + + else if (p->packet[0] == ( 0x0f + ALL_FRAMES)) { + // MI response from get hardware information request + record_t<> *rec = iv->getRecordStruct(InverterDevInform_All); // choose the record structure + rec->ts = mPayload[iv->id].ts; + mPayload[iv->id].gotFragment = true; + +/* + Polling the device software and hardware version number command + start byte Command word routing address target address User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] + 0x7e 0x0f xx xx xx xx YY YY YY YY 0x00 CRC 0x7f + Command Receipt - First Frame + start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] + 0x7e 0x8f YY YY YY YY xx xx xx xx 0x00 USFWBuild_VER APPFWBuild_VER APPFWBuild_YYYY APPFWBuild_MMDD APPFWBuild_HHMM APPFW_PN HW_VER CRC 0x7f + Command Receipt - Second Frame + start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] + 0x7e 0x8f YY YY YY YY xx xx xx xx 0x01 HW_PN HW_FB_TLmValue HW_FB_ReSPRT HW_GridSamp_ResValule HW_ECapValue Matching_APPFW_PN CRC 0x7f + Command receipt - third frame + start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[15] byte[16] byte[17] byte[18] + 0x7e 0x8f YY YY YY YY xx xx xx xx 0x12 APPFW_MINVER HWInfoAddr PNInfoCRC_gusv PNInfoCRC_gusv CRC 0x7f +*/ + +/* +case InverterDevInform_All: + rec->length = (uint8_t)(HMINFO_LIST_LEN); + rec->assign = (byteAssign_t *)InfoAssignment; + rec->pyldLen = HMINFO_PAYLOAD_LEN; + break; +const byteAssign_t InfoAssignment[] = { + { FLD_FW_VERSION, UNIT_NONE, CH0, 0, 2, 1 }, + { FLD_FW_BUILD_YEAR, UNIT_NONE, CH0, 2, 2, 1 }, + { FLD_FW_BUILD_MONTH_DAY, UNIT_NONE, CH0, 4, 2, 1 }, + { FLD_FW_BUILD_HOUR_MINUTE, UNIT_NONE, CH0, 6, 2, 1 }, + { FLD_HW_ID, UNIT_NONE, CH0, 8, 2, 1 } +}; +*/ + + if ( p->packet[9] == 0x00 ) {//first frame + //FLD_FW_VERSION + for (uint8_t i = 0; i < 5; i++) { + iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); + } + /*iv->setQueuedCmdFinished(); + mStat->rxSuccess++; + mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ + } else if ( p->packet[9] == 0x01 ) {//second frame + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("got 2nd frame (hw info)")); + //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); + } else if ( p->packet[9] == 0x12 ) {//3rd frame + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("got 3rd frame (hw info)")); + iv->setQueuedCmdFinished(); + mStat->rxSuccess++; + } + + } else if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command + // atm, we just do nothing else than print out what we got... + // for decoding see xls- Data collection instructions - #147ff + 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")); + + iv->setQueuedCmdFinished(); + } //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 + miDPRINTHead(DBG_DEBUG, iv->id); + DBGPRINTLN(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])); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(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; + } else { // some other response; copied from hmPayload:process; might not be correct to do that here!!! + 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 != mCbMiAlarm) + (mCbMiAlarm)(code, start, end); + yield(); + } + } + } else { + DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); + mStat->rxFail++; + } + + iv->setQueuedCmdFinished(); + } + } + + 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 (IV_HM == iv->ivGen) // only process MI inverters + continue; // skip to next inverter + + if ( !mPayload[iv->id].complete && + (mPayload[iv->id].txId != (TX_REQ_INFO + ALL_FRAMES)) && + (mPayload[iv->id].txId < (0x36 + ALL_FRAMES)) && + (mPayload[iv->id].txId > (0x39 + ALL_FRAMES)) && + (mPayload[iv->id].txId != (0x09 + ALL_FRAMES)) && + (mPayload[iv->id].txId != (0x11 + ALL_FRAMES)) && + (mPayload[iv->id].txId != (0x88)) && + (mPayload[iv->id].txId != (0x92)) && + (mPayload[iv->id].txId != 0 )) { + // no processing needed if txId is not one of 0x95, 0x88, 0x89, 0x91, 0x92 or resonse to 0x36ff + mPayload[iv->id].complete = true; + continue; // skip to next inverter + } + + //delayed next message? + //mPayload[iv->id].skipfirstrepeat++; + if (mPayload[iv->id].skipfirstrepeat) { + mPayload[iv->id].skipfirstrepeat = 0; //reset counter*/ + continue; // skip to next inverter + } + + if (!mPayload[iv->id].complete) { + //DPRINTLN(DBG_INFO, F("Pyld incompl code")); //info for testing only + 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. + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); + mPayload[iv->id].retransmits = mMaxRetrans; + } else if(iv->devControlCmd == ActivePowerContr) { + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("retransmit power limit")); + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); + } else { + uint8_t cmd = mPayload[iv->id].txCmd; + if (mPayload[iv->id].retransmits < mMaxRetrans) { + mPayload[iv->id].retransmits++; + if( !mPayload[iv->id].gotFragment ) { + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("nothing received")); + mPayload[iv->id].retransmits = mMaxRetrans; + } else if ( cmd == 0x0f ) { + //hard/firmware request + mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x00, true); + //iv->setQueuedCmdFinished(); + //cmd = iv->getQueuedCmd(); + } else { + bool change = false; + if ( cmd >= 0x36 && cmd < 0x39 ) { // MI-1500 Data command + cmd++; // just request the next channel + change = true; + } else if ( cmd == 0x09 ) {//MI single or dual channel device + if ( mPayload[iv->id].dataAB[CH1] && iv->type == INV_TYPE_2CH ) { + if (!mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].retransmits<2) {} + //first try to get missing sts for first channel a second time + else if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) { + cmd = 0x11; + change = true; + mPayload[iv->id].retransmits = 0; //reset counter + } + } + } else if ( cmd == 0x11) { + if ( mPayload[iv->id].dataAB[CH2] ) { // data + status ch2 are there? + if (mPayload[iv->id].stsAB[CH2] && (!mPayload[iv->id].stsAB[CH1] || !mPayload[iv->id].dataAB[CH1])) { + cmd = 0x09; + change = true; + } + } + } + miDPRINTHead(DBG_INFO, iv->id); + if (change) { + DBGPRINT(F("next request is 0x")); + } else { + DBGPRINT(F("not complete: Request Retransmit 0x")); + } + DBGPRINTLN(String(cmd, HEX)); + //mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd, true); + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, true, cmd); + mPayload[iv->id].txCmd = cmd; + yield(); + } + } + } + } + } else if(!crcPass && pyldComplete) { // crc error on complete Payload + if (mPayload[iv->id].retransmits < mMaxRetrans) { + mPayload[iv->id].retransmits++; + miDPRINTHead(DBG_WARN, iv->id); + DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); + mPayload[iv->id].txCmd = iv->getQueuedCmd(); + miDPRINTHead(DBG_INFO, iv->id); + + DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); + } + } + /*else { // payload complete + //This tree is not really tested, most likely it's not truly 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 ac_pow = 0; + //if (mPayload[iv->id].sts[0] == 3) { + ac_pow = calcPowerDcCh0(iv, 0)*9.5; + //} + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser + iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); + DPRINTLN(DBG_INFO, F("process: compl. set of msgs detected")); + iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); + iv->doCalculations(); + //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); + } + + void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) { + //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX)); + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure + rec->ts = mPayload[iv->id].ts; + mPayload[iv->id].gotFragment = true; + mPayload[iv->id].txId = p->packet[0]; + + //uint8_t status = (p->packet[11] << 8) + p->packet[12]; + uint8_t status = (p->packet[9] << 8) + p->packet[10]; + //uint8_t stschan = p->packet[0] == 0x88 ? CH1 : CH2; + mPayload[iv->id].sts[stschan] = status; + mPayload[iv->id].stsAB[stschan] = true; + if (mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].stsAB[CH2]) + mPayload[iv->id].stsAB[CH0] = true; + if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) { + mPayload[iv->id].sts[0] = status; + iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status); + } + + if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ + iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? + + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); + iv->enqueCommand(AlarmData); + } + //mPayload[iv->id].skipfirstrepeat = 1; + if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0] && !mPayload[iv->id].complete) { + miComplete(iv); + } + } + + void miDataDecode(Inverter<> *iv, packet_t *p) { + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser + rec->ts = mPayload[iv->id].ts; + mPayload[iv->id].gotFragment = true; + + uint8_t datachan = ( p->packet[0] == 0x89 || p->packet[0] == (0x36 + ALL_FRAMES) ) ? CH1 : + ( p->packet[0] == 0x91 || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : + p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : + CH4; + //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") data msg 0x") + String(p->packet[0], HEX) + F(" channel ") + datachan); + // count in RF_communication_protocol.xlsx is with offset = -1 + iv->setValue(iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); + yield(); + iv->setValue(iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); + yield(); + iv->setValue(iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); + yield(); + iv->setValue(iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); + iv->setValue(iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); + yield(); + iv->setValue(iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); + yield(); + iv->setValue(iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); + iv->setValue(iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(iv, datachan))); + //AC Power is missing; we may have to calculate, as no respective data is in payload + + if ( datachan < 3 ) { + mPayload[iv->id].dataAB[datachan] = true; + } + if ( !mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].dataAB[CH2] && mPayload[iv->id].dataAB[CH2] ) { + mPayload[iv->id].dataAB[CH0] = true; + } + + if (p->packet[0] >= (0x36 + ALL_FRAMES) ) { + + /*For MI1500: + if (MI1500) { + STAT = (uint8_t)(p->packet[25] ); + FCNT = (uint8_t)(p->packet[26]); + FCODE = (uint8_t)(p->packet[27]); + }*/ + + uint8_t status = (uint8_t)(p->packet[23]); + mPayload[iv->id].sts[datachan] = status; + if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) { + mPayload[iv->id].sts[0] = status; + iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status); + } + + if (p->packet[0] < (0x39 + ALL_FRAMES) ) { + /*uint8_t cmd = p->packet[0] - ALL_FRAMES + 1; + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); + mPayload[iv->id].txCmd = cmd;*/ + mPayload[iv->id].complete = false; + } + + else if (p->packet[0] == (0x39 + ALL_FRAMES) ) { + /*uint8_t cmd = p->packet[0] - ALL_FRAMES + 1; + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); + mPayload[iv->id].txCmd = cmd;*/ + mPayload[iv->id].complete = true; + } + + //iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, calcMiSts(iv));yield(); + if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ + iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; + + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); + //iv->enqueCommand(AlarmData); + } + + } + + if ( mPayload[iv->id].complete || //4ch device + (iv->type != INV_TYPE_4CH //other devices + && mPayload[iv->id].dataAB[CH0] + && mPayload[iv->id].stsAB[CH0])) { + miComplete(iv); + } + + + +/* + 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 != mCbMiAlarm) + (mCbAlarm)(code, start, end); + yield(); + } + }*/ + } + + void miComplete(Inverter<> *iv) { + mPayload[iv->id].complete = true; // For 2 CH devices, this might be too short... + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); + iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); + + //preliminary AC calculation... + float ac_pow = 0; + for(uint8_t i = 1; i <= iv->channels; i++) { + if (mPayload[iv->id].sts[i] == 3) { + uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); + ac_pow += iv->getValue(pos, rec); + } + } + ac_pow = (int) (ac_pow*9.5); + iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10); + + iv->doCalculations(); + iv->setQueuedCmdFinished(); + mStat->rxSuccess++; + yield(); + notify(mPayload[iv->id].txCmd); + } + + 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 messages are there + + *complete = mPayload[id].complete; + uint8_t txCmd = mPayload[id].txCmd; + //uint8_t cmd = getQueuedCmd(); + if(!*complete) { + DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); // + F("cmd is 0x") + String(cmd, HEX)); + if (txCmd == 0x09 || txCmd == 0x11 || (txCmd >= 0x36 && txCmd <= 0x39)) + 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 miDPRINTHead(uint8_t lvl, uint8_t id) { + DPRINT(lvl, F("(#")); + DBGPRINT(String(id)); + DBGPRINT(F(") ")); + } + + void reset(uint8_t id) { + //DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); + miDPRINTHead(DBG_INFO, id); + DBGPRINTLN(F("resetPayload")); + memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); + mPayload[id].gotFragment = false; + /*mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; + mPayload[id].lastFound = false;*/ + mPayload[id].retransmits = 0; + mPayload[id].complete = false; + mPayload[id].dataAB[CH0] = true; //required for 1CH and 2CH devices + mPayload[id].dataAB[CH1] = true; //required for 1CH and 2CH devices + mPayload[id].dataAB[CH2] = true; //only required for 2CH devices + mPayload[id].stsAB[CH0] = true; //required for 1CH and 2CH devices + mPayload[id].stsAB[CH1] = true; //required for 1CH and 2CH devices + mPayload[id].stsAB[CH2] = true; //only required for 2CH devices + mPayload[id].txCmd = 0; + mPayload[id].skipfirstrepeat = 0; + mPayload[id].requested = false; + mPayload[id].ts = *mTimestamp; + mPayload[id].sts[0] = 0; + mPayload[id].sts[CH1] = 0; + mPayload[id].sts[CH2] = 0; + mPayload[id].sts[CH3] = 0; + mPayload[id].sts[CH4] = 0; + } + + + + IApp *mApp; + HMSYSTEM *mSys; + statistics_t *mStat; + uint8_t mMaxRetrans; + uint32_t *mTimestamp; + miPayload_t mPayload[MAX_NUM_INVERTERS]; + bool mSerialDebug; + + Inverter<> *mHighPrioIv; + alarmListenerType mCbMiAlarm; + payloadListenerType mCbMiPayload; +}; + +#endif /*__MI_PAYLOAD_H__*/ From a2f559d91eba5628e09a7260d27b0305656f7246 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 16:50:20 +0100 Subject: [PATCH 4/9] Delete miPayload.h wrong place... --- miPayload.h | 757 ---------------------------------------------------- 1 file changed, 757 deletions(-) delete mode 100644 miPayload.h diff --git a/miPayload.h b/miPayload.h deleted file mode 100644 index 7e32ea92..00000000 --- a/miPayload.h +++ /dev/null @@ -1,757 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 "hmInverter.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]; - bool complete; - bool dataAB[3]; - bool stsAB[3]; - uint8_t sts[5]; - uint8_t txId; - uint8_t invId; - uint8_t retransmits; - uint8_t skipfirstrepeat; - bool gotFragment; - /* - uint8_t data[MAX_PAYLOAD_ENTRIES][MAX_RF_PAYLOAD_SIZE]; - uint8_t maxPackId; - bool lastFound;*/ -} 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; - mHighPrioIv = NULL; - mCbMiPayload = NULL; - } - - void enableSerialDebug(bool enable) { - mSerialDebug = enable; - } - - void addPayloadListener(miPayloadListenerType cb) { - mCbMiPayload = cb; - } - - void addAlarmListener(alarmListenerType cb) { - mCbMiAlarm = cb; - } - - void loop() { - if(NULL != mHighPrioIv) { - ivSend(mHighPrioIv, true); // for devcontrol commands? - mHighPrioIv = NULL; - } - } - - void ivSendHighPrio(Inverter<> *iv) { - mHighPrioIv = iv; - } - - void ivSend(Inverter<> *iv, bool highPrio = false) { - if(!highPrio) { - if (mPayload[iv->id].requested) { - if (!mPayload[iv->id].complete) - process(false); // no retransmit - - if (!mPayload[iv->id].complete) { - if (!mPayload[iv->id].gotFragment) - mStat->rxFailNoAnser++; // got nothing - else - mStat->rxFail++; // got fragments but not complete response - - iv->setQueuedCmdFinished(); // command failed - if (mSerialDebug) - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("enqueued cmd failed/timeout")); - if (mSerialDebug) { - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINT(F("no Payload received! (retransmits: ")); - DBGPRINT(String(mPayload[iv->id].retransmits)); - DBGPRINTLN(F(")")); - } - } - } - } - - reset(iv->id); - mPayload[iv->id].requested = true; - - yield(); - if (mSerialDebug){ - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINT(F("Requesting Inv SN ")); - DBGPRINTLN(String(iv->config->serial.u64, HEX)); - } - - if (iv->getDevControlRequest()) { - if (mSerialDebug) { - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINT(F("Devcontrol request 0x")); - DBGPRINT(String(iv->devControlCmd, HEX)); - DBGPRINT(F(" power limit ")); - DBGPRINTLN(String(iv->powerLimit[0])); - } - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false); - mPayload[iv->id].txCmd = iv->devControlCmd; - //iv->clearCmdQueue(); - //iv->enqueCommand(SystemConfigPara); // read back power limit - } else { - uint8_t cmd = iv->getQueuedCmd(); - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINT(F("prepareDevInformCmd 0x")); - DBGPRINTLN(String(cmd, HEX)); - uint8_t cmd2 = cmd; - if (cmd == 0x1 ) { //0x1 - cmd = 0x0f; - cmd2 = 0x00; - mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); - } else { - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); - }; - - mPayload[iv->id].txCmd = cmd; - if (iv->type == INV_TYPE_1CH || iv->type == INV_TYPE_2CH) { - mPayload[iv->id].dataAB[CH1] = false; - mPayload[iv->id].stsAB[CH1] = false; - mPayload[iv->id].dataAB[CH0] = false; - mPayload[iv->id].stsAB[CH0] = false; - } - - if (iv->type == INV_TYPE_2CH) { - mPayload[iv->id].dataAB[CH2] = false; - mPayload[iv->id].stsAB[CH2] = false; - } - } - } - - void add(Inverter<> *iv, packet_t *p) { - //DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX)); - - if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09 - miStsDecode(iv, p); - } - - else if (p->packet[0] == (0x11 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 - miStsDecode(iv, p, CH2); - } - - else if ( p->packet[0] == 0x09 + ALL_FRAMES || - p->packet[0] == 0x11 + ALL_FRAMES || - ( p->packet[0] >= (0x36 + ALL_FRAMES) && p->packet[0] < (0x39 + SINGLE_FRAME) ) ) { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 - mPayload[iv->id].txId = p->packet[0]; - miDataDecode(iv,p); - } - - else if (p->packet[0] == ( 0x0f + ALL_FRAMES)) { - // MI response from get hardware information request - record_t<> *rec = iv->getRecordStruct(InverterDevInform_All); // choose the record structure - rec->ts = mPayload[iv->id].ts; - mPayload[iv->id].gotFragment = true; - -/* - Polling the device software and hardware version number command - start byte Command word routing address target address User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] - 0x7e 0x0f xx xx xx xx YY YY YY YY 0x00 CRC 0x7f - Command Receipt - First Frame - start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] - 0x7e 0x8f YY YY YY YY xx xx xx xx 0x00 USFWBuild_VER APPFWBuild_VER APPFWBuild_YYYY APPFWBuild_MMDD APPFWBuild_HHMM APPFW_PN HW_VER CRC 0x7f - Command Receipt - Second Frame - start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] - 0x7e 0x8f YY YY YY YY xx xx xx xx 0x01 HW_PN HW_FB_TLmValue HW_FB_ReSPRT HW_GridSamp_ResValule HW_ECapValue Matching_APPFW_PN CRC 0x7f - Command receipt - third frame - start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[15] byte[16] byte[17] byte[18] - 0x7e 0x8f YY YY YY YY xx xx xx xx 0x12 APPFW_MINVER HWInfoAddr PNInfoCRC_gusv PNInfoCRC_gusv CRC 0x7f -*/ - -/* -case InverterDevInform_All: - rec->length = (uint8_t)(HMINFO_LIST_LEN); - rec->assign = (byteAssign_t *)InfoAssignment; - rec->pyldLen = HMINFO_PAYLOAD_LEN; - break; -const byteAssign_t InfoAssignment[] = { - { FLD_FW_VERSION, UNIT_NONE, CH0, 0, 2, 1 }, - { FLD_FW_BUILD_YEAR, UNIT_NONE, CH0, 2, 2, 1 }, - { FLD_FW_BUILD_MONTH_DAY, UNIT_NONE, CH0, 4, 2, 1 }, - { FLD_FW_BUILD_HOUR_MINUTE, UNIT_NONE, CH0, 6, 2, 1 }, - { FLD_HW_ID, UNIT_NONE, CH0, 8, 2, 1 } -}; -*/ - - if ( p->packet[9] == 0x00 ) {//first frame - //FLD_FW_VERSION - for (uint8_t i = 0; i < 5; i++) { - iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); - } - /*iv->setQueuedCmdFinished(); - mStat->rxSuccess++; - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ - } else if ( p->packet[9] == 0x01 ) {//second frame - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("got 2nd frame (hw info)")); - //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); - } else if ( p->packet[9] == 0x12 ) {//3rd frame - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("got 3rd frame (hw info)")); - iv->setQueuedCmdFinished(); - mStat->rxSuccess++; - } - - } else if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - // atm, we just do nothing else than print out what we got... - // for decoding see xls- Data collection instructions - #147ff - 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")); - - iv->setQueuedCmdFinished(); - } //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 - miDPRINTHead(DBG_DEBUG, iv->id); - DBGPRINTLN(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])); - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(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; - } else { // some other response; copied from hmPayload:process; might not be correct to do that here!!! - 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 != mCbMiAlarm) - (mCbMiAlarm)(code, start, end); - yield(); - } - } - } else { - DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); - mStat->rxFail++; - } - - iv->setQueuedCmdFinished(); - } - } - - 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 (IV_HM == iv->ivGen) // only process MI inverters - continue; // skip to next inverter - - if ( !mPayload[iv->id].complete && - (mPayload[iv->id].txId != (TX_REQ_INFO + ALL_FRAMES)) && - (mPayload[iv->id].txId < (0x36 + ALL_FRAMES)) && - (mPayload[iv->id].txId > (0x39 + ALL_FRAMES)) && - (mPayload[iv->id].txId != (0x09 + ALL_FRAMES)) && - (mPayload[iv->id].txId != (0x11 + ALL_FRAMES)) && - (mPayload[iv->id].txId != (0x88)) && - (mPayload[iv->id].txId != (0x92)) && - (mPayload[iv->id].txId != 0 )) { - // no processing needed if txId is not one of 0x95, 0x88, 0x89, 0x91, 0x92 or resonse to 0x36ff - mPayload[iv->id].complete = true; - continue; // skip to next inverter - } - - //delayed next message? - //mPayload[iv->id].skipfirstrepeat++; - if (mPayload[iv->id].skipfirstrepeat) { - mPayload[iv->id].skipfirstrepeat = 0; //reset counter*/ - continue; // skip to next inverter - } - - if (!mPayload[iv->id].complete) { - //DPRINTLN(DBG_INFO, F("Pyld incompl code")); //info for testing only - 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. - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); - mPayload[iv->id].retransmits = mMaxRetrans; - } else if(iv->devControlCmd == ActivePowerContr) { - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("retransmit power limit")); - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); - } else { - uint8_t cmd = mPayload[iv->id].txCmd; - if (mPayload[iv->id].retransmits < mMaxRetrans) { - mPayload[iv->id].retransmits++; - if( !mPayload[iv->id].gotFragment ) { - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("nothing received")); - mPayload[iv->id].retransmits = mMaxRetrans; - } else if ( cmd == 0x0f ) { - //hard/firmware request - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x00, true); - //iv->setQueuedCmdFinished(); - //cmd = iv->getQueuedCmd(); - } else { - bool change = false; - if ( cmd >= 0x36 && cmd < 0x39 ) { // MI-1500 Data command - cmd++; // just request the next channel - change = true; - } else if ( cmd == 0x09 ) {//MI single or dual channel device - if ( mPayload[iv->id].dataAB[CH1] && iv->type == INV_TYPE_2CH ) { - if (!mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].retransmits<2) {} - //first try to get missing sts for first channel a second time - else if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) { - cmd = 0x11; - change = true; - mPayload[iv->id].retransmits = 0; //reset counter - } - } - } else if ( cmd == 0x11) { - if ( mPayload[iv->id].dataAB[CH2] ) { // data + status ch2 are there? - if (mPayload[iv->id].stsAB[CH2] && (!mPayload[iv->id].stsAB[CH1] || !mPayload[iv->id].dataAB[CH1])) { - cmd = 0x09; - change = true; - } - } - } - miDPRINTHead(DBG_INFO, iv->id); - if (change) { - DBGPRINT(F("next request is 0x")); - } else { - DBGPRINT(F("not complete: Request Retransmit 0x")); - } - DBGPRINTLN(String(cmd, HEX)); - //mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd, true); - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, true, cmd); - mPayload[iv->id].txCmd = cmd; - yield(); - } - } - } - } - } else if(!crcPass && pyldComplete) { // crc error on complete Payload - if (mPayload[iv->id].retransmits < mMaxRetrans) { - mPayload[iv->id].retransmits++; - miDPRINTHead(DBG_WARN, iv->id); - DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); - mPayload[iv->id].txCmd = iv->getQueuedCmd(); - miDPRINTHead(DBG_INFO, iv->id); - - DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); - } - } - /*else { // payload complete - //This tree is not really tested, most likely it's not truly 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 ac_pow = 0; - //if (mPayload[iv->id].sts[0] == 3) { - ac_pow = calcPowerDcCh0(iv, 0)*9.5; - //} - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); - DPRINTLN(DBG_INFO, F("process: compl. set of msgs detected")); - iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - iv->doCalculations(); - //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); - } - - void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) { - //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX)); - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure - rec->ts = mPayload[iv->id].ts; - mPayload[iv->id].gotFragment = true; - mPayload[iv->id].txId = p->packet[0]; - - //uint8_t status = (p->packet[11] << 8) + p->packet[12]; - uint8_t status = (p->packet[9] << 8) + p->packet[10]; - //uint8_t stschan = p->packet[0] == 0x88 ? CH1 : CH2; - mPayload[iv->id].sts[stschan] = status; - mPayload[iv->id].stsAB[stschan] = true; - if (mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].stsAB[CH2]) - mPayload[iv->id].stsAB[CH0] = true; - if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) { - mPayload[iv->id].sts[0] = status; - iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status); - } - - if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ - iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? - - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); - iv->enqueCommand(AlarmData); - } - //mPayload[iv->id].skipfirstrepeat = 1; - if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0] && !mPayload[iv->id].complete) { - miComplete(iv); - } - } - - void miDataDecode(Inverter<> *iv, packet_t *p) { - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser - rec->ts = mPayload[iv->id].ts; - mPayload[iv->id].gotFragment = true; - - uint8_t datachan = ( p->packet[0] == 0x89 || p->packet[0] == (0x36 + ALL_FRAMES) ) ? CH1 : - ( p->packet[0] == 0x91 || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : - p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : - CH4; - //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") data msg 0x") + String(p->packet[0], HEX) + F(" channel ") + datachan); - // count in RF_communication_protocol.xlsx is with offset = -1 - iv->setValue(iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); - yield(); - iv->setValue(iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); - yield(); - iv->setValue(iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); - yield(); - iv->setValue(iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); - iv->setValue(iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); - yield(); - iv->setValue(iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); - yield(); - iv->setValue(iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); - iv->setValue(iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(iv, datachan))); - //AC Power is missing; we may have to calculate, as no respective data is in payload - - if ( datachan < 3 ) { - mPayload[iv->id].dataAB[datachan] = true; - } - if ( !mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].dataAB[CH2] && mPayload[iv->id].dataAB[CH2] ) { - mPayload[iv->id].dataAB[CH0] = true; - } - - if (p->packet[0] >= (0x36 + ALL_FRAMES) ) { - - /*For MI1500: - if (MI1500) { - STAT = (uint8_t)(p->packet[25] ); - FCNT = (uint8_t)(p->packet[26]); - FCODE = (uint8_t)(p->packet[27]); - }*/ - - uint8_t status = (uint8_t)(p->packet[23]); - mPayload[iv->id].sts[datachan] = status; - if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) { - mPayload[iv->id].sts[0] = status; - iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status); - } - - if (p->packet[0] < (0x39 + ALL_FRAMES) ) { - /*uint8_t cmd = p->packet[0] - ALL_FRAMES + 1; - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); - mPayload[iv->id].txCmd = cmd;*/ - mPayload[iv->id].complete = false; - } - - else if (p->packet[0] == (0x39 + ALL_FRAMES) ) { - /*uint8_t cmd = p->packet[0] - ALL_FRAMES + 1; - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); - mPayload[iv->id].txCmd = cmd;*/ - mPayload[iv->id].complete = true; - } - - //iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, calcMiSts(iv));yield(); - if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ - iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; - - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); - //iv->enqueCommand(AlarmData); - } - - } - - if ( mPayload[iv->id].complete || //4ch device - (iv->type != INV_TYPE_4CH //other devices - && mPayload[iv->id].dataAB[CH0] - && mPayload[iv->id].stsAB[CH0])) { - miComplete(iv); - } - - - -/* - 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 != mCbMiAlarm) - (mCbAlarm)(code, start, end); - yield(); - } - }*/ - } - - void miComplete(Inverter<> *iv) { - mPayload[iv->id].complete = true; // For 2 CH devices, this might be too short... - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - - //preliminary AC calculation... - float ac_pow = 0; - for(uint8_t i = 1; i <= iv->channels; i++) { - if (mPayload[iv->id].sts[i] == 3) { - uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); - ac_pow += iv->getValue(pos, rec); - } - } - ac_pow = (int) (ac_pow*9.5); - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10); - - iv->doCalculations(); - iv->setQueuedCmdFinished(); - mStat->rxSuccess++; - yield(); - notify(mPayload[iv->id].txCmd); - } - - 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 messages are there - - *complete = mPayload[id].complete; - uint8_t txCmd = mPayload[id].txCmd; - //uint8_t cmd = getQueuedCmd(); - if(!*complete) { - DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); // + F("cmd is 0x") + String(cmd, HEX)); - if (txCmd == 0x09 || txCmd == 0x11 || (txCmd >= 0x36 && txCmd <= 0x39)) - 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 miDPRINTHead(uint8_t lvl, uint8_t id) { - DPRINT(lvl, F("(#")); - DBGPRINT(String(id)); - DBGPRINT(F(") ")); - } - - void reset(uint8_t id) { - //DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); - miDPRINTHead(DBG_INFO, id); - DBGPRINTLN(F("resetPayload")); - memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); - mPayload[id].gotFragment = false; - /*mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; - mPayload[id].lastFound = false;*/ - mPayload[id].retransmits = 0; - mPayload[id].complete = false; - mPayload[id].dataAB[CH0] = true; //required for 1CH and 2CH devices - mPayload[id].dataAB[CH1] = true; //required for 1CH and 2CH devices - mPayload[id].dataAB[CH2] = true; //only required for 2CH devices - mPayload[id].stsAB[CH0] = true; //required for 1CH and 2CH devices - mPayload[id].stsAB[CH1] = true; //required for 1CH and 2CH devices - mPayload[id].stsAB[CH2] = true; //only required for 2CH devices - mPayload[id].txCmd = 0; - mPayload[id].skipfirstrepeat = 0; - mPayload[id].requested = false; - mPayload[id].ts = *mTimestamp; - mPayload[id].sts[0] = 0; - mPayload[id].sts[CH1] = 0; - mPayload[id].sts[CH2] = 0; - mPayload[id].sts[CH3] = 0; - mPayload[id].sts[CH4] = 0; - } - - - - IApp *mApp; - HMSYSTEM *mSys; - statistics_t *mStat; - uint8_t mMaxRetrans; - uint32_t *mTimestamp; - miPayload_t mPayload[MAX_NUM_INVERTERS]; - bool mSerialDebug; - - Inverter<> *mHighPrioIv; - alarmListenerType mCbMiAlarm; - payloadListenerType mCbMiPayload; -}; - -#endif /*__MI_PAYLOAD_H__*/ From 95420e35de44492a8c7d0bf944b252519f70719d Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 16:50:37 +0100 Subject: [PATCH 5/9] Delete hmRadio.h wrong place... --- hmRadio.h | 335 ------------------------------------------------------ 1 file changed, 335 deletions(-) delete mode 100644 hmRadio.h diff --git a/hmRadio.h b/hmRadio.h deleted file mode 100644 index 8f528784..00000000 --- a/hmRadio.h +++ /dev/null @@ -1,335 +0,0 @@ -//----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ -//----------------------------------------------------------------------------- - -#ifndef __RADIO_H__ -#define __RADIO_H__ - -#include "../utils/dbg.h" -#include -#include "../utils/crc.h" -#include "../config/config.h" - -#define SPI_SPEED 1000000 - -#define RF_CHANNELS 5 - -#define TX_REQ_INFO 0x15 -#define TX_REQ_DEVCONTROL 0x51 -#define ALL_FRAMES 0x80 -#define SINGLE_FRAME 0x81 - -const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; - - -//----------------------------------------------------------------------------- -// MACROS -//----------------------------------------------------------------------------- -#define CP_U32_LittleEndian(buf, v) ({ \ - uint8_t *b = buf; \ - b[0] = ((v >> 24) & 0xff); \ - b[1] = ((v >> 16) & 0xff); \ - b[2] = ((v >> 8) & 0xff); \ - b[3] = ((v ) & 0xff); \ -}) - -#define CP_U32_BigEndian(buf, v) ({ \ - uint8_t *b = buf; \ - b[3] = ((v >> 24) & 0xff); \ - b[2] = ((v >> 16) & 0xff); \ - b[1] = ((v >> 8) & 0xff); \ - b[0] = ((v ) & 0xff); \ -}) - -#define BIT_CNT(x) ((x)<<3) - -//----------------------------------------------------------------------------- -// HM Radio class -//----------------------------------------------------------------------------- -template -class HmRadio { - public: - HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) { - DPRINT(DBG_VERBOSE, F("hmRadio.h : HmRadio():mNrf24(CE_PIN: ")); - DPRINT(DBG_VERBOSE, String(CE_PIN)); - DPRINT(DBG_VERBOSE, F(", CS_PIN: ")); - DPRINT(DBG_VERBOSE, String(CS_PIN)); - DPRINT(DBG_VERBOSE, F(", SPI_SPEED: ")); - DPRINTLN(DBG_VERBOSE, String(SPI_SPEED) + ")"); - - // Depending on the program, the module can work on 2403, 2423, 2440, 2461 or 2475MHz. - // Channel List 2403, 2423, 2440, 2461, 2475MHz - mRfChLst[0] = 03; - mRfChLst[1] = 23; - mRfChLst[2] = 40; - mRfChLst[3] = 61; - mRfChLst[4] = 75; - - // default channels - mTxChIdx = 2; // Start TX with 40 - mRxChIdx = 0; // Start RX with 03 - - mSendCnt = 0; - mRetransmits = 0; - - mSerialDebug = false; - mIrqRcvd = false; - } - ~HmRadio() {} - - void setup(uint8_t ampPwr = RF24_PA_LOW, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN) { - DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); - pinMode(irq, INPUT_PULLUP); - - uint32_t dtuSn = 0x87654321; - uint32_t chipID = 0; // will be filled with last 3 bytes of MAC - #ifdef ESP32 - uint64_t MAC = ESP.getEfuseMac(); - chipID = ((MAC >> 8) & 0xFF0000) | ((MAC >> 24) & 0xFF00) | ((MAC >> 40) & 0xFF); - #else - chipID = ESP.getChipId(); - #endif - if(chipID) { - dtuSn = 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal - for(int i = 0; i < 7; i++) { - dtuSn |= (chipID % 10) << (i * 4); - chipID /= 10; - } - } - // change the byte order of the DTU serial number and append the required 0x01 at the end - DTU_RADIO_ID = ((uint64_t)(((dtuSn >> 24) & 0xFF) | ((dtuSn >> 8) & 0xFF00) | ((dtuSn << 8) & 0xFF0000) | ((dtuSn << 24) & 0xFF000000)) << 8) | 0x01; - - mNrf24.begin(ce, cs); - mNrf24.setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms - - mNrf24.setChannel(mRfChLst[mRxChIdx]); - mNrf24.startListening(); - mNrf24.setDataRate(RF24_250KBPS); - mNrf24.setAutoAck(true); - mNrf24.enableDynamicPayloads(); - mNrf24.setCRCLength(RF24_CRC_16); - mNrf24.setAddressWidth(5); - mNrf24.openReadingPipe(1, DTU_RADIO_ID); - - // enable all receiving interrupts - mNrf24.maskIRQ(false, false, false); - - DPRINT(DBG_INFO, F("RF24 Amp Pwr: RF24_PA_")); - DPRINTLN(DBG_INFO, String(rf24AmpPowerNames[ampPwr])); - mNrf24.setPALevel(ampPwr & 0x03); - - if(mNrf24.isChipConnected()) { - DPRINTLN(DBG_INFO, F("Radio Config:")); - mNrf24.printPrettyDetails(); - } - else - DPRINTLN(DBG_WARN, F("WARNING! your NRF24 module can't be reached, check the wiring")); - } - - bool loop(void) { - if (!mIrqRcvd) - return false; // nothing to do - mIrqRcvd = false; - bool tx_ok, tx_fail, rx_ready; - mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH - mNrf24.flush_tx(); // empty TX FIFO - //DBGPRINTLN("TX whatHappened Ch" + String(mRfChLst[mTxChIdx]) + " " + String(tx_ok) + String(tx_fail) + String(rx_ready)); - - // start listening on the default RX channel - mRxChIdx = 0; - mNrf24.setChannel(mRfChLst[mRxChIdx]); - mNrf24.startListening(); - - //uint32_t debug_ms = millis(); - uint16_t cnt = 300; // that is 60 times 5 channels - while (0 < cnt--) { - uint32_t startMillis = millis(); - while (millis()-startMillis < 4) { // listen 4ms to each channel - if (mIrqRcvd) { - mIrqRcvd = false; - if (getReceived()) { // everything received - //DBGPRINTLN("RX finished Cnt: " + String(300-cnt) + " time used: " + String(millis()-debug_ms)+ " ms"); - return true; - } - } - yield(); - } - switchRxCh(); // switch to next RX channel - yield(); - } - // not finished but time is over - //DBGPRINTLN("RX not finished: 300 time used: " + String(millis()-debug_ms)+ " ms"); - return true; - } - - void handleIntr(void) { - mIrqRcvd = true; - } - - bool isChipConnected(void) { - //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:isChipConnected")); - return mNrf24.isChipConnected(); - } - void enableDebug() { - mSerialDebug = true; - } - - void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data, bool isRetransmit) { - DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); - DBGPRINTLN(String(cmd, HEX)); - initPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME); - uint8_t cnt = 10; - mTxBuf[cnt++] = cmd; // cmd -> 0 on, 1 off, 2 restart, 11 active power, 12 reactive power, 13 power factor - mTxBuf[cnt++] = 0x00; - if(cmd >= ActivePowerContr && cmd <= PFSet) { // ActivePowerContr, ReactivePowerContr, PFSet - mTxBuf[cnt++] = ((data[0] * 10) >> 8) & 0xff; // power limit - mTxBuf[cnt++] = ((data[0] * 10) ) & 0xff; // power limit - mTxBuf[cnt++] = ((data[1] ) >> 8) & 0xff; // setting for persistens handlings - mTxBuf[cnt++] = ((data[1] ) ) & 0xff; // setting for persistens handling - } - sendPacket(invId, cnt, isRetransmit, true); - } - - void prepareDevInformCmd(uint64_t invId, uint8_t cmd, uint32_t ts, uint16_t alarmMesId, bool isRetransmit, uint8_t reqfld=TX_REQ_INFO) { // might not be necessary to add additional arg. - DPRINTLN(DBG_DEBUG, F("prepareDevInformCmd 0x") + String(cmd, HEX)); - initPacket(invId, reqfld, ALL_FRAMES); - mTxBuf[10] = cmd; // cid - mTxBuf[11] = 0x00; - CP_U32_LittleEndian(&mTxBuf[12], ts); - if (cmd == RealTimeRunData_Debug || cmd == AlarmData ) { - mTxBuf[18] = (alarmMesId >> 8) & 0xff; - mTxBuf[19] = (alarmMesId ) & 0xff; - } - sendPacket(invId, 24, isRetransmit, true); - } - - void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t pid, bool isRetransmit) { - initPacket(invId, mid, pid); - sendPacket(invId, 10, isRetransmit, false); - } - - void dumpBuf(uint8_t buf[], uint8_t len) { - //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:dumpBuf")); - for(uint8_t i = 0; i < len; i++) { - DHEX(buf[i]); - DBGPRINT(" "); - } - DBGPRINTLN(""); - } - - uint8_t getDataRate(void) { - if(!mNrf24.isChipConnected()) - return 3; // unkown - return mNrf24.getDataRate(); - } - - bool isPVariant(void) { - return mNrf24.isPVariant(); - } - - std::queue mBufCtrl; - - uint32_t mSendCnt; - uint32_t mRetransmits; - - bool mSerialDebug; - - private: - bool getReceived(void) { - bool tx_ok, tx_fail, rx_ready; - mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH - //DBGPRINTLN("RX whatHappened Ch" + String(mRfChLst[mRxChIdx]) + " " + String(tx_ok) + String(tx_fail) + String(rx_ready)); - - bool isLastPackage = false; - while(mNrf24.available()) { - uint8_t len; - len = mNrf24.getDynamicPayloadSize(); // if payload size > 32, corrupt payload has been flushed - if (len > 0) { - packet_t p; - p.ch = mRfChLst[mRxChIdx]; - p.len = len; - mNrf24.read(p.packet, len); - mBufCtrl.push(p); - if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command - isLastPackage = (p.packet[9] > 0x81); // > 0x81 indicates last packet received - else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command - isLastPackage = (p.packet[9] > 0x11); // > 0x11 indicates last packet received - else if (p.packet[0] != 0x00 && p.packet[0] != 0x88 && p.packet[0] != 0x92) - // ignore fragment number zero and MI status messages - isLastPackage = true; // response from dev control command - yield(); - } - } - return isLastPackage; - } - - void switchRxCh() { - mNrf24.stopListening(); - // get next channel index - if(++mRxChIdx >= RF_CHANNELS) - mRxChIdx = 0; - mNrf24.setChannel(mRfChLst[mRxChIdx]); - mNrf24.startListening(); - } - - void initPacket(uint64_t invId, uint8_t mid, uint8_t pid) { - DPRINTLN(DBG_VERBOSE, F("initPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX)); - memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE); - mTxBuf[0] = mid; // message id - CP_U32_BigEndian(&mTxBuf[1], (invId >> 8)); - CP_U32_BigEndian(&mTxBuf[5], (DTU_RADIO_ID >> 8)); - mTxBuf[9] = pid; - } - - void sendPacket(uint64_t invId, uint8_t len, bool isRetransmit, bool clear=false) { - //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:sendPacket")); - //DPRINTLN(DBG_VERBOSE, "sent packet: #" + String(mSendCnt)); - - // append crc's - if (len > 10) { - // crc control data - uint16_t crc = ah::crc16(&mTxBuf[10], len - 10); - mTxBuf[len++] = (crc >> 8) & 0xff; - mTxBuf[len++] = (crc ) & 0xff; - } - // crc over all - mTxBuf[len] = ah::crc8(mTxBuf, len); - len++; - - if(mSerialDebug) { - DPRINT(DBG_INFO, F("TX ")); - DBGPRINT(String(len)); - DBGPRINT("B Ch"); - DBGPRINT(String(mRfChLst[mTxChIdx])); - DBGPRINT(F(" | ")); - dumpBuf(mTxBuf, len); - } - - mNrf24.stopListening(); - mNrf24.setChannel(mRfChLst[mTxChIdx]); - mNrf24.openWritingPipe(reinterpret_cast(&invId)); - mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response - - // switch TX channel for next packet - if(++mTxChIdx >= RF_CHANNELS) - mTxChIdx = 0; - - if(isRetransmit) - mRetransmits++; - else - mSendCnt++; - } - - volatile bool mIrqRcvd; - uint64_t DTU_RADIO_ID; - - uint8_t mRfChLst[RF_CHANNELS]; - uint8_t mTxChIdx; - uint8_t mRxChIdx; - - RF24 mNrf24; - uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; -}; - -#endif /*__RADIO_H__*/ From c3fce0af243b70b30f664f8be76986226d5d9a02 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 16:51:28 +0100 Subject: [PATCH 6/9] MI - optimize debug output and resending logic --- src/hm/miPayload.h | 89 +++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 931c9657..7e32ea92 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -92,11 +92,11 @@ class MiPayload { iv->setQueuedCmdFinished(); // command failed if (mSerialDebug) - DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("enqueued cmd failed/timeout")); if (mSerialDebug) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") no Payload received! (retransmits: ")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("no Payload received! (retransmits: ")); DBGPRINT(String(mPayload[iv->id].retransmits)); DBGPRINTLN(F(")")); } @@ -109,17 +109,15 @@ class MiPayload { yield(); if (mSerialDebug){ - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") Requesting Inv SN ")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("Requesting Inv SN ")); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } if (iv->getDevControlRequest()) { if (mSerialDebug) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") Devcontrol request 0x")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("Devcontrol request 0x")); DBGPRINT(String(iv->devControlCmd, HEX)); DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); @@ -130,9 +128,8 @@ class MiPayload { //iv->enqueCommand(SystemConfigPara); // read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") prepareDevInformCmd 0x")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("prepareDevInformCmd 0x")); DBGPRINTLN(String(cmd, HEX)); uint8_t cmd2 = cmd; if (cmd == 0x1 ) { //0x1 @@ -225,10 +222,12 @@ const byteAssign_t InfoAssignment[] = { mStat->rxSuccess++; mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ } else if ( p->packet[9] == 0x01 ) {//second frame - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got 2nd frame (hw info)")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("got 2nd frame (hw info)")); //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); } else if ( p->packet[9] == 0x12 ) {//3rd frame - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got 3rd frame (hw info)")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("got 3rd frame (hw info)")); iv->setQueuedCmdFinished(); mStat->rxSuccess++; } @@ -262,7 +261,8 @@ const byteAssign_t InfoAssignment[] = { } } */ } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command - DPRINTLN(DBG_DEBUG, F("Response from devcontrol request received")); + miDPRINTHead(DBG_DEBUG, iv->id); + DBGPRINTLN(F("Response from devcontrol request received")); mPayload[iv->id].txId = p->packet[0]; iv->clearDevControlRequest(); @@ -273,7 +273,10 @@ const byteAssign_t InfoAssignment[] = { 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])); + //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])); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(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 } @@ -376,21 +379,20 @@ const byteAssign_t InfoAssignment[] = { 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...")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINTLN(F(") retransmit power limit")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("retransmit power limit")); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); } else { uint8_t cmd = mPayload[iv->id].txCmd; if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; if( !mPayload[iv->id].gotFragment ) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINTLN(F(") nothing received")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("nothing received")); mPayload[iv->id].retransmits = mMaxRetrans; } else if ( cmd == 0x0f ) { //hard/firmware request @@ -404,23 +406,23 @@ const byteAssign_t InfoAssignment[] = { change = true; } else if ( cmd == 0x09 ) {//MI single or dual channel device if ( mPayload[iv->id].dataAB[CH1] && iv->type == INV_TYPE_2CH ) { - if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) { + if (!mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].retransmits<2) {} + //first try to get missing sts for first channel a second time + else if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) { cmd = 0x11; change = true; mPayload[iv->id].retransmits = 0; //reset counter } } } else if ( cmd == 0x11) { - if ( mPayload[iv->id].dataAB[CH2] ) { // data is there, but no status - if (!mPayload[iv->id].stsAB[CH1] || !mPayload[iv->id].dataAB[CH1] ) { + if ( mPayload[iv->id].dataAB[CH2] ) { // data + status ch2 are there? + if (mPayload[iv->id].stsAB[CH2] && (!mPayload[iv->id].stsAB[CH1] || !mPayload[iv->id].dataAB[CH1])) { cmd = 0x09; change = true; } } } - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") ")); + miDPRINTHead(DBG_INFO, iv->id); if (change) { DBGPRINT(F("next request is 0x")); } else { @@ -438,9 +440,12 @@ const byteAssign_t InfoAssignment[] = { } 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")); + miDPRINTHead(DBG_WARN, iv->id); + DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); + miDPRINTHead(DBG_INFO, iv->id); + + DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } @@ -516,7 +521,7 @@ const byteAssign_t InfoAssignment[] = { } void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) { - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX)); + //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX)); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure rec->ts = mPayload[iv->id].ts; mPayload[iv->id].gotFragment = true; @@ -537,7 +542,8 @@ const byteAssign_t InfoAssignment[] = { if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") alarm ID incremented to ") + String(iv->alarmMesIndex)); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); iv->enqueCommand(AlarmData); } //mPayload[iv->id].skipfirstrepeat = 1; @@ -555,7 +561,7 @@ const byteAssign_t InfoAssignment[] = { ( p->packet[0] == 0x91 || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : CH4; - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") data msg 0x") + String(p->packet[0], HEX) + F(" channel ") + datachan); + //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") data msg 0x") + String(p->packet[0], HEX) + F(" channel ") + datachan); // count in RF_communication_protocol.xlsx is with offset = -1 iv->setValue(iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); yield(); @@ -613,7 +619,8 @@ const byteAssign_t InfoAssignment[] = { if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; - DPRINTLN(DBG_INFO, F("alarm ID incremented to ") + String(iv->alarmMesIndex)); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); //iv->enqueCommand(AlarmData); } @@ -699,8 +706,16 @@ const byteAssign_t InfoAssignment[] = { return true; } + void miDPRINTHead(uint8_t lvl, uint8_t id) { + DPRINT(lvl, F("(#")); + DBGPRINT(String(id)); + DBGPRINT(F(") ")); + } + void reset(uint8_t id) { - DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); + //DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); + miDPRINTHead(DBG_INFO, id); + DBGPRINTLN(F("resetPayload")); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].gotFragment = false; /*mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; From d01b527eb4977316bd340e4d0306a7e0ab60edca Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 17:31:42 +0100 Subject: [PATCH 7/9] Debug: introduce DPRINTHEAD function --- src/utils/dbg.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/utils/dbg.h b/src/utils/dbg.h index bdfa2b15..b5cc57c6 100644 --- a/src/utils/dbg.h +++ b/src/utils/dbg.h @@ -146,6 +146,10 @@ }\ }) +#define DPRINTHEAD(level, id) ({\ + DPRINT(level, F("(#")); DBGPRINT(String(id)); DBGPRINT(F(") "));\ +}) + #define DPRINTLN(level, str) ({\ switch(level) {\ case DBG_ERROR: PERRLN(str); break; \ @@ -155,7 +159,6 @@ default: PVERBLN(str); break; \ }\ }) - /*class ahoyLog { public: ahoyLog() {} From ff93954612680399b7343901b8a9170e9d29bec0 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 17:32:56 +0100 Subject: [PATCH 8/9] use DPRINTHEAD for MI saves ~2+% of flash mem --- src/hm/miPayload.h | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 7e32ea92..64a345c4 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -92,10 +92,10 @@ class MiPayload { iv->setQueuedCmdFinished(); // command failed if (mSerialDebug) - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("enqueued cmd failed/timeout")); if (mSerialDebug) { - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINT(F("no Payload received! (retransmits: ")); DBGPRINT(String(mPayload[iv->id].retransmits)); DBGPRINTLN(F(")")); @@ -109,14 +109,14 @@ class MiPayload { yield(); if (mSerialDebug){ - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINT(F("Requesting Inv SN ")); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } if (iv->getDevControlRequest()) { if (mSerialDebug) { - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINT(F("Devcontrol request 0x")); DBGPRINT(String(iv->devControlCmd, HEX)); DBGPRINT(F(" power limit ")); @@ -128,7 +128,7 @@ class MiPayload { //iv->enqueCommand(SystemConfigPara); // read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINT(F("prepareDevInformCmd 0x")); DBGPRINTLN(String(cmd, HEX)); uint8_t cmd2 = cmd; @@ -222,11 +222,11 @@ const byteAssign_t InfoAssignment[] = { mStat->rxSuccess++; mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ } else if ( p->packet[9] == 0x01 ) {//second frame - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("got 2nd frame (hw info)")); //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); } else if ( p->packet[9] == 0x12 ) {//3rd frame - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("got 3rd frame (hw info)")); iv->setQueuedCmdFinished(); mStat->rxSuccess++; @@ -261,7 +261,7 @@ const byteAssign_t InfoAssignment[] = { } } */ } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command - miDPRINTHead(DBG_DEBUG, iv->id); + DPRINTHEAD(DBG_DEBUG, iv->id); DBGPRINTLN(F("Response from devcontrol request received")); mPayload[iv->id].txId = p->packet[0]; @@ -274,7 +274,7 @@ const byteAssign_t InfoAssignment[] = { 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])); - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); iv->clearCmdQueue(); @@ -379,11 +379,11 @@ const byteAssign_t InfoAssignment[] = { if ((mPayload[iv->id].requested) && (retransmit)) { if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("retransmit power limit")); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); } else { @@ -391,7 +391,7 @@ const byteAssign_t InfoAssignment[] = { if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; if( !mPayload[iv->id].gotFragment ) { - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("nothing received")); mPayload[iv->id].retransmits = mMaxRetrans; } else if ( cmd == 0x0f ) { @@ -422,7 +422,7 @@ const byteAssign_t InfoAssignment[] = { } } } - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); if (change) { DBGPRINT(F("next request is 0x")); } else { @@ -440,10 +440,10 @@ const byteAssign_t InfoAssignment[] = { } else if(!crcPass && pyldComplete) { // crc error on complete Payload if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; - miDPRINTHead(DBG_WARN, iv->id); + DPRINTHEAD(DBG_WARN, iv->id); DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); @@ -542,7 +542,7 @@ const byteAssign_t InfoAssignment[] = { if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); iv->enqueCommand(AlarmData); } @@ -619,7 +619,7 @@ const byteAssign_t InfoAssignment[] = { if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); //iv->enqueCommand(AlarmData); } @@ -706,15 +706,15 @@ const byteAssign_t InfoAssignment[] = { return true; } - void miDPRINTHead(uint8_t lvl, uint8_t id) { +/* void miDPRINTHead(uint8_t lvl, uint8_t id) { DPRINT(lvl, F("(#")); DBGPRINT(String(id)); DBGPRINT(F(") ")); - } + }*/ void reset(uint8_t id) { //DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); - miDPRINTHead(DBG_INFO, id); + DPRINTHEAD(DBG_INFO, id); DBGPRINTLN(F("resetPayload")); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].gotFragment = false; From a2f4807f5a4902fe4a188cb197fb8b9560b74589 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 17 Mar 2023 07:35:12 +0100 Subject: [PATCH 9/9] Move some fix texts to debug.h Add * DBGPRINT_TXT * DBGPRINTLN_TXT --- src/utils/dbg.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/utils/dbg.h b/src/utils/dbg.h index b5cc57c6..56623cf8 100644 --- a/src/utils/dbg.h +++ b/src/utils/dbg.h @@ -159,6 +159,38 @@ default: PVERBLN(str); break; \ }\ }) + +// available text variables +#define TXT_NOPYLD 1 +#define TXT_INVSERNO 2 +#define TXT_GDEVINF 3 +#define TXT_DEVCTRL 4 +#define TXT_INCRALM 5 + + +#define DBGPRINT_TXT(text) ({\ + switch(text) {\ + case TXT_NOPYLD: DBGPRINT(F("no Payload received! (retransmits: ")); break; \ + case TXT_INVSERNO: DBGPRINT(F("Requesting Inv SN ")); break; \ + case TXT_GDEVINF: DBGPRINT(F("prepareDevInformCmd 0x")); break; \ + case TXT_DEVCTRL: DBGPRINT(F("Devcontrol request 0x")); break; \ + case TXT_INCRALM: DBGPRINT(F("alarm ID incremented to ")); break; \ + default: ; break; \ + }\ +}) + +// available text variables w. lf +#define TXT_TIMEOUT 1 +#define TXT_NOPYLD2 2 + +#define DBGPRINTLN_TXT(text) ({\ + switch(text) {\ + case TXT_TIMEOUT: DBGPRINT(F("enqueued cmd failed/timeout\r\n")); break; \ + case TXT_NOPYLD2: DBGPRINT(F("nothing received\r\n")); break; \ + default: ; break; \ + }\ +}) + /*class ahoyLog { public: ahoyLog() {}