PHP Serial Port Development

To use an external device and send and receive data over a serial port, you need some serial port handling code on the PHP side.
PHP’s dio extension (Direct I/O) provides access to low-level I/O operations, including serial port communication. Through the dio extension, you can directly operate serial port device files (such as /dev/ttyUSB0 or COM1) to implement serial port communication.

1. Installing the dio extension

The dio extension is a PECL extension for PHP. You can install it with the following steps:

Installing on Linux:

1
2
3
sudo apt-get install php-dev  # install PHP development tools
sudo pecl install dio # install the dio extension

After installation is complete, enable the extension in the php.ini file:

1
2
extension=dio.so

2. Using dio for serial port communication

Below is a sample program that uses the dio extension to implement serial port communication:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
// serial port device path
$device = '/dev/pts/4'; // Linux
// $device = 'COM1'; // Windows

// open the serial port device
$fd = dio_open($device, O_RDWR | O_NOCTTY | O_NONBLOCK);

if (!$fd) {
die("无法打开串口设备: $device\n");
}

// configure serial port parameters
dio_tcsetattr($fd, [
'baud' => 9600, // baud rate
'bits' => 8, // data bits
'stop' => 1, // stop bits
'parity' => 0, // parity (0: none, 1: odd, 2: even)
'flow_control' => 0, // flow control (0: none, 1: hardware)
]);

// send data to the serial port
$message = "你好我在https://erik.xyz上出生了!";
dio_write($fd, $message);
echo "已发送: $message";

// read data from the serial port
$data = dio_read($fd, 1024); // read at most 1024 bytes
echo "已接收: $data\n";

// close the serial port
dio_close($fd);
?>

3. Code explanation

  • dio_open: opens the serial port device file. O_RDWR means open in read-write mode, O_NOCTTY means do not make the device the controlling terminal, O_NONBLOCK means non-blocking mode.

  • dio_tcsetattr: configures the serial port parameters, including baud rate, data bits, stop bits, parity, and flow control.

  • dio_write: writes data to the serial port.

  • dio_read: reads data from the serial port.

  • dio_close: closes the serial port device.

4. Serial port parameter configuration

  • Configuration options for dio_tcsetattr:

  • baud: baud rate (such as 9600, 19200, 38400, 57600, 115200).

  • bits: data bits (usually 8).

  • stop: stop bits (1 or 2).

  • parity: parity bit (0: none, 1: odd, 2: even).

  • flow_control: flow control (0: none, 1: hardware flow control).

So at this point we need to test the code. Surely you don’t want to actually go find a serial port device — but virtual serial ports are a treat.

5. Using socat to simulate virtual serial ports in Linux

socat is a powerful tool that can create pairs of virtual serial ports.

Installing socat:
On Debian/Ubuntu systems:

1
2
sudo apt update
sudo apt install socat

Creating a virtual serial port pair:
Run the following command to create a pair of virtual serial ports:

1
socat -d -d pty,raw,echo=0 pty,raw,echo=0

After running it, it looks like this:
https://erik.xyz
You can see that two virtual serial ports have appeared.
Put the PHP code above into a file and run it:
https://erik.xyz

At the same time, open another window and run: cat /dev/pts/5 to read the serial port data.
As shown below:
https://erik.xyz

This is sending data — so how do you see the received data?
Well, just modify the code and add a for loop:

1
2
3
// read data from the serial port
$data = dio_read($fd, 1024); // read at most 1024 bytes
echo "已接收: $data\n";

This modification is mainly for testing; in practice it isn’t needed.
1
2
3
4
5
6
7
//test receiving
for($i=0;$i<20;$i++){
sleep(3);
// read data from the serial port
$data = dio_read($fd, 1024); // read at most 1024 bytes
echo "已接收: $data\n";
}

Then run the PHP code again, and in a new window run echo "欢迎你出生在https://erik.xyz" > /dev/pts/5 to send a message, and you will see the reception as shown in the image:
https://erik.xyz

At this point, sending and receiving over the serial port are working.