Improved sysfs file access code
This commit is contained in:
		| @@ -15,28 +15,16 @@ try { | |||||||
| $gpio->setMapper( new WiringPiMapper(2) ); | $gpio->setMapper( new WiringPiMapper(2) ); | ||||||
|  |  | ||||||
| // Access logical pin 0, since we got a mapper assigned. Otherwise this would | // Access logical pin 0, since we got a mapper assigned. Otherwise this would | ||||||
| // be the actual GPIO0 pin. | // be the actual GPIO0 pin.  | ||||||
| $led = $gpio[0] | $led = $gpio[0] | ||||||
|     ->export() |     ->export() | ||||||
|     ->setDirection("output") |     ->setDirection("output") | ||||||
|     ->setValue(0) |     ->setValue(0) | ||||||
|     ->setLabel("red led") |  | ||||||
|     ->dumpStatus(true); |     ->dumpStatus(true); | ||||||
|  |  | ||||||
| $btn1 = $gpio[1] | $x = 0; | ||||||
|     ->setDirection("input") | while(true) { | ||||||
|     ->setValue(0) |     $x = (int)(!$x); | ||||||
|     ->setEdge("rising") |     $led->setValue($x); | ||||||
|     ->setHandler(function() { echo "INTERRUPT!\n"; }) |     usleep(500000); | ||||||
|     ->setLabel("button 1") | } | ||||||
|     ->dumpStatus(true); |  | ||||||
|  |  | ||||||
| $btn2 = $gpio[2] |  | ||||||
|     ->setDirection("input") |  | ||||||
|     ->setValue(0) |  | ||||||
|     ->setEdge("rising") |  | ||||||
|     ->setHandler(function() { echo "INTERRUPT!\n"; }) |  | ||||||
|     ->setLabel("button 2") |  | ||||||
|     ->dumpStatus(true); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										42
									
								
								examples/buttons.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								examples/buttons.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | require_once __DIR__."/../vendor/autoload.php"; | ||||||
|  |  | ||||||
|  | use NoccyLabs\Gpio\Gpio; | ||||||
|  | use NoccyLabs\Gpio\GpioMapper\WiringPiMapper; | ||||||
|  |  | ||||||
|  | try { | ||||||
|  |     $gpio = new Gpio(); | ||||||
|  | } catch (Gpio\Exception $e) { | ||||||
|  |     error_log("Error: {$e}"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // The mapper translates GPIO to logical pins and vice versa | ||||||
|  | $gpio->setMapper( new WiringPiMapper(2) ); | ||||||
|  |  | ||||||
|  | // Access logical pin 0, since we got a mapper assigned. Otherwise this would | ||||||
|  | // be the actual GPIO0 pin. | ||||||
|  | $led = $gpio[0] | ||||||
|  |     ->export() | ||||||
|  |     ->setDirection("output") | ||||||
|  |     ->setValue(0) | ||||||
|  |     ->setLabel("red led") | ||||||
|  |     ->dumpStatus(true); | ||||||
|  |  | ||||||
|  | $btn1 = $gpio[1] | ||||||
|  |     ->setDirection("input") | ||||||
|  |     ->setValue(0) | ||||||
|  |     ->setEdge("rising") | ||||||
|  |     ->setHandler(function() { echo "INTERRUPT!\n"; }) | ||||||
|  |     ->setLabel("button 1") | ||||||
|  |     ->dumpStatus(true); | ||||||
|  |  | ||||||
|  | $btn2 = $gpio[2] | ||||||
|  |     ->setDirection("input") | ||||||
|  |     ->setValue(0) | ||||||
|  |     ->setEdge("rising") | ||||||
|  |     ->setHandler(function() { echo "INTERRUPT!\n"; }) | ||||||
|  |     ->setLabel("button 2") | ||||||
|  |     ->dumpStatus(true); | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -2,6 +2,21 @@ | |||||||
|  |  | ||||||
| require_once __DIR__."/../vendor/autoload.php"; | require_once __DIR__."/../vendor/autoload.php"; | ||||||
|  |  | ||||||
|  | /*  | ||||||
|  |  * This example demonstrates using a 4-button wireless remote control with the | ||||||
|  |  * GPIO, in this case with the pins mapped against WiringPi for a Rev2 board. | ||||||
|  |  * If you are using this code with any other hardware, please update the mapper | ||||||
|  |  * below. | ||||||
|  |  * | ||||||
|  |  * It is assumed that Pin 0 is the interrupt pin (VT) to signal when a button | ||||||
|  |  * press has been received, and Pin 1-4 are connected to the pins for button | ||||||
|  |  * A to D on the remote control. | ||||||
|  |  * | ||||||
|  |  * Note that the Raspberry Pi GPIO is not 5V tolerant, so use an optoisolator | ||||||
|  |  * or transistors to ensure that you don't zap your preciouos hardware. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
| use NoccyLabs\Gpio\Gpio; | use NoccyLabs\Gpio\Gpio; | ||||||
| use NoccyLabs\Gpio\GpioMapper\WiringPiMapper; | use NoccyLabs\Gpio\GpioMapper\WiringPiMapper; | ||||||
|  |  | ||||||
| @@ -21,7 +36,12 @@ $led = $gpio[0] | |||||||
|     ->setDirection("input") |     ->setDirection("input") | ||||||
|     ->setEdge("rising") |     ->setEdge("rising") | ||||||
|     ->setHandler(function($e) use($gpio) { |     ->setHandler(function($e) use($gpio) { | ||||||
|          |             if ($gpio[1]->getValue()) { echo "A"; } | ||||||
|  |         elseif ($gpio[2]->getValue()) { echo "B"; } | ||||||
|  |         elseif ($gpio[3]->getValue()) { echo "C"; } | ||||||
|  |         elseif ($gpio[4]->getValue()) { echo "D"; } | ||||||
|  |         else { echo "None"; } | ||||||
|  |         echo "\n"; | ||||||
|     }) |     }) | ||||||
|     ->setLabel("rfint") |     ->setLabel("rfint") | ||||||
|     ->dumpStatus(true); |     ->dumpStatus(true); | ||||||
| @@ -33,3 +53,7 @@ for($n = 1; $n < 5; $n++) { | |||||||
|         ->dumpStatus(true); |         ->dumpStatus(true); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | while(true) { | ||||||
|  |     $gpio->refresh(); | ||||||
|  |     usleep(10000); | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										36
									
								
								lib/Gpio.php
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								lib/Gpio.php
									
									
									
									
									
								
							| @@ -23,6 +23,18 @@ use NoccyLabs\Gpio\Exception\HardwareException; | |||||||
|  |  | ||||||
| class Gpio implements \ArrayAccess | class Gpio implements \ArrayAccess | ||||||
| { | { | ||||||
|  |     // Direction | ||||||
|  |     const DIR_IN       = "in"; | ||||||
|  |     const DIR_OUT      = "out"; | ||||||
|  |     // Values | ||||||
|  |     const VAL_HIGH     = 1; | ||||||
|  |     const VAL_LOW      = 0; | ||||||
|  |     // Edges | ||||||
|  |     const EDGE_NONE    = "none"; | ||||||
|  |     const EDGE_RISING  = "rising"; | ||||||
|  |     const EDGE_FALLING = "faling"; | ||||||
|  |     const EDGE_BOTH    = "both"; | ||||||
|  |  | ||||||
|     protected $gpio = array(); |     protected $gpio = array(); | ||||||
|      |      | ||||||
|     /** @var NoccyLabs\Gpio\GpioMapperInterface */ |     /** @var NoccyLabs\Gpio\GpioMapperInterface */ | ||||||
| @@ -51,7 +63,29 @@ class Gpio implements \ArrayAccess | |||||||
|             $pin->doInterrupt(); |             $pin->doInterrupt(); | ||||||
|          |          | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|      |      | ||||||
|  |     public function getPinFromFd($fd) | ||||||
|  |     { | ||||||
|  |         foreach($this->fd_pins as $pinfd=>$pin) { | ||||||
|  |             if ($pinfd == $fd) { return $pin; } | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     protected $fd_gpio = array(); | ||||||
|  |     protected $fd_pins = array(); | ||||||
|  |      | ||||||
|  |     public function enableInterrupt(GpioPin $pin, $fd) | ||||||
|  |     { | ||||||
|  |         $this->fd_gpio[] = $fd; | ||||||
|  |          | ||||||
|  |         $this->fd_pins[$fd] = $pin; | ||||||
|  |          | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     public function disableInterrupt(GpioPin $pin) | ||||||
|  |     { | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     public function setMapper(GpioMapperInterface $mapper=null) |     public function setMapper(GpioMapperInterface $mapper=null) | ||||||
| @@ -64,7 +98,7 @@ class Gpio implements \ArrayAccess | |||||||
|     { |     { | ||||||
|         if ($this->mapper) { $index = $this->mapper->mapLogicalToGpioPin($index); } |         if ($this->mapper) { $index = $this->mapper->mapLogicalToGpioPin($index); } | ||||||
|         if (empty($this->gpio[$index])) { |         if (empty($this->gpio[$index])) { | ||||||
|             $this->gpio[$index] = new GpioPin($index); |             $this->gpio[$index] = new GpioPin($index, $this); | ||||||
|         } |         } | ||||||
|         return $this->gpio[$index]; |         return $this->gpio[$index]; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -19,6 +19,8 @@ | |||||||
|  |  | ||||||
| namespace NoccyLabs\Gpio; | namespace NoccyLabs\Gpio; | ||||||
|  |  | ||||||
|  | use NoccyLabs\Gpio\Exception\HardwareException; | ||||||
|  |  | ||||||
| use NoccyLabs\Sansi\Charset as CS; | use NoccyLabs\Sansi\Charset as CS; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -41,10 +43,13 @@ class GpioPin | |||||||
|     protected $handler; |     protected $handler; | ||||||
|  |  | ||||||
|     protected $label; |     protected $label; | ||||||
|  |      | ||||||
|  |     protected $gpio; | ||||||
|  |  | ||||||
|     public function __construct($pin) |     public function __construct($pin, Gpio $gpio) | ||||||
|     { |     { | ||||||
|         $this->pin = (int)$pin; |         $this->pin = (int)$pin; | ||||||
|  |         $this->gpio = $gpio; | ||||||
|         $this->export(); |         $this->export(); | ||||||
|         $this->fd = fopen("/sys/class/gpio/gpio{$pin}/value", "rb"); |         $this->fd = fopen("/sys/class/gpio/gpio{$pin}/value", "rb"); | ||||||
|     } |     } | ||||||
| @@ -80,13 +85,24 @@ class GpioPin | |||||||
|     { |     { | ||||||
|         return $this->value; |         return $this->value; | ||||||
|     } |     } | ||||||
|      |  | ||||||
|  |     /** | ||||||
|  |      * Set a descriptive label for the pin, used for debugging and troubleshooting. | ||||||
|  |      * | ||||||
|  |      * @param string $label | ||||||
|  |      * @return NoccyLabs\Gpio\GpioPin  | ||||||
|  |      */     | ||||||
|     public function setLabel($label) |     public function setLabel($label) | ||||||
|     { |     { | ||||||
|         $this->label = (string)$label; |         $this->label = (string)$label; | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     /** | ||||||
|  |      * Get the assigned label for this pin. | ||||||
|  |      * | ||||||
|  |      * @return string The label | ||||||
|  |      */     | ||||||
|     public function getLabel() |     public function getLabel() | ||||||
|     { |     { | ||||||
|         return $this->label; |         return $this->label; | ||||||
| @@ -94,9 +110,9 @@ class GpioPin | |||||||
|      |      | ||||||
|     public function export() |     public function export() | ||||||
|     { |     { | ||||||
|         @file_put_contents("/sys/class/gpio/export", $this->pin); |         $this->sysfsWrite(null, "export", $this->pin); | ||||||
|         if (!file_exists("/sys/class/gpio/gpio{$this->pin}")) { |         if (!file_exists("/sys/class/gpio/gpio{$this->pin}")) { | ||||||
|             throw new \Exception(); |             throw new HardwareException("Unable to export pin {$this->pin}"); | ||||||
|         } |         } | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
| @@ -107,23 +123,54 @@ class GpioPin | |||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     public function sysfsWrite($pin, $file, $value) | ||||||
|  |     { | ||||||
|  |         if ($pin) { | ||||||
|  |             $path = "/sys/class/gpio/gpio{$pin}/{$file}"; | ||||||
|  |         } else { | ||||||
|  |             $path = "/sys/class/gpio/{$file}"; | ||||||
|  |         } | ||||||
|  |         if (!is_writable($path)) { | ||||||
|  |             throw new HardwareException("Sysfs file {$path} not writable"); | ||||||
|  |         } | ||||||
|  |         $f = fopen($path,"w+"); | ||||||
|  |         if (!is_resource($f)) { | ||||||
|  |             throw new HardwareException("Unable to write to sysfs file {$path}"); | ||||||
|  |         } | ||||||
|  |         fwrite($f,$value); | ||||||
|  |         fclose($f); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     public function sysfsRead($pin, $file) | ||||||
|  |     { | ||||||
|  |         $path = "/sys/class/gpio/gpio{$pin}/{$file}"; | ||||||
|  |         $f = fopen($path,"r"); | ||||||
|  |         if (!is_resource($f)) { | ||||||
|  |             throw new HardwareException("Unable to read from sysfs file {$path}"); | ||||||
|  |         } | ||||||
|  |         $ret = fgets($f); | ||||||
|  |         fclose($f); | ||||||
|  |         return $ret; | ||||||
|  |     } | ||||||
|  |      | ||||||
|     public function setEdge($edge) |     public function setEdge($edge) | ||||||
|     { |     { | ||||||
|         if (!in_array($edge, array("rising", "falling", "both", "none"))) { |         if (!in_array($edge, array("rising", "falling", "both", "none"))) { | ||||||
|             throw new \Exception; |             throw new \Exception; | ||||||
|         } |         } | ||||||
|         $this->edge = $edge; |         $this->edge = $edge; | ||||||
|         @file_put_contents("/sys/class/gpio/gpio{$this->pin}/edge", $edge); |         $this->sysfsWrite($this->pin, "edge", $edge); | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     public function getEdge() |     public function getEdge() | ||||||
|     { |     { | ||||||
|         return $this->edge; |         return $this->sysfsRead($this->pin, "edge"); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     public function setHandler(callable $handler=null) |     public function setHandler(callable $handler=null) | ||||||
|     { |     { | ||||||
|  |         $this->gpio->setInterruptHandler($this->pin, $this->fd); | ||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user