Update magic box firmware

This commit is contained in:
2026-09-02 18:20:54 +08:00
parent b63a928b92
commit 3d1ca8bda9
22 changed files with 402 additions and 279 deletions
+4 -15
View File
@@ -19,6 +19,7 @@
#include "app_mode.h"
#include "app_led.h"
#include "app_shake_wake.h"
#include "app_no_disturb.h"
#include "app_time_util.h"
#include "bsp_hw.h"
#include "board_pin.h"
@@ -46,7 +47,6 @@ typedef struct {
volatile uint8_t play_write_pending;
volatile uint8_t play_write_mode;
uint8_t shake_wake;
uint8_t no_disturb;
} AppFunctionCtx_t;
static AppFunctionCtx_t s_func;
@@ -71,7 +71,6 @@ void app_function_init(void)
app_shake_wake_init(function_shake_wake_allowed,
function_shake_wake_trigger);
s_func.shake_wake = !!gDevData.shake_wake;
s_func.no_disturb = !!gDevData.no_disturb_enable[0];
app_shake_wake_set_enable(s_func.shake_wake);
}
@@ -89,7 +88,7 @@ void app_function_dp_play_write(uint8_t mode)
/**
* @brief DP2 写入钩子:仅记录第 1 字节,真正执行在 app_function_poll
* @param cmd 0=忽略1=原地右转,2=原地左转
* @param cmd 0=停止1=上部电机探出,2=下部电机探出
* @return 无
*/
void app_function_dp_hand_write(uint8_t cmd)
@@ -105,12 +104,6 @@ void app_function_set_shake_wake(uint8_t enable)
app_shake_wake_set_enable(s_func.shake_wake);
}
void app_function_set_no_disturb(uint8_t enable)
{
s_func.no_disturb = !!enable;
app_shake_wake_reset();
}
/**
* @brief 跟随 APP 下发的 DP0/DP1,并处理 DP2 手动点动
* @return 无
@@ -120,10 +113,6 @@ void app_function_poll(void)
if (s_func.shake_wake != !!gDevData.shake_wake) {
app_function_set_shake_wake(gDevData.shake_wake);
}
if (s_func.no_disturb != !!gDevData.no_disturb_enable[0]) {
app_function_set_no_disturb(gDevData.no_disturb_enable[0]);
}
if (s_func.power_write_pending) {
uint8_t enable = s_func.power_write_value;
s_func.power_write_pending = 0;
@@ -341,7 +330,7 @@ static void function_play_mode_timeout(uint16_t dt)
}
/**
* @brief DP2 手动:只看第 1 字节。0=空闲,1=顺时针,2=逆时针,3=停
* @brief DP2 手动:只看第 1 字节。0=空闲,1=上部探出,2=下部探出
* @return 无
*/
static void function_hand_poll(void)
@@ -501,7 +490,7 @@ static uint8_t function_power_on(uint8_t show_hint)
static uint8_t function_shake_wake_allowed(void)
{
return s_func.shake_wake &&
!s_func.no_disturb &&
!app_no_disturb_is_active() &&
!s_func.app_power &&
!app_power_usb_online() &&
!app_power_poweroff_pending() &&
+4 -6
View File
@@ -23,24 +23,22 @@
*/
void app_function_init(void);
/** CBC3 DP0 写入:排队到业务节拍统一执行。 */
/** CBC4 DP0 写入:排队到业务节拍统一执行。 */
void app_function_dp_power_write(uint8_t enable);
/** CBC3 DP1 写入:支持重复下发当前模式时停止。 */
/** CBC4 DP1 写入:支持重复下发当前模式时停止。 */
void app_function_dp_play_write(uint8_t mode);
/**
* @brief DP2 写入钩子:仅记录第 1 字节,真正执行在 app_function_poll
* @param cmd 0=忽略1=原地右转,2=原地左转
* @param cmd 0=停止1=上部电机探出,2=下部电机探出
* @return 无
*/
void app_function_dp_hand_write(uint8_t cmd);
/** CBC3 DP6 震动开机开关。 */
/** CBC4 DP6 震动开机开关。 */
void app_function_set_shake_wake(uint8_t enable);
/** 勿扰时段是否正在生效;生效时屏蔽震动开机。 */
void app_function_set_no_disturb(uint8_t enable);
/**
* @brief 跟随 APP 下发的 DP0/DP1,并处理 DP2 手动点动,每个业务 tick 调用一次
+1 -1
View File
@@ -1,6 +1,6 @@
/******************************************************************************
* @file app_led.c
* @brief CBC2 灯效适配:充电红与待机绿可同时亮,不再 if-else 互斥
* @brief CBC4 灯效适配:充电红与待机绿可同时亮,不再 if-else 互斥
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V2.0.0
+1 -1
View File
@@ -1,6 +1,6 @@
/******************************************************************************
* @file app_led.h
* @brief CBC2 灯效:红绿独立通道,充电红与待机绿可同时亮
* @brief CBC4 灯效:红绿独立通道,充电红与待机绿可同时亮
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V2.0.0
+168
View File
@@ -0,0 +1,168 @@
#include "app_no_disturb.h"
#include "usr_rtc.h"
#include "system/includes.h"
#define APP_MINUTES_PER_DAY (24U * 60U)
#define APP_NO_DISTURB_VM_MAGIC 0x444e4431UL
#define APP_NO_DISTURB_VM_VERSION 1U
typedef struct {
uint8_t enabled;
uint8_t weekdays_mask;
uint16_t start_minute;
uint16_t end_minute;
} AppNoDisturbCtx_t;
typedef struct {
uint32_t magic;
uint8_t version;
uint8_t length;
uint16_t checksum;
uint8_t data[APP_NO_DISTURB_DATA_LEN];
} AppNoDisturbVm_t;
static AppNoDisturbCtx_t s_no_disturb;
static uint8_t s_saved_data[APP_NO_DISTURB_DATA_LEN];
static uint8_t s_saved_valid;
static uint16_t app_no_disturb_checksum(const uint8_t *data)
{
uint16_t checksum = 0xa55aU;
uint8_t i;
for (i = 0; i < APP_NO_DISTURB_DATA_LEN; i++) {
checksum = (uint16_t)((checksum << 5) | (checksum >> 11));
checksum ^= data[i];
}
return checksum;
}
static uint8_t app_no_disturb_vm_valid(const AppNoDisturbVm_t *vm)
{
return vm->magic == APP_NO_DISTURB_VM_MAGIC &&
vm->version == APP_NO_DISTURB_VM_VERSION &&
vm->length == APP_NO_DISTURB_DATA_LEN &&
vm->checksum == app_no_disturb_checksum(vm->data);
}
static uint8_t app_no_disturb_weekday_monday0(const struct sys_time *time)
{
static const uint8_t month_offset[12] = {
0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4
};
uint32_t year = time->year;
uint8_t sunday0;
if (time->month < 3U) {
year--;
}
sunday0 = (uint8_t)((year + year / 4U - year / 100U + year / 400U +
month_offset[time->month - 1U] + time->day) % 7U);
return (uint8_t)((sunday0 + 6U) % 7U);
}
static uint8_t app_no_disturb_day_selected(uint8_t weekday)
{
return (uint8_t)((s_no_disturb.weekdays_mask & (1U << weekday)) != 0U);
}
void app_no_disturb_configure(uint8_t enable, uint8_t weekdays_mask,
uint16_t start_minute, uint16_t end_minute)
{
s_no_disturb.enabled = !!enable;
s_no_disturb.weekdays_mask = weekdays_mask & 0x7fU;
s_no_disturb.start_minute = start_minute;
s_no_disturb.end_minute = end_minute;
}
uint8_t app_no_disturb_is_active_at(const struct sys_time *time)
{
uint8_t weekday;
uint16_t now_minute;
if (!time || !s_no_disturb.enabled || !s_no_disturb.weekdays_mask ||
s_no_disturb.start_minute >= APP_MINUTES_PER_DAY ||
s_no_disturb.end_minute >= APP_MINUTES_PER_DAY ||
time->month < 1U || time->month > 12U ||
time->day < 1U || time->day > 31U ||
time->hour > 23U || time->min > 59U) {
return 0;
}
weekday = app_no_disturb_weekday_monday0(time);
now_minute = (uint16_t)(time->hour * 60U + time->min);
if (s_no_disturb.start_minute == s_no_disturb.end_minute) {
return app_no_disturb_day_selected(weekday);
}
if (s_no_disturb.start_minute < s_no_disturb.end_minute) {
return app_no_disturb_day_selected(weekday) &&
now_minute >= s_no_disturb.start_minute &&
now_minute < s_no_disturb.end_minute;
}
if (now_minute >= s_no_disturb.start_minute) {
return app_no_disturb_day_selected(weekday);
}
if (now_minute < s_no_disturb.end_minute) {
return app_no_disturb_day_selected((uint8_t)((weekday + 6U) % 7U));
}
return 0;
}
uint8_t app_no_disturb_is_active(void)
{
struct sys_time time;
if (!usr_rtc_get_time(&time)) {
return 0;
}
return app_no_disturb_is_active_at(&time);
}
uint8_t app_no_disturb_storage_load(uint8_t data[APP_NO_DISTURB_DATA_LEN])
{
AppNoDisturbVm_t vm;
int ret;
if (!data) {
return 0;
}
memset(&vm, 0, sizeof(vm));
ret = syscfg_read(CFG_USER_NO_DISTURB, (uint8_t *)&vm, sizeof(vm));
if (ret != (int)sizeof(vm) || !app_no_disturb_vm_valid(&vm)) {
s_saved_valid = 0;
return 0;
}
memcpy(data, vm.data, APP_NO_DISTURB_DATA_LEN);
memcpy(s_saved_data, vm.data, APP_NO_DISTURB_DATA_LEN);
s_saved_valid = 1;
return 1;
}
uint8_t app_no_disturb_storage_save(const uint8_t data[APP_NO_DISTURB_DATA_LEN])
{
AppNoDisturbVm_t vm;
int ret;
if (!data) {
return 0;
}
if (s_saved_valid &&
!memcmp(s_saved_data, data, APP_NO_DISTURB_DATA_LEN)) {
return 1;
}
memset(&vm, 0, sizeof(vm));
vm.magic = APP_NO_DISTURB_VM_MAGIC;
vm.version = APP_NO_DISTURB_VM_VERSION;
vm.length = APP_NO_DISTURB_DATA_LEN;
memcpy(vm.data, data, APP_NO_DISTURB_DATA_LEN);
vm.checksum = app_no_disturb_checksum(vm.data);
ret = syscfg_write(CFG_USER_NO_DISTURB, (uint8_t *)&vm, sizeof(vm));
if (ret != (int)sizeof(vm)) {
return 0;
}
memcpy(s_saved_data, data, APP_NO_DISTURB_DATA_LEN);
s_saved_valid = 1;
return 1;
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef __APP_NO_DISTURB_H__
#define __APP_NO_DISTURB_H__
#include <stdint.h>
#include "system/sys_time.h"
#define APP_NO_DISTURB_DATA_LEN 13U
/* weekdays_mask bit 0..6 means Monday..Sunday. */
void app_no_disturb_configure(uint8_t enable, uint8_t weekdays_mask,
uint16_t start_minute, uint16_t end_minute);
uint8_t app_no_disturb_is_active(void);
uint8_t app_no_disturb_is_active_at(const struct sys_time *time);
uint8_t app_no_disturb_storage_load(uint8_t data[APP_NO_DISTURB_DATA_LEN]);
uint8_t app_no_disturb_storage_save(const uint8_t data[APP_NO_DISTURB_DATA_LEN]);
#endif /* __APP_NO_DISTURB_H__ */
+1 -1
View File
@@ -1,6 +1,6 @@
/******************************************************************************
* @file key_manager.c
* @brief CBC2 按键:读 PB1,短按/长按交给 usr_jb_main
* @brief CBC4 按键:读 PB1,短按/长按交给 usr_jb_main
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V1.0.0
+1 -1
View File
@@ -1,6 +1,6 @@
/******************************************************************************
* @file key_manager.h
* @brief CBC2 单按键:短按切模式,长按 3s 关机;开机 3s/5s 不走本库
* @brief CBC4 单按键:短按切模式,长按 3s 关机;开机 3s/5s 不走本库
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V1.0.0
+2 -2
View File
@@ -1,6 +1,6 @@
/******************************************************************************
* @file led_manager.c
* @brief CBC2 灯事件:充电红与待机绿走不同通道,可同时亮
* @brief CBC4 灯事件:充电红与待机绿走不同通道,可同时亮
* @author cyWu <1917507415@qq.com>
* @date 2026.08.27
* @version V1.1.0
@@ -157,7 +157,7 @@ static uint8_t led_boot_reject_handler(LED_Config_t *led_config)
}
/**
* @brief 注册回调并装载 CBC2 事件表(GPIO 已在 bsp_hw_init
* @brief 注册回调并装载 CBC4 事件表(GPIO 已在 bsp_hw_init
* @return 无
*/
void user_led_init(void)
+2 -2
View File
@@ -1,6 +1,6 @@
/******************************************************************************
* @file led_manager.h
* @brief CBC2 红绿 LED 通道与事件表
* @brief CBC4 红绿 LED 通道与事件表
* @author cyWu <1917507415@qq.com>
* @date 2026.08.25
* @version V1.0.0
@@ -20,7 +20,7 @@ typedef enum {
} LedChannel_t;
/**
* @brief 注册 GPIO 回调并装载 CBC2 事件表
* @brief 注册 GPIO 回调并装载 CBC4 事件表
* @return 无
*/
void user_led_init(void);