|
@ -64,13 +64,28 @@ struct calcFunc_t { |
|
|
func_t<T>* func; // function pointer
|
|
|
func_t<T>* func; // function pointer
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
enum class MqttSentStatus : uint8_t { |
|
|
|
|
|
NEW_DATA, |
|
|
|
|
|
LAST_SUCCESS_SENT, |
|
|
|
|
|
DATA_SENT |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
enum class InverterStatus : uint8_t { |
|
|
|
|
|
OFF, |
|
|
|
|
|
STARTING, |
|
|
|
|
|
PRODUCING, |
|
|
|
|
|
WAS_PRODUCING, |
|
|
|
|
|
WAS_ON |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
template<class T=float> |
|
|
template<class T=float> |
|
|
struct record_t { |
|
|
struct record_t { |
|
|
byteAssign_t* assign; // assignment of bytes in payload
|
|
|
byteAssign_t* assign; // assignment of bytes in payload
|
|
|
uint8_t length; // length of the assignment list
|
|
|
uint8_t length; // length of the assignment list
|
|
|
T *record; // data pointer
|
|
|
T *record; // data pointer
|
|
|
uint32_t ts; // timestamp of last received payload
|
|
|
uint32_t ts; // timestamp of last received payload
|
|
|
uint8_t pyldLen; // expected payload length for plausibility check
|
|
|
uint8_t pyldLen; // expected payload length for plausibility check
|
|
|
|
|
|
MqttSentStatus mqttSentStatus; // indicates the current MqTT sent status
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
struct alarm_t { |
|
|
struct alarm_t { |
|
@ -94,14 +109,6 @@ const calcFunc_t<T> calcFunctions[] = { |
|
|
{ CALC_MPDC_CH, &calcMaxPowerDc } |
|
|
{ CALC_MPDC_CH, &calcMaxPowerDc } |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
enum class InverterStatus : uint8_t { |
|
|
|
|
|
OFF, |
|
|
|
|
|
STARTING, |
|
|
|
|
|
PRODUCING, |
|
|
|
|
|
WAS_PRODUCING, |
|
|
|
|
|
WAS_ON |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
template <class REC_TYP> |
|
|
template <class REC_TYP> |
|
|
class Inverter { |
|
|
class Inverter { |
|
|
public: |
|
|
public: |
|
@ -124,26 +131,28 @@ class Inverter { |
|
|
bool isConnected; // shows if inverter was successfully identified (fw version and hardware info)
|
|
|
bool isConnected; // shows if inverter was successfully identified (fw version and hardware info)
|
|
|
InverterStatus status; // indicates the current inverter status
|
|
|
InverterStatus status; // indicates the current inverter status
|
|
|
std::array<alarm_t, 10> lastAlarm; // holds last 10 alarms
|
|
|
std::array<alarm_t, 10> lastAlarm; // holds last 10 alarms
|
|
|
uint8_t alarmNxtWrPos; // indicates the position in array (rolling buffer)
|
|
|
int8_t rssi; // RSSI
|
|
|
uint16_t alarmCnt; // counts the total number of occurred alarms
|
|
|
uint16_t alarmCnt; // counts the total number of occurred alarms
|
|
|
uint16_t alarmLastId; // lastId which was received
|
|
|
uint16_t alarmLastId; // lastId which was received
|
|
|
int8_t rssi; // RSSI
|
|
|
uint8_t mCmd; // holds the command to send
|
|
|
|
|
|
bool mGotFragment; // shows if inverter has sent at least one fragment
|
|
|
uint8_t miMultiParts; // helper info for MI multiframe msgs
|
|
|
uint8_t miMultiParts; // helper info for MI multiframe msgs
|
|
|
uint8_t outstandingFrames; // helper info to count difference between expected and received frames
|
|
|
uint8_t outstandingFrames; // helper info to count difference between expected and received frames
|
|
|
bool mGotFragment; // shows if inverter has sent at least one fragment
|
|
|
|
|
|
uint8_t curFrmCnt; // count received frames in current loop
|
|
|
uint8_t curFrmCnt; // count received frames in current loop
|
|
|
bool mGotLastMsg; // shows if inverter has already finished transmission cycle
|
|
|
bool mGotLastMsg; // shows if inverter has already finished transmission cycle
|
|
|
uint8_t mCmd; // holds the command to send
|
|
|
|
|
|
bool mIsSingleframeReq; // indicates this is a missing single frame request
|
|
|
bool mIsSingleframeReq; // indicates this is a missing single frame request
|
|
|
Radio *radio; // pointer to associated radio class
|
|
|
Radio *radio; // pointer to associated radio class
|
|
|
statistics_t radioStatistics; // information about transmitted, failed, ... packets
|
|
|
statistics_t radioStatistics; // information about transmitted, failed, ... packets
|
|
|
HeuristicInv heuristics; // heuristic information / logic
|
|
|
HeuristicInv heuristics; // heuristic information / logic
|
|
|
uint8_t curCmtFreq; // current used CMT frequency, used to check if freq. was changed during runtime
|
|
|
uint8_t curCmtFreq; // current used CMT frequency, used to check if freq. was changed during runtime
|
|
|
bool commEnabled; // 'pause night communication' sets this field to false
|
|
|
bool commEnabled; // 'pause night communication' sets this field to false
|
|
|
|
|
|
uint32_t tsMaxAcPower; // holds the timestamp when the MaxAC power was seen
|
|
|
|
|
|
|
|
|
static uint32_t *timestamp; // system timestamp
|
|
|
static uint32_t *timestamp; // system timestamp
|
|
|
static cfgInst_t *generalConfig; // general inverter configuration from setup
|
|
|
static cfgInst_t *generalConfig; // general inverter configuration from setup
|
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
Inverter() { |
|
|
Inverter() { |
|
|
ivGen = IV_HM; |
|
|
ivGen = IV_HM; |
|
|
powerLimit[0] = 0xffff; // 6553.5 W Limit -> unlimited
|
|
|
powerLimit[0] = 0xffff; // 6553.5 W Limit -> unlimited
|
|
@ -155,7 +164,6 @@ class Inverter { |
|
|
alarmMesIndex = 0; |
|
|
alarmMesIndex = 0; |
|
|
isConnected = false; |
|
|
isConnected = false; |
|
|
status = InverterStatus::OFF; |
|
|
status = InverterStatus::OFF; |
|
|
alarmNxtWrPos = 0; |
|
|
|
|
|
alarmCnt = 0; |
|
|
alarmCnt = 0; |
|
|
alarmLastId = 0; |
|
|
alarmLastId = 0; |
|
|
rssi = -127; |
|
|
rssi = -127; |
|
@ -165,6 +173,7 @@ class Inverter { |
|
|
mIsSingleframeReq = false; |
|
|
mIsSingleframeReq = false; |
|
|
radio = NULL; |
|
|
radio = NULL; |
|
|
commEnabled = true; |
|
|
commEnabled = true; |
|
|
|
|
|
tsMaxAcPower = 0; |
|
|
|
|
|
|
|
|
memset(&radioStatistics, 0, sizeof(statistics_t)); |
|
|
memset(&radioStatistics, 0, sizeof(statistics_t)); |
|
|
memset(heuristics.txRfQuality, -6, 5); |
|
|
memset(heuristics.txRfQuality, -6, 5); |
|
@ -310,11 +319,11 @@ class Inverter { |
|
|
rec->record[pos] = (REC_TYP)(val); |
|
|
rec->record[pos] = (REC_TYP)(val); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
rec->mqttSentStatus = MqttSentStatus::NEW_DATA; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if(rec == &recordMeas) { |
|
|
if(rec == &recordMeas) { |
|
|
DPRINTLN(DBG_VERBOSE, "add real time"); |
|
|
DPRINTLN(DBG_VERBOSE, "add real time"); |
|
|
|
|
|
|
|
|
// get last alarm message index and save it in the inverter object
|
|
|
// get last alarm message index and save it in the inverter object
|
|
|
if (getPosByChFld(0, FLD_EVT, rec) == pos) { |
|
|
if (getPosByChFld(0, FLD_EVT, rec) == pos) { |
|
|
if (alarmMesIndex < rec->record[pos]) { |
|
|
if (alarmMesIndex < rec->record[pos]) { |
|
@ -498,6 +507,7 @@ class Inverter { |
|
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:initAssignment")); |
|
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:initAssignment")); |
|
|
rec->ts = 0; |
|
|
rec->ts = 0; |
|
|
rec->length = 0; |
|
|
rec->length = 0; |
|
|
|
|
|
rec->mqttSentStatus = MqttSentStatus::DATA_SENT; // nothing new to transmit
|
|
|
switch (cmd) { |
|
|
switch (cmd) { |
|
|
case RealTimeRunData_Debug: |
|
|
case RealTimeRunData_Debug: |
|
|
if (INV_TYPE_1CH == type) { |
|
|
if (INV_TYPE_1CH == type) { |
|
@ -582,7 +592,7 @@ class Inverter { |
|
|
|
|
|
|
|
|
void resetAlarms() { |
|
|
void resetAlarms() { |
|
|
lastAlarm.fill({0, 0, 0}); |
|
|
lastAlarm.fill({0, 0, 0}); |
|
|
alarmNxtWrPos = 0; |
|
|
mAlarmNxtWrPos = 0; |
|
|
alarmCnt = 0; |
|
|
alarmCnt = 0; |
|
|
alarmLastId = 0; |
|
|
alarmLastId = 0; |
|
|
|
|
|
|
|
@ -596,10 +606,18 @@ class Inverter { |
|
|
uint16_t txCnt = (pyld[2] << 8) + pyld[3]; |
|
|
uint16_t txCnt = (pyld[2] << 8) + pyld[3]; |
|
|
|
|
|
|
|
|
if (mIvRxCnt || mIvTxCnt) { // there was successful GetLossRate in the past
|
|
|
if (mIvRxCnt || mIvTxCnt) { // there was successful GetLossRate in the past
|
|
|
radioStatistics.ivLoss = mDtuTxCnt - (rxCnt - mIvRxCnt); |
|
|
|
|
|
radioStatistics.ivSent = mDtuTxCnt; |
|
|
radioStatistics.ivSent = mDtuTxCnt; |
|
|
radioStatistics.dtuLoss = txCnt - mIvTxCnt - mDtuRxCnt; |
|
|
if (rxCnt < mIvRxCnt) // overflow
|
|
|
radioStatistics.dtuSent = txCnt - mIvTxCnt; |
|
|
radioStatistics.ivLoss = radioStatistics.ivSent - (rxCnt + ((uint16_t)65535 - mIvRxCnt) + 1); |
|
|
|
|
|
else |
|
|
|
|
|
radioStatistics.ivLoss = radioStatistics.ivSent - (rxCnt - mIvRxCnt); |
|
|
|
|
|
|
|
|
|
|
|
if (txCnt < mIvTxCnt) // overflow
|
|
|
|
|
|
radioStatistics.dtuSent = txCnt + ((uint16_t)65535 - mIvTxCnt) + 1; |
|
|
|
|
|
else |
|
|
|
|
|
radioStatistics.dtuSent = txCnt - mIvTxCnt; |
|
|
|
|
|
|
|
|
|
|
|
radioStatistics.dtuLoss = radioStatistics.dtuSent - mDtuRxCnt; |
|
|
|
|
|
|
|
|
DPRINT_IVID(DBG_INFO, id); |
|
|
DPRINT_IVID(DBG_INFO, id); |
|
|
DBGPRINT(F("Inv loss: ")); |
|
|
DBGPRINT(F("Inv loss: ")); |
|
@ -790,9 +808,9 @@ class Inverter { |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
inline void addAlarm(uint16_t code, uint32_t start, uint32_t end) { |
|
|
inline void addAlarm(uint16_t code, uint32_t start, uint32_t end) { |
|
|
lastAlarm[alarmNxtWrPos] = alarm_t(code, start, end); |
|
|
lastAlarm[mAlarmNxtWrPos] = alarm_t(code, start, end); |
|
|
if(++alarmNxtWrPos >= 10) // rolling buffer
|
|
|
if(++mAlarmNxtWrPos >= 10) // rolling buffer
|
|
|
alarmNxtWrPos = 0; |
|
|
mAlarmNxtWrPos = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void toRadioId(void) { |
|
|
void toRadioId(void) { |
|
@ -813,6 +831,7 @@ class Inverter { |
|
|
uint8_t mGetLossInterval; // request iv every AHOY_GET_LOSS_INTERVAL RealTimeRunData_Debug
|
|
|
uint8_t mGetLossInterval; // request iv every AHOY_GET_LOSS_INTERVAL RealTimeRunData_Debug
|
|
|
uint16_t mIvRxCnt = 0; |
|
|
uint16_t mIvRxCnt = 0; |
|
|
uint16_t mIvTxCnt = 0; |
|
|
uint16_t mIvTxCnt = 0; |
|
|
|
|
|
uint8_t mAlarmNxtWrPos = 0; // indicates the position in array (rolling buffer)
|
|
|
|
|
|
|
|
|
public: |
|
|
public: |
|
|
uint16_t mDtuRxCnt = 0; |
|
|
uint16_t mDtuRxCnt = 0; |
|
@ -948,8 +967,10 @@ static T calcMaxPowerDc(Inverter<> *iv, uint8_t arg0) { |
|
|
dcMaxPower = iv->getValue(i, rec); |
|
|
dcMaxPower = iv->getValue(i, rec); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
if(dcPower > dcMaxPower) |
|
|
if(dcPower > dcMaxPower) { |
|
|
|
|
|
iv->tsMaxAcPower = *iv->timestamp; |
|
|
return dcPower; |
|
|
return dcPower; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
return dcMaxPower; |
|
|
return dcMaxPower; |
|
|
} |
|
|
} |
|
|