ChimeraTK-DeviceAccess-DoocsBackend 01.12.01
Loading...
Searching...
No Matches
CatalogueFetcher.cc
Go to the documentation of this file.
1#include "CatalogueFetcher.h"
2
3#include "ChimeraTK/MappedImage.h"
4#include "DoocsBackend.h"
5#include "RegisterInfo.h"
6#include "StringUtility.h"
7
8#include <doocs/EqCall.h>
9
10#include <boost/range/algorithm/find.hpp>
11
12const std::vector<std::string> IGNORE_PATTERNS = {".HIST", ".FILT", "._FILT", ".EGU", ".DESC", ".HSTAT", "._HSTAT",
13 "._HIST", ".LIST", ".SAVE", ".COMMENT", ".XEGU", ".POLYPARA"};
14
15const std::vector<std::string> IGNORE_LIST = {"MESSAGE.TICKER", "SPN"};
16
17/********************************************************************************************************************/
18
19std::pair<DoocsBackendRegisterCatalogue, bool> CatalogueFetcher::fetch() {
20 auto nSlashes = detail::slashes(serverAddress_);
21
22 fillCatalogue(serverAddress_, nSlashes);
23
24 catalogue_._isCatalogueComplete = !isCancelled() && !locationLookupError_ && catalogue_.getNumberOfRegisters() != 0;
25
26 if(!_failedPropertyFirst.empty()) {
27 std::cerr << std::format("DoocsBackend::CatalogueFetcher: Failed to query shape information for {} properties. "
28 "First failed property '{}' failed with error '{}'.",
29 _failedPropertyCount, _failedPropertyFirst, _failedPropertyError)
30 << std::endl;
31 }
32
33 return {std::move(catalogue_), catalogue_._isCatalogueComplete};
34}
35
36/********************************************************************************************************************/
37
38void CatalogueFetcher::fillCatalogue(std::string fixedComponents, long level) {
39 // obtain list of elements within the given partial address
40 doocs::EqAdr ea;
41 doocs::EqCall eq;
42 doocs::EqData src, propList;
43 ea.adr(fixedComponents + "/*");
44 int rc = eq.names(&ea, &propList);
45 if(rc) {
46 // if the enumeration failes, maybe the server is not available (but
47 // exists in ENS) -> just ignore this address but warn
48 std::cout << "DoocsBackend::CatalogueFetcher: Failed to query names for " + fixedComponents
49 << ": \"" + propList.get_string() + "\"" << std::endl;
50
51 locationLookupError_ = true;
52 return;
53 }
54
55 // iterate over list
56
57 for(int i = 0; i < propList.array_length() && not isCancelled(); ++i) {
58 // obtain the name of the element
59 auto u = propList.get_ustr(i);
60 std::string name(u->str_data.str_data_val);
61 name = name.substr(0, name.find_first_of(" ")); // ignore comment which is following the space
62
63 // if we are not yet at the property-level, recursivly call the function
64 // again to resolve the next hierarchy level
65 if(level < 2) {
66 fillCatalogue(fixedComponents + "/" + name, level + 1);
67 }
68 else { // this is a property: create RegisterInfo entry and set its name
69
70 // It matches one of DOOCS's internal properties; skip
71 if(detail::endsWith(name, IGNORE_PATTERNS).first || boost::range::find(IGNORE_LIST, name) != IGNORE_LIST.end()) {
72 continue;
73 }
74
75 // read property once to determine its length and data type
77 std::string fqn = fixedComponents + "/" + name;
78 doocs::EqData dst;
79 ea.adr(fqn); // strip leading slash
80 rc = eq.get(&ea, &src, &dst);
81 if((rc && doocs::is_system_error(dst.error())) || dst.error() == eq_errors::device_error) {
82 // if the property is not accessible, ignore it. This happens frequently e.g. for archiver-related properties.
83 // device_error seems to be reported permanently by some x2timer properties, so exclude them, too.
84 continue;
85 }
86 if(rc && dst.error()) {
87 // If error has been set, the shape information is not correct (because DOOCS seems to store a string instead).
88 // Until a better solution has been found, the entire catalogue fetching is marked as erroneous to prevent
89 // saving it to the cache file.
90 if(!locationLookupError_) {
91 _failedPropertyFirst = fqn;
92 _failedPropertyError = dst.get_string();
93 }
94 _failedPropertyCount++;
95 locationLookupError_ = true;
96 continue;
97 }
98
99 auto regPath = fqn.substr(std::string(serverAddress_).length());
100 auto length = dst.array_length();
101 auto doocsTypeId = dst.type();
102
103 ChimeraTK::AccessModeFlags flags{};
104 if(checkZmqAvailability(fqn)) {
105 flags.add(ChimeraTK::AccessMode::wait_for_new_data);
106 }
107 if(doocsTypeId == DATA_IMAGE) {
108 // length of the byte string (body part, no header) is reported by DOOCS.
109 // We must add our header length.
110 length += sizeof(ChimeraTK::ImgHeader);
111 }
112 catalogue_.addProperty(regPath, length, doocsTypeId, flags);
113 }
114 }
115}
116
117/********************************************************************************************************************/
118
119bool CatalogueFetcher::checkZmqAvailability(const std::string& fullQualifiedName) const {
120 auto lastSlash = fullQualifiedName.find_last_of('/');
121 assert(lastSlash != std::string::npos && lastSlash > 0);
122 auto fullLocationPath = fullQualifiedName.substr(0, lastSlash);
123 auto propertyName = fullQualifiedName.substr(lastSlash + 1);
124
125 int rc;
126 doocs::EqAdr ea;
127 doocs::EqData dat;
128 doocs::EqData dst;
129 doocs::EqCall eq;
130 int portp{0};
131
132 ea.adr(fullLocationPath + "/SPN");
133
134 // get channel port number
135 dat.set(1, 0.0F, 0.0F, time_t{0}, propertyName, 0);
136
137 // call get () to see whether it is supported
138 rc = eq.get(&ea, &dat, &dst);
139 if(rc) {
140 return false;
141 }
142
143 auto* ustr = dst.get_ustr();
144 if(ustr != nullptr) {
145 portp = ustr->i1_data;
146 }
147 if(ustr == nullptr || (portp == 0 && int(ustr->f1_data + ustr->f2_data) == 0)) {
148 // get() not supported, call set()
149 rc = eq.set(&ea, &dat, &dst);
150 if(rc) {
151 return false;
152 }
153 }
154
155 if(dst.type() == DATA_INT) {
156 portp = dst.get_int();
157 }
158 else {
159 ustr = dst.get_ustr();
160 if(ustr != nullptr) {
161 portp = ustr->i1_data;
162 }
163 }
164 return portp != 0;
165}
166
167/********************************************************************************************************************/
const std::vector< std::string > IGNORE_LIST
const std::vector< std::string > IGNORE_PATTERNS
std::pair< DoocsBackendRegisterCatalogue, bool > fetch()
void addProperty(const std::string &name, unsigned int length, int doocsType, ChimeraTK::AccessModeFlags flags)
std::pair< bool, std::string > endsWith(std::string const &s, const std::vector< std::string > &patterns)
long slashes(const std::string &s)