打印

php服务器+pruss初尝甜头+与pruss交换数据+php管道通信

[复制链接]
530|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Violin11|  楼主 | 2017-9-29 11:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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系统的实时性不满足要求的时候;二是芯片的功能模块不够用的时候(比如你想要10UART,但芯片上只有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]复制代码


相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

717

主题

1010

帖子

3

粉丝