Browse Source

various fixes

- increase buffer
- fix incomplete miHwDecode
- shorten timeout for MI
pull/1219/head^2
rejoe2 2 years ago
committed by GitHub
parent
commit
810afaac8b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      src/hm/CommQueue.h
  2. 303
      src/hm/Communication.h
  3. 10
      src/hm/hmInverter.h
  4. 6
      src/hm/hmPayload.h

17
src/hm/CommQueue.h

@ -22,6 +22,10 @@ class CommQueue {
void add(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) {
mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop, false);
/*mQueue[mRdPtr].firstTry = false;
if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) {
mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000));
}*/
inc(&mWrPtr);
}
@ -30,9 +34,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) {}
@ -48,6 +52,10 @@ class CommQueue {
mQueue[mWrPtr] = *q;
if(rstAttempts)
mQueue[mWrPtr].attempts = 5;
/*mQueue[mRdPtr].firstTry = false;
if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) {
mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000));
}*/
inc(&mWrPtr);
}
@ -67,6 +75,13 @@ class CommQueue {
inc(&mRdPtr);
}
bool isFirstTry(void) {
if(!mQueue[mRdPtr].firstTry)
return false;
mQueue[mRdPtr].firstTry = false;
return true;
}
void setTs(uint32_t *ts) {
mQueue[mRdPtr].ts = *ts;
}

303
src/hm/Communication.h

@ -10,8 +10,9 @@
#include <Arduino.h>
#include "../utils/crc.h"
#define MI_TIMEOUT 500
#define MI_TIMEOUT 250
#define DEFAULT_TIMEOUT 500
#define MAX_BUFFER 200 //was: 150 (hardcoded)
typedef std::function<void(uint8_t, Inverter<> *)> payloadListenerType;
typedef std::function<void(Inverter<> *)> alarmListenerType;
@ -40,7 +41,7 @@ class Communication : public CommQueue<> {
if(!valid)
return; // empty
uint16_t lcl_tmo = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT;
uint16_t timeout = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT;
switch(mState) {
case States::RESET:
@ -59,22 +60,10 @@ class Communication : public CommQueue<> {
if(ActivePowerContr == q->cmd)
q->iv->powerLimitAck = false;
q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false);
}
else if (q->iv->ivGen != IV_MI)
} else
q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false);
else { // IV_MI
//uint8_t cmd = q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1;
//q->iv->radio->sendCmdPacket(q->iv, cmd, cmd, false, false);
q->iv->radio->sendCmdPacket(q->iv, q->cmd, q->cmd, false, false);
//if (q->iv->radio->mSerialDebug) {
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("legacy cmd 0x"));
DBGHEXLN(q->cmd);
//}
//mPayload[q->iv->id]. = cmd;
}
q->iv->radioStatistics.txCnt++;
mWaitTimeout = millis() + lcl_tmo;
mWaitTimeout = millis() + timeout;
setAttempt();
mState = States::WAIT;
break;
@ -90,7 +79,7 @@ class Communication : public CommQueue<> {
cmdDone();
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("request timeout: "));
DBGPRINT(String(millis() - mWaitTimeout + lcl_tmo));
DBGPRINT(String(millis() - mWaitTimeout + timeout));
DBGPRINTLN(F("ms"));
q->iv->radioStatistics.rxFailNoAnser++; // got nothing
@ -109,15 +98,14 @@ 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));
if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) {
DBGPRINT(F(" CH"));
if(3 == p->ch)
DBGPRINT(F("03"));
else
DBGPRINT(F("0"));
DBGPRINT(String(p->ch));
}
DBGPRINT(F(", "));
@ -137,13 +125,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();
}
if(0 == q->attempts) {
cmdDone(q);
mState = States::RESET;
} else
mState = nextState;
}
break;
@ -158,14 +153,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() + lcl_tmo;
mWaitTimeout = millis() + timeout;
mState = States::WAIT;
} else {
add(q, true);
@ -187,9 +183,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() + lcl_tmo;
mWaitTimeout = millis() + timeout;
mState = States::WAIT;
} else {
add(q, true);
@ -257,24 +253,126 @@ class Communication : public CommQueue<> {
|| (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))) {
)) { //&& (p->packet[0] != (0x0f + ALL_FRAMES)))) {
// 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);
}
else if (p->packet[0] == 0x0f + ALL_FRAMES)
} 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]);
miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]);
}
}
inline void parseDevCtrl(packet_t *p, const queue_s *q) {
if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00))
return;
bool accepted = true;
if((p->packet[10] == 0x00) && (p->packet[11] == 0x00))
q->iv->powerLimitAck = true;
else
accepted = false;
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F(" has "));
if(!accepted) DBGPRINT(F("not "));
DBGPRINT(F("accepted power limit set point "));
DBGPRINT(String(q->iv->powerLimit[0]));
DBGPRINT(F(" with PowerLimitControl "));
DBGPRINTLN(String(q->iv->powerLimit[1]));
q->iv->actPowerLimit = 0xffff; // unknown, readback current value
}
inline void compilePayload(const queue_s *q) {
uint16_t crc = 0xffff, crcRcv = 0x0000;
for(uint8_t i = 0; i < mMaxFrameId; i++) {
if(i == (mMaxFrameId - 1)) {
crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len - 2, crc);
crcRcv = (mLocalBuf[i].buf[mLocalBuf[i].len-2] << 8);
crcRcv |= mLocalBuf[i].buf[mLocalBuf[i].len-1];
} else
crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len, crc);
}
if(crc != crcRcv) {
DPRINT_IVID(DBG_WARN, q->iv->id);
DBGPRINT(F("CRC Error "));
if(q->attempts == 0) {
DBGPRINTLN(F("-> Fail"));
q->iv->radioStatistics.rxFail++; // got fragments but not complete response
cmdDone();
} else
DBGPRINTLN(F("-> complete retransmit"));
mState = States::RESET;
return;
}
/*DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("procPyld: cmd: 0x"));
DBGHEXLN(q->cmd);*/
memset(mPayload, 0, MAX_BUFFER);
int8_t rssi = -127;
uint8_t len = 0;
for(uint8_t i = 0; i < mMaxFrameId; i++) {
if(mLocalBuf[i].len + len > MAX_BUFFER) {
DPRINTLN(DBG_ERROR, F("payload buffer to small!"));
return;
}
memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len);
len += mLocalBuf[i].len;
// get worst RSSI (high value is better)
if(mLocalBuf[i].rssi > rssi)
rssi = mLocalBuf[i].rssi;
}
len -= 2;
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("Payload ("));
DBGPRINT(String(len));
DBGPRINT(F("): "));
ah::dumpBuf(mPayload, len);
record_t<> *rec = q->iv->getRecordStruct(q->cmd);
if(NULL == rec) {
DPRINTLN(DBG_ERROR, F("record is NULL!"));
return;
}
if((rec->pyldLen != len) && (0 != rec->pyldLen)) {
DPRINT(DBG_ERROR, F("plausibility check failed, expected "));
DBGPRINT(String(rec->pyldLen));
DBGPRINTLN(F(" bytes"));
q->iv->radioStatistics.rxFail++;
return;
}
q->iv->radioStatistics.rxSuccess++;
rec->ts = q->ts;
for (uint8_t i = 0; i < rec->length; i++) {
q->iv->addValue(i, mPayload, rec);
}
q->iv->rssi = rssi;
q->iv->doCalculations();
if(AlarmData == q->cmd) {
uint8_t i = 0;
while(1) {
if(0 == q->iv->parseAlarmLog(i++, mPayload, len))
break;
if (NULL != mCbAlarm)
(mCbAlarm)(q->iv);
yield();
}
}
}
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;
@ -306,7 +404,6 @@ case InverterDevInform_All:
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 },
@ -315,7 +412,6 @@ const byteAssign_t InfoAssignment[] = {
{ FLD_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 }
};
*/
if ( p->packet[9] == 0x00 ) {//first frame
//FLD_FW_VERSION
for (uint8_t i = 0; i < 5; i++) {
@ -413,9 +509,6 @@ const byteAssign_t InfoAssignment[] = {
q->iv->radioStatistics.rxSuccess++;
mState = States::RESET;
//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 :
@ -434,18 +527,13 @@ const byteAssign_t InfoAssignment[] = {
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 ( 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) {
@ -456,11 +544,16 @@ const byteAssign_t InfoAssignment[] = {
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 ) {
} 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);
@ -488,17 +581,6 @@ const byteAssign_t InfoAssignment[] = {
}
}
/* inline void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) {
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].multi_parts += 3;
mPayload[iv->id].txId = p->packet[0];
miStsConsolidate(iv, stschan, rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]);
mPayload[iv->id].stsAB[stschan] = true;
if (mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].stsAB[CH2])
*/
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?
@ -598,113 +680,6 @@ const byteAssign_t InfoAssignment[] = {
iv->isProducing();
}
inline void parseDevCtrl(packet_t *p, const queue_s *q) {
if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00))
return;
bool accepted = true;
if((p->packet[10] == 0x00) && (p->packet[11] == 0x00))
q->iv->powerLimitAck = true;
else
accepted = false;
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("has "));
if(!accepted) DBGPRINT(F("not "));
DBGPRINT(F("accepted power limit set point "));
DBGPRINT(String(q->iv->powerLimit[0]));
DBGPRINT(F(" with PowerLimitControl "));
DBGPRINTLN(String(q->iv->powerLimit[1]));
q->iv->actPowerLimit = 0xffff; // unknown, readback current value
}
inline void compilePayload(const queue_s *q) {
uint16_t crc = 0xffff, crcRcv = 0x0000;
for(uint8_t i = 0; i < mMaxFrameId; i++) {
if(i == (mMaxFrameId - 1)) {
crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len - 2, crc);
crcRcv = (mLocalBuf[i].buf[mLocalBuf[i].len-2] << 8);
crcRcv |= mLocalBuf[i].buf[mLocalBuf[i].len-1];
} else
crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len, crc);
}
if(crc != crcRcv) {
DPRINT_IVID(DBG_WARN, q->iv->id);
DBGPRINT(F("CRC Error "));
if(q->attempts == 0) {
DBGPRINTLN(F("-> Fail"));
q->iv->radioStatistics.rxFail++; // got fragments but not complete response
cmdDone();
} else
DBGPRINTLN(F("-> complete retransmit"));
mState = States::RESET;
return;
}
/*DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("procPyld: cmd: 0x"));
DBGHEXLN(q->cmd);*/
memset(mPayload, 0, 150);
int8_t rssi = -127;
uint8_t len = 0;
for(uint8_t i = 0; i < mMaxFrameId; i++) {
if(mLocalBuf[i].len + len > 150) {
DPRINTLN(DBG_ERROR, F("payload buffer to small!"));
return;
}
memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len);
len += mLocalBuf[i].len;
// get best RSSI
if(mLocalBuf[i].rssi > rssi)
rssi = mLocalBuf[i].rssi;
}
len -= 2;
DPRINT_IVID(DBG_INFO, q->iv->id);
DBGPRINT(F("Payload ("));
DBGPRINT(String(len));
DBGPRINT(F("): "));
ah::dumpBuf(mPayload, len);
record_t<> *rec = q->iv->getRecordStruct(q->cmd);
if(NULL == rec) {
DPRINTLN(DBG_ERROR, F("record is NULL!"));
return;
}
if((rec->pyldLen != len) && (0 != rec->pyldLen)) {
DPRINT(DBG_ERROR, F("plausibility check failed, expected "));
DBGPRINT(String(rec->pyldLen));
DBGPRINTLN(F(" bytes"));
q->iv->radioStatistics.rxFail++;
return;
}
q->iv->radioStatistics.rxSuccess++;
rec->ts = q->ts;
for (uint8_t i = 0; i < rec->length; i++) {
q->iv->addValue(i, mPayload, rec);
}
q->iv->rssi = rssi;
q->iv->doCalculations();
if(AlarmData == q->cmd) {
uint8_t i = 0;
while(1) {
if(0 == q->iv->parseAlarmLog(i++, mPayload, len))
break;
if (NULL != mCbAlarm)
(mCbAlarm)(q->iv);
yield();
}
}
}
private:
enum class States : uint8_t {
RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE
@ -722,7 +697,7 @@ const byteAssign_t InfoAssignment[] = {
uint32_t mWaitTimeout = 0;
std::array<frame_t, MAX_PAYLOAD_ENTRIES> mLocalBuf;
uint8_t mMaxFrameId;
uint8_t mPayload[150];
uint8_t mPayload[MAX_BUFFER];
payloadListenerType mCbPayload = NULL;
alarmListenerType mCbAlarm = NULL;
};

10
src/hm/hmInverter.h

@ -197,14 +197,6 @@ class Inverter {
else
cb(RealTimeRunData_Debug, false); // get live data
} else {
/*if (cmd == 0x01) { //0x1 for HM-types
cmd2 = 0x00;
cmd = 0x0f; // for MI, these seem to make part of polling the device software and hardware version number command
}
if (cmd == SystemConfigPara ) { // 0x05 for HM-types
cmd2 = 0x00;
cmd = 0x10; // legacy GPF request
*/
if(mDevControlRequest) {
cb(devControlCmd, true);
mDevControlRequest = false;
@ -215,7 +207,7 @@ class Inverter {
if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0)
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);
}
}
}

6
src/hm/hmPayload.h

@ -330,15 +330,15 @@ class HmPayload {
mPayload[iv->id].requested = false;
mPayload[iv->id].rxTmo = false;
uint8_t payload[150];
uint8_t payload[MAX_BUFFER];
uint8_t payloadLen = 0;
memset(payload, 0, 150);
memset(payload, 0, MAX_BUFFER);
int8_t rssi = -127;
for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) {
if((mPayload[iv->id].len[i] + payloadLen) > 150) {
if((mPayload[iv->id].len[i] + payloadLen) > MAX_BUFFER) {
DPRINTLN(DBG_ERROR, F("payload buffer to small!"));
break;
}

Loading…
Cancel
Save