[mythtv-users] MyBlaster/Dish Network
Robert Denier
rdenier at finiteinfinity.org
Wed Nov 16 17:32:04 EST 2005
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;
}
More information about the mythtv-users
mailing list