*/ namespace NoccyLabs\Gpio; use NoccyLabs\Gpio\Exception\HardwareException; use NoccyLabs\Sansi\Charset as CS; /** * GPIO pin implementation. This class wraps all interaction with a GPIO pin, * thus decoupling it from the main Gpio class. * */ class GpioPin { protected $fd; protected $pin; protected $value = 0; protected $direction; protected $edge; protected $handler; protected $hardware; protected $label; protected $gpio; public function __construct($pin, Gpio $gpio) { $this->pin = (int)$pin; $this->gpio = $gpio; } public function getPin() { return $this->pin; } private function findHardware() { $chips = glob("/sys/class/gpio/gpiochip*"); $pinchip = null; foreach($chips as $chip) { $r = null; if (preg_match("/([0-9]+?)/", $chip, $r)) { $base = (int)$r[1]; if ($base < $this->pin) { $pinchip = $chip; } } } if ($pinchip) { $hw = trim(file_get_contents($pinchip."/label")); return $hw; } return "unknown"; } public function __destruct() { if ($this->fd) { fclose($this->fd); } } public function setDirection($direction) { if (!in_array($direction, array("in", "out"))) { throw new \Exception; } $this->direction = $direction; $this->sysfsWrite($this->pin, "direction", $direction); return $this; } public function getDirection() { return $this->sysfsRead($this->pin, "direction"); } public function setValue($value) { $this->value = (bool)$value; @file_put_contents("/sys/class/gpio/gpio{$this->pin}/value", (int)$this->value); return $this; } public function getValue() { return $this->sysfsRead($this->pin, "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; } public function export() { if (file_exists("/sys/class/gpio/gpio{$this->pin}")) { return $this; } $this->sysfsWrite(null, "export", $this->pin); if (!file_exists("/sys/class/gpio/gpio{$this->pin}")) { throw new HardwareException("Unable to export pin {$this->pin}"); } $this->hardware = $this->findHardware(); return $this; } public function unexport() { $this->sysfsWrite(null, "unexport", $this->pin); return $this; } public function sysfsWrite($pin, $file, $value) { if ($pin) { $path = "/sys/class/gpio/gpio{$pin}/{$file}"; } else { $path = "/sys/class/gpio/{$file}"; } if (!file_exists($path)) { throw new HardwareException("Sysfs file {$path} does not exist"); } $ts = microtime(true); while ((!is_writable($path)) && (microtime(true) < $ts+1)) { usleep(10000); } $f = @fopen($path,"c"); if (!is_resource($f)) { $err = error_get_last(); throw new HardwareException("Unable to write to sysfs file {$path}: ".$err['message']); } 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 trim($ret); } public function setEdge($edge) { if (!in_array($edge, array("rising", "falling", "both", "none"))) { throw new \Exception; } $this->edge = $edge; $this->sysfsWrite($this->pin, "edge", $edge); return $this; } public function getEdge() { return $this->sysfsRead($this->pin, "edge"); } public function setHandler(callable $handler=null) { $this->gpio->setInterruptHandler($this->pin, $this->fd); return $this; } public function doInterrupt() { fseek($this->fd,0,SEEK_SET); $val = fgets($this->fd); } public function dumpStatus($ansi=false) { if ($ansi) { $status = "\e[44;37;1m GPIO{$this->pin} \e[0m\n"; $direction = ($this->direction=="input"?(CS::chr(0x2190)):(CS::chr(0x2192))). " ".$this->direction; $edge = $this->edge; //""; /*if ($this->edge == "rising") { $edge.= CS::chr(0x21A5)." rising"; } elseif ($this->edge == "falling") { $edge.= CS::chr(0x21A7)." falling"; } else { $edge.= "\e[0m".$this->edge; }*/ } else { $status = "********** GPIO{$this->pin} **********\n"; $direction = $this->direction; } foreach(array( "Direction" => $this->getDirection(), "Value" => ($this->getValue()?1:0), "Edge" => $this->getEdge(), "Label" => $this->label, "Hardware" => $this->hardware, "Int count" => 0 ) as $k=>$v) { if ($ansi) { $status.= sprintf(" \e[32;1m%10s\e[0m: \e[0m%s\e[0m\n", $k, $v); } else { $status.= sprintf(" %-10s: %s\n", $k, $v); } } error_log($status); return $this; } }