/**
* @file usart2.c
* @author zhaoguangxin (zhaoguangxin@qq.com)
* @brief
* @version 0.1
* @date 2022-08-25
*
* @copyright Copyright (c) 2022
*
*/
#include <rtthread.h>
#include <string.h>
#include <serial.h>
/* 设备句柄 */
#define UART_NAME "uart2"
static rt_device_t serial;
/* 消息传递队列 */
#define USART2_QUE_NUM (10)
static struct rt_messagequeue rx_que;
typedef struct{
rt_uint32_t p_read; //开始读取地址
rt_uint32_t p_end; //读取的结束地址
}Rx_Index_t;
static rt_uint8_t msg_pool[sizeof(Rx_Index_t) * USART2_QUE_NUM];
/* FIFO */
#define USART2_RX_MAX (1024UL)
typedef struct{
rt_uint32_t wIndex;
rt_uint32_t rIndex;
rt_uint8_t overFlag;
rt_uint8_t *fifo;
}Rx_FIFO_t;
static Rx_FIFO_t usart2FIFO;
/* 分帧定时器 */
static struct rt_timer firTimer;
static rt_uint8_t timerStatus = 0; //0未启动 1:启动
/**
* @name: firTimer_timeout
* @func: 分帧定时器回调函数
* @input:
* parameter:参数
* @output: none
* @return: none
*/
static void firTimer_timeout(void* parameter)
{
Rx_Index_t rIndex;
rIndex.p_read = usart2FIFO.rIndex;
rIndex.p_end = (usart2FIFO.wIndex == 0) ? (USART2_RX_MAX - 1) : (usart2FIFO.wIndex - 1);
usart2FIFO.rIndex = usart2FIFO.wIndex;
if( rt_mq_send( &rx_que, &rIndex, sizeof(rIndex) ) == -RT_EFULL )
rt_kprintf("message queue full!\n");
}
/**
* @name: uart_input
* @func: 串口2接收回调函数
* @input:
* dev:设备
* size:接收的数据量
* @output: none
* @return: none
*/
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
while( 1 ){
if( rt_device_read(serial, -1, &usart2FIFO.fifo[usart2FIFO.wIndex], 1) == 1 ){
usart2FIFO.wIndex += 1;
if( usart2FIFO.wIndex >= USART2_RX_MAX )
usart2FIFO.wIndex = 0;
if( usart2FIFO.wIndex == usart2FIFO.rIndex )
usart2FIFO.overFlag = 1;
}else{
break;
}
}
if( timerStatus == 0 )
rt_timer_start(&firTimer);
else{
int arg = 10;
rt_timer_control(&firTimer, RT_TIMER_CTRL_SET_TIME, &arg);
}
return RT_EOK;
}
/**
* @name: USART2_GetData
* @func: 串口2获取数据
* @input:
* timeout:超时
* @output:
* getBuff:输出获取的数据 需要外部释放
* len:获取的数据长度
* @return:
* 0:成功 其他失败
*/
int USART2_GetData(rt_uint8_t **getBuff, rt_uint32_t *len, rt_uint32_t timeout)
{
rt_uint32_t tempLen = 0;
Rx_Index_t recIndex;
rt_uint8_t *p = RT_NULL;
if( getBuff == RT_NULL || len == RT_NULL){
return -1;
}
memset(&recIndex, 0, sizeof(recIndex));
if(rt_mq_recv(&rx_que, &recIndex, sizeof(recIndex), timeout) != RT_EOK){ //读取串口队列消息,没有数据就阻塞等待
return -1;
}
if( usart2FIFO.overFlag != 0 ){
usart2FIFO.overFlag = 0;
}
if( recIndex.p_end >= recIndex.p_read ){
*len = recIndex.p_end - recIndex.p_read + 1;
p = rt_malloc(*len + 1);
if( p != RT_NULL ){
memset(p, 0, *len + 1);
memcpy(p, &usart2FIFO.fifo[recIndex.p_read], *len);
}
}else{
tempLen = USART2_RX_MAX - recIndex.p_read;
*len = tempLen + recIndex.p_end +1;
p = rt_malloc(*len + 1);
if( p != RT_NULL ){
memset(p, 0, *len + 1);
memcpy(p, &usart2FIFO.fifo[recIndex.p_read], tempLen);
memcpy(p + tempLen, usart2FIFO.fifo,recIndex.p_end + 1);
}
}
*getBuff = p;
return 0;
}
/**
* @name: serial_thread_entry
* @func: 串口2线程
* @input:
* parameter:线程参数
* @output: none
* @return:
* 初始化结果
*/
static void serial_thread_entry(void *parameter)
{
rt_uint8_t *buf;
rt_uint32_t len;
while(1){
if( 0 == USART2_GetData(&buf, &len, (rt_uint32_t)RT_WAITING_FOREVER)){
rt_device_write(serial, 0, buf, len);
rt_free(buf);
}
}
}
/**
* @name: uart2_init
* @func: 串口2初始化
* @input:
* bound:波特率
* @output: none
* @return:
* 初始化结果
*/
int uart2_init(int bound)
{
serial = rt_device_find(UART_NAME);
if( !serial ){
rt_kprintf("find %s failed!\n", UART_NAME);
return RT_ERROR;
}
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
struct serial_configure serialConfig = RT_SERIAL_CONFIG_DEFAULT;
serialConfig.baud_rate = bound;
rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &serialConfig);
rt_device_set_rx_indicate(serial, uart_input);
rt_mq_init(&rx_que, "rx_que", //队列名称
msg_pool, //存放队列的数据
sizeof(Rx_Index_t), //队列元素的大小
sizeof(msg_pool), //队列缓存的大小
RT_IPC_FLAG_FIFO); //有多个线程等待时,先到先得
rt_timer_init(&firTimer, "firTimer", //定时器名字是 firTimer
firTimer_timeout, //超时时回调的处理函数
RT_NULL, //超时函数的入口参数
10, //定时长度为 30 个 OS Tick
RT_TIMER_FLAG_ONE_SHOT); //单次定时器
usart2FIFO.fifo = rt_malloc(USART2_RX_MAX);
if( usart2FIFO.fifo == RT_NULL )
return RT_ERROR;
#if 1
rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
if( thread != RT_NULL ){
rt_thread_startup(thread);
}else{
return RT_ERROR;
}
#endif
return RT_EOK;
}