Improved sysfs file access code

This commit is contained in:
Chris 2014-06-12 02:35:19 +02:00
parent 2304372129
commit b53cabec90
5 changed files with 162 additions and 27 deletions

View File

@ -20,23 +20,11 @@ $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
View 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);

View File

@ -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);
}

View File

@ -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];
} }

View File

@ -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;
/** /**
@ -42,9 +44,12 @@ class GpioPin
protected $label; protected $label;
public function __construct($pin) protected $gpio;
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");
} }
@ -81,12 +86,23 @@ 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;
} }