机智云Gokit3.0源代码分析之协议结构体的定义

电子说

1.3w人已加入

描述

今天重点给大家分析下机智云整个程序的数据格式,机智云运行这么稳定得益于整个数据格式合理规范命名,我们直接进入主题

机智云

首先定义了一个数据类型为gizwitsProtocol_t 的全局变量,如下

/** 协议全局变量 **/

gizwitsProtocol_t gizwitsProtocol;

我们追踪下结构体的定义

__packed typedef struct

{

uint8_t issuedFlag;

uint8_t protocolBuf[MAX_PACKAGE_LEN];

uint8_t transparentBuff[MAX_PACKAGE_LEN];

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_t attrVals;

}gizwitsIssued_t;

__packed typedef struct {

uint8_t LED_OnOff:1;

uint8_t LED_Color:1;

uint8_t LED_R:1;

uint8_t LED_G:1;

uint8_t LED_B:1;

uint8_t Motor_Speed:1;

}attrFlags_t;

__packed typedef struct {

uint8_t LED_OnOff:1;

uint8_t LED_Color:2;

uint8_t reserve:5;

uint8_t LED_R;

uint8_t LED_G;

uint8_t LED_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[2];

uint16_t len;

uint8_t cmd;

uint8_t sn;

uint8_t flags[2];

} 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_t LED_OnOff:1;

uint8_t LED_Color:2;

uint8_t reserve_0:5;

uint8_t LED_R;

uint8_t LED_G;

uint8_t LED_B;

uint16_t Motor_Speed;

uint8_t Infrared:1;

uint8_t reserve_1:7;

uint8_t Temperature;

uint8_t Humidity;

uint8_t Alert_1:1;

uint8_t Alert_2:1;

uint8_t reserve_2:6;

uint8_t Fault_LED:1;

uint8_t Fault_Motor:1;

uint8_t Fault_TemHum:1;

uint8_t Fault_IR:1;

uint8_t reserve_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[EVENT_MAX];

}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);

}

下面的处理函数大家就都可以看懂了,可能讲的有点乱,但是如果跟着代码看的话还是很容易理解的,我们看下面这幅图就一目了然了,我将协议中所有的结构体定义以及连接关系都详细的标注出来不了,参考这个理解会事半功倍!

机智云

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分