usb-uirt-config.pl

#!/usr/bin/perl## Copyright (C) 2007 Kenneth L. Root. <https://the-b.org>## This program is free software: you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation, either version 3 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program.  If not, see <https://www.gnu.org/licenses/>.
use strict;use warnings;
use Device::SerialPort;use Getopt::Long;use Pod::Usage;
use constant TIMEOUT_DEFAULT => 10;
use constant TRANSMITTING => 0x20;use constant CMDOK => 0x21;use constant CSERROR => 0x80;use constant TOERROR => 0x81;use constant CMDERROR => 0x82;
use constant ACTIONS => ['Pulse pin (positive)',                        'Set pin',                        'Clear pin',                        'Pulse pin (negative)',                        ];
my %config = (        'port' => '/dev/ttyUSB0',        'slot' => 0);
my $port;
my $slots = -1;
sub openPort {  my($portName) = @_;
  my $port = new Device::SerialPort($portName)        || die "Can't open $portName: $!\n";
  $port->read_char_time(0);  $port->read_const_time(1000);
  return $port;}
sub checksum {  my(@bytes) = @_;
  my $cksum = 0;
  map { $cksum += $_ } @bytes;
  return 0x100 - ($cksum & 0xFF);}
sub printCommand {  my ($prefix, @cmd) = @_;
  print "$prefix: ";
  map { printf "0x%02x ", $_ } @cmd;
  print "\n";}
sub sendCommand {  my @cmd = @_;
  push @cmd, checksum(@cmd);
  printCommand("send", @cmd) if $config{'debug'};
  $port->write(pack('C*', @cmd));}
sub readCommand {  my($numBytes) = @_;
  my $timeout = TIMEOUT_DEFAULT;  my $buffer;  my $chars = 0;
  while ($timeout > 0) {    my ($count, $saw) = $port->read(255);    if ($count > 0) {      $chars += $count;      $buffer .= $saw;      if ($chars >= $numBytes) {        my @cmd = map { ord } unpack("(Z)*", $buffer);
        printCommand("recv", @cmd) if $config{'debug'};
        return @cmd;      }    } else {      $timeout--;    }  }
  if ($timeout == 0) {    die "Couldn't communicate with USB-UIRT device after ". TIMEOUT_DEFAULT ." seconds.\n";  }}
sub getVersion {  my $printing = shift;
  sendCommand(0x23);  my @res = readCommand(7);
  return if not $printing;
  print "Firmware information:\n";  printf "\tFirmware version = %d.%d\n", $res[1], $res[0];  printf "\tProtocol compatability version = %d.%d\n", $res[3], $res[2];  # Y3K bug  printf "\tFirmware date (DMY) = %02d/%02d/%02d\n", $res[4], $res[5], $res[6] + 2000;}
sub setUIRMode {  sendCommand(0x20);  my @res = readCommand(1);  die "Cannot set UIR mode" if ($res[0] != CMDOK);}
sub getGpioCaps {  my $printing = shift;
  sendCommand(0x30, 0x01);
  my @res = readCommand(6);
  die "Failed to get GPIO caps" if (checksum(@res[0..$#res-1]) != $res[$#res]);
  $slots = $res[0];
  return if not $printing;
  print "GPIO capabilities:\n";  printf "\tNumber of slots = %d\n", $slots;  foreach my $slot (0..$slots-1) {    printf "\tPort %c bitmask: %08b\n", (ord("A") + $slot), $res[1+$slot];;  }}
sub getGpioCfg {  my ($slot) = @_;
  getGpioCaps if ($slots == -1);
  die "No such programmable slot: $slot" if ($slot > $slots);
  sendCommand(0x31, 0x02, $slot);  my @res = readCommand(9);  die "Failed to get GPIO config for slot $slot"        if (checksum(@res[0..$#res-1]) != $res[$#res]);
  my $action = ($res[6] & 0xC0) >> 6;  my $port = ($res[6] & 0x18) >> 3;  my $pin = $res[6] & 0x03;  my $duration = $res[7] * 5;
  print "GPIO configuration for slot $slot\n";  printCommand("\tIR Code", @res[0..5]);  print "\tPin action: " . ACTIONS->[$action] . "\n";  print "\tPort: ". chr(ord("A") + $port) .".". $pin . "\n";  print "\tDuration: ". $duration ." ms\n";}
sub setWakeUpCode {  my ($slot, @irCode) = @_;
  # bit   7,6: 11 (Pulse Pin (negative))  # bit     5: reserved  # bit   4,3: 00 (Port A)  # bit 2,1,0: 011 (Pin 3)  my $action = 0xC3;  my $duration = 100 / 5; # Duration is in 5mS increments.
  sendCommand(0x32, 0x0A, $slot, @irCode, $action, $duration);  my @res = readCommand(1);
  if ($res[0] == CMDOK) {    print "Successfully set Wake-Up code in slot $slot.\n";  } else {    print "Error setting Wake-Up code.\n";  }}
sub getConfiguration {  sendCommand(0x38, 0x01);
  my @res = readCommand(3);
  print "Configuration:\n";  print "\tLED blink on IR TX: " . ((($res[0] & 0x01) == 0x01) ? "yes" : "no") ."\n";  print "\tLED blink on IR RX: " . ((($res[0] & 0x02) == 0x02) ? "yes" : "no") ."\n";}
sub compareCodes {  my ($first, $second) = @_;
  no warnings;
  return 0 unless @$first == @$second;  for (my $i = 0; $i < @$first; $i++) {    return 0 if ($first->[$i] ne $second->[$i]);  }  return 1;}
GetOptions(\%config,        'help|?',        'debug!',        'port=s',        'version!',        'get-configuration!',        'gpio-capabilities|gpiocaps|gpio-caps!',        'slot-configuration!',        'wakeup!',        'slot=i',        'get-code!',        'code=s',);
if (exists $config{'help'}) {  pod2usage(1);}
$port = openPort($config{'port'});
print "Opened port ". $config{'port'} ."\n" if ($config{'debug'});
getVersion($config{'version'});exit(0) if $config{'version'};
if (exists $config{'gpio-capabilities'}) {  getGpioCaps(1);  exit(0);}
if (exists $config{'get-configuration'}) {  getConfiguration;  exit(0);}
if (exists $config{'slot-configuration'}) {  getGpioCfg($config{'slot'});  exit(0);}
if (exists $config{'get-code'}) {  setUIRMode;  print "Press the button on the remote you want to see the UIR code for...\n";  my @res = readCommand(6);  printCommand("IR Code", @res);  exit(0);}
if ($config{'wakeup'}) {  if (not exists $config{'code'}) {    setUIRMode;    print "Press key on remote that you want to be the Wake-Up key...\n";    my @code1 = readCommand(6);
    my $tries = 6;    my $identical = 0;    while ($tries-- > 0 && !$identical) {      print "Press key on remote that you want to be the Wake-Up key again...\n";      my @code2 = readCommand(6);
      $identical = compareCodes(\@code1, \@code2);      if (not $identical) {        @code1 = @code2;        print "Codes are not identical. Please press the button again...\n";      }    }    if ($tries == 0) {      print "Couldn't get two identical codes! Exiting...\n";      exit(1);    }
    $config{'code'} = \@code1;  }
  setWakeUpCode($config{'slot'}, @{$config{'code'}});  getGpioCfg($config{'slot'});  exit(0);}
$port->close        || die "Failed to close ". $config{'port'} .": $!\n";
print "No actions specified!\n";pod2usage(1);exit(1);
__END__
=head1 NAME
usb-uirt-config - Configuration program for the USB-UIRT
=head1 SYNOPSIS
usb-uirt-config [options]
=head1 OPTIONS
=over 8
=item B<--port>
Serial port to which USB-UIRT is connected.
=item B<--debug>
Enable debugging.
=item B<--version>
Output USB-UIRT version.
=item B<--get-configuration>
Prints out the USB-UIRT's current configuration.
=item B<--gpio-capabilities>
Get GPIO capabilities of USB-UIRT.
=item B<--slot-configuration>
Get GPIO configuration for a single slot.
=item B<--get-code>
Reads and prints an incoming IR code.
=item B<--wakeup>
Configure wake-up on GPIO slot
=item B<--slot>
Specify GPIO slot to configure.
=item B<--code>
IR code to use (not yet implemented).
=back
=head1 DESCRIPTION
Configures the USB-UIRT device.=cut

Kenny Root

Copyright © Kenny Root. All rights reserved.