10#include <boost/make_shared.hpp>
30 [[nodiscard]]
size_t useCount()
const;
33 thread_local static size_t targetUseCount;
34 std::unique_lock<std::recursive_mutex> _lock;
39 thread_local size_t ReferenceCountedUniqueLock::targetUseCount;
44 assert(_lock.owns_lock());
45 return targetUseCount;
51 assert(targetUseCount > 0);
69 if(numberOfBits == 0) {
73 return (
static_cast<uint64_t
>(-(numberOfBits != 0)) &
74 (
static_cast<uint64_t
>(-1) >> ((
sizeof(uint64_t) * CHAR_BIT) - numberOfBits)));
79 template<
typename UserType>
85 boost::shared_ptr<DeviceBackend>& targetDevice,
87 uint64_t shift, uint64_t numberOfBits, uint64_t dataInterpretationFractionalBits,
88 uint64_t dataInterpretationIsSigned)
100 int32_t(dataInterpretationFractionalBits), bool(dataInterpretationIsSigned)};
101 _converterLoopHelper =
102 RawConverter::ConverterLoopHelper::makeConverterLoopHelper<UserType>(registerInfo, 0, 0, *
this);
104 if(_target->getNumberOfChannels() > 1 || _target->getNumberOfSamples() > 1) {
109 auto& map = boost::fusion::at_key<uint64_t>(backend->sharedAccessorMap.table);
115 auto it = map.find(key);
116 if(it != map.end()) {
124 _maskOnTarget = _baseBitMask << _shift;
132 _target->preRead(type);
138 auto unlock = cppext::finally([
this] { this->_lock.
unlock(); });
139 _target->postRead(type, hasNewData);
144 _converterLoopHelper->doPostRead();
152 [[maybe_unused]]
size_t implParameter) {
153 static_assert(std::is_same_v<UserType, CookedType>);
154 if constexpr(!std::is_same_v<RawType, ChimeraTK::Void>) {
155 auto validity = _target->dataValidity();
156 uint64_t v{_target->accessData(0)};
157 v = (v & _maskOnTarget) >> _shift;
187 _converterLoopHelper->doPreWrite();
189 _temporaryVersion = std::max(versionNumber, _target->getVersionNumber());
190 _target->preWrite(type, _temporaryVersion);
198 [[maybe_unused]]
size_t implParameter) {
199 static_assert(std::is_same_v<UserType, CookedType>);
200 if constexpr(!std::is_same_v<RawType, ChimeraTK::Void>) {
213 _target->accessData(0) &= ~_maskOnTarget;
214 _target->accessData(0) |= (value << _shift);
226 auto unlock = cppext::finally([
this] { this->_lock.
unlock(); });
227 _target->postWrite(type, _temporaryVersion);
233 auto casted = boost::dynamic_pointer_cast<BitRangeAccessPluginDecorator<UserType>>(newElement);
239 if(casted && casted.get() !=
this && casted->_target == _target) {
241 if((casted->_maskOnTarget & _maskOnTarget) != 0) {
242 casted->_writeable =
false;
253 uint64_t _numberOfBits;
254 uint64_t _maskOnTarget;
256 uint64_t _targetTypeMask{
getMaskForNBits(
sizeof(uint64_t) * CHAR_BIT)};
257 uint64_t _baseBitMask;
259 ReferenceCountedUniqueLock _lock;
260 VersionNumber _temporaryVersion;
261 bool _writeable{
false};
262 std::unique_ptr<RawConverter::ConverterLoopHelper> _converterLoopHelper;
270 const LNMBackendRegisterInfo& info,
size_t pluginIndex,
const std::map<std::string, std::string>& parameters)
273 const auto& shift = parameters.at(
"shift");
277 auto [suffix, ec]{std::from_chars(shift.data(), shift.data() + shift.size(),
_shift)};
278 if(ec != std::errc()) {
280 R
"(: Unparseable parameter "shift".)");
283 catch(std::out_of_range&) {
285 R
"(: Missing parameter "shift".)");
289 const auto& numberOfBits = parameters.at(
"numberOfBits");
292 auto [suffix, ec]{std::from_chars(numberOfBits.data(), numberOfBits.data() + numberOfBits.size(),
_numberOfBits)};
293 if(ec != std::errc()) {
295 R
"(: Unparseable parameter "numberOfBits".)");
298 catch(std::out_of_range&) {
300 R
"(: Unparseable parameter "numberOfBits".)");
303 if(
const auto it = parameters.find(
"fractionalBits"); it != parameters.end()) {
308 if(ec != std::errc()) {
310 R
"(: Unparseable parameter "fractionalBits".)");
314 if(
const auto it = parameters.find(
"signed"); it != parameters.end()) {
315 std::stringstream ss(it->second);
334 template<
typename UserType,
typename TargetType>
338 if constexpr(std::is_same_v<TargetType, uint64_t>) {
345 "BitRangePlugin (on {}) must have size <=1, but {} was requested", params.
_name, params.
_numberOfWords));
350 std::format(
"BitRangePlugin (on {}) Unsupported flags in {}", params.
_name, params.
_flags.
serialize()));
355 boost::shared_ptr<DeviceBackend> targetDevice;
356 if(devName !=
"this") {
357 targetDevice = backend->_devices[devName];
360 targetDevice = backend;
362 return boost::make_shared<BitRangeAccessPluginDecorator<UserType>>(backend, targetDevice, target, params.
_name,
void remove(AccessMode flag)
Remove the given flag from the set.
std::string serialize() const
Get a comma seperated list of all flag strings contained in the class.
bool has(AccessMode flag) const
Check if a certain flag is in the set.
Wrapper Class to avoid vector<bool> problems.
void setRawDataType(const DataType &d)
Set the raw data type.
@ none
The data type/concept does not exist, e.g. there is no raw transfer (do not confuse with Void)
LNMBackendRegisterInfo _info
RegisterInfo describing the the target register for which this plugin instance should work.
Base class for plugins that modify the behaviour of accessors in the logical name mapping backend.
BitRangeAccessPlugin(const LNMBackendRegisterInfo &info, size_t pluginIndex, const std::map< std::string, std::string > ¶meters)
bool dataInterpretationIsSigned
boost::shared_ptr< NDRegisterAccessor< UserType > > decorateAccessor(boost::shared_ptr< LogicalNameMappingBackend > &backend, boost::shared_ptr< NDRegisterAccessor< TargetType > > &target, const UndecoratedParams &accessorParams)
void doRegisterInfoUpdate() override
Implementation of the plugin specific register information update.
uint32_t dataInterpretationFractionalBits
Helper class that keeps track of how many locks were taken on the recursive mutex in the current thre...
ReferenceCountedUniqueLock()=default
ReferenceCountedUniqueLock(std::recursive_mutex &mutex)
RegisterInfo structure for the LogicalNameMappingBackend.
RegisterPath getRegisterName() const override
Return full path name of the register (including modules)
DataDescriptor _dataDescriptor
AccessModeFlags supportedFlags
Supported AccessMode flags.
std::string deviceName
The target device alias.
std::pair< DeviceBackend *, RegisterPath > AccessorKey
Map of target accessors which are potentially shared across our accessors.
Base class for decorators of the NDRegisterAccessor.
void replaceTransferElement(boost::shared_ptr< ChimeraTK::TransferElement > newElement) override
bool isWriteable() const override
N-dimensional register accessor.
std::vector< std::vector< UserType > > buffer_2D
Buffer of converted data elements.
Converter class for conversions from raw to cooked values.
UserType toCooked(RawType rawValue)
RawType toRaw(UserType cookedValue)
Class to store a register path name.
void setAltSeparator(const std::string &altSeparator)
set alternative separator.
DataValidity _dataValidity
The validity of the data in the application buffer.
VersionNumber _versionNumber
The version number of the last successful transfer.
bool _isInTransferGroup
Flag whether this TransferElement has been added to a TransferGroup or not.
const std::string & getName() const
Returns the name that identifies the process variable.
Class for generating and holding version numbers without exposing a numeric representation.
Exception thrown when a logic error has occured.
constexpr uint64_t getMaskForNBits(uint64_t numberOfBits)
@ faulty
The data is considered valid.
@ wait_for_new_data
Make any read blocking until new data has arrived since the last read.
@ 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.
void doPreRead(TransferType type) override
Backend specific implementation of preRead().
void doPreWriteImpl(RawConverter::Converter< CookedType, RawType, sc, fc, isSigned > converter, size_t implParameter)
void doPostReadImpl(RawConverter::Converter< CookedType, RawType, sc, fc, isSigned > converter, size_t implParameter)
void replaceTransferElement(boost::shared_ptr< ChimeraTK::TransferElement > newElement) override
void doPostRead(TransferType type, bool hasNewData) override
Backend specific implementation of postRead().
void doPreWrite(TransferType type, VersionNumber versionNumber) override
Backend specific implementation of preWrite().
BitRangeAccessPluginDecorator(boost::shared_ptr< LogicalNameMappingBackend > &backend, boost::shared_ptr< DeviceBackend > &targetDevice, const boost::shared_ptr< ChimeraTK::NDRegisterAccessor< uint64_t > > &target, const std::string &name, uint64_t shift, uint64_t numberOfBits, uint64_t dataInterpretationFractionalBits, uint64_t dataInterpretationIsSigned)
void doPostWrite(TransferType type, VersionNumber) override
Backend specific implementation of postWrite().
Helper struct to hold extra parameters needed by some plugins, used in decorateAccessor()
size_t _wordOffsetInRegister