查看: 3381|回复: 1

GOKIT 二代智能设备串口通信协议分析

[复制链接]
  • TA的每日心情
    无聊
    2018-8-2 09:51
  • 签到天数: 276 天

    连续签到: 1 天

    [LV.8]以坛为家I

    发表于 2015-9-16 08:59:33 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 lmt50222 于 2015-9-16 09:12 编辑
    1. <div class="blockcode"><blockquote>GOKIT 二代智能设备通信协议分析
    2. 1.        机智云串口协议定义
    3. 命令格式:
    4. header(2B)=0xffff, len(2B), cmd(1B), sn(1B), flags(2B), payload(xB), checksum(1B)
    5. 命令格式约定:
    6. 1.        包头(header)固定为0XFFFF,
    7. 2.        长度(len)是指从CMD开始到整个数据包结束所占用的字节数
    8. 3.        多于一个字节的整型数字以大端字序编码
    9. 4.        消息序号(SN)由发送方给出,接收方响应命令时需把消息序号返回给发送方
    10. 5.        检验和(checksum)的计算方式为把按字节求和得出的结果对256求余
    11. 6.        除“非法消息通知”外的命令都带确认,如果200MS内没有收到接收方的响应,发送方应重发,最多3次
    12. 2.        串口接收数据
    13. 首先,先分析串口通信定义
    14. extern UART_HandleTypeDef  UART_HandleStruct;   引用外部结构体定义
    15. 在Protocol.h文件中可以看到下面的定义
    16. //设备串口通信
    17. __packed        typedef struct       
    18. {       
    19. uint8_t         Package_Flag;                     //判断是否接收到一个完整的串口数据包         
    20. uint8_t         UART_Flag1;              //固定码第1位 0xff
    21. uint8_t         UART_Flag2;              //固定码第2位 0xff
    22. uint16_t          UART_Count;                                 //串口缓冲区计算数据长度       
    23. uint8_t         UART_Cmd_len;                         //指令长度       
    24. uint8_t          UART_Buf[Max_UartBuf];          //串口缓冲区
    25. uint8_t   Message_Buf[Max_UartBuf]; //处理接收到指令的Buf
    26. uint8_t   Message_Len;                 //处理信息长度
    27. }UART_HandleTypeDef;
    28.         接着我看一下通信里面都有些什么内容。
    29. 1.        Package_Flag :一个完整串口数据包标志位,0 则没有接收到数据包 1 则是已经接收到数据包了。
    30. 2.        UART_Flag1  :串口协议包固定码1位接收标志,= 0Xff.
    31. 3.        UART_Flag2  :串口协议包固定码2位接收标志,= 0Xff.
    32. 4.        UART_Count  :串口接收数据长度计数。
    33. 5.        UART_Cmd_len :串口接收到的长度数据。
    34. 6.        UART_Buf[Max_UartBuf] :串口数据缓存区。
    35. 7.        Message_Buf[Max_UartBuf] :数据处理缓存区。
    36. 8.        Message_Len :数据处理长度

    37. 现在我们开始分析串口接收函数:
    38. 1.void USART2_IRQHandler(void)      
    39. 2.{
    40. 3.        uint8_t         vlue;
    41. 4. if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
    42. 5. {
    43. 6.                USART_ClearITPendingBit(USART2,USART_IT_RXNE);
    44. 7.                vlue = USART_ReceiveData(USART2);
    45. 8.                if(UART_HandleStruct.Package_Flag ==0)
    46. 9.                {
    47. 10.                if(UART_HandleStruct.UART_Flag1 ==0)
    48. 11.                {
    49. 12.                        if(vlue == 0xff)
    50. 13.                        {   
    51. 14.                                UART_HandleStruct.UART_Count = 0;
    52. 15.                                UART_HandleStruct.UART_Buf[UART_HandleStruct.UART_Count]=vlue;
    53. 16.                                UART_HandleStruct.UART_Count++;       
    54. 17.                                UART_HandleStruct.UART_Flag1 = 1;
    55. 18.                        }                       
    56. 19.                        return ;
    57. 19.                }
    58. 20.                else if(UART_HandleStruct.UART_Flag2 ==0)
    59. 21.                {
    60. 22.                        UART_HandleStruct.UART_Buf[UART_HandleStruct.UART_Count]=vlue;
    61. 23.                        UART_HandleStruct.UART_Count++;
    62. 24.                        if(UART_HandleStruct.UART_Buf[1] == 0xff)
    63. 25.                        {
    64. 26.                                UART_HandleStruct.UART_Flag2 = 1;       
    65. 27.                        }                                       
    66. 28.                        else
    67. 29.                        {
    68. 30.                                UART_HandleStruct.UART_Flag1 = 0;
    69. 31.                        }
    70. 32.                        return ;
    71. 33.                }
    72. 34.                else
    73. 35.                {
    74. 36.                        UART_HandleStruct.UART_Buf[UART_HandleStruct.UART_Count] = vlue;
    75. 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)
    76. 38.                        {}
    77. 39.                        else
    78. 40.                        UART_HandleStruct.UART_Count++;
    79. 41.                        if(UART_HandleStruct.UART_Count == 0x04)
    80. 42.                        {
    81. 43.                                UART_HandleStruct.UART_Cmd_len = UART_HandleStruct.UART_Buf[2]*256+  UART_HandleStruct.UART_Buf[3];        
    82. 44.                        }
    83. 45.                        if(UART_HandleStruct.UART_Count == (UART_HandleStruct.UART_Cmd_len + 4))
    84. 46.                        {
    85. 47.                                UART_HandleStruct.Package_Flag = 1;
    86. 48.                                UART_HandleStruct.UART_Flag1 = 0;
    87. 49.                                UART_HandleStruct.UART_Flag2 = 0;
    88. 50.                        }       
    89. 51.                }
    90. 52.        }               
    91. 53.}       
    92. 54.}
    93. 详细说明:
    94. 1.串口2中断服务处理函数
    95. 3.定义局部变量Vlue
    96. 4.判断是否是接收中断产生,如果是则进行下一步处理,否则,退出中断函数。
    97. 6.进入接收中断后,清除接收中断标志位,为一下次中断做准备。
    98. 7.读取数据并赋值到Vlue寄存器。
    99. 8.判断是否接收完整的数据,如果没有则进行数据接收,否则,退出中断函数。
    100. 10.判断固定码第1位是否接收标志位,如果未接收则进入接收,否则进行其它判断。
    101. 12.固定码第1位未接收,判断接收数据是否为0XFF,不是则返回退出。
    102. 14.把串口数据接收计数清除
    103. 15.把接收到的数据放在串口缓存区第1个
    104. 16.把串口数据接收计数移到第2位
    105. 17.置固定码第1位已经接收完成
    106. 19.退出
    107. 20.判断固定码第2位是否接收标志位,如果未接收则进入接收,否则进行其它判断。
    108. 22.把接收到的数据放在串口缓存区第2个
    109. 23.把串口数据接收计数移到第3位
    110. 24.判断接收数据是否为0XFF
    111. 26.如果是0XFF,则置固定码第2位已经接收完成
    112. 30.如果不是0XFF,则清固定码第1位已经接收完成标志,说明数据有误,需要重新接收
    113. 32.退出
    114. 34.已经接收完固定码第1位和第2位后,则进行数据包的其它数据接收工作
    115. 36.把接收到数据放在串口缓存区内
    116. 37.如果接收计数大于或者等于4且接收到的数据等于0X55及接收到的前一个数据等于0XFF
    117. 38.不做处理
    118. 39.如果不符合上面条件,则进行下一步处理
    119. 40.串口数据接收计数移到下一位
    120. 41.如果串口接收计数为第5位,
    121. 43.计算本条指令信号数据长度,第3位和第4位代表长度数据
    122. 45.判断串口接收数据计数是否为指令长度加上固定码和长度数据之和,如果已经达到
    123. 47.置接收了完整的串口数据包
    124. 48.清固定码第1位已经接收完成标志
    125. 49.清固定码第2位已经接收完成标志

    126. 以前则是串口接收数据函数的相关内容。下面则是处理接收到的数据。

    127. 3.        串口数据处理
    128. 在分析数据处理前,我们先要理解以下两个函数,这两个函数是<string.h> 自带的,
    129. Memset() 作用是某个数据和数组清0
    130. memset(&Recv_HeadPart, 0, sizeof(Recv_HeadPart));
    131. memset(&UART_HandleStruct.Message_Buf, 0, sizeof(16));
    132. 以上内容是清Recv_HeadPart和UART_HandleStruct.Message_Buf缓存区的内容
    133. memcpy()作用是用做内存拷贝
    134. memcpy(&Recv_HeadPart, UART_HandleStruct.Message_Buf, sizeof(Recv_HeadPart));
    135. 把串口缓存区的数据复制到Recv_HeadPart里面

    136. Pro_HeadPartTypeDef   Recv_HeadPart; 定义接收结构体
    137. 在Protocol.h文件中可以看到下面的定义
    138. /******************************************************
    139. * 协议的公用部分
    140. ********************************************************/
    141. __packed        typedef struct       
    142. {
    143.         uint8_t        Head[2];  //固定码
    144.         uint16_t        Len;                 //指令长度
    145.         uint8_t        Cmd;     //指令内容
    146.         uint8_t        SN;      //序列号
    147.         uint8_t        Flags[2];  //标志位
    148. }Pro_HeadPartTypeDef;

    149. 接着我看一下里面都有些什么内容。

    150. 1.Head[2] :2位固定码
    151. 2.Len    :指令长度数据
    152. 3.Cmd    :指令内容
    153. 4.SN     :序列号
    154. 5.Flags[2] :状态标志位

    155. 现在我们开始分析消息处理函数:

    156. 1.void MessageHandle(void)
    157. 2.{
    158. 3.        Pro_HeadPartTypeDef   Recv_HeadPart;
    159. 4.        memset(&Recv_HeadPart, 0, sizeof(Recv_HeadPart));
    160. 5.        memset(&UART_HandleStruct.Message_Buf, 0, sizeof(16));
    161. 6.        if(UART_HandleStruct.Package_Flag)
    162. 7.        {
    163. 8.                UART_HandleStruct.Message_Len = UART_HandleStruct.UART_Cmd_len + 4;               
    164. 9.        memcpy(&UART_HandleStruct.Message_Buf, UART_HandleStruct.UART_Buf, UART_HandleStruct.Message_Len );
    165. 10.        memcpy(&Recv_HeadPart, UART_HandleStruct.Message_Buf, sizeof(Recv_HeadPart));
    166. 11.        memset(&UART_HandleStruct.UART_Buf, 0, sizeof(UART_HandleStruct.Message_Buf));               
    167. 12.        UART_HandleStruct.Package_Flag = 0;
    168. 13.        UART_HandleStruct.UART_Count = 0;
    169. 14.        if(CheckSum(UART_HandleStruct.Message_Buf, UART_HandleStruct.Message_Len) != UART_HandleStruct.Message_Buf[UART_HandleStruct.Message_Len - 1])
    170. 15.        {
    171. 16.                Pro_W2D_ErrorCmdHandle();
    172. 17.                return ;               
    173. 18.        }
    174. 19.        switch (Recv_HeadPart.Cmd)
    175. 20.        {
    176. 21.                case Pro_W2D_GetDeviceInfo_Cmd:
    177. 22.                        Pro_W2D_GetMcuInfo();
    178. 23.                        break;
    179. 24.                case Pro_W2D_P0_Cmd:
    180. 25.                        Pro_W2D_P0CmdHandle();                 
    181. 26.                        break;
    182. 27.                case Pro_W2D_Heartbeat_Cmd:                                                       
    183. 28.                        Pro_W2D_CommonCmdHandle();
    184. 29.                        printf("Pro_W2D_Heartbeat ...\r\n");       
    185. 30.                        break;                                               
    186. 31.                case Pro_W2D_ReportWifiStatus_Cmd:
    187. 32.                        Pro_D2W_ReportDevStatusHandle();
    188. 33.                        break;
    189. 34.                case Pro_W2D_ErrorPackage_Cmd:
    190. 35.                        Pro_W2D_ErrorCmdHandle();
    191. 36.                        break;
    192. 37.                default:
    193. 38.                        break;
    194. 39.        }       
    195. 40.}
    196. 41.}
    197. 详细说明:
    198. 1.消息处理函数
    199. 3.定义数据结构体Pro_HeadPartTypeDef  Recv_HeadPart
    200. 4.清结构体Recv_HeadPart数据
    201. 5.清结构体UART_HandleStruct.Message_Buf缓存区数据
    202. 6.检测是否有接收到完整的串口数据包
    203. 8.处理相应的指令长度
    204. 9.把串口接收到的数据复制到消息处理缓存区内
    205. 10.把消息处理缓存区数据复制到接收数据处理结构体Recv_HeadPart中
    206. 11.清结构体UART_HandleStruct.Message_Buf缓存区数据
    207. 12.清掉接收到完整串口数据包标志,以接收后续数据
    208. 13.清串口接收计数
    209. 14.判断检验码是否正确
    210. 16.如果检验码错误则进行错误判断处理
    211. 17.退出函数
    212. 19.如果检验码正确,则根据相应指令码进行相关处理
    213. 21.如果是“获取设备状态”命令
    214. 22.进行设备状态上传处理
    215. 23.退出
    216. 24.如果是“P0指令状态”命令
    217. 25.进行P0指令解析处理
    218. 26.退出
    219. 27.如果是“心跳指令状态”命令
    220. 28.进行心跳传送处理
    221. 29.串口打印“心跳报告”
    222. 30.退出
    223. 31.如果是“WIFI状态报告”命令
    224. 32.进行WIFI状态报告传送处理
    225. 33.退出
    226. 34.如果是“串口数据包错误状态”命令
    227. 35.进行串口数据包错误状态回复处理
    228. 36.退出
    229. 37.以上状态都不是,则不做处理
    230. 38.退出判断

    231. 那么现在我再回过头来看一下Recv_HeadPart.Cmd指令分别是怎么定义的
    232. //所有协议指令集合
    233. typedef  enum
    234. {
    235. Pro_W2D_GetDeviceInfo_Cmd                         = 0x01,  //获取设备状态命令
    236. Pro_D2W__GetDeviceInfo_Ack_Cmd                = 0x02,  //获取设备状态命令应答
    237. Pro_W2D_P0_Cmd                                         = 0x03,  //W2D P0协议控制指令(WIFI对设备发指令)
    238. Pro_D2W_P0_Ack_Cmd                                        = 0x04,  //D2W P0协议控制指令应答(设备对WIFI发应答)
    239. Pro_D2W_P0_Cmd                                         = 0x05,  //D2W P0协议控制指令(设备对WIFI发指令)
    240. Pro_W2D_P0_Ack_Cmd                                        = 0x06,  //W2D P0协议控制指令应答(WIFI对设备发应答)
    241. Pro_W2D_Heartbeat_Cmd                                 = 0x07,  //心跳指令
    242. Pro_D2W_heartbeatAck_Cmd                        = 0x08,  //心跳指令应答
    243. Pro_D2W_ControlWifi_Config_Cmd                 = 0x09,  //配置WIFI模式指令
    244. Pro_W2D_ControlWifi_Config_Ack_Cmd        = 0x0A,  //配置WIFI模式指令应答
    245. Pro_D2W_ResetWifi_Cmd                                 = 0x0B,  //复位WIFI模块指令
    246. Pro_W2D_ResetWifi_Ack_Cmd                        = 0x0C,  //复位WIFI模块指令应答
    247. Pro_W2D_ReportWifiStatus_Cmd                 = 0x0D,  //获取WIFI模块状态指令
    248. Pro_D2W_ReportWifiStatus_Ack_Cmd                = 0x0E,  //获取WIFI模块状态指令应答
    249. Pro_D2W_ReportWifiReset_Cmd                         = 0x0F,  //获取WIFI模块复位状态指令
    250. Pro_W2D_ReportWifiReset_Ack_Cmd                = 0x10,  //获取WIFI模块复位状态指令应答
    251. Pro_W2D_ErrorPackage_Cmd                         = 0x11,  //串口数据包错误信息报告指令
    252. Pro_D2W_ErrorPackage_Ack_Cmd                = 0x12,  //串口数据包错误信息报告指令应答
    253. }Pro_CmdTypeDef;
    254. Pro_CmdTypeDef 是一个枚举类型的数据,分别把不同命令进行取值定义,以备后续程序使用。

    255. 未完待续。。。。。
    复制代码
    回复

    使用道具 举报

  • TA的每日心情
    郁闷
    2015-9-17 16:07
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2015-9-17 16:17:16 | 显示全部楼层
    分析很到位!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-11-22 11:30 , Processed in 0.130559 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.