Let's look closer at the PHP program that reads the serial port and prints it on the web page:
<?php
exec('mode com3: baud=115200 data=8 stop=1 parity=n');
$fd = dio_open( "com3:", O_RDWR );
if( $fd )
{
$count = 0;
for( $x = 0; $x < 1000; $x++ )
{
$data = dio_read( $fd, 1 );
echo $data;
if( $data == "\n" || $data == "\r" )
{
if( $count++ > 0 )
{
break;
}
}
}
dio_close( $fd );
}
else
print( "Can't open com3:" );
?>
PHP is a language much like C++. It has functions, classes, for loops, and curly braces.
One important difference is in variables. In C++, we must declare our variables before we use them, and the declaration includes the type of the variable (integer, float, double, etc.). In PHP, variables do not need to be declared, and they have no type. And, they begin with a dollar sign.
The first line in our program tells the web server that this is a PHP program. Anything not enclosed in <?php ... ?> will be output on the page as if it were regular text or HTML.
The next line is the exec() function, which sends the command string to the operating system to be executed. In this case, it sets up the serial port, telling it things like what baud rate to use, and how many bits are in a character.
Then we find the dio_open() function. It opens the serial port, and returns a handle (called $fd) that is used by the dio_read() and dio_close() functions later in the program.
If the serial port can be opened, we set $count to zero, and loop for 1000 times.
In the loop, we call dio_read() to read a character from the serial port and put it into$data. We then output $data to the web page with the command echo.
Next, we check to see if the character was one of the characters that signal the end of a line (either a newline character, or a carriage return). If so, and it was the second time we have seen an end-of-line character, then we break out of the loop (using the breakkeyword), close the serial port, and exit the program.
If we can't open the serial port (did you remember to exit the Arduino IDE?), then we print out an error message.
So this program simply reads two lines from the serial port, and sends them to the browser, before exiting.
Our modified thermometer program running in the tiny computer prints out two lines every 30 seconds. But whenever the PHP program is run (whenever someone refreshes the web page to get the latest temperature), the act of opening the serial port causes the tiny computer to reset. So it starts all over from the beginning, every time someone asks for a web page. This can be a problem if there are a lot of people refreshing the web page. The little program might be halfway through printing the temperature when it gets reset. We will look at ways to get around this problem later.
Cleaning up the code
Let's wrap up our serial port reading code into a nice class, and clean up the logic a bit:
<?php
class Serial
{
private $fd;
public function open( $port )
{
exec( 'mode ' . $port . ' baud=115200 data=8 stop=1 parity=n' );
$this->fd = dio_open( $port, O_RDWR );
return $this->fd;
}
public function close()
{
dio_close( $this->fd );
}
public function readline()
{
if( $this->fd )
{
$line = "";
while( ($ch = dio_read( $this->fd, 1 )) != "\n" )
{
if( $ch != "\r" )
$line .= $ch;
}
return $line;
}
}
}
$serial = new Serial();
if( $serial->open( "com3:" ) )
{
for( $x = 0 ; $x < 2; $x++ )
{
$line = $serial->readline();
print( $line . PHP_EOL );
}
$serial->close();
}
else
print( "Can't open com3:" );
?>
Let's see what's new here:
- PHP has classes, just like C++.
- private $fd defines a variable that is known only to methods in the class Serial (fd is short for 'file descriptor')
- public function open( $port ) is how we define a method that takes an argument. $port is the port we want to open.
- The first line of the open method uses the period operator (.) to join strings of characters together.
- $this->fd is how we refer to the class variable $fd inside a method. $this means the current instance of the class.
- while( ($ch = dio_read( $this->fd, 1 )) != "\n" ) This line is tricky. It reads a character into $ch, and tests to see if it is a newline character. If it is, then the loop stops.
- $line .= $ch; This line attaches the character we just read to the end of the string$line. Notice that $line starts out empty.
- $serial = new Serial(); This line creates an instance of out class Serial, and puts it into $serial.
- print( $line . PHP_EOL ); Here we add a newline to the line (remember we stripped the carriage return and line feed from the string the tiny computer sent us), and then print it. The special name PHP_EOL makes sure that the newline matches whatever operating system PHP is running on. Windows uses carriage return followed by a line feed. Linux use just a line feed. Macs use a carriage return. This way, we don't care -- it just works.
With our new Serial class, we can copy it to other programs that need to read lines from the tiny computer, or put it into a library of code to re-use even easier.
Using PHP from the command line
Up to this point, we have been using PHP to print things to a web browser. But we can run PHP on our host computer as a normal program, without web servers and web browsers. If we just wanted to save our temperature data in a file, we could use the command
php temperature_class.php > my_temperature_data.txt
If we wanted to save a whole bunch of readings, we could replace the line
for( $x = 0 ; $x < 2; $x++ )
with
for(;;)
We have stripped the for() statement of its initialization, test, and change sections. Afor() loop with an empty test never stops (until you kill the program from the terminal). This way we can record temperatures for as long as we like.