9#include <boost/algorithm/string.hpp>
10#ifdef CHIMERATK_HAVE_PCIE_BACKEND
13#ifdef CHIMERATK_HAVE_XDMA_BACKEND
16#ifdef CHIMERATK_HAVE_UIO_BACKEND
22#include "DeviceAccessVersion.h"
31#include <boost/bind/bind.hpp>
32#include <boost/function.hpp>
47 boost::shared_ptr<DeviceBackend> (*creatorFunction)(
48 std::string address, std::map<std::string, std::string> parameters),
49 const std::vector<std::string>& sdmParameterNames,
const std::string& version) {
51 std::cout <<
"adding:" << backendType << std::endl << std::flush;
56 throw ChimeraTK::logic_error(
"A backend with the type name '" + backendType +
"' has already been registered.");
59 if(version != CHIMERATK_DEVICEACCESS_VERSION) {
65 std::stringstream errorMessage;
66 errorMessage <<
"Backend plugin '" << backendType <<
"' compiled with wrong DeviceAccess version " << version
67 <<
". Please recompile with version " << CHIMERATK_DEVICEACCESS_VERSION;
68 std::string errorMessageString = errorMessage.str();
71 creatorMap_compat[make_pair(backendType,
"")] = [errorMessageString](std::string host, std::string instance,
72 std::list<std::string> parameters, std::string mapFileName) {
74 host, instance, parameters, mapFileName, errorMessageString);
76 creatorMap[backendType] = [errorMessageString](std::string,
77 std::map<std::string, std::string>) -> boost::shared_ptr<ChimeraTK::DeviceBackend> {
86 creatorMap_compat[make_pair(backendType,
"")] = [creatorFunction, sdmParameterNames](std::string,
87 std::string instance, std::list<std::string> parameters,
88 std::string mapFileName) {
90 std::map<std::string, std::string> pars;
92 for(
auto& p : parameters) {
93 if(i >= sdmParameterNames.size())
break;
94 pars[sdmParameterNames[i]] = p;
97 if(!mapFileName.empty()) {
98 if(pars[
"map"].empty()) {
99 pars[
"map"] = mapFileName;
102 std::cout <<
"WARNING: You have specified the map file name twice, in "
103 "the parameter list and in the 3rd "
104 "column of the DMAP file."
106 std::cout <<
"Please only specify the map file name in the parameter list!" << std::endl;
109 return creatorFunction(std::move(instance), pars);
116 boost::shared_ptr<DeviceBackend> (*creatorFunction)(
117 std::string host, std::string instance, std::list<std::string> parameters, std::string mapFileName),
118 const std::string& version) {
120 std::cout <<
"adding:" <<
interface << std::endl <<
std::flush;
123 if(version != CHIMERATK_DEVICEACCESS_VERSION) {
129 std::stringstream errorMessage;
130 errorMessage <<
"Backend plugin '" <<
interface << "' compiled with wrong DeviceAccess version
" << version
131 << ". Please recompile with version
" << CHIMERATK_DEVICEACCESS_VERSION;
132 std::string errorMessageString = errorMessage.str();
133 // FIXME #11279 Implement API breaking changes from linter warnings
134 // NOLINTBEGIN(performance-unnecessary-value-param)
135 creatorMap_compat[make_pair(interface, protocol)] = [errorMessageString](std::string host, std::string instance,
136 std::list<std::string> parameters,
137 std::string mapFileName) {
138 return BackendFactory::failedRegistrationThrowerFunction(
139 host, instance, parameters, mapFileName, errorMessageString);
141 creatorMap[interface] = [errorMessageString](std::string,
142 std::map<std::string, std::string>) -> boost::shared_ptr<ChimeraTK::DeviceBackend> {
143 // NOLINTEND(performance-unnecessary-value-param)
144 throw ChimeraTK::logic_error(errorMessageString);
148 creatorMap_compat[make_pair(interface, protocol)] = creatorFunction;
149 // FIXME #11279 Implement API breaking changes from linter warnings
150 // NOLINTBEGIN(performance-unnecessary-value-param)
151 creatorMap[interface] = [interface](std::string,
152 std::map<std::string, std::string>) -> boost::shared_ptr<ChimeraTK::DeviceBackend> {
153 // NOLINTEND(performance-unnecessary-value-param)
154 throw ChimeraTK::logic_error("The backend type '
" + interface +
156 "descriptors! Please update the backend!
");
160 /********************************************************************************************************************/
162 void BackendFactory::setDMapFilePath(std::string dMapFilePath) {
163 _dMapFile = std::move(dMapFilePath);
164 loadAllPluginsFromDMapFile();
166 /********************************************************************************************************************/
168 std::string BackendFactory::getDMapFilePath() {
171 /********************************************************************************************************************/
173 BackendFactory::BackendFactory() {
174#ifdef CHIMERATK_HAVE_PCIE_BACKEND
175 registerBackendType("pci
", &PcieBackend::createInstance, {"map
"});
177#ifdef CHIMERATK_HAVE_XDMA_BACKEND
178 registerBackendType("xdma
", &XdmaBackend::createInstance, {"map
"});
180#ifdef CHIMERATK_HAVE_UIO_BACKEND
181 registerBackendType("uio
", &UioBackend::createInstance, {"map
"});
183 registerBackendType("dummy
", &DummyBackend::createInstance, {"map
"});
184 registerBackendType("rebot
", &RebotBackend::createInstance, {"ip
", "port
", "map
", "timeout
"});
185 registerBackendType("logicalNameMap
", &LogicalNameMappingBackend::createInstance, {"map
"});
186 registerBackendType("subdevice
", &SubdeviceBackend::createInstance, {"map
"});
187 registerBackendType("sharedMemoryDummy
", &SharedDummyBackend::createInstance, {"map
"});
188 registerBackendType("ExceptionDummy", &ExceptionDummy::createInstance, {"map
"});
190 /********************************************************************************************************************/
192 BackendFactory& BackendFactory::getInstance() {
194 std::cout << "getInstance
" << std::endl << std::flush;
196 static BackendFactory factoryInstance; /** Thread safe in C++11*/
197 return factoryInstance;
200 /********************************************************************************************************************/
202 boost::shared_ptr<DeviceBackend> BackendFactory::createBackend(const std::string& aliasOrUri) {
203 std::lock_guard<std::mutex> lock(_mutex);
205 if(Utilities::isDeviceDescriptor(aliasOrUri) || Utilities::isSdm(aliasOrUri)) {
206 // it is a URI, directly create a deviceinfo and call the internal creator
208 DeviceInfoMap::DeviceInfo deviceInfo;
209 deviceInfo.uri = aliasOrUri;
210 return createBackendInternal(deviceInfo);
213 // it's not a URI. Try finding the alias in the dmap file.
214 if(_dMapFile.empty()) {
215 throw ChimeraTK::logic_error("DMap file not set.
");
217 auto deviceInfo = Utilities::aliasLookUp(aliasOrUri, _dMapFile);
218 return createBackendInternal(deviceInfo);
221 /********************************************************************************************************************/
223 boost::shared_ptr<DeviceBackend> BackendFactory::createBackendInternal(const DeviceInfoMap::DeviceInfo& deviceInfo) {
225 std::cout << "uri
to parse
" << deviceInfo.uri << std::endl;
226 std::cout << "Entries
" << creatorMap.size() << std::endl << std::flush;
229 // Check if backend already exists
230 auto iterator = _existingBackends.find(deviceInfo.uri);
231 if(iterator != _existingBackends.end()) {
232 auto strongPtr = iterator->second.lock();
238 // Check if descriptor string is a ChimeraTK device descriptor
239 if(Utilities::isDeviceDescriptor(deviceInfo.uri)) {
240 auto cdd = Utilities::parseDeviceDesciptor(deviceInfo.uri);
242 auto backend = (creatorMap.at(cdd.backendType))(cdd.address, cdd.parameters);
243 _existingBackends[deviceInfo.uri] = backend;
246 catch(std::out_of_range&) {
247 throw ChimeraTK::logic_error("Unknown backend: \"" +
cdd.backendType + "\" at " + deviceInfo.dmapFileName +
248 ":" +
std::to_string(deviceInfo.dmapFileLineNumber) + " for " + deviceInfo.uri);
255 if(Utilities::isSdm(deviceInfo.uri)) {
256 sdm = Utilities::parseSdm(deviceInfo.uri);
257 std::cout <<
"Using the SDM descriptor is deprecated. Please change to CDD (ChimeraTK device descriptor)."
261 sdm = Utilities::parseDeviceString(deviceInfo.uri);
263 <<
"Using the device node in a dmap file is deprecated. Please change to CDD (ChimeraTK device descriptor)."
266 for(
auto& iter : creatorMap_compat) {
267 if((iter.first.first == sdm.interface)) {
268 auto backend = (iter.second)(sdm.host, sdm.instance, sdm.parameters, deviceInfo.mapFileName);
269 boost::weak_ptr<DeviceBackend> weakBackend = backend;
270 _existingBackends[deviceInfo.uri] = weakBackend;
276 throw ChimeraTK::logic_error(
"Unregistered device: Interface = " + sdm.interface +
" Protocol = " + sdm.protocol);
288 void* hndl = dlopen(soFile.c_str(), RTLD_LAZY);
289 if(hndl ==
nullptr) {
297 "'" + soFile +
"' is not a valid DeviceAccess plugin, it does not register any backends!");
310 for(
const auto& lib : dmap->getPluginLibraries()) {
318 std::cerr <<
"Error: Caught exception loading plugin '" << lib <<
"' specified in dmap file: " << e.
what()
320 std::cerr <<
"Some backends will not be available!" << std::endl;
330 std::string , std::list<std::string> , std::string ,
331 std::string exception_what) {
void registerBackendType(const std::string &backendType, boost::shared_ptr< DeviceBackend >(*creatorFunction)(std::string address, std::map< std::string, std::string > parameters), const std::vector< std::string > &sdmParameterNames={}, const std::string &deviceAccessVersion=CHIMERATK_DEVICEACCESS_VERSION)
Register a backend by the name backendType with the given creatorFunction.
bool called_registerBackendType
Flag whether the function registerBackendType() was called.
std::map< std::pair< std::string, std::string >, boost::function< boost::shared_ptr< DeviceBackend >(std::string host, std::string instance, std::list< std::string > parameters, std::string mapFileName)> > creatorMap_compat
Compatibility creatorMap for old-style backends which just take a plain list of parameters.
void loadPluginLibrary(const std::string &soFile)
Load a shared library (.so file) with a Backend at run time.
static boost::shared_ptr< DeviceBackend > failedRegistrationThrowerFunction(std::string host, std::string instance, std::list< std::string > parameters, std::string mapFileName, std::string exception_what)
std::string _dMapFile
The dmap file set at run time.
std::map< std::string, boost::function< boost::shared_ptr< DeviceBackend >(std::string address, std::map< std::string, std::string > parameters)> > creatorMap
Holds device type and function pointer to the createInstance function of plugin.
void loadAllPluginsFromDMapFile()
Load all shared libraries specified in the dmap file.
static DeviceInfoMapPointer parse(const std::string &file_name)
Performs parsing of specified DMAP file.
Exception thrown when a logic error has occured.
const char * what() const noexcept override
Return the message describing what exactly went wrong.
This header collects some conversion routines which should be useful both for ApplicationCore Python ...
std::string to_string(const std::string &v)
This structure holds the information of an SDM.