• 安防监控项目---通信结构体设计



    前言

    书接上次项目概要,本期和大家主要分享的此项目中通信结构体的设计,那么这部分是非常重要的,可以说,在了解清楚了项目需求之后,接下来软件设计中通信结构体的设计是非常重要的一环!本期只介绍关于结构体的设计,后期各个模块的具体实现中再带大家来看具体结构体在软件中的巧妙用处!


    一、分层意识

    1.web网页显示
    环境信息:实时刷新
    (1)ADC电压数据
    (2)MPU6050的六轴数据
    (3)温度和湿度
    摄像头:实时刷新视频流
    硬件控制:web指令下发至A9
    (1)风扇
    (2)蜂鸣器
    (3)LED
    (4)GPRS
    2.A9数据处理
    在主进程中创建各个线程,比如zigbee、LED、蜂鸣器、姿态传感器、ADC等硬件设备的具体处理线程,也包括数据刷新线程和客户端请求线程;
    3.zigbee采集部分
    这里主要是通过A9平台上传ADC,姿态传感器,以及zigbee平台的温湿度信息,这里大家也可以自主进行扩展;

    二、数据流

    数据上传:共享内存
    指令下发:消息队列

    三、应用场景

    此项目可以应用于家庭的安防监控,工业工厂监控,校园环境监控等多个监控场所;

    3.1 A9平台:


    蜂鸣器:蜂鸣器报警
    LED灯:卧室-厕所-楼道-公共照明-----LED2-LED3-LED4-LED5
    按键:按键触发中断—控制卧室和厕所灯-----LED2-LED3
    ADC:获取ADC的采样数据
    mpu6050:获取MPU6050的六轴数据

    #define		GPRS_DEV   		 "/dev/ttyUSB0"
    #define		ZIGBEE_DEV 		 "/dev/ttyUSB1"
    #define		BEEPER_DEV 		 "/dev/fsbeeper0"
    #define		LED_DEV    		 "/dev/fsled0"
    
    • 1
    • 2
    • 3
    • 4

    3.2 zigbee


    adc:协调器
    风扇:终端节点 下发命令控制风扇
    温湿度:终端节点 上传温湿度数据

    四、通信结构体具体设计及分析

    4.1 数据上传

    	数据类型定义: 	
    		typedef uint8_t  unsigned char;
    		typedef uint16_t unsigned short;
    		typedef uint32_t unsigned int;
    
    		//考虑到内存对齐的问题,zigbee平台的相关数据
    		struct makeru_zigbee_info{
    				uint8_t head[3]; //标识位: 'm' 's' 'm'  makeru-security-monitor  
    				uint8_t type;	 //数据类型  'z'---zigbee  'a'---a9
    
    				float temperature; //温度
    				float humidity;  //湿度
    				float tempMIN;//温度下限
    				float tempMAX;//温度上限 
    				float humidityMIN;   //湿度下限
    				float humidityMAX;   //湿度上限
    				uint32_t reserved[2]; //保留扩展位,默认填充0
    				//void *data;  内核预留的扩展接口  参考版
    		};
    		
    		//A9平台的相关数据
    		struct makeru_a9_info{
    			uint8_t head[3]; //标识位: 'm' 's' 'm'  makeru-security-monitor  
    			uint8_t type;	 //数据类型  'z'---zigbee  'a'---a9
    			uint32_t adc;
    			short gyrox;   //陀螺仪数据
    			short gyroy;
    			short gyroz;
    			short  aacx;  //加速计数据
    			short  aacy;
    			short  aacz;
    			uint32_t reserved[2]; //保留扩展位,默认填充0
    			//void *data;  内核预留的扩展接口  参考版
    		};
    		
    		struct makeru_env_data{
    			struct makeru_a9_info       a9_info;    
    			struct makeru_zigbee_info   zigbee_info;
    		};
    		
    		//所有监控区域的信息结构体
    		struct env_info_client_addr
    		{
    			struct makeru_env_data  monitor_no[MONITOR_NUM];	//数组  老家---新家 MONITOR_NUM表示家的数量,此项目只有一个家,所以不存在家的切换
    		};
    		
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    4.2 数据下发

    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
    		//消息队列用于通信的结构体: 包括数据类型和数据
    		
    将消息队列封装成函数,直接通过参数传递的方式来发送信息: 
    int send_msg_queue(long type,unsigned char text)
    {
    	struct msg msgbuf;
    	msgbuf.type = 1L;
    	msgbuf.msgtype = type;   //具体的消息类型
    	msgbuf.text[0] = text;   //控制命令字 
    	if(msgsnd(msgid,&msgbuf,sizeof(msgbuf) - sizeof(long),0) == -1){
    		perror("fail to msgsnd type2");
    		exit(1);
    	}
    	return 0;
    }
    		
    struct msgbuf {
           long mtype;       /* message type, must be > 0 */
           char mtext[1];    /* message data */
    };
    
    //消息队列结构体
    #define QUEUE_MSG_LEN 32                 
    struct msg
    {
    	long type;   //从消息队列接收消息时用于判断的消息类型  ==== 暂时不用 1L===home1  2L===home2 ... 
    	long msgtype;//具体的消息类型 === 指代控制的设备,是什么类型的设备
    	unsigned char text[QUEUE_MSG_LEN];//消息正文  ====> CMD 控制指定的设备
    };
    		
    		long msgtype;//具体的消息类型
    		消息类型的分配:
    			1L: 		LED控制
    			2L:			蜂鸣器控制
    			3L:			四路LED灯模拟的数码管
    			4L:			风扇
    			5L:			温湿度最值设置
    			6L-7L-8L-9L,用于个人的扩展
    			10L: 		3G通信模块-GPRS 
    		switch(msgbuf.msgtype){
    			case 1L: ...  break;
    			....
    			default ....  break;
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    4.3 控制命令字的制定

    消息队列接收消息:
    			msgrcv (msgid, &msgbuf, sizeof (msgbuf) - sizeof (long), 1L, 0);
    解析buf中的数据:
    			printf ("Get %ldL msg\n", msgbuf.msgtype);
    			printf ("text[0] = %#x\n", msgbuf.text[0]);
    
    A9-ZIGBEE通用指令
    		命令格式:一个字节,unsigned char 
    		对应消息队列中正文的类型:unsigned int 
    		----------------------------------------
    		7	6	|  5	4	|	3	2	1	0
    		平台编号|  设备编号 |	操作设备
    		----------------------------------------
    		 
    		平台编号	
    		0x00		0-ZigBee平台 
    		0x40		1-A9/A53平台
    		0x80		2-STM32平台(可以自己扩展)
    		0xc0		3-avr arduino....保留
    		(如果平台继续增多的话可以采用2个字节或多个字节来对设备进行唯一的编号,
    		比如A9类下的1号平台,2号平台,先分类,然后再具体标识设备)
    		
    		----------------------------------------		
    		设备编号		操作掩码	
    		0x00	LED		0x00	全部关闭
    						0x01	全部打开
    						0x02	打开LED2
    						0x03	打开LED3
    						0X04	打开LED4
    						0x05	打开LED5
    						0X10	打开流水灯
    		----------------------------------------
    		0x10	蜂鸣器	0x00	关闭
    						0x01	打开
    						0x02	自动报警关闭
    						0x03	自动报警打开
    		----------------------------------------
    		0x20	风扇	0x00	关闭风扇
    						0x01	打开风扇
    		----------------------------------------			
    		0x30	数码管	0x0~0xF	    显示0~F数字(四盏灯,对应0000-表示0,0001-表示1....1110-表示14)
    						0x0f		关闭数码管				led2-3-4-5
    		----------------------------------------
    		
    		控制命令:		
    			平台编号 + 设备编号 + 操作掩码 = 命令 (命令的封装)
    			例如:
    					0x00 + 0x20 + 0x01 = 0x21   风扇打开
     
    					0x40 + 0x10 + 0x01 = 0x51   蜂鸣器打开
    					0x40 + 0x30 + 0x08 = 0x78   数码管显示8
    					0x40 + 0x30 + 0x0f = 0x7f   关闭数码管
    					
    					a 高位数据,b代表低位数据
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    上行:封装的结构体----共享内存和信号量 —交给CGI(C语言和HTML语言之间的转化接口)—交给HTML
    下行:封装的命令字----消息队列 ----msgbuf msgsnd----控制命令字封装在msgsnd的msgbuf中 —A9端解析—向下控制硬件


    总结

    到此为止呢所有的通信结构体就已经设计完成了,最终呢很显然将A9所有的数据对象成了一个以家为单位的结构体,而这个结构体又包括了A9平台和zigbee采集数据的两个结构体,那么这两个结构体又仔细划分就是具体的数据对象了,比如ADC电压数据,温湿度数据;数据的下发是通过消息队列下发的,也定义了消息队列的结构体,这里需要注意的是结构体中第一个类型是必须有的,此项目中这个类型既作为消息队列的发送消息类型,也作为哪一个家(当然此项目只涉及到一个家,所以一直是类型1L,当有两个家时那么消息队列的类型就可以创建一个2L类型的);最后呢是控制命令字的设计,这个也是我在这个项目中学习到的一个非常好的设计思想,极大的提高了效率,可扩展、也可高效管理多个平台以及多个平台下的具体设备;这写呢时很好的设计思想,将采集对象在软件设计中模块化,从而提高开发效率,便于管理和代码编写,是良好的项目代码风格!

  • 相关阅读:
    官宣!Wayland正式支持基于IntelliJ的IDE
    Validating Data in Angular Grids-you need
    【数据结构】栈和队列
    多商户商城系统功能拆解26讲-平台端分销设置
    phar反序列化学习
    CV复习:K-means聚类
    FIddler抓手机的通讯包的设置记录
    Matlab彩色图像卷积的数学原理及纯手工实现
    Spring通知类型简介说明及使用ProxyFactoryBean创建AOP代理的示例分享
    里氏替换原则在继承关系中子类对父类方法的重写(覆盖)或重载时应遵循的规则
  • 原文地址:https://blog.csdn.net/weixin_58016534/article/details/134059354