diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index ab2069cc..9646fb88 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -119,6 +119,8 @@ const byteAssign_t AlarmDataAssignment[] = { #define HMALARMDATA_PAYLOAD_LEN 0 // 0: means check is off #define ALARM_LOG_ENTRY_SIZE 12 +#define HMGETLOSSRATE_PAYLOAD_LEN 4 + //------------------------------------- // HM300, HM350, HM400 diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 138f22ad..5cf54194 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -31,6 +31,8 @@ // mark current test chan as 1st use during this test period #define RF_TX_TEST_CHAN_1ST_USE 0xff +#define AHOY_GET_LOSS_INTERVAL 10 + /** * For values which are of interest and not transmitted by the inverter can be * calculated automatically. @@ -146,6 +148,10 @@ class Inverter { bool isConnected; // shows if inverter was successfully identified (fw version and hardware info) uint32_t pac_sum; // average calc for chart: sum of ac power values for cur interval uint16_t pac_cnt; // average calc for chart: number of ac power values for cur interval + uint16_t mIvRxCnt; // last iv rx frames (from GetLossRate) + uint16_t mIvTxCnt; // last iv tx frames (from GetLossRate) + uint16_t mDtuRxCnt; // cur dtu rx frames (since last GetLossRate) + uint16_t mDtuTxCnt; // cur dtu tx frames (since last getLoassRate) uint16_t alarmCode; // last Alarm uint32_t alarmStart; uint32_t alarmEnd; @@ -157,6 +163,7 @@ class Inverter { uint8_t mTestPeriodSendCnt; // increment of current test period uint8_t mTestPeriodFailCnt; // no of fails during current test period uint8_t mSaveOldTestChanQuality; // original quality of current TestTxChanIndex + uint8_t mGetLossInterval; // request iv every AHOY_GET_LOSS_INTERVAL RealTimeRunData_Debug Inverter() { ivGen = IV_HM; @@ -210,6 +217,12 @@ class Inverter { } else if (alarmDataReqPending) { enqueCommand(AlarmData); // alarm not answered } else { + if ((mIvRxCnt || mIvTxCnt) && (mGetLossInterval < AHOY_GET_LOSS_INTERVAL)) { // initially mIvRxCnt = mIvTxCnt = 0 + mGetLossInterval++; + } else { + mGetLossInterval = 1; // 1: RealTimeRunData_Debug will always be enqueued + enqueCommand(GetLossRate); + } enqueCommand(RealTimeRunData_Debug); // live data } } else if (ivGen == IV_MI){ @@ -533,7 +546,7 @@ class Inverter { uint16_t parseAlarmLog(uint8_t id, uint8_t pyld[], uint8_t len, uint32_t *start, uint32_t *endTime) { uint8_t startOff = 2 + id * ALARM_LOG_ENTRY_SIZE; - if (alarmDataReqPending) { + if (!id && alarmDataReqPending) { // evaluate if 1st of seq only alarmDataReqPending--; } if((startOff + ALARM_LOG_ENTRY_SIZE) > len) @@ -558,6 +571,27 @@ class Inverter { return alarmCode; } + bool parseGetLossRate(uint8_t pyld[], uint8_t len) { + if (len == HMGETLOSSRATE_PAYLOAD_LEN) { + uint16_t rxCnt = (pyld[0] << 8) + pyld[1]; + uint16_t txCnt = (pyld[2] << 8) + pyld[3]; + + if (mIvRxCnt || mIvTxCnt) { // there was successful GetLossRate in the past + DPRINT_IVID(DBG_INFO, id); + DBGPRINTLN("Inv loss: " + String (mDtuTxCnt - (rxCnt - mIvRxCnt)) + " of " + + String (mDtuTxCnt) + ", DTU loss: " + + String (txCnt - mIvTxCnt - mDtuRxCnt) + " of " + + String (txCnt - mIvTxCnt)); + } + mIvRxCnt = rxCnt; + mIvTxCnt = txCnt; + mDtuRxCnt = 0; // start new interval + mDtuTxCnt = 0; // start new interval + return true; + } + return false; + } + String getAlarmStr(uint16_t alarmCode) { switch (alarmCode) { // breaks are intentionally missing! case 1: return String(F("Inverter start")); diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 7b6ae95c..c9c15bfd 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -157,6 +157,7 @@ class HmPayload { DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); } + iv->mDtuTxCnt++; mSys->Radio.sendControlPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, false); mPayload[iv->id].txCmd = iv->devControlCmd; @@ -167,6 +168,7 @@ class HmPayload { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("prepareDevInformCmd 0x")); DBGHEXLN(cmd); + iv->mDtuTxCnt++; mSys->Radio.prepareDevInformCmd(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false); mPayload[iv->id].txCmd = cmd; @@ -174,6 +176,7 @@ class HmPayload { } void add(Inverter<> *iv, packet_t *p) { + iv->mDtuRxCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command mPayload[iv->id].txId = p->packet[0]; DPRINTLN(DBG_DEBUG, F("Response from info request received")); @@ -272,6 +275,7 @@ class HmPayload { } else if(iv->devControlCmd == ActivePowerContr) { DPRINT_IVID(DBG_INFO, iv->id); DPRINTLN(DBG_INFO, F("retransmit power limit")); + iv->mDtuTxCnt++; mSys->Radio.sendControlPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, true); } else { @@ -285,6 +289,7 @@ class HmPayload { mPayload[iv->id].txCmd = iv->getQueuedCmd(); DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); + iv->mDtuTxCnt++; mSys->Radio.prepareDevInformCmd(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } @@ -295,6 +300,7 @@ class HmPayload { DBGPRINT(F("Frame ")); DBGPRINT(String(i + 1)); DBGPRINTLN(F(" missing: Request Retransmit")); + iv->mDtuTxCnt++; mSys->Radio.sendCmdPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex (), TX_REQ_INFO, (SINGLE_FRAME + i), true); break; // only request retransmit one frame per loop @@ -316,6 +322,7 @@ class HmPayload { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("prepareDevInformCmd 0x")); DBGHEXLN(mPayload[iv->id].txCmd); + iv->mDtuTxCnt++; mSys->Radio.prepareDevInformCmd(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex (), mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } else if (false == mPayload[iv->id].gotFragment) { @@ -358,7 +365,16 @@ class HmPayload { #endif if (NULL == rec) { - DPRINTLN(DBG_ERROR, F("record is NULL!")); + if(GetLossRate == mPayload[iv->id].txCmd) { + if ((mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) && + iv->parseGetLossRate (payload, payloadLen)) { + mStat->rxSuccess++; + } else { + mStat->rxFail++; + } + } else { + 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++; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index c791960b..d1c093c2 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -12,6 +12,8 @@ #include "../config/config.h" #include "SPI.h" +// #define AHOY_RADIO_TX_PENDING_LOOP + #define SPI_SPEED 1000000 #define TX_REQ_INFO 0x15 @@ -21,7 +23,7 @@ #define RX_ANSWER_TMO 400 #define RX_WAIT_SFR_TMO 40 -#define RX_WAIT_SAFETY_MRGN 20 +#define RX_WAIT_SAFETY_MRGN 10 #define RX_CHAN_TMO 5110 #define RX_CHAN_MHCH1_TMO 10220 @@ -165,8 +167,18 @@ class HmRadio { } bool loop(void) { +#ifdef AHOY_RADIO_TX_PENDING_LOOP + if (!mTxPending) { + return false; + } + mTxPending = false; + while (!mIrqRcvd) { + yield(); + } +#else if (!mIrqRcvd) return false; // nothing to do +#endif mIrqRcvd = false; bool tx_ok, tx_fail, rx_ready; mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH @@ -183,7 +195,6 @@ class HmRadio { if (mIrqRcvd) { mIrqRcvd = false; if (getReceived()) { // everything received - return true; } } @@ -259,8 +270,9 @@ class HmRadio { DPRINTLN(DBG_DEBUG,String(cmd, HEX)); } prepareReceive (invType, txChan, - // could be optimized for other inverter types as well - ((cmd == RealTimeRunData_Debug) && (invType == INV_TYPE_HMCH1)) ? 2 : 10); + // could be optimized for other HM inverter types as well + ((cmd == RealTimeRunData_Debug) && (invType == INV_TYPE_HMCH1)) ? 2 : + ((invType == INV_TYPE_HMCH1) && ((cmd == InverterDevInform_All) || (cmd == SystemConfigPara) || (GetLossRate))) ? 1 : 10); initPacket(invId, reqfld, ALL_FRAMES); mTxBuf[10] = cmd; // cid mTxBuf[11] = 0x00; @@ -314,8 +326,7 @@ class HmRadio { if (invType == INV_TYPE_HMCH1) { mRxChannels = (uint8_t *)(rf24RxHMCh1[txChan]); mMaxRxChannels = RX_HMCH1_MAX_CHANNELS; - mRxAnswerTmo = rxFrameCnt * RX_WAIT_SFR_TMO; // typical inverter answer has 2 packets - mRxAnswerTmo += RX_WAIT_SAFETY_MRGN; + mRxAnswerTmo = rxFrameCnt * (RX_WAIT_SFR_TMO + RX_WAIT_SAFETY_MRGN); // current formula for hm inverters if (mRxAnswerTmo > RX_ANSWER_TMO) { mRxAnswerTmo = RX_ANSWER_TMO; } @@ -409,6 +420,9 @@ class HmRadio { mNrf24.stopListening(); mNrf24.setChannel(rf24ChLst[mTxChIdx]); mNrf24.openWritingPipe(reinterpret_cast(&invId)); +#ifdef AHOY_RADIO_TX_PENDING_LOOP + mTxPending = true; +#endif mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response if(isRetransmit) @@ -429,6 +443,9 @@ class HmRadio { uint8_t mMaxRxChannels; // actual size of mRxChannels; depends on inverter and previous tx channel uint32_t mRxAnswerTmo; // max wait time in millis for answers of inverter uint32_t mRxChanTmo; // max wait time in micros for a rx channel +#ifdef AHOY_RADIO_TX_PENDING_LOOP + bool mTxPending; // send has been started: wait in loop to setup receive without break +#endif }; #endif /*__RADIO_H__*/