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
This commit is contained in:
parent
7d5aa0c0bf
commit
8a8e090ff6
7 changed files with 57 additions and 66 deletions
12
app/Kconfig
12
app/Kconfig
|
@ -388,11 +388,17 @@ if ZMK_BATTERY_REPORTING
|
||||||
choice ZMK_BATTERY_REPORTING_FETCH_MODE
|
choice ZMK_BATTERY_REPORTING_FETCH_MODE
|
||||||
prompt "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
|
config ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE
|
||||||
bool "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
|
endchoice
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -85,4 +85,8 @@ if BOARD_CORNEISH_ZEN_V1_LEFT || BOARD_CORNEISH_ZEN_V1_RIGHT
|
||||||
config BQ274XX
|
config BQ274XX
|
||||||
default y
|
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
|
endif # BOARD_CORNEISH_ZEN_V1_LEFT || BOARD_CORNEISH_ZEN_V1_RIGHT
|
||||||
|
|
|
@ -12,32 +12,14 @@
|
||||||
int battery_channel_get(const struct battery_value *value, enum sensor_channel chan,
|
int battery_channel_get(const struct battery_value *value, enum sensor_channel chan,
|
||||||
struct sensor_value *val_out) {
|
struct sensor_value *val_out) {
|
||||||
switch (chan) {
|
switch (chan) {
|
||||||
case SENSOR_CHAN_GAUGE_VOLTAGE:
|
case SENSOR_CHAN_VOLTAGE:
|
||||||
val_out->val1 = value->millivolts / 1000;
|
val_out->val1 = value->millivolts / 1000;
|
||||||
val_out->val2 = (value->millivolts % 1000) * 1000U;
|
val_out->val2 = (value->millivolts % 1000) * 1000U;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE:
|
|
||||||
val_out->val1 = value->state_of_charge;
|
|
||||||
val_out->val2 = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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;
|
|
||||||
}
|
|
|
@ -12,10 +12,7 @@
|
||||||
struct battery_value {
|
struct battery_value {
|
||||||
uint16_t adc_raw;
|
uint16_t adc_raw;
|
||||||
uint16_t millivolts;
|
uint16_t millivolts;
|
||||||
uint8_t state_of_charge;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int battery_channel_get(const struct battery_value *value, enum sensor_channel chan,
|
int battery_channel_get(const struct battery_value *value, enum sensor_channel chan,
|
||||||
struct sensor_value *val_out);
|
struct sensor_value *val_out);
|
||||||
|
|
||||||
uint8_t lithium_ion_mv_to_pct(int16_t bat_mv);
|
|
||||||
|
|
|
@ -31,8 +31,7 @@ struct vddh_data {
|
||||||
|
|
||||||
static int vddh_sample_fetch(const struct device *dev, enum sensor_channel chan) {
|
static int vddh_sample_fetch(const struct device *dev, enum sensor_channel chan) {
|
||||||
// Make sure selected channel is supported
|
// Make sure selected channel is supported
|
||||||
if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE &&
|
if (chan != SENSOR_CHAN_VOLTAGE && chan != SENSOR_CHAN_ALL) {
|
||||||
chan != SENSOR_CHAN_ALL) {
|
|
||||||
LOG_DBG("Selected channel is not supported: %d.", chan);
|
LOG_DBG("Selected channel is not supported: %d.", chan);
|
||||||
return -ENOTSUP;
|
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.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,
|
LOG_DBG("ADC raw %u ~ %u mV", drv_data->value.adc_raw, drv_data->value.millivolts);
|
||||||
drv_data->value.state_of_charge);
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,7 @@ static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan)
|
||||||
struct adc_sequence *as = &drv_data->as;
|
struct adc_sequence *as = &drv_data->as;
|
||||||
|
|
||||||
// Make sure selected channel is supported
|
// Make sure selected channel is supported
|
||||||
if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE &&
|
if (chan != SENSOR_CHAN_VOLTAGE && chan != SENSOR_CHAN_ALL) {
|
||||||
chan != SENSOR_CHAN_ALL) {
|
|
||||||
LOG_DBG("Selected channel is not supported: %d.", chan);
|
LOG_DBG("Selected channel is not supported: %d.", chan);
|
||||||
return -ENOTSUP;
|
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;
|
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);
|
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.millivolts = millivolts;
|
||||||
drv_data->value.state_of_charge = percent;
|
|
||||||
} else {
|
} else {
|
||||||
LOG_DBG("Failed to read ADC: %d", rc);
|
LOG_DBG("Failed to read ADC: %d", rc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ static const struct device *battery;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE)
|
#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:
|
// Simple linear approximation of a battery based off adafruit's discharge graph:
|
||||||
// https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages
|
// 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;
|
return bat_mv * 2 / 15 - 459;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING_FETCH_MODE_LITHIUM_VOLTAGE)
|
static int get_state_of_charge(uint8_t *result) {
|
||||||
|
int rc = sensor_sample_fetch_chan(battery, SENSOR_CHAN_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);
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
LOG_DBG("Failed to fetch battery values: %d", rc);
|
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;
|
|
||||||
}
|
|
||||||
#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);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sensor_value voltage;
|
struct sensor_value voltage;
|
||||||
rc = sensor_channel_get(battery, SENSOR_CHAN_VOLTAGE, &voltage);
|
rc = sensor_channel_get(battery, SENSOR_CHAN_VOLTAGE, &voltage);
|
||||||
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
LOG_DBG("Failed to get battery voltage: %d", rc);
|
LOG_DBG("Failed to get battery voltage: %d", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t mv = voltage.val1 * 1000 + (voltage.val2 / 1000);
|
int millivolts = voltage.val1 * 1000 + (voltage.val2 / 1000);
|
||||||
state_of_charge.val1 = lithium_ion_mv_to_pct(mv);
|
*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
|
#else
|
||||||
#error "Not a supported reporting fetch mode"
|
#error "Unsupported reporting fetch mode"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (last_state_of_charge != state_of_charge.val1) {
|
static int zmk_battery_update(const struct device *battery) {
|
||||||
last_state_of_charge = state_of_charge.val1;
|
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)
|
#if IS_ENABLED(CONFIG_BT_BAS)
|
||||||
LOG_DBG("Setting BAS GATT battery level to %d.", last_state_of_charge);
|
LOG_DBG("Setting BAS GATT battery level to %d.", last_state_of_charge);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue