diff --git a/esphome/components/i2c/i2c.h b/esphome/components/i2c/i2c.h index 7ee4cdd811..50a0b3ae50 100644 --- a/esphome/components/i2c/i2c.h +++ b/esphome/components/i2c/i2c.h @@ -1,6 +1,7 @@ #pragma once #include "i2c_bus.h" +#include "esphome/core/helpers.h" #include "esphome/core/optional.h" #include #include @@ -32,16 +33,8 @@ class I2CRegister { // like ntohs/htons but without including networking headers. // ("i2c" byte order is big-endian) -inline uint16_t i2ctohs(uint16_t i2cshort) { - union { - uint16_t x; - uint8_t y[2]; - } conv; - conv.x = i2cshort; - return ((uint16_t) conv.y[0] << 8) | ((uint16_t) conv.y[1] << 0); -} - -inline uint16_t htoi2cs(uint16_t hostshort) { return i2ctohs(hostshort); } +inline uint16_t i2ctohs(uint16_t i2cshort) { return convert_big_endian(i2cshort); } +inline uint16_t htoi2cs(uint16_t hostshort) { return convert_big_endian(hostshort); } class I2CDevice { public: diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index fde631514b..f29af06d89 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -306,6 +306,31 @@ template T *new_buffer(size_t length) { // --------------------------------------------------------------------------------------------------------------------- +/// @name STL backports +///@{ + +// std::byteswap is from C++23 and technically should be a template, but this will do for now. +constexpr uint8_t byteswap(uint8_t n) { return n; } +constexpr uint16_t byteswap(uint16_t n) { return __builtin_bswap16(n); } +constexpr uint32_t byteswap(uint32_t n) { return __builtin_bswap32(n); } +constexpr uint64_t byteswap(uint64_t n) { return __builtin_bswap64(n); } + +///@} + +/// @name Bit manipulation +///@{ + +/// Convert a value between host byte order and big endian (most significant byte first) order. +template::value, int> = 0> constexpr T convert_big_endian(T val) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return byteswap(val); +#else + return val; +#endif +} + +///@} + /// @name Parsing & formatting ///@{