Serial port access in PHP with Windows (XP and higher)

... is not as easy as it should be. Each solution has its limitations. Here are some ideas...


With fopen/fread/fgets/fputs you can treat the serial port as a file $device = "COM8"; exec("mode $device BAUD=115200 PARITY=n DATA=8 STOP=1 xon=off octs=off rts=on"); $comport = fopen($device, "wb+"); fputs($comport,'test'.chr(22).chr(252)); fclose($comport); Unfortunately COM10 and above do not work with Windows.

The php serial extension by thebyteworks

Download here is a commercial solution working that also copes with COM10+. Installation is a bit difficult though: You must modify the httpd.conf of the Apache server and switch to PHP-CGI mode. The required extension dll is dependent on the PHP version (only tested up to 5.3.0). The trial version has several seconds of delay or additional output "TRIAL". Full functionality costs about $30.

shell_exec and set (DOS command)

$x=shell_exec('set /p x="hello" $lt;nul $gt>\\\\.\\COM11'); Will transfer "hello" to COM11. Unfortunately this is limited to ASCII text characters.

shell_exec and copy (DOS command)

First you create the binary file, then transfer the file to COM11. Be aware that you need to set data & parity first. 8 bits of data are needed for binary safe files! $x=shell_exec('mode COM11 PARITY=N data=8 stop=1 xon=off'); $x=shell_exec('copy test.bin \\\\.\\COM11'); But this was unreliant too. That's why I've written and compiled a univeral tool for serial port access that can be called by PHP via the shell extension.

my own C++ workaround

Structure: comxs.exe (string port, no of bytes to read as hex, command as hex values) Example from shell: comxs.exe COM11 10 FE FE 00 E0 03 FD will write the sequence (fe fe 00 e0 03 fd) to COM11 and then listen until 10 bytes are received. In PHP you can call the tool like: $x=shell_exec("comxs.exe $comport $readbytes $command"); $x will contain (as a written string): "fe fe 00 e0 03 fd fe fe e0 00 03 66 10 20 14 00 fd" (This is a CI-V dialogue for the Perseus SDR communications receiver) Download This is the C++ source:
/* comxs by Peer-Axel Kroeske 18-Nov-2012 This tool helps to access serial ports in PHP where ports from COM10 and above cause problems. For binary safe in and output. Structure: comxs.exe comport, bytestoread, command in hex values Example: comxs.exe COM11 11 fe fe 00 03 fd will write the sequence (fe fe 00 e0 03 fd) to COM11 and then listen until 17 (0x11) bytes are received. There is no timeout. It won't terminate until all bytes are received. Use 0 for write-only. It returns a string with written hex values like "fe fe 00 03 ... fd" */ #include <iostream> #include <string.h> #include <unistd.h> #include <windows.h> using namespace std; //htoi by John Santic unsigned int htoi (const char *ptr) { unsigned int value = 0; char ch = *ptr; while (ch == ' ' || ch == '\t') ch = *(++ptr); for (;;) { if (ch >= '0' && ch <= '9') value = (value << 4) + (ch - '0'); else if (ch >= 'A' && ch <= 'F') value = (value << 4) + (ch - 'A' + 10); else if (ch >= 'a' && ch <= 'f') value = (value << 4) + (ch - 'a' + 10); else return value; ch = *(++ptr);}} int main(int argc, char *argv[]) { char *sp; char path[]="\\\\.\\"; strcat(path,argv[1]); int x,y,z; if (argc<1) {cout<<"parameter missing";return FALSE;} HANDLE hCom; COMMTIMEOUTS timeouts = {1000}; DWORD size, BytesRead, BytesWritten; hCom = CreateFile(path,GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,0,0); if(hCom == INVALID_HANDLE_VALUE) {hCom = NULL; cout<<"invalid port";return FALSE;} for (x=3;x<argc;x++) {y=htoi(argv[x]); WriteFile(hCom,&y,1,&BytesWritten,0);} usleep(1000); y=z=int(htoi(argv[2])); if (y>0) { unsigned char* data[y]; ReadFile(hCom,data,y,&BytesRead,0); for (x=0;x<=y;x++) { z=((int(data[x>>2]))>>((x%4)<<3))&0xff; if (z<16) {cout<<'0';} cout<<hex<<z<<' ';}}}
It's very basic and still beta. There is no timeout - the process will be active until the requested number of bytes have been received. Use 0 for write-only.
Questions? Corrections? Ideas? Comments? main index

This site is based at: