Skip to content

Commit 4d854a5

Browse files
maxpowelnashif
authored andcommitted
drivers: fixed div by zero when reading max17048
Avoid divsion by zero when current rate is zero Signed-off-by: Alvaro Garcia <[email protected]>
1 parent d5792ab commit 4d854a5

File tree

3 files changed

+92
-35
lines changed

3 files changed

+92
-35
lines changed

drivers/fuel_gauge/max17048/emul_max17048.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ LOG_MODULE_REGISTER(maxim_max17048);
2121

2222
#include "max17048.h"
2323

24+
static int crate_value = 0x4000;
25+
26+
void emul_max17048_set_crate_status(int value)
27+
{
28+
crate_value = value;
29+
}
30+
2431
/** Static configuration for the emulator */
2532
struct max17048_emul_cfg {
2633
/** I2C address of emulator */
@@ -41,7 +48,7 @@ static int emul_max17048_reg_read(const struct emul *target, int reg, int *val)
4148
*val = 0x1000;
4249
break;
4350
case REGISTER_CRATE:
44-
*val = 0x4000;
51+
*val = crate_value;
4552
break;
4653
case REGISTER_SOC:
4754
*val = 0x3525;

drivers/fuel_gauge/max17048/max17048.c

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -234,41 +234,53 @@ static int max17048_get_props(const struct device *dev, struct fuel_gauge_get_pr
234234
return rc;
235235
}
236236

237-
/**
238-
* May take some time until the chip detects the change between discharging to charging
239-
* (and vice versa) especially if your device consumes little power
240-
*/
241-
data->charging = crate > 0;
242-
243-
244-
/**
245-
* In the following code, we multiply by 1000 the charge to increase the precision. If we
246-
* just truncate the division without this multiplier, the precision lost is very
247-
* significant when converting it into minutes (the value given is in hours)
248-
*
249-
* The value coming from crate is already 1000 times higher (check the function
250-
* max17048_crate to
251-
* see the reason) so the multiplier for the charge
252-
* will be 1000000
253-
*/
254-
if (data->charging) {
255-
uint8_t percentage_pending = 100 - data->charge;
256-
uint32_t hours_pending = percentage_pending * 1000000 / crate;
257-
258-
data->time_to_empty = 0;
259-
data->time_to_full = hours_pending * 60 / 1000;
237+
if (crate != 0) {
238+
239+
/**
240+
* May take some time until the chip detects the change between discharging to
241+
* charging (and vice versa) especially if your device consumes little power
242+
*/
243+
data->charging = crate > 0;
244+
245+
246+
/**
247+
* In the following code, we multiply by 1000 the charge to increase the
248+
* precision. If we just truncate the division without this multiplier,
249+
* the precision lost is very significant when converting it into minutes
250+
* (the value given is in hours)
251+
*
252+
* The value coming from crate is already 1000 times higher (check the
253+
* function max17048_crate to see the reason) so the multiplier for the
254+
* charge will be 1000000
255+
*/
256+
if (data->charging) {
257+
uint8_t percentage_pending = 100 - data->charge;
258+
uint32_t hours_pending = percentage_pending * 1000000 / crate;
259+
260+
data->time_to_empty = 0;
261+
data->time_to_full = hours_pending * 60 / 1000;
262+
} else {
263+
/* Discharging */
264+
uint32_t hours_pending = data->charge * 1000000 / -crate;
265+
266+
data->time_to_empty = hours_pending * 60 / 1000;
267+
data->time_to_full = 0;
268+
}
269+
270+
for (int i = 0; i < len; i++) {
271+
int ret = max17048_get_prop(dev, props + i);
272+
273+
err_count += ret ? 1 : 0;
274+
}
260275
} else {
261-
/* Discharging */
262-
uint32_t hours_pending = data->charge * 1000000 / -crate;
263-
264-
data->time_to_empty = hours_pending * 60 / 1000;
276+
/**
277+
* This case is to avoid a division by 0 when the charge rate is the same
278+
* than consumption rate. It could also happen when the sensor is still
279+
* calibrating the battery
280+
*/
281+
data->charging = false;
265282
data->time_to_full = 0;
266-
}
267-
268-
for (int i = 0; i < len; i++) {
269-
int ret = max17048_get_prop(dev, props + i);
270-
271-
err_count += ret ? 1 : 0;
283+
data->time_to_empty = 0;
272284
}
273285

274286
err_count = (err_count == len) ? -1 : err_count;

tests/drivers/fuel_gauge/max17048/src/test_max17048.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ struct max17048_fixture {
1818
const struct fuel_gauge_driver_api *api;
1919
};
2020

21+
void emul_max17048_set_crate_status(int value);
22+
2123
static void *max17048_setup(void)
2224
{
2325
static ZTEST_DMEM struct max17048_fixture fixture;
2426

2527
fixture.dev = DEVICE_DT_GET_ANY(maxim_max17048);
26-
2728
k_object_access_all_grant(fixture.dev);
2829

2930
zassert_true(device_is_ready(fixture.dev), "Fuel Gauge not found");
@@ -110,5 +111,42 @@ ZTEST_USER_F(max17048, test_get_props__returns_ok)
110111
zassert_ok(ret);
111112
}
112113

114+
ZTEST_USER_F(max17048, test_current_rate_zero)
115+
{
116+
/* Test when crate is 0, which is a special case */
117+
118+
struct fuel_gauge_get_property props[] = {
119+
{
120+
.property_type = FUEL_GAUGE_RUNTIME_TO_EMPTY,
121+
},
122+
{
123+
.property_type = FUEL_GAUGE_RUNTIME_TO_FULL,
124+
}
125+
};
126+
127+
/** Null value, not charging either discharging. If not handled correctly,
128+
* it will cause a division by zero
129+
*/
130+
emul_max17048_set_crate_status(0);
131+
int ret = fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props));
132+
133+
for (int i = 0; i < ARRAY_SIZE(props); i++) {
134+
zassert_ok(props[i].status, "Property %d getting %d has a bad status.", i,
135+
props[i].property_type);
136+
}
137+
zassert_equal(props[0].value.runtime_to_empty, 0,
138+
"Runtime to empty is %d but it should be 0.",
139+
props[0].value.runtime_to_full
140+
);
141+
zassert_equal(props[1].value.runtime_to_full, 0,
142+
"Runtime to full is %d but it should be 0.",
143+
props[1].value.runtime_to_full
144+
);
145+
146+
zassert_ok(ret);
147+
/* Return value to the original state */
148+
emul_max17048_set_crate_status(0x4000);
149+
}
150+
113151

114152
ZTEST_SUITE(max17048, NULL, max17048_setup, NULL, NULL, NULL);

0 commit comments

Comments
 (0)