今天重点给大家分析下机智云整个程序的数据格式,机智云运行这么稳定得益于整个数据格式合理规范命名,我们直接进入主题
首先定义了一个数据类型为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);
}
下面的处理函数大家就都可以看懂了,可能讲的有点乱,但是如果跟着代码看的话还是很容易理解的,我们看下面这幅图就一目了然了,我将协议中所有的结构体定义以及连接关系都详细的标注出来不了,参考这个理解会事半功倍!
运营商Tele2和诺基亚合作5G网络部署
人工智能与文娱行业结合,编曲者或将可以歇业了
SpaceX计划2月份进行星际飞船系统第三次飞行测试
机器人实时定位方案的介绍
HoloRide推出可以防止晕车的虚拟现实技术
机智云Gokit3.0源代码分析之协议结构体的定义
禾赛科技AT128获国际顶级OEM激光雷达量产定点,加速拓展全球ADAS市场
IMAX首席业务拓展官:看重中国用户的体验
电化学合成多维纳米硅用于锂离子电池负极材料
EDA处于芯片产业链的最上游,是芯片设计和生产的必备工具
网络摄像机综合布线方法和安装步骤
除小米Mix外颜值最高的小米手机:小米5C开箱图赏
供应商工厂突发爆炸,日本丰田7座工厂停工
vivoX27拍照怎么样
陶瓷涂层绝缘轴承的制备方法
ST-Link到底有多少个版本?
什么是D什么是DPWM调制方式?PWM调制方式?
十大案例分析,机器学习的十种网络攻击
lyapunov指数解析
小米7渲染图曝光:全面屏+骁龙845+双摄,就想问多少钱