[mythtv-users] MyBlaster/Dish Network
Steve Adeff
adeffs at gmail.com
Thu Nov 17 10:28:33 EST 2005
On Wednesday 16 November 2005 17:32, Robert Denier wrote:
> 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 =@bytes\n" 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);
> $rem_keys{@val[0]} = @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)=@_;
> 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)=@_;
> 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)=@_;
> 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, at ret);
> my ($Expected_Count)=@_;
> 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)=@_;
> 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;
> }
>
You should add a TRAC for inclusion in the contrib folder.
Steve
More information about the mythtv-users
mailing list