From 8a8e090ff6927fb07ae5c6c689e7afdf2a7237c9 Mon Sep 17 00:00:00 2001 From: Joel Spadin Date: Wed, 3 Apr 2024 22:31:32 -0500 Subject: [PATCH] refactor(battery)!: Deduplicate battery code Changed the zmk,battery-voltage-divider and zmk,battery-nrf-vddh drivers to support only SENSOR_CHAN_VOLTAGE, and changed the default battery fetch mode to ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE. This allowed for removing the copy of lithium_ion_mv_to_pct() from the driver code, leaving only the version in battery.c. Custom boards/shields that use a fuel gauge driver instead of a voltage sensor, will need the following added to their Kconfig.defconfig: choice ZMK_BATTERY_REPORTING_FETCH_MODE default ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE endchoice Alternatively, add the following to the _defconfig file: ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE=y --- app/Kconfig | 12 +++- app/boards/arm/corneish_zen/Kconfig.defconfig | 4 ++ .../drivers/sensor/battery/battery_common.c | 20 +----- .../drivers/sensor/battery/battery_common.h | 3 - .../drivers/sensor/battery/battery_nrf_vddh.c | 7 +- .../sensor/battery/battery_voltage_divider.c | 6 +- app/src/battery.c | 71 +++++++++++-------- 7 files changed, 57 insertions(+), 66 deletions(-) diff --git a/app/Kconfig b/app/Kconfig index 8f2fe837..779bd340 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -388,11 +388,17 @@ if ZMK_BATTERY_REPORTING choice ZMK_BATTERY_REPORTING_FETCH_MODE prompt "Battery Reporting Fetch Mode" -config ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE - bool "State of charge" - config ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE bool "Lithium Voltage" + help + Estimate the battery level by reading the voltage of a Lithium battery. + zmk,battery chosen node should be a sensor driver that implements SENSOR_CHAN_VOLTAGE. + +config ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE + bool "State of charge" + help + Read the battery level from a fuel gauge sensor. + zmk,battery chosen node should be a sensor driver that implements SENSOR_CHAN_GAUGE_STATE_OF_CHARGE. endchoice endif diff --git a/app/boards/arm/corneish_zen/Kconfig.defconfig b/app/boards/arm/corneish_zen/Kconfig.defconfig index 11f932b5..afffa7db 100644 --- a/app/boards/arm/corneish_zen/Kconfig.defconfig +++ b/app/boards/arm/corneish_zen/Kconfig.defconfig @@ -85,4 +85,8 @@ if BOARD_CORNEISH_ZEN_V1_LEFT || BOARD_CORNEISH_ZEN_V1_RIGHT config BQ274XX default y +choice ZMK_BATTERY_REPORTING_FETCH_MODE + default ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE +endchoice + endif # BOARD_CORNEISH_ZEN_V1_LEFT || BOARD_CORNEISH_ZEN_V1_RIGHT diff --git a/app/module/drivers/sensor/battery/battery_common.c b/app/module/drivers/sensor/battery/battery_common.c index 9afe2d5b..571c1a12 100644 --- a/app/module/drivers/sensor/battery/battery_common.c +++ b/app/module/drivers/sensor/battery/battery_common.c @@ -12,32 +12,14 @@ int battery_channel_get(const struct battery_value *value, enum sensor_channel chan, struct sensor_value *val_out) { switch (chan) { - case SENSOR_CHAN_GAUGE_VOLTAGE: + case SENSOR_CHAN_VOLTAGE: val_out->val1 = value->millivolts / 1000; val_out->val2 = (value->millivolts % 1000) * 1000U; break; - case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: - val_out->val1 = value->state_of_charge; - val_out->val2 = 0; - break; - default: return -ENOTSUP; } return 0; } - -uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) { - // Simple linear approximation of a battery based off adafruit's discharge graph: - // https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages - - if (bat_mv >= 4200) { - return 100; - } else if (bat_mv <= 3450) { - return 0; - } - - return bat_mv * 2 / 15 - 459; -} \ No newline at end of file diff --git a/app/module/drivers/sensor/battery/battery_common.h b/app/module/drivers/sensor/battery/battery_common.h index 3e16ceed..f97c51d5 100644 --- a/app/module/drivers/sensor/battery/battery_common.h +++ b/app/module/drivers/sensor/battery/battery_common.h @@ -12,10 +12,7 @@ struct battery_value { uint16_t adc_raw; uint16_t millivolts; - uint8_t state_of_charge; }; int battery_channel_get(const struct battery_value *value, enum sensor_channel chan, struct sensor_value *val_out); - -uint8_t lithium_ion_mv_to_pct(int16_t bat_mv); diff --git a/app/module/drivers/sensor/battery/battery_nrf_vddh.c b/app/module/drivers/sensor/battery/battery_nrf_vddh.c index 32c7c61e..3c654254 100644 --- a/app/module/drivers/sensor/battery/battery_nrf_vddh.c +++ b/app/module/drivers/sensor/battery/battery_nrf_vddh.c @@ -31,8 +31,7 @@ struct vddh_data { static int vddh_sample_fetch(const struct device *dev, enum sensor_channel chan) { // Make sure selected channel is supported - if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE && - chan != SENSOR_CHAN_ALL) { + if (chan != SENSOR_CHAN_VOLTAGE && chan != SENSOR_CHAN_ALL) { LOG_DBG("Selected channel is not supported: %d.", chan); return -ENOTSUP; } @@ -56,10 +55,8 @@ static int vddh_sample_fetch(const struct device *dev, enum sensor_channel chan) } drv_data->value.millivolts = val * VDDHDIV; - drv_data->value.state_of_charge = lithium_ion_mv_to_pct(drv_data->value.millivolts); - LOG_DBG("ADC raw %d ~ %d mV => %d%%", drv_data->value.adc_raw, drv_data->value.millivolts, - drv_data->value.state_of_charge); + LOG_DBG("ADC raw %u ~ %u mV", drv_data->value.adc_raw, drv_data->value.millivolts); return rc; } diff --git a/app/module/drivers/sensor/battery/battery_voltage_divider.c b/app/module/drivers/sensor/battery/battery_voltage_divider.c index 62a02e9c..7fe4bdd3 100644 --- a/app/module/drivers/sensor/battery/battery_voltage_divider.c +++ b/app/module/drivers/sensor/battery/battery_voltage_divider.c @@ -41,8 +41,7 @@ static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan) struct adc_sequence *as = &drv_data->as; // Make sure selected channel is supported - if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE && - chan != SENSOR_CHAN_ALL) { + if (chan != SENSOR_CHAN_VOLTAGE && chan != SENSOR_CHAN_ALL) { LOG_DBG("Selected channel is not supported: %d.", chan); return -ENOTSUP; } @@ -74,11 +73,8 @@ static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan) uint16_t millivolts = val * (uint64_t)drv_cfg->full_ohm / drv_cfg->output_ohm; LOG_DBG("ADC raw %d ~ %d mV => %d mV", drv_data->value.adc_raw, val, millivolts); - uint8_t percent = lithium_ion_mv_to_pct(millivolts); - LOG_DBG("Percent: %d", percent); drv_data->value.millivolts = millivolts; - drv_data->value.state_of_charge = percent; } else { LOG_DBG("Failed to read ADC: %d", rc); } diff --git a/app/src/battery.c b/app/src/battery.c index ae79d5f7..4bc7ff20 100644 --- a/app/src/battery.c +++ b/app/src/battery.c @@ -35,7 +35,7 @@ static const struct device *battery; #endif #if IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE) -static uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) { +static uint8_t lithium_ion_mv_to_pct(int bat_mv) { // Simple linear approximation of a battery based off adafruit's discharge graph: // https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages @@ -48,51 +48,60 @@ static uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) { return bat_mv * 2 / 15 - 459; } -#endif // IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE) - -static int zmk_battery_update(const struct device *battery) { - struct sensor_value state_of_charge; - int rc; - -#if IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE) - - rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE); +static int get_state_of_charge(uint8_t *result) { + int rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_VOLTAGE); if (rc != 0) { - LOG_DBG("Failed to fetch battery values: %d", rc); - return rc; - } - - rc = sensor_channel_get(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE, &state_of_charge); - - if (rc != 0) { - LOG_DBG("Failed to get battery state of charge: %d", rc); - return rc; - } -#elif IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE) - rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_VOLTAGE); - if (rc != 0) { - LOG_DBG("Failed to fetch battery values: %d", rc); + LOG_DBG("Failed to fetch sensor value: %d", rc); return rc; } struct sensor_value voltage; rc = sensor_channel_get(battery, SENSOR_CHAN_VOLTAGE, &voltage); - if (rc != 0) { LOG_DBG("Failed to get battery voltage: %d", rc); return rc; } - uint16_t mv = voltage.val1 * 1000 + (voltage.val2 / 1000); - state_of_charge.val1 = lithium_ion_mv_to_pct(mv); + int millivolts = voltage.val1 * 1000 + (voltage.val2 / 1000); + *result = lithium_ion_mv_to_pct(millivolts); + + LOG_DBG("Battery voltage = %d mv -> %u%%", millivolts, *result); + return 0; +} + +#elif IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_STATE_OF_CHARGE) + +static int get_state_of_charge(uint8_t *result) { + struct sensor_value state_of_charge; + int rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE); + if (rc != 0) { + LOG_DBG("Failed to fetch sensor value: %d", rc); + return rc; + } + + rc = sensor_channel_get(battery, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE, &state_of_charge); + if (rc != 0) { + LOG_DBG("Failed to get battery state of charge: %d", rc); + return rc; + } + + *result = state_of_charge.val1; + return 0; +} - LOG_DBG("State of change %d from %d mv", state_of_charge.val1, mv); #else -#error "Not a supported reporting fetch mode" +#error "Unsupported reporting fetch mode" #endif - if (last_state_of_charge != state_of_charge.val1) { - last_state_of_charge = state_of_charge.val1; +static int zmk_battery_update(const struct device *battery) { + uint8_t new_state_of_charge = 0; + int rc = get_state_of_charge(&new_state_of_charge); + if (rc != 0) { + return rc; + } + + if (new_state_of_charge != last_state_of_charge) { + last_state_of_charge = new_state_of_charge; #if IS_ENABLED(CONFIG_BT_BAS) LOG_DBG("Setting BAS GATT battery level to %d.", last_state_of_charge);