All pastes #16858 Raw Edit

Something

public text v1 · immutable
#16858 ·published 2005-07-04 17:23 UTC
rendered paste body
#!/usr/bin/perl

# rca_control.pl:  Remote control of a RCA DirecTV unit via the serial port
# By Josh Wilmes (http://www.hitchhiker.org/dss)
# Based on info from http://www.isd.net/mevenmo/audiovideo.html
#
# I take no responsibility for any damage this script might cause.  
# Feel free to modify and redistribute this as you see fit, but please retain
# the comments above.

# Modified by Dave Manaloto < dave@practicecode.com >
# - Put discrete code to turn on IRD
# - Try and clear OSD after changing channel
# - sync computer to IRD time "--sync-time"

# Modified by John Gruenenfelder < johng@as.arizona.edu >
# - Use codes for newer RCA model receivers (same as Sony codes?)
#   Info from http://www.dar.net/~andy/tivo/rca_dss_serial.html
# - Use Perl's select function to pause 0.20 seconds rather than external
#   usleep call
# - Use 9600 baud rate instead of 115200
# 
#  Originally posted to KnoppMythWiki by Bret Shroyer <bret  <at>  bretshroyer ,dot, org> Dec 16, 2004


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

#
# Verbose output
#
$verbose=1;

#
# Serial port settings.  Change to suit.  Baudrate probably doesn't need to be
# changed.
#
$baudrate = "9600";
$serport = "/dev/ttyS0";

#
# Delay between sending channel change command and clearing the on-screen
# display.  0.20 seconds seems to be fine.  Must be > 0 otherwise OSD won't
# actually get cleared.
#
$clearosd_delay = 0.20;

%pkt_decode=("0xF0" => "START PKT",
             "0xF1" => "ERR 1",
             "0xF2" => "GOT EXTENDED",
             "0xF4" => "END PKT",
             "0xF5" => "ERR 2",
             "0xFB" => "PROMPT");

%terminal=("0xF1" => -1,
           "0xF4" => 1,
           "0xF5" => -1);


%keymap=(right => "0xa8",
            left => "0xa9",
            up => "0xa6",
          down => "0xa7",
      favorite => "0x9e",
        select => "0xc3",
          exit => "0xc5",
             9 => "0xc6",

             8 => "0xc7",
             7 => "0xc8",
             6 => "0xc9",
             5 => "0xca",
             4 => "0xcb",
             3 => "0xcc",
             2 => "0xcd",
             1 => "0xce",
             0 => "0xcf",         
         ch_up => "0xd2",
         ch_dn => "0xd3",
         power => "0xd5",
          jump => "0xd8",
         guide => "0xe5",
          menu => "0xf7");

my $serial=init_serial($serport,$baudrate);

exit if($#ARGV == 1);

# Make sure reciever is on
turn_on_ird();

if($ARGV[0] == "--sync-time")
{
  dss_sync_time();
  exit(0);
}

$ret=&change_channel(@ARGV);
select(undef, undef, undef, $clearosd_delay);
clear_osd();

exit(0);





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


sub dss_command {
    sendbytes("0xFA",@_);
    return get_reply();
} 


sub change_channel { 
    my ($channel)=@_;

    $_=sprintf("%4.4x",$channel);
    ($n1,$n2)=/(..)(..)/;

    simple_command("0xA6",$n1,$n2,"0xff","0xff");
}


sub turn_on_ird {
  printf("Turning on IRD\n") if ($verbose);
  simple_command("0x82");
}


sub clear_osd {
  printf("Clearing OSD\n") if ($verbose);
  simple_command("0xA5","0x00","0x00","0xf9");
}


sub dss_sync_time {
   printf("Synching time to IRD\n") if ($verbose);
   dss_set_time(dss_get_time());
}


sub dss_get_time {
    printf("Getting time\n") if ($verbose);
    @ret = dss_command("0x91");
    return @ret;
}


sub dss_set_time {
    @inTime = @_;
    return if($#inTime != 6);
    $strTime = "$inTime[1]/$inTime[2] $inTime[3]:$inTime[4]:$inTime[5]";
    print("Setting system time to $strTime\n") if ($verbose);
    $cmd = "date -s \"$strTime\"";
    `$cmd`;
}


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


sub get_reply {
    my $starttime=time();
    my ($last,$ok,@ret);

    print "RECV: " if ($verbose);

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

       # busy wait bad!
       die ("Error ($str)\n") if (time() - $starttime > 8);
       next if $str eq "0x00";

       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 ($terminal{$str});
       last if ($last eq "0xFB" && $str eq "0xFB");
       $last=$str;
   }
   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;
    $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;
}