Files
LPT26x-HSF-4MB-Hilink_14.2.…/bootloader/flashboot_ws63/startup/main.c
ekko.bao 3dc430b62b 1. 解决ble 冷启动不能局域网控制的问题
之前的版本只能应对中途断网的情况。现在的应该可以应对无网启动的情况
2025-07-09 21:49:09 +08:00

1204 lines
38 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

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

/*
* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2021-2021. All rights reserved.
* Description: main
*
* Create: 2021-03-09
*/
#include "boot_serial.h"
#include "boot_init.h"
#include "boot_reset.h"
#include "boot_verify.h"
#include "secure_verify_boot.h"
#include "efuse.h"
#include "efuse_porting.h"
#include "chip_io.h"
#include "pinctrl.h"
#include "boot_flash.h"
#include "sfc.h"
#include "boot_delay.h"
#include "boot_jump.h"
#include "tcxo.h"
#include "watchdog.h"
#include "drv_pmp.h"
#include "pmp_cfg.h"
#include "malloc_porting.h"
#include "upg_porting.h"
#include "upg_common.h"
#include "upg_alloc.h"
#include "soc_porting.h"
#include "drv_flashboot_cipher.h"
#ifdef CONFIG_MIDDLEWARE_SUPPORT_UPG_AB
#include "upg_ab.h"
#endif
#include "factory.h"
#include "sfc_protect.h"
#include "reset_porting.h"
#define FLASHBOOT_UART_DEFAULT_PARAM {115200, 8, 1, 0, 0, 2, 1, 4, 0}
#define APP_START_INSTRUCTION 0x40006f
#define DELAY_100MS 100
#define REG_CMU_CFG0 0x40003408
#define APP_IMAGE_HEADER_LEN ((KEY_AREA_STRUCTURE_LENGTH) + (CODE_INFO_STRUCTURE_LENGTH))
#define BOOT_WATCH_DOG_TIMOUT 7 // 7s
#define FLASH_KEY_SALT_LEN 28
#define FLASH_ENCRY_ADDR_ALINE 256
#define FLASH_NO_ENCRY_FLAG 0x3C7896E1
#define FLASHBOOT_RAM_ADDR 0xA28000
#define FLASH_BOOT_TYPE_REG 0x40000024
#define FLASH_BOOT_TYPE_REG_MAIN 0xA5A5A5A5
#define FLASH_BOOT_TYPE_REG_BKUP 0x5A5A5A5A
const sfc_flash_config_t sfc_cfg = {
.read_type = FAST_READ_QUAD_OUTPUT,
.write_type = PAGE_PROGRAM,
.mapping_addr = 0x200000,
.mapping_size = 0x800000,
};
#if 1 //ADD LYL 2024 1122 --------
#define USERPAGE 0x003F2000 //AT参数存储区
#define BLE_CONKEYLEN 16
#pragma pack(push)
#pragma pack(1)
typedef struct
{
int8_t updateflag; //update flag
int8_t validflag; //valid flag
int8_t tmode_mode;
int8_t wmode_mode;
//STA, 140 bytes
uint8_t sta_ssid[33];
uint8_t sta_key[65];
int8_t wsauth;
int8_t wsencry;
uint8_t wslko;
uint8_t pmk_av;
uint8_t sta_padding[6];
uint8_t pmk[32];
//AP, 144 bytes
int8_t wap_mode;
int8_t wap_channel;
int8_t waauth;
int8_t waencry;
uint8_t walk_led;
uint8_t max_sta_num;
uint8_t ap_enable_hide;
uint8_t ap_ssid[33];
uint8_t ap_key[65];
uint8_t ap_pmk_av;
uint8_t ap_pmk[32];
uint8_t ap_padding[6];
//UART, 20 bytes
int8_t baudrate;
int8_t data_bits;
int8_t stop_bits;
int8_t parity;
int8_t ctsrts;
int8_t uart1_baudrate;
int8_t uart1_data_bits;
int8_t uart1_stop_bits;
int8_t uart1_parity;
int8_t uart1_debug;
int8_t uartfable;
int8_t fuartte_mode;
uint16_t uarttm;
uint16_t uartbuf;
uint8_t uart_padding[4];
//NETP, 108 bytes
int8_t protocol;
int8_t app_mode;
uint8_t maxsocket;
char cipadd[101];
uint16_t pro_port;
uint16_t tcpto;
//SOCKB, 112 bytes
uint16_t sockb_port;
uint16_t sockb_tcpto;
int8_t sockb_pro;
char sockb_cipadd[101];
int8_t tcpdis;
int8_t tcpdisb;
uint16_t udp_localporta;
uint16_t udp_localportb;
//NETWORK, 108 bytes
char wann_ipaddr[16];
char wann_mask[16];
char wann_gateway[16];
char lann_ipaddr[16];
char lann_mask[16];
uint8_t wann_mode;
uint8_t network_padding[2];
uint8_t domain_name[21];
uint32_t dns_addr;
//UTILS, 124 bytes
int8_t echo;
int8_t rlden;
uint8_t debug_level;
char wel_msg[11];
uint8_t event_onoff;
uint8_t noise_filter;
uint8_t wifi_switch;
uint8_t sta_dtim;
uint8_t utils_padding[40];
uint8_t dis_power_saving;
int8_t modechange;
uint8_t ps_interval;
uint8_t mid[21];
uint8_t aswd[21];
uint8_t cmdpw[21];
//HTTPD, 36 bytes
char user_name[16];
char user_password[16];
int8_t web_switch;
uint8_t web_language;
uint8_t web_encode_format;
uint8_t httpd_padding;
//DHCPD, 4 bytes
int8_t dhcpsw;
uint8_t dhcpd_addr_start;
uint8_t dhcpd_addr_end;
uint8_t dhcpd_padding;
//UPDATE, 124 bytes
char update_url[101];
char update_file[21];
uint8_t update_padding[2];
//NTP, 8 bytes
uint8_t ntp_time;
uint8_t ntp_enable;
uint8_t ntp_padding;
int8_t time_zone;
uint32_t ntpserver;
//SMTLK, 16 bytes
uint32_t smtlk_sign;
uint8_t smtlk_mode;
uint8_t smtlk_protocol;
uint8_t smtlk_rtype;
uint8_t smtlk_ak_random;
uint8_t connect_flag;
uint8_t sta_channel;
uint8_t sta_bssid[6];
//SMARTAPLINK, 44 bytes
uint8_t smartaplink_enable;
uint8_t smartaplink_padding;
uint8_t smartaplink_prefix[21];
uint8_t smartaplink_key[21];
//NETPID, 24 bytes
uint8_t netpa_iden;
char netpa_id[11];
uint8_t netpb_iden;
char netpb_id[11];
//NETPREG, 264 bytes
uint8_t netpa_regen;
uint8_t netpa_regtype;
uint8_t netpa_reg_padding;
char netpa_regdata[129];
uint8_t netpb_regen;
uint8_t netpb_regtype;
uint8_t netpb_reg_padding;
char netpb_regdata[129];
//HEART, 124 bytes
uint16_t heart_netp_time;
uint16_t heart_sockb_time;
uint16_t heart_uart_time;
char heart_netp_data[39];
char heart_sockb_data[39];
char heart_uart_data[39];
uint8_t heart_padding;
//HTTP, 236 bytes
uint8_t http_type;
uint8_t http_version;
uint8_t http_connect_type;
uint8_t http_recv_time;
char http_url[51];
char http_header[181];
//MQTT, 224 bytes
char mqtt_username[33];
char mqtt_password[33];
char mqtt_clientid[33];
char mqtt_pub_topic[61];
char mqtt_sub_topic[61];
uint8_t mqtt_qos;
uint16_t mqtt_heart_time;
//BLE, 188 bytes
uint16_t conn_min;
uint16_t conn_max;
uint16_t conn_latency;
uint16_t supervisionTO;
uint16_t adver_min;
uint16_t adver_max;
uint8_t ble_name[27]; //BLE广播名
uint8_t ble_dms_name[27]; //BLE配网名
uint8_t ble_adver_data[27];
uint8_t ble_adver_data_len;
uint8_t ble_switch;
uint8_t ble_uuid_server;
uint8_t dms_type;
uint8_t ble_padding;
uint8_t uuid_ntf_server[17];
uint8_t uuid_ntf_read[17];
uint8_t uuid_ntf_write[17];
uint8_t uuid_ind_server[17];
uint8_t uuid_ind_read[17];
uint8_t uuid_ind_write[17];
uint8_t adver_type;
uint8_t adver_channel;
uint8_t ble_ind;
uint8_t smartconfiglink;
uint8_t ble_conenable;
uint8_t ble_conkey[BLE_CONKEYLEN];
uint8_t ble_contimeout;
uint8_t netpc_iden;
char netpc_id[11];
uint8_t netpc_idflag;
uint8_t ble_padding2[17];
uint8_t mqtt_tls;
uint8_t mqtt_padding[3];
char iot_productkey[12];
char iot_devicename[48];
char iot_devicesecret[48];
char iot_pubtopic[96];
char iot_subtopic[96];
char iot_mode;
char iot_padding[3];
uint8_t product_mode;
int8_t ctsrts_pin;
char instance_flag;
char instance_id[32];
char ntp_domain_server[33];
int8_t smk_find;
uint32_t mcu_ota_size;
uint8_t scan_ch14;
uint32_t module_reset_reason;
uint8_t reserved1[60+512-4];
uint8_t validflag_magic;
int8_t validflag_end; //valid flag
}HF_CONFIG_FILE;
#pragma pack(pop)
HF_CONFIG_FILE g_hf_config_file_boot = {0};
int hfdbg_get_sw(void)
{
if(g_hf_config_file_boot.debug_level > 0 && g_hf_config_file_boot.debug_level<=20) //1~20允许打印
return 0;
if(g_hf_config_file_boot.uart1_debug == 1) //1允许打印
return 1;
return 0;
}
#endif
static uint32_t sfc_flash_init(void)
{
return uapi_sfc_init((sfc_flash_config_t *)&sfc_cfg);
}
static uint32_t sfc_flash_read(uint32_t flash_addr, uint32_t read_size, uint8_t *read_buffer)
{
return uapi_sfc_reg_read(flash_addr, read_buffer, read_size);
}
static uint32_t sfc_flash_write(uint32_t flash_addr, uint32_t flash_write_size, const uint8_t *p_flash_write_data,
bool do_erase)
{
unused(do_erase);
return uapi_sfc_reg_write(flash_addr, (uint8_t *)p_flash_write_data, flash_write_size);
}
static uint32_t sfc_flash_erase(uint32_t flash_addr, uint32_t flash_erase_size)
{
return uapi_sfc_reg_erase(flash_addr - sfc_cfg.mapping_addr, flash_erase_size);
}
static void boot_flash_init(void)
{
flash_cmd_func flash_funcs = {0};
flash_funcs.init = sfc_flash_init;
flash_funcs.read = sfc_flash_read;
flash_funcs.write = sfc_flash_write;
flash_funcs.erase = sfc_flash_erase;
boot_regist_flash_cmd(&flash_funcs);
uint32_t ret = sfc_flash_init();
if (ret != ERRCODE_SUCC) {
boot_msg1("Flash Init Fail! ret = ", ret);
} else {
uapi_sfc_reg_read(USERPAGE, (unsigned char *)&g_hf_config_file_boot, sizeof(HF_CONFIG_FILE));
boot_msg0("Flash Init Succ!");
}
hf_boot_msg1("BootLoader debug_level = ", g_hf_config_file_boot.debug_level);
switch_flash_clock_to_pll();
config_sfc_ctrl_ds();
}
#define FAMA_REMAP_SRC_BASE_ADDR 0x44007800
#define FAMA_REMAP_LEN_BASE_ADDR 0x44007820
#define FAMA_REMAP_DST_BASE_ADDR 0x44007840
#define FAMA_REMAP_REGION_OFFSET 0x4
#define FAMA_REMAP_LOW_BITS 12
static void dmmu_set(uint32_t src_start_addr, uint32_t src_end_addr, uint32_t dst_start_addr, uint32_t region)
{
uint32_t src_reg_addr = FAMA_REMAP_SRC_BASE_ADDR + region * FAMA_REMAP_REGION_OFFSET;
uint32_t len_reg_addr = FAMA_REMAP_LEN_BASE_ADDR + region * FAMA_REMAP_REGION_OFFSET;
uint32_t dst_reg_addr = FAMA_REMAP_DST_BASE_ADDR + region * FAMA_REMAP_REGION_OFFSET;
uint32_t src_start_align_addr = src_start_addr >> FAMA_REMAP_LOW_BITS;
uint32_t src_end_align_addr = src_end_addr >> FAMA_REMAP_LOW_BITS;
uint32_t dst_start_align_addr = dst_start_addr >> FAMA_REMAP_LOW_BITS;
uint32_t dst_src_offset = 0;
if (region >= FAMA_REMAP_LOW_BITS) {
return ;
}
writel(src_reg_addr, src_start_align_addr);
writel(len_reg_addr, src_end_align_addr);
if (src_start_align_addr > dst_start_align_addr) {
dst_src_offset = src_start_align_addr - dst_start_align_addr;
dst_src_offset = ~dst_src_offset;
dst_src_offset = dst_src_offset + 1;
} else {
dst_src_offset = dst_start_align_addr - src_start_align_addr;
}
writel(dst_reg_addr, dst_src_offset);
}
static bool flashboot_need_recovery(void)
{
uint32_t reg = readl(FLASH_BOOT_TYPE_REG);
writel(FLASH_BOOT_TYPE_REG, 0);
return (reg == FLASH_BOOT_TYPE_REG_BKUP) ? true : false;
}
static void ws63_flashboot_recovery(void)
{
if (!flashboot_need_recovery()) {
return;
}
uapi_watchdog_kick();
boot_msg0("Flashboot backup is working!");
partition_information_t src_img_info = {0};
partition_information_t dst_img_info = {0};
errcode_t ret;
ret = uapi_partition_get_info(PARTITION_FLASH_BOOT_IMAGE_BACKUP, &src_img_info);
ret |= uapi_partition_get_info(PARTITION_FLASH_BOOT_IMAGE, &dst_img_info);
if (ret != ERRCODE_SUCC) {
boot_msg0("Flashboot partition info get fail!");
return;
}
ret = uapi_sfc_reg_erase(dst_img_info.part_info.addr_info.addr, dst_img_info.part_info.addr_info.size);
if (ret != ERRCODE_SUCC) {
boot_msg1("flashboot recovery erase failed!! ret = ", ret);
}
ret = uapi_sfc_reg_write(dst_img_info.part_info.addr_info.addr,
(uint8_t *)(uintptr_t)(src_img_info.part_info.addr_info.addr + FLASH_START),
src_img_info.part_info.addr_info.size);
if (ret != ERRCODE_SUCC) {
boot_msg1("flashboot recovery write failed!! ret = ", ret);
}
boot_msg0("Flashboot fix ok!");
}
#define UPG_FIX_RETRY_CNT_REG RESET_COUNT_REG
#define VERIFY_RETRY_CNT_THRES 0x3
#define UPG_FIX_RETRY_CNT_THRES (VERIFY_RETRY_CNT_THRES + 0x3)
#define UPG_AB_RETRY_CNT_THRES (VERIFY_RETRY_CNT_THRES + 0x3)
static uint8_t ws63_get_try_fix_cnt(void)
{
gp_reg1_union gp;
gp.u32 = readl(UPG_FIX_RETRY_CNT_REG);
return gp.bits.fota_fix_app_cnt;
}
static void ws63_set_try_fix_cnt(uint8_t cnt)
{
gp_reg1_union gp;
gp.u32 = readl(UPG_FIX_RETRY_CNT_REG);
gp.bits.fota_fix_app_cnt = cnt & 0xF;
writel(UPG_FIX_RETRY_CNT_REG, gp.u32);
}
#ifdef CONFIG_MIDDLEWARE_SUPPORT_UPG_AB
static void ws63_try_fix_app(void)
{
uint8_t try_cnt = ws63_get_try_fix_cnt() + 1;
ws63_set_try_fix_cnt(try_cnt);
/* 启动分区连续验签失败次数等于阈值倍数时,切换启动分区 */
if (try_cnt % VERIFY_RETRY_CNT_THRES) { // 1 2 4 5 7 8 a b d e
return;
} else { // 3 6 9 c f
boot_msg0("switch booting");
upg_set_run_region(upg_get_upg_region());
return;
}
}
#else // 压缩
/* 尝试ota修复运行区镜像 */
static void ws63_try_fix_app(void)
{
uint8_t try_cnt = ws63_get_try_fix_cnt();
/* 连续验签失败次数小于阈值不做处理 */
if (try_cnt < VERIFY_RETRY_CNT_THRES) {
ws63_set_try_fix_cnt(try_cnt + 1);
return;
}
/* 修复app超次数阈值后不再尝试 */
if (try_cnt >= UPG_FIX_RETRY_CNT_THRES) {
return;
}
ws63_set_try_fix_cnt(try_cnt + 1);
/* 重置升级标记 */
errcode_t ret = uapi_upg_reset_upgrade_flag();
if (ret != ERRCODE_SUCC) {
boot_msg1("reset_upgrade_flag fail, ret = ", ret);
return;
}
/* 请求升级 */
ret = uapi_upg_request_upgrade(false);
if (ret != ERRCODE_SUCC) {
boot_msg0("request_upgrade fail, fota_pkt_not_exit.");
return;
}
boot_msg0("fota_pkt exit, try_fota_fix_app.");
}
#endif
static bool ws63_upg_need_upgrade(void)
{
uint32_t fota_address = 0;
partition_information_t info;
errcode_t ret_val = uapi_partition_get_info(PARTITION_FOTA_DATA, &info);
if (ret_val != ERRCODE_SUCC || info.type != PARTITION_BY_ADDRESS) {
boot_msg1("uapi_partition_get_info failed ", __LINE__);
return false;
}
upg_get_upgrade_flag_flash_start_addr(&fota_address);
fota_upgrade_flag_area_t upg_flag_info;
ret_val = upg_flash_read(fota_address, sizeof(fota_upgrade_flag_area_t), (uint8_t *)(&upg_flag_info));
if (ret_val != ERRCODE_SUCC) {
boot_msg1("upg_flash_read failed ", ret_val);
return false;
}
if (!(upg_flag_info.head_magic == UPG_HEAD_MAGIC &&
upg_flag_info.head_end_magic == UPG_END_MAGIC &&
upg_flag_info.complete_flag != 0)) {
/* 不需要升级直接返回 */
boot_msg0("No need to upgrade...");
return false;
}
return true;
}
static void ws63_upg_check(void)
{
(void)ws63_upg_init();
#ifdef CONFIG_MIDDLEWARE_SUPPORT_UPG_AB
return;
#endif
if (ws63_upg_need_upgrade()) {
boot_msg0("need upgrade");
errcode_t ret = uapi_upg_start();
// 1, 没有升级包、或者升级标记区结果已经设置的情况不需要重启
// 2, 升级模块没有初始化不需要重启
// 3, 升级成功需要重启
// 4, 升级失败的时候需要重启重新进入升级流程尝试三次未成功后会变为1的情况
if (!(ret == ERRCODE_UPG_NOT_NEED_TO_UPDATE || ret == ERRCODE_UPG_NOT_INIT || ret == ERRCODE_SUCC)) {
boot_msg0("--------------------------");
boot_msg0("upgrade failed, reset now");
} else {
// 升级后重启
boot_msg0("--------------------------");
boot_msg0("upgrade success, reset now");
}
reset();
}
}
#define PMU_CMU_CTL_POC_COEX 0x40003238
#define RG_POC_SEL_SW_MODE 0x2
#define PMU_VDD_FLAG_3V3 0
#define POC_SEL_SW_MODE 1
#define POC_VALUE_3V3 0
#define LEVEL_3V3 0x33
#define LEVEL_1V8 0x18
typedef union {
struct {
uint32_t rg_poc_value : 1; /* [0] */
uint32_t rg_poc_sel : 1; /* [1] */
uint32_t pmu_vdd3318_flag : 1; /* [2] */
uint32_t ms1c : 1; /* [3] */
uint32_t rsv : 28; /* [31:4] */
} bits;
uint32_t u32;
} u_poc_coex;
static void fix_io_level(void)
{
u_poc_coex poc_coex = {0};
poc_coex.u32 = readl(PMU_CMU_CTL_POC_COEX);
if (poc_coex.bits.ms1c == poc_coex.bits.pmu_vdd3318_flag) {
return;
}
if (poc_coex.bits.pmu_vdd3318_flag != PMU_VDD_FLAG_3V3) {
return;
}
poc_coex.bits.rg_poc_value = POC_VALUE_3V3;
poc_coex.bits.rg_poc_sel = POC_SEL_SW_MODE;
writel(PMU_CMU_CTL_POC_COEX, poc_coex.u32);
}
static void dump_io_level(void)
{
u_poc_coex poc_coex = {0};
uint32_t chip_level = LEVEL_3V3;
uint32_t sw_level = LEVEL_3V3;
poc_coex.u32 = readl(PMU_CMU_CTL_POC_COEX);
if (poc_coex.bits.rg_poc_sel == POC_SEL_SW_MODE) {
sw_level = (poc_coex.bits.rg_poc_value == POC_VALUE_3V3) ? LEVEL_3V3 : LEVEL_1V8;
chip_level = (poc_coex.bits.ms1c == POC_VALUE_3V3) ? LEVEL_3V3 : LEVEL_1V8;
boot_msg2("io level work in sw mode, level[sw:chip]:", sw_level, chip_level);
} else {
chip_level = (poc_coex.bits.ms1c == POC_VALUE_3V3) ? LEVEL_3V3 : LEVEL_1V8;
boot_msg1("io level work in hw mode, level[chip]:", chip_level);
}
}
#define FASTBOOT_PWM 1 //CONFIG_PWM_USING_V151
#if FASTBOOT_PWM
#define e_printf print_str
#include "pwm.h"
#ifndef __SPOTLIGHT_H__
#define __SPOTLIGHT_H__
typedef enum elightMode {
LIGHT_MODE_CUSTOMER = 0, // 非情景模式
LIGHT_MODE_RELAX, // 休闲模式
LIGHT_MODE_MOVIE, // 观影模式
LIGHT_MODE_DINING, // 用餐模式
LIGHT_MODE_HOME, // 回家模式
LIGHT_MODE_WINTER, // 冬天模式
LIGHT_MODE_SUMMER, // 夏天模式
LIGHT_MODE_LEAVE, // 离家模式
LIGHT_MODE_MAX // 模式数量
} lightMode_e;
// 位掩码定义
#define LIGHT_MODE_LEAVE_BIT (1 << 7) // 离家模式位
#define LIGHT_MODE_MASK (0x7F) // 基础模式掩码7位
#define LIGHT_MODE_IS_LEAVE(mode) ((mode) & LIGHT_MODE_LEAVE_BIT)
#define LIGHT_MODE_GET_BASE(mode) ((mode) & LIGHT_MODE_MASK)
#define LIGHT_MODE_SET_LEAVE(base_mode) ((base_mode) | LIGHT_MODE_LEAVE_BIT)
typedef enum {
INIT_POWER_ON,
NET_CONFIGING,
BIND_OK,
}eDeviceBindStatus;
// 服务ID定义
#define SVC_ID_SWITCH "switch" // 开关控制
#define SVC_ID_BRIGHTNESS "brightness" // 亮度控制
#define SVC_ID_CCT "cct" // 色温控制
#define SVC_ID_LIGHT_MODE "lightMode" // 场景模式控制
#define SVC_ID_FADE_TIME "progressSwitch" // 渐变时长的控制
#define SVC_ID_COLOUR_MODE "colourMode" // 色温模式控制
// JSON字段名定义
#define JSON_FIELD_ON "on" // 开关状态字段
#define JSON_FIELD_BRIGHTNESS "brightness" // 亮度字段
#define JSON_FIELD_CCT "colorTemperature" // 色温字段
#define JSON_FIELD_MODE "mode" // 场景模式字段
#define JSON_FIELD_FADE_TIME "fadeTime" // 渐变时长字段
#define JSON_FIELD_COLOUR_MODE "mode" // 色温模式字段
typedef enum {
REPORT_SWITCH = 1 << 0,
REPORT_BRIGHTNESS = 1 << 1,
REPORT_CCT = 1 << 2,
REPORT_LIGHT_MODE = 1 << 3,
REPORT_FADE_TIME = 1 << 4,
REPORT_COLOUR_MODE = 1 << 5,
REPORT_ALL = REPORT_SWITCH | REPORT_BRIGHTNESS | REPORT_CCT | REPORT_LIGHT_MODE | REPORT_FADE_TIME | REPORT_COLOUR_MODE,
} report_mask_e;
// 色温模式定义
typedef enum {
COLOUR_MODE_SINGLE = 0, // 单色温模式
COLOUR_MODE_DUAL = 1, // 双色温模式
} colourMode_e;
// 当前亮度和色温状态
typedef struct __attribute__((packed, aligned(1))) {
// 物模型同步需要 持久化维持
uint8_t on; // 开关状态
lightMode_e elightMode;
uint16_t brightness_local; // 当前亮度 (0-1000)
uint16_t fade_time; // 渐变时长(s)
uint16_t cct_local; // 当前色温 (2700-6500)
uint8_t colourMode; // 色温模式 (0:单色温, 1:双色温)
// 持久化维持
int32_t power_on_cnt; // 上电次数计数
uint8_t is_bound; // 是否已配网
uint8_t is_net_configured; // 设备是否曾经配网成功过
uint32_t reserve[10]; // 保留字段
//运行时的数据
uint16_t duty_cw; // 冷白LED占空比
uint16_t duty_ww; // 暖白LED占空比
uint8_t read_done; // 读取数据done
} device_control_t;
// 色温范围定义
#define CCT_MIN 2700 // 最小色温 2700K (暖白)
#define CCT_MAX 6000 // 最大色温 6000K (冷白)
#define CCT_RANGE (CCT_MAX - CCT_MIN)
#define CCT_LOCAL_MIN 0 // 最小色温 0K (暖白)
#define CCT_LOCAL_MAX (CCT_LOCAL_MIN + CCT_RANGE) // 最大色温 6000K (冷白)
#define CCT_LOCAL2REMOTE(x) (x + (CCT_MIN - CCT_LOCAL_MIN))
#define CCT_REMOTE2LOCAL(x) (x - (CCT_MIN - CCT_LOCAL_MIN))
#define CCT_LITME_RANGE(x) do { \
if (x > CCT_LOCAL_MAX) x = CCT_LOCAL_MAX; \
if (x < CCT_LOCAL_MIN) x = CCT_LOCAL_MIN; \
} while (0)
// 亮度范围定义
#define BRIGHTNESS_MIN 0 // 最小亮度
#define BRIGHTNESS_MAX 100 // 最大亮度
#define BRIGHTNESS_LOCAL_MIN 0 // 最小亮度
#define BRIGHTNESS_LOCAL_MAX 1000 // 最大亮度
#define BRIGHTNESS_REMOTE2LOCAL(x) (x * 10) //变化范围0 -1000
#define BRIGHTNESS_LOCAL2REMOTE(x) (x / 10)
#define BRIGHTNESS_LITME_RANGE(x) do { \
if (x > BRIGHTNESS_LOCAL_MAX) x = BRIGHTNESS_LOCAL_MAX; \
if (x < BRIGHTNESS_LOCAL_MIN) x = BRIGHTNESS_LOCAL_MIN; \
} while (0)
// 设备上电并未进入配网的状态
#define INIT_STA__LIGHT_MODE LIGHT_MODE_CUSTOMER
#define INIT_STA__BRIGHTNESS 50
#define INIT_STA__CCT 4000
#define INIT_NET_CFG_PWOER_ON_KEEP_TIME (5 * 1000) // 统计进入配网每次打开状态的保持时间
#define NET_CFG_ENTRY_CNT 6 // 配网进入的上电次数
#define NET_CFG_BREATH_DURATION 1*60*1000 // 配网呼吸灯持续时间(ms)
#define NET_CFG_TOTAL_TIMEOUT 10*60*1000 // 配网总超时时间(ms)
// 配网成功后的默认值
#define NET_CFG_DEFAULT_BRIGHTNESS 80 // 默认亮度
#define NET_CFG_DEFAULT_CCT 6000 // 默认色温
#define NET_CFG_DEFAULT_FADE_TIME 1 // 默认渐变时长(s)
#define NET_CFG_DEFAULT_LIGHTMODE LIGHT_MODE_CUSTOMER // 默认模式
// 配网超时后的默认值
#define NET_CFG_TIMEOUT_BRIGHTNESS 50 // 呼吸灯超时后的亮度
#define NET_CFG_TIMEOUT_CCT 4000 // 呼吸灯超时后的色温
#define FADE_INTERVAL_MIN (10*1000) //us
#define NORMAL_FADE_TIME 3 //s
#define PWM_DUTY_RATIO_MAX 1000
//呼吸灯定义
#define BREARTH_PERIOD (3*1000*1000) //呼吸灯周期(Us)
#define BREARTH_INTERVAL (3*1000) //更新pwm的间隔 us
#define BREARTH_STEP ((PWM_DUTY_RATIO_MAX) * 2) / (BREARTH_PERIOD / BREARTH_INTERVAL) //每次变化的幅度
// PWM频率和周期定义
#define PWM_FREQUENCY 3000 // PWM频率 2KHz
//渐变范围
#define SMOOTH_TIME_MAX 30
#define SMOOTH_TIME_MIN 0
#define SUPPORT_SAVE_TO_FLASH 1
// 定义Flash存储地址和大小
#define DEVICE_DATA_FLASH_ADDR 0x000000 // 主数据区地址
#define DEVICE_DATA_BACKUP_ADDR 0x001000 // 备份数据区地址
#define DEVICE_DATA_FLASH_SIZE 0x001000 // 使用一个页的大小
// 设备数据结构
typedef struct __attribute__((packed, aligned(1))) {
uint8_t checksum; // 校验和
uint32_t magic; // 魔数,用于验证数据有效性
uint32_t version; // 数据版本号
device_control_t control; // 设备控制状态
} device_data_t;
#define DEVICE_DATA_MAGIC 0x4C505426 // "LPT&"的ASCII码
#define DEVICE_DATA_VERSION 1 // 数据版本号
// 保存任务相关定义
#define SAVE_TASK_PRIO 25
#define SAVE_TASK_STACK_SIZE 0x1000
#define SAVE_TASK_SLEEP_TIME 100 // 100ms
// 保存任务状态
typedef enum {
SAVE_STATE_IDLE = 0, // 空闲状态
SAVE_STATE_SAVING, // 正在保存
SAVE_STATE_WAITING // 等待保存
} save_state_e;
typedef enum {
APP_CHANGE_LIGHT_MODE = 0,
APP_CHANGE_LIGHT_BRIGHTNESS_CCT,
APP_CLOSE_LIGHT,
APP_OPEN_LIGHT,
DEV_POWER_ON,
} light_ctrl_source_e;
// 单色温模式的固定色温值
#define SINGLE_COLOUR_CCT 6000 // 单色温模式固定色温 6000K
#define SINGLE_COLOUR_CCT_LOCAL CCT_REMOTE2LOCAL(SINGLE_COLOUR_CCT) // 转换为本地值
#define BRIGHTNESS_PIN GPIO_04 // 冷白LED (CW)
#define CCT_PIN GPIO_00 // 暖白LED (WW)
#define SWITCH_PIN GPIO_13
#define CONFIG_PWM_GROUP_ID 2
#define DEFAULT_DEVICE_DATA { \
.read_done = false, \
.on = true, \
.elightMode = INIT_STA__LIGHT_MODE, \
.cct_local = CCT_REMOTE2LOCAL(INIT_STA__CCT), \
.brightness_local = BRIGHTNESS_REMOTE2LOCAL(INIT_STA__BRIGHTNESS), \
.fade_time = NET_CFG_DEFAULT_FADE_TIME, \
.colourMode = COLOUR_MODE_DUAL, \
.is_bound = false, \
.is_net_configured = false, \
.duty_cw = 0, \
.duty_ww = 0, \
};
int spotlight_main(void);
int set_light(light_ctrl_source_e source,
int32_t brightness_local_target, int32_t cct_local_target);
int set_smooth_time(uint32_t smooth_time); // 设置渐变时长
void update_pwm_output(bool on_state, uint16_t duty_cw, uint16_t duty_ww);
// 模式转换函数
lightMode_e convert_mode_for_report(lightMode_e current_mode); // 将bitmask转换为上报用的枚举值
void stop_net_config(void);
extern int fast_report(const char* svc_id);
#endif // __SPOTLIGHT_H__
device_control_t g_device_control = DEFAULT_DEVICE_DATA;
static uint32_t pwm_period_cnt = 0; // PWM周期 40us
static uint8_t channel_id_cw = 0; // 冷白LED通道ID
static uint8_t channel_id_ww = 0; // 暖白LED通道ID
// 计算PWM占空比
void calculate_pwm_duty(device_control_t* pdevice_control)
{ // 如果开关关闭则占空比为0
uint32_t total_brightness_pwm = pdevice_control->brightness_local;
if (pdevice_control->colourMode == COLOUR_MODE_SINGLE) { // 单色模式,色温设置为最大值
pdevice_control->cct_local = SINGLE_COLOUR_CCT_LOCAL;
}
// 根据色温比例计算CW和WW的占空比
// 计算色温比例 (0-10000)
uint16_t cct_ratio = ((pdevice_control->cct_local - CCT_LOCAL_MIN) * 10000) / CCT_RANGE;
// 根据色温比例计算CW和WW的占空比
// 总亮度保持不变只调整CW和WW的比例
pdevice_control->duty_cw = (total_brightness_pwm * cct_ratio) / 10000;
pdevice_control->duty_ww = total_brightness_pwm - pdevice_control->duty_cw;
}
// 更新PWM输出
void update_pwm_output(bool on_state, uint16_t duty_cw_val, uint16_t duty_ww_val)
{
pwm_config_t cfg_repeat = {0};
cfg_repeat.repeat = true;
uint16_t current_duty_cw = duty_cw_val;
uint16_t current_duty_ww = duty_ww_val;
if (current_duty_cw > PWM_DUTY_RATIO_MAX) {
current_duty_cw = PWM_DUTY_RATIO_MAX;
}
if (current_duty_ww > PWM_DUTY_RATIO_MAX) {
current_duty_ww = PWM_DUTY_RATIO_MAX;
}
uint32_t high_cnt_cw = (pwm_period_cnt * current_duty_cw) / PWM_DUTY_RATIO_MAX;
uint32_t low_cnt_cw = pwm_period_cnt - high_cnt_cw;
uint32_t high_cnt_ww = (pwm_period_cnt * current_duty_ww) / PWM_DUTY_RATIO_MAX;
uint32_t low_cnt_ww = pwm_period_cnt - high_cnt_ww;
if (!on_state) {
high_cnt_cw = 0;
low_cnt_cw = pwm_period_cnt; // Ensure low_cnt is full period if off
high_cnt_ww = 0;
low_cnt_ww = pwm_period_cnt; // Ensure low_cnt is full period if off
}
// uapi_pwm_stop_group(CONFIG_PWM_GROUP_ID);
cfg_repeat.high_time = high_cnt_cw;
cfg_repeat.low_time = low_cnt_cw;
uapi_pwm_open(channel_id_cw, &cfg_repeat);
// uapi_pwm_update_duty_ratio(channel_id_cw, cfg_repeat.low_time, cfg_repeat.high_time);
cfg_repeat.high_time = high_cnt_ww;
cfg_repeat.low_time = low_cnt_ww;
cfg_repeat.offset_time = high_cnt_cw; // WW PWM starts after CW PWM high time
uapi_pwm_open(channel_id_ww, &cfg_repeat);
// uapi_pwm_update_duty_ratio(channel_id_ww, cfg_repeat.low_time, cfg_repeat.high_time);
uapi_pwm_start_group(CONFIG_PWM_GROUP_ID);
}
static void pwm_init(pin_t pin, pin_t pin1)
{
// uapi_pin_set_mode(pin, PIN_MODE_1);
// uapi_pin_set_mode(pin1, PIN_MODE_1);
writel(0x4400d000, 1); //设置GPIO00引脚PWM输出 寄存器地址和io复用号参考文档
writel(0x4400d010, 1); //设置GPIO04引脚PWM输出 寄存器地址和io复用号参考文档
uapi_pwm_init();
// uint32_t frequency = uapi_pwm_get_frequency(pin%8);
// uint32_t pwm_base_period_ns = 1000 * 1000 * 1000 / frequency;
// uint32_t pwm_base_period_ns = 1000 * 1000 * 1000 / (80 * 1000 * 1000);// 80MHZ
// uint32_t pwm_target_period_ns = 1000 * 1000 * 1000 / PWM_FREQUENCY;
pwm_period_cnt = ((80 * 1000 * 1000) / PWM_FREQUENCY);
// 设置PWM组
channel_id_cw = pin%8;
channel_id_ww = pin1%8;
uint8_t channel_ids[2] = {channel_id_cw, channel_id_ww};
pwm_config_t cfg_repeat = {0};
cfg_repeat.repeat = true;
cfg_repeat.low_time = pwm_period_cnt;
uapi_pwm_open(channel_id_cw, &cfg_repeat);
uapi_pwm_open(channel_id_ww, &cfg_repeat);
uapi_pwm_set_group(CONFIG_PWM_GROUP_ID, channel_ids, sizeof(channel_ids));
uapi_pwm_start_group(CONFIG_PWM_GROUP_ID);
// 计算PWM占空比
calculate_pwm_duty(&g_device_control);
// 更新PWM输出
update_pwm_output(g_device_control.on, g_device_control.duty_cw, g_device_control.duty_ww);
boot_msg0("PWM init success!");
}
// 计算校验和
static uint8_t calculate_checksum(const device_data_t* data)
{
uint8_t sum = 0;
const uint8_t* ptr = (const uint8_t*)(((char*)data) + sizeof(data->checksum));
size_t len = sizeof(device_data_t) - sizeof(data->checksum); // 减去checksum字段的大小
for (size_t i = 0; i < len; i++) {
sum ^= ptr[i];
}
return sum;
}
// 验证数据有效性
static bool verify_device_data(const device_data_t* data)
{
if (data->magic != DEVICE_DATA_MAGIC) {
e_printf("magic error:%x\n", data->magic);
return false;
}
if (data->version > DEVICE_DATA_VERSION) {
e_printf("versoin missmatch:%x\n", data->version);
return false;
}
uint8_t checksum = calculate_checksum(data);
if (checksum != data->checksum) {
e_printf("check sum error:%x\n", data->version);
return false;
}
return true;
}
// 从指定地址读取设备数据
static bool read_device_data_from_addr(uint32_t addr, device_data_t* data)
{
int ret = uapi_sfc_reg_read(addr, (uint8_t*)data, sizeof(device_data_t));
if (ret != 0) {
print_str("read device data from address 0x%x failed, actual read length: %d\r\n", addr, ret);
return false;
}
if (!verify_device_data(data)) {
print_str("address 0x%x data is invalid\r\n", addr);
return false;
}
return true;
}
void read_device_data(void)
{
#if SUPPORT_SAVE_TO_FLASH
device_data_t data;
bool main_valid = false;
bool backup_valid = false;
// 尝试读取主数据区
main_valid = read_device_data_from_addr(DEVICE_DATA_FLASH_ADDR + 0x003DE000, &data);
// 如果主数据区无效,尝试读取备份区
if (!main_valid) {
backup_valid = read_device_data_from_addr(DEVICE_DATA_BACKUP_ADDR + 0x003DE000, &data);
}
if (!main_valid && backup_valid) { // 如果主数据区无效但备份区有效,从备份区恢复
print_str("restore data from backup\r\n");
} else if (!main_valid && !backup_valid) { // 如果两个区域都无效,使用默认值
print_str("main and backup data are invalid, use default value\r\n");
goto lab_exit;
}
// 更新设备控制状态
print_str("restore device status:\r\n");
print_str("on: %d => %d\r\n", g_device_control.on, data.control.on);
print_str("brightness: %d => %d\r\n", g_device_control.brightness_local, data.control.brightness_local);
print_str("cct: %d => %d\r\n", g_device_control.cct_local, data.control.cct_local);
e_printf("colourMode: %d => %d\r\n", g_device_control.colourMode, data.control.colourMode);
data.control.read_done = false;
g_device_control = data.control;
lab_exit:
#endif
g_device_control.read_done = true;
print_str("read device data success\r\n");
}
#endif // end of FASTBOOT_PWM
static uint32_t ws63_flashboot_init(void)
{
errcode_t err;
uart_param_stru uart_param = FLASHBOOT_UART_DEFAULT_PARAM;
uapi_tcxo_init();
hiburn_uart_init(uart_param, HIBURN_CODELOADER_UART);
boot_msg0("Flashboot Uart Init Succ!");
uapi_partition_init();
pmp_enable();
malloc_port_init();
boot_flash_init();
boot_msg0("Flashboot Uart Init Succ!");
boot_msg0("Flashboot Malloc Init Succ!");
err = sfc_port_fix_sr();
if (err != ERRCODE_SUCC) {
boot_msg1("SFC fix SR ret =", err);
}
dump_io_level();
#if FASTBOOT_PWM
read_device_data();
pwm_init(BRIGHTNESS_PIN, CCT_PIN);
#endif
print_str("flashboot version : %s\r\n", SDK_VERSION);
return 0;
}
static errcode_t ws63_verify_app(uint32_t addr)
{
errcode_t ret = ERRCODE_SUCC;
image_key_area_t *flashboot_key_area = (image_key_area_t *)(FLASHBOOT_RAM_ADDR);
ret = verify_image_head(APP_BOOT_TYPE, (uint32_t)(uintptr_t)flashboot_key_area->ext_pulic_key_area, addr);
if (ret != ERRCODE_SUCC) {
boot_msg1("flashboot verify_image_app_head failed!! ret = ", ret);
return ret;
}
ret = verify_image_body(addr, addr + APP_IMAGE_HEADER_LEN);
if (ret != ERRCODE_SUCC) {
boot_msg1("verify_image_app_body failed!! ret = ", ret);
return ret;
}
return ERRCODE_SUCC;
}
static void ws63_verify_app_handle(uint32_t addr)
{
errcode_t ret = ws63_verify_app(addr);
if (ret != ERRCODE_SUCC) {
ws63_try_fix_app();
reset();
}
set_reset_count(0);
ws63_set_try_fix_cnt(0);
}
static void ws63_flash_encrypt_config(uint32_t image_addr, uint32_t image_size)
{
image_code_info_t *img_info = (image_code_info_t *)(uintptr_t)(image_addr + sizeof(image_key_area_t));
crypto_klad_effective_key flash_key = {0};
uint32_t start_addr = image_addr + APP_IMAGE_HEADER_LEN;
uint32_t end_addr = image_addr + image_size;
int32_t ret = ERRCODE_SUCC;
if (img_info->code_enc_flag == FLASH_NO_ENCRY_FLAG) {
boot_msg0("flash_encrypt disable.");
return;
}
if (start_addr % FLASH_ENCRY_ADDR_ALINE != 0 || end_addr % FLASH_ENCRY_ADDR_ALINE != 0) {
boot_msg2("app_image start or end addr err, must 256byte alignment ", image_addr, end_addr);
reset();
}
boot_msg0("flash_encrypt enable.");
flash_key.kdf_hard_alg = CRYPTO_KDF_HARD_ALG_SHA256;
flash_key.key_parity = TD_FALSE;
flash_key.key_size = CRYPTO_KLAD_KEY_SIZE_128BIT;
flash_key.salt = img_info->protection_key_l1;
flash_key.salt_length = FLASH_KEY_SALT_LEN;
flash_key.oneway = TD_TRUE;
ret = drv_rom_cipher_config_odrk1(flash_key);
if (ret != ERRCODE_SUCC) {
boot_msg1("fapc_set_config drv_rom_cipher_config_odrk1 err = ", (uint32_t)ret);
reset();
}
ret = drv_rom_cipher_fapc_config(0, start_addr, end_addr, img_info->iv, IV_LEN);
if (ret != ERRCODE_SUCC) {
boot_msg1("fapc_set_config drv_rom_cipher_fapc_config err = ", (uint32_t)ret);
reset();
}
ret = drv_rom_cipher_fapc_bypass_config(1, end_addr, FLASH_MAX_END, TD_TRUE);
if (ret != ERRCODE_SUCC) {
boot_msg1("fapc_set_config drv_rom_cipher_fapc_bypass_config err = ", (uint32_t)ret);
reset();
}
}
static uint32_t ws63_ftm_mode_init(uint32_t image_addr)
{
uint32_t image_size = 0;
uint32_t jump_addr = 0;
mfg_factory_config_t mfg_factory_cfg = {0};
uint32_t run_region = mfg_get_ftm_run_region(&mfg_factory_cfg);
if (run_region == FTM_REGION_SERVICE) {
return 0;
}
jump_addr = mfg_factory_cfg.factory_addr_start;
image_size = mfg_factory_cfg.factory_size;
image_key_area_t *mfg_key_area = (image_key_area_t *)(uintptr_t)(jump_addr);
if (mfg_key_area->image_id == FACTORYBOOT_KEY_AREA_IMAGE_ID && mfg_factory_cfg.factory_valid == MFG_FACTORY_VALID) {
dmmu_set(image_addr, image_addr + image_size, jump_addr, 0);
}
return 0;
}
/* the entry of C. */
void start_fastboot(void)
{
partition_information_t img_info = {0};
uint32_t image_addr = 0;
uint32_t image_size = 0;
errcode_t err;
fix_io_level();
// 关闭CMU假负载
uapi_reg_setbits(REG_CMU_CFG0, 3, 3, 0x7); // 0x7 -> 0x40003408 bit 5:3 (3 bits)
boot_clock_adapt();
dmmu_set(0, 0, 0, FAMA_REMAP_LOW_BITS);
uapi_watchdog_init(BOOT_WATCH_DOG_TIMOUT);
uapi_watchdog_enable(WDT_MODE_RESET);
ws63_flashboot_init();
set_efuse_period();
uapi_efuse_init();
ws63_upg_check(); // 升级模式判断
err = uapi_partition_get_info(PARTITION_APP_IMAGE, &img_info);
if (err != ERRCODE_SUCC) {
boot_msg0("Flashboot get app partition failed!, boot abort!");
reset();
}
image_addr = img_info.part_info.addr_info.addr + FLASH_START;
image_size = img_info.part_info.addr_info.size;
#ifdef CONFIG_MIDDLEWARE_SUPPORT_UPG_AB
char *boot_str = "A";
uint32_t jump_addr = upg_get_region_addr(upg_get_run_region()) + FLASH_START;
*boot_str = (image_addr == jump_addr) ? 'A' : 'B';
boot_msg0(boot_str);
ws63_flash_encrypt_config(jump_addr, image_size); // flash在线加解密配置
ws63_verify_app_handle(jump_addr); // A/B验签
if (image_addr != jump_addr) {
// 0x1000: dmmu配置都是闭区间且需要是4K对齐的地址, 0: 第0组dmmu配置
dmmu_set(image_addr, image_addr + image_size - 0x1000, jump_addr, 0);
// 0x1000: dmmu配置都是闭区间且需要是4K对齐的地址, 1: 第1组dmmu配置
dmmu_set(jump_addr, jump_addr + image_size - 0x1000, image_addr, 1);
}
#else // 压缩
ws63_flash_encrypt_config(image_addr, image_size); // flash在线加解密配置
ws63_verify_app_handle(image_addr); // app验签
#endif
ws63_ftm_mode_init(image_addr);
ws63_flashboot_recovery();
uapi_watchdog_kick();
jump_to_execute_addr(image_addr + APP_IMAGE_HEADER_LEN);
}