From 6d1bfd3ccc80541b32bb07adec9fd010c969214d Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Thu, 15 Jan 2026 01:13:42 +0000 Subject: [PATCH 01/19] Removed integration tests for now --- .github/workflows/build-and-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 463698c3..daed82a2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -51,10 +51,10 @@ jobs: ./build_clean_linux64.sh shell: bash - - name: Run coverage (unit tests + signalloadtest) + - name: Run coverage (unit tests) run: | chmod +x ./coverage_linux.sh - ./coverage_linux.sh --testdefinition Tests/signalloadtest.xml --build-target libmctest_signalloadtest + ./coverage_linux.sh shell: bash - name: Upload coverage report From 5f16454be8b7b5e98198766083695fabd81320ca Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Thu, 15 Jan 2026 11:26:35 +0100 Subject: [PATCH 02/19] Small change in telemetry multi-chunking --- ACT/LibMC.xml | 1 + .../HeadersCore/CppDynamic/libmc_dynamic.hpp | 2 ++ .../HeadersCore/CppDynamic/libmc_types.hpp | 2 ++ Framework/InterfacesCore/libmc_types.hpp | 2 ++ Implementation/Core/amc_telemetry.cpp | 30 +++++++++++++++---- Implementation/Core/amc_telemetry.hpp | 16 +++++++--- 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/ACT/LibMC.xml b/ACT/LibMC.xml index 753c7094..1cb544c9 100644 --- a/ACT/LibMC.xml +++ b/ACT/LibMC.xml @@ -722,6 +722,7 @@ + diff --git a/Framework/HeadersCore/CppDynamic/libmc_dynamic.hpp b/Framework/HeadersCore/CppDynamic/libmc_dynamic.hpp index 7885b4f0..e7e2fac8 100644 --- a/Framework/HeadersCore/CppDynamic/libmc_dynamic.hpp +++ b/Framework/HeadersCore/CppDynamic/libmc_dynamic.hpp @@ -791,6 +791,7 @@ class ELibMCException : public std::exception { case LIBMC_ERROR_INVALIDTELEMETRYMARKERFINISHTIMESTAMP: return "INVALIDTELEMETRYMARKERFINISHTIMESTAMP"; case LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION: return "UNFINISHEDTELEMETRYMARKERSHAVENODURATION"; case LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED: return "TELEMETRYMARKERALREADYREGISTERED"; + case LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND: return "TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND"; } return "UNKNOWN"; } @@ -1416,6 +1417,7 @@ class ELibMCException : public std::exception { case LIBMC_ERROR_INVALIDTELEMETRYMARKERFINISHTIMESTAMP: return "Invalid telemetry marker finish timestamp."; case LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION: return "Unfinished telemetry marker have no duration."; case LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED: return "Telemetry Marker has been already registered."; + case LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND: return "Telemetry Chunk Start timestamp is after end timestamp."; } return "unknown error"; } diff --git a/Framework/HeadersCore/CppDynamic/libmc_types.hpp b/Framework/HeadersCore/CppDynamic/libmc_types.hpp index 32734971..0edaceb9 100644 --- a/Framework/HeadersCore/CppDynamic/libmc_types.hpp +++ b/Framework/HeadersCore/CppDynamic/libmc_types.hpp @@ -713,6 +713,7 @@ typedef void * LibMC_pvoid; #define LIBMC_ERROR_INVALIDTELEMETRYMARKERFINISHTIMESTAMP 697 /** Invalid telemetry marker finish timestamp. */ #define LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION 698 /** Unfinished telemetry marker have no duration. */ #define LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED 699 /** Telemetry Marker has been already registered. */ +#define LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND 700 /** Telemetry Chunk Start timestamp is after end timestamp. */ /************************************************************************************************************************* Error strings for LibMC @@ -1338,6 +1339,7 @@ inline const char * LIBMC_GETERRORSTRING (LibMCResult nErrorCode) { case LIBMC_ERROR_INVALIDTELEMETRYMARKERFINISHTIMESTAMP: return "Invalid telemetry marker finish timestamp."; case LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION: return "Unfinished telemetry marker have no duration."; case LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED: return "Telemetry Marker has been already registered."; + case LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND: return "Telemetry Chunk Start timestamp is after end timestamp."; default: return "unknown error"; } } diff --git a/Framework/InterfacesCore/libmc_types.hpp b/Framework/InterfacesCore/libmc_types.hpp index 32734971..0edaceb9 100644 --- a/Framework/InterfacesCore/libmc_types.hpp +++ b/Framework/InterfacesCore/libmc_types.hpp @@ -713,6 +713,7 @@ typedef void * LibMC_pvoid; #define LIBMC_ERROR_INVALIDTELEMETRYMARKERFINISHTIMESTAMP 697 /** Invalid telemetry marker finish timestamp. */ #define LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION 698 /** Unfinished telemetry marker have no duration. */ #define LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED 699 /** Telemetry Marker has been already registered. */ +#define LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND 700 /** Telemetry Chunk Start timestamp is after end timestamp. */ /************************************************************************************************************************* Error strings for LibMC @@ -1338,6 +1339,7 @@ inline const char * LIBMC_GETERRORSTRING (LibMCResult nErrorCode) { case LIBMC_ERROR_INVALIDTELEMETRYMARKERFINISHTIMESTAMP: return "Invalid telemetry marker finish timestamp."; case LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION: return "Unfinished telemetry marker have no duration."; case LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED: return "Telemetry Marker has been already registered."; + case LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND: return "Telemetry Chunk Start timestamp is after end timestamp."; default: return "unknown error"; } } diff --git a/Implementation/Core/amc_telemetry.cpp b/Implementation/Core/amc_telemetry.cpp index fd4ebc2f..ff8f9956 100644 --- a/Implementation/Core/amc_telemetry.cpp +++ b/Implementation/Core/amc_telemetry.cpp @@ -36,15 +36,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "libmcdata_dynamic.hpp" +#define TELEMETRY_DEFAULT_CHUNKINTERVAL_MICROSECONDS 60000000 // 60 seconds + namespace AMC { - CTelemetryDataChunk::CTelemetryDataChunk(CTelemetryWriter* pWriter, uint32_t nChunkID) + CTelemetryDataChunk::CTelemetryDataChunk(CTelemetryWriter* pWriter, uint32_t nChunkID, uint64_t nChunkStartTimestamp, uint64_t nChunkEndTimestamp) : m_nTelemetryChunkID(nChunkID), m_nMinTimestamp(0), m_nMaxTimestamp(0), m_nMinMarkerID(0), m_nMaxMarkerID(0), - m_pWriter(pWriter) + m_pWriter(pWriter), m_nChunkStartTimestamp(nChunkStartTimestamp), m_nChunkEndTimestamp(nChunkEndTimestamp) { if (pWriter == nullptr) throw ELibMCInterfaceException(LIBMC_ERROR_INVALIDPARAM); + if (nChunkStartTimestamp >= nChunkEndTimestamp) + throw ELibMCInterfaceException(LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND); + } CTelemetryDataChunk::~CTelemetryDataChunk() @@ -103,7 +108,8 @@ namespace AMC { CTelemetryWriter::CTelemetryWriter(LibMCData::PTelemetrySession pTelemetrySession, AMCCommon::PChrono pGlobalChrono) - : m_nNextChunkIndex(1), m_pTelemetrySession(pTelemetrySession), m_nNextMarkerID(1), m_pGlobalChrono (pGlobalChrono) + : m_nNextChunkIndex(1), m_pTelemetrySession(pTelemetrySession), m_nNextMarkerID(1), m_pGlobalChrono (pGlobalChrono), + m_nChunkIntervalInMicroseconds (TELEMETRY_DEFAULT_CHUNKINTERVAL_MICROSECONDS), m_nNextChunkStartTimestamp (0) { if (pGlobalChrono.get () == nullptr) throw ELibMCInterfaceException(LIBMC_ERROR_INVALIDPARAM); @@ -118,26 +124,38 @@ namespace AMC { } - PTelemetryDataChunk CTelemetryWriter::getCurrentChunk() + PTelemetryDataChunk CTelemetryWriter::getCurrentChunk(uint64_t nTimestamp) { std::lock_guard lock(m_ChunkMutex); + if (nTimestamp >= m_nNextChunkStartTimestamp) + createNewChunkNoMutex(); + return m_pCurrentChunk; } PTelemetryDataChunk CTelemetryWriter::createNewChunk() { std::lock_guard lock(m_ChunkMutex); - auto pChunk = std::make_shared (this, m_nNextChunkIndex); + return createNewChunkNoMutex(); + } + + PTelemetryDataChunk CTelemetryWriter::createNewChunkNoMutex() + { + uint64_t nChunkEndTimestamp = m_nNextChunkStartTimestamp + m_nChunkIntervalInMicroseconds - 1; + + auto pChunk = std::make_shared (this, m_nNextChunkIndex, m_nNextChunkStartTimestamp, nChunkEndTimestamp); m_nNextChunkIndex++; m_Chunks.emplace_back(pChunk); m_pCurrentChunk = pChunk; + m_nNextChunkStartTimestamp = nChunkEndTimestamp + 1; + return pChunk; } void CTelemetryWriter::writeEntry(const sTelemetryChunkEntry& entry) { - auto pChunk = getCurrentChunk(); + auto pChunk = getCurrentChunk(entry.m_nTimestamp); pChunk->writeEntry(entry); } diff --git a/Implementation/Core/amc_telemetry.hpp b/Implementation/Core/amc_telemetry.hpp index 017ddaf1..38f9060a 100644 --- a/Implementation/Core/amc_telemetry.hpp +++ b/Implementation/Core/amc_telemetry.hpp @@ -78,8 +78,11 @@ namespace AMC { private: CTelemetryWriter* m_pWriter; - uint64_t m_nMinTimestamp; - uint64_t m_nMaxTimestamp; + uint64_t m_nChunkStartTimestamp; + uint64_t m_nChunkEndTimestamp; + + uint64_t m_nMinTimestamp; // Should be within chunk time interval + uint64_t m_nMaxTimestamp; // Should be within chunk time interval uint64_t m_nMinMarkerID; uint64_t m_nMaxMarkerID; @@ -91,7 +94,7 @@ namespace AMC { public: - CTelemetryDataChunk (CTelemetryWriter* pWriter, uint32_t nChunkID); + CTelemetryDataChunk (CTelemetryWriter* pWriter, uint32_t nChunkID, uint64_t nChunkStartTimestamp, uint64_t nChunkEndTimestamp); virtual ~CTelemetryDataChunk(); @@ -108,8 +111,11 @@ namespace AMC { private: std::mutex m_ChunkMutex; std::deque m_Chunks; + uint32_t m_nNextChunkIndex; PTelemetryDataChunk m_pCurrentChunk; + uint64_t m_nNextChunkStartTimestamp; + uint64_t m_nChunkIntervalInMicroseconds; std::mutex m_OpenIntervalMutex; std::unordered_map m_OpenIntervalMarkers; @@ -121,13 +127,15 @@ namespace AMC { std::atomic m_nNextMarkerID; + PTelemetryDataChunk createNewChunkNoMutex(); + public: CTelemetryWriter(LibMCData::PTelemetrySession pTelemetrySession, AMCCommon::PChrono pGlobalChrono); virtual ~CTelemetryWriter(); - PTelemetryDataChunk getCurrentChunk(); + PTelemetryDataChunk getCurrentChunk(uint64_t nTimestamp); PTelemetryDataChunk createNewChunk(); From eae6e8a60aa3684316527d6881022a64a6210c5e Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Thu, 15 Jan 2026 17:00:17 +0100 Subject: [PATCH 03/19] Fixed Signal queue race condition --- Implementation/Core/amc_statesignal.cpp | 27 ++++++++++++++----------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/Implementation/Core/amc_statesignal.cpp b/Implementation/Core/amc_statesignal.cpp index 554cb470..3eac7b72 100644 --- a/Implementation/Core/amc_statesignal.cpp +++ b/Implementation/Core/amc_statesignal.cpp @@ -405,23 +405,26 @@ namespace AMC { } pMessage = std::make_shared(sNormalizedUUID, nReactionTimeoutInMS, m_pQueueTelemetryChannel, m_pProcessingTelemetryChannel, m_pAcknowledgementTelemetryChannel); - m_Queue.push_back(pMessage); - m_QueueMap.insert(std::make_pair(sNormalizedUUID, std::prev(m_Queue.end()))); - m_MessageMap.insert(std::make_pair(sNormalizedUUID, pMessage)); + pMessage->setParameterDataJSON(sParameterData); + + // should be outside the lock, but we need to make sure that registration and addition are atomic + try { + m_pRegistry->registerMessage(sNormalizedUUID, this); + } + catch (...) { + eraseMessage(sNormalizedUUID); + throw; + }; increaseTriggerCount(); + m_MessageMap.insert(std::make_pair(sNormalizedUUID, pMessage)); - pMessage->setParameterDataJSON(sParameterData); - } + // Adding to queue will start the signal processing + m_Queue.push_back(pMessage); + m_QueueMap.insert(std::make_pair(sNormalizedUUID, std::prev(m_Queue.end()))); - // needs to be outside lock - try { - m_pRegistry->registerMessage(sNormalizedUUID, this); + } - catch (...) { - eraseMessage(sNormalizedUUID); - throw; - }; return pMessage; } From e0060d0524c00b2485f75258d1cc53c5d995aee6 Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Fri, 16 Jan 2026 15:55:09 +0100 Subject: [PATCH 04/19] Fixed signal claiming behavior --- Examples/LPBFSystem/config.xml | 2 +- Implementation/Core/amc_statesignal.cpp | 65 ++++++++++++------- Implementation/Core/amc_statesignal.hpp | 7 +- .../Core/amc_statesignalhandler.cpp | 4 +- .../Core/amc_statesignalhandler.hpp | 2 +- Implementation/LibMC/libmc_mccontext.cpp | 7 +- .../LibMCEnv/libmcenv_stateenvironment.cpp | 4 +- 7 files changed, 60 insertions(+), 31 deletions(-) diff --git a/Examples/LPBFSystem/config.xml b/Examples/LPBFSystem/config.xml index a2a3e771..0c066f7b 100644 --- a/Examples/LPBFSystem/config.xml +++ b/Examples/LPBFSystem/config.xml @@ -112,7 +112,7 @@ - + diff --git a/Implementation/Core/amc_statesignal.cpp b/Implementation/Core/amc_statesignal.cpp index 3eac7b72..9c13e23e 100644 --- a/Implementation/Core/amc_statesignal.cpp +++ b/Implementation/Core/amc_statesignal.cpp @@ -41,9 +41,11 @@ namespace AMC { CStateSignalMessage::CStateSignalMessage(const std::string& sUUID, uint32_t nReactionTimeoutInMS, PTelemetryChannel pQueueTelemetryChannel, PTelemetryChannel pInProcessTelemetryChannel, PTelemetryChannel pAcknowledgeTelemetryChannel) : m_sUUID(AMCCommon::CUtils::normalizeUUIDString(sUUID)), m_nReactionTimeoutInMS(nReactionTimeoutInMS), - m_MessagePhase (eAMCSignalPhase::InQueue), - m_pInProcessTelemetryChannel (pInProcessTelemetryChannel), - m_pAcknowledgeTelemetryChannel (pAcknowledgeTelemetryChannel) + m_MessagePhase(eAMCSignalPhase::InQueue), + m_pInProcessTelemetryChannel(pInProcessTelemetryChannel), + m_pAcknowledgeTelemetryChannel(pAcknowledgeTelemetryChannel), + m_nCreationTimestamp(0), + m_nTerminalTimestamp(0) { if (pQueueTelemetryChannel.get () == nullptr) @@ -54,6 +56,7 @@ namespace AMC { throw ELibMCInterfaceException(LIBMC_ERROR_INVALIDPARAM); m_pTelemetryInQueueMarker = pQueueTelemetryChannel->startIntervalMarker(0); + m_nCreationTimestamp = m_pTelemetryInQueueMarker->getStartTimestamp(); } CStateSignalMessage::~CStateSignalMessage() @@ -71,28 +74,23 @@ namespace AMC { uint64_t CStateSignalMessage::getCreationTimestamp() const { - return m_pTelemetryInQueueMarker->getStartTimestamp (); + return m_nCreationTimestamp; } uint64_t CStateSignalMessage::getTerminalTimestamp() const - { - if (m_pTelemetryInProcessMarker.get() != nullptr) { - if (m_pTelemetryInProcessMarker->isFinished()) - return m_pTelemetryInProcessMarker->getFinishTimestamp(); - } - - return 0; + { + return m_nTerminalTimestamp; } bool CStateSignalMessage::setPhase(AMC::eAMCSignalPhase messagePhase) { if (m_pTelemetryInQueueMarker.get() != nullptr) { m_pTelemetryInQueueMarker->finishMarker(); - m_pTelemetryInQueueMarker = nullptr; } if (m_pTelemetryInProcessMarker.get () != nullptr) { m_pTelemetryInProcessMarker->finishMarker(); + m_nTerminalTimestamp = m_pTelemetryInProcessMarker->getFinishTimestamp(); m_pTelemetryInProcessMarker = nullptr; } @@ -192,6 +190,7 @@ namespace AMC { m_nHandledCount (0), m_nFailedCount (0), m_nTimedOutCount (0), + m_nArchivedCount (0), m_nMaxReactionTime (0), m_pRegistry (pRegistry) @@ -205,6 +204,7 @@ namespace AMC { pSignalInformationGroup->addNewIntParameter("handled_" + m_sName, m_sName + " was handled", 0); pSignalInformationGroup->addNewIntParameter("failed_" + m_sName, m_sName + " has failed", 0); pSignalInformationGroup->addNewIntParameter("timeout_" + m_sName, m_sName + " timed out", 0); + pSignalInformationGroup->addNewIntParameter("archived_" + m_sName, m_sName + " archived", 0); pSignalInformationGroup->addNewIntParameter("reactiontime_" + m_sName, m_sName + " max reaction time (microseconds)", 0); pSignalInformationGroup->addNewIntParameter("finishtime_" + m_sName, m_sName + " max finish time (microseconds)", 0); pSignalInformationGroup->addNewIntParameter("acknowledgetime_" + m_sName, m_sName + " max acknowledge time (microseconds)", 0); @@ -307,6 +307,15 @@ namespace AMC { updateTimingStatistics(); } + void CStateSignalSlot::increaseArchivedCount() + { + m_nArchivedCount++; + if (m_pSignalInformationGroup.get() != nullptr) { + m_pSignalInformationGroup->setIntParameterValueByName("archived_" + m_sName, (int64_t)m_nArchivedCount); + } + + } + bool CStateSignalSlot::queueIsFullNoMutex() { @@ -545,6 +554,9 @@ namespace AMC { } if (bToArchive) { + + increaseArchivedCount(); + pMessage->setPhase(eAMCSignalPhase::Archived); m_MessagesToArchive.push_back(pMessage); m_MessageMap.erase(iMessageIter); @@ -687,6 +699,7 @@ namespace AMC { } if (nGlobalTimestamp >= nArchiveTimestamp) { + increaseArchivedCount(); messagesToArchive.push_back(it.first); } } @@ -700,8 +713,6 @@ namespace AMC { void CStateSignalSlot::writeMessagesToArchive(CStateSignalArchiveWriter* pArchiveWriter) { - if (pArchiveWriter == nullptr) - throw ELibMCCustomException(LIBMC_ERROR_INVALIDPARAM, "writeMessagesToArchive: Archive writer is null"); std::deque messagesToArchive; { @@ -709,14 +720,19 @@ namespace AMC { messagesToArchive.swap (m_MessagesToArchive); } - for (auto pMessage : messagesToArchive) { - pArchiveWriter->writeSignalMessageToArchive (m_sInstanceName, m_sName, pMessage.get ()); + if (pArchiveWriter != nullptr) { + // If Archive Writer is null, we just clear the archive queue + + for (auto pMessage : messagesToArchive) { + pArchiveWriter->writeSignalMessageToArchive(m_sInstanceName, m_sName, pMessage.get()); + } + } } - PStateSignalMessage CStateSignalSlot::claimMessageFromQueueInternal(bool bCheckForReactionTimeout, uint64_t nGlobalTimestamp, uint64_t nTimeStamp) + PStateSignalMessage CStateSignalSlot::claimMessageFromQueueInternal(bool bCheckForReactionTimeout, uint64_t nGlobalTimestamp, uint64_t nTimeStamp, bool bChangePhaseToInprocess) { (void)nTimeStamp; std::lock_guard lockGuard(m_Mutex); @@ -731,13 +747,18 @@ namespace AMC { auto pMessage = m_Queue.front(); std::string sUUID = pMessage->getUUID(); - m_Queue.pop_front(); - m_QueueMap.erase(sUUID); + if (bChangePhaseToInprocess) { - pMessage->setPhase(eAMCSignalPhase::InProcess); - m_InProcess.insert(sUUID); + // Change the phase to Inprocess in an atomic way + m_Queue.pop_front(); + m_QueueMap.erase(sUUID); - updateTimingStatistics(); + pMessage->setPhase(eAMCSignalPhase::InProcess); + m_InProcess.insert(sUUID); + + updateTimingStatistics(); + + } return pMessage; } diff --git a/Implementation/Core/amc_statesignal.hpp b/Implementation/Core/amc_statesignal.hpp index 836ea4cf..bb204573 100644 --- a/Implementation/Core/amc_statesignal.hpp +++ b/Implementation/Core/amc_statesignal.hpp @@ -91,6 +91,9 @@ namespace AMC { std::string m_sErrorMessage; + uint64_t m_nCreationTimestamp; + uint64_t m_nTerminalTimestamp; + AMC::PTelemetryMarker m_pTelemetryInQueueMarker; AMC::PTelemetryMarker m_pTelemetryInProcessMarker; AMC::PTelemetryMarker m_pTelemetryAcknowledgedMarker; @@ -164,6 +167,7 @@ namespace AMC { uint64_t m_nHandledCount; uint64_t m_nFailedCount; uint64_t m_nTimedOutCount; + uint64_t m_nArchivedCount; uint64_t m_nMaxReactionTime; PTelemetryChannel m_pQueueTelemetryChannel; @@ -174,6 +178,7 @@ namespace AMC { void increaseHandledCount(); void increaseFailedCount(); void increaseTimeoutCount(); + void increaseArchivedCount(); void updateTimingStatistics(); PParameterGroup m_pSignalInformationGroup; @@ -223,7 +228,7 @@ namespace AMC { void writeMessagesToArchive (CStateSignalArchiveWriter * pArchiveWriter); - PStateSignalMessage claimMessageFromQueueInternal(bool bCheckForReactionTimeout, uint64_t nGlobalTimestamp, uint64_t nTimeStamp); + PStateSignalMessage claimMessageFromQueueInternal(bool bCheckForReactionTimeout, uint64_t nGlobalTimestamp, uint64_t nTimeStamp, bool bChangePhaseToInprocess); std::string getResultDataJSONInternal(const std::string& sMessageUUID); std::string getParameterDataJSONInternal(const std::string& sMessageUUID); diff --git a/Implementation/Core/amc_statesignalhandler.cpp b/Implementation/Core/amc_statesignalhandler.cpp index 1620b9e6..8d87de94 100644 --- a/Implementation/Core/amc_statesignalhandler.cpp +++ b/Implementation/Core/amc_statesignalhandler.cpp @@ -167,11 +167,11 @@ namespace AMC { } - bool CStateSignalInstance::claimSignalMessage(const std::string& sSignalName, bool bCheckForReactionTimeout, uint64_t nGlobalTimestamp, uint64_t nTimeStamp, std::string& sSignalUUID, std::string& sParameterDataJSON) + bool CStateSignalInstance::claimSignalMessage(const std::string& sSignalName, bool bCheckForReactionTimeout, uint64_t nGlobalTimestamp, uint64_t nTimeStamp, std::string& sSignalUUID, std::string& sParameterDataJSON, bool bChangePhaseToInprocess) { AMC::PStateSignalSlot pSlot = getSignalSlot(sSignalName); - auto pMessage = pSlot->claimMessageFromQueueInternal(bCheckForReactionTimeout, nGlobalTimestamp, nTimeStamp); + auto pMessage = pSlot->claimMessageFromQueueInternal(bCheckForReactionTimeout, nGlobalTimestamp, nTimeStamp, bChangePhaseToInprocess); if (pMessage.get() == nullptr) return false; diff --git a/Implementation/Core/amc_statesignalhandler.hpp b/Implementation/Core/amc_statesignalhandler.hpp index 86373041..097508d8 100644 --- a/Implementation/Core/amc_statesignalhandler.hpp +++ b/Implementation/Core/amc_statesignalhandler.hpp @@ -91,7 +91,7 @@ namespace AMC { bool hasSignalDefinition(const std::string& sSignalName); - bool claimSignalMessage(const std::string& sSignalName, bool bCheckForReactionTimeout, uint64_t nGlobalTimestamp, uint64_t nTimeStamp, std::string& sSignalUUID, std::string& sParameterDataJSON); + bool claimSignalMessage(const std::string& sSignalName, bool bCheckForReactionTimeout, uint64_t nGlobalTimestamp, uint64_t nTimeStamp, std::string& sSignalUUID, std::string& sParameterDataJSON, bool bChangePhaseToInprocess); bool addNewInQueueSignal(const std::string& sSignalName, const std::string& sSignalUUID, const std::string& sParameterData, uint32_t nResponseTimeOutInMS, uint64_t nTimestamp); diff --git a/Implementation/LibMC/libmc_mccontext.cpp b/Implementation/LibMC/libmc_mccontext.cpp index f123b345..60f37bb0 100644 --- a/Implementation/LibMC/libmc_mccontext.cpp +++ b/Implementation/LibMC/libmc_mccontext.cpp @@ -951,8 +951,11 @@ void CMCContext::executeSystemThread() while (!systemThreadShallTerminate()) { - uint64_t nGlobalTimestamp = m_pSystemState->globalChrono()->getElapsedMicroseconds(); - m_pSystemState->stateSignalHandler()->checkForReactionTimeouts(nGlobalTimestamp); + + auto pSignalHandler = m_pSystemState->getStateSignalHandlerInstance(); + pSignalHandler->checkForReactionTimeouts(m_pSystemState->globalChrono()->getElapsedMicroseconds()); + pSignalHandler->autoArchiveMessages(m_pSystemState->globalChrono()->getElapsedMicroseconds()); + pSignalHandler->writeMessagesToArchive(nullptr); m_pSystemState->updateMemoryUsageParameters(); } diff --git a/Implementation/LibMCEnv/libmcenv_stateenvironment.cpp b/Implementation/LibMCEnv/libmcenv_stateenvironment.cpp index 4c13fe74..6a593810 100644 --- a/Implementation/LibMCEnv/libmcenv_stateenvironment.cpp +++ b/Implementation/LibMCEnv/libmcenv_stateenvironment.cpp @@ -134,7 +134,7 @@ bool CStateEnvironment::WaitForSignal(const std::string& sSignalName, const LibM std::string sUnhandledSignalUUID; std::string sParameterDataJSON; - bool bHasSignal = pSignalInstance->claimSignalMessage(sSignalName, true, nCurrentTime, nCurrentTime, sUnhandledSignalUUID, sParameterDataJSON); + bool bHasSignal = pSignalInstance->claimSignalMessage(sSignalName, true, nCurrentTime, nCurrentTime, sUnhandledSignalUUID, sParameterDataJSON, false); if (bHasSignal) { pHandlerInstance = new CSignalHandler(m_pSystemState->getStateSignalHandlerInstance(), m_sInstanceName, sSignalName, sUnhandledSignalUUID, sParameterDataJSON, m_pSystemState->getGlobalChronoInstance()); @@ -164,7 +164,7 @@ ISignalHandler* CStateEnvironment::GetUnhandledSignal(const std::string& sSignal std::string sUnhandledSignalUUID; std::string sParameterDataJSON; uint64_t nCurrentTime = pChronoInstance->getElapsedMicroseconds(); - bool bHasSignal = pSignalInstance->claimSignalMessage(sSignalTypeName, true, nCurrentTime, nCurrentTime, sUnhandledSignalUUID, sParameterDataJSON); + bool bHasSignal = pSignalInstance->claimSignalMessage(sSignalTypeName, true, nCurrentTime, nCurrentTime, sUnhandledSignalUUID, sParameterDataJSON, false); if (bHasSignal) { return new CSignalHandler(m_pSystemState->getStateSignalHandlerInstance(), m_sInstanceName, sSignalTypeName, sUnhandledSignalUUID, sParameterDataJSON, pChronoInstance); } From 4e410e450570a94de31ad4006715a19525ab69b7 Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Fri, 16 Jan 2026 16:32:08 +0100 Subject: [PATCH 05/19] Fixed crash in State Signal --- Implementation/Core/amc_statesignal.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Implementation/Core/amc_statesignal.cpp b/Implementation/Core/amc_statesignal.cpp index 9c13e23e..21c845d1 100644 --- a/Implementation/Core/amc_statesignal.cpp +++ b/Implementation/Core/amc_statesignal.cpp @@ -86,6 +86,7 @@ namespace AMC { { if (m_pTelemetryInQueueMarker.get() != nullptr) { m_pTelemetryInQueueMarker->finishMarker(); + m_pTelemetryInQueueMarker = nullptr; } if (m_pTelemetryInProcessMarker.get () != nullptr) { @@ -139,9 +140,7 @@ namespace AMC { bool CStateSignalMessage::hadReactionTimeout(uint64_t nGlobalTimestamp) { - uint64_t nInQueueTimestamp = m_pTelemetryInQueueMarker->getStartTimestamp(); - - uint64_t nTimeoutTimestamp = nInQueueTimestamp + (uint64_t)m_nReactionTimeoutInMS * 1000; + uint64_t nTimeoutTimestamp = m_nCreationTimestamp + (uint64_t)m_nReactionTimeoutInMS * 1000; return (nGlobalTimestamp >= nTimeoutTimestamp); } From 37a876d62dca136992231ccc7c3ca7577e6d3807 Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Fri, 16 Jan 2026 16:36:06 +0000 Subject: [PATCH 06/19] Improved Unit tests --- Implementation/UnitTest/amc_unittests.cpp | 4 + .../UnitTest/amc_unittests_common_utils.hpp | 66 ++++++ .../UnitTest/amc_unittests_jpeg.hpp | 177 +++++++++++++++ .../UnitTest/amc_unittests_streams.hpp | 208 ++++++++++++++++++ 4 files changed, 455 insertions(+) create mode 100644 Implementation/UnitTest/amc_unittests_jpeg.hpp create mode 100644 Implementation/UnitTest/amc_unittests_streams.hpp diff --git a/Implementation/UnitTest/amc_unittests.cpp b/Implementation/UnitTest/amc_unittests.cpp index 45f77108..247cd25b 100644 --- a/Implementation/UnitTest/amc_unittests.cpp +++ b/Implementation/UnitTest/amc_unittests.cpp @@ -45,6 +45,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "amc_unittests_statejournal.hpp" #include "amc_unittests_common_utils.hpp" #include "amc_unittests_resourcepackage.hpp" +#include "amc_unittests_jpeg.hpp" +#include "amc_unittests_streams.hpp" using namespace AMCUnitTest; @@ -68,4 +70,6 @@ CUnitTests::CUnitTests (PUnitTestIO pIO) registerTestGroup(std::make_shared ()); registerTestGroup(std::make_shared ()); registerTestGroup(std::make_shared ()); + registerTestGroup(std::make_shared ()); + registerTestGroup(std::make_shared ()); } diff --git a/Implementation/UnitTest/amc_unittests_common_utils.hpp b/Implementation/UnitTest/amc_unittests_common_utils.hpp index d5db9057..d2604d1f 100644 --- a/Implementation/UnitTest/amc_unittests_common_utils.hpp +++ b/Implementation/UnitTest/amc_unittests_common_utils.hpp @@ -56,6 +56,7 @@ namespace AMCUnitTest { registerTest("FilePathFunctions", "Path handling and file/directory helpers", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_CommonUtils::testFilePathFunctions, this)); registerTest("TempAndDirectoryFunctions", "Temporary paths, directory content, and OS helpers", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_CommonUtils::testTempAndDirectoryFunctions, this)); registerTest("AlphanumericValidation", "Alphanumeric name and path validation", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_CommonUtils::testAlphanumericValidation, this)); + registerTest("FileNameValidation", "Filename validation for invalid characters and dot-dot", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_CommonUtils::testFileNameValidation, this)); } void initializeTests() override { @@ -116,6 +117,14 @@ namespace AMCUnitTest { assertTrue(AMCCommon::CUtils::stringIsUUIDString(uuid)); assertTrue(AMCCommon::CUtils::stringIsNonEmptyUUIDString(uuid)); assertTrue(AMCCommon::CUtils::normalizeUUIDString(uuid) == uuid); + assertTrue(AMCCommon::CUtils::stringIsUUIDString(" " + uuid + " ")); + + std::string uuidV4 = AMCCommon::CUtils::createUUIDV4(); + assertTrue(AMCCommon::CUtils::stringIsUUIDString(uuidV4)); + assertTrue(AMCCommon::CUtils::stringIsNonEmptyUUIDString(uuidV4)); + assertTrue(AMCCommon::CUtils::normalizeUUIDString(uuidV4) == uuidV4); + assertTrue(uuidV4.at(14) == '4'); + assertTrue((uuidV4.at(19) == '8') || (uuidV4.at(19) == '9') || (uuidV4.at(19) == 'a') || (uuidV4.at(19) == 'b')); std::string emptyUUID = AMCCommon::CUtils::createEmptyUUID(); assertTrue(AMCCommon::CUtils::stringIsUUIDString(emptyUUID)); @@ -126,6 +135,13 @@ namespace AMCUnitTest { assertTrue(normalizedUUID == "a1b2c3d4-1111-2222-3333-444455556666"); assertFalse(AMCCommon::CUtils::stringIsUUIDString("not-a-uuid")); + assertFalse(AMCCommon::CUtils::stringIsUUIDString("a1b2c3d4-1111-2222-3333-44445555666")); + assertFalse(AMCCommon::CUtils::stringIsUUIDString("a1b2c3d4-1111-2222-3333-4444555566667")); + assertFalse(AMCCommon::CUtils::stringIsUUIDString("a1b2c3d4-1111-2222-3333444455556666")); + assertFalse(AMCCommon::CUtils::stringIsUUIDString("a1b2c3d4-1111-2222-3333-44445555666x")); + assertFalse(AMCCommon::CUtils::stringIsUUIDString("a1b2c3d4-1111-2222-3333_444455556666")); + assertFalse(AMCCommon::CUtils::stringIsUUIDString("A1B2C3D4-1111-2222-3333-44445555666G")); + assertFalse(AMCCommon::CUtils::stringIsUUIDString("a1b2c3d4111122223333444455556666")); bool thrown = false; try { @@ -135,6 +151,15 @@ namespace AMCUnitTest { thrown = true; } assertTrue(thrown, "Expected normalizeUUIDString to throw on invalid input"); + + thrown = false; + try { + AMCCommon::CUtils::normalizeUUIDString("a1b2c3d4111122223333444455556666ff"); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected normalizeUUIDString to throw on oversized input"); } void testUTF8Conversions() @@ -290,6 +315,24 @@ namespace AMCUnitTest { std::string normalizedSHA = AMCCommon::CUtils::normalizeSHA256String(rawSHA); assertTrue(normalizedSHA == expectedHash); + thrown = false; + try { + AMCCommon::CUtils::normalizeSHA256String("abc"); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected normalizeSHA256String to throw on invalid length"); + + thrown = false; + try { + AMCCommon::CUtils::normalizeSHA256String(expectedHash + "0"); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected normalizeSHA256String to throw on oversized input"); + thrown = false; try { AMCCommon::CUtils::calculateRandomSHA256String(0); @@ -396,6 +439,7 @@ namespace AMCUnitTest { std::string fullPath = AMCCommon::CUtils::getFullPathName(nonExistingPath, false); assertTrue(!fullPath.empty()); assertFalse(AMCCommon::CUtils::fileOrPathExistsOnDisk(nonExistingPath)); + assertFalse(AMCCommon::CUtils::pathIsDirectory(nonExistingPath)); char delimiter = AMCCommon::CUtils::getPathDelimiter(); #ifdef _WIN32 @@ -406,6 +450,9 @@ namespace AMCUnitTest { std::string withDelimiter = AMCCommon::CUtils::includeTrailingPathDelimiter("path"); assertTrue(withDelimiter.back() == '/' || withDelimiter.back() == '\\'); assertTrue(AMCCommon::CUtils::includeTrailingPathDelimiter(withDelimiter) == withDelimiter); + std::string emptyWithDelimiter = AMCCommon::CUtils::includeTrailingPathDelimiter(""); + assertTrue(emptyWithDelimiter.size() == 1); + assertTrue(emptyWithDelimiter.at(0) == delimiter); assertTrue(AMCCommon::CUtils::removeLeadingPathDelimiter("///path") == "path"); } @@ -473,6 +520,25 @@ namespace AMCUnitTest { assertFalse(AMCCommon::CUtils::stringIsValidAlphanumericPathString(".abc")); assertFalse(AMCCommon::CUtils::stringIsValidAlphanumericPathString("abc.")); } + + void testFileNameValidation() + { + assertFalse(AMCCommon::CUtils::stringIsValidFileName("")); + assertFalse(AMCCommon::CUtils::stringIsValidFileName("file:name.txt")); + assertFalse(AMCCommon::CUtils::stringIsValidFileName("file>name.txt")); + assertFalse(AMCCommon::CUtils::stringIsValidFileName("file imageData = { + 255, 0, 0, + 0, 255, 0, + 0, 0, 255, + 255, 255, 0 + }; + + std::vector jpegData; + AMCCommon::CJPEGImageEncoder encoder(nWidth, nHeight, AMCCommon::eJPEGChannelCount::ccRGB, imageData.data(), jpegData, true); + assertTrue(encoder.getWidth() == nWidth); + assertTrue(encoder.getHeight() == nHeight); + assertTrue(encoder.getChannelCount() == AMCCommon::eJPEGChannelCount::ccRGB); + assertTrue(!jpegData.empty()); + + AMCCommon::CJPEGImageDecoder decoder(jpegData.data(), jpegData.size()); + assertTrue(decoder.getWidth() == nWidth); + assertTrue(decoder.getHeight() == nHeight); + assertTrue(decoder.getChannelCount() == AMCCommon::eJPEGChannelCount::ccRGB); + + std::vector rgbBuffer; + decoder.writeToBufferRGB24bit(rgbBuffer); + assertTrue(rgbBuffer.size() == (size_t)nWidth * (size_t)nHeight * 3); + + std::vector grayBuffer; + decoder.writeToBufferGreyScale8bit(grayBuffer); + assertTrue(grayBuffer.size() == (size_t)nWidth * (size_t)nHeight); + + std::vector rgbaBuffer; + decoder.writeToBufferRGBA32bit(rgbaBuffer); + assertTrue(rgbaBuffer.size() == (size_t)nWidth * (size_t)nHeight * 4); + } + + void testEncodeGrayUnsupported() + { + const uint32_t nWidth = 2; + const uint32_t nHeight = 2; + std::vector imageData = { + 0, + 64, + 128, + 255 + }; + + bool thrown = false; + try { + std::vector jpegData; + AMCCommon::CJPEGImageEncoder encoder(nWidth, nHeight, AMCCommon::eJPEGChannelCount::ccGray, imageData.data(), jpegData, true); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected grayscale JPEG encode to throw on unsupported channel count"); + } + + void testDecoderInvalidInput() + { + bool thrown = false; + try { + uint8_t data = 0; + AMCCommon::CJPEGImageDecoder decoder(&data, 0); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected decoder to throw on empty buffer size"); + + thrown = false; + try { + AMCCommon::CJPEGImageDecoder decoder(nullptr, 1); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected decoder to throw on null buffer"); + + thrown = false; + try { + std::vector invalidData = { 0x00, 0x01, 0x02, 0x03 }; + AMCCommon::CJPEGImageDecoder decoder(invalidData.data(), invalidData.size()); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected decoder to throw on invalid JPEG data"); + } + + void testEncoderInvalidInput() + { + bool thrown = false; + try { + std::vector jpegData; + AMCCommon::CJPEGImageEncoder encoder(1, 1, AMCCommon::eJPEGChannelCount::ccRGB, nullptr, jpegData, true); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected encoder to throw on null image data"); + + thrown = false; + try { + std::vector imageData = { 0, 0, 0 }; + std::vector jpegData; + AMCCommon::CJPEGImageEncoder encoder(0, 1, AMCCommon::eJPEGChannelCount::ccRGB, imageData.data(), jpegData, true); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected encoder to throw on invalid image size"); + } + }; + +} + +#endif // __AMCTEST_UNITTEST_JPEG diff --git a/Implementation/UnitTest/amc_unittests_streams.hpp b/Implementation/UnitTest/amc_unittests_streams.hpp new file mode 100644 index 00000000..d5370f7e --- /dev/null +++ b/Implementation/UnitTest/amc_unittests_streams.hpp @@ -0,0 +1,208 @@ +/*++ + +Copyright (C) 2025 Autodesk Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Autodesk Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AUTODESK INC. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef __AMCTEST_UNITTEST_STREAMS +#define __AMCTEST_UNITTEST_STREAMS + + +#include "amc_unittests.hpp" +#include "common_exportstream_native.hpp" +#include "common_importstream_native.hpp" +#include "common_portablezipwriter.hpp" +#include "common_utils.hpp" + + +namespace AMCUnitTest { + + class CUnitTestGroup_Streams : public CUnitTestGroup { + public: + + std::string getTestGroupName() override { + return "Streams"; + } + + void registerTests() override { + registerTest("NativeRoundTrip", "Export/import stream roundtrip including seek operations", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_Streams::testNativeRoundTrip, this)); + registerTest("ZIPRoundTrip", "ZIP export stream writes expected ZIP structures", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_Streams::testZIPRoundTrip, this)); + } + + void initializeTests() override { + } + + private: + + struct CScopedTempDir { + std::string m_sPath; + CScopedTempDir() + { + m_sPath = std::string("amc_unittest_streams_") + AMCCommon::CUtils::createUUID(); + AMCCommon::CUtils::createDirectoryOnDisk(m_sPath); + } + ~CScopedTempDir() + { + try { + AMCCommon::CUtils::deleteDirectoryFromDisk(m_sPath, false); + } + catch (...) { + } + } + }; + + std::string joinPath(const std::string& sBase, const std::string& sEntry) + { + std::string baseWithDelimiter = AMCCommon::CUtils::includeTrailingPathDelimiter(sBase); + return baseWithDelimiter + sEntry; + } + + bool bufferContainsSequence(const std::vector& buffer, const std::vector& sequence) + { + if (sequence.empty() || (buffer.size() < sequence.size())) + return false; + + for (size_t offset = 0; offset <= buffer.size() - sequence.size(); offset++) { + bool matches = true; + for (size_t index = 0; index < sequence.size(); index++) { + if (buffer[offset + index] != sequence[index]) { + matches = false; + break; + } + } + if (matches) + return true; + } + + return false; + } + + void testNativeRoundTrip() + { + CScopedTempDir tempDir; + std::string filePath = joinPath(tempDir.m_sPath, "stream.bin"); + + { + AMCCommon::CExportStream_Native exportStream(filePath); + const char* initialData = "abcdef"; + exportStream.writeBuffer(initialData, 6); + assertTrue(exportStream.getPosition() == 6); + + exportStream.seekPosition(2, true); + exportStream.writeBuffer("ZZ", 2); + assertTrue(exportStream.getPosition() == 4); + + exportStream.seekForward(1, true); + exportStream.writeBuffer("X", 1); + + exportStream.seekFromEnd(0, true); + exportStream.writeZeros(2); + exportStream.flushStream(); + } + + AMCCommon::CImportStream_Native importStream(filePath); + uint64_t size = importStream.retrieveSize(); + assertTrue(size == 8); + + std::vector buffer; + buffer.resize(size); + importStream.seekPosition(0, true); + importStream.readBuffer(buffer.data(), size, true); + assertTrue(buffer.at(0) == 'a'); + assertTrue(buffer.at(1) == 'b'); + assertTrue(buffer.at(2) == 'Z'); + assertTrue(buffer.at(3) == 'Z'); + assertTrue(buffer.at(4) == 'e'); + assertTrue(buffer.at(5) == 'X'); + assertTrue(buffer.at(6) == 0); + assertTrue(buffer.at(7) == 0); + + importStream.seekPosition(2, true); + uint8_t zz[2] = { 0, 0 }; + importStream.readBuffer(zz, 2, true); + assertTrue((zz[0] == 'Z') && (zz[1] == 'Z')); + + importStream.seekPosition(0, true); + importStream.seekForward(1, true); + uint8_t bChar = 0; + importStream.readBuffer(&bChar, 1, true); + assertTrue(bChar == 'b'); + + importStream.seekFromEnd(2, true); + uint8_t tail[2] = { 1, 1 }; + importStream.readBuffer(tail, 2, true); + assertTrue((tail[0] == 0) && (tail[1] == 0)); + } + + void testZIPRoundTrip() + { + CScopedTempDir tempDir; + std::string filePath = joinPath(tempDir.m_sPath, "stream.zip"); + + const std::string entryName = "test.txt"; + const std::string entryData = "hello zip"; + + { + auto pExportStream = std::make_shared(filePath); + AMCCommon::CPortableZIPWriter zipWriter(pExportStream, true); + auto pEntryStream = zipWriter.createEntry(entryName, 0); + + bool thrown = false; + try { + pEntryStream->seekPosition(0, true); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected ZIP export stream to reject seeking"); + + pEntryStream->writeBuffer(entryData.data(), entryData.size()); + zipWriter.closeEntry(); + zipWriter.writeDirectory(); + } + + AMCCommon::CImportStream_Native importStream(filePath); + std::vector buffer; + importStream.readIntoMemory(buffer); + assertTrue(buffer.size() > 0); + + const std::vector localHeader = { 'P', 'K', 0x03, 0x04 }; + const std::vector centralHeader = { 'P', 'K', 0x01, 0x02 }; + const std::vector endHeader = { 'P', 'K', 0x05, 0x06 }; + const std::vector nameBytes(entryName.begin(), entryName.end()); + + assertTrue(bufferContainsSequence(buffer, localHeader)); + assertTrue(bufferContainsSequence(buffer, centralHeader)); + assertTrue(bufferContainsSequence(buffer, endHeader)); + assertTrue(bufferContainsSequence(buffer, nameBytes)); + } + + }; + +} + +#endif // __AMCTEST_UNITTEST_STREAMS From b389b9dfa2a1c299de01210b2c5ccc24a8a963a2 Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Fri, 16 Jan 2026 23:15:43 +0100 Subject: [PATCH 07/19] Introduced ClaimSignalFromQueue for save signal retrieval. Depreciated older methods... --- ACT/LibMCEnv.xml | 71 ++-- .../HeadersDev/CppDynamic/libmcenv_dynamic.h | 116 ++++--- .../CppDynamic/libmcenv_dynamic.hpp | 302 +++++++++++------- Framework/InterfacesCore/libmcenv_abi.hpp | 104 +++--- .../InterfacesCore/libmcenv_interfaces.hpp | 80 +++-- .../libmcenv_interfacewrapper.cpp | 190 +++++++---- Implementation/Core/amc_statesignal.cpp | 6 + Implementation/Core/amc_statesignal.hpp | 1 + .../Core/amc_statesignalhandler.cpp | 7 + .../Core/amc_statesignalhandler.hpp | 2 + .../LibMCEnv/libmcenv_stateenvironment.cpp | 23 ++ .../LibMCEnv/libmcenv_stateenvironment.hpp | 4 + 12 files changed, 571 insertions(+), 335 deletions(-) diff --git a/ACT/LibMCEnv.xml b/ACT/LibMCEnv.xml index 4cdd6085..53f36589 100644 --- a/ACT/LibMCEnv.xml +++ b/ACT/LibMCEnv.xml @@ -5040,28 +5040,26 @@ - - - - - - + + + + - + - - - - + + + + - + - + - + @@ -5098,7 +5096,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5124,21 +5152,6 @@ - - - - - - - - - - - - - - - diff --git a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h index b2b1a1eb..bb1b8b0b 100644 --- a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h +++ b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h @@ -9218,29 +9218,27 @@ typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_GetPreviousStatePtr) (LibMCEn typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_PrepareSignalPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pMachineInstance, const char * pSignalName, LibMCEnv_SignalTrigger * pSignalInstance); /** -* Waits for a signal for a certain amount of time. +* Retrieves an InQueue signal by type and changes its phase to InProcess. Recommended to use as it is robust against signal timeouts... * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pSignalName - Name Of Signal -* @param[in] nTimeOut - Timeout in Milliseconds. 0 for Immediate return. -* @param[out] pHandlerInstance - Signal object. If Success is false, the Signal Handler Object will be null. -* @param[out] pSuccess - Signal has been triggered +* @param[in] pSignalTypeName - Name Of Signal to be returned +* @param[out] pHandlerInstance - Signal object. If no signal is InQueue the signal handler object will be null. * @return error code or 0 (success) */ -typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_WaitForSignalPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalName, LibMCEnv_uint32 nTimeOut, LibMCEnv_SignalHandler * pHandlerInstance, bool * pSuccess); +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_ClaimSignalFromQueuePtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, LibMCEnv_SignalHandler * pHandlerInstance); /** -* Retrieves an unhandled signal By signal type name. Only affects signals with Phase InQueue. +* Returns if a signal queue is empty for a specific type... * * @param[in] pStateEnvironment - StateEnvironment instance. * @param[in] pSignalTypeName - Name Of Signal to be returned -* @param[out] pHandlerInstance - Signal object. If no signal has been found the signal handler object will be null. +* @param[out] pIsEmpty - Returns if the signal queue is empty. Please be aware that even a false return value does not guarantee that ClaimSignalFromQueue returns a non-null value. * @return error code or 0 (success) */ -typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_GetUnhandledSignalPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, LibMCEnv_SignalHandler * pHandlerInstance); +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_SignalQueueIsEmptyPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, bool * pIsEmpty); /** -* Clears all unhandled signals of a certain type and marks them as Cleared. Only affects signals with Phase InQueue. +* Clears all InQueue or InProcess signals of a certain type and marks them as Cleared. Handled, failed or timedout signals are unaffected * * @param[in] pStateEnvironment - StateEnvironment instance. * @param[in] pSignalTypeName - Name Of Signal to be cleared. @@ -9249,7 +9247,7 @@ typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_GetUnhandledSignalPtr) (LibMC typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_ClearUnhandledSignalsOfTypePtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName); /** -* Clears all unhandled signals and marks them Cleared. Only affects signals in the specific queue (as well as with Phase InQueue. +* Clears all InQueue or InProcess signals of this state machine and marks them Cleared. Handled, failed or timedout signals are unaffected * * @param[in] pStateEnvironment - StateEnvironment instance. * @return error code or 0 (success) @@ -9257,11 +9255,11 @@ typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_ClearUnhandledSignalsOfTypePt typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_ClearAllUnhandledSignalsPtr) (LibMCEnv_StateEnvironment pStateEnvironment); /** -* retrieves an unhandled signal from the current state machine by UUID. +* Retrieves an InQueue or InProcess signal from the current state machine by UUID. * * @param[in] pStateEnvironment - StateEnvironment instance. * @param[in] pUUID - Name -* @param[in] bMustExist - The call fails if MustExist is true and not signal with UUID does exist or a signal with UUID has been handled already. +* @param[in] bMustExist - The call fails if MustExist is true and not signal with UUID does exist or a signal with UUID has been handled, failed, cleared or timedout already. * @param[out] pHandler - Signal handler instance. Returns null, if signal does not exist. * @return error code or 0 (success) */ @@ -9339,87 +9337,109 @@ typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_GetBuildExecutionPtr) (LibMCE typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_UnloadAllToolpathesPtr) (LibMCEnv_StateEnvironment pStateEnvironment); /** -* sets the next state +* DEPRECIATED: Waits for an InQueue signal to exist for a certain amount of time. DOES NOT change signal phase to InProcess, and is not atomic. And so NOT robust against signal timeouts. USE claim signal instead. * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pStateName - Name of next state +* @param[in] pSignalName - Name Of Signal +* @param[in] nTimeOut - Timeout in Milliseconds. 0 for Immediate return. +* @param[out] pHandlerInstance - Signal object. If Success is false, the Signal Handler Object will be null. +* @param[out] pSuccess - Signal has been triggered * @return error code or 0 (success) */ -typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_SetNextStatePtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pStateName); +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_WaitForSignalPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalName, LibMCEnv_uint32 nTimeOut, LibMCEnv_SignalHandler * pHandlerInstance, bool * pSuccess); /** -* logs a string as message +* DEPRECIATED: Retrieves am InQueue signal by type. DOES NOT change signal phase to InProcess, and is not atomic. And so NOT robust against signal timeouts. USE ClaimSignalFromQueue instead. * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pLogString - String to Log +* @param[in] pSignalTypeName - Name Of Signal to be returned +* @param[out] pHandlerInstance - Signal object. If no signal has been found the signal handler object will be null. * @return error code or 0 (success) */ -typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_LogMessagePtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_GetUnhandledSignalPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, LibMCEnv_SignalHandler * pHandlerInstance); /** -* logs a string as warning +* DEPRECIATED: stores a signal handler in the current state machine * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pLogString - String to Log +* @param[in] pName - Name +* @param[in] pHandler - Signal handler to store. * @return error code or 0 (success) */ -typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_LogWarningPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_StoreSignalPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler pHandler); /** -* logs a string as info +* DEPRECIATED: retrieves a signal handler from the current state machine. Fails if value has not been stored before or signal has been already handled. * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pLogString - String to Log +* @param[in] pName - Name +* @param[out] pHandler - Signal handler instance. * @return error code or 0 (success) */ -typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_LogInfoPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_RetrieveSignalPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler * pHandler); /** -* Puts the current instance to sleep for a definite amount of time. MUST be used instead of a blocking sleep call. +* DEPRECIATED: deletes a value from the data store. * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] nDelay - Milliseconds to sleeps +* @param[in] pName - Name * @return error code or 0 (success) */ -typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_SleepPtr) (LibMCEnv_StateEnvironment pStateEnvironment, LibMCEnv_uint32 nDelay); +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_ClearStoredValuePtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pName); /** -* checks environment for termination signal. MUST be called frequently in longer-running operations. +* sets the next state * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[out] pShallTerminate - Returns if termination shall appear +* @param[in] pStateName - Name of next state * @return error code or 0 (success) */ -typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_CheckForTerminationPtr) (LibMCEnv_StateEnvironment pStateEnvironment, bool * pShallTerminate); +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_SetNextStatePtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pStateName); /** -* DEPRECIATED: stores a signal handler in the current state machine +* logs a string as message * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pName - Name -* @param[in] pHandler - Signal handler to store. +* @param[in] pLogString - String to Log * @return error code or 0 (success) */ -typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_StoreSignalPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler pHandler); +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_LogMessagePtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); /** -* DEPRECIATED: retrieves a signal handler from the current state machine. Fails if value has not been stored before or signal has been already handled. +* logs a string as warning * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pName - Name -* @param[out] pHandler - Signal handler instance. +* @param[in] pLogString - String to Log * @return error code or 0 (success) */ -typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_RetrieveSignalPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler * pHandler); +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_LogWarningPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); /** -* DEPRECIATED: deletes a value from the data store. +* logs a string as info * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pName - Name +* @param[in] pLogString - String to Log * @return error code or 0 (success) */ -typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_ClearStoredValuePtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pName); +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_LogInfoPtr) (LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); + +/** +* Puts the current instance to sleep for a definite amount of time. MUST be used instead of a blocking sleep call. +* +* @param[in] pStateEnvironment - StateEnvironment instance. +* @param[in] nDelay - Milliseconds to sleeps +* @return error code or 0 (success) +*/ +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_SleepPtr) (LibMCEnv_StateEnvironment pStateEnvironment, LibMCEnv_uint32 nDelay); + +/** +* checks environment for termination signal. MUST be called frequently in longer-running operations. +* +* @param[in] pStateEnvironment - StateEnvironment instance. +* @param[out] pShallTerminate - Returns if termination shall appear +* @return error code or 0 (success) +*/ +typedef LibMCEnvResult (*PLibMCEnvStateEnvironment_CheckForTerminationPtr) (LibMCEnv_StateEnvironment pStateEnvironment, bool * pShallTerminate); /** * sets a string parameter @@ -11867,8 +11887,8 @@ typedef struct { PLibMCEnvStateEnvironment_GetMachineStatePtr m_StateEnvironment_GetMachineState; PLibMCEnvStateEnvironment_GetPreviousStatePtr m_StateEnvironment_GetPreviousState; PLibMCEnvStateEnvironment_PrepareSignalPtr m_StateEnvironment_PrepareSignal; - PLibMCEnvStateEnvironment_WaitForSignalPtr m_StateEnvironment_WaitForSignal; - PLibMCEnvStateEnvironment_GetUnhandledSignalPtr m_StateEnvironment_GetUnhandledSignal; + PLibMCEnvStateEnvironment_ClaimSignalFromQueuePtr m_StateEnvironment_ClaimSignalFromQueue; + PLibMCEnvStateEnvironment_SignalQueueIsEmptyPtr m_StateEnvironment_SignalQueueIsEmpty; PLibMCEnvStateEnvironment_ClearUnhandledSignalsOfTypePtr m_StateEnvironment_ClearUnhandledSignalsOfType; PLibMCEnvStateEnvironment_ClearAllUnhandledSignalsPtr m_StateEnvironment_ClearAllUnhandledSignals; PLibMCEnvStateEnvironment_GetUnhandledSignalByUUIDPtr m_StateEnvironment_GetUnhandledSignalByUUID; @@ -11879,15 +11899,17 @@ typedef struct { PLibMCEnvStateEnvironment_HasBuildExecutionPtr m_StateEnvironment_HasBuildExecution; PLibMCEnvStateEnvironment_GetBuildExecutionPtr m_StateEnvironment_GetBuildExecution; PLibMCEnvStateEnvironment_UnloadAllToolpathesPtr m_StateEnvironment_UnloadAllToolpathes; + PLibMCEnvStateEnvironment_WaitForSignalPtr m_StateEnvironment_WaitForSignal; + PLibMCEnvStateEnvironment_GetUnhandledSignalPtr m_StateEnvironment_GetUnhandledSignal; + PLibMCEnvStateEnvironment_StoreSignalPtr m_StateEnvironment_StoreSignal; + PLibMCEnvStateEnvironment_RetrieveSignalPtr m_StateEnvironment_RetrieveSignal; + PLibMCEnvStateEnvironment_ClearStoredValuePtr m_StateEnvironment_ClearStoredValue; PLibMCEnvStateEnvironment_SetNextStatePtr m_StateEnvironment_SetNextState; PLibMCEnvStateEnvironment_LogMessagePtr m_StateEnvironment_LogMessage; PLibMCEnvStateEnvironment_LogWarningPtr m_StateEnvironment_LogWarning; PLibMCEnvStateEnvironment_LogInfoPtr m_StateEnvironment_LogInfo; PLibMCEnvStateEnvironment_SleepPtr m_StateEnvironment_Sleep; PLibMCEnvStateEnvironment_CheckForTerminationPtr m_StateEnvironment_CheckForTermination; - PLibMCEnvStateEnvironment_StoreSignalPtr m_StateEnvironment_StoreSignal; - PLibMCEnvStateEnvironment_RetrieveSignalPtr m_StateEnvironment_RetrieveSignal; - PLibMCEnvStateEnvironment_ClearStoredValuePtr m_StateEnvironment_ClearStoredValue; PLibMCEnvStateEnvironment_SetStringParameterPtr m_StateEnvironment_SetStringParameter; PLibMCEnvStateEnvironment_SetUUIDParameterPtr m_StateEnvironment_SetUUIDParameter; PLibMCEnvStateEnvironment_SetDoubleParameterPtr m_StateEnvironment_SetDoubleParameter; diff --git a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp index c3ae0567..22f8bcf7 100644 --- a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp +++ b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp @@ -3349,8 +3349,8 @@ class CStateEnvironment : public CBase { inline std::string GetMachineState(const std::string & sMachineInstance); inline std::string GetPreviousState(); inline PSignalTrigger PrepareSignal(const std::string & sMachineInstance, const std::string & sSignalName); - inline bool WaitForSignal(const std::string & sSignalName, const LibMCEnv_uint32 nTimeOut, PSignalHandler & pHandlerInstance); - inline PSignalHandler GetUnhandledSignal(const std::string & sSignalTypeName); + inline PSignalHandler ClaimSignalFromQueue(const std::string & sSignalTypeName); + inline bool SignalQueueIsEmpty(const std::string & sSignalTypeName); inline void ClearUnhandledSignalsOfType(const std::string & sSignalTypeName); inline void ClearAllUnhandledSignals(); inline PSignalHandler GetUnhandledSignalByUUID(const std::string & sUUID, const bool bMustExist); @@ -3361,15 +3361,17 @@ class CStateEnvironment : public CBase { inline bool HasBuildExecution(const std::string & sExecutionUUID); inline PBuildExecution GetBuildExecution(const std::string & sExecutionUUID); inline void UnloadAllToolpathes(); + inline bool WaitForSignal(const std::string & sSignalName, const LibMCEnv_uint32 nTimeOut, PSignalHandler & pHandlerInstance); + inline PSignalHandler GetUnhandledSignal(const std::string & sSignalTypeName); + inline void StoreSignal(const std::string & sName, classParam pHandler); + inline PSignalHandler RetrieveSignal(const std::string & sName); + inline void ClearStoredValue(const std::string & sName); inline void SetNextState(const std::string & sStateName); inline void LogMessage(const std::string & sLogString); inline void LogWarning(const std::string & sLogString); inline void LogInfo(const std::string & sLogString); inline void Sleep(const LibMCEnv_uint32 nDelay); inline bool CheckForTermination(); - inline void StoreSignal(const std::string & sName, classParam pHandler); - inline PSignalHandler RetrieveSignal(const std::string & sName); - inline void ClearStoredValue(const std::string & sName); inline void SetStringParameter(const std::string & sParameterGroup, const std::string & sParameterName, const std::string & sValue); inline void SetUUIDParameter(const std::string & sParameterGroup, const std::string & sParameterName, const std::string & sValue); inline void SetDoubleParameter(const std::string & sParameterGroup, const std::string & sParameterName, const LibMCEnv_double dValue); @@ -4484,8 +4486,8 @@ class CUIEnvironment : public CBase { pWrapperTable->m_StateEnvironment_GetMachineState = nullptr; pWrapperTable->m_StateEnvironment_GetPreviousState = nullptr; pWrapperTable->m_StateEnvironment_PrepareSignal = nullptr; - pWrapperTable->m_StateEnvironment_WaitForSignal = nullptr; - pWrapperTable->m_StateEnvironment_GetUnhandledSignal = nullptr; + pWrapperTable->m_StateEnvironment_ClaimSignalFromQueue = nullptr; + pWrapperTable->m_StateEnvironment_SignalQueueIsEmpty = nullptr; pWrapperTable->m_StateEnvironment_ClearUnhandledSignalsOfType = nullptr; pWrapperTable->m_StateEnvironment_ClearAllUnhandledSignals = nullptr; pWrapperTable->m_StateEnvironment_GetUnhandledSignalByUUID = nullptr; @@ -4496,15 +4498,17 @@ class CUIEnvironment : public CBase { pWrapperTable->m_StateEnvironment_HasBuildExecution = nullptr; pWrapperTable->m_StateEnvironment_GetBuildExecution = nullptr; pWrapperTable->m_StateEnvironment_UnloadAllToolpathes = nullptr; + pWrapperTable->m_StateEnvironment_WaitForSignal = nullptr; + pWrapperTable->m_StateEnvironment_GetUnhandledSignal = nullptr; + pWrapperTable->m_StateEnvironment_StoreSignal = nullptr; + pWrapperTable->m_StateEnvironment_RetrieveSignal = nullptr; + pWrapperTable->m_StateEnvironment_ClearStoredValue = nullptr; pWrapperTable->m_StateEnvironment_SetNextState = nullptr; pWrapperTable->m_StateEnvironment_LogMessage = nullptr; pWrapperTable->m_StateEnvironment_LogWarning = nullptr; pWrapperTable->m_StateEnvironment_LogInfo = nullptr; pWrapperTable->m_StateEnvironment_Sleep = nullptr; pWrapperTable->m_StateEnvironment_CheckForTermination = nullptr; - pWrapperTable->m_StateEnvironment_StoreSignal = nullptr; - pWrapperTable->m_StateEnvironment_RetrieveSignal = nullptr; - pWrapperTable->m_StateEnvironment_ClearStoredValue = nullptr; pWrapperTable->m_StateEnvironment_SetStringParameter = nullptr; pWrapperTable->m_StateEnvironment_SetUUIDParameter = nullptr; pWrapperTable->m_StateEnvironment_SetDoubleParameter = nullptr; @@ -12400,21 +12404,21 @@ class CUIEnvironment : public CBase { return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 - pWrapperTable->m_StateEnvironment_WaitForSignal = (PLibMCEnvStateEnvironment_WaitForSignalPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_waitforsignal"); + pWrapperTable->m_StateEnvironment_ClaimSignalFromQueue = (PLibMCEnvStateEnvironment_ClaimSignalFromQueuePtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_claimsignalfromqueue"); #else // _WIN32 - pWrapperTable->m_StateEnvironment_WaitForSignal = (PLibMCEnvStateEnvironment_WaitForSignalPtr) dlsym(hLibrary, "libmcenv_stateenvironment_waitforsignal"); + pWrapperTable->m_StateEnvironment_ClaimSignalFromQueue = (PLibMCEnvStateEnvironment_ClaimSignalFromQueuePtr) dlsym(hLibrary, "libmcenv_stateenvironment_claimsignalfromqueue"); dlerror(); #endif // _WIN32 - if (pWrapperTable->m_StateEnvironment_WaitForSignal == nullptr) + if (pWrapperTable->m_StateEnvironment_ClaimSignalFromQueue == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 - pWrapperTable->m_StateEnvironment_GetUnhandledSignal = (PLibMCEnvStateEnvironment_GetUnhandledSignalPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_getunhandledsignal"); + pWrapperTable->m_StateEnvironment_SignalQueueIsEmpty = (PLibMCEnvStateEnvironment_SignalQueueIsEmptyPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_signalqueueisempty"); #else // _WIN32 - pWrapperTable->m_StateEnvironment_GetUnhandledSignal = (PLibMCEnvStateEnvironment_GetUnhandledSignalPtr) dlsym(hLibrary, "libmcenv_stateenvironment_getunhandledsignal"); + pWrapperTable->m_StateEnvironment_SignalQueueIsEmpty = (PLibMCEnvStateEnvironment_SignalQueueIsEmptyPtr) dlsym(hLibrary, "libmcenv_stateenvironment_signalqueueisempty"); dlerror(); #endif // _WIN32 - if (pWrapperTable->m_StateEnvironment_GetUnhandledSignal == nullptr) + if (pWrapperTable->m_StateEnvironment_SignalQueueIsEmpty == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 @@ -12508,84 +12512,102 @@ class CUIEnvironment : public CBase { return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 - pWrapperTable->m_StateEnvironment_SetNextState = (PLibMCEnvStateEnvironment_SetNextStatePtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_setnextstate"); + pWrapperTable->m_StateEnvironment_WaitForSignal = (PLibMCEnvStateEnvironment_WaitForSignalPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_waitforsignal"); #else // _WIN32 - pWrapperTable->m_StateEnvironment_SetNextState = (PLibMCEnvStateEnvironment_SetNextStatePtr) dlsym(hLibrary, "libmcenv_stateenvironment_setnextstate"); + pWrapperTable->m_StateEnvironment_WaitForSignal = (PLibMCEnvStateEnvironment_WaitForSignalPtr) dlsym(hLibrary, "libmcenv_stateenvironment_waitforsignal"); dlerror(); #endif // _WIN32 - if (pWrapperTable->m_StateEnvironment_SetNextState == nullptr) + if (pWrapperTable->m_StateEnvironment_WaitForSignal == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 - pWrapperTable->m_StateEnvironment_LogMessage = (PLibMCEnvStateEnvironment_LogMessagePtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_logmessage"); + pWrapperTable->m_StateEnvironment_GetUnhandledSignal = (PLibMCEnvStateEnvironment_GetUnhandledSignalPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_getunhandledsignal"); #else // _WIN32 - pWrapperTable->m_StateEnvironment_LogMessage = (PLibMCEnvStateEnvironment_LogMessagePtr) dlsym(hLibrary, "libmcenv_stateenvironment_logmessage"); + pWrapperTable->m_StateEnvironment_GetUnhandledSignal = (PLibMCEnvStateEnvironment_GetUnhandledSignalPtr) dlsym(hLibrary, "libmcenv_stateenvironment_getunhandledsignal"); dlerror(); #endif // _WIN32 - if (pWrapperTable->m_StateEnvironment_LogMessage == nullptr) + if (pWrapperTable->m_StateEnvironment_GetUnhandledSignal == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 - pWrapperTable->m_StateEnvironment_LogWarning = (PLibMCEnvStateEnvironment_LogWarningPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_logwarning"); + pWrapperTable->m_StateEnvironment_StoreSignal = (PLibMCEnvStateEnvironment_StoreSignalPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_storesignal"); #else // _WIN32 - pWrapperTable->m_StateEnvironment_LogWarning = (PLibMCEnvStateEnvironment_LogWarningPtr) dlsym(hLibrary, "libmcenv_stateenvironment_logwarning"); + pWrapperTable->m_StateEnvironment_StoreSignal = (PLibMCEnvStateEnvironment_StoreSignalPtr) dlsym(hLibrary, "libmcenv_stateenvironment_storesignal"); dlerror(); #endif // _WIN32 - if (pWrapperTable->m_StateEnvironment_LogWarning == nullptr) + if (pWrapperTable->m_StateEnvironment_StoreSignal == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 - pWrapperTable->m_StateEnvironment_LogInfo = (PLibMCEnvStateEnvironment_LogInfoPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_loginfo"); + pWrapperTable->m_StateEnvironment_RetrieveSignal = (PLibMCEnvStateEnvironment_RetrieveSignalPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_retrievesignal"); #else // _WIN32 - pWrapperTable->m_StateEnvironment_LogInfo = (PLibMCEnvStateEnvironment_LogInfoPtr) dlsym(hLibrary, "libmcenv_stateenvironment_loginfo"); + pWrapperTable->m_StateEnvironment_RetrieveSignal = (PLibMCEnvStateEnvironment_RetrieveSignalPtr) dlsym(hLibrary, "libmcenv_stateenvironment_retrievesignal"); dlerror(); #endif // _WIN32 - if (pWrapperTable->m_StateEnvironment_LogInfo == nullptr) + if (pWrapperTable->m_StateEnvironment_RetrieveSignal == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 - pWrapperTable->m_StateEnvironment_Sleep = (PLibMCEnvStateEnvironment_SleepPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_sleep"); + pWrapperTable->m_StateEnvironment_ClearStoredValue = (PLibMCEnvStateEnvironment_ClearStoredValuePtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_clearstoredvalue"); #else // _WIN32 - pWrapperTable->m_StateEnvironment_Sleep = (PLibMCEnvStateEnvironment_SleepPtr) dlsym(hLibrary, "libmcenv_stateenvironment_sleep"); + pWrapperTable->m_StateEnvironment_ClearStoredValue = (PLibMCEnvStateEnvironment_ClearStoredValuePtr) dlsym(hLibrary, "libmcenv_stateenvironment_clearstoredvalue"); dlerror(); #endif // _WIN32 - if (pWrapperTable->m_StateEnvironment_Sleep == nullptr) + if (pWrapperTable->m_StateEnvironment_ClearStoredValue == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 - pWrapperTable->m_StateEnvironment_CheckForTermination = (PLibMCEnvStateEnvironment_CheckForTerminationPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_checkfortermination"); + pWrapperTable->m_StateEnvironment_SetNextState = (PLibMCEnvStateEnvironment_SetNextStatePtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_setnextstate"); #else // _WIN32 - pWrapperTable->m_StateEnvironment_CheckForTermination = (PLibMCEnvStateEnvironment_CheckForTerminationPtr) dlsym(hLibrary, "libmcenv_stateenvironment_checkfortermination"); + pWrapperTable->m_StateEnvironment_SetNextState = (PLibMCEnvStateEnvironment_SetNextStatePtr) dlsym(hLibrary, "libmcenv_stateenvironment_setnextstate"); dlerror(); #endif // _WIN32 - if (pWrapperTable->m_StateEnvironment_CheckForTermination == nullptr) + if (pWrapperTable->m_StateEnvironment_SetNextState == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 - pWrapperTable->m_StateEnvironment_StoreSignal = (PLibMCEnvStateEnvironment_StoreSignalPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_storesignal"); + pWrapperTable->m_StateEnvironment_LogMessage = (PLibMCEnvStateEnvironment_LogMessagePtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_logmessage"); #else // _WIN32 - pWrapperTable->m_StateEnvironment_StoreSignal = (PLibMCEnvStateEnvironment_StoreSignalPtr) dlsym(hLibrary, "libmcenv_stateenvironment_storesignal"); + pWrapperTable->m_StateEnvironment_LogMessage = (PLibMCEnvStateEnvironment_LogMessagePtr) dlsym(hLibrary, "libmcenv_stateenvironment_logmessage"); dlerror(); #endif // _WIN32 - if (pWrapperTable->m_StateEnvironment_StoreSignal == nullptr) + if (pWrapperTable->m_StateEnvironment_LogMessage == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 - pWrapperTable->m_StateEnvironment_RetrieveSignal = (PLibMCEnvStateEnvironment_RetrieveSignalPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_retrievesignal"); + pWrapperTable->m_StateEnvironment_LogWarning = (PLibMCEnvStateEnvironment_LogWarningPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_logwarning"); #else // _WIN32 - pWrapperTable->m_StateEnvironment_RetrieveSignal = (PLibMCEnvStateEnvironment_RetrieveSignalPtr) dlsym(hLibrary, "libmcenv_stateenvironment_retrievesignal"); + pWrapperTable->m_StateEnvironment_LogWarning = (PLibMCEnvStateEnvironment_LogWarningPtr) dlsym(hLibrary, "libmcenv_stateenvironment_logwarning"); dlerror(); #endif // _WIN32 - if (pWrapperTable->m_StateEnvironment_RetrieveSignal == nullptr) + if (pWrapperTable->m_StateEnvironment_LogWarning == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 - pWrapperTable->m_StateEnvironment_ClearStoredValue = (PLibMCEnvStateEnvironment_ClearStoredValuePtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_clearstoredvalue"); + pWrapperTable->m_StateEnvironment_LogInfo = (PLibMCEnvStateEnvironment_LogInfoPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_loginfo"); #else // _WIN32 - pWrapperTable->m_StateEnvironment_ClearStoredValue = (PLibMCEnvStateEnvironment_ClearStoredValuePtr) dlsym(hLibrary, "libmcenv_stateenvironment_clearstoredvalue"); + pWrapperTable->m_StateEnvironment_LogInfo = (PLibMCEnvStateEnvironment_LogInfoPtr) dlsym(hLibrary, "libmcenv_stateenvironment_loginfo"); dlerror(); #endif // _WIN32 - if (pWrapperTable->m_StateEnvironment_ClearStoredValue == nullptr) + if (pWrapperTable->m_StateEnvironment_LogInfo == nullptr) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_StateEnvironment_Sleep = (PLibMCEnvStateEnvironment_SleepPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_sleep"); + #else // _WIN32 + pWrapperTable->m_StateEnvironment_Sleep = (PLibMCEnvStateEnvironment_SleepPtr) dlsym(hLibrary, "libmcenv_stateenvironment_sleep"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_StateEnvironment_Sleep == nullptr) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_StateEnvironment_CheckForTermination = (PLibMCEnvStateEnvironment_CheckForTerminationPtr) GetProcAddress(hLibrary, "libmcenv_stateenvironment_checkfortermination"); + #else // _WIN32 + pWrapperTable->m_StateEnvironment_CheckForTermination = (PLibMCEnvStateEnvironment_CheckForTerminationPtr) dlsym(hLibrary, "libmcenv_stateenvironment_checkfortermination"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_StateEnvironment_CheckForTermination == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; #ifdef _WIN32 @@ -17365,12 +17387,12 @@ class CUIEnvironment : public CBase { if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_PrepareSignal == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; - eLookupError = (*pLookup)("libmcenv_stateenvironment_waitforsignal", (void**)&(pWrapperTable->m_StateEnvironment_WaitForSignal)); - if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_WaitForSignal == nullptr) ) + eLookupError = (*pLookup)("libmcenv_stateenvironment_claimsignalfromqueue", (void**)&(pWrapperTable->m_StateEnvironment_ClaimSignalFromQueue)); + if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_ClaimSignalFromQueue == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; - eLookupError = (*pLookup)("libmcenv_stateenvironment_getunhandledsignal", (void**)&(pWrapperTable->m_StateEnvironment_GetUnhandledSignal)); - if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_GetUnhandledSignal == nullptr) ) + eLookupError = (*pLookup)("libmcenv_stateenvironment_signalqueueisempty", (void**)&(pWrapperTable->m_StateEnvironment_SignalQueueIsEmpty)); + if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_SignalQueueIsEmpty == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; eLookupError = (*pLookup)("libmcenv_stateenvironment_clearunhandledsignalsoftype", (void**)&(pWrapperTable->m_StateEnvironment_ClearUnhandledSignalsOfType)); @@ -17413,6 +17435,26 @@ class CUIEnvironment : public CBase { if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_UnloadAllToolpathes == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_stateenvironment_waitforsignal", (void**)&(pWrapperTable->m_StateEnvironment_WaitForSignal)); + if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_WaitForSignal == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libmcenv_stateenvironment_getunhandledsignal", (void**)&(pWrapperTable->m_StateEnvironment_GetUnhandledSignal)); + if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_GetUnhandledSignal == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libmcenv_stateenvironment_storesignal", (void**)&(pWrapperTable->m_StateEnvironment_StoreSignal)); + if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_StoreSignal == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libmcenv_stateenvironment_retrievesignal", (void**)&(pWrapperTable->m_StateEnvironment_RetrieveSignal)); + if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_RetrieveSignal == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libmcenv_stateenvironment_clearstoredvalue", (void**)&(pWrapperTable->m_StateEnvironment_ClearStoredValue)); + if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_ClearStoredValue == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_stateenvironment_setnextstate", (void**)&(pWrapperTable->m_StateEnvironment_SetNextState)); if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_SetNextState == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; @@ -17437,18 +17479,6 @@ class CUIEnvironment : public CBase { if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_CheckForTermination == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; - eLookupError = (*pLookup)("libmcenv_stateenvironment_storesignal", (void**)&(pWrapperTable->m_StateEnvironment_StoreSignal)); - if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_StoreSignal == nullptr) ) - return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; - - eLookupError = (*pLookup)("libmcenv_stateenvironment_retrievesignal", (void**)&(pWrapperTable->m_StateEnvironment_RetrieveSignal)); - if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_RetrieveSignal == nullptr) ) - return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; - - eLookupError = (*pLookup)("libmcenv_stateenvironment_clearstoredvalue", (void**)&(pWrapperTable->m_StateEnvironment_ClearStoredValue)); - if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_ClearStoredValue == nullptr) ) - return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; - eLookupError = (*pLookup)("libmcenv_stateenvironment_setstringparameter", (void**)&(pWrapperTable->m_StateEnvironment_SetStringParameter)); if ( (eLookupError != 0) || (pWrapperTable->m_StateEnvironment_SetStringParameter == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; @@ -29813,45 +29843,37 @@ class CUIEnvironment : public CBase { } /** - * CStateEnvironment::WaitForSignal - Waits for a signal for a certain amount of time. - * @param[in] sSignalName - Name Of Signal - * @param[in] nTimeOut - Timeout in Milliseconds. 0 for Immediate return. - * @param[out] pHandlerInstance - Signal object. If Success is false, the Signal Handler Object will be null. - * @return Signal has been triggered + * CStateEnvironment::ClaimSignalFromQueue - Retrieves an InQueue signal by type and changes its phase to InProcess. Recommended to use as it is robust against signal timeouts... + * @param[in] sSignalTypeName - Name Of Signal to be returned + * @return Signal object. If no signal is InQueue the signal handler object will be null. */ - bool CStateEnvironment::WaitForSignal(const std::string & sSignalName, const LibMCEnv_uint32 nTimeOut, PSignalHandler & pHandlerInstance) + PSignalHandler CStateEnvironment::ClaimSignalFromQueue(const std::string & sSignalTypeName) { LibMCEnvHandle hHandlerInstance = nullptr; - bool resultSuccess = 0; - CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_WaitForSignal(m_pHandle, sSignalName.c_str(), nTimeOut, &hHandlerInstance, &resultSuccess)); + CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_ClaimSignalFromQueue(m_pHandle, sSignalTypeName.c_str(), &hHandlerInstance)); + if (hHandlerInstance) { - pHandlerInstance = std::make_shared(m_pWrapper, hHandlerInstance); + return std::make_shared(m_pWrapper, hHandlerInstance); } else { - pHandlerInstance = nullptr; + return nullptr; } - - return resultSuccess; } /** - * CStateEnvironment::GetUnhandledSignal - Retrieves an unhandled signal By signal type name. Only affects signals with Phase InQueue. + * CStateEnvironment::SignalQueueIsEmpty - Returns if a signal queue is empty for a specific type... * @param[in] sSignalTypeName - Name Of Signal to be returned - * @return Signal object. If no signal has been found the signal handler object will be null. + * @return Returns if the signal queue is empty. Please be aware that even a false return value does not guarantee that ClaimSignalFromQueue returns a non-null value. */ - PSignalHandler CStateEnvironment::GetUnhandledSignal(const std::string & sSignalTypeName) + bool CStateEnvironment::SignalQueueIsEmpty(const std::string & sSignalTypeName) { - LibMCEnvHandle hHandlerInstance = nullptr; - CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_GetUnhandledSignal(m_pHandle, sSignalTypeName.c_str(), &hHandlerInstance)); + bool resultIsEmpty = 0; + CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_SignalQueueIsEmpty(m_pHandle, sSignalTypeName.c_str(), &resultIsEmpty)); - if (hHandlerInstance) { - return std::make_shared(m_pWrapper, hHandlerInstance); - } else { - return nullptr; - } + return resultIsEmpty; } /** - * CStateEnvironment::ClearUnhandledSignalsOfType - Clears all unhandled signals of a certain type and marks them as Cleared. Only affects signals with Phase InQueue. + * CStateEnvironment::ClearUnhandledSignalsOfType - Clears all InQueue or InProcess signals of a certain type and marks them as Cleared. Handled, failed or timedout signals are unaffected * @param[in] sSignalTypeName - Name Of Signal to be cleared. */ void CStateEnvironment::ClearUnhandledSignalsOfType(const std::string & sSignalTypeName) @@ -29860,7 +29882,7 @@ class CUIEnvironment : public CBase { } /** - * CStateEnvironment::ClearAllUnhandledSignals - Clears all unhandled signals and marks them Cleared. Only affects signals in the specific queue (as well as with Phase InQueue. + * CStateEnvironment::ClearAllUnhandledSignals - Clears all InQueue or InProcess signals of this state machine and marks them Cleared. Handled, failed or timedout signals are unaffected */ void CStateEnvironment::ClearAllUnhandledSignals() { @@ -29868,9 +29890,9 @@ class CUIEnvironment : public CBase { } /** - * CStateEnvironment::GetUnhandledSignalByUUID - retrieves an unhandled signal from the current state machine by UUID. + * CStateEnvironment::GetUnhandledSignalByUUID - Retrieves an InQueue or InProcess signal from the current state machine by UUID. * @param[in] sUUID - Name - * @param[in] bMustExist - The call fails if MustExist is true and not signal with UUID does exist or a signal with UUID has been handled already. + * @param[in] bMustExist - The call fails if MustExist is true and not signal with UUID does exist or a signal with UUID has been handled, failed, cleared or timedout already. * @return Signal handler instance. Returns null, if signal does not exist. */ PSignalHandler CStateEnvironment::GetUnhandledSignalByUUID(const std::string & sUUID, const bool bMustExist) @@ -29977,6 +29999,80 @@ class CUIEnvironment : public CBase { CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_UnloadAllToolpathes(m_pHandle)); } + /** + * CStateEnvironment::WaitForSignal - DEPRECIATED: Waits for an InQueue signal to exist for a certain amount of time. DOES NOT change signal phase to InProcess, and is not atomic. And so NOT robust against signal timeouts. USE claim signal instead. + * @param[in] sSignalName - Name Of Signal + * @param[in] nTimeOut - Timeout in Milliseconds. 0 for Immediate return. + * @param[out] pHandlerInstance - Signal object. If Success is false, the Signal Handler Object will be null. + * @return Signal has been triggered + */ + bool CStateEnvironment::WaitForSignal(const std::string & sSignalName, const LibMCEnv_uint32 nTimeOut, PSignalHandler & pHandlerInstance) + { + LibMCEnvHandle hHandlerInstance = nullptr; + bool resultSuccess = 0; + CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_WaitForSignal(m_pHandle, sSignalName.c_str(), nTimeOut, &hHandlerInstance, &resultSuccess)); + if (hHandlerInstance) { + pHandlerInstance = std::make_shared(m_pWrapper, hHandlerInstance); + } else { + pHandlerInstance = nullptr; + } + + return resultSuccess; + } + + /** + * CStateEnvironment::GetUnhandledSignal - DEPRECIATED: Retrieves am InQueue signal by type. DOES NOT change signal phase to InProcess, and is not atomic. And so NOT robust against signal timeouts. USE ClaimSignalFromQueue instead. + * @param[in] sSignalTypeName - Name Of Signal to be returned + * @return Signal object. If no signal has been found the signal handler object will be null. + */ + PSignalHandler CStateEnvironment::GetUnhandledSignal(const std::string & sSignalTypeName) + { + LibMCEnvHandle hHandlerInstance = nullptr; + CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_GetUnhandledSignal(m_pHandle, sSignalTypeName.c_str(), &hHandlerInstance)); + + if (hHandlerInstance) { + return std::make_shared(m_pWrapper, hHandlerInstance); + } else { + return nullptr; + } + } + + /** + * CStateEnvironment::StoreSignal - DEPRECIATED: stores a signal handler in the current state machine + * @param[in] sName - Name + * @param[in] pHandler - Signal handler to store. + */ + void CStateEnvironment::StoreSignal(const std::string & sName, classParam pHandler) + { + LibMCEnvHandle hHandler = pHandler.GetHandle(); + CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_StoreSignal(m_pHandle, sName.c_str(), hHandler)); + } + + /** + * CStateEnvironment::RetrieveSignal - DEPRECIATED: retrieves a signal handler from the current state machine. Fails if value has not been stored before or signal has been already handled. + * @param[in] sName - Name + * @return Signal handler instance. + */ + PSignalHandler CStateEnvironment::RetrieveSignal(const std::string & sName) + { + LibMCEnvHandle hHandler = nullptr; + CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_RetrieveSignal(m_pHandle, sName.c_str(), &hHandler)); + + if (!hHandler) { + CheckError(LIBMCENV_ERROR_INVALIDPARAM); + } + return std::make_shared(m_pWrapper, hHandler); + } + + /** + * CStateEnvironment::ClearStoredValue - DEPRECIATED: deletes a value from the data store. + * @param[in] sName - Name + */ + void CStateEnvironment::ClearStoredValue(const std::string & sName) + { + CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_ClearStoredValue(m_pHandle, sName.c_str())); + } + /** * CStateEnvironment::SetNextState - sets the next state * @param[in] sStateName - Name of next state @@ -30034,42 +30130,6 @@ class CUIEnvironment : public CBase { return resultShallTerminate; } - /** - * CStateEnvironment::StoreSignal - DEPRECIATED: stores a signal handler in the current state machine - * @param[in] sName - Name - * @param[in] pHandler - Signal handler to store. - */ - void CStateEnvironment::StoreSignal(const std::string & sName, classParam pHandler) - { - LibMCEnvHandle hHandler = pHandler.GetHandle(); - CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_StoreSignal(m_pHandle, sName.c_str(), hHandler)); - } - - /** - * CStateEnvironment::RetrieveSignal - DEPRECIATED: retrieves a signal handler from the current state machine. Fails if value has not been stored before or signal has been already handled. - * @param[in] sName - Name - * @return Signal handler instance. - */ - PSignalHandler CStateEnvironment::RetrieveSignal(const std::string & sName) - { - LibMCEnvHandle hHandler = nullptr; - CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_RetrieveSignal(m_pHandle, sName.c_str(), &hHandler)); - - if (!hHandler) { - CheckError(LIBMCENV_ERROR_INVALIDPARAM); - } - return std::make_shared(m_pWrapper, hHandler); - } - - /** - * CStateEnvironment::ClearStoredValue - DEPRECIATED: deletes a value from the data store. - * @param[in] sName - Name - */ - void CStateEnvironment::ClearStoredValue(const std::string & sName) - { - CheckError(m_pWrapper->m_WrapperTable.m_StateEnvironment_ClearStoredValue(m_pHandle, sName.c_str())); - } - /** * CStateEnvironment::SetStringParameter - sets a string parameter * @param[in] sParameterGroup - Parameter Group diff --git a/Framework/InterfacesCore/libmcenv_abi.hpp b/Framework/InterfacesCore/libmcenv_abi.hpp index 6cbced6e..d1f18195 100644 --- a/Framework/InterfacesCore/libmcenv_abi.hpp +++ b/Framework/InterfacesCore/libmcenv_abi.hpp @@ -9231,29 +9231,27 @@ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_getpreviousstate(LibM LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_preparesignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pMachineInstance, const char * pSignalName, LibMCEnv_SignalTrigger * pSignalInstance); /** -* Waits for a signal for a certain amount of time. +* Retrieves an InQueue signal by type and changes its phase to InProcess. Recommended to use as it is robust against signal timeouts... * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pSignalName - Name Of Signal -* @param[in] nTimeOut - Timeout in Milliseconds. 0 for Immediate return. -* @param[out] pHandlerInstance - Signal object. If Success is false, the Signal Handler Object will be null. -* @param[out] pSuccess - Signal has been triggered +* @param[in] pSignalTypeName - Name Of Signal to be returned +* @param[out] pHandlerInstance - Signal object. If no signal is InQueue the signal handler object will be null. * @return error code or 0 (success) */ -LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_waitforsignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalName, LibMCEnv_uint32 nTimeOut, LibMCEnv_SignalHandler * pHandlerInstance, bool * pSuccess); +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_claimsignalfromqueue(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, LibMCEnv_SignalHandler * pHandlerInstance); /** -* Retrieves an unhandled signal By signal type name. Only affects signals with Phase InQueue. +* Returns if a signal queue is empty for a specific type... * * @param[in] pStateEnvironment - StateEnvironment instance. * @param[in] pSignalTypeName - Name Of Signal to be returned -* @param[out] pHandlerInstance - Signal object. If no signal has been found the signal handler object will be null. +* @param[out] pIsEmpty - Returns if the signal queue is empty. Please be aware that even a false return value does not guarantee that ClaimSignalFromQueue returns a non-null value. * @return error code or 0 (success) */ -LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_getunhandledsignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, LibMCEnv_SignalHandler * pHandlerInstance); +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_signalqueueisempty(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, bool * pIsEmpty); /** -* Clears all unhandled signals of a certain type and marks them as Cleared. Only affects signals with Phase InQueue. +* Clears all InQueue or InProcess signals of a certain type and marks them as Cleared. Handled, failed or timedout signals are unaffected * * @param[in] pStateEnvironment - StateEnvironment instance. * @param[in] pSignalTypeName - Name Of Signal to be cleared. @@ -9262,7 +9260,7 @@ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_getunhandledsignal(Li LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_clearunhandledsignalsoftype(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName); /** -* Clears all unhandled signals and marks them Cleared. Only affects signals in the specific queue (as well as with Phase InQueue. +* Clears all InQueue or InProcess signals of this state machine and marks them Cleared. Handled, failed or timedout signals are unaffected * * @param[in] pStateEnvironment - StateEnvironment instance. * @return error code or 0 (success) @@ -9270,11 +9268,11 @@ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_clearunhandledsignals LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_clearallunhandledsignals(LibMCEnv_StateEnvironment pStateEnvironment); /** -* retrieves an unhandled signal from the current state machine by UUID. +* Retrieves an InQueue or InProcess signal from the current state machine by UUID. * * @param[in] pStateEnvironment - StateEnvironment instance. * @param[in] pUUID - Name -* @param[in] bMustExist - The call fails if MustExist is true and not signal with UUID does exist or a signal with UUID has been handled already. +* @param[in] bMustExist - The call fails if MustExist is true and not signal with UUID does exist or a signal with UUID has been handled, failed, cleared or timedout already. * @param[out] pHandler - Signal handler instance. Returns null, if signal does not exist. * @return error code or 0 (success) */ @@ -9352,87 +9350,109 @@ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_getbuildexecution(Lib LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_unloadalltoolpathes(LibMCEnv_StateEnvironment pStateEnvironment); /** -* sets the next state +* DEPRECIATED: Waits for an InQueue signal to exist for a certain amount of time. DOES NOT change signal phase to InProcess, and is not atomic. And so NOT robust against signal timeouts. USE claim signal instead. * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pStateName - Name of next state +* @param[in] pSignalName - Name Of Signal +* @param[in] nTimeOut - Timeout in Milliseconds. 0 for Immediate return. +* @param[out] pHandlerInstance - Signal object. If Success is false, the Signal Handler Object will be null. +* @param[out] pSuccess - Signal has been triggered * @return error code or 0 (success) */ -LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_setnextstate(LibMCEnv_StateEnvironment pStateEnvironment, const char * pStateName); +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_waitforsignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalName, LibMCEnv_uint32 nTimeOut, LibMCEnv_SignalHandler * pHandlerInstance, bool * pSuccess); /** -* logs a string as message +* DEPRECIATED: Retrieves am InQueue signal by type. DOES NOT change signal phase to InProcess, and is not atomic. And so NOT robust against signal timeouts. USE ClaimSignalFromQueue instead. * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pLogString - String to Log +* @param[in] pSignalTypeName - Name Of Signal to be returned +* @param[out] pHandlerInstance - Signal object. If no signal has been found the signal handler object will be null. * @return error code or 0 (success) */ -LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_logmessage(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_getunhandledsignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, LibMCEnv_SignalHandler * pHandlerInstance); /** -* logs a string as warning +* DEPRECIATED: stores a signal handler in the current state machine * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pLogString - String to Log +* @param[in] pName - Name +* @param[in] pHandler - Signal handler to store. * @return error code or 0 (success) */ -LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_logwarning(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_storesignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler pHandler); /** -* logs a string as info +* DEPRECIATED: retrieves a signal handler from the current state machine. Fails if value has not been stored before or signal has been already handled. * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pLogString - String to Log +* @param[in] pName - Name +* @param[out] pHandler - Signal handler instance. * @return error code or 0 (success) */ -LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_loginfo(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_retrievesignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler * pHandler); /** -* Puts the current instance to sleep for a definite amount of time. MUST be used instead of a blocking sleep call. +* DEPRECIATED: deletes a value from the data store. * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] nDelay - Milliseconds to sleeps +* @param[in] pName - Name * @return error code or 0 (success) */ -LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_sleep(LibMCEnv_StateEnvironment pStateEnvironment, LibMCEnv_uint32 nDelay); +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_clearstoredvalue(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName); /** -* checks environment for termination signal. MUST be called frequently in longer-running operations. +* sets the next state * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[out] pShallTerminate - Returns if termination shall appear +* @param[in] pStateName - Name of next state * @return error code or 0 (success) */ -LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_checkfortermination(LibMCEnv_StateEnvironment pStateEnvironment, bool * pShallTerminate); +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_setnextstate(LibMCEnv_StateEnvironment pStateEnvironment, const char * pStateName); /** -* DEPRECIATED: stores a signal handler in the current state machine +* logs a string as message * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pName - Name -* @param[in] pHandler - Signal handler to store. +* @param[in] pLogString - String to Log * @return error code or 0 (success) */ -LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_storesignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler pHandler); +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_logmessage(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); /** -* DEPRECIATED: retrieves a signal handler from the current state machine. Fails if value has not been stored before or signal has been already handled. +* logs a string as warning * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pName - Name -* @param[out] pHandler - Signal handler instance. +* @param[in] pLogString - String to Log * @return error code or 0 (success) */ -LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_retrievesignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler * pHandler); +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_logwarning(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); /** -* DEPRECIATED: deletes a value from the data store. +* logs a string as info * * @param[in] pStateEnvironment - StateEnvironment instance. -* @param[in] pName - Name +* @param[in] pLogString - String to Log * @return error code or 0 (success) */ -LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_clearstoredvalue(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName); +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_loginfo(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString); + +/** +* Puts the current instance to sleep for a definite amount of time. MUST be used instead of a blocking sleep call. +* +* @param[in] pStateEnvironment - StateEnvironment instance. +* @param[in] nDelay - Milliseconds to sleeps +* @return error code or 0 (success) +*/ +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_sleep(LibMCEnv_StateEnvironment pStateEnvironment, LibMCEnv_uint32 nDelay); + +/** +* checks environment for termination signal. MUST be called frequently in longer-running operations. +* +* @param[in] pStateEnvironment - StateEnvironment instance. +* @param[out] pShallTerminate - Returns if termination shall appear +* @return error code or 0 (success) +*/ +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_stateenvironment_checkfortermination(LibMCEnv_StateEnvironment pStateEnvironment, bool * pShallTerminate); /** * sets a string parameter diff --git a/Framework/InterfacesCore/libmcenv_interfaces.hpp b/Framework/InterfacesCore/libmcenv_interfaces.hpp index c655dd7a..31e3e2e8 100644 --- a/Framework/InterfacesCore/libmcenv_interfaces.hpp +++ b/Framework/InterfacesCore/libmcenv_interfaces.hpp @@ -7168,36 +7168,34 @@ class IStateEnvironment : public virtual IBase { virtual ISignalTrigger * PrepareSignal(const std::string & sMachineInstance, const std::string & sSignalName) = 0; /** - * IStateEnvironment::WaitForSignal - Waits for a signal for a certain amount of time. - * @param[in] sSignalName - Name Of Signal - * @param[in] nTimeOut - Timeout in Milliseconds. 0 for Immediate return. - * @param[out] pHandlerInstance - Signal object. If Success is false, the Signal Handler Object will be null. - * @return Signal has been triggered + * IStateEnvironment::ClaimSignalFromQueue - Retrieves an InQueue signal by type and changes its phase to InProcess. Recommended to use as it is robust against signal timeouts... + * @param[in] sSignalTypeName - Name Of Signal to be returned + * @return Signal object. If no signal is InQueue the signal handler object will be null. */ - virtual bool WaitForSignal(const std::string & sSignalName, const LibMCEnv_uint32 nTimeOut, ISignalHandler*& pHandlerInstance) = 0; + virtual ISignalHandler * ClaimSignalFromQueue(const std::string & sSignalTypeName) = 0; /** - * IStateEnvironment::GetUnhandledSignal - Retrieves an unhandled signal By signal type name. Only affects signals with Phase InQueue. + * IStateEnvironment::SignalQueueIsEmpty - Returns if a signal queue is empty for a specific type... * @param[in] sSignalTypeName - Name Of Signal to be returned - * @return Signal object. If no signal has been found the signal handler object will be null. + * @return Returns if the signal queue is empty. Please be aware that even a false return value does not guarantee that ClaimSignalFromQueue returns a non-null value. */ - virtual ISignalHandler * GetUnhandledSignal(const std::string & sSignalTypeName) = 0; + virtual bool SignalQueueIsEmpty(const std::string & sSignalTypeName) = 0; /** - * IStateEnvironment::ClearUnhandledSignalsOfType - Clears all unhandled signals of a certain type and marks them as Cleared. Only affects signals with Phase InQueue. + * IStateEnvironment::ClearUnhandledSignalsOfType - Clears all InQueue or InProcess signals of a certain type and marks them as Cleared. Handled, failed or timedout signals are unaffected * @param[in] sSignalTypeName - Name Of Signal to be cleared. */ virtual void ClearUnhandledSignalsOfType(const std::string & sSignalTypeName) = 0; /** - * IStateEnvironment::ClearAllUnhandledSignals - Clears all unhandled signals and marks them Cleared. Only affects signals in the specific queue (as well as with Phase InQueue. + * IStateEnvironment::ClearAllUnhandledSignals - Clears all InQueue or InProcess signals of this state machine and marks them Cleared. Handled, failed or timedout signals are unaffected */ virtual void ClearAllUnhandledSignals() = 0; /** - * IStateEnvironment::GetUnhandledSignalByUUID - retrieves an unhandled signal from the current state machine by UUID. + * IStateEnvironment::GetUnhandledSignalByUUID - Retrieves an InQueue or InProcess signal from the current state machine by UUID. * @param[in] sUUID - Name - * @param[in] bMustExist - The call fails if MustExist is true and not signal with UUID does exist or a signal with UUID has been handled already. + * @param[in] bMustExist - The call fails if MustExist is true and not signal with UUID does exist or a signal with UUID has been handled, failed, cleared or timedout already. * @return Signal handler instance. Returns null, if signal does not exist. */ virtual ISignalHandler * GetUnhandledSignalByUUID(const std::string & sUUID, const bool bMustExist) = 0; @@ -7250,6 +7248,42 @@ class IStateEnvironment : public virtual IBase { */ virtual void UnloadAllToolpathes() = 0; + /** + * IStateEnvironment::WaitForSignal - DEPRECIATED: Waits for an InQueue signal to exist for a certain amount of time. DOES NOT change signal phase to InProcess, and is not atomic. And so NOT robust against signal timeouts. USE claim signal instead. + * @param[in] sSignalName - Name Of Signal + * @param[in] nTimeOut - Timeout in Milliseconds. 0 for Immediate return. + * @param[out] pHandlerInstance - Signal object. If Success is false, the Signal Handler Object will be null. + * @return Signal has been triggered + */ + virtual bool WaitForSignal(const std::string & sSignalName, const LibMCEnv_uint32 nTimeOut, ISignalHandler*& pHandlerInstance) = 0; + + /** + * IStateEnvironment::GetUnhandledSignal - DEPRECIATED: Retrieves am InQueue signal by type. DOES NOT change signal phase to InProcess, and is not atomic. And so NOT robust against signal timeouts. USE ClaimSignalFromQueue instead. + * @param[in] sSignalTypeName - Name Of Signal to be returned + * @return Signal object. If no signal has been found the signal handler object will be null. + */ + virtual ISignalHandler * GetUnhandledSignal(const std::string & sSignalTypeName) = 0; + + /** + * IStateEnvironment::StoreSignal - DEPRECIATED: stores a signal handler in the current state machine + * @param[in] sName - Name + * @param[in] pHandler - Signal handler to store. + */ + virtual void StoreSignal(const std::string & sName, ISignalHandler* pHandler) = 0; + + /** + * IStateEnvironment::RetrieveSignal - DEPRECIATED: retrieves a signal handler from the current state machine. Fails if value has not been stored before or signal has been already handled. + * @param[in] sName - Name + * @return Signal handler instance. + */ + virtual ISignalHandler * RetrieveSignal(const std::string & sName) = 0; + + /** + * IStateEnvironment::ClearStoredValue - DEPRECIATED: deletes a value from the data store. + * @param[in] sName - Name + */ + virtual void ClearStoredValue(const std::string & sName) = 0; + /** * IStateEnvironment::SetNextState - sets the next state * @param[in] sStateName - Name of next state @@ -7286,26 +7320,6 @@ class IStateEnvironment : public virtual IBase { */ virtual bool CheckForTermination() = 0; - /** - * IStateEnvironment::StoreSignal - DEPRECIATED: stores a signal handler in the current state machine - * @param[in] sName - Name - * @param[in] pHandler - Signal handler to store. - */ - virtual void StoreSignal(const std::string & sName, ISignalHandler* pHandler) = 0; - - /** - * IStateEnvironment::RetrieveSignal - DEPRECIATED: retrieves a signal handler from the current state machine. Fails if value has not been stored before or signal has been already handled. - * @param[in] sName - Name - * @return Signal handler instance. - */ - virtual ISignalHandler * RetrieveSignal(const std::string & sName) = 0; - - /** - * IStateEnvironment::ClearStoredValue - DEPRECIATED: deletes a value from the data store. - * @param[in] sName - Name - */ - virtual void ClearStoredValue(const std::string & sName) = 0; - /** * IStateEnvironment::SetStringParameter - sets a string parameter * @param[in] sParameterGroup - Parameter Group diff --git a/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp b/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp index 2dcd6043..39955d16 100644 --- a/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp +++ b/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp @@ -27731,24 +27731,22 @@ LibMCEnvResult libmcenv_stateenvironment_preparesignal(LibMCEnv_StateEnvironment } } -LibMCEnvResult libmcenv_stateenvironment_waitforsignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalName, LibMCEnv_uint32 nTimeOut, LibMCEnv_SignalHandler * pHandlerInstance, bool * pSuccess) +LibMCEnvResult libmcenv_stateenvironment_claimsignalfromqueue(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, LibMCEnv_SignalHandler * pHandlerInstance) { IBase* pIBaseClass = (IBase *)pStateEnvironment; try { - if (pSignalName == nullptr) + if (pSignalTypeName == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); if (pHandlerInstance == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); - if (pSuccess == nullptr) - throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); - std::string sSignalName(pSignalName); - ISignalHandler* pBaseHandlerInstance(nullptr); + std::string sSignalTypeName(pSignalTypeName); + IBase* pBaseHandlerInstance(nullptr); IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); if (!pIStateEnvironment) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); - *pSuccess = pIStateEnvironment->WaitForSignal(sSignalName, nTimeOut, pBaseHandlerInstance); + pBaseHandlerInstance = pIStateEnvironment->ClaimSignalFromQueue(sSignalTypeName); *pHandlerInstance = (IBase*)(pBaseHandlerInstance); return LIBMCENV_SUCCESS; @@ -27764,24 +27762,22 @@ LibMCEnvResult libmcenv_stateenvironment_waitforsignal(LibMCEnv_StateEnvironment } } -LibMCEnvResult libmcenv_stateenvironment_getunhandledsignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, LibMCEnv_SignalHandler * pHandlerInstance) +LibMCEnvResult libmcenv_stateenvironment_signalqueueisempty(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, bool * pIsEmpty) { IBase* pIBaseClass = (IBase *)pStateEnvironment; try { if (pSignalTypeName == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); - if (pHandlerInstance == nullptr) + if (pIsEmpty == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); std::string sSignalTypeName(pSignalTypeName); - IBase* pBaseHandlerInstance(nullptr); IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); if (!pIStateEnvironment) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); - pBaseHandlerInstance = pIStateEnvironment->GetUnhandledSignal(sSignalTypeName); + *pIsEmpty = pIStateEnvironment->SignalQueueIsEmpty(sSignalTypeName); - *pHandlerInstance = (IBase*)(pBaseHandlerInstance); return LIBMCENV_SUCCESS; } catch (ELibMCEnvInterfaceException & Exception) { @@ -28103,20 +28099,26 @@ LibMCEnvResult libmcenv_stateenvironment_unloadalltoolpathes(LibMCEnv_StateEnvir } } -LibMCEnvResult libmcenv_stateenvironment_setnextstate(LibMCEnv_StateEnvironment pStateEnvironment, const char * pStateName) +LibMCEnvResult libmcenv_stateenvironment_waitforsignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalName, LibMCEnv_uint32 nTimeOut, LibMCEnv_SignalHandler * pHandlerInstance, bool * pSuccess) { IBase* pIBaseClass = (IBase *)pStateEnvironment; try { - if (pStateName == nullptr) + if (pSignalName == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); - std::string sStateName(pStateName); + if (pHandlerInstance == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + if (pSuccess == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sSignalName(pSignalName); + ISignalHandler* pBaseHandlerInstance(nullptr); IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); if (!pIStateEnvironment) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); - pIStateEnvironment->SetNextState(sStateName); + *pSuccess = pIStateEnvironment->WaitForSignal(sSignalName, nTimeOut, pBaseHandlerInstance); + *pHandlerInstance = (IBase*)(pBaseHandlerInstance); return LIBMCENV_SUCCESS; } catch (ELibMCEnvInterfaceException & Exception) { @@ -28130,20 +28132,24 @@ LibMCEnvResult libmcenv_stateenvironment_setnextstate(LibMCEnv_StateEnvironment } } -LibMCEnvResult libmcenv_stateenvironment_logmessage(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString) +LibMCEnvResult libmcenv_stateenvironment_getunhandledsignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pSignalTypeName, LibMCEnv_SignalHandler * pHandlerInstance) { IBase* pIBaseClass = (IBase *)pStateEnvironment; try { - if (pLogString == nullptr) + if (pSignalTypeName == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); - std::string sLogString(pLogString); + if (pHandlerInstance == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sSignalTypeName(pSignalTypeName); + IBase* pBaseHandlerInstance(nullptr); IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); if (!pIStateEnvironment) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); - pIStateEnvironment->LogMessage(sLogString); + pBaseHandlerInstance = pIStateEnvironment->GetUnhandledSignal(sSignalTypeName); + *pHandlerInstance = (IBase*)(pBaseHandlerInstance); return LIBMCENV_SUCCESS; } catch (ELibMCEnvInterfaceException & Exception) { @@ -28157,19 +28163,24 @@ LibMCEnvResult libmcenv_stateenvironment_logmessage(LibMCEnv_StateEnvironment pS } } -LibMCEnvResult libmcenv_stateenvironment_logwarning(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString) +LibMCEnvResult libmcenv_stateenvironment_storesignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler pHandler) { IBase* pIBaseClass = (IBase *)pStateEnvironment; try { - if (pLogString == nullptr) + if (pName == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); - std::string sLogString(pLogString); + std::string sName(pName); + IBase* pIBaseClassHandler = (IBase *)pHandler; + ISignalHandler* pIHandler = dynamic_cast(pIBaseClassHandler); + if (!pIHandler) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDCAST); + IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); if (!pIStateEnvironment) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); - pIStateEnvironment->LogWarning(sLogString); + pIStateEnvironment->StoreSignal(sName, pIHandler); return LIBMCENV_SUCCESS; } @@ -28184,20 +28195,24 @@ LibMCEnvResult libmcenv_stateenvironment_logwarning(LibMCEnv_StateEnvironment pS } } -LibMCEnvResult libmcenv_stateenvironment_loginfo(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString) +LibMCEnvResult libmcenv_stateenvironment_retrievesignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler * pHandler) { IBase* pIBaseClass = (IBase *)pStateEnvironment; try { - if (pLogString == nullptr) + if (pName == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); - std::string sLogString(pLogString); + if (pHandler == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sName(pName); + IBase* pBaseHandler(nullptr); IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); if (!pIStateEnvironment) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); - pIStateEnvironment->LogInfo(sLogString); + pBaseHandler = pIStateEnvironment->RetrieveSignal(sName); + *pHandler = (IBase*)(pBaseHandler); return LIBMCENV_SUCCESS; } catch (ELibMCEnvInterfaceException & Exception) { @@ -28211,16 +28226,19 @@ LibMCEnvResult libmcenv_stateenvironment_loginfo(LibMCEnv_StateEnvironment pStat } } -LibMCEnvResult libmcenv_stateenvironment_sleep(LibMCEnv_StateEnvironment pStateEnvironment, LibMCEnv_uint32 nDelay) +LibMCEnvResult libmcenv_stateenvironment_clearstoredvalue(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName) { IBase* pIBaseClass = (IBase *)pStateEnvironment; try { + if (pName == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sName(pName); IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); if (!pIStateEnvironment) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); - pIStateEnvironment->Sleep(nDelay); + pIStateEnvironment->ClearStoredValue(sName); return LIBMCENV_SUCCESS; } @@ -28235,18 +28253,19 @@ LibMCEnvResult libmcenv_stateenvironment_sleep(LibMCEnv_StateEnvironment pStateE } } -LibMCEnvResult libmcenv_stateenvironment_checkfortermination(LibMCEnv_StateEnvironment pStateEnvironment, bool * pShallTerminate) +LibMCEnvResult libmcenv_stateenvironment_setnextstate(LibMCEnv_StateEnvironment pStateEnvironment, const char * pStateName) { IBase* pIBaseClass = (IBase *)pStateEnvironment; try { - if (pShallTerminate == nullptr) + if (pStateName == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sStateName(pStateName); IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); if (!pIStateEnvironment) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); - *pShallTerminate = pIStateEnvironment->CheckForTermination(); + pIStateEnvironment->SetNextState(sStateName); return LIBMCENV_SUCCESS; } @@ -28261,24 +28280,19 @@ LibMCEnvResult libmcenv_stateenvironment_checkfortermination(LibMCEnv_StateEnvir } } -LibMCEnvResult libmcenv_stateenvironment_storesignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler pHandler) +LibMCEnvResult libmcenv_stateenvironment_logmessage(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString) { IBase* pIBaseClass = (IBase *)pStateEnvironment; try { - if (pName == nullptr) + if (pLogString == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); - std::string sName(pName); - IBase* pIBaseClassHandler = (IBase *)pHandler; - ISignalHandler* pIHandler = dynamic_cast(pIBaseClassHandler); - if (!pIHandler) - throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDCAST); - + std::string sLogString(pLogString); IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); if (!pIStateEnvironment) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); - pIStateEnvironment->StoreSignal(sName, pIHandler); + pIStateEnvironment->LogMessage(sLogString); return LIBMCENV_SUCCESS; } @@ -28293,24 +28307,47 @@ LibMCEnvResult libmcenv_stateenvironment_storesignal(LibMCEnv_StateEnvironment p } } -LibMCEnvResult libmcenv_stateenvironment_retrievesignal(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName, LibMCEnv_SignalHandler * pHandler) +LibMCEnvResult libmcenv_stateenvironment_logwarning(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString) { IBase* pIBaseClass = (IBase *)pStateEnvironment; try { - if (pName == nullptr) + if (pLogString == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); - if (pHandler == nullptr) + std::string sLogString(pLogString); + IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); + if (!pIStateEnvironment) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + pIStateEnvironment->LogWarning(sLogString); + + return LIBMCENV_SUCCESS; + } + catch (ELibMCEnvInterfaceException & Exception) { + return handleLibMCEnvException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibMCEnvResult libmcenv_stateenvironment_loginfo(LibMCEnv_StateEnvironment pStateEnvironment, const char * pLogString) +{ + IBase* pIBaseClass = (IBase *)pStateEnvironment; + + try { + if (pLogString == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); - std::string sName(pName); - IBase* pBaseHandler(nullptr); + std::string sLogString(pLogString); IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); if (!pIStateEnvironment) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); - pBaseHandler = pIStateEnvironment->RetrieveSignal(sName); + pIStateEnvironment->LogInfo(sLogString); - *pHandler = (IBase*)(pBaseHandler); return LIBMCENV_SUCCESS; } catch (ELibMCEnvInterfaceException & Exception) { @@ -28324,19 +28361,42 @@ LibMCEnvResult libmcenv_stateenvironment_retrievesignal(LibMCEnv_StateEnvironmen } } -LibMCEnvResult libmcenv_stateenvironment_clearstoredvalue(LibMCEnv_StateEnvironment pStateEnvironment, const char * pName) +LibMCEnvResult libmcenv_stateenvironment_sleep(LibMCEnv_StateEnvironment pStateEnvironment, LibMCEnv_uint32 nDelay) { IBase* pIBaseClass = (IBase *)pStateEnvironment; try { - if (pName == nullptr) + IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); + if (!pIStateEnvironment) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + pIStateEnvironment->Sleep(nDelay); + + return LIBMCENV_SUCCESS; + } + catch (ELibMCEnvInterfaceException & Exception) { + return handleLibMCEnvException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibMCEnvResult libmcenv_stateenvironment_checkfortermination(LibMCEnv_StateEnvironment pStateEnvironment, bool * pShallTerminate) +{ + IBase* pIBaseClass = (IBase *)pStateEnvironment; + + try { + if (pShallTerminate == nullptr) throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); - std::string sName(pName); IStateEnvironment* pIStateEnvironment = dynamic_cast(pIBaseClass); if (!pIStateEnvironment) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); - pIStateEnvironment->ClearStoredValue(sName); + *pShallTerminate = pIStateEnvironment->CheckForTermination(); return LIBMCENV_SUCCESS; } @@ -34793,10 +34853,10 @@ LibMCEnvResult LibMCEnv::Impl::LibMCEnv_GetProcAddress (const char * pProcName, *ppProcAddress = (void*) &libmcenv_stateenvironment_getpreviousstate; if (sProcName == "libmcenv_stateenvironment_preparesignal") *ppProcAddress = (void*) &libmcenv_stateenvironment_preparesignal; - if (sProcName == "libmcenv_stateenvironment_waitforsignal") - *ppProcAddress = (void*) &libmcenv_stateenvironment_waitforsignal; - if (sProcName == "libmcenv_stateenvironment_getunhandledsignal") - *ppProcAddress = (void*) &libmcenv_stateenvironment_getunhandledsignal; + if (sProcName == "libmcenv_stateenvironment_claimsignalfromqueue") + *ppProcAddress = (void*) &libmcenv_stateenvironment_claimsignalfromqueue; + if (sProcName == "libmcenv_stateenvironment_signalqueueisempty") + *ppProcAddress = (void*) &libmcenv_stateenvironment_signalqueueisempty; if (sProcName == "libmcenv_stateenvironment_clearunhandledsignalsoftype") *ppProcAddress = (void*) &libmcenv_stateenvironment_clearunhandledsignalsoftype; if (sProcName == "libmcenv_stateenvironment_clearallunhandledsignals") @@ -34817,6 +34877,16 @@ LibMCEnvResult LibMCEnv::Impl::LibMCEnv_GetProcAddress (const char * pProcName, *ppProcAddress = (void*) &libmcenv_stateenvironment_getbuildexecution; if (sProcName == "libmcenv_stateenvironment_unloadalltoolpathes") *ppProcAddress = (void*) &libmcenv_stateenvironment_unloadalltoolpathes; + if (sProcName == "libmcenv_stateenvironment_waitforsignal") + *ppProcAddress = (void*) &libmcenv_stateenvironment_waitforsignal; + if (sProcName == "libmcenv_stateenvironment_getunhandledsignal") + *ppProcAddress = (void*) &libmcenv_stateenvironment_getunhandledsignal; + if (sProcName == "libmcenv_stateenvironment_storesignal") + *ppProcAddress = (void*) &libmcenv_stateenvironment_storesignal; + if (sProcName == "libmcenv_stateenvironment_retrievesignal") + *ppProcAddress = (void*) &libmcenv_stateenvironment_retrievesignal; + if (sProcName == "libmcenv_stateenvironment_clearstoredvalue") + *ppProcAddress = (void*) &libmcenv_stateenvironment_clearstoredvalue; if (sProcName == "libmcenv_stateenvironment_setnextstate") *ppProcAddress = (void*) &libmcenv_stateenvironment_setnextstate; if (sProcName == "libmcenv_stateenvironment_logmessage") @@ -34829,12 +34899,6 @@ LibMCEnvResult LibMCEnv::Impl::LibMCEnv_GetProcAddress (const char * pProcName, *ppProcAddress = (void*) &libmcenv_stateenvironment_sleep; if (sProcName == "libmcenv_stateenvironment_checkfortermination") *ppProcAddress = (void*) &libmcenv_stateenvironment_checkfortermination; - if (sProcName == "libmcenv_stateenvironment_storesignal") - *ppProcAddress = (void*) &libmcenv_stateenvironment_storesignal; - if (sProcName == "libmcenv_stateenvironment_retrievesignal") - *ppProcAddress = (void*) &libmcenv_stateenvironment_retrievesignal; - if (sProcName == "libmcenv_stateenvironment_clearstoredvalue") - *ppProcAddress = (void*) &libmcenv_stateenvironment_clearstoredvalue; if (sProcName == "libmcenv_stateenvironment_setstringparameter") *ppProcAddress = (void*) &libmcenv_stateenvironment_setstringparameter; if (sProcName == "libmcenv_stateenvironment_setuuidparameter") diff --git a/Implementation/Core/amc_statesignal.cpp b/Implementation/Core/amc_statesignal.cpp index 21c845d1..3a852265 100644 --- a/Implementation/Core/amc_statesignal.cpp +++ b/Implementation/Core/amc_statesignal.cpp @@ -327,6 +327,12 @@ namespace AMC { return queueIsFullNoMutex(); } + bool CStateSignalSlot::queueIsEmpty() + { + std::lock_guard lockGuard(m_Mutex); + return m_Queue.size() == 0; + } + uint32_t CStateSignalSlot::getAvailableSignalQueueEntriesInternal() { std::lock_guard lockGuard(m_Mutex); diff --git a/Implementation/Core/amc_statesignal.hpp b/Implementation/Core/amc_statesignal.hpp index bb204573..5900269b 100644 --- a/Implementation/Core/amc_statesignal.hpp +++ b/Implementation/Core/amc_statesignal.hpp @@ -204,6 +204,7 @@ namespace AMC { std::string getSignalTelemetryAcknowledgementIdentifier() const; bool queueIsFull(); + bool queueIsEmpty(); size_t clearQueueInternal(); bool eraseMessage(const std::string& sUUID); diff --git a/Implementation/Core/amc_statesignalhandler.cpp b/Implementation/Core/amc_statesignalhandler.cpp index 8d87de94..685958a9 100644 --- a/Implementation/Core/amc_statesignalhandler.cpp +++ b/Implementation/Core/amc_statesignalhandler.cpp @@ -166,6 +166,13 @@ namespace AMC { return !pSlot->queueIsFull(); } + bool CStateSignalInstance::queueIsEmpty(const std::string& sSignalName) + { + AMC::PStateSignalSlot pSlot = getSignalSlot(sSignalName); + return pSlot->queueIsEmpty(); + } + + bool CStateSignalInstance::claimSignalMessage(const std::string& sSignalName, bool bCheckForReactionTimeout, uint64_t nGlobalTimestamp, uint64_t nTimeStamp, std::string& sSignalUUID, std::string& sParameterDataJSON, bool bChangePhaseToInprocess) { diff --git a/Implementation/Core/amc_statesignalhandler.hpp b/Implementation/Core/amc_statesignalhandler.hpp index 097508d8..6c50ad46 100644 --- a/Implementation/Core/amc_statesignalhandler.hpp +++ b/Implementation/Core/amc_statesignalhandler.hpp @@ -89,6 +89,8 @@ namespace AMC { bool canTrigger(const std::string& sSignalName); + bool queueIsEmpty(const std::string& sSignalName); + bool hasSignalDefinition(const std::string& sSignalName); bool claimSignalMessage(const std::string& sSignalName, bool bCheckForReactionTimeout, uint64_t nGlobalTimestamp, uint64_t nTimeStamp, std::string& sSignalUUID, std::string& sParameterDataJSON, bool bChangePhaseToInprocess); diff --git a/Implementation/LibMCEnv/libmcenv_stateenvironment.cpp b/Implementation/LibMCEnv/libmcenv_stateenvironment.cpp index 6a593810..5c49f0df 100644 --- a/Implementation/LibMCEnv/libmcenv_stateenvironment.cpp +++ b/Implementation/LibMCEnv/libmcenv_stateenvironment.cpp @@ -172,6 +172,29 @@ ISignalHandler* CStateEnvironment::GetUnhandledSignal(const std::string& sSignal return nullptr; } +ISignalHandler* CStateEnvironment::ClaimSignalFromQueue(const std::string& sSignalTypeName) +{ + auto pChronoInstance = m_pSystemState->getGlobalChronoInstance(); + auto pSignalInstance = m_pSystemState->stateSignalHandler()->getInstance(m_sInstanceName); + + std::string sUnhandledSignalUUID; + std::string sParameterDataJSON; + uint64_t nCurrentTime = pChronoInstance->getElapsedMicroseconds(); + bool bHasSignal = pSignalInstance->claimSignalMessage(sSignalTypeName, true, nCurrentTime, nCurrentTime, sUnhandledSignalUUID, sParameterDataJSON, true); + if (bHasSignal) { + return new CSignalHandler(m_pSystemState->getStateSignalHandlerInstance(), m_sInstanceName, sSignalTypeName, sUnhandledSignalUUID, sParameterDataJSON, pChronoInstance); + } + + return nullptr; +} + +bool CStateEnvironment::SignalQueueIsEmpty(const std::string& sSignalTypeName) +{ + auto pSignalInstance = m_pSystemState->stateSignalHandler()->getInstance(m_sInstanceName); + return pSignalInstance->queueIsEmpty(sSignalTypeName); +} + + void CStateEnvironment::ClearAllUnhandledSignals() { auto pChrono = m_pSystemState->globalChrono(); diff --git a/Implementation/LibMCEnv/libmcenv_stateenvironment.hpp b/Implementation/LibMCEnv/libmcenv_stateenvironment.hpp index 1f623740..718edaa5 100644 --- a/Implementation/LibMCEnv/libmcenv_stateenvironment.hpp +++ b/Implementation/LibMCEnv/libmcenv_stateenvironment.hpp @@ -85,6 +85,10 @@ class CStateEnvironment : public virtual IStateEnvironment, public virtual CBase ISignalHandler* GetUnhandledSignal(const std::string& sSignalTypeName) override; + ISignalHandler* ClaimSignalFromQueue(const std::string& sSignalTypeName) override; + + bool SignalQueueIsEmpty(const std::string& sSignalTypeName) override; + ISignalHandler* GetUnhandledSignalByUUID(const std::string& sUUID, const bool bMustExist) override; void ClearUnhandledSignalsOfType(const std::string& sSignalTypeName) override; From 4a95658d0e474d5e3a1346820cc0d86ab8206055 Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Fri, 16 Jan 2026 23:36:54 +0000 Subject: [PATCH 08/19] Extended Unit tests --- .../Core/amc_discretefielddata2d.cpp | 6 +- Implementation/UnitTest/amc_unittests.cpp | 6 + .../UnitTest/amc_unittests_alerts.hpp | 182 +++++++ .../UnitTest/amc_unittests_dataseries.hpp | 142 ++++++ .../amc_unittests_discretefielddata2d.hpp | 480 ++++++++++++++++++ 5 files changed, 813 insertions(+), 3 deletions(-) create mode 100644 Implementation/UnitTest/amc_unittests_alerts.hpp create mode 100644 Implementation/UnitTest/amc_unittests_dataseries.hpp create mode 100644 Implementation/UnitTest/amc_unittests_discretefielddata2d.hpp diff --git a/Implementation/Core/amc_discretefielddata2d.cpp b/Implementation/Core/amc_discretefielddata2d.cpp index de741c04..7cfc2553 100644 --- a/Implementation/Core/amc_discretefielddata2d.cpp +++ b/Implementation/Core/amc_discretefielddata2d.cpp @@ -133,9 +133,9 @@ CDiscreteFieldData2DInstance::CDiscreteFieldData2DInstance(size_t nPixelCountX, throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDDPIVALUE); if (dDPIY <= 0.0) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDDPIVALUE); - if (abs (dOriginX) > DISCRETEFIELD_MAXORIGINCOORDINATE) + if (std::abs(dOriginX) > DISCRETEFIELD_MAXORIGINCOORDINATE) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_ORIGINOUTOFRANGE); - if (abs(dOriginY) > DISCRETEFIELD_MAXORIGINCOORDINATE) + if (std::abs(dOriginY) > DISCRETEFIELD_MAXORIGINCOORDINATE) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_ORIGINOUTOFRANGE); m_Data = std::make_unique> (); @@ -400,7 +400,7 @@ PDiscreteFieldData2DInstance CDiscreteFieldData2DInstance::ScaleFieldUp(const ui pSource++; for (uint32_t dY = 0; dY < nFactorY; dY++) { - double* pTarget = &pNewField->m_Data->at(((size_t)nY * nFactorY + dY) * nNewPixelCountX); + double* pTarget = &pNewField->m_Data->at(((size_t)nY * nFactorY + dY) * nNewPixelCountX + (size_t)nX * nFactorX); for (uint32_t dX = 0; dX < nFactorX; dX++) { *pTarget = dValue; pTarget++; diff --git a/Implementation/UnitTest/amc_unittests.cpp b/Implementation/UnitTest/amc_unittests.cpp index 247cd25b..a84a1af2 100644 --- a/Implementation/UnitTest/amc_unittests.cpp +++ b/Implementation/UnitTest/amc_unittests.cpp @@ -47,6 +47,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "amc_unittests_resourcepackage.hpp" #include "amc_unittests_jpeg.hpp" #include "amc_unittests_streams.hpp" +#include "amc_unittests_alerts.hpp" +#include "amc_unittests_dataseries.hpp" +#include "amc_unittests_discretefielddata2d.hpp" using namespace AMCUnitTest; @@ -72,4 +75,7 @@ CUnitTests::CUnitTests (PUnitTestIO pIO) registerTestGroup(std::make_shared ()); registerTestGroup(std::make_shared ()); registerTestGroup(std::make_shared ()); + registerTestGroup(std::make_shared ()); + registerTestGroup(std::make_shared ()); + registerTestGroup(std::make_shared ()); } diff --git a/Implementation/UnitTest/amc_unittests_alerts.hpp b/Implementation/UnitTest/amc_unittests_alerts.hpp new file mode 100644 index 00000000..74a04e68 --- /dev/null +++ b/Implementation/UnitTest/amc_unittests_alerts.hpp @@ -0,0 +1,182 @@ +/*++ + +Copyright (C) 2025 Autodesk Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Autodesk Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AUTODESK INC. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef __AMCTEST_UNITTEST_ALERTS +#define __AMCTEST_UNITTEST_ALERTS + + +#include "amc_unittests.hpp" +#include "amc_alerthandler.hpp" +#include "amc_languagedefinition.hpp" + + +namespace AMCUnitTest { + + class CUnitTestGroup_Alerts : public CUnitTestGroup { + public: + + std::string getTestGroupName() override { + return "Alerts"; + } + + void registerTests() override { + registerTest("AlertDefinitionBasics", "Alert definition properties and translations", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_Alerts::testAlertDefinitionBasics, this)); + registerTest("AlertLevelConversions", "Alert level string conversions", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_Alerts::testAlertLevelConversions, this)); + registerTest("AlertHandlerDefinitions", "Alert handler add/find/validate definitions", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_Alerts::testAlertHandlerDefinitions, this)); + } + + void initializeTests() override { + } + + private: + + void testAlertDefinitionBasics() + { + AMC::CLanguageString description("test_desc", "Custom"); + AMC::CAlertDefinition definition("AlertOne", LibMCData::eAlertLevel::Warning, description, true); + assertTrue(definition.getIdentifier() == "AlertOne"); + assertTrue(definition.getAlertLevel() == LibMCData::eAlertLevel::Warning); + assertTrue(definition.needsAcknowledgement()); + assertTrue(definition.getDescription().getStringIdentifier() == "test_desc"); + assertTrue(definition.getDescription().getCustomValue() == "Custom"); + + auto pLanguage = std::make_shared("en", nullptr); + pLanguage->addTranslation("test_desc", "Translated"); + assertTrue(definition.getTranslatedDescription(pLanguage.get()) == "Translated"); + + AMC::CLanguageString customOnly("", "Fallback"); + AMC::CAlertDefinition customDefinition("AlertTwo", LibMCData::eAlertLevel::Message, customOnly, false); + assertFalse(customDefinition.needsAcknowledgement()); + assertTrue(customDefinition.getTranslatedDescription(pLanguage.get()) == "Fallback"); + + definition.setAckPermissionIdentifier("ack_permission"); + assertTrue(definition.getAckPermissionIdentifier() == "ack_permission"); + } + + void testAlertLevelConversions() + { + assertTrue(AMC::CAlertDefinition::stringToAlertLevel("fatalerror", true) == LibMCData::eAlertLevel::FatalError); + assertTrue(AMC::CAlertDefinition::stringToAlertLevel("criticalerror", true) == LibMCData::eAlertLevel::CriticalError); + assertTrue(AMC::CAlertDefinition::stringToAlertLevel("warning", true) == LibMCData::eAlertLevel::Warning); + assertTrue(AMC::CAlertDefinition::stringToAlertLevel("message", true) == LibMCData::eAlertLevel::Message); + assertTrue(AMC::CAlertDefinition::stringToAlertLevel("unknown", false) == LibMCData::eAlertLevel::Unknown); + + bool thrown = false; + try { + AMC::CAlertDefinition::stringToAlertLevel("unknown", true); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected stringToAlertLevel to throw on unknown input"); + + assertTrue(AMC::CAlertDefinition::alertLevelToString(LibMCData::eAlertLevel::FatalError) == "fatalerror"); + assertTrue(AMC::CAlertDefinition::alertLevelToString(LibMCData::eAlertLevel::CriticalError) == "criticalerror"); + assertTrue(AMC::CAlertDefinition::alertLevelToString(LibMCData::eAlertLevel::Warning) == "warning"); + assertTrue(AMC::CAlertDefinition::alertLevelToString(LibMCData::eAlertLevel::Message) == "message"); + assertTrue(AMC::CAlertDefinition::alertLevelToString(LibMCData::eAlertLevel::Unknown) == "unknown"); + } + + void testAlertHandlerDefinitions() + { + AMC::CAlertHandler handler; + AMC::CLanguageString description("desc", "Desc"); + + assertFalse(handler.hasDefinition("AlertOne")); + auto pDefinition = handler.addDefinition("AlertOne", LibMCData::eAlertLevel::Warning, description, true); + assertTrue(handler.hasDefinition("AlertOne")); + assertTrue(pDefinition.get() != nullptr); + + auto pFound = handler.findDefinition("AlertOne", true); + assertTrue(pFound.get() == pDefinition.get()); + assertTrue(pFound->needsAcknowledgement()); + + auto pMissing = handler.findDefinition("Missing", false); + assertTrue(pMissing.get() == nullptr); + + bool thrown = false; + try { + handler.findDefinition("Missing", true); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected findDefinition to throw on missing definition"); + + thrown = false; + try { + handler.addDefinition("AlertOne", LibMCData::eAlertLevel::Warning, description, false); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected addDefinition to throw on duplicate identifier"); + + thrown = false; + try { + handler.addDefinition("", LibMCData::eAlertLevel::Warning, description, false); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected addDefinition to throw on empty identifier"); + + thrown = false; + try { + handler.addDefinition("bad-char", LibMCData::eAlertLevel::Warning, description, false); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected addDefinition to throw on invalid identifier"); + + thrown = false; + try { + handler.hasDefinition(""); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected hasDefinition to throw on empty identifier"); + + thrown = false; + try { + handler.hasDefinition("bad-char"); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected hasDefinition to throw on invalid identifier"); + } + }; + +} + +#endif // __AMCTEST_UNITTEST_ALERTS diff --git a/Implementation/UnitTest/amc_unittests_dataseries.hpp b/Implementation/UnitTest/amc_unittests_dataseries.hpp new file mode 100644 index 00000000..221d03f0 --- /dev/null +++ b/Implementation/UnitTest/amc_unittests_dataseries.hpp @@ -0,0 +1,142 @@ +/*++ + +Copyright (C) 2025 Autodesk Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Autodesk Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AUTODESK INC. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef __AMCTEST_UNITTEST_DATASERIES +#define __AMCTEST_UNITTEST_DATASERIES + + +#include "amc_unittests.hpp" +#include "amc_dataseries.hpp" +#include "amc_dataserieshandler.hpp" +#include "common_utils.hpp" + + +namespace AMCUnitTest { + + class CUnitTestGroup_DataSeries : public CUnitTestGroup { + public: + + std::string getTestGroupName() override { + return "DataSeries"; + } + + void registerTests() override { + registerTest("DataSeriesBasics", "Data series properties and entry operations", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_DataSeries::testDataSeriesBasics, this)); + registerTest("DataSeriesHandlerBasics", "Data series handler create/find/memory operations", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_DataSeries::testDataSeriesHandlerBasics, this)); + } + + void initializeTests() override { + } + + private: + + void testDataSeriesBasics() + { + std::string rawUUID = " {A1B2C3D4-1111-2222-3333-444455556666} "; + AMC::CDataSeries series(rawUUID, "SeriesOne"); + assertTrue(series.getUUID() == "a1b2c3d4-1111-2222-3333-444455556666"); + assertTrue(series.getName() == "SeriesOne"); + assertTrue(series.getVersion() == 1); + assertTrue(series.isEmpty()); + assertTrue(series.getEntryCount() == 0); + + bool thrown = false; + try { + series.getMinimum(); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected getMinimum to throw on empty data series"); + + thrown = false; + try { + series.getMaximum(); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected getMaximum to throw on empty data series"); + + auto& entries = series.getEntries(); + entries.push_back({ 10, 1.0 }); + entries.push_back({ 20, 2.0 }); + entries.push_back({ 30, 3.0 }); + + assertFalse(series.isEmpty()); + assertTrue(series.getEntryCount() == 3); + assertTrue(series.getMinimum() == 10); + assertTrue(series.getMaximum() == 30); + assertTrue(series.getMemoryUsageInBytes() >= series.getEntryCount() * sizeof(AMC::sDataSeriesEntry)); + + series.increaseVersion(); + assertTrue(series.getVersion() == 2); + + series.clearData(); + assertTrue(series.isEmpty()); + assertTrue(series.getEntryCount() == 0); + } + + void testDataSeriesHandlerBasics() + { + AMC::CDataSeriesHandler handler; + std::string missingUUID = AMCCommon::CUtils::createUUID(); + + assertFalse(handler.hasDataSeries(missingUUID)); + assertTrue(handler.findDataSeries(missingUUID, false).get() == nullptr); + + bool thrown = false; + try { + handler.findDataSeries(missingUUID, true); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected findDataSeries to throw on missing entry"); + + auto pSeries = handler.createDataSeries("SeriesTwo"); + assertTrue(pSeries.get() != nullptr); + + std::string seriesUUID = pSeries->getUUID(); + assertTrue(handler.hasDataSeries(seriesUUID)); + assertTrue(handler.findDataSeries(seriesUUID, true).get() == pSeries.get()); + + pSeries->getEntries().push_back({ 100, 1.0 }); + uint64_t usage = handler.getMemoryUsageInBytes(); + assertTrue(usage >= pSeries->getMemoryUsageInBytes()); + + handler.unloadDataSeries(seriesUUID); + handler.unloadAllEntities(); + } + }; + +} + +#endif // __AMCTEST_UNITTEST_DATASERIES diff --git a/Implementation/UnitTest/amc_unittests_discretefielddata2d.hpp b/Implementation/UnitTest/amc_unittests_discretefielddata2d.hpp new file mode 100644 index 00000000..b2ea94d1 --- /dev/null +++ b/Implementation/UnitTest/amc_unittests_discretefielddata2d.hpp @@ -0,0 +1,480 @@ +/*++ + +Copyright (C) 2025 Autodesk Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Autodesk Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AUTODESK INC. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef __AMCTEST_UNITTEST_DISCRETEFIELDDATA2D +#define __AMCTEST_UNITTEST_DISCRETEFIELDDATA2D + + +#include "amc_unittests.hpp" +#include "amc_discretefielddata2d.hpp" + +#include + + +namespace AMCUnitTest { + + class CUnitTestGroup_DiscreteFieldData2D : public CUnitTestGroup { + public: + + std::string getTestGroupName() override { + return "DiscreteFieldData2D"; + } + + void registerTests() override { + registerTest("ConstructionAndBasics", "Discrete field construction and basic properties", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_DiscreteFieldData2D::testConstructionAndBasics, this)); + registerTest("ResizeClampAndPixels", "Discrete field resizing, clamping, and pixel access", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_DiscreteFieldData2D::testResizeClampAndPixels, this)); + registerTest("ScalingAndTransform", "Discrete field scaling and transform operations", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_DiscreteFieldData2D::testScalingAndTransform, this)); + registerTest("DuplicateAndAdd", "Discrete field duplication and add operations", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_DiscreteFieldData2D::testDuplicateAndAdd, this)); + registerTest("RenderAndSampling", "Discrete field rendering and sampling operations", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_DiscreteFieldData2D::testRenderAndSampling, this)); + registerTest("SerializationAndLoad", "Discrete field serialization and raw pixel loading", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_DiscreteFieldData2D::testSerializationAndLoad, this)); + registerTest("NotImplementedPaths", "Discrete field not implemented paths throw", eUnitTestCategory::utMandatoryPass, std::bind(&CUnitTestGroup_DiscreteFieldData2D::testNotImplementedPaths, this)); + } + + void initializeTests() override { + } + + private: + + bool nearlyEqual(const double a, const double b, const double epsilon = 1.0e-9) + { + return std::abs(a - b) < epsilon; + } + + void testConstructionAndBasics() + { + bool thrown = false; + try { + AMC::CDiscreteFieldData2DInstance invalidField(0, 1, 1.0, 1.0, 0.0, 0.0, 0.0, true); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected constructor to reject zero pixel count"); + + thrown = false; + try { + AMC::CDiscreteFieldData2DInstance invalidField(1, 1, 0.0, 1.0, 0.0, 0.0, 0.0, true); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected constructor to reject invalid DPI"); + + thrown = false; + try { + AMC::CDiscreteFieldData2DInstance invalidField(1, 1, 1.0, 1.0, 1.0e10, 0.0, 0.0, true); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected constructor to reject origin out of range"); + + AMC::CDiscreteFieldData2DInstance field(2, 3, 25.4, 25.4, 1.0, 2.0, 7.0, true); + double dpiX = 0.0, dpiY = 0.0; + field.GetDPI(dpiX, dpiY); + assertTrue(nearlyEqual(dpiX, 25.4)); + assertTrue(nearlyEqual(dpiY, 25.4)); + + double originX = 0.0, originY = 0.0; + field.GetOriginInMM(originX, originY); + assertTrue(nearlyEqual(originX, 1.0)); + assertTrue(nearlyEqual(originY, 2.0)); + + double sizeX = 0.0, sizeY = 0.0; + field.GetSizeInMM(sizeX, sizeY); + assertTrue(nearlyEqual(sizeX, 2.0)); + assertTrue(nearlyEqual(sizeY, 3.0)); + + uint32_t sizeXPix = 0, sizeYPix = 0; + field.GetSizeInPixels(sizeXPix, sizeYPix); + assertTrue(sizeXPix == 2); + assertTrue(sizeYPix == 3); + + assertTrue(nearlyEqual(field.GetPixel(0, 0), 7.0)); + + field.SetDPI(50.0, 100.0); + field.GetDPI(dpiX, dpiY); + assertTrue(nearlyEqual(dpiX, 50.0)); + assertTrue(nearlyEqual(dpiY, 100.0)); + + field.SetOriginInMM(-1.0, -2.0); + field.GetOriginInMM(originX, originY); + assertTrue(nearlyEqual(originX, -1.0)); + assertTrue(nearlyEqual(originY, -2.0)); + + thrown = false; + try { + field.SetDPI(0.0, 1.0); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected SetDPI to reject invalid values"); + } + + void testResizeClampAndPixels() + { + AMC::CDiscreteFieldData2DInstance field(2, 2, 25.4, 25.4, 0.0, 0.0, 0.0, true); + field.SetPixel(0, 0, 1.0); + field.SetPixel(1, 0, 2.0); + field.SetPixel(0, 1, 3.0); + field.SetPixel(1, 1, 4.0); + + assertTrue(nearlyEqual(field.GetPixel(1, 1), 4.0)); + + bool thrown = false; + try { + field.GetPixel(2, 0); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected GetPixel to reject invalid X coordinate"); + + thrown = false; + try { + field.SetPixel(0, 3, 1.0); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected SetPixel to reject invalid Y coordinate"); + + thrown = false; + try { + field.Clamp(1.0, 1.0); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected Clamp to reject invalid range"); + + field.Clamp(0.0, 3.0); + assertTrue(nearlyEqual(field.GetPixel(1, 1), 3.0)); + + uint32_t newX = 3; + uint32_t newY = 1; + field.ResizeField(newX, newY, 5.0); + uint32_t sizeX = 0, sizeY = 0; + field.GetSizeInPixels(sizeX, sizeY); + assertTrue(sizeX == 3); + assertTrue(sizeY == 1); + assertTrue(nearlyEqual(field.GetPixel(0, 0), 1.0)); + assertTrue(nearlyEqual(field.GetPixel(1, 0), 2.0)); + assertTrue(nearlyEqual(field.GetPixel(2, 0), 5.0)); + } + + void testScalingAndTransform() + { + AMC::CDiscreteFieldData2DInstance field(2, 2, 25.4, 25.4, 0.0, 0.0, 0.0, true); + field.SetPixel(0, 0, 1.0); + field.SetPixel(1, 0, 2.0); + field.SetPixel(0, 1, 3.0); + field.SetPixel(1, 1, 4.0); + + bool thrown = false; + try { + field.ScaleFieldDown(0, 1); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected ScaleFieldDown to reject invalid factors"); + + auto scaledDown = field.ScaleFieldDown(2, 2); + uint32_t sizeX = 0, sizeY = 0; + scaledDown->GetSizeInPixels(sizeX, sizeY); + assertTrue(sizeX == 1); + assertTrue(sizeY == 1); + assertTrue(nearlyEqual(scaledDown->GetPixel(0, 0), 2.5)); + + thrown = false; + try { + field.ScaleFieldUp(0, 1); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected ScaleFieldUp to reject invalid factors"); + + auto scaledUp = field.ScaleFieldUp(2, 2); + scaledUp->GetSizeInPixels(sizeX, sizeY); + assertTrue(sizeX == 4); + assertTrue(sizeY == 4); + assertTrue(nearlyEqual(scaledUp->GetPixel(0, 0), 1.0)); + assertTrue(nearlyEqual(scaledUp->GetPixel(1, 0), 1.0)); + assertTrue(nearlyEqual(scaledUp->GetPixel(2, 0), 2.0)); + assertTrue(nearlyEqual(scaledUp->GetPixel(3, 0), 2.0)); + assertTrue(nearlyEqual(scaledUp->GetPixel(0, 1), 1.0)); + assertTrue(nearlyEqual(scaledUp->GetPixel(2, 1), 2.0)); + assertTrue(nearlyEqual(scaledUp->GetPixel(0, 2), 3.0)); + assertTrue(nearlyEqual(scaledUp->GetPixel(2, 2), 4.0)); + + field.TransformField(2.0, 1.0); + assertTrue(nearlyEqual(field.GetPixel(0, 0), 3.0)); + assertTrue(nearlyEqual(field.GetPixel(1, 1), 9.0)); + } + + void testDuplicateAndAdd() + { + AMC::CDiscreteFieldData2DInstance field(2, 2, 25.4, 25.4, 0.0, 0.0, 0.0, true); + field.SetPixel(0, 0, 1.0); + field.SetPixel(1, 0, 2.0); + field.SetPixel(0, 1, 3.0); + field.SetPixel(1, 1, 4.0); + + auto duplicate = field.Duplicate(); + assertTrue(duplicate.get() != nullptr); + assertTrue(duplicate.get() != &field); + assertTrue(nearlyEqual(duplicate->GetPixel(1, 1), 4.0)); + + bool thrown = false; + try { + field.AddField(nullptr, 1.0, 0.0); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected AddField to reject null input"); + + AMC::CDiscreteFieldData2DInstance other(3, 2, 25.4, 25.4, 0.0, 0.0, 0.0, true); + thrown = false; + try { + field.AddField(&other, 1.0, 0.0); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected AddField to reject mismatched sizes"); + + AMC::CDiscreteFieldData2DInstance same(2, 2, 25.4, 25.4, 0.0, 0.0, 0.0, true); + same.SetPixel(0, 0, 10.0); + field.AddField(&same, 0.5, 1.0); + assertTrue(nearlyEqual(field.GetPixel(0, 0), 1.0 + 10.0 * 0.5 + 1.0)); + } + + void testRenderAndSampling() + { + AMC::CDiscreteFieldData2DInstance field(3, 1, 25.4, 25.4, 0.0, 0.0, 0.0, true); + field.SetPixel(0, 0, 0.0); + field.SetPixel(1, 0, 0.5); + field.SetPixel(2, 0, 1.0); + + bool thrown = false; + try { + field.renderRGBImage(nullptr, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected renderRGBImage to reject null output buffer"); + + std::vector pixels; + field.renderRGBImage(&pixels, 0.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0); + assertTrue(pixels.size() == 9); + assertTrue(pixels.at(0) == 0); + assertTrue(pixels.at(1) == 0); + assertTrue(pixels.at(2) == 0); + assertTrue(pixels.at(3) == 128); + assertTrue(pixels.at(4) == 128); + assertTrue(pixels.at(5) == 128); + assertTrue(pixels.at(6) == 255); + assertTrue(pixels.at(7) == 255); + assertTrue(pixels.at(8) == 255); + + thrown = false; + try { + field.renderRGBImage(&pixels, 1.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.5, 0.5, 0.0, 1.0, 1.0, 1.0); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected renderRGBImage to reject invalid color range"); + + AMC::CDiscreteFieldData2DInstance samplingField(2, 2, 25.4, 25.4, 0.0, 0.0, 0.0, true); + LibMCEnv::sFieldData2DPoint points[3]; + points[0].m_Coordinates[0] = 0.2; + points[0].m_Coordinates[1] = 0.2; + points[0].m_Value = 2.0; + points[1].m_Coordinates[0] = 0.8; + points[1].m_Coordinates[1] = 0.8; + points[1].m_Value = 4.0; + points[2].m_Coordinates[0] = 1.2; + points[2].m_Coordinates[1] = 0.2; + points[2].m_Value = 6.0; + samplingField.renderAveragePointValues_FloorSampling(-1.0, 3, points); + assertTrue(nearlyEqual(samplingField.GetPixel(0, 0), 3.0)); + assertTrue(nearlyEqual(samplingField.GetPixel(1, 0), 6.0)); + assertTrue(nearlyEqual(samplingField.GetPixel(0, 1), -1.0)); + assertTrue(nearlyEqual(samplingField.GetPixel(1, 1), -1.0)); + + samplingField.SetPixel(0, 0, 9.0); + samplingField.renderAveragePointValues_FloorSampling(7.0, 0, nullptr); + assertTrue(nearlyEqual(samplingField.GetPixel(0, 0), 7.0)); + + thrown = false; + try { + samplingField.renderAveragePointValues_FloorSampling(0.0, 1, nullptr); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected renderAveragePointValues_FloorSampling to reject null input"); + } + + void testSerializationAndLoad() + { + AMC::CDiscreteFieldData2DInstance field(2, 2, 10.0, 20.0, 1.0, 2.0, 0.0, true); + field.SetPixel(0, 0, 1.0); + field.SetPixel(1, 0, 2.0); + field.SetPixel(0, 1, 3.0); + field.SetPixel(1, 1, 4.0); + + std::vector buffer; + field.saveToBuffer(buffer); + auto loaded = AMC::CDiscreteFieldData2DInstance::createFromBuffer(buffer); + uint32_t sizeX = 0, sizeY = 0; + loaded->GetSizeInPixels(sizeX, sizeY); + assertTrue(sizeX == 2); + assertTrue(sizeY == 2); + + double dpiX = 0.0, dpiY = 0.0; + loaded->GetDPI(dpiX, dpiY); + assertTrue(nearlyEqual(dpiX, 10.0)); + assertTrue(nearlyEqual(dpiY, 20.0)); + + double originX = 0.0, originY = 0.0; + loaded->GetOriginInMM(originX, originY); + assertTrue(nearlyEqual(originX, 1.0)); + assertTrue(nearlyEqual(originY, 2.0)); + assertTrue(nearlyEqual(loaded->GetPixel(1, 1), 4.0)); + + bool thrown = false; + try { + std::vector tiny; + AMC::CDiscreteFieldData2DInstance::createFromBuffer(tiny); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected createFromBuffer to reject empty buffer"); + + thrown = false; + try { + std::vector corrupted = buffer; + if (corrupted.size() > 0) + corrupted[0] = 0; + AMC::CDiscreteFieldData2DInstance::createFromBuffer(corrupted); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected createFromBuffer to reject invalid signature"); + + AMC::CDiscreteFieldData2DInstance pixelField(2, 2, 25.4, 25.4, 0.0, 0.0, 0.0, true); + std::vector grayData = { 0, 255, 128, 64 }; + pixelField.loadFromRawPixelData(grayData, LibMCEnv::eImagePixelFormat::GreyScale8bit, 0.0, 1.0); + assertTrue(nearlyEqual(pixelField.GetPixel(0, 0), 0.0)); + assertTrue(nearlyEqual(pixelField.GetPixel(1, 0), 1.0)); + + std::vector rgbData = { + 0, 0, 0, + 255, 255, 255, + 255, 0, 0, + 0, 255, 0 + }; + pixelField.loadFromRawPixelData(rgbData, LibMCEnv::eImagePixelFormat::RGB24bit, 0.0, 1.0); + assertTrue(nearlyEqual(pixelField.GetPixel(0, 0), 0.0)); + assertTrue(nearlyEqual(pixelField.GetPixel(1, 0), 1.0)); + + std::vector rgbaData = { + 0, 0, 0, 255, + 255, 255, 255, 255, + 255, 0, 0, 255, + 0, 255, 0, 255 + }; + pixelField.loadFromRawPixelData(rgbaData, LibMCEnv::eImagePixelFormat::RGBA32bit, 0.0, 1.0); + assertTrue(nearlyEqual(pixelField.GetPixel(0, 0), 0.0)); + assertTrue(nearlyEqual(pixelField.GetPixel(1, 0), 1.0)); + + thrown = false; + try { + pixelField.loadFromRawPixelData(grayData, LibMCEnv::eImagePixelFormat::RGB24bit, 0.0, 1.0); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected loadFromRawPixelData to reject mismatched buffer size"); + + thrown = false; + try { + pixelField.loadFromRawPixelData(grayData, LibMCEnv::eImagePixelFormat::Unknown, 0.0, 1.0); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected loadFromRawPixelData to reject unknown pixel format"); + } + + void testNotImplementedPaths() + { + AMC::CDiscreteFieldData2DInstance field(2, 2, 25.4, 25.4, 0.0, 0.0, 0.0, true); + bool thrown = false; + try { + field.GetPixelRange(0, 0, 1, 1, 0, nullptr, nullptr); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected GetPixelRange to throw not implemented"); + + thrown = false; + try { + field.SetPixelRange(0, 0, 1, 1, 0, nullptr); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected SetPixelRange to throw not implemented"); + + thrown = false; + try { + field.DiscretizeWithMapping(0, nullptr, 0, nullptr); + } + catch (...) { + thrown = true; + } + assertTrue(thrown, "Expected DiscretizeWithMapping to throw not implemented"); + } + }; + +} + +#endif // __AMCTEST_UNITTEST_DISCRETEFIELDDATA2D From 27d3f1d8c16799e3a06fe38778ea73f303613dd5 Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Sat, 17 Jan 2026 01:03:10 +0100 Subject: [PATCH 09/19] Added Telemetry archiving --- ACT/LibMC.xml | 8 +- .../HeadersCore/CppDynamic/libmc_dynamic.hpp | 8 + .../HeadersCore/CppDynamic/libmc_types.hpp | 8 + Framework/InterfacesCore/libmc_types.hpp | 8 + Implementation/Core/amc_telemetry.cpp | 208 ++++++++++++++---- Implementation/Core/amc_telemetry.hpp | 56 ++--- Implementation/LibMC/libmc_mccontext.cpp | 7 + 7 files changed, 231 insertions(+), 72 deletions(-) diff --git a/ACT/LibMC.xml b/ACT/LibMC.xml index 1cb544c9..dd83e703 100644 --- a/ACT/LibMC.xml +++ b/ACT/LibMC.xml @@ -723,8 +723,14 @@ + + + + - + + + diff --git a/Framework/HeadersCore/CppDynamic/libmc_dynamic.hpp b/Framework/HeadersCore/CppDynamic/libmc_dynamic.hpp index e7e2fac8..f5278f44 100644 --- a/Framework/HeadersCore/CppDynamic/libmc_dynamic.hpp +++ b/Framework/HeadersCore/CppDynamic/libmc_dynamic.hpp @@ -792,6 +792,10 @@ class ELibMCException : public std::exception { case LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION: return "UNFINISHEDTELEMETRYMARKERSHAVENODURATION"; case LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED: return "TELEMETRYMARKERALREADYREGISTERED"; case LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND: return "TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND"; + case LIBMC_ERROR_TELEMETRYCHUNKINDEXOUTOFRANGE: return "TELEMETRYCHUNKINDEXOUTOFRANGE"; + case LIBMC_ERROR_TELEMETRYCHUNKIDMISMATCH: return "TELEMETRYCHUNKIDMISMATCH"; + case LIBMC_ERROR_TELEMETRYCHUNKISREADONLY: return "TELEMETRYCHUNKISREADONLY"; + case LIBMC_ERROR_TELEMETRYCHUNKSCANONLYBEARCHIVEDIFREADONLY: return "TELEMETRYCHUNKSCANONLYBEARCHIVEDIFREADONLY"; } return "UNKNOWN"; } @@ -1418,6 +1422,10 @@ class ELibMCException : public std::exception { case LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION: return "Unfinished telemetry marker have no duration."; case LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED: return "Telemetry Marker has been already registered."; case LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND: return "Telemetry Chunk Start timestamp is after end timestamp."; + case LIBMC_ERROR_TELEMETRYCHUNKINDEXOUTOFRANGE: return "Telemetry Chunk index out of range."; + case LIBMC_ERROR_TELEMETRYCHUNKIDMISMATCH: return "Telemetry Chunk ID mismatch."; + case LIBMC_ERROR_TELEMETRYCHUNKISREADONLY: return "Telemetry Chunk is readonly."; + case LIBMC_ERROR_TELEMETRYCHUNKSCANONLYBEARCHIVEDIFREADONLY: return "Telemetry Chunks can only be archived if readonly."; } return "unknown error"; } diff --git a/Framework/HeadersCore/CppDynamic/libmc_types.hpp b/Framework/HeadersCore/CppDynamic/libmc_types.hpp index 0edaceb9..dad52a6d 100644 --- a/Framework/HeadersCore/CppDynamic/libmc_types.hpp +++ b/Framework/HeadersCore/CppDynamic/libmc_types.hpp @@ -714,6 +714,10 @@ typedef void * LibMC_pvoid; #define LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION 698 /** Unfinished telemetry marker have no duration. */ #define LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED 699 /** Telemetry Marker has been already registered. */ #define LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND 700 /** Telemetry Chunk Start timestamp is after end timestamp. */ +#define LIBMC_ERROR_TELEMETRYCHUNKINDEXOUTOFRANGE 701 /** Telemetry Chunk index out of range. */ +#define LIBMC_ERROR_TELEMETRYCHUNKIDMISMATCH 702 /** Telemetry Chunk ID mismatch. */ +#define LIBMC_ERROR_TELEMETRYCHUNKISREADONLY 703 /** Telemetry Chunk is readonly. */ +#define LIBMC_ERROR_TELEMETRYCHUNKSCANONLYBEARCHIVEDIFREADONLY 704 /** Telemetry Chunks can only be archived if readonly. */ /************************************************************************************************************************* Error strings for LibMC @@ -1340,6 +1344,10 @@ inline const char * LIBMC_GETERRORSTRING (LibMCResult nErrorCode) { case LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION: return "Unfinished telemetry marker have no duration."; case LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED: return "Telemetry Marker has been already registered."; case LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND: return "Telemetry Chunk Start timestamp is after end timestamp."; + case LIBMC_ERROR_TELEMETRYCHUNKINDEXOUTOFRANGE: return "Telemetry Chunk index out of range."; + case LIBMC_ERROR_TELEMETRYCHUNKIDMISMATCH: return "Telemetry Chunk ID mismatch."; + case LIBMC_ERROR_TELEMETRYCHUNKISREADONLY: return "Telemetry Chunk is readonly."; + case LIBMC_ERROR_TELEMETRYCHUNKSCANONLYBEARCHIVEDIFREADONLY: return "Telemetry Chunks can only be archived if readonly."; default: return "unknown error"; } } diff --git a/Framework/InterfacesCore/libmc_types.hpp b/Framework/InterfacesCore/libmc_types.hpp index 0edaceb9..dad52a6d 100644 --- a/Framework/InterfacesCore/libmc_types.hpp +++ b/Framework/InterfacesCore/libmc_types.hpp @@ -714,6 +714,10 @@ typedef void * LibMC_pvoid; #define LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION 698 /** Unfinished telemetry marker have no duration. */ #define LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED 699 /** Telemetry Marker has been already registered. */ #define LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND 700 /** Telemetry Chunk Start timestamp is after end timestamp. */ +#define LIBMC_ERROR_TELEMETRYCHUNKINDEXOUTOFRANGE 701 /** Telemetry Chunk index out of range. */ +#define LIBMC_ERROR_TELEMETRYCHUNKIDMISMATCH 702 /** Telemetry Chunk ID mismatch. */ +#define LIBMC_ERROR_TELEMETRYCHUNKISREADONLY 703 /** Telemetry Chunk is readonly. */ +#define LIBMC_ERROR_TELEMETRYCHUNKSCANONLYBEARCHIVEDIFREADONLY 704 /** Telemetry Chunks can only be archived if readonly. */ /************************************************************************************************************************* Error strings for LibMC @@ -1340,6 +1344,10 @@ inline const char * LIBMC_GETERRORSTRING (LibMCResult nErrorCode) { case LIBMC_ERROR_UNFINISHEDTELEMETRYMARKERSHAVENODURATION: return "Unfinished telemetry marker have no duration."; case LIBMC_ERROR_TELEMETRYMARKERALREADYREGISTERED: return "Telemetry Marker has been already registered."; case LIBMC_ERROR_TELEMETRYCHUNKSTARTTIMESTAMPAFTEREND: return "Telemetry Chunk Start timestamp is after end timestamp."; + case LIBMC_ERROR_TELEMETRYCHUNKINDEXOUTOFRANGE: return "Telemetry Chunk index out of range."; + case LIBMC_ERROR_TELEMETRYCHUNKIDMISMATCH: return "Telemetry Chunk ID mismatch."; + case LIBMC_ERROR_TELEMETRYCHUNKISREADONLY: return "Telemetry Chunk is readonly."; + case LIBMC_ERROR_TELEMETRYCHUNKSCANONLYBEARCHIVEDIFREADONLY: return "Telemetry Chunks can only be archived if readonly."; default: return "unknown error"; } } diff --git a/Implementation/Core/amc_telemetry.cpp b/Implementation/Core/amc_telemetry.cpp index ff8f9956..0f40daaf 100644 --- a/Implementation/Core/amc_telemetry.cpp +++ b/Implementation/Core/amc_telemetry.cpp @@ -37,12 +37,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "libmcdata_dynamic.hpp" #define TELEMETRY_DEFAULT_CHUNKINTERVAL_MICROSECONDS 60000000 // 60 seconds +#define TELEMETRY_ONEHOURINMICROSECONDS 3600000000ULL namespace AMC { - CTelemetryDataChunk::CTelemetryDataChunk(CTelemetryWriter* pWriter, uint32_t nChunkID, uint64_t nChunkStartTimestamp, uint64_t nChunkEndTimestamp) + CTelemetryDataChunk::CTelemetryDataChunk(CTelemetryWriter* pWriter, uint64_t nChunkID, uint64_t nChunkStartTimestamp, uint64_t nChunkEndTimestamp) : m_nTelemetryChunkID(nChunkID), m_nMinTimestamp(0), m_nMaxTimestamp(0), m_nMinMarkerID(0), m_nMaxMarkerID(0), - m_pWriter(pWriter), m_nChunkStartTimestamp(nChunkStartTimestamp), m_nChunkEndTimestamp(nChunkEndTimestamp) + m_pWriter(pWriter), m_nChunkStartTimestamp(nChunkStartTimestamp), m_nChunkEndTimestamp(nChunkEndTimestamp), m_bChunkIsReadonly (false), m_bChunkHasBeenArchived (false) { if (pWriter == nullptr) throw ELibMCInterfaceException(LIBMC_ERROR_INVALIDPARAM); @@ -57,6 +58,11 @@ namespace AMC { } + uint64_t CTelemetryDataChunk::getChunkID() const + { + return m_nTelemetryChunkID; + } + bool CTelemetryDataChunk::isEmpty() const { std::lock_guard lock(m_ChunkMutex); @@ -64,59 +70,120 @@ namespace AMC { return m_Entries.empty(); } - void CTelemetryDataChunk::writeEntry(const sTelemetryChunkEntry& entry) + void CTelemetryDataChunk::writeEntry(const LibMCData::sTelemetryChunkEntry& entry) { uint32_t nEntryIndex; { std::lock_guard lock(m_ChunkMutex); + if (m_bChunkIsReadonly) + throw ELibMCCustomException(LIBMC_ERROR_TELEMETRYCHUNKISREADONLY, std::to_string(m_nTelemetryChunkID)); + m_Entries.emplace_back(entry); // entry index shall be one-based nEntryIndex = static_cast (m_Entries.size()); if (nEntryIndex == 1) { - m_nMinMarkerID = entry.m_nMarkerID; - m_nMaxMarkerID = entry.m_nMarkerID; - m_nMinTimestamp = entry.m_nTimestamp; - m_nMaxTimestamp = entry.m_nTimestamp; + m_nMinMarkerID = entry.m_MarkerID; + m_nMaxMarkerID = entry.m_MarkerID; + m_nMinTimestamp = entry.m_TimeStamp; + m_nMaxTimestamp = entry.m_TimeStamp; } else { - if (entry.m_nMarkerID < m_nMinMarkerID) - m_nMinMarkerID = entry.m_nMarkerID; - if (entry.m_nMarkerID > m_nMaxMarkerID) - m_nMaxMarkerID = entry.m_nMarkerID; - if (entry.m_nTimestamp < m_nMinTimestamp) - m_nMinTimestamp = entry.m_nTimestamp; - if (entry.m_nTimestamp > m_nMaxTimestamp) - m_nMaxTimestamp = entry.m_nTimestamp; + if (entry.m_MarkerID < m_nMinMarkerID) + m_nMinMarkerID = entry.m_MarkerID; + if (entry.m_MarkerID > m_nMaxMarkerID) + m_nMaxMarkerID = entry.m_MarkerID; + if (entry.m_TimeStamp < m_nMinTimestamp) + m_nMinTimestamp = entry.m_TimeStamp; + if (entry.m_TimeStamp > m_nMaxTimestamp) + m_nMaxTimestamp = entry.m_TimeStamp; } } - if (entry.m_EntryType == eTelemetryChunkEntryType::IntervalStartMarker) { - m_pWriter->registerOpenInterval (entry.m_nMarkerID, m_nTelemetryChunkID, nEntryIndex); + if (entry.m_EntryType == LibMCData::eTelemetryChunkEntryType::IntervalStartMarker) { + m_pWriter->registerOpenInterval (entry.m_MarkerID, m_nTelemetryChunkID, nEntryIndex); } - else if (entry.m_EntryType == eTelemetryChunkEntryType::IntervalEndMarker) { - m_pWriter->eraseOpenInterval(entry.m_nMarkerID); + else if (entry.m_EntryType == LibMCData::eTelemetryChunkEntryType::IntervalEndMarker) { + m_pWriter->eraseOpenInterval(entry.m_MarkerID); } } + void CTelemetryDataChunk::makeReadOnly() + { + std::lock_guard lock(m_ChunkMutex); + m_bChunkIsReadonly = true; + } + + bool CTelemetryDataChunk::isReadOnly() const + { + std::lock_guard lock(m_ChunkMutex); + return m_bChunkIsReadonly; + } + + bool CTelemetryDataChunk::hasBeenArchived() const + { + std::lock_guard lock(m_ChunkMutex); + return m_bChunkHasBeenArchived; + } + + void CTelemetryDataChunk::writeToArchive(LibMCData::PTelemetrySession pTelemetrySession) + { + if (pTelemetrySession.get() == nullptr) + throw ELibMCInterfaceException(LIBMC_ERROR_INVALIDPARAM); + + std::vector chunkEntries; + uint64_t nChunkStartTimestamp; + uint64_t nChunkEndTimestamp; + + { + std::lock_guard lock(m_ChunkMutex); + if (!m_bChunkIsReadonly) + throw ELibMCCustomException(LIBMC_ERROR_TELEMETRYCHUNKSCANONLYBEARCHIVEDIFREADONLY, std::to_string(m_nTelemetryChunkID)); + + if (m_bChunkHasBeenArchived) + return; + + chunkEntries.swap(m_Entries); + + nChunkStartTimestamp = m_nChunkStartTimestamp; + nChunkEndTimestamp = m_nChunkEndTimestamp; + m_bChunkHasBeenArchived = true; + } + + try { + pTelemetrySession->WriteTelemetryChunk(nChunkStartTimestamp, nChunkEndTimestamp, chunkEntries); + } + catch (...) { + // Restore entries on failure + std::lock_guard lock(m_ChunkMutex); + chunkEntries.swap(m_Entries); + m_bChunkHasBeenArchived = false; + + // Propagate exception to archiving routine + throw; + } + + + + } CTelemetryWriter::CTelemetryWriter(LibMCData::PTelemetrySession pTelemetrySession, AMCCommon::PChrono pGlobalChrono) - : m_nNextChunkIndex(1), m_pTelemetrySession(pTelemetrySession), m_nNextMarkerID(1), m_pGlobalChrono (pGlobalChrono), - m_nChunkIntervalInMicroseconds (TELEMETRY_DEFAULT_CHUNKINTERVAL_MICROSECONDS), m_nNextChunkStartTimestamp (0) + : m_pTelemetrySession(pTelemetrySession), m_nNextMarkerID(1), m_pGlobalChrono (pGlobalChrono), + m_nChunkIntervalInMicroseconds (TELEMETRY_DEFAULT_CHUNKINTERVAL_MICROSECONDS) { if (pGlobalChrono.get () == nullptr) throw ELibMCInterfaceException(LIBMC_ERROR_INVALIDPARAM); if (pTelemetrySession.get() == nullptr) throw ELibMCInterfaceException(LIBMC_ERROR_INVALIDPARAM); - createNewChunk(); + extendChunksUntil(1); } CTelemetryWriter::~CTelemetryWriter() @@ -124,38 +191,61 @@ namespace AMC { } - PTelemetryDataChunk CTelemetryWriter::getCurrentChunk(uint64_t nTimestamp) + PTelemetryDataChunk CTelemetryWriter::getOrCreateChunkByTimestamp(uint64_t nTimestamp) { + + uint64_t nChunkIndexZeroBased = nTimestamp / m_nChunkIntervalInMicroseconds; + uint64_t nChunkIndexOneBased = nChunkIndexZeroBased + 1; + + // Telemetry chunk IDs are one-based + // telemetry session is per-process-lifetime, and + // the DB schema expects chunk ranges per session + extendChunksUntil(nChunkIndexOneBased); + std::lock_guard lock(m_ChunkMutex); - if (nTimestamp >= m_nNextChunkStartTimestamp) - createNewChunkNoMutex(); - return m_pCurrentChunk; + // Telemetry array is zero-based + auto pChunk = m_Chunks.at (nChunkIndexZeroBased); + + if (pChunk->getChunkID() != nChunkIndexOneBased) + throw ELibMCCustomException(LIBMC_ERROR_TELEMETRYCHUNKIDMISMATCH, std::to_string (pChunk->getChunkID()) + " != " + std::to_string (nChunkIndexOneBased)); + + return pChunk; + } - PTelemetryDataChunk CTelemetryWriter::createNewChunk() + void CTelemetryWriter::extendChunksUntil(uint64_t nMaxChunkIndexOneBased) { - std::lock_guard lock(m_ChunkMutex); - return createNewChunkNoMutex(); - } + // Reasonable max chunk index based on current time is maximum an hour in the future! + uint64_t nReasonableMaxChunkIndex = ((m_pGlobalChrono->getElapsedMicroseconds() + TELEMETRY_ONEHOURINMICROSECONDS) / m_nChunkIntervalInMicroseconds) + 1; + if (nMaxChunkIndexOneBased > nReasonableMaxChunkIndex) + throw ELibMCCustomException(LIBMC_ERROR_TELEMETRYCHUNKINDEXOUTOFRANGE, std::to_string(nMaxChunkIndexOneBased)); - PTelemetryDataChunk CTelemetryWriter::createNewChunkNoMutex() - { - uint64_t nChunkEndTimestamp = m_nNextChunkStartTimestamp + m_nChunkIntervalInMicroseconds - 1; + std::lock_guard lock(m_ChunkMutex); + for (uint64_t nZeroBasedIndexToAdd = m_Chunks.size(); nZeroBasedIndexToAdd < nMaxChunkIndexOneBased; nZeroBasedIndexToAdd++) { + uint64_t nChunkStartTimestamp = nZeroBasedIndexToAdd * m_nChunkIntervalInMicroseconds; + uint64_t nChunkEndTimestamp = nChunkStartTimestamp + m_nChunkIntervalInMicroseconds - 1; - auto pChunk = std::make_shared (this, m_nNextChunkIndex, m_nNextChunkStartTimestamp, nChunkEndTimestamp); - m_nNextChunkIndex++; - m_Chunks.emplace_back(pChunk); - m_pCurrentChunk = pChunk; + uint64_t nOneBasedChunkIndex = nZeroBasedIndexToAdd + 1; - m_nNextChunkStartTimestamp = nChunkEndTimestamp + 1; + auto pChunk = std::make_shared(this, nOneBasedChunkIndex, nChunkStartTimestamp, nChunkEndTimestamp); + m_Chunks.emplace_back(pChunk); - return pChunk; + // We make all chunks read-only except for the last two chunks (which might get some writing due to timing race conditions) + if (nZeroBasedIndexToAdd >= 2) { + uint64_t nZeroBasedMakeReadonly = nZeroBasedIndexToAdd - 2; + auto pChunkToMakeReadonly = m_Chunks.at(nZeroBasedMakeReadonly); + pChunkToMakeReadonly->makeReadOnly(); + + std::lock_guard archiveLock(m_ArchiveQueueMutex); + m_ArchiveQueue.push (pChunkToMakeReadonly); + } + } } - void CTelemetryWriter::writeEntry(const sTelemetryChunkEntry& entry) + void CTelemetryWriter::writeEntry(const LibMCData::sTelemetryChunkEntry& entry) { - auto pChunk = getCurrentChunk(entry.m_nTimestamp); + auto pChunk = getOrCreateChunkByTimestamp(entry.m_TimeStamp); pChunk->writeEntry(entry); } @@ -184,6 +274,32 @@ namespace AMC { m_pTelemetrySession->CreateChannelInDB (sUUID, channelType, nChannelIndex, sChannelIdentifier, sChannelDescription); } + void CTelemetryWriter::archiveOldChunksToDB() + { + + bool bIsEmpty = false; + while (!bIsEmpty) { + + PTelemetryDataChunk pChunkToArchive; + { + std::lock_guard archiveLock(m_ArchiveQueueMutex); + bIsEmpty = m_ArchiveQueue.empty (); + if (bIsEmpty) + break; + + pChunkToArchive = m_ArchiveQueue.front(); + m_ArchiveQueue.pop(); + } + + { + std::lock_guard lock(m_DataMutex); + pChunkToArchive->writeToArchive(m_pTelemetrySession); + } + } + + } + + uint64_t CTelemetryWriter::createMarkerID() { return m_nNextMarkerID.fetch_add(1, std::memory_order_relaxed); @@ -209,10 +325,10 @@ namespace AMC { if (bMarkInstant) { m_nFinishTimestamp = m_nStartTimestamp; - pWriter->writeEntry({ eTelemetryChunkEntryType::InstantMarker, nChannelIndex, m_nMarkerID, m_nStartTimestamp, m_nContextData }); + pWriter->writeEntry({ LibMCData::eTelemetryChunkEntryType::InstantMarker, nChannelIndex, m_nMarkerID, m_nStartTimestamp, m_nContextData }); } else { - pWriter->writeEntry({ eTelemetryChunkEntryType::IntervalStartMarker, nChannelIndex, m_nMarkerID, m_nStartTimestamp, m_nContextData }); + pWriter->writeEntry({ LibMCData::eTelemetryChunkEntryType::IntervalStartMarker, nChannelIndex, m_nMarkerID, m_nStartTimestamp, m_nContextData }); } @@ -253,7 +369,7 @@ namespace AMC { pLockedChannel->getChannelIdentifier() + " / " + std::to_string(m_nMarkerID)); } - pWriter->writeEntry({ eTelemetryChunkEntryType::IntervalEndMarker, nChannelIndex, m_nMarkerID, nTimestamp, m_nContextData }); + pWriter->writeEntry({ LibMCData::eTelemetryChunkEntryType::IntervalEndMarker, nChannelIndex, m_nMarkerID, nTimestamp, m_nContextData }); uint64_t nDuration = nTimestamp - m_nStartTimestamp; pLockedChannel->unregisterMarker(m_nMarkerID, nDuration); @@ -527,6 +643,10 @@ namespace AMC { } + void CTelemetryHandler::archiveOldChunksToDB() + { + m_pTelemetryWriter->archiveOldChunksToDB(); + } } diff --git a/Implementation/Core/amc_telemetry.hpp b/Implementation/Core/amc_telemetry.hpp index 38f9060a..a1df4811 100644 --- a/Implementation/Core/amc_telemetry.hpp +++ b/Implementation/Core/amc_telemetry.hpp @@ -55,20 +55,6 @@ namespace AMC { class CTelemetryWriter; - enum class eTelemetryChunkEntryType : uint32_t { - InstantMarker = 1, - IntervalStartMarker = 2, - IntervalEndMarker = 3 - }; - - struct sTelemetryChunkEntry { - eTelemetryChunkEntryType m_EntryType; - uint32_t m_nChannelIndex; - uint64_t m_nMarkerID; - uint64_t m_nTimestamp; - uint64_t m_nContextData; - }; - struct sTelemetryOpenIntervalMarker { uint32_t m_nChunkID; uint32_t m_nEntryIndex; @@ -86,21 +72,35 @@ namespace AMC { uint64_t m_nMinMarkerID; uint64_t m_nMaxMarkerID; - uint32_t m_nTelemetryChunkID; + uint64_t m_nTelemetryChunkID; + + std::vector m_Entries; - std::vector m_Entries; + bool m_bChunkIsReadonly; + + bool m_bChunkHasBeenArchived; mutable std::mutex m_ChunkMutex; public: - CTelemetryDataChunk (CTelemetryWriter* pWriter, uint32_t nChunkID, uint64_t nChunkStartTimestamp, uint64_t nChunkEndTimestamp); + CTelemetryDataChunk (CTelemetryWriter* pWriter, uint64_t nTelemetryChunkID, uint64_t nChunkStartTimestamp, uint64_t nChunkEndTimestamp); virtual ~CTelemetryDataChunk(); + uint64_t getChunkID() const; + bool isEmpty() const; - void writeEntry(const sTelemetryChunkEntry& entry); + void writeEntry(const LibMCData::sTelemetryChunkEntry& entry); + + void makeReadOnly(); + + bool isReadOnly() const; + + bool hasBeenArchived() const; + + void writeToArchive(LibMCData::PTelemetrySession pTelemetrySession); }; @@ -110,11 +110,11 @@ namespace AMC { { private: std::mutex m_ChunkMutex; - std::deque m_Chunks; + std::vector m_Chunks; + + std::mutex m_ArchiveQueueMutex; + std::queue m_ArchiveQueue; - uint32_t m_nNextChunkIndex; - PTelemetryDataChunk m_pCurrentChunk; - uint64_t m_nNextChunkStartTimestamp; uint64_t m_nChunkIntervalInMicroseconds; std::mutex m_OpenIntervalMutex; @@ -127,7 +127,7 @@ namespace AMC { std::atomic m_nNextMarkerID; - PTelemetryDataChunk createNewChunkNoMutex(); + void extendChunksUntil(uint64_t nMaxChunkIndexOneBased); public: @@ -135,11 +135,9 @@ namespace AMC { virtual ~CTelemetryWriter(); - PTelemetryDataChunk getCurrentChunk(uint64_t nTimestamp); - - PTelemetryDataChunk createNewChunk(); + PTelemetryDataChunk getOrCreateChunkByTimestamp(uint64_t nTimestamp); - void writeEntry(const sTelemetryChunkEntry& entry); + void writeEntry(const LibMCData::sTelemetryChunkEntry& entry); void registerOpenInterval (uint64_t nMarkerID, uint32_t nChunkID, uint32_t nChunkEntryIndex); @@ -147,6 +145,8 @@ namespace AMC { void createChannelInDB(const std::string & sUUID, LibMCData::eTelemetryChannelType channelType, uint32_t nChannelIndex, const std::string & sChannelIdentifier, const std::string & sChannelDescription); + void archiveOldChunksToDB(); + uint64_t createMarkerID(); uint64_t getCurrentTimestamp(); @@ -295,6 +295,8 @@ namespace AMC { PTelemetryChannel findChannelByIdentifier(const std::string& sChannelIdentifier, bool bFailIfNotExisting); + void archiveOldChunksToDB(); + }; diff --git a/Implementation/LibMC/libmc_mccontext.cpp b/Implementation/LibMC/libmc_mccontext.cpp index 60f37bb0..4a9b657c 100644 --- a/Implementation/LibMC/libmc_mccontext.cpp +++ b/Implementation/LibMC/libmc_mccontext.cpp @@ -38,6 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "amc_statemachineinstance.hpp" #include "amc_logger.hpp" #include "amc_alerthandler.hpp" +#include "amc_telemetry.hpp" #include "amc_parameterhandler.hpp" #include "amc_statemachinedata.hpp" #include "amc_logger_multi.hpp" @@ -956,8 +957,14 @@ void CMCContext::executeSystemThread() pSignalHandler->checkForReactionTimeouts(m_pSystemState->globalChrono()->getElapsedMicroseconds()); pSignalHandler->autoArchiveMessages(m_pSystemState->globalChrono()->getElapsedMicroseconds()); pSignalHandler->writeMessagesToArchive(nullptr); + + auto pTelemetryHandler = m_pSystemState->getTelemetryHandlerInstance(); + pTelemetryHandler->archiveOldChunksToDB(); + m_pSystemState->updateMemoryUsageParameters(); + + } } catch (std::exception & E) From 303b5b52c321fefca2a8fd44de076ee189e41069 Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Sat, 17 Jan 2026 01:03:45 +0100 Subject: [PATCH 10/19] Added Dummy signal tests to Example Plugins --- Examples/LPBFSystem/Main/mcplugin_main.cpp | 4 ++++ Examples/LPBFSystem/PLC/mcplugin_plc.cpp | 6 ++++++ Examples/LPBFSystem/config.xml | 7 ++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Examples/LPBFSystem/Main/mcplugin_main.cpp b/Examples/LPBFSystem/Main/mcplugin_main.cpp index eefc1eb4..57302608 100644 --- a/Examples/LPBFSystem/Main/mcplugin_main.cpp +++ b/Examples/LPBFSystem/Main/mcplugin_main.cpp @@ -128,6 +128,10 @@ __DECLARESTATE(idle) auto dCounterTest = pStateEnvironment->GetDoubleParameter("jobinfo", "countertest"); auto nTimer = pStateEnvironment->GetGlobalTimerInMilliseconds(); + auto pDummyTrigger = pStateEnvironment->PrepareSignal("plc", "signal_dummy"); + pDummyTrigger->SetInteger("timer", (int32_t)nTimer); + pDummyTrigger->Trigger(); + pStateEnvironment->SetDoubleParameter ("jobinfo", "countertest", dCounterTest + abs (sin (nTimer * 0.001))); //pStateEnvironment->LogMessage ("Waiting for user input..."); diff --git a/Examples/LPBFSystem/PLC/mcplugin_plc.cpp b/Examples/LPBFSystem/PLC/mcplugin_plc.cpp index 4331bee8..430589e1 100644 --- a/Examples/LPBFSystem/PLC/mcplugin_plc.cpp +++ b/Examples/LPBFSystem/PLC/mcplugin_plc.cpp @@ -112,6 +112,12 @@ __DECLARESTATE(idle) pDriver->QueryParameters(); + auto pDummySignal = pStateEnvironment->ClaimSignalFromQueue("signal_dummy"); + if (pDummySignal.get() != nullptr) { + pDummySignal->SignalHandled(); + } + + pStateEnvironment->ClearUnhandledSignalsOfType("signal_dummy"); LibMCEnv::PSignalHandler pHandlerInstance; if (pStateEnvironment->WaitForSignal("signal_recoatlayer", 0, pHandlerInstance)) { diff --git a/Examples/LPBFSystem/config.xml b/Examples/LPBFSystem/config.xml index 0c066f7b..cce8e50d 100644 --- a/Examples/LPBFSystem/config.xml +++ b/Examples/LPBFSystem/config.xml @@ -134,7 +134,7 @@ - + @@ -263,6 +263,11 @@ + + + + + From acd48b74cea34f0f2b8dbccb8ffc1fe0bf486e6d Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Sun, 18 Jan 2026 00:04:25 +0000 Subject: [PATCH 11/19] Added telemetry journal files --- Implementation/DataModel/amcdata_journal.cpp | 69 +++++++++++++++---- Implementation/DataModel/amcdata_journal.hpp | 10 ++- .../LibMCData/libmcdata_telemetrysession.cpp | 2 +- 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/Implementation/DataModel/amcdata_journal.cpp b/Implementation/DataModel/amcdata_journal.cpp index f5a97527..0e4f273b 100644 --- a/Implementation/DataModel/amcdata_journal.cpp +++ b/Implementation/DataModel/amcdata_journal.cpp @@ -153,8 +153,18 @@ namespace AMCData { CJournal::CJournal(const std::string& sJournalBasePath, const std::string& sJournalName, const std::string& sJournalChunkBaseName, const std::string& sSessionUUID) : m_LogID(1), m_AlertID(1), m_sSessionUUID(AMCCommon::CUtils::normalizeUUIDString(sSessionUUID)), - m_sJournalBasePath(sJournalBasePath), m_sChunkBaseName (sJournalChunkBaseName) - { + m_sJournalBasePath(sJournalBasePath), m_sChunkBaseName (sJournalChunkBaseName), + m_TelemetryChunkID (1) + { + m_sTelemetryChunkBaseName = m_sChunkBaseName; + const std::string sJournalPrefix = "journal_"; + const std::string sTelemetryPrefix = "telemetry_"; + if (m_sTelemetryChunkBaseName.rfind(sJournalPrefix, 0) == 0) { + m_sTelemetryChunkBaseName.replace(0, sJournalPrefix.size(), sTelemetryPrefix); + } + else { + m_sTelemetryChunkBaseName = sTelemetryPrefix + m_sTelemetryChunkBaseName; + } m_pSQLHandler = std::make_shared(m_sJournalBasePath + sJournalName); @@ -268,6 +278,7 @@ namespace AMCData { pTelemetryChunkStatement = nullptr; m_pCurrentJournalFile = createJournalFile(); + m_pCurrentTelemetryFile = createTelemetryFile(); } @@ -300,6 +311,30 @@ namespace AMCData { return pJournalFile; } + PActiveJournalFile CJournal::createTelemetryFile() + { + uint32_t nFileIndex = (uint32_t)m_TelemetryFiles.size(); + if (nFileIndex > JOURNAL_MAXFILESPERSESSION) + throw ELibMCDataInterfaceException(LIBMCDATA_ERROR_JOURNALEXCEEDSMAXIMUMFILES); + + std::stringstream sFileNameStream; + sFileNameStream << m_sTelemetryChunkBaseName << std::setw(JOURNAL_MAXFILEDIGITS) << std::setfill('0') << nFileIndex << ".data"; + + std::string sFileName = sFileNameStream.str(); + + std::string sQuery = "INSERT INTO telemetry_datafiles (fileindex, filename) VALUES (?, ?)"; + auto pStatement = m_pSQLHandler->prepareStatement(sQuery); + pStatement->setInt(1, nFileIndex); + pStatement->setString(2, sFileName); + pStatement->execute(); + pStatement = nullptr; + + auto pTelemetryFile = std::make_shared(m_sJournalBasePath + sFileName, nFileIndex); + m_TelemetryFiles.push_back(pTelemetryFile); + + return pTelemetryFile; + } + std::string CJournal::getSessionUUID() { return m_sSessionUUID; @@ -926,26 +961,36 @@ namespace AMCData { { std::lock_guard lockGuard(m_JournalMutex); - uint32_t nChunkIndex = 0; - uint32_t nFileIndex = 0; - uint32_t nDataOffset = 0; - uint32_t nDataLength = 0; + if (nTelemetryEntriesBufferSize == 0) + return; + if (pTelemetryEntriesBuffer == nullptr) + throw ELibMCDataInterfaceException(LIBMCDATA_ERROR_INVALIDPARAM); + if (nStartTimeStamp > nEndTimeStamp) + throw ELibMCDataInterfaceException(LIBMCDATA_ERROR_INVALIDPARAM); + + if (m_pCurrentTelemetryFile->getTotalSize() > getMaxChunkFileSizeQuotaInBytes()) + m_pCurrentTelemetryFile = createTelemetryFile(); + + uint64_t nDataLength = nTelemetryEntriesBufferSize * sizeof(LibMCData::sTelemetryChunkEntry); + uint64_t nDataOffset = m_pCurrentTelemetryFile->retrieveWritePosition(); + m_pCurrentTelemetryFile->writeBuffer(pTelemetryEntriesBuffer, nDataLength); + m_pCurrentTelemetryFile->flushBuffers(); + + uint32_t nChunkIndex = m_TelemetryChunkID.fetch_add(1, std::memory_order_relaxed); - std::string sQuery = "INSERT INTO telemetry_chunks (chunkindex, fileindex, starttimestamp, endtimestamp, entrycount, dataoffset, datalength) VALUES (?, ?, ?, ?, ?)"; + std::string sQuery = "INSERT INTO telemetry_chunks (chunkindex, fileindex, starttimestamp, endtimestamp, entrycount, dataoffset, datalength) VALUES (?, ?, ?, ?, ?, ?, ?)"; auto pStatement = m_pSQLHandler->prepareStatement(sQuery); pStatement->setInt64(1, nChunkIndex); - pStatement->setInt64(2, nFileIndex); + pStatement->setInt64(2, m_pCurrentTelemetryFile->getFileIndex()); pStatement->setInt64(3, (int64_t)nStartTimeStamp); pStatement->setInt64(4, (int64_t)nEndTimeStamp); - pStatement->setInt64(5, (int64_t) nTelemetryEntriesBufferSize); + pStatement->setInt64(5, (int64_t)nTelemetryEntriesBufferSize); pStatement->setInt64(6, (int64_t)nDataOffset); pStatement->setInt64(7, (int64_t)nDataLength); pStatement->execute(); - pStatement = nullptr; + pStatement = nullptr; } } - - diff --git a/Implementation/DataModel/amcdata_journal.hpp b/Implementation/DataModel/amcdata_journal.hpp index 04d9997d..d09f560b 100644 --- a/Implementation/DataModel/amcdata_journal.hpp +++ b/Implementation/DataModel/amcdata_journal.hpp @@ -91,6 +91,7 @@ namespace AMCData { std::string m_sJournalBasePath; std::string m_sChunkBaseName; + std::string m_sTelemetryChunkBaseName; std::vector m_JournalFiles; @@ -98,6 +99,14 @@ namespace AMCData { PActiveJournalFile createJournalFile(); + std::vector m_TelemetryFiles; + + PActiveJournalFile m_pCurrentTelemetryFile; + + std::atomic m_TelemetryChunkID; + + PActiveJournalFile createTelemetryFile(); + public: static std::string convertAlertLevelToString(const LibMCData::eAlertLevel eLevel); @@ -175,4 +184,3 @@ namespace AMCData { #endif //__AMCDATA_JOURNAL - diff --git a/Implementation/LibMCData/libmcdata_telemetrysession.cpp b/Implementation/LibMCData/libmcdata_telemetrysession.cpp index f5eb28d8..6edc6373 100644 --- a/Implementation/LibMCData/libmcdata_telemetrysession.cpp +++ b/Implementation/LibMCData/libmcdata_telemetrysession.cpp @@ -67,5 +67,5 @@ void CTelemetrySession::CreateChannelInDB(const std::string & sUUID, const LibMC void CTelemetrySession::WriteTelemetryChunk(const LibMCData_uint64 nStartTimeStamp, const LibMCData_uint64 nEndTimeStamp, const LibMCData_uint64 nTelemetryEntriesBufferSize, const LibMCData::sTelemetryChunkEntry* pTelemetryEntriesBuffer) { - + m_pJournal->writeTelemetryChunk(nStartTimeStamp, nEndTimeStamp, nTelemetryEntriesBufferSize, pTelemetryEntriesBuffer); } From ba5f6499bc55102828f73211aa31635d00cc3750 Mon Sep 17 00:00:00 2001 From: Alexander Oster Date: Sun, 18 Jan 2026 00:15:40 +0000 Subject: [PATCH 12/19] Explicitly store telemetry base name --- Implementation/DataModel/amcdata_journal.cpp | 19 ++++++++++++------- Implementation/DataModel/amcdata_journal.hpp | 2 +- .../LibMCData/libmcdata_datamodel.cpp | 3 ++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Implementation/DataModel/amcdata_journal.cpp b/Implementation/DataModel/amcdata_journal.cpp index 0e4f273b..e00a9b7c 100644 --- a/Implementation/DataModel/amcdata_journal.cpp +++ b/Implementation/DataModel/amcdata_journal.cpp @@ -151,19 +151,24 @@ namespace AMCData { return m_nTotalSize; } - CJournal::CJournal(const std::string& sJournalBasePath, const std::string& sJournalName, const std::string& sJournalChunkBaseName, const std::string& sSessionUUID) + CJournal::CJournal(const std::string& sJournalBasePath, const std::string& sJournalName, const std::string& sJournalChunkBaseName, const std::string& sTelemetryChunkBaseName, const std::string& sSessionUUID) : m_LogID(1), m_AlertID(1), m_sSessionUUID(AMCCommon::CUtils::normalizeUUIDString(sSessionUUID)), m_sJournalBasePath(sJournalBasePath), m_sChunkBaseName (sJournalChunkBaseName), m_TelemetryChunkID (1) { - m_sTelemetryChunkBaseName = m_sChunkBaseName; - const std::string sJournalPrefix = "journal_"; - const std::string sTelemetryPrefix = "telemetry_"; - if (m_sTelemetryChunkBaseName.rfind(sJournalPrefix, 0) == 0) { - m_sTelemetryChunkBaseName.replace(0, sJournalPrefix.size(), sTelemetryPrefix); + if (!sTelemetryChunkBaseName.empty()) { + m_sTelemetryChunkBaseName = sTelemetryChunkBaseName; } else { - m_sTelemetryChunkBaseName = sTelemetryPrefix + m_sTelemetryChunkBaseName; + m_sTelemetryChunkBaseName = m_sChunkBaseName; + const std::string sJournalPrefix = "journal_"; + const std::string sTelemetryPrefix = "telemetry_"; + if (m_sTelemetryChunkBaseName.rfind(sJournalPrefix, 0) == 0) { + m_sTelemetryChunkBaseName.replace(0, sJournalPrefix.size(), sTelemetryPrefix); + } + else { + m_sTelemetryChunkBaseName = sTelemetryPrefix + m_sTelemetryChunkBaseName; + } } m_pSQLHandler = std::make_shared(m_sJournalBasePath + sJournalName); diff --git a/Implementation/DataModel/amcdata_journal.hpp b/Implementation/DataModel/amcdata_journal.hpp index d09f560b..c42393ce 100644 --- a/Implementation/DataModel/amcdata_journal.hpp +++ b/Implementation/DataModel/amcdata_journal.hpp @@ -113,7 +113,7 @@ namespace AMCData { static LibMCData::eAlertLevel convertStringToAlertLevel(const std::string & sValue, bool bFailIfUnknown); - CJournal(const std::string& sJournalBasePath, const std::string& sJournalName, const std::string& sJournalChunkBaseName, const std::string & sSessionUUID); + CJournal(const std::string& sJournalBasePath, const std::string& sJournalName, const std::string& sJournalChunkBaseName, const std::string& sTelemetryChunkBaseName, const std::string & sSessionUUID); virtual ~CJournal(); diff --git a/Implementation/LibMCData/libmcdata_datamodel.cpp b/Implementation/LibMCData/libmcdata_datamodel.cpp index 860c75ca..76febedc 100644 --- a/Implementation/LibMCData/libmcdata_datamodel.cpp +++ b/Implementation/LibMCData/libmcdata_datamodel.cpp @@ -144,8 +144,9 @@ void CDataModel::InitialiseDatabase(const std::string & sDataDirectory, const Li auto sJournalBasePath = m_pStorageState->getJournalBasePath(m_sTimeFileName); auto sJournalName = m_pStorageState->getJournalFileName(m_sTimeFileName); auto sJournalChunkBaseName = m_pStorageState->getJournalChunkBaseName(m_sTimeFileName); + auto sTelemetryChunkBaseName = "telemetry_" + m_sTimeFileName + "_chunk"; - m_pJournal = std::make_shared (sJournalBasePath, sJournalName, sJournalChunkBaseName, m_sSessionUUID); + m_pJournal = std::make_shared (sJournalBasePath, sJournalName, sJournalChunkBaseName, sTelemetryChunkBaseName, m_sSessionUUID); auto pStatement = m_pSQLHandler->prepareStatement("INSERT INTO journals (uuid, starttime, logfilename, journalfilename, logfilepath, journalfilepath, schemaversion, githash) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); pStatement->setString(1, m_sSessionUUID); From e591fefe29409f60aaa7b3e39c97963b1ca90681 Mon Sep 17 00:00:00 2001 From: krixkrix Date: Sun, 18 Jan 2026 01:43:30 +0100 Subject: [PATCH 13/19] Build api enhancements (#66) * Add GetCreatedTimestamp and GetLastExecutionTimestamp to Build interface * Feature: Add GetRecentBuildJobs() API to UIEnvironment Add new API method to retrieve recent validated build jobs for touchscreen UI display. Changes: 1. **IDL Definition** (ACT/LibMCEnv.xml): - Added BuildIterator class following BuildExecutionIterator pattern - Added GetRecentBuildJobs(maxCount) method to UIEnvironment 2. **BuildIterator Implementation**: - New class CBuildIterator (libmcenv_builditerator.hpp/cpp) - Implements GetCurrentBuild() to return IBuild instances - Follows standard AMCF iterator pattern 3. **UIEnvironment Implementation** (libmcenv_uienvironment.cpp): - GetRecentBuildJobs() queries validated build jobs via DataModel - Returns BuildIterator with most recent jobs (newest first) - Limited by maxCount parameter 4. **CBuild Factory Methods** (libmcenv_build.cpp/hpp): - Added makeFrom() and makeSharedFrom() static methods - Enables BuildIterator to wrap existing build job instances This API enables plugins to access build job data for UI display without direct DataModel access, maintaining proper abstraction. --- InterfacesCode: Regenerate interface files from ACT for GetRecentBuildJobs API Regenerated C++ interface bindings and headers using ACT (Automatic Component Toolkit) after adding GetRecentBuildJobs() method to LibMCEnv.xml. Generated/Updated files: - Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp - Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h - Framework/HeadersDev/CppDynamic/libmcenv_types.hpp - Framework/InterfacesCore/libmcenv_abi.hpp - Framework/InterfacesCore/libmcenv_interfaces.hpp - Framework/InterfacesCore/libmcenv_interfacewrapper.cpp - Framework/InterfacesCore/libmcenv_types.hpp - ACT/act.linux (binary timestamp update) These files are auto-generated by running: ./act.linux LibMCEnv.xml --- ACT/LibMCEnv.xml | 38 +++ ACT/act.linux | Bin .../HeadersDev/CppDynamic/libmcenv_dynamic.h | 93 ++++++ .../CppDynamic/libmcenv_dynamic.hpp | 246 +++++++++++++++ .../HeadersDev/CppDynamic/libmcenv_types.hpp | 1 + Framework/InterfacesCore/libmcenv_abi.hpp | 85 ++++++ .../InterfacesCore/libmcenv_interfaces.hpp | 65 ++++ .../libmcenv_interfacewrapper.cpp | 283 ++++++++++++++++++ Framework/InterfacesCore/libmcenv_types.hpp | 1 + Implementation/LibMCEnv/libmcenv_build.cpp | 46 +++ Implementation/LibMCEnv/libmcenv_build.hpp | 8 + .../LibMCEnv/libmcenv_builditerator.cpp | 97 ++++++ .../LibMCEnv/libmcenv_builditerator.hpp | 82 +++++ .../LibMCEnv/libmcenv_uienvironment.cpp | 90 ++++++ .../LibMCEnv/libmcenv_uienvironment.hpp | 11 + 15 files changed, 1146 insertions(+) mode change 100644 => 100755 ACT/act.linux create mode 100644 Implementation/LibMCEnv/libmcenv_builditerator.cpp create mode 100644 Implementation/LibMCEnv/libmcenv_builditerator.hpp diff --git a/ACT/LibMCEnv.xml b/ACT/LibMCEnv.xml index 53f36589..a16585b7 100644 --- a/ACT/LibMCEnv.xml +++ b/ACT/LibMCEnv.xml @@ -2591,6 +2591,12 @@ + + + + + + @@ -2602,6 +2608,14 @@ + + + + + + + + @@ -5742,6 +5756,10 @@ + + + + @@ -5913,6 +5931,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ACT/act.linux b/ACT/act.linux old mode 100644 new mode 100755 diff --git a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h index bb1b8b0b..5f891da6 100644 --- a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h +++ b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h @@ -4234,6 +4234,19 @@ typedef LibMCEnvResult (*PLibMCEnvBuildExecution_LoadAttachedJournalPtr) (LibMCE */ typedef LibMCEnvResult (*PLibMCEnvBuildExecutionIterator_GetCurrentExecutionPtr) (LibMCEnv_BuildExecutionIterator pBuildExecutionIterator, LibMCEnv_BuildExecution * pBuildExecutionInstance); +/************************************************************************************************************************* + Class definition for BuildIterator +**************************************************************************************************************************/ + +/** +* Returns the build the iterator points at. +* +* @param[in] pBuildIterator - BuildIterator instance. +* @param[out] pBuildInstance - returns the Build instance. +* @return error code or 0 (success) +*/ +typedef LibMCEnvResult (*PLibMCEnvBuildIterator_GetCurrentBuildPtr) (LibMCEnv_BuildIterator pBuildIterator, LibMCEnv_Build * pBuildInstance); + /************************************************************************************************************************* Class definition for Build **************************************************************************************************************************/ @@ -4260,6 +4273,28 @@ typedef LibMCEnvResult (*PLibMCEnvBuild_GetNamePtr) (LibMCEnv_Build pBuild, cons */ typedef LibMCEnvResult (*PLibMCEnvBuild_GetBuildUUIDPtr) (LibMCEnv_Build pBuild, const LibMCEnv_uint32 nBuildUUIDBufferSize, LibMCEnv_uint32* pBuildUUIDNeededChars, char * pBuildUUIDBuffer); +/** +* Returns creation timestamp of the build in ISO-8601 format. +* +* @param[in] pBuild - Build instance. +* @param[in] nTimestampBufferSize - size of the buffer (including trailing 0) +* @param[out] pTimestampNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pTimestampBuffer - buffer of Creation timestamp in ISO-8601 format (e.g., 2025-10-23T14:30:00.000Z)., may be NULL +* @return error code or 0 (success) +*/ +typedef LibMCEnvResult (*PLibMCEnvBuild_GetCreatedTimestampPtr) (LibMCEnv_Build pBuild, const LibMCEnv_uint32 nTimestampBufferSize, LibMCEnv_uint32* pTimestampNeededChars, char * pTimestampBuffer); + +/** +* Returns the most recent execution timestamp in ISO-8601 format. Returns empty string if build has never been executed. +* +* @param[in] pBuild - Build instance. +* @param[in] nTimestampBufferSize - size of the buffer (including trailing 0) +* @param[out] pTimestampNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pTimestampBuffer - buffer of Most recent execution timestamp in ISO-8601 format. Empty string if never executed., may be NULL +* @return error code or 0 (success) +*/ +typedef LibMCEnvResult (*PLibMCEnvBuild_GetLastExecutionTimestampPtr) (LibMCEnv_Build pBuild, const LibMCEnv_uint32 nTimestampBufferSize, LibMCEnv_uint32* pTimestampNeededChars, char * pTimestampBuffer); + /** * Returns storage uuid of the build stream. * @@ -10607,6 +10642,16 @@ typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_HasBuildExecutionPtr) (LibMCEnv_ */ typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_GetBuildExecutionPtr) (LibMCEnv_UIEnvironment pUIEnvironment, const char * pExecutionUUID, LibMCEnv_BuildExecution * pExecutionInstance); +/** +* Returns an iterator for recent build jobs, ordered by timestamp (newest first). +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] nMaxCount - Maximum number of jobs to return. Must be greater than 0. +* @param[out] pBuildIterator - Iterator for build jobs, ordered newest first. +* @return error code or 0 (success) +*/ +typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_GetRecentBuildJobsPtr) (LibMCEnv_UIEnvironment pUIEnvironment, LibMCEnv_uint32 nMaxCount, LibMCEnv_BuildIterator * pBuildIterator); + /** * Creates an empty discrete field. * @@ -10949,6 +10994,46 @@ typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_GetExternalEventParameterPtr) (L */ typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_AddExternalEventResultValuePtr) (LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, const char * pReturnValue); +/** +* Sets a string result value for external event return (typed convenience wrapper). +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] pReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) +* @param[in] pReturnValue - Return value. +* @return error code or 0 (success) +*/ +typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_SetStringResultPtr) (LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, const char * pReturnValue); + +/** +* Sets an integer result value for external event return. +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] pReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) +* @param[in] nReturnValue - Return value. +* @return error code or 0 (success) +*/ +typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_SetIntegerResultPtr) (LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, LibMCEnv_int64 nReturnValue); + +/** +* Sets a boolean result value for external event return. +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] pReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) +* @param[in] bReturnValue - Return value. +* @return error code or 0 (success) +*/ +typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_SetBoolResultPtr) (LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, bool bReturnValue); + +/** +* Sets a double result value for external event return. +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] pReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) +* @param[in] dReturnValue - Return value. +* @return error code or 0 (success) +*/ +typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_SetDoubleResultPtr) (LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, LibMCEnv_double dReturnValue); + /** * Returns the external event parameters. This JSON Object was passed on from the external API. * @@ -11424,8 +11509,11 @@ typedef struct { PLibMCEnvBuildExecution_GetMetaDataStringPtr m_BuildExecution_GetMetaDataString; PLibMCEnvBuildExecution_LoadAttachedJournalPtr m_BuildExecution_LoadAttachedJournal; PLibMCEnvBuildExecutionIterator_GetCurrentExecutionPtr m_BuildExecutionIterator_GetCurrentExecution; + PLibMCEnvBuildIterator_GetCurrentBuildPtr m_BuildIterator_GetCurrentBuild; PLibMCEnvBuild_GetNamePtr m_Build_GetName; PLibMCEnvBuild_GetBuildUUIDPtr m_Build_GetBuildUUID; + PLibMCEnvBuild_GetCreatedTimestampPtr m_Build_GetCreatedTimestamp; + PLibMCEnvBuild_GetLastExecutionTimestampPtr m_Build_GetLastExecutionTimestamp; PLibMCEnvBuild_GetStorageUUIDPtr m_Build_GetStorageUUID; PLibMCEnvBuild_GetStorageSHA256Ptr m_Build_GetStorageSHA256; PLibMCEnvBuild_EnsureStorageSHA256IsValidPtr m_Build_EnsureStorageSHA256IsValid; @@ -12019,6 +12107,7 @@ typedef struct { PLibMCEnvUIEnvironment_GetBuildJobPtr m_UIEnvironment_GetBuildJob; PLibMCEnvUIEnvironment_HasBuildExecutionPtr m_UIEnvironment_HasBuildExecution; PLibMCEnvUIEnvironment_GetBuildExecutionPtr m_UIEnvironment_GetBuildExecution; + PLibMCEnvUIEnvironment_GetRecentBuildJobsPtr m_UIEnvironment_GetRecentBuildJobs; PLibMCEnvUIEnvironment_CreateDiscreteField2DPtr m_UIEnvironment_CreateDiscreteField2D; PLibMCEnvUIEnvironment_CreateDiscreteField2DFromImagePtr m_UIEnvironment_CreateDiscreteField2DFromImage; PLibMCEnvUIEnvironment_CheckPermissionPtr m_UIEnvironment_CheckPermission; @@ -12051,6 +12140,10 @@ typedef struct { PLibMCEnvUIEnvironment_HasExternalEventParameterPtr m_UIEnvironment_HasExternalEventParameter; PLibMCEnvUIEnvironment_GetExternalEventParameterPtr m_UIEnvironment_GetExternalEventParameter; PLibMCEnvUIEnvironment_AddExternalEventResultValuePtr m_UIEnvironment_AddExternalEventResultValue; + PLibMCEnvUIEnvironment_SetStringResultPtr m_UIEnvironment_SetStringResult; + PLibMCEnvUIEnvironment_SetIntegerResultPtr m_UIEnvironment_SetIntegerResult; + PLibMCEnvUIEnvironment_SetBoolResultPtr m_UIEnvironment_SetBoolResult; + PLibMCEnvUIEnvironment_SetDoubleResultPtr m_UIEnvironment_SetDoubleResult; PLibMCEnvUIEnvironment_GetExternalEventParametersPtr m_UIEnvironment_GetExternalEventParameters; PLibMCEnvUIEnvironment_GetExternalEventResultsPtr m_UIEnvironment_GetExternalEventResults; PLibMCEnvUIEnvironment_CreateMachineConfigurationHandlerPtr m_UIEnvironment_CreateMachineConfigurationHandler; diff --git a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp index 22f8bcf7..248cd5d6 100644 --- a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp +++ b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp @@ -97,6 +97,7 @@ class CToolpathLayer; class CToolpathAccessor; class CBuildExecution; class CBuildExecutionIterator; +class CBuildIterator; class CBuild; class CWorkingFileProcess; class CWorkingFile; @@ -183,6 +184,7 @@ typedef CToolpathLayer CLibMCEnvToolpathLayer; typedef CToolpathAccessor CLibMCEnvToolpathAccessor; typedef CBuildExecution CLibMCEnvBuildExecution; typedef CBuildExecutionIterator CLibMCEnvBuildExecutionIterator; +typedef CBuildIterator CLibMCEnvBuildIterator; typedef CBuild CLibMCEnvBuild; typedef CWorkingFileProcess CLibMCEnvWorkingFileProcess; typedef CWorkingFile CLibMCEnvWorkingFile; @@ -269,6 +271,7 @@ typedef std::shared_ptr PToolpathLayer; typedef std::shared_ptr PToolpathAccessor; typedef std::shared_ptr PBuildExecution; typedef std::shared_ptr PBuildExecutionIterator; +typedef std::shared_ptr PBuildIterator; typedef std::shared_ptr PBuild; typedef std::shared_ptr PWorkingFileProcess; typedef std::shared_ptr PWorkingFile; @@ -355,6 +358,7 @@ typedef PToolpathLayer PLibMCEnvToolpathLayer; typedef PToolpathAccessor PLibMCEnvToolpathAccessor; typedef PBuildExecution PLibMCEnvBuildExecution; typedef PBuildExecutionIterator PLibMCEnvBuildExecutionIterator; +typedef PBuildIterator PLibMCEnvBuildIterator; typedef PBuild PLibMCEnvBuild; typedef PWorkingFileProcess PLibMCEnvWorkingFileProcess; typedef PWorkingFile PLibMCEnvWorkingFile; @@ -1145,6 +1149,7 @@ class CWrapper { friend class CToolpathAccessor; friend class CBuildExecution; friend class CBuildExecutionIterator; + friend class CBuildIterator; friend class CBuild; friend class CWorkingFileProcess; friend class CWorkingFile; @@ -2232,6 +2237,23 @@ class CBuildExecutionIterator : public CIterator { inline PBuildExecution GetCurrentExecution(); }; +/************************************************************************************************************************* + Class CBuildIterator +**************************************************************************************************************************/ +class CBuildIterator : public CIterator { +public: + + /** + * CBuildIterator::CBuildIterator - Constructor for BuildIterator class. + */ + CBuildIterator(CWrapper* pWrapper, LibMCEnvHandle pHandle) + : CIterator(pWrapper, pHandle) + { + } + + inline PBuild GetCurrentBuild(); +}; + /************************************************************************************************************************* Class CBuild **************************************************************************************************************************/ @@ -2248,6 +2270,8 @@ class CBuild : public CBase { inline std::string GetName(); inline std::string GetBuildUUID(); + inline std::string GetCreatedTimestamp(); + inline std::string GetLastExecutionTimestamp(); inline std::string GetStorageUUID(); inline std::string GetStorageSHA256(); inline void EnsureStorageSHA256IsValid(); @@ -3513,6 +3537,7 @@ class CUIEnvironment : public CBase { inline PBuild GetBuildJob(const std::string & sBuildUUID); inline bool HasBuildExecution(const std::string & sExecutionUUID); inline PBuildExecution GetBuildExecution(const std::string & sExecutionUUID); + inline PBuildIterator GetRecentBuildJobs(const LibMCEnv_uint32 nMaxCount); inline PDiscreteFieldData2D CreateDiscreteField2D(const LibMCEnv_uint32 nPixelCountX, const LibMCEnv_uint32 nPixelCountY, const LibMCEnv_double dDPIValueX, const LibMCEnv_double dDPIValueY, const LibMCEnv_double dOriginX, const LibMCEnv_double dOriginY, const LibMCEnv_double dDefaultValue); inline PDiscreteFieldData2D CreateDiscreteField2DFromImage(classParam pImageDataInstance, const LibMCEnv_double dBlackValue, const LibMCEnv_double dWhiteValue, const LibMCEnv_double dOriginX, const LibMCEnv_double dOriginY); inline bool CheckPermission(const std::string & sPermissionIdentifier); @@ -3545,6 +3570,10 @@ class CUIEnvironment : public CBase { inline bool HasExternalEventParameter(const std::string & sParameterName); inline std::string GetExternalEventParameter(const std::string & sParameterName); inline void AddExternalEventResultValue(const std::string & sReturnValueName, const std::string & sReturnValue); + inline void SetStringResult(const std::string & sReturnValueName, const std::string & sReturnValue); + inline void SetIntegerResult(const std::string & sReturnValueName, const LibMCEnv_int64 nReturnValue); + inline void SetBoolResult(const std::string & sReturnValueName, const bool bReturnValue); + inline void SetDoubleResult(const std::string & sReturnValueName, const LibMCEnv_double dReturnValue); inline PJSONObject GetExternalEventParameters(); inline PJSONObject GetExternalEventResults(); inline PMachineConfigurationHandler CreateMachineConfigurationHandler(); @@ -4023,8 +4052,11 @@ class CUIEnvironment : public CBase { pWrapperTable->m_BuildExecution_GetMetaDataString = nullptr; pWrapperTable->m_BuildExecution_LoadAttachedJournal = nullptr; pWrapperTable->m_BuildExecutionIterator_GetCurrentExecution = nullptr; + pWrapperTable->m_BuildIterator_GetCurrentBuild = nullptr; pWrapperTable->m_Build_GetName = nullptr; pWrapperTable->m_Build_GetBuildUUID = nullptr; + pWrapperTable->m_Build_GetCreatedTimestamp = nullptr; + pWrapperTable->m_Build_GetLastExecutionTimestamp = nullptr; pWrapperTable->m_Build_GetStorageUUID = nullptr; pWrapperTable->m_Build_GetStorageSHA256 = nullptr; pWrapperTable->m_Build_EnsureStorageSHA256IsValid = nullptr; @@ -4618,6 +4650,7 @@ class CUIEnvironment : public CBase { pWrapperTable->m_UIEnvironment_GetBuildJob = nullptr; pWrapperTable->m_UIEnvironment_HasBuildExecution = nullptr; pWrapperTable->m_UIEnvironment_GetBuildExecution = nullptr; + pWrapperTable->m_UIEnvironment_GetRecentBuildJobs = nullptr; pWrapperTable->m_UIEnvironment_CreateDiscreteField2D = nullptr; pWrapperTable->m_UIEnvironment_CreateDiscreteField2DFromImage = nullptr; pWrapperTable->m_UIEnvironment_CheckPermission = nullptr; @@ -4650,6 +4683,10 @@ class CUIEnvironment : public CBase { pWrapperTable->m_UIEnvironment_HasExternalEventParameter = nullptr; pWrapperTable->m_UIEnvironment_GetExternalEventParameter = nullptr; pWrapperTable->m_UIEnvironment_AddExternalEventResultValue = nullptr; + pWrapperTable->m_UIEnvironment_SetStringResult = nullptr; + pWrapperTable->m_UIEnvironment_SetIntegerResult = nullptr; + pWrapperTable->m_UIEnvironment_SetBoolResult = nullptr; + pWrapperTable->m_UIEnvironment_SetDoubleResult = nullptr; pWrapperTable->m_UIEnvironment_GetExternalEventParameters = nullptr; pWrapperTable->m_UIEnvironment_GetExternalEventResults = nullptr; pWrapperTable->m_UIEnvironment_CreateMachineConfigurationHandler = nullptr; @@ -8236,6 +8273,15 @@ class CUIEnvironment : public CBase { if (pWrapperTable->m_BuildExecutionIterator_GetCurrentExecution == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + #ifdef _WIN32 + pWrapperTable->m_BuildIterator_GetCurrentBuild = (PLibMCEnvBuildIterator_GetCurrentBuildPtr) GetProcAddress(hLibrary, "libmcenv_builditerator_getcurrentbuild"); + #else // _WIN32 + pWrapperTable->m_BuildIterator_GetCurrentBuild = (PLibMCEnvBuildIterator_GetCurrentBuildPtr) dlsym(hLibrary, "libmcenv_builditerator_getcurrentbuild"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_BuildIterator_GetCurrentBuild == nullptr) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + #ifdef _WIN32 pWrapperTable->m_Build_GetName = (PLibMCEnvBuild_GetNamePtr) GetProcAddress(hLibrary, "libmcenv_build_getname"); #else // _WIN32 @@ -8254,6 +8300,24 @@ class CUIEnvironment : public CBase { if (pWrapperTable->m_Build_GetBuildUUID == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + #ifdef _WIN32 + pWrapperTable->m_Build_GetCreatedTimestamp = (PLibMCEnvBuild_GetCreatedTimestampPtr) GetProcAddress(hLibrary, "libmcenv_build_getcreatedtimestamp"); + #else // _WIN32 + pWrapperTable->m_Build_GetCreatedTimestamp = (PLibMCEnvBuild_GetCreatedTimestampPtr) dlsym(hLibrary, "libmcenv_build_getcreatedtimestamp"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_Build_GetCreatedTimestamp == nullptr) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_Build_GetLastExecutionTimestamp = (PLibMCEnvBuild_GetLastExecutionTimestampPtr) GetProcAddress(hLibrary, "libmcenv_build_getlastexecutiontimestamp"); + #else // _WIN32 + pWrapperTable->m_Build_GetLastExecutionTimestamp = (PLibMCEnvBuild_GetLastExecutionTimestampPtr) dlsym(hLibrary, "libmcenv_build_getlastexecutiontimestamp"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_Build_GetLastExecutionTimestamp == nullptr) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + #ifdef _WIN32 pWrapperTable->m_Build_GetStorageUUID = (PLibMCEnvBuild_GetStorageUUIDPtr) GetProcAddress(hLibrary, "libmcenv_build_getstorageuuid"); #else // _WIN32 @@ -13591,6 +13655,15 @@ class CUIEnvironment : public CBase { if (pWrapperTable->m_UIEnvironment_GetBuildExecution == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + #ifdef _WIN32 + pWrapperTable->m_UIEnvironment_GetRecentBuildJobs = (PLibMCEnvUIEnvironment_GetRecentBuildJobsPtr) GetProcAddress(hLibrary, "libmcenv_uienvironment_getrecentbuildjobs"); + #else // _WIN32 + pWrapperTable->m_UIEnvironment_GetRecentBuildJobs = (PLibMCEnvUIEnvironment_GetRecentBuildJobsPtr) dlsym(hLibrary, "libmcenv_uienvironment_getrecentbuildjobs"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_UIEnvironment_GetRecentBuildJobs == nullptr) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + #ifdef _WIN32 pWrapperTable->m_UIEnvironment_CreateDiscreteField2D = (PLibMCEnvUIEnvironment_CreateDiscreteField2DPtr) GetProcAddress(hLibrary, "libmcenv_uienvironment_creatediscretefield2d"); #else // _WIN32 @@ -13879,6 +13952,42 @@ class CUIEnvironment : public CBase { if (pWrapperTable->m_UIEnvironment_AddExternalEventResultValue == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + #ifdef _WIN32 + pWrapperTable->m_UIEnvironment_SetStringResult = (PLibMCEnvUIEnvironment_SetStringResultPtr) GetProcAddress(hLibrary, "libmcenv_uienvironment_setstringresult"); + #else // _WIN32 + pWrapperTable->m_UIEnvironment_SetStringResult = (PLibMCEnvUIEnvironment_SetStringResultPtr) dlsym(hLibrary, "libmcenv_uienvironment_setstringresult"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_UIEnvironment_SetStringResult == nullptr) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_UIEnvironment_SetIntegerResult = (PLibMCEnvUIEnvironment_SetIntegerResultPtr) GetProcAddress(hLibrary, "libmcenv_uienvironment_setintegerresult"); + #else // _WIN32 + pWrapperTable->m_UIEnvironment_SetIntegerResult = (PLibMCEnvUIEnvironment_SetIntegerResultPtr) dlsym(hLibrary, "libmcenv_uienvironment_setintegerresult"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_UIEnvironment_SetIntegerResult == nullptr) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_UIEnvironment_SetBoolResult = (PLibMCEnvUIEnvironment_SetBoolResultPtr) GetProcAddress(hLibrary, "libmcenv_uienvironment_setboolresult"); + #else // _WIN32 + pWrapperTable->m_UIEnvironment_SetBoolResult = (PLibMCEnvUIEnvironment_SetBoolResultPtr) dlsym(hLibrary, "libmcenv_uienvironment_setboolresult"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_UIEnvironment_SetBoolResult == nullptr) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_UIEnvironment_SetDoubleResult = (PLibMCEnvUIEnvironment_SetDoubleResultPtr) GetProcAddress(hLibrary, "libmcenv_uienvironment_setdoubleresult"); + #else // _WIN32 + pWrapperTable->m_UIEnvironment_SetDoubleResult = (PLibMCEnvUIEnvironment_SetDoubleResultPtr) dlsym(hLibrary, "libmcenv_uienvironment_setdoubleresult"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_UIEnvironment_SetDoubleResult == nullptr) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + #ifdef _WIN32 pWrapperTable->m_UIEnvironment_GetExternalEventParameters = (PLibMCEnvUIEnvironment_GetExternalEventParametersPtr) GetProcAddress(hLibrary, "libmcenv_uienvironment_getexternaleventparameters"); #else // _WIN32 @@ -15535,6 +15644,10 @@ class CUIEnvironment : public CBase { if ( (eLookupError != 0) || (pWrapperTable->m_BuildExecutionIterator_GetCurrentExecution == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_builditerator_getcurrentbuild", (void**)&(pWrapperTable->m_BuildIterator_GetCurrentBuild)); + if ( (eLookupError != 0) || (pWrapperTable->m_BuildIterator_GetCurrentBuild == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_build_getname", (void**)&(pWrapperTable->m_Build_GetName)); if ( (eLookupError != 0) || (pWrapperTable->m_Build_GetName == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; @@ -15543,6 +15656,14 @@ class CUIEnvironment : public CBase { if ( (eLookupError != 0) || (pWrapperTable->m_Build_GetBuildUUID == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_build_getcreatedtimestamp", (void**)&(pWrapperTable->m_Build_GetCreatedTimestamp)); + if ( (eLookupError != 0) || (pWrapperTable->m_Build_GetCreatedTimestamp == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libmcenv_build_getlastexecutiontimestamp", (void**)&(pWrapperTable->m_Build_GetLastExecutionTimestamp)); + if ( (eLookupError != 0) || (pWrapperTable->m_Build_GetLastExecutionTimestamp == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_build_getstorageuuid", (void**)&(pWrapperTable->m_Build_GetStorageUUID)); if ( (eLookupError != 0) || (pWrapperTable->m_Build_GetStorageUUID == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; @@ -17915,6 +18036,10 @@ class CUIEnvironment : public CBase { if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_GetBuildExecution == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_uienvironment_getrecentbuildjobs", (void**)&(pWrapperTable->m_UIEnvironment_GetRecentBuildJobs)); + if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_GetRecentBuildJobs == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_uienvironment_creatediscretefield2d", (void**)&(pWrapperTable->m_UIEnvironment_CreateDiscreteField2D)); if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_CreateDiscreteField2D == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; @@ -18043,6 +18168,22 @@ class CUIEnvironment : public CBase { if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_AddExternalEventResultValue == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_uienvironment_setstringresult", (void**)&(pWrapperTable->m_UIEnvironment_SetStringResult)); + if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_SetStringResult == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libmcenv_uienvironment_setintegerresult", (void**)&(pWrapperTable->m_UIEnvironment_SetIntegerResult)); + if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_SetIntegerResult == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libmcenv_uienvironment_setboolresult", (void**)&(pWrapperTable->m_UIEnvironment_SetBoolResult)); + if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_SetBoolResult == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libmcenv_uienvironment_setdoubleresult", (void**)&(pWrapperTable->m_UIEnvironment_SetDoubleResult)); + if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_SetDoubleResult == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_uienvironment_getexternaleventparameters", (void**)&(pWrapperTable->m_UIEnvironment_GetExternalEventParameters)); if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_GetExternalEventParameters == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; @@ -23343,6 +23484,25 @@ class CUIEnvironment : public CBase { return std::make_shared(m_pWrapper, hBuildExecutionInstance); } + /** + * Method definitions for class CBuildIterator + */ + + /** + * CBuildIterator::GetCurrentBuild - Returns the build the iterator points at. + * @return returns the Build instance. + */ + PBuild CBuildIterator::GetCurrentBuild() + { + LibMCEnvHandle hBuildInstance = nullptr; + CheckError(m_pWrapper->m_WrapperTable.m_BuildIterator_GetCurrentBuild(m_pHandle, &hBuildInstance)); + + if (!hBuildInstance) { + CheckError(LIBMCENV_ERROR_INVALIDPARAM); + } + return std::make_shared(m_pWrapper, hBuildInstance); + } + /** * Method definitions for class CBuild */ @@ -23377,6 +23537,36 @@ class CUIEnvironment : public CBase { return std::string(&bufferBuildUUID[0]); } + /** + * CBuild::GetCreatedTimestamp - Returns creation timestamp of the build in ISO-8601 format. + * @return Creation timestamp in ISO-8601 format (e.g., 2025-10-23T14:30:00.000Z). + */ + std::string CBuild::GetCreatedTimestamp() + { + LibMCEnv_uint32 bytesNeededTimestamp = 0; + LibMCEnv_uint32 bytesWrittenTimestamp = 0; + CheckError(m_pWrapper->m_WrapperTable.m_Build_GetCreatedTimestamp(m_pHandle, 0, &bytesNeededTimestamp, nullptr)); + std::vector bufferTimestamp(bytesNeededTimestamp); + CheckError(m_pWrapper->m_WrapperTable.m_Build_GetCreatedTimestamp(m_pHandle, bytesNeededTimestamp, &bytesWrittenTimestamp, &bufferTimestamp[0])); + + return std::string(&bufferTimestamp[0]); + } + + /** + * CBuild::GetLastExecutionTimestamp - Returns the most recent execution timestamp in ISO-8601 format. Returns empty string if build has never been executed. + * @return Most recent execution timestamp in ISO-8601 format. Empty string if never executed. + */ + std::string CBuild::GetLastExecutionTimestamp() + { + LibMCEnv_uint32 bytesNeededTimestamp = 0; + LibMCEnv_uint32 bytesWrittenTimestamp = 0; + CheckError(m_pWrapper->m_WrapperTable.m_Build_GetLastExecutionTimestamp(m_pHandle, 0, &bytesNeededTimestamp, nullptr)); + std::vector bufferTimestamp(bytesNeededTimestamp); + CheckError(m_pWrapper->m_WrapperTable.m_Build_GetLastExecutionTimestamp(m_pHandle, bytesNeededTimestamp, &bytesWrittenTimestamp, &bufferTimestamp[0])); + + return std::string(&bufferTimestamp[0]); + } + /** * CBuild::GetStorageUUID - Returns storage uuid of the build stream. * @return Storage UUID of the build. @@ -31695,6 +31885,22 @@ class CUIEnvironment : public CBase { return std::make_shared(m_pWrapper, hExecutionInstance); } + /** + * CUIEnvironment::GetRecentBuildJobs - Returns an iterator for recent build jobs, ordered by timestamp (newest first). + * @param[in] nMaxCount - Maximum number of jobs to return. Must be greater than 0. + * @return Iterator for build jobs, ordered newest first. + */ + PBuildIterator CUIEnvironment::GetRecentBuildJobs(const LibMCEnv_uint32 nMaxCount) + { + LibMCEnvHandle hBuildIterator = nullptr; + CheckError(m_pWrapper->m_WrapperTable.m_UIEnvironment_GetRecentBuildJobs(m_pHandle, nMaxCount, &hBuildIterator)); + + if (!hBuildIterator) { + CheckError(LIBMCENV_ERROR_INVALIDPARAM); + } + return std::make_shared(m_pWrapper, hBuildIterator); + } + /** * CUIEnvironment::CreateDiscreteField2D - Creates an empty discrete field. * @param[in] nPixelCountX - Pixel count in X. MUST be positive. @@ -32186,6 +32392,46 @@ class CUIEnvironment : public CBase { CheckError(m_pWrapper->m_WrapperTable.m_UIEnvironment_AddExternalEventResultValue(m_pHandle, sReturnValueName.c_str(), sReturnValue.c_str())); } + /** + * CUIEnvironment::SetStringResult - Sets a string result value for external event return (typed convenience wrapper). + * @param[in] sReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) + * @param[in] sReturnValue - Return value. + */ + void CUIEnvironment::SetStringResult(const std::string & sReturnValueName, const std::string & sReturnValue) + { + CheckError(m_pWrapper->m_WrapperTable.m_UIEnvironment_SetStringResult(m_pHandle, sReturnValueName.c_str(), sReturnValue.c_str())); + } + + /** + * CUIEnvironment::SetIntegerResult - Sets an integer result value for external event return. + * @param[in] sReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) + * @param[in] nReturnValue - Return value. + */ + void CUIEnvironment::SetIntegerResult(const std::string & sReturnValueName, const LibMCEnv_int64 nReturnValue) + { + CheckError(m_pWrapper->m_WrapperTable.m_UIEnvironment_SetIntegerResult(m_pHandle, sReturnValueName.c_str(), nReturnValue)); + } + + /** + * CUIEnvironment::SetBoolResult - Sets a boolean result value for external event return. + * @param[in] sReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) + * @param[in] bReturnValue - Return value. + */ + void CUIEnvironment::SetBoolResult(const std::string & sReturnValueName, const bool bReturnValue) + { + CheckError(m_pWrapper->m_WrapperTable.m_UIEnvironment_SetBoolResult(m_pHandle, sReturnValueName.c_str(), bReturnValue)); + } + + /** + * CUIEnvironment::SetDoubleResult - Sets a double result value for external event return. + * @param[in] sReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) + * @param[in] dReturnValue - Return value. + */ + void CUIEnvironment::SetDoubleResult(const std::string & sReturnValueName, const LibMCEnv_double dReturnValue) + { + CheckError(m_pWrapper->m_WrapperTable.m_UIEnvironment_SetDoubleResult(m_pHandle, sReturnValueName.c_str(), dReturnValue)); + } + /** * CUIEnvironment::GetExternalEventParameters - Returns the external event parameters. This JSON Object was passed on from the external API. * @return Parameter value. diff --git a/Framework/HeadersDev/CppDynamic/libmcenv_types.hpp b/Framework/HeadersDev/CppDynamic/libmcenv_types.hpp index 42e8f6a1..35641291 100644 --- a/Framework/HeadersDev/CppDynamic/libmcenv_types.hpp +++ b/Framework/HeadersDev/CppDynamic/libmcenv_types.hpp @@ -656,6 +656,7 @@ typedef LibMCEnvHandle LibMCEnv_ToolpathLayer; typedef LibMCEnvHandle LibMCEnv_ToolpathAccessor; typedef LibMCEnvHandle LibMCEnv_BuildExecution; typedef LibMCEnvHandle LibMCEnv_BuildExecutionIterator; +typedef LibMCEnvHandle LibMCEnv_BuildIterator; typedef LibMCEnvHandle LibMCEnv_Build; typedef LibMCEnvHandle LibMCEnv_WorkingFileProcess; typedef LibMCEnvHandle LibMCEnv_WorkingFile; diff --git a/Framework/InterfacesCore/libmcenv_abi.hpp b/Framework/InterfacesCore/libmcenv_abi.hpp index d1f18195..a5e36da0 100644 --- a/Framework/InterfacesCore/libmcenv_abi.hpp +++ b/Framework/InterfacesCore/libmcenv_abi.hpp @@ -4247,6 +4247,19 @@ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_buildexecution_loadattachedjournal(Lib */ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_buildexecutioniterator_getcurrentexecution(LibMCEnv_BuildExecutionIterator pBuildExecutionIterator, LibMCEnv_BuildExecution * pBuildExecutionInstance); +/************************************************************************************************************************* + Class definition for BuildIterator +**************************************************************************************************************************/ + +/** +* Returns the build the iterator points at. +* +* @param[in] pBuildIterator - BuildIterator instance. +* @param[out] pBuildInstance - returns the Build instance. +* @return error code or 0 (success) +*/ +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_builditerator_getcurrentbuild(LibMCEnv_BuildIterator pBuildIterator, LibMCEnv_Build * pBuildInstance); + /************************************************************************************************************************* Class definition for Build **************************************************************************************************************************/ @@ -4273,6 +4286,28 @@ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_build_getname(LibMCEnv_Build pBuild, c */ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_build_getbuilduuid(LibMCEnv_Build pBuild, const LibMCEnv_uint32 nBuildUUIDBufferSize, LibMCEnv_uint32* pBuildUUIDNeededChars, char * pBuildUUIDBuffer); +/** +* Returns creation timestamp of the build in ISO-8601 format. +* +* @param[in] pBuild - Build instance. +* @param[in] nTimestampBufferSize - size of the buffer (including trailing 0) +* @param[out] pTimestampNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pTimestampBuffer - buffer of Creation timestamp in ISO-8601 format (e.g., 2025-10-23T14:30:00.000Z)., may be NULL +* @return error code or 0 (success) +*/ +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_build_getcreatedtimestamp(LibMCEnv_Build pBuild, const LibMCEnv_uint32 nTimestampBufferSize, LibMCEnv_uint32* pTimestampNeededChars, char * pTimestampBuffer); + +/** +* Returns the most recent execution timestamp in ISO-8601 format. Returns empty string if build has never been executed. +* +* @param[in] pBuild - Build instance. +* @param[in] nTimestampBufferSize - size of the buffer (including trailing 0) +* @param[out] pTimestampNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pTimestampBuffer - buffer of Most recent execution timestamp in ISO-8601 format. Empty string if never executed., may be NULL +* @return error code or 0 (success) +*/ +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_build_getlastexecutiontimestamp(LibMCEnv_Build pBuild, const LibMCEnv_uint32 nTimestampBufferSize, LibMCEnv_uint32* pTimestampNeededChars, char * pTimestampBuffer); + /** * Returns storage uuid of the build stream. * @@ -10620,6 +10655,16 @@ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_hasbuildexecution(LibMCE */ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_getbuildexecution(LibMCEnv_UIEnvironment pUIEnvironment, const char * pExecutionUUID, LibMCEnv_BuildExecution * pExecutionInstance); +/** +* Returns an iterator for recent build jobs, ordered by timestamp (newest first). +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] nMaxCount - Maximum number of jobs to return. Must be greater than 0. +* @param[out] pBuildIterator - Iterator for build jobs, ordered newest first. +* @return error code or 0 (success) +*/ +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_getrecentbuildjobs(LibMCEnv_UIEnvironment pUIEnvironment, LibMCEnv_uint32 nMaxCount, LibMCEnv_BuildIterator * pBuildIterator); + /** * Creates an empty discrete field. * @@ -10962,6 +11007,46 @@ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_getexternaleventparamete */ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_addexternaleventresultvalue(LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, const char * pReturnValue); +/** +* Sets a string result value for external event return (typed convenience wrapper). +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] pReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) +* @param[in] pReturnValue - Return value. +* @return error code or 0 (success) +*/ +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_setstringresult(LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, const char * pReturnValue); + +/** +* Sets an integer result value for external event return. +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] pReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) +* @param[in] nReturnValue - Return value. +* @return error code or 0 (success) +*/ +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_setintegerresult(LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, LibMCEnv_int64 nReturnValue); + +/** +* Sets a boolean result value for external event return. +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] pReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) +* @param[in] bReturnValue - Return value. +* @return error code or 0 (success) +*/ +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_setboolresult(LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, bool bReturnValue); + +/** +* Sets a double result value for external event return. +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] pReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) +* @param[in] dReturnValue - Return value. +* @return error code or 0 (success) +*/ +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_setdoubleresult(LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, LibMCEnv_double dReturnValue); + /** * Returns the external event parameters. This JSON Object was passed on from the external API. * diff --git a/Framework/InterfacesCore/libmcenv_interfaces.hpp b/Framework/InterfacesCore/libmcenv_interfaces.hpp index 31e3e2e8..71734574 100644 --- a/Framework/InterfacesCore/libmcenv_interfaces.hpp +++ b/Framework/InterfacesCore/libmcenv_interfaces.hpp @@ -92,6 +92,7 @@ class IToolpathLayer; class IToolpathAccessor; class IBuildExecution; class IBuildExecutionIterator; +class IBuildIterator; class IBuild; class IWorkingFileProcess; class IWorkingFile; @@ -3517,6 +3518,23 @@ class IBuildExecutionIterator : public virtual IIterator { typedef IBaseSharedPtr PIBuildExecutionIterator; +/************************************************************************************************************************* + Class interface for BuildIterator +**************************************************************************************************************************/ + +class IBuildIterator : public virtual IIterator { +public: + /** + * IBuildIterator::GetCurrentBuild - Returns the build the iterator points at. + * @return returns the Build instance. + */ + virtual IBuild * GetCurrentBuild() = 0; + +}; + +typedef IBaseSharedPtr PIBuildIterator; + + /************************************************************************************************************************* Class interface for Build **************************************************************************************************************************/ @@ -3535,6 +3553,18 @@ class IBuild : public virtual IBase { */ virtual std::string GetBuildUUID() = 0; + /** + * IBuild::GetCreatedTimestamp - Returns creation timestamp of the build in ISO-8601 format. + * @return Creation timestamp in ISO-8601 format (e.g., 2025-10-23T14:30:00.000Z). + */ + virtual std::string GetCreatedTimestamp() = 0; + + /** + * IBuild::GetLastExecutionTimestamp - Returns the most recent execution timestamp in ISO-8601 format. Returns empty string if build has never been executed. + * @return Most recent execution timestamp in ISO-8601 format. Empty string if never executed. + */ + virtual std::string GetLastExecutionTimestamp() = 0; + /** * IBuild::GetStorageUUID - Returns storage uuid of the build stream. * @return Storage UUID of the build. @@ -8141,6 +8171,13 @@ class IUIEnvironment : public virtual IBase { */ virtual IBuildExecution * GetBuildExecution(const std::string & sExecutionUUID) = 0; + /** + * IUIEnvironment::GetRecentBuildJobs - Returns an iterator for recent build jobs, ordered by timestamp (newest first). + * @param[in] nMaxCount - Maximum number of jobs to return. Must be greater than 0. + * @return Iterator for build jobs, ordered newest first. + */ + virtual IBuildIterator * GetRecentBuildJobs(const LibMCEnv_uint32 nMaxCount) = 0; + /** * IUIEnvironment::CreateDiscreteField2D - Creates an empty discrete field. * @param[in] nPixelCountX - Pixel count in X. MUST be positive. @@ -8375,6 +8412,34 @@ class IUIEnvironment : public virtual IBase { */ virtual void AddExternalEventResultValue(const std::string & sReturnValueName, const std::string & sReturnValue) = 0; + /** + * IUIEnvironment::SetStringResult - Sets a string result value for external event return (typed convenience wrapper). + * @param[in] sReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) + * @param[in] sReturnValue - Return value. + */ + virtual void SetStringResult(const std::string & sReturnValueName, const std::string & sReturnValue) = 0; + + /** + * IUIEnvironment::SetIntegerResult - Sets an integer result value for external event return. + * @param[in] sReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) + * @param[in] nReturnValue - Return value. + */ + virtual void SetIntegerResult(const std::string & sReturnValueName, const LibMCEnv_int64 nReturnValue) = 0; + + /** + * IUIEnvironment::SetBoolResult - Sets a boolean result value for external event return. + * @param[in] sReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) + * @param[in] bReturnValue - Return value. + */ + virtual void SetBoolResult(const std::string & sReturnValueName, const bool bReturnValue) = 0; + + /** + * IUIEnvironment::SetDoubleResult - Sets a double result value for external event return. + * @param[in] sReturnValueName - The name of the return parameter. MUST be an alphanumeric ASCII string (with optional _ and -) + * @param[in] dReturnValue - Return value. + */ + virtual void SetDoubleResult(const std::string & sReturnValueName, const LibMCEnv_double dReturnValue) = 0; + /** * IUIEnvironment::GetExternalEventParameters - Returns the external event parameters. This JSON Object was passed on from the external API. * @return Parameter value. diff --git a/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp b/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp index 39955d16..209caba7 100644 --- a/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp +++ b/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp @@ -12187,6 +12187,38 @@ LibMCEnvResult libmcenv_buildexecutioniterator_getcurrentexecution(LibMCEnv_Buil } +/************************************************************************************************************************* + Class implementation for BuildIterator +**************************************************************************************************************************/ +LibMCEnvResult libmcenv_builditerator_getcurrentbuild(LibMCEnv_BuildIterator pBuildIterator, LibMCEnv_Build * pBuildInstance) +{ + IBase* pIBaseClass = (IBase *)pBuildIterator; + + try { + if (pBuildInstance == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + IBase* pBaseBuildInstance(nullptr); + IBuildIterator* pIBuildIterator = dynamic_cast(pIBaseClass); + if (!pIBuildIterator) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + pBaseBuildInstance = pIBuildIterator->GetCurrentBuild(); + + *pBuildInstance = (IBase*)(pBaseBuildInstance); + return LIBMCENV_SUCCESS; + } + catch (ELibMCEnvInterfaceException & Exception) { + return handleLibMCEnvException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + + /************************************************************************************************************************* Class implementation for Build **************************************************************************************************************************/ @@ -12286,6 +12318,102 @@ LibMCEnvResult libmcenv_build_getbuilduuid(LibMCEnv_Build pBuild, const LibMCEnv } } +LibMCEnvResult libmcenv_build_getcreatedtimestamp(LibMCEnv_Build pBuild, const LibMCEnv_uint32 nTimestampBufferSize, LibMCEnv_uint32* pTimestampNeededChars, char * pTimestampBuffer) +{ + IBase* pIBaseClass = (IBase *)pBuild; + + try { + if ( (!pTimestampBuffer) && !(pTimestampNeededChars) ) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sTimestamp(""); + IBuild* pIBuild = dynamic_cast(pIBaseClass); + if (!pIBuild) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + bool isCacheCall = (pTimestampBuffer == nullptr); + if (isCacheCall) { + sTimestamp = pIBuild->GetCreatedTimestamp(); + + pIBuild->_setCache (new ParameterCache_1 (sTimestamp)); + } + else { + auto cache = dynamic_cast*> (pIBuild->_getCache ()); + if (cache == nullptr) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + cache->retrieveData (sTimestamp); + pIBuild->_setCache (nullptr); + } + + if (pTimestampNeededChars) + *pTimestampNeededChars = (LibMCEnv_uint32) (sTimestamp.size()+1); + if (pTimestampBuffer) { + if (sTimestamp.size() >= nTimestampBufferSize) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_BUFFERTOOSMALL); + for (size_t iTimestamp = 0; iTimestamp < sTimestamp.size(); iTimestamp++) + pTimestampBuffer[iTimestamp] = sTimestamp[iTimestamp]; + pTimestampBuffer[sTimestamp.size()] = 0; + } + return LIBMCENV_SUCCESS; + } + catch (ELibMCEnvInterfaceException & Exception) { + return handleLibMCEnvException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibMCEnvResult libmcenv_build_getlastexecutiontimestamp(LibMCEnv_Build pBuild, const LibMCEnv_uint32 nTimestampBufferSize, LibMCEnv_uint32* pTimestampNeededChars, char * pTimestampBuffer) +{ + IBase* pIBaseClass = (IBase *)pBuild; + + try { + if ( (!pTimestampBuffer) && !(pTimestampNeededChars) ) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sTimestamp(""); + IBuild* pIBuild = dynamic_cast(pIBaseClass); + if (!pIBuild) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + bool isCacheCall = (pTimestampBuffer == nullptr); + if (isCacheCall) { + sTimestamp = pIBuild->GetLastExecutionTimestamp(); + + pIBuild->_setCache (new ParameterCache_1 (sTimestamp)); + } + else { + auto cache = dynamic_cast*> (pIBuild->_getCache ()); + if (cache == nullptr) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + cache->retrieveData (sTimestamp); + pIBuild->_setCache (nullptr); + } + + if (pTimestampNeededChars) + *pTimestampNeededChars = (LibMCEnv_uint32) (sTimestamp.size()+1); + if (pTimestampBuffer) { + if (sTimestamp.size() >= nTimestampBufferSize) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_BUFFERTOOSMALL); + for (size_t iTimestamp = 0; iTimestamp < sTimestamp.size(); iTimestamp++) + pTimestampBuffer[iTimestamp] = sTimestamp[iTimestamp]; + pTimestampBuffer[sTimestamp.size()] = 0; + } + return LIBMCENV_SUCCESS; + } + catch (ELibMCEnvInterfaceException & Exception) { + return handleLibMCEnvException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + LibMCEnvResult libmcenv_build_getstorageuuid(LibMCEnv_Build pBuild, const LibMCEnv_uint32 nStorageUUIDBufferSize, LibMCEnv_uint32* pStorageUUIDNeededChars, char * pStorageUUIDBuffer) { IBase* pIBaseClass = (IBase *)pBuild; @@ -31988,6 +32116,34 @@ LibMCEnvResult libmcenv_uienvironment_getbuildexecution(LibMCEnv_UIEnvironment p } } +LibMCEnvResult libmcenv_uienvironment_getrecentbuildjobs(LibMCEnv_UIEnvironment pUIEnvironment, LibMCEnv_uint32 nMaxCount, LibMCEnv_BuildIterator * pBuildIterator) +{ + IBase* pIBaseClass = (IBase *)pUIEnvironment; + + try { + if (pBuildIterator == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + IBase* pBaseBuildIterator(nullptr); + IUIEnvironment* pIUIEnvironment = dynamic_cast(pIBaseClass); + if (!pIUIEnvironment) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + pBaseBuildIterator = pIUIEnvironment->GetRecentBuildJobs(nMaxCount); + + *pBuildIterator = (IBase*)(pBaseBuildIterator); + return LIBMCENV_SUCCESS; + } + catch (ELibMCEnvInterfaceException & Exception) { + return handleLibMCEnvException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + LibMCEnvResult libmcenv_uienvironment_creatediscretefield2d(LibMCEnv_UIEnvironment pUIEnvironment, LibMCEnv_uint32 nPixelCountX, LibMCEnv_uint32 nPixelCountY, LibMCEnv_double dDPIValueX, LibMCEnv_double dDPIValueY, LibMCEnv_double dOriginX, LibMCEnv_double dOriginY, LibMCEnv_double dDefaultValue, LibMCEnv_DiscreteFieldData2D * pFieldDataInstance) { IBase* pIBaseClass = (IBase *)pUIEnvironment; @@ -33044,6 +33200,117 @@ LibMCEnvResult libmcenv_uienvironment_addexternaleventresultvalue(LibMCEnv_UIEnv } } +LibMCEnvResult libmcenv_uienvironment_setstringresult(LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, const char * pReturnValue) +{ + IBase* pIBaseClass = (IBase *)pUIEnvironment; + + try { + if (pReturnValueName == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + if (pReturnValue == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sReturnValueName(pReturnValueName); + std::string sReturnValue(pReturnValue); + IUIEnvironment* pIUIEnvironment = dynamic_cast(pIBaseClass); + if (!pIUIEnvironment) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + pIUIEnvironment->SetStringResult(sReturnValueName, sReturnValue); + + return LIBMCENV_SUCCESS; + } + catch (ELibMCEnvInterfaceException & Exception) { + return handleLibMCEnvException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibMCEnvResult libmcenv_uienvironment_setintegerresult(LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, LibMCEnv_int64 nReturnValue) +{ + IBase* pIBaseClass = (IBase *)pUIEnvironment; + + try { + if (pReturnValueName == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sReturnValueName(pReturnValueName); + IUIEnvironment* pIUIEnvironment = dynamic_cast(pIBaseClass); + if (!pIUIEnvironment) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + pIUIEnvironment->SetIntegerResult(sReturnValueName, nReturnValue); + + return LIBMCENV_SUCCESS; + } + catch (ELibMCEnvInterfaceException & Exception) { + return handleLibMCEnvException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibMCEnvResult libmcenv_uienvironment_setboolresult(LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, bool bReturnValue) +{ + IBase* pIBaseClass = (IBase *)pUIEnvironment; + + try { + if (pReturnValueName == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sReturnValueName(pReturnValueName); + IUIEnvironment* pIUIEnvironment = dynamic_cast(pIBaseClass); + if (!pIUIEnvironment) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + pIUIEnvironment->SetBoolResult(sReturnValueName, bReturnValue); + + return LIBMCENV_SUCCESS; + } + catch (ELibMCEnvInterfaceException & Exception) { + return handleLibMCEnvException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibMCEnvResult libmcenv_uienvironment_setdoubleresult(LibMCEnv_UIEnvironment pUIEnvironment, const char * pReturnValueName, LibMCEnv_double dReturnValue) +{ + IBase* pIBaseClass = (IBase *)pUIEnvironment; + + try { + if (pReturnValueName == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sReturnValueName(pReturnValueName); + IUIEnvironment* pIUIEnvironment = dynamic_cast(pIBaseClass); + if (!pIUIEnvironment) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + pIUIEnvironment->SetDoubleResult(sReturnValueName, dReturnValue); + + return LIBMCENV_SUCCESS; + } + catch (ELibMCEnvInterfaceException & Exception) { + return handleLibMCEnvException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + LibMCEnvResult libmcenv_uienvironment_getexternaleventparameters(LibMCEnv_UIEnvironment pUIEnvironment, LibMCEnv_JSONObject * pParameterValue) { IBase* pIBaseClass = (IBase *)pUIEnvironment; @@ -33927,10 +34194,16 @@ LibMCEnvResult LibMCEnv::Impl::LibMCEnv_GetProcAddress (const char * pProcName, *ppProcAddress = (void*) &libmcenv_buildexecution_loadattachedjournal; if (sProcName == "libmcenv_buildexecutioniterator_getcurrentexecution") *ppProcAddress = (void*) &libmcenv_buildexecutioniterator_getcurrentexecution; + if (sProcName == "libmcenv_builditerator_getcurrentbuild") + *ppProcAddress = (void*) &libmcenv_builditerator_getcurrentbuild; if (sProcName == "libmcenv_build_getname") *ppProcAddress = (void*) &libmcenv_build_getname; if (sProcName == "libmcenv_build_getbuilduuid") *ppProcAddress = (void*) &libmcenv_build_getbuilduuid; + if (sProcName == "libmcenv_build_getcreatedtimestamp") + *ppProcAddress = (void*) &libmcenv_build_getcreatedtimestamp; + if (sProcName == "libmcenv_build_getlastexecutiontimestamp") + *ppProcAddress = (void*) &libmcenv_build_getlastexecutiontimestamp; if (sProcName == "libmcenv_build_getstorageuuid") *ppProcAddress = (void*) &libmcenv_build_getstorageuuid; if (sProcName == "libmcenv_build_getstoragesha256") @@ -35117,6 +35390,8 @@ LibMCEnvResult LibMCEnv::Impl::LibMCEnv_GetProcAddress (const char * pProcName, *ppProcAddress = (void*) &libmcenv_uienvironment_hasbuildexecution; if (sProcName == "libmcenv_uienvironment_getbuildexecution") *ppProcAddress = (void*) &libmcenv_uienvironment_getbuildexecution; + if (sProcName == "libmcenv_uienvironment_getrecentbuildjobs") + *ppProcAddress = (void*) &libmcenv_uienvironment_getrecentbuildjobs; if (sProcName == "libmcenv_uienvironment_creatediscretefield2d") *ppProcAddress = (void*) &libmcenv_uienvironment_creatediscretefield2d; if (sProcName == "libmcenv_uienvironment_creatediscretefield2dfromimage") @@ -35181,6 +35456,14 @@ LibMCEnvResult LibMCEnv::Impl::LibMCEnv_GetProcAddress (const char * pProcName, *ppProcAddress = (void*) &libmcenv_uienvironment_getexternaleventparameter; if (sProcName == "libmcenv_uienvironment_addexternaleventresultvalue") *ppProcAddress = (void*) &libmcenv_uienvironment_addexternaleventresultvalue; + if (sProcName == "libmcenv_uienvironment_setstringresult") + *ppProcAddress = (void*) &libmcenv_uienvironment_setstringresult; + if (sProcName == "libmcenv_uienvironment_setintegerresult") + *ppProcAddress = (void*) &libmcenv_uienvironment_setintegerresult; + if (sProcName == "libmcenv_uienvironment_setboolresult") + *ppProcAddress = (void*) &libmcenv_uienvironment_setboolresult; + if (sProcName == "libmcenv_uienvironment_setdoubleresult") + *ppProcAddress = (void*) &libmcenv_uienvironment_setdoubleresult; if (sProcName == "libmcenv_uienvironment_getexternaleventparameters") *ppProcAddress = (void*) &libmcenv_uienvironment_getexternaleventparameters; if (sProcName == "libmcenv_uienvironment_getexternaleventresults") diff --git a/Framework/InterfacesCore/libmcenv_types.hpp b/Framework/InterfacesCore/libmcenv_types.hpp index 42e8f6a1..35641291 100644 --- a/Framework/InterfacesCore/libmcenv_types.hpp +++ b/Framework/InterfacesCore/libmcenv_types.hpp @@ -656,6 +656,7 @@ typedef LibMCEnvHandle LibMCEnv_ToolpathLayer; typedef LibMCEnvHandle LibMCEnv_ToolpathAccessor; typedef LibMCEnvHandle LibMCEnv_BuildExecution; typedef LibMCEnvHandle LibMCEnv_BuildExecutionIterator; +typedef LibMCEnvHandle LibMCEnv_BuildIterator; typedef LibMCEnvHandle LibMCEnv_Build; typedef LibMCEnvHandle LibMCEnv_WorkingFileProcess; typedef LibMCEnvHandle LibMCEnv_WorkingFile; diff --git a/Implementation/LibMCEnv/libmcenv_build.cpp b/Implementation/LibMCEnv/libmcenv_build.cpp index d7b3dd6d..2cdab0a6 100644 --- a/Implementation/LibMCEnv/libmcenv_build.cpp +++ b/Implementation/LibMCEnv/libmcenv_build.cpp @@ -81,6 +81,19 @@ CBuild::~CBuild() { } +CBuild* CBuild::makeFrom(CBuild* pBuild) +{ + if (pBuild == nullptr) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDPARAM); + + return new CBuild(pBuild->m_pDataModel, pBuild->m_sBuildJobUUID, pBuild->m_pToolpathHandler, pBuild->m_pMeshHandler, pBuild->m_pGlobalChrono, pBuild->m_pStateJournal); +} + +std::shared_ptr CBuild::makeSharedFrom(CBuild* pBuild) +{ + return std::shared_ptr(makeFrom(pBuild)); +} + std::string CBuild::GetName() { auto pBuildJobHandler = m_pDataModel->CreateBuildJobHandler(); @@ -95,6 +108,39 @@ std::string CBuild::GetBuildUUID() return pBuildJob->GetUUID(); } +std::string CBuild::GetCreatedTimestamp() +{ + auto pBuildJobHandler = m_pDataModel->CreateBuildJobHandler(); + auto pBuildJob = pBuildJobHandler->RetrieveJob(m_sBuildJobUUID); + return pBuildJob->GetTimeStamp(); +} + +std::string CBuild::GetLastExecutionTimestamp() +{ + auto pBuildJobHandler = m_pDataModel->CreateBuildJobHandler(); + auto pBuildJob = pBuildJobHandler->RetrieveJob(m_sBuildJobUUID); + + // Find the latest execution timestamp + std::string sLatestExecutionTime = ""; + uint64_t nLatestExecutionMicroseconds = 0; + + auto pJobExecutionIterator = pBuildJob->RetrieveBuildJobExecutions(""); + while (pJobExecutionIterator->MoveNext()) { + auto pJobExecution = pJobExecutionIterator->GetCurrentJobExecution(); + uint64_t nExecutionTime = pJobExecution->GetStartTimeStampInMicroseconds(); + if (nExecutionTime > nLatestExecutionMicroseconds) { + nLatestExecutionMicroseconds = nExecutionTime; + } + } + + // Convert to ISO 8601 format if we found any executions + if (nLatestExecutionMicroseconds > 0) { + sLatestExecutionTime = AMCCommon::CChrono::convertToISO8601TimeUTC(nLatestExecutionMicroseconds); + } + + return sLatestExecutionTime; +} + std::string CBuild::GetStorageUUID() { auto pBuildJobHandler = m_pDataModel->CreateBuildJobHandler(); diff --git a/Implementation/LibMCEnv/libmcenv_build.hpp b/Implementation/LibMCEnv/libmcenv_build.hpp index de140f2f..f793b02d 100644 --- a/Implementation/LibMCEnv/libmcenv_build.hpp +++ b/Implementation/LibMCEnv/libmcenv_build.hpp @@ -73,10 +73,18 @@ class CBuild : public virtual IBuild, public virtual CBase { virtual ~CBuild(); + static CBuild* makeFrom (CBuild * pBuild); + + static std::shared_ptr makeSharedFrom(CBuild* pBuild); + std::string GetName() override; std::string GetBuildUUID() override; + std::string GetCreatedTimestamp() override; + + std::string GetLastExecutionTimestamp() override; + std::string GetStorageUUID() override; std::string GetStorageSHA256() override; diff --git a/Implementation/LibMCEnv/libmcenv_builditerator.cpp b/Implementation/LibMCEnv/libmcenv_builditerator.cpp new file mode 100644 index 00000000..0250eaf7 --- /dev/null +++ b/Implementation/LibMCEnv/libmcenv_builditerator.cpp @@ -0,0 +1,97 @@ +/*++ + +Copyright (C) 2020 Autodesk Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Autodesk Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AUTODESK INC. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Abstract: This is a stub class definition of CBuildIterator + +*/ + +#include "libmcenv_builditerator.hpp" +#include "libmcenv_interfaceexception.hpp" + +// Include custom headers here. + + +using namespace LibMCEnv::Impl; + +/************************************************************************************************************************* + Class definition of CBuildIterator +**************************************************************************************************************************/ + +CBuildIterator::CBuildIterator() +{ + +} + +CBuildIterator::~CBuildIterator() +{ + +} + + +IBase* CBuildIterator::GetCurrent() +{ + return GetCurrentBuild(); +} + +IBuild* CBuildIterator::GetCurrentBuild() +{ + if ((m_nCurrentIndex < 0) || (m_nCurrentIndex >= m_List.size())) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDITERATOR); + + auto pBuild = std::dynamic_pointer_cast (m_List[m_nCurrentIndex]); + if (pBuild.get() == nullptr) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + return CBuild::makeFrom(pBuild.get()); +} + + +IIterator* CBuildIterator::Clone() +{ + std::unique_ptr pNewIterator(new CBuildIterator()); + + for (auto pBase : m_List) { + auto pBuild = std::dynamic_pointer_cast (pBase); + if (pBuild.get() == nullptr) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + pNewIterator->AddBuild(CBuild::makeSharedFrom(pBuild.get())); + } + + return pNewIterator.release(); +} + +void CBuildIterator::AddBuild(std::shared_ptr pBuild) +{ + if (pBuild.get() == nullptr) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDPARAM); + + m_List.push_back(pBuild); +} + + diff --git a/Implementation/LibMCEnv/libmcenv_builditerator.hpp b/Implementation/LibMCEnv/libmcenv_builditerator.hpp new file mode 100644 index 00000000..a2d8aa90 --- /dev/null +++ b/Implementation/LibMCEnv/libmcenv_builditerator.hpp @@ -0,0 +1,82 @@ +/*++ + +Copyright (C) 2020 Autodesk Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Autodesk Inc. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AUTODESK INC. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Abstract: This is the class declaration of CBuildIterator + +*/ + + +#ifndef __LIBMCENV_BUILDITERATOR +#define __LIBMCENV_BUILDITERATOR + +#include "libmcenv_interfaces.hpp" + +// Parent classes +#include "libmcenv_iterator.hpp" +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4250) +#endif + +// Include custom headers here. +#include "libmcenv_build.hpp" + + +namespace LibMCEnv { +namespace Impl { + + +/************************************************************************************************************************* + Class declaration of CBuildIterator +**************************************************************************************************************************/ + +class CBuildIterator : public virtual IBuildIterator, public virtual CIterator { + +public: + CBuildIterator(); + + virtual ~CBuildIterator(); + + IIterator* Clone() override; + + IBase* GetCurrent() override; + + IBuild* GetCurrentBuild() override; + + void AddBuild(std::shared_ptr pBuild); + +}; + +} // namespace Impl +} // namespace LibMCEnv + +#ifdef _MSC_VER +#pragma warning(pop) +#endif +#endif // __LIBMCENV_BUILDITERATOR diff --git a/Implementation/LibMCEnv/libmcenv_uienvironment.cpp b/Implementation/LibMCEnv/libmcenv_uienvironment.cpp index afc93668..739d1626 100644 --- a/Implementation/LibMCEnv/libmcenv_uienvironment.cpp +++ b/Implementation/LibMCEnv/libmcenv_uienvironment.cpp @@ -60,6 +60,7 @@ Abstract: This is a stub class definition of CUIEnvironment #include "libmcenv_imagedata.hpp" #include "libmcenv_testenvironment.hpp" #include "libmcenv_build.hpp" +#include "libmcenv_builditerator.hpp" #include "libmcenv_buildexecution.hpp" #include "libmcenv_streamreader.hpp" #include "libmcenv_datatable.hpp" @@ -617,6 +618,32 @@ IBuildExecution* CUIEnvironment::GetBuildExecution(const std::string& sExecution } +IBuildIterator* CUIEnvironment::GetRecentBuildJobs(const LibMCEnv_uint32 nMaxCount) +{ + if (nMaxCount == 0) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDPARAM, "MaxCount must be greater than 0"); + + auto pDataModel = m_pUISystemState->getDataModel(); + auto pBuildJobHandler = pDataModel->CreateBuildJobHandler(); + auto pBuildJobIterator = pBuildJobHandler->ListJobsByStatus(LibMCData::eBuildJobStatus::Validated); + + std::unique_ptr pResultIterator(new CBuildIterator()); + + uint32_t nCount = 0; + while (pBuildJobIterator->MoveNext() && (nCount < nMaxCount)) { + auto pBuildJob = pBuildJobIterator->GetCurrentJob(); + auto pBuild = std::make_shared(pDataModel, pBuildJob->GetUUID(), + m_pUISystemState->getToolpathHandler(), + m_pUISystemState->getMeshHandler(), + m_pUISystemState->getGlobalChronoInstance(), + m_pUISystemState->getStateJournal()); + pResultIterator->AddBuild(pBuild); + nCount++; + } + + return pResultIterator.release(); +} + IDiscreteFieldData2D* CUIEnvironment::CreateDiscreteField2D(const LibMCEnv_uint32 nPixelSizeX, const LibMCEnv_uint32 nPixelSizeY, const LibMCEnv_double dDPIValueX, const LibMCEnv_double dDPIValueY, const LibMCEnv_double dOriginX, const LibMCEnv_double dOriginY, const LibMCEnv_double dDefaultValue) { @@ -1024,6 +1051,69 @@ void CUIEnvironment::AddExternalEventResultValue(const std::string& sReturnValue m_ExternalEventReturnValues->AddMember(jsonName, jsonValue, m_ExternalEventReturnValues->GetAllocator ()); } +void CUIEnvironment::SetStringResult(const std::string& sReturnValueName, const std::string& sReturnValue) +{ + // Convenience wrapper for AddExternalEventResultValue + AddExternalEventResultValue(sReturnValueName, sReturnValue); +} + +void CUIEnvironment::SetIntegerResult(const std::string& sReturnValueName, const LibMCEnv_int64 nReturnValue) +{ + if (!AMCCommon::CUtils::stringIsValidAlphanumericNameString(sReturnValueName)) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDEXTERNALEVENTRETURNVALUEKEY, "invalid external return value key: " + sReturnValueName); + + if (AMC::CUIHandleEventResponse::externalValueNameIsReserved(sReturnValueName)) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_EXTERNALEVENTRETURNVALUEKEYISRESERVED, "external return value key is reserved: " + sReturnValueName); + + if (m_ExternalEventReturnValues->HasMember(sReturnValueName.c_str())) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_DUPLICATEEXTERNALEVENTRETURNKEY, "duplicate external event return key: " + sReturnValueName); + + rapidjson::Value jsonName; + rapidjson::Value jsonValue; + + jsonName.SetString(sReturnValueName.c_str(), m_ExternalEventReturnValues->GetAllocator()); + jsonValue.SetInt64(nReturnValue); + m_ExternalEventReturnValues->AddMember(jsonName, jsonValue, m_ExternalEventReturnValues->GetAllocator()); +} + +void CUIEnvironment::SetBoolResult(const std::string& sReturnValueName, const bool bReturnValue) +{ + if (!AMCCommon::CUtils::stringIsValidAlphanumericNameString(sReturnValueName)) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDEXTERNALEVENTRETURNVALUEKEY, "invalid external return value key: " + sReturnValueName); + + if (AMC::CUIHandleEventResponse::externalValueNameIsReserved(sReturnValueName)) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_EXTERNALEVENTRETURNVALUEKEYISRESERVED, "external return value key is reserved: " + sReturnValueName); + + if (m_ExternalEventReturnValues->HasMember(sReturnValueName.c_str())) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_DUPLICATEEXTERNALEVENTRETURNKEY, "duplicate external event return key: " + sReturnValueName); + + rapidjson::Value jsonName; + rapidjson::Value jsonValue; + + jsonName.SetString(sReturnValueName.c_str(), m_ExternalEventReturnValues->GetAllocator()); + jsonValue.SetBool(bReturnValue); + m_ExternalEventReturnValues->AddMember(jsonName, jsonValue, m_ExternalEventReturnValues->GetAllocator()); +} + +void CUIEnvironment::SetDoubleResult(const std::string& sReturnValueName, const LibMCEnv_double dReturnValue) +{ + if (!AMCCommon::CUtils::stringIsValidAlphanumericNameString(sReturnValueName)) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDEXTERNALEVENTRETURNVALUEKEY, "invalid external return value key: " + sReturnValueName); + + if (AMC::CUIHandleEventResponse::externalValueNameIsReserved(sReturnValueName)) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_EXTERNALEVENTRETURNVALUEKEYISRESERVED, "external return value key is reserved: " + sReturnValueName); + + if (m_ExternalEventReturnValues->HasMember(sReturnValueName.c_str())) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_DUPLICATEEXTERNALEVENTRETURNKEY, "duplicate external event return key: " + sReturnValueName); + + rapidjson::Value jsonName; + rapidjson::Value jsonValue; + + jsonName.SetString(sReturnValueName.c_str(), m_ExternalEventReturnValues->GetAllocator()); + jsonValue.SetDouble(dReturnValue); + m_ExternalEventReturnValues->AddMember(jsonName, jsonValue, m_ExternalEventReturnValues->GetAllocator()); +} + IJSONObject* CUIEnvironment::GetExternalEventParameters() { return new CJSONObject(m_ExternalEventParameters, m_ExternalEventParameters.get()); diff --git a/Implementation/LibMCEnv/libmcenv_uienvironment.hpp b/Implementation/LibMCEnv/libmcenv_uienvironment.hpp index 10f409de..9ba33b23 100644 --- a/Implementation/LibMCEnv/libmcenv_uienvironment.hpp +++ b/Implementation/LibMCEnv/libmcenv_uienvironment.hpp @@ -198,6 +198,8 @@ class CUIEnvironment : public virtual IUIEnvironment, public virtual CBase { IBuildExecution* GetBuildExecution(const std::string& sExecutionUUID) override; + IBuildIterator* GetRecentBuildJobs(const LibMCEnv_uint32 nMaxCount) override; + IDiscreteFieldData2D* CreateDiscreteField2D(const LibMCEnv_uint32 nPixelSizeX, const LibMCEnv_uint32 nPixelSizeY, const LibMCEnv_double dDPIValueX, const LibMCEnv_double dDPIValueY, const LibMCEnv_double dOriginX, const LibMCEnv_double dOriginY, const LibMCEnv_double dDefaultValue) override; IDiscreteFieldData2D* CreateDiscreteField2DFromImage(IImageData* pImageDataInstance, const LibMCEnv_double dBlackValue, const LibMCEnv_double dWhiteValue, const LibMCEnv_double dOriginX, const LibMCEnv_double dOriginY) override; @@ -268,6 +270,15 @@ class CUIEnvironment : public virtual IUIEnvironment, public virtual CBase { void AddExternalEventResultValue(const std::string& sReturnValueName, const std::string& sReturnValue) override; + // Typed result setters for /api/ext event handlers + void SetStringResult(const std::string& sReturnValueName, const std::string& sReturnValue) override; + + void SetIntegerResult(const std::string& sReturnValueName, const LibMCEnv_int64 nReturnValue) override; + + void SetBoolResult(const std::string& sReturnValueName, const bool bReturnValue) override; + + void SetDoubleResult(const std::string& sReturnValueName, const LibMCEnv_double dReturnValue) override; + IJSONObject* GetExternalEventParameters() override; IJSONObject* GetExternalEventResults() override; From cb6bef30213007db468d35f13cba231ee78acefe Mon Sep 17 00:00:00 2001 From: krixkrix Date: Sun, 18 Jan 2026 01:44:17 +0100 Subject: [PATCH 14/19] Building dev package: preserve Unix file permissions (#63) --- BuildScripts/createDevPackage.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/BuildScripts/createDevPackage.go b/BuildScripts/createDevPackage.go index fd0adc1d..2a262480 100644 --- a/BuildScripts/createDevPackage.go +++ b/BuildScripts/createDevPackage.go @@ -23,22 +23,28 @@ func addFile (zipWriter * zip.Writer, diskPath string, zipPath string) (error) { if err != nil { return err } - - + + // Get file info to preserve permissions + fileInfo, err := os.Stat(diskPath) + if err != nil { + return err + } + var header zip.FileHeader; header.Name = zipPath; header.Method = zip.Deflate; - + header.SetMode(fileInfo.Mode()); // Preserve Unix file permissions + filewriter, err := zipWriter.CreateHeader(&header) if err != nil { return err } - + _, err = filewriter.Write(input) if err != nil { return err } - + return nil; } From 7e69912285126fbe1ba001ec8e2002909d249548 Mon Sep 17 00:00:00 2001 From: krixkrix Date: Sun, 18 Jan 2026 01:44:52 +0100 Subject: [PATCH 15/19] build tool: add ACT/generate.sh as the linux equivalent of ACT/generate.bat (#60) --- ACT/generate.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100755 ACT/generate.sh diff --git a/ACT/generate.sh b/ACT/generate.sh new file mode 100755 index 00000000..4137bf15 --- /dev/null +++ b/ACT/generate.sh @@ -0,0 +1,8 @@ + +./act.linux LibMCEnv.xml -bindings ../Framework/HeadersDev -interfaces ../Framework/InterfacesCore -suppresssubcomponents -suppresslicense -suppressstub -suppressexamples +./act.linux LibMCPlugin.xml -bindings ../Framework/HeadersCore -interfaces ../Framework/InterfacesDev -suppresssubcomponents -suppresslicense -suppressstub -suppressexamples +./act.linux LibMCUI.xml -bindings ../Framework/HeadersCore -interfaces ../Framework/InterfacesDev -suppresssubcomponents -suppresslicense -suppressstub -suppressexamples +./act.linux LibMCDriver.xml -bindings ../Framework/HeadersCore -interfaces ../Framework/InterfacesDev -suppresssubcomponents -suppresslicense -suppressstub -suppressexamples +./act.linux LibMCData.xml -bindings ../Framework/HeadersCore -interfaces ../Framework/InterfacesCore -suppresssubcomponents -suppresslicense -suppressstub -suppressexamples +./act.linux LibMC.xml -bindings ../Framework/HeadersCore -interfaces ../Framework/InterfacesCore -suppresssubcomponents -suppresslicense -suppressstub -suppressexamples + From b20f6fe9bd5e622b29a96fa462ea2ef775f3b007 Mon Sep 17 00:00:00 2001 From: krixkrix Date: Sun, 18 Jan 2026 01:45:46 +0100 Subject: [PATCH 16/19] build_clean_linux64.sh: forward additional arguments to CMake build system (#62) E.g. to exclude drivers from build: ./build_clean_linux64.sh -DINCLUDE_DRIVERS=OFF --- build_clean_linux64.sh | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/build_clean_linux64.sh b/build_clean_linux64.sh index acf85a64..d1dca4c5 100755 --- a/build_clean_linux64.sh +++ b/build_clean_linux64.sh @@ -7,18 +7,21 @@ export GO111MODULE="off" basepath="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" PLATFORMNAME="linux64" +CMAKE_OPTIONS="" for var in "$@" do -echo "command line parameter: $var" -if test $var = "--buildrpi" -then - PLATFORMNAME="rpi" -fi -if test $var = "--buildwin64" -then - PLATFORMNAME="win64" -fi + echo "command line parameter: $var" + if test "$var" = "--buildrpi" + then + PLATFORMNAME="rpi" + elif test "$var" = "--buildwin64" + then + PLATFORMNAME="win64" + elif [[ "$var" == -D* ]] + then + CMAKE_OPTIONS="$CMAKE_OPTIONS $var" + fi done builddir="$basepath/build_${PLATFORMNAME}" @@ -136,9 +139,9 @@ cd "$builddir" echo "Building Core Modules" if test $PLATFORMNAME = "win64" then -cmake -DOVERRIDE_PLATFORM=linux64 -DCMAKE_TOOLCHAIN_FILE=$basepath/BuildScripts/CrossCompile_Win32FromDebian.txt .. +cmake -DOVERRIDE_PLATFORM=linux64 -DCMAKE_TOOLCHAIN_FILE=$basepath/BuildScripts/CrossCompile_Win32FromDebian.txt $CMAKE_OPTIONS .. else -cmake -DOVERRIDE_PLATFORM=$PLATFORMNAME .. +cmake -DOVERRIDE_PLATFORM=$PLATFORMNAME $CMAKE_OPTIONS .. fi cmake --build . --config Release @@ -167,7 +170,7 @@ cp ../Output/${GITHASH}_core_libmcdata.${DLLEXT} Framework/Dist/ cp ../Output/${GITHASH}_*.data Framework/Dist/ cp ../Output/${GITHASH}_core.client Framework/Dist/ cp ../Output/${GITHASH}_package.xml Framework/Dist/ -cp ../Output/${GITHASH}_driver_*.${DLLEXT} Framework/Dist/ +cp ../Output/${GITHASH}_driver_*.${DLLEXT} Framework/Dist/ 2>/dev/null || echo "No driver libraries found" cp ../../Framework/HeadersDev/CppDynamic/*.* Framework/HeadersDev/CppDynamic cp ../../Framework/InterfacesDev/*.* Framework/InterfacesDev cp ../../Framework/PluginCpp/*.* Framework/PluginCpp From 0fd09a3a4b59b1cd21bf67c7fffa5d096e1b45e0 Mon Sep 17 00:00:00 2001 From: krixkrix Date: Sun, 18 Jan 2026 01:46:27 +0100 Subject: [PATCH 17/19] Support jsonarrays in /api/ext responses (#61) --- Implementation/API/amc_api_handler_external.cpp | 5 +++++ Implementation/Core/amc_jsonwriter.cpp | 5 +++++ Implementation/Core/amc_jsonwriter.hpp | 2 ++ Implementation/LibMCEnv/libmcenv_jsonarray.cpp | 10 ++++++++-- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Implementation/API/amc_api_handler_external.cpp b/Implementation/API/amc_api_handler_external.cpp index 962040f7..a0e59d96 100644 --- a/Implementation/API/amc_api_handler_external.cpp +++ b/Implementation/API/amc_api_handler_external.cpp @@ -147,6 +147,11 @@ uint32_t CAPIHandler_External::handleEventRequest(CJSONWriter& writer, const std newObject.copyFromObject (iIter->value); writer.addObject(sValueName, newObject); } + if (iIter->value.IsArray()) { + AMC::CJSONWriterArray newArray (writer); + newArray.copyFromArray (iIter->value); + writer.addArray(sValueName, newArray); + } } diff --git a/Implementation/Core/amc_jsonwriter.cpp b/Implementation/Core/amc_jsonwriter.cpp index 290c5015..53809501 100644 --- a/Implementation/Core/amc_jsonwriter.cpp +++ b/Implementation/Core/amc_jsonwriter.cpp @@ -152,6 +152,11 @@ void CJSONWriterArray::addArray(CJSONWriterArray& array) m_Value.PushBack(array.m_Value, m_allocator); } +void CJSONWriterArray::copyFromArray(const rapidjson::Value& arrayValue) +{ + m_Value.CopyFrom(arrayValue, m_allocator); +} + CJSONWriter::CJSONWriter() diff --git a/Implementation/Core/amc_jsonwriter.hpp b/Implementation/Core/amc_jsonwriter.hpp index 490232a8..a8ef30bd 100644 --- a/Implementation/Core/amc_jsonwriter.hpp +++ b/Implementation/Core/amc_jsonwriter.hpp @@ -98,6 +98,8 @@ namespace AMC { void addArray(CJSONWriterArray& array); + void copyFromArray(const rapidjson::Value& arrayValue); + bool isEmpty(); }; diff --git a/Implementation/LibMCEnv/libmcenv_jsonarray.cpp b/Implementation/LibMCEnv/libmcenv_jsonarray.cpp index abc5f84b..0ef813c0 100644 --- a/Implementation/LibMCEnv/libmcenv_jsonarray.cpp +++ b/Implementation/LibMCEnv/libmcenv_jsonarray.cpp @@ -260,7 +260,10 @@ IJSONObject * CJSONArray::AddObjectValue() jsonValue.SetObject(); - auto pMember = &m_pInstance->PushBack(jsonValue, m_pDocument->GetAllocator()); + m_pInstance->PushBack(jsonValue, m_pDocument->GetAllocator()); + + // Get pointer to the newly added element (last element in array) + auto pMember = &(*m_pInstance)[m_pInstance->Size() - 1]; return new CJSONObject(m_pDocument, pMember); } @@ -271,7 +274,10 @@ IJSONArray * CJSONArray::AddArrayValue() jsonValue.SetArray(); - auto pMember = &m_pInstance->PushBack(jsonValue, m_pDocument->GetAllocator()); + m_pInstance->PushBack(jsonValue, m_pDocument->GetAllocator()); + + // Get pointer to the newly added element (last element in array) + auto pMember = &(*m_pInstance)[m_pInstance->Size() - 1]; return new CJSONArray(m_pDocument, pMember); } From 6b9eca8009273f5658b584f35fe7a161d517430a Mon Sep 17 00:00:00 2001 From: craigsturgess Date: Sun, 18 Jan 2026 00:47:35 +0000 Subject: [PATCH 18/19] Simplify GetPixels by removing redundant checks (#59) Removed redundant null checks for pValueBuffer and m_PixelData, these checks stops the two-call pattern of the GetPixels(). --- Implementation/LibMCEnv/libmcenv_imagedata.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Implementation/LibMCEnv/libmcenv_imagedata.cpp b/Implementation/LibMCEnv/libmcenv_imagedata.cpp index aff0afa2..fb9c843b 100644 --- a/Implementation/LibMCEnv/libmcenv_imagedata.cpp +++ b/Implementation/LibMCEnv/libmcenv_imagedata.cpp @@ -888,18 +888,10 @@ void CImageData::GetPixels(const LibMCEnv_uint32 nStartX, const LibMCEnv_uint32 { if (m_PixelData.get() == nullptr) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDIMAGEBUFFER); - - if (pValueBuffer == nullptr) - throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDPARAM); - - if (m_PixelData.get() == nullptr) - throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDIMAGEBUFFER); - if (nCountX <= 0) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDPIXELCOUNT); if (nCountY <= 0) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDPIXELCOUNT); - if (nStartX >= m_nPixelCountX) throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDXCOORDINATE); if (nStartY >= m_nPixelCountY) From 8fdb0ba15fe115742411f5155118985a62ee0ab6 Mon Sep 17 00:00:00 2001 From: krixkrix Date: Sun, 18 Jan 2026 01:48:18 +0100 Subject: [PATCH 19/19] Fix: JSON API AddObjectValue/AddArrayValue returning parent instead of child (#64) Bug: AddObjectValue() and AddArrayValue() were returning a pointer to the parent object instead of the newly created child value, causing JSON structure corruption. Fix: 1. Call AddMember() to add the member to the parent 2. Use &(*m_pInstance)[sName.c_str()] to get pointer to the newly added child value in the parent's member map Impact: This bug affected any endpoint using AddArrayValue() or nested AddObjectValue(), such as my /api/ext/builds/list which uses arrays. The error "Referenced JSON value is not array" occurred. --- Implementation/LibMCEnv/libmcenv_jsonobject.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Implementation/LibMCEnv/libmcenv_jsonobject.cpp b/Implementation/LibMCEnv/libmcenv_jsonobject.cpp index 06ba7ffc..f1034e7a 100644 --- a/Implementation/LibMCEnv/libmcenv_jsonobject.cpp +++ b/Implementation/LibMCEnv/libmcenv_jsonobject.cpp @@ -347,10 +347,13 @@ IJSONObject * CJSONObject::AddObjectValue(const std::string & sName) jsonName.SetString(sName.c_str(), m_pDocument->GetAllocator()); jsonValue.SetObject (); - auto pMember = &m_pInstance->AddMember(jsonName, jsonValue, m_pDocument->GetAllocator()); + m_pInstance->AddMember(jsonName, jsonValue, m_pDocument->GetAllocator()); + + // Get pointer to the newly added member value (not the parent object) + auto pMember = &(*m_pInstance)[sName.c_str()]; return new CJSONObject (m_pDocument, pMember); - + } IJSONArray * CJSONObject::AddArrayValue(const std::string & sName) @@ -361,7 +364,10 @@ IJSONArray * CJSONObject::AddArrayValue(const std::string & sName) jsonName.SetString(sName.c_str(), m_pDocument->GetAllocator()); jsonValue.SetArray(); - auto pMember = &m_pInstance->AddMember(jsonName, jsonValue, m_pDocument->GetAllocator()); + m_pInstance->AddMember(jsonName, jsonValue, m_pDocument->GetAllocator()); + + // Get pointer to the newly added member value (not the parent object) + auto pMember = &(*m_pInstance)[sName.c_str()]; return new CJSONArray(m_pDocument, pMember); }