电子说
今天重点给大家分析下机智云整个程序的数据格式,机智云运行这么稳定得益于整个数据格式合理规范命名,我们直接进入主题
首先定义了一个数据类型为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);
}
下面的处理函数大家就都可以看懂了,可能讲的有点乱,但是如果跟着代码看的话还是很容易理解的,我们看下面这幅图就一目了然了,我将协议中所有的结构体定义以及连接关系都详细的标注出来不了,参考这个理解会事半功倍!
全部0条评论
快来发表一下你的评论吧 !