KT24-1110_65E-HA-651B/apps/common/charge_box/chgbox_box.c
2024-11-10 18:44:17 +08:00

564 lines
18 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 "app_config.h"
#include "system/includes.h"
#include "chgbox_box.h"
#include "user_cfg.h"
#include "device/vm.h"
#include "app_task.h"
#include "app_main.h"
#include "chargeIc_manage.h"
#include "chgbox_ctrl.h"
#include "device/chargebox.h"
#include "asm/power/p33.h"
#include "chgbox_det.h"
#if(TCFG_CHARGE_BOX_ENABLE)
#define LOG_TAG_CONST APP_CHGBOX
#define LOG_TAG "[APP_CBOX]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
#define LOG_CLI_ENABLE
#include "debug.h"
#define CHGBOX_THR_NAME "chgbox_n"
OS_MUTEX power_mutex;
//电池参数,电池不同,参数不同
//使用不同的电池要更新此表,不然数据可能会不准确
#define POWER_TOP_LVL 4200
#define POWER_BOOT_LVL 3100
#define POWER_LVL_MAX 11
const u16 voltage_table[2][POWER_LVL_MAX] = {
{0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100},
{POWER_BOOT_LVL, 3600, 3660, 3720, 3780, 3840, 3900, 3950, 4000, 4050, POWER_TOP_LVL},
};
/*------------------------------------------------------------------------------------*/
/**@brief 获取充电仓电量值
@param 无
@return 0~100 的电量值
@note 电量根据电池电量表换算成0~100
*/
/*------------------------------------------------------------------------------------*/
u8 get_box_power_lvl()
{
u16 max, min, power;
u8 i;
power = get_vbat_voltage();
if (power <= POWER_BOOT_LVL) {
return 0;
}
if (power >= POWER_TOP_LVL) {
return 100;
}
for (i = 0; i < POWER_LVL_MAX; i++) {
if (power < voltage_table[1][i]) {
break;
}
}
min = voltage_table[1][i - 1];
max = voltage_table[1][i];
return ((u8)(((power - min) * 10 / (max - min)) + voltage_table[0][i - 1]));
}
//通信的时候不能进入低功耗
static volatile u8 is_comm_active = 0;
static u8 comm_idle_query(void)
{
return (!is_comm_active);
}
REGISTER_LP_TARGET(comm_lp_target) = {
.name = "chgbox_comm",
.is_idle = comm_idle_query,
};
/*------------------------------------------------------------------------------------*/
/**@brief 进入发送数据关处理
@param 无
@return 无
@note 通信前要设置相关接口
*/
/*------------------------------------------------------------------------------------*/
void enter_hook(void)
{
//进入发送数据前,先关闭升压输出
os_mutex_pend(&power_mutex, 0);
if (sys_info.charge) {
chargeIc_pwr_ctrl(0);
}
chargebox_api_open_port(EAR_L);
chargebox_api_open_port(EAR_R);
is_comm_active = 1;
}
/*------------------------------------------------------------------------------------*/
/**@brief 发送数据后恢复处理
@param 无
@return 无
@note 根据状态恢复通信口
*/
/*------------------------------------------------------------------------------------*/
void exit_hook(void)
{
//退出发送数据后,是否需要打开升压输出
if (sys_info.charge && (sys_info.temperature_limit == 0)) {
chargebox_check_output_short();
chargebox_api_shutdown_port(EAR_L);
chargebox_api_shutdown_port(EAR_R);
if (sys_info.current_limit == 0) {
chargeIc_pwr_ctrl(1);
}
} else {
chargebox_api_close_port(EAR_L);
chargebox_api_close_port(EAR_R);
}
is_comm_active = 0;
os_mutex_post(&power_mutex);
}
/*------------------------------------------------------------------------------------*/
/**@brief 发消息到通信处理线程
@param msg:待发送消息
@return 无
@note
*/
/*------------------------------------------------------------------------------------*/
void app_chargebox_send_mag(int msg)
{
//有数据需要发送,自动关机计时器复位
sys_info.life_cnt = 0;
os_taskq_post_msg(CHGBOX_THR_NAME, 1, msg);
}
/*------------------------------------------------------------------------------------*/
/**@brief 充电仓事件发送函数
@param event:待发送事件
@return 无
@note
*/
/*------------------------------------------------------------------------------------*/
void app_chargebox_event_to_user(u8 event)
{
struct sys_event e;
e.type = SYS_DEVICE_EVENT;
e.arg = (void *)DEVICE_EVENT_FROM_CHARGEBOX;
e.u.dev.event = event;
sys_event_notify(&e);
}
/*------------------------------------------------------------------------------------*/
/**@brief 耳机在线检测
@param ret_l:左耳命令回应标志
ret_r:右耳命令回应标志
@return 无
@note 检测并发相应的出入仓事件
*/
/*------------------------------------------------------------------------------------*/
void app_chargebox_api_check_online(bool ret_l, bool ret_r)
{
if (ret_l == TRUE) {
if (ear_info.online[EAR_L] == 0) {
//发事件,耳机入舱
app_chargebox_event_to_user(CHGBOX_EVENT_EAR_L_ONLINE);
}
ear_info.online[EAR_L] = TCFG_EAR_OFFLINE_MAX;
} else {
if (ear_info.online[EAR_L]) {
ear_info.online[EAR_L]--;
if (ear_info.online[EAR_L] == 0) {
ear_info.power[EAR_L] = 0xff;
//发事件,耳机离舱
app_chargebox_event_to_user(CHGBOX_EVENT_EAR_L_OFFLINE);
}
}
}
if (ret_r == TRUE) {
if (ear_info.online[EAR_R] == 0) {
//发事件,耳机入舱
app_chargebox_event_to_user(CHGBOX_EVENT_EAR_R_ONLINE);
}
ear_info.online[EAR_R] = TCFG_EAR_OFFLINE_MAX;
} else {
if (ear_info.online[EAR_R]) {
ear_info.online[EAR_R]--;
if (ear_info.online[EAR_R] == 0) {
ear_info.power[EAR_R] = 0xff;
//发事件,耳机离舱
app_chargebox_event_to_user(CHGBOX_EVENT_EAR_R_OFFLINE);
}
}
}
if ((ear_info.online[EAR_L] == 0) && (ear_info.online[EAR_R] == 0)) {
chargebox_api_reset();
}
}
/*------------------------------------------------------------------------------------*/
/**@brief 发送 耳机关机 指令
@param 无
@return TRUE:发送成功 FALSE:发送失败
@note
*/
/*------------------------------------------------------------------------------------*/
u8 app_chargebox_api_send_shutdown(void)
{
u8 ret0, ret1;
enter_hook();
ret0 = chargebox_send_shut_down(EAR_L);
ret1 = chargebox_send_shut_down(EAR_R);
exit_hook();
if ((ret0 == TRUE) && (ret1 == TRUE)) {
log_debug("send shutdown ok!\n");
return TRUE;
} else {
log_error("shut down, L:%d,R:%d\n", ret0, ret1);
}
return FALSE;
}
/*------------------------------------------------------------------------------------*/
/**@brief 发送合盖指令
@param 无
@return 无
@note 发指令并检测在线
*/
/*------------------------------------------------------------------------------------*/
u8 app_chargebox_api_send_close_cid(void)
{
u8 online_cnt = 0;;
u8 ret0, ret1;
if (ear_info.online[EAR_L]) {
online_cnt += 1;
}
if (ear_info.online[EAR_R]) {
online_cnt += 1;
}
enter_hook();
ret0 = chargebox_send_close_cid(EAR_L, online_cnt);
ret1 = chargebox_send_close_cid(EAR_R, online_cnt);
exit_hook();
app_chargebox_api_check_online(ret0, ret1);
if ((ret0 == TRUE) && (ret1 == TRUE)) {
log_debug("send close CID ok\n");
return TRUE;
} else {
log_error("LID close, L:%d,R:%d\n", ret0, ret1);
}
return FALSE;
}
//存放左、右、公共地址
static u8 adv_addr_tmp_buf[3][6];
/*------------------------------------------------------------------------------------*/
/**@brief 记录左/右耳机地址
@param lr:1--左耳机 0--右耳机
inbuf:输入地址的buf指针
@return 无
@note 记录地址到对应的buf
*/
/*------------------------------------------------------------------------------------*/
void get_lr_adr_cb(u8 lr, u8 *inbuf)
{
if (lr) {
memcpy(&adv_addr_tmp_buf[1][0], inbuf, 6);
} else {
memcpy(&adv_addr_tmp_buf[0][0], inbuf, 6);
}
}
/*------------------------------------------------------------------------------------*/
/**@brief 修改广播地址回调
@param
@return 无
@note 修改广播地址并把广播地址更新到对应的buf
*/
/*------------------------------------------------------------------------------------*/
void exchange_addr_succ_cb(void)
{
u8 i;
for (i = 0; i < 6; i++) {
adv_addr_tmp_buf[2][i] = adv_addr_tmp_buf[0][i] + adv_addr_tmp_buf[1][i];
}
sys_info.chg_addr_ok = 1;
}
/*------------------------------------------------------------------------------------*/
/**@brief 获取广播地址
@param
@return NULL:无广播地址 其他:返回数组地址
@note
*/
/*------------------------------------------------------------------------------------*/
u8 *get_chargebox_adv_addr(void)
{
if (sys_info.chg_addr_ok) {
return &adv_addr_tmp_buf[2][0];
} else {
return NULL;
}
}
/*------------------------------------------------------------------------------------*/
/**@brief 从vm读取广播地址
@param 无
@return TRUE:读取成功 0:读取不到地址
@note 读取成功就记录在对应的数组中
*/
/*------------------------------------------------------------------------------------*/
u8 chgbox_addr_read_from_vm(void)
{
if (6 == syscfg_read(CFG_CHGBOX_ADDR, &adv_addr_tmp_buf[2][0], 6)) {
sys_info.chg_addr_ok = 1;
log_info("Read adv addr OK:");
put_buf(&adv_addr_tmp_buf[2][0], 6);
return TRUE;
} else {
sys_info.chg_addr_ok = 0;
log_error("Read adv addr error\n");
return FALSE;
}
}
/*------------------------------------------------------------------------------------*/
/**@brief 充电仓获取两耳机地址扫描
@param 无
@return 1:无操作 0:配对中
@note 没有检测到广播地址chg_addr_ok==0做配对扫描获取广播地址(左右耳在线且开盖)
*/
/*------------------------------------------------------------------------------------*/
u8 chgbox_addr_save_to_vm(void)
{
if (6 == syscfg_write(CFG_CHGBOX_ADDR, &adv_addr_tmp_buf[2][0], 6)) {
log_info("Write adv addr OK!\n");
return TRUE;
} else {
log_error("Write adv addr error!\n");
return FALSE;
}
}
/*------------------------------------------------------------------------------------*/
/**@brief 充电仓获取两耳机地址扫描
@param 无
@return 1:无操作 0:配对中
@note 没有检测到广播地址chg_addr_ok==0做配对扫描获取广播地址(左右耳在线且开盖)
*/
/*------------------------------------------------------------------------------------*/
u8 chgbox_adv_addr_scan(void)
{
//注意部分耳机要收到open_power指令后才跑蓝牙流程,才能拿到地址
static u8 caa_cnt = 0;
if (!sys_info.chg_addr_ok) {
if (ear_info.online[EAR_L] && ear_info.online[EAR_R] && sys_info.chgbox_status == CHG_STATUS_COMM) {
caa_cnt++;
if (caa_cnt < 8) {
//0~4是直接返回1不做操作留给外面的200Ms操作发open_power指令
if (caa_cnt == 5) { //交换地址(配对)
log_debug("ss-0\n");
app_chargebox_send_mag(CHGBOX_MSG_SEND_PAIR);
}
if (caa_cnt > 4) {
log_debug("ss-1\n");
return 0;//发配对指令后不发其他命令,避免干扰
}
} else {
caa_cnt = 0; //如果拿不到地址(chg_addr_ok==0)清0循环
}
}
}
log_debug("ss-2\n");
return 1;
}
/*------------------------------------------------------------------------------------*/
/**@brief 充电仓交换地址app
@param 无
@return 交换地址是否成功
@note 如果左右耳机在线,则交换地址,若交换成功就记录下地址
*/
/*------------------------------------------------------------------------------------*/
u8 app_chargebox_api_exchange_addr(void)
{
u8 ret = FALSE;
if (ear_info.online[EAR_L] && ear_info.online[EAR_R]) {
enter_hook();
ret = chargebox_exchange_addr(get_lr_adr_cb, exchange_addr_succ_cb);
exit_hook();
}
if (ret) {
//交换地址成功后记录地址
chgbox_addr_save_to_vm();
}
return ret;
}
/*------------------------------------------------------------------------------------*/
/**@brief 私有命令例子
* @param 无
* @return 无
* @note 1、自定义命令必须在0xC0和0xFE之间
* 2、发送长度必须小于32字节
* 3、读回来的数据在lr_buf 长度在lr_len
*/
/*------------------------------------------------------------------------------------*/
void app_chargebox_api_send_cmd_demo(void)
{
extern u8 lr_buf[2][32];
extern u8 lr_len[2];
u8 buf[3];
buf[0] = CMD_USER;
buf[1] = 0x12;
buf[2] = 0x34;
enter_hook();
if (chargebox_api_write_read(EAR_L, buf, 3, 4) == TRUE) {
//耳机有回复数据
log_dump(lr_buf[EAR_L], lr_len[EAR_L]);
}
if (chargebox_api_write_read(EAR_R, buf, 3, 4) == TRUE) {
//耳机有回复数据
log_dump(lr_buf[EAR_R], lr_len[EAR_R]);
}
exit_hook();
}
/*------------------------------------------------------------------------------------*/
/**@brief 充电仓发送电量命令获取电量
@param flag:1 合盖 0 开盖
@return 无
@note 发送仓电量、充电态、A耳机的电量 给B耳机获取B耳机的电量根据回应判断B是否在线 (两个耳机都进行)
*/
/*------------------------------------------------------------------------------------*/
void app_chargebox_api_send_power(u8 flag)
{
u8 power;
u8 ret0, ret1, is_charge = 0;
power = get_box_power_lvl();//获取仓的电量
if (sys_info.status[USB_DET] == STATUS_ONLINE) {
is_charge = 1;
}
enter_hook();
if (flag == 0) {
ret0 = chargebox_send_power_open(EAR_L, power, is_charge, ear_info.power[EAR_R]);
ret1 = chargebox_send_power_open(EAR_R, power, is_charge, ear_info.power[EAR_L]);
} else {
ret0 = chargebox_send_power_close(EAR_L, power, is_charge, ear_info.power[EAR_R]);
ret1 = chargebox_send_power_close(EAR_R, power, is_charge, ear_info.power[EAR_L]);
}
exit_hook();
app_chargebox_api_check_online(ret0, ret1);
if (ret0 == TRUE) {
ear_info.power[EAR_L] = chargebox_get_power(EAR_L);
log_info("Ear_L:%d_%d", ear_info.power[EAR_L]&BIT(7) ? 1 : 0, ear_info.power[EAR_L] & (~BIT(7)));
} else {
/* log_error("Can't got L\n"); */
}
if (ret1 == TRUE) {
ear_info.power[EAR_R] = chargebox_get_power(EAR_R);
log_info("Ear_R:%d_%d", ear_info.power[EAR_R]&BIT(7) ? 1 : 0, ear_info.power[EAR_R] & (~BIT(7)));
} else {
/* log_error("Can't got R\n"); */
}
}
/*------------------------------------------------------------------------------------*/
/**@brief 充电仓通信线程
@param priv:扩展参数
@return 无
@note 该线程负责给左右耳发送数据
*/
/*------------------------------------------------------------------------------------*/
void app_chargebox_task_handler(void *priv)
{
int msg[32];
log_info("data thread running! \n");
while (1) {
if (os_task_pend("taskq", msg, ARRAY_SIZE(msg)) != OS_TASKQ) {
continue;
}
switch (msg[1]) {
case CHGBOX_MSG_SEND_POWER_OPEN:
app_chargebox_api_send_power(0);
break;
case CHGBOX_MSG_SEND_POWER_CLOSE:
app_chargebox_api_send_power(1);
break;
case CHGBOX_MSG_SEND_CLOSE_LID:
app_chargebox_api_send_close_cid();
break;
case CHGBOX_MSG_SEND_SHUTDOWN:
app_chargebox_api_send_shutdown();
break;
case CHGBOX_MSG_SEND_PAIR:
log_info("CHANGE ear ADDR\n");
if (app_chargebox_api_exchange_addr() == TRUE) {
sys_info.pair_succ = 1;
} else {
log_error("pair_fail\n");
}
break;
default:
log_info("default msg: %d\n", msg[1]);
break;
}
}
}
CHARGEBOX_PLATFORM_DATA_BEGIN(chargebox_data)
.L_port = TCFG_CHARGEBOX_L_PORT,
.R_port = TCFG_CHARGEBOX_R_PORT,
CHARGEBOX_PLATFORM_DATA_END()
/*------------------------------------------------------------------------------------*/
/**@brief 充电仓提前初始化内容
@param priv:扩展参数
@return 无
@note
*/
/*------------------------------------------------------------------------------------*/
void app_chargebox_timer_handle(void *priv)
{
static u8 ms200_cnt = 0;
static u8 ms500_cnt = 0;
ms200_cnt++;
if (ms200_cnt >= 2) {
ms200_cnt = 0;
app_chargebox_event_to_user(CHGBOX_EVENT_200MS);
}
ms500_cnt++;
if (ms500_cnt >= 5) {
ms500_cnt = 0;
app_chargebox_event_to_user(CHGBOX_EVENT_500MS);
}
}
/*------------------------------------------------------------------------------------*/
/**@brief 充电仓提前初始化内容
@param 无
@return 无
@note 读取广播地址、初始化模块、创建通信线程、注册相关函数到timer
*/
/*------------------------------------------------------------------------------------*/
int chargebox_advanced_init(void)
{
chgbox_addr_read_from_vm();
chargebox_api_init(&chargebox_data);
task_create(app_chargebox_task_handler, NULL, CHGBOX_THR_NAME);
os_mutex_create(&power_mutex);
sys_timer_add(NULL, app_chargebox_timer_handle, 100);//推事件处理
return 0;
}
__initcall(chargebox_advanced_init);
#endif