mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-10-06 09:02:52 +08:00
fix(drivers/power_monitor): reject out-of-range INA226 cal and INA228 index (#28316)
CAL = 0.00512 / (current_lsb * R_shunt) is a 16-bit register. Legal INA226_CURRENT × INA226_SHUNT combos overflow it, and the float-to-uint16 conversion is undefined. Fail start with the offending params rather than program a wrapped value. ina228 -t outside 1-3 was accepted; Battery() silently clamps to index 1. Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
This commit is contained in:
@@ -53,12 +53,28 @@ INA226::INA226(const I2CSPIDriverConfig &config, int battery_index)
|
||||
const float shunt_resistance = _param_ina226_shunt.get();
|
||||
|
||||
_current_lsb = max_current / 32768.f; // From datasheet: current_lsb = max_current / 2^15
|
||||
_calibration = static_cast<uint16_t>(CAL_K / (_current_lsb * shunt_resistance));
|
||||
|
||||
// CAL is a 16-bit register. Legal INA226_CURRENT × INA226_SHUNT combos can
|
||||
// overflow it; converting that float to uint16_t is undefined.
|
||||
const float denom = _current_lsb * shunt_resistance;
|
||||
const float cal = (denom > 0.f) ? (CAL_K / denom) : 0.f;
|
||||
|
||||
if ((cal < 1.f) || (cal > 65535.f)) {
|
||||
PX4_ERR("INA226 calibration %.1f out of uint16 range (INA226_CURRENT=%.4f INA226_SHUNT=%.9f)",
|
||||
(double)cal, (double)max_current, (double)shunt_resistance);
|
||||
_current_lsb = 0.f;
|
||||
_calibration = 0;
|
||||
|
||||
} else {
|
||||
_calibration = static_cast<uint16_t>(cal);
|
||||
}
|
||||
|
||||
_config_value = MODE_SHUNT_BUS_CONT | VSHCT_588US | VBUSCT_588US | AVERAGES_64;
|
||||
|
||||
// Publish an initial disconnected status so the first instance grabs uORB instance 0 immediately.
|
||||
_battery.updateAndPublishBatteryStatus(hrt_absolute_time());
|
||||
if (_calibration != 0) {
|
||||
// Publish an initial disconnected status so the first instance grabs uORB instance 0 immediately.
|
||||
_battery.updateAndPublishBatteryStatus(hrt_absolute_time());
|
||||
}
|
||||
|
||||
// Let the lower I2C layer absorb transient bus errors before we see them.
|
||||
I2C::_retries = 5;
|
||||
@@ -75,6 +91,10 @@ INA226::~INA226()
|
||||
|
||||
int INA226::init()
|
||||
{
|
||||
if (_calibration == 0) {
|
||||
return PX4_ERROR;
|
||||
}
|
||||
|
||||
if (I2C::init() != PX4_OK) {
|
||||
return PX4_ERROR;
|
||||
}
|
||||
@@ -313,6 +333,11 @@ I2CSPIDriverBase *INA226::instantiate(const I2CSPIDriverConfig &config, int /*ru
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (instance->_calibration == 0) {
|
||||
delete instance;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (instance->init() == PX4_OK) {
|
||||
instance->ScheduleNow();
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ this flag set, the battery must be plugged in before starting the driver.
|
||||
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(true, false);
|
||||
PRINT_MODULE_USAGE_PARAMS_I2C_ADDRESS(0x45);
|
||||
PRINT_MODULE_USAGE_PARAMS_I2C_KEEP_RUNNING_FLAG();
|
||||
PRINT_MODULE_USAGE_PARAM_INT('t', 1, 1, 3, "battery index for calibration values (1 or 3)", true);
|
||||
PRINT_MODULE_USAGE_PARAM_INT('t', 1, 1, 3, "battery index for calibration values (1-3)", true);
|
||||
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
|
||||
}
|
||||
|
||||
@@ -101,6 +101,12 @@ ina228_main(int argc, char *argv[])
|
||||
switch (ch) {
|
||||
case 't': // battery index
|
||||
cli.custom1 = (int)strtol(cli.optArg(), NULL, 0);
|
||||
|
||||
if (cli.custom1 < 1 || cli.custom1 > 3) {
|
||||
PX4_ERR("index must be 1-3");
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user