一、数据刷新
在主框架中可以看到数据刷新线程: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. ",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: %0.2f</H4> ", shm_buf->sm_all_env_info.monitor_no[shm_buf->shm_status].zigbee_info.temperature ); 39 ... 40 fprintf(cgiOut, "<h4>A9数据显示部分</H4> "); 41 fprintf(cgiOut, "<h4>Adc: %0.2f</H4> ", shm_buf->sm_all_env_info.monitor_no[shm_buf->shm_status].a9_info.adc); 42 ... 43 fprintf(cgiOut, "<h4>A9-RESERVED[1]: %d</H4> ", shm_buf->sm_all_env_info.monitor_no[shm_buf->shm_status].a9_info.reserved[1]); 44 45 fprintf(cgiOut, "<h4>......</H4> "); 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 "); 51 fprintf(cgiOut, "<HTML><HEAD> "); 52 fprintf(cgiOut, "<TITLE>My CGI</TITLE></HEAD> "); 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> "); 60 fprintf(cgiOut, "</HTML> "); 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... "); 29 //从消息队列接收消息 30 msgrcv (msgid, &msgbuf, sizeof (msgbuf) - sizeof (long), 1L, 0); 31 printf ("Get %ldL msg ", msgbuf.msgtype); 32 printf ("text[0] = %#x ", msgbuf.text[0]); 33 34 //对消息进行判断进而去调用不同的线程处理 35 switch(msgbuf.msgtype){ 36 case 1L: 37 printf("hello led "); 38 break; 39 case 2L: 40 printf("hello beep "); 41 break; 42 case 3L: 43 printf("hello seg "); 44 break; 45 case 4L: 46 printf("hello fan "); 47 break; 48 case 5L: 49 printf("set env data "); 50 printf("temMAX: %d ",*((int *)&msgbuf.text[1])); 51 ... 52 printf("illMAX: %d ",*((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
测试结果: