ESPHome  2021.11.3
helpers.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <cmath>
4 
5 #include <string>
6 #include <functional>
7 #include <vector>
8 #include <memory>
9 #include <type_traits>
10 
11 #ifdef USE_ESP32_FRAMEWORK_ARDUINO
12 #include "esp32-hal-psram.h"
13 #endif
14 
15 #include "esphome/core/optional.h"
16 
17 #define HOT __attribute__((hot))
18 #define ESPDEPRECATED(msg, when) __attribute__((deprecated(msg)))
19 #define ALWAYS_INLINE __attribute__((always_inline))
20 #define PACKED __attribute__((packed))
21 
22 #define xSemaphoreWait(semaphore, wait_time) \
23  xSemaphoreTake(semaphore, wait_time); \
24  xSemaphoreGive(semaphore);
25 
26 namespace esphome {
27 
29 void get_mac_address_raw(uint8_t *mac);
30 
33 std::string get_mac_address();
34 
36 std::string get_mac_address_pretty();
37 
38 #ifdef USE_ESP32
39 void set_mac_address(uint8_t *mac);
41 #endif
42 
43 std::string to_string(const std::string &val);
44 std::string to_string(int val);
45 std::string to_string(long val); // NOLINT
46 std::string to_string(long long val); // NOLINT
47 std::string to_string(unsigned val); // NOLINT
48 std::string to_string(unsigned long val); // NOLINT
49 std::string to_string(unsigned long long val); // NOLINT
50 std::string to_string(float val);
51 std::string to_string(double val);
52 std::string to_string(long double val);
53 optional<int> parse_hex(const std::string &str, size_t start, size_t length);
54 optional<int> parse_hex(char chr);
55 
57 bool str_equals_case_insensitive(const std::string &a, const std::string &b);
58 bool str_startswith(const std::string &full, const std::string &start);
59 bool str_endswith(const std::string &full, const std::string &ending);
60 
62 std::string __attribute__((format(printf, 1, 2))) str_sprintf(const char *fmt, ...);
63 
65  public:
66  void start();
67  void stop();
68 
69  static bool is_high_frequency();
70 
71  protected:
72  bool started_{false};
73 };
74 
82 template<typename T> T clamp(T val, T min, T max);
83 
92 float lerp(float completion, float start, float end);
93 
94 // Not all platforms we support target C++14 yet, so we can't unconditionally use std::make_unique. Provide our own
95 // implementation if needed, and otherwise pull std::make_unique into scope so that we have a uniform API.
96 #if __cplusplus >= 201402L
97 using std::make_unique;
98 #else
99 template<typename T, typename... Args> std::unique_ptr<T> make_unique(Args &&...args) {
100  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
101 }
102 #endif
103 
105 uint32_t random_uint32();
106 
111 double random_double();
112 
114 float random_float();
115 
116 void fill_random(uint8_t *data, size_t len);
117 
118 void fast_random_set_seed(uint32_t seed);
119 uint32_t fast_random_32();
120 uint16_t fast_random_16();
121 uint8_t fast_random_8();
122 
124 float gamma_correct(float value, float gamma);
126 float gamma_uncorrect(float value, float gamma);
127 
129 std::string value_accuracy_to_string(float value, int8_t accuracy_decimals);
130 
132 std::string uint64_to_string(uint64_t num);
133 
135 std::string uint32_to_string(uint32_t num);
136 
137 uint8_t reverse_bits_8(uint8_t x);
138 uint16_t reverse_bits_16(uint16_t x);
139 uint32_t reverse_bits_32(uint32_t x);
140 
142 void rgb_to_hsv(float red, float green, float blue, int &hue, float &saturation, float &value);
144 void hsv_to_rgb(int hue, float saturation, float value, float &red, float &green, float &blue);
145 
146 /***
147  * An interrupt helper class.
148  *
149  * This behaves like std::lock_guard. As long as the value is visible in the current stack, all interrupts
150  * (including flash reads) will be disabled.
151  *
152  * Please note all functions called when the interrupt lock must be marked IRAM_ATTR (loading code into
153  * instruction cache is done via interrupts; disabling interrupts prevents data not already in cache from being
154  * pulled from flash).
155  *
156  * Example:
157  *
158  * ```cpp
159  * // interrupts are enabled
160  * {
161  * InterruptLock lock;
162  * // do something
163  * // interrupts are disabled
164  * }
165  * // interrupts are enabled
166  * ```
167  */
169  public:
170  InterruptLock();
171  ~InterruptLock();
172 
173  protected:
174 #ifdef USE_ESP8266
175  uint32_t xt_state_;
176 #endif
177 };
178 
180 uint8_t crc8(uint8_t *data, uint8_t len);
181 
187 };
188 
189 ParseOnOffState parse_on_off(const char *str, const char *on = nullptr, const char *off = nullptr);
190 
191 // Encode raw data to a human-readable string (for debugging)
192 std::string hexencode(const uint8_t *data, uint32_t len);
193 template<typename T> std::string hexencode(const T &data) { return hexencode(data.data(), data.size()); }
194 
195 // https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer/7858971#7858971
196 template<int...> struct seq {}; // NOLINT
197 template<int N, int... S> struct gens : gens<N - 1, N - 1, S...> {}; // NOLINT
198 template<int... S> struct gens<0, S...> { using type = seq<S...>; }; // NOLINT
199 
200 template<bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;
201 
202 template<typename T, enable_if_t<!std::is_pointer<T>::value, int> = 0> T id(T value) { return value; }
203 template<typename T, enable_if_t<std::is_pointer<T *>::value, int> = 0> T &id(T *value) { return *value; }
204 
205 template<typename... X> class CallbackManager;
206 
211 template<typename... Ts> class CallbackManager<void(Ts...)> {
212  public:
214  void add(std::function<void(Ts...)> &&callback) { this->callbacks_.push_back(std::move(callback)); }
215 
217  void call(Ts... args) {
218  for (auto &cb : this->callbacks_)
219  cb(args...);
220  }
221 
222  protected:
223  std::vector<std::function<void(Ts...)>> callbacks_;
224 };
225 
226 // https://stackoverflow.com/a/37161919/8924614
227 template<class T, class... Args>
228 struct is_callable // NOLINT
229 {
230  template<class U> static auto test(U *p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type());
231 
232  template<class U> static auto test(...) -> decltype(std::false_type());
233 
234  static constexpr auto value = decltype(test<T>(nullptr))::value; // NOLINT
235 };
236 
237 void delay_microseconds_safe(uint32_t us);
238 
239 template<typename T> class Deduplicator {
240  public:
241  bool next(T value) {
242  if (this->has_value_) {
243  if (this->last_value_ == value)
244  return false;
245  }
246  this->has_value_ = true;
247  this->last_value_ = value;
248  return true;
249  }
250  bool has_value() const { return this->has_value_; }
251 
252  protected:
253  bool has_value_{false};
254  T last_value_{};
255 };
256 
257 template<typename T> class Parented {
258  public:
259  Parented() {}
260  Parented(T *parent) : parent_(parent) {}
261 
262  T *get_parent() const { return parent_; }
263  void set_parent(T *parent) { parent_ = parent; }
264 
265  protected:
266  T *parent_{nullptr};
267 };
268 
269 uint32_t fnv1_hash(const std::string &str);
270 
271 template<typename T> T *new_buffer(size_t length) {
272  T *buffer;
273 #ifdef USE_ESP32_FRAMEWORK_ARDUINO
274  if (psramFound()) {
275  buffer = (T *) ps_malloc(length);
276  } else {
277  buffer = new T[length]; // NOLINT(cppcoreguidelines-owning-memory)
278  }
279 #else
280  buffer = new T[length]; // NOLINT(cppcoreguidelines-owning-memory)
281 #endif
282 
283  return buffer;
284 }
285 
286 // ---------------------------------------------------------------------------------------------------------------------
287 
290 
291 // std::byteswap is from C++23 and technically should be a template, but this will do for now.
292 constexpr uint8_t byteswap(uint8_t n) { return n; }
293 constexpr uint16_t byteswap(uint16_t n) { return __builtin_bswap16(n); }
294 constexpr uint32_t byteswap(uint32_t n) { return __builtin_bswap32(n); }
295 constexpr uint64_t byteswap(uint64_t n) { return __builtin_bswap64(n); }
296 
298 
301 
303 constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb) {
304  return (static_cast<uint16_t>(msb) << 8) | (static_cast<uint16_t>(lsb));
305 }
307 constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4) {
308  return (static_cast<uint32_t>(byte1) << 24) | (static_cast<uint32_t>(byte2) << 16) |
309  (static_cast<uint32_t>(byte3) << 8) | (static_cast<uint32_t>(byte4));
310 }
311 
313 template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> inline T encode_value(const uint8_t *bytes) {
314  T val = 0;
315  for (size_t i = 0; i < sizeof(T); i++) {
316  val <<= 8;
317  val |= bytes[i];
318  }
319  return val;
320 }
322 template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
323 inline T encode_value(const std::array<uint8_t, sizeof(T)> bytes) {
324  return encode_value<T>(bytes.data());
325 }
327 template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0>
328 inline std::array<uint8_t, sizeof(T)> decode_value(T val) {
329  std::array<uint8_t, sizeof(T)> ret{};
330  for (size_t i = sizeof(T); i > 0; i--) {
331  ret[i - 1] = val & 0xFF;
332  val >>= 8;
333  }
334  return ret;
335 }
336 
338 template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> constexpr T convert_big_endian(T val) {
339 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
340  return byteswap(val);
341 #else
342  return val;
343 #endif
344 }
345 
347 
350 
352 std::string str_truncate(const std::string &str, size_t length);
353 
355 std::string str_snake_case(const std::string &str);
356 
358 std::string str_sanitize(const std::string &str);
359 
361 
364 
366 template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
367 optional<T> parse_number(const char *str, size_t len) {
368  char *end = nullptr;
369  unsigned long value = ::strtoul(str, &end, 10); // NOLINT(google-runtime-int)
370  if (end == str || *end != '\0' || value > std::numeric_limits<T>::max())
371  return {};
372  return value;
373 }
375 template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0>
376 optional<T> parse_number(const std::string &str) {
377  return parse_number<T>(str.c_str(), str.length() + 1);
378 }
380 template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
381 optional<T> parse_number(const char *str, size_t len) {
382  char *end = nullptr;
383  signed long value = ::strtol(str, &end, 10); // NOLINT(google-runtime-int)
384  if (end == str || *end != '\0' || value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max())
385  return {};
386  return value;
387 }
389 template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0>
390 optional<T> parse_number(const std::string &str) {
391  return parse_number<T>(str.c_str(), str.length() + 1);
392 }
394 template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0>
395 optional<T> parse_number(const char *str, size_t len) {
396  char *end = nullptr;
397  float value = ::strtof(str, &end);
398  if (end == str || *end != '\0' || value == HUGE_VALF)
399  return {};
400  return value;
401 }
403 template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0>
404 optional<T> parse_number(const std::string &str) {
405  return parse_number<T>(str.c_str(), str.length() + 1);
406 }
407 
409 
410 } // namespace esphome
void hsv_to_rgb(int hue, float saturation, float value, float &red, float &green, float &blue)
Convert hue (0-360) & saturation/value percentage (0-1) to RGB floats (0-1)
Definition: helpers.cpp:392
constexpr T convert_big_endian(T val)
Convert a value between host byte order and big endian (most significant byte first) order...
Definition: helpers.h:338
uint16_t fast_random_16()
Definition: helpers.cpp:106
std::string str_snake_case(const std::string &str)
Convert the string to snake case (lowercase with underscores).
Definition: helpers.cpp:447
uint32_t reverse_bits_32(uint32_t x)
std::string str_truncate(const std::string &str, size_t length)
Truncate a string to a specific length.
Definition: helpers.cpp:444
std::string value_accuracy_to_string(float value, int8_t accuracy_decimals)
Create a string from a value and an accuracy in decimals.
Definition: helpers.cpp:132
bool next(T value)
Definition: helpers.h:241
uint8_t reverse_bits_8(uint8_t x)
Definition: helpers.cpp:200
uint32_t random_uint32()
Return a random 32 bit unsigned integer.
Definition: helpers.cpp:76
optional< T > parse_number(const char *str, size_t len)
Parse an unsigned decimal number (requires null-terminated string).
Definition: helpers.h:367
uint8_t crc8(uint8_t *data, uint8_t len)
Calculate a crc8 of data with the provided data length.
Definition: helpers.cpp:170
void fast_random_set_seed(uint32_t seed)
Definition: helpers.cpp:101
typename std::enable_if< B, T >::type enable_if_t
Definition: helpers.h:200
uint8_t fast_random_8()
Definition: helpers.cpp:110
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Definition: helpers.h:307
std::string to_string(const std::string &val)
Definition: helpers.cpp:210
T id(T value)
Definition: helpers.h:202
std::vector< std::function< void(Ts...)> > callbacks_
Definition: helpers.h:223
float lerp(float completion, float start, float end)
Linearly interpolate between end start and end by completion.
Definition: helpers.cpp:332
void set_parent(T *parent)
Definition: helpers.h:263
std::string uint32_to_string(uint32_t num)
Convert a uint32_t to a hex string.
Definition: helpers.cpp:148
void delay_microseconds_safe(uint32_t us)
Definition: helpers.cpp:186
void call(Ts... args)
Call all callbacks in this manager.
Definition: helpers.h:217
void __attribute__((noreturn)) arch_restart()
uint16_t reverse_bits_16(uint16_t x)
Definition: helpers.cpp:207
ParseOnOffState
Definition: helpers.h:182
float gamma_correct(float value, float gamma)
Applies gamma correction with the provided gamma to value.
Definition: helpers.cpp:115
bool str_startswith(const std::string &full, const std::string &start)
Definition: helpers.cpp:334
void rgb_to_hsv(float red, float green, float blue, int &hue, float &saturation, float &value)
Convert RGB floats (0-1) to hue (0-360) & saturation/value percentage (0-1)
Definition: helpers.cpp:370
std::string str_sprintf(const char *fmt,...)
Definition: helpers.cpp:338
std::string get_mac_address()
Get the MAC address as a string, using lower case hex notation.
Definition: helpers.cpp:50
T * new_buffer(size_t length)
Definition: helpers.h:271
std::string hexencode(const uint8_t *data, uint32_t len)
Definition: helpers.cpp:354
void fill_random(uint8_t *data, size_t len)
Definition: helpers.cpp:88
uint8_t type
T clamp(const T val, const T min, const T max)
Clamp the value between min and max.
Definition: helpers.cpp:321
bool has_value() const
Definition: helpers.h:250
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition: helpers.h:303
void set_mac_address(uint8_t *mac)
Set the MAC address to use from the provided byte array (6 bytes).
Definition: helpers.cpp:71
uint32_t fast_random_32()
Definition: helpers.cpp:102
Parented(T *parent)
Definition: helpers.h:260
T * get_parent() const
Definition: helpers.h:262
constexpr uint8_t byteswap(uint8_t n)
Definition: helpers.h:292
optional< int > parse_hex(const char chr)
Definition: helpers.cpp:257
ParseOnOffState parse_on_off(const char *str, const char *on, const char *off)
Definition: helpers.cpp:155
std::string str_sanitize(const std::string &str)
Sanitizes the input string by removing all characters but alphanumerics, dashes and underscores...
Definition: helpers.cpp:454
uint32_t fnv1_hash(const std::string &str)
Definition: helpers.cpp:289
std::array< uint8_t, sizeof(T)> decode_value(T val)
Decode a value into its constituent bytes (from most to least significant).
Definition: helpers.h:328
Library based on https://github.com/miguelbalboa/rfid and adapted to ESPHome by . ...
Definition: a4988.cpp:4
double random_double()
Returns a random double between 0 and 1.
Definition: helpers.cpp:84
num_t cb(num_t x)
Definition: sun.cpp:31
std::unique_ptr< T > make_unique(Args &&...args)
Definition: helpers.h:99
std::string get_mac_address_pretty()
Get the MAC address as a string, using colon-separated upper case hex notation.
Definition: helpers.cpp:62
void add(std::function< void(Ts...)> &&callback)
Add a callback to the internal callback list.
Definition: helpers.h:214
bool str_endswith(const std::string &full, const std::string &ending)
Definition: helpers.cpp:335
std::string uint64_to_string(uint64_t num)
Convert a uint64_t to a hex string.
Definition: helpers.cpp:142
float random_float()
Returns a random float between 0 and 1. Essentially just casts random_double() to a float...
Definition: helpers.cpp:86
T encode_value(const uint8_t *bytes)
Encode a value from its constituent bytes (from most to least significant) in an array with length si...
Definition: helpers.h:313
bool str_equals_case_insensitive(const std::string &a, const std::string &b)
Compare string a to string b (ignoring case) and return whether they are equal.
Definition: helpers.cpp:297
void get_mac_address_raw(uint8_t *mac)
Read the raw MAC address into the provided byte array (6 bytes).
Definition: helpers.cpp:33
float gamma_uncorrect(float value, float gamma)
Reverts gamma correction with the provided gamma to value.
Definition: helpers.cpp:123