44 UserType toCooked(RawType rawValue);
46 RawType toRaw(UserType cookedValue);
49 RawType _signBitMask, _usedBitMask, _unusedBitMask;
50 UserType _minCookedValues, _maxCookedValues;
51 RawType _minRawValue, _maxRawValue;
55 using PromotedRawType = std::conditional_t<isSigned, std::make_signed_t<RawType>, RawType>;
59 using FloatIntermediate = std::conditional_t<std::is_same_v<UserType, float>, float,
double>;
61 FloatIntermediate _conversionFactor, _inverseConversionFactor;
65 uint32_t _nNegativeFractionalBits;
156 using SignificantBitsCaseTypes = std::tuple<uint8_t, uint16_t, uint32_t, uint64_t>;
160 constexpr int getMinWidthsForFractionalCase(
const FractionalCase& fc) {
171 template<
typename RawType,
typename F>
175 if constexpr(std::numeric_limits<RawType>::digits >= 8) {
180 if constexpr(std::numeric_limits<RawType>::digits >= 16) {
185 if constexpr(std::numeric_limits<RawType>::digits >= 32) {
190 if constexpr(std::numeric_limits<RawType>::digits >= 64) {
200 template<
typename RawType,
typename F>
218 if constexpr(std::numeric_limits<RawType>::digits >= 32) {
227 throw std::logic_error(
"NOT IMPLEMENTED");
232 template<
typename UserType,
typename RawType,
typename F>
233 void callWithConverterParamsFixedRaw(
236 detail::callForSignificantBitsCase<RawType>(info.channels[channelIndex], [&]<
SignificantBitsCase sc> {
238 detail::callForFractionalCase<RawType>(info.channels[channelIndex], [&]<FractionalCase fc> {
239 if constexpr(std::numeric_limits<RawType>::digits >= detail::getMinWidthsForFractionalCase(fc)) {
240 if constexpr(fc == FractionalCase::ieee754_32) {
242 std::forward<F>(fun).template operator()<RawType, sc, fc, true>();
246 if(info.channels[channelIndex].signedFlag) {
247 std::forward<F>(fun).template operator()<RawType, sc, fc, true>();
250 std::forward<F>(fun).template operator()<RawType, sc, fc, false>();
255 throw ChimeraTK::logic_error(
256 std::format(
"Requested data type does not fit into the raw data width for register '{}', channel {}.",
257 std::string(info.getRegisterName()), channelIndex));
265 template<
typename UserType,
typename F>
277 using RawType = std::make_unsigned_t<decltype(x)>;
278 if constexpr(std::is_same_v<UserType, ChimeraTK::Void>) {
283 .template operator()<RawType, SignificantBitsCase::generic, FractionalCase::integer, false>();
287 callWithConverterParamsFixedRaw<UserType, RawType>(info, channelIndex, fun);
294 template<std::size_t... Is>
295 constexpr auto makeUnusedBitMaskTable(std::index_sequence<Is...>) {
296 return std::array<uint64_t, 64>{(~uint64_t{} << Is)...};
301 template<std::size_t... Is>
302 constexpr auto makeUsedBitMaskTable(std::index_sequence<Is...>) {
303 return std::array<uint64_t, 64>{(~(~uint64_t{} << Is))...};
308 template<std::size_t... Is>
309 constexpr auto makeSignBitMaskTable(std::index_sequence<Is...>) {
310 return std::array<uint64_t, 64>{(Is > 0 ? (uint64_t{1} << (Is - 1)) : 0)...};
315 constexpr auto unusedBitMaskTable = makeUnusedBitMaskTable(std::make_index_sequence<64>{});
316 constexpr auto usedBitMaskTable = makeUsedBitMaskTable(std::make_index_sequence<64>{});
317 constexpr auto signBitMaskTable = makeSignBitMaskTable(std::make_index_sequence<64>{});
322 template<
typename PromotedRawType,
typename RawType, SignificantBitsCase significantBitsCase>
323 constexpr PromotedRawType interpretArbitraryBitInteger(
324 RawType signBitMask, RawType usedBitMask, RawType unusedBitMask, RawType rawValue) {
325 static_assert(std::is_integral_v<RawType>);
326 static_assert(!std::is_signed_v<RawType>);
328 if constexpr(significantBitsCase == SignificantBitsCase::generic) {
329 if constexpr(std::is_signed_v<PromotedRawType>) {
330 if(!(rawValue & signBitMask)) {
331 return PromotedRawType(rawValue & usedBitMask);
334 return PromotedRawType(rawValue | unusedBitMask);
338 return PromotedRawType(rawValue & usedBitMask);
347 using UnsignedType = std::tuple_element_t<int(significantBitsCase), SignificantBitsCaseTypes>;
348 using SignedType = std::make_signed_t<UnsignedType>;
349 if constexpr(std::is_signed_v<PromotedRawType>) {
350 return PromotedRawType(SignedType(rawValue));
353 return PromotedRawType(UnsignedType(rawValue));
368 : _signBitMask(isSigned ? detail::signBitMaskTable[info.width] : 0),
369 _usedBitMask(detail::usedBitMaskTable[info.width]), _unusedBitMask(detail::unusedBitMaskTable[info.width]) {
372 constexpr uint32_t maxRawWidth = std::numeric_limits<uint64_t>::digits;
373 if(info.
width > maxRawWidth) {
375 std::format(
"RawConverter cannot deal with a bit width of {} > {}.", info.
width, maxRawWidth));
379 "RawConverter cannot deal with {} fractional bits (larger than total width).", info.
nFractionalBits));
383 "RawConverter cannot deal with {} fractional bits (too negative, result doesn't fit in {} bits).",
390 _inverseConversionFactor = std::pow(FloatIntermediate(2), info.
nFractionalBits);
395 _conversionFactor = FloatIntermediate(1.) / _inverseConversionFactor;
406 if constexpr(isSigned) {
407 _maxRawValue = _usedBitMask ^ _signBitMask;
408 _minRawValue = _signBitMask;
411 _maxRawValue = _usedBitMask;
417 _maxRawValue = RawType(std::bit_cast<uint32_t>(std::numeric_limits<float>::max()));
418 _minRawValue = RawType(std::bit_cast<uint32_t>(std::numeric_limits<float>::lowest()));
420 _maxCookedValues =
toCooked(_maxRawValue);
421 _minCookedValues =
toCooked(_minRawValue);
428 auto promotedRawValue = detail::interpretArbitraryBitInteger<PromotedRawType, RawType, sc>(
429 _signBitMask, _usedBitMask, _unusedBitMask, rawValue);
432 return numericToUserType<UserType>(promotedRawValue);
438 return numericToUserType<UserType>(FloatIntermediate(promotedRawValue) * _conversionFactor);
443 using IntIntermediate = std::conditional_t<isSigned, int64_t, uint64_t>;
444 auto intermediateUnsigned = uint64_t(IntIntermediate(promotedRawValue));
445 intermediateUnsigned <<= _nNegativeFractionalBits;
446 return numericToUserType<UserType>(IntIntermediate(intermediateUnsigned));
450 static_assert(std::numeric_limits<RawType>::digits >= 32);
451 static_assert(std::numeric_limits<float>::is_iec559);
452 return numericToUserType<UserType>(std::bit_cast<float>(uint32_t(promotedRawValue)));
462 if constexpr(!std::is_same_v<UserType, ChimeraTK::Void>) {
463 if(cookedValue < _minCookedValues) {
466 if(cookedValue > _maxCookedValues) {
471 PromotedRawType promotedRawValue;
474 promotedRawValue = userTypeToNumeric<PromotedRawType>(cookedValue);
478 promotedRawValue = userTypeToNumeric<PromotedRawType>(
479 userTypeToNumeric<FloatIntermediate>(cookedValue) * _inverseConversionFactor);
483 static_assert(std::numeric_limits<RawType>::digits >= 32);
484 static_assert(std::numeric_limits<float>::is_iec559);
485 promotedRawValue = PromotedRawType(std::bit_cast<uint32_t>(userTypeToNumeric<float>(cookedValue)));
488 return RawType(promotedRawValue) & _usedBitMask;