OpenDTU/lib/Hoymiles/src/inverters/InverterAbstract.cpp
Thomas Basler a2880cc447 Add RX main command to structure which is passed to handleResponse
This is required because the DevControlCommands just set the first byte to define whether the request was successfull or not
2022-09-30 18:34:30 +02:00

143 lines
4.1 KiB
C++

#include "InverterAbstract.h"
#include "crc.h"
#include <cstring>
InverterAbstract::InverterAbstract(uint64_t serial)
{
_serial.u64 = serial;
_alarmLogParser.reset(new AlarmLogParser());
_devInfoParser.reset(new DevInfoParser());
_statisticsParser.reset(new StatisticsParser());
_systemConfigParaParser.reset(new SystemConfigParaParser());
}
void InverterAbstract::init()
{
// This has to be done here because:
// Not possible in constructor --> virtual function
// Not possible in verifyAllFragments --> Because no data if nothing is ever received
// It has to be executed because otherwise the getChannelCount method in stats always returns 0
_statisticsParser.get()->setByteAssignment(getByteAssignment(), getAssignmentCount());
}
uint64_t InverterAbstract::serial()
{
return _serial.u64;
}
void InverterAbstract::setName(const char* name)
{
uint8_t len = strlen(name);
if (len + 1 > MAX_NAME_LENGTH) {
len = MAX_NAME_LENGTH - 1;
}
strncpy(_name, name, len);
_name[len] = '\0';
}
const char* InverterAbstract::name()
{
return _name;
}
AlarmLogParser* InverterAbstract::EventLog()
{
return _alarmLogParser.get();
}
DevInfoParser* InverterAbstract::DevInfo()
{
return _devInfoParser.get();
}
StatisticsParser* InverterAbstract::Statistics()
{
return _statisticsParser.get();
}
SystemConfigParaParser* InverterAbstract::SystemConfigPara()
{
return _systemConfigParaParser.get();
}
void InverterAbstract::clearRxFragmentBuffer()
{
memset(_rxFragmentBuffer, 0, MAX_RF_FRAGMENT_COUNT * sizeof(fragment_t));
_rxFragmentMaxPacketId = 0;
_rxFragmentLastPacketId = 0;
_rxFragmentRetransmitCnt = 0;
}
void InverterAbstract::addRxFragment(uint8_t fragment[], uint8_t len)
{
if (len < 11) {
Serial.printf("FATAL: (%s, %d) fragment too short\n", __FILE__, __LINE__);
return;
}
if (len - 11 > MAX_RF_PAYLOAD_SIZE) {
Serial.printf("FATAL: (%s, %d) fragment too large\n", __FILE__, __LINE__);
return;
}
uint8_t fragmentCount = fragment[9];
if (fragmentCount == 0) {
Serial.println("ERROR: fragment number zero received and ignored");
return;
}
if ((fragmentCount & 0b01111111) < MAX_RF_FRAGMENT_COUNT) {
// Packets with 0x81 will be seen as 1
memcpy(_rxFragmentBuffer[(fragmentCount & 0b01111111) - 1].fragment, &fragment[10], len - 11);
_rxFragmentBuffer[(fragmentCount & 0b01111111) - 1].len = len - 11;
_rxFragmentBuffer[(fragmentCount & 0b01111111) - 1].mainCmd = fragment[0];
_rxFragmentBuffer[(fragmentCount & 0b01111111) - 1].wasReceived = true;
if ((fragmentCount & 0b01111111) > _rxFragmentLastPacketId) {
_rxFragmentLastPacketId = fragmentCount & 0b01111111;
}
}
// 0b10000000 == 0x80
if ((fragmentCount & 0b10000000) == 0b10000000) {
_rxFragmentMaxPacketId = fragmentCount & 0b01111111;
}
}
// Returns Zero on Success or the Fragment ID for retransmit or error code
uint8_t InverterAbstract::verifyAllFragments(CommandAbstract* cmd)
{
// All missing
if (_rxFragmentLastPacketId == 0) {
Serial.println(F("All missing"));
return FRAGMENT_ALL_MISSING;
}
// Last fragment is missing (thte one with 0x80)
if (_rxFragmentMaxPacketId == 0) {
Serial.println(F("Last missing"));
if (_rxFragmentRetransmitCnt++ < MAX_RETRANSMIT_COUNT) {
return _rxFragmentLastPacketId + 1;
} else {
return FRAGMENT_RETRANSMIT_TIMEOUT;
}
}
// Middle fragment is missing
for (uint8_t i = 0; i < _rxFragmentMaxPacketId - 1; i++) {
if (!_rxFragmentBuffer[i].wasReceived) {
Serial.println(F("Middle missing"));
if (_rxFragmentRetransmitCnt++ < MAX_RETRANSMIT_COUNT) {
return i + 1;
} else {
return FRAGMENT_RETRANSMIT_TIMEOUT;
}
}
}
if (!cmd->handleResponse(this, _rxFragmentBuffer, _rxFragmentMaxPacketId)) {
return FRAGMENT_HANDLE_ERROR;
}
return FRAGMENT_OK;
}