写在最前面

华清远见教育集团
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>&nbsp;</td>
    <td>&nbsp;</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>