#!/usr/bin/perl # dss_control: Remote control of a Sony DSS 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. $|=1; use POSIX qw(:termios_h); use FileHandle; $verbose=0; %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 => "0x9a", left => "0x9b", up => "0x9c", down => "0x9d", 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("/dev/ttyS0","115200"); $ret=&change_channel(@ARGV); exit(0); sub change_channel { my ($channel)=@_; $_=sprintf("%4.4x",$channel); ($n1,$n2)=/(..)(..)/; simple_command("0x46",$n1,$n2,"0x0"); } sub simple_command { if (defined(dss_command(@_))) { return(1); } else { return(undef); } } sub dss_command { sendbytes("0xFA",@_); return get_reply(); } 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; } 1;