|
|
|
#ifndef __HM_INVERTER_H__
|
|
|
|
#define __HM_INVERTER_H__
|
|
|
|
|
|
|
|
#include "hmDefines.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* For values which are of interest and not transmitted by the inverter can be
|
|
|
|
* calculated automatically.
|
|
|
|
* A list of functions can be linked to the assignment and will be executed
|
|
|
|
* automatically. Their result does not differ from original read values.
|
|
|
|
* The special command 0xff (CMDFF) must be used.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// forward declaration of class
|
|
|
|
template <class RECORDTYPE=float>
|
|
|
|
class Inverter;
|
|
|
|
|
|
|
|
|
|
|
|
// prototypes
|
|
|
|
template<class T=float>
|
|
|
|
static T calcYieldTotalCh0(Inverter<> *iv, uint8_t arg0);
|
|
|
|
|
|
|
|
template<class T=float>
|
|
|
|
static T calcYieldDayCh0(Inverter<> *iv, uint8_t arg0);
|
|
|
|
|
|
|
|
template<class T=float>
|
|
|
|
static T calcUdcCh(Inverter<> *iv, uint8_t arg0);
|
|
|
|
|
|
|
|
template<class T=float>
|
|
|
|
using func_t = T (Inverter<> *, uint8_t);
|
|
|
|
|
|
|
|
template<class T=float>
|
|
|
|
struct calcFunc_t {
|
|
|
|
uint8_t funcId; // unique id
|
|
|
|
func_t<T>* func; // function pointer
|
|
|
|
} ;
|
|
|
|
|
|
|
|
|
|
|
|
// list of all available functions, mapped in hmDefines.h
|
|
|
|
template<class T=float>
|
|
|
|
const calcFunc_t<T> calcFunctions[] = {
|
|
|
|
{ CALC_YT_CH0, &calcYieldTotalCh0 },
|
|
|
|
{ CALC_YD_CH0, &calcYieldDayCh0 },
|
|
|
|
{ CALC_UDC_CH, &calcUdcCh }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <class RECORDTYPE>
|
|
|
|
class Inverter {
|
|
|
|
public:
|
|
|
|
uint8_t id; // unique id
|
|
|
|
char name[MAX_NAME_LENGTH]; // human readable name, eg. "HM-600.1"
|
|
|
|
uint8_t type; // integer which refers to inverter type
|
|
|
|
byteAssign_t* assign; // type of inverter
|
|
|
|
uint8_t listLen; // length of assignments
|
|
|
|
serial_u serial; // serial number as on barcode
|
|
|
|
serial_u radioId; // id converted to modbus
|
|
|
|
uint8_t channels; // number of PV channels (1-4)
|
|
|
|
RECORDTYPE *record; // pointer for values
|
|
|
|
|
|
|
|
Inverter() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
~Inverter() {
|
|
|
|
// TODO: cleanup
|
|
|
|
}
|
|
|
|
|
|
|
|
void init(void) {
|
|
|
|
getAssignment();
|
|
|
|
toRadioId();
|
|
|
|
record = new RECORDTYPE[listLen];
|
|
|
|
memset(name, 0, MAX_NAME_LENGTH);
|
|
|
|
memset(record, 0, sizeof(RECORDTYPE) * listLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t getPosByChFld(uint8_t channel, uint8_t fieldId) {
|
|
|
|
uint8_t pos = 0;
|
|
|
|
for(; pos < listLen; pos++) {
|
|
|
|
if((assign[pos].ch == channel) && (assign[pos].fieldId == fieldId))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (pos >= listLen) ? 0xff : pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *getFieldName(uint8_t pos) {
|
|
|
|
return fields[assign[pos].fieldId];
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *getUnit(uint8_t pos) {
|
|
|
|
return units[assign[pos].unitId];
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t getChannel(uint8_t pos) {
|
|
|
|
return assign[pos].ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t getCmdId(uint8_t pos) {
|
|
|
|
return assign[pos].cmdId;
|
|
|
|
}
|
|
|
|
|
|
|
|
void addValue(uint8_t pos, uint8_t buf[]) {
|
|
|
|
uint8_t ptr = assign[pos].start;
|
|
|
|
uint8_t end = ptr + assign[pos].num;
|
|
|
|
uint16_t div = assign[pos].div;
|
|
|
|
|
|
|
|
uint32_t val = 0;
|
|
|
|
do {
|
|
|
|
val <<= 8;
|
|
|
|
val |= buf[ptr];
|
|
|
|
} while(++ptr != end);
|
|
|
|
|
|
|
|
record[pos] = (RECORDTYPE)(val) / (RECORDTYPE)(div);
|
|
|
|
}
|
|
|
|
|
|
|
|
RECORDTYPE getValue(uint8_t pos) {
|
|
|
|
return record[pos];
|
|
|
|
}
|
|
|
|
|
|
|
|
void doCalculations(void) {
|
|
|
|
for(uint8_t i = 0; i < listLen; i++) {
|
|
|
|
if(CMDFF == assign[i].cmdId) {
|
|
|
|
record[i] = calcFunctions<RECORDTYPE>[assign[i].start].func(this, assign[i].num);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void toRadioId(void) {
|
|
|
|
radioId.u64 = 0ULL;
|
|
|
|
radioId.b[4] = serial.b[0];
|
|
|
|
radioId.b[3] = serial.b[1];
|
|
|
|
radioId.b[2] = serial.b[2];
|
|
|
|
radioId.b[1] = serial.b[3];
|
|
|
|
radioId.b[0] = 0x01;
|
|
|
|
}
|
|
|
|
|
|
|
|
void getAssignment(void) {
|
|
|
|
if(INV_TYPE_HM400 == type) {
|
|
|
|
listLen = (uint8_t)(HM400_LIST_LEN);
|
|
|
|
assign = (byteAssign_t*)hm400assignment;
|
|
|
|
channels = 1;
|
|
|
|
}
|
|
|
|
else if(INV_TYPE_HM600 == type) {
|
|
|
|
listLen = (uint8_t)(HM600_LIST_LEN);
|
|
|
|
assign = (byteAssign_t*)hm600assignment;
|
|
|
|
channels = 2;
|
|
|
|
}
|
|
|
|
else if(INV_TYPE_HM800 == type) {
|
|
|
|
listLen = (uint8_t)(HM800_LIST_LEN);
|
|
|
|
assign = (byteAssign_t*)hm800assignment;
|
|
|
|
channels = 2;
|
|
|
|
}
|
|
|
|
else if(INV_TYPE_HM1200 == type) {
|
|
|
|
listLen = (uint8_t)(HM1200_LIST_LEN);
|
|
|
|
assign = (byteAssign_t*)hm1200assignment;
|
|
|
|
channels = 4;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
listLen = 0;
|
|
|
|
channels = 0;
|
|
|
|
assign = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* To calculate values which are not transmitted by the unit there is a generic
|
|
|
|
* list of functions which can be linked to the assignment.
|
|
|
|
* The special command 0xff (CMDFF) must be used.
|
|
|
|
*/
|
|
|
|
|
|
|
|
template<class T=float>
|
|
|
|
static T calcYieldTotalCh0(Inverter<> *iv, uint8_t arg0) {
|
|
|
|
if(NULL != iv) {
|
|
|
|
T yield = 0;
|
|
|
|
for(uint8_t i = 1; i <= iv->channels; i++) {
|
|
|
|
uint8_t pos = iv->getPosByChFld(i, FLD_YT);
|
|
|
|
yield += iv->getValue(pos);
|
|
|
|
}
|
|
|
|
return yield;
|
|
|
|
}
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T=float>
|
|
|
|
static T calcYieldDayCh0(Inverter<> *iv, uint8_t arg0) {
|
|
|
|
if(NULL != iv) {
|
|
|
|
T yield = 0;
|
|
|
|
for(uint8_t i = 1; i <= iv->channels; i++) {
|
|
|
|
uint8_t pos = iv->getPosByChFld(i, FLD_YD);
|
|
|
|
yield += iv->getValue(pos);
|
|
|
|
}
|
|
|
|
return yield;
|
|
|
|
}
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class T=float>
|
|
|
|
static T calcUdcCh(Inverter<> *iv, uint8_t arg0) {
|
|
|
|
// arg0 = channel of source
|
|
|
|
for(uint8_t i = 0; i < iv->listLen; i++) {
|
|
|
|
if((FLD_UDC == iv->assign[i].fieldId) && (arg0 == iv->assign[i].ch)) {
|
|
|
|
return iv->getValue(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif /*__HM_INVERTER_H__*/
|