ChimeraTK-DeviceAccess 03.25.00
Loading...
Searching...
No Matches
MuxedInterruptDistributor.cc
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
4
7#include "async/SubDomain.h"
9
10#include <nlohmann/json.hpp> // https://json.nlohmann.me/features/element_access/
11
12using json = nlohmann::json;
13
14#include <tuple>
15
16namespace ChimeraTK::async {
17
18 /********************************************************************************************************************/
19
20 MuxedInterruptDistributorFactory::MuxedInterruptDistributorFactory() {
21 // we already know about the build-in handlers
24 }
25
26 /********************************************************************************************************************/
27
32
33 /********************************************************************************************************************/
34
35 std::pair<std::string, std::string> MuxedInterruptDistributorFactory::
37 std::vector<size_t> const& subdomainID, DeviceBackend& backend) {
38 for(auto const& metaDataEntry : backend.getMetadataCatalogue()) {
39 auto const& key = metaDataEntry.first;
40 if(key[0] == '!') {
41 try {
42 auto jkey = nlohmann::json::parse(std::string({++key.begin(), key.end()})); // key without the leading !
43 auto interruptId = jkey.get<std::vector<size_t>>();
44
45 if(interruptId == subdomainID) {
46 auto jdescriptor = nlohmann::json::parse(metaDataEntry.second);
47 auto controllerType = jdescriptor.begin().key();
48 auto controllerDescription = jdescriptor.front().dump();
49 return {controllerType, controllerDescription};
50 }
51 }
52 catch(json::parse_error& e) {
53 throw ChimeraTK::logic_error("Json parse error in \"" + key + "\": " + e.what());
54 }
55 }
56 }
57 std::string subdomainIdString;
58 for(auto i : subdomainID) {
59 subdomainIdString += std::to_string(i) + ":";
60 }
61 subdomainIdString.pop_back();
62
64 "No interrupt controller description for SubDomain " + subdomainIdString + " in MetadataCatalogue");
65 }
66
67 /********************************************************************************************************************/
68
69 boost::shared_ptr<MuxedInterruptDistributor> MuxedInterruptDistributorFactory::createMuxedInterruptDistributor(
70 boost::shared_ptr<SubDomain<std::nullptr_t>> parent) {
71 std::string name, description;
72 std::tie(name, description) =
73 getInterruptControllerNameAndDescriptionFromCatalogue(parent->getId(), *parent->getBackend());
74 auto creatorFunctionIter = _creatorFunctions.find(name);
75 if(creatorFunctionIter == _creatorFunctions.end()) {
76 throw ChimeraTK::logic_error("Unknown interrupt controller type \"" + name + "\"");
77 }
78 return creatorFunctionIter->second(description, std::move(parent));
79 }
80
81 /********************************************************************************************************************/
83 : _backend(parent->getBackend()), _id(parent->getId()), _parent(std::move(parent)),
84 _asyncDomain(_parent->getDomain()) {}
85
86 /********************************************************************************************************************/
87 template<typename DistributorType>
88 boost::shared_ptr<AsyncAccessorManager> MuxedInterruptDistributor::getAccessorManager(
89 std::vector<size_t> const& qualififedSubDomainId) {
90 // the qualified SubDomainId is relative. We need an absolute (fully qualified ID) in case we have to crate a SubDomain
91 assert(!qualififedSubDomainId.empty());
92 auto fullyQualifiedId = _id;
93 fullyQualifiedId.push_back(qualififedSubDomainId.front());
94
95 // we can't use try_emplace because the map contains weak pointers
96 boost::shared_ptr<SubDomain<std::nullptr_t>> subDomain;
97 auto subDomainIter = _subDomains.find(qualififedSubDomainId.front());
98 if(subDomainIter != _subDomains.end()) {
99 subDomain = subDomainIter->second.lock();
100 }
101 if(!subDomain) {
102 subDomain =
103 boost::make_shared<SubDomain<std::nullptr_t>>(_backend, fullyQualifiedId, shared_from_this(), _asyncDomain);
104 _subDomains[qualififedSubDomainId.front()] = subDomain;
105 if(_asyncDomain->unsafeGetIsActive()) {
106 // Creating a new version here is correct. Nothing has been distributed to any accessor connected to this
107 // sub-interrupt yet because we just created this subDomain.
108 activateSubDomain(*subDomain, {});
109 }
110 }
111 return subDomain->getAccessorManager<DistributorType>(qualififedSubDomainId);
112 }
113
114 /********************************************************************************************************************/
115
116 template boost::shared_ptr<AsyncAccessorManager> MuxedInterruptDistributor::getAccessorManager<
117 TriggeredPollDistributor>(std::vector<size_t> const& qualififedSubDomainId);
118
119 /********************************************************************************************************************/
120
121 template boost::shared_ptr<AsyncAccessorManager> MuxedInterruptDistributor::getAccessorManager<
122 VariableDistributor<std::nullptr_t>>(std::vector<size_t> const& qualififedSubDomainId);
123
124 /********************************************************************************************************************/
126 for(auto& subDomainIter : _subDomains) {
127 auto subDomain = subDomainIter.second.lock();
128 if(subDomain) {
129 activateSubDomain(*subDomain, version);
130 }
131 }
132 }
133
134 /********************************************************************************************************************/
135 void MuxedInterruptDistributor::sendException(const std::exception_ptr& e) {
136 for(auto& subDomainIter : _subDomains) {
137 auto subDomain = subDomainIter.second.lock();
138 if(subDomain) {
139 subDomain->sendException(e);
140 }
141 }
142 }
143
144 /********************************************************************************************************************/
146 SubDomain<std::nullptr_t>& subDomain, VersionNumber const& version) {
147 subDomain.activate(nullptr, version);
148 }
149
150} // namespace ChimeraTK::async
nlohmann::json json
The base class for backends providing IO functionality for the Device class.
virtual MetadataCatalogue getMetadataCatalogue() const =0
Return the device metadata catalogue.
Class for generating and holding version numbers without exposing a numeric representation.
static std::unique_ptr< DummyMuxedInterruptDistributor > create(std::string const &desrciption, boost::shared_ptr< SubDomain< std::nullptr_t > > parent)
static std::unique_ptr< GenericMuxedInterruptDistributor > create(std::string const &description, const boost::shared_ptr< SubDomain< std::nullptr_t > > &parent)
Create parses the json configuration snippet 'description', and calls the constructor.
static MuxedInterruptDistributorFactory & getInstance()
std::map< std::string, std::function< std::unique_ptr< MuxedInterruptDistributor >(std::string, boost::shared_ptr< SubDomain< std::nullptr_t > >)> > _creatorFunctions
Each controller type is registered via name and creator function.
boost::shared_ptr< MuxedInterruptDistributor > createMuxedInterruptDistributor(boost::shared_ptr< SubDomain< std::nullptr_t > > parent)
static std::pair< std::string, std::string > getInterruptControllerNameAndDescriptionFromCatalogue(std::vector< size_t > const &subdomainID, DeviceBackend &backend)
std::vector< size_t > _id
The ID of this controller handler.
MuxedInterruptDistributor(boost::shared_ptr< SubDomain< std::nullptr_t > > parent)
MuxedInterruptDistributor classes must only be constructed inside and held by a DeviceBackend,...
virtual void activateSubDomain(SubDomain< std::nullptr_t > &subDomain, VersionNumber const &version)
Function to activate a (new) single SubDomain if the MuxedInterruptDistributor is already active.
boost::shared_ptr< AsyncAccessorManager > getAccessorManager(std::vector< size_t > const &qualififedSubDomainId)
Get an AsyncAccessorManager of type DistributorType from the matching SubDomain.
std::map< size_t, boost::weak_ptr< SubDomain< std::nullptr_t > > > _subDomains
Send backend-specific asynchronous data to different distributors:
Definition SubDomain.h:33
void activate(BackendSpecificDataType, VersionNumber v)
Definition SubDomain.h:211
The TriggeredPollDistributor has std::nullptr_t source data type and is polling the data for the Asyn...
Exception thrown when a logic error has occured.
Definition Exception.h:51
STL namespace.
std::string to_string(const std::string &v)