diff --git a/examples/basic.php b/examples/basic.php index 36d1798..2226188 100644 --- a/examples/basic.php +++ b/examples/basic.php @@ -15,28 +15,16 @@ try { $gpio->setMapper( new WiringPiMapper(2) ); // 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] ->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); - - +$x = 0; +while(true) { + $x = (int)(!$x); + $led->setValue($x); + usleep(500000); +} diff --git a/examples/buttons.php b/examples/buttons.php new file mode 100644 index 0000000..36d1798 --- /dev/null +++ b/examples/buttons.php @@ -0,0 +1,42 @@ +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); + + diff --git a/examples/rf-remote.php b/examples/rf-remote.php index 2524769..61a365b 100644 --- a/examples/rf-remote.php +++ b/examples/rf-remote.php @@ -2,6 +2,21 @@ 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\GpioMapper\WiringPiMapper; @@ -21,7 +36,12 @@ $led = $gpio[0] ->setDirection("input") ->setEdge("rising") ->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") ->dumpStatus(true); @@ -33,3 +53,7 @@ for($n = 1; $n < 5; $n++) { ->dumpStatus(true); } +while(true) { + $gpio->refresh(); + usleep(10000); +} diff --git a/lib/Gpio.php b/lib/Gpio.php index 08bb3b4..ee5f4f8 100644 --- a/lib/Gpio.php +++ b/lib/Gpio.php @@ -23,6 +23,18 @@ use NoccyLabs\Gpio\Exception\HardwareException; 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(); /** @var NoccyLabs\Gpio\GpioMapperInterface */ @@ -51,7 +63,29 @@ class Gpio implements \ArrayAccess $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) @@ -64,7 +98,7 @@ class Gpio implements \ArrayAccess { if ($this->mapper) { $index = $this->mapper->mapLogicalToGpioPin($index); } if (empty($this->gpio[$index])) { - $this->gpio[$index] = new GpioPin($index); + $this->gpio[$index] = new GpioPin($index, $this); } return $this->gpio[$index]; } diff --git a/lib/GpioPin.php b/lib/GpioPin.php index 1d0de84..05b5dc4 100644 --- a/lib/GpioPin.php +++ b/lib/GpioPin.php @@ -19,6 +19,8 @@ namespace NoccyLabs\Gpio; +use NoccyLabs\Gpio\Exception\HardwareException; + use NoccyLabs\Sansi\Charset as CS; /** @@ -41,10 +43,13 @@ class GpioPin protected $handler; protected $label; + + protected $gpio; - public function __construct($pin) + public function __construct($pin, Gpio $gpio) { $this->pin = (int)$pin; + $this->gpio = $gpio; $this->export(); $this->fd = fopen("/sys/class/gpio/gpio{$pin}/value", "rb"); } @@ -80,13 +85,24 @@ class GpioPin { 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) { $this->label = (string)$label; return $this; } + /** + * Get the assigned label for this pin. + * + * @return string The label + */ public function getLabel() { return $this->label; @@ -94,9 +110,9 @@ class GpioPin 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}")) { - throw new \Exception(); + throw new HardwareException("Unable to export pin {$this->pin}"); } return $this; } @@ -107,23 +123,54 @@ class GpioPin 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) { if (!in_array($edge, array("rising", "falling", "both", "none"))) { throw new \Exception; } $this->edge = $edge; - @file_put_contents("/sys/class/gpio/gpio{$this->pin}/edge", $edge); + $this->sysfsWrite($this->pin, "edge", $edge); return $this; } public function getEdge() { - return $this->edge; + return $this->sysfsRead($this->pin, "edge"); } public function setHandler(callable $handler=null) { + $this->gpio->setInterruptHandler($this->pin, $this->fd); return $this; }