一、数据刷新
在主框架中可以看到数据刷新线程:pthread_refrash.c
略去出错处理,如下:
1 #include "data_global.h"
2 #include "sem.h"
3
4 #define N 1024 //for share memory
5
6 //外部声明键值与id
7 extern int shmid;
8 extern int msgid;
9 extern int semid;
10
11 extern key_t shm_key;
12 extern key_t sem_key;
13 extern key_t key; //msg_key
14
15 //外部互斥体声明
16 extern pthread_mutex_t mutex_client_request,
17 mutex_refresh,
18 ...
19 //外部声明条件变量
20 extern pthread_cond_t cond_client_request,
21 cond_refresh,
22 ...
23
24 //包含所有环境信息的结构体,在data_global.h中声明,
25 //最终为makeru_zigbee_info与makeru_a9_info这两个结构体的组合
26 extern struct env_info_client_addr sm_all_env_info;
27
28 //将所有环境信息结构体与home_id再次封装成一个结构体
29 struct shm_addr
30 {
31 char shm_status; //shm_status可以等于home_id,用来区分共享内存数据
32 struct env_info_client_addr sm_all_env_info;
33 };
34 struct shm_addr *shm_buf;
35
36 //模拟数据刷新的函数
37 int file_env_info_struct(struct env_info_client_addr *rt_status,int home_id);
38
39 /* shm复习:
40 * 共享内存使用步骤:
41 * 1 创建/打开共享内存 —— shmget
42 * 2 映射共享内存,即把指定的共享内存映射到进程地址空间用于访问 —— shmat
43 * 3 读写共享内存 —— 地址 = shmat
44 * 4 撤销共享内存映射 —— shmdt
45 * 5 删除共享内存对象 —— shmctl
46 */
47
48 void *pthread_refresh(void *arg)
49 {
50 //semaphore for access to resource limits
51 //信号量+共享内存实现对资源的互斥操作
52
53 //"/tmp"--路径,'i'--生成key的数字,范围1-255 ,返回值:key_t
54 sem_key = ftok("/tmp",'i');
55
56 //创建信号量,返回id
57 semid = semget(sem_key,1,IPC_CREAT|IPC_EXCL|0666);
58
59 init_sem (semid, 0, 1);
60
61
62 //创建共享内存
63 shm_key = ftok("/tmp",'i');
64 shmid = shmget(shm_key,N,IPC_CREAT|IPC_EXCL|0666);
65
66 //映射共享内存,为shm_buf指定共享内存
67 shm_buf = (struct shm_addr *)shmat(shmid,NULL,0));
68
69 //清空一下shm_buf
70 bzero (shm_buf, sizeof (struct shm_addr));
71 //
72 while(1){
73 sem_p(semid,0); //P操作
74 shm_buf->shm_status = 1; //指定home1
75 file_env_info_struct(&shm_buf->sm_all_env_info,shm_buf->shm_status); //刷新数据到web
76 sleep(1);
77 sem_v(semid,0); //V操作
78 }
79
80
81 int file_env_info_struct(struct env_info_client_addr *rt_status,int home_id)
82 {
83 int env_info_size = sizeof(struct env_info_client_addr);
84 printf("env_info_size = %d.\n",env_info_size);
85
86 rt_status->monitor_no[home_id].zigbee_info.temperature = 10.0;
87 ...
88 rt_status->monitor_no[home_id].zigbee_info.reserved[1] = -0.01;
89
90 rt_status->monitor_no[home_id].a9_info.adc = 9.0;
91 ...
92 rt_status->monitor_no[home_id].a9_info.reserved[1] = -0.01;
93
94 return 0;
95 }
2、在CGI部分
env1.c -- > env1.cgi
1 #include <stdio.h>
2 ...
3 #include "cgic.h"
4 #include "data_global.h"
5
6
7 //包含环境信息的结构体
8 struct shm_addr
9 {
10 char shm_status;
11 struct env_info_client_addr sm_all_env_info;
12 };
13
14 int cgiMain()
15 {
16 key_t key;
17 int shmid,semid;
18 struct shm_addr *shm_buf;
19
20 //key就相当于文件名,/tmp为其路径
21 key = ftok("/tmp",'i');
22
23 //创建信号量
24 semid = semget(key, 1, 0666);
25
26 //映射shm,并让shm_buf指向shm
27 shm_buf = (struct shm_addr*)shmat(shmid, NULL, 0);
28
29 //信号量:P操作
30 sem_p(semid,0);
31
32 //CGI接口规范
33 //CGI即通用网关接口,就是处理HTML网页端数据与服务器端的接口
34 //使服务器和网页端能互相识别处理彼此的数据
35 if (shm_buf->shm_status == 1)
36 {
37 //最终会在网页端打印以下信息
38 fprintf(cgiOut, "<h4>Temperature:\t%0.2f</H4>\n ", shm_buf->sm_all_env_info.monitor_no[shm_buf->shm_status].zigbee_info.temperature );
39 ...
40 fprintf(cgiOut, "<h4>A9数据显示部分</H4>\n ");
41 fprintf(cgiOut, "<h4>Adc:\t%0.2f</H4>\n ", shm_buf->sm_all_env_info.monitor_no[shm_buf->shm_status].a9_info.adc);
42 ...
43 fprintf(cgiOut, "<h4>A9-RESERVED[1]:\t%d</H4>\n ", shm_buf->sm_all_env_info.monitor_no[shm_buf->shm_status].a9_info.reserved[1]);
44
45 fprintf(cgiOut, "<h4>......</H4>\n ");
46 }
47 else
48 {
49 }
50 //信号量:V操作
51 sem_v (semid, 0);
52 return 0;
53 }
3、网页端
env1.html
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html xmlns="http://www.w3.org/1999/xhtml">
3
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6 <title>仓库一环境信息</title>
7 </head>
8
9 <body>
10
11 <body background="./images/huaqing002.jpg">
12 </div>
13 <table width="1080" border="0" height="200" background="./images/huaqing2.jpg" align="center">
14 <tr>
15 <td> </td>
16 <td> </td>
17 </tr>
18 </table>
19 <table width="1080" border="1" align="center">
20 <tr>
21 <td width="556">
22 <div align="center">
23 <h3>环境信息</h3></div>
24 </td>
25 <td width="500">
26 <div align="center">
27 <a href="home1.html">
28 <h3>回主页</h3></a>
29 </div>
30 </td>
31 </tr>
32 </table>
33 <table width="1080" height="511" border="1" align="center">
34 <tr>
35 <td width="283" height="500" background="./images/zigee.jpg" align="left"></td>
36 <td width="432"><iframe src="cgi-bin/env1.cgi" height="500" width="518" align="middle"></iframe></td>
37 <td width="283" background="./images/gprs.jpg" align="right"></td>
38 </tr>
39 </table>
40 </body>
41
42 </html>
在第36行,网页端会调用到服务器端的cgi-bin目录下的env1.cgi文件进行数据的刷新与显示,
效果如下:
服务器端下的目录结构:
二、web端命令下发
从上往下分析
在html端通过action,将对应的控制指令交给xxxx.cgi,在CGI进程中,对数据进行解析,将数据填充进消息,在将消息发送给消息队列,
给主线程中的接收用户请求线程,获取消息队列里的消息,进而将指令分发给不同的主线程。
以led为例:
在网页查看控制部分的源码:
1 <table width="400" height="270" align="center" border="3" bordercolor="red">
2 <td height="60">
3 <div align="center">
4 <form id="form1" name="form1" method="post" action="cgi-bin/a9_led.cgi">
5 <div class="strip1">
6 <input type="hidden" name="store" id="hiddenField" value="1" /> Led:
7 <label>
8 <input type="radio" name="led" value="1" id="led_0" />
9 on</label>
10
11 <label>
12 <input type="radio" name="led" value="0" id="led_1" />
13 off</label>
14 <input type="submit" name="button" id="button" value="确定" />
15 </div>
16 </form>
17 </div>
18 </td>
19 </tr>
20 <tr>
由4四行,去查看a9_led.c
1 #include <stdio.h>
2 #include "cgic.h"
3 ...
4 #include <sys/msg.h>
5
6 #define N 8
7
8 struct msg
9 {
10 long type;
11 long msgtype;
12 unsigned char text[N];
13 };
14
15
16 int cgiMain()
17 {
18 key_t key;
19 char buf[N];
20 char sto_no[2];
21 int msgid;
22 struct msg msg_buf;
23 memset(&msg_buf,0,sizeof(msg_buf));
24
25 cgiFormString("led",buf,N);
26 cgiFormString("store",sto_no,2);
27
28 key = ftok("/tmp", 'g');
29
30 msgid = msgget(key, 0666);
31
32 bzero (msg_buf.text, sizeof (msg_buf.text));
33
34 if (buf[0] == '1')
35 { //构造命令,并填充结构体
36 msg_buf.text[0] = ((sto_no[0] - 48)) << 6 | (0x0 << 4) | (1 << 0);
37 }
38 else
39 {
40 msg_buf.text[0] = ((sto_no[0] - 48)) << 6 | (0x0 << 4) | (0 << 0);
41 }
42
43 //填充结构体
44 msg_buf.type = 1L;
45 msg_buf.msgtype = 1L; //具体的消息类型 === 指代控制的设备,如1L->LED
46 msgsnd(msgid, &msg_buf,sizeof(msg_buf)-sizeof(long),0);
47
48 sto_no[0] -= 48;
49
50 cgiHeaderContentType("text/html\n\n");
51 fprintf(cgiOut, "<HTML><HEAD>\n");
52 fprintf(cgiOut, "<TITLE>My CGI</TITLE></HEAD>\n");
53 fprintf(cgiOut, "<BODY>");
54
55 fprintf(cgiOut, "<H2>send sucess</H2>");
56
57 //fprintf(cgiOut, "<a href='.html'>返回</a>");
58 fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"1;url=../a9_zigbee%d.html\">", sto_no[0]);
59 fprintf(cgiOut, "</BODY>\n");
60 fprintf(cgiOut, "</HTML>\n");
61
62 return 0;
63 }
在A9主线程中的接收用户请求线程获取消息队列中的消息,进而判断并分发给不同子线程
1 #include "data_global.h"
2
3 extern int msgid;
4 extern key_t key;
5
6 extern pthread_mutex_t mutex_client_request,
7 mutex_refresh,
8 ...
9 mutex_led,
10
11 extern pthread_cond_t cond_client_request,
12 cond_refresh,
13 ...
14 cond_led;
15
16
17 struct msg msgbuf;
18
19
20 void *pthread_client_request(void *arg)
21 {
22 key = ftok("/tmp",'g')) < 0);
23
24 msgid = msgget(key,IPC_CREAT|IPC_EXCL|0666);
25
26 while(1){
27 bzero(&msgbuf,sizeof(msgbuf));
28 printf("wait form client request...\n");
29 //从消息队列接收消息
30 msgrcv (msgid, &msgbuf, sizeof (msgbuf) - sizeof (long), 1L, 0);
31 printf ("Get %ldL msg\n", msgbuf.msgtype);
32 printf ("text[0] = %#x\n", msgbuf.text[0]);
33
34 //对消息进行判断进而去调用不同的线程处理
35 switch(msgbuf.msgtype){
36 case 1L:
37 printf("hello led\n");
38 break;
39 case 2L:
40 printf("hello beep\n");
41 break;
42 case 3L:
43 printf("hello seg\n");
44 break;
45 case 4L:
46 printf("hello fan\n");
47 break;
48 case 5L:
49 printf("set env data\n");
50 printf("temMAX: %d\n",*((int *)&msgbuf.text[1]));
51 ...
52 printf("illMAX: %d\n",*((int *)&msgbuf.text[21]));
53
54 break;
55 case ...
56 case 10L:
57 default:
58 break;
59
60 }
61 }
62
63 }
64
65 #if 0
66
67 long msgtype;//具体的消息类型
68 消息类型的分配:
69 1L: LED控制
70 2L: 蜂鸣器控制
71 3L: 四路LED灯模拟的数码管
72 4L: 风扇
73 5L: 温湿度最值设置
74 6L-7L-8L-9L,用于个人的扩展
75 10L: 3G通信模块-GPRS
76 switch(msgbuf.msgtype){
77 case 1L: ... break;
78 ....
79 default .... break;
80 }
81 #endif
测试结果: