[components] Use sign_extend for raw sensor readings (#20934)

This commit is contained in:
J. Nick Koston
2026-10-16 15:24:45 -10:00
committed by GitHub
parent 1147b024d6
commit 107bebebad
8 changed files with 16 additions and 36 deletions
+1 -7
View File
@@ -11,12 +11,6 @@
namespace esphome::ade7880 {
// adapted from https://stackoverflow.com/a/55912127/1886371
template<size_t Bits, typename T> inline T sign_extend(const T &v) noexcept {
using S = struct { signed Val : Bits; };
return reinterpret_cast<const S *>(&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<uint8_t *>(&in), sizeof(in));
return sign_extend<24>(convert_big_endian(in));
}
@@ -3,6 +3,7 @@
#include "bme280_base.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include <esphome/components/sensor/sensor.h>
#include <esphome/core/component.h>
@@ -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<int16_t>(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<int16_t>(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;
+2 -1
View File
@@ -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;
}
+1 -3
View File
@@ -67,9 +67,7 @@ bool HX711Sensor::read_sensor_(uint32_t *result) {
this->status_clear_warning();
if (data & 0x800000ULL) {
data |= 0xFF000000ULL;
}
data = static_cast<uint32_t>(sign_extend<24>(data));
if (result != nullptr)
*result = data;
+3 -6
View File
@@ -1,5 +1,6 @@
#include "max31856.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include <cmath>
@@ -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;
+2 -9
View File
@@ -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<typename T, unsigned B> 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<signed int, 9>(t_register) * TEMP_LSB;
float temp = sign_extend<9>(t_register) * TEMP_LSB;
float amps = shunt_voltage / current_resistor_;
float watts = amps * voltage;
+1 -2
View File
@@ -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<int32_t>(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<float>(raw_pressure) / CONVERT_PRESSURE) *
+1 -3
View File
@@ -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<float>(sign_extend<24>(pressure_raw)) / this->k_value_;
float temperature = ((float) (int16_t) temperature_raw) / 256.0f;