676 lines
18 KiB
C
676 lines
18 KiB
C
/**
|
||
* @file app_flow.c
|
||
* @author xxx
|
||
* @date 2023-08-30 08:58:43
|
||
* @brief 此文件用于管理各个任务流程
|
||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||
*/
|
||
|
||
#include <math.h>
|
||
#include "app.h"
|
||
#include "main.h"
|
||
#include "flow.h"
|
||
#include "tim.h"
|
||
#include "filter.h"
|
||
#include "lcds.h"
|
||
#include "menus.h"
|
||
#include "mode.h"
|
||
#include "mode_diagnosis.h"
|
||
#include "at_bluetooth.h"
|
||
#include "bootload.h"
|
||
#include "app_hart.h"
|
||
// bootloader
|
||
static struct flow bootload_system_fw; // BOOTLOAD系统流程
|
||
|
||
uint16_t scheduler_use_time = 0;
|
||
|
||
/**
|
||
* @brief 100毫秒定时中断处理函数
|
||
*
|
||
* 当定时器到达100毫秒时,会触发此中断处理函数。
|
||
* 在该函数中,启动或重置定时器计数。
|
||
* @param cycle 定时器周期 毫秒
|
||
*/
|
||
void scheduler_time_1s_irqhandler(uint8_t cycle)
|
||
{
|
||
DBG_ASSERT(cycle > 0 __DBG_LINE);
|
||
static uint32_t cnt = 0;
|
||
uint32_t time_ms = ++cnt * cycle;
|
||
|
||
// 考虑是否要控制器工作的时候才计时
|
||
if (rt_save.dev_run_time_h < WORK_HOURS_MAX)
|
||
{
|
||
if (time_ms % 1000 == 0)
|
||
{
|
||
rt_save.dev_run_time_s++; // 工作时长
|
||
}
|
||
if (rt_save.dev_run_time_s >= 3600)
|
||
{
|
||
rt_save.dev_run_time_h++;
|
||
rt_save.dev_run_time_s = 0;
|
||
}
|
||
}
|
||
|
||
// 控制过程中快速闪灯
|
||
if (mode_get()->interface_req.mode_control_idle() == FALSE)
|
||
{
|
||
if (time_ms % 200 == 0)
|
||
{
|
||
diagnosis_fault_indicate((diag_class_e)get_diagnosis_result()->priority);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (time_ms % 1000 == 0)
|
||
{
|
||
diagnosis_fault_indicate((diag_class_e)get_diagnosis_result()->priority);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief bootload系统检测
|
||
* @param {struct flow *} fl
|
||
* @return {*}
|
||
*/
|
||
static uint8_t bootload_systom_inspection(struct flow *fl)
|
||
{
|
||
FL_HEAD(fl);
|
||
for (;;)
|
||
{
|
||
if (TRUE == BLE_IS_ENABLE())
|
||
{
|
||
leds_off(LEDS_RED);
|
||
leds_toggle(LEDS_GREEN);
|
||
}
|
||
else
|
||
{
|
||
leds_off(LEDS_GREEN);
|
||
leds_toggle(LEDS_RED);
|
||
}
|
||
FL_LOCK_DELAY(fl, FL_CLOCK_SEC);
|
||
}
|
||
FL_TAIL(fl);
|
||
}
|
||
|
||
#if HART_SOFTWARE_TEST_ENABLE == FALSE
|
||
static struct flow sensor_fw; // 传感器检测
|
||
static struct flow business_fw; // 业务流程
|
||
static struct flow system_fw; // 系统检测
|
||
static struct flow idle_fw; // 空闲任务
|
||
|
||
// 时间戳更新
|
||
static void timestamp_update(uint8_t cycle)
|
||
{
|
||
BOOL ret = FALSE;
|
||
rtc_date_t date;
|
||
rtc_time_t time;
|
||
uint32_t timestamp = 0;
|
||
static uint8_t count = 0;
|
||
if (count++ >= cycle)
|
||
{
|
||
count = 0;
|
||
ret = rtc_get_datetime(&date, &time);
|
||
if (ret == TRUE)
|
||
{
|
||
timestamp = time2stamp(&date, &time);
|
||
if (timestamp > rt_data.seconds)
|
||
{
|
||
rt_save.real_time.date.year = date.year;
|
||
rt_save.real_time.date.month = date.month;
|
||
rt_save.real_time.date.day = date.day;
|
||
rt_save.real_time.date.hour = time.hour;
|
||
rt_save.real_time.date.minute = time.minute;
|
||
rt_save.real_time.date.second = time.second;
|
||
rt_data.seconds = timestamp;
|
||
}
|
||
// 如果rtc_get_datetime失败,则不需要额外操作,但可以在调试时记录
|
||
// else
|
||
// {
|
||
// // 记录错误或进行其他处理
|
||
// }
|
||
}
|
||
}
|
||
}
|
||
|
||
// 实时数据部分更新
|
||
static void rt_data_update(void)
|
||
{
|
||
rt_data.board_current = get_board_current();
|
||
rt_data.cpu_percent = scheduler_time_occupancy_get(1000);
|
||
rt_data.cpu_temperature = get_cpu_temperature();
|
||
rt_data.cpu_volt = get_cpu_volt();
|
||
rt_data.mem_percent = my_mem_perused(SRAMIN);
|
||
rt_data.dc = CPU_VREF * adc_raw[ADC_DCDC_CHANNEL] * 4 / ADC_MAX;
|
||
rt_data.vdd = CPU_VREF * adc_raw[ADC_VDD_CHANNEL] * 4 / ADC_MAX;
|
||
timestamp_update(3); // 这个周期数量根据外面的任务时间来定
|
||
}
|
||
|
||
/**
|
||
* @brief 菜单检测
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
void menu_inspection(void)
|
||
{
|
||
if (lcd->info.need_build == TRUE)
|
||
{
|
||
lcd->info.need_build = FALSE; // need_build 在menu_build中被置位
|
||
menus_rebuild();
|
||
}
|
||
menu_task();
|
||
}
|
||
|
||
/**
|
||
* @brief 图标检测
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void icon_inspection(void)
|
||
{
|
||
if (FALSE == HART_IS_ENABLE())
|
||
{
|
||
driver_icon_enable.bits.hart = 0; // 禁用HART
|
||
}
|
||
else
|
||
{
|
||
driver_icon_enable.bits.hart = 1; // 使能HART
|
||
}
|
||
|
||
if (FALSE == BLE_IS_ENABLE()) // 检查蓝牙是否已启用
|
||
{
|
||
driver_icon_enable.bits.bluetooth = 0; // 禁用蓝牙
|
||
}
|
||
else
|
||
{
|
||
driver_icon_enable.bits.bluetooth = 1; // 使能蓝牙
|
||
}
|
||
|
||
driver_icon_enable.bits.work_mode = (uint8_t)udevice.control_mode; // 工作模式
|
||
|
||
// TODO 设备是否锁定检查
|
||
}
|
||
|
||
static void bootload_start_inspection(void)
|
||
{
|
||
}
|
||
|
||
// LCD 、LED检测
|
||
static void lcd_detection(float32 loop_current, float32 temperature)
|
||
{
|
||
BOOL lcd_close = FALSE, led_close = FALSE;
|
||
// LCD扩展板必须接入
|
||
if (is_lcd_ext_board() == FALSE)
|
||
{
|
||
lcd_close = TRUE;
|
||
rt_data.flag.bits.lcd_detect = FALSE;
|
||
// GPS2000的LED在板子上,简单处理LED不要反初始化了
|
||
// led_close = TRUE;
|
||
}
|
||
else
|
||
{
|
||
rt_data.flag.bits.lcd_detect = TRUE;
|
||
}
|
||
|
||
if (gui_can_work() == FALSE)
|
||
{
|
||
lcd_close = TRUE;
|
||
}
|
||
|
||
if (*mode_get()->ctrl.mode == STOP_MODE)
|
||
{
|
||
lcd_close = TRUE;
|
||
}
|
||
|
||
/**
|
||
* 检查温度是否在LCD的有效工作范围内。
|
||
* 如果温度低于最小值或高于最大值,则关闭LCD。
|
||
*
|
||
* @param rt_data 包含温度值的实时数据结构。
|
||
*/
|
||
if (temperature < temperature_c2unit(LCD_WORK_TEMP_MIN, udevice.temp_unit) || temperature > temperature_c2unit(LCD_WORK_TEMP_MAX, udevice.temp_unit))
|
||
{
|
||
lcd_close = TRUE;
|
||
}
|
||
|
||
// 如果工作模式为停止模式,则关闭LCD
|
||
if (*mode_get()->ctrl.mode == STOP_MODE)
|
||
{
|
||
lcd_close = TRUE;
|
||
}
|
||
|
||
if (lcd_close == TRUE)
|
||
{
|
||
gui_clr(); // 清除LCD
|
||
lcd_dinit();
|
||
get_menus()->run_enable = FALSE;
|
||
}
|
||
else
|
||
{
|
||
lcd_init(); // 初始化LCD
|
||
if (rt_data.flag.bits.lcd_detect == TRUE) // 检查LCD是否已关闭,如果是,则打开LCD
|
||
{
|
||
if (get_menus()->run_enable == FALSE)
|
||
{
|
||
#if LCD_DESIGN == FALSE
|
||
menus_jump(MENUS_WORK, FALSE); // 跳转到工作界面
|
||
#endif
|
||
}
|
||
get_menus()->run_enable = TRUE;
|
||
}
|
||
else
|
||
{
|
||
get_menus()->run_enable = FALSE;
|
||
}
|
||
|
||
gui_set_scandir(udevice.display_direction); // 更新扫描方向
|
||
menus_set_scandir(udevice.display_direction); // 设置菜单显示方向
|
||
gui_open(); // 打开LCD
|
||
}
|
||
|
||
if (led_close == TRUE)
|
||
{
|
||
leds_dinit();
|
||
}
|
||
else
|
||
{
|
||
leds_init(); // 初始化LED
|
||
}
|
||
}
|
||
|
||
static void ble_detection(float32 loop_current, float32 temperature)
|
||
{
|
||
float32 ble_close = FALSE;
|
||
// 判断当前电流是否大于等于3.8mA,如果是,则启动UART
|
||
if (loop_current >= INPUT_CURRENT_MIN_UART)
|
||
{
|
||
driver_init(); // 初始化驱动
|
||
if (FALSE == HART_IS_ENABLE()) // 检查HART是否已启用,如果否,则初始化HART UART
|
||
{
|
||
hart_uart_init();
|
||
}
|
||
else
|
||
{
|
||
// #if DEBUG_ENABLE == TRUE
|
||
// static uint8_t hart_send_test_cnt = 0;
|
||
// if (hart_send_test_cnt++ <= 2)
|
||
// {
|
||
// hart_write_test();
|
||
// }
|
||
// #endif
|
||
}
|
||
}
|
||
// 否则,关闭UART
|
||
else
|
||
{
|
||
driver_dinit(); // 关闭驱动
|
||
hart_uart_dinit(); // 关闭HART UART
|
||
}
|
||
|
||
if (temperature < BLE_WORK_TEMP_MIN || temperature > BLE_WORK_TEMP_MAX)
|
||
{
|
||
ble_close = TRUE;
|
||
}
|
||
|
||
// 蓝牙
|
||
// 判断当前电流是否大于等于xx mA且工作模式在离线模式下,如果是,则启动蓝牙
|
||
if (udevice.wireless_enable == TRUE)
|
||
{
|
||
if ((loop_current >= BLE_CURRENT_WORK && udevice.control_mode == DIGITAL_CTRL_MODE) ||
|
||
(loop_current >= BLE_CURRENT_WORK && DEBUG_ENABLE == TRUE))
|
||
{
|
||
if (FALSE == BLE_IS_ENABLE()) // 检查蓝牙是否已启用,如果否,则初始化蓝牙
|
||
{
|
||
hart_ble_init();
|
||
delay_ms(500);
|
||
}
|
||
else
|
||
{
|
||
// 检查蓝牙是否正常工作
|
||
if (BIT_IS_CLR(bluetooth_state, BIT2))
|
||
{
|
||
delay_ms(500);
|
||
if (BIT_IS_CLR(bluetooth_state, BIT0))
|
||
{
|
||
bluetooth_work(AT_CMD_TEST);
|
||
delay_ms(500);
|
||
}
|
||
|
||
if (BIT_IS_SET(bluetooth_state, BIT0))
|
||
{
|
||
// 检查蓝牙名称
|
||
bluetooth_work(AT_CMD_NAME_REQ);
|
||
delay_ms(500);
|
||
if (BIT_IS_CLR(bluetooth_state, BIT1))
|
||
{
|
||
// 设置蓝牙名称
|
||
bluetooth_work(AT_CMD_NAME);
|
||
}
|
||
#if BLE_TYPE == BLE_TYPE_MX02
|
||
delay_ms(100);
|
||
bluetooth_work(AT_CMD_TX_POWER);
|
||
#endif
|
||
BIT_SET(bluetooth_state, BIT2);
|
||
}
|
||
else
|
||
{
|
||
BIT_SET(bluetooth_state, BIT2); // 如果蓝牙被主动连接的话,上面的AT指令不会有响应
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// bluetooth_work(100);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ble_close = TRUE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ble_close = TRUE;
|
||
}
|
||
|
||
if (ble_close == TRUE)
|
||
{
|
||
if (TRUE == BLE_IS_ENABLE())
|
||
{
|
||
hart_ble_dinit(); // 关闭蓝牙
|
||
}
|
||
bluetooth_state = BIT0;
|
||
}
|
||
}
|
||
|
||
/************************************************ 以下为应用线程 ************************************************/
|
||
|
||
static uint8_t sensor_detection(struct flow *fl)
|
||
{
|
||
FL_HEAD(fl);
|
||
static float32 current = 0.0f;
|
||
static float32 temperature = 0.0f, humidity = 0.0f;
|
||
for (;;)
|
||
{
|
||
scheduler_time_start();
|
||
// 计算当前电流,方法为读取ADC通道ADC_LOOP_CHANNEL的平均值并转换为浮点数
|
||
current = get_current_by_resistance();
|
||
// 获取当前温度
|
||
rt_data.temperature = get_temperature();
|
||
// 获取当前湿度
|
||
if (sht40_read(&temperature, &humidity) == TRUE)
|
||
{
|
||
rt_data.humidity = (uint16_t)humidity;
|
||
}
|
||
|
||
if (current < INPUT_CURRENT_RUN) // 待机状态是如果电流小于INPUT_CURRENT_MIN_MCU,则进行系统复位
|
||
{
|
||
sys_soft_reset();
|
||
}
|
||
else
|
||
{
|
||
if (current < SYSTEM_CLOCK_HIGHT_CURRENT_MIN)
|
||
{
|
||
rt_data.flag.bits.current_low = TRUE;
|
||
}
|
||
else
|
||
{
|
||
if (rt_data.flag.bits.current_low == TRUE)
|
||
{
|
||
#if LCD_DESIGN == FALSE
|
||
menus_jump(MENUS_WORK, FALSE); // 跳转到工作界面
|
||
#endif
|
||
}
|
||
rt_data.flag.bits.current_low = FALSE;
|
||
}
|
||
|
||
// 蓝牙
|
||
ble_detection(current, rt_data.temperature);
|
||
|
||
// LCD 、LED
|
||
lcd_detection(current, rt_data.temperature);
|
||
}
|
||
scheduler_use_time = scheduler_time_stop();
|
||
FL_LOCK_DELAY(fl, FL_CLOCK_SEC);
|
||
}
|
||
|
||
FL_TAIL(fl);
|
||
}
|
||
|
||
/**
|
||
* @brief 系统检测
|
||
* @param {struct flow *} fl
|
||
* @return {*}
|
||
*/
|
||
static uint8_t systom_inspection(struct flow *fl)
|
||
{
|
||
FL_HEAD(fl);
|
||
static BOOL run_first = TRUE;
|
||
for (;;)
|
||
{
|
||
scheduler_time_start();
|
||
// 图标检测
|
||
icon_inspection();
|
||
scheduler_use_time = scheduler_time_stop();
|
||
|
||
if (run_first == FALSE)
|
||
{
|
||
menus_set_language(udevice.display_language);
|
||
|
||
// 参数复位检测
|
||
params_restart_inspection();
|
||
|
||
set_app_preload_language_flag(udevice.display_language); // 缓存语言实时更新,用于重启是第一时间判断语言
|
||
|
||
// 在停机模式下,不进行诊断
|
||
if (*mode_get()->ctrl.mode != STOP_MODE)
|
||
{
|
||
// 过程报警 1s一次(时间可以改)
|
||
diagnosis_inspection(); // 第一次不做诊断,防止报错
|
||
|
||
// 故障处理
|
||
diagnosis_fault_deal();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
run_first = FALSE;
|
||
}
|
||
|
||
scheduler_use_time = scheduler_time_stop();
|
||
|
||
bootload_start_inspection();
|
||
|
||
FL_LOCK_DELAY(fl, FL_CLOCK_SEC);
|
||
}
|
||
FL_TAIL(fl);
|
||
}
|
||
|
||
/**
|
||
* @brief 业务流程
|
||
* @param {flow} *fl
|
||
* @return {*}
|
||
*/
|
||
static uint8_t business_inspection(struct flow *fl)
|
||
{
|
||
FL_HEAD(fl);
|
||
for (;;)
|
||
{
|
||
scheduler_time_start();
|
||
// 实时数据更新
|
||
rt_data_update();
|
||
|
||
// 工作模式检测
|
||
mode_master_detection();
|
||
|
||
// HART检测
|
||
app_hart_inspection();
|
||
|
||
// KEIL窗口强制跳转到自整定流程,需要在这里做判断
|
||
if (mode_get()->interface_req.mode_is_adjusting() == TRUE && is_selftune_menu() == FALSE)
|
||
{
|
||
// 跳转到自动整定界面
|
||
menus_jump(MENUS_SELFTUNE, TRUE);
|
||
}
|
||
|
||
uart1_set_idel_handle_1_sec(); // 设置UART1空闲处理函数
|
||
|
||
noinit_data_set(); // 设置未初始化的数据
|
||
|
||
scheduler_use_time = scheduler_time_stop();
|
||
FL_LOCK_DELAY(fl, FL_CLOCK_SEC);
|
||
}
|
||
FL_TAIL(fl);
|
||
}
|
||
|
||
/**
|
||
* @brief 空闲任务用来计算CPU占用率和内存使用率
|
||
* @param {flow} *fl
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static uint8_t idle_inspection(struct flow *fl)
|
||
{
|
||
FL_HEAD(fl);
|
||
for (;;)
|
||
{
|
||
scheduler_time_start();
|
||
scheduler_use_time = scheduler_time_stop();
|
||
FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
|
||
}
|
||
FL_TAIL(fl);
|
||
}
|
||
|
||
#endif
|
||
|
||
#if HART_SOFTWARE_TEST_ENABLE == TRUE
|
||
static struct flow hart_soft_test; // HART软件测试
|
||
static uint8_t hart_soft_test_inspection(struct flow *fl)
|
||
{
|
||
FL_HEAD(fl);
|
||
for (;;)
|
||
{
|
||
// 模拟传感器数据
|
||
rt_data.loop_current = 5;
|
||
rt_data.temperature = 20;
|
||
rt_data.pressure_a = 210;
|
||
rt_data.actual_travel = i2psb(rt_data.loop_current);
|
||
rt_data.driver_signal = 50;
|
||
rt_data.pressure_b = 210;
|
||
rt_save.travel_set_pt = i2psb(rt_data.loop_current);
|
||
rt_data.pressure_cross_point = 60;
|
||
rt_data.pressure_s = 210;
|
||
rt_data.target_travel = i2psb(rt_data.loop_current);
|
||
rt_data.servo_feedback = 50;
|
||
leds_toggle(LEDS_GREEN);
|
||
FL_LOCK_DELAY(fl, FL_CLOCK_SEC * 1);
|
||
}
|
||
FL_TAIL(fl);
|
||
}
|
||
|
||
#endif
|
||
|
||
#if HART_HARDWARE_TEST_ENABLE == TRUE
|
||
static struct flow hart_hardware_test; // HART硬件测试
|
||
static uint8_t hart_hardware_test_inspection(struct flow *fl)
|
||
{
|
||
FL_HEAD(fl);
|
||
static uint8_t data[64];
|
||
for (;;)
|
||
{
|
||
if (rt_data.flag.bits.hart_rts_on == TRUE)
|
||
{
|
||
if (rt_data.flag.bits.hart_send_test != 0)
|
||
{
|
||
if (rt_data.flag.bits.hart_send_test == 1)
|
||
{
|
||
osel_memset(data, 0x00, ARRAY_LEN(data));
|
||
}
|
||
else
|
||
{
|
||
osel_memset(data, 0xff, ARRAY_LEN(data));
|
||
}
|
||
HART_RTS_OFF();
|
||
hart_get_handle()->interface.response(APP_UART_1, data, ARRAY_LEN(data));
|
||
}
|
||
}
|
||
FL_LOCK_DELAY(fl, FL_CLOCK_10MSEC);
|
||
}
|
||
|
||
FL_TAIL(fl);
|
||
}
|
||
#endif
|
||
|
||
/**
|
||
* @brief: 流程启动
|
||
* @return {*}
|
||
*/
|
||
void flow_start(void)
|
||
{
|
||
#if HART_HARDWARE_TEST_ENABLE == TRUE
|
||
hart_hardware_test_inspection(&hart_hardware_test); // HART硬件测试流程
|
||
#elif HART_SOFTWARE_TEST_ENABLE == TRUE
|
||
hart_soft_test_inspection(&hart_soft_test); // HART软件测试流程
|
||
|
||
// 参数复位检测
|
||
params_restart_inspection();
|
||
if (get_current_by_resistance() >= FAL_WRITE_CURRENT)
|
||
{
|
||
fal_execution_process(); // fal执行
|
||
}
|
||
#else
|
||
sensor_detection(&sensor_fw);
|
||
systom_inspection(&system_fw); // 系统检测
|
||
business_inspection(&business_fw); // 业务流程检测
|
||
|
||
menus_process(); // 菜单处理
|
||
if (get_current_by_resistance() >= FAL_WRITE_CURRENT)
|
||
{
|
||
fal_execution_process(); // fal执行
|
||
}
|
||
|
||
idle_inspection(&idle_fw); // 空闲任务用来计算CPU占用率
|
||
#endif
|
||
}
|
||
|
||
/**
|
||
* @brief: bootload流程启动
|
||
* @return {*}
|
||
*/
|
||
void bootload_flow_start(void)
|
||
{
|
||
bootload_systom_inspection(&bootload_system_fw); // BOOTLOAD系统流程
|
||
if (BIT_IS_CLR(bluetooth_state, BIT2) == FALSE)
|
||
{
|
||
bootload_inspection(); // BOOTLOAD检测
|
||
if (bootload_timeout() == TRUE)
|
||
{
|
||
// 如果超时退出bootload模式
|
||
set_app_preload_bootload_flag(BOOTLOAD_UNSET_FLAG);
|
||
leds_off_all();
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化流程
|
||
* @return {*}
|
||
*/
|
||
void flow_init(void)
|
||
{
|
||
#if HART_HARDWARE_TEST_ENABLE == TRUE
|
||
hart_uart_init();
|
||
FL_INIT(&hart_hardware_test); // HART硬件测试流程
|
||
#elif HART_SOFTWARE_TEST_ENABLE == TRUE
|
||
hart_uart_init();
|
||
FL_INIT(&hart_soft_test);
|
||
#else
|
||
rt_data.flag.bits.current_low == TRUE;
|
||
FL_INIT(&sensor_fw); // 电流检测
|
||
FL_INIT(&system_fw); // 系统检测
|
||
FL_INIT(&business_fw); // 业务流程
|
||
FL_INIT(&idle_fw); // 空闲任务
|
||
FL_INIT(&bootload_system_fw); // bootload系统流程
|
||
#endif
|
||
}
|