Raspberry Pi help: READ Serial port using PHP (serial port configuration in Linux?)

1,117 views
Skip to first unread message

J.Dugan

unread,
Oct 3, 2018, 10:43:22 AM10/3/18
to milwaukeemakerspace
Hey Gang-

I know many here like to tinker with Arduino/RPi stuff...

I have a project that I am working on.. and have been STUCK for over a week now....  and finally need to reach out and ask for some help/advice/suggestions. :)

 
* Disclaimer:  I am using PHP, please no mention of Python, I dont know any Python, I -want- to use PHP   :)

Long story short:

Arduino connected to RPi via straight USB cable
RPi has Apache, MySQL, PHP, PhpMyAdmin installed on it
Locally hosted web page (RPi) coded and working as expected...
My 'web page' is basically just a 'menu' GUI/front end..  (scroll.. find something you like.. hit order button)
Page submits to itself.. where I grab the $_POST string value.


When the page submits.. I am using an AJAX call to load/execute an external .php script...

in this external .php script.... is where I am doing:
* the port opening...
* writing (sending the $_POST data from above) to the serial port (connected Arduino)..
* Arduino 'does its thing'  (move some steppers/servos around..etc)
* Arduino send back a serial confirmation stating it is done/complete


^ At this point.. everything works fine.. stable & reliable.

I do NOT get port not open error...
Arduino always gets and parses its incoming serial data (sent from the RPi/PHP)
Arduino -always- sends back its completed serial confirmation..

--------------

Here is where the problem comes into play... after I open the port.. send [ fwrite() ] my string data to the Arduino....

I then put the php script into a 'loop' checking the serial port over and over [ fread() ] until I get a response (character)....  (there is no set time on when the Arduino response will come back)

However, I never can actually get a read/response*

I am just stuck in the while loop() checking the serial port/reading it over and over...

if I comment out the loop and add a static echo 'complete'; statement, it works fine!  (EACH AND EVERY TIME!)...

I can even put a sleep(10); action before it.. and the awaiting AJAX callback will still receive it.. (10 seconds later!)...

I have read, and read,.... and read some more.. everything I have tried (except one test) did not work.  I can NEVER get a READ from the serial port.

I am not well versed with using RPi's for projects...  and am a complete beginner with Linux and CLI stuff...  (so I sorta read, and blindly execute some of the commands)


* I stumbled upon others talking about the same issues..(stack overflow)..  where someone mentioned using 'minicom'   (not sure what minicom even is.. my best understanding is some sort of terminal app?)

I was (am) desperate for a solution.. so I installed this minicom....  and started it up manually (using Putty on my PC and connecting to the RPi)...

When minicom was 'running'....  and I then loaded the page up, submitted the form...  data got sent to the Arduino and it did its tihng (as normal).. but then the SERIAL READ WORKED!!..

I got a response/read from the serial port......and it was echo'd back to the awaiting AJAX (success) callback!.. Which in turn refreshes the webpage and brings it back to the 'menu' front end.. awaiting for another submission!!

This works exactly 2 times!.. on the 3rd time.. I saw my response show up/display in this 'minicom' screen?  the 4th submission...  nothing.. on either end (webpage or minicom).. and the minicom menu/screen... seemed to be frozen.


So my questions are:

1.) How can I configure the PORT correctly on the RPi so I can RELIABLY read it using PHP each and every time?
2.) What is this minicom doing that cant be set permanently on the RPi port settings itself?  (and why did it steal my data on the 3rd attempt.. and then freeze?)



Here is the 'submit' routine ofthe MAIN .php page (the HTML form)


if ($mode == 'submit') {
   
        //grab posted data (save to var)
        $drinkRecipe
= $_POST['selectedDrink'];
   
           
        //output some jQuery/AJAX call to an external PHP script that does the port LISTENING, and respond back once data is received
        ?>
        <script type="text/JavaScript" language="JavaScript">
                var submittedDrink = <?=$drinkRecipe?>;
               
                $.ajax({
                        //async: false,
                        type: "POST",                          
                        url: "serial_listener.php",                            
                        datatype: "text",
                        data:{
                                "submittedDrink": submittedDrink
                        },
                       
                        //define success handler actions
                        success: function(response) {
                                //alert("PHP RETURN CHECK: "+response);
                                if($.trim(response) == 'complete'){
                                        alert("Drink making is complete... return to main menu");
                                        //do redirect here
                                }else{
                                        alert("Some value other than 'complete' was returned... look into it!");
                                        alert("Response Received: " + response);
                                        //not sure what to do? (back to main menu anyways?)
                                }
                        },
                       
                        //define error handler actions
                        error: function(response) {
                                alert("PHP SERIAL READ FAIL: "+ 'Ready State: '+ response.readyState + ' Status: ' + response.status);
                               
                        }
                });    
        </script>              
        <?                      
       
}



And an example of the code/routine in the serial_listener.php script the AJAX snippet executes...


$drinkData = $_POST['submittedDrink'];
//open serial port
$fp
= fopen("/dev/ttyACM0", "w+"); //w = write w+ = read/write

//check if open
if (!$fp) {
        echo
"Not open";
       
} else {
       
//if open send data (via PHP) to connected Arduino on serial comm port 1 (ttyACM0)
        fwrite
($fp, '<' . $drinkData  . '>');
       
        sleep
(2);

       
//check and wait for incoming serial data form Arduino response        
        $responseValue
= "";
       
while(strlen($responseValue) < 1){
            $incomingChar
= fread($fp, 1);
           
if($incomingChar != ''){
                $responseValue
.= $incomingChar;
           
}
       
}
        echo $responseValue
;
}


What am I missing? or doing wrong?  I -feel- this is a port configuration issue.... since I have NOT changed any code (Arduino or PHP side).. and installing that 'minicom' app allowed communication (briefly)...

Thanks for any advice/feedback here... its been a LONG week+ just on this serial stuff!

Thanks!
-J









Royce Pipkins

unread,
Oct 3, 2018, 10:57:28 AM10/3/18
to milwaukee...@googlegroups.com
Looking very briefly I don't see any port setup. You just open and go. Speed, data bits, start bits, stop bits, and flow control are all settings you should be mindful of.

I'm not familiar with serial on PHP but a quick search for adjusting serial port speed turned up this page:


about a dio function. There is a dio_open as well.

The comments look like they may be useful too you as well as I see a exec call to a command line utility that may be able to setup the serial port as well.





--

---
You received this message because you are subscribed to the Google Groups "milwaukeemakerspace" group.
To unsubscribe from this group and stop receiving emails from it, send an email to milwaukeemakers...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
The real problem is not whether machines think but whether men do.
B. F. Skinner

J.Dugan

unread,
Oct 3, 2018, 12:22:20 PM10/3/18
to milwaukeemakerspace
Thanks Royce-

I am 'attempting' to run this line in an exec() call:


exec('stty -F /dev/ttyACM0 cs8 9600 ignbrk -brkint -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts');

before opening the port... but it sdidnt seem to make any difference?  (and when I asked about the params.. I was told' you dont need to worry about those, disable some errors..etc... even though I sorta pushed back and stated I do feel like I should understand those params in case it pertains to why things arent working!!)...

From more searching.. I found several people posting that these params were needed: (which I have)
-isig -icanon


I have never heard of 'dio_' stuff before.. (thanks for the link.. I'll check it out)
To unsubscribe from this group and stop receiving emails from it, send an email to milwaukeemakerspace+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Pete Prodoehl

unread,
Oct 3, 2018, 12:35:36 PM10/3/18
to milwaukee...@googlegroups.com

Any chance it's a user permissions thing? What user is your php script running as? Does it have permission to run the exec command?


Pete
To unsubscribe from this group and stop receiving emails from it, send an email to milwaukeemakers...@googlegroups.com.

Chris Hemmerly

unread,
Oct 3, 2018, 1:59:02 PM10/3/18
to milwaukeemakerspace
I'm not sure fopen() is what you want to use to read/write to a serial port. Probably works fine with a file, but maybe it's not working correctly on a character device ("ttyAMA0")?

From what I've found in a few quick searches, as Royce mentioned, DIO seems to be the way to go. Here's a reference:

-Chris

Daren Schwenke

unread,
Oct 3, 2018, 5:04:30 PM10/3/18
to milwaukee...@googlegroups.com
Well I can tell you, it can be done as I had a CD changer I ran over serial from php somewhere around 1999 for mounting install discs.  
There is no way in hell I still have that code though unless it's in a box on a CD somewhere.

Permissions is the first issue.  Changing the permissions on the serial ports is transient, aka.. they will disappear and be back to what they were.  You need to add yourself and your webserver to the 'dialout' group, or whatever that is called nowadays.. probably still 'dialout' or perhaps 'serial'..

Php can be disallowed from going below your webroot, which would prevent access to devices as device files.  I believe it's an ini setting related to security.

minicom is just for testing your serial port (or talking to terminals).  If your code works after running minicom, you are likely missing initialization stuff.
As to what stuff you need... 8N1, and disable hardware flow control is usually enough.

If you go through the OS (aka commands piped to each other) you are adding the issue of buffering... where the output from your port won't be sent to you until you get a line of data.  Sounds like you are working character-wise, so unless you disable buffering, I would avoid reading command line stuff.

As for the actual reading/writing the port, dio is probably the way to go.  
I believe I used fopen personally, and here is a class I found that looks a lot like what I recall doing: https://www.phpclasses.org/browse/file/17926.html

J.Dugan

unread,
Oct 3, 2018, 5:23:45 PM10/3/18
to milwaukeemakerspace
Thanks everyone...


Lots to read up upon.. I'll be home in a few hours.. and if motivated, I'll be back on trying to get this all sorted out.

@Pete-

Yes I believe I have the correct permissions for the www/dial-out group.....   I can post my actually lines i ran on the RPi while setting up Apache, PHP, MySQL.. as it was part of that process..


I have actually tired that serial class before... (didnt work).. and it seems a bit SLOW even when trying to send my WRITE data to the Arduino... 

It never READ anything either.. (stuck in same READ loop)...  serial.readPort()
*(or whatever the method is,... off hand I dont recall)


I will also give DIO that Royce, CHris & Darren mention...

Barring that.. I might have to pack all this junk and up make it tot he space one night for 'hand handling'  LOL..

Thanks again guys!   (fingers crossed)
To unsubscribe from this group and stop receiving emails from it, send an email to milwaukeemakerspace+unsub...@googlegroups.com.

con...@brandoncorlett.com

unread,
Oct 8, 2018, 9:18:23 AM10/8/18
to milwaukee...@googlegroups.com
I documented using PHP to exicure BASH scripts.

It's not Python ;)

https://www.brandoncorlett.com/blog/article/execute-bash-script-using-php

rocky53204

unread,
Oct 9, 2018, 8:36:32 AM10/9/18
to milwaukee...@googlegroups.com
Nice blog!

--

---
You received this message because you are subscribed to the Google Groups "milwaukeemakerspace" group.
To unsubscribe from this group and stop receiving emails from it, send an email to milwaukeemakers...@googlegroups.com.

J.Dugan

unread,
Oct 9, 2018, 12:16:37 PM10/9/18
to milwaukeemakerspace
At first I was thinking, this had no bearing on my project as I have no issues with the PHP/AJAX side of things.. but was (at least I felt a permission or configuration issue)..

I used the *SECURITY RISK* line.. (last one posted) in your tutorial.. and BOOM!..  it had started working, each and every time, flawlessly..

Rebooted, powered down...etc..  as long as I have this line in my PHP script still it works each and every time!

* Which I dont think all parameters are needed:

exec("stty -F /dev/ttyACM0 cs8 9600 ignbrk -brkint -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts");


1.) Is the above line supposed to be executed EACH and EVERY time the php script is called/loaded?
2.) Is there some way to run this in via terminal.. so it never has to be done again?

3.) Question on your blog/post...  that line is presented like:

'echo "www-data    ALL=NOPASSWD: ALL" | sudo tee -a /etc/sudoers'

The 'echo' made me think it was supposed to be run in the PHP side of things?

but I ran it (as is) via terminal (Putty on my PC remote aceess into my RPi)

Is the correct way ti was to be run?

I'm not 100% clear what its doing (specifically)... but it got my project working! So I am grateful!..  

now I just want to learn a bit more... so I'm not just blindly following things...  but have a true understanding.


If I didnt want the 'full access' (security risk)...  how would I alter the line to allow my PHP stuff to access (read,...as writing was never an issue) the serial port on the RPi?

I believe Pete brought this up originally sorta (permissions)...  but I guess I was falsely assuming these lines set the permissions correctly:

# sudo usermod -a -G dialout www-data
# sudo chmod 777 /dev/ttyACM0

Thanks everyone!
Reply all
Reply to author
Forward
0 new messages