FastArduino  v1.7
C++ library to build fast but small Arduino/AVR projects
utilities.h
Go to the documentation of this file.
1 // Copyright 2016-2021 Jean-Francois Poilpret
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
21 #ifndef UTILITIES_HH
22 #define UTILITIES_HH
23 
24 #include "defines.h"
25 #include "boards/board.h"
26 #include <util/atomic.h>
27 
46 #define synchronized _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
47 
51 namespace utils
52 {
62  template<typename T> constexpr T constrain(T value, T min, T max)
63  {
64  if (value < min)
65  return min;
66  else if (value > max)
67  return max;
68  else
69  return value;
70  }
71 
88  template<typename TI, typename TO>
89  constexpr TO map(TI value, TI input_min, TI input_max, TO output_min, TO output_max)
90  {
91  return output_min + (value - input_min) * (output_max - output_min) / (input_max - input_min);
92  }
93 
94  // NOTE: we use prefixes that can be covered in a uint32
101  enum class UnitPrefix : int8_t
102  {
103  GIGA = 9,
104  MEGA = 6,
105  KILO = 3,
106  HECTO = 2,
107  DECA = 1,
108  NONE = 0,
109  DECI = -1,
110  CENTI = -2,
111  MILLI = -3,
112  MICRO = -6,
113  NANO = -9,
114  };
115 
124  constexpr uint32_t power_of_10(int8_t n)
125  {
126  if (n > 0)
127  return 10UL * power_of_10(n - 1);
128  else if (n < 0)
129  return power_of_10(-n);
130  else
131  return 1;
132  }
133 
187  constexpr int16_t map_raw_to_physical(int16_t value, UnitPrefix prefix, int16_t range, uint8_t precision_bits)
188  {
189  // Here we approximate the calculation by using 2^n instead of (2^n - 1) as input range
190  const int8_t prefix_value = int8_t(prefix);
191  if (prefix_value > 0)
192  return (int32_t(value) * int32_t(range) / int32_t(power_of_10(prefix_value))) >> precision_bits;
193  else
194  return (int32_t(value) * int32_t(range) * int32_t(power_of_10(prefix_value))) >> precision_bits;
195  }
196 
198  // This is intermediate function used by map_physical_to_raw() but without overflow issue (int32 only)
199  constexpr int32_t map_physical_to_raw_(int32_t value, int8_t prefix, int32_t range, uint8_t precision_bits)
200  {
201  // Here we approximate the calculation by using 2^n instead of (2^n - 1) as input range
202  if (prefix >= 0)
203  return (value << precision_bits) * int32_t(power_of_10(prefix)) / range;
204  else
205  return (value << precision_bits) / int32_t(power_of_10(prefix)) / range;
206  }
208 
260  constexpr int16_t map_physical_to_raw(int16_t value, UnitPrefix prefix, int16_t range, uint8_t precision_bits)
261  {
262  // We first perform calculation as int32
263  const int32_t output = map_physical_to_raw_(value, int8_t(prefix), range, precision_bits);
264  //Then we deal with boundary cases before conversion to int16
265  if (output > INT16_MAX)
266  return INT16_MAX;
267  else if (output <= INT16_MIN)
268  return INT16_MIN;
269  else
270  return output;
271  }
272 
276  constexpr uint8_t low_byte(uint16_t word)
277  {
278  return uint8_t(word & 0xFF);
279  }
280 
284  constexpr uint8_t high_byte(uint16_t word)
285  {
286  return uint8_t(word >> 8);
287  }
288 
295  constexpr uint16_t as_uint16_t(uint8_t high, uint8_t low)
296  {
297  return uint16_t(uint16_t(high) << 8) | uint16_t(low);
298  }
299 
307  template<typename T> constexpr T is_zero(T value, T default_value)
308  {
309  return (value ? value : default_value);
310  }
311 
320  template<typename T> void set_mask(volatile T& reg, T mask, T value)
321  {
322  reg = (reg & ~mask) | (value & mask);
323  }
324 
332  template<typename T> constexpr bool is_mask_equal(T actual, T mask, T expected)
333  {
334  return (actual & mask) == (expected & mask);
335  }
336 
343  inline uint8_t bcd_to_binary(uint8_t bcd)
344  {
345  const uint8_t tens = bcd / 16;
346  // We avoid tens * 10 to avoid adding library for multiplication
347  return (tens << 3) + (tens << 1) + (bcd & 0x0F);
348  }
349 
357  inline uint8_t binary_to_bcd(uint8_t binary)
358  {
359  uint8_t bcd = 0;
360  while (binary >= 10)
361  {
362  bcd += 0x10;
363  binary -= 10;
364  }
365  return bcd + binary;
366  }
367 
373  inline void swap_bytes(uint16_t& value)
374  {
375  value = (value >> 8) | (value << 8);
376  }
377 
383  inline void swap_bytes(int16_t& value)
384  {
385  swap_bytes((uint16_t&) value);
386  }
387 
389  template<typename T> union ToUint8
390  {
391  static_assert(sizeof(T) == 1, "T must be a one-byte size type");
392  explicit ToUint8(T value) : value_(value) {}
393  T value_;
394  uint8_t as_uint8_;
395  };
396 
397  template<typename T> union ToArray
398  {
399  explicit ToArray(const T& value): value_{value} {}
400  T value_;
401  uint8_t as_array_[sizeof(T)];
402  };
404 
412  template<typename T> constexpr uint8_t as_uint8_t(T input)
413  {
414  return ToUint8<T>(input).as_uint8_;
415  }
416 
423  template<typename T, typename U = uint8_t[sizeof(T)]>
424  constexpr void as_array(const T& input, U output)
425  {
426  memcpy(output, ToArray<T>(input).as_array_, sizeof(T));
427  }
428 
437  constexpr uint8_t calculate_delay1_count(float time_us)
438  {
439  return uint8_t(INST_PER_US / 3.0 * time_us);
440  }
441 
447  constexpr uint8_t num_bits(uint8_t mask, uint8_t num = 0)
448  {
449  if (mask == 0)
450  return num;
451  else if (mask & 1)
452  return num_bits(mask >> 1, num + 1);
453  else
454  return num_bits(mask >> 1, num);
455  }
456 }
457 
458 #endif /* UTILITIES_HH */
459 
utils::constrain
constexpr T constrain(T value, T min, T max)
Constrain value to be greater than or equal to min and lower than or equal to max.
Definition: utilities.h:62
utils::map_raw_to_physical
constexpr int16_t map_raw_to_physical(int16_t value, UnitPrefix prefix, int16_t range, uint8_t precision_bits)
Convert the raw value, obtained from an electronics device, using precision_bit number of bits (that ...
Definition: utilities.h:187
utils::swap_bytes
void swap_bytes(uint16_t &value)
Swap 2 bytes of a 2-bytes integer.
Definition: utilities.h:373
utils::map
constexpr TO map(TI value, TI input_min, TI input_max, TO output_min, TO output_max)
Linearly transform value from range [input_min ; input_max] to range [output_min ; output_max].
Definition: utilities.h:89
utils::high_byte
constexpr uint8_t high_byte(uint16_t word)
Extract the high order byte of a 16-bits word.
Definition: utilities.h:284
utils::num_bits
constexpr uint8_t num_bits(uint8_t mask, uint8_t num=0)
Calculate the number of 1 bits in a byte.
Definition: utilities.h:447
defines.h
Useful defines GCC specific attributes.
utils::binary_to_bcd
uint8_t binary_to_bcd(uint8_t binary)
Convert a natural integers to a BCD byte (2 digits).
Definition: utilities.h:357
utils::power_of_10
constexpr uint32_t power_of_10(int8_t n)
Calculate a power of 10 at compile-time, provided that n is a constant at call time.
Definition: utilities.h:124
utils::UnitPrefix
UnitPrefix
Common prefixes for measurement units.
Definition: utilities.h:102
utils::as_uint16_t
constexpr uint16_t as_uint16_t(uint8_t high, uint8_t low)
Convert 2 bytes into an unsigned int.
Definition: utilities.h:295
utils::is_zero
constexpr T is_zero(T value, T default_value)
Replace value by default_value if not "true" (also known as "Elvis operator").
Definition: utilities.h:307
utils::as_array
constexpr void as_array(const T &input, U output)
Cast an instance of type T to an array of uint8_t of the size of T.
Definition: utilities.h:424
utils::low_byte
constexpr uint8_t low_byte(uint16_t word)
Extract the low order byte of a 16-bits word.
Definition: utilities.h:276
utils::bcd_to_binary
uint8_t bcd_to_binary(uint8_t bcd)
Convert Binary-coded decimal byte (each nibble is a digit from 0 to 9) into a natural byte.
Definition: utilities.h:343
utils::is_mask_equal
constexpr bool is_mask_equal(T actual, T mask, T expected)
Common utility to check if 2 values are equal according to a mask.
Definition: utilities.h:332
utils::as_uint8_t
constexpr uint8_t as_uint8_t(T input)
Cast a one byte long bit-fields struct into a byte.
Definition: utilities.h:412
utils::map_physical_to_raw
constexpr int16_t map_physical_to_raw(int16_t value, UnitPrefix prefix, int16_t range, uint8_t precision_bits)
Convert an absolute physical value, expressed in some given measurement unit, scaled with prefix,...
Definition: utilities.h:260
utils
Contains all generic utility methods.
Definition: utilities.h:52
utils::set_mask
void set_mask(volatile T &reg, T mask, T value)
Common utility to force a part of the value of a register, designated by a bit mask.
Definition: utilities.h:320
utils::calculate_delay1_count
constexpr uint8_t calculate_delay1_count(float time_us)
Calculate the count to pass to delay1() in order to reach time_us microseconds delay.
Definition: utilities.h:437