| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -23,7 +23,7 @@ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					 */ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// forward declaration of class
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					template <class RECORDTYPE=float> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					template <class REC_TYP=float> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					class Inverter; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -55,17 +55,23 @@ struct calcFunc_t { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    func_t<T>*  func;   // function pointer
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					template<class T=float> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					struct record_t { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    byteAssign_t* assign; // assigment of bytes in payload
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    uint8_t length;       // length of the assignment list
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    T *record;            // data pointer
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    uint32_t ts;          // timestamp of last received payload
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					class CommandAbstract { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    public: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        CommandAbstract(uint8_t txType = 0, uint8_t cmd = 0){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        CommandAbstract(uint8_t txType = 0, uint8_t cmd = 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _TxType = txType; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _Cmd = cmd; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        }; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        virtual ~CommandAbstract() {}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        const uint8_t getCmd() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        {        | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        const uint8_t getCmd() { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return _Cmd; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -75,11 +81,11 @@ class CommandAbstract { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					class InfoCommand : public CommandAbstract { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					public: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    InfoCommand(uint8_t cmd){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        _TxType = 0x15; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        _Cmd = cmd; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    public: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        InfoCommand(uint8_t cmd){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _TxType = 0x15; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            _Cmd = cmd; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// list of all available functions, mapped in hmDefines.h
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -94,35 +100,34 @@ const calcFunc_t<T> calcFunctions[] = { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					template <class RECORDTYPE> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					template <class REC_TYP> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					class Inverter { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    public: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t       id;       // unique id
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        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
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint16_t      alarmMesIndex; // Last recorded Alarm Message Index
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint16_t      fwVersion; // Firmware Version from Info Command Request
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint16_t      powerLimit[2];  // limit power output
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint16_t      actPowerLimit; //
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t       devControlCmd;  // carries the requested cmd
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        bool          devControlRequest; // true if change needed
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        serial_u      serial;   // serial number as on barcode
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        serial_u      radioId;  // id converted to modbus
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t       channels; // number of PV channels (1-4)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint32_t      ts;       // timestamp of last received payload
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        RECORDTYPE    *record;  // pointer for values
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint16_t      chMaxPwr[4]; // maximum power of the modules (Wp)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        char          chName[4][MAX_NAME_LENGTH]; // human readable name for channel
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t       type;                  // integer which refers to inverter type
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint16_t      alarmMesIndex;         // Last recorded Alarm Message Index
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint16_t      fwVersion;             // Firmware Version from Info Command Request
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint16_t      powerLimit[2];         // limit power output
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint16_t      actPowerLimit;         //
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t       devControlCmd;         // carries the requested cmd
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        bool          devControlRequest;     // true if change needed
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        serial_u      serial;                // serial number as on barcode
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        serial_u      radioId;               // id converted to modbus
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t       channels;              // number of PV channels (1-4)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        record_t<REC_TYP> recordMeas;        // structure for measured values
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        record_t<REC_TYP> recordInfo;        // structure for info values
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        record_t<REC_TYP> recordConfig;      // structure for system config values
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        record_t<REC_TYP> recordAlarm;       // structure for alarm values
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint16_t      chMaxPwr[4];           // maximum power of the modules (Wp)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        char          chName[4][MAX_NAME_LENGTH]; // human readable name for channels
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        String        lastAlarmMsg; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        bool          initialized; // needed to check if the inverter was correctly added (ESP32 specific - union types are never null)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        bool          initialized;           // needed to check if the inverter was correctly added (ESP32 specific - union types are never null)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        Inverter() { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            ts = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            powerLimit[0] = 0xffff; // 65535 W Limit -> unlimited
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            powerLimit[1] = NoPowerLimit; //
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            actPowerLimit = 0xffff; // init feedback from inverter to -1
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            powerLimit[0] = 0xffff;       // 65535 W Limit -> unlimited
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            powerLimit[1] = NoPowerLimit; // default power limit setting
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            actPowerLimit = 0xffff;       // init feedback from inverter to -1
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            devControlRequest = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            devControlCmd = InitDataState; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            initialized = false; | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -174,187 +179,201 @@ class Inverter { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        void init(void) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:init")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            getAssignment(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            initAssignment(&recordMeas, RealTimeRunData_Debug); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            initAssignment(&recordInfo, InverterDevInform_All); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            initAssignment(&recordConfig, SystemConfigPara); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            initAssignment(&recordAlarm, AlarmData); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            toRadioId(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            record = new RECORDTYPE[listLen]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            memset(name, 0, MAX_NAME_LENGTH); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            memset(chName, 0, MAX_NAME_LENGTH * 4); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            memset(record, 0, sizeof(RECORDTYPE) * listLen); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            initialized = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t getPosByChFld(uint8_t channel, uint8_t fieldId) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t getPosByChFld(uint8_t channel, uint8_t fieldId, record_t<> *rec) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getPosByChFld")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint8_t pos = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            for(; pos < listLen; pos++) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if((assign[pos].ch == channel) && (assign[pos].fieldId == fieldId)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if(NULL != rec) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                for(; pos < rec->length; pos++) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if((rec->assign[pos].ch == channel) && (rec->assign[pos].fieldId == fieldId)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return (pos >= rec->length) ? 0xff : pos; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return (pos >= listLen) ? 0xff : pos; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return 0xff; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        const char *getFieldName(uint8_t pos) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        const char *getFieldName(uint8_t pos, record_t<> *rec) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getFieldName")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return fields[assign[pos].fieldId]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if(NULL != rec) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return fields[rec->assign[pos].fieldId]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return notAvail; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        const char *getUnit(uint8_t pos) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        const char *getUnit(uint8_t pos, record_t<> *rec) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getUnit")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return units[assign[pos].unitId]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if(NULL != rec) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return units[rec->assign[pos].unitId]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return notAvail; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t getChannel(uint8_t pos) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t getChannel(uint8_t pos, record_t<> *rec) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getChannel")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return assign[pos].ch; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if(NULL != rec) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return rec->assign[pos].ch; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        void addValue(uint8_t pos, uint8_t buf[]) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        void addValue(uint8_t pos, uint8_t buf[], record_t<> *rec) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:addValue")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint8_t cmd = getQueuedCmd(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint8_t ptr  = assign[pos].start; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint8_t end  = ptr + assign[pos].num; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint16_t div = assign[pos].div; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if(CMD_CALC != div) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                uint32_t val = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                do { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    val <<= 8; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    val |= buf[ptr]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } while(++ptr != end); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if ((RECORDTYPE)(div) > 1){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    record[pos] = (RECORDTYPE)(val) / (RECORDTYPE)(div);                 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    record[pos] = (RECORDTYPE)(val);                 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (cmd == RealTimeRunData_Debug) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // get last alarm message index and save it in the inverter object
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (getPosByChFld(0, FLD_ALARM_MES_ID) == pos){  | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (alarmMesIndex < record[pos]){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        alarmMesIndex = record[pos]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        //enqueCommand<InfoCommand>(AlarmUpdate); // What is the function of AlarmUpdate?
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        enqueCommand<InfoCommand>(AlarmData); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if(NULL != rec) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                uint8_t  ptr = rec->assign[pos].start; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                uint8_t  end = ptr + rec->assign[pos].num; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                uint16_t div = rec->assign[pos].div; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if(rec == &recordMeas) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if(CMD_CALC != div) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        uint32_t val = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        do { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            val <<= 8; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            val |= buf[ptr]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        } while(++ptr != end); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        if ((REC_TYP)(div) > 1) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            rec->record[pos] = (REC_TYP)(val) / (REC_TYP)(div); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        else | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            rec->record[pos] = (REC_TYP)(val); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        alarmMesIndex = record[pos]; // no change
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    // get last alarm message index and save it in the inverter object
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (getPosByChFld(0, FLD_ALARM_MES_ID, rec) == pos){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        if (alarmMesIndex < rec->record[pos]){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            alarmMesIndex = rec->record[pos]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            //enqueCommand<InfoCommand>(AlarmUpdate); // What is the function of AlarmUpdate?
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            enqueCommand<InfoCommand>(AlarmData); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                            alarmMesIndex = rec->record[pos]; // no change
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (cmd == InverterDevInform_All) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // get at least the firmware version and save it to the inverter object
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (getPosByChFld(0, FLD_FW_VERSION) == pos){  | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    fwVersion = record[pos]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    DPRINT(DBG_DEBUG, F("Inverter FW-Version: ") + String(fwVersion)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (rec == &recordInfo) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    // get at least the firmware version and save it to the inverter object
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (getPosByChFld(0, FLD_FW_VERSION, rec) == pos){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        fwVersion = rec->record[pos]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        DPRINT(DBG_DEBUG, F("Inverter FW-Version: ") + String(fwVersion)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (cmd == SystemConfigPara) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                // get at least the firmware version and save it to the inverter object
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (getPosByChFld(0, FLD_ACT_PWR_LIMIT) == pos){  | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    actPowerLimit = record[pos]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    DPRINT(DBG_DEBUG, F("Inverter actual power limit: ") + String(actPowerLimit)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (rec == &recordConfig) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    // get at least the firmware version and save it to the inverter object
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (getPosByChFld(0, FLD_ACT_PWR_LIMIT, rec) == pos){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        actPowerLimit = rec->record[pos]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        DPRINT(DBG_DEBUG, F("Inverter actual power limit: ") + String(actPowerLimit)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (cmd == AlarmData){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (getPosByChFld(0, FLD_LAST_ALARM_CODE) == pos){  | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    lastAlarmMsg = getAlarmStr(record[pos]); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if (rec == &recordAlarm){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (getPosByChFld(0, FLD_LAST_ALARM_CODE, rec) == pos){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        lastAlarmMsg = getAlarmStr(rec->record[pos]); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                DPRINTLN(DBG_ERROR, F("addValue: assignment not found with cmd 0x")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        RECORDTYPE getValue(uint8_t pos) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        REC_TYP getValue(uint8_t pos, record_t<> *rec) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getValue")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return record[pos]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if(NULL == rec) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return rec->record[pos]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        void doCalculations() { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:doCalculations")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint8_t cmd = getQueuedCmd(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            getAssignment(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (cmd == RealTimeRunData_Debug){ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                for(uint8_t i = 0; i < listLen; i++) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if(CMD_CALC == assign[i].div) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        record[i] = calcFunctions<RECORDTYPE>[assign[i].start].func(this, assign[i].num); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    yield(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            record_t<> *rec = getRecordStruct(RealTimeRunData_Debug); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            for(uint8_t i = 0; i < rec->length; i++) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                if(CMD_CALC == rec->assign[i].div) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    rec->record[i] = calcFunctions<REC_TYP>[rec->assign[i].start].func(this, rec->assign[i].num); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                yield(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        bool isAvailable(uint32_t timestamp) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        bool isAvailable(uint32_t timestamp, record_t<> *rec) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:isAvailable")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return ((timestamp - ts) < INACT_THRES_SEC); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return ((timestamp - rec->ts) < INACT_THRES_SEC); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        bool isProducing(uint32_t timestamp) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        bool isProducing(uint32_t timestamp, record_t<> *rec) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:isProducing")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if(isAvailable(timestamp)) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                uint8_t pos = getPosByChFld(CH0, FLD_PAC); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return (getValue(pos) > INACT_PWR_THRESH); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if(isAvailable(timestamp, rec)) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                uint8_t pos = getPosByChFld(CH0, FLD_PAC, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return (getValue(pos, rec) > INACT_PWR_THRESH); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint32_t getLastTs(void) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint32_t getLastTs(record_t<> *rec) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getLastTs")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return ts; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return rec->ts; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        void getAssignment()  { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_DEBUG, F("hmInverter.h:getAssignment")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            // Default assignment;
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (INV_TYPE_1CH == type) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                listLen = (uint8_t)(HM1CH_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                assign = (byteAssign_t *)hm1chAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                channels = 1; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else if (INV_TYPE_2CH == type) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                listLen = (uint8_t)(HM2CH_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                assign = (byteAssign_t *)hm2chAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                channels = 2; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else if (INV_TYPE_4CH == type) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                listLen = (uint8_t)(HM4CH_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                assign = (byteAssign_t *)hm4chAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                channels = 4; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                listLen = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                channels = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                assign = NULL; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        record_t<> *getRecordStruct(uint8_t cmd) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            switch (cmd) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                case RealTimeRunData_Debug: return &recordMeas; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                case InverterDevInform_All: return &recordInfo; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                case SystemConfigPara:      return &recordConfig; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                case AlarmData:             return &recordAlarm; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                default:                    break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return NULL; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            switch (getQueuedCmd()) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        void initAssignment(record_t<> *rec, uint8_t cmd) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:initAssignment")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            rec->ts     = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            rec->length = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            switch (cmd) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                case RealTimeRunData_Debug: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    // Do nothing will use default
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    if (INV_TYPE_1CH == type) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        rec->length = (uint8_t)(HM1CH_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        rec->assign = (byteAssign_t *)hm1chAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        channels    = 1; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    else if (INV_TYPE_2CH == type) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        rec->length = (uint8_t)(HM2CH_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        rec->assign = (byteAssign_t *)hm2chAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        channels    = 2; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    else if (INV_TYPE_4CH == type) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        rec->length = (uint8_t)(HM4CH_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        rec->assign = (byteAssign_t *)hm4chAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        channels    = 4; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        rec->length = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        rec->assign = NULL; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                        channels    = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                case InverterDevInform_All: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    listLen = (uint8_t)(HMINFO_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    assign = (byteAssign_t *)InfoAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    rec->length = (uint8_t)(HMINFO_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    rec->assign = (byteAssign_t *)InfoAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                case SystemConfigPara: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    listLen = (uint8_t)(HMSYSTEM_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    assign = (byteAssign_t *)SystemConfigParaAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    rec->length = (uint8_t)(HMSYSTEM_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    rec->assign = (byteAssign_t *)SystemConfigParaAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                case AlarmData: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    listLen = (uint8_t)(HMALARMDATA_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    assign = (byteAssign_t *)AlarmDataAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    rec->length = (uint8_t)(HMALARMDATA_LIST_LEN); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    rec->assign = (byteAssign_t *)AlarmDataAssignment; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                default: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    DPRINTLN(DBG_INFO, "Parser not implemented"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    DPRINTLN(DBG_INFO, F("initAssignment: Parser not implemented")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                    break; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        bool isLiveDataAssignment(void) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if(assign == (byteAssign_t *)hm1chAssignment) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else if(assign == (byteAssign_t *)hm2chAssignment) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else if(assign == (byteAssign_t *)hm4chAssignment) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            else | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                return false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if(0 != rec->length) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                rec->record = new REC_TYP[rec->length]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                memset(rec->record, 0, sizeof(REC_TYP) * rec->length); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        String getAlarmStr(u_int16_t alarmCode) { | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -455,10 +474,11 @@ template<class T=float> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					static T calcYieldTotalCh0(Inverter<> *iv, uint8_t arg0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcYieldTotalCh0")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if(NULL != iv) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        T yield = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        for(uint8_t i = 1; i <= iv->channels; i++) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint8_t pos = iv->getPosByChFld(i, FLD_YT); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            yield += iv->getValue(pos); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint8_t pos = iv->getPosByChFld(i, FLD_YT, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            yield += iv->getValue(pos, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        return yield; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -469,10 +489,11 @@ template<class T=float> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					static T calcYieldDayCh0(Inverter<> *iv, uint8_t arg0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcYieldDayCh0")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if(NULL != iv) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        T yield = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        for(uint8_t i = 1; i <= iv->channels; i++) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint8_t pos = iv->getPosByChFld(i, FLD_YD); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            yield += iv->getValue(pos); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint8_t pos = iv->getPosByChFld(i, FLD_YD, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            yield += iv->getValue(pos, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        return yield; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -483,9 +504,10 @@ template<class T=float> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					static T calcUdcCh(Inverter<> *iv, uint8_t arg0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcUdcCh")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    // 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); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    for(uint8_t i = 0; i < rec->length; i++) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        if((FLD_UDC == rec->assign[i].fieldId) && (arg0 == rec->assign[i].ch)) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return iv->getValue(i, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -496,10 +518,11 @@ template<class T=float> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					static T calcPowerDcCh0(Inverter<> *iv, uint8_t arg0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcPowerDcCh0")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if(NULL != iv) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        T dcPower = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        for(uint8_t i = 1; i <= iv->channels; i++) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint8_t pos = iv->getPosByChFld(i, FLD_PDC); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            dcPower += iv->getValue(pos); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            dcPower += iv->getValue(pos, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        return dcPower; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -510,12 +533,13 @@ template<class T=float> | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					static T calcEffiencyCh0(Inverter<> *iv, uint8_t arg0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcEfficiencyCh0")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if(NULL != iv) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t pos = iv->getPosByChFld(CH0, FLD_PAC); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        T acPower = iv->getValue(pos); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t pos = iv->getPosByChFld(CH0, FLD_PAC, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        T acPower = iv->getValue(pos, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        T dcPower = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        for(uint8_t i = 1; i <= iv->channels; i++) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            pos = iv->getPosByChFld(i, FLD_PDC); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            dcPower += iv->getValue(pos); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            pos = iv->getPosByChFld(i, FLD_PDC, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            dcPower += iv->getValue(pos, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        if(dcPower > 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return acPower / dcPower * 100.0f; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -528,9 +552,10 @@ static T calcIrradiation(Inverter<> *iv, uint8_t arg0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcIrradiation")); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    // arg0 = channel
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    if(NULL != iv) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t pos = iv->getPosByChFld(arg0, FLD_PDC); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        uint8_t pos = iv->getPosByChFld(arg0, FLD_PDC, rec); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        if(iv->chMaxPwr[arg0-1] > 0) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return iv->getValue(pos) / iv->chMaxPwr[arg0-1] * 100.0f; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            return iv->getValue(pos, rec) / iv->chMaxPwr[arg0-1] * 100.0f; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return 0.0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
  |