14#include <boost/algorithm/string.hpp>
15#include <boost/algorithm/string/predicate.hpp>
19using namespace std::string_literals;
24 std::string address, std::map<std::string, std::string> parameters) {
25 if(parameters[
"map"].empty()) {
29 if(!address.empty()) {
30 if(parameters.size() > 1) {
33 "other than the map file in the device descriptor.");
36 std::vector<std::string> tokens;
37 boost::split(tokens, address, boost::is_any_of(
","));
38 if(tokens.size() != 3) {
40 "parameters in the address string.");
42 parameters[
"type"] = tokens[0];
43 parameters[
"device"] = tokens[1];
44 parameters[
"area"] = tokens[2];
56 if(parameters[
"type"].empty()) {
61 if(parameters[
"device"].empty()) {
63 "specified in the device descriptor.");
68 if(parameters[
"type"] ==
"area") {
71 else if(parameters[
"type"] ==
"areaHandshake") {
75 else if(parameters[
"type"] ==
"3regs") {
78 else if(parameters[
"type"] ==
"2regs") {
81 if(parameters[
"sleep"].empty()) {
83 "descriptor for type '2regs'.");
93 if(parameters[
"area"].empty()) {
95 "must be specified in the device "
96 "descriptor for types 'area' and 'areaHandshake'.");
102 if(parameters[
"data"].empty()) {
104 "name must be specified in the device "
105 "descriptor for types '2regs' and '3regs'.");
110 if(parameters[
"address"].empty()) {
112 "name must be specified in the device "
113 "descriptor for type '2regs' and '3regs'.");
117 if(!parameters[
"dataDelay"].empty()) {
121 catch(std::exception& e) {
123 parameters[
"dataDelay"] +
"': " + e.what());
128 if(parameters[
"status"].empty()) {
130 "name must be specified in the device "
131 "descriptor for types '3regs' and 'areaHandshake'.");
134 if(!parameters[
"timeout"].empty()) {
136 timeout = std::stoul(parameters[
"timeout"]);
138 catch(std::exception& e) {
140 "SubdeviceBackend: Invalid value for parameter 'timeout': '" + parameters[
"timeout"] +
"': " + e.what());
145 if(!parameters[
"sleep"].empty()) {
147 sleepTime = std::stoul(parameters[
"sleep"]);
149 catch(std::exception& e) {
151 "SubdeviceBackend: Invalid value for parameter 'sleep': '" + parameters[
"sleep"] +
"': " + e.what());
155 if(parameters[
"map"].empty()) {
209 template<
typename UserType,
typename TargetUserType>
220 _target->postRead(type, hasNewData);
221 if(!hasNewData)
return;
222 for(
size_t i = 0; i < this->
buffer_2D.size(); ++i) {
224 _target->accessChannel(i).begin(), _target->accessChannel(i).end(),
buffer_2D[i].begin());
231 for(
size_t i = 0; i < this->
buffer_2D.size(); ++i) {
232 for(
size_t j = 0; j < this->
buffer_2D[i].size(); ++j) {
237 _target->preWrite(type, versionNumber);
241 _target->postWrite(type, versionNumber);
245 const boost::shared_ptr<ChimeraTK::TransferElement const>& other)
const override {
246 auto casted = boost::dynamic_pointer_cast<FixedPointConvertingDecorator<UserType, TargetUserType>
const>(other);
247 if(!casted)
return false;
249 return _target->mayReplaceOther(casted->_target);
261 template<
typename TargetUserType>
271 template<
typename COOKED_TYPE>
273 std::vector<int32_t> rawVector(1);
274 std::vector<COOKED_TYPE> cookedVector(1);
275 rawVector[0] =
buffer_2D[channel][sample];
277 rawVector.begin(), rawVector.end(), cookedVector.begin());
278 return cookedVector[0];
281 template<
typename COOKED_TYPE>
287 const boost::shared_ptr<ChimeraTK::TransferElement const>& other)
const override {
288 auto casted = boost::dynamic_pointer_cast<FixedPointConvertingRawDecorator<TargetUserType>
const>(other);
289 if(!casted)
return false;
291 return _target->mayReplaceOther(casted->_target);
308 template<
typename UserType>
312 boost::shared_ptr<NDRegisterAccessor<UserType>> returnValue;
314 returnValue = getRegisterAccessor_area<UserType>(registerPathName, numberOfWords, wordOffsetInRegister, flags);
318 getRegisterAccessor_synchronized<UserType>(registerPathName, numberOfWords, wordOffsetInRegister, flags);
323 returnValue->setExceptionBackend(shared_from_this());
331 size_t wordOffsetInRegister,
bool forceAlignment) {
336 std::cout <<
"SubdeviceBackend: WARNING: BAR others then 0 detected. BAR 0 will be used instead. Register "
349 if(wordOffsetInRegister != 0) {
351 "threeRegisters and twoRegisters. Register " +
354 if((numberOfWords != 0) && (numberOfWords != info.
nElements)) {
356 "threeRegisters and twoRegisters. Register " +
363 size_t byteOffset = info.
address +
sizeof(int32_t) * wordOffsetInRegister;
364 if(forceAlignment && (byteOffset % 4 != 0)) {
366 "multiple of 4 are supported.");
370 if(numberOfWords == 0) {
373 else if(numberOfWords > info.
nElements) {
375 " elements from register '" + info.
pathName +
"', which only has a length of " +
381 if(numberOfWords + wordOffsetInRegister > info.
nElements) {
383 "SubdeviceBackend: Requested offset + number of words exceeds the size of the register '" + info.
pathName +
390 template<
typename UserType>
403 size_t wordOffset = (info.address +
sizeof(int32_t) * wordOffsetInRegister) / 4;
410 return boost::make_shared<FixedPointConvertingDecorator<UserType, int32_t>>(rawAcc,
412 info.channels.front().nFractionalBits, info.channels.front().signedFlag));
415 throw ChimeraTK::logic_error(
"Given UserType when obtaining the SubdeviceBackend in raw mode does not "s +
416 "match the expected type. Use an int32_t instead! (Register name: " + registerPathName +
"')");
431 "2reg or areaHandshake must have writeable registers only!");
435 boost::shared_ptr<NDRegisterAccessor<int32_t>> accAddress, accData;
445 size_t wordOffset = (info.
address +
sizeof(int32_t) * wordOffsetInRegister) / 4;
449 boost::shared_ptr<NDRegisterAccessor<int32_t>> accStatus;
454 size_t byteOffset = info.
address +
sizeof(int32_t) * wordOffsetInRegister;
455 auto sharedThis = boost::enable_shared_from_this<DeviceBackend>::shared_from_this();
457 return boost::make_shared<SubdeviceRegisterAccessor>(boost::dynamic_pointer_cast<SubdeviceBackend>(sharedThis),
458 info.
pathName, accAddress, accData, accStatus, byteOffset, numberOfWords);
463 template<
typename UserType>
465 const RegisterPath& registerPathName,
size_t numberOfWords,
size_t wordOffsetInRegister,
468 boost::shared_ptr<SubdeviceRegisterAccessor> rawAcc =
474 return boost::make_shared<FixedPointConvertingDecorator<UserType, int32_t>>(rawAcc,
476 info.channels.front().nFractionalBits, info.channels.front().signedFlag));
479 throw ChimeraTK::logic_error(
"Given UserType when obtaining the SubdeviceBackend in raw mode does not "s +
480 "match the expected type. Use an int32_t instead! (Register name: " + registerPathName +
"')");
486 boost::shared_ptr<NDRegisterAccessor<int32_t>> SubdeviceBackend::getRegisterAccessor_area<int32_t>(
498 size_t wordOffset = (info.address +
sizeof(int32_t) * wordOffsetInRegister) / 4;
505 return boost::make_shared<FixedPointConvertingDecorator<int32_t, int32_t>>(rawAcc,
507 info.channels.front().nFractionalBits, info.channels.front().signedFlag));
509 return boost::make_shared<FixedPointConvertingRawDecorator<int32_t>>(rawAcc,
510 FixedPointConverter<DEPRECATED_FIXEDPOINT_DEFAULT>(registerPathName, info.channels.front().width,
511 info.channels.front().nFractionalBits, info.channels.front().signedFlag));
517 boost::shared_ptr<NDRegisterAccessor<int32_t>> SubdeviceBackend::getRegisterAccessor_synchronized<int32_t>(
518 const RegisterPath& registerPathName,
size_t numberOfWords,
size_t wordOffsetInRegister,
519 const AccessModeFlags& flags) {
521 boost::shared_ptr<SubdeviceRegisterAccessor> rawAcc =
527 return boost::make_shared<FixedPointConvertingDecorator<int32_t, int32_t>>(rawAcc,
528 FixedPointConverter<DEPRECATED_FIXEDPOINT_DEFAULT>(registerPathName, info.channels.front().width,
529 info.channels.front().nFractionalBits, info.channels.front().signedFlag));
531 return boost::make_shared<FixedPointConvertingRawDecorator<int32_t>>(rawAcc,
532 FixedPointConverter<DEPRECATED_FIXEDPOINT_DEFAULT>(registerPathName, info.channels.front().width,
533 info.channels.front().nFractionalBits, info.channels.front().signedFlag));
553 std::set<DeviceBackend::BackendID> retVal{
getBackendID()};
#define FILL_VIRTUAL_FUNCTION_TEMPLATE_VTABLE(functionName)
Fill the vtable of a virtual function template defined with DEFINE_VIRTUAL_FUNCTION_TEMPLATE.
Set of AccessMode flags with additional functionality for an easier handling.
bool has(AccessMode flag) const
Check if a certain flag is in the set.
void add(AccessMode flag)
Add the given flag to the set.
void checkForUnknownFlags(const std::set< AccessMode > &knownFlags) const
Check of any flag which is not in the given set "knownFlags" is set.
BackendFactory is a the factory class to create devices.
static BackendFactory & getInstance()
Static function to get an instance of factory.
boost::shared_ptr< DeviceBackend > createBackend(const std::string &aliasOrUri)
Create a new backend and return the instance as a shared pointer.
void modifyRegister(const BackendRegisterInfo ®isterInfo)
Replaces the register information for the matching register.
BackendID getBackendID()
Get a unique ID for this backend instance.
void setOpenedAndClearException() noexcept
Backends should call this function at the end of a (successful) open() call.
std::string getActiveExceptionMessage() noexcept
std::atomic< bool > _opened
flag if backend is opened
The fixed point converter provides conversion functions between a user type and up to 32 bit fixed po...
RawType toRaw(UserType cookedValue) const
Conversion function from type T to fixed point.
FixedPointConvertingDecorator(const boost::shared_ptr< ChimeraTK::NDRegisterAccessor< TargetUserType > > &target, FixedPointConverter< DEPRECATED_FIXEDPOINT_DEFAULT > fixedPointConverter)
void doPreWrite(TransferType type, VersionNumber versionNumber) override
Backend specific implementation of preWrite().
void doPostWrite(TransferType type, VersionNumber versionNumber) override
Backend specific implementation of postWrite().
void doPreRead(TransferType type) override
Backend specific implementation of preRead().
bool mayReplaceOther(const boost::shared_ptr< ChimeraTK::TransferElement const > &other) const override
void doPostRead(TransferType type, bool hasNewData) override
Backend specific implementation of postRead().
FixedPointConverter< DEPRECATED_FIXEDPOINT_DEFAULT > _fixedPointConverter
DEFINE_VIRTUAL_FUNCTION_TEMPLATE_VTABLE_FILLER(FixedPointConvertingRawDecorator< TargetUserType >, setAsCooked_impl, 3)
void setAsCooked_impl(unsigned int channel, unsigned int sample, COOKED_TYPE value)
FixedPointConverter< DEPRECATED_FIXEDPOINT_DEFAULT > _fixedPointConverter
bool mayReplaceOther(const boost::shared_ptr< ChimeraTK::TransferElement const > &other) const override
FixedPointConvertingRawDecorator(const boost::shared_ptr< ChimeraTK::NDRegisterAccessor< TargetUserType > > &target, FixedPointConverter< DEPRECATED_FIXEDPOINT_DEFAULT > fixedPointConverter)
COOKED_TYPE getAsCooked_impl(unsigned int channel, unsigned int sample)
DEFINE_VIRTUAL_FUNCTION_TEMPLATE_VTABLE_FILLER(FixedPointConvertingRawDecorator< TargetUserType >, getAsCooked_impl, 2)
static std::pair< NumericAddressedRegisterCatalogue, MetadataCatalogue > parse(const std::string &fileName)
Performs parsing of specified MAP file, resulting in catalogue objects describing all registers and m...
Base class for decorators of the NDRegisterAccessor.
N-dimensional register accessor.
std::vector< std::vector< UserType > > buffer_2D
Buffer of converted data elements.
NumericAddressedRegisterInfo getBackendRegister(const RegisterPath ®isterPathName) const override
Note: Override this function if backend has "hidden" registers which are not added to the map and hen...
std::unique_ptr< BackendRegisterCatalogueBase > clone() const override
Create deep copy of the catalogue.
uint32_t nElements
Number of elements in register.
std::vector< ChannelInfo > channels
Define per-channel information (bit interpretation etc.), 1D/scalars have exactly one entry.
uint64_t bar
Upper part of the address (name originally from PCIe, meaning now generalised)
uint64_t address
Lower part of the address relative to BAR, in bytes.
bool isWriteable() const override
Return whether the register is writeable.
Catalogue of register information.
Class to store a register path name.
Backend for subdevices which are passed through some register or area of another device (subsequently...
std::string targetAddress
for type == threeRegisters or twoRegisters: the name of the target registers
size_t timeout
timeout (in milliseconds), used in threeRegisters to throw a runtime_error if status register stuck a...
NumericAddressedRegisterCatalogue _registerMap
map from register names to addresses
size_t addressToDataDelay
for type == threeRegisters or twoRegisters: sleep time between address and data write
void open() override
Open the device.
static boost::shared_ptr< DeviceBackend > createInstance(std::string address, std::map< std::string, std::string > parameters)
void close() override
Close the device.
MetadataCatalogue getMetadataCatalogue() const override
Return the device metadata catalogue.
std::string targetAlias
the target device name
void setExceptionImpl() noexcept override
Function to be (optionally) implemented by backends if additional actions are needed when switching t...
MetadataCatalogue _metadataCatalogue
SubdeviceBackend(std::map< std::string, std::string > parameters)
void obtainTargetBackend()
obtain the target backend if not yet done
boost::shared_ptr< NDRegisterAccessor< UserType > > getRegisterAccessor_impl(const RegisterPath ®isterPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
std::string targetArea
for type == area: the name of the target register
void verifyRegisterAccessorSize(const NumericAddressedRegisterInfo &info, size_t &numberOfWords, size_t wordOffsetInRegister, bool enforceAlignment)
Check consistency of the passed sizes and offsets against the information in the map file Will adjust...
Type type
type of the subdeivce
boost::shared_ptr< SubdeviceRegisterAccessor > getRegisterAccessor_helper(const NumericAddressedRegisterInfo &info, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
size_t sleepTime
for type == threeRegisters or twoRegisters: sleep time of polling loop resp. between operations,...
boost::shared_ptr< ChimeraTK::DeviceBackend > targetDevice
The target device backend itself.
boost::shared_ptr< NDRegisterAccessor< UserType > > getRegisterAccessor_area(const RegisterPath ®isterPathName, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
getRegisterAccessor implemenation for area types
RegisterCatalogue getRegisterCatalogue() const override
Return the register catalogue with detailed information on all registers.
void activateAsyncRead() noexcept override
Activate asyncronous read for all transfer elements where AccessMode::wait_for_new_data is set.
std::set< DeviceBackend::BackendID > getInvolvedBackendIDs() override
Get the backend IDs of all involved backends.
boost::shared_ptr< NDRegisterAccessor< UserType > > getRegisterAccessor_synchronized(const RegisterPath ®isterPathName, size_t numberOfWords, size_t wordOffsetInRegister, const AccessModeFlags &flags)
getRegisterAccessor implemenation for threeRegisters types
std::string targetControl
DataValidity _dataValidity
The validity of the data in the application buffer.
VersionNumber _versionNumber
The version number of the last successful transfer.
Class for generating and holding version numbers without exposing a numeric representation.
Exception thrown when a logic error has occured.
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...
TransferType
Used to indicate the applicable operation on a Transferelement.
std::string to_string(const std::string &v)