FastArduino v1.10
C++ library to build fast but small Arduino/AVR projects
Loading...
Searching...
No Matches
utilities.h
Go to the documentation of this file.
1// Copyright 2016-2023 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
51namespace 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
127 template<typename T> constexpr T min(T a, T b)
128 {
129 return (a < b ? a : b);
130 }
131
143 template<typename T> constexpr T max(T a, T b)
144 {
145 return (a > b ? a : b);
146 }
147
156 constexpr uint32_t power_of_10(int8_t n)
157 {
158 if (n > 0)
159 return 10UL * power_of_10(n - 1);
160 else if (n < 0)
161 return power_of_10(-n);
162 else
163 return 1;
164 }
165
219 constexpr int16_t map_raw_to_physical(int16_t value, UnitPrefix prefix, int16_t range, uint8_t precision_bits)
220 {
221 // Here we approximate the calculation by using 2^n instead of (2^n - 1) as input range
222 const int8_t prefix_value = int8_t(prefix);
223 if (prefix_value > 0)
224 return (int32_t(value) * int32_t(range) / int32_t(power_of_10(prefix_value))) >> precision_bits;
225 else
226 return (int32_t(value) * int32_t(range) * int32_t(power_of_10(prefix_value))) >> precision_bits;
227 }
228
230 // This is intermediate function used by map_physical_to_raw() but without overflow issue (int32 only)
231 constexpr int32_t map_physical_to_raw_(int32_t value, int8_t prefix, int32_t range, uint8_t precision_bits)
232 {
233 // Here we approximate the calculation by using 2^n instead of (2^n - 1) as input range
234 if (prefix >= 0)
235 return (value << precision_bits) * int32_t(power_of_10(prefix)) / range;
236 else
237 return (value << precision_bits) / int32_t(power_of_10(prefix)) / range;
238 }
240
292 constexpr int16_t map_physical_to_raw(int16_t value, UnitPrefix prefix, int16_t range, uint8_t precision_bits)
293 {
294 // We first perform calculation as int32
295 const int32_t output = map_physical_to_raw_(value, int8_t(prefix), range, precision_bits);
296 //Then we deal with boundary cases before conversion to int16
297 if (output > INT16_MAX)
298 return INT16_MAX;
299 else if (output <= INT16_MIN)
300 return INT16_MIN;
301 else
302 return output;
303 }
304
308 constexpr uint8_t low_byte(uint16_t word)
309 {
310 return uint8_t(word & 0xFF);
311 }
312
316 constexpr uint8_t high_byte(uint16_t word)
317 {
318 return uint8_t(word >> 8);
319 }
320
327 constexpr uint16_t as_uint16_t(uint8_t high, uint8_t low)
328 {
329 return uint16_t(uint16_t(high) << 8) | uint16_t(low);
330 }
331
339 template<typename T> constexpr T is_zero(T value, T default_value)
340 {
341 return (value ? value : default_value);
342 }
343
352 template<typename T> void set_mask(volatile T& reg, T mask, T value)
353 {
354 reg = (reg & ~mask) | (value & mask);
355 }
356
364 template<typename T> constexpr bool is_mask_equal(T actual, T mask, T expected)
365 {
366 return (actual & mask) == (expected & mask);
367 }
368
375 inline uint8_t bcd_to_binary(uint8_t bcd)
376 {
377 const uint8_t tens = bcd / 16;
378 // We avoid tens * 10 to avoid adding library for multiplication
379 return (tens << 3) + (tens << 1) + (bcd & 0x0F);
380 }
381
389 inline uint8_t binary_to_bcd(uint8_t binary)
390 {
391 uint8_t bcd = 0;
392 while (binary >= 10)
393 {
394 bcd += 0x10;
395 binary -= 10;
396 }
397 return bcd + binary;
398 }
399
405 inline void swap_bytes(uint16_t& value)
406 {
407 value = (value >> 8) | (value << 8);
408 }
409
415 inline void swap_bytes(int16_t& value)
416 {
417 swap_bytes((uint16_t&) value);
418 }
419
425 inline void swap_bytes(uint32_t& value)
426 {
427 uint16_t value1 = uint16_t(value >> 16);
428 uint16_t value2 = uint16_t(value & 0xFFFFU);
429 swap_bytes(value1);
430 swap_bytes(value2);
431 value = uint32_t(value1) | (uint32_t(value2) << 16);
432 }
433
439 inline void swap_bytes(int32_t& value)
440 {
441 swap_bytes((uint32_t&) value);
442 }
443
449 inline void swap_bytes(uint64_t& value)
450 {
451 uint32_t value1 = uint32_t(value >> 32);
452 uint32_t value2 = uint32_t(value & 0xFFFF'FFFFUL);
453 swap_bytes(value1);
454 swap_bytes(value2);
455 value = uint64_t(value1) | (uint64_t(value2) << 32);
456 }
457
463 inline void swap_bytes(int64_t& value)
464 {
465 swap_bytes((uint64_t&) value);
466 }
467
475 template<typename T> void swap(T& a, T&b)
476 {
477 T c = a;
478 a = b;
479 b = c;
480 }
481
483 template<typename T> union ToUint8
484 {
485 static_assert(sizeof(T) == 1, "T must be a one-byte size type");
486 explicit ToUint8(T value) : value_(value) {}
487 T value_;
488 uint8_t as_uint8_;
489 };
490
491 template<typename T> union ToArray
492 {
493 explicit ToArray(const T& value): value_{value} {}
494 T value_;
495 uint8_t as_array_[sizeof(T)];
496 };
498
506 template<typename T> constexpr uint8_t as_uint8_t(T input)
507 {
508 return ToUint8<T>(input).as_uint8_;
509 }
510
517 template<typename T, typename U = uint8_t[sizeof(T)]>
518 constexpr void as_array(const T& input, U output)
519 {
520 memcpy(output, ToArray<T>(input).as_array_, sizeof(T));
521 }
522
531 constexpr uint8_t calculate_delay1_count(float time_us)
532 {
533 return uint8_t(INST_PER_US / 3.0 * time_us);
534 }
535
542 constexpr uint8_t num_bits(uint8_t mask, uint8_t num = 0)
543 {
544 if (mask == 0)
545 return num;
546 else if (mask & 1)
547 return num_bits(mask >> 1, num + 1);
548 else
549 return num_bits(mask >> 1, num);
550 }
551
560 template<typename T> T inline change_endianness(const T& value)
561 {
562 return value;
563 }
564
566 template<> uint16_t inline change_endianness(const uint16_t& value)
567 {
568 uint16_t temp = value;
569 utils::swap_bytes(temp);
570 return temp;
571 }
572 template<> int16_t inline change_endianness(const int16_t& value)
573 {
574 int16_t temp = value;
575 utils::swap_bytes(temp);
576 return temp;
577 }
578 template<> uint32_t inline change_endianness(const uint32_t& value)
579 {
580 uint32_t temp = value;
581 utils::swap_bytes(temp);
582 return temp;
583 }
584 template<> int32_t inline change_endianness(const int32_t& value)
585 {
586 int32_t temp = value;
587 utils::swap_bytes(temp);
588 return temp;
589 }
591}
592
593#endif /* UTILITIES_HH */
Iterable class that can embed arrays or initializer lists through implicit conversion.
Definition: iterator.h:51
Useful defines GCC specific attributes.
Contains all generic utility methods.
Definition: iterator.h:29
constexpr T min(T a, T b)
Compute the min of 2 integral values.
Definition: utilities.h:127
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:156
T change_endianness(const T &value)
Change endianness of any integral type (from big to small or small to big).
Definition: utilities.h:560
constexpr T max(T a, T b)
Compute the max of 2 integral values.
Definition: utilities.h:143
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:339
void swap(T &a, T &b)
Swap the values of 2 variables passed by reference.
Definition: utilities.h:475
void swap_bytes(uint16_t &value)
Swap 2 bytes of a 2-bytes integer.
Definition: utilities.h:405
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:518
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
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:219
UnitPrefix
Common prefixes for measurement units.
Definition: utilities.h:102
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:531
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:364
uint8_t binary_to_bcd(uint8_t binary)
Convert a natural integers to a BCD byte (2 digits).
Definition: utilities.h:389
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:292
constexpr uint8_t as_uint8_t(T input)
Cast a one byte long bit-fields struct into a byte.
Definition: utilities.h:506
constexpr uint8_t high_byte(uint16_t word)
Extract the high order byte of a 16-bits word.
Definition: utilities.h:316
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:352
constexpr uint16_t as_uint16_t(uint8_t high, uint8_t low)
Convert 2 bytes into an unsigned int.
Definition: utilities.h:327
constexpr uint8_t num_bits(uint8_t mask, uint8_t num=0)
Calculate the number of 1 bits in a byte.
Definition: utilities.h:542
constexpr uint8_t low_byte(uint16_t word)
Extract the low order byte of a 16-bits word.
Definition: utilities.h:308
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
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:375