I'm going to use the format [----FILENAME----] and then paste the file.  The 
only change to the perl script was just an edit to make it find the file 
easier.  Perhaps it wasn't even needed.  I have everything in /usr/local/bin.  
To use these you will need to copy paste these into files and make the 
scripts executable.  Myth calls the change_channel scripts.

[Don't forget the alternate keys are for receiver remote code 2.  This is 
settable on the receiver, or at least the ones I have.]

-Robert Denier

[---/usr/local/bin/change_channel.sh---]
#!/bin/bash
perl /usr/local/bin/MyBlaster.pl $1

[---/usr/local/bin/change_channel2.sh---]
#!/bin/bash
cd /usr/local/bin
perl /usr/local/bin/MyBlaster.pl changechannel d2.keys $1

[---/usr/local/bin/d2.keys---]
power = 00001B008B0300C70C1700C7058900BE0354010091111121211111111100
select = 00001B008C0300C90C1500C9058700C00352010091121111211111111100
exit = 00001B008C0300C90C1400C9058600C00357010091121121211111111100
0 = 00001B008C0300C90C1400C9058700C00354010091121112211111111100
1 = 00001B008C0300C90C1500C9058700C00354010091111211211111111100
2 = 00001B008C0300C90C1400C9058700C00354010091111212211111111100
3 = 00001B008C0300C90C1400C9058700C00356010091111221211111111100
4 = 00001B008C0300C90C1500C9058700C9034A010091112111211111111100
5 = 00001B008C0300C90C1400C9058600C9034E010091112112211111111100
6 = 00001B008C0300C90C1400C9058600C90351010091112121211111111100
7 = 00001B008C0300C90C1400C9058700C9034D021091112211211111111100
8 = 00001B008C0300C90C1400C9058700C9034C010091112212211111111100
9 = 00001B008C0300C90C1400C9058700C9034C010091112221211111111100

[---/usr/local/bin/MyBlaster.pl---]
#!/usr/bin/perl

# MyBlaster.pl:  Controller for the MyBlaster serial IR blaster 
(www.mytvstore.com)
# By William Munson [wmunson] (July 26, 2004, ver-1.4)
#
# This code is being released into the public domain for non-profit use.
# For commercial use please contact me at our support forum:
# http://www.mythtvtalk.com/forum/viewtopic.php?p=622#622
#
# Version 1.0 - Initial release of code.
# Version 1.1 - Added macro feature.
# Version 1.2 - Fixed some timing issues in the data transfer to MyBlaster.
# Version 1.3 - Fixed output for devices other than DSS/Satellite receivers.
#             - Added support for port locking which keeps a second instance
#                   suspended until the 1st has completed.
# Version 1.4 - Public Release #1 - Updated documentation for release.
# Version 1.4.1 - Added Learing and emitting learned keys - Vlado


$|=1;
use POSIX qw(:termios_h);
use FileHandle;
use Time::HiRes qw( sleep );


# Defaults to standard COM2 port, 19200 baud.
my $serial=init_serial("/dev/ttyS0","19200"); # Com 1
# my $serial=init_serial("/dev/ttyS1","19200"); # Com 2

# Device code for the piece of equipment you want to control. This info can
# be found in the MyBlaster Library folder.
#
# 775 controls a standard Dishnet receiver.
$remote_code="775";

# Device Type is a hex value from 0 to A and represents the type of device you
# want to control. Below is a list of the available device type codes.
# 0=TV, 1=CABLE, 2=Video Acc, 3=DSS/Satellite, 4-VCR, 5=Laser Disk, 6=DVD
# 7=Tuner/Amp, 8=Amplifier, 9=CD, A=Home Control
$Device_Type="3";

# Duplicate process protection. Enable this if you use the same blaster to 
control
# multiple devices. With this enabled, multiple instances of the program will 
each
# sleep until the blaster port is free. Uses a lock file.
$Use_Locking=0;

# Lock File name.
$LockFile="/tmp/MyBlaster.lock";

# remote file prefix. The file name will be $prefix_<remote>.keys
$remote_prefix = "/home/mythtv/MyBlaster_";

# Use verbose output mode for debugging.
$verbose=0;

# Time delay between each channel digit.
$inter_key_delay=0.1;

# Emit time. This is the length of time the command is sent. Probably a
# good idea to leave this alone but if you are getting repeats of buttons
# then you can shorten it a little bit.
$Emit_Time=0.333;

# Learn Time. This is the length of time we let MyBlaster to try to learn a 
command.
$Learn_Time=3.0;

# Enable to press a key to finalize channel entry
$finalize=1;

# Key used to finalize channel entry
$finalize_key="select";

# Enable to clear the on screen display more quickly.
$quick_clear=1;

# Key used to clear the display. Taken from keymap below.
$quick_clear_key="exit";

# Time to wait until clearing the display
$clear_delay=2.0;

# Misc variables needed by the program
$Count=0;

# These keys should be common to all device codes. The remote buttons
# may have different names. Feel free to change the name but not the value.
%keymap=(1 => "0x01",
                 2 => "0x02",
                 3 => "0x03",
                 4 => "0x04",
                 5 => "0x05",
                 6 => "0x06",
                 7 => "0x07",
                 8 => "0x08",
                 9 => "0x09",
                 0 => "0x0a",
    vol_up => "0x0b",
    vol_dn => "0x0c",
      mute => "0x0d",
     ch_up => "0x0e",
     ch_dn => "0x0f",
     power => "0x10",
     enter => "0x11",
    ch_100 => "0x11",
 last_chan => "0x12",
    tv_sat => "0x13",
     input => "0x13",
      play => "0x14",
      stop => "0x15",
   page_up => "0x16",
      ffwd => "0x16",
       rew => "0x17",
   page_dn => "0x17",
     pause => "0x18",
    record => "0x19",
      menu => "0x1a",
        up => "0x1b",
      down => "0x1c",
      left => "0x1d",
     right => "0x1e",
    select => "0x1f",
      exit => "0x20",
   display => "0x21",
     guide => "0x22");

#config file vars
my %rem_keys;
my @rem_lines;



# Start of main code.
#
# Pull the command line info into the program
$input_cmd=$ARGV[0];

if ($Use_Locking) {
        if (-e $LockFile) { #found a lock file so sleep
                sleep(5.0);
        }
        open(OUTFILE, ">$LockFile") || die "cannot open file"; # create our 
lock file
}

# These bits define which remote control protocol to use and the device type.
#
# Convert remote code to MyBlaster format
$hex_remote_code = sprintf("%X", $remote_code);

if ($remote_code > 255) {
        $hi_bit="0x" . $Device_Type . substr($hex_remote_code, 0, 1);
        $lo_bit="0x" . substr($hex_remote_code, 1, 2);
} else {
        $hi_bit="0x" . $Device_Type . "0";
        if ($remote_code > 15) {
                $lo_bit="0x" . substr($hex_remote_code, 0, 2);
        } else {
                $lo_bit="0x0" . substr($hex_remote_code, 0, 1);
        }
}
print "hi bit = " if ($verbose);
print $hi_bit if ($verbose);
print "\n" if ($verbose);
print "lo bit = " if ($verbose);
print $lo_bit if ($verbose);
print "\n" if ($verbose);


# Start of command decoding

if (length($input_cmd)) {
        # Check to see if a channel number was entered.
        if ($input_cmd != 0) {
                change_channel($input_cmd);
                if ($Use_Locking) {
                        close(OUTFILE);
                        unlink($LockFile);
                }
                exit;
        }
        if ($input_cmd eq "macro") {
                # Do macro command. Use your own key sequence here.
                # Change it around as required for your needs.
                mb_key("down");
                sleep(1.0);
                mb_key("up");
                sleep(1.0);
                mb_key("select");
                sleep(1.0);
                mb_key("display");
                if ($Use_Locking) {
                        close(OUTFILE);
                        unlink($LockFile);
                }
                exit;
        }
        # Attempt to learn a command
        if ($input_cmd eq "learn") {
                $remote = $ARGV[1] || die "No remote name";
                $keyname = $ARGV[2] || die "No key name to learn";
                $keydata = learn_key($keyname);

                # WILL CREATE DUPLICATES and use the first (old one)
                open (FH, ">>" . $remote_prefix . $remote . ".keys");
                printf (FH "$keyname = $keydata\n");
                close (FH);
                print "$keyname = $keydata\n";
                exit;
        }
        # Emit learned key (raw or by name)
        if ($input_cmd eq "send") {
                $key_data = $ARGV[1] || die "No key data\n";
                if (length($key_data) > 29) {                   #this should 
be a raw data - just send it
                        emit_learned_key ($key_data);
                        $stat = get_mb_status();
                }
                else {
                        $remote = $key_data;                            #this 
is a remote, and we should have a key name
                        $key_name = $ARGV[2] || die "No Key name\n";
                        $key_data = lookup_key ($remote, $key_name);
                        emit_learned_key($key_data);
                }
                exit;
        }
        if ($input_cmd eq "changechannel") {
                $remote = $ARGV[1] || die "No remote specified\n";
                $chan = $ARGV[2] || die "No channel number\n";
                change_channel_learned ($remote, $chan);
                exit;
        }
        # No special processing required. Send a single command.
        mb_key($input_cmd);
        if ($Use_Locking) {
                close(OUTFILE);
                unlink($LockFile);
        }
}

# begin subroutines.

sub emit_learned_key {
        $key_data = shift;
        my @bytes;
        $len = length ($key_data);
        die "Invalid key data" if ($len % 2 != 0);    #@@@ TODO: check for non 
hex symbols with a regexp
        $t_len = sprintf("0x%2.2X", 4 + $len / 2);

        @bytes = ("0xBC","0xAC","0x0D","0x00",$t_len,"0x0B","0x00","0x00", 
"0x10");
        $i=0;
                while ($i < length($key_data) ) {
                push (@bytes,"0x" . substr($key_data,$i,2));
                $i++; $i++;
        }
        print "Will send bytes [EMAIL PROTECTED]" if ($verbose);


        simple_command("0x00");         #wake up
        sleep(0.1);
        simple_command(@bytes);
        sleep(0.333);
        simple_command("0x00");         #wake up

        return;
}

sub emit_learned_key_byname {
        $remote = shift;
        $key_name = shift;

        print "elkn $remote/$key_name\n";
}

sub learn_key {
        my $keyname=shift;

        simple_command("0x00");         #wake up
        sleep(0.1);
        simple_command("0xBC","0xAC","0x0D","0x00","0x02","0x06","0x01");  # 
reset
        sleep(0.3);

        print "*** Press and hold '$keyname' on the remote for 5 seconds...
\n";        simple_command("0x00");         #wake up
        sleep(0.1);
        # send the data packet
        
simple_command("0xBC","0xAC","0x0D","0x00","0x03","0x0C","0x00","0x00");  
#learn in buf 0 (always use buf 0)
        sleep($Learn_Time);

        $stat = get_mb_status();
        die "Learning failed with status code $stat\n" if ($stat != 0);
        simple_command("0x00");         #wake up
        sleep(0.1);
        
simple_command("0xBC","0xAC","0x0D","0x00","0x03","0x0D","0x00","0x00");  
#read buf 0 (always use buf 0)
        sleep(0.1);
        $stat = get_mb_status();
        die "Reading learn code failed with status code $stat\n" if ($stat != 
0);


        $len = get_ser_byte();
        $stat = get_ser_byte();
        $len--;  #status was in the length the rest is the key
        $count = 0;
        $str = "";
        while ($count < $len) {
                $b = get_ser_byte();
                $count++;
                $str = sprintf("%s%2.2X", $str, $b);
        }
        print "Learned Key $keyname: $str\n" if ($verbose);
        print "  Length: $count\n" if ($verbose);
        print "  (Suspicious = less then 30)\n" if ($verbose && $len < 30);
        return $str;
}

sub get_mb_status {
        $ret = get_ser_byte();  # get length
        return  if ($ret ne 1);
        return  get_ser_byte();
}

sub get_ser_byte {
        my $starttime=time();
        print "RECVB: " if ($verbose);

        $size = 0;
        while (!$size) {
        $size=sysread($serial,$buf,1);
                if (time() - $starttime > 5) {
                        print "time...\n" if ($verbose);
                        return;
                }
        next;
        }
        print ord($buf),"\n" if ($verbose);
        return ord($buf);
}

sub change_channel_learned {
        # Send a command for each digit of the channel number
        my ($remote) = shift;
        my ($channel_num)=shift;
        my ($position)=0;
        my ($digit)="";

        if ($verbose){
                print "Channel number: ";
                print $channel_num;
                print "\n";
        }
        while ($position<length($channel_num)){
                $digit=substr($channel_num,$position,1);
                if ($verbose){
                        print "Digit: ";
                        print $digit;
                        print "\n";
                }
                #@@@ look up name
                $key_data = lookup_key ($remote, $digit);
                emit_learned_key($key_data);
                $position++;
                sleep($inter_key_delay);
        }
        # wait a little bit and press enter to finalize channel entry
        if ($finalize){
                print "Finalize Entry:\n" if ($verbose);
                $key_data = lookup_key ($remote, $finalize_key);
                emit_learned_key($key_data);
        }

        #If enabled, clear the display after sleeping one second
        if ($quick_clear){
                sleep($clear_delay);
                print "Clear Display:\n" if ($verbose);
                $key_data = lookup_key ($remote, $quick_clear_key);
                emit_learned_key($key_data);
        }
}


sub lookup_key {
        $remote = shift;
        $key_name = shift;
        if (!%rem_keys) {
                #read it from the file
                print "Reading remote config file 
$remote_prefix$remote.keys\n" if ($verbose);
                open (FH, $remote);
                @rem_lines = <FH>;
                foreach $l (@rem_lines) {
                        chomp($l);
                        next if ($l =~ /^#/);
                        next if ($l =~ /^\s*$/);
                        next if ($l =~ /!=/);
                        @val = split(/\s*=\s*/, $l);
                        [EMAIL PROTECTED] = @val[1];
                }
                close (FH);
        }
        $key_data = $rem_keys{$key_name};
        print "$key_name -> $key_data\n" ;#if ($verbose);
        return $key_data;
}


sub change_channel {
        # Send a command for each digit of the channel number
        my ($channel_num)[EMAIL PROTECTED];
        my ($position)=0;
        my ($digit)="";

        if ($verbose){
                print "Channel number: ";
                print $channel_num;
                print "\n";
        }
        while ($position<length($channel_num)){
                $digit=substr($channel_num,$position,1);
                if ($verbose){
                        print "Digit: ";
                        print $digit;
                        print "\n";
                }
                mb_key($digit);
                $position++;
                sleep($inter_key_delay);
        }
        # wait a little bit and press enter to finalize channel entry
        if ($finalize){
                print "Finalize Entry:\n" if ($verbose);
                mb_key($finalize_key);
        }

        #If enabled, clear the display after sleeping one second
        if ($quick_clear){
                sleep($clear_delay);
                print "Clear Display:\n" if ($verbose);
                mb_key($quick_clear_key);
        }
}


sub mb_key {
        my ($key)[EMAIL PROTECTED];
        my ($Count)=0;
        my ($Looping)=1;
        return undef unless $keymap{$key};
        simple_command("0x00");
                sleep(0.1);
                # send the data packet
                simple_command("0xBC","0xAC","0x0D","0x00","0x06","0x01",
$hi_bit,$lo_bit,$keymap{$key},"0x00","0x00");
                sleep($Emit_Time);      #Execution delay
                simple_command("0x00");
                print "\n" if ($verbose);
                get_reply();
}

sub simple_command {
        if (defined(sendbytes(@_))) {
                return(1);
        } else {
                return(undef);
        }
}

sub mb_command {
        sendbytes(@_);
}


sub sendbytes {
        (@send)[EMAIL PROTECTED];
        foreach (@send) { s/^0x//g; $_=hex($_); }
        print "SEND: " if ($verbose);
        foreach $num (@send) {
                $str=pack('C',$num);
                printf("0x%X ", $num, $str) if ($verbose);
                syswrite($serial,$str,length($str));
        }
        print "\n" if ($verbose);
}

sub get_reply {
        my $starttime=time();
        my ($last,$ok,@ret);
        my ($Expected_Count)[EMAIL PROTECTED];
        my ($Count)=0;
        print "RECV: " if ($verbose);

        while (1) {
                $ret=sysread($serial,$buf,1);
                $str=sprintf("0x%2.2X", ord($buf));

                # busy wait bad!
                die ("\n") if (time() - $starttime > 5);
                next if $str eq "0x00";
                $Count++;
                if ($pkt_decode{$str}) {
                        print $str if ($verbose);
                        print "[$pkt_decode{$str}] " if ($verbose);
                } else {
                        $_=$str; s/^0x//g; $_=hex($_);
                        printf("$str(%3.3s) ",$_) if ($verbose);
                        push (@ret,$_);
                }

                $ok=1 if ($terminal{$str} > 0);
                last if $str eq "0x31";
                last if $str eq "0x01";
                next;
        }
        print "\n\n" if ($verbose);

        return @ret if ($ok);
        return undef;
}


sub init_serial {
        my($port,$baud)[EMAIL PROTECTED];
        my($termios,$cflag,$lflag,$iflag,$oflag);
        my($voice);

        my $serial=new FileHandle("+>$port") || die "Could not open $port: $!
\n";

        $termios = POSIX::Termios->new();
        $termios->getattr($serial->fileno()) || die "getattr: $!\n";
        $cflag= 0 | CS8 | HUPCL | CREAD | CLOCAL;
        $lflag= 0;
        $iflag= 0 | IGNBRK | IGNPAR | IXON | IXOFF | IGNCR;
        #$iflag= 0 | IGNBRK | IGNPAR | IGNCR;
        $oflag= 0;

        $termios->setcflag($cflag);
        $termios->setlflag($lflag);
        $termios->setiflag($iflag);
        $termios->setoflag($oflag);
        $termios->setattr($serial->fileno(),TCSANOW) || die "setattr: $!\n";
        eval qq[
                \$termios->setospeed(POSIX::B$baud) || die "setospeed: \$!\n";
                \$termios->setispeed(POSIX::B$baud) || die "setispeed: \$!\n";
        ];

        die $@ if $@;

        $termios->setattr($serial->fileno(),TCSANOW) || die "setattr: $!\n";

        # This gets rid of all the special characters..
        $termios->getattr($serial->fileno()) || die "getattr: $!\n";
        for (0..NCCS) {
                if ($_ == NCCS) { last; }

                # Dont mess up XON/XOFF..
#               if ($_ == VSTART || $_ == VSTOP) { next; }

                $termios->setcc($_,0);
        }
        $termios->setattr($serial->fileno(),TCSANOW) || die "setattr: $!\n";

        return $serial;
}

_______________________________________________
mythtv-users mailing list
[email protected]
http://mythtv.org/cgi-bin/mailman/listinfo/mythtv-users

Reply via email to