diff --git a/esphome/components/ade7880/ade7880_i2c.cpp b/esphome/components/ade7880/ade7880_i2c.cpp index 294fd430d3e..dfc7a58300f 100644 --- a/esphome/components/ade7880/ade7880_i2c.cpp +++ b/esphome/components/ade7880/ade7880_i2c.cpp @@ -11,12 +11,6 @@ namespace esphome::ade7880 { -// adapted from https://stackoverflow.com/a/55912127/1886371 -template inline T sign_extend(const T &v) noexcept { - using S = struct { signed Val : Bits; }; - return reinterpret_cast(&v)->Val; -} - // Register types // unsigned 8-bit (uint8_t) // signed 10-bit - 16-bit ZP on wire (int16_t, needs sign extension) @@ -49,7 +43,7 @@ uint16_t ADE7880::read_u16_register16_(uint16_t a_register) { int32_t ADE7880::read_s24zp_register16_(uint16_t a_register) { // s24zp means 24 bit signed value in the lower 24 bits of a 32-bit register - int32_t in; + uint32_t in; this->read_register16(a_register, reinterpret_cast(&in), sizeof(in)); return sign_extend<24>(convert_big_endian(in)); } diff --git a/esphome/components/bme280_base/bme280_base.cpp b/esphome/components/bme280_base/bme280_base.cpp index 4b74a15c0a6..cf61160f77e 100644 --- a/esphome/components/bme280_base/bme280_base.cpp +++ b/esphome/components/bme280_base/bme280_base.cpp @@ -3,6 +3,7 @@ #include "bme280_base.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include #include @@ -144,11 +145,10 @@ void BME280Component::setup() { this->calibration_.h1 = read_u8_(BME280_REGISTER_DIG_H1); this->calibration_.h2 = read_s16_le_(BME280_REGISTER_DIG_H2); this->calibration_.h3 = read_u8_(BME280_REGISTER_DIG_H3); - // h4 and h5 are signed 12-bit values; shift left then arithmetic right shift to sign-extend - int16_t h4_raw = read_u8_(BME280_REGISTER_DIG_H4) << 4 | (read_u8_(BME280_REGISTER_DIG_H4 + 1) & 0x0F); - this->calibration_.h4 = static_cast(h4_raw << 4) >> 4; - int16_t h5_raw = read_u8_(BME280_REGISTER_DIG_H5 + 1) << 4 | (read_u8_(BME280_REGISTER_DIG_H5) >> 4); - this->calibration_.h5 = static_cast(h5_raw << 4) >> 4; + this->calibration_.h4 = + sign_extend<12>(read_u8_(BME280_REGISTER_DIG_H4) << 4 | (read_u8_(BME280_REGISTER_DIG_H4 + 1) & 0x0F)); + this->calibration_.h5 = + sign_extend<12>(read_u8_(BME280_REGISTER_DIG_H5 + 1) << 4 | (read_u8_(BME280_REGISTER_DIG_H5) >> 4)); this->calibration_.h6 = read_u8_(BME280_REGISTER_DIG_H6); uint8_t humid_control_val = 0; diff --git a/esphome/components/cs5460a/cs5460a.cpp b/esphome/components/cs5460a/cs5460a.cpp index 7c4e4847911..4631e5ce3cd 100644 --- a/esphome/components/cs5460a/cs5460a.cpp +++ b/esphome/components/cs5460a/cs5460a.cpp @@ -1,4 +1,5 @@ #include "cs5460a.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome::cs5460a { @@ -304,7 +305,7 @@ bool CS5460AComponent::check_status_() { voltage_sensor_->publish_state(raw_voltage * voltage_multiplier_); if (power_sensor_ != nullptr && raw_energy != prev_raw_energy_) { - int32_t raw = (int32_t) (raw_energy << 8) >> 8; /* Sign-extend */ + int32_t raw = sign_extend<24>(raw_energy); power_sensor_->publish_state(raw * power_multiplier_); prev_raw_energy_ = raw_energy; } diff --git a/esphome/components/hx711/hx711.cpp b/esphome/components/hx711/hx711.cpp index 48afc0192de..9a81befcc45 100644 --- a/esphome/components/hx711/hx711.cpp +++ b/esphome/components/hx711/hx711.cpp @@ -67,9 +67,7 @@ bool HX711Sensor::read_sensor_(uint32_t *result) { this->status_clear_warning(); - if (data & 0x800000ULL) { - data |= 0xFF000000ULL; - } + data = static_cast(sign_extend<24>(data)); if (result != nullptr) *result = data; diff --git a/esphome/components/max31856/max31856.cpp b/esphome/components/max31856/max31856.cpp index bdb47216daa..b6bfb6127be 100644 --- a/esphome/components/max31856/max31856.cpp +++ b/esphome/components/max31856/max31856.cpp @@ -1,5 +1,6 @@ #include "max31856.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include @@ -53,12 +54,8 @@ void MAX31856Sensor::read_thermocouple_temperature_() { // Faults have been logged, clear it for next loop this->clear_fault_(); } else { - int32_t temp24 = this->read_register24_(MAX31856_LTCBH_REG); - if (temp24 & 0x800000) { - temp24 |= 0xFF000000; // fix sign - } - - temp24 >>= 5; // bottom 5 bits are unused + // bottom 5 bits are unused + const int32_t temp24 = sign_extend<24>(this->read_register24_(MAX31856_LTCBH_REG)) >> 5; float temp_c = temp24; temp_c *= 0.0078125; diff --git a/esphome/components/max9611/max9611.cpp b/esphome/components/max9611/max9611.cpp index 420eb7da7cb..486ceaee148 100644 --- a/esphome/components/max9611/max9611.cpp +++ b/esphome/components/max9611/max9611.cpp @@ -1,17 +1,10 @@ #include "max9611.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include "esphome/components/i2c/i2c_bus.h" namespace esphome::max9611 { using namespace esphome::i2c; -// Sign extend -// http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend -template inline T signextend(const T x) { - struct { - T x : B; - } s; - return s.x = x; -} // Map the gain register to in uV/LSB float gain_to_lsb(MAX9611Multiplexer gain) { float lsb = 0.0; @@ -72,7 +65,7 @@ void MAX9611Component::update() { uint16_t t_register = ((register_map_[TEMP_DATA_BYTE_MSB_ADRR] << 8) | (register_map_[TEMP_DATA_BYTE_LSB_ADRR])) >> 7; float voltage = rs_register * VOUT_LSB; float shunt_voltage = (csa_register * gain_to_lsb(gain_)) / MICRO_VOLTS_PER_VOLT; - float temp = signextend(t_register) * TEMP_LSB; + float temp = sign_extend<9>(t_register) * TEMP_LSB; float amps = shunt_voltage / current_resistor_; float watts = amps * voltage; diff --git a/esphome/components/xdb401/xdb401.cpp b/esphome/components/xdb401/xdb401.cpp index 5539a1318fd..11a1a569f3f 100644 --- a/esphome/components/xdb401/xdb401.cpp +++ b/esphome/components/xdb401/xdb401.cpp @@ -127,8 +127,7 @@ i2c::ErrorCode XDB401Component::read_pressure_(float &pressure) { format_hex_pretty_to(pressure_buf, sizeof(pressure_buf), p_data, 3); ESP_LOGV(TAG, "Got pressure data: %s", pressure_buf); - // Sign-extend 24-bit big-endian pressure value to int32_t. - int32_t raw_pressure = static_cast(encode_uint24(p_data[0], p_data[1], p_data[2]) << 8) >> 8; + int32_t raw_pressure = sign_extend<24>(encode_uint24(p_data[0], p_data[1], p_data[2])); ESP_LOGD(TAG, "Pressure data raw %" PRId32, raw_pressure); pressure = (static_cast(raw_pressure) / CONVERT_PRESSURE) * diff --git a/esphome/components/xgzp68xx/xgzp68xx.cpp b/esphome/components/xgzp68xx/xgzp68xx.cpp index 795db448f0b..b184a855f6f 100644 --- a/esphome/components/xgzp68xx/xgzp68xx.cpp +++ b/esphome/components/xgzp68xx/xgzp68xx.cpp @@ -76,9 +76,7 @@ void XGZP68XXComponent::update() { ESP_LOGV(TAG, "Got raw pressure=%" PRIu32 ", raw temperature=%u, K value=%u", pressure_raw, temperature_raw, this->k_value_); - // Sign extend the pressure - float pressure_in_pa = (float) (((int32_t) pressure_raw << 8) >> 8); - pressure_in_pa /= (float) (this->k_value_); + const float pressure_in_pa = static_cast(sign_extend<24>(pressure_raw)) / this->k_value_; float temperature = ((float) (int16_t) temperature_raw) / 256.0f;