#!/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.