From 14305a9f120467096e6f521c4732b32eb6804ee0 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Mon, 31 Jul 2023 21:48:26 +0200 Subject: [PATCH] Fix: Prevent wrong values of statistics data because of non-atomic transaction --- .../src/commands/RealTimeRunDataCommand.cpp | 2 ++ lib/Hoymiles/src/parser/StatisticsParser.cpp | 24 +++++++++++++++++++ lib/Hoymiles/src/parser/StatisticsParser.h | 5 ++++ 3 files changed, 31 insertions(+) diff --git a/lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp b/lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp index d59e1443..3f0aed36 100644 --- a/lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp +++ b/lib/Hoymiles/src/commands/RealTimeRunDataCommand.cpp @@ -40,11 +40,13 @@ bool RealTimeRunDataCommand::handleResponse(InverterAbstract* inverter, fragment // Move all fragments into target buffer uint8_t offs = 0; + inverter->Statistics()->beginAppendFragment(); inverter->Statistics()->clearBuffer(); for (uint8_t i = 0; i < max_fragment_id; i++) { inverter->Statistics()->appendFragment(offs, fragment[i].fragment, fragment[i].len); offs += (fragment[i].len); } + inverter->Statistics()->endAppendFragment(); inverter->Statistics()->resetRxFailureCount(); inverter->Statistics()->setLastUpdate(millis()); return true; diff --git a/lib/Hoymiles/src/parser/StatisticsParser.cpp b/lib/Hoymiles/src/parser/StatisticsParser.cpp index 59d0148b..2cbf9c84 100644 --- a/lib/Hoymiles/src/parser/StatisticsParser.cpp +++ b/lib/Hoymiles/src/parser/StatisticsParser.cpp @@ -5,6 +5,11 @@ #include "StatisticsParser.h" #include "../Hoymiles.h" +#define HOY_SEMAPHORE_TAKE() \ + do { \ + } while (xSemaphoreTake(_xSemaphore, portMAX_DELAY) != pdPASS) +#define HOY_SEMAPHORE_GIVE() xSemaphoreGive(_xSemaphore) + static float calcYieldTotalCh0(StatisticsParser* iv, uint8_t arg0); static float calcYieldDayCh0(StatisticsParser* iv, uint8_t arg0); static float calcUdcCh(StatisticsParser* iv, uint8_t arg0); @@ -28,6 +33,13 @@ const calcFunc_t calcFunctions[] = { { CALC_IRR_CH, &calcIrradiation } }; +StatisticsParser::StatisticsParser() + : Parser() +{ + _xSemaphore = xSemaphoreCreateMutex(); + HOY_SEMAPHORE_GIVE(); // release before first use +} + void StatisticsParser::setByteAssignment(const byteAssign_t* byteAssignment, uint8_t size) { _byteAssignment = byteAssignment; @@ -62,6 +74,16 @@ void StatisticsParser::appendFragment(uint8_t offset, uint8_t* payload, uint8_t _statisticLength += len; } +void StatisticsParser::beginAppendFragment() +{ + HOY_SEMAPHORE_TAKE(); +} + +void StatisticsParser::endAppendFragment() +{ + HOY_SEMAPHORE_GIVE(); +} + const byteAssign_t* StatisticsParser::getAssignmentByChannelField(ChannelType_t type, ChannelNum_t channel, FieldId_t fieldId) { for (uint8_t i = 0; i < _byteAssignmentSize; i++) { @@ -98,10 +120,12 @@ float StatisticsParser::getChannelFieldValue(ChannelType_t type, ChannelNum_t ch if (CMD_CALC != div) { // Value is a static value uint32_t val = 0; + HOY_SEMAPHORE_TAKE(); do { val <<= 8; val |= _payloadStatistic[ptr]; } while (++ptr != end); + HOY_SEMAPHORE_GIVE(); float result; if (pos->isSigned && pos->num == 2) { diff --git a/lib/Hoymiles/src/parser/StatisticsParser.h b/lib/Hoymiles/src/parser/StatisticsParser.h index 7c8d64f0..436dba27 100644 --- a/lib/Hoymiles/src/parser/StatisticsParser.h +++ b/lib/Hoymiles/src/parser/StatisticsParser.h @@ -104,8 +104,11 @@ typedef struct { class StatisticsParser : public Parser { public: + StatisticsParser(); void clearBuffer(); void appendFragment(uint8_t offset, uint8_t* payload, uint8_t len); + void beginAppendFragment(); + void endAppendFragment(); void setByteAssignment(const byteAssign_t* byteAssignment, uint8_t size); @@ -146,4 +149,6 @@ private: std::list _fieldSettings; uint32_t _rxFailureCount = 0; + + SemaphoreHandle_t _xSemaphore; }; \ No newline at end of file