ademmler has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, who can point me to a general tut about best practise how to detect and interpret serial port data. I have "googled" a lot but I don't find a "general explanation". I have a couple of protocol specifications for serial devices, which I want to talk with and read from. The biggest hurdle for me is to get the "data stream" out of a continous message. thx in advance Alexander

Replies are listed 'Best First'.
Re: BP: Serial protocol detection
by BrowserUk (Patriarch) on Jun 15, 2014 at 12:24 UTC
    how to detect and interpret serial port data. I have "googled" a lot but I don't find a "general explanation". I have a couple of protocol specifications for serial devices, which I want to talk with and read from. The biggest hurdle for me is to get the "data stream" out of a continuous message

    I've never seen such a tutorial, and I've been playing with serial ports for 30+ years. Mind you, I haven't gone looking for a long time either :)

    There are basically two types of serial line protocol:

    • Length-prefixed based.

      With this, the first 1, 2, or 4 characters from the stream identify how many more characters must be read for a complete, single message:

      <0x1A>This is a complete message
    • Terminator based.

      With this, you have to keep reading until you see the specified terminator:

      This is a complete message<0x03>

    In general, the former is easier and more efficient to deal with at the lower level.

    However, at the higher level, the latter allows you to use filetype line-oriented reads and writes provided that your libraries allow you to set the EOL character -- which Perl allows by the setting of $/ & $\.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: BP: Serial protocol detection
by Anonymous Monk on Jun 15, 2014 at 23:35 UTC

    A good module to access the serial port is Device::SerialPort in *NIX and Win32::SerialPort on Windows. Their docs as well as googling their names will get you some sample programs which is probably the easiest way to get started, here are some examples: Device::SerialPort Examples.., Reading Data from a Serial Port using Win32::SerialPort

    The general approach to read from the serial port is to read it a single byte at a time, unless you know exactly how many bytes you're expecting, in which case you can request that number of bytes from the driver. Make sure to read about the different timeout settings the driver accepts, so that you don't time out too soon or end up waiting for a byte forever in case one gets lost somewhere (which does tend to happen on serial ports). Also note that the modules I mentioned are generally blocking I/O, meaning that your program won't do anything else if it's waiting for data from the serial port. Although I've rarely needed it, there are ways to work around this, but it can be tricky to get right, so looking for help online is very helpful there too.

    Lastly, I've found it's important to remember the distinction between bytes and characters, a line which Perl unfortunately blurs a little from time to time. Most serial protocols I've seen express their data in bytes, and you want to keep treating them as such, and not as characters at the Unicode level, until the protocol calls for some explicit decoding of the bytes.

Re: BP: Serial protocol detection
by crusty_collins (Friar) on Jun 16, 2014 at 18:07 UTC
    Years ago I had to make a call to a Parallel Port using perl This is the code that I used. This was used to check if a radio station was broadcasting or not.. Hope this helps
    use strict; my $settings; while (1 > 0 ) { $settings->{ports}->{status} = &CheckPort($settings); &SetStatus($settings); } sub CheckPort { my $parport = Device::ParallelPort->new('win32'); $parport->set_control(32); #Grab values from DATA port my $data = $parport->get_bit(0); $data = $data . $parport->get_bit(1); $data = $data . $parport->get_bit(2); $data = $data . $parport->get_bit(3); $data = $data . $parport->get_bit(4); $data = $data . $parport->get_bit(5); $data = $data . $parport->get_bit(6); $data = $data . $parport->get_bit(7); return unpack("N", pack("B32", substr("0" x 32 . $data, -32))); } ########################################################### # Set the status of each port ########################################################### sub SetStatus { my $settings = shift(@_); my $sendMail; my $station; my $stationNumber; my $writeStatus; my $number = $settings->{ports}->{status}; my $checkFor = $settings->{checkFor}; # the port has 8 data registers. if port 8 is low then we have 011 +11111 as a binary value. print "--[ If the port is not " . $checkFor . " then we have a prob +lem\n"; $bin = sprintf("%08b", $number); print "--[ sprintf result " . $bin . "\n"; @chars = unpack("A1" x length($bin), $bin); for( $i=0; $i <= $#chars; $i++) { # convert $status = sprintf("%d", $chars[$i]); # $i + 1 is equivelent to the position on the port $stationNumber = ($i+1); # may not have a station for all ports unless (exists($settings->{ports}->{$stationNumber})) {next;} # station id $station = $settings->{ports}->{$stationNumber}->{id}; if ($status != $checkFor) { print "--[ houston we have a problem\n"; $writeStatus = $settings->{statusBad}; $color = $settings->{colorBad}; $sendMail = 1; }else{ print "--[ all ok \n"; $writeStatus = $settings->{statusGood}; $color = $settings->{colorGood}; $sendMail = 0; } $settings->{ports}->{$stationNumber}->{status} = $writeStatus; $settings->{ports}->{$stationNumber}->{sendMail} = $sendMail; $settings->{ports}->{$stationNumber}->{color} = $color; print "--[ " . $station . " on port " . $stationNumber . " is +" . $writeStatus . "\n"; } return; }