Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Device::SerialPort on debian Buster

29 views
Skip to first unread message

Shlomi Fish

unread,
Jul 11, 2019, 7:15:05 AM7/11/19
to Martin McCormick, begi...@perl.org
Hi Martin,

commenting on your code:

On Wed, 10 Jul 2019 08:51:08 -0500
"Martin McCormick" <mart...@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.
>
> 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

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;
>

Use explicit imports -
https://perl-begin.org/tutorials/bad-elements/#non_explicitly_imported_symbols

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

"our" inside a function?

>
> until ( "" ne $received ) {

double negative and perhaps use
https://stackoverflow.com/questions/223393/how-do-i-get-the-length-of-a-string-in-perl
> $received = $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 = "";
> my $ONEARG = "";
>
> #my $counter = 1;
>
> #Setup the comm port.
> my $dev = "/dev/ttyACM0";
> our $instring = "";
> our $port = 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 = 0.5 seconds
> $port->are_match( "\r", "\n", ); # possible end strings
>
> foreach $ONEARG (@ARGV) { #each argument

see https://perl-begin.org/tutorials/bad-elements/#non_lexical_loop_iterators

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

perhaps use \A and \z

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

use ".="

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


see https://perl-begin.org/tutorials/bad-elements/#declaring_all_vars_at_top .

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

use .= and you can use https://perldoc.perl.org/functions/join.html and regex
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 = "";
> exit(0);
>

Why the assignment right before exiting?

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

--
-----------------------------------------------------------------
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 whatever
he wants. — Kattana on Freenode’s #perl6 .
http://www.shlomifish.org/humour/bits/facts/Chuck-Norris/

Please reply to list if it's a mailing list post - http://shlom.in/reply .

David Precious

unread,
Jul 11, 2019, 12:00:05 PM7/11/19
to begi...@perl.org
On Wed, 10 Jul 2019 08:51:08 -0500
"Martin McCormick" <mart...@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)

Mike

unread,
Aug 5, 2019, 5:45:04 AM8/5/19
to begi...@perl.org, mart...@suddenlink.net

I didn't see a lot of responses to this, so I guess
you really answered your own question.  Must be something
wrong with the Buster OS.

See if these do you any good:
https://forum.arduino.cc/index.php?topic=109475.0
https://www.linuxquestions.org/questions/ubuntu-63/serial-port-problem-516635/


Mike



On 7/10/2019 8:51 AM, Martin McCormick 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.
>
> 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 = "";
> our $port;
>
> until ( "" ne $received ) {
> $received = $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 = "";
> my $ONEARG = "";
>
> #my $counter = 1;
>
> #Setup the comm port.
> my $dev = "/dev/ttyACM0";
> our $instring = "";
> our $port = 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 = 0.5 seconds
> $port->are_match( "\r", "\n", ); # possible end strings
>
> foreach $ONEARG (@ARGV) { #each argument
> $ONEARG =~ s/^\s+//;
> $ONEARG =~ s/\s+$//;
> $cmd = $cmd . " " . $ONEARG;
> $cmd =~ s/^\s+//;
> $cmd =~ s/\s+$//;
> } #each argument
>
> $cmd = uc $cmd;
> $port->write("$cmd\r");
> $instring = waitfor;
> my @chars = split( "", $instring );
> foreach my $char (@chars) { #
>
> #print ord($char);
> if ( $char =~ /[\,\s\.\-\+\_0-9A-Za-z]/ ) { #printable
> $response = $response . $char;
0 new messages