基本功能已完成,还差功耗和架构优化
This commit is contained in:
+14
@@ -177,6 +177,7 @@
|
|||||||
<Add directory="apps/usr_jb_proto/Protocol" />
|
<Add directory="apps/usr_jb_proto/Protocol" />
|
||||||
<Add directory="apps/usr_jb_proto/Utils" />
|
<Add directory="apps/usr_jb_proto/Utils" />
|
||||||
<Add directory="apps/usr_periph" />
|
<Add directory="apps/usr_periph" />
|
||||||
|
<Add directory="apps/usr_app" />
|
||||||
</Compiler>
|
</Compiler>
|
||||||
<Linker>
|
<Linker>
|
||||||
<Add option="-flto" />
|
<Add option="-flto" />
|
||||||
@@ -783,6 +784,19 @@
|
|||||||
<Option compilerVar="CC" />
|
<Option compilerVar="CC" />
|
||||||
</Unit>
|
</Unit>
|
||||||
<Unit filename="apps/usr_periph/usr_rtc.h" />
|
<Unit filename="apps/usr_periph/usr_rtc.h" />
|
||||||
|
<Unit filename="apps/usr_periph/board_pin.h" />
|
||||||
|
<Unit filename="apps/usr_periph/bsp_hw.c">
|
||||||
|
<Option compilerVar="CC" />
|
||||||
|
</Unit>
|
||||||
|
<Unit filename="apps/usr_periph/bsp_hw.h" />
|
||||||
|
<Unit filename="apps/usr_app/app_led.c">
|
||||||
|
<Option compilerVar="CC" />
|
||||||
|
</Unit>
|
||||||
|
<Unit filename="apps/usr_app/app_led.h" />
|
||||||
|
<Unit filename="apps/usr_app/app_mode.c">
|
||||||
|
<Option compilerVar="CC" />
|
||||||
|
</Unit>
|
||||||
|
<Unit filename="apps/usr_app/app_mode.h" />
|
||||||
<Unit filename="apps/usr_le_code/ble_proto.h" />
|
<Unit filename="apps/usr_le_code/ble_proto.h" />
|
||||||
<Unit filename="apps/usr_le_code/bleproto.h" />
|
<Unit filename="apps/usr_le_code/bleproto.h" />
|
||||||
<Unit filename="apps/usr_le_code/bleproto_api.h" />
|
<Unit filename="apps/usr_le_code/bleproto_api.h" />
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ INCLUDES := \
|
|||||||
-Iapps/usr_jb_proto/Protocol \
|
-Iapps/usr_jb_proto/Protocol \
|
||||||
-Iapps/usr_jb_proto/Utils \
|
-Iapps/usr_jb_proto/Utils \
|
||||||
-Iapps/usr_periph \
|
-Iapps/usr_periph \
|
||||||
|
-Iapps/usr_app \
|
||||||
-I$(SYS_INC_DIR) \
|
-I$(SYS_INC_DIR) \
|
||||||
|
|
||||||
|
|
||||||
@@ -621,6 +622,9 @@ c_SRC_FILES := \
|
|||||||
apps/usr_jb_proto/Utils/jb_ringbuffer.c \
|
apps/usr_jb_proto/Utils/jb_ringbuffer.c \
|
||||||
apps/usr_jb_proto/usr_jb_main.c \
|
apps/usr_jb_proto/usr_jb_main.c \
|
||||||
apps/usr_periph/usr_rtc.c \
|
apps/usr_periph/usr_rtc.c \
|
||||||
|
apps/usr_periph/bsp_hw.c \
|
||||||
|
apps/usr_app/app_led.c \
|
||||||
|
apps/usr_app/app_mode.c \
|
||||||
|
|
||||||
|
|
||||||
# usr_le_code 预编译静态库(Release 不附带协议源码,禁止本地重建)
|
# usr_le_code 预编译静态库(Release 不附带协议源码,禁止本地重建)
|
||||||
|
|||||||
@@ -156,7 +156,6 @@ extern void uart_dev_test_main();
|
|||||||
extern int ana_demo();
|
extern int ana_demo();
|
||||||
extern void uart_dev_main_init();
|
extern void uart_dev_main_init();
|
||||||
extern void usr_check_mcu_all_sta();
|
extern void usr_check_mcu_all_sta();
|
||||||
extern void usr_clear_pair_info_noreset(void);
|
|
||||||
extern void usr_disable_intterupt();
|
extern void usr_disable_intterupt();
|
||||||
extern void usr_disable_charge_intterupt();
|
extern void usr_disable_charge_intterupt();
|
||||||
u8 power_reset_flag=0;
|
u8 power_reset_flag=0;
|
||||||
@@ -327,13 +326,10 @@ void app_main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 上电强制进入配对模式:
|
* 配对只在 usr_jb_init() 里、BLE 起来之前处理:
|
||||||
* 1) usr_goto_pair=1:后续 usr_ble_adv_init() 走绑定广播(encode4bind),不走重连广播
|
* 深睡长按 5s → usr_goto_pair=1 + 清绑定;长按 3s 仅开机。
|
||||||
* 2) usr_clear_pair_info_noreset():清 VM 中三元组,保证 paired_flag=0
|
* 此处不要再强制配对,也不要在协议栈起来后调用 usr_goto_pair_mode()。
|
||||||
* 注意:须在 BLE 协议栈调用 usr_ble_adv_init() 之前设置;此处不清复位,避免上电死循环复位
|
|
||||||
*/
|
*/
|
||||||
usr_var.usr_goto_pair = 1;
|
|
||||||
usr_clear_pair_info_noreset();
|
|
||||||
|
|
||||||
ui_manage_init();
|
ui_manage_init();
|
||||||
ui_update_status(STATUS_POWERON);
|
ui_update_status(STATUS_POWERON);
|
||||||
|
|||||||
@@ -0,0 +1,621 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @file app_cbc2.c
|
||||||
|
* @brief CBC2 电源 / 充电 / 按键 / 配对 / DP 协调
|
||||||
|
* @author cyWu <1917507415@qq.com>
|
||||||
|
* @date 2026.08.24
|
||||||
|
* @version V1.0.2
|
||||||
|
* @history
|
||||||
|
* - V1.0.0, 2026.08.21, cyWu, 首次发布
|
||||||
|
* - V1.0.2, 2026.08.24, cyWu, 上电即绑定广播,与 81bd2f7 行为对齐
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "system/includes.h"
|
||||||
|
#include "app_main.h"
|
||||||
|
#include "app_cbc2.h"
|
||||||
|
#include "app_nv.h"
|
||||||
|
#include "app_led.h"
|
||||||
|
#include "app_rope.h"
|
||||||
|
#include "app_mode.h"
|
||||||
|
#include "app_dnd.h"
|
||||||
|
#include "bsp_hw.h"
|
||||||
|
#include "usr_le_api.h"
|
||||||
|
#include "asm/power/power_api.h"
|
||||||
|
|
||||||
|
#define LOG_TAG_CONST APP
|
||||||
|
#define LOG_TAG "[APP_CBC2]"
|
||||||
|
#define LOG_ERROR_ENABLE
|
||||||
|
#define LOG_DEBUG_ENABLE
|
||||||
|
#define LOG_INFO_ENABLE
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
extern void sys_enter_soft_poweroff(void *priv);
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
/* 类型 */
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
APP_LIFE_CHARGE_ONLY = 0,
|
||||||
|
APP_LIFE_ON,
|
||||||
|
APP_LIFE_PAIR
|
||||||
|
} AppLife_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t inited;
|
||||||
|
AppLife_t life;
|
||||||
|
uint8_t power; /* DP0 APP 功能开关 */
|
||||||
|
uint8_t play_mode;
|
||||||
|
uint8_t battery;
|
||||||
|
uint8_t charge_dp; /* 1 充电中 2 未充电 */
|
||||||
|
uint8_t alm_low;
|
||||||
|
uint8_t charge_led; /* 0 无 1 充 2 满 */
|
||||||
|
uint8_t usb_raw;
|
||||||
|
uint8_t usb_debounced;
|
||||||
|
uint8_t usb_cnt;
|
||||||
|
uint8_t restore_on; /* 插电前是否开机 */
|
||||||
|
uint8_t full_latched;
|
||||||
|
uint8_t from_deep_boot;
|
||||||
|
uint8_t boot_key_lock; /* 开机按键未松开前,忽略短按/关机 */
|
||||||
|
uint8_t key_raw;
|
||||||
|
uint8_t key_stable;
|
||||||
|
uint8_t key_cnt;
|
||||||
|
uint8_t key_pressed;
|
||||||
|
uint16_t key_hold_ms;
|
||||||
|
uint8_t req_click;
|
||||||
|
uint8_t req_poweroff;
|
||||||
|
uint8_t req_pair;
|
||||||
|
uint32_t pair_ms;
|
||||||
|
uint32_t lowbat_ms;
|
||||||
|
uint8_t lowbat_run;
|
||||||
|
uint16_t vbat_mv;
|
||||||
|
uint8_t pause_mode;
|
||||||
|
uint8_t pause_cal;
|
||||||
|
uint8_t pause_percent;
|
||||||
|
uint8_t pause_percent_valid;
|
||||||
|
uint8_t run_timer;
|
||||||
|
} AppCbc2_t;
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
/* 私有变量 */
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
|
static AppCbc2_t s_app;
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
/* 私有函数 */
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
|
static uint8_t app_cbc2_ctrl_allowed(void)
|
||||||
|
{
|
||||||
|
return (uint8_t)(s_app.life != APP_LIFE_CHARGE_ONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_apply_stop_reset(void)
|
||||||
|
{
|
||||||
|
app_mode_stop();
|
||||||
|
app_rope_stop();
|
||||||
|
s_app.play_mode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_apply_play_mode(uint8_t mode, uint8_t blink)
|
||||||
|
{
|
||||||
|
if (mode > 6) {
|
||||||
|
mode = 0;
|
||||||
|
}
|
||||||
|
app_rope_stop();
|
||||||
|
if (mode == 0) {
|
||||||
|
app_mode_stop();
|
||||||
|
} else {
|
||||||
|
app_mode_start(mode);
|
||||||
|
}
|
||||||
|
s_app.play_mode = mode;
|
||||||
|
if (blink) {
|
||||||
|
app_led_request_mode_blink();
|
||||||
|
}
|
||||||
|
log_info("play_mode=%d\n", mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_do_poweroff(void)
|
||||||
|
{
|
||||||
|
log_info("enter deep off\n");
|
||||||
|
app_mode_stop();
|
||||||
|
bsp_hw_enter_sleep_io();
|
||||||
|
app_nv_save_if_dirty();
|
||||||
|
sys_enter_soft_poweroff(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_boot_poweroff(void)
|
||||||
|
{
|
||||||
|
log_info("boot deep off\n");
|
||||||
|
bsp_hw_enter_sleep_io();
|
||||||
|
app_nv_save_if_dirty();
|
||||||
|
power_set_soft_poweroff();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_enter_pair(void)
|
||||||
|
{
|
||||||
|
log_info("enter pair mode\n");
|
||||||
|
app_cbc2_apply_stop_reset();
|
||||||
|
s_app.life = APP_LIFE_PAIR;
|
||||||
|
s_app.power = 1;
|
||||||
|
s_app.pair_ms = 0;
|
||||||
|
s_app.from_deep_boot = 0;
|
||||||
|
usr_var.usr_goto_pair = 1;
|
||||||
|
usr_goto_pair_mode();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_pair_end(uint8_t ok)
|
||||||
|
{
|
||||||
|
log_info("pair %s\n", ok ? "ok" : "fail");
|
||||||
|
app_led_start_pair_result(ok);
|
||||||
|
s_app.life = APP_LIFE_ON;
|
||||||
|
s_app.power = 1;
|
||||||
|
s_app.play_mode = 0;
|
||||||
|
usr_var.usr_goto_pair = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_pause_functions(void)
|
||||||
|
{
|
||||||
|
s_app.pause_mode = s_app.play_mode;
|
||||||
|
s_app.pause_cal = app_rope_is_calibrating();
|
||||||
|
s_app.pause_percent_valid = 0;
|
||||||
|
if (app_rope_is_busy() && !s_app.pause_cal && app_rope_is_calibrated()
|
||||||
|
&& app_rope_get_turns()) {
|
||||||
|
int32_t max_x = (int32_t)app_rope_get_turns() * 100;
|
||||||
|
if (max_x > 0) {
|
||||||
|
int32_t pct = app_rope_remaining_x100() * 100 / max_x;
|
||||||
|
if (pct < 0) {
|
||||||
|
pct = 0;
|
||||||
|
}
|
||||||
|
if (pct > 100) {
|
||||||
|
pct = 100;
|
||||||
|
}
|
||||||
|
s_app.pause_percent = (uint8_t)pct;
|
||||||
|
s_app.pause_percent_valid = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app_mode_stop();
|
||||||
|
app_rope_stop();
|
||||||
|
log_info("app power pause mode=%d cal=%d\n", s_app.pause_mode, s_app.pause_cal);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_resume_functions(void)
|
||||||
|
{
|
||||||
|
log_info("app power resume mode=%d cal=%d\n", s_app.pause_mode, s_app.pause_cal);
|
||||||
|
if (s_app.pause_cal) {
|
||||||
|
app_rope_cal_start();
|
||||||
|
} else if (s_app.pause_percent_valid) {
|
||||||
|
app_rope_goto_percent(s_app.pause_percent);
|
||||||
|
} else if (s_app.pause_mode >= 1 && s_app.pause_mode <= 6) {
|
||||||
|
app_cbc2_apply_play_mode(s_app.pause_mode, 0);
|
||||||
|
}
|
||||||
|
s_app.pause_cal = 0;
|
||||||
|
s_app.pause_percent_valid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t app_cbc2_bat_percent(uint16_t mv)
|
||||||
|
{
|
||||||
|
int32_t span = BOARD_VBAT_FULL_MV - BOARD_VBAT_EMPTY_MV;
|
||||||
|
int32_t pct;
|
||||||
|
|
||||||
|
if (mv <= BOARD_VBAT_EMPTY_MV) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (mv >= BOARD_VBAT_FULL_MV) {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
pct = ((int32_t)mv - BOARD_VBAT_EMPTY_MV) * 100 / span;
|
||||||
|
if (pct < 0) {
|
||||||
|
pct = 0;
|
||||||
|
}
|
||||||
|
if (pct > 100) {
|
||||||
|
pct = 100;
|
||||||
|
}
|
||||||
|
return (uint8_t)pct;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_sample_charge(void)
|
||||||
|
{
|
||||||
|
uint8_t usb = bsp_vpwr_is_online();
|
||||||
|
|
||||||
|
if (usb == s_app.usb_raw) {
|
||||||
|
if (s_app.usb_cnt < 5) {
|
||||||
|
s_app.usb_cnt++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s_app.usb_raw = usb;
|
||||||
|
s_app.usb_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_app.usb_cnt >= 5 && s_app.usb_debounced != s_app.usb_raw) {
|
||||||
|
s_app.usb_debounced = s_app.usb_raw;
|
||||||
|
if (s_app.usb_debounced) {
|
||||||
|
s_app.restore_on = (uint8_t)(s_app.life != APP_LIFE_CHARGE_ONLY);
|
||||||
|
s_app.full_latched = 0;
|
||||||
|
app_cbc2_apply_stop_reset();
|
||||||
|
s_app.life = APP_LIFE_CHARGE_ONLY;
|
||||||
|
log_info("usb in, charge-only (restore_on=%d)\n", s_app.restore_on);
|
||||||
|
} else {
|
||||||
|
log_info("usb out full_latched=%d restore_on=%d\n",
|
||||||
|
s_app.full_latched, s_app.restore_on);
|
||||||
|
if (s_app.full_latched || !s_app.restore_on) {
|
||||||
|
s_app.req_poweroff = 1;
|
||||||
|
} else {
|
||||||
|
s_app.life = APP_LIFE_ON;
|
||||||
|
app_cbc2_apply_stop_reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_app.usb_debounced) {
|
||||||
|
if (bsp_chg_is_low()) {
|
||||||
|
s_app.charge_led = 1;
|
||||||
|
s_app.charge_dp = 1;
|
||||||
|
s_app.full_latched = 0;
|
||||||
|
} else {
|
||||||
|
s_app.charge_led = 2;
|
||||||
|
s_app.charge_dp = 2; /* 充满:DP 报未充电 */
|
||||||
|
s_app.full_latched = 1;
|
||||||
|
}
|
||||||
|
usr_var.usr_power_charge_flag = 1;
|
||||||
|
} else {
|
||||||
|
s_app.charge_led = 0;
|
||||||
|
s_app.charge_dp = 2;
|
||||||
|
usr_var.usr_power_charge_flag = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_sample_battery(void)
|
||||||
|
{
|
||||||
|
uint16_t mv = bsp_vbat_mv();
|
||||||
|
uint8_t alarm_on;
|
||||||
|
uint8_t alarm_off;
|
||||||
|
|
||||||
|
s_app.vbat_mv = mv;
|
||||||
|
s_app.battery = app_cbc2_bat_percent(mv);
|
||||||
|
|
||||||
|
alarm_on = BOARD_VBAT_LOW_MV;
|
||||||
|
alarm_off = BOARD_VBAT_LOW_MV + BOARD_VBAT_LOW_HYST_MV;
|
||||||
|
|
||||||
|
if (mv <= BOARD_VBAT_EMPTY_MV && !s_app.usb_debounced) {
|
||||||
|
if (s_app.life != APP_LIFE_CHARGE_ONLY) {
|
||||||
|
log_info("vbat %d mV lock\n", mv);
|
||||||
|
s_app.req_poweroff = 1;
|
||||||
|
}
|
||||||
|
s_app.alm_low = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s_app.alm_low && mv < alarm_on) {
|
||||||
|
s_app.alm_low = 1;
|
||||||
|
s_app.lowbat_ms = 0;
|
||||||
|
s_app.lowbat_run = 1;
|
||||||
|
log_info("low battery warn %d mV\n", mv);
|
||||||
|
} else if (s_app.alm_low && mv > alarm_off) {
|
||||||
|
s_app.alm_low = 0;
|
||||||
|
s_app.lowbat_run = 0;
|
||||||
|
s_app.lowbat_ms = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_app.usb_debounced || s_app.life == APP_LIFE_CHARGE_ONLY) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (s_app.lowbat_run && s_app.alm_low) {
|
||||||
|
s_app.lowbat_ms += 50;
|
||||||
|
if (s_app.lowbat_ms >= BOARD_LOWBAT_SLEEP_MS) {
|
||||||
|
log_info("low battery 1min, deep off\n");
|
||||||
|
s_app.req_poweroff = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_handle_click(void)
|
||||||
|
{
|
||||||
|
uint8_t next;
|
||||||
|
|
||||||
|
if (s_app.life != APP_LIFE_ON) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (s_app.power == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (app_rope_is_calibrating()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
next = (uint8_t)((s_app.play_mode + 1) % 7);
|
||||||
|
app_cbc2_apply_play_mode(next, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_key_hold_check(void)
|
||||||
|
{
|
||||||
|
if (!s_app.key_pressed || s_app.boot_key_lock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s_app.key_hold_ms++;
|
||||||
|
if (s_app.life == APP_LIFE_CHARGE_ONLY || s_app.life == APP_LIFE_PAIR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (s_app.life == APP_LIFE_ON && s_app.key_hold_ms == BOARD_KEY_POWER_MS) {
|
||||||
|
s_app.req_poweroff = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_key_tick_1ms(void)
|
||||||
|
{
|
||||||
|
uint8_t raw = bsp_key_is_pressed();
|
||||||
|
|
||||||
|
if (raw == s_app.key_raw) {
|
||||||
|
if (s_app.key_cnt < BOARD_KEY_DEBOUNCE_MS) {
|
||||||
|
s_app.key_cnt++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s_app.key_raw = raw;
|
||||||
|
s_app.key_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_app.key_cnt != BOARD_KEY_DEBOUNCE_MS) {
|
||||||
|
app_cbc2_key_hold_check();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw && !s_app.key_pressed) {
|
||||||
|
s_app.key_pressed = 1;
|
||||||
|
s_app.key_hold_ms = 0;
|
||||||
|
} else if (!raw && s_app.key_pressed) {
|
||||||
|
if (s_app.boot_key_lock) {
|
||||||
|
s_app.boot_key_lock = 0;
|
||||||
|
s_app.key_pressed = 0;
|
||||||
|
s_app.key_hold_ms = 0;
|
||||||
|
log_info("boot key released\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (s_app.life == APP_LIFE_ON &&
|
||||||
|
s_app.power &&
|
||||||
|
s_app.key_hold_ms < BOARD_KEY_CLICK_MS &&
|
||||||
|
s_app.key_hold_ms >= 10) {
|
||||||
|
s_app.req_click = 1;
|
||||||
|
}
|
||||||
|
s_app.key_pressed = 0;
|
||||||
|
s_app.key_hold_ms = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
app_cbc2_key_hold_check();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void app_cbc2_boot_decide(void)
|
||||||
|
{
|
||||||
|
s_app.usb_raw = bsp_vpwr_is_online();
|
||||||
|
s_app.usb_debounced = s_app.usb_raw;
|
||||||
|
s_app.usb_cnt = 5;
|
||||||
|
s_app.vbat_mv = bsp_vbat_mv();
|
||||||
|
|
||||||
|
if (s_app.usb_debounced) {
|
||||||
|
s_app.life = APP_LIFE_CHARGE_ONLY;
|
||||||
|
s_app.restore_on = 0;
|
||||||
|
s_app.power = 0;
|
||||||
|
log_info("boot CHARGE_ONLY vbat=%d\n", s_app.vbat_mv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_app.vbat_mv <= BOARD_VBAT_EMPTY_MV) {
|
||||||
|
log_info("boot vbat %d too low\n", s_app.vbat_mv);
|
||||||
|
app_cbc2_boot_poweroff();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 与 81bd2f7 一致:上电即绑定广播,不等按键、不 deep off */
|
||||||
|
s_app.power = 1;
|
||||||
|
s_app.play_mode = 0;
|
||||||
|
s_app.from_deep_boot = 0;
|
||||||
|
s_app.boot_key_lock = bsp_key_is_pressed() ? 1 : 0;
|
||||||
|
s_app.key_pressed = s_app.boot_key_lock;
|
||||||
|
s_app.key_hold_ms = 0;
|
||||||
|
s_app.key_raw = s_app.key_pressed;
|
||||||
|
s_app.key_stable = s_app.key_pressed;
|
||||||
|
s_app.key_cnt = BOARD_KEY_DEBOUNCE_MS;
|
||||||
|
usr_var.usr_goto_pair = 1;
|
||||||
|
s_app.life = APP_LIFE_PAIR;
|
||||||
|
s_app.pair_ms = 0;
|
||||||
|
log_info("boot PAIR power-on bind adv\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
/* 公有函数 */
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
|
AppCbc2_Ret_t app_cbc2_init(void)
|
||||||
|
{
|
||||||
|
if (s_app.inited) {
|
||||||
|
return APP_CBC2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&s_app, 0, sizeof(s_app));
|
||||||
|
s_app.charge_dp = 2;
|
||||||
|
s_app.power = 0;
|
||||||
|
|
||||||
|
bsp_hw_init();
|
||||||
|
app_nv_init();
|
||||||
|
app_led_init();
|
||||||
|
app_rope_init();
|
||||||
|
app_mode_init();
|
||||||
|
app_dnd_init();
|
||||||
|
|
||||||
|
app_cbc2_boot_decide();
|
||||||
|
|
||||||
|
s_app.inited = 1;
|
||||||
|
sys_timer_add(NULL, app_cbc2_run, 50);
|
||||||
|
|
||||||
|
log_info("cbc2 init life=%d power=%d\n", s_app.life, s_app.power);
|
||||||
|
return APP_CBC2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppCbc2_Ret_t app_cbc2_get_status(void)
|
||||||
|
{
|
||||||
|
return s_app.inited ? APP_CBC2_OK : APP_CBC2_ERR_NOT_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_cbc2_tick_1ms(void)
|
||||||
|
{
|
||||||
|
AppLedCtx_t led;
|
||||||
|
|
||||||
|
if (!s_app.inited) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
app_rope_tick_1ms();
|
||||||
|
app_cbc2_key_tick_1ms();
|
||||||
|
(void)bsp_aloft_is_active();
|
||||||
|
|
||||||
|
memset(&led, 0, sizeof(led));
|
||||||
|
led.charge_led = s_app.charge_led;
|
||||||
|
led.pairing = (uint8_t)(s_app.life == APP_LIFE_PAIR);
|
||||||
|
led.app_power = s_app.power;
|
||||||
|
led.low_bat = s_app.alm_low;
|
||||||
|
led.life_on = (uint8_t)(s_app.life != APP_LIFE_CHARGE_ONLY);
|
||||||
|
app_led_tick_1ms(&led);
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_cbc2_run(void *priv)
|
||||||
|
{
|
||||||
|
(void)priv;
|
||||||
|
if (!s_app.inited) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
app_cbc2_sample_charge();
|
||||||
|
app_cbc2_sample_battery();
|
||||||
|
app_dnd_run();
|
||||||
|
app_mode_run();
|
||||||
|
|
||||||
|
if (s_app.life == APP_LIFE_PAIR) {
|
||||||
|
s_app.pair_ms += 50;
|
||||||
|
if (usr_get_pair_flag()) {
|
||||||
|
app_cbc2_pair_end(1);
|
||||||
|
} else if (s_app.pair_ms >= BOARD_PAIR_TIMEOUT_MS) {
|
||||||
|
app_cbc2_pair_end(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 仅 BLE 已起来后才允许再调 usr_goto_pair_mode,避免和 bt_ble_init 抢广播 */
|
||||||
|
if (s_app.req_pair) {
|
||||||
|
s_app.req_pair = 0;
|
||||||
|
if (s_app.life != APP_LIFE_CHARGE_ONLY) {
|
||||||
|
app_cbc2_enter_pair();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s_app.req_click) {
|
||||||
|
s_app.req_click = 0;
|
||||||
|
app_cbc2_handle_click();
|
||||||
|
}
|
||||||
|
if (s_app.req_poweroff) {
|
||||||
|
s_app.req_poweroff = 0;
|
||||||
|
app_cbc2_do_poweroff();
|
||||||
|
}
|
||||||
|
|
||||||
|
app_nv_save_if_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_cbc2_fill_report(AppCbc2Report_t *out)
|
||||||
|
{
|
||||||
|
if (!out) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(out, 0, sizeof(*out));
|
||||||
|
out->power = s_app.power;
|
||||||
|
out->play_mode = s_app.play_mode;
|
||||||
|
out->calibration = app_rope_is_calibrating();
|
||||||
|
out->numberturns = app_rope_get_turns();
|
||||||
|
out->alm_low_battery = s_app.alm_low;
|
||||||
|
out->battery = s_app.battery;
|
||||||
|
out->charge = s_app.charge_dp;
|
||||||
|
app_dnd_get_raw(out->dnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
AppCbc2_Ret_t app_cbc2_ctrl_power(uint8_t on)
|
||||||
|
{
|
||||||
|
if (!app_cbc2_ctrl_allowed()) {
|
||||||
|
log_info("ctrl power ignored (charge)\n");
|
||||||
|
return APP_CBC2_ERR_DENIED;
|
||||||
|
}
|
||||||
|
if (s_app.life == APP_LIFE_PAIR) {
|
||||||
|
return APP_CBC2_ERR_BUSY;
|
||||||
|
}
|
||||||
|
on = on ? 1 : 0;
|
||||||
|
if (on == s_app.power) {
|
||||||
|
return APP_CBC2_OK;
|
||||||
|
}
|
||||||
|
if (on) {
|
||||||
|
s_app.power = 1;
|
||||||
|
app_cbc2_resume_functions();
|
||||||
|
} else {
|
||||||
|
app_cbc2_pause_functions();
|
||||||
|
s_app.power = 0;
|
||||||
|
}
|
||||||
|
return APP_CBC2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppCbc2_Ret_t app_cbc2_ctrl_play_mode(uint8_t mode)
|
||||||
|
{
|
||||||
|
if (!app_cbc2_ctrl_allowed() || s_app.power == 0) {
|
||||||
|
return APP_CBC2_ERR_DENIED;
|
||||||
|
}
|
||||||
|
if (app_rope_is_calibrating()) {
|
||||||
|
return APP_CBC2_ERR_BUSY;
|
||||||
|
}
|
||||||
|
app_cbc2_apply_play_mode(mode, (uint8_t)(mode != s_app.play_mode));
|
||||||
|
return APP_CBC2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppCbc2_Ret_t app_cbc2_ctrl_hand(uint8_t reserved, uint8_t percent)
|
||||||
|
{
|
||||||
|
(void)reserved;
|
||||||
|
if (!app_cbc2_ctrl_allowed() || s_app.power == 0) {
|
||||||
|
return APP_CBC2_ERR_DENIED;
|
||||||
|
}
|
||||||
|
if (app_rope_is_calibrating()) {
|
||||||
|
return APP_CBC2_ERR_BUSY;
|
||||||
|
}
|
||||||
|
app_cbc2_apply_stop_reset();
|
||||||
|
if (app_rope_goto_percent(percent) != APP_ROPE_OK) {
|
||||||
|
return APP_CBC2_ERR_DENIED;
|
||||||
|
}
|
||||||
|
return APP_CBC2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppCbc2_Ret_t app_cbc2_ctrl_cal(uint8_t on)
|
||||||
|
{
|
||||||
|
if (!app_cbc2_ctrl_allowed() || s_app.power == 0) {
|
||||||
|
return APP_CBC2_ERR_DENIED;
|
||||||
|
}
|
||||||
|
if (on) {
|
||||||
|
app_mode_stop();
|
||||||
|
s_app.play_mode = 0;
|
||||||
|
if (app_rope_cal_start() != APP_ROPE_OK) {
|
||||||
|
return APP_CBC2_ERR_DENIED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
app_rope_cal_stop();
|
||||||
|
}
|
||||||
|
return APP_CBC2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppCbc2_Ret_t app_cbc2_ctrl_turns(uint8_t turns)
|
||||||
|
{
|
||||||
|
if (!app_cbc2_ctrl_allowed()) {
|
||||||
|
return APP_CBC2_ERR_DENIED;
|
||||||
|
}
|
||||||
|
app_rope_set_turns(turns);
|
||||||
|
return APP_CBC2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppCbc2_Ret_t app_cbc2_ctrl_dnd(const uint8_t raw[APP_CBC2_DND_LEN])
|
||||||
|
{
|
||||||
|
if (!raw) {
|
||||||
|
return APP_CBC2_ERR_PARAM;
|
||||||
|
}
|
||||||
|
if (!app_cbc2_ctrl_allowed()) {
|
||||||
|
return APP_CBC2_ERR_DENIED;
|
||||||
|
}
|
||||||
|
app_dnd_set_raw(raw);
|
||||||
|
return APP_CBC2_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @file app_led.c
|
||||||
|
* @brief CBC2 灯效:充电 > 配对 > APP 暂停 > 低电 > 切模式闪 > 开机常亮
|
||||||
|
* @author cyWu <1917507415@qq.com>
|
||||||
|
* @date 2026.08.21
|
||||||
|
* @version V1.0.0
|
||||||
|
* @history
|
||||||
|
* - V1.0.0, 2026.08.21, cyWu, 首次发布
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "app_led.h"
|
||||||
|
#include "bsp_hw.h"
|
||||||
|
#include "board_pin.h"
|
||||||
|
|
||||||
|
static uint8_t s_initialized;
|
||||||
|
static uint16_t s_phase_ms;
|
||||||
|
static uint8_t s_mode_left;
|
||||||
|
static uint16_t s_mode_ms;
|
||||||
|
static uint8_t s_mode_on;
|
||||||
|
static uint16_t s_pair_res_ms;
|
||||||
|
static uint8_t s_pair_res; /* 0 none 1 ok 2 fail */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 灯效初始化,先全灭
|
||||||
|
* @return APP_LED_OK=成功
|
||||||
|
*/
|
||||||
|
AppLed_Ret_t app_led_init(void)
|
||||||
|
{
|
||||||
|
if (s_initialized) {
|
||||||
|
return APP_LED_OK;
|
||||||
|
}
|
||||||
|
bsp_led_all_off();
|
||||||
|
s_initialized = 1;
|
||||||
|
return APP_LED_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询模块是否已初始化
|
||||||
|
* @return APP_LED_OK=已初始化,APP_LED_ERR_NOT_INIT=未初始化
|
||||||
|
*/
|
||||||
|
AppLed_Ret_t app_led_get_status(void)
|
||||||
|
{
|
||||||
|
return s_initialized ? APP_LED_OK : APP_LED_ERR_NOT_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 请求切模式绿灯闪两下
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void app_led_request_mode_blink(void)
|
||||||
|
{
|
||||||
|
s_mode_left = BOARD_LED_MODE_BLINK_N;
|
||||||
|
s_mode_ms = 0;
|
||||||
|
s_mode_on = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 播放一次性配对结果灯:成功常绿,失败红绿交替
|
||||||
|
* @param ok 1=成功,0=失败
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void app_led_start_pair_result(uint8_t ok)
|
||||||
|
{
|
||||||
|
s_pair_res = ok ? 1 : 2;
|
||||||
|
s_pair_res_ms = ok ? BOARD_LED_PAIR_OK_MS : BOARD_LED_PAIR_FAIL_MS;
|
||||||
|
s_phase_ms = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 按优先级刷新灯,1ms 调用
|
||||||
|
* @param ctx 当前充电/配对/开关/低电;为空则直接返回
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void app_led_tick_1ms(const AppLedCtx_t *ctx)
|
||||||
|
{
|
||||||
|
uint8_t red = 0;
|
||||||
|
uint8_t green = 0;
|
||||||
|
|
||||||
|
if (!s_initialized || !ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_phase_ms++;
|
||||||
|
|
||||||
|
/* 1-2 充电独占 */
|
||||||
|
if (ctx->charge_led == 1) {
|
||||||
|
red = 1;
|
||||||
|
green = 0;
|
||||||
|
bsp_led_red_set(1);
|
||||||
|
bsp_led_green_set(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ctx->charge_led == 2) {
|
||||||
|
bsp_led_red_set(0);
|
||||||
|
bsp_led_green_set(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3 配对快闪 */
|
||||||
|
if (ctx->pairing) {
|
||||||
|
uint16_t t = s_phase_ms % (BOARD_LED_FAST_ON_MS + BOARD_LED_FAST_OFF_MS);
|
||||||
|
green = (t < BOARD_LED_FAST_ON_MS) ? 1 : 0;
|
||||||
|
bsp_led_red_set(0);
|
||||||
|
bsp_led_green_set(green);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4 配对结果一次性 */
|
||||||
|
if (s_pair_res && s_pair_res_ms) {
|
||||||
|
if (s_pair_res == 1) {
|
||||||
|
green = 1;
|
||||||
|
} else {
|
||||||
|
uint16_t t = s_phase_ms % (BOARD_LED_ALT_MS * 2);
|
||||||
|
if (t < BOARD_LED_ALT_MS) {
|
||||||
|
red = 1;
|
||||||
|
} else {
|
||||||
|
green = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s_pair_res_ms > 0) {
|
||||||
|
s_pair_res_ms--;
|
||||||
|
if (s_pair_res_ms == 0) {
|
||||||
|
s_pair_res = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bsp_led_red_set(red);
|
||||||
|
bsp_led_green_set(green);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5 APP 暂停:功能灯灭 */
|
||||||
|
if (ctx->life_on && ctx->app_power == 0) {
|
||||||
|
bsp_led_all_off();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 6 低电 */
|
||||||
|
if (ctx->life_on && ctx->low_bat && ctx->app_power) {
|
||||||
|
uint16_t t = s_phase_ms % BOARD_LED_LOWBAT_PERIOD_MS;
|
||||||
|
red = (t < BOARD_LED_LOWBAT_ON_MS) ? 1 : 0;
|
||||||
|
bsp_led_red_set(red);
|
||||||
|
bsp_led_green_set(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 7 切模式闪 2 下 */
|
||||||
|
if (s_mode_left) {
|
||||||
|
s_mode_ms++;
|
||||||
|
if (!s_mode_on) {
|
||||||
|
if (s_mode_ms >= BOARD_LED_MODE_OFF_MS) {
|
||||||
|
s_mode_ms = 0;
|
||||||
|
s_mode_on = 1;
|
||||||
|
}
|
||||||
|
green = 0;
|
||||||
|
} else {
|
||||||
|
if (s_mode_ms >= BOARD_LED_MODE_ON_MS) {
|
||||||
|
s_mode_ms = 0;
|
||||||
|
s_mode_on = 0;
|
||||||
|
s_mode_left--;
|
||||||
|
}
|
||||||
|
green = 1;
|
||||||
|
}
|
||||||
|
bsp_led_red_set(0);
|
||||||
|
bsp_led_green_set(green);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 8 开机绿灯常亮 */
|
||||||
|
if (ctx->life_on && ctx->app_power) {
|
||||||
|
bsp_led_red_set(0);
|
||||||
|
bsp_led_green_set(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bsp_led_all_off();
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @file app_led.h
|
||||||
|
* @brief CBC2 灯效优先级:充电 > 配对 > 软关 > 低电 > 切模式闪 > 绿灯
|
||||||
|
* @author cyWu <1917507415@qq.com>
|
||||||
|
* @date 2026.08.21
|
||||||
|
* @version V1.0.0
|
||||||
|
* @history
|
||||||
|
* - V1.0.0, 2026.08.21, cyWu, 首次发布
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __APP_LED_H__
|
||||||
|
#define __APP_LED_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
APP_LED_OK = 0,
|
||||||
|
APP_LED_ERR_NOT_INIT
|
||||||
|
} AppLed_Ret_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t charge_led; /**< 0=无 1=充电红常亮 2=充满绿常亮 */
|
||||||
|
uint8_t pairing; /**< 1=配对中绿快闪 */
|
||||||
|
uint8_t app_power; /**< DP0,为 0 则功能灯灭 */
|
||||||
|
uint8_t low_bat; /**< 1=低电红闪 */
|
||||||
|
uint8_t life_on; /**< 1=允许显示开机灯效 */
|
||||||
|
} AppLedCtx_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 灯效初始化,先全灭
|
||||||
|
* @return APP_LED_OK=成功
|
||||||
|
*/
|
||||||
|
AppLed_Ret_t app_led_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 1ms 按优先级刷新灯
|
||||||
|
* @param ctx 充电/配对/开关/低电状态,不可为空
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void app_led_tick_1ms(const AppLedCtx_t *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 请求切模式绿灯闪两下
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void app_led_request_mode_blink(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 播放一次性配对结果灯
|
||||||
|
* @param ok 1=成功常绿,0=失败红绿交替
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void app_led_start_pair_result(uint8_t ok);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询是否已初始化
|
||||||
|
* @return APP_LED_OK=已初始化,APP_LED_ERR_NOT_INIT=未初始化
|
||||||
|
*/
|
||||||
|
AppLed_Ret_t app_led_get_status(void);
|
||||||
|
|
||||||
|
#endif /* __APP_LED_H__ */
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @file app_mode.c
|
||||||
|
* @brief 自动模式 1~6:按节拍改方向与 PWM 占空比
|
||||||
|
* @author cyWu <1917507415@qq.com>
|
||||||
|
* @date 2026.08.24
|
||||||
|
* @version V1.2.0
|
||||||
|
* @history
|
||||||
|
* - V1.0.0, 2026.08.21, cyWu, 首次发布
|
||||||
|
* - V1.1.0, 2026.08.24, cyWu, 接入 H 桥往返节拍
|
||||||
|
* - V1.2.0, 2026.08.24, cyWu, 节拍带占空比;六档波形加花样
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "system/includes.h"
|
||||||
|
#include "app_mode.h"
|
||||||
|
#include "bsp_hw.h"
|
||||||
|
|
||||||
|
#define LOG_TAG_CONST APP
|
||||||
|
#define LOG_TAG "[APP_MODE]"
|
||||||
|
#define LOG_INFO_ENABLE
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BspMotorDir_t dir;
|
||||||
|
uint16_t ms;
|
||||||
|
uint16_t duty; /**< 0~10000,STOP 忽略 */
|
||||||
|
} AppModeStep_t;
|
||||||
|
|
||||||
|
#define DUTY_SOFT 3500 /* 轻 */
|
||||||
|
#define DUTY_MID 5500 /* 中 */
|
||||||
|
#define DUTY_RUN 8000 /* 主速度 80% */
|
||||||
|
#define DUTY_PUNCH 9500 /* 猛一下 */
|
||||||
|
|
||||||
|
#define STEP_OUT(ms, duty) { BSP_MOTOR_OUT, (ms), (duty) }
|
||||||
|
#define STEP_IN(ms, duty) { BSP_MOTOR_IN, (ms), (duty) }
|
||||||
|
#define STEP_STOP(ms) { BSP_MOTOR_STOP, (ms), 0 }
|
||||||
|
#define STEP_END { BSP_MOTOR_STOP, 0, 0 }
|
||||||
|
|
||||||
|
/* 节拍以 ms=0 结尾,循环播放。同向连续步进只改占空比,换向才刹车。 */
|
||||||
|
|
||||||
|
static const AppModeStep_t s_mode1[] = { /* 弹力呼吸:慢加速放、慢加速收,最长 2s */
|
||||||
|
STEP_OUT(600, DUTY_MID), STEP_OUT(2000, DUTY_RUN), STEP_OUT(500, DUTY_PUNCH),
|
||||||
|
STEP_STOP(400),
|
||||||
|
STEP_IN(600, DUTY_MID), STEP_IN(2000, DUTY_RUN), STEP_IN(500, DUTY_PUNCH),
|
||||||
|
STEP_STOP(400),
|
||||||
|
STEP_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static const AppModeStep_t s_mode2[] = { /* 飞鸟俯冲:快冲出去,2s 慢慢收回 */
|
||||||
|
STEP_OUT(150, DUTY_PUNCH), STEP_OUT(250, DUTY_RUN),
|
||||||
|
STEP_STOP(150),
|
||||||
|
STEP_IN(2000, DUTY_SOFT), STEP_IN(800, DUTY_MID),
|
||||||
|
STEP_STOP(400),
|
||||||
|
STEP_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static const AppModeStep_t s_mode3[] = { /* 云阶陀螺:短步往返加长,力度一档档加 */
|
||||||
|
STEP_OUT(220, DUTY_SOFT), STEP_IN(220, DUTY_SOFT),
|
||||||
|
STEP_OUT(220, DUTY_MID), STEP_IN(220, DUTY_MID),
|
||||||
|
STEP_OUT(220, DUTY_RUN), STEP_IN(220, DUTY_RUN),
|
||||||
|
STEP_STOP(400),
|
||||||
|
STEP_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static const AppModeStep_t s_mode4[] = { /* 起伏攻防:2s 慢逗再猛收 */
|
||||||
|
STEP_OUT(500, DUTY_SOFT), STEP_OUT(2000, DUTY_MID), STEP_OUT(400, DUTY_RUN),
|
||||||
|
STEP_STOP(250),
|
||||||
|
STEP_IN(180, DUTY_PUNCH), STEP_IN(400, DUTY_MID),
|
||||||
|
STEP_STOP(500),
|
||||||
|
STEP_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static const AppModeStep_t s_mode5[] = { /* 微风拂动:轻点后歇 2s */
|
||||||
|
STEP_OUT(200, DUTY_MID), STEP_STOP(2000),
|
||||||
|
STEP_IN(200, DUTY_MID), STEP_STOP(2000),
|
||||||
|
STEP_OUT(400, DUTY_RUN), STEP_STOP(800),
|
||||||
|
STEP_IN(400, DUTY_RUN), STEP_STOP(1500),
|
||||||
|
STEP_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static const AppModeStep_t s_mode6[] = { /* 闪电快闪:两下轻、两下重,短停防 LVD */
|
||||||
|
STEP_OUT(200, DUTY_MID), STEP_IN(200, DUTY_MID),
|
||||||
|
STEP_OUT(400, DUTY_RUN), STEP_IN(400, DUTY_RUN),
|
||||||
|
STEP_OUT(100, DUTY_PUNCH), STEP_IN(100, DUTY_PUNCH),
|
||||||
|
STEP_OUT(100, DUTY_PUNCH), STEP_IN(100, DUTY_PUNCH),
|
||||||
|
STEP_STOP(300),
|
||||||
|
STEP_END
|
||||||
|
};
|
||||||
|
|
||||||
|
static const AppModeStep_t *const s_tables[7] = {
|
||||||
|
0, s_mode1, s_mode2, s_mode3, s_mode4, s_mode5, s_mode6
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t s_initialized;
|
||||||
|
static uint8_t s_active;
|
||||||
|
static uint8_t s_step;
|
||||||
|
static u32 s_step_t0;
|
||||||
|
|
||||||
|
extern u32 timer_get_ms(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 输出当前节拍的方向与占空比;ms=0 表示表尾,回到第 0 步循环
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void app_mode_apply_step(void)
|
||||||
|
{
|
||||||
|
const AppModeStep_t *tbl = s_tables[s_active];
|
||||||
|
|
||||||
|
if (!tbl) {
|
||||||
|
bsp_motor_set(BSP_MOTOR_STOP);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (tbl[s_step].ms == 0) {
|
||||||
|
s_step = 0;
|
||||||
|
}
|
||||||
|
s_step_t0 = timer_get_ms();
|
||||||
|
if (tbl[s_step].dir == BSP_MOTOR_STOP) {
|
||||||
|
bsp_motor_set(BSP_MOTOR_STOP);
|
||||||
|
} else {
|
||||||
|
bsp_motor_set_pwm(tbl[s_step].dir, tbl[s_step].duty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 玩法初始化,电机停
|
||||||
|
* @return APP_MODE_OK=成功
|
||||||
|
*/
|
||||||
|
AppMode_Ret_t app_mode_init(void)
|
||||||
|
{
|
||||||
|
s_active = 0;
|
||||||
|
s_step = 0;
|
||||||
|
s_step_t0 = timer_get_ms();
|
||||||
|
s_initialized = 1;
|
||||||
|
bsp_motor_set(BSP_MOTOR_STOP);
|
||||||
|
return APP_MODE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询模块是否已初始化
|
||||||
|
* @return APP_MODE_OK=已初始化,APP_MODE_ERR_NOT_INIT=未初始化
|
||||||
|
*/
|
||||||
|
AppMode_Ret_t app_mode_get_status(void)
|
||||||
|
{
|
||||||
|
return s_initialized ? APP_MODE_OK : APP_MODE_ERR_NOT_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取当前自动模式
|
||||||
|
* @return 0=停转,1~6=对应玩法
|
||||||
|
*/
|
||||||
|
uint8_t app_mode_get_active(void)
|
||||||
|
{
|
||||||
|
return s_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 启动自动模式 1~6,按节拍表循环
|
||||||
|
* @param mode 玩法编号,范围 1~6
|
||||||
|
* @return APP_MODE_OK=成功,APP_MODE_ERR_NOT_INIT=未初始化,APP_MODE_ERR_PARAM=参数非法
|
||||||
|
*/
|
||||||
|
AppMode_Ret_t app_mode_start(uint8_t mode)
|
||||||
|
{
|
||||||
|
if (!s_initialized) {
|
||||||
|
return APP_MODE_ERR_NOT_INIT;
|
||||||
|
}
|
||||||
|
if (mode < 1 || mode > 6) {
|
||||||
|
app_mode_stop();
|
||||||
|
return APP_MODE_ERR_PARAM;
|
||||||
|
}
|
||||||
|
s_active = mode;
|
||||||
|
s_step = 0;
|
||||||
|
app_mode_apply_step();
|
||||||
|
log_info("auto mode %d start\n", mode);
|
||||||
|
return APP_MODE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 停止当前玩法并刹车
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void app_mode_stop(void)
|
||||||
|
{
|
||||||
|
if (s_active) {
|
||||||
|
log_info("auto mode %d stop\n", s_active);
|
||||||
|
}
|
||||||
|
s_active = 0;
|
||||||
|
s_step = 0;
|
||||||
|
s_step_t0 = timer_get_ms();
|
||||||
|
bsp_motor_set(BSP_MOTOR_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 推进当前节拍(按 timer_get_ms 真实时间)
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void app_mode_run(void)
|
||||||
|
{
|
||||||
|
const AppModeStep_t *tbl;
|
||||||
|
|
||||||
|
bsp_motor_brake_tick();
|
||||||
|
if (!s_initialized || s_active == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbl = s_tables[s_active];
|
||||||
|
if (!tbl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((timer_get_ms() - s_step_t0) >= tbl[s_step].ms) {
|
||||||
|
s_step++;
|
||||||
|
app_mode_apply_step();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @file app_mode.h
|
||||||
|
* @brief 6 种自动玩法:节拍含方向与 PWM 占空比(0=停,1~6=波形)
|
||||||
|
* @author cyWu <1917507415@qq.com>
|
||||||
|
* @date 2026.08.24
|
||||||
|
* @version V1.2.0
|
||||||
|
* @history
|
||||||
|
* - V1.0.0, 2026.08.21, cyWu, 首次发布
|
||||||
|
* - V1.1.0, 2026.08.24, cyWu, 接入 H 桥往返节拍
|
||||||
|
* - V1.2.0, 2026.08.24, cyWu, 节拍带占空比;六档波形加花样
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __APP_MODE_H__
|
||||||
|
#define __APP_MODE_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
APP_MODE_OK = 0,
|
||||||
|
APP_MODE_ERR_PARAM,
|
||||||
|
APP_MODE_ERR_NOT_INIT
|
||||||
|
} AppMode_Ret_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化,电机停
|
||||||
|
* @return APP_MODE_OK=成功
|
||||||
|
*/
|
||||||
|
AppMode_Ret_t app_mode_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 启动自动模式 1~6,循环播放节拍
|
||||||
|
* @param mode 玩法编号,范围 1~6
|
||||||
|
* @return APP_MODE_OK=成功,APP_MODE_ERR_NOT_INIT=未初始化,APP_MODE_ERR_PARAM=参数非法
|
||||||
|
*/
|
||||||
|
AppMode_Ret_t app_mode_start(uint8_t mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 停止玩法并刹车
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void app_mode_stop(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 推进当前节拍(按真实毫秒,不依赖回调是否刚好 1ms)
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void app_mode_run(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取当前自动模式
|
||||||
|
* @return 0=停转,1~6=对应玩法
|
||||||
|
*/
|
||||||
|
uint8_t app_mode_get_active(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询是否已初始化
|
||||||
|
* @return APP_MODE_OK=已初始化,APP_MODE_ERR_NOT_INIT=未初始化
|
||||||
|
*/
|
||||||
|
AppMode_Ret_t app_mode_get_status(void);
|
||||||
|
|
||||||
|
#endif /* __APP_MODE_H__ */
|
||||||
@@ -127,7 +127,11 @@ int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
|
|||||||
/* ── DP2 手动模式 (raw) ── */
|
/* ── DP2 手动模式 (raw) ── */
|
||||||
case DP_ID_HAND_MODE:
|
case DP_ID_HAND_MODE:
|
||||||
memcpy(gDevData.hand_mode, ctrl->hand_mode, 2);
|
memcpy(gDevData.hand_mode, ctrl->hand_mode, 2);
|
||||||
// TODO: 根据 gDevData.hand_mode 执行动作 (长度 2 字节)
|
/* 薄适配:通知业务层;03=停,00=空闲 */
|
||||||
|
{
|
||||||
|
extern void usr_dp_hand_write(uint8_t cmd);
|
||||||
|
usr_dp_hand_write(ctrl->hand_mode[0]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ── DP3 绳索校准 (bool) ── */
|
/* ── DP3 绳索校准 (bool) ── */
|
||||||
|
|||||||
+785
-10
@@ -1,16 +1,43 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @file usr_jb_main.c
|
||||||
|
* @brief CBC2 业务主循环:按键 / 充电 / 电量 / 灯 / 6 档玩法 / 手动点动
|
||||||
|
* @author cyWu <1917507415@qq.com>
|
||||||
|
* @date 2026.08.24
|
||||||
|
* @version V1.3.0
|
||||||
|
* @history
|
||||||
|
* - V1.0.0, 2026.08.21, cyWu, 首次发布
|
||||||
|
* - V1.1.0, 2026.08.24, cyWu, 收口未接线模块;DP2 仅第 1 字节点动 1s
|
||||||
|
* - V1.2.0, 2026.08.24, cyWu, 按键:深睡 3s 开机、5s 开机+配对;开机中 3s 深睡
|
||||||
|
* - V1.3.0, 2026.08.24, cyWu, DP2:00=空闲,01/02 转,03 停
|
||||||
|
*
|
||||||
|
* @note 协议生成文件 jb_product.c 不要填业务。APP 下行写 gDevData,
|
||||||
|
* 本文件 1ms 轮询执行。usr_timer_loop 由 BLE 库回调,勿再注册第二份。
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
#include "system/includes.h"
|
#include "system/includes.h"
|
||||||
#include "app_config.h"
|
#include "app_config.h"
|
||||||
#include "app_main.h"
|
#include "app_main.h"
|
||||||
#include "app_task.h"
|
#include "app_task.h"
|
||||||
#include "user_cfg.h"
|
#include "user_cfg.h"
|
||||||
#include "vm.h"
|
|
||||||
#include "sys_time.h"
|
|
||||||
|
|
||||||
#include "jb_protocol.h"
|
#include "jb_protocol.h"
|
||||||
#include "jb_product.h"
|
#include "jb_product.h"
|
||||||
#include "jb_ringbuffer.h"
|
#include "jb_ringbuffer.h"
|
||||||
#include "jb_common.h"
|
#include "jb_common.h"
|
||||||
#include "usr_le_product.h"
|
#include "usr_le_product.h"
|
||||||
|
#include "usr_le_api.h"
|
||||||
|
#include "bsp_hw.h"
|
||||||
|
#include "app_led.h"
|
||||||
|
#include "app_mode.h"
|
||||||
|
#include "ui_manage.h"
|
||||||
|
#include "asm/power/power_api.h"
|
||||||
|
#include "asm/power/power_reset.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define LOG_TAG_CONST APP
|
||||||
|
#define LOG_TAG "[USR_JB]"
|
||||||
|
#define LOG_INFO_ENABLE
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
/* 向 usr_le_code 库提供产品身份(换产品只改 jb_protocol.h 宏即可) */
|
/* 向 usr_le_code 库提供产品身份(换产品只改 jb_protocol.h 宏即可) */
|
||||||
const uint8_t g_usr_le_prodcode[USR_LE_PRODCODE_LEN] = {
|
const uint8_t g_usr_le_prodcode[USR_LE_PRODCODE_LEN] = {
|
||||||
@@ -22,27 +49,775 @@ const uint8_t g_usr_le_pcode[USR_LE_PCODE_LEN] = {
|
|||||||
JB_PRODUCT_CODE[3], JB_PRODUCT_CODE[4], JB_PRODUCT_CODE[5]
|
JB_PRODUCT_CODE[3], JB_PRODUCT_CODE[4], JB_PRODUCT_CODE[5]
|
||||||
};
|
};
|
||||||
|
|
||||||
void usr_timer_1_ms();
|
static void usr_timer_1_ms(void *priv);
|
||||||
static int jb_timer_id=0;
|
void usr_timer_loop(void);
|
||||||
|
extern void clr_wdt(void);
|
||||||
|
extern u32 timer_get_ms(void);
|
||||||
|
|
||||||
void usr_jb_init()
|
static int jb_timer_id;
|
||||||
|
static uint8_t s_pairing; /**< 1=深睡 5s 进入配对中 */
|
||||||
|
static uint8_t s_play_mode; /**< 当前自动模式 0~6 */
|
||||||
|
static uint8_t s_key_raw;
|
||||||
|
static uint8_t s_key_cnt;
|
||||||
|
static uint8_t s_key_pressed;
|
||||||
|
static uint8_t s_boot_key_lock; /**< 上电按着键,松开前不当短按 */
|
||||||
|
static uint16_t s_key_hold_ms;
|
||||||
|
static uint16_t s_key_led_override_ms; /**< 切模式闪灯期间不显示配对快闪 */
|
||||||
|
static uint8_t s_req_poweroff;
|
||||||
|
static uint8_t s_usb_online;
|
||||||
|
static uint8_t s_charge_led; /**< 0=无 1=充电红 2=充满绿 */
|
||||||
|
static uint8_t s_charge_led_last;
|
||||||
|
static uint16_t s_full_ms;
|
||||||
|
static uint8_t s_app_power; /**< DP0:0=软关,电机/玩法停,BLE 仍在 */
|
||||||
|
static uint16_t s_bat_tick;
|
||||||
|
static uint16_t s_bat_acc;
|
||||||
|
static uint8_t s_bat_n;
|
||||||
|
static uint16_t s_bat_mv;
|
||||||
|
static uint8_t s_bat_pct;
|
||||||
|
static uint8_t s_low_bat;
|
||||||
|
static uint32_t s_low_ms;
|
||||||
|
static uint8_t s_empty_win;
|
||||||
|
static uint8_t s_low_enter_win;
|
||||||
|
static uint8_t s_low_exit_win;
|
||||||
|
static uint16_t s_bat_boot_ms;
|
||||||
|
static uint16_t s_bat_log_ms;
|
||||||
|
static uint8_t s_hand_busy; /**< 手动点动进行中 */
|
||||||
|
static uint8_t s_hand_cmd_last; /**< 边沿:同一 1/2 不重复启动 */
|
||||||
|
static uint16_t s_hand_ms;
|
||||||
|
static volatile uint8_t s_hand_write_pending; /**< DP2 刚写入(03 停转要靠事件) */
|
||||||
|
static volatile uint8_t s_hand_write_cmd;
|
||||||
|
static uint32_t s_pair_ms; /**< 配对已持续 ms,满 60s 判失败 */
|
||||||
|
|
||||||
|
#define BAT_SAMPLE_MS 100
|
||||||
|
#define BAT_AVG_N 8
|
||||||
|
#define BAT_BOOT_MS 3000 /* 上电 3s 内不因低电深睡 */
|
||||||
|
#define BAT_LOG_MS 10000
|
||||||
|
#define BAT_LOW_WIN 3 /* 连续约 2.4s 才进低电告警 */
|
||||||
|
#define BAT_EMPTY_WIN 5 /* 连续约 4s 才 3.2V 深睡 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 忙等若干毫秒,并喂狗
|
||||||
|
* @param ms 等待时长
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_boot_delay_ms(uint32_t ms)
|
||||||
|
{
|
||||||
|
uint32_t t0 = timer_get_ms();
|
||||||
|
|
||||||
|
while ((timer_get_ms() - t0) < ms) {
|
||||||
|
clr_wdt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief BLE 起来前进深睡(1ms 定时器尚未启动)
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_boot_sleep(void)
|
||||||
|
{
|
||||||
|
log_info("boot sleep\n");
|
||||||
|
bsp_hw_enter_sleep_io();
|
||||||
|
power_set_soft_poweroff();
|
||||||
|
while (1) {
|
||||||
|
clr_wdt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 上电是否跳过 3s/5s 按键判定
|
||||||
|
* @return 1=USB / 软复位 / LVD / 看门狗,保持开机且不进配对
|
||||||
|
*/
|
||||||
|
static uint8_t usr_boot_skip_key_wait(void)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
if (bsp_chg_is_low() || bsp_vpwr_is_online()) {
|
||||||
|
log_info("boot usb, skip key wait\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
usr_boot_delay_ms(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu_reset_by_soft()
|
||||||
|
|| is_reset_source(MSYS_SOFT_RST)
|
||||||
|
|| is_reset_source(P33_SOFT_RST)
|
||||||
|
|| is_reset_source(P33_VDDIO_LVD_RST)
|
||||||
|
|| is_reset_source(P11_WDT_RST)) {
|
||||||
|
log_info("boot reset-keep, skip key wait\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 深睡唤醒/上电:长按 3s 开机,长按 5s 开机并配对;不足 3s 松手再睡
|
||||||
|
* @note 必须在 BLE 起来之前调用。配对只置 usr_goto_pair,不调用 usr_goto_pair_mode
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_boot_key_wait(void)
|
||||||
|
{
|
||||||
|
uint32_t t0;
|
||||||
|
uint32_t elapsed;
|
||||||
|
uint8_t green_on = 0;
|
||||||
|
|
||||||
|
usr_var.usr_goto_pair = 0;
|
||||||
|
s_pairing = 0;
|
||||||
|
s_pair_ms = 0;
|
||||||
|
|
||||||
|
if (usr_boot_skip_key_wait()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bsp_key_is_pressed()) {
|
||||||
|
log_info("boot no key, sleep\n");
|
||||||
|
usr_boot_sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
t0 = timer_get_ms();
|
||||||
|
bsp_led_all_off();
|
||||||
|
log_info("boot key hold, wait 3s on / 5s pair\n");
|
||||||
|
|
||||||
|
while (bsp_key_is_pressed()) {
|
||||||
|
elapsed = timer_get_ms() - t0;
|
||||||
|
clr_wdt();
|
||||||
|
|
||||||
|
if (elapsed >= BOARD_KEY_PAIR_MS) {
|
||||||
|
usr_var.usr_goto_pair = 1;
|
||||||
|
usr_clear_pair_info_noreset();
|
||||||
|
s_pairing = 1;
|
||||||
|
s_pair_ms = 0;
|
||||||
|
log_info("boot hold %ums, power on + pair\n", (unsigned)elapsed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!green_on && (elapsed >= BOARD_KEY_POWER_MS)) {
|
||||||
|
green_on = 1;
|
||||||
|
bsp_led_green_set(1);
|
||||||
|
log_info("boot hold 3s, will power on\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elapsed = timer_get_ms() - t0;
|
||||||
|
if (elapsed < BOARD_KEY_POWER_MS) {
|
||||||
|
log_info("boot hold %ums < 3s, sleep\n", (unsigned)elapsed);
|
||||||
|
usr_boot_sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("boot hold %ums, power on\n", (unsigned)elapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 停手动点动(走电机反转刹车)
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_hand_stop(void)
|
||||||
|
{
|
||||||
|
s_hand_busy = 0;
|
||||||
|
s_hand_ms = 0;
|
||||||
|
bsp_motor_set(BSP_MOTOR_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 停手动 + 自动模式,并清 DP1
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_motor_all_stop(void)
|
||||||
|
{
|
||||||
|
s_play_mode = 0;
|
||||||
|
gDevData.play_mode = 0;
|
||||||
|
app_mode_stop();
|
||||||
|
usr_hand_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief DP2 写入钩子(jb_product 薄适配调用,不在此驱电机)
|
||||||
|
* @param cmd 第 1 字节:0=空闲,1=顺时针,2=逆时针,3=停
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void usr_dp_hand_write(uint8_t cmd)
|
||||||
|
{
|
||||||
|
s_hand_write_cmd = cmd;
|
||||||
|
s_hand_write_pending = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 软关:电机停、DP0=0,等 APP/短按再开。不断 BLE
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_app_soft_off(void)
|
||||||
|
{
|
||||||
|
s_app_power = 0;
|
||||||
|
gDevData.power = 0;
|
||||||
|
s_play_mode = 0;
|
||||||
|
gDevData.play_mode = 0;
|
||||||
|
app_mode_stop();
|
||||||
|
usr_hand_stop();
|
||||||
|
log_info("soft off, wait APP power on\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 切换自动模式 0~6
|
||||||
|
* @param mode 0=停转,1~6=对应玩法
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_play_mode_apply(uint8_t mode)
|
||||||
|
{
|
||||||
|
if (mode > 6) {
|
||||||
|
mode = 0;
|
||||||
|
}
|
||||||
|
if (s_usb_online || !s_app_power || s_req_poweroff || s_hand_busy || s_pairing) {
|
||||||
|
mode = 0;
|
||||||
|
}
|
||||||
|
s_play_mode = mode;
|
||||||
|
gDevData.play_mode = mode;
|
||||||
|
if (mode == 0) {
|
||||||
|
app_mode_stop();
|
||||||
|
} else {
|
||||||
|
app_mode_start(mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 跟随 APP 下发的 DP1 自动模式
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_play_mode_poll(void)
|
||||||
|
{
|
||||||
|
uint8_t mode;
|
||||||
|
|
||||||
|
if (s_usb_online || !s_app_power || s_req_poweroff || s_hand_busy || s_pairing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mode = gDevData.play_mode;
|
||||||
|
if (mode > 6) {
|
||||||
|
mode = 0;
|
||||||
|
gDevData.play_mode = 0;
|
||||||
|
}
|
||||||
|
if (mode == s_play_mode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usr_play_mode_apply(mode);
|
||||||
|
log_info("APP play_mode=%d\n", mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 跟随 APP 下发的 DP0 开关
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_app_power_poll(void)
|
||||||
|
{
|
||||||
|
if (s_usb_online || s_req_poweroff) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (gDevData.power && !s_app_power) {
|
||||||
|
s_app_power = 1;
|
||||||
|
log_info("APP power on\n");
|
||||||
|
} else if (!gDevData.power && s_app_power) {
|
||||||
|
usr_app_soft_off();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief DP2 手动:只看第 1 字节。0=空闲,1=顺时针,2=逆时针,3=停
|
||||||
|
* @note 00 00 是 DP 默认值,不当停止。百分比/力度、DP3、DP4 预留不接。
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_hand_poll(void)
|
||||||
|
{
|
||||||
|
uint8_t cmd;
|
||||||
|
uint8_t got_write = s_hand_write_pending;
|
||||||
|
|
||||||
|
if (got_write) {
|
||||||
|
s_hand_write_pending = 0;
|
||||||
|
cmd = s_hand_write_cmd;
|
||||||
|
} else {
|
||||||
|
cmd = gDevData.hand_mode[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_usb_online || !s_app_power || s_req_poweroff || s_pairing) {
|
||||||
|
if (s_hand_busy || (got_write && (cmd == 3))) {
|
||||||
|
usr_motor_all_stop();
|
||||||
|
}
|
||||||
|
s_hand_cmd_last = cmd;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd == 0) {
|
||||||
|
s_hand_cmd_last = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd == 3) {
|
||||||
|
if (got_write || s_hand_busy || app_mode_get_active()) {
|
||||||
|
usr_motor_all_stop();
|
||||||
|
log_info("hand stop cmd=3\n");
|
||||||
|
}
|
||||||
|
s_hand_cmd_last = 3;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cmd == 1 || cmd == 2) && (got_write || (cmd != s_hand_cmd_last))) {
|
||||||
|
s_play_mode = 0;
|
||||||
|
gDevData.play_mode = 0;
|
||||||
|
app_mode_stop();
|
||||||
|
s_hand_busy = 1;
|
||||||
|
s_hand_ms = 0;
|
||||||
|
/* 1=顺时针收绳,2=逆时针放绳(BOARD_MOTOR_IN_INA_HIGH=1) */
|
||||||
|
bsp_motor_set((cmd == 1) ? BSP_MOTOR_IN : BSP_MOTOR_OUT);
|
||||||
|
log_info("hand cmd=%d %s until 03\n", cmd,
|
||||||
|
(cmd == 1) ? "cw" : "ccw");
|
||||||
|
}
|
||||||
|
s_hand_cmd_last = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 手动运行时推进刹车;停转改由 DP2 写 03
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_hand_tick_1ms(void)
|
||||||
|
{
|
||||||
|
if (!s_hand_busy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bsp_motor_brake_tick();
|
||||||
|
if (s_hand_ms < 0xffff) {
|
||||||
|
s_hand_ms++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 深睡入口(须在 1ms 高优定时器之外调用)
|
||||||
|
* @param priv 未使用
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_do_poweroff(void *priv)
|
||||||
|
{
|
||||||
|
(void)priv;
|
||||||
|
log_info("enter deep off\n");
|
||||||
|
app_mode_stop();
|
||||||
|
usr_hand_stop();
|
||||||
|
bsp_hw_enter_sleep_io();
|
||||||
|
sys_enter_soft_poweroff(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 请求深睡:先停电机,50ms 后真正关机
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_key_request_poweroff(void)
|
||||||
|
{
|
||||||
|
if (s_req_poweroff) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s_req_poweroff = 1;
|
||||||
|
log_info("request deep off\n");
|
||||||
|
app_mode_stop();
|
||||||
|
usr_hand_stop();
|
||||||
|
bsp_led_all_off();
|
||||||
|
sys_timeout_add(NULL, usr_do_poweroff, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 电压换算电量:4.2V=100%,3.2V=0%
|
||||||
|
* @param mv 电池电压,单位 mV
|
||||||
|
* @return 电量百分比,范围 0~100
|
||||||
|
*/
|
||||||
|
static uint8_t usr_bat_percent(uint16_t mv)
|
||||||
|
{
|
||||||
|
int32_t span = (int32_t)BOARD_VBAT_FULL_MV - (int32_t)BOARD_VBAT_EMPTY_MV;
|
||||||
|
int32_t pct;
|
||||||
|
|
||||||
|
if (mv <= BOARD_VBAT_EMPTY_MV) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (mv >= BOARD_VBAT_FULL_MV) {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
pct = ((int32_t)mv - BOARD_VBAT_EMPTY_MV) * 100 / span;
|
||||||
|
if (pct < 0) {
|
||||||
|
pct = 0;
|
||||||
|
}
|
||||||
|
if (pct > 100) {
|
||||||
|
pct = 100;
|
||||||
|
}
|
||||||
|
return (uint8_t)pct;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 电量采样与低电策略
|
||||||
|
* @note 电机运转时只记电压、不改百分比/告警,避免电流拉垮 VBAT 误报
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_bat_tick_1ms(void)
|
||||||
|
{
|
||||||
|
uint16_t mv;
|
||||||
|
uint8_t pct;
|
||||||
|
uint8_t motor_busy;
|
||||||
|
|
||||||
|
if (s_bat_boot_ms < BAT_BOOT_MS) {
|
||||||
|
s_bat_boot_ms++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++s_bat_tick >= BAT_SAMPLE_MS) {
|
||||||
|
s_bat_tick = 0;
|
||||||
|
s_bat_acc += bsp_vbat_mv();
|
||||||
|
s_bat_n++;
|
||||||
|
if (s_bat_n >= BAT_AVG_N) {
|
||||||
|
mv = (uint16_t)(s_bat_acc / s_bat_n);
|
||||||
|
s_bat_acc = 0;
|
||||||
|
s_bat_n = 0;
|
||||||
|
s_bat_mv = mv;
|
||||||
|
motor_busy = (uint8_t)(app_mode_get_active() != 0 || s_hand_busy);
|
||||||
|
|
||||||
|
if (!motor_busy) {
|
||||||
|
pct = usr_bat_percent(mv);
|
||||||
|
if (pct != s_bat_pct) {
|
||||||
|
s_bat_pct = pct;
|
||||||
|
gDevData.battery = pct;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_bat_boot_ms >= BAT_BOOT_MS) {
|
||||||
|
if (!s_usb_online && mv <= BOARD_VBAT_EMPTY_MV) {
|
||||||
|
if (s_empty_win < 0xFF) {
|
||||||
|
s_empty_win++;
|
||||||
|
}
|
||||||
|
if (s_empty_win >= BAT_EMPTY_WIN) {
|
||||||
|
s_low_bat = 1;
|
||||||
|
gDevData.alm_low_battery = 1;
|
||||||
|
if (!s_req_poweroff) {
|
||||||
|
log_info("vbat %dmV empty, deep off\n", mv);
|
||||||
|
usr_key_request_poweroff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s_empty_win = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mv < BOARD_VBAT_LOW_MV) {
|
||||||
|
s_low_exit_win = 0;
|
||||||
|
if (!s_low_bat && s_low_enter_win < 0xFF) {
|
||||||
|
s_low_enter_win++;
|
||||||
|
if (s_low_enter_win >= BAT_LOW_WIN) {
|
||||||
|
s_low_bat = 1;
|
||||||
|
s_low_ms = 0;
|
||||||
|
gDevData.alm_low_battery = 1;
|
||||||
|
log_info("low battery %dmV %d%%\n", mv, s_bat_pct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (mv > (BOARD_VBAT_LOW_MV + BOARD_VBAT_LOW_HYST_MV)) {
|
||||||
|
s_low_enter_win = 0;
|
||||||
|
if (s_low_bat) {
|
||||||
|
if (s_low_exit_win < 0xFF) {
|
||||||
|
s_low_exit_win++;
|
||||||
|
}
|
||||||
|
if (s_low_exit_win >= BAT_LOW_WIN) {
|
||||||
|
s_low_bat = 0;
|
||||||
|
s_low_ms = 0;
|
||||||
|
gDevData.alm_low_battery = 0;
|
||||||
|
log_info("battery recover %dmV %d%%\n", mv, s_bat_pct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s_low_enter_win = 0;
|
||||||
|
s_low_exit_win = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_usb_online || s_req_poweroff || (s_bat_boot_ms < BAT_BOOT_MS)) {
|
||||||
|
s_low_ms = 0;
|
||||||
|
} else if (s_low_bat && (s_low_ms < BOARD_LOWBAT_SLEEP_MS)) {
|
||||||
|
s_low_ms++;
|
||||||
|
if (s_low_ms == BOARD_LOWBAT_SLEEP_MS) {
|
||||||
|
log_info("low battery 1min, deep off\n");
|
||||||
|
usr_key_request_poweroff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++s_bat_log_ms >= BAT_LOG_MS) {
|
||||||
|
s_bat_log_ms = 0;
|
||||||
|
log_info("bat %d%% %dmV alm=%d\n", s_bat_pct, s_bat_mv, s_low_bat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 短按:自动模式 0→1→…→6→0
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_key_on_click(void)
|
||||||
|
{
|
||||||
|
if (s_hand_busy) {
|
||||||
|
log_info("key click ignored, hand busy\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usr_play_mode_apply((uint8_t)((s_play_mode + 1) % 7));
|
||||||
|
app_led_request_mode_blink();
|
||||||
|
s_key_led_override_ms = (uint16_t)((BOARD_LED_MODE_OFF_MS + BOARD_LED_MODE_ON_MS)
|
||||||
|
* BOARD_LED_MODE_BLINK_N + 50);
|
||||||
|
log_info("key click play_mode=%d\n", s_play_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 按键状态初值
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_key_init(void)
|
||||||
|
{
|
||||||
|
s_play_mode = 0;
|
||||||
|
s_boot_key_lock = bsp_key_is_pressed() ? 1 : 0;
|
||||||
|
s_key_pressed = s_boot_key_lock;
|
||||||
|
s_key_raw = s_key_pressed;
|
||||||
|
s_key_cnt = BOARD_KEY_DEBOUNCE_MS;
|
||||||
|
s_key_hold_ms = 0;
|
||||||
|
if (s_boot_key_lock) {
|
||||||
|
log_info("boot key held, wait release\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 按键消抖:开机后 1s 内短按切模式,按住 3s 深睡;充电时忽略
|
||||||
|
* @note 开机中即使按满 5s 也不进配对。配对只在深睡长按 5s、BLE 起来前判定
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_key_tick_1ms(void)
|
||||||
|
{
|
||||||
|
uint8_t raw;
|
||||||
|
|
||||||
|
if (s_req_poweroff) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw = bsp_key_is_pressed();
|
||||||
|
|
||||||
|
if (raw == s_key_raw) {
|
||||||
|
if (s_key_cnt < BOARD_KEY_DEBOUNCE_MS) {
|
||||||
|
s_key_cnt++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s_key_raw = raw;
|
||||||
|
s_key_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_key_cnt != BOARD_KEY_DEBOUNCE_MS) {
|
||||||
|
if (s_key_pressed && !s_boot_key_lock) {
|
||||||
|
s_key_hold_ms++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw && !s_key_pressed) {
|
||||||
|
s_key_pressed = 1;
|
||||||
|
s_key_hold_ms = 0;
|
||||||
|
} else if (!raw && s_key_pressed) {
|
||||||
|
if (s_boot_key_lock) {
|
||||||
|
s_boot_key_lock = 0;
|
||||||
|
log_info("boot key released\n");
|
||||||
|
} else if (s_key_hold_ms < BOARD_KEY_CLICK_MS && s_key_hold_ms >= 10) {
|
||||||
|
if (s_usb_online) {
|
||||||
|
log_info("key click ignored, charging\n");
|
||||||
|
} else if (s_pairing) {
|
||||||
|
log_info("key click ignored, pairing\n");
|
||||||
|
} else if (!s_app_power) {
|
||||||
|
s_app_power = 1;
|
||||||
|
gDevData.power = 1;
|
||||||
|
log_info("key click cancel soft off\n");
|
||||||
|
} else {
|
||||||
|
usr_key_on_click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s_key_pressed = 0;
|
||||||
|
s_key_hold_ms = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_key_pressed && !s_boot_key_lock) {
|
||||||
|
s_key_hold_ms++;
|
||||||
|
if (s_key_hold_ms == BOARD_KEY_POWER_MS) {
|
||||||
|
if (s_usb_online) {
|
||||||
|
log_info("key hold 3s ignored, charging\n");
|
||||||
|
} else if (s_pairing) {
|
||||||
|
log_info("key hold 3s ignored, pairing\n");
|
||||||
|
} else {
|
||||||
|
log_info("key hold 3s, poweroff\n");
|
||||||
|
usr_key_request_poweroff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 充电检测:CHG 低=充电中;VPWR 在且 CHG 高满 1s=充满;拔电软关
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_chg_tick_1ms(void)
|
||||||
|
{
|
||||||
|
uint8_t chg_low = bsp_chg_is_low();
|
||||||
|
uint8_t vpwr = bsp_vpwr_is_online();
|
||||||
|
uint8_t usb;
|
||||||
|
|
||||||
|
if (chg_low) {
|
||||||
|
s_full_ms = 0;
|
||||||
|
s_charge_led = 1;
|
||||||
|
gDevData.charge = CHARGE_1;
|
||||||
|
usb = 1;
|
||||||
|
} else if (vpwr) {
|
||||||
|
/* 拔电时 CHG 先变高、VPWR 还没掉,不能立刻当充满 */
|
||||||
|
if (s_full_ms < 0xFFFF) {
|
||||||
|
s_full_ms++;
|
||||||
|
}
|
||||||
|
if (s_full_ms >= BOARD_CHG_FULL_MS) {
|
||||||
|
s_charge_led = 2;
|
||||||
|
}
|
||||||
|
gDevData.charge = (s_charge_led == 1) ? CHARGE_1 : CHARGE_2;
|
||||||
|
usb = 1;
|
||||||
|
} else {
|
||||||
|
s_full_ms = 0;
|
||||||
|
s_charge_led = 0;
|
||||||
|
gDevData.charge = CHARGE_2;
|
||||||
|
usb = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usb != s_usb_online) {
|
||||||
|
s_usb_online = usb;
|
||||||
|
log_info("usb %s vpwr=%d chg=%d mv=%d pair=%d goto=%d\n",
|
||||||
|
usb ? "in" : "out", vpwr, chg_low, bsp_vpwr_mv(),
|
||||||
|
usr_get_pair_flag(), usr_var.usr_goto_pair);
|
||||||
|
if (usb) {
|
||||||
|
app_mode_stop();
|
||||||
|
usr_hand_stop();
|
||||||
|
s_play_mode = 0;
|
||||||
|
gDevData.play_mode = 0;
|
||||||
|
log_info("usb in, motor stop\n");
|
||||||
|
} else {
|
||||||
|
ui_update_status(STATUS_NORMAL_POWER);
|
||||||
|
usr_app_soft_off();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_var.usr_power_charge_flag = s_usb_online ? 1 : 2;
|
||||||
|
|
||||||
|
if (s_charge_led != s_charge_led_last) {
|
||||||
|
s_charge_led_last = s_charge_led;
|
||||||
|
log_info("charge_led=%d chg=%d vpwr=%d mv=%d\n",
|
||||||
|
s_charge_led, chg_low, vpwr, bsp_vpwr_mv());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 组装灯效上下文:充电 > 配对 > 软关灭灯 > 低电 > 切模式闪 > 绿灯
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_led_tick_1ms(void)
|
||||||
|
{
|
||||||
|
AppLedCtx_t led;
|
||||||
|
uint8_t paired;
|
||||||
|
|
||||||
|
if (s_req_poweroff) {
|
||||||
|
bsp_led_all_off();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
paired = usr_get_pair_flag();
|
||||||
|
|
||||||
|
if (s_pairing) {
|
||||||
|
if (paired) {
|
||||||
|
app_led_start_pair_result(1);
|
||||||
|
s_pairing = 0;
|
||||||
|
s_pair_ms = 0;
|
||||||
|
log_info("pair ok\n");
|
||||||
|
} else if (++s_pair_ms >= BOARD_PAIR_TIMEOUT_MS) {
|
||||||
|
s_pairing = 0;
|
||||||
|
s_pair_ms = 0;
|
||||||
|
app_led_start_pair_result(0);
|
||||||
|
log_info("pair timeout 60s, stay on\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_key_led_override_ms) {
|
||||||
|
s_key_led_override_ms--;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&led, 0, sizeof(led));
|
||||||
|
led.charge_led = s_charge_led;
|
||||||
|
led.pairing = (uint8_t)(s_pairing && s_app_power && (s_key_led_override_ms == 0));
|
||||||
|
led.app_power = s_app_power;
|
||||||
|
led.low_bat = s_low_bat;
|
||||||
|
led.life_on = 1;
|
||||||
|
app_led_tick_1ms(&led);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 业务初始化(在 BLE 栈起来之前由 app_main 调用)
|
||||||
|
* @note 内部会等按键 3s/5s;不足 3s 直接深睡,不会启动 1ms 定时器
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void usr_jb_init(void)
|
||||||
{
|
{
|
||||||
jbInit();
|
jbInit();
|
||||||
userInit();
|
userInit();
|
||||||
if(jb_timer_id==0)jb_timer_id = sys_s_hi_timer_add(NULL, usr_timer_1_ms, TIMER_PERIOD_MS);
|
bsp_hw_init();
|
||||||
|
app_led_init();
|
||||||
|
app_mode_init();
|
||||||
|
|
||||||
|
usr_boot_key_wait();
|
||||||
|
|
||||||
|
usr_key_init();
|
||||||
|
s_app_power = 1;
|
||||||
|
gDevData.power = 1;
|
||||||
|
s_hand_busy = 0;
|
||||||
|
s_hand_cmd_last = 0;
|
||||||
|
s_hand_write_pending = 0;
|
||||||
|
s_hand_write_cmd = 0;
|
||||||
|
s_charge_led_last = 0xff;
|
||||||
|
|
||||||
|
if (jb_timer_id == 0) {
|
||||||
|
jb_timer_id = sys_hi_timer_add(NULL, usr_timer_1_ms, TIMER_PERIOD_MS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void usr_timer_1_ms()
|
/**
|
||||||
|
* @brief 约 1ms 高优定时器:按键/充电/电量/DP 轮询/电机节拍/灯
|
||||||
|
* @param priv 未使用
|
||||||
|
* @note 用 sys_hi_timer(priority=1)避免休眠把节拍拉长。禁止在这里直接 sys_enter_soft_poweroff
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void usr_timer_1_ms(void *priv)
|
||||||
{
|
{
|
||||||
|
(void)priv;
|
||||||
jbTimerIrq();
|
jbTimerIrq();
|
||||||
|
usr_key_tick_1ms();
|
||||||
|
usr_chg_tick_1ms();
|
||||||
|
usr_bat_tick_1ms();
|
||||||
|
usr_app_power_poll();
|
||||||
|
usr_hand_poll();
|
||||||
|
usr_play_mode_poll();
|
||||||
|
if (s_hand_busy) {
|
||||||
|
usr_hand_tick_1ms();
|
||||||
|
} else {
|
||||||
|
app_mode_run();
|
||||||
|
}
|
||||||
|
usr_led_tick_1ms();
|
||||||
}
|
}
|
||||||
|
|
||||||
void usr_jb_le_recieve_data(u8* data,u16 len)
|
/**
|
||||||
|
* @brief BLE 收到见宝载荷,送入协议环形缓冲
|
||||||
|
* @param data 载荷指针
|
||||||
|
* @param len 载荷长度,单位字节
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void usr_jb_le_recieve_data(u8 *data, u16 len)
|
||||||
{
|
{
|
||||||
jbPutData(data,len);
|
jbPutData(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void usr_timer_loop()///500ms
|
/**
|
||||||
|
* @brief 约 500ms:协议收包与 DP 上报(由 usr_le_code 库回调,不要再注册一份)
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void usr_timer_loop(void)
|
||||||
{
|
{
|
||||||
userHandle();
|
userHandle();
|
||||||
jbProtocolHandle(&gDevData);
|
jbProtocolHandle(&gDevData);
|
||||||
|
|||||||
@@ -24,16 +24,19 @@ extern "C" {
|
|||||||
/**
|
/**
|
||||||
* @brief 进入配对/配网模式
|
* @brief 进入配对/配网模式
|
||||||
* @note 断开当前连接、清除配对信息(不复位),重新发绑定广播
|
* @note 断开当前连接、清除配对信息(不复位),重新发绑定广播
|
||||||
|
* @return 无
|
||||||
*/
|
*/
|
||||||
void usr_goto_pair_mode(void);
|
void usr_goto_pair_mode(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 清除配对信息但不复位
|
* @brief 清除配对信息但不复位
|
||||||
|
* @return 无
|
||||||
*/
|
*/
|
||||||
void usr_clear_pair_info_noreset(void);
|
void usr_clear_pair_info_noreset(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 清除配对信息并延时复位
|
* @brief 清除配对信息并延时复位
|
||||||
|
* @return 无
|
||||||
*/
|
*/
|
||||||
void usr_clear_pair_info(void);
|
void usr_clear_pair_info(void);
|
||||||
|
|
||||||
@@ -46,6 +49,7 @@ uint8_t usr_get_pair_flag(void);
|
|||||||
/**
|
/**
|
||||||
* @brief 启动应用侧 OTA 流程
|
* @brief 启动应用侧 OTA 流程
|
||||||
* @note 置位 usr_goto_updata,并创建 1s 周期定时器驱动断连与 OTA 广播切换
|
* @note 置位 usr_goto_updata,并创建 1s 周期定时器驱动断连与 OTA 广播切换
|
||||||
|
* @return 无
|
||||||
*/
|
*/
|
||||||
void usr_app_ota_init(void);
|
void usr_app_ota_init(void);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @file board_pin.h
|
||||||
|
* @brief CBC2 门夹弹力绳板级引脚、电平与时序(换板只改本文件)
|
||||||
|
* @author cyWu <1917507415@qq.com>
|
||||||
|
* @date 2026.08.24
|
||||||
|
* @version V1.3.0
|
||||||
|
* @history
|
||||||
|
* - V1.0.0, 2026.08.21, cyWu, 首次发布
|
||||||
|
* - V1.1.0, 2026.08.24, cyWu, 收口:去掉实验开关与未贴件限位
|
||||||
|
* - V1.2.0, 2026.08.24, cyWu, 按键:深睡 3s 开机、5s 开机+配对
|
||||||
|
* - V1.3.0, 2026.08.24, cyWu, 电机改 MCPWM 50% 占空比降速
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __BOARD_PIN_H__
|
||||||
|
#define __BOARD_PIN_H__
|
||||||
|
|
||||||
|
#include "asm/gpio.h"
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
/* 功能开关:某路硬件异常时可单独关掉,不影响配网 */
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
|
#define BOARD_LED_ENABLE 1 /**< 1=红绿 LED */
|
||||||
|
#define BOARD_KEY_ENABLE 1 /**< 1=按键 PB1 */
|
||||||
|
#define BOARD_CHG_ENABLE 1 /**< 1=充电检测 PG8 + VPWR */
|
||||||
|
#define BOARD_MOTOR_ENABLE 1 /**< 1=电机 PA6/PC2 */
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
/* GPIO */
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
|
#define BOARD_MOTOR_INA_PIN IO_PORTA_06 /**< 电机 INA */
|
||||||
|
#define BOARD_MOTOR_INB_PIN IO_PORTC_02 /**< 电机 INB */
|
||||||
|
#define BOARD_LED_RED_PIN IO_PORTA_08 /**< 红灯 LED_PWR,低电平亮 */
|
||||||
|
#define BOARD_LED_GREEN_PIN IO_PORTA_07 /**< 绿灯 LED_CHG,低电平亮 */
|
||||||
|
#define BOARD_KEY_PIN IO_PORTB_01 /**< 按键,低电平按下 */
|
||||||
|
#define BOARD_CHG_PIN IO_PORTG_08 /**< ME4054 CHG,外部 2.2k 上拉 */
|
||||||
|
/* PA3 限位未贴件,空脚不初始化 */
|
||||||
|
|
||||||
|
#define BOARD_LED_ON_LEVEL 0 /**< LED 点亮电平:0=低亮 */
|
||||||
|
#define BOARD_KEY_ACTIVE_LEVEL 0 /**< 按键有效电平:0=按下为低 */
|
||||||
|
#define BOARD_CHG_CHARGING_LEVEL 0 /**< CHG 充电中为低 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收绳方向:1 = INA 高 / INB 低 为收绳(顺时针)
|
||||||
|
* 若实测方向反了,把本宏改为 0
|
||||||
|
*/
|
||||||
|
#define BOARD_MOTOR_IN_INA_HIGH 1
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
/* 电量 / 充电 */
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
|
#define BOARD_VBAT_FULL_MV 4200 /**< 100% */
|
||||||
|
#define BOARD_VBAT_EMPTY_MV 3200 /**< 0%,持续低于此值深睡 */
|
||||||
|
#define BOARD_VBAT_LOW_MV 3700 /**< 低电预警阈值 */
|
||||||
|
#define BOARD_VBAT_LOW_HYST_MV 50 /**< 低电恢复回差 */
|
||||||
|
#define BOARD_VPWR_ONLINE_MV 4000 /**< VPWR 判定 USB 插入 */
|
||||||
|
#define BOARD_VPWR_OFF_MV 1500 /**< 低于此值认定已拔出 */
|
||||||
|
#define BOARD_CHG_FULL_MS 1000 /**< CHG 已高且 VPWR 在,满 1s 认充满 */
|
||||||
|
#define BOARD_LOWBAT_SLEEP_MS (60u * 1000u) /**< 低电告警满 1 分钟后深睡 */
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
/* 按键 / 灯效 */
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
|
#define BOARD_KEY_CLICK_MS 1000 /**< 开机后:按下 <1s 松开为短按切模式 */
|
||||||
|
#define BOARD_KEY_POWER_MS 3000 /**< 深睡:按住 3s 开机;开机中:按住 3s 深睡 */
|
||||||
|
#define BOARD_KEY_PAIR_MS 5000 /**< 深睡:按住 5s 开机并进配对(开机中继续按不住配对) */
|
||||||
|
#define BOARD_KEY_DEBOUNCE_MS 20 /**< 按键消抖 */
|
||||||
|
#define BOARD_PAIR_TIMEOUT_MS (60u * 1000u) /**< 配对超时,失败后保持开机 */
|
||||||
|
|
||||||
|
#define BOARD_LED_FAST_ON_MS 100 /**< 配对绿快闪:亮 */
|
||||||
|
#define BOARD_LED_FAST_OFF_MS 100 /**< 配对绿快闪:灭 */
|
||||||
|
#define BOARD_LED_ALT_MS 200 /**< 配对失败红绿交替半周期 */
|
||||||
|
#define BOARD_LED_PAIR_OK_MS 3000 /**< 配对成功绿灯常亮时长 */
|
||||||
|
#define BOARD_LED_PAIR_FAIL_MS 3000 /**< 配对失败提示时长 */
|
||||||
|
#define BOARD_LED_LOWBAT_ON_MS 200 /**< 低电红闪:亮 */
|
||||||
|
#define BOARD_LED_LOWBAT_PERIOD_MS 2000 /**< 低电红闪:周期 */
|
||||||
|
#define BOARD_LED_MODE_OFF_MS 150 /**< 切模式闪:灭 */
|
||||||
|
#define BOARD_LED_MODE_ON_MS 150 /**< 切模式闪:亮 */
|
||||||
|
#define BOARD_LED_MODE_BLINK_N 2 /**< 切模式闪次数 */
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
/* 电机 */
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
|
#define BOARD_MOTOR_REVERSE_MS 1 /**< 换向前先松开,防 H 桥直通 */
|
||||||
|
#define BOARD_MOTOR_STOP_BRAKE_MS 30 /**< 停转先反转刹车(ms),太长会倒转 */
|
||||||
|
#define BOARD_HAND_PULSE_MS 1000 /**< 预留;手动 1/2 一直转到写 03 停止 */
|
||||||
|
#define BOARD_MOTOR_PWM_HZ 20000 /**< MCPWM 频率(Hz),20k 避开可听啸叫 */
|
||||||
|
#define BOARD_MOTOR_PWM_DUTY 8000 /**< 占空比 0~10000=0%~100%,80% */
|
||||||
|
|
||||||
|
#endif /* __BOARD_PIN_H__ */
|
||||||
@@ -0,0 +1,429 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @file bsp_hw.c
|
||||||
|
* @brief CBC2 板级 GPIO / ADC:电机 H 桥、LED、按键、充电检测
|
||||||
|
* @author cyWu <1917507415@qq.com>
|
||||||
|
* @date 2026.08.24
|
||||||
|
* @version V1.4.0
|
||||||
|
* @history
|
||||||
|
* - V1.0.0, 2026.08.21, cyWu, 首次发布
|
||||||
|
* - V1.1.0, 2026.08.24, cyWu, 停转反转刹车;去掉限位脚
|
||||||
|
* - V1.3.0, 2026.08.24, cyWu, 电机改 MCPWM 占空比降速
|
||||||
|
* - V1.4.0, 2026.08.24, cyWu, 增加按占空比驱动,供玩法变速
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "system/includes.h"
|
||||||
|
#include "asm/gpio.h"
|
||||||
|
#include "asm/adc_api.h"
|
||||||
|
#include "asm/charge.h"
|
||||||
|
#include "asm/mcpwm.h"
|
||||||
|
#include "bsp_hw.h"
|
||||||
|
|
||||||
|
#define LOG_TAG_CONST APP
|
||||||
|
#define LOG_TAG "[BSP_HW]"
|
||||||
|
#define LOG_ERROR_ENABLE
|
||||||
|
#define LOG_INFO_ENABLE
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
static uint8_t s_initialized;
|
||||||
|
static BspMotorDir_t s_motor_dir;
|
||||||
|
static BspMotorDir_t s_motor_pending;
|
||||||
|
static uint16_t s_motor_duty;
|
||||||
|
static uint16_t s_pending_duty;
|
||||||
|
static uint16_t s_brake_ms;
|
||||||
|
static u32 s_brake_t0;
|
||||||
|
|
||||||
|
extern u32 timer_get_ms(void);
|
||||||
|
|
||||||
|
#if (BOARD_LED_ENABLE || BOARD_MOTOR_ENABLE)
|
||||||
|
/**
|
||||||
|
* @brief 配置 GPIO 为推挽输出
|
||||||
|
* @param pin GPIO 编号
|
||||||
|
* @param value 输出初值
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void bsp_pin_output(u32 pin, int value)
|
||||||
|
{
|
||||||
|
gpio_set_pull_up(pin, 0);
|
||||||
|
gpio_set_pull_down(pin, 0);
|
||||||
|
gpio_set_die(pin, 1);
|
||||||
|
gpio_direction_output(pin, value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (BOARD_KEY_ENABLE || BOARD_CHG_ENABLE)
|
||||||
|
/**
|
||||||
|
* @brief 配置 GPIO 为数字输入(可内部上拉)
|
||||||
|
* @param pin GPIO 编号
|
||||||
|
* @param pull_up 1=内部上拉,0=不上拉
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void bsp_pin_input(u32 pin, int pull_up)
|
||||||
|
{
|
||||||
|
gpio_direction_output(pin, 1);
|
||||||
|
gpio_set_direction(pin, 1);
|
||||||
|
gpio_set_pull_down(pin, 0);
|
||||||
|
gpio_set_pull_up(pin, pull_up ? 1 : 0);
|
||||||
|
gpio_set_die(pin, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOARD_MOTOR_ENABLE
|
||||||
|
/**
|
||||||
|
* @brief 初始化 INA/INB 两路 MCPWM,初始占空比 0(停转)
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void bsp_motor_pwm_init(void)
|
||||||
|
{
|
||||||
|
struct pwm_platform_data pwm;
|
||||||
|
|
||||||
|
gpio_set_pull_up(BOARD_MOTOR_INA_PIN, 0);
|
||||||
|
gpio_set_pull_down(BOARD_MOTOR_INA_PIN, 0);
|
||||||
|
gpio_set_die(BOARD_MOTOR_INA_PIN, 1);
|
||||||
|
gpio_set_pull_up(BOARD_MOTOR_INB_PIN, 0);
|
||||||
|
gpio_set_pull_down(BOARD_MOTOR_INB_PIN, 0);
|
||||||
|
gpio_set_die(BOARD_MOTOR_INB_PIN, 1);
|
||||||
|
|
||||||
|
pwm.pwm_aligned_mode = pwm_edge_aligned;
|
||||||
|
pwm.frequency = BOARD_MOTOR_PWM_HZ;
|
||||||
|
pwm.duty = 0;
|
||||||
|
pwm.l_pin = (u8) - 1;
|
||||||
|
pwm.complementary_en = 0;
|
||||||
|
|
||||||
|
pwm.pwm_ch_num = pwm_ch0;
|
||||||
|
pwm.h_pin = BOARD_MOTOR_INA_PIN;
|
||||||
|
mcpwm_init(&pwm);
|
||||||
|
|
||||||
|
pwm.pwm_ch_num = pwm_ch1;
|
||||||
|
pwm.h_pin = BOARD_MOTOR_INB_PIN;
|
||||||
|
mcpwm_init(&pwm);
|
||||||
|
|
||||||
|
mcpwm_set_duty(pwm_ch0, 0);
|
||||||
|
mcpwm_set_duty(pwm_ch1, 0);
|
||||||
|
log_info("motor pwm %uHz duty=%u/10000\n",
|
||||||
|
(unsigned)BOARD_MOTOR_PWM_HZ, (unsigned)BOARD_MOTOR_PWM_DUTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 立刻改 INA/INB PWM。运转脚输出 duty,另一脚 0%;STOP=两路 0%
|
||||||
|
* @param dir 目标方向
|
||||||
|
* @param duty 占空比 0~10000
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
static void bsp_motor_gpio(BspMotorDir_t dir, uint16_t duty)
|
||||||
|
{
|
||||||
|
u16 ina_duty = 0;
|
||||||
|
u16 inb_duty = 0;
|
||||||
|
|
||||||
|
if (duty > 10000) {
|
||||||
|
duty = 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir == BSP_MOTOR_IN) {
|
||||||
|
if (BOARD_MOTOR_IN_INA_HIGH) {
|
||||||
|
ina_duty = duty;
|
||||||
|
} else {
|
||||||
|
inb_duty = duty;
|
||||||
|
}
|
||||||
|
} else if (dir == BSP_MOTOR_OUT) {
|
||||||
|
if (BOARD_MOTOR_IN_INA_HIGH) {
|
||||||
|
inb_duty = duty;
|
||||||
|
} else {
|
||||||
|
ina_duty = duty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mcpwm_set_duty(pwm_ch0, ina_duty);
|
||||||
|
mcpwm_set_duty(pwm_ch1, inb_duty);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化 GPIO / 充电 ADC
|
||||||
|
* @return BSP_HW_OK=成功
|
||||||
|
*/
|
||||||
|
BspHw_Ret_t bsp_hw_init(void)
|
||||||
|
{
|
||||||
|
if (s_initialized) {
|
||||||
|
return BSP_HW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BOARD_LED_ENABLE
|
||||||
|
bsp_pin_output(BOARD_LED_RED_PIN, !BOARD_LED_ON_LEVEL);
|
||||||
|
bsp_pin_output(BOARD_LED_GREEN_PIN, !BOARD_LED_ON_LEVEL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOARD_KEY_ENABLE
|
||||||
|
bsp_pin_input(BOARD_KEY_PIN, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOARD_CHG_ENABLE
|
||||||
|
/* PORTG 作数字输入必须开 dieh,否则读不到 ME4054 CHG */
|
||||||
|
gpio_disable_fun_output_port(BOARD_CHG_PIN);
|
||||||
|
gpio_set_pull_up(BOARD_CHG_PIN, 0);
|
||||||
|
gpio_set_pull_down(BOARD_CHG_PIN, 0);
|
||||||
|
gpio_set_die(BOARD_CHG_PIN, 1);
|
||||||
|
gpio_set_dieh(BOARD_CHG_PIN, 1);
|
||||||
|
gpio_direction_input(BOARD_CHG_PIN);
|
||||||
|
adc_add_sample_ch(AD_CH_LDO5V);
|
||||||
|
adc_set_sample_freq(AD_CH_LDO5V, 500);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BOARD_MOTOR_ENABLE
|
||||||
|
bsp_motor_pwm_init();
|
||||||
|
s_motor_dir = BSP_MOTOR_STOP;
|
||||||
|
s_motor_pending = BSP_MOTOR_STOP;
|
||||||
|
s_motor_duty = 0;
|
||||||
|
s_pending_duty = 0;
|
||||||
|
s_brake_ms = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
s_initialized = 1;
|
||||||
|
log_info("hw init led=%d key=%d chg=%d motor=%d\n",
|
||||||
|
BOARD_LED_ENABLE, BOARD_KEY_ENABLE, BOARD_CHG_ENABLE,
|
||||||
|
BOARD_MOTOR_ENABLE);
|
||||||
|
return BSP_HW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询板级硬件是否已初始化
|
||||||
|
* @return BSP_HW_OK=已初始化,BSP_HW_ERR_NOT_INIT=未初始化
|
||||||
|
*/
|
||||||
|
BspHw_Ret_t bsp_hw_get_status(void)
|
||||||
|
{
|
||||||
|
return s_initialized ? BSP_HW_OK : BSP_HW_ERR_NOT_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 红灯开关
|
||||||
|
* @param on 1=亮,0=灭
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_led_red_set(uint8_t on)
|
||||||
|
{
|
||||||
|
#if BOARD_LED_ENABLE
|
||||||
|
gpio_direction_output(BOARD_LED_RED_PIN, on ? BOARD_LED_ON_LEVEL : !BOARD_LED_ON_LEVEL);
|
||||||
|
#else
|
||||||
|
(void)on;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 绿灯开关
|
||||||
|
* @param on 1=亮,0=灭
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_led_green_set(uint8_t on)
|
||||||
|
{
|
||||||
|
#if BOARD_LED_ENABLE
|
||||||
|
gpio_direction_output(BOARD_LED_GREEN_PIN, on ? BOARD_LED_ON_LEVEL : !BOARD_LED_ON_LEVEL);
|
||||||
|
#else
|
||||||
|
(void)on;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 红绿灯全灭
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_led_all_off(void)
|
||||||
|
{
|
||||||
|
bsp_led_red_set(0);
|
||||||
|
bsp_led_green_set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置电机方向。STOP 时若正在转,先反转刹车再滑行
|
||||||
|
* @param dir 收绳 / 放绳 / 停转
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_motor_set(BspMotorDir_t dir)
|
||||||
|
{
|
||||||
|
bsp_motor_set_pwm(dir, (dir == BSP_MOTOR_STOP) ? 0 : BOARD_MOTOR_PWM_DUTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置电机方向与 PWM 占空比
|
||||||
|
* @param dir 收绳 / 放绳 / 停转
|
||||||
|
* @param duty 占空比 0~10000;STOP 时按 0 处理
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty)
|
||||||
|
{
|
||||||
|
#if !BOARD_MOTOR_ENABLE
|
||||||
|
(void)dir;
|
||||||
|
(void)duty;
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
if (duty > 10000) {
|
||||||
|
duty = 10000;
|
||||||
|
}
|
||||||
|
if (dir == BSP_MOTOR_STOP) {
|
||||||
|
duty = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 同向只改占空比:直接改 PWM,不走换向死区 */
|
||||||
|
if (dir == s_motor_dir && s_brake_ms == 0) {
|
||||||
|
if (duty == s_motor_duty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s_motor_duty = duty;
|
||||||
|
s_motor_pending = dir;
|
||||||
|
s_pending_duty = duty;
|
||||||
|
bsp_motor_gpio(dir, duty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 已经在反转刹车等到停,忽略重复 STOP */
|
||||||
|
if (dir == BSP_MOTOR_STOP && s_motor_pending == BSP_MOTOR_STOP && s_brake_ms) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 正在转时要停:先反向驱动再滑行,短接对此驱动无效 */
|
||||||
|
if (dir == BSP_MOTOR_STOP
|
||||||
|
&& (s_motor_dir == BSP_MOTOR_IN || s_motor_dir == BSP_MOTOR_OUT)) {
|
||||||
|
BspMotorDir_t rev = (s_motor_dir == BSP_MOTOR_OUT) ? BSP_MOTOR_IN : BSP_MOTOR_OUT;
|
||||||
|
uint16_t brake_duty = s_motor_duty ? s_motor_duty : BOARD_MOTOR_PWM_DUTY;
|
||||||
|
|
||||||
|
bsp_motor_gpio(rev, brake_duty);
|
||||||
|
s_motor_dir = rev;
|
||||||
|
s_motor_duty = brake_duty;
|
||||||
|
s_motor_pending = BSP_MOTOR_STOP;
|
||||||
|
s_pending_duty = 0;
|
||||||
|
s_brake_ms = BOARD_MOTOR_STOP_BRAKE_MS;
|
||||||
|
s_brake_t0 = timer_get_ms();
|
||||||
|
log_info("motor rev-brake %ums duty=%u\n",
|
||||||
|
(unsigned)BOARD_MOTOR_STOP_BRAKE_MS, (unsigned)brake_duty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 换向:先松开再输出,避免 H 桥直通 */
|
||||||
|
if (dir != BSP_MOTOR_STOP && s_motor_dir != BSP_MOTOR_STOP && dir != s_motor_dir) {
|
||||||
|
bsp_motor_gpio(BSP_MOTOR_STOP, 0);
|
||||||
|
s_motor_pending = dir;
|
||||||
|
s_pending_duty = duty;
|
||||||
|
s_brake_ms = BOARD_MOTOR_REVERSE_MS;
|
||||||
|
s_brake_t0 = timer_get_ms();
|
||||||
|
s_motor_dir = BSP_MOTOR_STOP;
|
||||||
|
s_motor_duty = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_brake_ms = 0;
|
||||||
|
s_motor_dir = dir;
|
||||||
|
s_motor_pending = dir;
|
||||||
|
s_motor_duty = duty;
|
||||||
|
s_pending_duty = duty;
|
||||||
|
bsp_motor_gpio(dir, duty);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 推进换向死区与停转反转刹车,按真实毫秒计时
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_motor_brake_tick(void)
|
||||||
|
{
|
||||||
|
#if !BOARD_MOTOR_ENABLE
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
if (s_brake_ms == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((timer_get_ms() - s_brake_t0) < s_brake_ms) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s_brake_ms = 0;
|
||||||
|
s_motor_dir = s_motor_pending;
|
||||||
|
s_motor_duty = s_pending_duty;
|
||||||
|
bsp_motor_gpio(s_motor_dir, s_motor_duty);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取按键电平
|
||||||
|
* @return 1=按下,0=未按下
|
||||||
|
*/
|
||||||
|
uint8_t bsp_key_is_pressed(void)
|
||||||
|
{
|
||||||
|
#if BOARD_KEY_ENABLE
|
||||||
|
return (uint8_t)(gpio_read(BOARD_KEY_PIN) == BOARD_KEY_ACTIVE_LEVEL);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取 ME4054 CHG 脚:充电中为低
|
||||||
|
* @return 1=充电中,0=未充电
|
||||||
|
*/
|
||||||
|
uint8_t bsp_chg_is_low(void)
|
||||||
|
{
|
||||||
|
#if BOARD_CHG_ENABLE
|
||||||
|
return (uint8_t)(gpio_read(BOARD_CHG_PIN) == BOARD_CHG_CHARGING_LEVEL);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取电池电压
|
||||||
|
* @return 电池电压,单位 mV
|
||||||
|
*/
|
||||||
|
uint16_t bsp_vbat_mv(void)
|
||||||
|
{
|
||||||
|
return (uint16_t)(adc_get_voltage(AD_CH_VBAT) * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取 5V 口电压,用于判断 USB
|
||||||
|
* @return VPWR 电压,单位 mV
|
||||||
|
*/
|
||||||
|
uint16_t bsp_vpwr_mv(void)
|
||||||
|
{
|
||||||
|
return (uint16_t)(adc_get_voltage(AD_CH_LDO5V) * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USB 是否在位(以 ADC 为主,比较器为辅)
|
||||||
|
* @return 1=插入,0=未插入
|
||||||
|
*/
|
||||||
|
uint8_t bsp_vpwr_is_online(void)
|
||||||
|
{
|
||||||
|
#if BOARD_CHG_ENABLE
|
||||||
|
uint16_t mv = bsp_vpwr_mv();
|
||||||
|
|
||||||
|
/* 以 ADC 为准:拔电后比较器可能仍为 1,但电压已经掉到几百 mV */
|
||||||
|
if (mv >= BOARD_VPWR_ONLINE_MV) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (mv <= BOARD_VPWR_OFF_MV) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (get_ldo5v_online_hw() || get_lvcmp_det()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 进深睡前把电机 PWM 关掉并拉低,灯全灭
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_hw_enter_sleep_io(void)
|
||||||
|
{
|
||||||
|
bsp_motor_set(BSP_MOTOR_STOP);
|
||||||
|
#if BOARD_MOTOR_ENABLE
|
||||||
|
mcpwm_set_duty(pwm_ch0, 0);
|
||||||
|
mcpwm_set_duty(pwm_ch1, 0);
|
||||||
|
mcpwm_close(pwm_ch0);
|
||||||
|
mcpwm_close(pwm_ch1);
|
||||||
|
gpio_och_disable_output_signal(BOARD_MOTOR_INA_PIN, OUTPUT_CH_SIGNAL_MC_PWM0_H);
|
||||||
|
gpio_och_disable_output_signal(BOARD_MOTOR_INB_PIN, OUTPUT_CH_SIGNAL_MC_PWM1_H);
|
||||||
|
gpio_direction_output(BOARD_MOTOR_INA_PIN, 0);
|
||||||
|
gpio_direction_output(BOARD_MOTOR_INB_PIN, 0);
|
||||||
|
#endif
|
||||||
|
bsp_led_all_off();
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @file bsp_hw.h
|
||||||
|
* @brief CBC2 板级硬件:电机 / LED / 按键 / 充电 / 电量
|
||||||
|
* @author cyWu <1917507415@qq.com>
|
||||||
|
* @date 2026.08.24
|
||||||
|
* @version V1.4.0
|
||||||
|
* @history
|
||||||
|
* - V1.0.0, 2026.08.21, cyWu, 首次发布
|
||||||
|
* - V1.1.0, 2026.08.24, cyWu, 停转改为反转刹车;去掉未贴件限位
|
||||||
|
* - V1.3.0, 2026.08.24, cyWu, 电机改 MCPWM 50% 占空比降速
|
||||||
|
* - V1.4.0, 2026.08.24, cyWu, 增加按占空比驱动,供玩法变速
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __BSP_HW_H__
|
||||||
|
#define __BSP_HW_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "board_pin.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BSP_HW_OK = 0,
|
||||||
|
BSP_HW_ERR_PARAM,
|
||||||
|
BSP_HW_ERR_NOT_INIT
|
||||||
|
} BspHw_Ret_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BSP_MOTOR_STOP = 0, /**< 滑行停(INA/INB 都低) */
|
||||||
|
BSP_MOTOR_IN, /**< 收绳(顺时针,见 BOARD_MOTOR_IN_INA_HIGH) */
|
||||||
|
BSP_MOTOR_OUT /**< 放绳 */
|
||||||
|
} BspMotorDir_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化 GPIO / 充电 ADC
|
||||||
|
* @return BSP_HW_OK=成功
|
||||||
|
*/
|
||||||
|
BspHw_Ret_t bsp_hw_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询是否已初始化
|
||||||
|
* @return BSP_HW_OK=已初始化,BSP_HW_ERR_NOT_INIT=未初始化
|
||||||
|
*/
|
||||||
|
BspHw_Ret_t bsp_hw_get_status(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 红灯开关
|
||||||
|
* @param on 1=亮,0=灭
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_led_red_set(uint8_t on);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 绿灯开关
|
||||||
|
* @param on 1=亮,0=灭
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_led_green_set(uint8_t on);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 红绿灯全灭
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_led_all_off(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置电机方向。STOP 时若正在转,先反转刹车再滑行
|
||||||
|
* @note 占空比用 BOARD_MOTOR_PWM_DUTY(手动点动)
|
||||||
|
* @param dir 收绳 / 放绳 / 停转
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_motor_set(BspMotorDir_t dir);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 设置电机方向与 PWM 占空比
|
||||||
|
* @param dir 收绳 / 放绳 / 停转
|
||||||
|
* @param duty 占空比 0~10000(0%~100%);STOP 时忽略
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 推进换向死区与停转反转刹车,按真实毫秒计时
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_motor_brake_tick(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取按键
|
||||||
|
* @return 1=按下,0=未按下
|
||||||
|
*/
|
||||||
|
uint8_t bsp_key_is_pressed(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取 ME4054 CHG:充电中为低
|
||||||
|
* @return 1=充电中,0=未充电
|
||||||
|
*/
|
||||||
|
uint8_t bsp_chg_is_low(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取电池电压
|
||||||
|
* @return 电池电压,单位 mV
|
||||||
|
*/
|
||||||
|
uint16_t bsp_vbat_mv(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取 5V 口电压,用于判断 USB
|
||||||
|
* @return VPWR 电压,单位 mV
|
||||||
|
*/
|
||||||
|
uint16_t bsp_vpwr_mv(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USB 是否在位(以 ADC 为主,比较器为辅)
|
||||||
|
* @return 1=插入,0=未插入
|
||||||
|
*/
|
||||||
|
uint8_t bsp_vpwr_is_online(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 进深睡前把电机 PWM 关掉并拉低,灯全灭
|
||||||
|
* @return 无
|
||||||
|
*/
|
||||||
|
void bsp_hw_enter_sleep_io(void);
|
||||||
|
|
||||||
|
#endif /* __BSP_HW_H__ */
|
||||||
@@ -64,7 +64,7 @@ static void usr_rtc_save_tz(int32_t tz_s);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 打开 rtc 设备并加载时区
|
* @brief 打开 rtc 设备并加载时区
|
||||||
* @return UsrRtc_Ret_t
|
* @return USR_RTC_OK=成功,USR_RTC_ERR_NOT_INIT=设备打开失败或 RTC 未使能
|
||||||
*/
|
*/
|
||||||
UsrRtc_Ret_t usr_rtc_init(void)
|
UsrRtc_Ret_t usr_rtc_init(void)
|
||||||
{
|
{
|
||||||
@@ -101,7 +101,7 @@ UsrRtc_Ret_t usr_rtc_init(void)
|
|||||||
/**
|
/**
|
||||||
* @brief 获取当前本地时间
|
* @brief 获取当前本地时间
|
||||||
* @param t 成功时赋值;失败不改动
|
* @param t 成功时赋值;失败不改动
|
||||||
* @return 1/0
|
* @return 1=已对时且读成功,0=未初始化/未对时/参数非法
|
||||||
*/
|
*/
|
||||||
uint8_t usr_rtc_get_time(struct sys_time *t)
|
uint8_t usr_rtc_get_time(struct sys_time *t)
|
||||||
{
|
{
|
||||||
@@ -127,7 +127,7 @@ uint8_t usr_rtc_get_time(struct sys_time *t)
|
|||||||
* @brief UTC 秒 + 时区 → 本地日历写入 RTC
|
* @brief UTC 秒 + 时区 → 本地日历写入 RTC
|
||||||
* @param unix_utc UTC 秒
|
* @param unix_utc UTC 秒
|
||||||
* @param tz_s 时区偏移秒
|
* @param tz_s 时区偏移秒
|
||||||
* @return UsrRtc_Ret_t
|
* @return USR_RTC_OK=成功,USR_RTC_ERR_NOT_INIT=未初始化,USR_RTC_ERR_PARAM=参数非法,USR_RTC_ERR_INVALID=年份非法
|
||||||
*/
|
*/
|
||||||
UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s)
|
UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s)
|
||||||
{
|
{
|
||||||
@@ -184,7 +184,7 @@ UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s)
|
|||||||
/**
|
/**
|
||||||
* @brief 写硬件日历
|
* @brief 写硬件日历
|
||||||
* @param t 本地日历
|
* @param t 本地日历
|
||||||
* @return UsrRtc_Ret_t
|
* @return USR_RTC_OK=成功,USR_RTC_ERR_PARAM=参数非法,USR_RTC_ERR_NOT_INIT=未初始化
|
||||||
*/
|
*/
|
||||||
static UsrRtc_Ret_t usr_rtc_write(const struct sys_time *t)
|
static UsrRtc_Ret_t usr_rtc_write(const struct sys_time *t)
|
||||||
{
|
{
|
||||||
@@ -216,7 +216,7 @@ static UsrRtc_Ret_t usr_rtc_write(const struct sys_time *t)
|
|||||||
/**
|
/**
|
||||||
* @brief 是否闰年
|
* @brief 是否闰年
|
||||||
* @param year 公历年
|
* @param year 公历年
|
||||||
* @return 1/0
|
* @return 1=闰年,0=平年
|
||||||
*/
|
*/
|
||||||
static uint8_t usr_rtc_is_leap(uint16_t year)
|
static uint8_t usr_rtc_is_leap(uint16_t year)
|
||||||
{
|
{
|
||||||
@@ -235,7 +235,7 @@ static uint8_t usr_rtc_is_leap(uint16_t year)
|
|||||||
* @brief 某月天数
|
* @brief 某月天数
|
||||||
* @param year 年
|
* @param year 年
|
||||||
* @param month 月 1~12
|
* @param month 月 1~12
|
||||||
* @return 天数,非法月返回 0
|
* @return 该月天数;非法月份返回 0
|
||||||
*/
|
*/
|
||||||
static uint8_t usr_rtc_days_in_month(uint16_t year, uint8_t month)
|
static uint8_t usr_rtc_days_in_month(uint16_t year, uint8_t month)
|
||||||
{
|
{
|
||||||
@@ -256,7 +256,7 @@ static uint8_t usr_rtc_days_in_month(uint16_t year, uint8_t month)
|
|||||||
/**
|
/**
|
||||||
* @brief 年份是否在合法窗口
|
* @brief 年份是否在合法窗口
|
||||||
* @param year 年
|
* @param year 年
|
||||||
* @return 1/0
|
* @return 1=合法,0=非法
|
||||||
*/
|
*/
|
||||||
static uint8_t usr_rtc_year_ok(uint16_t year)
|
static uint8_t usr_rtc_year_ok(uint16_t year)
|
||||||
{
|
{
|
||||||
@@ -266,8 +266,9 @@ static uint8_t usr_rtc_year_ok(uint16_t year)
|
|||||||
/**
|
/**
|
||||||
* @brief UTC 秒 + 时区 → 本地日历
|
* @brief UTC 秒 + 时区 → 本地日历
|
||||||
* @param unix_utc UTC 秒
|
* @param unix_utc UTC 秒
|
||||||
* @param tz_s 时区偏移
|
* @param tz_s 时区偏移秒
|
||||||
* @param t 输出
|
* @param t 输出本地日历
|
||||||
|
* @return 无
|
||||||
*/
|
*/
|
||||||
static void usr_rtc_unix_to_calendar(uint32_t unix_utc, int32_t tz_s,
|
static void usr_rtc_unix_to_calendar(uint32_t unix_utc, int32_t tz_s,
|
||||||
struct sys_time *t)
|
struct sys_time *t)
|
||||||
@@ -324,6 +325,7 @@ static void usr_rtc_unix_to_calendar(uint32_t unix_utc, int32_t tz_s,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 从 VM 加载时区
|
* @brief 从 VM 加载时区
|
||||||
|
* @return 无
|
||||||
*/
|
*/
|
||||||
static void usr_rtc_load_tz(void)
|
static void usr_rtc_load_tz(void)
|
||||||
{
|
{
|
||||||
@@ -350,6 +352,7 @@ static void usr_rtc_load_tz(void)
|
|||||||
/**
|
/**
|
||||||
* @brief 时区写入 VM
|
* @brief 时区写入 VM
|
||||||
* @param tz_s 时区偏移秒
|
* @param tz_s 时区偏移秒
|
||||||
|
* @return 无
|
||||||
*/
|
*/
|
||||||
static void usr_rtc_save_tz(int32_t tz_s)
|
static void usr_rtc_save_tz(int32_t tz_s)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,9 +40,8 @@ typedef enum {
|
|||||||
/*============================================================================*/
|
/*============================================================================*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 打开 "rtc" 设备并加载时区
|
* @brief 打开 rtc 设备并加载时区
|
||||||
* @return UsrRtc_Ret_t
|
* @return USR_RTC_OK=成功,USR_RTC_ERR_NOT_INIT=设备打开失败或 RTC 未使能
|
||||||
* @note app_main 启动时调用一次即可
|
|
||||||
*/
|
*/
|
||||||
UsrRtc_Ret_t usr_rtc_init(void);
|
UsrRtc_Ret_t usr_rtc_init(void);
|
||||||
|
|
||||||
@@ -57,7 +56,7 @@ uint8_t usr_rtc_get_time(struct sys_time *t);
|
|||||||
* @brief App/网关 DEVICEINFO:UTC 秒 + 时区写入 RTC
|
* @brief App/网关 DEVICEINFO:UTC 秒 + 时区写入 RTC
|
||||||
* @param unix_utc UTC Unix 秒;0 无效
|
* @param unix_utc UTC Unix 秒;0 无效
|
||||||
* @param tz_s 时区偏移秒(东八区 28800)
|
* @param tz_s 时区偏移秒(东八区 28800)
|
||||||
* @return UsrRtc_Ret_t
|
* @return USR_RTC_OK=成功,USR_RTC_ERR_NOT_INIT=未初始化,USR_RTC_ERR_PARAM=参数非法,USR_RTC_ERR_INVALID=年份非法
|
||||||
*/
|
*/
|
||||||
UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s);
|
UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s);
|
||||||
|
|
||||||
|
|||||||
+2079
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sdfile_vfs_ops
|
||||||
|
sbc_decoder
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
msbc_decoder
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sbc_hwaccel
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cvsd_decoder
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pcm_decoder
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mp3_decoder
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@echo off
|
||||||
|
Setlocal enabledelayedexpansion
|
||||||
|
@echo ********************************************************************************
|
||||||
|
@echo SDK BR28
|
||||||
|
@echo ********************************************************************************
|
||||||
|
@echo %date%
|
||||||
|
|
||||||
|
|
||||||
|
cd /d %~dp0
|
||||||
|
|
||||||
|
set OBJDUMP=C:\JL\pi32\bin\llvm-objdump.exe
|
||||||
|
set OBJCOPY=C:\JL\pi32\bin\llvm-objcopy.exe
|
||||||
|
set ELFFILE=sdk.elf
|
||||||
|
set bankfiles=
|
||||||
|
set LZ4_PACKET=.\lz4_packet.exe
|
||||||
|
|
||||||
|
REM %OBJDUMP% -D -address-mask=0x1ffffff -print-dbg $1.elf > $1.lst
|
||||||
|
%OBJCOPY% -O binary -j .text %ELFFILE% text.bin
|
||||||
|
%OBJCOPY% -O binary -j .data %ELFFILE% data.bin
|
||||||
|
%OBJCOPY% -O binary -j .data_code %ELFFILE% data_code.bin
|
||||||
|
%OBJCOPY% -O binary -j .overlay_aec %ELFFILE% aec.bin
|
||||||
|
%OBJCOPY% -O binary -j .overlay_aac %ELFFILE% aac.bin
|
||||||
|
%OBJCOPY% -O binary -j .overlay_aptx %ELFFILE% aptx.bin
|
||||||
|
|
||||||
|
%OBJCOPY% -O binary -j .common %ELFFILE% common.bin
|
||||||
|
|
||||||
|
for /L %%i in (0,1,20) do (
|
||||||
|
%OBJCOPY% -O binary -j .overlay_bank%%i %ELFFILE% bank%%i.bin
|
||||||
|
set bankfiles=!bankfiles! bank%%i.bin 0x0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
%LZ4_PACKET% -dict text.bin -input common.bin 0 aec.bin 0 aac.bin 0 !bankfiles! -o bank.bin
|
||||||
|
|
||||||
|
%OBJDUMP% -section-headers -address-mask=0x1ffffff %ELFFILE%
|
||||||
|
REM %OBJDUMP% -t %ELFFILE% > symbol_tbl.txt
|
||||||
|
|
||||||
|
copy /b text.bin + data.bin + mov_slot.bin + data_code.bin + aec.bin + aac.bin + psr_data_code.bin app.bin
|
||||||
|
|
||||||
|
|
||||||
|
del !bankfiles! common.bin text.bin data.bin bank.bin
|
||||||
|
copy eq_cfg_hw_less.bin eq_cfg_hw.bin
|
||||||
|
call download/earphone/download_app_ota.bat
|
||||||
@@ -10,9 +10,9 @@ copy ..\..\ota.bin .
|
|||||||
copy ..\..\anc_coeff.bin .
|
copy ..\..\anc_coeff.bin .
|
||||||
copy ..\..\anc_gains.bin .
|
copy ..\..\anc_gains.bin .
|
||||||
|
|
||||||
..\..\isd_download.exe ..\..\isd_config.ini -tonorflash -dev br28 -boot 0x120000 -div8 -wait 300 -uboot ..\..\uboot.boot -app ..\..\app.bin -res ..\..\cfg_tool.bin tone.cfg p11_code.bin -uboot_compress
|
..\..\isd_download.exe ..\..\isd_config.ini -tonorflash -dev br28 -boot 0x120000 -div8 -wait 300 -uboot ..\..\uboot.boot -app ..\..\app.bin -res ..\..\cfg_tool.bin tone.cfg p11_code.bin -uboot_compress -key RS-5B88.key
|
||||||
|
|
||||||
:: -format all -key RS-5B88.key
|
:: -format all
|
||||||
::-reboot 2500
|
::-reboot 2500
|
||||||
|
|
||||||
@rem delete temp files
|
@rem delete temp files
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[EXTRA_CFG_PARAM]
|
||||||
|
|
||||||
|
BR22_TWS_DB = YES;
|
||||||
|
FLASH_SIZE = 0x100000;
|
||||||
|
BR22_TWS_VERSION = 0;
|
||||||
|
FORCE_4K_ALIGN = YES;
|
||||||
|
SPECIAL_OPT = 0;
|
||||||
|
|
||||||
|
DB_UPDATE_DATA = YES;
|
||||||
|
CHIP_NAME = AC701N;
|
||||||
|
ENTRY = 0x6000100;
|
||||||
|
PID = AC701N;
|
||||||
|
VID = 0.01;
|
||||||
|
|
||||||
|
SDK_VERSION = JL701N_V1.6.1;
|
||||||
|
|
||||||
|
RESERVED_OPT = 0;
|
||||||
|
|
||||||
|
UFW_ELEMENT = 0x10 - 0x0, 0x1 - 0x0;
|
||||||
|
|
||||||
|
DOWNLOAD_MODEL = USB;
|
||||||
|
SERIAL_DEVICE_NAME = JlVirtualJtagSerial;
|
||||||
|
SERIAL_BARD_RATE = 1000000;
|
||||||
|
SERIAL_CMD_OPT = 2;
|
||||||
|
SERIAL_CMD_RATE = 100;
|
||||||
|
SERIAL_CMD_RES = 0;
|
||||||
|
SERIAL_INIT_BAUD_RATE = 9600;
|
||||||
|
LOADER_BAUD_RATE = 1000000;
|
||||||
|
LOADER_ASK_BAUD_RATE = 1000000;
|
||||||
|
BEFORE_LOADER_WAIT_TIME = 150;
|
||||||
|
SERIAL_SEND_KEY = YES;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[CHIP_VERSION]
|
||||||
|
SUPPORTED_LIST = P, B;
|
||||||
|
|
||||||
|
[SYS_CFG_PARAM]
|
||||||
|
SPI = 2_3_0_0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
UTTX = PB02;
|
||||||
|
UTBD = 1000000;
|
||||||
|
UTRX = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RESET1 = PB01_16_0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
VLVD = 3;
|
||||||
|
[FW_ADDITIONAL]
|
||||||
|
FILE_LIST = (file = ota.bin: type = 100);
|
||||||
|
[RESERVED_CONFIG]
|
||||||
|
BTIF_ADR = AUTO;
|
||||||
|
BTIF_LEN = 0x1000;
|
||||||
|
BTIF_OPT = 1;
|
||||||
|
PRCT_ADR = 0;
|
||||||
|
PRCT_LEN = CODE_LEN;
|
||||||
|
PRCT_OPT = 2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
VM_ADR = 0;
|
||||||
|
VM_LEN = 8K;
|
||||||
|
VM_OPT = 1;
|
||||||
|
[BURNER_CONFIG]
|
||||||
|
SIZE = 32;
|
||||||
Reference in New Issue
Block a user