fix(battery): detect TP4056 charging and full states on new board
This commit is contained in:
@@ -52,6 +52,8 @@ typedef enum {
|
||||
DOMAIN_BATTERY_CHARGE_UNKNOWN = 0,
|
||||
DOMAIN_BATTERY_CHARGE_NOT_CHARGING,
|
||||
DOMAIN_BATTERY_CHARGE_CHARGING,
|
||||
DOMAIN_BATTERY_CHARGE_FULL,
|
||||
DOMAIN_BATTERY_CHARGE_FAULT,
|
||||
} domain_battery_charge_state_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -67,6 +69,9 @@ typedef struct {
|
||||
int latest_sample_mv;
|
||||
uint8_t percentage;
|
||||
domain_battery_charge_state_t charge_state;
|
||||
bool charge_inputs_valid;
|
||||
bool charge_signal_active;
|
||||
bool full_signal_active;
|
||||
domain_battery_level_state_t level_state;
|
||||
bool valid;
|
||||
bool latest_sample_valid;
|
||||
@@ -83,6 +88,11 @@ esp_err_t domain_battery_init(void);
|
||||
/** 获取并处理一次电池采样,不执行产品策略。 / Process one battery sample without product policy. */
|
||||
esp_err_t domain_battery_sample(void);
|
||||
|
||||
/** 每100ms调用;两路输入连续采样稳定1秒后更新充电状态,间隔>250ms重新确认。
|
||||
* 不访问ADC;两把锁各最多等待100ms,失败不会后台继续。并发调用安全。
|
||||
*/
|
||||
esp_err_t domain_battery_poll_charge(void);
|
||||
|
||||
/** 复制最新电池 SSOT 快照。 / Copy the latest battery SSOT snapshot into `out_status`. */
|
||||
esp_err_t domain_battery_get_status(domain_battery_status_t *out_status);
|
||||
|
||||
|
||||
@@ -100,17 +100,66 @@ static void unlock_state(void)
|
||||
(void)xSemaphoreGive(s_lock);
|
||||
}
|
||||
|
||||
static domain_battery_charge_state_t map_charge_state(
|
||||
platform_battery_charge_state_t state)
|
||||
/* 只有领域层解释 TP4056 CHRG#/STDBY#。两个低电平同时出现视为异常,
|
||||
* 两个高电平只表示未充电,不能证明 USB 是否接入或电池是否存在。 */
|
||||
static domain_battery_charge_state_t s_charge_candidate;
|
||||
static int64_t s_charge_candidate_since_ms;
|
||||
static int64_t s_charge_last_poll_ms;
|
||||
static bool s_charge_candidate_valid;
|
||||
static int64_t s_charge_last_confirmed_ms;
|
||||
|
||||
static domain_battery_charge_state_t decode_charge_inputs(bool charging, bool full)
|
||||
{
|
||||
switch (state) {
|
||||
case PLATFORM_BATTERY_CHARGE_CHARGING:
|
||||
return DOMAIN_BATTERY_CHARGE_CHARGING;
|
||||
case PLATFORM_BATTERY_CHARGE_NOT_CHARGING:
|
||||
return DOMAIN_BATTERY_CHARGE_NOT_CHARGING;
|
||||
default:
|
||||
return DOMAIN_BATTERY_CHARGE_UNKNOWN;
|
||||
if (charging && full) {
|
||||
return DOMAIN_BATTERY_CHARGE_FAULT;
|
||||
}
|
||||
if (charging) {
|
||||
return DOMAIN_BATTERY_CHARGE_CHARGING;
|
||||
}
|
||||
return full ? DOMAIN_BATTERY_CHARGE_FULL : DOMAIN_BATTERY_CHARGE_NOT_CHARGING;
|
||||
}
|
||||
|
||||
esp_err_t domain_battery_poll_charge(void)
|
||||
{
|
||||
/* 在领域锁内读取原始输入,保证并发采样不会倒序发布状态。
|
||||
* 数字输入独立于ADC:ADC失败或电机负载抑制不影响充电状态更新。 */
|
||||
if (!lock_state()) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
platform_battery_charge_inputs_t inputs = {0};
|
||||
esp_err_t err = platform_battery_read_charge_inputs(&inputs);
|
||||
int64_t now_ms = esp_timer_get_time() / 1000;
|
||||
if (err != ESP_OK || !inputs.valid) {
|
||||
s_charge_candidate_valid = false;
|
||||
s_status.charge_inputs_valid = false;
|
||||
s_status.charge_state = DOMAIN_BATTERY_CHARGE_UNKNOWN;
|
||||
unlock_state();
|
||||
return err != ESP_OK ? err : ESP_ERR_INVALID_RESPONSE;
|
||||
}
|
||||
s_status.charge_inputs_valid = true;
|
||||
s_status.charge_signal_active = inputs.charge_level == CONFIG_TQ_BATTERY_CHARGE_ACTIVE_LEVEL;
|
||||
s_status.full_signal_active = inputs.full_level == CONFIG_TQ_BATTERY_FULL_ACTIVE_LEVEL;
|
||||
domain_battery_charge_state_t candidate = decode_charge_inputs(
|
||||
s_status.charge_signal_active, s_status.full_signal_active);
|
||||
if (!s_charge_candidate_valid || candidate != s_charge_candidate ||
|
||||
now_ms - s_charge_last_poll_ms > 250 || now_ms < s_charge_last_poll_ms) {
|
||||
if (s_charge_candidate_valid && now_ms - s_charge_last_poll_ms > 250) {
|
||||
s_status.charge_state = DOMAIN_BATTERY_CHARGE_UNKNOWN;
|
||||
}
|
||||
s_charge_candidate = candidate;
|
||||
s_charge_candidate_since_ms = now_ms;
|
||||
s_charge_candidate_valid = true;
|
||||
}
|
||||
s_charge_last_poll_ms = now_ms;
|
||||
if (now_ms - s_charge_candidate_since_ms >= 1000) {
|
||||
s_status.charge_state = candidate;
|
||||
s_charge_last_confirmed_ms = now_ms;
|
||||
} else if (now_ms - s_charge_last_confirmed_ms >= 2000) {
|
||||
/* 持续抖动不能无限沿用旧的“充电中”,否则可能长期屏蔽低压保护。 */
|
||||
s_status.charge_state = DOMAIN_BATTERY_CHARGE_UNKNOWN;
|
||||
}
|
||||
unlock_state();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static uint8_t voltage_to_percentage(int voltage_mv)
|
||||
@@ -221,14 +270,8 @@ esp_err_t domain_battery_init(void)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t err = platform_battery_init();
|
||||
if (err != ESP_OK) {
|
||||
unlock_state();
|
||||
return err;
|
||||
}
|
||||
|
||||
memset(&s_status, 0, sizeof(s_status));
|
||||
s_status.charge_state = DOMAIN_BATTERY_CHARGE_UNKNOWN;
|
||||
/* ADC由电压采样路径幂等初始化;失败时充电输入仍能独立工作。 */
|
||||
/* 允许启动保护在 ADC 初始化前独立轮询充电输入,不能清掉已确认状态。 */
|
||||
s_status.level_state = DOMAIN_BATTERY_LEVEL_UNKNOWN;
|
||||
s_initialized = true;
|
||||
unlock_state();
|
||||
@@ -264,7 +307,6 @@ esp_err_t domain_battery_sample(void)
|
||||
s_status.latest_adc_mv = sample.adc_voltage_mv;
|
||||
s_status.latest_sample_mv = sample.voltage_mv;
|
||||
s_status.latest_sample_valid = sample.voltage_valid;
|
||||
s_status.charge_state = map_charge_state(sample.charge_state);
|
||||
s_status.high_load_active = sample.high_load_active;
|
||||
s_status.cooldown_active = sample.cooldown_active;
|
||||
s_status.measurement_suppressed = sample.high_load_active || sample.cooldown_active;
|
||||
@@ -385,6 +427,11 @@ esp_err_t domain_battery_init(void)
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_err_t domain_battery_poll_charge(void)
|
||||
{
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_err_t domain_battery_sample(void)
|
||||
{
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
|
||||
Reference in New Issue
Block a user