diff --git a/AC701N.cbp b/AC701N.cbp
index f2b466b..dcbec0d 100644
--- a/AC701N.cbp
+++ b/AC701N.cbp
@@ -177,6 +177,7 @@
+
@@ -783,6 +784,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Makefile b/Makefile
index c4761fe..bb80165 100644
--- a/Makefile
+++ b/Makefile
@@ -251,6 +251,7 @@ INCLUDES := \
-Iapps/usr_jb_proto/Protocol \
-Iapps/usr_jb_proto/Utils \
-Iapps/usr_periph \
+ -Iapps/usr_app \
-I$(SYS_INC_DIR) \
@@ -621,6 +622,9 @@ c_SRC_FILES := \
apps/usr_jb_proto/Utils/jb_ringbuffer.c \
apps/usr_jb_proto/usr_jb_main.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 不附带协议源码,禁止本地重建)
diff --git a/apps/earphone/app_main.c b/apps/earphone/app_main.c
index 4aca9ac..b94ec0c 100644
--- a/apps/earphone/app_main.c
+++ b/apps/earphone/app_main.c
@@ -156,7 +156,6 @@ extern void uart_dev_test_main();
extern int ana_demo();
extern void uart_dev_main_init();
extern void usr_check_mcu_all_sta();
-extern void usr_clear_pair_info_noreset(void);
extern void usr_disable_intterupt();
extern void usr_disable_charge_intterupt();
u8 power_reset_flag=0;
@@ -327,13 +326,10 @@ void app_main()
}
/*
- * 上电强制进入配对模式:
- * 1) usr_goto_pair=1:后续 usr_ble_adv_init() 走绑定广播(encode4bind),不走重连广播
- * 2) usr_clear_pair_info_noreset():清 VM 中三元组,保证 paired_flag=0
- * 注意:须在 BLE 协议栈调用 usr_ble_adv_init() 之前设置;此处不清复位,避免上电死循环复位
+ * 配对只在 usr_jb_init() 里、BLE 起来之前处理:
+ * 深睡长按 5s → usr_goto_pair=1 + 清绑定;长按 3s 仅开机。
+ * 此处不要再强制配对,也不要在协议栈起来后调用 usr_goto_pair_mode()。
*/
- usr_var.usr_goto_pair = 1;
- usr_clear_pair_info_noreset();
ui_manage_init();
ui_update_status(STATUS_POWERON);
diff --git a/apps/usr_app/app_cbc2.c b/apps/usr_app/app_cbc2.c
new file mode 100644
index 0000000..5908a1d
--- /dev/null
+++ b/apps/usr_app/app_cbc2.c
@@ -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;
+}
diff --git a/apps/usr_app/app_led.c b/apps/usr_app/app_led.c
new file mode 100644
index 0000000..2f12981
--- /dev/null
+++ b/apps/usr_app/app_led.c
@@ -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();
+}
diff --git a/apps/usr_app/app_led.h b/apps/usr_app/app_led.h
new file mode 100644
index 0000000..42383c6
--- /dev/null
+++ b/apps/usr_app/app_led.h
@@ -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
+
+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__ */
diff --git a/apps/usr_app/app_mode.c b/apps/usr_app/app_mode.c
new file mode 100644
index 0000000..676f0f9
--- /dev/null
+++ b/apps/usr_app/app_mode.c
@@ -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();
+ }
+}
diff --git a/apps/usr_app/app_mode.h b/apps/usr_app/app_mode.h
new file mode 100644
index 0000000..f67548a
--- /dev/null
+++ b/apps/usr_app/app_mode.h
@@ -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
+
+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__ */
diff --git a/apps/usr_jb_proto/Protocol/jb_product.c b/apps/usr_jb_proto/Protocol/jb_product.c
index 91ee902..1cc9739 100644
--- a/apps/usr_jb_proto/Protocol/jb_product.c
+++ b/apps/usr_jb_proto/Protocol/jb_product.c
@@ -127,7 +127,11 @@ int8_t jbEventProcess(jb_event_info_t *info, jb_data_point_t *ctrl)
/* ── DP2 手动模式 (raw) ── */
case DP_ID_HAND_MODE:
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;
/* ── DP3 绳索校准 (bool) ── */
diff --git a/apps/usr_jb_proto/usr_jb_main.c b/apps/usr_jb_proto/usr_jb_main.c
index ebf80b1..3724c39 100644
--- a/apps/usr_jb_proto/usr_jb_main.c
+++ b/apps/usr_jb_proto/usr_jb_main.c
@@ -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 "app_config.h"
#include "app_main.h"
#include "app_task.h"
#include "user_cfg.h"
-#include "vm.h"
-#include "sys_time.h"
#include "jb_protocol.h"
#include "jb_product.h"
#include "jb_ringbuffer.h"
#include "jb_common.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
+
+#define LOG_TAG_CONST APP
+#define LOG_TAG "[USR_JB]"
+#define LOG_INFO_ENABLE
+#include "debug.h"
/* 向 usr_le_code 库提供产品身份(换产品只改 jb_protocol.h 宏即可) */
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]
};
-void usr_timer_1_ms();
-static int jb_timer_id=0;
+static void usr_timer_1_ms(void *priv);
+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();
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();
+ 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();
jbProtocolHandle(&gDevData);
diff --git a/apps/usr_le_code/usr_le_api.h b/apps/usr_le_code/usr_le_api.h
index 4ccb3ba..0dd1746 100644
--- a/apps/usr_le_code/usr_le_api.h
+++ b/apps/usr_le_code/usr_le_api.h
@@ -24,16 +24,19 @@ extern "C" {
/**
* @brief 进入配对/配网模式
* @note 断开当前连接、清除配对信息(不复位),重新发绑定广播
+ * @return 无
*/
void usr_goto_pair_mode(void);
/**
* @brief 清除配对信息但不复位
+ * @return 无
*/
void usr_clear_pair_info_noreset(void);
/**
* @brief 清除配对信息并延时复位
+ * @return 无
*/
void usr_clear_pair_info(void);
@@ -46,6 +49,7 @@ uint8_t usr_get_pair_flag(void);
/**
* @brief 启动应用侧 OTA 流程
* @note 置位 usr_goto_updata,并创建 1s 周期定时器驱动断连与 OTA 广播切换
+ * @return 无
*/
void usr_app_ota_init(void);
diff --git a/apps/usr_periph/board_pin.h b/apps/usr_periph/board_pin.h
new file mode 100644
index 0000000..00ef301
--- /dev/null
+++ b/apps/usr_periph/board_pin.h
@@ -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__ */
diff --git a/apps/usr_periph/bsp_hw.c b/apps/usr_periph/bsp_hw.c
new file mode 100644
index 0000000..425c3c3
--- /dev/null
+++ b/apps/usr_periph/bsp_hw.c
@@ -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();
+}
diff --git a/apps/usr_periph/bsp_hw.h b/apps/usr_periph/bsp_hw.h
new file mode 100644
index 0000000..d7c7287
--- /dev/null
+++ b/apps/usr_periph/bsp_hw.h
@@ -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
+#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__ */
diff --git a/apps/usr_periph/usr_rtc.c b/apps/usr_periph/usr_rtc.c
index d44dbe4..8a4d116 100644
--- a/apps/usr_periph/usr_rtc.c
+++ b/apps/usr_periph/usr_rtc.c
@@ -64,7 +64,7 @@ static void usr_rtc_save_tz(int32_t tz_s);
/**
* @brief 打开 rtc 设备并加载时区
- * @return UsrRtc_Ret_t
+ * @return USR_RTC_OK=成功,USR_RTC_ERR_NOT_INIT=设备打开失败或 RTC 未使能
*/
UsrRtc_Ret_t usr_rtc_init(void)
{
@@ -101,7 +101,7 @@ UsrRtc_Ret_t usr_rtc_init(void)
/**
* @brief 获取当前本地时间
* @param t 成功时赋值;失败不改动
- * @return 1/0
+ * @return 1=已对时且读成功,0=未初始化/未对时/参数非法
*/
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
* @param unix_utc UTC 秒
* @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)
{
@@ -184,7 +184,7 @@ UsrRtc_Ret_t usr_rtc_set_from_unix(uint64_t unix_utc, int32_t tz_s)
/**
* @brief 写硬件日历
* @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)
{
@@ -216,7 +216,7 @@ static UsrRtc_Ret_t usr_rtc_write(const struct sys_time *t)
/**
* @brief 是否闰年
* @param year 公历年
- * @return 1/0
+ * @return 1=闰年,0=平年
*/
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 某月天数
* @param year 年
* @param month 月 1~12
- * @return 天数,非法月返回 0
+ * @return 该月天数;非法月份返回 0
*/
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 年份是否在合法窗口
* @param year 年
- * @return 1/0
+ * @return 1=合法,0=非法
*/
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 秒 + 时区 → 本地日历
* @param unix_utc UTC 秒
- * @param tz_s 时区偏移
- * @param t 输出
+ * @param tz_s 时区偏移秒
+ * @param t 输出本地日历
+ * @return 无
*/
static void usr_rtc_unix_to_calendar(uint32_t unix_utc, int32_t tz_s,
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 加载时区
+ * @return 无
*/
static void usr_rtc_load_tz(void)
{
@@ -350,6 +352,7 @@ static void usr_rtc_load_tz(void)
/**
* @brief 时区写入 VM
* @param tz_s 时区偏移秒
+ * @return 无
*/
static void usr_rtc_save_tz(int32_t tz_s)
{
diff --git a/apps/usr_periph/usr_rtc.h b/apps/usr_periph/usr_rtc.h
index 9c5de7e..ce4cb8d 100644
--- a/apps/usr_periph/usr_rtc.h
+++ b/apps/usr_periph/usr_rtc.h
@@ -40,9 +40,8 @@ typedef enum {
/*============================================================================*/
/**
- * @brief 打开 "rtc" 设备并加载时区
- * @return UsrRtc_Ret_t
- * @note app_main 启动时调用一次即可
+ * @brief 打开 rtc 设备并加载时区
+ * @return USR_RTC_OK=成功,USR_RTC_ERR_NOT_INIT=设备打开失败或 RTC 未使能
*/
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
* @param unix_utc UTC Unix 秒;0 无效
* @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);
diff --git a/cpu/br28/sdk.ld b/cpu/br28/sdk.ld
new file mode 100644
index 0000000..e05c972
--- /dev/null
+++ b/cpu/br28/sdk.ld
@@ -0,0 +1,2079 @@
+
+
+
+
+
+ lp_signature_set = ABSOLUTE(0x1fd6c);
+ memmem = ABSOLUTE(0x1fd70);
+ memcpy = ABSOLUTE(0x1fd74);
+ memmove = ABSOLUTE(0x1fd78);
+ memcmp = ABSOLUTE(0x1fd7c);
+ memset = ABSOLUTE(0x1fd80);
+ strcmp = ABSOLUTE(0x1fd84);
+ strcpy = ABSOLUTE(0x1fd88);
+ strlen = ABSOLUTE(0x1fd8c);
+ strncmp = ABSOLUTE(0x1fd90);
+ strstr = ABSOLUTE(0x1fd94);
+ strchr = ABSOLUTE(0x1fd98);
+ __divdi3 = ABSOLUTE(0x1fd9c);
+ __udivmoddi4 = ABSOLUTE(0x1fda0);
+ __adddf3 = ABSOLUTE(0x1fda4);
+ __fixdfsi = ABSOLUTE(0x1fda8);
+ flush_dcache = ABSOLUTE(0x1fdac);
+ flushinv_dcache = ABSOLUTE(0x1fdb0);
+ IcuWaitIdle = ABSOLUTE(0x1fdb4);
+ DcuWaitIdle = ABSOLUTE(0x1fdb8);
+ IcuInitial = ABSOLUTE(0x1fdbc);
+ DcuInitial = ABSOLUTE(0x1fdc0);
+
+
+ sfc_drop_cache = ABSOLUTE(0x1fdcc);
+ chip_crc16 = ABSOLUTE(0x1fdd0);
+ CrcDecode = ABSOLUTE(0x1fdd4);
+ get_flash_file_key = ABSOLUTE(0x1fdd8);
+ dec_isd_cfg_ini = ABSOLUTE(0x1fddc);
+ _jlfs_mount = ABSOLUTE(0x1fde0);
+ sfc_boot = ABSOLUTE(0x1fde4);
+ mask_init = ABSOLUTE(0x1fde8);
+
+ nvram_set_boot_state = ABSOLUTE(0x1fdf0);
+ chip_reset = ABSOLUTE(0x1fdf4);
+ the_debug_isr = ABSOLUTE(0x1fdf8);
+ print = ABSOLUTE(0x1fdfc);
+ sprintf = ABSOLUTE(0x1fe00);
+ printf = ABSOLUTE(0x1fe04);
+ puts = ABSOLUTE(0x1fe08);
+ doe = ABSOLUTE(0x1fe0c);
+ spi_get_port = ABSOLUTE(0x1fe10);
+ _pll_init = ABSOLUTE(0x1fe14);
+ flash_poweron = ABSOLUTE(0x1fe18);
+ spi_unmount = ABSOLUTE(0x1fe1c);
+ spi_port_io_init = ABSOLUTE(0x1fe20);
+ usb_slave_mode = ABSOLUTE(0x1fe24);
+ LZ4_setStreamDecode = ABSOLUTE(0x1fe28);
+ LZ4_decompress_safe_continue = ABSOLUTE(0x1fe2c);
+ LZ4_decompress_generic = ABSOLUTE(0x1fe30);
+ _sdk_mkey_lock = ABSOLUTE(0x1fe34);
+ g_hash_function = ABSOLUTE(0x1fe38);
+ f1_hash_function = ABSOLUTE(0x1fe3c);
+ f2_hash_function = ABSOLUTE(0x1fe40);
+ f3_hash_function = ABSOLUTE(0x1fe44);
+ h2_hash_function = ABSOLUTE(0x1fe48);
+ h3_hash_function = ABSOLUTE(0x1fe4c);
+ h4_hash_function = ABSOLUTE(0x1fe50);
+ h5_hash_function = ABSOLUTE(0x1fe54);
+ g_function = ABSOLUTE(0x1fe58);
+ f1_function = ABSOLUTE(0x1fe5c);
+ f2_function = ABSOLUTE(0x1fe60);
+ f3_function = ABSOLUTE(0x1fe64);
+ sha256Compute = ABSOLUTE(0x1fe68);
+ uECC_compute_public_key = ABSOLUTE(0x1fe6c);
+ uECC_shared_secret = ABSOLUTE(0x1fe70);
+ bi_initialize = ABSOLUTE(0x1fe74);
+ bi_read_from_byte = ABSOLUTE(0x1fe78);
+ bi_poly_mod2 = ABSOLUTE(0x1fe7c);
+ bi_poly_mul = ABSOLUTE(0x1fe80);
+ trim = ABSOLUTE(0x1fe84);
+ bi_wirte_to_byte = ABSOLUTE(0x1fe88);
+ bi_free = ABSOLUTE(0x1fe8c);
+ bi_terminate = ABSOLUTE(0x1fe90);
+ get_cvsd_codec_ops = ABSOLUTE(0x1fe94);
+ wtgv2_silk_NLSF_CB_NB_MB = ABSOLUTE(0x18590);
+ wtgv2_LSFCosTab_FIX_Q12 = ABSOLUTE(0x1848c);
+ icdf_global_table = ABSOLUTE(0x18a88);
+ get_wtgv2dec_ops = ABSOLUTE(0x1fe98);
+ wtgv2_silk_Decode = ABSOLUTE(0x1fe9c);
+ wtgv2_silk_decode_frame = ABSOLUTE(0x1fea0);
+ wtgv2_silk_decoder_set_fs = ABSOLUTE(0x1fea4);
+ wtgv2_silk_decode_indices = ABSOLUTE(0x1fea8);
+ wtgv2_silk_decode_pulses = ABSOLUTE(0x1feac);
+ wtgv2_silk_decode_parameters = ABSOLUTE(0x1feb0);
+ wtgv2_silk_decode_core = ABSOLUTE(0x1feb4);
+ logAprx_CORDIC_float = ABSOLUTE(0x1feb8);
+ expAprx_CORDIC_float = ABSOLUTE(0x1febc);
+ magnAprx_float = ABSOLUTE(0x1fec0);
+ MatrixCopy_float_c_c = ABSOLUTE(0x1fec4);
+ MatrixCopy_float_f_f = ABSOLUTE(0x1fec8);
+ MatrixEwMulAndSumOneDim_float_c_c_c_s0 = ABSOLUTE(0x1fecc);
+ MatrixEwMulAndSumOneDim_float_c_c_c_s1 = ABSOLUTE(0x1fed0);
+ MatrixEwMulAndSumOneDim_float_f_f_f_s0 = ABSOLUTE(0x1fed4);
+ MatrixEwMulAndSumOneDim_float_f_f_f_s1 = ABSOLUTE(0x1fed8);
+ MatrixEwConjMulAndSumOneDim_float_c_c_c_s0 = ABSOLUTE(0x1fedc);
+ MatrixEwConjMulAndSumOneDim_float_c_c_c_s1 = ABSOLUTE(0x1fee0);
+ VecMeanSq_s16_f32 = ABSOLUTE(0x1fee4);
+ VecOverShift_s16_f32 = ABSOLUTE(0x1fee8);
+ VecMinus_s16_f32_f32 = ABSOLUTE(0x1feec);
+ VectorCopy_f32_s16 = ABSOLUTE(0x1fef0);
+ VecEleMul_s16_s16_f32 = ABSOLUTE(0x1fef4);
+ VecEleMul_f32_s16_f32 = ABSOLUTE(0x1fef8);
+ VecMeanSq_float_f_f = ABSOLUTE(0x1fefc);
+ VectorSet_float_f_f = ABSOLUTE(0x1ff00);
+ VecMagRecAve_float_c_f_f = ABSOLUTE(0x1ff04);
+ VecMulScalar_float_c_f_c = ABSOLUTE(0x1ff08);
+ VecConjEleMul_float_c_c_c = ABSOLUTE(0x1ff0c);
+ VecPlus_float_f_f_f = ABSOLUTE(0x1ff10);
+ VecDivide_float_c_f_c_f = ABSOLUTE(0x1ff14);
+ VecPlus_float_c_c_c = ABSOLUTE(0x1ff18);
+ VecConjMulRecAve_float_c_c_c_f = ABSOLUTE(0x1ff1c);
+ VecGetMag_float_c_f = ABSOLUTE(0x1ff20);
+ VecMax_float_f_f = ABSOLUTE(0x1ff24);
+ VecRecAve_float_f_f_f = ABSOLUTE(0x1ff28);
+ VecEleMul_float_f_f_f = ABSOLUTE(0x1ff2c);
+ VecMagAndDiv_float_c_f_f_f = ABSOLUTE(0x1ff30);
+ VecMin_float_f_f = ABSOLUTE(0x1ff34);
+ VecMinus_float_f_f_f = ABSOLUTE(0x1ff38);
+ VecMean_float_f_f = ABSOLUTE(0x1ff3c);
+ VecEleMul_float_c_f_c = ABSOLUTE(0x1ff40);
+ VecMeanSqu_float_c_f = ABSOLUTE(0x1ff44);
+ VecCopy_float_f_f = ABSOLUTE(0x1ff48);
+ VecMin_float_f_f_f = ABSOLUTE(0x1ff4c);
+ VecDivide_float_f_f_f_f = ABSOLUTE(0x1ff50);
+ VecCompBT_float_f_f_f = ABSOLUTE(0x1ff54);
+ VecCondCopy_float_f_f_f = ABSOLUTE(0x1ff58);
+ VecMulScalar_float_f_f_f = ABSOLUTE(0x1ff5c);
+ VecPlusScalar_float_f_f_f = ABSOLUTE(0x1ff60);
+ VecMinScalar_float_f_f_f = ABSOLUTE(0x1ff64);
+ VecOpposite_float_f_f = ABSOLUTE(0x1ff68);
+ VecEleMla_float_f_f_f = ABSOLUTE(0x1ff6c);
+ VecEleMla_float_c_c_c = ABSOLUTE(0x1ff70);
+ VecMinus_float_c_c_c = ABSOLUTE(0x1ff74);
+ VecDotProduct_float_f_f_f = ABSOLUTE(0x1ff78);
+ VecDotProduct_float_c_c_c = ABSOLUTE(0x1ff7c);
+ VecDotProduct_float_c_f_c = ABSOLUTE(0x1ff80);
+ VecCopy_float_c_c = ABSOLUTE(0x1ff84);
+ VecCopy_float_f_c = ABSOLUTE(0x1ff88);
+ VecConjDotProduct_float_c_c_c = ABSOLUTE(0x1ff8c);
+ VecNormalize_float_c_c_f = ABSOLUTE(0x1ff90);
+ VecRecAve_float_c_c_f = ABSOLUTE(0x1ff94);
+ VecOverlapShift_float_f_f_i = ABSOLUTE(0x1ff98);
+ VecMax_float_f_f_f = ABSOLUTE(0x1ff9c);
+ VecConjEwMulAndDiv_float_c_c_f_f_c = ABSOLUTE(0x1ffa0);
+ VecPlusMulScalar_float_c_c_f_c = ABSOLUTE(0x1ffa4);
+ VecCondCopy_float_c_i_c = ABSOLUTE(0x1ffa8);
+ VecEleMulAndDiv_float_f_f_f_f_f = ABSOLUTE(0x1ffac);
+ VectorSet_float_f_c = ABSOLUTE(0x1ffb0);
+ VecDivScalar_float_f_f_f = ABSOLUTE(0x1ffb4);
+ VecDivScalar_float_c_f_c = ABSOLUTE(0x1ffb8);
+ VecPlusScalar_float_c_f_c = ABSOLUTE(0x1ffbc);
+ VecMinScalar_float_c_f_c = ABSOLUTE(0x1ffc0);
+ mdct_tab_256 = ABSOLUTE(0x19000);
+ mdct_tab_2048 = ABSOLUTE(0x19200);
+ sine_long_1024 = ABSOLUTE(0x1a200);
+ sine_short_128 = ABSOLUTE(0x1b200);
+ kbd_long_1024 = ABSOLUTE(0x1b400);
+ kbd_short_128 = ABSOLUTE(0x1c400);
+ Huffmancb_SCL = ABSOLUTE(0x1c634);
+ num_swb_960_window = ABSOLUTE(0x1c844);
+ num_swb_1024_window = ABSOLUTE(0x1c850);
+ num_swb_128_window = ABSOLUTE(0x1c85c);
+ swb_offset_1024_96 = ABSOLUTE(0x1c868);
+ swb_offset_128_96 = ABSOLUTE(0x1c8bc);
+ swb_offset_1024_64 = ABSOLUTE(0x1c8d6);
+ swb_offset_128_64 = ABSOLUTE(0x1c936);
+ swb_offset_1024_48 = ABSOLUTE(0x1c950);
+ swb_offset_128_48 = ABSOLUTE(0x1c9b4);
+ swb_offset_1024_32 = ABSOLUTE(0x1c9d2);
+ swb_offset_1024_24 = ABSOLUTE(0x1ca3a);
+ swb_offset_128_24 = ABSOLUTE(0x1ca9a);
+ swb_offset_1024_16 = ABSOLUTE(0x1caba);
+ swb_offset_128_16 = ABSOLUTE(0x1cb12);
+ swb_offset_1024_8 = ABSOLUTE(0x1cb32);
+ swb_offset_128_8 = ABSOLUTE(0x1cb84);
+ swb_offset_1024_window = ABSOLUTE(0x1cba4);
+ swb_offset_128_window = ABSOLUTE(0x1cbd4);
+ iq_table = ABSOLUTE(0x1cc04);
+ tns_coef_0_3 = ABSOLUTE(0x1d008);
+ tns_coef_0_4 = ABSOLUTE(0x1d048);
+ tns_coef_1_3 = ABSOLUTE(0x1d088);
+ tns_coef_1_4 = ABSOLUTE(0x1d0c8);
+ pow05_table = ABSOLUTE(0x1d108);
+ sample_rates = ABSOLUTE(0x1d124);
+ pred_sfb_max = ABSOLUTE(0x1d154);
+ tns_sbf_max = ABSOLUTE(0x1d160);
+ Huffmancb_1 = ABSOLUTE(0x1d1a0);
+ Huffmancb_2 = ABSOLUTE(0x1d338);
+ Huffmancb_3 = ABSOLUTE(0x1d470);
+ Huffmancb_4 = ABSOLUTE(0x1d5a8);
+ Huffmancb_5 = ABSOLUTE(0x1d6d8);
+ Huffmancb_6 = ABSOLUTE(0x1d820);
+ Huffmancb_7 = ABSOLUTE(0x1d960);
+ Huffmancb_8 = ABSOLUTE(0x1da58);
+ Huffmancb_9 = ABSOLUTE(0x1db50);
+ Huffmancb_10 = ABSOLUTE(0x1ddf0);
+ Huffmancb_11 = ABSOLUTE(0x1e080);
+ AACcodeBookDTable = ABSOLUTE(0x1e540);
+ AAC_SFHUFF_TAB = ABSOLUTE(0x1c83c);
+ get_aac_ops = ABSOLUTE(0x1ffc4);
+ silk_NLSF_CB_WB = ABSOLUTE(0x1e5b8);
+ silk_LTP_vq_ptrs_Q7 = ABSOLUTE(0x1ea5c);
+ get_opus_enc_ops = ABSOLUTE(0x1ffc8);
+ opus_encode = ABSOLUTE(0x1ffcc);
+ silk_Encode = ABSOLUTE(0x1ffd0);
+ silk_encode_do_VAD_FIX = ABSOLUTE(0x1ffd4);
+ silk_encode_frame_FIX = ABSOLUTE(0x1ffd8);
+ silk_find_pitch_lags_FIX = ABSOLUTE(0x1ffdc);
+ silk_noise_shape_analysis_FIX = ABSOLUTE(0x1ffe0);
+ silk_find_pred_coefs_FIX = ABSOLUTE(0x1ffe4);
+ silk_process_gains_FIX = ABSOLUTE(0x1ffe8);
+ silk_prefilter_FIX = ABSOLUTE(0x1ffec);
+ silk_NSQ_del_dec_c = ABSOLUTE(0x1fff0);
+ silk_encode_indices = ABSOLUTE(0x1fff4);
+ silk_encode_pulses = ABSOLUTE(0x1fff8);
+ silk_ana_filt_bank_1 = ABSOLUTE(0x1fffc);
+ STFT_Win_FixHalf_M512_D160 = ABSOLUTE(0x3804);
+ STFT_Win_FixHalf_M256_D160 = ABSOLUTE(0x3c04);
+ STFT_Win_FixHalf_M256_D80 = ABSOLUTE(0x3e04);
+ STFT_Win_FixHalf_M128_D80 = ABSOLUTE(0x4004);
+ WOLAAnalysisFilter_Float_M64_m4_r1 = ABSOLUTE(0x4);
+ WOLASynthesisFilter_Float_M64_m4_r1 = ABSOLUTE(0x404);
+ WOLAAnalysisFilter_Float_M128_m4_r1 = ABSOLUTE(0x804);
+ WOLASynthesisFilter_Float_M128_m4_r1 = ABSOLUTE(0x1004);
+ WOLAAnalysisFilter_Float_M256_m4_r1 = ABSOLUTE(0x1804);
+ WOLASynthesisFilter_Float_M256_m4_r1 = ABSOLUTE(0x2804);
+ quantize_intervals_LF = ABSOLUTE(0x9914);
+ invert_quantize_dither_factors_LF = ABSOLUTE(0x9a18);
+ quantize_dither_factors_LF = ABSOLUTE(0x9b1c);
+ quantize_factor_select_offset_LF = ABSOLUTE(0x9c20);
+ hd_quantize_intervals_LF = ABSOLUTE(0x9ca4);
+ boot_arg_list = ABSOLUTE(0x19fc28);
+ _IRQ_MEM_ADDR = ABSOLUTE(0x19fe00);
+ _MASK_MEM_BEGIN = ABSOLUTE(0x19fc00);
+ _MASK_MEM_SIZE = ABSOLUTE(0x1a4);
+
+EXTERN(
+_start
+
+sdfile_vfs_ops
+sbc_decoder
+
+
+
+msbc_decoder
+
+
+
+sbc_hwaccel
+
+
+
+cvsd_decoder
+
+
+
+pcm_decoder
+
+
+
+
+
+
+
+mp3_decoder
+);
+
+UPDATA_SIZE = 0x80;
+UPDATA_BEG = _MASK_MEM_BEGIN - UPDATA_SIZE;
+UPDATA_BREDR_BASE_BEG = 0x1A0000;
+
+RAM_LIMIT_L = 0x100000;
+RAM_LIMIT_H = UPDATA_BEG;
+PHY_RAM_SIZE = RAM_LIMIT_H - RAM_LIMIT_L;
+
+
+ISR_BASE = _IRQ_MEM_ADDR;
+ROM_RAM_SIZE = _MASK_MEM_SIZE;
+ROM_RAM_BEG = _MASK_MEM_BEGIN;
+
+
+RAM0_BEG = RAM_LIMIT_L + (128K * 2);
+
+
+
+RAM0_END = RAM_LIMIT_H;
+RAM0_SIZE = RAM0_END - RAM0_BEG;
+
+RAM1_BEG = RAM_LIMIT_L;
+RAM1_END = RAM0_BEG;
+RAM1_SIZE = RAM1_END - RAM1_BEG;
+
+
+CODE_BEG = 0x6000100;
+
+
+
+
+
+
+EQ_PRIV_COEFF_BASE =0x1A0600;
+EQ_PRIV_SECTION_NUM = 10;
+EQ_PRIV_COEFF_END = EQ_PRIV_COEFF_BASE + 4 * EQ_PRIV_SECTION_NUM * (5+3)*2;
+EQ_SECTION_NUM = 10;
+
+
+
+
+MEMORY
+{
+ code0(rx) : ORIGIN = CODE_BEG, LENGTH = 0x100000
+ ram0(rwx) : ORIGIN = RAM0_BEG, LENGTH = RAM0_SIZE
+
+
+
+
+ psr_ram(rwx) : ORIGIN = 0x2000000, LENGTH = 8*1024*1024
+}
+
+
+ENTRY(_start)
+
+SECTIONS
+{
+ . = ORIGIN(code0);
+ .text ALIGN(4):
+ {
+ PROVIDE(text_rodata_begin = .);
+
+ *(.startup.text)
+
+ *(.text)
+
+ . = ALIGN(4);
+ update_target_begin = .;
+ PROVIDE(update_target_begin = .);
+ KEEP(*(.update_target))
+ update_target_end = .;
+ PROVIDE(update_target_end = .);
+ . = ALIGN(4);
+
+ *(.LOG_TAG_CONST*)
+ *(.rodata*)
+
+ . = ALIGN(4);
+ PROVIDE(text_rodata_end = .);
+
+ clock_critical_handler_begin = .;
+ KEEP(*(.clock_critical_txt))
+ clock_critical_handler_end = .;
+
+ chargestore_handler_begin = .;
+ KEEP(*(.chargestore_callback_txt))
+ chargestore_handler_end = .;
+
+
+ *(.opcore_table_maskrom)
+ *(.bfilt_table_maskroom)
+ *(.opcore_maskrom)
+ *(.bfilt_code)
+ *(.bfilt_const)
+
+
+ . = ALIGN(4);
+
+ lcd_interface_begin = .;
+ KEEP(*(.lcd_if_info))
+ lcd_interface_end = .;
+
+ ui_style_begin = .;
+ KEEP(*(.ui_style))
+ ui_style_end = .;
+
+
+ elm_event_handler_begin_JL = .;
+ KEEP(*(.elm_event_handler_JL))
+ elm_event_handler_end_JL = .;
+
+ elm_event_handler_begin_UPGRADE = .;
+ KEEP(*(.elm_event_handler_UPGRADE))
+ elm_event_handler_end_UPGRADE = .;
+
+
+
+ elm_event_handler_begin_DIAL = .;
+ KEEP(*(.elm_event_handler_DIAL))
+ elm_event_handler_end_DIAL = .;
+
+
+ control_event_handler_begin = .;
+ KEEP(*(.control_event_handler))
+ control_event_handler_end = .;
+
+ control_ops_begin = .;
+ KEEP(*(.control_ops))
+ control_ops_end = .;
+
+ battery_notify_begin = .;
+ *(.battery_notify)
+ battery_notify_end = .;
+ . = ALIGN(4);
+ __VERSION_BEGIN = .;
+ KEEP(*(.sys.version))
+ __VERSION_END = .;
+
+ *(.noop_version)
+ . = ALIGN(4);
+
+ . = ALIGN(4);
+ tool_interface_begin = .;
+ KEEP(*(.tool_interface))
+ tool_interface_end = .;
+ . = ALIGN(4);
+ cmd_interface_begin = .;
+ KEEP(*(.eff_cmd))
+ cmd_interface_end = .;
+ . = ALIGN(4);
+
+
+ . = ALIGN(32);
+ m_code_addr = . ;
+ *(.m.code*)
+ *(.movable.code*)
+ m_code_size = ABSOLUTE(. - m_code_addr) ;
+ . = ALIGN(32);
+ } > code0
+
+ . = ORIGIN(ram0);
+
+ .mmu_tlb ALIGN(0x10000):
+ {
+ *(.mmu_tlb_segment);
+ } > ram0
+
+ .boot_info ALIGN(32):
+ {
+ *(.boot_info)
+ . = ALIGN(32);
+ } > ram0
+
+ .irq_stack ALIGN(32):
+ {
+ _cpu0_sstack_begin = .;
+ *(.cpu0_stack)
+ _cpu0_sstack_end = .;
+ . = ALIGN(4);
+
+ _cpu1_sstack_begin = .;
+ *(.cpu1_stack)
+ _cpu1_sstack_end = .;
+ . = ALIGN(4);
+
+ } > ram0
+
+ .data ALIGN(32):
+ {
+
+ . = ALIGN(4);
+ *(.data_magic)
+
+ . = ALIGN(4);
+
+
+ . = ALIGN(4);
+ audio_sync_data_begin = .;
+ *(.audio_sync_data)
+ audio_sync_data_end = .;
+ . = ALIGN(4);
+
+ *(.sbc_data)
+ *(.msbc_data)
+ *(.cvsd_data)
+ *(.aac_data)
+ *(.sbc_eng_data)
+ *(.bt_audioplc_data)
+ *(.lc3_decoder_data)
+ *(.lc3_dec_data)
+ *(.wtgv2_data)
+ *(.wtgv2dec_data)
+
+ *(.anc_data)
+ *(.anc_core_data)
+ *(.anc_user_data)
+ *(.anc_box_data)
+ *(.anc_btspp_data)
+
+ *(.sms_data)
+ *(.audio_track_data)
+ *(.audio_adc_data)
+
+ . = ALIGN(4);
+ *(.data*)
+
+ . = ALIGN(4);
+ } > ram0
+
+ .bss ALIGN(32):
+ {
+ . = ALIGN(4);
+ *(.bss)
+ . = ALIGN(4);
+ *(.volatile_ram)
+
+ *(.btstack_pool)
+
+ *(.mem_heap)
+ *(.memp_memory_x)
+
+ . = ALIGN(4);
+ *(.non_volatile_ram)
+
+ . = ALIGN(32);
+
+ *(.usb_h_dma)
+ *(.usb_ep0)
+
+
+
+
+
+
+
+ *(.usb_audio_play_dma)
+ *(.usb_audio_rec_dma)
+ *(.uac_rx)
+ *(.mass_storage)
+
+ *(.usb_msd_dma)
+ *(.usb_hid_dma)
+ *(.usb_iso_dma)
+ *(.usb_cdc_dma)
+ *(.uac_var)
+ *(.usb_config_var)
+ *(.cdc_var)
+ . = ALIGN(32);
+
+ } > ram0
+
+ .data_code ALIGN(32):
+ {
+ data_code_pc_limit_begin = .;
+ *(.flushinv_icache)
+ *(.cache)
+ *(.os_critical_code)
+ *(.volatile_ram_code)
+ *(.chargebox_code)
+ *(.fat_data_code)
+ *(.fat_data_code_ex)
+
+ *(.ui_ram)
+ *(.math_fast_funtion_code)
+ . = ALIGN(4);
+ *(.pSOUND360TD_cal_const)
+ *(.pSOUND360TD_cal_code)
+ . = ALIGN(4);
+ *(.SpatialAudio.text.const)
+ *(.SpatialAudio.text)
+ *(.SpatialAudio.text.cache.L1)
+
+ . = ALIGN(4);
+ _SPI_CODE_START = . ;
+ *(.spi_code)
+ . = ALIGN(4);
+ _SPI_CODE_END = . ;
+ . = ALIGN(4);
+
+ } > ram0
+
+ .moveable_slot ALIGN(4):
+ {
+ *(movable.slot.*)
+
+ } >ram0
+
+ __report_overlay_begin = .;
+
+
+ OVERLAY : AT(0x200000) SUBALIGN(4)
+ {
+ .overlay_aec
+ {
+ aec_code_begin = . ;
+ *(.text._*)
+ *(.data._*)
+ *(.aec_code)
+ *(.aec_const)
+ *(.res_code)
+ *(.res_const)
+ *(.ns_code)
+ *(.ns_const)
+ *(.bark_const)
+ *(.fft_code)
+ *(.fft_const)
+ *(.agc_code)
+ *(.dms_code)
+ *(.dms_const)
+ *(.dms_sparse_code)
+ aec_code_end = . ;
+ aec_code_size = aec_code_end - aec_code_begin ;
+
+ *(.msbc_enc)
+ *(.cvsd_codec)
+ *(.aec_bss)
+ *(.aec_data)
+ *(.res_data)
+ *(.ns_data)
+ *(.dns_common_data)
+ *(.dns_param_data_single)
+ *(.dns_param_data_dual)
+ *(.jlsp_nlp_code)
+ *(.jlsp_nlp_const)
+ *(.jlsp_aec_code)
+ *(.jlsp_aec_const)
+ *(.jlsp_prep_code)
+ *(.jlsp_prep_const)
+ *(.jlsp_enc_code)
+ *(.jlsp_enc_const)
+ *(.jlsp_wn_code)
+ *(.jlsp_wn_const)
+ *(.jlsp_tri_code)
+ *(.jlsp_tri_const)
+ *(.jlsp_agc_code)
+ *(.jlsp_agc_const)
+ *(.res_bss)
+ *(.ns_bss)
+ *(.aec_mem)
+ }
+ .overlay_aac
+ {
+
+ aac_dec_code_begin = .;
+ *(.bt_aac_dec_code)
+ *(.bt_aac_dec_sparse_code)
+ aac_dec_code_end = .;
+ aac_dec_code_size = aac_dec_code_end - aac_dec_code_begin ;
+
+ . = ALIGN(4);
+ bt_aac_dec_const_begin = .;
+ *(.bt_aac_dec_const)
+ *(.bt_aac_dec_sparse_const)
+ bt_aac_dec_const_end = .;
+ bt_aac_dec_const_size = bt_aac_dec_const_end - bt_aac_dec_const_begin ;
+
+ *(.bt_aac_dec_data)
+ *(.bt_aac_dec_bss)
+
+ . = ALIGN(4);
+ *(.aac_mem)
+ *(.aac_ctrl_mem)
+
+
+
+ }
+ .overlay_mp3
+ {
+ *(.mp3_mem)
+ *(.mp3_ctrl_mem)
+ *(.mp3pick_mem)
+ *(.mp3pick_ctrl_mem)
+ *(.dec2tws_mem)
+ }
+ .overlay_wma
+ {
+ *(.wma_mem)
+ *(.wma_ctrl_mem)
+ *(.wmapick_mem)
+ *(.wmapick_ctrl_mem)
+ }
+ .overlay_wav
+ {
+ *(.wav_mem)
+ *(.wav_ctrl_mem)
+ }
+ .overlay_ape
+ {
+ *(.ape_mem)
+ *(.ape_ctrl_mem)
+ }
+ .overlay_flac
+ {
+ *(.flac_mem)
+ *(.flac_ctrl_mem)
+ }
+ .overlay_m4a
+ {
+ *(.m4a_mem)
+ *(.m4a_ctrl_mem)
+ }
+ .overlay_amr
+ {
+ *(.amr_mem)
+ *(.amr_ctrl_mem)
+ }
+ .overlay_dts
+ {
+ *(.dts_mem)
+ *(.dts_ctrl_mem)
+ }
+ .overlay_fm
+ {
+ *(.fm_mem)
+ }
+ .overlay_pc
+ {
+ *(.usb_audio_play_dma)
+ *(.usb_audio_rec_dma)
+ *(.uac_rx)
+ *(.mass_storage)
+
+ *(.usb_ep0)
+ *(.usb_msd_dma)
+ *(.usb_hid_dma)
+ *(.usb_iso_dma)
+ *(.usb_cdc_dma)
+ *(.uac_var)
+ *(.usb_config_var)
+ *(.cdc_var)
+ }
+
+ } > ram0
+
+ data_code_pc_limit_end = .;
+ __report_overlay_end = .;
+
+ _HEAP_BEGIN = . ;
+ _HEAP_END = RAM0_END;
+
+
+ . = ORIGIN(psr_ram);
+ .psr_data_code ALIGN(32):
+ {
+ *(.psram_data_code)
+ . = ALIGN(4);
+ } > psr_ram
+
+ .psr_bss_code ALIGN(32):
+ {
+ . = ALIGN(4);
+ } > psr_ram
+}
+
+
+
+
+SECTIONS
+{
+ .text : ALIGN(4)
+ {
+ gsensor_dev_begin = .;
+ KEEP(*(.gsensor_dev))
+ gsensor_dev_end = .;
+
+ fm_dev_begin = .;
+ KEEP(*(.fm_dev))
+ fm_dev_end = .;
+
+ fm_emitter_dev_begin = .;
+ KEEP(*(.fm_emitter_dev))
+ fm_emitter_dev_end = .;
+
+ storage_device_begin = .;
+ KEEP(*(.storage_device))
+ storage_device_end = .;
+
+ imusensor_dev_begin = .;
+ KEEP(*(.imusensor_dev))
+ imusensor_dev_end = .;
+ . = ALIGN(32);
+ }
+
+ .data ALIGN(32):
+ {
+ } > ram0
+
+ .bss ALIGN(32):
+ {
+ } > ram0
+
+ .data_code ALIGN(32):
+ {
+ } > ram0
+
+}
+
+
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ update_data_start = .;
+
+ update_data_end = .;
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ update_bss_start = .;
+
+ *(.update_bss)
+ update_bss_end = .;
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ update_code_start = .;
+
+ *(.bt_updata_ram_code)
+ *(.update_const)
+ *(.update_code)
+
+ update_code_end = .;
+ } > code0
+
+
+ UPDATE_CODE_TOTAL_SIZE = update_code_end - update_code_start;
+}
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ btstack_data_start = .;
+ *(.bt_stack_data)
+ *(.ble_db_data)
+ *(.ble_sm_data)
+ *(.ble_att_data)
+ *(.ble_gatt_data)
+
+
+ BTSTACK_LE_HOST_MESH_DATA_START = .;
+ . = (. +3) & ~ 3;
+ _net_buf_pool_list = .;
+ *(._net_buf_pool.static.*)
+
+ *(.ble_mesh_data)
+ *(.ble_mesh_tinycrypt_data)
+ BTSTACK_LE_HOST_MESH_DATA_SIZE = ABSOLUTE(. - BTSTACK_LE_HOST_MESH_DATA_START);
+
+ btstack_data_end = .;
+
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ btstack_bss_start = .;
+ *(.bt_stack_bss)
+ *(.ble_db_bss)
+ *(.ble_sm_bss)
+ *(.ble_att_bss)
+ *(.ble_gatt_bss)
+ *(.btstack_pool)
+
+
+ BTSTACK_LE_HOST_MESH_BSS_START = .;
+ *(.ble_mesh_bss)
+ *(.ble_mesh_tinycrypt_bss)
+ BTSTACK_LE_HOST_MESH_BSS_SIZE = ABSOLUTE(. - BTSTACK_LE_HOST_MESH_BSS_START);
+
+ btstack_bss_end = .;
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ btstack_code_start = .;
+
+ . = ALIGN(4);
+
+ a2dp_source_media_codec_begin = .;
+ KEEP(*(.a2dp_source_media_codec))
+ a2dp_source_media_codec_end = .;
+ a2dp_sink_media_probe_begin = .;
+ KEEP(*(.a2dp_sink_media_probe))
+ a2dp_sink_media_probe_end = .;
+
+ a2dp_sink_media_codec_begin = .;
+ KEEP(*(.a2dp_sink_media_codec))
+ a2dp_sink_media_codec_end = .;
+
+ a2dp_event_handler_begin = .;
+ KEEP(*(.a2dp_event_handler))
+ a2dp_event_handler_end = .;
+
+ sdp_record_item_begin = .;
+ KEEP(*(.sdp_record_item))
+ sdp_record_item_end = .;
+
+ bt_sleep_begin = .;
+ KEEP(*(.bt_sleep))
+ bt_sleep_end = .;
+
+ *(.bt_stack_const)
+ *(.bt_stack_code)
+ *(.ble_db_const)
+ *(.ble_db_code)
+ *(.ble_sm_const)
+ *(.ble_sm_code)
+ *(.ble_att_const)
+ *(.ble_att_code)
+ *(.ble_gatt_const)
+ *(.ble_gatt_code)
+
+
+ BTSTACK_LE_HOST_MESH_CODE_START = .;
+ *(.ble_mesh_code)
+ *(.ble_mesh_tinycrypt_code)
+
+ *(.ble_mesh_const)
+ *(.ble_mesh_tinycrypt_const)
+ BTSTACK_LE_HOST_MESH_CODE_SIZE = ABSOLUTE(. - BTSTACK_LE_HOST_MESH_CODE_START);
+
+ btstack_code_end = .;
+ . = ALIGN(4);
+ } > code0
+}
+
+BTSTACK_LE_HOST_MESH_RAM_TOTAL = BTSTACK_LE_HOST_MESH_DATA_SIZE + BTSTACK_LE_HOST_MESH_BSS_SIZE;
+BTSTACK_LE_HOST_MESH_FLASH_TOTAL = BTSTACK_LE_HOST_MESH_CODE_SIZE;
+
+BTSTACK_CODE_SIZE = (btstack_code_end - btstack_code_start) + (btstack_data_end - btstack_data_start);
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ . = ALIGN(4);
+ system_data_start = .;
+
+ _video_subdev_begin = .;
+ PROVIDE(video_subdev_begin = .);
+ KEEP(*(.video_subdev.0))
+ KEEP(*(.video_subdev.1))
+ KEEP(*(.video_subdev.2))
+ KEEP(*(.video_subdev.3))
+ KEEP(*(.video_subdev.4))
+ KEEP(*(.video_subdev.5))
+ _video_subdev_end = .;
+ PROVIDE(video_subdev_end = .);
+
+ _audio_subdev_begin = .;
+ PROVIDE(audio_subdev_begin = .);
+ KEEP(*(.audio_subdev.0))
+ KEEP(*(.audio_subdev.1))
+ KEEP(*(.audio_subdev.2))
+ KEEP(*(.audio_subdev.3))
+ _audio_subdev_end = .;
+ PROVIDE(audio_subdev_end = .);
+
+ _iic_device_begin = .;
+ PROVIDE(iic_device_begin = .);
+ KEEP(*(.iic))
+ _iic_device_end = .;
+ PROVIDE(iic_device_end = .);
+
+ _avin_spi_device_begin = .;
+ PROVIDE(avin_spi_device_begin = .);
+ KEEP(*(.sw_spi))
+ _avin_spi_device_end = .;
+ PROVIDE(avin_spi_device_end = .);
+
+ _video_dev_begin = .;
+ PROVIDE(video_dev_begin = .);
+ KEEP(*(.video_device))
+ _video_dev_end = .;
+ PROVIDE(video_dev_end = .);
+
+ _key_driver_ops_begin = .;
+ PROVIDE(key_driver_ops_begin = .);
+ KEEP(*(.key_driver_ops))
+ _key_driver_ops_end = .;
+ PROVIDE(key_driver_ops_end = .);
+
+ _touch_driver_begin = .;
+ PROVIDE(touch_driver_begin = .);
+ KEEP(*(.touch_driver))
+ _touch_driver_end = .;
+ PROVIDE(touch_driver_end = .);
+
+ _static_hi_timer_begin = .;
+ PROVIDE(static_hi_timer_begin = .);
+ KEEP(*(.hi_timer))
+ _static_hi_timer_end = .;
+ PROVIDE(static_hi_timer_end = .);
+
+ _sys_cpu_timer_begin = .;
+ PROVIDE(sys_cpu_timer_begin = .);
+ KEEP(*(.sys_cpu_timer))
+ _sys_cpu_timer_end = .;
+ PROVIDE(sys_cpu_timer_end = .);
+
+ _sys_config_begin = .;
+ PROVIDE(sys_config_begin = .);
+ KEEP(*(.sys_cfg))
+ _sys_config_end = .;
+ PROVIDE(sys_config_end = .);
+
+ _sys_fat_begin = .;
+ PROVIDE(sys_fat_begin = .);
+ KEEP(*(.fs_fat))
+ _sys_fat_end = .;
+ PROVIDE(sys_fat_end = .);
+
+ _app_begin = .;
+ PROVIDE(app_begin = .);
+ KEEP(*(.app))
+ _app_end = .;
+ PROVIDE(app_end = .);
+
+ *(.crypto_ecdh_data)
+ *(.crypto_data)
+
+ *(.mem_data)
+ *(.os_port_data)
+
+ *(.os_str)
+ *(.os_data)
+
+ *(.uECC_data)
+ *(.ECDH_sample_data)
+
+ __movable_slot_start = .;
+ *(movable.slot.*);
+ __movable_slot_end = .;
+
+ system_data_end = .;
+
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ system_bss_start = .;
+ . = ALIGN(4);
+ *(.os_bss)
+ *(.mem_heap)
+ *(.memp_memory_x)
+ *(.mem_bss)
+ *(.os_port_bss)
+
+ *(.uECC_bss)
+ *(.ECDH_sample_bss)
+
+ system_bss_end = .;
+
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ . = ALIGN(4);
+ system_text_start = .;
+
+ _device_node_begin = .;
+ PROVIDE(device_node_begin = .);
+ KEEP(*(.device))
+ _device_node_end = .;
+ PROVIDE(device_node_end = .);
+
+ config_target_begin = .;
+ PROVIDE(config_target_begin = .);
+ KEEP(*(.config_target))
+ config_target_end = .;
+ PROVIDE(config_target_end = .);
+
+ system_code_begin = .;
+ KEEP(*(.system.*.text))
+ system_code_end = .;
+ . = ALIGN(4);
+ system_code_size = system_code_end - system_code_begin;
+
+ vfs_ops_begin = .;
+ KEEP(*(.vfs_operations))
+ vfs_ops_end = .;
+
+ _lib_version_begin = .;
+ PROVIDE(lib_version_begin = .);
+ KEEP(*(.lib_version))
+ _lib_version_end = .;
+ PROVIDE(lib_version_end = .);
+
+ _initcall_begin = .;
+ PROVIDE(initcall_begin = .);
+ KEEP(*(.initcall))
+ _initcall_end = .;
+ PROVIDE(initcall_end = .);
+
+ _early_initcall_begin = .;
+ PROVIDE(early_initcall_begin = .);
+ KEEP(*(.early.initcall))
+ _early_initcall_end = .;
+ PROVIDE(early_initcall_end = .);
+
+ _late_initcall_begin = .;
+ PROVIDE(late_initcall_begin = .);
+ KEEP(*(.late.initcall))
+ _late_initcall_end = .;
+ PROVIDE(late_initcall_end = .);
+
+ _platform_initcall_begin = .;
+ PROVIDE(platform_initcall_begin = .);
+ KEEP(*(.platform.initcall))
+ _platform_initcall_end = .;
+ PROVIDE(platform_initcall_end = .);
+
+ _module_initcall_begin = .;
+ PROVIDE(module_initcall_begin = .);
+ KEEP(*(.module.initcall))
+ _module_initcall_end = .;
+ PROVIDE(module_initcall_end = .);
+
+ _sys_event_handler_begin = .;
+ PROVIDE(sys_event_handler_begin = .);
+ KEEP(*(.sys_event.4.handler))
+ KEEP(*(.sys_event.3.handler))
+ KEEP(*(.sys_event.2.handler))
+ KEEP(*(.sys_event.1.handler))
+ KEEP(*(.sys_event.0.handler))
+ _sys_event_handler_end = .;
+ PROVIDE(sys_event_handler_end = .);
+
+ _syscfg_arg_begin = .;
+ PROVIDE(syscfg_arg_begin = .);
+ KEEP(*(.syscfg.arg))
+ _syscfg_arg_end = .;
+ PROVIDE(syscfg_arg_end = .);
+
+ _syscfg_handler_begin = .;
+ PROVIDE(syscfg_handler_begin = .);
+ KEEP(*(.syscfg.handler))
+ _syscfg_handler_end = .;
+ PROVIDE(syscfg_handler_end = .);
+
+ _syscfg_ops_begin = .;
+ PROVIDE(syscfg_ops_begin = .);
+ KEEP(*(.syscfg.2.ops))
+ KEEP(*(.syscfg.1.ops))
+ KEEP(*(.syscfg.0.ops))
+ _syscfg_ops_end = .;
+ PROVIDE(syscfg_ops_end = .);
+
+ _server_info_begin = .;
+ PROVIDE(server_info_begin = .);
+ KEEP(*(.server_info))
+ _server_info_end = .;
+ PROVIDE(server_info_end = .);
+
+ _bus_device_begin = .;
+ PROVIDE(bus_device_begin = .);
+ KEEP(*(.bus_device))
+ _bus_device_end = .;
+ PROVIDE(bus_device_end = .);
+
+ _sys_power_hal_ops_begin = .;
+ PROVIDE(sys_power_hal_ops_begin = .);
+ KEEP(*(.sys_power_hal_ops))
+ _sys_power_hal_ops_end = .;
+ PROVIDE(sys_power_hal_ops_end = .);
+
+
+
+ crypto_begin = .;
+ *(.crypto_ecdh_code)
+ *(.crypto_ecdh_const)
+
+ *(.crypto_bigint_code)
+ *(.crypto_bigint_const)
+
+ *(.crypto_code)
+ *(.crypto_const)
+
+ *(.ECDH_sample_code)
+ *(.ECDH_sample_const)
+
+ *(.uECC_code)
+ *(.uECC_const)
+
+ *(.hmac_code)
+ *(.hmac_const)
+
+ *(.hash_sample_code)
+ *(.hash_sample_const)
+
+ *(.aes_cmac_sample_code)
+ *(.aes_cmac_sample_const)
+ crypto_end = .;
+ crypto_size = . - crypto_begin;
+
+ *(.mem_code)
+ *(.mem_const)
+
+ *(.os_port_code)
+ *(.os_port_const)
+
+ *(.os_const)
+
+ *(.math_fast_funtion_code)
+
+ __movable_function_start = .;
+ *(movable.text.*);
+ *(movable.stub.*);
+ *(movable.region.*);
+
+ __movable_function_end = .;
+ __movable_function_size = __movable_function_end - __movable_function_start;
+
+ system_text_end = .;
+
+
+ system_code_total_size = system_text_end - system_text_start;
+ } > code0
+
+ .data_code ALIGN(32):
+ {
+ *(.os_code)
+ } > ram0
+}
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ btctler_data_start = .;
+
+ BTCTLER_CONTROLLER_DATA_START = .;
+ *(.bt_rf_data)
+ *(.vendor_manager_data)
+ *(.device_manager_data)
+ *(.hci_controller_data)
+ *(.hci_interface_data)
+ BTCTLER_CONTROLLER_DATA_SIZE = ABSOLUTE(. - BTCTLER_CONTROLLER_DATA_START);
+
+ BTCTLER_LE_CONTROLLER_DATA_START = .;
+ *(.ble_ll_data)
+ *(.ble_hci_data)
+ *(.ble_rf_data)
+ BTCTLER_LE_CONTROLLER_DATA_SIZE = ABSOLUTE(. - BTCTLER_LE_CONTROLLER_DATA_START);
+
+ BTCTLER_CL_DATA_START = .;
+ *(.classic_hci_data)
+ *(.classic_lmp_data)
+ *(.classic_lmp_auth_data)
+ *(.classic_lmp_bigint_data)
+ *(.classic_lmp_crypt_data)
+ *(.classic_lmp_ecdh_data)
+ *(.classic_lmp_linkbulk_data)
+ *(.classic_lmp_hmac_data)
+ *(.classic_rf_data)
+ *(.classic_bb_data)
+ BTCTLER_CL_DATA_SIZE = ABSOLUTE(. - BTCTLER_CL_DATA_START);
+
+ btctler_data_end = .;
+
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ btctler_bss_start = .;
+
+ BTCTLER_CONTROLLER_BSS_START = .;
+
+ *(.bd_base)
+ *(.bredr_rxtx_bulk)
+ *(.bredr_tx_bulk)
+ *(.bt_rf_bss)
+ *(.hci_controller_bss)
+ *(.hci_interface_bss)
+ *(.device_manager_bss)
+ *(.vendor_manager_bss)
+ BTCTLER_CONTROLLER_BSS_SIZE = ABSOLUTE(. - BTCTLER_CONTROLLER_BSS_START);
+
+ BTCTLER_LE_CONTROLLER_BSS_START = .;
+ *(.ble_hci_bss)
+ *(.ble_ll_bss)
+ *(.ble_rf_bss)
+ BTCTLER_LE_CONTROLLER_BSS_SIZE = ABSOLUTE(. - BTCTLER_LE_CONTROLLER_BSS_START);
+
+ BTCTLER_CL_BSS_START = .;
+ *(.classic_rf_bss)
+ *(.classic_lmp_bss)
+ *(.classic_lmp_auth_bss)
+ *(.classic_lmp_bigint_bss)
+ *(.classic_lmp_crypt_bss)
+ *(.classic_lmp_ecdh_bss)
+ *(.classic_lmp_linkbulk_bss)
+ *(.classic_lmp_hmac_bss)
+ *(.classic_bb_bss)
+ *(.classic_hci_bss)
+ BTCTLER_CL_BSS_SIZE = ABSOLUTE(. - BTCTLER_CL_BSS_START);
+
+ btctler_bss_end = .;
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ btctler_code_start = .;
+
+ BTCTLER_CONTROLLER_CODE_START = .;
+ *(.bt_rf_const)
+ *(.bt_rf_code)
+ *(.vendor_manager_const)
+ *(.vendor_manager_code)
+ *(.device_manager_const)
+ *(.device_manager_code)
+ *(.hci_controller_const)
+ *(.hci_controller_code)
+ *(.hci_interface_const)
+ *(.hci_interface_code)
+ BTCTLER_CONTROLLER_CODE_SIZE = ABSOLUTE(. - BTCTLER_CONTROLLER_CODE_START);
+
+ BTCTLER_LE_CONTROLLER_CODE_START = .;
+ *(.ble_rf_const)
+ *(.ble_rf_code)
+
+ *(.ble_ll_const)
+ *(.ble_ll_code)
+ *(.ble_hci_const)
+ *(.ble_hci_code)
+ BTCTLER_LE_CONTROLLER_CODE_SIZE = ABSOLUTE(. - BTCTLER_LE_CONTROLLER_CODE_START);
+
+ BTCTLER_CL_CODE_START = .;
+ *(.bredr_irq)
+ *(.bredr_irq_code)
+ *(.bredr_irq_const)
+
+ *(.classic_hci_const)
+ *(.classic_hci_code)
+ *(.classic_lmp_const)
+ *(.classic_lmp_auth_const)
+ *(.classic_lmp_bigint_const)
+ *(.classic_lmp_crypt_const)
+ *(.classic_lmp_ecdh_const)
+ *(.classic_lmp_hmac_const)
+ *(.classic_lmp_code)
+ *(.classic_lmp_auth_code)
+ *(.classic_lmp_bigint_code)
+ *(.classic_lmp_crypt_code)
+ *(.classic_lmp_ecdh_code)
+ *(.classic_lmp_hmac_code)
+ *(.classic_rf_const)
+ *(.classic_rf_code)
+ *(.classic_bb_const)
+ *(.classic_bb_code)
+ BTCTLER_CL_CODE_SIZE = ABSOLUTE(. - BTCTLER_CL_CODE_START);
+
+ *(.classic_tws_const)
+ *(.classic_tws_code)
+ *(.classic_tws_code.esco)
+
+ . = ALIGN(4);
+
+ } > code0
+
+
+ .data_code ALIGN(32):
+ {
+
+ . = ALIGN(4);
+
+ *(.lmp_irq_code)
+ *(.link_bulk_code)
+ *(.frame_irq_code)
+
+ . = ALIGN(4);
+ *(.link_task_const)
+ *(.link_task_code)
+
+ . = ALIGN(4);
+ *(.classic_irq_const)
+ *(.classic_irq_code)
+
+
+ . = ALIGN(4);
+ *(.tws_irq_code)
+
+ . = ALIGN(4);
+ tws_sync_call_begin = .;
+ KEEP(*(.tws_sync_call))
+ tws_sync_call_end = .;
+
+ . = ALIGN(4);
+ tws_func_stub_begin = .;
+ KEEP(*(.tws_func_stub))
+ tws_func_stub_end = .;
+
+ *(.tws_media_sync_code)
+ *(.tws_media_sync_const)
+
+ *(.tws_data_forward_code)
+ *(.tws_data_forward_const)
+
+ . = ALIGN(4);
+ tws_sync_channel_begin = .;
+ KEEP(*(.tws_sync_channel.0))
+ KEEP(*(.tws_sync_channel.1))
+ KEEP(*(.tws_sync_channel.2))
+ KEEP(*(.tws_sync_channel.3))
+ KEEP(*(.tws_sync_channel.4))
+ KEEP(*(.tws_sync_channel.5))
+ KEEP(*(.tws_sync_channel.6))
+ KEEP(*(.tws_sync_channel.7))
+ KEEP(*(.tws_sync_channel.8))
+ KEEP(*(.tws_sync_channel.9))
+ KEEP(*(.tws_sync_channel.10))
+ KEEP(*(.tws_sync_channel.11))
+ KEEP(*(.tws_sync_channel.12))
+ KEEP(*(.tws_sync_channel.13))
+ tws_sync_channel_end = .;
+
+ btctler_code_end = .;
+
+ . = ALIGN(4);
+ } > ram0
+
+
+ BTCTLER_LE_RAM_TOTAL = BTCTLER_LE_CONTROLLER_DATA_SIZE + BTCTLER_LE_CONTROLLER_BSS_SIZE;
+ BTCTLER_LE_CODE_TOTAL = BTCTLER_LE_CONTROLLER_CODE_SIZE;
+
+ BTCTLER_CL_RAM_TOTAL = BTCTLER_CL_DATA_SIZE + BTCTLER_CL_BSS_SIZE;
+ BTCTLER_CL_CODE_TOTAL = BTCTLER_CL_CODE_SIZE;
+
+ BTCTLER_COMMON_RAM_TOTAL = BTCTLER_CONTROLLER_BSS_SIZE + BTCTLER_CONTROLLER_DATA_SIZE;
+ BTCTLER_COMMON_CODE_TOTAL = BTCTLER_CONTROLLER_CODE_SIZE ;
+
+ BTCTLER_RAM_TOTAL = (btctler_data_end - btctler_data_start) + (btctler_bss_end - btctler_bss_start);
+ BTCTLER_CODE_TOTAL = (btctler_code_end - btctler_code_start);
+}
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ driver_data_start = .;
+
+
+ CLOCK_DATA_START = .;
+ *(.clock_data)
+ CLOCK_DATA_SIZE = ABSOLUTE(. - CLOCK_DATA_START);
+
+ *(.debug_data)
+
+ *(.uart_data)
+
+ *(.power_driver.data)
+ *(.power_reset.data)
+ *(.power_wakeup.data)
+
+ driver_data_end = .;
+ . = ALIGN(32);
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ driver_bss_start = .;
+
+ CLOCK_BSS_START = .;
+ *(.clock_bss)
+ CLOCK_BSS_SIZE = ABSOLUTE(. - CLOCK_BSS_START);
+
+ *(.debug_bss)
+
+ *(.uart_bss)
+
+ *(.sd_var)
+
+ *(.power_driver.data.bss)
+ *(.power_reset.data.bss)
+ *(.power_wakeup.data.bss)
+
+ driver_bss_end = .;
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ driver_code_start = .;
+
+ *(.fm_code)
+
+ CLOCK_CODE_START = .;
+ *(.clock_code)
+ *(.clock_const)
+ CLOCK_CODE_SIZE = ABSOLUTE(. - CLOCK_CODE_START);
+
+ *(.debug_code)
+ *(.debug_const)
+
+ *(.uart_code)
+ *(.uart_const)
+
+ *(.power_driver.text)
+ *(.power_driver.text.const)
+
+ *(.power_reset.text)
+ *(.power_reset.text.const)
+
+ *(.power_wakeup.text)
+ *(.power_wakeup.text.const)
+
+ . = ALIGN(4);
+ lp_target_begin = .;
+ PROVIDE(lp_target_begin = .);
+ KEEP(*(.lp_target))
+ lp_target_end = .;
+ PROVIDE(lp_target_end = .);
+
+ . = ALIGN(4);
+ lp_request_begin = .;
+ PROVIDE(lp_request_begin = .);
+ KEEP(*(.lp_request))
+ lp_request_end = .;
+ PROVIDE(lp_request_end = .);
+
+ . = ALIGN(4);
+ deepsleep_target_begin = .;
+ PROVIDE(deepsleep_target_begin = .);
+ KEEP(*(.deepsleep_target))
+ deepsleep_target_end = .;
+ PROVIDE(deepsleep_target_end = .);
+
+ . = ALIGN(4);
+ p2m_msg_handler_begin = .;
+ PROVIDE(p2m_msg_handler_begin = .);
+ KEEP(*(.p2m_msg_handler))
+ PROVIDE(p2m_msg_handler_end = .);
+ p2m_msg_handler_end = .;
+
+ driver_code_end = .;
+ . = ALIGN(4);
+ } > code0
+
+ .data_code : ALIGN(4)
+ {
+ driver_data_code_start = .;
+
+
+ CLOCK_CACHE_L1_CODE_START = .;
+ *(.clock.text.cache.L1)
+ CLOCK_CACHE_L1_SIZE = ABSOLUTE(. - CLOCK_CACHE_L1_CODE_START);
+
+ *(.vm.text.cache.L1)
+
+ *(.power_driver.text.cache.L1)
+ *(.timer.text.cache.L1)
+ *(.gpio.text.cache.L1)
+ *(.iic_hw.text.cache.L1)
+ driver_data_code_end = .;
+ . = ALIGN(4);
+ } > ram0
+
+
+ DRIVER_RAM_TOTAL = (driver_data_end - driver_data_start) + (driver_bss_end - driver_bss_start);
+ DRIVER_CODE_TOTAL = (driver_code_end - driver_code_start);
+ DRIVER_DATA_CODE_TOTAL = (driver_data_code_end - driver_data_code_start);
+
+}
+SECTIONS
+{
+ .data : ALIGN(4)
+ {
+ . = ALIGN(4);
+ audio_sync_data_begin = .;
+ *(.audio_sync_data)
+ audio_sync_data_end = .;
+ . = ALIGN(4);
+
+ *(.sbc_data)
+ *(.msbc_data)
+ *(.cvsd_data)
+ *(.aac_data)
+ *(.ldac_decoder_data)
+ *(.sbc_eng_data)
+ *(.bt_audioplc_data)
+ *(.lc3_decoder_data)
+ *(.lc3_dec_data)
+ *(.wtgv2_data)
+ *(.wtgv2dec_data)
+ *(.opus_encoder_data)
+ *(.speex_encoder_data)
+
+ *(.anc_data)
+ *(.anc_user_data)
+ *(.anc_box_data)
+ *(.anc_btspp_data)
+ *(.audio_adc_data)
+ *(.audio_cfifo_data)
+
+ *(.sms_data)
+ . = ALIGN(4);
+ *(.pSOUND360TD_cal_data)
+ . = ALIGN(4);
+ *(.jlsp_data)
+ *(.jlsp_aec_data)
+ *(.jlsp_nlp_data)
+ *(.jlsp_dns_data)
+ *(.jlsp_enc_data)
+ *(.jlsp_prep_data)
+ *(.jlsp_wn_data)
+ *(.jlsp_tri_data)
+ *(.jlsp_agc_data)
+ . = ALIGN(4);
+
+
+
+
+ } > ram0
+
+ .bss (NOLOAD) :ALIGN(4)
+ {
+ . = ALIGN(4);
+ audio_sync_bss_begin = .;
+ *(.audio_sync_bss)
+ audio_sync_bss_end = .;
+ . = ALIGN(4);
+
+ *(.cvsd_bss)
+ *(.aac_bss)
+ *(.ldac_decoder_bss)
+ *(.sbc_eng_bss)
+ *(.bt_audioplc_bss)
+ *(.lc3_decoder_bss)
+ *(.lc3_dec_bss)
+ *(.wtgv2_bss)
+ *(.wtgv2dec_bss)
+ *(.speex_encoder_bss)
+ *(.opus_encoder_bss)
+
+ *(.anc_bss)
+ *(.anc_user_bss)
+ *(.anc_box_bss)
+ *(.anc_btspp_bss)
+ *(.audio_adc_bss)
+ *(.audio_cfifo_bss)
+
+ *(.audio_dec_bss)
+ *(.audio_buf)
+ *(.src_filt)
+ *(.src_dma)
+
+ *(.jlsp_bss)
+ *(.jlsp_aec_bss)
+ *(.jlsp_nlp_bss)
+ *(.jlsp_dns_bss)
+ *(.jlsp_enc_bss)
+ *(.jlsp_prep_bss)
+ *(.jlsp_wn_bss)
+ *(.jlsp_tri_bss)
+ *(.jlsp_agc_bss)
+ . = ALIGN(4);
+ *(.pSOUND360TD_cal_bss)
+
+ } > ram0
+
+ .text : ALIGN(4)
+ {
+ media_text_start = .;
+
+ . = ALIGN(4);
+ *(.stream_code)
+ *(.howlings_phf_code)
+ *(.notchhowling_sparse_code)
+ *(.notchhowling_code)
+ *(.howlings_phf_sparse_code)
+ *(.notchhowling_const)
+ *(.howlings_phf_const)
+
+ . = ALIGN(4);
+ *(.llns.text)
+ *(.llns.text.const)
+
+ . = ALIGN(4);
+ *(.aec_code)
+ *(.aec_const)
+
+ . = ALIGN(4);
+ *(.res_code)
+ *(.res_const)
+
+ . = ALIGN(4);
+ *(.ns_code)
+ *(.ns_const)
+ *(.bark_const)
+
+ . = ALIGN(4);
+ *(.jlsp_code)
+ . = ALIGN(4);
+ *(.jlsp_const)
+ . = ALIGN(4);
+ *(.dns_16k_data)
+ . = ALIGN(4);
+ *(.dns_8k_data)
+ . = ALIGN(4);
+ *(.jlsp_dns_code)
+ *(.jlsp_dns_const)
+ *(.dns_param_data_wind)
+ *(.dns_common_data_wind)
+
+ *(.agc_code)
+ *(.dms_code)
+ *(.dms_sparse_code)
+
+ *(.nlp_code)
+ *(.nlp_const)
+ *(.der_code)
+ *(.der_const)
+ *(.qmf_code)
+ *(.qmf_const)
+ *(.fft_code)
+ *(.fft_const)
+ *(.drc_sparse_code)
+ *(.drc_code)
+ *(.drc_const)
+
+ *(.audio_gain_code)
+ *(.audio_gain_const)
+
+ *(.ns_sparse_code )
+ *(.aec_sparse_code)
+ *(.nlp_sparse_code)
+ *(.der_sparse_code)
+ *(.qmf_sparse_code)
+ *(.bt_audioplc_code)
+ *(.bt_audioplc_sparse_code)
+ *(.bt_audioplc_const)
+ . = ALIGN(4);
+ *(.lf_audioplc_code)
+ *(.lf_audioplc_sparse_code)
+ *(.lf_audioplc_const)
+
+ . = ALIGN(4);
+ *(.pcm_code)
+ *(.pcm_const)
+
+
+
+
+ *(.wtg_dec_code)
+ *(.wtg_dec_sparse_code)
+ *(.wtg_dec_const)
+ *(.wtgv2_code)
+ *(.wtgv2_const)
+ *(.wtgv2dec_code)
+ *(.wtgv2dec_const)
+ *(.wtgv2dec_str)
+ *(.wtg_decv2_sparse_code)
+ *(.speex_dec_code)
+ *(.speex_dec_const)
+ *(.speex_const)
+ *(.speex_code)
+ *(.speex_encoder_code)
+ *(.speex_encoder_const)
+ *(.opus_code)
+ *(.opus_const)
+ *(.opus_encoder_code)
+ *(.opus_encoder_const)
+ *(.mp3_code)
+ *(.mp3_const)
+ *(.mp3_dec_sparse_code)
+ *(.mp3_dec_sparse_const)
+ *(.mp3_dec_code)
+ *(.mp3_dec_const)
+ *(.bfilt_code)
+ *(.msbc_code)
+ *(.msbc_const)
+ *(.mty_code)
+ *(.mp3tsy_dec_code)
+ *(.mp3tsy_dec_sparse_code)
+ *(.mp3tsy_dec_const)
+ *(.sbc_code)
+ *(.sbc_const)
+ *(.sine_code)
+ *(.sine_const)
+ *(.wav_code)
+ *(.wav_const)
+ *(.wav_dec_code)
+ *(.wav_dec_const)
+ *(.wav_dec_sparse_code)
+ *(.wav_dec_sparse_const)
+ *(.wma_code)
+ *(.wma_const)
+ *(.wma_dec_code)
+ *(.wma_dec_sparse_code)
+ *(.wma_dec_const)
+ *(.aac_code)
+ *(.aac_const)
+ *(.ldac_decoder_code)
+ *(.ldac_decoder_const)
+ *(.bt_ldac_dec_code)
+ *(.bt_ldac_dec_const)
+ *(.amr_code)
+ *(.amr_const)
+ *(.amr_dec_code)
+ *(.amr_dec_const)
+ *(.amr_dec_sparse_code)
+ *(.ape_code)
+ *(.ape_const)
+ *(.ape_dec_code)
+ *(.ape_dec_sparse_code)
+ *(.ape_dec_const)
+ *(.dts_code)
+ *(.dts_const)
+ *(.dts_dec_sparse_code)
+ *(.dts_dec_code)
+ *(.dts_dec_const)
+ *(.dts_dec_ff_const)
+ *(.flac_code)
+ *(.flac_const)
+ *(.flac_dec_code)
+ *(.flac_dec_const)
+ *(.flac_dec_sparse_code)
+ *(.audio_decoder_code)
+ *(.audio_decoder_const)
+ *(.audio_track_const)
+ *(.audio_track_code)
+
+
+
+ *(.m4a_code)
+ *(.m4a_const)
+ *(.m4a_dec_code)
+ *(.m4a_dec_sparse_code)
+ *(.m4a_dec_sparse_const)
+ *(.bt_aac_dec_core_sparse_const)
+ *(.bt_aac_dec_core_sparse_code)
+ *(.bt_aac_dec_core_code)
+ *(.bt_aac_dec_eng_code)
+ *(.bt_aac_dec_eng_const)
+ *(.alac_code)
+ *(.alac_const)
+ *(.alac_dec_code)
+ *(.media_device_code)
+ *(.media_device_const)
+ *(.audio_encoder_code)
+ *(.audio_encoder_const)
+ *(.mixer_code)
+ *(.mixer_const)
+ *(.dec_server_code)
+ *(.dec_server_const)
+ *(.rec_server_code)
+ *(.rec_server_const)
+ *(.auto_mute_code)
+ *(.auto_mute_const)
+ *(.plc_code)
+ *(.plc_const)
+ *(.wireless_sync_code)
+ *(.wireless_sync_const)
+ *(.sbc_eng_code)
+ *(.sbc_eng_const)
+
+ anc_code_begin = .;
+ *(.anc_user_const)
+ *(.anc_user_code)
+ *(.anc_const)
+ *(.anc_code)
+ *(.anc_core_const)
+ *(.anc_core_code)
+ *(.anc_box_const)
+ *(.anc_box_code)
+ *(.anc_btspp_const)
+ *(.anc_btspp_code)
+ anc_code_end = .;
+ anc_code_size = anc_code_end - anc_code_begin;
+
+ *(.audio_codec_code)
+ *(.audio_adc_code)
+ *(.audio_adc_const)
+ *(.audio_cfifo_code)
+ *(.audio_cfifo_const)
+
+ *(.bt_compressor_sparse_const)
+ *(.bt_compressor_sparse_code)
+ *(.compressor_sparse_code)
+ *(.compressor_sparse_const)
+
+ *(.bt_limiter_sparse_const)
+ *(.bt_limiter_sparse_code)
+ *(.limiter_sparse_code)
+ *(.limiter_sparse_const)
+
+ *(.bt_crossOver_sparse_const)
+ *(.bt_crossOver_sparse_code)
+ *(.crossOver_sparse_code)
+ *(.crossOver_sparse_const)
+
+ *(.lib_pitchshift_code)
+ *(.lib_pitchshift_const)
+
+ . = ALIGN(4);
+ _audio_decoder_begin = .;
+ PROVIDE(audio_decoder_begin = .);
+ *(.audio_decoder)
+ _audio_decoder_end = .;
+ PROVIDE(audio_decoder_end = .);
+
+ _audio_encoder_begin = .;
+ PROVIDE(audio_encoder_begin = .);
+ *(.audio_encoder)
+ _audio_encoder_end = .;
+ PROVIDE(audio_encoder_end = .);
+
+ _audio_package_begin = .;
+ PROVIDE(audio_package_begin = .);
+ *(.audio_package)
+ _audio_package_end = .;
+ PROVIDE(audio_package_end = .);
+
+ _audio_dev_begin = .;
+ PROVIDE(audio_dev_begin = .);
+ *(.audio_device)
+ _audio_dev_end = .;
+ PROVIDE(audio_dev_end = .);
+
+ _audio_hwaccel_begin = .;
+ PROVIDE(audio_hwaccel_begin = .);
+ *(.audio_hwaccel)
+ _audio_hwaccel_end = .;
+ PROVIDE(audio_hwaccel_end = .);
+
+ . = ALIGN(4);
+ media_code_begin = .;
+ *(.media.*.text)
+ . = ALIGN(4);
+
+ *(.compressor_code)
+ *(.compressor_const)
+ *(.bt_compressor_const)
+ *(.bt_compressor_code)
+
+ *(.crossOver_code)
+ *(.crossOver_const)
+ *(.bt_crossOver_const)
+ *(.bt_crossOver_code)
+
+ *(.limiter_code)
+ *(.limiter_const)
+ *(.bt_limiter_const)
+ *(.bt_limiter_code)
+
+ *(.lc3_decoder_const)
+ *(.lc3_decoder_code)
+ *(.lc3_dec_const)
+ *(.lc3_dec_code)
+
+ *(.audio_vbass_code)
+ *(.audio_vbass_const)
+ *(.vbss_code)
+ *(.vbss_const)
+ *(.vbss_sparse_code)
+ *(.vbss_sparse_const)
+
+
+ . = ALIGN(4);
+ *(.pSOUND360TD_cal_sparse_code)
+
+ . = ALIGN(4);
+ *(.g729_code)
+ *(.g729_const)
+ *(.cvsd_code)
+ *(.cvsd_const)
+
+ *(.media.audio*)
+ *(.media.mixer*)
+ *(.media.media*)
+
+ *( .lib_wtg_dec_code )
+ *( .lib_wtg_dec_const)
+
+ *(.audio_resample_code)
+ *(.audio_resample_const)
+
+ *(.resample_fastcal_sparse_code)
+ *(.resample_fastcal_code)
+ *(.resample_fastcal_const)
+
+ audio_sync_code_begin = .;
+ *(.audio_sync_code)
+ audio_sync_code_end = .;
+
+ . = ALIGN(4);
+
+ media_code_end = .;
+ . = ALIGN(4);
+ media_code_size = media_code_end - media_code_begin;
+
+ . = ALIGN(4);
+ media_text_end = .;
+ } > code0
+
+
+ .data_code ALIGN(32):
+ {
+ *(.media.aec.text)
+ } > ram0
+}
+
+text_begin = ADDR(.text);
+text_size = SIZEOF(.text);
+text_end = text_begin + text_size;
+
+bss_begin = ADDR(.bss);
+bss_size = SIZEOF(.bss);
+bss_end = bss_begin + bss_size;
+
+data_addr = ADDR(.data);
+data_begin = text_begin + text_size;
+data_size = SIZEOF(.data);
+
+moveable_slot_addr = ADDR(.moveable_slot);
+moveable_slot_begin = data_begin + data_size;
+moveable_slot_size = SIZEOF(.moveable_slot);
+
+data_code_addr = ADDR(.data_code);
+data_code_begin = moveable_slot_begin + moveable_slot_size;
+data_code_size = SIZEOF(.data_code);
+
+
+
+aec_addr = ADDR(.overlay_aec);
+aec_begin = data_code_begin + data_code_size;
+aec_size = SIZEOF(.overlay_aec);
+
+aac_addr = ADDR(.overlay_aac);
+aac_begin = aec_begin + aec_size;
+aac_size = SIZEOF(.overlay_aac);
+
+psr_data_code_addr = ADDR(.psr_data_code);
+psr_data_code_begin = aac_begin + aac_size;
+psr_data_code_size = SIZEOF(.psr_data_code);
+ASSERT(_HEAP_BEGIN > bss_begin,"_HEAP_BEGIN < bss_begin");
+ASSERT(_HEAP_BEGIN > data_addr,"_HEAP_BEGIN < data_addr");
+ASSERT(_HEAP_BEGIN > data_code_addr,"_HEAP_BEGIN < data_code_addr");
+
+
+
+PROVIDE(HEAP_BEGIN = _HEAP_BEGIN);
+PROVIDE(HEAP_END = _HEAP_END);
+_MALLOC_SIZE = _HEAP_END - _HEAP_BEGIN;
+PROVIDE(MALLOC_SIZE = _HEAP_END - _HEAP_BEGIN);
+
+ASSERT(MALLOC_SIZE >= 0x8000, "heap space too small !")
+
+
+
+
+report_text_beign = ADDR(.text);
+report_text_size = SIZEOF(.text);
+report_text_end = report_text_beign + report_text_size;
+
+report_mmu_tlb_begin = ADDR(.mmu_tlb);
+report_mmu_tlb_size = SIZEOF(.mmu_tlb);
+report_mmu_tlb_end = report_mmu_tlb_begin + report_mmu_tlb_size;
+
+report_boot_info_begin = ADDR(.boot_info);
+report_boot_info_size = SIZEOF(.boot_info);
+report_boot_info_end = report_boot_info_begin + report_boot_info_size;
+
+report_irq_stack_begin = ADDR(.irq_stack);
+report_irq_stack_size = SIZEOF(.irq_stack);
+report_irq_stack_end = report_irq_stack_begin + report_irq_stack_size;
+
+report_data_begin = ADDR(.data);
+report_data_size = SIZEOF(.data);
+report_data_end = report_data_begin + report_data_size;
+
+report_bss_begin = ADDR(.bss);
+report_bss_size = SIZEOF(.bss);
+report_bss_end = report_bss_begin + report_bss_size;
+
+report_data_code_begin = ADDR(.data_code);
+report_data_code_size = SIZEOF(.data_code);
+report_data_code_end = report_data_code_begin + report_data_code_size;
+
+report_overlay_begin = __report_overlay_begin;
+report_overlay_size = __report_overlay_end - __report_overlay_begin;
+report_overlay_end = __report_overlay_end;
+
+report_heap_beign = _HEAP_BEGIN;
+report_heap_size = _HEAP_END - _HEAP_BEGIN;
+report_heap_end = _HEAP_END;
+
+BR28_PHY_RAM_SIZE = PHY_RAM_SIZE;
+BR28_SDK_RAM_SIZE = report_mmu_tlb_size + report_boot_info_size + report_irq_stack_size + report_data_size + report_bss_size + report_overlay_size + report_data_code_size + report_heap_size;
diff --git a/cpu/br28/sdk_used_list.used b/cpu/br28/sdk_used_list.used
new file mode 100644
index 0000000..79b91ea
--- /dev/null
+++ b/cpu/br28/sdk_used_list.used
@@ -0,0 +1,30 @@
+
+
+
+
+sdfile_vfs_ops
+sbc_decoder
+
+
+
+msbc_decoder
+
+
+
+sbc_hwaccel
+
+
+
+cvsd_decoder
+
+
+
+pcm_decoder
+
+
+
+
+
+
+
+mp3_decoder
diff --git a/cpu/br28/tools/aac.bin b/cpu/br28/tools/aac.bin
new file mode 100644
index 0000000..e69de29
diff --git a/cpu/br28/tools/aec.bin b/cpu/br28/tools/aec.bin
new file mode 100644
index 0000000..e69de29
diff --git a/cpu/br28/tools/aptx.bin b/cpu/br28/tools/aptx.bin
new file mode 100644
index 0000000..e69de29
diff --git a/cpu/br28/tools/download.bat b/cpu/br28/tools/download.bat
new file mode 100644
index 0000000..64f3c15
--- /dev/null
+++ b/cpu/br28/tools/download.bat
@@ -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
diff --git a/cpu/br28/tools/download/earphone/download_app_ota.bat b/cpu/br28/tools/download/earphone/download_app_ota.bat
index 59fc4df..bdeea66 100644
--- a/cpu/br28/tools/download/earphone/download_app_ota.bat
+++ b/cpu/br28/tools/download/earphone/download_app_ota.bat
@@ -10,9 +10,9 @@ copy ..\..\ota.bin .
copy ..\..\anc_coeff.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
@rem delete temp files
diff --git a/cpu/br28/tools/eq_cfg_hw.bin b/cpu/br28/tools/eq_cfg_hw.bin
new file mode 100644
index 0000000..b589b69
Binary files /dev/null and b/cpu/br28/tools/eq_cfg_hw.bin differ
diff --git a/cpu/br28/tools/isd_config.ini b/cpu/br28/tools/isd_config.ini
new file mode 100644
index 0000000..a3be0ba
--- /dev/null
+++ b/cpu/br28/tools/isd_config.ini
@@ -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;