MIP_SDK  v3.0.0-187-g93c7302
MicroStrain Communications Library for embedded systems
bits.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <type_traits>
4 #include <limits>
5 #include <stdint.h>
6 #include <assert.h>
7 
8 
9 namespace microstrain
10 {
11 
14 //
15 // bitmaskXXX
16 //
17 
30 template<typename T>
31 constexpr T bitmaskFirstN(unsigned int nbits)
32 {
33  static_assert(std::is_unsigned<T>::value, "Register type must be unsigned.");
34  assert(nbits <= std::numeric_limits<T>::digits);
35 
36  nbits &= std::numeric_limits<T>::digits - 1;
37  return T( T(1u) << nbits ) - 1;
38 }
39 
57 template<typename T>
58 constexpr T bitmaskN(unsigned int bitI, unsigned int nbits)
59 {
60  assert(bitI < std::numeric_limits<T>::digits);
61  return bitmaskFirstN<T>(nbits) << bitI;
62 }
63 
79 template<typename T>
80 constexpr T bitmaskItoJ(unsigned int bitI, unsigned int bitJ)
81 {
82  assert(bitI <= bitJ);
83  return bitmaskFirstN<T>(bitJ) & ~bitmaskFirstN<T>(bitI);
84 }
85 
103 template<typename T>
104 constexpr T bitmaskIthruJ(unsigned int bitI, unsigned int bitJ)
105 {
106  return bitmaskFirstN<T>(bitJ+1) & ~bitmaskFirstN<T>(bitI);
107 }
108 
109 
112 //
113 // testBit
114 //
115 
116 
128 template<typename RegType>
129 constexpr bool testBit(RegType reg, unsigned int bit)
130 {
131  assert(bit < std::numeric_limits<RegType>::digits); // bit must be less than the number of bits in T.
132 
133  return (reg >> bit) & 1u;
134 }
135 
146 template<typename RegType>
147 constexpr void setBit(RegType& reg, unsigned int bit, bool value=true)
148 {
149  assert(bit < std::numeric_limits<RegType>::digits); // bit must be less than the number of bits in T.
150 
151  using T = typename std::remove_volatile<RegType>::type;
152  T tmp = reg;
153  tmp &= ~T(T(1) << bit);
154  tmp |= T(value) << bit;
155  reg = tmp;
156 }
157 
160 //
161 // getRegisterBitXXX
162 //
163 
164 
177 template<typename RegType>
178 constexpr RegType getBitsN(RegType reg, unsigned int bitI, unsigned int nbits)
179 {
180  assert(bitI < std::numeric_limits<RegType>::digits); // BitI must be less than the number of bits in T.
181 
182  return (reg >> bitI) & bitmaskFirstN<RegType>(nbits);
183 }
184 
199 template<typename RegType>
200 constexpr RegType getBitsItoJ(RegType reg, unsigned int bitI, unsigned int bitJ)
201 {
202  assert(bitI < std::numeric_limits<RegType>::digits); // BitI must be less than the number of bits in T.
203 
204  return (reg >> bitI) & bitmaskItoJ<RegType>(bitI, bitJ);
205 }
206 
220 template<typename RegType>
221 constexpr RegType getBitsIthruJ(RegType reg, unsigned int bitI, unsigned int bitJ)
222 {
223  assert(bitI < std::numeric_limits<RegType>::digits); // BitI must be less than the number of bits in T.
224 
225  return (reg >> bitI) & bitmaskIthruJ<RegType>(bitI, bitJ);
226 }
227 
228 
231 //
232 // setRegisterBitXXX
233 //
234 
235 
245 template<typename RegType>
246 constexpr void setBitsN(RegType& reg, unsigned int bitI, unsigned int nbits)
247 {
248  using T = typename std::remove_volatile<RegType>::type;
249 
250  T tmp = reg;
251  tmp |= bitmaskN<T>(bitI, nbits);
252  reg = tmp;
253 }
254 
264 template<typename RegType>
265 constexpr void setBitsItoJ(RegType& reg, unsigned int bitI, unsigned int bitJ)
266 {
267  using T = typename std::remove_volatile<RegType>::type;
268 
269  T tmp = reg;
270  tmp |= bitmaskItoJ<T>(bitI, bitJ);
271  reg = tmp;
272 }
273 
283 template<typename RegType>
284 constexpr void setBitsIthruJ(RegType& reg, unsigned int bitI, unsigned int bitJ)
285 {
286  using T = typename std::remove_volatile<RegType>::type;
287 
288  T tmp = reg;
289  tmp |= bitmaskIthruJ<T>(bitI, bitJ);
290  reg = tmp;
291 }
292 
293 
296 //
297 // clearRegisterBitXXX
298 //
299 
300 
310 template<typename RegType>
311 constexpr void clearBitsN(RegType& reg, unsigned int bitI, unsigned int nbits)
312 {
313  using T = typename std::remove_volatile<RegType>::type;
314 
315  T tmp = reg;
316  tmp &= ~bitmaskN<T>(bitI, nbits);
317  reg = tmp;
318 }
319 
329 template<typename RegType>
330 constexpr void clearBitsItoJ(RegType& reg, unsigned int bitI, unsigned int bitJ)
331 {
332  using T = typename std::remove_volatile<RegType>::type;
333 
334  T tmp = reg;
335  tmp &= ~bitmaskItoJ<T>(bitI, bitJ);
336  reg = tmp;
337 }
338 
348 template<typename RegType>
349 constexpr void clearBitsIthruJ(RegType& reg, unsigned int bitI, unsigned int bitJ)
350 {
351  using T = typename std::remove_volatile<RegType>::type;
352 
353  T tmp = reg;
354  tmp &= ~bitmaskIthruJ<T>(bitI, bitJ);
355  reg = tmp;
356 }
357 
358 
361 //
362 // modifyBitsXXX
363 //
364 
365 
378 template<typename RegType, typename ValType>
379 constexpr void setBitsN(RegType& reg, unsigned int bitI, unsigned int nbits, ValType value)
380 {
381  static_assert(std::is_unsigned<RegType>::value, "Register type must be unsigned.");
382 
383  using T = typename std::remove_volatile<RegType>::type;
384 
385  T valueT = value;
386 
387  assert(bitI < std::numeric_limits<T>::digits); // bit I is within T
388  assert(nbits <= std::numeric_limits<T>::digits-bitI); // Sane number of bits
389  assert((valueT & ~bitmaskFirstN<T>(nbits)) == 0); // Value has no bits outside the window
390 
391  T tmp = reg; // Do all operations on a local copy, in case T is volatile.
392 
393  const T mask = bitmaskN<T>(bitI, nbits);
394 
395  tmp &= ~mask;
396  tmp |= (valueT << bitI) & mask;
397 
398  reg = tmp; // Write back to register.
399 }
400 
413 template<typename RegType, typename ValType>
414 constexpr void setBitsItoJ(RegType& reg, unsigned int bitI, unsigned int bitJ, ValType value)
415 {
416  assert(bitJ >= bitI); // J comes after I (non-negative number of bits)
417 
418  return setBitsN(reg, bitI, bitJ-bitI, value);
419 }
420 
433 template<typename RegType, typename ValType>
434 constexpr void modifyBitsIthruJ(RegType& reg, unsigned int bitI, unsigned int bitJ, ValType value)
435 {
436  return setBitsItoJ(reg, bitI, bitJ+1, value);
437 }
438 
439 
442 //
443 // BitfieldMemberXXX
444 //
445 
446 
447 namespace detail
448 {
449  template<class TestType, bool IsEnum = std::is_enum<TestType>::value>
451  {
452  static_assert(std::is_integral<TestType>::value, "Type must be an integer.");
453 
454  using type = TestType;
455  };
456 
457  template<class TestType>
458  struct BaseIntegerType<TestType, true>
459  {
460  static_assert(std::is_enum<TestType>::value, "Expected an enum.");
461 
462  using type = typename std::underlying_type<TestType>::type;
463  };
464 }
465 
466 
490 template<class T, unsigned int BitI, unsigned int Nbits>
492 {
493  using Type = T;
495  static constexpr inline unsigned int bitI = BitI;
496  static constexpr inline unsigned int nbits = Nbits;
497 
498  static_assert(std::numeric_limits<BaseType>::digits >= nbits, "T doesn't have enough bits");
499 
500  template<typename RegType>
501  static constexpr T get(RegType reg) { return static_cast<Type>(getBitsN(reg, bitI, nbits)); }
502 
503  template<typename RegType>
504  static constexpr void set(RegType& reg, Type value) { setBitsN(reg, bitI, nbits, static_cast<BaseType>(value)); }
505 
506  template<typename RegType>
507  static constexpr void clear(RegType& reg) { clearBitsN(reg, bitI, nbits); }
508 };
509 
510 
518 template<class T, unsigned int BitI, unsigned int BitJ>
519 struct BitfieldMemberItoJ : public BitfieldMemberN<T, BitI, BitJ-BitI> {};
520 
521 
529 template<class T, unsigned int BitI, unsigned int BitJ>
530 struct BitfieldMemberIthruJ : public BitfieldMemberItoJ<T, BitI, BitJ+1> {};
531 
532 
533 
537 template<unsigned int nbytes>
539 
540 template<> struct IntegerWithBytes<8>
541 {
542  using Unsigned = uint64_t;
543  using Signed = int64_t;
544 };
545 template<> struct IntegerWithBytes<7> : IntegerWithBytes<8> {};
546 template<> struct IntegerWithBytes<6> : IntegerWithBytes<8> {};
547 template<> struct IntegerWithBytes<5> : IntegerWithBytes<8> {};
548 template<> struct IntegerWithBytes<4>
549 {
550  using Unsigned = uint32_t;
551  using Signed = int32_t;
552 };
553 template<> struct IntegerWithBytes<3> : IntegerWithBytes<4> {};
554 template<> struct IntegerWithBytes<2>
555 {
556  using Unsigned = uint16_t;
557  using Signed = int16_t;
558 };
559 template<> struct IntegerWithBytes<1>
560 {
561  using Unsigned = uint8_t;
562  using Signed = int8_t;
563 };
564 
565 
569 template<unsigned int nbits>
570 struct IntegerWithBits : IntegerWithBytes< (nbits+7)/8 > {};
571 
572 
573 } // namespace microstrain::common
microstrain::modifyBitsIthruJ
constexpr void modifyBitsIthruJ(RegType &reg, unsigned int bitI, unsigned int bitJ, ValType value)
Writes a value to a specific set of bits in a variable as if it were a bitfield.
Definition: bits.hpp:434
microstrain::bitmaskN
constexpr T bitmaskN(unsigned int bitI, unsigned int nbits)
Creates a bitmask with N '1' bits starting at bit I.
Definition: bits.hpp:58
microstrain::BitfieldMemberN::clear
static constexpr void clear(RegType &reg)
Definition: bits.hpp:507
microstrain::bitmaskIthruJ
constexpr T bitmaskIthruJ(unsigned int bitI, unsigned int bitJ)
Creates a bitmask with bits [bitI..bitJ] set to 1 (includes bit J).
Definition: bits.hpp:104
microstrain::IntegerWithBits
Helper type to get an integer of at least N bits in size.
Definition: bits.hpp:570
microstrain::setBitsN
constexpr void setBitsN(RegType &reg, unsigned int bitI, unsigned int nbits)
Sets a series of consecutive bits in a variable to 1.
Definition: bits.hpp:246
microstrain::getBitsIthruJ
constexpr RegType getBitsIthruJ(RegType reg, unsigned int bitI, unsigned int bitJ)
Extracts a bitfield from a variable value.
Definition: bits.hpp:221
microstrain::IntegerWithBytes< 4 >::Unsigned
uint32_t Unsigned
Definition: bits.hpp:550
microstrain::IntegerWithBytes< 8 >::Signed
int64_t Signed
Definition: bits.hpp:543
microstrain::IntegerWithBytes
Helper type to get an integer of at least N bytes in size.
Definition: bits.hpp:538
microstrain::bitmaskItoJ
constexpr T bitmaskItoJ(unsigned int bitI, unsigned int bitJ)
Creates a bitmask with bits [bitI..bitJ) set to 1 (excludes bit J).
Definition: bits.hpp:80
microstrain::IntegerWithBytes< 1 >::Signed
int8_t Signed
Definition: bits.hpp:562
microstrain::getBitsItoJ
constexpr RegType getBitsItoJ(RegType reg, unsigned int bitI, unsigned int bitJ)
Extracts a bitfield from a variable value.
Definition: bits.hpp:200
microstrain::detail::BaseIntegerType< TestType, true >::type
typename std::underlying_type< TestType >::type type
Definition: bits.hpp:462
microstrain::BitfieldMemberN< T, BitI, BitJ-BitI >::BaseType
typename detail::BaseIntegerType< T >::type BaseType
Definition: bits.hpp:494
microstrain::IntegerWithBytes< 1 >::Unsigned
uint8_t Unsigned
Definition: bits.hpp:561
microstrain::testBit
constexpr bool testBit(RegType reg, unsigned int bit)
Checks if a specific bit in a value is set.
Definition: bits.hpp:129
microstrain::setBitsIthruJ
constexpr void setBitsIthruJ(RegType &reg, unsigned int bitI, unsigned int bitJ)
Sets a series of consecutive bits in a variable to 1.
Definition: bits.hpp:284
microstrain::BitfieldMemberItoJ
A class which represents part of a bitfield (see BitfieldMemberN)
Definition: bits.hpp:519
microstrain::clearBitsIthruJ
constexpr void clearBitsIthruJ(RegType &reg, unsigned int bitI, unsigned int bitJ)
Sets a series of consecutive bits in a variable to 0.
Definition: bits.hpp:349
microstrain::detail::BaseIntegerType::type
TestType type
Definition: bits.hpp:454
microstrain::IntegerWithBytes< 2 >::Unsigned
uint16_t Unsigned
Definition: bits.hpp:556
microstrain::BitfieldMemberIthruJ
A class which represents part of a bitfield (see BitfieldMemberN)
Definition: bits.hpp:530
microstrain::BitfieldMemberN< T, BitI, BitJ-BitI >::Type
T Type
Definition: bits.hpp:493
microstrain::BitfieldMemberN::set
static constexpr void set(RegType &reg, Type value)
Definition: bits.hpp:504
microstrain::getBitsN
constexpr RegType getBitsN(RegType reg, unsigned int bitI, unsigned int nbits)
Extracts a bitfield from a variable value.
Definition: bits.hpp:178
microstrain::detail::BaseIntegerType
Definition: bits.hpp:450
microstrain::setBit
constexpr void setBit(RegType &reg, unsigned int bit, bool value=true)
Sets a specific bit in a variable to a specified value.
Definition: bits.hpp:147
microstrain::IntegerWithBytes< 2 >::Signed
int16_t Signed
Definition: bits.hpp:557
microstrain::clearBitsItoJ
constexpr void clearBitsItoJ(RegType &reg, unsigned int bitI, unsigned int bitJ)
Sets a series of consecutive bits in a variable to 0.
Definition: bits.hpp:330
microstrain::IntegerWithBytes< 4 >::Signed
int32_t Signed
Definition: bits.hpp:551
microstrain::BitfieldMemberN::get
static constexpr T get(RegType reg)
Definition: bits.hpp:501
microstrain::setBitsItoJ
constexpr void setBitsItoJ(RegType &reg, unsigned int bitI, unsigned int bitJ)
Sets a series of consecutive bits in a variable to 1.
Definition: bits.hpp:265
microstrain::bitmaskFirstN
constexpr T bitmaskFirstN(unsigned int nbits)
Creates a bitmask with 1s in the first N bits, i.e. bits [0..N).
Definition: bits.hpp:31
microstrain::BitfieldMemberN
A class which represents part of a bitfield.
Definition: bits.hpp:491
microstrain::BitfieldMemberN::nbits
static constexpr unsigned int nbits
Definition: bits.hpp:496
microstrain::BitfieldMemberN::bitI
static constexpr unsigned int bitI
Definition: bits.hpp:495
microstrain::clearBitsN
constexpr void clearBitsN(RegType &reg, unsigned int bitI, unsigned int nbits)
Sets a series of consecutive bits in a variable to 0.
Definition: bits.hpp:311
microstrain::IntegerWithBytes< 8 >::Unsigned
uint64_t Unsigned
Definition: bits.hpp:542
microstrain
Definition: embedded_time.h:8