Reading serial port with Event and DIO
suggest changeDIO streams are currently not recognized by the Event extension. There is no clean way to obtain the file descriptor encapsulated into the DIO resource. But there is a workaround:
- open stream for the port with
fopen()
; - make the stream non-blocking with
stream_set_blocking()
; - obtain numeric file descriptor from the stream with
EventUtil::getSocketFd()
; - pass the numeric file descriptor to
dio_fdopen()
(currently undocumented) and get the DIO resource; - add an
Event
with a callback for listening to the read events on the file descriptor; - in the callback drain the available data and process it according to the logic of your application.
dio.php
<?php
class Scanner {
protected $port; // port path, e.g. /dev/pts/5
protected $fd; // numeric file descriptor
protected $base; // EventBase
protected $dio; // dio resource
protected $e_open; // Event
protected $e_read; // Event
public function __construct ($port) {
$this->port = $port;
$this->base = new EventBase();
}
public function __destruct() {
$this->base->exit();
if ($this->e_open)
$this->e_open->free();
if ($this->e_read)
$this->e_read->free();
if ($this->dio)
dio_close($this->dio);
}
public function run() {
$stream = fopen($this->port, 'rb');
stream_set_blocking($stream, false);
$this->fd = EventUtil::getSocketFd($stream);
if ($this->fd < 0) {
fprintf(STDERR, "Failed attach to port, events: %d\n", $events);
return;
}
$this->e_open = new Event($this->base, $this->fd, Event::WRITE, [$this, '_onOpen']);
$this->e_open->add();
$this->base->dispatch();
fclose($stream);
}
public function _onOpen($fd, $events) {
$this->e_open->del();
$this->dio = dio_fdopen($this->fd);
// Call other dio functions here, e.g.
dio_tcsetattr($this->dio, [
'baud' => 9600,
'bits' => 8,
'stop' => 1,
'parity' => 0
]);
$this->e_read = new Event($this->base, $this->fd, Event::READ | Event::PERSIST,
[$this, '_onRead']);
$this->e_read->add();
}
public function _onRead($fd, $events) {
while ($data = dio_read($this->dio, 1)) {
var_dump($data);
}
}
}
// Change the port argument
$scanner = new Scanner('/dev/pts/5');
$scanner->run();
Testing
Run the following command in terminal A:
$ socat -d -d pty,raw,echo=0 pty,raw,echo=0
2016/12/01 18:04:06 socat[16750] N PTY is /dev/pts/5
2016/12/01 18:04:06 socat[16750] N PTY is /dev/pts/8
2016/12/01 18:04:06 socat[16750] N starting data transfer loop with FDs [5,5] and [7,7]
The output may be different. Use the PTYs from the first couple of rows (/dev/pts/5
and /dev/pts/8
, in particular).
In terminal B run the above-mentioned script. You may need root privileges:
$ sudo php dio.php
In terminal C send a string to the first PTY:
$ echo test > /dev/pts/8
Output
string(1) "t"
string(1) "e"
string(1) "s"
string(1) "t"
string(1) "
"
Found a mistake? Have a question or improvement idea?
Let me know.
Table Of Contents