958 lines
30 KiB
C
958 lines
30 KiB
C
/**
|
||
* @file app_hart.c
|
||
* @author xxx
|
||
* @date 2023-07-06 13:08:52
|
||
* @brief 此文件主要实现板卡的HART功能
|
||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||
*/
|
||
|
||
#include "app.h"
|
||
#include "hart.h"
|
||
#include "hart_frame.h"
|
||
#include "uarts.h"
|
||
#include "test_bsp.h"
|
||
#include "at_bluetooth.h"
|
||
#include "menus.h"
|
||
#include "bootload.h"
|
||
#include "ymodem.h"
|
||
#include "flow.h"
|
||
#include "app_hart.h"
|
||
#include <stdlib.h>
|
||
#include "app_hart_user.h"
|
||
|
||
#define HART_UART_RXSIZE (240u)
|
||
#define BLE_UART_RXSIZE (1100u) // 接收1100个字节,考虑到BOOTLOAD需要接收大量数据,在RAM允许的情况下,可以适当增大
|
||
#define HART_UART_TXSIZE (240u) // 发送240个字节
|
||
|
||
uart_t* uarts[APP_UART_MAX];
|
||
|
||
static void _get_real_time_clock(uint8_t* year, uint8_t* month, uint8_t* day, uint8_t* hour, uint8_t* min, uint8_t* sec);
|
||
static void update_device_status(void); // 更新其他设备状态
|
||
|
||
/**
|
||
* @brief 处理用户自定义事件
|
||
*
|
||
* @param event 用户自定义事件类型
|
||
* @param data 用户自定义事件数据
|
||
*
|
||
* @return 返回处理结果
|
||
*/
|
||
static BOOL _user_common_event(hart_interface_user_event_e event, const void* const data)
|
||
{
|
||
return hart_user_handle(event, data);
|
||
}
|
||
|
||
/**
|
||
* @brief 发送数据(hart协议数据帧)
|
||
* @param {uint8_t} *txBuf
|
||
* @param {uint16_t} len
|
||
* @return {*}
|
||
*/
|
||
static void _response(uint8_t uart_index, uint8_t* data, uint16_t len)
|
||
{
|
||
#ifdef STM32
|
||
rt_data.flag.bits.hart_rts_on = FALSE;
|
||
uart_send_data(uarts[uart_index], data, len);
|
||
uart_data_storage_reset(uarts[uart_index]);
|
||
#else
|
||
LOG_HEX(data, len);
|
||
#endif
|
||
}
|
||
|
||
/**
|
||
* @brief 获取指定UART的错误计数
|
||
*
|
||
* 根据UART索引获取指定UART的错误计数。
|
||
*
|
||
* @param uart_index UART索引
|
||
*
|
||
* @return 如果定义了STM32宏,则返回指定UART的错误计数;否则返回0
|
||
*/
|
||
static uint16_t _uart_error_count(uint8_t uart_index)
|
||
{
|
||
#ifdef STM32
|
||
return uart_get_error_count(uarts[uart_index]);
|
||
#else
|
||
return 0;
|
||
#endif
|
||
}
|
||
|
||
static void _uart_errors(uint8_t uart_index, hart_uart_error_t* errors)
|
||
{
|
||
uint16_t count = uart_get_error_count(uarts[uart_index]);
|
||
if (count > 0)
|
||
{
|
||
uarts_interupt_error_t* uart_errors = uart_get_error(uarts[uart_index]);
|
||
if (uart_errors != NULL)
|
||
{
|
||
for (uint16_t i = 0; i < count; i++)
|
||
{
|
||
errors[i].uart_error = (hart_uarts_interupt_error_e)uart_errors[i].err;
|
||
errors[i].rx_index = uart_errors[i].index;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static void _frame_data_parse_time_start(uint16_t timer_period)
|
||
{
|
||
hart_timer_start(timer_period);
|
||
}
|
||
|
||
/**
|
||
* @brief 获取时间戳
|
||
* @return {*}
|
||
*/
|
||
static uint32_t _get_timestamp(void)
|
||
{
|
||
uint8_t year, month, day, hour, min, sec;
|
||
uint32_t stamp;
|
||
rtc_date_t date;
|
||
rtc_time_t time;
|
||
_get_real_time_clock(&year, &month, &day, &hour, &min, &sec);
|
||
date.year = year;
|
||
date.month = month;
|
||
date.day = day;
|
||
time.hour = hour;
|
||
time.minute = min;
|
||
time.second = sec;
|
||
stamp = time2stamp(&date, &time);
|
||
return stamp;
|
||
}
|
||
|
||
/**
|
||
* @brief flash读取接口
|
||
* @param {uint32_t} addr
|
||
* @param {uint8_t} *data
|
||
* @param {uint16_t} len
|
||
* @return {*}
|
||
*/
|
||
static BOOL _flash_read(hart_storage_e index, uint8_t* data)
|
||
{
|
||
BOOL res = FALSE;
|
||
switch (index)
|
||
{
|
||
case HART_STORAGE_PARAMS:
|
||
res = storage_read_all(hart_attribute_storage, data);
|
||
break;
|
||
case HART_STORAGE_VARIABLE:
|
||
res = storage_read_all(hart_variable_storage, data);
|
||
break;
|
||
case HART_STORAGE_CONSTANT:
|
||
res = storage_read_all(hart_constant_storage, data);
|
||
break;
|
||
case HART_STORAGE_STANDARD_VARIABLE:
|
||
res = storage_read_all(hart_standard_variable_storage, data);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* @brief flash写入接口
|
||
* @param {uint32_t} addr
|
||
* @param {uint8_t} *data
|
||
* @param {uint16_t} len
|
||
* @return {*}
|
||
*/
|
||
static BOOL _flash_write(hart_storage_e index, uint8_t* data)
|
||
{
|
||
BOOL res = FALSE;
|
||
switch (index)
|
||
{
|
||
case HART_STORAGE_PARAMS:
|
||
res = storage_write_all(hart_attribute_storage, data);
|
||
if (storage_check_all(hart_attribute_storage, data) == FALSE)
|
||
{
|
||
rt_data.flag.bits.hart_attribute_storage = FALSE;
|
||
}
|
||
break;
|
||
case HART_STORAGE_VARIABLE:
|
||
res = storage_write_all(hart_variable_storage, data);
|
||
if (storage_check_all(hart_variable_storage, data) == FALSE)
|
||
{
|
||
rt_data.flag.bits.hart_variable_storage = FALSE;
|
||
}
|
||
break;
|
||
case HART_STORAGE_CONSTANT:
|
||
res = storage_write_all(hart_constant_storage, data);
|
||
if (storage_check_all(hart_constant_storage, data) == FALSE)
|
||
{
|
||
rt_data.flag.bits.hart_constant_storage = FALSE;
|
||
}
|
||
break;
|
||
case HART_STORAGE_STANDARD_VARIABLE:
|
||
res = storage_write_all(hart_standard_variable_storage, data);
|
||
if (storage_check_all(hart_standard_variable_storage, data) == FALSE)
|
||
{
|
||
rt_data.flag.bits.hart_standard_variable_storage = FALSE;
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
static BOOL _flash_read_item(hart_storage_e index, uint8_t item, uint8_t* data)
|
||
{
|
||
BOOL res = FALSE;
|
||
switch (index)
|
||
{
|
||
case HART_STORAGE_PARAMS:
|
||
res = storage_read(hart_attribute_storage, item, data);
|
||
break;
|
||
case HART_STORAGE_VARIABLE:
|
||
res = storage_read(hart_variable_storage, item, data);
|
||
break;
|
||
case HART_STORAGE_CONSTANT:
|
||
res = storage_read(hart_constant_storage, item, data);
|
||
break;
|
||
case HART_STORAGE_STANDARD_VARIABLE:
|
||
res = storage_read(hart_standard_variable_storage, item, data);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
static BOOL _flash_write_item(hart_storage_e index, uint8_t item, uint8_t* data)
|
||
{
|
||
BOOL res = FALSE;
|
||
switch (index)
|
||
{
|
||
case HART_STORAGE_PARAMS:
|
||
res = storage_write(hart_attribute_storage, item, data);
|
||
if (storage_check(hart_attribute_storage, item, data) == FALSE)
|
||
{
|
||
rt_data.flag.bits.hart_attribute_storage = FALSE;
|
||
}
|
||
break;
|
||
case HART_STORAGE_VARIABLE:
|
||
res = storage_write(hart_variable_storage, item, data);
|
||
if (storage_check(hart_variable_storage, item, data) == FALSE)
|
||
{
|
||
rt_data.flag.bits.hart_variable_storage = FALSE;
|
||
}
|
||
break;
|
||
case HART_STORAGE_CONSTANT:
|
||
res = storage_write(hart_constant_storage, item, data);
|
||
if (storage_check(hart_constant_storage, item, data) == FALSE)
|
||
{
|
||
rt_data.flag.bits.hart_constant_storage = FALSE;
|
||
}
|
||
break;
|
||
case HART_STORAGE_STANDARD_VARIABLE:
|
||
res = storage_write(hart_standard_variable_storage, item, data);
|
||
if (storage_check(hart_standard_variable_storage, item, data) == FALSE)
|
||
{
|
||
rt_data.flag.bits.hart_standard_variable_storage = FALSE;
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* @brief 执行自检
|
||
* @param {*}
|
||
* @return {*}
|
||
*/
|
||
static void _perform_self_test(void)
|
||
{
|
||
// power_on_diagnosis(); // 是否需要延时回复
|
||
menus_show_custom_window(SET_CUSTOM_SELF_TEST);
|
||
}
|
||
|
||
/**
|
||
* @brief 设备复位
|
||
* @param {*}
|
||
* @return {*}
|
||
*/
|
||
static void _device_reset(void)
|
||
{
|
||
get_menus()->accelerate = TRUE;
|
||
menus_show_custom_window(SET_CUSTOM_RESET);
|
||
}
|
||
|
||
/**
|
||
* @brief 设备呼叫,0一直呼叫,1-255秒
|
||
* @param {*}
|
||
* @return {*}
|
||
*/
|
||
static void _squawk_control(BOOL open, uint8_t second)
|
||
{
|
||
}
|
||
|
||
/**
|
||
* @brief 技术人员按下一个特殊的按钮或按钮组合,指示从机应响应command74
|
||
* @param {*}
|
||
* @return {*}
|
||
*/
|
||
static BOOL _armed(void)
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
static void _set_real_time_clock(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec)
|
||
{
|
||
set_real_time(year, month, day, hour, min, sec);
|
||
}
|
||
|
||
static void _get_real_time_clock(uint8_t* year, uint8_t* month, uint8_t* day, uint8_t* hour, uint8_t* min, uint8_t* sec)
|
||
{
|
||
get_real_time(year, month, day, hour, min, sec);
|
||
}
|
||
|
||
/**
|
||
* @brief 设置动态变量
|
||
* @return {*}
|
||
*/
|
||
static BOOL _set_dynamics(device_variable_dynamics_t* const dynamics)
|
||
{
|
||
// HART自带部分
|
||
|
||
// 下面是用户自定义部分
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/**
|
||
* @brief 蓝牙输出
|
||
* @param {uint8_t} *data
|
||
* @param {uint16_t} len
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
void bluetooth_output(uint8_t* data, uint16_t len)
|
||
{
|
||
DBG_ASSERT(data != NULL __DBG_LINE);
|
||
if (len == 0)
|
||
{
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
if (uarts[APP_UART_2] != NULL && BLE_IS_ENABLE() == TRUE)
|
||
{
|
||
uart_send_data(uarts[APP_UART_2], data, len);
|
||
}
|
||
}
|
||
}
|
||
|
||
void h24_bluetooth_output_dbg(uint8_t* data, uint16_t len)
|
||
{
|
||
DBG_ASSERT(data != NULL __DBG_LINE);
|
||
if (len == 0)
|
||
{
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
#if DEBUG_ENABLE == TRUE
|
||
if (rt_data.flag.bits.ble_on == TRUE)
|
||
{
|
||
bluetooth_output(data, len);
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
void hart_write_test(void)
|
||
{
|
||
#define TEST_LEN 10
|
||
uint8_t buf[TEST_LEN];
|
||
osel_memset(buf, 0, ARRAY_LEN(buf));
|
||
buf[0] = 0xFF;
|
||
buf[1] = 0xFF;
|
||
buf[2] = 0xFF;
|
||
buf[3] = 0xFF;
|
||
buf[4] = 0xFF;
|
||
buf[5] = 0xaa;
|
||
buf[6] = 0xbb;
|
||
buf[7] = 0xD5;
|
||
buf[8] = 0xC8;
|
||
buf[TEST_LEN - 1] = 0xce;
|
||
_response(APP_UART_1, buf, TEST_LEN);
|
||
}
|
||
|
||
/**
|
||
* @brief 蓝牙H24模块配置工作
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
void bluetooth_work(uint8_t index)
|
||
{
|
||
system_clock_config_low();
|
||
|
||
uint8_t len = 0;
|
||
char data[128];
|
||
osel_memset((uint8_t*)data, 0, 128);
|
||
// HC42蓝牙模块设置名称总长度不超过 12 字节 MX02蓝牙模块设置名称总长度不超过 20 字节
|
||
#if BOOTLOAD
|
||
char device_id[] = "BOOTLOAD";
|
||
#else
|
||
char device_id[HART_PACKED20_LEN];
|
||
char str[HART_LONG_ADDRESS_LEN * 2 + 1];
|
||
osel_memset((uint8_t*)device_id, 0, ARRAY_LEN(device_id));
|
||
osel_memset((uint8_t*)str, 0, ARRAY_LEN(str));
|
||
hart_long_address_to_string(str, hart_device_attribute.flash_variable.long_address, HART_LONG_ADDRESS_LEN);
|
||
sprintf(device_id, "%s-%s", DESCRIPTOR, str);
|
||
__NOP();
|
||
#endif
|
||
|
||
#if BLE_TYPE == BLE_TYPE_HC42
|
||
char* test_cmd[AT_END] =
|
||
{
|
||
"AT",
|
||
"AT+NAME",
|
||
"AT+NAME=%s",
|
||
"AT+RESET",
|
||
};
|
||
#elif BLE_TYPE == BLE_TYPE_MX02
|
||
char* test_cmd[AT_END] =
|
||
{
|
||
"AT+VER?\r\n",
|
||
"AT+NAME?\r\n",
|
||
"AT+NAME=%s\r\n",
|
||
"AT+TXPOWER=0\r\n",
|
||
"AT+MAC?\r\n",
|
||
};
|
||
#else
|
||
// 编译时输出错误提示
|
||
#error "BLE_TYPE 类型错误"
|
||
#endif
|
||
switch (index)
|
||
{
|
||
case AT_CMD_TEST: // 测试指令
|
||
{
|
||
bluetooth_state = 0;
|
||
sprintf(data, test_cmd[AT_CMD_TEST]);
|
||
len = osel_mstrlen((unsigned char*)data);
|
||
bluetooth_output((uint8_t*)data, len);
|
||
break;
|
||
}
|
||
|
||
case AT_CMD_NAME_REQ: // 获取设备名称
|
||
{
|
||
sprintf(data, "%s", device_id);
|
||
at_set_memcmp_cache((unsigned char*)data, osel_mstrlen((unsigned char*)data));
|
||
osel_memset((uint8_t*)data, 0, 128);
|
||
|
||
sprintf(data, test_cmd[AT_CMD_NAME_REQ]);
|
||
len = osel_mstrlen((unsigned char*)data);
|
||
bluetooth_output((uint8_t*)data, len);
|
||
break;
|
||
}
|
||
|
||
case AT_CMD_NAME: // 设置设备名称
|
||
{
|
||
sprintf(data, "%s", device_id);
|
||
at_set_memcmp_cache((unsigned char*)data, osel_mstrlen((unsigned char*)data));
|
||
osel_memset((uint8_t*)data, 0, 128);
|
||
|
||
sprintf(data, test_cmd[AT_CMD_NAME], device_id);
|
||
len = osel_mstrlen((unsigned char*)data);
|
||
bluetooth_output((uint8_t*)data, len);
|
||
break;
|
||
}
|
||
case AT_CMD_TX_POWER: // 设置发射功率
|
||
{
|
||
sprintf(data, test_cmd[AT_GET_MAC]);
|
||
len = osel_mstrlen((unsigned char*)data);
|
||
bluetooth_output((uint8_t*)data, len);
|
||
break;
|
||
}
|
||
case AT_GET_MAC:
|
||
{
|
||
sprintf(data, test_cmd[AT_CMD_TX_POWER]);
|
||
len = osel_mstrlen((unsigned char*)data);
|
||
bluetooth_output((uint8_t*)data, len);
|
||
break;
|
||
}
|
||
case 100:
|
||
{
|
||
sprintf(data, "%f,%f,%f\r\n", 1.1, 2.2, 3.3);
|
||
len = osel_mstrlen((unsigned char*)data);
|
||
bluetooth_output((uint8_t*)data, len);
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 串口1、5接收中断回调函数
|
||
static void hart_rx1_cb(uint8_t uart_index, uint8_t* data, uint16_t len)
|
||
{
|
||
DBG_ASSERT(uart_index < APP_UART_MAX __DBG_LINE);
|
||
|
||
#ifndef BOOTLOAD
|
||
HART_RTS_OFF(); // RTS需要提前
|
||
uart1_set_idel_status(FALSE);
|
||
if (hart_handle(uart_index, data, len) == FALSE)
|
||
{
|
||
HART_RTS_ON();
|
||
}
|
||
#else
|
||
rym_receive(uart_index, data, len);
|
||
#endif
|
||
}
|
||
|
||
static void hart_rx5_cb(uint8_t uart_index, uint8_t* data, uint16_t len)
|
||
{
|
||
DBG_ASSERT(uart_index < APP_UART_MAX __DBG_LINE);
|
||
|
||
if (data[0] == 'O' && data[1] == 'K') // HC42蓝牙协议
|
||
{
|
||
data[0] = 'A';
|
||
data[1] = 'T';
|
||
at_cmd_parse(data, len);
|
||
}
|
||
else if (data[0] == '+' && data[len - 1] == '\n' && data[len - 2] == '\r') // MX02蓝牙协议
|
||
{
|
||
uint8_t mx02_data[32];
|
||
mx02_data[0] = 'A';
|
||
mx02_data[1] = 'T';
|
||
osel_memcpy(&mx02_data[2], data, len);
|
||
at_cmd_parse((unsigned char*)mx02_data, len + 2);
|
||
}
|
||
else if (data[0] == 'B' && data[1] == 'T') // 收到BOOTLOAD启动命令
|
||
{
|
||
if (osel_memcmp(data, "BT RUN", 6) == 0)
|
||
{
|
||
if (get_app_preload_bootload_flag() == BOOTLOAD_UNSET_FLAG) // 如果已经在BOOTLOAD模式下,不再重复启动
|
||
{
|
||
set_app_preload_bootload_flag(BOOTLOAD_SET_FLAG); // 设置BOOTLOAD标志
|
||
bootload_transmit_from(uart_index); // 从指定位置开始发送数据
|
||
}
|
||
}
|
||
else if (osel_memcmp(data, "BT STOP", 7) == 0)
|
||
{
|
||
set_app_preload_bootload_flag(BOOTLOAD_UNSET_FLAG); // 设置BOOTLOAD标志
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 注:在BOOTLOAD模式下,不接收HART数据
|
||
#ifndef BOOTLOAD
|
||
uart1_set_idel_status(FALSE);
|
||
if (hart_handle(uart_index, data, len) == FALSE)
|
||
{
|
||
__NOP();
|
||
}
|
||
#else
|
||
rym_receive(uart_index, data, len);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
static void hart_tx_complete_cb(void)
|
||
{
|
||
// 串口1发送完成回调函数
|
||
HART_RTS_ON();
|
||
rt_data.flag.bits.hart_rts_on = TRUE;
|
||
}
|
||
|
||
// HART协议的使用的串口 --- 串口1
|
||
void hart_uart_init(void)
|
||
{
|
||
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
|
||
GPIO_SET_OUTPUT(HART_PWR_GPIO_Port, HART_PWR_Pin);
|
||
GPIO_SET_OUTPUT(HART_RST_GPIO_Port, HART_RST_Pin);
|
||
GPIO_SET_OUTPUT(HART_RTS_GPIO_Port, HART_RTS_Pin);
|
||
GPIO_SET_ALTERNATE(HART_TX_GPIO_Port, HART_TX_Pin);
|
||
GPIO_SET_ALTERNATE(HART_RX_GPIO_Port, HART_RX_Pin);
|
||
LL_mDelay(10);
|
||
// 串口1初始化开始
|
||
HART_RTS_ON();
|
||
HART_RST_OFF();
|
||
LL_mDelay(20);
|
||
HART_RST_ON();
|
||
HART_EN_DISABLE();
|
||
HART_EN_ENABLE();
|
||
HART_RTS_ON();
|
||
if (uarts[APP_UART_1] == NULL)
|
||
{
|
||
LL_mDelay(100);
|
||
|
||
uarts[APP_UART_1] = uart_create(HART_UART1, FALSE, HART_UART_RXSIZE, hart_rx1_cb, FALSE, HART_UART_TXSIZE, hart_tx_complete_cb);
|
||
uarts[APP_UART_1]->rx_cd_en = TRUE;
|
||
uarts[APP_UART_1]->uart_index = APP_UART_1;
|
||
uarts[APP_UART_1]->dma = DMA2;
|
||
uarts[APP_UART_1]->dma_rx_channel = LL_DMA_CHANNEL_7;
|
||
uarts[APP_UART_1]->dma_tx_channel = LL_DMA_CHANNEL_6;
|
||
uart_recv_en(uarts[APP_UART_1], TRUE);
|
||
rt_data.flag.bits.hart_rts_on = TRUE;
|
||
}
|
||
// 串口1初始化结束
|
||
uart1_set_idel_status(TRUE);
|
||
uart_data_storage_reset(uarts[APP_UART_1]);
|
||
rt_data.flag.bits.hart_on = TRUE;
|
||
}
|
||
|
||
// HART协议使用的串口,为模拟IO口
|
||
void hart_uart_dinit(void)
|
||
{
|
||
rt_data.flag.bits.hart_on = FALSE;
|
||
HART_EN_DISABLE();
|
||
LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_USART1);
|
||
LL_USART_Disable(USART1);
|
||
GPIO_SET_ANALOG(HART_PWR_GPIO_Port, HART_PWR_Pin);
|
||
GPIO_SET_ANALOG(HART_RST_GPIO_Port, HART_RST_Pin);
|
||
// GPIO_SET_ANALOG(HART_CD_GPIO_Port, HART_CD_Pin); // CD作为外部输入中断,不需要设置为模拟IO口
|
||
GPIO_SET_ANALOG(HART_TX_GPIO_Port, HART_TX_Pin);
|
||
GPIO_SET_ANALOG(HART_RX_GPIO_Port, HART_RX_Pin);
|
||
}
|
||
|
||
// 蓝牙模块串口初始化
|
||
void hart_ble_init(void)
|
||
{
|
||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_UART5);
|
||
GPIO_SET_OUTPUT(BLE_PWR_GPIO_Port, BLE_PWR_Pin);
|
||
GPIO_SET_INPUT(BLE_RST_GPIO_Port, BLE_RST_Pin);
|
||
GPIO_SET_ALTERNATE(BLE_TX_GPIO_Port, BLE_TX_Pin);
|
||
GPIO_SET_ALTERNATE(BLE_RX_GPIO_Port, BLE_RX_Pin);
|
||
|
||
if (uarts[APP_UART_2] == NULL)
|
||
{
|
||
uarts[APP_UART_2] = uart_create(HART_UART2, TRUE, BLE_UART_RXSIZE, hart_rx5_cb, TRUE, HART_UART_TXSIZE, NULL);
|
||
uarts[APP_UART_2]->uart_index = APP_UART_2;
|
||
uarts[APP_UART_2]->dma = DMA2;
|
||
uarts[APP_UART_2]->dma_rx_channel = LL_DMA_CHANNEL_2;
|
||
uarts[APP_UART_2]->dma_tx_channel = LL_DMA_CHANNEL_1;
|
||
uart_recv_en(uarts[APP_UART_2], FALSE);
|
||
}
|
||
BLE_EN_ENABLE();
|
||
}
|
||
|
||
// 蓝牙模块端口IO口反初始化
|
||
void hart_ble_dinit(void)
|
||
{
|
||
// 关闭蓝牙串口
|
||
BLE_EN_DISABLE();
|
||
LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_UART5);
|
||
LL_USART_Disable(UART5);
|
||
// 端口转成模拟IO口
|
||
GPIO_SET_ANALOG(BLE_PWR_GPIO_Port, BLE_PWR_Pin);
|
||
GPIO_SET_ANALOG(BLE_RST_GPIO_Port, BLE_RST_Pin);
|
||
GPIO_SET_ANALOG(BLE_TX_GPIO_Port, BLE_TX_Pin);
|
||
GPIO_SET_ANALOG(BLE_RX_GPIO_Port, BLE_RX_Pin);
|
||
}
|
||
|
||
static void hart_params_init(void)
|
||
{
|
||
hart_storage_variable_t* p = &hart_device_attribute.flash_variable;
|
||
// 记录消息
|
||
if (dbg_assert_line != 0)
|
||
{
|
||
uint32_t stmp = _get_timestamp();
|
||
uint8_t message[HART_PACKED32_LEN];
|
||
osel_memset(message, 0, HART_PACKED32_LEN);
|
||
uint16_t line = dbg_assert_line;
|
||
sprintf((char*)message, "RESET[%d]:%d", line, stmp);
|
||
osel_memcpy(p->message, message, HART_PACKED32_LEN); // 消息
|
||
hart_storage_write_item(HART_STORAGE_PARAMS, HPB_MESSAGE,
|
||
hart_device_attribute.flash_variable.message);
|
||
hart_device_status_set_operational_state(DEVICE_OPERATIONAL_STATE_7);
|
||
dbg_assert_line = 0;
|
||
}
|
||
|
||
hart_attribute_params_map_address_update(); // 参数变量地址映射
|
||
}
|
||
|
||
// HART初始化
|
||
BOOL app_hart_init(void)
|
||
{
|
||
hart_init_t init;
|
||
init.hart_protocol_version = HART_VERSION; // 协议版本
|
||
init.dir = MODULE_SLAVE; // 协议模式--从
|
||
init.private_command = HART_SOFTWARE_TEST_ENABLE == FALSE ? TRUE : FALSE; // 是否支持大命令
|
||
init.interface.response = _response;
|
||
init.interface.uart_error_count = _uart_error_count;
|
||
init.interface.uart_errors = _uart_errors;
|
||
init.interface.frame_data_parse_time_start = _frame_data_parse_time_start;
|
||
init.interface.get_timestamp = _get_timestamp;
|
||
init.interface.flash_read = _flash_read;
|
||
init.interface.flash_write = _flash_write;
|
||
init.interface.flash_read_item = _flash_read_item;
|
||
init.interface.flash_write_item = _flash_write_item;
|
||
init.interface.perform_self_test = _perform_self_test;
|
||
init.interface.device_reset = _device_reset;
|
||
init.interface.squawk_control = _squawk_control;
|
||
init.interface.armed = _armed;
|
||
init.interface.set_dynamics = _set_dynamics;
|
||
init.interface.set_real_time_clock = _set_real_time_clock;
|
||
init.interface.get_real_time_clock = _get_real_time_clock;
|
||
init.interface.user_common_event = _user_common_event;
|
||
init.interface.attribute_init = hart_attribute_params_restart;
|
||
init.interface.variable_init = hart_attribute_params_map_restart;
|
||
init.hart_timer.timer_cycle = TIM_CYCLE(HART_TIM); // 定时器周期
|
||
hart_device_attribute.last_device_variable = (uint8_t*)&rt_save.last_dev_variable;
|
||
|
||
uarts[APP_UART_1] = NULL;
|
||
uarts[APP_UART_2] = NULL;
|
||
hart_init(&init);
|
||
hart_params_init();
|
||
|
||
ENABLE_TIM(HART_OUT_TIM);
|
||
PWM_START(HART_OUT_TIM, LL_TIM_CHANNEL_CH2);
|
||
set_tim_hart_out(SystemCoreClock);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/**
|
||
* @brief HART检测任务
|
||
* @return {*}
|
||
* @note 对于实时要求不高的参数,可以在这里更新
|
||
*/
|
||
void app_hart_inspection(void)
|
||
{
|
||
hart_device_attribute.internal++;
|
||
hart_cache_detection(); // HART缓存区探测,如果缓存区过期则回收
|
||
rt_data.hart_run_time_h = rt_save.dev_run_time_h / 18; // 1:18,运行时间 详见参数读取-129 RUN_TIME_18HR
|
||
// 扩展设备类型
|
||
if (hart_device_attribute.flash_variable.extended_device_type != udevice.dev_model)
|
||
{
|
||
hart_device_attribute.flash_variable.extended_device_type = udevice.dev_model;
|
||
hart_long_addr_set();
|
||
hart_storage_write_item(HART_STORAGE_PARAMS, HPB_EXTENDED_DEVICE_TYPE,
|
||
(uint8_t*)&hart_device_attribute.flash_variable.extended_device_type);
|
||
hart_storage_write_item(HART_STORAGE_PARAMS, HPB_LONG_ADDRESS,
|
||
hart_device_attribute.flash_variable.long_address);
|
||
}
|
||
|
||
if (hart_device_attribute.internal % HART_INTERNAL == 0) // 需要延时判断的
|
||
{
|
||
if (hart_device_attribute.device_status.reset == TRUE)
|
||
{
|
||
LL_mDelay(200);
|
||
sys_soft_reset();
|
||
}
|
||
else if (hart_device_attribute.device_status.busy == TRUE)
|
||
{
|
||
perform_self_test_finish();
|
||
menus_rebuild();
|
||
}
|
||
}
|
||
|
||
update_device_status(); // 扩展现场设备状态 48号指令
|
||
spec_table_data_mapping(TRUE); // udevice中数据映射到规格表
|
||
|
||
// 同步params和hart变量数据
|
||
if (hart_device_attribute.internal % HART_INTERNAL == 0)
|
||
{
|
||
params_hart_variable_sync();
|
||
}
|
||
|
||
// 每60次进入,执行一次检查ram和存储中数据是否一致
|
||
if (hart_device_attribute.internal % (HART_INTERNAL * 20) == 0)
|
||
{
|
||
params_hart_storage_check();
|
||
}
|
||
}
|
||
|
||
// 更新HART软件时间,和RTC同步
|
||
void app_hart_update_time(void)
|
||
{
|
||
BOOL change = FALSE;
|
||
uint8_t y, h, m, s;
|
||
real_time_clock_t* p = &hart_device_attribute.real_time_clock;
|
||
uint8_t* date = hart_device_attribute.flash_variable.date;
|
||
y = rt_save.real_time.date.year;
|
||
covert_rtc_year(&y);
|
||
|
||
if (date[2] != y || date[1] != rt_save.real_time.date.month || date[0] != rt_save.real_time.date.day)
|
||
{
|
||
change = TRUE;
|
||
}
|
||
|
||
date[2] = y;
|
||
date[1] = rt_save.real_time.date.month;
|
||
date[0] = rt_save.real_time.date.day;
|
||
|
||
p->date[0] = hart_device_attribute.flash_variable.date[0];
|
||
p->date[1] = hart_device_attribute.flash_variable.date[1];
|
||
p->date[2] = hart_device_attribute.flash_variable.date[2];
|
||
|
||
h = rt_save.real_time.date.hour;
|
||
m = rt_save.real_time.date.minute;
|
||
s = rt_save.real_time.date.second;
|
||
convert_timestrap(&p->time, h, m, s, 0);
|
||
p->rtc_flags = REAL_TIME_CLOCK_FLAGS_1;
|
||
|
||
if (change == TRUE)
|
||
{
|
||
hart_storage_write_item(HART_STORAGE_PARAMS, HPB_DATE,
|
||
hart_device_attribute.flash_variable.date);
|
||
}
|
||
}
|
||
|
||
// 判断下一篇存储数据是否已经写过数据
|
||
BOOL app_hart_storage_is_written(uint32_t address, uint16_t length)
|
||
{
|
||
uint8_t* data;
|
||
uint16_t count = 0;
|
||
ErrorStatus rst = ERROR;
|
||
BOOL res = FALSE;
|
||
count = length / LL_FLASH_PAGE_SIZE;
|
||
data = osel_mem_alloc(LL_FLASH_PAGE_SIZE);
|
||
DBG_ASSERT(data != NULL __DBG_LINE);
|
||
for (uint16_t i = 0; i < count; i++)
|
||
{
|
||
rst = LL_FLASH_Read(address + i * LL_FLASH_PAGE_SIZE, data, LL_FLASH_PAGE_SIZE);
|
||
if (rst == SUCCESS)
|
||
{
|
||
for (uint16_t j = 0; j < LL_FLASH_PAGE_SIZE; j++)
|
||
{
|
||
if (data[j] != 0xff)
|
||
{
|
||
res = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
res = TRUE;
|
||
}
|
||
|
||
if (res == TRUE)
|
||
{
|
||
break;
|
||
}
|
||
res = FALSE;
|
||
}
|
||
osel_mem_free(data);
|
||
return res;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取更多状态标志
|
||
* @param {uint8_t} *rev_buf
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void hart_get_device_specific_status(uint8_t* rev_buf)
|
||
{
|
||
hart_device_specific_status_u st;
|
||
osel_memset((uint8_t*)&st, 0, HART_PACKED6_LEN);
|
||
st.bits.u1.travel_sensor_failure = get_diagnosis_alarm(DIAGNOSIS_TRAVEL_SENSOR);
|
||
st.bits.u1.pressure_sensor_failure = get_diagnosis_alarm(DIAGNOSIS_PRESS_SENSOR);
|
||
st.bits.u1.temperature_sensor_failure = get_diagnosis_alarm(DIAGNOSIS_TEMPERATURE_SENSOR);
|
||
st.bits.u1.critical_nvm_failure = get_diagnosis_alarm(DIAGNOSIS_CRITICAL_NVM);
|
||
st.bits.u1.drive_current_failure = get_diagnosis_alarm(DIAGNOSIS_IP_DRIVER);
|
||
st.bits.u1.reference_voltage_failure = get_diagnosis_alarm(DIAGNOSIS_VREF);
|
||
st.bits.u1.mlfb_sensor_alarm = get_diagnosis_alarm(DIAGNOSIS_MICRO_LOOP);
|
||
st.bits.u1.flash_integrity_failure = get_diagnosis_alarm(DIAGNOSIS_FLASH_INTEGRITY);
|
||
st.bits.u2.auto_cal_in_progress_alert = get_diagnosis_alarm(INDICATE_AUTO_CALIBRATION);
|
||
st.bits.u2.nvm_protective_mode = get_diagnosis_alarm(INDICATE_NVM_PROTECT_MODE);
|
||
st.bits.u2.pressure_fallback_active_alert = get_diagnosis_alarm(INDICATE_PRESS_ACTIVE);
|
||
st.bits.u2.diagnostics_in_progress_alert = get_diagnosis_alarm(INDICATE_TEST_PROGRESS);
|
||
st.bits.u2.calibration_in_progress_alert = get_diagnosis_alarm(INDICATE_CALIBRATION);
|
||
st.bits.u2.alert_record_not_empty_alert = get_diagnosis_alarm(INDICATE_ALERT_RECORD_NOT_EMPTY);
|
||
st.bits.u3.alert_record_full_alert = get_diagnosis_alarm(INDICATE_ALERT_RECORD_FULL);
|
||
st.bits.u3.cycle_counter_high_alert = get_diagnosis_alarm(DIAGNOSIS_ACT_SUM);
|
||
st.bits.u3.instrument_time_is_approximate_alert = get_diagnosis_alarm(DIAGNOSIS_DEV_REALTIME);
|
||
st.bits.u3.non_critical_nvm_alert = get_diagnosis_alarm(DIAGNOSIS_NON_CRITICAL_NVM);
|
||
st.bits.u3.offline_failed_alert = get_diagnosis_alarm(INDICATE_OFFLINE);
|
||
st.bits.u3.travel_accumulator_high_alert = get_diagnosis_alarm(DIAGNOSIS_TRAVEL_SUM);
|
||
st.bits.u4.diagnostic_data_available_alert = get_diagnosis_alarm(INDICATE_DIAG_DATA_AVAILABLE);
|
||
st.bits.u4.end_point_pressure_deviation_alert = get_diagnosis_alarm(DIAGNOSIS_PRESS_ERROR);
|
||
st.bits.u4.integrator_saturated_high_alert = get_diagnosis_alarm(DIAGNOSIS_UI_SATURATED_HIGH);
|
||
st.bits.u4.integrator_saturated_low_alert = get_diagnosis_alarm(DIAGNOSIS_UI_SATURATED_LOW);
|
||
st.bits.u4.supply_pressure_high_alert = get_diagnosis_alarm(DIAGNOSIS_SUPPLY_UPPER);
|
||
st.bits.u4.supply_pressure_low_alert = get_diagnosis_alarm(DIAGNOSIS_SUPPLY_LOWER);
|
||
st.bits.u5.drive_signal_alert = get_diagnosis_alarm(DIAGNOSIS_DRIVE_SIGNAL);
|
||
st.bits.u5.travel_alert_hi = get_diagnosis_alarm(DIAGNOSIS_TRAVEL_HI);
|
||
st.bits.u5.travel_alert_hi_hi = get_diagnosis_alarm(DIAGNOSIS_TRAVEL_HI_HI);
|
||
st.bits.u5.travel_alert_lo = get_diagnosis_alarm(DIAGNOSIS_TRAVEL_LO);
|
||
st.bits.u5.travel_alert_lo_lo = get_diagnosis_alarm(DIAGNOSIS_TRAVEL_LO_LO);
|
||
st.bits.u5.travel_deviation_alert = get_diagnosis_alarm(DIAGNOSIS_TRAVEL_ERROR);
|
||
st.bits.u5.travel_limit_cutoff_hi_alert = get_diagnosis_alarm(DIAGNOSIS_LIMIT_CUTOFF_HI);
|
||
st.bits.u5.travel_limit_cutoff_lo_alert = get_diagnosis_alarm(DIAGNOSIS_LIMIT_CUTOFF_LO);
|
||
st.bits.u6.output_circuit_error = get_diagnosis_alarm(DIAGNOSIS_OUTPUT_CIRCUIT_ERROR);
|
||
st.bits.u6.output_pressure_limiting = get_diagnosis_alarm(DIAGNOSIS_OUTPUT_PRESS_LIMIT);
|
||
osel_memcpy(rev_buf, (uint8_t*)&st, HART_PACKED6_LEN);
|
||
}
|
||
|
||
/**
|
||
* @brief 更新设备状态
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void update_device_status(void)
|
||
{
|
||
additional_device_status_t* p = &hart_device_attribute.device_status.additional_device_status;
|
||
// 设备特定状态 - 48号指令
|
||
{
|
||
hart_get_device_specific_status(p->device_specific_status);
|
||
osel_memcpy(diagnosis_get()->device_specific_status.data, p->device_specific_status, HART_PACKED6_LEN);
|
||
}
|
||
// 扩展设备状态
|
||
{
|
||
diag_class_e status = get_diagnosis_fault_priority();
|
||
switch (status)
|
||
{
|
||
case DIAGNOSIS_CLASS_FAIL:
|
||
p->extended_device_status = EXTENDED_DEVICE_STATUS_4; // 设备故障
|
||
break;
|
||
case DIAGNOSIS_CLASS_SPEC:
|
||
p->extended_device_status = EXTENDED_DEVICE_STATUS_5; // 超出规格
|
||
break;
|
||
case DIAGNOSIS_CLASS_CHECK:
|
||
p->extended_device_status = EXTENDED_DEVICE_STATUS_6; // 功能检查
|
||
break;
|
||
case DIAGNOSIS_CLASS_MAINT:
|
||
p->extended_device_status = EXTENDED_DEVICE_STATUS_1; // 需要维护
|
||
break;
|
||
default:
|
||
p->extended_device_status = EXTENDED_DEVICE_STATUS_0; // 正常
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 标准化状态0
|
||
{
|
||
p->standardized_status0 = STANDARDIZED_STATUS0_0;
|
||
// 非易失性存储器缺陷
|
||
BOOL eeprom_status = FALSE;
|
||
eeprom_status = eeprom_m95_status_get(M95_1);
|
||
|
||
if (eeprom_status == TRUE)
|
||
{
|
||
eeprom_status = eeprom_m95_status_get(M95_2);
|
||
if (eeprom_status == TRUE)
|
||
{
|
||
eeprom_status = eeprom_fm24_status_get();
|
||
if (eeprom_status == TRUE)
|
||
{
|
||
eeprom_status = eeprom_lc02b_status_get();
|
||
}
|
||
}
|
||
}
|
||
if (eeprom_status == FALSE)
|
||
{
|
||
p->standardized_status0 = STANDARDIZED_STATUS0_2; // 非易失性存储器缺陷
|
||
}
|
||
|
||
// 电源条件超出范围
|
||
if (rt_data.loop_current < LOOP_CURRENT_MIN || rt_data.loop_current > LOOP_CURRENT_MAX)
|
||
{
|
||
p->standardized_status0 = STANDARDIZED_STATUS0_5; // 电源条件超出范围
|
||
}
|
||
|
||
if (hart_device_attribute.flash_variable.write_protect_code == WRITE_PROTECT_CODE_WRITE_PROTECT ||
|
||
hart_device_attribute.flash_variable.lock_code != LOCK_DEVICE_CODE_0)
|
||
{
|
||
p->standardized_status0 = STANDARDIZED_STATUS0_8; // 设备配置已锁定。设备处于写保护状态或已锁定
|
||
}
|
||
}
|
||
}
|