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
or present-time current/voltage.
Properties are fetched using a client allocated array of :c:struct:`fuel_gauge_property`. This
array is then populated by values as according to its `property_type` field.
Properties are fetched one at a time using a client allocated :c:struct:`fuel_gauge_property` or
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
==============

View file

@ -260,22 +260,6 @@ static int bq27z746_set_prop(const struct device *dev, struct fuel_gauge_propert
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,
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 = {
.get_property = &bq27z746_get_props,
.get_property = &bq27z746_get_prop,
.set_property = &bq27z746_set_props,
.get_buffer_property = &bq27z746_get_buffer_prop,
};

View file

@ -9,24 +9,40 @@
#include <zephyr/drivers/fuel_gauge.h>
static inline int z_vrfy_fuel_gauge_get_prop(const struct device *dev,
struct fuel_gauge_property *props,
size_t props_len)
struct fuel_gauge_property *prop)
{
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];
Z_OOPS(Z_SYSCALL_DRIVER_FUEL_GAUGE(dev, get_property));
Z_OOPS(z_user_from_copy(k_props, props,
props_len * sizeof(struct fuel_gauge_property)));
Z_OOPS(z_user_from_copy(k_props, props, 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)));
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,
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
*/
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;
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,
size_t len)
static int max17048_get_prop(const struct device *dev, struct fuel_gauge_property *prop)
{
int err_count = 0;
struct max17048_data *data = dev->data;
int rc = max17048_percent(dev, &data->charge);
int16_t crate;
int ret;
if (rc < 0) {
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;
/**
* In the following code, we multiply by 1000 the charge to increase the
* 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_full = 0;
}
for (int i = 0; i < len; i++) {
int ret = max17048_get_prop(dev, props + i);
err_count += ret ? 1 : 0;
}
} else {
/**
* 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;
}
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 = {
.get_property = &max17048_get_props,
.get_property = &max17048_get_prop,
};
#define MAX17048_DEFINE(inst) \

View file

@ -274,22 +274,6 @@ static int sbs_gauge_get_buffer_prop(const struct device *dev,
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,
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 = {
.get_property = &sbs_gauge_get_props,
.get_property = &sbs_gauge_get_prop,
.set_property = &sbs_gauge_set_props,
.get_buffer_property = &sbs_gauge_get_buffer_prop,
.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
*/
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
@ -254,6 +254,12 @@ typedef int (*fuel_gauge_battery_cutoff_t)(const struct device *dev);
/* Caching is entirely on the onus of the client */
__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_set_property_t set_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
*
* @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
* 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 props_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.
* @return 0 if successful, negative errno code if failure.
*/
__syscall int fuel_gauge_get_prop(const struct device *dev, struct fuel_gauge_property *props,
size_t props_len);
__syscall int fuel_gauge_get_prop(const struct device *dev, struct fuel_gauge_property *prop);
static inline int z_impl_fuel_gauge_get_prop(const struct device *dev,
struct fuel_gauge_property *props,
size_t props_len)
struct fuel_gauge_property *prop)
{
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 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) {
printk("Error: cannot get properties\n");
} 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.",
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.",
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 */
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.",
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.",
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++) {
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
*/
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++) {
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.",
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.",
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);
}
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++) {
zassert_ok(get_props[i].status, "Property %d getting %d has a bad status.", i,
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++) {
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_uA = 3000 * 1000;
struct fuel_gauge_property props[] = {
{
.property_type = FUEL_GAUGE_VOLTAGE,
},
{
.property_type = FUEL_GAUGE_CURRENT,
},
struct fuel_gauge_property voltage = {
.property_type = FUEL_GAUGE_VOLTAGE,
};
struct fuel_gauge_property current = {
.property_type = FUEL_GAUGE_CURRENT,
};
zassume_ok(emul_fuel_gauge_set_battery_charging(fixture->sbs_fuel_gauge, expected_uV,
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_equal(props[0].value.voltage, expected_uV, "Got %d instead of %d",
props[0].value.voltage, expected_uV);
zassert_ok(voltage.status);
zassert_equal(voltage.value.voltage, expected_uV, "Got %d instead of %d",
voltage.value.voltage, expected_uV);
zassert_ok(props[1].status);
zassert_equal(props[1].value.current, expected_uA, "Got %d instead of %d",
props[1].value.current, expected_uA);
zassert_ok(current.status);
zassert_equal(current.value.current, expected_uA, "Got %d instead of %d",
current.value.current, expected_uA);
}
ZTEST_SUITE(sbs_gauge_new_api, NULL, sbs_gauge_new_api_setup, NULL, NULL, NULL);