We help IT Professionals succeed at work.

Linux/php serial port read - How to stop fread() waiting forever if no new data?

I'm working through exactly the same issue as described by skaap2k. (11/04/07 12:01 AM, ID: 22503690)

I am using a Linux (Ubuntu) server and PHP as a web server. The solution offered appears to be for a command line version of PHP, and doesn't work in my web server.

In short, I need to read and write to a GSM modem via the serial port using php. Writing is working fine.

Reading using fread() of /dev/ttyS1 stalls the server until the required number of bytes set in fread() and a CR is received.

I need to return from checking the serial port with a null if there is no new data. I'm happy to pick a byte at a time from the serial buffer and assemble it into a string in php.

Any suggestions welcome!
Comment
Watch Question

nociSoftware Engineer
Distinguished Expert 2019

Commented:
A command line tool runs permanently (until you exit).
A web tool exits after the request is handled.

In your case probably the best solution is to have a daemon process that monitors the serial port and handles the protocol there.
Any message (even an NONE_AVAILABLE) can then be signalled to the frontend when needed.

The php frontend needs to have a defined protocol with which it can request data from the backend.

Author

Commented:
I can see the logic there, any suggestions who to achieve it?

I've also looked at the php stream_set_timeout function but his does not seem to have  any effect.
The stream_set_blocking function when active, returns immediately without any data.
Thec current test script that gets stuck until the serial data and a CR arrives is below.

There are also "dio_open" (etc) functions within php - but I'm not clear how they differ. Is this a direction worth exploring?

// define serial port to be used & open port
$FilePointer = fopen("/dev/ttyS1", "w+");
// 	read data
//stream_set_blocking($FilePointer, 0);
stream_set_timeout($FilePointer, 0,2000);
$TextIn = fread($FilePointer, 5);
//	close port
fclose($FilePointer);
echo("Rx Text: ");
echo($TextIn);

Open in new window

"Reading using fread() of /dev/ttyS1 stalls the server until the required number of bytes set in fread() and a CR is received."

You can't set fread loose to take all CPU power, it HAS to be time sliced on the server, else it will sieze the server, as you are experiencing.  Typically one uses a time loop of 100ms and in that time loop you check for a byte in the stream.  Then do it again.  Then adjust the time window for optimum balance.

Remember, a serial port is a hardware device with a continuous data stream or an endless wait for some data stream.  You cannot let it run full throttle, you MUST limit it to time slicing to free up CPU time.

Author

Commented:
I think we have a problem with communication here. What I meant to convey is that the php script stalls, waiting for serial data. The linux operating system is fine. The php script will continue ONLY when the fread() receives the required number of bytes AND a Carriage Return. If the serial port has not received the full amount of data, the fread() routine loops forever, and therefore the php script is also stuck.

Commented:
Use tream_set_blocking($FilePointer, 0); and PHP 4.3.0 or later.
For earlier versions there is no way to do it.

Author

Commented:
Hi,
I'm using PHP Version 5.3.2-1ubuntu4.2 (as reported from phpinfo()  )
When stream_set_blocking($FilePointer, 0); is set, the routine returns immediately from fread() with no data. It's as if the serial port is not buffering/storing input. I hoped it would return all serial data received up to that point, and clear the serial port buffer.
The stream_set_timeout() function appears to have no effect.

Commented:
serial port is not buffering/storing input, ie. if you not read it, it's being dropped, so you need to read it in a fast loop
nociSoftware Engineer
Distinguished Expert 2019

Commented:
@mish33, the issue is that in a web interface there are periods that there is no one looking for info on a serial port. That needs to be made consistent.

Then a web interface should not wait, even if there is no info a backend tool should notify the frontend tool that there is nothing right now.

Author

Commented:
Thanks Everyone,
What you are saying makes sense, and matches what I am seeing with the hardware. It sounds like serial I/O is not a simple task to tackle with php running as a web server. (There has to be a way to do it though!)

The alternative is to have php call on an external routine? I'm good at  learning by example - can anyone please provide or suggest examples of techniques to call on external routines (and pass data)  from within a php web server?
Thanks,
James
Software Engineer
Distinguished Expert 2019
Commented:
Maybe you didn't understand the first answer correctly.
Make two programs - One is the php script you have now (but a littlebit modified).
The 2nd is a program that continuously read /writes on the Serial port what ever it's protocol requires and that either gives each change to the first program whenever is requests this. (f.e. by giving a length + data) then even if the amount of data is 0 (no data) you do pass something that it can act upon (the 0 size).

The other possiblity is that you keep a scrolling buffer in the second program (like a video buffer in VGA or a terminal) every time the front end requests it you send the whole current frame to the front end.

The valid method really depends on what you want to do with the data.

Author

Commented:
The answer described a concept that I had already raised in earlier postings. I was looking for concrete examples of a technique to achieve this. My final solution was to pay a contract programmer to do the job.