Device::SerialPort on debian Buster

	Before I take this too far, I want to make sure I am not
doing something wrong with use of the Device::SerialPort module
in perl.

	The code below talks to what it thinks is a RS-232 serial
port and controlls a radio scanner so that one can program the
scanner's settings and enter frequency and operational data.
Don't worry about all that.  It used to work on debian stretch
which is last year's version of debian.  After an upgrade to
buster which is this year's version, also known as debian 10, all
RS-232 ports appear to be dead.  Interestingly enough, a debian
system running stretch, containing perl was upgraded to buster
and serial communications between that system and a native serial
port on it's mother board are fine.  The very same code ported to
the buster system also fails with
Can't call method "baudrate" on an undefined value at /home/martin/etc/mm =
line 121.

	It doesn't matter what serial port or whether it is
native mother board hardware or what.  Serial ports are all
broken right now.

	Here is the scanner control code.  I am sending it to see
if I am using some deprecated method that is wrong to set the
serial port or we really do have big trouble.

	Thanks for any and all constructive ideas.  Code follows:



#!/usr/bin/perl -w
use strict;
use warnings::unused;
use File::Basename;
use File::Copy;
use File::Spec;
use Time::Local;
use Device::SerialPort;

sub waitfor {    #Receive from serial port.

    my $received =3D "";
    our $port;

    until ( "" ne $received ) {
        $received =3D $port->lookfor;
    }
    return ($received);
}    #Receive from serial port.

#no more sub routine code past this point

#main global variables
our @dbstrings;

#main local variables
my $response;
my $cmd    =3D "";
my $ONEARG =3D "";

#my $counter =3D 1;

#Setup the comm port.
my $dev =3D "/dev/ttyACM0";
our $instring =3D "";
our $port     =3D Device::SerialPort->new("$dev");
$port->baudrate(115200);
$port->databits(8);
$port->parity("none");
$port->stopbits(1);
$port->handshake("none");
$port->read_const_time(500);    # 500 milliseconds =3D 0.5 seconds
$port->are_match( "\r", "\n", );    # possible end strings

foreach $ONEARG (@ARGV) {           #each argument
    $ONEARG =3D~ s/^\s+//;
    $ONEARG =3D~ s/\s+$//;
    $cmd =3D $cmd . " " . $ONEARG;
    $cmd =3D~ s/^\s+//;
    $cmd =3D~ s/\s+$//;
}    #each argument

$cmd =3D uc $cmd;
$port->write("$cmd\r");
$instring =3D waitfor;
my @chars =3D split( "", $instring );
foreach my $char (@chars) {    #

    #print ord($char);
    if ( $char =3D~ /[\,\s\.\-\+\_0-9A-Za-z]/ ) {    #printable
        $response =3D $response . $char;
    }    #printable
}    #
print "$response\n";
$instring =3D "";
exit(0);
0
martin
7/10/2019 1:51:08 PM
perl.beginners 29344 articles. 3 followers. Follow

2 Replies
13 Views

Similar Articles

[PageSpeed] 10

Hi Martin,

commenting on your code:

On Wed, 10 Jul 2019 08:51:08 -0500
"Martin McCormick" <martin.m@suddenlink.net> wrote:

> 	Before I take this too far, I want to make sure I am not
> doing something wrong with use of the Device::SerialPort module
> in perl.
>=20
> 	The code below talks to what it thinks is a RS-232 serial
> port and controlls a radio scanner so that one can program the
> scanner's settings and enter frequency and operational data.
> Don't worry about all that.  It used to work on debian stretch
> which is last year's version of debian.  After an upgrade to
> buster which is this year's version, also known as debian 10, all
> RS-232 ports appear to be dead.  Interestingly enough, a debian
> system running stretch, containing perl was upgraded to buster
> and serial communications between that system and a native serial
> port on it's mother board are fine.  The very same code ported to
> the buster system also fails with
> Can't call method "baudrate" on an undefined value at /home/martin/etc/mm
> line 121.
>=20
> 	It doesn't matter what serial port or whether it is
> native mother board hardware or what.  Serial ports are all
> broken right now.
>=20
> 	Here is the scanner control code.  I am sending it to see
> if I am using some deprecated method that is wrong to set the
> serial port or we really do have big trouble.
>=20
> 	Thanks for any and all constructive ideas.  Code follows:
>=20
>=20
>=20
> #!/usr/bin/perl -w

See https://perl-begin.org/tutorials/bad-elements/#the-dash-w-flag .

> use strict;

good!

> use warnings::unused;
> use File::Basename;
> use File::Copy;
> use File::Spec;
> use Time::Local;
> use Device::SerialPort;
>=20

Use explicit imports -
https://perl-begin.org/tutorials/bad-elements/#non_explicitly_imported_symb=
ols

> sub waitfor {    #Receive from serial port.
>=20
>     my $received =3D "";
>     our $port;

"our" inside a function?

>=20
>     until ( "" ne $received ) {

double negative and perhaps use
https://stackoverflow.com/questions/223393/how-do-i-get-the-length-of-a-str=
ing-in-perl
>         $received =3D $port->lookfor;
>     }
>     return ($received);
> }    #Receive from serial port.
>=20
> #no more sub routine code past this point
>=20
> #main global variables
> our @dbstrings;
>=20
> #main local variables
> my $response;
> my $cmd    =3D "";
> my $ONEARG =3D "";
>=20
> #my $counter =3D 1;
>=20
> #Setup the comm port.
> my $dev =3D "/dev/ttyACM0";
> our $instring =3D "";
> our $port     =3D Device::SerialPort->new("$dev");

why our?
> $port->baudrate(115200);
> $port->databits(8);
> $port->parity("none");
> $port->stopbits(1);
> $port->handshake("none");
> $port->read_const_time(500);    # 500 milliseconds =3D 0.5 seconds
> $port->are_match( "\r", "\n", );    # possible end strings
>=20
> foreach $ONEARG (@ARGV) {           #each argument

see https://perl-begin.org/tutorials/bad-elements/#non_lexical_loop_iterato=
rs

>     $ONEARG =3D~ s/^\s+//;
>     $ONEARG =3D~ s/\s+$//;

perhaps use \A and \z

>     $cmd =3D $cmd . " " . $ONEARG;

use ".=3D"

>     $cmd =3D~ s/^\s+//;
>     $cmd =3D~ s/\s+$//;
> }    #each argument
>=20
> $cmd =3D uc $cmd;
> $port->write("$cmd\r");
> $instring =3D waitfor;


see https://perl-begin.org/tutorials/bad-elements/#declaring_all_vars_at_to=
p .

> my @chars =3D split( "", $instring );
> foreach my $char (@chars) {    #
>=20
>     #print ord($char);
>     if ( $char =3D~ /[\,\s\.\-\+\_0-9A-Za-z]/ ) {    #printable
>         $response =3D $response . $char;

use .=3D and you can use https://perldoc.perl.org/functions/join.html and r=
egex
matches. it is good that you follow
https://perl-begin.org/tutorials/bad-elements/#using-character-classes-with=
-unicode-text
..
>     }    #printable
> }    #
> print "$response\n";
> $instring =3D "";
> exit(0);
>

Why the assignment right before exiting?=20

I'm not sure if any of the issues I pointed are the culprit.

--=20
-----------------------------------------------------------------
Shlomi Fish       http://www.shlomifish.org/
https://github.com/sindresorhus/awesome - curated list of lists

Chuck Norris does not code; when he sits at a computer, it just does whatev=
er
he wants. =E2=80=94 Kattana on Freenode=E2=80=99s #perl6 .
    =E2=80=94 http://www.shlomifish.org/humour/bits/facts/Chuck-Norris/

Please reply to list if it's a mailing list post - http://shlom.in/reply .
0
shlomif
7/11/2019 10:20:05 AM
On Wed, 10 Jul 2019 08:51:08 -0500
"Martin McCormick" <martin.m@suddenlink.net> wrote:
> 	The code below talks to what it thinks is a RS-232 serial
> port and controlls a radio scanner so that one can program the
> scanner's settings and enter frequency and operational data.
> Don't worry about all that.  It used to work on debian stretch
> which is last year's version of debian.  After an upgrade to
> buster which is this year's version, also known as debian 10, all
> RS-232 ports appear to be dead.  [...]
> The very same code ported to the buster system also fails with
> Can't call method "baudrate" on an undefined value
> at /home/martin/etc/mm line 121.

OK, so it failed to get the Device::SerialPort object; there's no
error-checking in your code where you instantiate it, so it explodes on
the next line when you try to call a method on it:

> our $port     = Device::SerialPort->new("$dev");
> $port->baudrate(115200);

Adding some error checking could help - e.g.:

  my $port = Device::SerialPort->new($dev)
      or die "Failed to open serial port $dev - $!";

I'd guess that $! may contain an error explaining what happened - and
the constructors section of Device::SerialPort's doco supports that.

Try modifying your code as mentioned above, and see what error you
get.  (And, while you're modifying, Shlomi's helpful review of your
code contained loads of useful advice too - but you might want to focus
on just resolving the actual problem first I guess).

I'd also, without having seen anything else, take a gut feeling guess
in the dark that Buster has changed the permissions applied to serial
port device nodes, possibly via AppArmor and that the user you run your
code as no longer has access to open the port - but that *is* just a
guess - you'll know if it's right if your modified code reports a
permissions error as it dies.

If so, you could look at the device node permissions to see the user
and group it's owned by, e.g.:

[davidp@supernova:~]$ ls -l /dev/ttyS0
crw-rw---- 1 root dialout 4, 64 Jul  8 09:28 /dev/ttyS0

.... change to suit which device you're trying to use, and make sure your
user is a member of the group specified.


Cheers

Dave P (BIGPRESH)
0
davidp
7/11/2019 3:41:49 PM
Reply: