23 #include <ChimeraTK/BackendFactory.h>
24 #include <ChimeraTK/DeviceAccessVersion.h>
25 #include <ChimeraTK/TypeChangingDecorator.h>
27 #include <boost/algorithm/string.hpp>
39 std::string address, std::map<std::string, std::string> parameters) {
43 static std::vector<std::string> ChimeraTK_DeviceAccess_sdmParameterNames{
"facility",
"device",
"location"};
45 static std::string ChimeraTK_DeviceAccess_version{CHIMERATK_DEVICEACCESS_VERSION};
47 static std::string backend_name =
"doocs";
51 std::string serverAddress, std::string cacheFile, std::future<void> cancelFlag);
56 std::string serverAddress, std::string cacheFile, std::future<void> cancelFlag) {
58 auto catalogue = std::move(result.first);
59 auto isCatalogueComplete = result.second;
60 bool isCacheFileNameSpecified = not cacheFile.empty();
62 if(isCatalogueComplete && isCacheFileNameSpecified) {
75 std::cout <<
"DoocsBackend::BackendRegisterer: registering backend type doocs" << std::endl;
76 ChimeraTK::BackendFactory::getInstance().registerBackendType(
83 const std::string& serverAddress,
const std::string& cacheFile,
const std::string& updateCache)
85 if(cacheFileExists() && isCachingEnabled()) {
90 if(updateCache ==
"1") {
91 std::thread(fetchCatalogue, serverAddress, cacheFile, _cancelFlag.get_future()).detach();
97 std::async(std::launch::async, fetchCatalogue, serverAddress, cacheFile, _cancelFlag.get_future());
103 doocs::zmq_set_subscription_timeout(10);
111 if(_catalogueFuture.valid()) {
113 _cancelFlag.set_value();
114 _catalogueFuture.get();
124 bool DoocsBackend::cacheFileExists() {
125 if(_cacheFile.empty()) {
128 std::ifstream f(_cacheFile.c_str());
134 bool DoocsBackend::isCachingEnabled()
const {
135 return !_cacheFile.empty();
141 std::string address, std::map<std::string, std::string> parameters) {
143 if(address.empty()) {
144 RegisterPath serverAddress;
145 serverAddress /= parameters[
"facility"];
146 serverAddress /= parameters[
"device"];
147 serverAddress /= parameters[
"location"];
148 address = std::string(serverAddress).substr(1);
150 std::string cacheFile{};
151 std::string updateCache{
"0"};
153 cacheFile = parameters.at(
"cacheFile");
154 updateCache = parameters.at(
"updateCache");
156 catch(std::out_of_range&) {
162 return boost::shared_ptr<DeviceBackend>(
new DoocsBackend(address, cacheFile, updateCache));
168 std::unique_lock<std::mutex> lk(_mxRecovery);
169 if(lastFailedAddress !=
"") {
172 ea.adr(lastFailedAddress);
174 doocs::EqData src, dst;
175 int rc = eq.get(&ea, &src, &dst);
179 auto message = std::string(
"Cannot read from DOOCS property: ") + dst.get_string();
180 setException(message);
181 throw ChimeraTK::runtime_error(message);
183 lastFailedAddress =
"";
186 setOpenedAndClearException();
198 if(_catalogueFuture.valid()) {
199 catalogue = _catalogueFuture.get();
211 std::unique_lock<std::mutex> lk(_mxRecovery);
213 lastFailedAddress =
"";
220 std::lock_guard<std::mutex> lk(_mxRecovery);
221 if(lastFailedAddress ==
"") {
222 lastFailedAddress = address;
236 if(!isFunctional()) {
245 template<
typename UserType>
247 const RegisterPath& registerPathName,
size_t numberOfWords,
size_t wordOffsetInRegister, AccessModeFlags flags) {
248 boost::shared_ptr<NDRegisterAccessor<UserType>> p;
252 bool hasExtraLevel =
false;
253 if(!boost::starts_with(path,
"doocs://") && !boost::starts_with(path,
"epics://")) {
254 size_t nSlashes = std::count(path.begin(), path.end(),
'/');
256 hasExtraLevel =
true;
258 else if(nSlashes < 3 || nSlashes > 4) {
259 throw ChimeraTK::logic_error(std::string(
"DOOCS address has an illegal format: ") + path);
262 else if(boost::starts_with(path,
"doocs://")) {
263 size_t nSlashes = std::count(path.begin(), path.end(),
'/');
265 if(nSlashes == 4 + 3) {
266 hasExtraLevel =
true;
268 else if(nSlashes < 3 + 3 || nSlashes > 4 + 3) {
269 throw ChimeraTK::logic_error(std::string(
"DOOCS address has an illegal format: ") + path);
276 field = path.substr(path.find_last_of(
'/') + 1);
277 path = path.substr(0, path.find_last_of(
'/'));
281 int doocsTypeId = DATA_NULL;
285 doocs::EqData src, dst;
287 int rc = eq.get(&ea, &src, &dst);
289 if(rc == eq_errors::ill_property || rc == eq_errors::ill_location ||
290 rc == eq_errors::ill_address) {
291 throw ChimeraTK::logic_error(
"Property does not exist: " + path +
"': " + dst.get_string());
296 doocsTypeId = dst.type();
301 if(doocsTypeId == DATA_NULL) {
303 doocsTypeId = reg.doocsTypeId;
307 bool extraLevelUsed =
false;
308 auto sharedThis = boost::static_pointer_cast<DoocsBackend>(shared_from_this());
310 if(field ==
"eventId") {
311 extraLevelUsed =
true;
314 else if(field ==
"timeStamp") {
315 extraLevelUsed =
true;
319 switch(doocsTypeId) {
341 sharedThis, path, registerPathName, numberOfWords, wordOffsetInRegister, flags));
346 sharedThis, path, registerPathName, numberOfWords, wordOffsetInRegister, flags));
351 throw ChimeraTK::logic_error(
"DOOCS property of IFFF type '" +
_serverAddress + registerPathName +
352 "' cannot be accessed as a whole.");
354 extraLevelUsed =
true;
356 sharedThis, path, field, registerPathName, numberOfWords, wordOffsetInRegister, flags));
362 sharedThis, path, registerPathName, numberOfWords, wordOffsetInRegister, flags));
367 sharedThis, path, registerPathName, numberOfWords, wordOffsetInRegister, flags);
368 if constexpr(std::is_same_v<UserType, std::uint8_t>) {
372 boost::shared_ptr<NDRegisterAccessor<std::uint8_t>> pImpl(accImpl);
374 boost::shared_ptr<NDRegisterAccessor<UserType>> accDecorated(
375 new TypeChangingRangeCheckingDecorator<UserType, std::uint8_t>(
376 boost::dynamic_pointer_cast<ChimeraTK::NDRegisterAccessor<std::uint8_t>>(pImpl)));
383 throw ChimeraTK::logic_error(
"Unsupported DOOCS data type " +
384 std::string(doocs::EqData().type_string(doocsTypeId)) +
" of property '" +
_serverAddress +
385 registerPathName +
"'");
390 if(hasExtraLevel && !extraLevelUsed) {
391 throw ChimeraTK::logic_error(
"Specifiaction of field name is not supported for the DOOCS data type " +
392 std::string(doocs::EqData().type_string(doocsTypeId)) +
": " +
_serverAddress + registerPathName);
395 p->setExceptionBackend(shared_from_this());
403 switch(doocs_error) {
404 case eq_errors::unsup_domain:
405 case eq_errors::no_ens_entry:
406 case eq_errors::ill_monitor:
407 case eq_errors::faulty_chans:
408 case eq_errors::unavail_serv:
409 case eq_errors::ill_serv:
410 case eq_errors::rpc_prot_error:
411 case eq_errors::ens_fault:
412 case eq_errors::ill_protocol:
413 case eq_errors::ill_location:
414 case eq_errors::ill_property:
415 case eq_errors::no_connection:
416 case eq_errors::conn_timeout:
417 case eq_errors::alias_error:
418 case eq_errors::no_permission: