php服务器+pruss初尝甜头+与pruss交换数据+php管道通信
【一、PHP服务器的搭建】
仅仅是花了一会儿的时间,服务器就建立完毕,接下来是php的学习,不得不花点时间,学学网页开发吧。可以简单的编一些代码用于测试什么的。
如何用PHP页面控制小灯?我们来实现一个页面吧……
- <html>
- <head>
- <title>Test Page</title>
- </head>
- <body>
- <?php
- $led = $_REQUEST['led'];
- print("Hello World!");
- echo nl2br("\n");
- print("Led : ");
- echo $led;
- echo nl2br("\n");
- print("sjtitr");
- echo nl2br("\n");
- if($led == 1)
- {
- $file = fopen("/sys/class/gpio/gpio44/value","w");
- if($file)
- {
- fputs($file, "1");
- fclose($file);
- }
- ?>
- <a href="test.php?led=0">LED=0</a>
- <?php
- }
- else
- {
- $file = fopen("/sys/class/gpio/gpio44/value","w");
- if($file)
- {
- fputs($file, "0");
- fclose($file);
- }
- ?>
- <a href="test.php?led=1">LED=1</a>
- <?php
- }
- ?><br>
- </body>
- </html>
[color=rgb(51, 102, 153) !important]复制代码
使用页面以前呢,先通过命令行打开端口的设定。
- echo 44 > /sys/class/gpio/export
- echo out > /sys/class/gpio/gpio44/direction
- echo 1 > /sys/class/gpio/gpio44/value
[color=rgb(51, 102, 153) !important]复制代码
可是PHP如何与内核驱动结合起来呢?另外内核驱动控制小灯,明显频率不稳定,毕竟也参与系统调度中来了,那么如何获取精准的时序控制呢?那楼主第二周就来研究这个问题吧。
【二、pruss初次探秘】
不得不说,之前根本没有关注过BBB的这部分硬件内容。要不是我追求时序上的完美,几乎AM335x的这一利刃都要被我无视了。幸亏楼主孜孜不倦的搜索,终于被我给发现了——这是一个AM335x等芯片上自带的,独立于ARM CPU运行的子系统。其时钟频率为200MHz,可以直接控制特定的IO口,可以达到非常高的实时性要求。一般两种情况需要用到它:一是linux系统的实时性不满足要求的时候;二是芯片的功能模块不够用的时候(比如你想要10个UART,但芯片上只有6个,那你可以用它再创造4个)。
楼主比较懒,所以还是先用命令行把端口设置妥当:
- echo 44 > /sys/class/gpio/export
- echo out > /sys/class/gpio/gpio44/direction
- echo 1 > /sys/class/gpio/gpio44/value
[color=rgb(51, 102, 153) !important]复制代码
之后pru只需要控制输出值的0、1就可以了。
- //prucode.p
- .origin 0
- .entrypoint START
- //Refer to this mapping in the file - prussdrvincludepruss_intc_mapping.h
- #define PRU0_ARM_INTERRUPT 19
- #define CONST_PRUCFG C4
- //Refer to AM335X Technical Reference Manual & BBB SRM
- #define GPIO1 0x4804c000
- #define GPIO_CLEARDATAOUT 0x190
- #define GPIO_SETDATAOUT 0x194
- START:
- // Enable OCP master port
- LBCO r0, CONST_PRUCFG, 4, 4
- CLR r0, r0, 4 // Clear SYSCFG[STANDBY_INIT] to enable OCP master port
- SBCO r0, CONST_PRUCFG, 4, 4
- MOV r1, 3 // loop 3 times
- LOOP0:
- MOV r2, 1<<12
- MOV r3, GPIO1 | GPIO_SETDATAOUT
- SBBO r2, r3, 0, 4
- MOV r0, 20000000
- DEL1:
- SUB r0, r0, 1
- QBNE DEL1, r0, 0
- MOV r2, 1<<12
- MOV r3, GPIO1 | GPIO_CLEARDATAOUT
- SBBO r2, r3, 0, 4
- MOV r0, 20000000
- DEL2:
- SUB r0, r0, 1
- QBNE DEL2, r0, 0
- SUB r1, r1, 1
- QBNE LOOP0, r1, 0
- // Send notification to Host for program completion
- MOV r31.b0, PRU0_ARM_INTERRUPT+16
- // Halt the processor
- HALT
[color=rgb(51, 102, 153) !important]复制代码
真不骗人,我敢贴出代码,就是因为这代码我改过了,即便是那么一点点修改,也要翻看各种手册才得以确认。
就是这段代码,参考原文编译加载执行,就能看到我们前面一辑里描述的小灯一闪一闪亮3次啦,时间上嘛,相当精准。
但是要实现利用这代码来控制实现红外线遥控器波形,恐怕还得挨些累呀。所以必须要继续研究。
【三、与pruss交换数据】
想用pruss控制波形,第一件麻烦事就是要发送的数据由C语言程序传递到pru程序。在这一研究过程中,了解到的东西远不止这几个数据。简单说,其实pru使用的空间(无论数据还是代码),都存在在我们的flat内存空间上。所以只要找对地方,把数据写入。
- //mytest.c
- #include <stdio.h>
- #include <prussdrv.h>
- #include <pruss_intc_mapping.h>
- #define PRU_NUM 0
- int main (void)
- {
- unsigned int ret;
- tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;
- prussdrv_init ();//Initialize the PRU
- if (prussdrv_open(PRU_EVTOUT_0))//Open PRU Interrupt
- {
- printf("prussdrv_open open failed");
- return (-1);
- }
- prussdrv_pruintc_init(&pruss_intc_initdata);
- {
- unsigned int v = 10;
- prussdrv_pru_write_memory(PRUSS0_PRU0_DATARAM, 0, &v, 4);
- }
- prussdrv_exec_program (PRU_NUM, "./prucode.bin");//Execute example on PRU
- prussdrv_pru_wait_event (PRU_EVTOUT_0);//Waiting for this instruction: MOV r31.b0, PRU0_ARM_INTERRUPT+16
- prussdrv_pru_clear_event (PRU0_ARM_INTERRUPT,0);
- prussdrv_pru_disable (PRU_NUM);//Disable PRU and close memory mapping
- prussdrv_exit ();
- return(0);
- }
[color=rgb(51, 102, 153) !important]复制代码
注意到其中的
- {
- unsigned int v = 10;
- prussdrv_pru_write_memory(PRUSS0_PRU0_DATARAM, 0, &v, 4);
- }
[color=rgb(51, 102, 153) !important]复制代码
这就是向pru单元写入数据(事实上传程序进去,也是类似的就这样一个实质上的数据copy)。
而我们在pru中,则先对数据进行一个简单分析——再确定闪灯的次数。
- //prucode.p
- .origin 0
- .entrypoint START
- //Refer to this mapping in the file - prussdrvincludepruss_intc_mapping.h
- #define PRU0_ARM_INTERRUPT 19
- #define CONST_PRUCFG C4
- //Refer to AM335X Technical Reference Manual & BBB SRM
- #define GPIO1 0x4804c000
- #define GPIO_CLEARDATAOUT 0x190
- #define GPIO_SETDATAOUT 0x194
- START:
- // Enable OCP master port
- LBCO r0, CONST_PRUCFG, 4, 4
- CLR r0, r0, 4 // Clear SYSCFG[STANDBY_INIT] to enable OCP master port
- SBCO r0, CONST_PRUCFG, 4, 4
- //MOV r1, 3 // loop 3 times
- MOV r2, 0
- LBBO r1, r2, 0, 4
- LOOP0:
- MOV r2, 1<<12
- MOV r3, GPIO1 | GPIO_SETDATAOUT
- SBBO r2, r3, 0, 4
- MOV r0, 20000000
- DEL1:
- SUB r0, r0, 1
- QBNE DEL1, r0, 0
- MOV r2, 1<<12
- MOV r3, GPIO1 | GPIO_CLEARDATAOUT
- SBBO r2, r3, 0, 4
- MOV r0, 20000000
- DEL2:
- SUB r0, r0, 1
- QBNE DEL2, r0, 0
- SUB r1, r1, 1
- QBNE LOOP0, r1, 0
- // Send notification to Host for program completion
- MOV r31.b0, PRU0_ARM_INTERRUPT+16
- // Halt the processor
- HALT
[color=rgb(51, 102, 153) !important]复制代码
这个pru的成功,令楼主很是兴奋。不过,之后的,如何能把pru结合到内核驱动里去,却另楼主很是挠头。好在,两天后,楼主想通了。
控制红外线的时序,交给pru就好啦,根本没必要再加一个内核驱动了。剩下的事,无非就是,应用程序从php获取数据,然后传递给pru,再让pru执行生成红外线时序的代码咯。
于是楼主的设计方案就变了。
【四、PHP通过命名管道和应用程序交换数据】
最后一件事呢,无疑就是PHP怎样把数据交给到应用程序里了。这里不知怎的,楼主是很自然的就想到用命名管道。于是针对这个内容的调查研究很快就展开了。
学习过程省略,首先实现一个监听程序:这里做了个很简单的协议啦。
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define FIFO "/tmp/irfifo"
- int main(int argc, char** argv)
- {
- char buf[64];
- int fd;
- int nread;
- if((mkfifo(FIFO, O_CREAT|O_EXCL)<0) && (errno!=EEXIST))
- {
- printf("cannot create fifo\n");
- }
- fd = open(FIFO, O_RDONLY);
- if(fd==-1)
- {
- printf("cannot open fifo\n");
- exit(1);
- }
- while(1)
- {
- int i = 0;
- memset(buf, 0, sizeof(buf));
- read(fd, buf, 1);
- if(buf[0]!=0x5A)
- {
- // printf("%X,", buf[0]);
- continue;
- }
- read(fd, buf, 1);
- if(buf[0] == 0)
- {
- break;
- }
- read(fd, &buf[1], buf[0]);
- printf("%d: ", buf[0]);
- while(i < buf[0])
- {
- i++;
- printf("%X,",buf);
- }
- printf("\n");
- }
- unlink(FIFO);
- exit(0);
- }
[color=rgb(51, 102, 153) !important]复制代码
其次,不要着急PHP,再写个工作程序给监听程序送些试验数据:很简单,执行时候的第一个参数字符串和它的长度作为内容传递给pipe
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define FIFO "/tmp/irfifo"
- int main(int argc, char** argv)
- {
- char buf[64];
- int fd;
- int nread;
- fd = open(FIFO, O_WRONLY);
- if(fd==-1)
- {
- printf("cannot open fifo\n");
- exit(1);
- }
- buf[0] = 0x5A;
- if(argc <=1)
- {
- buf[1] = 0;
- }
- else
- {
- buf[1] = strlen(argv[1]);
- memcpy(&buf[2], argv[1], buf[1]);
- }
- if(write(fd, &buf[0], buf[1]+2)==-1)
- {
- printf("error\n");
- }
- close(fd);
- exit(0);
- }
[color=rgb(51, 102, 153) !important]复制代码
这不是完美程序。完美还有很远的路要走。
经过试验,确信监听程序可用了。太好了,接下来我们才准备PHP。
这下可遇到麻烦了,php里面写文件全是用字符串么?唉,对PHP还是不够了解呀……继续学!
于是了解到如果利用php处理字节流数据……很好很强大……pack函数。
随后,终于形成了php的测试页面,可以把字节流传递给pipe文件。
- <html>
- <head>
- <title>Test Pipe Page</title>
- </head>
- <body>
- <?php
- $str = $_REQUEST['str'];
- $fp = @fopen("////tmp//irfifo", 'w');
- echo $fp;
- echo nl2br("\n");
- $num = 0x5a;
- $data = pack("H2", "5a");
- echo @fwrite($fp, $data);
- echo nl2br("\n");
- $data = pack("C1", strlen($str)/2);
- echo @fwrite($fp, $data);//D′
- echo nl2br("\n");
- $data = pack("H*", $str);
- echo @fwrite($fp,$data);//D′
- echo nl2br("\n");
- fclose($fp);
- echo nl2br("\n");
- print("Hello World!");
- echo nl2br("\n");
- print("sjtitr");
- echo nl2br("\n");
- ?>
- </body>
- </html>
[color=rgb(51, 102, 153) !important]复制代码
|