完整框架如下图所示:
(由于客观原因限制,只做部分功能的实现)
web 页面显示部分
A9 数据处理部分
数据采集部分
数据上传
通过共享内存和信号量实现数据上传。
数据类型定义(参考)
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
//考虑到内存对齐的问题
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
};
struct makeru_a9_info{
uint8_t head[3]; //标识位: 'm' 's' 'm' makeru-security-monitor
uint8_t type; //数据类型 'z'---zigbee 'a'---a9
float adc;
short gyrox; //陀螺仪数据
short gyroy;
short gyroz;
short aacx; //加速计数据
short aacy;
short aacz;
uint32_t reserved[2]; //保留扩展位,默认填充0
};
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]; //数组 老家---新家
};
数据下发
采用消息队列将消息下发到下位机,用于控制硬件。
man msgsnd
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
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; //从消息队列接收消息时用于判断的消息类型
long msgtype;//具体的消息类型
unsigned char text[QUEUE_MSG_LEN];//消息正文
};
long msgtype;//具体的消息类型
消息类型的分配:
1L: LED控制
2L: 蜂鸣器控制
3L: 四路LED灯模拟的数码管
4L: 风扇
5L: 温湿度最值设置
6L-7L-8L-9L,用于个人的扩展
10L: 3G通信模块-GPRS
switch(msgbuf.msgtype){
case 1L: ... break;
....
default .... break;
}
控制命令的制定:
消息队列接收消息:
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]);
extern void *pthread_client_request (void *arg); //接收 CGI 等的请求
extern void *pthread_refresh(void *arg); //刷新共享内存数据线程
extern void *pthread_sqlite(void *arg); //数据库线程,保存数据库的数据
extern void *pthread_transfer(void *arg); //接收ZigBee的数据并解析
extern void *pthread_sms(void *arg); //发送短信线程
extern void *pthread_buzzer(void *arg); //蜂鸣器控制线程
extern void *pthread_led(void *arg); //led灯控制线程
extern int send_msg_queue(long type,unsigned char text);
处理消息队列中请求的线程
void *pthread_client_request(void *arg)
{
// convert a pathname and a project identifier to a System V IPC key
if((key = ftok("/tmp",'g')) < 0){
perror("ftok failed .\n");
exit(-1);
}
// get a System V message queue identifier
msgid = msgget(key,IPC_CREAT|IPC_EXCL|0666);
if(msgid == -1) {
/*
If msgflg specifies both IPC_CREAT and IPC_EXCL and a message queue
already exists for key, then msgget() fails with errno set to EEXIST.
(This is analogous to the effect of the combination O_CREAT | O_EXCL for open(2).)
*/
if(errno == EEXIST){
msgid = msgget(key,0777);
}else{
perror("fail to msgget");
exit(1);
}
}
printf("pthread_client_request\n");
while(1){
/*
The bzero() function erases the data in the n bytes of the memory
starting at the location pointed to by s, by writing zeroes (bytes con‐
taining '\0') to that area.
*/
bzero(&msgbuf,sizeof(msgbuf));
printf("wait form client request...\n");
msgrcv (msgid, &msgbuf, sizeof (msgbuf) - sizeof (long), 1L, 0);
printf ("Get %ldL msg\n", msgbuf.msgtype);
printf ("text[0] = %#x\n", msgbuf.text[0]);
...
...
...
LED模块线程
#include "data_global.h"
void *pthread_led(void *arg)
{
printf("pthread_led\n");
#if 0
5. open(dev_led, )
6. pthread_cond_wait (cond_led, );
7. 获取dev_led_mask(控制标志)
8. 通过 ioctl() 控制led
#endif
}
刷新共享内存数据线程
extern struct env_info_client_addr sm_all_env_info;
struct shm_addr
{
char shm_status; //shm_status可以等于home_id,用来区分共享内存数据
struct env_info_client_addr sm_all_env_info;
};
struct shm_addr *shm_buf;
int file_env_info_struct(struct env_info_client_addr *rt_status,int home_id);
void *pthread_refresh(void *arg)
{
...
//share memap
if((shm_buf = (struct shm_addr *)shmat(shmid,NULL,0)) == (void *)-1)
{
perror("fail to shmat");
exit(1);
}
printf("pthread_refresh ......>>>>>>>\n");
#if 0
bzero (shm_buf, sizeof (struct shm_addr));
while(1){
sem_p(semid,0);
shm_buf->shm_status = 1;
file_env_info_struct(&shm_buf->sm_all_env_info,shm_buf->shm_status);
sleep(1);
sem_v(semid,0);
}
#endif
}
int file_env_info_struct(struct env_info_client_addr *rt_status,int home_id)
{
int env_info_size = sizeof(struct env_info_client_addr);
printf("env_info_size = %d.\n",env_info_size);
...
...
介绍安防系统整体框架,从两个维度进行分析:
1. 分层意识
用户层、处理层和感知层
2. 数据流
从上到下:配置下发(消息队列)
从下到上:数据采集(共享内存)
每类元器件都有一个对应线程,多个线程之间通过互斥锁和条件变量,实现同步互斥。
Q1. 感知层元器件怎么把采集到的数据写入共享内存?
A:通过驱动读取元器件中的寄存器