From f8be52aa61fa9c1f9948bf274d51dd3bcdb21d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Sat, 23 Mar 2024 08:10:55 +0100 Subject: [PATCH] merge changes from upstream --- .../Foundation/include/Poco/MemoryStream.h | 6 ++ .../testsuite/src/MemoryStreamTest.cpp | 8 ++ platform/Util/include/Poco/Util/Timer.h | 9 ++ platform/XML/include/Poco/XML/expat.h | 5 +- platform/XML/src/internal.h | 17 ++- platform/XML/src/xmlparse.cpp | 30 ++++-- protocols/Modbus/RTU/src/BundleActivator.cpp | 7 +- .../include/IoT/Modbus/ModbusMasterImpl.h | 101 +++++++++++------- 8 files changed, 123 insertions(+), 60 deletions(-) diff --git a/platform/Foundation/include/Poco/MemoryStream.h b/platform/Foundation/include/Poco/MemoryStream.h index e168c8a03..f50e9fb89 100644 --- a/platform/Foundation/include/Poco/MemoryStream.h +++ b/platform/Foundation/include/Poco/MemoryStream.h @@ -141,6 +141,12 @@ class BasicMemoryStreamBuf: public std::basic_streambuf return newoff; } + virtual pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) + { + const off_type off = pos; + return seekoff(off, std::ios::beg, which); + } + virtual int sync() { return 0; diff --git a/platform/Foundation/testsuite/src/MemoryStreamTest.cpp b/platform/Foundation/testsuite/src/MemoryStreamTest.cpp index 9c705a589..bb613b2e3 100644 --- a/platform/Foundation/testsuite/src/MemoryStreamTest.cpp +++ b/platform/Foundation/testsuite/src/MemoryStreamTest.cpp @@ -143,6 +143,14 @@ void MemoryStreamTest::testInputSeek() assertTrue (istr.good()); assertTrue (9 == istr.tellg()); + + istr.seekg(5); + assertTrue (istr.good()); + assertTrue (5 == istr.tellg()); + istr >> c; + assertTrue (c == '6'); + + { Poco::MemoryInputStream istr2(buffer.begin(), buffer.size()); istr2.seekg(10, std::ios_base::beg); diff --git a/platform/Util/include/Poco/Util/Timer.h b/platform/Util/include/Poco/Util/Timer.h index 34e2dbf7c..b6bd14a85 100644 --- a/platform/Util/include/Poco/Util/Timer.h +++ b/platform/Util/include/Poco/Util/Timer.h @@ -191,6 +191,15 @@ class Util_API Timer: protected Poco::Runnable }; +// +// inlines +// +inline bool Timer::idle() const +{ + return _queue.empty(); +} + + } } // namespace Poco::Util diff --git a/platform/XML/include/Poco/XML/expat.h b/platform/XML/include/Poco/XML/expat.h index 95464b0dd..c2770be38 100644 --- a/platform/XML/include/Poco/XML/expat.h +++ b/platform/XML/include/Poco/XML/expat.h @@ -18,6 +18,7 @@ Copyright (c) 2022 Thijs Schreijer Copyright (c) 2023 Hanno Böck Copyright (c) 2023 Sony Corporation / Snild Dolkow + Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -1042,7 +1043,7 @@ typedef struct { XMLPARSEAPI(const XML_Feature *) XML_GetFeatureList(void); -#if XML_GE == 1 +#if defined(XML_DTD) || (defined(XML_GE) && XML_GE == 1) /* Added in Expat 2.4.0 for XML_DTD defined and * added in Expat 2.6.0 for XML_GE == 1. */ XMLPARSEAPI(XML_Bool) @@ -1065,7 +1066,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled); */ #define XML_MAJOR_VERSION 2 #define XML_MINOR_VERSION 6 -#define XML_MICRO_VERSION 0 +#define XML_MICRO_VERSION 2 #ifdef __cplusplus } diff --git a/platform/XML/src/internal.h b/platform/XML/src/internal.h index a82c68b4b..a27eb20bc 100644 --- a/platform/XML/src/internal.h +++ b/platform/XML/src/internal.h @@ -28,10 +28,11 @@ Copyright (c) 2002-2003 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2003 Greg Stein - Copyright (c) 2016-2023 Sebastian Pipping + Copyright (c) 2016-2024 Sebastian Pipping Copyright (c) 2018 Yury Gribov Copyright (c) 2019 David Loffredo - Copyright (c) 2023 Sony Corporation / Snild Dolkow + Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow + Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp> Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -155,14 +156,20 @@ extern "C" { void _INTERNAL_trim_to_complete_utf8_characters(const char *from, const char **fromLimRef); -#if XML_GE == 1 +#if defined(XML_GE) && XML_GE == 1 unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser); unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser); const char *unsignedCharToPrintable(unsigned char c); #endif -extern XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c -extern unsigned int g_parseAttempts; // used for testing only +extern +#if ! defined(XML_TESTING) + const +#endif + XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c +#if defined(XML_TESTING) +extern unsigned int g_bytesScanned; // used for testing only +#endif #ifdef __cplusplus } diff --git a/platform/XML/src/xmlparse.cpp b/platform/XML/src/xmlparse.cpp index 8791b8efe..e9cf7a46a 100644 --- a/platform/XML/src/xmlparse.cpp +++ b/platform/XML/src/xmlparse.cpp @@ -1,4 +1,4 @@ -/* 628e24d4966bedbd4800f6ed128d06d29703765b4bce12d3b7f099f90f842fc9 (2.6.0+) +/* 2a14271ad4d35e82bde8ba210b4edb7998794bcbae54deab114046a300f9639a (2.6.2+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -38,7 +38,7 @@ Copyright (c) 2022 Jann Horn Copyright (c) 2022 Sean McBride Copyright (c) 2023 Owain Davies - Copyright (c) 2023 Sony Corporation / Snild Dolkow + Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -217,7 +217,7 @@ typedef char ICHAR; #endif /* Round up n to be a multiple of sz, where sz is a power of 2. */ -#define ROUND_UP(n, sz) (((n) + ((sz)-1)) & ~((sz)-1)) +#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) /* Do safe (NULL-aware) pointer arithmetic */ #define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0) @@ -255,7 +255,7 @@ static void copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key); it odd, since odd numbers are always relative prime to a power of 2. */ #define SECOND_HASH(hash, mask, power) \ - ((((hash) & ~(mask)) >> ((power)-1)) & ((mask) >> 2)) + ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2)) #define PROBE_STEP(hash, mask, power) \ ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1)) @@ -636,8 +636,14 @@ static unsigned long getDebugLevel(const char *variableName, ? 0 \ : ((*((pool)->ptr)++ = c), 1)) -XML_Bool g_reparseDeferralEnabledDefault = XML_TRUE; // write ONLY in runtests.c -unsigned int g_parseAttempts = 0; // used for testing only +#if ! defined(XML_TESTING) +const +#endif + XML_Bool g_reparseDeferralEnabledDefault + = XML_TRUE; // write ONLY in runtests.c +#if defined(XML_TESTING) +unsigned int g_bytesScanned = 0; // used for testing only +#endif struct XML_ParserStruct { /* The first member must be m_userData so that the XML_GetUserData @@ -1035,7 +1041,9 @@ callProcessor(XML_Parser parser, const char *start, const char *end, return XML_ERROR_NONE; } } - g_parseAttempts += 1; +#if defined(XML_TESTING) + g_bytesScanned += (unsigned)have_now; +#endif const enum XML_Error ret = parser->m_processor(parser, start, end, endPtr); if (ret == XML_ERROR_NONE) { // if we consumed nothing, remember what we had on this parse attempt. @@ -6250,7 +6258,7 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc, dtd->keepProcessing = dtd->standalone; goto endEntityValue; } - if (entity->open) { + if (entity->open || (entity == parser->m_declEntity)) { if (enc == parser->m_encoding) parser->m_eventPtr = entityTextPtr; result = XML_ERROR_RECURSIVE_ENTITY_REF; @@ -7797,6 +7805,8 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) { static float accountingGetCurrentAmplification(XML_Parser rootParser) { + // 1.........1.........12 => 22 + const size_t lenOfShortestInclude = sizeof("") - 1; const XmlBigCount countBytesOutput = rootParser->m_accounting.countBytesDirect + rootParser->m_accounting.countBytesIndirect; @@ -7804,7 +7814,9 @@ accountingGetCurrentAmplification(XML_Parser rootParser) { = rootParser->m_accounting.countBytesDirect ? (countBytesOutput / (float)(rootParser->m_accounting.countBytesDirect)) - : 1.0f; + : ((lenOfShortestInclude + + rootParser->m_accounting.countBytesIndirect) + / (float)lenOfShortestInclude); assert(! rootParser->m_parentParser); return amplificationFactor; } diff --git a/protocols/Modbus/RTU/src/BundleActivator.cpp b/protocols/Modbus/RTU/src/BundleActivator.cpp index 955a5b3ba..15c45a1b6 100644 --- a/protocols/Modbus/RTU/src/BundleActivator.cpp +++ b/protocols/Modbus/RTU/src/BundleActivator.cpp @@ -53,9 +53,9 @@ class BundleActivator: public Poco::OSP::BundleActivator { } - void createModbusRTUMaster(const std::string& uid, Poco::SharedPtr pSerialPort, Poco::Timespan timeout, Poco::Timespan frameTimeout, std::size_t maxAsyncQueueSize) + void createModbusRTUMaster(const std::string& uid, Poco::SharedPtr pSerialPort, Poco::Timespan timeout, Poco::Timespan frameTimeout, std::size_t maxAsyncQueueSize, Poco::Timespan frameSpacing) { - Poco::SharedPtr pModbusMaster = new ModbusMasterImpl(new RTUMasterPort(pSerialPort, frameTimeout), timeout, maxAsyncQueueSize); + Poco::SharedPtr pModbusMaster = new ModbusMasterImpl(new RTUMasterPort(pSerialPort, frameTimeout), timeout, maxAsyncQueueSize, frameSpacing); std::string symbolicName = "io.macchina.modbus.rtu"s; Poco::RemotingNG::Identifiable::ObjectId oid = symbolicName; oid += '#'; @@ -88,6 +88,7 @@ class BundleActivator: public Poco::OSP::BundleActivator const int speed = _pPrefs->configuration()->getInt(baseKey + ".speed", 9600); const Poco::Timespan timeout = 1000*_pPrefs->configuration()->getInt(baseKey + ".timeout"s, 2000); const Poco::Timespan frameTimeout = _pPrefs->configuration()->getInt(baseKey + ".frameTimeout"s, 10000); + const Poco::Timespan frameSpacing = _pPrefs->configuration()->getInt(baseKey + ".frameSpacing"s, 3000); const std::size_t maxAsyncQueueSize = _pPrefs->configuration()->getUInt32(baseKey + ".maxAsyncQueueSize"s, 32); try @@ -113,7 +114,7 @@ class BundleActivator: public Poco::OSP::BundleActivator pSerialPort->configureRS485(rs485Params); } - createModbusRTUMaster(*it, pSerialPort, timeout, frameTimeout, maxAsyncQueueSize); + createModbusRTUMaster(*it, pSerialPort, timeout, frameTimeout, maxAsyncQueueSize, frameSpacing); } catch (Poco::Exception& exc) { diff --git a/protocols/Modbus/include/IoT/Modbus/ModbusMasterImpl.h b/protocols/Modbus/include/IoT/Modbus/ModbusMasterImpl.h index 37ddee4bb..aab41a0a7 100644 --- a/protocols/Modbus/include/IoT/Modbus/ModbusMasterImpl.h +++ b/protocols/Modbus/include/IoT/Modbus/ModbusMasterImpl.h @@ -42,10 +42,11 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable /// protocol over a serial line. { public: - ModbusMasterImpl(Poco::SharedPtr pPort, Poco::Timespan responseTimeout = Poco::Timespan(2, 0), std::size_t maxAsyncQueueSize = 256): + ModbusMasterImpl(Poco::SharedPtr pPort, Poco::Timespan responseTimeout = Poco::Timespan(2, 0), std::size_t maxAsyncQueueSize = 256, Poco::Timespan frameSpacing = Poco::Timespan(0, 0)): _pPort(pPort), _timeout(responseTimeout), _maxAsyncQueueSize(maxAsyncQueueSize), + _frameSpacing(frameSpacing), _logger(Poco::Logger::get("IoT.ModbusMaster")) { _pPort->connectionStateChanged += Poco::delegate(this, &ModbusMasterImpl::onConnectionStateChanged); @@ -211,7 +212,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { ReadCoilsResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); return response.coilStatus; } else throw Poco::ProtocolException("incomplete or invalid frame received"); @@ -242,7 +243,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { ReadDiscreteInputsResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); return response.inputStatus; } else throw Poco::ProtocolException("incomplete or invalid frame received"); @@ -273,7 +274,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { ReadHoldingRegistersResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); return response.registerValues; } else throw Poco::ProtocolException("incomplete or invalid frame received"); @@ -304,7 +305,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { ReadInputRegistersResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); return response.registerValues; } else throw Poco::ProtocolException("incomplete or invalid frame received"); @@ -335,7 +336,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { WriteSingleCoilResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); } else throw Poco::ProtocolException("incomplete or invalid frame received"); } @@ -365,7 +366,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { WriteSingleRegisterResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); } else throw Poco::ProtocolException("incomplete or invalid frame received"); } @@ -393,7 +394,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { ReadExceptionStatusResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); return response.data; } else throw Poco::ProtocolException("incomplete or invalid frame received"); @@ -426,7 +427,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { WriteMultipleCoilsResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); } else throw Poco::ProtocolException("incomplete or invalid frame received"); } @@ -456,7 +457,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { WriteMultipleRegistersResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); } else throw Poco::ProtocolException("incomplete or invalid frame received"); } @@ -487,7 +488,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { MaskWriteRegisterResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); } else throw Poco::ProtocolException("incomplete or invalid frame received"); } @@ -524,7 +525,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { ReadWriteMultipleRegistersResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); return response.values; } else throw Poco::ProtocolException("incomplete or invalid frame received"); @@ -554,7 +555,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable else if ((fc & MODBUS_FUNCTION_CODE_MASK) == request.functionCode) { ReadFIFOQueueResponse response; - decodeFrame(response, transactionID); + decodeFrameAndCheckTransactionID(response, transactionID); return response.values; } else throw Poco::ProtocolException("incomplete or invalid frame received"); @@ -649,12 +650,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable throw Poco::ProtocolException("Maximum number of queued requests exceeded"); } - message.transactionID = _nextTransactionID; - if (_pPort->hasTransactionIDs()) - { - ++_nextTransactionID; - } - + message.transactionID = _nextTransactionID++; if (_pAsyncThread) { addPending(message); @@ -668,13 +664,6 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable return message.transactionID; } - template - void decodeFrame(M& message, Poco::UInt16 transactionID) - { - _pPort->decodeFrame(message); - if (message.transactionID != transactionID) throw Poco::ProtocolException("transaction ID mismatch"); - } - void enableEvents() { using namespace std::string_literals; @@ -708,9 +697,12 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable using namespace std::string_literals; bool stopped = false; + Poco::Clock nextSendTime; + Poco::Clock currentTime; const std::size_t maxPending = _pPort->maxSimultaneousTransactions(); while (!stopped) { + currentTime.update(); const auto p = countPendingSent(); std::size_t pendingSent = p.first; const std::size_t pending = p.second; @@ -719,7 +711,11 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable _logger.debug("Currently pending requests: %z, sent: %z."s, pending, pendingSent); } const long dequeueTimeout = pending == 0 ? 100 : 0; - Poco::Notification::Ptr pNf = _asyncQueue.waitDequeueNotification(dequeueTimeout); + Poco::Notification::Ptr pNf; + if (currentTime >= nextSendTime) + { + pNf = _asyncQueue.waitDequeueNotification(dequeueTimeout); + } if (pNf) { if (pNf.cast()) @@ -742,6 +738,8 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable markPendingSent(pSendNf->message().transactionID); pendingSent++; pSendNf->run(); + nextSendTime.update(); + nextSendTime += _frameSpacing.totalMicroseconds(); } catch (Poco::Exception& exc) { @@ -779,6 +777,8 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable { this->error(this, exc.displayText()); } + nextSendTime.update(); + nextSendTime += _frameSpacing.totalMicroseconds(); } } catch (Poco::Exception& exc) @@ -791,6 +791,24 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable } } + template + void decodeFrameAndFixTransactionID(M& message) + { + _pPort->decodeFrame(message); + if (!_pPort->hasTransactionIDs()) + { + auto it = _pendingMap.begin(); + if (it != _pendingMap.end()) message.transactionID = it->first; + } + } + + template + void decodeFrameAndCheckTransactionID(M& message, Poco::UInt16 transactionID) + { + _pPort->decodeFrame(message); + if (message.transactionID != transactionID) throw Poco::ProtocolException("transaction ID mismatch"); + } + void processFrame() { using namespace std::string_literals; @@ -811,7 +829,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable if ((fc & MODBUS_EXCEPTION_MASK) == MODBUS_EXCEPTION_MASK) { ModbusExceptionMessage message; - _pPort->decodeFrame(message); + decodeFrameAndFixTransactionID(message); if (removePending(message.transactionID)) { this->exceptionReceived(this, message); @@ -822,7 +840,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_READ_COILS: { ReadCoilsResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->readCoilsResponseReceived(this, response); @@ -833,7 +851,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_READ_DISCRETE_INPUTS: { ReadDiscreteInputsResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->readDiscreteInputsResponseReceived(this, response); @@ -844,7 +862,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_READ_HOLDING_REGISTERS: { ReadHoldingRegistersResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->readHoldingRegistersResponseReceived(this, response); @@ -855,7 +873,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_READ_INPUT_REGISTERS: { ReadInputRegistersResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->readInputRegistersResponseReceived(this, response); @@ -866,7 +884,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_WRITE_SINGLE_COIL: { WriteSingleCoilResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->writeSingleCoilResponseReceived(this, response); @@ -877,7 +895,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_WRITE_SINGLE_REGISTER: { WriteSingleRegisterResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->writeSingleRegisterResponseReceived(this, response); @@ -888,7 +906,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_READ_EXCEPTION_STATUS: { ReadExceptionStatusResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->readExceptionStatusResponseReceived(this, response); @@ -899,7 +917,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_WRITE_MULTIPLE_COILS: { WriteMultipleCoilsResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->writeMultipleCoilsResponseReceived(this, response); @@ -910,7 +928,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_WRITE_MULTIPLE_REGISTERS: { WriteMultipleRegistersResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->writeMultipleRegistersResponseReceived(this, response); @@ -921,7 +939,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_MASK_WRITE_REGISTER: { MaskWriteRegisterResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->maskWriteRegisterResponseReceived(this, response); @@ -932,7 +950,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_READ_WRITE_MULTIPLE_REGISTERS: { ReadWriteMultipleRegistersResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->readWriteMultipleRegistersResponseReceived(this, response); @@ -943,7 +961,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable case MODBUS_READ_FIFO_QUEUE: { ReadFIFOQueueResponse response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->readFIFOQueueResponseReceived(this, response); @@ -954,7 +972,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable default: { GenericMessage response; - _pPort->decodeFrame(response); + decodeFrameAndFixTransactionID(response); if (removePending(response.transactionID)) { this->responseReceived(this, response); @@ -1091,6 +1109,7 @@ class IoTModbus_API ModbusMasterImpl: public ModbusMaster, public Poco::Runnable Poco::SharedPtr _pPort; Poco::Timespan _timeout; std::size_t _maxAsyncQueueSize; + Poco::Timespan _frameSpacing; std::unique_ptr _pAsyncThread; Poco::NotificationQueue _asyncQueue; Poco::UInt16 _nextTransactionID = 0;