需要3个FIFO
TX
rt_ringbuffer_init(&sendRingBuffer, sendBuffer, sizeof(sendBuffer));---发送数据出去TCP
RX
rt_ringbuffer_init(&rxRingBuffer, rxBuffer, sizeof(rxBuffer));--串口收到数据
rt_ringbuffer_init(&messageRingBuffer, messageBuffer, sizeof(messageBuffer));--对上面的数据分析提炼以后拿到协议数据在分析的FIFO
其实FIFO已经很好理解 就是FREERTOS的消息队列 !!!一个发 一个收
比如TX的
在串口里面:
uint32_t tslTcpWrite(int fd, uint8_t *data, uint32_t size) {
int32_t count = 0;
if(NULL == data) {
return 0;
}
count = rbWrite(&pRb, data, size);
return count;
}
这样就放进去了
在任务或者TIMER里面周期
int8_t tslProtocolHandleSend(void) {
int32_t tempLength = 0;
uint8_t tempData[20];
tempLength = rbRead(&pRb, (uint8_t *)&tempData, sizeof(tempData));
if (tempLength >0)
{
printf("\r\n#\r\n");
G_printHEX(tempData,tempLength);
printf("\r\n#\r\n");
//tcpWrite(tempData, tempLength);//模块发送出去 可以是BLE W5500等
return 0;
}
return 1;
}
这样就发出去!需要的细节是 每次我都是len>就发了!!所以!!你放入的时候 就规规矩矩 一个完整的包放去即可!!
后面RX为什么需要2个??
一个是基本的RX就是串口快速拿到数据
后面的那个是在上一层的 从里面提取一个完整的包!
从一个读出来 在完整的一包放到另外一个
其实这里 和之前我说的细节 也是一样 不要随便放!需要规规矩矩放!
我拿出来的依据不是len》0而是 if (tempLength == sizeof(ProtocolMessage_t))
所以你最好一次性放入一个包!
WHY 因为里面还有一个数组VALUE可能不会完全赋值满!
开始自己代码:
协议的文档转化为结构体!这个是真正的一个包
#define MAX_DATA_LEN 0x32
typedef struct {
uint8_t head;
uint8_t num;
uint8_t rnum;
uint16_t alen;
} ProtocolHead_t;
typedef struct {
ProtocolHead_t head;
uint8_t data[MAX_DATA_LEN];
uint16_t crc;
int fd;
} ProtocolCommon_t;
static ProtocolCommon_t dataProtocol;
分析数据的状态机
//分析状态机
typedef enum {
Protocol_head,
Protocol_num,
Protocol_rnum,
Protocol_alen,
Protocol_body,
Protocol_crc,
} ProtocolStatus_t;
typedef struct {
ProtocolStatus_t status;
uint8_t alen;
uint8_t rlen;
uint8_t cmdCount;
uint16_t check;
} StatusData_t;
static StatusData_t statusMachineData;
开始分析:
/*
* 复位状态机 仅仅针对POS设置
*/
void resetStateMachine(void) {
statusMachineData.status = Protocol_head;
}
/*
* 复位状态机中间变量 其他成员清0
*/
void resetStateMachineData(void) {
statusMachineData.alen = 0;
statusMachineData.rlen = 0;
statusMachineData.cmdCount = 0;
statusMachineData.check = 0;
}
/*
* 协议分析
*/
int8_t protocolAnalyze(int fd, ProtocolCommon_t *protocol, uint8_t element)
{
uint16_t crc16 = 0;
uint8_t finish = 0;
switch(statusMachineData.status)
{
case Protocol_head:
{
if (element == 0XAA)
{
statusMachineData.status = Protocol_num;
protocol->head.head = 0XAA;
}
else
{
resetStateMachine();
resetStateMachineData();
}
} break;
case Protocol_num:
{
protocol->head.num = element;
statusMachineData.status = Protocol_rnum;
} break;
case Protocol_rnum :
{
protocol->head.rnum = element;
statusMachineData.status = Protocol_alen;
} break;
case Protocol_alen:
{
if (statusMachineData.cmdCount == 0)
{
protocol->head.alen = element << 8;
statusMachineData.cmdCount = 1;
}
else if (statusMachineData.cmdCount == 1)
{
protocol->head.alen |= element;
statusMachineData.cmdCount = 0;
statusMachineData.alen = protocol->head.alen;
statusMachineData.status = Protocol_body;
}
} break;
case Protocol_body:
{
protocol->data[statusMachineData.rlen++] = element;
if (statusMachineData.rlen >= statusMachineData.alen)
{
statusMachineData.status = Protocol_crc;
}
} break;
case Protocol_crc:
{
if (statusMachineData.cmdCount == 0)
{
protocol->crc = element << 8;
statusMachineData.cmdCount = 1;
}
else if (statusMachineData.cmdCount == 1)
{
protocol->crc |= element;
statusMachineData.cmdCount = 0;
finish =1;
}
} break;
default : NEVERSHOW break;
}
if(finish)
if (crc16 == protocol->crc)
{
show_ProtData(protocol);
protocol->fd = fd;
resetStateMachine();
resetStateMachineData();
return 0;
}
return -1;
}
可以测试 发AA 00 FF 00 01 AB 00 00
注意:是一个一个的发送 不是一下子全部发送!
就可以看到一个包被拿出来
每次其实是放入1个 然后每次读出来也就分析一次
注意:这样的状态机分析有一个超时问题 比如我发送AA 00 以后再也没有发送了 那么状态机就
一直POS死在那个位置 可以考虑用一个定期器去割韭菜复位状态机!
暂时没有这么做
完成测试一次:
初始化2个FIFO
gizwitsInit();//L1级别
FIFO_Init_L2();//L2级别
串口中:
ProtocolMessage_t message;
message.fd = 0;
memcpy(message.data, (uint8_t *)udata.rxBuff,udata.len);
message.len = 1;
tslProtocolPutMessage(&message);
每次就是放置一个数据
main有timer 周期后台处理
void timerpaly(void)
{
tslProtocolLoop();
tslProtocolHandle();
}
下面是L1到L2的传递 可以测试发送 AA 00 FF 00 01 01 00 00 00看到回调了一个注册函数
AA ---头
00 FF --num rnum
int8_t tslProtocolLoop(void) {
int32_t tempLength = 0;
ProtocolMessage_t message;
int8_t ret = 0;
tempLength = rbRead(&pRb, (uint8_t *)&message, sizeof(ProtocolMessage_t));
if (tempLength == sizeof(ProtocolMessage_t)) {
for (int i = 0; i < message.len; i++) {
ret = protocolAnalyze(message.fd, &dataProtocol, message.data[i]);
if (ret == 0)
{
if (reciveDataHandleHook)
{
reciveDataHandleHook(dataProtocol.head.alen, dataProtocol.data);
}
rbWrite(&pRbL2, (uint8_t *)&dataProtocol, sizeof(ProtocolCommon_t));
}
}
}
return 0;
}
/*
* 处理用户注册的命令
* 需要单独在一个线程中运行
这里的用法是在串口中接收数据 也即是放入到FIFO 然后在任务中读FIFO拿出来解析
*/
int8_t tslProtocolHandle(void)
{
int32_t tempLength = 0;
ProtocolCommon_t dataProtocol;
tempLength = rbRead(&pRbL2, (uint8_t *)&dataProtocol, sizeof(ProtocolCommon_t));
if (tempLength == sizeof(ProtocolCommon_t))
{
printf("\r\n");
G_printHEX(&dataProtocol,sizeof(ProtocolCommon_t));
printf("\r\n");
show_ProtData(&dataProtocol);
node_command_type *node = commer.Find(dataProtocol.data[0]<<8 |dataProtocol.data[1] );
if(node !=NULL)
node->fun(0,0,0,NULL);
return 0;
}
else
{
return -1;
}
}