写在最前面
华清远见教育集团
15年专注高端IT培训
做良心教育,做专业教育,做受人尊敬的职业教育创客学院官网:http://www.makeru.com.cn/
华清远见创客学院嵌入式课程链接:http://www.makeru.com.cn/emb
华清远见创客学院物联网课程链接:http://www.makeru.com.cn/iot
正文
在本文介绍的仓储项目中,用户通过客户端的一些控件实现对向底层硬件发送指令,这一过程是命令数据的下发;用户还可以实时查看到仓库的环境数据,这是数据的上报。总体上分为三个的对象和两条数据流向,网页端-服务器-底层实现命令数据的下发和环境数据的上报,也就实现了人机交互的过程。下面是命令下发部分框图:
目的:完成html 和 CGI 和 用户进程 的交互,实现命令下发并接受到返回结果。随便从程序上加以分析这一过程。
- HTML(超文本标记语言):就是一种标签语言,用来描述资源的。加上CSS渲染,就可以通过浏览器看到成精美的页面了。
- CGI:简单理解是用户进程对html实现的一组接口。
- 用户进程:用户程序在系统上的的执行结果。
实现步骤
1.实现html文件,放在boa服务器的www目录下
2.实现.cgi程序,放在boa服务器的www目录下
3.编写应用程序消息队列处理部分,实现与cgi进行交互
4.在开发板上运行boa服务器,运行应用程序
5.测试结果
关于消息队列的使用,我之前写过一篇介绍:https://mp.csdn.net/postedit/81412616
源码分析
1.html main.html
在浏览器中右键查看源码,显示如下内容。代码的意思是用户点击提交按钮,即提交表单数据到boa服务器目录的cgi-bin/setEnv.cgi处理。
<form action="cgi-bin/setEnv.cgi" method="get"><input name="store" type="hidden" value="1" />
<tr>
<th height="55"><div align="center">
<label>最高温度:
<input type="text" name="temMAX" id="textfield" width="50" maxlength="50" size="10" style="height:10"height="10" onFocus="if(this.value=='*'){this.value='';}" value='50' />
</label>
</div></th>
<th><div align="center">
<label>最高湿度:
<input type="text" name="humMAX" id="textfield3" width="50" size="10" style="height:10"height="10" onFocus="if(this.value=='*'){this.value='';}" value='50'/>
</label>
</div></th>
<th><div align="center">
<label>最高光度:
<input type="text" name="illMAX" id="textfield5" width="50" size="10" style="height:10"height="10" onFocus="if(this.value=='*'){this.value='';}" value='500'/>
</label>
</div></th>
</tr>
<tr>
<th height="55"><div align="center">
<label>最低温度:
<input type="text" name="temMIN" id="textfield2" width="50" size="10" style="height:10"height="10" onFocus="if(this.value=='*'){this.value='';}" value='5'/>
</label>
</div></th>
<th><div align="center">
<label>最低湿度:
<input type="text" name="humMIN" id="textfield4" width="50" size="10" style="height:10"height="10" onFocus="if(this.value=='*'){this.value='';}" value='10'/>
</label>
</div></th>
<th><div align="center">
<label>最低光度:
<input type="text" name="illMIN" id="textfield6" width="50" size="10" style="height:10"height="10" onFocus="if(this.value=='*'){this.value='';}" value='10'/>
</label>
</div></th>
</tr>
<tr>
<th height="50" colspan="3"><div align="center">
<input type="reset" name="button7" style="background-color:transparent" id="button7" value="重置" />
<input type="submit" name="button8" id="button8" value="提交" style="background-color:transparent"/>
</div></th>
</tr>
</form>
2.cgic setenv.c
用户提交表单,执行到这个接口。cgic使用c语言进行实现,一方面从用户提交的表单数据中提取到有效的命令数据,将数据内容放在一个消息结构体msg_buf中;另一方面通过消息队列实现与用户进程/线程间的交互。最后将结果一html文件的形式返回浏览器。
#define N 32
struct msg
{
long type;
long msgtype;
unsigned char text[N];
};
struct setEnv
{
int temMAX;
int temMIN;
int humMAX;
int humMIN;
int illMAX;
int illMIN;
};
int cgiMain()
{
key_t key;
char sto_no[2];
char buf[20];
struct setEnv new;
int msgid;
struct msg msg_buf;
memset(&msg_buf,0,sizeof(msg_buf));
cgiFormString("store", sto_no, 2);
cgiFormString("temMAX", buf, 20); //通过cgic.c提供的接口函数 提取表单数据
new.temMAX = atoi (buf);
cgiFormString("temMIN", buf, 20);
new.temMIN = atoi (buf);
cgiFormString("humMAX", buf, 20);
new.humMAX = atoi (buf);
cgiFormString("humMIN", buf, 20);
new.humMIN = atoi (buf);
cgiFormString("illMAX", buf, 20);
new.illMAX = atoi (buf);
cgiFormString("illMIN", buf, 20);
new.illMIN = atoi (buf);
if((key = ftok("/app", 'g')) < 0)
{
perror("ftok");
exit(1);
}
if((msgid = msgget(key, 0666)) < 0)
{
perror("msgget");
exit(1);
}
memcpy (msg_buf.text+1, &new, 24);
msg_buf.type = 1L;
msg_buf.msgtype = 5L;
msg_buf.text[0] = sto_no[0];
msgsnd(msgid, &msg_buf,sizeof(msg_buf)-sizeof(long),0); //消息队列与应用进程/线程交互
sto_no[0] -= 48;
cgiHeaderContentType("text/html\n\n"); //成功结果通过html文件的形式返回
fprintf(cgiOut, "<HTML><HEAD>\n");
fprintf(cgiOut, "<TITLE>My CGI</TITLE></HEAD>\n");
fprintf(cgiOut, "<BODY>");
fprintf(cgiOut, "<H2>send sucess</H2>");
//fprintf(cgiOut, "<a href='.html'>返回</a>");
fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"1;url=../main%d.html\">", sto_no[0]);
fprintf(cgiOut, "</BODY>\n");
fprintf(cgiOut, "</HTML>\n");
return 0;
}
3.用户处理程序
下面是用户主进程中调度的一个线程,处理消息队列中的请求线程。线程中一直阻塞等待请求,当从队列中接收到消息,表示“我收到了”,然后进行命令的类型判断,做相应的处理。由于底层还没有实现,这里就仅简单的打印处理
void *pthread_client_request (void *arg)
{
printf("pthread_client_request\n");
if((key = ftok("/tmp",'g')) < 0){
perror("ftok failed .\n");
exit(-1);
}
msgid = msgget(key,IPC_CREAT|IPC_EXCL|0666);
if(msgid == -1) {
if(errno == EEXIST){
msgid = msgget(key,0777);
}else{
perror("fail to msgget");
exit(1);
}
}
printf("pthread_client_request\n");
while(1){
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]);
//1L - 5L为线程分类的消息类型
switch(msgbuf.msgtype){
case 1L:
printf("hello led\n");
break;
case 2L:
printf("hello beep\n");
break;
case 3L:
printf("hello seg\n");
break;
case 4L:
printf("hello fan\n");
break;
case 5L:
printf("set env data\n");
printf("temMAX: %d\n",*((int *)&msgbuf.text[1]));
printf("temMIN: %d\n",*((int *)&msgbuf.text[5]));
printf("humMAX: %d\n",*((int *)&msgbuf.text[9]));
printf("humMAX: %d\n",*((int *)&msgbuf.text[13]));
printf("illMAX: %d\n",*((int *)&msgbuf.text[17]));
printf("illMAX: %d\n",*((int *)&msgbuf.text[21]));
break;
case 6L:
pthread_mutex_lock(&mutex_led);
pthread_cond_wait(&cond_led,&mutex_led);
printf("hello led\n");
pthread_mutex_unlock(&mutex_led);
pthread_cond_broadcast(&cond_led);
break;
case 10L:
{
int i = 0 , j = 0 ;
for(i = 0 ; i < 11; i++){
recive_phone[i] = msgbuf.text[i];
}
recive_phone[i] = '\0';
printf("recive:%s\n",recive_phone);
for(j = 0 ;msgbuf.text[i] != '\0' && j < 12; i++, j++)
{
center_phone[j] = msgbuf.text[i];
}
center_phone[j] = '\0';
printf("center:%s\n",center_phone);
}
break;
default:
break;
}
}
}