fuel_gauge: Add fuel_guage_get_props()

The fuel_gauge_get_prop() function prototype declares a function that
retrieves multiple fuel gauge properties at once. The naming suggests it
ought to fetch a singular property at a time. Moreso, some clients may just
want to fetch properties one at a time and may feel uncomfortable using a
prototype for fetching multiple properties when wanting to fetch them one
at a time.

Modify fuel_gauge_get_prop() to fetch a single property and add
fuel_gauge_get_props() to support fetching multiple properties. Modify
existing tests/drivers/samples.

This is part of #61818 work.

Signed-off-by: Aaron Massey <aaronmassey@google.com>
This commit is contained in:
Aaron Massey 2023-09-19 11:40:10 -06:00 committed by Carles Cufí
parent 18eff4ea00
commit e294b16a2f
10 changed files with 105 additions and 93 deletions

View file

@ -20,8 +20,9 @@ Fundamentally, a property is a quantity that a fuel gauge device can measure.
Fuel gauges typically support multiple properties, such as temperature readings of the battery-pack Fuel gauges typically support multiple properties, such as temperature readings of the battery-pack
or present-time current/voltage. or present-time current/voltage.
Properties are fetched using a client allocated array of :c:struct:`fuel_gauge_property`. This Properties are fetched one at a time using a client allocated :c:struct:`fuel_gauge_property` or
array is then populated by values as according to its `property_type` field. fetched all at once using a client allocated array of :c:struct:`fuel_gauge_property`. Each
:c:struct:`fuel_gauge_property` is populated by values according to its `property_type` field.
Battery Cutoff Battery Cutoff
============== ==============

View file

@ -260,22 +260,6 @@ static int bq27z746_set_prop(const struct device *dev, struct fuel_gauge_propert
return rc; return rc;
} }
static int bq27z746_get_props(const struct device *dev, struct fuel_gauge_property *props,
size_t len)
{
int err_count = 0;
for (int i = 0; i < len; i++) {
int ret = bq27z746_get_prop(dev, props + i);
err_count += ret ? 1 : 0;
}
err_count = (err_count == len) ? -1 : err_count;
return err_count;
}
static int bq27z746_set_props(const struct device *dev, struct fuel_gauge_property *props, static int bq27z746_set_props(const struct device *dev, struct fuel_gauge_property *props,
size_t len) size_t len)
{ {
@ -307,7 +291,7 @@ static int bq27z746_init(const struct device *dev)
} }
static const struct fuel_gauge_driver_api bq27z746_driver_api = { static const struct fuel_gauge_driver_api bq27z746_driver_api = {
.get_property = &bq27z746_get_props, .get_property = &bq27z746_get_prop,
.set_property = &bq27z746_set_props, .set_property = &bq27z746_set_props,
.get_buffer_property = &bq27z746_get_buffer_prop, .get_buffer_property = &bq27z746_get_buffer_prop,
}; };

View file

@ -9,24 +9,40 @@
#include <zephyr/drivers/fuel_gauge.h> #include <zephyr/drivers/fuel_gauge.h>
static inline int z_vrfy_fuel_gauge_get_prop(const struct device *dev, static inline int z_vrfy_fuel_gauge_get_prop(const struct device *dev,
struct fuel_gauge_property *props, struct fuel_gauge_property *prop)
size_t props_len) {
struct fuel_gauge_property k_prop;
Z_OOPS(Z_SYSCALL_DRIVER_FUEL_GAUGE(dev, get_property));
Z_OOPS(z_user_from_copy(&k_prop, prop, sizeof(struct fuel_gauge_property)));
int ret = z_impl_fuel_gauge_get_prop(dev, &k_prop);
Z_OOPS(z_user_to_copy(prop, &k_prop, sizeof(struct fuel_gauge_property)));
return ret;
}
#include <syscalls/fuel_gauge_get_prop_mrsh.c>
static inline int z_vrfy_fuel_gauge_get_props(const struct device *dev,
struct fuel_gauge_property *props, size_t props_len)
{ {
struct fuel_gauge_property k_props[props_len]; struct fuel_gauge_property k_props[props_len];
Z_OOPS(Z_SYSCALL_DRIVER_FUEL_GAUGE(dev, get_property)); Z_OOPS(Z_SYSCALL_DRIVER_FUEL_GAUGE(dev, get_property));
Z_OOPS(z_user_from_copy(k_props, props, Z_OOPS(z_user_from_copy(k_props, props, props_len * sizeof(struct fuel_gauge_property)));
props_len * sizeof(struct fuel_gauge_property)));
int ret = z_impl_fuel_gauge_get_prop(dev, k_props, props_len); int ret = z_impl_fuel_gauge_get_props(dev, k_props, props_len);
Z_OOPS(z_user_to_copy(props, k_props, props_len * sizeof(struct fuel_gauge_property))); Z_OOPS(z_user_to_copy(props, k_props, props_len * sizeof(struct fuel_gauge_property)));
return ret; return ret;
} }
#include <syscalls/fuel_gauge_get_prop_mrsh.c> #include <syscalls/fuel_gauge_get_props_mrsh.c>
static inline int z_vrfy_fuel_gauge_set_prop(const struct device *dev, static inline int z_vrfy_fuel_gauge_set_prop(const struct device *dev,
struct fuel_gauge_property *props, struct fuel_gauge_property *props,

View file

@ -175,7 +175,7 @@ static int max17048_init(const struct device *dev)
/** /**
* Get a single property from the fuel gauge * Get a single property from the fuel gauge
*/ */
static int max17048_get_prop(const struct device *dev, struct fuel_gauge_property *prop) static int max17048_get_single_prop_impl(const struct device *dev, struct fuel_gauge_property *prop)
{ {
struct max17048_data *data = dev->data; struct max17048_data *data = dev->data;
int rc = 0; int rc = 0;
@ -203,15 +203,14 @@ static int max17048_get_prop(const struct device *dev, struct fuel_gauge_propert
} }
/** /**
* Get all possible properties from the fuel gague * Get properties from the fuel gauge
*/ */
static int max17048_get_props(const struct device *dev, struct fuel_gauge_property *props, static int max17048_get_prop(const struct device *dev, struct fuel_gauge_property *prop)
size_t len)
{ {
int err_count = 0;
struct max17048_data *data = dev->data; struct max17048_data *data = dev->data;
int rc = max17048_percent(dev, &data->charge); int rc = max17048_percent(dev, &data->charge);
int16_t crate; int16_t crate;
int ret;
if (rc < 0) { if (rc < 0) {
LOG_ERR("Error while reading battery percentage"); LOG_ERR("Error while reading battery percentage");
@ -242,7 +241,6 @@ static int max17048_get_props(const struct device *dev, struct fuel_gauge_proper
*/ */
data->charging = crate > 0; data->charging = crate > 0;
/** /**
* In the following code, we multiply by 1000 the charge to increase the * In the following code, we multiply by 1000 the charge to increase the
* precision. If we just truncate the division without this multiplier, * precision. If we just truncate the division without this multiplier,
@ -266,12 +264,6 @@ static int max17048_get_props(const struct device *dev, struct fuel_gauge_proper
data->time_to_empty = hours_pending * 60 / 1000; data->time_to_empty = hours_pending * 60 / 1000;
data->time_to_full = 0; data->time_to_full = 0;
} }
for (int i = 0; i < len; i++) {
int ret = max17048_get_prop(dev, props + i);
err_count += ret ? 1 : 0;
}
} else { } else {
/** /**
* This case is to avoid a division by 0 when the charge rate is the same * This case is to avoid a division by 0 when the charge rate is the same
@ -283,13 +275,13 @@ static int max17048_get_props(const struct device *dev, struct fuel_gauge_proper
data->time_to_empty = 0; data->time_to_empty = 0;
} }
err_count = (err_count == len) ? -1 : err_count; ret = max17048_get_single_prop_impl(dev, prop);
return err_count; return ret;
} }
static const struct fuel_gauge_driver_api max17048_driver_api = { static const struct fuel_gauge_driver_api max17048_driver_api = {
.get_property = &max17048_get_props, .get_property = &max17048_get_prop,
}; };
#define MAX17048_DEFINE(inst) \ #define MAX17048_DEFINE(inst) \

View file

@ -274,22 +274,6 @@ static int sbs_gauge_get_buffer_prop(const struct device *dev,
return rc; return rc;
} }
static int sbs_gauge_get_props(const struct device *dev, struct fuel_gauge_property *props,
size_t len)
{
int err_count = 0;
for (int i = 0; i < len; i++) {
int ret = sbs_gauge_get_prop(dev, props + i);
err_count += ret ? 1 : 0;
}
err_count = (err_count == len) ? -1 : err_count;
return err_count;
}
static int sbs_gauge_set_props(const struct device *dev, struct fuel_gauge_property *props, static int sbs_gauge_set_props(const struct device *dev, struct fuel_gauge_property *props,
size_t len) size_t len)
{ {
@ -326,7 +310,7 @@ static int sbs_gauge_init(const struct device *dev)
} }
static const struct fuel_gauge_driver_api sbs_gauge_driver_api = { static const struct fuel_gauge_driver_api sbs_gauge_driver_api = {
.get_property = &sbs_gauge_get_props, .get_property = &sbs_gauge_get_prop,
.set_property = &sbs_gauge_set_props, .set_property = &sbs_gauge_set_props,
.get_buffer_property = &sbs_gauge_get_buffer_prop, .get_buffer_property = &sbs_gauge_get_buffer_prop,
.battery_cutoff = &sbs_gauge_do_battery_cutoff, .battery_cutoff = &sbs_gauge_do_battery_cutoff,

View file

@ -222,7 +222,7 @@ struct sbs_gauge_device_chemistry {
* See fuel_gauge_get_property() for argument description * See fuel_gauge_get_property() for argument description
*/ */
typedef int (*fuel_gauge_get_property_t)(const struct device *dev, typedef int (*fuel_gauge_get_property_t)(const struct device *dev,
struct fuel_gauge_property *props, size_t props_len); struct fuel_gauge_property *prop);
/** /**
* @typedef fuel_gauge_set_property_t * @typedef fuel_gauge_set_property_t
@ -254,6 +254,12 @@ typedef int (*fuel_gauge_battery_cutoff_t)(const struct device *dev);
/* Caching is entirely on the onus of the client */ /* Caching is entirely on the onus of the client */
__subsystem struct fuel_gauge_driver_api { __subsystem struct fuel_gauge_driver_api {
/**
* Note: Historically this API allowed drivers to implement a custom multi-get/set property
* function, this was added so drivers could potentially optimize batch read with their
* specific chip. However, it was removed because of no existing concrete case upstream.
* If this need is demonstrated, we can add this back in as an API field.
*/
fuel_gauge_get_property_t get_property; fuel_gauge_get_property_t get_property;
fuel_gauge_set_property_t set_property; fuel_gauge_set_property_t set_property;
fuel_gauge_get_buffer_property_t get_buffer_property; fuel_gauge_get_buffer_property_t get_buffer_property;
@ -264,21 +270,17 @@ __subsystem struct fuel_gauge_driver_api {
* @brief Fetch a battery fuel-gauge property * @brief Fetch a battery fuel-gauge property
* *
* @param dev Pointer to the battery fuel-gauge device * @param dev Pointer to the battery fuel-gauge device
* @param props pointer to array of fuel_gauge_property struct where the property struct * @param prop pointer to a fuel_gauge_property struct where the property struct
* field is set by the caller to determine what property is read from the * field is set by the caller to determine what property is read from the
* fuel gauge device into the fuel_gauge_property struct's value field. The props array * fuel gauge device into the fuel_gauge_property struct's value field. The props array
* maintains the same order of properties as it was given. * maintains the same order of properties as it was given.
* @param props_len number of properties in props array
* *
* @return return=0 if successful, return < 0 if getting all properties failed, return > 0 if some * @return 0 if successful, negative errno code if failure.
* properties failed where return=number of failing properties.
*/ */
__syscall int fuel_gauge_get_prop(const struct device *dev, struct fuel_gauge_property *props, __syscall int fuel_gauge_get_prop(const struct device *dev, struct fuel_gauge_property *prop);
size_t props_len);
static inline int z_impl_fuel_gauge_get_prop(const struct device *dev, static inline int z_impl_fuel_gauge_get_prop(const struct device *dev,
struct fuel_gauge_property *props, struct fuel_gauge_property *prop)
size_t props_len)
{ {
const struct fuel_gauge_driver_api *api = (const struct fuel_gauge_driver_api *)dev->api; const struct fuel_gauge_driver_api *api = (const struct fuel_gauge_driver_api *)dev->api;
@ -286,7 +288,41 @@ static inline int z_impl_fuel_gauge_get_prop(const struct device *dev,
return -ENOSYS; return -ENOSYS;
} }
return api->get_property(dev, props, props_len); return api->get_property(dev, prop);
}
/**
* @brief Fetch multiple battery fuel-gauge properies. The default implementation is the same as
* calling fuel_gauge_get_prop() multiple times. A driver may implement the `get_properties` field
* of the fuel gauge driver APIs struct to override this implementation.
*
* @param dev Pointer to the battery fuel-gauge device
* @param props pointer to array of fuel_gauge_property struct where the property struct
* field is set by the caller to determine what property is read from the
* fuel gauge device into the fuel_gauge_property struct's value field. The props array
* maintains the same order of properties as it was given.
* @param len number of properties in props array
*
* @return return=0 if successful, return < 0 if getting all properties failed, return > 0 if some
* properties failed where return=number of failing properties.
*/
__syscall int fuel_gauge_get_props(const struct device *dev, struct fuel_gauge_property *props,
size_t len);
static inline int z_impl_fuel_gauge_get_props(const struct device *dev,
struct fuel_gauge_property *props, size_t len)
{
int err_count = 0;
const struct fuel_gauge_driver_api *api = dev->api;
for (int i = 0; i < len; i++) {
int ret = api->get_property(dev, props + i);
err_count += ret ? 1 : 0;
}
err_count = (err_count == len) ? -1 : err_count;
return err_count;
} }
/** /**

View file

@ -53,7 +53,7 @@ int main(void)
} }
}; };
ret = fuel_gauge_get_prop(dev, props, ARRAY_SIZE(props)); ret = fuel_gauge_get_props(dev, props, ARRAY_SIZE(props));
if (ret < 0) { if (ret < 0) {
printk("Error: cannot get properties\n"); printk("Error: cannot get properties\n");
} else { } else {

View file

@ -40,7 +40,7 @@ ZTEST_USER_F(bq27z746, test_get_all_props_failed_returns_negative)
}, },
}; };
int ret = fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props)); int ret = fuel_gauge_get_props(fixture->dev, props, ARRAY_SIZE(props));
zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.", zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.",
props[0].property_type); props[0].property_type);
@ -66,7 +66,7 @@ ZTEST_USER_F(bq27z746, test_get_some_props_failed_returns_failed_prop_count)
}; };
int ret = fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props)); int ret = fuel_gauge_get_props(fixture->dev, props, ARRAY_SIZE(props));
zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.", zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.",
props[0].property_type); props[0].property_type);
@ -191,7 +191,7 @@ ZTEST_USER_F(bq27z746, test_get_props__returns_ok)
}, },
}; };
int ret = fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props)); int ret = fuel_gauge_get_props(fixture->dev, props, ARRAY_SIZE(props));
/* All props shall have a good status */ /* All props shall have a good status */
for (int i = 0; i < ARRAY_SIZE(props); i++) { for (int i = 0; i < ARRAY_SIZE(props); i++) {

View file

@ -41,7 +41,7 @@ ZTEST_USER_F(max17048, test_get_all_props_failed_returns_negative)
}, },
}; };
int ret = fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props)); int ret = fuel_gauge_get_props(fixture->dev, props, ARRAY_SIZE(props));
zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.", zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.",
props[0].property_type); props[0].property_type);
@ -67,7 +67,7 @@ ZTEST_USER_F(max17048, test_get_some_props_failed_returns_failed_prop_count)
}; };
int ret = fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props)); int ret = fuel_gauge_get_props(fixture->dev, props, ARRAY_SIZE(props));
zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.", zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.",
props[0].property_type); props[0].property_type);
@ -101,7 +101,7 @@ ZTEST_USER_F(max17048, test_get_props__returns_ok)
} }
}; };
int ret = fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props)); int ret = fuel_gauge_get_props(fixture->dev, props, ARRAY_SIZE(props));
for (int i = 0; i < ARRAY_SIZE(props); i++) { for (int i = 0; i < ARRAY_SIZE(props); i++) {
zassert_ok(props[i].status, "Property %d getting %d has a bad status.", i, zassert_ok(props[i].status, "Property %d getting %d has a bad status.", i,
@ -128,7 +128,7 @@ ZTEST_USER_F(max17048, test_current_rate_zero)
* it will cause a division by zero * it will cause a division by zero
*/ */
emul_max17048_set_crate_status(0); emul_max17048_set_crate_status(0);
int ret = fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props)); int ret = fuel_gauge_get_props(fixture->dev, props, ARRAY_SIZE(props));
for (int i = 0; i < ARRAY_SIZE(props); i++) { for (int i = 0; i < ARRAY_SIZE(props); i++) {
zassert_ok(props[i].status, "Property %d getting %d has a bad status.", i, zassert_ok(props[i].status, "Property %d getting %d has a bad status.", i,

View file

@ -41,7 +41,7 @@ ZTEST_USER_F(sbs_gauge_new_api, test_get_all_props_failed_returns_negative)
}, },
}; };
int ret = fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props)); int ret = fuel_gauge_get_props(fixture->dev, props, ARRAY_SIZE(props));
zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.", zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.",
props[0].property_type); props[0].property_type);
@ -67,7 +67,7 @@ ZTEST_USER_F(sbs_gauge_new_api, test_get_some_props_failed_returns_failed_prop_c
}; };
int ret = fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props)); int ret = fuel_gauge_get_props(fixture->dev, props, ARRAY_SIZE(props));
zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.", zassert_equal(props[0].status, -ENOTSUP, "Getting bad property %d has a good status.",
props[0].property_type); props[0].property_type);
@ -184,7 +184,7 @@ ZTEST_USER_F(sbs_gauge_new_api, test_set_prop_can_be_get)
set_props[i].property_type); set_props[i].property_type);
} }
zassert_ok(fuel_gauge_get_prop(fixture->dev, get_props, ARRAY_SIZE(get_props))); zassert_ok(fuel_gauge_get_props(fixture->dev, get_props, ARRAY_SIZE(get_props)));
for (int i = 0; i < ARRAY_SIZE(get_props); i++) { for (int i = 0; i < ARRAY_SIZE(get_props); i++) {
zassert_ok(get_props[i].status, "Property %d getting %d has a bad status.", i, zassert_ok(get_props[i].status, "Property %d getting %d has a bad status.", i,
get_props[i].property_type); get_props[i].property_type);
@ -276,7 +276,7 @@ ZTEST_USER_F(sbs_gauge_new_api, test_get_props__returns_ok)
}, },
}; };
int ret = fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props)); int ret = fuel_gauge_get_props(fixture->dev, props, ARRAY_SIZE(props));
for (int i = 0; i < ARRAY_SIZE(props); i++) { for (int i = 0; i < ARRAY_SIZE(props); i++) {
zassert_ok(props[i].status, "Property %d getting %d has a bad status.", i, zassert_ok(props[i].status, "Property %d getting %d has a bad status.", i,
@ -350,26 +350,25 @@ ZTEST_USER_F(sbs_gauge_new_api, test_charging_5v_3a)
uint32_t expected_uV = 5000 * 1000; uint32_t expected_uV = 5000 * 1000;
uint32_t expected_uA = 3000 * 1000; uint32_t expected_uA = 3000 * 1000;
struct fuel_gauge_property props[] = { struct fuel_gauge_property voltage = {
{ .property_type = FUEL_GAUGE_VOLTAGE,
.property_type = FUEL_GAUGE_VOLTAGE, };
}, struct fuel_gauge_property current = {
{ .property_type = FUEL_GAUGE_CURRENT,
.property_type = FUEL_GAUGE_CURRENT,
},
}; };
zassume_ok(emul_fuel_gauge_set_battery_charging(fixture->sbs_fuel_gauge, expected_uV, zassume_ok(emul_fuel_gauge_set_battery_charging(fixture->sbs_fuel_gauge, expected_uV,
expected_uA)); expected_uA));
zassert_ok(fuel_gauge_get_prop(fixture->dev, props, ARRAY_SIZE(props))); zassert_ok(fuel_gauge_get_prop(fixture->dev, &voltage));
zassert_ok(fuel_gauge_get_prop(fixture->dev, &current));
zassert_ok(props[0].status); zassert_ok(voltage.status);
zassert_equal(props[0].value.voltage, expected_uV, "Got %d instead of %d", zassert_equal(voltage.value.voltage, expected_uV, "Got %d instead of %d",
props[0].value.voltage, expected_uV); voltage.value.voltage, expected_uV);
zassert_ok(props[1].status); zassert_ok(current.status);
zassert_equal(props[1].value.current, expected_uA, "Got %d instead of %d", zassert_equal(current.value.current, expected_uA, "Got %d instead of %d",
props[1].value.current, expected_uA); current.value.current, expected_uA);
} }
ZTEST_SUITE(sbs_gauge_new_api, NULL, sbs_gauge_new_api_setup, NULL, NULL, NULL); ZTEST_SUITE(sbs_gauge_new_api, NULL, sbs_gauge_new_api_setup, NULL, NULL, NULL);