TA的每日心情 | 无聊 2018-8-2 09:51 |
---|
签到天数: 276 天 连续签到: 1 天 [LV.8]以坛为家I
|
本帖最后由 lmt50222 于 2015-9-16 09:12 编辑
- <div class="blockcode"><blockquote>GOKIT 二代智能设备通信协议分析
- 1. 机智云串口协议定义
- 命令格式:
- header(2B)=0xffff, len(2B), cmd(1B), sn(1B), flags(2B), payload(xB), checksum(1B)
- 命令格式约定:
- 1. 包头(header)固定为0XFFFF,
- 2. 长度(len)是指从CMD开始到整个数据包结束所占用的字节数
- 3. 多于一个字节的整型数字以大端字序编码
- 4. 消息序号(SN)由发送方给出,接收方响应命令时需把消息序号返回给发送方
- 5. 检验和(checksum)的计算方式为把按字节求和得出的结果对256求余
- 6. 除“非法消息通知”外的命令都带确认,如果200MS内没有收到接收方的响应,发送方应重发,最多3次
- 2. 串口接收数据
- 首先,先分析串口通信定义
- extern UART_HandleTypeDef UART_HandleStruct; 引用外部结构体定义
- 在Protocol.h文件中可以看到下面的定义
- //设备串口通信
- __packed typedef struct
- {
- uint8_t Package_Flag; //判断是否接收到一个完整的串口数据包
- uint8_t UART_Flag1; //固定码第1位 0xff
- uint8_t UART_Flag2; //固定码第2位 0xff
- uint16_t UART_Count; //串口缓冲区计算数据长度
- uint8_t UART_Cmd_len; //指令长度
- uint8_t UART_Buf[Max_UartBuf]; //串口缓冲区
- uint8_t Message_Buf[Max_UartBuf]; //处理接收到指令的Buf
- uint8_t Message_Len; //处理信息长度
- }UART_HandleTypeDef;
- 接着我看一下通信里面都有些什么内容。
- 1. Package_Flag :一个完整串口数据包标志位,0 则没有接收到数据包 1 则是已经接收到数据包了。
- 2. UART_Flag1 :串口协议包固定码1位接收标志,= 0Xff.
- 3. UART_Flag2 :串口协议包固定码2位接收标志,= 0Xff.
- 4. UART_Count :串口接收数据长度计数。
- 5. UART_Cmd_len :串口接收到的长度数据。
- 6. UART_Buf[Max_UartBuf] :串口数据缓存区。
- 7. Message_Buf[Max_UartBuf] :数据处理缓存区。
- 8. Message_Len :数据处理长度
- 现在我们开始分析串口接收函数:
- 1.void USART2_IRQHandler(void)
- 2.{
- 3. uint8_t vlue;
- 4. if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
- 5. {
- 6. USART_ClearITPendingBit(USART2,USART_IT_RXNE);
- 7. vlue = USART_ReceiveData(USART2);
- 8. if(UART_HandleStruct.Package_Flag ==0)
- 9. {
- 10. if(UART_HandleStruct.UART_Flag1 ==0)
- 11. {
- 12. if(vlue == 0xff)
- 13. {
- 14. UART_HandleStruct.UART_Count = 0;
- 15. UART_HandleStruct.UART_Buf[UART_HandleStruct.UART_Count]=vlue;
- 16. UART_HandleStruct.UART_Count++;
- 17. UART_HandleStruct.UART_Flag1 = 1;
- 18. }
- 19. return ;
- 19. }
- 20. else if(UART_HandleStruct.UART_Flag2 ==0)
- 21. {
- 22. UART_HandleStruct.UART_Buf[UART_HandleStruct.UART_Count]=vlue;
- 23. UART_HandleStruct.UART_Count++;
- 24. if(UART_HandleStruct.UART_Buf[1] == 0xff)
- 25. {
- 26. UART_HandleStruct.UART_Flag2 = 1;
- 27. }
- 28. else
- 29. {
- 30. UART_HandleStruct.UART_Flag1 = 0;
- 31. }
- 32. return ;
- 33. }
- 34. else
- 35. {
- 36. UART_HandleStruct.UART_Buf[UART_HandleStruct.UART_Count] = vlue;
- 37. if(UART_HandleStruct.UART_Count >=4 && UART_HandleStruct.UART_Buf[UART_HandleStruct.UART_Count] == 0x55 && UART_HandleStruct.UART_Buf[UART_HandleStruct.UART_Count - 1] == 0xFF)
- 38. {}
- 39. else
- 40. UART_HandleStruct.UART_Count++;
- 41. if(UART_HandleStruct.UART_Count == 0x04)
- 42. {
- 43. UART_HandleStruct.UART_Cmd_len = UART_HandleStruct.UART_Buf[2]*256+ UART_HandleStruct.UART_Buf[3];
- 44. }
- 45. if(UART_HandleStruct.UART_Count == (UART_HandleStruct.UART_Cmd_len + 4))
- 46. {
- 47. UART_HandleStruct.Package_Flag = 1;
- 48. UART_HandleStruct.UART_Flag1 = 0;
- 49. UART_HandleStruct.UART_Flag2 = 0;
- 50. }
- 51. }
- 52. }
- 53.}
- 54.}
- 详细说明:
- 1.串口2中断服务处理函数
- 3.定义局部变量Vlue
- 4.判断是否是接收中断产生,如果是则进行下一步处理,否则,退出中断函数。
- 6.进入接收中断后,清除接收中断标志位,为一下次中断做准备。
- 7.读取数据并赋值到Vlue寄存器。
- 8.判断是否接收完整的数据,如果没有则进行数据接收,否则,退出中断函数。
- 10.判断固定码第1位是否接收标志位,如果未接收则进入接收,否则进行其它判断。
- 12.固定码第1位未接收,判断接收数据是否为0XFF,不是则返回退出。
- 14.把串口数据接收计数清除
- 15.把接收到的数据放在串口缓存区第1个
- 16.把串口数据接收计数移到第2位
- 17.置固定码第1位已经接收完成
- 19.退出
- 20.判断固定码第2位是否接收标志位,如果未接收则进入接收,否则进行其它判断。
- 22.把接收到的数据放在串口缓存区第2个
- 23.把串口数据接收计数移到第3位
- 24.判断接收数据是否为0XFF
- 26.如果是0XFF,则置固定码第2位已经接收完成
- 30.如果不是0XFF,则清固定码第1位已经接收完成标志,说明数据有误,需要重新接收
- 32.退出
- 34.已经接收完固定码第1位和第2位后,则进行数据包的其它数据接收工作
- 36.把接收到数据放在串口缓存区内
- 37.如果接收计数大于或者等于4且接收到的数据等于0X55及接收到的前一个数据等于0XFF
- 38.不做处理
- 39.如果不符合上面条件,则进行下一步处理
- 40.串口数据接收计数移到下一位
- 41.如果串口接收计数为第5位,
- 43.计算本条指令信号数据长度,第3位和第4位代表长度数据
- 45.判断串口接收数据计数是否为指令长度加上固定码和长度数据之和,如果已经达到
- 47.置接收了完整的串口数据包
- 48.清固定码第1位已经接收完成标志
- 49.清固定码第2位已经接收完成标志
- 以前则是串口接收数据函数的相关内容。下面则是处理接收到的数据。
- 3. 串口数据处理
- 在分析数据处理前,我们先要理解以下两个函数,这两个函数是<string.h> 自带的,
- Memset() 作用是某个数据和数组清0
- memset(&Recv_HeadPart, 0, sizeof(Recv_HeadPart));
- memset(&UART_HandleStruct.Message_Buf, 0, sizeof(16));
- 以上内容是清Recv_HeadPart和UART_HandleStruct.Message_Buf缓存区的内容
- memcpy()作用是用做内存拷贝
- memcpy(&Recv_HeadPart, UART_HandleStruct.Message_Buf, sizeof(Recv_HeadPart));
- 把串口缓存区的数据复制到Recv_HeadPart里面
- Pro_HeadPartTypeDef Recv_HeadPart; 定义接收结构体
- 在Protocol.h文件中可以看到下面的定义
- /******************************************************
- * 协议的公用部分
- ********************************************************/
- __packed typedef struct
- {
- uint8_t Head[2]; //固定码
- uint16_t Len; //指令长度
- uint8_t Cmd; //指令内容
- uint8_t SN; //序列号
- uint8_t Flags[2]; //标志位
- }Pro_HeadPartTypeDef;
- 接着我看一下里面都有些什么内容。
- 1.Head[2] :2位固定码
- 2.Len :指令长度数据
- 3.Cmd :指令内容
- 4.SN :序列号
- 5.Flags[2] :状态标志位
- 现在我们开始分析消息处理函数:
- 1.void MessageHandle(void)
- 2.{
- 3. Pro_HeadPartTypeDef Recv_HeadPart;
- 4. memset(&Recv_HeadPart, 0, sizeof(Recv_HeadPart));
- 5. memset(&UART_HandleStruct.Message_Buf, 0, sizeof(16));
- 6. if(UART_HandleStruct.Package_Flag)
- 7. {
- 8. UART_HandleStruct.Message_Len = UART_HandleStruct.UART_Cmd_len + 4;
- 9. memcpy(&UART_HandleStruct.Message_Buf, UART_HandleStruct.UART_Buf, UART_HandleStruct.Message_Len );
- 10. memcpy(&Recv_HeadPart, UART_HandleStruct.Message_Buf, sizeof(Recv_HeadPart));
- 11. memset(&UART_HandleStruct.UART_Buf, 0, sizeof(UART_HandleStruct.Message_Buf));
- 12. UART_HandleStruct.Package_Flag = 0;
- 13. UART_HandleStruct.UART_Count = 0;
- 14. if(CheckSum(UART_HandleStruct.Message_Buf, UART_HandleStruct.Message_Len) != UART_HandleStruct.Message_Buf[UART_HandleStruct.Message_Len - 1])
- 15. {
- 16. Pro_W2D_ErrorCmdHandle();
- 17. return ;
- 18. }
- 19. switch (Recv_HeadPart.Cmd)
- 20. {
- 21. case Pro_W2D_GetDeviceInfo_Cmd:
- 22. Pro_W2D_GetMcuInfo();
- 23. break;
- 24. case Pro_W2D_P0_Cmd:
- 25. Pro_W2D_P0CmdHandle();
- 26. break;
- 27. case Pro_W2D_Heartbeat_Cmd:
- 28. Pro_W2D_CommonCmdHandle();
- 29. printf("Pro_W2D_Heartbeat ...\r\n");
- 30. break;
- 31. case Pro_W2D_ReportWifiStatus_Cmd:
- 32. Pro_D2W_ReportDevStatusHandle();
- 33. break;
- 34. case Pro_W2D_ErrorPackage_Cmd:
- 35. Pro_W2D_ErrorCmdHandle();
- 36. break;
- 37. default:
- 38. break;
- 39. }
- 40.}
- 41.}
- 详细说明:
- 1.消息处理函数
- 3.定义数据结构体Pro_HeadPartTypeDef Recv_HeadPart
- 4.清结构体Recv_HeadPart数据
- 5.清结构体UART_HandleStruct.Message_Buf缓存区数据
- 6.检测是否有接收到完整的串口数据包
- 8.处理相应的指令长度
- 9.把串口接收到的数据复制到消息处理缓存区内
- 10.把消息处理缓存区数据复制到接收数据处理结构体Recv_HeadPart中
- 11.清结构体UART_HandleStruct.Message_Buf缓存区数据
- 12.清掉接收到完整串口数据包标志,以接收后续数据
- 13.清串口接收计数
- 14.判断检验码是否正确
- 16.如果检验码错误则进行错误判断处理
- 17.退出函数
- 19.如果检验码正确,则根据相应指令码进行相关处理
- 21.如果是“获取设备状态”命令
- 22.进行设备状态上传处理
- 23.退出
- 24.如果是“P0指令状态”命令
- 25.进行P0指令解析处理
- 26.退出
- 27.如果是“心跳指令状态”命令
- 28.进行心跳传送处理
- 29.串口打印“心跳报告”
- 30.退出
- 31.如果是“WIFI状态报告”命令
- 32.进行WIFI状态报告传送处理
- 33.退出
- 34.如果是“串口数据包错误状态”命令
- 35.进行串口数据包错误状态回复处理
- 36.退出
- 37.以上状态都不是,则不做处理
- 38.退出判断
- 那么现在我再回过头来看一下Recv_HeadPart.Cmd指令分别是怎么定义的
- //所有协议指令集合
- typedef enum
- {
- Pro_W2D_GetDeviceInfo_Cmd = 0x01, //获取设备状态命令
- Pro_D2W__GetDeviceInfo_Ack_Cmd = 0x02, //获取设备状态命令应答
- Pro_W2D_P0_Cmd = 0x03, //W2D P0协议控制指令(WIFI对设备发指令)
- Pro_D2W_P0_Ack_Cmd = 0x04, //D2W P0协议控制指令应答(设备对WIFI发应答)
- Pro_D2W_P0_Cmd = 0x05, //D2W P0协议控制指令(设备对WIFI发指令)
- Pro_W2D_P0_Ack_Cmd = 0x06, //W2D P0协议控制指令应答(WIFI对设备发应答)
- Pro_W2D_Heartbeat_Cmd = 0x07, //心跳指令
- Pro_D2W_heartbeatAck_Cmd = 0x08, //心跳指令应答
- Pro_D2W_ControlWifi_Config_Cmd = 0x09, //配置WIFI模式指令
- Pro_W2D_ControlWifi_Config_Ack_Cmd = 0x0A, //配置WIFI模式指令应答
- Pro_D2W_ResetWifi_Cmd = 0x0B, //复位WIFI模块指令
- Pro_W2D_ResetWifi_Ack_Cmd = 0x0C, //复位WIFI模块指令应答
- Pro_W2D_ReportWifiStatus_Cmd = 0x0D, //获取WIFI模块状态指令
- Pro_D2W_ReportWifiStatus_Ack_Cmd = 0x0E, //获取WIFI模块状态指令应答
- Pro_D2W_ReportWifiReset_Cmd = 0x0F, //获取WIFI模块复位状态指令
- Pro_W2D_ReportWifiReset_Ack_Cmd = 0x10, //获取WIFI模块复位状态指令应答
- Pro_W2D_ErrorPackage_Cmd = 0x11, //串口数据包错误信息报告指令
- Pro_D2W_ErrorPackage_Ack_Cmd = 0x12, //串口数据包错误信息报告指令应答
- }Pro_CmdTypeDef;
- Pro_CmdTypeDef 是一个枚举类型的数据,分别把不同命令进行取值定义,以备后续程序使用。
- 未完待续。。。。。
复制代码 |
|