Gemini 发表于 2016-10-29 22:54:57

Gokit3.0 STM32源代码分析之三

本帖最后由 Gemini 于 2016-11-4 09:49 编辑

本文转载自芯片之家-张晓宇,如需转载请注明出处芯片之家-张晓宇
有小伙伴反映图片不清晰,现附上原文链接:http://mp.weixin.qq.com/s?__biz=MzI4NTQ4NTA3NA==&mid=2247483768&idx=1&sn=3401cb025ef5bef3ce4dad53ea6968b6&chksm=ebea3005dc9db913fec8484ef8aa98afa69fc366be7d9acfdadb7371a0775759f5a0b8cf44fc&scene=0#wechat_redirect



今天重点给大家分析下机智云整个程序的数据格式,机智云运行这么稳定得益于整个数据格式合理规范命名,没有看过之前源代码分析的可以关注芯片之家公众号去了看下历史记录,我们直接进入主题
首先定义了一个数据类型为gizwitsProtocol_t 的全局变量,如下/** 协议全局变量 **/
gizwitsProtocol_t gizwitsProtocol;
我们追踪下结构体的定义
__packed typedef struct{uint8_t issuedFlag;
uint8_t protocolBuf;
uint8_t transparentBuff;
uint32_t transparentLen;
uint32_t sn;
uint32_t timerMsCount;
uint32_t lastReportTime;
protocolWaitAck_t waitAck;
eventInfo_t issuedProcessEvent;   //控制事件
eventInfo_t wifiStatusEvent;      //WIFI状态 事件
volatile gizwitsReport_t lastReportData;gizwitsIssued_t issuedData;      //云端下发控制报文数据
moduleStatusInfo_t wifiStatusData;            //WIFI 状态信息(信号强度)
}gizwitsProtocol_t;

之前一直没见过__packed,百度下才知道__packed是字节对齐的意思,比如说int float double char它的总大小是4 + 4 + 8 + 1 = 17
但如果不用__packed的话,系统将以默认的方式对齐(假设是4字节),那么它占4 + 4 + 8 + 4 = 20;(不足4字节以4字节补齐)。
这里主要定义了一些gizwits协议的下发报文标志、缓冲区、数据长度、sn、系统时间、上次上报数据的时间、重发机制定义、控制事件、WiFi状态事件、上次上报的数据、云端下发的控制报文以及WiFi状态信息这些数据的定义,这里我们重点关注几个就行了。
首先是 gizwitsIssued_t ,这个结构体里面定义了2个结构体,一个是控制功能Flag,一个是对应的Value,如下所示
__packed typedef struct
{
attrFlags_t attrFlags;
attrVals_tattrVals;
}gizwitsIssued_t;
__packed typedef struct {
uint8_tLED_OnOff:1
;uint8_tLED_Color:1;
uint8_tLED_R:1;
uint8_tLED_G:1;
uint8_tLED_B:1;
uint8_tMotor_Speed:1;
}attrFlags_t;
__packed typedef struct{
uint8_tLED_OnOff:1;
uint8_tLED_Color:2;
uint8_treserve:5;
uint8_tLED_R;
uint8_tLED_G;
uint8_tLED_B;
uint16_t Motor_Speed;
}attrVals_t;
我们看到,有LED_OnOff、LED_Color、LED的RGB值,以及电机转速这6个功能可以被控制,那么这个结构体是在哪里被赋值的呢?我们这主函数的while循环中找到gizwitsHandle这个函数,进去之后追踪到protocolGetOnePacket这个函数,这个函数就是从gizwits的接收缓冲中拿一个完整的数据包出来,不懂的可以结合我们第二讲的串口环形buff,进去一看就明白了。好,到这里我们就接到一帧从WiFi模块发送到MCU的信号帧了,协议是将接收的数据放gizwitsProtocol的protocolBuf这个数组的,我们接着往下看,
recvHead = (protocolHead_t*)gizwitsProtocol.protocolBuf;
我们往上看recvHead的定义,是一个protocolHead_t的指针,顾名思义,这个应该是协议头,我们进去看看/************ 协议标准头************/__
packed typedef struct
{
uint8_t               head;
uint16_t                len;
uint8_t               cmd;
uint8_t               sn;
uint8_t               flags;
} protocolHead_t;
协议头包括5部分,包头header固定为0xFFFF,len指从cmd开始到整个数据包结束所占用的字节,命令字节cmd表示具体的命令定义,sn由发送方给出,原路返回就是,标志位flag默认0,之后便是数据区与校验和了,这里将gizwitsProtocol.protocolBuf强制转换成protocolHead_t格式 赋给recvHead ,之后就可以通过recvHead 调用协议头的各项成员数据了,然后通过recvHead->cmd判断相应的命令进去相应的语句中去执行不同的命令,这里我们看下CMD_ISSUED_P0,这个的意思是命令为WiFi向MCU发送数据的命令,我们继续执行,来到protocolIssuedProcess这个函数,进去之后,我们看看数据是怎么定义的
protocolReport_t *protocolIssuedData = (protocolReport_t *)inData;
首先,将gizwitsProtocol.protocolBuf强制转换成protocolReport_t这个类型的指针,我们看看protocolReport_t的定义,看表面,应该是协议上报数据格式的定义__packed typedef struct
{
protocolHead_t          head;
actionType_t            action;
gizwitsReport_t         reportData;
uint8_t               sum;
} protocolReport_t;
这里包括协议头、动作、上报数据与校验和四部分,我们重点看看
gizwitsReport_t,其定义为
__packed typedef struct {
devStatus_t devStatus;
}gizwitsReport_t;
__packed typedef struct{uint8_tLED_OnOff:1;
uint8_tLED_Color:2;
uint8_treserve_0:5;
uint8_tLED_R;
uint8_tLED_G;
uint8_tLED_B;
uint16_t Motor_Speed;
uint8_tInfrared:1;
uint8_treserve_1:7;
uint8_tTemperature;
uint8_tHumidity;
uint8_tAlert_1:1;
uint8_tAlert_2:1;
uint8_treserve_2:6;
uint8_tFault_LED:1;
uint8_tFault_Motor:1;
uint8_tFault_TemHum:1;
uint8_tFault_IR:1;
uint8_treserve_3:4;
}devStatus_t;
这个结构体的定义符合了MCU 主动发送状态时或者回复 wifi 模块的状态查询时携带 p0 命令和完整数据区之后,issuedAction = protocolIssuedData->action;通过issuedAction 判断 P0 command 命令码,这里我们进入ACTION_CONTROL_DEVICE,将P0区的数据转换成事件格式,由下面这行代码实现
dataPoint2Event((gizwitsIssued_t *)(inData+sizeof(protocolP0Head_t)), &gizwitsProtocol.issuedProcessEvent);
这个函数将P0数据区的数据强制转换成gizwitsIssued_t格式的数据,也就是我们上面介绍的事件Flag和事件Value。我们还看到有一个gizwitsProtocol.issuedProcessEvent作为实参传到函数中,这个也是在gizwitsProtocol_t结构体中定义的,我们看下其结构体定义
__packed typedef struct {uint8_t num;uint8_t event;
}eventInfo_t;
这个结构体将上面传入的数据转换成相应的时间格式,每个num对应一个事件,处理完之后直接进入对应num处理对应时间就OK了。
处理完这些之后,将gizwitsProtocol.issuedFlag置1,然后判断gizwitsProtocol.issuedFlag,进入下面函数if(1 == gizwitsProtocol.issuedFlag){gizwitsProtocol.issuedFlag = 0;eventProcess(&gizwitsProtocol.issuedProcessEvent, (uint8_t *)&gizwitsProtocol.issuedData, sizeof(gizwitsIssued_t));memset((uint8_t *)&gizwitsProtocol.issuedProcessEvent,0x0,sizeof(gizwitsProtocol.issuedProcessEvent));//WORK_DONE}接下来就看到控制LED的实际出处了case SetLED_OnOff:if(LED_OnOn == issuedData->attrVals.LED_OnOff){reportData.devStatus.LED_OnOff = LED_OnOn;ledRgbControl(254,0,0);
}
else
{
reportData.devStatus.LED_OnOff = LED_OnOff;ledRgbControl(0,0,0);
}
下面的处理函数大家就都可以看懂了,可能讲的有点乱,但是如果跟着代码看的话还是很容易理解的,我们看下面这幅图就一目了然了,我将协议中所有的结构体定义以及连接关系都详细的标注出来不了,参考这个理解会事半功倍!







星迹 发表于 2016-10-31 20:54:04

楼主,图片好模糊看不清,能不能分享一张清晰的

Xuedong 发表于 2016-11-3 15:35:24

是啊,图太不清楚了,而且直接到之三了,给出原文链接或者贴个清晰的图吧!

Gemini 发表于 2016-11-4 09:50:54

星迹 发表于 2016-10-31 20:54
楼主,图片好模糊看不清,能不能分享一张清晰的

有需要只能向原作者索取了:lol,我给原文链接你们看看

Gemini 发表于 2016-11-4 09:51:09

Xuedong 发表于 2016-11-3 15:35
是啊,图太不清楚了,而且直接到之三了,给出原文链接或者贴个清晰的图吧! ...

有需要只能向原作者索取了:lol,我给原文链接你们看看

知莫 发表于 2017-7-25 16:47:09

您的图片太模糊了

知莫 发表于 2017-7-25 16:48:25

太模糊了图片

一块有脾气的板 发表于 2018-2-6 14:49:10

请问P0是什么意思呢,我一直不太明白:P
页: [1]
查看完整版本: Gokit3.0 STM32源代码分析之三