From c01b4d8106e0ff6ecc0b1ac77b906ab537df684c Mon Sep 17 00:00:00 2001 From: Aaron Massey Date: Tue, 10 May 2022 12:17:34 -0600 Subject: [PATCH] emul: Add sbs_gauge emulator Add an initial bare-bones functionality sbs_gauge emulator that only supports register reads tested by the current sbs_gauge driver tests and what the sbs_driver currently supports. Signed-off-by: Aaron Massey --- subsys/emul/Kconfig | 6 ++ subsys/emul/i2c/CMakeLists.txt | 3 + subsys/emul/i2c/emul_sbs_gauge.c | 157 +++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 subsys/emul/i2c/emul_sbs_gauge.c diff --git a/subsys/emul/Kconfig b/subsys/emul/Kconfig index 6958dca7a4..15bacf32e7 100644 --- a/subsys/emul/Kconfig +++ b/subsys/emul/Kconfig @@ -45,6 +45,12 @@ config EMUL_BMI160 It supports both I2C and SPI which is why it is not in one of the i2c/ or spi/ directories. +config EMUL_SBS_GAUGE + bool "Emulate an SBS 1.1 compliant smart battery fuel gauge" + help + It provides readings which follow a simple sequence, thus allowing + test code to check that things are working as expected. + source "subsys/emul/i2c/Kconfig" source "subsys/emul/espi/Kconfig" diff --git a/subsys/emul/i2c/CMakeLists.txt b/subsys/emul/i2c/CMakeLists.txt index 37e882964f..2786919eb0 100644 --- a/subsys/emul/i2c/CMakeLists.txt +++ b/subsys/emul/i2c/CMakeLists.txt @@ -3,3 +3,6 @@ # Once we have more than 10 devices we should consider splitting them into # subdirectories to match the drivers/ structure. zephyr_library_sources_ifdef(CONFIG_EMUL_EEPROM_AT2X emul_atmel_at24.c) + +zephyr_include_directories_ifdef(CONFIG_EMUL_SBS_GAUGE ${ZEPHYR_BASE}/drivers/sensor/sbs_gauge) +zephyr_library_sources_ifdef(CONFIG_EMUL_SBS_GAUGE emul_sbs_gauge.c) diff --git a/subsys/emul/i2c/emul_sbs_gauge.c b/subsys/emul/i2c/emul_sbs_gauge.c new file mode 100644 index 0000000000..ab00ced4e1 --- /dev/null +++ b/subsys/emul/i2c/emul_sbs_gauge.c @@ -0,0 +1,157 @@ +/* + * Copyright 2022 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + * + * Emulator for SBS 1.1 compliant smart battery fuel gauge. + */ + +#define DT_DRV_COMPAT sbs_sbs_gauge + +#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL +#include +LOG_MODULE_REGISTER(sbs_sbs_gauge); + +#include +#include +#include +#include +#include + +#include + +/** Run-time data used by the emulator */ +struct sbs_gauge_emul_data { + /* Stub */ +}; + +/** Static configuration for the emulator */ +struct sbs_gauge_emul_cfg { + /** I2C address of emulator */ + uint16_t addr; +}; + +static void reg_write(const struct emul *target, int reg, int val) +{ + ARG_UNUSED(target); + + LOG_INF("write %x = %x", reg, val); + switch (reg) { + default: + LOG_INF("Unknown write %x", reg); + } +} + +static int reg_read(const struct emul *target, int reg) +{ + int val; + + ARG_UNUSED(target); + + switch (reg) { + case SBS_GAUGE_CMD_VOLTAGE: + case SBS_GAUGE_CMD_AVG_CURRENT: + case SBS_GAUGE_CMD_TEMP: + case SBS_GAUGE_CMD_ASOC: + case SBS_GAUGE_CMD_FULL_CAPACITY: + case SBS_GAUGE_CMD_REM_CAPACITY: + case SBS_GAUGE_CMD_NOM_CAPACITY: + case SBS_GAUGE_CMD_AVG_TIME2EMPTY: + case SBS_GAUGE_CMD_AVG_TIME2FULL: + case SBS_GAUGE_CMD_CYCLE_COUNT: + case SBS_GAUGE_CMD_DESIGN_VOLTAGE: + /* Arbitrary stub value. */ + val = 1; + break; + default: + LOG_ERR("Unknown register 0x%x read", reg); + return -EIO; + } + LOG_INF("read 0x%x = 0x%x", reg, val); + + return val; +} + +static int sbs_gauge_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs, + int num_msgs, int addr) +{ + /* Largely copied from emul_bmi160.c */ + struct sbs_gauge_emul_data *data; + unsigned int val; + int reg; + + data = target->data; + + __ASSERT_NO_MSG(msgs && num_msgs); + + i2c_dump_msgs("emul", msgs, num_msgs, addr); + switch (num_msgs) { + case 2: + if (msgs->flags & I2C_MSG_READ) { + LOG_ERR("Unexpected read"); + return -EIO; + } + if (msgs->len != 1) { + LOG_ERR("Unexpected msg0 length %d", msgs->len); + return -EIO; + } + reg = msgs->buf[0]; + + /* Now process the 'read' part of the message */ + msgs++; + if (msgs->flags & I2C_MSG_READ) { + switch (msgs->len - 1) { + case 1: + val = reg_read(target, reg); + msgs->buf[0] = val; + break; + default: + LOG_ERR("Unexpected msg1 length %d", msgs->len); + return -EIO; + } + } else { + if (msgs->len != 1) { + LOG_ERR("Unexpected msg1 length %d", msgs->len); + } + reg_write(target, reg, msgs->buf[0]); + } + break; + default: + LOG_ERR("Invalid number of messages: %d", num_msgs); + return -EIO; + } + + return 0; +} + +static const struct i2c_emul_api sbs_gauge_emul_api_i2c = { + .transfer = sbs_gauge_emul_transfer_i2c, +}; + +/** + * Set up a new SBS_GAUGE emulator (I2C) + * + * @param emul Emulation information + * @param parent Device to emulate (must use sbs_gauge driver) + * @return 0 indicating success (always) + */ +static int emul_sbs_sbs_gauge_init(const struct emul *target, const struct device *parent) +{ + ARG_UNUSED(target); + ARG_UNUSED(parent); + + return 0; +} + +/* + * 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 const struct sbs_gauge_emul_cfg sbs_gauge_emul_cfg_##n = { \ + .addr = DT_INST_REG_ADDR(n), \ + }; \ + EMUL_DEFINE(emul_sbs_sbs_gauge_init, DT_DRV_INST(n), &sbs_gauge_emul_cfg_##n, \ + &sbs_gauge_emul_data_##n, &sbs_gauge_emul_api_i2c) + +DT_INST_FOREACH_STATUS_OKAY(SBS_GAUGE_EMUL)