BLE_TYQ_BJQ_CH32V303/bsp/src/bsp_hr.c

669 lines
22 KiB
C
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.

/*
* @Author : stark1898y 1658608470@qq.com
* @Date : 2024-09-04 17:33:57
* @LastEditors: mbw && 1600520629@qq.com
* @LastEditTime: 2024-11-30 16:32:01
* @FilePath: \ble_bjq_ch303rct6_ml307\bsp\src\bsp_hr.c
* @Description :
*
* Copyright (c) 2024 by yzy, All Rights Reserved.
*/
#include "bsp_hr.h"
#include "lwrb.h"
#include "bsp_flash.h"
#include "bsp_rtc.h"
#include "at_device_ml307.h"
#include "user_sys.h"
#include <string.h>
#define LOG_TAG "bsp_hr"
#define LOG_LVL LOG_LVL_DBG
#include <ulog.h>
ALIGN(RT_ALIGN_SIZE)
static char hr_thread_stack[HR_THREAD_STACK_SIZE];
static struct rt_thread hr_thread;
#define HR_RX_RB_LENGTH (64U)
#define HR_TX_RB_LENGTH (256U)
static lwrb_t hr_rx_rb;
static rt_uint8_t hr_rx_rb_data[HR_RX_RB_LENGTH];
static lwrb_t hr_tx_rb;
static rt_uint8_t hr_tx_rb_data[HR_TX_RB_LENGTH];
static rt_sem_t hr_rx_ok_sem;
static rt_sem_t hr_rx_parity_err_sem;
static rt_timer_t hr_timer;
uint8_t hr_rx_count = 0; // 接收缓冲区中,已经收到的数据包数量
void hr_timeout(void *parameter)
{
rt_sem_release(hr_rx_ok_sem);
rt_timer_stop(hr_timer);
}
void USARTx_SendByte(USART_TypeDef *pUSARTx, uint8_t data)
{
USART_SendData(pUSARTx, data);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
void USARTx_SendStr(USART_TypeDef *pUSARTx, char *str)
{
uint8_t i = 0;
do
{
USARTx_SendByte(pUSARTx, *(str + i));
i++;
} while (*(str + i) != '\0');
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);
}
// 串口发送数据
unsigned int BSP_Hr_Send_Data(const void *buf, unsigned int len)
{
unsigned int ret;
ret = lwrb_write(&hr_tx_rb, buf, len);
USART_ITConfig(HR_UART, USART_IT_TXE, ENABLE);
return ret;
}
/**
* @description: 从接收缓冲区中获取一帧有效数据
* @param {TsFrameData} *pFrameData 主机帧
* @param {uint8_t} *p_src 接收缓冲区
* @param {uint16_t} src_len 接收缓冲区长度
* @return {*}
*/
TsFrameData *HR_GetFrameData(const rt_uint8_t *p_src, const rt_uint8_t src_len)
{
rt_uint8_t data_field_len = 0;
rt_uint8_t check_sum = 0;
TsFrameData *get_buffer = RT_NULL;
for (rt_size_t i = 0; i < src_len; i++)
{
if (p_src[i] == FRAME_HEADER)
{
data_field_len = p_src[i + 3];
if (p_src[i + 3 + data_field_len + 2] == FRAME_TAIL)
{
check_sum = XOR_CheckSum(&p_src[i], (4 + data_field_len));
if (p_src[i + 3 + data_field_len + 1] == check_sum)
{
get_buffer = (TsFrameData *)rt_malloc(sizeof(TsFrameData) + sizeof(rt_uint8_t) * data_field_len);
if (get_buffer == RT_NULL)
{
LOG_E("get space fail\r\n");
return RT_NULL;
}
get_buffer->c1 = p_src[i + 1];
get_buffer->c2 = p_src[i + 2];
get_buffer->len = data_field_len;
if (data_field_len > 0)
{
rt_memmove(get_buffer->data, &p_src[i + 4], data_field_len);
}
LOG_D("HR_GetDataFrame Success!");
return get_buffer;
}
}
}
}
LOG_E("HR_GetDataFrame Fail!");
return get_buffer;
}
rt_uint8_t HR_GenerateRawFrame(TsRawFrameData *pRawData, rt_uint8_t c1, TeFrameC2 c2, const rt_uint8_t *p_src, rt_uint8_t src_len)
{
pRawData->len = src_len + 6;
rt_memset(pRawData->buf, 0, sizeof(pRawData->buf));
pRawData->buf[0] = FRAME_HEADER;
pRawData->buf[1] = c1;
pRawData->buf[2] = c2;
pRawData->buf[3] = src_len;
rt_memmove(&pRawData->buf[4], p_src, src_len);
// 从帧起始符开始到校验码之前所有字节的和的模256
// 即各字节不计超过255的溢出值的二进制算术和。
pRawData->buf[pRawData->len - 2] = XOR_CheckSum(&pRawData->buf[0], pRawData->len - 2);
pRawData->buf[pRawData->len - 1] = FRAME_TAIL;
// LOG_HEX("HrRawData", 16, &pRawData->buf[0], pRawData->len);
return RT_EOK;
}
rt_uint8_t HR_ProcessData(const TsFrameData *pHostFrameData)
{
TuFlashProductTimeLimitFrame ReadLimitTime = {0};
TsRawFrameData RawData;
rt_uint8_t data_field[64] = {0};
rt_uint8_t c1, c2, data_len = 0;
c1 = pHostFrameData->c1;
c2 = pHostFrameData->c2;
switch (c2)
{
case kNumOfRecords: // 查询各类记录的总数 AA 00 00 00 AA 55
{
LOG_D("kNumOfRecords");
c1 = 0;
data_len = sizeof(TsTotalRecords);
if (Flash_GetTotalRecord((TsTotalRecords *)&data_field[0]) != RESET)
{
goto send;
}
break;
}
case kAlarmRecord: // 查询第n条探测器报警记录AA 01 01 00 AC 55
{
LOG_D("kAlarmRecord(%d)", c1);
data_len = 7;
data_field[0] = c1;
if (Flash_GetRecord(kAlarmRecord, c1, (TsRecordsTime *)(&data_field[1])) != RESET)
{
if (data_field[0] == 0)
{
rt_memset(data_field, 0, data_len);
}
goto send;
}
break;
}
case kAlarmRcyRecord: // 查询第n条探测器报警恢复记录 AA 01 02 00 AD 55
{
LOG_D("kAlarmRcyRecord(%d)", c1);
data_len = 7;
data_field[0] = c1;
if (Flash_GetRecord(kAlarmRcyRecord, c1, (TsRecordsTime *)(&data_field[1])) != RESET)
{
goto send;
}
break;
}
case kFaultRecord: // 查询第n条探测器故障记录 AA 01 03 00 AE 55
{
LOG_D("kFaultRecord(%d)", c1);
data_len = 7;
data_field[0] = c1;
if (Flash_GetRecord(kFaultRecord, c1, (TsRecordsTime *)(&data_field[1])) != RESET)
{
goto send;
}
break;
}
case kFaultRcyRecord: // 查询第n条探测器故障恢复记录 AA 01 04 00 AF 55 AA 66 04 00 14 55
{
LOG_D("kFaultRcyRecord(%d)", c1);
data_len = 7;
data_field[0] = c1;
if (Flash_GetRecord(kFaultRcyRecord, c1, (TsRecordsTime *)(&data_field[1])) != RESET)
{
goto send;
}
break;
}
case kPowerFailureRecord: // 查询第n条探测器掉电记录 AA 01 05 00 B0 55
{
LOG_D("kPowerFailureRecord(%d)", c1);
data_len = 7;
data_field[0] = c1;
if (Flash_GetRecord(kPowerFailureRecord, c1, (TsRecordsTime *)(&data_field[1])) != RESET)
{
goto send;
}
break;
}
case kPowerOnRecord: // 查询第n条探测器上电记录 AA 01 06 00 B1 55
{
LOG_D("kPowerOnRecord(%d)", c1);
data_len = 7;
data_field[0] = c1;
if (Flash_GetRecord(kPowerOnRecord, c1, (TsRecordsTime *)(&data_field[1])) == READY)
{
goto send;
}
break;
}
case kSensorFailureRecord: // 查询气体传感器失效记录 AA 00 07 00 B1 55
{
LOG_D("kSensorFailureRecord(%d)", c1);
data_len = 7;
if (Flash_GetRecord(kSensorFailureRecord, 1, (TsRecordsTime *)&data_field[1]) != RESET)
{
if (c1 != 0) // 接收到的数据不对直接返回0
{
rt_memset(data_field, 0, data_len);
}
else
{
if (data_field[1] == 0) // 未失效
{
rt_memset(data_field, 0, data_len);
}
else // 失效
{
data_field[0] = 1;
}
}
goto send;
}
break;
}
case kGetCurrentTime: // AA 00 08 00 B2 55
{
LOG_D("kGetCurrentTime");
data_len = sizeof(TsRecordsTime);
RTC_GetTime();
data_field[0] = (uint8_t)((RtcDateTime.year >> 8) & (0XFF));
data_field[1] = (uint8_t)((RtcDateTime.year) & (0xFF));
data_field[2] = RtcDateTime.month;
data_field[3] = RtcDateTime.day;
data_field[4] = RtcDateTime.hour;
data_field[5] = RtcDateTime.minute;
goto send;
break;
}
/*扩展命令*/
case kGetCurrentTimeSecond: // AA 00 09 00 B3 55
{
LOG_D("kGetCurrentTimeSecond");
data_len = 7;
RTC_GetTime();
data_field[0] = (uint8_t)((RtcDateTime.year >> 8) & (0XFF));
data_field[1] = (uint8_t)((RtcDateTime.year) & (0xFF));
data_field[2] = RtcDateTime.month;
data_field[3] = RtcDateTime.day;
data_field[4] = RtcDateTime.hour;
data_field[5] = RtcDateTime.minute;
data_field[6] = RtcDateTime.second;
goto send;
break;
}
case kSetCurrentTime: /*2024-03-25 17:34:56 AA 00 0A 07 07 E8 03 19 11 22 38 31 55*/
{
LOG_D("kSetCurrentTime");
data_len = 7;
RtcDateTime.hour = pHostFrameData->data[4];
RtcDateTime.minute = pHostFrameData->data[5];
RtcDateTime.second = pHostFrameData->data[6];
RtcDateTime.day = pHostFrameData->data[3];
RtcDateTime.month = pHostFrameData->data[2];
RtcDateTime.year = (rt_uint16_t)(pHostFrameData->data[0] << 8 | pHostFrameData->data[1]);
RTC_SetTime(RtcDateTime.year, RtcDateTime.month, RtcDateTime.day,
RtcDateTime.hour, RtcDateTime.minute, RtcDateTime.second);
RTC_GetTime();
data_field[0] = (uint8_t)((RtcDateTime.year >> 8) & (0XFF));
data_field[1] = (uint8_t)((RtcDateTime.year) & (0xFF));
data_field[2] = RtcDateTime.month;
data_field[3] = RtcDateTime.day;
data_field[4] = RtcDateTime.hour;
data_field[5] = RtcDateTime.minute;
data_field[6] = RtcDateTime.second;
goto send;
break;
}
case kSetFactoryTime: /*2024-03-26 9:30:00 AA 00 0B 07 07 E8 03 1A 09 1E 00 EF 55*/
{
LOG_D("kSetFactoryTime\r\n");
data_len = 7;
Flash_SetProductTimeLimit((rt_uint16_t)(pHostFrameData->data[0] << 8 | pHostFrameData->data[1]), pHostFrameData->data[2],
pHostFrameData->data[3], pHostFrameData->data[4], pHostFrameData->data[5], pHostFrameData->data[6], kFactoryTimeId);
Flash_GetProductTimeLimit(&ReadLimitTime, kFactoryTimeId);
data_field[0] = (uint8_t)(ReadLimitTime.Struct.year >> 8);
data_field[1] = (uint8_t)(ReadLimitTime.Struct.year);
data_field[2] = ReadLimitTime.Struct.month;
data_field[3] = ReadLimitTime.Struct.day;
data_field[4] = ReadLimitTime.Struct.hour;
data_field[5] = ReadLimitTime.Struct.minute;
data_field[6] = ReadLimitTime.Struct.second;
goto send;
break;
}
case kSetExpirationTime: /*2028-3-26 9:30:00 AA 00 0C 07 07 EC 03 1A 09 1E 00 F4 55*/
{
LOG_D("kSetExpirationTime");
data_len = 7;
Flash_SetProductTimeLimit((uint16_t)(pHostFrameData->data[0] << 8 | pHostFrameData->data[1]), pHostFrameData->data[2], pHostFrameData->data[3], pHostFrameData->data[4], pHostFrameData->data[5], pHostFrameData->data[6], kExpirationTimeId);
Flash_GetProductTimeLimit(&ReadLimitTime, kExpirationTimeId);
data_field[0] = (uint8_t)(ReadLimitTime.Struct.year >> 8);
data_field[1] = (uint8_t)(ReadLimitTime.Struct.year);
data_field[2] = ReadLimitTime.Struct.month;
data_field[3] = ReadLimitTime.Struct.day;
data_field[4] = ReadLimitTime.Struct.hour;
data_field[5] = ReadLimitTime.Struct.minute;
data_field[6] = ReadLimitTime.Struct.second;
goto send;
break;
}
default:
break;
}
send:
{
if ((c1 == 0) && ((0 < c2) & (c2 < kSensorFailureRecord)))
{
rt_memset(data_field, 0, data_len);
}
HR_GenerateRawFrame(&RawData, c1, (TeFrameC2)c2, data_field, data_len);
BSP_Hr_Send_Data(&RawData.buf[0], RawData.len);
return 0;
}
return RT_EOK;
}
// int usr_sprintf(char *buf, const char *format, ...)
// {
// int n;
// va_list arg_ptr;
// if (rt_thread_self() != RT_NULL)
// rt_enter_critical();
// va_start(arg_ptr, format);
// n = vsprintf(buf, format, arg_ptr);
// va_end(arg_ptr);
// if (rt_thread_self() != RT_NULL)
// rt_exit_critical();
// return n;
// }
// 查找 [] 并判断字符串
int Process_Factor_Cmd(const char *rx_buff, size_t length)
{
TuFlashProductTimeLimitFrame ReadLimitTime;
char buf[512] = {0};
char imei[16] = {0};
char imsi[16] = {0};
char iccid[21] = {0};
// 工厂命令
const char factory_cmd1[] = "[getParameter]"; // 工厂命令1
// const char factory_cmd2[] = "[getCH4]"; // 工厂命令2
// 查找 []
const char *start_bracket = memchr(rx_buff, '[', length);
const char *end_bracket = memchr(start_bracket, ']', length - (start_bracket - rx_buff));
if (start_bracket && end_bracket)
{
// 计算 [] 之间的字符串长度
size_t cmd_length = end_bracket - start_bracket + 1;
char cmd[cmd_length + 1];
rt_strncpy(cmd, start_bracket, cmd_length);
cmd[cmd_length] = '\0';
if (rt_strcmp(cmd, factory_cmd1) == 0) // 比较接收到的字符串与 factory_cmd1
{
rt_uint8_t time_buf[8] = {0};
if ((*(rt_uint8_t *)FLASH_FACTOR_TIME_NUM_ADDR != 0xE3)&&(*(rt_uint8_t *)FLASH_FACTOR_TIME_NUM_ADDR != 0x39))
{
for (rt_uint8_t i = 0; i < 6; i++)
{
time_buf[i] = *(rt_uint8_t *)( FLASH_FACTOR_TIME_NUM_ADDR + i);
LOG_D("%02x", time_buf[i]);
}
rt_uint32_t cnt = (rt_uint32_t)((time_buf[2]<<16)| (time_buf[1] << 8)|time_buf[0]);
LOG_D("time_buf[2] = %02x time_buf[1] = %02x time_buf[0] = %02x cnt = %04d", time_buf[2], time_buf[1], time_buf[0], cnt);
Get_Iot_Imei(imei, FLASH_IOT_IMEI_LEN);
Get_Iot_Imsi(imsi, FLASH_IOT_IMSI_LEN);
Get_Iot_Iccid(iccid, FLASH_IOT_ICCID_LEN);
rt_sprintf(buf,
"\r\n[ID :YD4N02/%02d%02d%02d%04d]\r\n"
"[IMEI:%s]\r\n"
"[IMSI:%s]\r\n"
"[CCID:%s]\r\nOK\r\n",
time_buf[5], time_buf[4], time_buf[3], cnt, imei, imsi, iccid);
BSP_Hr_Send_Data(buf, rt_strlen(buf));
Flash_GetProductTimeLimit(&ReadLimitTime, kFactoryTimeId);
if ((ReadLimitTime.Struct.year != 2000 + time_buf[5])&&
(ReadLimitTime.Struct.month != time_buf[4])&&
(ReadLimitTime.Struct.day != time_buf[3]))//只写入一次
{
RTC_GetTime();
Flash_SetProductTimeLimit(2000 + time_buf[5], time_buf[4], time_buf[3], RtcDateTime.hour, RtcDateTime.minute, RtcDateTime.second, kFactoryTimeId);
Flash_SetProductTimeLimit(2000 + time_buf[5] + 8, time_buf[4], time_buf[3], RtcDateTime.hour, RtcDateTime.minute, RtcDateTime.second, kExpirationTimeId);
}
}
else
{
LOG_E("[%s] is not set\r\n", "factory time");
BSP_Hr_Send_Data("factory time is not set\r\n", rt_strlen("factory time is not set\r\n"));
}
return RT_EOK;
}
// else if (rt_strcmp(cmd, factory_cmd2) == 0) // 比较接收到的字符串与 factory_cmd2
// {
// rt_sprintf(buf,
// "\r\n[STATUS :0x%X]\r\n"
// "[VALUE :%.2f]\r\n"
// "[LIGHT :%.2f]\r\n"
// "[PD :%.2f]\r\n"
// "[TEMPERTURE :%.2f]\r\n"
// "[TEC-TEMPERTURE:%.2f]\r\n"
// "[WORKTIME :%d]\r\nOK\r\n",
// H308.Data.fault_code, H308.Data.lel, H308.Data.signal_strength, H308.Data.gain, H308.Data.temp, (H308.Data.laser_temp / 10), work_duration);
// LOG_D("buf:%s", buf);
// BSP_Hr_Send_Data(buf, rt_strlen(buf));
//
// return RT_EOK;
// }
}
return RT_ERROR;
}
static void hr_thread_entry(void *param)
{
LOG_D("hr_thread_entry");
uint8_t rx_buff[32] = {0};
// LOG_D("factor_time addr = %x", FLASH_FACTOR_TIME_NUM_ADDR);
while (1)
{
rt_sem_take(hr_rx_ok_sem, RT_WAITING_FOREVER);
if (rt_sem_trytake(hr_rx_parity_err_sem) == 0)
{
LOG_D("hr_rx_parity_err_sem");
lwrb_free(&hr_rx_rb);
continue;
}
uint8_t len = lwrb_get_full(&hr_rx_rb);
lwrb_read(&hr_rx_rb, rx_buff, len);
LOG_HEX("hr_rx_data:", 16, &rx_buff[0], len);
if (SysControl.status <= kPreheatingEvent)//等待预热完成和激光器自检
{
char buf[128] = "[CH4-Module power-on self-check,please wait]";
BSP_Hr_Send_Data(buf, rt_strlen(buf));
}
else
{
if (Process_Factor_Cmd(rx_buff, len) == RT_EOK)
{
LOG_D("工厂命令处理"); // 工厂命令处理
}
else
{
if (len >= HOST_FRAME_MIN_LEN)
{
TsFrameData *HostFrameData = HR_GetFrameData(rx_buff, len);
if (HostFrameData != RT_NULL)
{
LOG_HEX("HostFrameData", 16, &HostFrameData->data[0], HostFrameData->len); // 数据段
HR_ProcessData(HostFrameData);
}
rt_free(HostFrameData);
HostFrameData = RT_NULL;
}
}
}
rt_memset(rx_buff, 0, len);
rt_thread_mdelay(10);
}
}
void Hr_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
USART_InitTypeDef USART_InitStructure = {0};
NVIC_InitTypeDef NVIC_InitStructure = {0};
lwrb_init(&hr_rx_rb, hr_rx_rb_data, sizeof(hr_rx_rb_data));
lwrb_init(&hr_tx_rb, hr_tx_rb_data, sizeof(hr_tx_rb_data));
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
GPIO_InitStructure.GPIO_Pin = HR_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(HR_TX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = HR_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(HR_RX_GPIO_PORT, &GPIO_InitStructure);
USART_DeInit(HR_UART); // 寄存器恢复默认值
USART_InitStructure.USART_BaudRate = HR_BAUDRATE;
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_Even;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(HR_UART, &USART_InitStructure);
USART_ITConfig(HR_UART, USART_IT_RXNE, ENABLE);
USART_ITConfig(HR_UART, USART_IT_PE, ENABLE);
USART_ITConfig(HR_UART, USART_IT_TXE, DISABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(HR_UART, ENABLE);
LOG_I("hr Init");
}
int BSP_HR_Init(void)
{
Hr_Init();
hr_rx_ok_sem = rt_sem_create("hr_rx_ok_sem", 0, RT_IPC_FLAG_FIFO);
if (hr_rx_ok_sem == RT_NULL)
{
LOG_E("hr_rx_ok_sem create failed");
}
hr_rx_parity_err_sem = rt_sem_create("hr_rx_pe", 0, RT_IPC_FLAG_FIFO);
if (hr_rx_parity_err_sem == RT_NULL)
{
LOG_E("hr_rx_parity_err_sem create failed");
}
hr_timer = rt_timer_create("hr_timeout", hr_timeout, RT_NULL, 100, RT_TIMER_FLAG_PERIODIC);
if (hr_timer == RT_NULL)
{
LOG_E("hr_timer create failed");
}
rt_err_t ret = rt_thread_init(&hr_thread,
"hr_thread",
hr_thread_entry,
RT_NULL,
&hr_thread_stack[0],
sizeof(hr_thread_stack),
HR_THREAD_PRIORITY, HR_THREAD_TIMESLICE);
if (ret == RT_EOK)
{
rt_thread_startup(&hr_thread);
}
else
{
LOG_E("rt_thread_init hr_thread Failed");
return ret;
}
return ret;
}
// INIT_PREV_EXPORT(BSP_HR_Init);
void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USART2_IRQHandler(void)
{
GET_INT_SP();
rt_interrupt_enter();
unsigned char data;
if (USART_GetITStatus(HR_UART, USART_IT_PE) != RESET)
{
rt_sem_release(hr_rx_parity_err_sem);
}
if (USART_GetITStatus(HR_UART, USART_IT_RXNE) != RESET)
{
data = USART_ReceiveData(HR_UART);
lwrb_write(&hr_rx_rb, &data, 1);
rt_timer_start(hr_timer);
}
if (USART_GetITStatus(HR_UART, USART_IT_TXE) != RESET)
{
if (lwrb_read(&hr_tx_rb, &data, 1))
USART_SendData(HR_UART, data);
else
{
USART_ITConfig(HR_UART, USART_IT_TXE, DISABLE);
}
}
rt_interrupt_leave();
FREE_INT_SP();
}