diff --git a/lib/Hoymiles/src/commands/MultiDataCommand.cpp b/lib/Hoymiles/src/commands/MultiDataCommand.cpp index b25c9027d..39a0d4c64 100644 --- a/lib/Hoymiles/src/commands/MultiDataCommand.cpp +++ b/lib/Hoymiles/src/commands/MultiDataCommand.cpp @@ -91,4 +91,13 @@ void MultiDataCommand::udpateCRC() uint16_t crc = crc16(&_payload[10], 14); // From data_type till password _payload[24] = (uint8_t)(crc >> 8); _payload[25] = (uint8_t)(crc); -} \ No newline at end of file +} + +uint8_t MultiDataCommand::getTotalFragmentSize(fragment_t fragment[], uint8_t max_fragment_id) +{ + uint8_t fragmentSize = 0; + for (uint8_t i = 0; i < max_fragment_id; i++) { + fragmentSize += fragment[i].len; + } + return fragmentSize; +} diff --git a/lib/Hoymiles/src/commands/MultiDataCommand.h b/lib/Hoymiles/src/commands/MultiDataCommand.h index ff835d7b9..4d2adfde4 100644 --- a/lib/Hoymiles/src/commands/MultiDataCommand.h +++ b/lib/Hoymiles/src/commands/MultiDataCommand.h @@ -20,6 +20,7 @@ class MultiDataCommand : public CommandAbstract { void setDataType(uint8_t data_type); uint8_t getDataType(); void udpateCRC(); + static uint8_t getTotalFragmentSize(fragment_t fragment[], uint8_t max_fragment_id); RequestFrameCommand _cmdRequestFrame; }; \ No newline at end of file diff --git a/lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp b/lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp index 6a7db92a9..646e363fe 100644 --- a/lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp +++ b/lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2022 Thomas Basler and others */ #include "RealTimeRunDataCommand.h" +#include "Hoymiles.h" #include "inverters/InverterAbstract.h" RealTimeRunDataCommand::RealTimeRunDataCommand(uint64_t target_address, uint64_t router_address, time_t time) @@ -25,6 +26,18 @@ bool RealTimeRunDataCommand::handleResponse(InverterAbstract* inverter, fragment return false; } + // Check if at least all required bytes are received + // In case of low power in the inverter it occours that some incomplete fragments + // with a valid CRC are received. + if (getTotalFragmentSize(fragment, max_fragment_id) < inverter->Statistics()->getMaxByteCount()) { + Hoymiles.getMessageOutput()->printf("ERROR in %s: Received fragment size: %d min. expected size: %d\r\n", + getCommandName().c_str(), + getTotalFragmentSize(fragment, max_fragment_id), + inverter->Statistics()->getMaxByteCount()); + + return false; + } + // Move all fragments into target buffer uint8_t offs = 0; inverter->Statistics()->clearBuffer(); diff --git a/lib/Hoymiles/src/parser/StatisticsParser.cpp b/lib/Hoymiles/src/parser/StatisticsParser.cpp index 0575a5fbb..c0e0b8ba5 100644 --- a/lib/Hoymiles/src/parser/StatisticsParser.cpp +++ b/lib/Hoymiles/src/parser/StatisticsParser.cpp @@ -34,6 +34,25 @@ void StatisticsParser::setByteAssignment(const byteAssign_t* byteAssignment, uin _byteAssignmentSize = size; } +uint8_t StatisticsParser::getMaxByteCount() +{ + static uint8_t maxByteCount = 0; + + // Use already calculated value + if (maxByteCount > 0) { + return maxByteCount; + } + + for (uint8_t i = 0; i < _byteAssignmentSize; i++) { + if (_byteAssignment[i].div == CMD_CALC) { + continue; + } + maxByteCount = max(maxByteCount, _byteAssignment[i].start + _byteAssignment[i].num); + } + + return maxByteCount; +} + void StatisticsParser::clearBuffer() { memset(_payloadStatistic, 0, STATISTIC_PACKET_SIZE); diff --git a/lib/Hoymiles/src/parser/StatisticsParser.h b/lib/Hoymiles/src/parser/StatisticsParser.h index f4bf7ae02..9f71045a3 100644 --- a/lib/Hoymiles/src/parser/StatisticsParser.h +++ b/lib/Hoymiles/src/parser/StatisticsParser.h @@ -109,6 +109,9 @@ class StatisticsParser : public Parser { void setByteAssignment(const byteAssign_t* byteAssignment, uint8_t size); + // Returns 1 based amount of expected bytes of statistic data + uint8_t getMaxByteCount(); + const byteAssign_t* getAssignmentByChannelField(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId); fieldSettings_t* getSettingByChannelField(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId);