KT24-1110_65E-HA-651B/apps/soundbox/power_manage/app_power_manage.c
2024-11-10 18:44:17 +08:00

515 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "system/includes.h"
#include "app_power_manage.h"
#include "app_main.h"
#include "app_config.h"
#include "app_action.h"
#include "asm/charge.h"
#include "ui_manage.h"
#include "tone_player.h"
#include "asm/adc_api.h"
#include "btstack/avctp_user.h"
#include "user_cfg.h"
#include "bt.h"
#include "asm/charge.h"
#if TCFG_USER_TWS_ENABLE
#include "bt_tws.h"
#endif
#define LOG_TAG_CONST APP_POWER
#define LOG_TAG "[APP_POWER]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
enum {
VBAT_NORMAL = 0,
VBAT_WARNING,
VBAT_LOWPOWER,
} VBAT_STATUS;
#define VBAT_DETECT_CNT 6
static int vbat_slow_timer = 0;
static int vbat_fast_timer = 0;
static int lowpower_timer = 0;
static u8 old_battery_level = 9;
static u16 bat_val = 0;
static volatile u8 cur_battery_level = 0;
static u16 battery_full_value = 0;
static u8 tws_sibling_bat_level = 0xff;
static u8 tws_sibling_bat_percent_level = 0xff;
static u8 cur_bat_st = VBAT_NORMAL;
void vbat_check(void *priv);
void sys_enter_soft_poweroff(void *priv);
void clr_wdt(void);
void power_event_to_user(u8 event);
u8 get_tws_sibling_bat_level(void)
{
#if TCFG_USER_TWS_ENABLE
/* log_info("***********get_tws_sibling_bat_level: %2x", tws_sibling_bat_percent_level); */
return tws_sibling_bat_level & 0x7f;
#endif
return 0xff;
}
u8 get_tws_sibling_bat_persent(void)
{
#if TCFG_USER_TWS_ENABLE
/* log_info("***********get_tws_sibling_bat_level: %2x", tws_sibling_bat_percent_level); */
return tws_sibling_bat_percent_level;
#endif
return 0xff;
}
void app_power_set_tws_sibling_bat_level(u8 vbat, u8 percent)
{
#if TCFG_USER_TWS_ENABLE
tws_sibling_bat_level = vbat;
tws_sibling_bat_percent_level = percent;
/*
** 发出电量同步事件进行进一步处理
**/
power_event_to_user(POWER_EVENT_SYNC_TWS_VBAT_LEVEL);
log_info("set_sibling_bat_level: %d, %d\n", vbat, percent);
#endif
}
static void set_tws_sibling_bat_level(void *_data, u16 len, bool rx)
{
u8 *data = (u8 *)_data;
if (rx) {
app_power_set_tws_sibling_bat_level(data[0], data[1]);
}
}
#if TCFG_USER_TWS_ENABLE
REGISTER_TWS_FUNC_STUB(vbat_sync_stub) = {
.func_id = TWS_FUNC_ID_VBAT_SYNC,
.func = set_tws_sibling_bat_level,
};
#endif
void tws_sync_bat_level(void)
{
#if (TCFG_USER_TWS_ENABLE && BT_SUPPORT_DISPLAY_BAT)
u8 battery_level = cur_battery_level;
#if CONFIG_DISPLAY_DETAIL_BAT
u8 percent_level = get_vbat_percent();
#else
u8 percent_level = get_self_battery_level() * 10 + 10;
#endif
if (get_charge_online_flag()) {
percent_level |= BIT(7);
}
u8 data[2];
data[0] = battery_level;
data[1] = percent_level;
tws_api_send_data_to_sibling(data, 2, TWS_FUNC_ID_VBAT_SYNC);
log_info("tws_sync_bat_level: %d,%d\n", battery_level, percent_level);
#endif
}
void power_event_to_user(u8 event)
{
struct sys_event e;
e.type = SYS_DEVICE_EVENT;
e.arg = (void *)DEVICE_EVENT_FROM_POWER;
e.u.dev.event = event;
e.u.dev.value = 0;
sys_event_notify(&e);
}
int app_power_event_handler(struct device_event *dev)
{
int ret = false;
#if(TCFG_SYS_LVD_EN == 1)
switch (dev->event) {
case POWER_EVENT_POWER_NORMAL:
ui_update_status(STATUS_EXIT_LOWPOWER);
if (lowpower_timer) {
sys_timer_del(lowpower_timer);
lowpower_timer = 0 ;
}
break;
case POWER_EVENT_POWER_WARNING:
/* ui_update_status(STATUS_LOWPOWER); */
if (lowpower_timer == 0) {
lowpower_timer = sys_timer_add((void *)POWER_EVENT_POWER_WARNING, (void (*)(void *))power_event_to_user, LOW_POWER_WARN_TIME);
}
break;
case POWER_EVENT_POWER_LOW:
r_printf(" POWER_EVENT_POWER_LOW");
vbat_timer_delete();
if (lowpower_timer) {
sys_timer_del(lowpower_timer);
lowpower_timer = 0 ;
}
#if TCFG_APP_BT_EN
#if (RCSP_ADV_EN)
extern u8 adv_tws_both_in_charge_box(u8 type);
adv_tws_both_in_charge_box(1);
#endif
soft_poweroff_mode(1); ///强制关机
sys_enter_soft_poweroff(NULL);
#else
void app_entry_idle() ;
app_entry_idle() ;
#ifdef CONFIG_BOARD_AC6083A
power_set_soft_poweroff();
#endif
#endif
break;
#if TCFG_APP_BT_EN
#if TCFG_USER_TWS_ENABLE
case POWER_EVENT_SYNC_TWS_VBAT_LEVEL:
if (tws_api_get_role() == TWS_ROLE_MASTER) {
user_send_cmd_prepare(USER_CTRL_HFP_CMD_UPDATE_BATTARY, 0, NULL);
}
break;
#endif
case POWER_EVENT_POWER_CHANGE:
/* log_info("POWER_EVENT_POWER_CHANGE\n"); */
#if TCFG_USER_TWS_ENABLE
if (tws_api_get_tws_state() & TWS_STA_SIBLING_CONNECTED) {
if (tws_api_get_tws_state()&TWS_STA_ESCO_OPEN) {
break;
}
tws_sync_bat_level();
}
#endif
user_send_cmd_prepare(USER_CTRL_HFP_CMD_UPDATE_BATTARY, 0, NULL);
#endif
break;
case POWER_EVENT_POWER_CHARGE:
if (lowpower_timer) {
sys_timer_del(lowpower_timer);
lowpower_timer = 0 ;
}
break;
default:
break;
}
#endif
return ret;
}
u16 get_vbat_level(void)
{
//return 370; //debug
return (adc_get_voltage(AD_CH_VBAT) * 4 / 10);
}
__attribute__((weak)) u8 remap_calculate_vbat_percent(u16 bat_val)
{
return 0;
}
u16 get_vbat_value(void)
{
return bat_val;
}
u8 get_vbat_percent(void)
{
u16 tmp_bat_val;
u16 bat_val = get_vbat_level();
if (battery_full_value == 0) {
#if TCFG_CHARGE_ENABLE
battery_full_value = (get_charge_full_value() - 100) / 10; //防止部分电池充不了这么高电量,充满显示未满的情况
#else
battery_full_value = 420;
#endif
}
if (bat_val <= app_var.poweroff_tone_v) {
return 0;
}
tmp_bat_val = remap_calculate_vbat_percent(bat_val);
if (!tmp_bat_val) {
tmp_bat_val = ((u32)bat_val - app_var.poweroff_tone_v) * 100 / (battery_full_value - app_var.poweroff_tone_v);
if (tmp_bat_val > 100) {
tmp_bat_val = 100;
}
}
return (u8)tmp_bat_val;
}
bool get_vbat_need_shutdown(void)
{
if ((bat_val <= LOW_POWER_SHUTDOWN) || adc_check_vbat_lowpower()) {
return TRUE;
}
return FALSE;
}
//将当前电量转换为1~9级发送给手机同步电量
u8 battery_value_to_phone_level(u16 bat_val)
{
u8 battery_level = 0;
u8 vbat_percent = get_vbat_percent();
if (vbat_percent < 5) { //小于5%电量等级为0显示10%
return 0;
}
battery_level = (vbat_percent - 5) / 10;
return battery_level;
}
//获取自身的电量
u8 get_self_battery_level(void)
{
return cur_battery_level;
}
u8 get_cur_battery_level(void)
{
u8 bat_lev = tws_sibling_bat_level & (~BIT(7));
#if TCFG_USER_TWS_ENABLE
if (bat_lev == 0x7f) {
return cur_battery_level;
}
#if (CONFIG_DISPLAY_TWS_BAT_TYPE == CONFIG_DISPLAY_TWS_BAT_LOWER)
return cur_battery_level < bat_lev ? cur_battery_level : bat_lev;
#elif (CONFIG_DISPLAY_TWS_BAT_TYPE == CONFIG_DISPLAY_TWS_BAT_HIGHER)
return cur_battery_level < bat_lev ? bat_lev : cur_battery_level;
#elif (CONFIG_DISPLAY_TWS_BAT_TYPE == CONFIG_DISPLAY_TWS_BAT_LEFT)
return tws_api_get_local_channel() == 'L' ? cur_battery_level : bat_lev;
#elif (CONFIG_DISPLAY_TWS_BAT_TYPE == CONFIG_DISPLAY_TWS_BAT_RIGHT)
return tws_api_get_local_channel() == 'R' ? cur_battery_level : bat_lev;
#else
return cur_battery_level;
#endif //END CONFIG_DISPLAY_TWS_BAT_TYPE
#else //TCFG_USER_TWS_ENABLE == 0
return cur_battery_level;
#endif
}
void vbat_check_slow(void *priv)
{
if (vbat_fast_timer == 0) {
vbat_fast_timer = usr_timer_add(NULL, vbat_check, 10, 1);
}
if (get_charge_online_flag()) {
sys_timer_modify(vbat_slow_timer, 60 * 1000);
} else {
sys_timer_modify(vbat_slow_timer, 10 * 1000);
}
}
void vbat_check_init(void)
{
if (vbat_slow_timer == 0) {
vbat_slow_timer = sys_timer_add(NULL, vbat_check_slow, 10 * 1000);
} else {
sys_timer_modify(vbat_slow_timer, 10 * 1000);
}
if (vbat_fast_timer == 0) {
vbat_fast_timer = usr_timer_add(NULL, vbat_check, 10, 1);
}
}
void vbat_timer_delete(void)
{
if (vbat_slow_timer) {
sys_timer_del(vbat_slow_timer);
vbat_slow_timer = 0;
}
if (vbat_fast_timer) {
usr_timer_del(vbat_fast_timer);
vbat_fast_timer = 0;
}
}
void vbat_check(void *priv)
{
static u8 unit_cnt = 0;
static u8 low_warn_cnt = 0;
static u8 low_off_cnt = 0;
static u8 low_voice_cnt = 0;
static u8 low_power_cnt = 0;
static u8 power_normal_cnt = 0;
static u8 charge_ccvol_v_cnt = 0;
static u8 charge_online_flag = 0;
static u8 low_voice_first_flag = 1;//进入低电后先提醒一次
if (!bat_val) {
bat_val = get_vbat_level();
} else {
bat_val = (get_vbat_level() + bat_val) / 2;
}
cur_battery_level = battery_value_to_phone_level(bat_val);
//printf("bv:%d, bl:%d , check_vbat:%d\n", bat_val, cur_battery_level, adc_check_vbat_lowpower());
unit_cnt++;
/* if (bat_val < LOW_POWER_OFF_VAL) { */
if (adc_check_vbat_lowpower() || (bat_val <= app_var.poweroff_tone_v)) {
low_off_cnt++;
}
/* if (bat_val < LOW_POWER_WARN_VAL) { */
if (bat_val <= app_var.warning_tone_v) {
low_warn_cnt++;
}
#if TCFG_CHARGE_ENABLE
if (bat_val >= CHARGE_CCVOL_V) {
charge_ccvol_v_cnt++;
}
#endif
/* log_info("unit_cnt:%d\n", unit_cnt); */
if (unit_cnt >= VBAT_DETECT_CNT) {
if (get_charge_online_flag() == 0) {
if (low_off_cnt > (VBAT_DETECT_CNT / 2)) { //低电关机
low_power_cnt++;
low_voice_cnt = 0;
power_normal_cnt = 0;
cur_bat_st = VBAT_LOWPOWER;
if (low_power_cnt > 6) {
log_info("\n*******Low Power,enter softpoweroff********\n");
low_power_cnt = 0;
power_event_to_user(POWER_EVENT_POWER_LOW);
usr_timer_del(vbat_fast_timer);
vbat_fast_timer = 0;
}
} else if (low_warn_cnt > (VBAT_DETECT_CNT / 2)) { //低电提醒
low_voice_cnt ++;
low_power_cnt = 0;
power_normal_cnt = 0;
cur_bat_st = VBAT_WARNING;
if ((low_voice_first_flag && low_voice_cnt > 1) || //第一次进低电10s后报一次
(!low_voice_first_flag && low_voice_cnt >= 5)) {
low_voice_first_flag = 0;
low_voice_cnt = 0;
if (!lowpower_timer) {
log_info("\n**Low Power,Please Charge Soon!!!**\n");
power_event_to_user(POWER_EVENT_POWER_WARNING);
}
}
} else {
power_normal_cnt++;
low_voice_cnt = 0;
low_power_cnt = 0;
if (power_normal_cnt > 2) {
if (cur_bat_st != VBAT_NORMAL) {
log_info("[Noraml power]\n");
cur_bat_st = VBAT_NORMAL;
power_event_to_user(POWER_EVENT_POWER_NORMAL);
}
}
}
} else {
power_event_to_user(POWER_EVENT_POWER_CHARGE);
#if TCFG_CHARGE_ENABLE
if (charge_ccvol_v_cnt > (VBAT_DETECT_CNT / 2)) {
set_charge_mA(get_charge_mA_config());
}
#endif
}
unit_cnt = 0;
low_off_cnt = 0;
low_warn_cnt = 0;
charge_ccvol_v_cnt = 0;
if (cur_bat_st != VBAT_LOWPOWER) {
usr_timer_del(vbat_fast_timer);
vbat_fast_timer = 0;
cur_battery_level = battery_value_to_phone_level(bat_val);
if (cur_battery_level != old_battery_level) {
power_event_to_user(POWER_EVENT_POWER_CHANGE);
} else {
if (charge_online_flag != get_charge_online_flag()) {
//充电变化也要交换,确定是否在充电仓
power_event_to_user(POWER_EVENT_POWER_CHANGE);
}
}
charge_online_flag = get_charge_online_flag();
old_battery_level = cur_battery_level;
}
}
}
bool vbat_is_low_power(void)
{
return (cur_bat_st != VBAT_NORMAL);
}
void check_power_on_voltage(void)
{
#if(TCFG_SYS_LVD_EN == 1)
u16 val = 0;
u8 normal_power_cnt = 0;
u8 low_power_cnt = 0;
while (1) {
clr_wdt();
val = get_vbat_level();
printf("vbat: %d\n", val);
if ((val < app_var.poweroff_tone_v) || adc_check_vbat_lowpower()) {
low_power_cnt++;
normal_power_cnt = 0;
if (low_power_cnt > 10) {
ui_update_status(STATUS_POWERON_LOWPOWER);
os_time_dly(100);
log_info("power on low power , enter softpoweroff!\n");
power_set_soft_poweroff();
}
} else {
normal_power_cnt++;
low_power_cnt = 0;
if (normal_power_cnt > 10) {
vbat_check_init();
return;
}
}
}
#endif
}
#if(CONFIG_CPU_BR25)
void app_reset_vddiom_lev(u8 lev)
{
if (TCFG_LOWPOWER_VDDIOM_LEVEL == VDDIOM_VOL_34V) {
/* printf("\n\n\n\n\n -------------------set vddiom again %d -----------------------\n\n\n\n\n",lev); */
reset_vddiom_lev(lev);
}
}
#else
void app_reset_vddiom_lev(u8 lev)
{
}
#endif