写在最前面
华清远见教育集团
15年专注高端IT培训
做良心教育,做专业教育,做受人尊敬的职业教育创客学院官网:http://www.makeru.com.cn/
华清远见创客学院嵌入式课程链接:http://www.makeru.com.cn/emb
华清远见创客学院物联网课程链接:http://www.makeru.com.cn/iot
正文
在本文介绍的仓储项目中,用户通过客户端的一些控件实现对向底层硬件发送指令,这一过程是命令数据的下发;用户还可以实时查看到仓库的环境数据,这是数据的上报。总体上分为三个的对象和两条数据流向,网页端-服务器-底层实现命令数据的下发和环境数据的上报,也就实现了人机交互的过程。下面是数据上报部分框图:
目的:完成html 和 CGI 和 用户进程 的交互,实现数据上报到html端。随便从程序上加以分析这一过程。
实现步骤
1.实现html文件,放在boa服务器的www目录下
2.实现.cgi程序,放在boa服务器的www目录下
3.编写应用程序上报线程,实现与cgi进行交互
4.在开发板上运行boa服务器,并运行应用程序
5.测试结果
共享内存:https://blog.csdn.net/feit2417/article/details/81412102
信号量:https://blog.csdn.net/feit2417/article/details/81429031
源码分析
处理上报的线程
通过共享内存实现与CGI那边数据的共享,为了避免使用冲突(同时对共享内存读写),有引入信号量实现互斥机制。这里还没有对底层获取数据的处理,就先使用写死的数值,模拟进行上报操作。
这里实现每隔1s对共享内存写一次数据,即上报一次。
#include "data_global.h"
#include "sem.h"
#define N 1024 //for share memory
extern int shmid;
extern int msgid;
extern int semid;
extern key_t shm_key;
extern key_t sem_key;
extern key_t key; //msg_key
extern pthread_mutex_t mutex_client_request,
mutex_refresh,
mutex_sqlite,
mutex_transfer,
mutex_analysis,
mutex_sms,
mutex_buzzer,
mutex_led,
mutex_camera;
extern pthread_cond_t cond_client_request,
cond_refresh,
cond_sqlite,
cond_transfer,
cond_analysis,
cond_sms,
cond_buzzer,
cond_led,
cond_camera;
extern struct env_info_clien_addr all_info_RT;
struct shm_addr
{
char cgi_status;
char qt_status;
struct env_info_clien_addr rt_status;
};
struct shm_addr *shm_buf;
int file_env_info_struct(struct env_info_clien_addr *rt_status,int storage_id);
//static char *my_itoa(int n);
//static char *reverse(char *s);
//更新共享内存里的实时数据
void *pthread_refresh(void *arg)
{
//semaphore for access to resource limits
if((sem_key = ftok("/tmp",'i')) < 0){
perror("ftok failed .\n");
exit(-1);
}
semid = semget(sem_key,1,IPC_CREAT|IPC_EXCL|0666);
if(semid == -1) {
if(errno == EEXIST){
semid = semget(sem_key,1,0777);
}else{
perror("fail to semget");
exit(1);
}
}else{
init_sem (semid, 0, 1);
}
//share memory for env_info refresh config
if((shm_key = ftok("/tmp",'i')) < //这里确保与CGI程序使用的是同个 key
perror("ftok failed .\n");
exit(-1);
}
shmid = shmget(shm_key,N,IPC_CREAT|IPC_EXCL|0666);
if(shmid == -1) {
if(errno == EEXIST){
shmid = shmget(key,N,0777);
}else{
perror("fail to shmget");
exit(1);
}
}
//share memap
if((shm_buf = (struct shm_addr *)shmat(shmid,NULL,0)) == (void *)-1)
{
perror("fail to shmat");
exit(1);
}
printf("pthread_refresh ......>>>>>>>\n");
bzero (shm_buf, sizeof (struct shm_addr));
while(1){ //实现每隔1s写一次数据,确保与其他读写操作是互斥的
sem_p(semid,0);
file_env_info_struct(&shm_buf->rt_status,1);
sleep(1);
sem_v(semid,0);
}
}
//把数据'写死',就不用底层实现了
int file_env_info_struct(struct env_info_clien_addr *rt_status,int storage_id)
{
int env_info_size = sizeof(struct env_info_clien_addr);
rt_status->storage_no[storage_id].storage_status = 0x01;
rt_status->storage_no[storage_id].led_status = 0x02;
rt_status->storage_no[storage_id].buzzer_status = 0x03;
rt_status->storage_no[storage_id].fan_status = 0x04;
rt_status->storage_no[storage_id].seg_status = 0x05;
rt_status->storage_no[storage_id].x = 10;
rt_status->storage_no[storage_id].y = -20;
rt_status->storage_no[storage_id].z = 30;
rt_status->storage_no[storage_id].temperature = 10.0;
rt_status->storage_no[storage_id].temperatureMIN = 2.0;
rt_status->storage_no[storage_id].temperatureMAX = 20.0;
rt_status->storage_no[storage_id].humidity = 20.0;;
rt_status->storage_no[storage_id].humidityMIN = 10.0;;
rt_status->storage_no[storage_id].humidityMAX = 30.0;;
rt_status->storage_no[storage_id].illumination = 20.0;;
rt_status->storage_no[storage_id].illuminationMIN = 10.0;;
rt_status->storage_no[storage_id].illuminationMAX = 50.0;;
rt_status->storage_no[storage_id].battery =90.0;;
rt_status->storage_no[storage_id].adc = 40.0;;
return 0;
}
CGI完成对HTML的同步更新
env1.cgi处理程序先通过ftok操作,获取到与应用层的线程相同的的共享内存,然后在信号量的控制下进行读操作。读到的数据写入html文件中,用来刷新用户页面看到的数据。
/***********************
省略一堆头文件include
**************************/
#include "sem.h"
#include "cgic.h"
#include "data_global.h"
#define N 32
#define STO_NO 1
char status[2][6] = {"Close", "Open"};
char fan_status[4][6] = {"Close", "One", "Two", "Three"};
struct shm_addr
{
char cgi_status;
char qt_status;
struct env_info_clien_addr rt_status;
};
int cgiMain()
{
key_t key;
int shmid,semid;
struct shm_addr *shm_buf;
if((key = ftok("/tmp",'i')) <0)
{
perror("ftok");
exit(1);
}
printf("key = %x\n",key);
if((semid = semget(key, 1, 0666)) < 0)
{
perror("semget");
exit(1);
}
if((shmid = shmget(key, N, 0666 )) == -1)
{
perror("shmget");
exit(1);
}
if((shm_buf = (struct shm_addr*)shmat(shmid, NULL, 0)) == (void*)-1 )
{
perror("shmat");
exit(1);
}
sem_p(semid,0);
/***********************
省略一堆写html文件的操作
**************************/
sem_v (semid, 0);
return 0;
}
html实现界面
实现我们看到的界面,在其中一个子板块指定从env1.cgi中获取源码,就是我们看到 不断刷新页面的结果了。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>仓库一环境信息</title>
</head>
<body>
<body background="./images/huaqing002.jpg">
</div>
<table width="912" border="0" height="173" background="./images/huaqing2.jpg" align="center">
<tr>
<td> </td>
<td> </td>
</tr>
</table><table width="912" border="1" align="center">
<tr>
<td width="476"><div align="center"><h3>环境信息</h3></div></td>
<td width="420"><div align="center"><a href="main1.html"><h3>回主页</h3></a></div></td>
</tr>
</table>
<table width="912" height="511" border="1" align="center" >
<tr>
<td width="203" background="./images/huaqing9.jpg"></td>
<td width="432"><iframe src="cgi-bin/env1.cgi" height="500" width="518" align="middle"></iframe></td>
<td width="203" background="./images/huaqing10.jpg"></td>
</tr>
</table>
</body>
</html>