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>
86 uint64_t shift, uint64_t numberOfBits, uint64_t dataInterpretationFractionalBits,
87 uint64_t dataInterpretationIsSigned)
93 int32_t(dataInterpretationFractionalBits), bool(dataInterpretationIsSigned)};
94 _converterLoopHelper =
95 RawConverter::ConverterLoopHelper::makeConverterLoopHelper<UserType>(registerInfo, 0, 0, *
this);
97 if(_target->getNumberOfChannels() > 1 || _target->getNumberOfSamples() > 1) {
102 auto& map = boost::fusion::at_key<uint64_t>(backend->sharedAccessorMap.table);
107 auto it = map.find(key);
108 if(it != map.end()) {
116 _maskOnTarget = _baseBitMask << _shift;
124 _target->preRead(type);
130 auto unlock = cppext::finally([
this] { this->_lock.
unlock(); });
131 _target->postRead(type, hasNewData);
136 _converterLoopHelper->doPostRead();
144 [[maybe_unused]]
size_t implParameter) {
145 static_assert(std::is_same_v<UserType, CookedType>);
146 if constexpr(!std::is_same_v<RawType, ChimeraTK::Void>) {
147 auto validity = _target->dataValidity();
148 uint64_t v{_target->accessData(0)};
149 v = (v & _maskOnTarget) >> _shift;
179 _converterLoopHelper->doPreWrite();
181 _temporaryVersion = std::max(versionNumber, _target->getVersionNumber());
182 _target->preWrite(type, _temporaryVersion);
190 [[maybe_unused]]
size_t implParameter) {
191 static_assert(std::is_same_v<UserType, CookedType>);
192 if constexpr(!std::is_same_v<RawType, ChimeraTK::Void>) {
205 _target->accessData(0) &= ~_maskOnTarget;
206 _target->accessData(0) |= (value << _shift);
218 auto unlock = cppext::finally([
this] { this->_lock.
unlock(); });
219 _target->postWrite(type, _temporaryVersion);
225 auto casted = boost::dynamic_pointer_cast<BitRangeAccessPluginDecorator<UserType>>(newElement);
231 if(casted && casted.get() !=
this && casted->_target == _target) {
233 if((casted->_maskOnTarget & _maskOnTarget) != 0) {
234 casted->_writeable =
false;
245 uint64_t _numberOfBits;
246 uint64_t _maskOnTarget;
248 uint64_t _targetTypeMask{
getMaskForNBits(
sizeof(uint64_t) * CHAR_BIT)};
249 uint64_t _baseBitMask;
251 ReferenceCountedUniqueLock _lock;
252 VersionNumber _temporaryVersion;
253 bool _writeable{
false};
254 std::unique_ptr<RawConverter::ConverterLoopHelper> _converterLoopHelper;
262 const LNMBackendRegisterInfo& info,
size_t pluginIndex,
const std::map<std::string, std::string>& parameters)
265 const auto& shift = parameters.at(
"shift");
269 auto [suffix, ec]{std::from_chars(shift.data(), shift.data() + shift.size(),
_shift)};
270 if(ec != std::errc()) {
272 R
"(: Unparseable parameter "shift".)");
275 catch(std::out_of_range&) {
277 R
"(: Missing parameter "shift".)");
281 const auto& numberOfBits = parameters.at(
"numberOfBits");
284 auto [suffix, ec]{std::from_chars(numberOfBits.data(), numberOfBits.data() + numberOfBits.size(),
_numberOfBits)};
285 if(ec != std::errc()) {
287 R
"(: Unparseable parameter "numberOfBits".)");
290 catch(std::out_of_range&) {
292 R
"(: Unparseable parameter "numberOfBits".)");
295 if(
const auto it = parameters.find(
"fractionalBits"); it != parameters.end()) {
300 if(ec != std::errc()) {
302 R
"(: Unparseable parameter "fractionalBits".)");
306 if(
const auto it = parameters.find(
"signed"); it != parameters.end()) {
307 std::stringstream ss(it->second);
326 template<
typename UserType,
typename TargetType>
330 if constexpr(std::is_same_v<TargetType, uint64_t>) {
331 return boost::make_shared<BitRangeAccessPluginDecorator<UserType>>(backend, target, params.
_name,
_shift,
void remove(AccessMode flag)
Remove the given flag from 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::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)
BitRangeAccessPluginDecorator(boost::shared_ptr< LogicalNameMappingBackend > &backend, 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 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().
void doPostWrite(TransferType type, VersionNumber) override
Backend specific implementation of postWrite().
Helper struct to hold extra parameters needed by some plugins, used in decorateAccessor()