网页控制IO分析

MINI2440 ARM开发板可以跑HTTP服务器,因此可以在上面开发一些web应用。比如做一个简单的LED灯控制页面。在PC浏览器可以访问开发板上的网页,这样可以远程控制开发板上的LED或者其他所有的IO口,甚至可以视频监控。

友善之臂公司开发了一个这样的例子,可以在网页上控制LED跑马灯的运行速度。现在笔者尝试对其中所用到的技术和整个的流程逻辑进行分析。

图片


IPC

开机后通过网页发送命令控制开发板上的LED闪烁模式,是IPC共享资源的一个典型例子。IPC(Inter-Process Communication)进程间通信,提供了各种进程间通信的方法。

进程间通信的目的一般有: 1) 数据传输 2) 共享数据 3) 通知事件 4) 资源共享 5) 进程控制

这里采用的通信机制是管道(Pipe)。


先看最简单的html

先看网页文件

<td colspan="2" align="center"><form method="get" action="leds.cgi" name="LED-TEST">
   <div align="left">
      <table border="0" width="280" align="center">
        <tr>
          <td width="131">
            <p align="center">类型</td>
            <td width="135">
              <p align="center">速率</td>
          </tr>
        <tr>
          <td width="131">
            <p align="center">&nbsp; <input type="radio" value="ping" checked name="type">跑马灯</td>
            <td width="135">
              <p align="center"><input type="radio" name="speed" value="slow" checked>慢速</td>
          </tr>
        <tr>
          <td width="131">
            <p align="center">&nbsp; <input type="radio" name="type" value="counter">计数器</td>
            <td width="135">
              <p align="center"><input type="radio" name="speed" value="normal">中速</td>
          </tr>
        <tr>
          <td width="131">
            <p align="center"><input type="radio" name="type" value="stop">停止</td>
            <td width="135">
              <p align="center"><input type="radio" name="speed" value="fast">高速</td>
          </tr>
        <tr>
          <td colspan="2" width="272">
            <p align="center"><input type="submit" value="确定(OK)" name="submit"></td>
        </tr>
      </table>
     </div>
    <div align="center"></div><div align="center"></div><div align="left"></div><div align="left"></div></form> </td>

可以看到采用get方法传参数,submit调用leds.cgi(shell脚本)程序,把radio框的参数传递到脚本中。


CGI调用

CGI是公共网关接口(Common Gateway Interface),是外部应用程序(leds-player.c)和web服务器(index.html)之间的接口标准。

case $QUERY_STRING in
        *slow*)
                period=0.25
                ;;
        *normal*)
                period=0.125
                ;;
        *normal*)
                period=0.0625
                ;;
esac

/bin/echo $type $period > /tmp/led-control

由submit传来的slow normal normal参数在这里进行解析赋给变量period,最后把参数以字符串的形式写入到管道文件/tmp/led-control。这个管道文件是在leds-player.c中创建的。


管道创建

使用命令mkfifo("/tmp/led-control", 0666)创建命令管道。

for (;;) {
                fd_set rds;
		struct timeval step;
		int ret;

		FD_ZERO(&rds);
		FD_SET(led_control_pipe, &rds);
		step.tv_sec  = period;
		step.tv_usec = (period - step.tv_sec) * 1000000L;

		ret = select(led_control_pipe + 1, &rds, NULL, NULL, &step);
		if (ret < 0) {
			perror("select");
			exit(1);
		}
		if (ret == 0) {
			push_leds();
		} else if (FD_ISSET(led_control_pipe, &rds)) {
			static char buffer[200];
			for (;;) {
				char c;
				int len = strlen(buffer);
				if (len >= sizeof buffer - 1) {
					memset(buffer, 0, sizeof buffer);
					break;
				}
				if (read(led_control_pipe, &c, 1) != 1) {
					break;
				}
				if (c == '\r') {
					continue;
				}
				if (c == '\n') {
					int tmp_type;
					double tmp_period;
					if (sscanf(buffer,"%d%lf", &tmp_type, &tmp_period) == 2) {
						type = tmp_type;
						period = tmp_period;
					}
					fprintf(stderr, "type is %d, period is %lf\n", type, period);
					memset(buffer, 0, sizeof buffer);
					break;
				}
				buffer[len] = c;
			}
		}
	}

接着就在一个for循环中监听管道中的参数变换,一旦变化调用push_leds()对led进行操作。操作的方法是ioctl操作/dev下的leds驱动。核心代码只有一句话ioctl(led_fd, led_bitmap & 1, i)

整个控制逻辑的流程图如下:

图片


Reference



Previous     Next
/
Published under (CC) BY-NC-SA in categories arm  tagged with