emul: Add SBS Gauge emulator backend_api

In order to support easier setup of test scenarios with fuel gauge
emulators, we should expose an API that can change internal emulator state.

Add a minimal fuel gauge emulator backend API for setting the charging
current and voltage with a sample implementation in the emul_sbs_gauge with
an associated driver test.

Signed-off-by: Aaron Massey <aaronmassey@google.com>
This commit is contained in:
Aaron Massey 2023-05-26 14:25:59 -06:00 committed by Carles Cufí
commit e1401fcf5e
4 changed files with 138 additions and 3 deletions

View file

@ -35,3 +35,4 @@ API Reference
*************
.. doxygengroup:: fuel_gauge_interface
.. doxygengroup:: fuel_gauge_emulator_backend

View file

@ -21,6 +21,7 @@ LOG_MODULE_REGISTER(sbs_sbs_gauge);
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/i2c_emul.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/emul_fuel_gauge.h>
#include <zephyr/drivers/fuel_gauge.h>
#include "sbs_gauge.h"
@ -32,6 +33,13 @@ struct sbs_gauge_emul_data {
uint16_t remaining_time_alarm;
uint16_t mode;
int16_t at_rate;
struct {
/* Non-register values associated with the state of the battery */
/* Battery terminal voltage */
uint32_t uV;
/* Battery terminal current - Pos is charging, Neg is discharging */
int uA;
} batt_state;
};
/** Static configuration for the emulator */
@ -90,6 +98,11 @@ static int emul_sbs_gauge_reg_read(const struct emul *target, int reg, int *val)
*val = data->at_rate;
break;
case SBS_GAUGE_CMD_VOLTAGE:
*val = data->batt_state.uV / 1000;
break;
case SBS_GAUGE_CMD_CURRENT:
*val = data->batt_state.uA / 1000;
break;
case SBS_GAUGE_CMD_AVG_CURRENT:
case SBS_GAUGE_CMD_TEMP:
case SBS_GAUGE_CMD_ASOC:
@ -102,7 +115,6 @@ static int emul_sbs_gauge_reg_read(const struct emul *target, int reg, int *val)
case SBS_GAUGE_CMD_RUNTIME2EMPTY:
case SBS_GAUGE_CMD_CYCLE_COUNT:
case SBS_GAUGE_CMD_DESIGN_VOLTAGE:
case SBS_GAUGE_CMD_CURRENT:
case SBS_GAUGE_CMD_CHG_CURRENT:
case SBS_GAUGE_CMD_CHG_VOLTAGE:
case SBS_GAUGE_CMD_FLAGS:
@ -220,6 +232,23 @@ static int sbs_gauge_emul_transfer_i2c(const struct emul *target, struct i2c_msg
return rc;
}
static int emul_sbs_fuel_gauge_set_battery_charging(const struct emul *target, uint32_t uV, int uA)
{
struct sbs_gauge_emul_data *data = target->data;
if (uV == 0 || uA == 0)
return -EINVAL;
data->batt_state.uA = uA;
data->batt_state.uV = uV;
return 0;
}
static const struct fuel_gauge_emul_driver_api sbs_gauge_backend_api = {
.set_battery_charging = emul_sbs_fuel_gauge_set_battery_charging,
};
static const struct i2c_emul_api sbs_gauge_emul_api_i2c = {
.transfer = sbs_gauge_emul_transfer_i2c,
};
@ -243,11 +272,12 @@ static int emul_sbs_sbs_gauge_init(const struct emul *target, const struct devic
* Main instantiation macro. SBS Gauge Emulator only implemented for I2C
*/
#define SBS_GAUGE_EMUL(n) \
static struct sbs_gauge_emul_data sbs_gauge_emul_data_##n; \
static struct sbs_gauge_emul_data sbs_gauge_emul_data_##n; \
static const struct sbs_gauge_emul_cfg sbs_gauge_emul_cfg_##n = { \
.addr = DT_INST_REG_ADDR(n), \
}; \
EMUL_DT_INST_DEFINE(n, emul_sbs_sbs_gauge_init, &sbs_gauge_emul_data_##n, \
&sbs_gauge_emul_cfg_##n, &sbs_gauge_emul_api_i2c, NULL)
&sbs_gauge_emul_cfg_##n, &sbs_gauge_emul_api_i2c, \
&sbs_gauge_backend_api)
DT_INST_FOREACH_STATUS_OKAY(SBS_GAUGE_EMUL)

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2023 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Backend APIs for the fuel gauge emulators.
*/
#ifndef ZEPHYR_INCLUDE_DRIVERS_EMUL_FUEL_GAUGE_H_
#define ZEPHYR_INCLUDE_DRIVERS_EMUL_FUEL_GAUGE_H_
#include <stdint.h>
#include <zephyr/drivers/emul.h>
#include <zephyr/drivers/fuel_gauge.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Fuel gauge backend emulator APIs
* @defgroup fuel_gauge_emulator_backend fuel gauge backed emulator APIs
* @ingroup io_interfaces
* @{
*/
/**
* @cond INTERNAL_HIDDEN
*
* These are for internal use only, so skip these in public documentation.
*/
__subsystem struct fuel_gauge_emul_driver_api {
int (*set_battery_charging)(const struct emul *emul, uint32_t uV, int uA);
};
/**
* @endcond
*/
/**
* @brief Set charging for fuel gauge associated battery.
*
* Set how much the battery associated with a fuel gauge IC is charging or discharging. Where
* voltage is always positive and a positive or negative current denotes charging or discharging,
* respectively.
*
* @param target Pointer to the emulator structure for the fuel gauge emulator instance.
* @param uV Microvolts describing the battery voltage.
* @param uA Microamps describing the battery current where negative is discharging.
*
* @retval 0 If successful.
* @retval -EINVAL if mV or mA are 0.
*/
static inline int emul_fuel_gauge_set_battery_charging(const struct emul *target, uint32_t uV,
int uA)
{
const struct fuel_gauge_emul_driver_api *backend_api =
(const struct fuel_gauge_emul_driver_api *)target->backend_api;
return backend_api->set_battery_charging(target, uV, uA);
}
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* ZEPHYR_INCLUDE_DRIVERS_EMUL_FUEL_GAUGE_H_*/

View file

@ -6,6 +6,8 @@
*/
#include <zephyr/device.h>
#include <zephyr/drivers/emul.h>
#include <zephyr/drivers/emul_fuel_gauge.h>
#include <zephyr/drivers/fuel_gauge.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/logging/log.h>
@ -16,6 +18,7 @@
struct sbs_gauge_new_api_fixture {
const struct device *dev;
const struct emul *sbs_fuel_gauge;
const struct fuel_gauge_driver_api *api;
};
@ -24,6 +27,7 @@ static void *sbs_gauge_new_api_setup(void)
static ZTEST_DMEM struct sbs_gauge_new_api_fixture fixture;
fixture.dev = DEVICE_DT_GET_ANY(sbs_sbs_gauge_new_api);
fixture.sbs_fuel_gauge = EMUL_DT_GET(DT_NODELABEL(smartbattery0));
k_object_access_all_grant(fixture.dev);
@ -344,5 +348,32 @@ ZTEST_USER_F(sbs_gauge_new_api, test_get_buffer_props__returns_ok)
zassert_ok(ret);
}
ZTEST_F(sbs_gauge_new_api, test_charging_5v_3a)
{
/* Validate what props are supported by the driver */
uint32_t expected_uV = 5000 * 1000;
uint32_t expected_uA = 3000 * 1000;
struct fuel_gauge_get_property props[] = {
{
.property_type = FUEL_GAUGE_VOLTAGE,
},
{
.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(props[0].status);
zassert_equal(props[0].value.voltage, expected_uV, "Got %d instead of %d",
props[0].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);
}
ZTEST_SUITE(sbs_gauge_new_api, NULL, sbs_gauge_new_api_setup, NULL, NULL, NULL);