From 96f181c6625cfe61d4adec81efc9a846d9fb529f Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 18 Oct 2023 22:39:41 +0200 Subject: [PATCH 1/3] some improvements --- src/app.cpp | 20 +++++++++++--------- src/hm/CommQueue.h | 7 +++++++ src/hm/Communication.h | 35 ++++++++++++++++++++++++----------- src/hm/hmInverter.h | 6 +++--- 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 44d8ab30..9cbe06a1 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -413,13 +413,15 @@ void app::tickSend(void) { for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { Inverter<> *iv = mSys.getInverterByPos(i); if(NULL != iv) { - iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { - if(isDevControl) - mCommunication.addImportant(iv, cmd); - else - mCommunication.add(iv, cmd); - }); - }; + if(iv->config->enabled) { + iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { + if(isDevControl) + mCommunication.addImportant(iv, cmd); + else + mCommunication.add(iv, cmd); + }); + } + } } /*if(mConfig->nrf.enabled) { @@ -468,9 +470,9 @@ void app::tickSend(void) { if (mConfig->serial.debug) DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!")); } - yield(); + yield();*/ - updateLed();*/ + updateLed(); } //----------------------------------------------------------------------------- diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 9c9da707..94cc63bd 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -44,6 +44,13 @@ class CommQueue { inc(&mWrPtr); } + void add(const queue_s *q, bool rstAttempts = false) { + mQueue[mWrPtr] = *q; + if(rstAttempts) + mQueue[mWrPtr].attempts = 5; + inc(&mWrPtr); + } + void get(std::function cb) { if(mRdPtr == mWrPtr) { cb(false, &mQueue[mRdPtr]); // empty diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 4cdf0beb..81dc763c 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -112,7 +112,8 @@ class Communication : public CommQueue<> { parseDevCtrl(p, q); cmdDone(true); // remove done request } - } + } else + DPRINTLN(DBG_WARN, F("Inverter serial does not match")); q->iv->radio->mBufCtrl.pop(); yield(); @@ -126,7 +127,7 @@ class Communication : public CommQueue<> { setAttempt(); DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("last frame missing: request retransmit (")); + DBGPRINT(F("frame missing: request retransmit (")); DBGPRINT(String(q->attempts)); DBGPRINTLN(F(" attempts left)")); @@ -136,11 +137,17 @@ class Communication : public CommQueue<> { break; } - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); - q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + 500; - mState = States::WAIT; - break; + if(q->attempts) { + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + 500; + mState = States::WAIT; + } else { + add(q, true); + cmdDone(q); + mState = States::RESET; + } + return; } for(uint8_t i = 0; i < mMaxFrameId; i++) { @@ -154,10 +161,16 @@ class Communication : public CommQueue<> { DBGPRINT(String(q->attempts)); DBGPRINTLN(F(" attempts left)")); - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); - q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + 500; - mState = States::WAIT; + if(q->attempts) { + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + 500; + mState = States::WAIT; + } else { + add(q, true); + cmdDone(q); + mState = States::RESET; + } return; } } diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 5e3e4266..45b861a7 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -617,9 +617,9 @@ class Inverter { uint32_t startTimeOffset = 0, endTimeOffset = 0; uint32_t start, endTime; - if (((wCode >> 13) & 0x01) == 1) // check if is AM or PM - startTimeOffset = 12 * 60 * 60; - if (((wCode >> 12) & 0x01) == 1) // check if is AM or PM + // check if is AM or PM + startTimeOffset = ((wCode >> 13) & 0x01) * 12 * 60 * 60; + if (((wCode >> 12) & 0x03) != 0) endTimeOffset = 12 * 60 * 60; start = (((uint16_t)pyld[startOff + 4] << 8) | ((uint16_t)pyld[startOff + 5])) + startTimeOffset; From 1b965d67a850d41be6a97eef72a9bab557057ddd Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 18 Oct 2023 23:11:46 +0200 Subject: [PATCH 2/3] added MI additions / corrections from @rejoe2 --- src/hm/Communication.h | 79 ++++++++++++++++++++++++++++++++++++++++-- src/hm/hmDefines.h | 4 +++ src/hm/hmInverter.h | 42 +++++++++++++++------- src/hm/hmRadio.h | 26 ++++++++------ src/hm/radio.h | 11 +++++- src/hms/hmsRadio.h | 6 +++- 6 files changed, 141 insertions(+), 27 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 81dc763c..1336e78c 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -71,7 +71,8 @@ class Communication : public CommQueue<> { case States::CHECK_FRAMES: { if(!q->iv->radio->get()) { // radio buffer empty cmdDone(); - DPRINT(DBG_INFO, F("request timeout: ")); + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("request timeout: ")); DBGPRINT(String(millis() - mWaitTimeout + 500)); DBGPRINTLN(F("ms")); @@ -90,11 +91,15 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("RX ")); + if(p->millis < 100) + DBGPRINT(F("0")); DBGPRINT(String(p->millis)); DBGPRINT(F("ms ")); DBGPRINT(String(p->len)); - if(IV_HM == q->iv->ivGen) { + if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { DBGPRINT(F(" CH")); + if(3 == p->ch) + DBGPRINT(F("0")); DBGPRINT(String(p->ch)); } DBGPRINT(F(", ")); @@ -111,6 +116,8 @@ class Communication : public CommQueue<> { } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command parseDevCtrl(p, q); cmdDone(true); // remove done request + } else if(IV_MI == q->iv->ivGen) { + parseMiFrame(p, q); } } else DPRINTLN(DBG_WARN, F("Inverter serial does not match")); @@ -227,6 +234,74 @@ class Communication : public CommQueue<> { f->rssi = p->rssi; } + inline void parseMiFrame(packet_t *p, const queue_s *q) { + if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) + || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) + || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) + && (p->packet[0] < (0x39 + SINGLE_FRAME)) + && (q->cmd != 0x0f))) { + // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 + //mPayload[iv->id].txId = p->packet[0]; + miDataDecode(p, q); + + } + } + + inline void miDataDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser + //rec->ts = mPayload[iv->id].ts; + //mPayload[iv->id].gotFragment = true; + //mPayload[iv->id].multi_parts += 4; + + uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : + ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : + p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : + CH4; + // count in RF_communication_protocol.xlsx is with offset = -1 + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); + //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + + /*if ( datachan < 3 ) { + mPayload[q->iv->id].dataAB[datachan] = true; + } + if ( !mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].dataAB[CH1] && mPayload[iv->id].dataAB[CH2] ) { + mPayload[iv->id].dataAB[CH0] = true; + }*/ + + if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { + /*For MI1500: + if (MI1500) { + STAT = (uint8_t)(p->packet[25] ); + FCNT = (uint8_t)(p->packet[26]); + FCODE = (uint8_t)(p->packet[27]); + }*/ + //miStsConsolidate(iv, datachan, rec, p->packet[23], p->packet[24]); + + if (p->packet[0] < (0x39 + ALL_FRAMES) ) { + addImportant(q->iv, (q->cmd + 1)); + //mPayload[iv->id].txCmd++; + //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response + //mPayload[iv->id].complete = false; + } else { + //miComplete(iv); + } + } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && q->iv->type == INV_TYPE_2CH ) { + addImportant(q->iv, MI_REQ_CH2); + } + } + inline void parseDevCtrl(packet_t *p, const queue_s *q) { if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) return; diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index acd81541..c00f4940 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -346,4 +346,8 @@ const devInfo_t devInfo[] = { { 0x103331, 2250 } }; +#define MI_REQ_CH1 0x09 +#define MI_REQ_CH2 0x11 +#define MI_REQ_4CH 0x36 + #endif /*__HM_DEFINES_H__*/ diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 45b861a7..618cf5da 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -182,19 +182,35 @@ class Inverter { } void tickSend(std::function cb) { - if(mDevControlRequest) { - cb(devControlCmd, true); - mDevControlRequest = false; - } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) - cb(AlarmData, false); // get last alarms - else if(0 == getFwVersion()) - cb(InverterDevInform_All, false); // get firmware version - else if(0 == getHwVersion()) - cb(InverterDevInform_Simple, false); // get hardware version - else if(actPowerLimit == 0xffff) - cb(SystemConfigPara, false); // power limit info - else - cb(RealTimeRunData_Debug, false); // get live data + if (IV_MI != ivGen) { + if(mDevControlRequest) { + cb(devControlCmd, true); + mDevControlRequest = false; + } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) + cb(AlarmData, false); // get last alarms + else if(0 == getFwVersion()) + cb(InverterDevInform_All, false); // get firmware version + else if(0 == getHwVersion()) + cb(InverterDevInform_Simple, false); // get hardware version + else if(actPowerLimit == 0xffff) + cb(SystemConfigPara, false); // power limit info + else + cb(RealTimeRunData_Debug, false); // get live data + } else { + if(mDevControlRequest) { + cb(devControlCmd, true); + mDevControlRequest = false; + } else if(0 == getFwVersion()) + cb(MI_REQ_CH1, false); // get firmware version + //cb(InverterDevInform_All, false); // get firmware version + else { + record_t<> *rec = getRecordStruct(InverterDevInform_Simple); + if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) + cb(InverterDevInform_All, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 + else + cb(type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, false); + } + } } /*template diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 461fd08e..3d74222d 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -117,24 +117,24 @@ class HmRadio : public Radio { mNrf24.setChannel(mRfChLst[mRxChIdx]); mNrf24.startListening(); - uint32_t startMicros = micros(); + uint32_t startMicros = micros() + 5110; uint32_t loopMillis = millis() + 400; while (millis() < loopMillis) { - while (micros()-startMicros < 5110) { // listen (4088us or?) 5110us to each channel + while (micros() < startMicros) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; - if (getReceived()) { // everything received + + if (getReceived()) // everything received return; - } + } yield(); } // switch to next RX channel - startMicros = micros(); if(++mRxChIdx >= RF_CHANNELS) mRxChIdx = 0; mNrf24.setChannel(mRfChLst[mRxChIdx]); - yield(); + startMicros = micros() + 5000; } // not finished but time is over return; @@ -145,12 +145,13 @@ class HmRadio : public Radio { return mNrf24.isChipConnected(); } - void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) { - DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); + void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) { + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("sendControlPacket cmd: 0x")); DBGHEXLN(cmd); initPacket(iv->radioId.u64, TX_REQ_DEVCONTROL, SINGLE_FRAME); uint8_t cnt = 10; - if (isNoMI) { + if (IV_MI != iv->ivGen) { 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 @@ -160,6 +161,7 @@ class HmRadio : public Radio { mTxBuf[cnt++] = ((data[1] ) ) & 0xff; // setting for persistens handling } } else { //MI 2nd gen. specific + uint16_t powerMax = ((iv->powerLimit[1] == RelativNonPersistent) ? 0 : iv->getMaxPower()); switch (cmd) { case Restart: case TurnOn: @@ -225,7 +227,7 @@ class HmRadio : public Radio { } cnt++; } - sendPacket(iv, cnt, isRetransmit, isNoMI); + sendPacket(iv, cnt, isRetransmit, (IV_MI != iv->ivGen)); } uint8_t getDataRate(void) { @@ -297,6 +299,10 @@ class HmRadio : public Radio { return iv->radioId.u64; } + uint8_t getIvGen(Inverter<> *iv) { + return iv->ivGen; + } + uint64_t DTU_RADIO_ID; uint8_t mRfChLst[RF_CHANNELS]; uint8_t mTxChIdx; diff --git a/src/hm/radio.h b/src/hm/radio.h index 2096f108..75db5436 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -21,7 +21,7 @@ class Inverter; // abstract radio interface class Radio { public: - virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) = 0; + virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) = 0; virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } virtual void loop(void) {}; @@ -43,6 +43,14 @@ class Radio { } void prepareDevInformCmd(Inverter<> *iv, 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. + if(IV_MI == getIvGen(iv)) { + DPRINT_IVID(DBG_INFO, getIvId(iv)); + DBGPRINT(F("legacy cmd 0x")); + DBGHEXLN(cmd); + sendCmdPacket(iv, cmd, cmd, false, false); + return; + } + if(mSerialDebug) { DPRINT(DBG_DEBUG, F("prepareDevInformCmd 0x")); DPRINTLN(DBG_DEBUG,String(cmd, HEX)); @@ -63,6 +71,7 @@ class Radio { protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; virtual uint64_t getIvId(Inverter<> *iv) = 0; + virtual uint8_t getIvGen(Inverter<> *iv) = 0; void initPacket(uint64_t ivId, uint8_t mid, uint8_t pid) { mTxBuf[0] = mid; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 24c3c7cd..097a3f03 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -44,7 +44,7 @@ class CmtRadio : public Radio { return mCmtAvail; } - void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) { + void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) { DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); DBGHEXLN(cmd); initPacket(iv->radioId.u64, TX_REQ_DEVCONTROL, SINGLE_FRAME); @@ -101,6 +101,10 @@ class CmtRadio : public Radio { return iv->radioId.u64; } + uint8_t getIvGen(Inverter<> *iv) { + return iv->ivGen; + } + inline void reset(bool genDtuSn) { if(genDtuSn) generateDtuSn(); From 70b2ae6246505baf68f937063d90a046c934204a Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 20 Oct 2023 23:10:50 +0200 Subject: [PATCH 3/3] updated to latest changes from @rejoe2 for MI inverters --- src/hm/CommQueue.h | 2 +- src/hm/Communication.h | 315 ++++++++++++++++++++++++++++++++--------- src/hm/hmInverter.h | 7 +- 3 files changed, 252 insertions(+), 72 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 94cc63bd..56e06bfc 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -30,9 +30,9 @@ class CommQueue { Inverter<> *iv; uint8_t cmd; uint8_t attempts; + uint32_t ts; bool delOnPop; bool isDevControl; - uint32_t ts; queue_s() {} queue_s(Inverter<> *i, uint8_t c, bool d, bool dev) : iv(i), cmd(c), attempts(5), ts(0), delOnPop(d), isDevControl(dev) {} diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 1336e78c..5a5e0b7d 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -10,6 +10,9 @@ #include #include "../utils/crc.h" +#define MI_TIMEOUT 500 +#define DEFAULT_TIMEOUT 500 + typedef std::function *)> payloadListenerType; typedef std::function *)> alarmListenerType; @@ -37,6 +40,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty + uint16_t timeout = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT; + switch(mState) { case States::RESET: if(millis() < mWaitTimeout) @@ -57,7 +62,7 @@ class Communication : public CommQueue<> { } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); q->iv->radioStatistics.txCnt++; - mWaitTimeout = millis() + 500; + mWaitTimeout = millis() + timeout; setAttempt(); mState = States::WAIT; break; @@ -73,7 +78,7 @@ class Communication : public CommQueue<> { cmdDone(); DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); - DBGPRINT(String(millis() - mWaitTimeout + 500)); + DBGPRINT(String(millis() - mWaitTimeout + timeout)); DBGPRINTLN(F("ms")); q->iv->radioStatistics.rxFailNoAnser++; // got nothing @@ -92,7 +97,7 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("RX ")); if(p->millis < 100) - DBGPRINT(F("0")); + DBGPRINT(F(" ")); DBGPRINT(String(p->millis)); DBGPRINT(F("ms ")); DBGPRINT(String(p->len)); @@ -119,13 +124,20 @@ class Communication : public CommQueue<> { } else if(IV_MI == q->iv->ivGen) { parseMiFrame(p, q); } - } else + } else { DPRINTLN(DBG_WARN, F("Inverter serial does not match")); + mWaitTimeout = millis() + timeout; + } q->iv->radio->mBufCtrl.pop(); yield(); } - mState = nextState; + if(0 == q->attempts) { + cmdDone(q); + mState = States::RESET; + } else + mState = nextState; + } break; @@ -140,14 +152,15 @@ class Communication : public CommQueue<> { uint8_t i = 0; while(i < MAX_PAYLOAD_ENTRIES) { - if(mLocalBuf[i++].len == 0) + if(mLocalBuf[i].len == 0) break; + i++; } if(q->attempts) { - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + 500; + mWaitTimeout = millis() + timeout; mState = States::WAIT; } else { add(q, true); @@ -169,9 +182,9 @@ class Communication : public CommQueue<> { DBGPRINTLN(F(" attempts left)")); if(q->attempts) { - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + 500; + mWaitTimeout = millis() + timeout; mState = States::WAIT; } else { add(q, true); @@ -243,62 +256,12 @@ class Communication : public CommQueue<> { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 //mPayload[iv->id].txId = p->packet[0]; miDataDecode(p, q); - - } - } - - inline void miDataDecode(packet_t *p, const queue_s *q) { - record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser - //rec->ts = mPayload[iv->id].ts; - //mPayload[iv->id].gotFragment = true; - //mPayload[iv->id].multi_parts += 4; - - uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : - ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : - p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : - CH4; - // count in RF_communication_protocol.xlsx is with offset = -1 - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); - - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); - - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); - q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); - //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; - - /*if ( datachan < 3 ) { - mPayload[q->iv->id].dataAB[datachan] = true; - } - if ( !mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].dataAB[CH1] && mPayload[iv->id].dataAB[CH2] ) { - mPayload[iv->id].dataAB[CH0] = true; - }*/ - - if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { - /*For MI1500: - if (MI1500) { - STAT = (uint8_t)(p->packet[25] ); - FCNT = (uint8_t)(p->packet[26]); - FCODE = (uint8_t)(p->packet[27]); - }*/ - //miStsConsolidate(iv, datachan, rec, p->packet[23], p->packet[24]); - - if (p->packet[0] < (0x39 + ALL_FRAMES) ) { - addImportant(q->iv, (q->cmd + 1)); - //mPayload[iv->id].txCmd++; - //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response - //mPayload[iv->id].complete = false; - } else { - //miComplete(iv); - } - } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && q->iv->type == INV_TYPE_2CH ) { - addImportant(q->iv, MI_REQ_CH2); + } else if (p->packet[0] == (0x0f + ALL_FRAMES)) + miHwDecode(p, q); + else if ((p->packet[0] == 0x88) || (p->packet[0] == 0x92)) { + record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure + rec->ts = q->ts; + miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); } } @@ -360,7 +323,7 @@ class Communication : public CommQueue<> { } memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); len += mLocalBuf[i].len; - // get worst RSSI + // get worst RSSI (high value is better) if(mLocalBuf[i].rssi > rssi) rssi = mLocalBuf[i].rssi; } @@ -408,6 +371,224 @@ class Communication : public CommQueue<> { } } + private: + inline void miHwDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure + rec->ts = q->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_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } + }; + */ + } + + inline void miDataDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser + rec->ts = q->ts; + q->iv->radioStatistics.rxSuccess++; + mState = States::RESET; + + uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : + ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : + p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : + CH4; + // count in RF_communication_protocol.xlsx is with offset = -1 + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); + //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + + if (datachan == 1) //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + q->iv->rssi = p->rssi; + else if(q->iv->rssi > p->rssi) + q->iv->rssi = p->rssi; + + if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { + /*For MI1500: + if (MI1500) { + STAT = (uint8_t)(p->packet[25] ); + FCNT = (uint8_t)(p->packet[26]); + FCODE = (uint8_t)(p->packet[27]); + }*/ + miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); + + if (p->packet[0] < (0x39 + ALL_FRAMES) ) { + addImportant(q->iv, (q->cmd + 1)); + //mPayload[iv->id].txCmd++; + //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response + //mPayload[iv->id].complete = false; + miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); + } else { + miComplete(q->iv); + } + } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { + addImportant(q->iv, MI_REQ_CH2); + miNextRequest(MI_REQ_CH2, q); + } else { // first data msg for 1ch, 2nd for 2ch + miComplete(q->iv); + } + //cmdDone(q); + } + + inline void miNextRequest(uint8_t cmd, const queue_s *q) { + //setAttempt(); + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("next request (")); + DBGPRINT(String(q->attempts)); + DBGPRINT(F(" attempts left): 0x")); + DBGHEXLN(cmd); + + if(q->attempts) { + q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + MI_TIMEOUT; + mState = States::WAIT; + } else { + add(q, true); + cmdDone(q); + mState = States::RESET; + } + } + + inline void miStsConsolidate(const queue_s *q, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) { + //uint8_t status = (p->packet[11] << 8) + p->packet[12]; + uint16_t statusMi = 3; // regular status for MI, change to 1 later? + if ( uState == 2 ) { + statusMi = 5050 + stschan; //first approach, needs review! + if (lState) + statusMi += lState*10; + } else if ( uState > 3 ) { + statusMi = uState*1000 + uEnum*10; + if (lState) + statusMi += lState*100; //needs review, esp. for 4ch-8310 state! + //if (lEnum) + statusMi += lEnum; + if (uEnum < 6) { + statusMi += stschan; + } + if (statusMi == 8000) + statusMi = 8310; //trick? + } + + uint16_t prntsts = statusMi == 3 ? 1 : statusMi; + bool stsok = true; + if ( prntsts != rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)] ) { //sth.'s changed? + q->iv->alarmCnt = 1; // minimum... + //sth is or was wrong? + if ( (q->iv->type != INV_TYPE_1CH) && ( (statusMi != 3) + || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) + ) { + q->iv->lastAlarm[stschan] = alarm_t(prntsts, q->ts,0); + q->iv->alarmCnt = q->iv->type == INV_TYPE_2CH ? 3 : 5; + } + + q->iv->alarmLastId = prntsts; //iv->alarmMesIndex; + + stsok = false; + if (q->iv->alarmCnt > 1) { //more than one channel + for (uint8_t ch = 0; ch < (q->iv->alarmCnt); ++ch) { //start with 1 + if (q->iv->lastAlarm[ch].code == 1) { + stsok = true; + break; + } + } + } + //if (mSerialDebug) { + DPRINT(DBG_WARN, F("New state on CH")); + DBGPRINT(String(stschan)); DBGPRINT(F(" (")); + DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); + DBGPRINTLN(q->iv->getAlarmStr(prntsts)); + //} + } + + if (!stsok) { + q->iv->setValue(q->iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts); + q->iv->lastAlarm[0] = alarm_t(prntsts, q->ts, 0); + } + + if (q->iv->alarmMesIndex < rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]) { + q->iv->alarmMesIndex = rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? + //if (mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("alarm ID incremented to ")); + DBGPRINTLN(String(q->iv->alarmMesIndex)); + //} + } + } + + + inline void miComplete(Inverter<> *iv) { + //if ( mPayload[iv->id].complete ) + // return; //if we got second message as well in repreated attempt + //mPayload[iv->id].complete = true; + //if (mSerialDebug) { + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINTLN(F("got all data 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; + if (iv->type == INV_TYPE_1CH) { + if ((!iv->lastAlarm[0].code) || (iv->lastAlarm[0].code == 1)) + ac_pow += iv->getValue(iv->getPosByChFld(1, FLD_PDC, rec), rec); + } else { + for(uint8_t i = 1; i <= iv->channels; i++) { + if ((!iv->lastAlarm[i].code) || (iv->lastAlarm[i].code == 1)) { + 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(); + // update status state-machine, + iv->isProducing(); + } + private: enum class States : uint8_t { RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 618cf5da..4b9add6f 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -201,14 +201,13 @@ class Inverter { cb(devControlCmd, true); mDevControlRequest = false; } else if(0 == getFwVersion()) - cb(MI_REQ_CH1, false); // get firmware version - //cb(InverterDevInform_All, false); // get firmware version + cb(0x0f, false); // get firmware version; for MI, this makes part of polling the device software and hardware version number else { record_t<> *rec = getRecordStruct(InverterDevInform_Simple); if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) - cb(InverterDevInform_All, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 + cb(0x0f, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 else - cb(type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, false); + cb(((type == INV_TYPE_4CH) ? MI_REQ_4CH : MI_REQ_CH1), false); } } }