由于有项目需要使用串口进行固件升级,采用的协议为Ymode,这个协议很多串口软件都支持,如果使用单缓存的话,在处理串口数据时又同时接收到串口数据可能会导致整个缓存出现混乱,导致数据丢失,所以在数据传输的过程中采用乒乓缓存机制,用于加速同时存在串口操作及数据处理操作的设备。其核心思想是使用两个缓存区交替进行数据的读写操作,从而提高设备的吞吐量和处理速度。
//串口支持的协议枚举,自己定义
enum PROTOCOL_TYPE
{
COMMAND = 0,
COMMAND_BURST,
UPLOAD_SOH,
UPLOAD_STX,
UPLOAD_EOT,
UPLOAD_ACK,
UPLOAD_NAK,
UPLOAD_CAN,
UPLOAD_CNC,
UPLOAD_CRT,
UNKNOW_TYPE=0xff,
};
#define BUFFER_LEN (1030)
#define COMMAND_LEN (32)
#define YMODE_SOH_LEN (128+5)
#define YMODE_STX_LEN (1024+5)
#define COMMAND_HEAD (0xaa)
#define COMMAND_BURST_HEAD (0x55)
#define SOH (0x01) /* start of 128-byte data packet */
#define STX (0x02) /* start of 1024-byte data packet */
#define EOT (0x04) /* end of transmission */
#define EOT_CRT (0x20) /* CRT end of transmission */
#define ACK (0x06) /* receive OK */
#define NAK (0x15) /* receiver error; retry */
#define CAN (0x18) /* two of these in succession aborts transfer */
#define CNC (0x43) /* character 'C' */
struct buffer_t
{
int cnt;
char buf_uart[BUFFER_LEN];
char type;
char flag;
};
struct buffer_pq_t
{
struct buffer_t buf1;
struct buffer_t buf2;
char position; //正在存储的buf
};
struct protocol_info_t
{
char head;
char type;
short head_len;
};
//串口协议查找表
struct protocol_info_t protocol[]=
{
{ COMMAND_HEAD , COMMAND , COMMAND_LEN},
{ COMMAND_BURST_HEAD , COMMAND_BURST , 1024},
{ SOH , UPLOAD_SOH , YMODE_SOH_LEN},
{ STX , UPLOAD_STX , YMODE_STX_LEN},
{ EOT , UPLOAD_EOT , 1},
{ ACK , UPLOAD_ACK , 1},
{ NAK , UPLOAD_NAK , 1},
{ CAN , UPLOAD_CAN , 1},
{ CNC , UPLOAD_CNC , 1},
// { 0x20 ,UPLOAD_CRT , 128},
};
struct buffer_pq_t uart_recvbuf={.buf1.type = UNKNOW_TYPE,.buf2.type = UNKNOW_TYPE,0};
//存储数据到缓存中
int put_buf(struct buffer_pq_t* pq , char data, int len)
{
int i =0;
int flag = 0;
int test = 0;
if(pq->position == 0 ) //第一个缓存
{
if(len + pq->buf1.cnt > BUFFER_LEN)
{
//print_str("put_buf1 err len\r\n");
return -1;
}
flag = 0;
if(pq->buf1.cnt == 0) //从协议表中查找对应协议的数据长度,用于后续的组帧操作
{
for(i=0;i < ( sizeof(protocol)/sizeof(protocol[0]) );i++)
{
if(data == protocol[i].head)
{
pq->buf1.type = protocol[i].type;
flag = 1;
break;
}
}
if(flag == 0 )
{
//print_str(" unknow1 protocol\r\n");
return -1;
}
}
if(pq->buf1.type == UNKNOW_TYPE)
{
uart_buf_unref(&pq->buf1);
return -1;
}
pq->buf1.buf_uart[pq->buf1.cnt] = data; //存储数据
pq->buf1.cnt+=1;
if(pq->buf1.type == protocol[pq->buf1.type].type)
{
//当组帧完成后,切换存储buffer
if(pq->buf1.cnt >= protocol[pq->buf1.type].head_len)
{
pq->position = 1;
pq->buf1.flag = 1;
}
}
}
else //第二个缓存
{
if(len + pq->buf2.cnt > BUFFER_LEN)
{
//print_str("put_buf2 err len\r\n");
return -1;
}
flag = 0;
if(pq->buf2.cnt == 0)
{
for(i=0;i < ( sizeof(protocol)/sizeof(protocol[0]) );i++)
{
if(data == protocol[i].head)
{
pq->buf2.type = protocol[i].type;
flag = 1;
break;
}
}
if(flag == 0)
{
//print_str(" unknow2 protocol\r\n");
return -1;
}
}
if(pq->buf2.type == UNKNOW_TYPE)
{
uart_buf_unref(&pq->buf2);
return -1;
}
pq->buf2.buf_uart[pq->buf2.cnt] = data;
pq->buf2.cnt+=1;
if(pq->buf2.type == protocol[pq->buf2.type].type)
{
if(pq->buf2.cnt >= protocol[pq->buf2.type].head_len)
{
pq->position = 0;
pq->buf2.flag = 1;
}
}
}
return 0;
}
// 从乒乓buffer中获取数据
struct buffer_t* get_uart_buf(void)
{
if(uart_recvbuf.position == 0)
{
if(uart_recvbuf.buf2.flag == 0)
return NULL;
else
return &uart_recvbuf.buf2;
}
else
{
if(uart_recvbuf.buf1.flag == 0)
return NULL;
else
return &uart_recvbuf.buf1;
}
}
//数据使用完后释放
int uart_buf_unref(struct buffer_t* buf_p)
{
if(buf_p != NULL)
{
buf_p->cnt = 0;
buf_p->flag = 0;
buf_p->type = UNKNOW_TYPE;
}
return 0;
}
//整个缓存结构状态清零
void uart_buf_reset()
{
uart_recvbuf.buf1.cnt = 0;
uart_recvbuf.buf1.flag = 0;
uart_recvbuf.buf1.type = UNKNOW_TYPE;
uart_recvbuf.buf2.cnt = 0;
uart_recvbuf.buf2.flag = 0;
uart_recvbuf.buf2.type = UNKNOW_TYPE;
uart_recvbuf.position = 0;
}
//使用方法
int main()
{
struct buffer_t* buf_recv;
buf_recv = get_uart_buf();
if(buf_recv != NULL)
{
//将接受的数据回写回去
for(int i =0;i<buf_recv->cnt;i++)
uart_write(SYSTEM_UART_A_APB, buf_recv->buf_uart[i]);
#if 0
if(buf_recv->type == COMMAND)
{
start = 1;
uart_buf_unref(buf_recv);
continue;
}
ymodem_rx_put(buf_recv->buf_uart,buf_recv->cnt);
#endif
uart_buf_unref(buf_recv); //释放缓存数据
}
else
{
//接收超时处理
}
}