/******************************************************************************** * Copyright (c) 2025-2026 ZF Friedrichshafen AG * * This program and the accompanying materials are made available under the * terms of the Apache License Version 2.0 which is available at * https://www.apache.org/licenses/LICENSE-2.0 * * SPDX-License-Identifier: Apache-2.0 * * Contributors: * Erik Verhoeven - initial API and implementation ********************************************************************************/ #include "dispatchservice.h" CDispatchService::CDispatchService() { CreateDirectTransactionID(); } sdv::IInterfaceAccess* CDispatchService::CreateTxTrigger(uint32_t uiCycleTime, uint32_t uiDelayTime, uint32_t uiBehaviorFlags, sdv::IInterfaceAccess* pTriggerCallback) { if (GetObjectState() != sdv::EObjectState::configuring) return nullptr; // Check for parameter validity if (!uiCycleTime && !(uiBehaviorFlags & static_cast(sdv::core::ISignalTransmission::ETxTriggerBehavior::spontaneous))) return nullptr; if (!pTriggerCallback) return nullptr; sdv::core::ITxTriggerCallback* pCallback = pTriggerCallback->GetInterface(); if (!pCallback) return nullptr; std::unique_ptr ptrTrigger = std::make_unique(*this, uiCycleTime, uiDelayTime, uiBehaviorFlags, pCallback); // Ignore cppcheck warning; normally the returned pointer should always have a value at this stage (otherwise an // exception was triggered). // cppcheck-suppress knownConditionTrueFalse if (!ptrTrigger) return nullptr; CTrigger* pObject = ptrTrigger.get(); // Ignore cppcheck warning; normally the returned pointer should always have a value at this stage (otherwise an // exception was triggered). // cppcheck-suppress knownConditionTrueFalse if (!pObject) return nullptr; if (!ptrTrigger->IsValid()) return nullptr; std::unique_lock lock(m_mtxTriggers); return m_mapTriggers.emplace(pObject, std::move(ptrTrigger)).second ? pObject : nullptr; } sdv::IInterfaceAccess* CDispatchService::RegisterTxSignal(/*in*/ const sdv::u8string& ssSignalName, /*in*/ sdv::any_t anyDefVal) { if (GetObjectState() != sdv::EObjectState::configuring) return nullptr; std::unique_lock lock(m_mtxSignals); auto prSignal = m_mapTxSignals.try_emplace(ssSignalName, *this, ssSignalName, sdv::core::ESignalDirection::sigdir_tx, anyDefVal); return prSignal.first->second.CreateConsumer(); } sdv::IInterfaceAccess* CDispatchService::RegisterRxSignal(/*in*/ const sdv::u8string& ssSignalName) { if (GetObjectState() != sdv::EObjectState::configuring) return nullptr; std::unique_lock lock(m_mtxSignals); auto prSignal = m_mapRxSignals.try_emplace(ssSignalName, *this, ssSignalName, sdv::core::ESignalDirection::sigdir_rx); return prSignal.first->second.CreateProvider(); } sdv::IInterfaceAccess* CDispatchService::RequestSignalPublisher(/*in*/ const sdv::u8string& ssSignalName) { if (GetObjectState() != sdv::EObjectState::configuring) return nullptr; std::unique_lock lock(m_mtxSignals); auto itSignal = m_mapTxSignals.find(ssSignalName); if (itSignal == m_mapTxSignals.end()) return nullptr; if (itSignal->second.GetDirection() != sdv::core::ESignalDirection::sigdir_tx) return nullptr; return itSignal->second.CreateProvider(); } sdv::IInterfaceAccess* CDispatchService::AddSignalSubscription(/*in*/ const sdv::u8string& ssSignalName, /*in*/ IInterfaceAccess* pSubscriber) { if (GetObjectState() != sdv::EObjectState::configuring) return nullptr; std::unique_lock lock(m_mtxSignals); auto itSignal = m_mapRxSignals.find(ssSignalName); if (itSignal == m_mapRxSignals.end()) return 0; if (itSignal->second.GetDirection() != sdv::core::ESignalDirection::sigdir_rx) return 0ull; return itSignal->second.CreateConsumer(pSubscriber); } sdv::sequence CDispatchService::GetRegisteredSignals() const { sdv::sequence seqRegistrations; std::unique_lock lock(m_mtxSignals); for (const auto& prSignal : m_mapRxSignals) seqRegistrations.push_back({prSignal.first, prSignal.second.GetDirection()}); for (const auto& prSignal : m_mapTxSignals) seqRegistrations.push_back({prSignal.first, prSignal.second.GetDirection()}); return seqRegistrations; } sdv::IInterfaceAccess* CDispatchService::CreateTransaction() { // NOTE: Transactions can take place at any time (not only when running). DO not restrict transactions to any // operation mode. std::unique_lock lock(m_mtxTransactions); auto itTransaction = m_lstTransactions.emplace(m_lstTransactions.end(), *this); if (itTransaction == m_lstTransactions.end()) return nullptr; itTransaction->SetIterator(itTransaction); return &(*itTransaction); } uint64_t CDispatchService::GetNextTransactionID() { return m_uiTransactionCnt++; } void CDispatchService::CreateDirectTransactionID() { m_uiDirectTransactionID = GetNextTransactionID(); } uint64_t CDispatchService::GetDirectTransactionID() const { return m_uiDirectTransactionID; } bool CDispatchService::OnInitialize() { m_scheduler.Start(); return true; } void CDispatchService::OnShutdown() { m_scheduler.Stop(); } void CDispatchService::UnregisterSignal(/*in*/ const sdv::u8string& ssSignalName, sdv::core::ESignalDirection eDirection) { // NOTE: Normally the remove function should be called in the configuration mode. Since it doesn't give // feedback and the associated caller might delete any receiving function, allow the removal to take place even // when running. std::unique_lock lock(m_mtxSignals); // Remove the signal if (eDirection == sdv::core::ESignalDirection::sigdir_rx) m_mapRxSignals.erase(ssSignalName); else m_mapTxSignals.erase(ssSignalName); } CSignal* CDispatchService::FindSignal(const sdv::u8string& rssSignalName, sdv::core::ESignalDirection eDirection) { std::unique_lock lock(m_mtxSignals); if (eDirection == sdv::core::ESignalDirection::sigdir_rx) { auto itSignal = m_mapRxSignals.find(rssSignalName); return itSignal == m_mapRxSignals.end() ? nullptr : &itSignal->second; } else { auto itSignal = m_mapTxSignals.find(rssSignalName); return itSignal == m_mapTxSignals.end() ? nullptr : &itSignal->second; } } void CDispatchService::FinishTransaction(const CTransaction* pTransaction) { // NOTE: Transactions can take place at any time (not only when running). DO not restrict transactions to any // operation mode. std::unique_lock lock(m_mtxTransactions); // Delete the transaction auto itTransaction = pTransaction->GetIterator(); m_lstTransactions.erase(itTransaction); } CScheduler& CDispatchService::GetScheduler() { return m_scheduler; } void CDispatchService::RemoveTxTrigger(CTrigger* pTrigger) { // NOTE: Normally the remove function should be called in the configuration mode. Since it doesn't give // feedback and the associated caller might delete any receiving function, allow the removal to take place even // when running. std::unique_lock lock(m_mtxTriggers); m_scheduler.RemoveFromSchedule(pTrigger); m_mapTriggers.erase(pTrigger); }