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

I am writing a program to download information from a radio scanner so I can make changes and re-upload. Anyway, I have the following code that actually works to a point, it writes and read to and from the scanner but is dropping characters I expect to be read in and not lost. The program I am mimicing keeps characters I am losing. Here is the code: (this is the smallest amount I thought would help give you how to help me out.)
#!/usr/bin/perl -w use strict; use warnings; use Win32::SerialPort; my $psr500bin = 'C:/Users/mbates/Documents/My PSR 500/20080330-mydownl +oad.bin'; open (FILE_IN_1, "> $psr500bin") or die "Could not open $psr500bin for write: $!\n"; binmode(FILE_IN_1); my $port_name = 'COM4'; my $config_file = 'tpj4.cfg'; my $port = new Win32::SerialPort($port_name, $config_file) || die "Una +ble to open: $^E\n"; #Setup the parameters $port->baudrate(115200) #$port->baudrate(38400) || die "Can't set serial port baudrate ...\n"; $port->parity("none") || die "Can't set serial port parity ...\n"; $port->databits(8) || die "Can't set serial port databits ...\n"; $port->stopbits(1) || die "Can't set serial port stopbits ...\n"; #$port->handshake('xoff'); $port->handshake('rts') || die "Can't set serial port handshake ...\n"; $port->binary('T'); $port->stty_echo(0); $port->stty_igncr(0); $port->stty_echoctl(0); $port->datatype('raw'); #my $dtr=$port->dtr_active(0); # my $rts=$port->rts_active(0); $port->write_settings || die "Can't write setting ...\n"; $port->read_char_time(1); #$port->read_const_time(1000); my $baud = $port->baudrate; my $parity = $port->parity; my $data = $port->databits; my $stop = $port->stopbits; my $hshake = $port->handshake; print "B = $baud, D = $data, S = $stop, P = $parity, H = $hshake\n"; $port-> error_msg(1); # prints hardware messages like "Framin +g Error" $port-> user_msg(1); # prints function messages like "Waiting + for my $status = pack('C*', 0x02, 0x50, 0x01, 0x03, 0x54 ); $port->write($status); sleep 1; $status = pack('C*', 0x45 ); $port->write($status); sleep 1; $port->lookclear; #clear the buffer $port->read_interval(0); $port->read_const_time(1000); my $in; my ($InBytes, $count_in); $InBytes = 132; ($count_in, $in) = $port->read($InBytes); warn "read unsuccessful\n" unless ($count_in == $InBytes); my $done = 0; my $blk; my $err; my $out; my $result; my $buf_in; my $count_total = 0; $count_total = $count_in; $buf_in = $in; my $reads = 1; print "CountIN: $count_in Reads: $reads Count Total: $count_total\n" +; $InBytes = 132; print_hex($in); for (;;) { ($count_in, $in) = $port->read($InBytes); warn "read unsuccessful\n" unless ($count_in == $InBytes); $reads = $reads + 1; $count_total = $count_total + $count_in; print "CountIN: $count_in Reads: $reads Count Total: $count_tot +al \n"; $buf_in = $buf_in . $in; print_hex($in); last if ($count_in == 0); } print FILE_IN_1 $buf_in; $port->close || warn "Close Failed!\n"; undef $port; close(FILE_IN_1);
The code reads and prints:
55 55 05 2f 10 05 10
and I am expecting:
55 55 01 05 2F 00 00 00 00 10 05 10
Any ideas? I have tried using a tie to filehandle with syswrite and sysread, but sysread is choking on something I have not figured out yet. Thanks Mike

Replies are listed 'Best First'.
Re: Win32:SerialPort not reading all characters
by GrandFather (Saint) on Mar 31, 2008 at 04:09 UTC

    It is interesting to note that the missing characters have values of 1 and 0. In particular the run of four missing 0 (null) characters somewhat argues against the problem being buffer overrun or framing related and suggests some sort of software filtering issue.


    Perl is environmentally friendly - it saves trees
      Grandfather, I think you are right there seems to be some kind of filtering or processing that does not pass through certain types of bytes. I have included the following two settings in my code to show errors.
      $port-> error_msg(1); # prints hardware messages like "Framin +g Error" $port-> user_msg(1); # prints function messages like "Waiting + for
      I was able to generate buffer overflows in a test I ran to prove the overflows and framing errors would be caught, but that does not account for the missing characters in my code. Since running the code does not generate buffer overflow errors at this time. Buffer overflows would account for missing characters at the end of the stream.

      The file from the scanner is 67452 bytes and the program here downloads 62451 bytes. I was running a port monitor and watch the 01, 00, 02 and 03 come from the scanner on the download but they did not seem to get passed through Win32::SerialPort as characters. The program I am mimicing does include all those characters in the output file.

      Thanks Mike

Re: Win32:SerialPort not reading all characters
by starbolin (Hermit) on Mar 31, 2008 at 03:08 UTC

    With serial drivers one always worries about overruns and framing errors. These are usually the reason for lost data. Probably also the reason sysread is choking. I would expect to see some error handling in your read loop but I don't see any. Something like: (From the manual)

    ($BlockingFlags, $InBytes, $OutBytes, $LatchErrorFlags) = $PortObj->i +s_status || warn "could not get port status\n"; $ClearedErrorFlags = $PortObj->reset_error; # The API resets errors when reading status, $LatchErrorFlags # is all $ErrorFlags since they were last explicitly cleared if ($BlockingFlags) { warn "Port is blocked"; } if ($BlockingFlags & BM_fCtsHold) { warn "Waiting for CTS"; } if ($LatchErrorFlags & CE_FRAME) { warn "Framing Error"; }

    Does your device implement rts/cts flow control? Does the serial cable contain the rts/cts lines. Do any adapters omit those lines?


    s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}
Re: Win32:SerialPort not reading all characters
by starbolin (Hermit) on Mar 31, 2008 at 03:06 UTC

    With serial drivers one always worries about overruns and framing errors. These are usually the reason for lost data. Probably also the reason sysread is choking. I would expect to see some error handling in your read loop but I don't see any. Something like:

     if ($LatchErrorFlags & CE_FRAME) { warn "Framing Error"; }

    Does your device implement rts/cts flow control? Does the serial cable contain the rts/cts lines. Do any adapters omit those lines?


    s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}
Re: Win32:SerialPort not reading all characters
by BrowserUk (Patriarch) on Mar 31, 2008 at 12:23 UTC
      BrowserUK,

      I will have to look at the laptop. Using a USB serial device to download data from the radio scanner. I am monitoring the port and all the data is coming from the scanner but it seems as if the program is filtering out specific bytes 00, 01, 02 and 03 from what I can tell so far. It may be filtering out these bytes as control characters that should just pass through as I see them in the monitor and the other program I am mimicing handles them just fine. I wonder if this is the way Win32::SerialPort is suppose to work or if I just have an incorrect setting.

      Mike

        A couple of things you could try:

        1. Check/configure the port using the MODE command.
          C:> mode com1 Status for device COM1: ----------------------- Baud: 1200 Parity: None Data Bits: 7 Stop Bits: 1 Timeout: OFF XON/XOFF: OFF CTS handshaking: OFF DSR handshaking: OFF DSR sensitivity: OFF DTR circuit: ON RTS circuit: ON c:> help mode Configures system devices. Serial port: MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s] [to=on|off] [xon=on|off] [odsr=on|off] [octs=on|off] [dtr=on|off|hs] [rts=on|off|hs|tg] [idsr=on|off] Device Status: MODE [device] [/STATUS] ...
        2. Then you can isolate whether it is perl or the module or the port configuration by driving the port manually.

          Write the command sequence into a file using a (binary capable) editor. Then send that sequence to the device: copy file.bin /b comN: /b

          Then retrieve the response using the same technique: copy comN/b response.bin /b. Then you can check the file to see what you get.

          By configuring the port using mode, you can start with a slow transmission rate (say 1200), and whatever handshaking (rts=on or xon=on) until you get reliable transmission. Then slowly ramp the baud rate until it starts to fail or you reach the maximum.

          Once you've figured out what the device is capable of, you can automate the process using the module .


        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: Win32:SerialPort not reading all characters
by zentara (Cardinal) on Mar 31, 2008 at 15:53 UTC
      zentara,

      I actually saw this over the weekend and used it to deal with my initial communication issues. This seems to be more an issue of what is coming off the serial port through Win32::SerialPort then packing/unpacking issue as that is working very cleanly.

      Mike