This repository has been archived on 2025-04-02. You can view files and clone it, but cannot push or open issues or pull requests.
controller-hart/User/app.c

391 lines
13 KiB
C
Raw Permalink 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.

/**
* @file app.c
* @author xxx
* @date 2023-08-30 08:58:43
* @brief app初始化和app启动
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#include "file_storage.h"
#include "app.h"
#include "adcs.h"
#include "menus.h"
#include "test_bsp.h"
#include "bootload.h"
#include "wl_flash.h"
#include "mode_diagnosis.h"
// https://blog.51cto.com/u_15427821/4586693
__IO device_reset_flag_e reset_flag __attribute__((section("NOINIT"), zero_init)); ///< 复位标志
__IO udevice_t udevice __attribute__((section("NOINIT"), zero_init)); ///< 设备参数
__IO rt_save_param_t rt_save __attribute__((section("NOINIT"), zero_init)); ///< 实时参数
__IO calib_param_t calib_param[CALIBPARA_MAX] __attribute__((section("NOINIT"), zero_init)); ///< 校准参数
pressure_calib_param_t pressure_calib_param[PRESSURE_PARAM_MAX] __attribute__((section("NOINIT"), zero_init)); ///< 压力校准参数
pid_t _pid; ///< pid参数
real_time_data_t rt_data; ///< 实时参数
driver_icon_enable_u driver_icon_enable; ///< 驱动使能图标
file_storage_t nvm1_file_storage; ///< 保存报警日志、出厂信息
// 模拟量
__IO uint16_t adc_raw[ADC1_MAX]; // ADC原始值
__IO const static uint32_t cupid_encrypt = 0xFFFFFFFF;
/**
* @brief 保存板载数据到Flash
*
* 该函数首先擦除存储板载数据的Flash区域然后将板载数据写入到该区域。
*
*/
void board_data_save(void)
{
wl_flash_erase(&wl_flash_board_data);
wl_flash_write(&wl_flash_board_data, (uint8_t*)&board_data, sizeof(board_data_t));
}
#ifndef BOOTLOAD // 非bootload模式
static void bootload_preload(void)
{
set_app_preload_bootload_flag(BOOTLOAD_UNSET_FLAG);
if (get_app_preload_bootload_jump_flag() == APP_PRELOAD_BOOTLOAD_JUMP_IMMEDIATELY) // 通过标志位判断是否跳转到BOOTLOAD
{
DBG_ASSERT(FALSE __DBG_LINE);
set_app_preload_bootload_jump_flag(APP_PRELOAD_BOOTLOAD_JUMP_NONE);
// 反初始化所有硬件
board_dinit();
LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_PWR);
bootload_jump(BOOTLOAD_START_ADDRESS);
}
}
static void app_preload_logo(BOOL is_first)
{
if (is_first)
{
menus_init(udevice.display_language);
}
else
{
menus_set_work_index(get_work_page_index());
menus_set_language(get_language());
}
if (is_lcd_ext_board() == TRUE)
{
get_menus()->accelerate = TRUE;
#if LCD_DESIGN == FALSE
menus_loading_draw(is_first);
#else
menus_jump(MENUS_MAIN, TRUE);
#endif
gui_flush();
}
}
static void app_preload(void)
{
get_cpu_id((uint8_t*)rt_data.cpuid);
get_cpu_id_32((uint32_t*)rt_data.cpuid_32);
#if CPU_ENCRYPT_ENABLE == TRUE
if (cpu_judge_encrypt(board_data.app_preload_cupid_encrypt) == FALSE)
{
board_dinit();
leds_on_all();
// 加密错误
while (1)
{
__NOP(); // 程序被拷贝才会运行到这里
}
}
#endif
bootload_preload();
if (is_lcd_ext_board() == TRUE)
{
#if LCD_DESIGN == FALSE
app_preload_logo(FALSE);
#endif
}
}
/**
* @brief BOOTLOAD传输数据
* @param {uint8_t} *data
* @param {uint16_t} len
* @return {*}
* @note
*/
static void bootload_transmit(const uint8_t data_src, const uint8_t* data, const uint16_t len)
{
extern uart_t* uarts[APP_UART_MAX];
uart_send_data(uarts[data_src], (uint8_t*)data, len);
}
/**
* @brief BOOTLOAD更新完成处理
* @return {*}
* @note BOOTLOAD更新完成恢复业务流程这个时候不要重启
*/
static void bootload_end(BOOL bootload_write_flag)
{
set_app_preload_bootload_flag(BOOTLOAD_UNSET_FLAG); // 更新完成恢复业务流程
if (bootload_write_flag == TRUE)
{
set_app_preload_bootload_jump_flag(APP_PRELOAD_BOOTLOAD_JUMP_WAIT); // 更新完成等待用户通知跳转到bootload
}
else
{
set_app_preload_bootload_jump_flag(APP_PRELOAD_BOOTLOAD_JUMP_NONE);
// 更新失败 通知用户
}
}
#endif
// 启动电压电量检查
static void startup_power_on_diagnosis(void)
{
BOOL is_low_battery = FALSE;
float32 voltage = 0.0f;
float32 current = 0.0f;
static float32 voltage_last = 0.0f;
static float32 current_last = 0.0f;
BOOL voltage_right = FALSE;
BOOL current_right = FALSE;
for (;;)
{
LL_mDelay(200);
voltage = get_cpu_volt();
current = get_current_by_resistance();
if (IS_BETWEEN(voltage, CPU_VREF_RUN_MIN, CPU_VREF_RUN_MAX) && current >= INPUT_CURRENT_RUN)
{
break;
}
// 这里需要在LCD上显示电量不足的LOG
if (is_low_battery == FALSE || (voltage_last != voltage || current_last != current))
{
voltage_right = IS_BETWEEN(voltage, CPU_VREF_RUN_MIN, CPU_VREF_RUN_MAX);
current_right = current >= INPUT_CURRENT_RUN;
voltage_last = voltage;
current_last = current;
menus_init(CHINESE);
if (is_lcd_ext_board() == TRUE)
{
menus_low_battery_draw(voltage, voltage_right, current, current_right);
gui_flush();
}
is_low_battery = TRUE;
}
}
if (reset_flag != DEVICE_IS_ON)
{
reset_flag = DEVICE_IS_POWER_DOWN;
}
}
/**
* @brief 判断当前是否在正确的型号下
*
* 检查当前是否处于正确的型号下,用于确保程序运行环境的正确性。
*
* @return 如果在正确的型号下,返回 TRUE否则返回 FALSE。
*/
BOOL in_correct_model(void)
{
if (udevice.dev_model == POSITIONER_MODEL_GPS2000 || udevice.dev_model == POSITIONER_MODEL_GPS3000)
{
return TRUE;
}
else
{
return FALSE;
}
}
// 设置设备重启后仪器模式和控制模式
static void device_reset_set_mode(void)
{
if (udevice.restart_inst_mode != RST_RESUME_INST)
{
udevice.inst_mode = udevice.restart_inst_mode;
}
if (udevice.restart_ctrl_mode != RST_RESUME_CTRL)
{
udevice.control_mode = udevice.restart_ctrl_mode;
}
}
// 考虑到主频加速除非PVD中断响应不一定成功
/**
* @brief PVD掉电检测功能回调处理
*
* 将系统切换到低功耗模式,关闭特定定时器、关闭特定电源、反初始化外设和驱动等。
*
* @return 无返回值
*/
// static void pvd_low(void)
// {
// // 设置掉电标志位
// {
// power_on.flag = PVD_RESET_FLAG;
// osel_memcpy(power_on.time.data, (uint8_t *)rt_save.real_time.data, ARRAY_LEN(rt_save.real_time.data));
// wl_flash_write(&wl_flash_power_on, (uint8_t *)&power_on, sizeof(device_reset_t));
// }
// }
/**
* @brief app初始化
* @return {*}
* @note
*/
void app_init(void)
{
osel_memset((uint8_t*)&rt_data, 0, sizeof(real_time_data_t));
rt_data.storage_used_page_count = BUSINESS_START_PAGE;
#if DEBUG_ENABLE == TRUE
#endif
rt_data.flag.bits.app_init_over = FALSE;
#ifndef BOOTLOAD // 非bootload模式
{
LCD_POWER_ON(); // 打开LCD,3000的LED电源来自LCD供电
leds_on(LEDS_RED);
startup_power_on_diagnosis(); // 启动电源检查,内部电压>=CPU_VREF,且输入电流>=INPUT_CURRENT_RUN
leds_off_all();
wl_flash_init(&wl_flash_board_data);
system_clock_config_high(); // 系统时钟配置为高速模式
timer_cycle_update(); // 定时器周期
params_storage_init(); // 参数存储初始化
if (board_data.app_preload_version == CURRENT_VERSION && board_data.app_preload_first_flag == APP_PRELOAD_FIRST)
{
device_reset_set_mode(); // 设置设备重启后仪器模式和控制模式
if (reset_flag == DEVICE_IS_ON)
{
if (in_correct_model())
{
mode_init(); // 工作模式初始化
mode_master_detection(); // 工作模式控制管理
ENABLE_TIM(MODE_TIM); // MODE_TIM用于算法控制
ENABLE_TIM(MODE_GATHE_TIM); // Enable MODE_GATHE_TIM
}
}
}
app_preload_logo(TRUE);
leds_on(LEDS_GREEN);
params_init(); // 参数初始化
device_reset_set_mode(); // 设置设备重启后仪器模式和控制模式
timer_cycle_update(); // 定时器周期
key_init(); // 按键初始化
diagnosis_init(); // 诊断模块初始化
{
file_storage_init(&nvm1_file_storage, _M95M02_, 2, eeprom_m95_1_read, eeprom_m95_1_write); // 文件存储初始化
uint16_t diagnosis_log_max_node = 30000;
uint32_t diagnosis_log_start_addr = 0;
file_storage_block_params_t diagnosis_log =
{
.is_node = TRUE,
.is_cycle_write = TRUE, // 诊断数据需要循环写入
.node_size = sizeof(diagnosis_log_data_node_t),
.start_node = rt_save.diagnosis_log_node_start_offset_index, // 诊断日志起始偏移索引
.used_node = rt_save.diagnosis_log_node_write_count, // 已写入节点数
.node_max = diagnosis_log_max_node,
.start_addr = diagnosis_log_start_addr,
.end_addr = diagnosis_log_start_addr + (diagnosis_log_max_node + 1) * sizeof(diagnosis_log_data_node_t),
.used_size = rt_save.diagnosis_log_node_write_count * sizeof(diagnosis_log_data_node_t),
};
file_storage_block_create(&nvm1_file_storage, FILE_BLOCK_DIAGNOSIS_LOG, &diagnosis_log);
/**
* 设备溯源信息
* 1. 设计存储10条记录每条记录占用64字节
* 2. 读取的时候按照诊断数据的格式读取每次读取一条记录每次读取64字节
* 3. 写入的时候按照诊断数据的格式写入每次写入一条记录每次写入64字节
*/
uint16_t instrument_information_max_node = 10;
uint32_t instrument_information_start_addr = diagnosis_log.end_addr;
file_storage_block_params_t instrument_information =
{
.is_node = TRUE,
.is_cycle_write = FALSE, // 设备溯源信息不需要循环写入
.node_size = PACKED64_LEN,
.start_node = 0,
.used_node = 0,
.node_max = instrument_information_max_node,
.start_addr = instrument_information_start_addr,
.end_addr = instrument_information_start_addr + instrument_information_max_node * PACKED64_LEN,
.used_size = 0,
};
file_storage_block_create(&nvm1_file_storage, FILE_BLOCK_EQUIPMENT_TRACEABILITY_INFORMATION, &instrument_information);
}
if (reset_flag == DEVICE_IS_POWER_DOWN && in_correct_model())
{
mode_init(); // 工作模式初始化
ENABLE_TIM(MODE_TIM); // MODE_TIM用于算法控制
}
ENABLE_TIM(MODE_GATHE_TIM); // Enable MODE_GATHE_TIM
app_preload(); // 预加载
app_hart_init(); // HART初始化,mode中的模拟诊断需要用到HART变量
flow_init(); // 流程初始化
mode_diagnosis_init(); // 控制模块诊断初始化
power_on_diagnosis(); // 自检
bootload_init(bootload_transmit, bootload_end); // 在用户代码中接受更新文件需要初始化bootload
}
#if (HART_SOFTWARE_TEST_ENABLE == TRUE || HART_HARDWARE_TEST_ENABLE == TRUE)
ENABLE_TIM(HART_TIM);
// HART测试不允许有中断否则串口异常会丢失导致测试失败
DISABLE_TIM(MODE_TIM);
DISABLE_TIM(MODE_GATHE_TIM);
#endif
rt_data.flag.bits.app_init_over = TRUE;
reset_flag = DEVICE_IS_ON;
ENABLE_TIM(TASK_TIM); // Enable TASK_TIM
#else // bootload模式
// 在BOOTLOAD模式下需要关闭所有外设且不需要接受用户代码所以不需要初始化
board_dinit();
leds_off_all(); // 关闭所有LED
ENABLE_TIM(TASK_TIM); // Enable TASK_TIM
#endif
#if DEBUG_ENABLE == TRUE
#endif
}
/**
* @brief app反初始化
* @return {*}
* @note
*/
void app_dinit(void)
{
hart_uart_dinit();
hart_ble_dinit();
}
/**
* @brief 业务流程启动
* @return {*}
* @note
*/
void app_start(void)
{
flow_start();
}