Serial Port programming - Reading DSR from port

Discussion in 'Perl Misc' started by msalerno, Jul 11, 2005.

  1. msalerno

    msalerno Guest

    I have a device that uses the dsr for communications. Basically what I
    am trying to do is get a count of how many pulses it sends per second.
    I have a script that counts the pulses, but there is something wrong.
    It is counting too many pulses. I think that what is happening is that
    it is counting one pulse many times. I know my count is wrong because I
    have some windows software that works, and when I compare the output of
    the windows software to the output of my script, the script is way off.
    If anyone out there could point me in the correct direction I would be
    very happy. It's tough to find informaion about monitoring the DSR
    lines. Does anyone here have any experience with a similar situation?

    #!/usr/bin/perl -w
    use strict;
    use Time::HiRes qw(usleep);

    use Device::SerialPort qw( :pARAM :STAT 0.07 );

    my %logged;
    my @then;

    # Open Serial Port
    my $PortObj = new Device::SerialPort ('/dev/ttyS0') || die "Cannot open
    Port: $!\n";

    while () {
    my $ModemStatus = $PortObj->modemlines;

    my $hour = ((localtime)[2]); $hour = "0$hour" if length($hour)
    < 2;
    my $min = ((localtime)[1]); $min = "0$min" if length($min) < 2;
    my $sec = ((localtime)[0]); $sec = "0$sec" if length($sec) < 2;
    my $now = "$hour-$min-$sec";

    push @then, $now;
    push @then, $now if $#then < 1;
    shift @then if $#then > 1;

    if (!exists($logged{$now})){
    $logged{$now} = 0;
    my $val1 = sprintf "%.2f", $logged{$then[-2]}/3.4;
    my $val2 = sprintf "%.2f", $logged{$then[-2]}/2.5;
    print "Then:$then[-2] - $logged{$then[-2]} - $val1 -

    my $pulse = 0!=($ModemStatus & MS_DSR_ON);

    $pulse = 0 if !$pulse;

    $logged{$now} = $pulse + $logged{$now};
    if ($pulse == 1){
    usleep(1); # sleep one milisecond if change detected.

    msalerno, Jul 11, 2005
    1. Advertisements

  2. Jim Gibson wrote:
    > In article <>,
    > msalerno <> wrote:
    >> my $hour = ((localtime)[2]); $hour = "0$hour" if length($hour)
    >>< 2;
    >> my $min = ((localtime)[1]); $min = "0$min" if length($min) < 2;
    >> my $sec = ((localtime)[0]); $sec = "0$sec" if length($sec) < 2;
    >> my $now = "$hour-$min-$sec";

    > Better, because you are calling localtime 3 times (untested):
    > my $now = sprintf( "%.2d-%.2d-%.2d", (localtime)[0..2] );

    It looks like the OP wants this instead:

    my $now = sprintf '%02d-%02d-%02d', ( localtime )[ 2, 1, 0 ];

    use Perl;
    John W. Krahn, Jul 12, 2005
    1. Advertisements

  3. msalerno

    msalerno Guest

    I changed the $now variable to use the sprintf. Thanks for that one.
    I changed the usleep(1) to usleep(1000), again thanks.

    The device (an anemometer) does not use a baud rate. The windows
    software looks at the signal from the reed switch in the anemometer
    head and measures the time between transitions of the switch. It sends
    the signal through the DSR channel. The conversion between switch
    pulses per second and MPH are either 1 pulse/second = 2.5 or 3.4 MPH. I
    think that I need to debounce the opening and/or closing transitions of
    the reed switch, I am pretty sure that this is where my problem is, but
    I don't know how to solve it. I added/removed/changed a 1 millisecond
    delay once I see a 1 in the $pulse variable, but I am still getting
    crazy numbers.

    I have also commented out the lines that check for $pulse == 1, and
    left the usleep in, so it will always sleep. The numbers are still

    Thanks for the help, any other ideas?
    msalerno, Jul 12, 2005
  4. msalerno <> kirjoitti 11.07.2005:
    > I have a device that uses the dsr for communications. Basically what I
    > am trying to do is get a count of how many pulses it sends per second.

    > my $pulse = 0!=($ModemStatus & MS_DSR_ON);

    > if ($pulse == 1){
    > usleep(1); # sleep one milisecond if change detected.
    > }

    Here's one major problem: $pulse will be 1 if the DSR line is on, not
    if it has changed.

    Anyway, here's how I'd rewrite your script:

    #!/usr/bin/perl -w
    use strict;
    use Time::HiRes qw(time sleep);
    use Device::SerialPort qw( :pARAM :STAT 0.07 );

    use constant SAMPLE_STEP => 1/1000; # sample once per msec
    use constant REPORT_STEP => 1; # report once per second

    # Open Serial Port
    my $PortObj = new Device::SerialPort ('/dev/ttyS0')
    or die "Cannot open Port: $!\n";

    my $lastdsr = $PortObj->modemlines & MS_DSR_ON;
    my $t0 = time;

    while (1) {
    my $changes = 0;
    while (time < $t0 + REPORT_STEP) {
    my $dsr = $PortObj->modemlines & MS_DSR_ON;
    $changes++ if $dsr xor $lastdsr;
    $lastdsr = $dsr;
    sleep SAMPLE_STEP;
    printf "%02d-%02d-%02d: %d - %.2f - %.2f\n",
    (localtime int $t0)[2, 1, 0], $changes,
    $changes / (3.4 * REPORT_STEP),
    $changes / (2.5 * REPORT_STEP);
    $t0 += REPORT_STEP;

    I haven't tested this code, as I don't have Device::SerialPort
    installed, nor do I have any suitable signal source available either.
    But I'm fairly confident it should work.

    The code counts state changes in both directions. If you only want to
    count transitions from off to on, replace "xor" with "and not".

    I'm assuming that SAMPLE_STEP is sufficiently small that no pulses can
    ever be missed. Therefore I haven't bothered to synchronize the inner
    loop; the actual time between samples will be SAMPLE_STEP plus however
    long it takes to execute the inner loop.

    The outer loop, however, is synchronized, which means you'll get
    reports exactly once every REPORT_STEP seconds on average, and there
    should be no statistical bias in the output (ignoring possible
    floating point roundoff errors). Actually, I think your original code
    would've worked the same way, had it worked correctly at all.

    Note that there's really nothing Perl-specific about this. The same
    code could be trivially ported to C or Java or just about any other
    language. Only the interfaces to the serial port and the system timer
    would change.

    Ilmari Karonen
    To reply by e-mail, please replace ".invalid" with ".net" in address.
    Ilmari Karonen, Jul 14, 2005
    1. Advertisements

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jim Hatfield

    Serial Port programming

    Jim Hatfield, Jun 15, 2004, in forum: Java
    Dale King
    Apr 15, 2006
  2. rfid
  3. crypto

    Serial Port Programming

    crypto, May 16, 2005, in forum: Java
    Dale King
    May 18, 2005
  4. Pom
    Jul 15, 2016
  5. Replies:
  6. Ani
    Jul 10, 2007
  7. Sabyasachi  Mustafi

    serial port programming

    Sabyasachi Mustafi, Apr 7, 2004, in forum: Ruby
    Stephan Kämper
    Apr 7, 2004
  8. Friend

    DSR and OpenSSL question

    Friend, Dec 12, 2013, in forum: C++
    red floyd
    Dec 12, 2013