TCP-Server Skript

Das auf dem VDR-Rechner eingesetzte perl Skript wartet auf eine Verbindung über einen fest definierten Port. Nach Verbindungsaufbau durch den PDA werden einfache Befehle ausgeführt. Zyklisch wird ein Ping-Paket an den Server geschickt, welcher der Server mit einem Status beantwortet. Im Status steht der Zustand von TV und AV-Receiver, der zur dynamischen Anzeige der Schaltflächen der Fernbedienung genutzt wird. Das Ping-Paket dient zudem zum Aufrechterhalten und zur Kontrolle der bestehenden Verbindung.

Um eine abgebrochene (statt ordentlich abgebaute) Verbindung zu erkennen, wird das perl Skript durch ein Shellskript überwacht und bei Ausbleiben einer Kommunikation für eine Minute neu gestartet.

Das Skript steht hier zum Download bereit.

#!/usr/bin/perl -w

# remote.pl - 06..07/2007 by mail@uwe-freese.de

# Read UDP packets and write commands to TCP connection
# of "remote" plugin.

use Cwd 'abs_path';
use IO::Socket;

$TCPPort = 13000;
$TCPPortVDR = 13010;

$debug = 0;

# load states

$stateTVF = "/usr/local/bin/remote/tv.on";
$stateAmpF = "/usr/local/bin/remote/amp.on";

$stateTV = 0;
$stateAmp = 0;
if (-f $stateTVF) { $stateTV = 1; }
if (-f $stateAmpF) { $stateAmp = 1; }

# delete time flag of last datagram (since now there is no connection up)
unlink "last_datagram";


sleep 10;


# open server connection

$server = IO::Socket::INET->new(LocalPort => $TCPPort,
                                Type      => SOCK_STREAM,
                                Reuse     => 1,
                                Listen    => 1 )
or die "Couldn't be a tcp server on port $TCPPort: $@n";

if (!$debug)
{
  $sock = new IO::Socket::INET (PeerAddr => 'localhost', PeerPort => $TCPPortVDR, Proto => 'tcp');
  die "Could not create socket: $!\n" unless $sock;
  # The first character is irnored on remote plugin...
  print $sock "x";
}

my $datagram;
my $MAX_TO_READ = 2048;

sub amp($)
{
  my ($state) = @_;
  if (0 == $state)
  {
    unlink $stateAmpF;
    $stateAmp = 0;
  }
  else
  {
    `touch $stateAmpF`;
    $stateAmp = 1;
  }
}

sub tv($)
{
  my ($state) = @_;
  if (0 == $state)
  {
    unlink $stateTVF;
    $stateTV = 0;
  }
  else
  {
    `touch $stateTVF`;
    $stateTV = 1;
  }
}

sub sendMsg($)
{
  my ($data) = @_;
#  $data = chr(length($data)) . $data;
  print $client $data . "\r\n";
  $client->flush();
}

sub info()
{
  $info = $stateTV . $stateAmp;
  sendMsg($info);
}


while ($client = $server->accept())
{
  print "Client connected!\n";
  $client->autoflush(1);

  while ($datagram = <$client>)
  {
    $datagram =~ s/\n//;
    $datagram =~ s/\r//;

    print "Datagram received: " . $datagram . "\n";
    `touch last_datagram`;

  if (substr($datagram, 0, 3) eq "AMP")
  {
    $cmd = substr($datagram, 3);
    if ($cmd eq "On")
    {
        amp(1);
    }
    elsif ($cmd eq "Off")
    {
        amp(0);
    }

    if ($cmd eq "VolUp")
    {
        # 150ms each Vol Command
      	`irsend send_once Yamaha2 VolUp VolUp`;
    }
    elsif ($cmd eq "VolDown")
    {
        # 150ms each Vol Command
      	`irsend send_once Yamaha2 VolDown VolDown`;
    }
    else
    {
        `irsend send_once Yamaha $cmd`;
    }
  }
  elsif (substr($datagram, 0, 2) eq "TV")
  {
    $cmd = substr($datagram, 2);
    if ($cmd eq "Input")
    {
      tv(1);
    }
    elsif ($cmd eq "Power")
    {
      tv(0);
    }
    info();
    `irsend send_once philipstv $cmd`;
  }
  elsif (substr($datagram, 0, 5) eq "PING_")
  {
    $pong = "PONG_" . substr($datagram, 5) . "_" . $stateTV . $stateAmp;
    sendMsg($pong);    
  }
  elsif ($datagram eq "POWER")
  {
    `wake_celex.sh`;
  }
  elsif ($datagram eq "MACAllOn")
  {
    tv(1);
    amp(1);
    info();
    `irsend send_once philipstv Input`;
    `irsend send_once Yamaha On`;
    sleep 5;
    `irsend send_once philipstv Input`;
  }
  elsif ($datagram eq "MACAllOff")
  {
    tv(0);
    amp(0);
    info();
    `irsend send_once philipstv Power`;
    `irsend send_once Yamaha Off`;
  }
    elsif ($datagram eq "MACTV1")
    {
      tv(1);
      info();
      `irsend send_once philipstv 0 1`;
      `irsend send_once Yamaha TV`;
      sleep 1;
      `irsend send_once philipstv Input`;
    }
    elsif ($datagram eq "MACTV2")
    {
      tv(1);
      info();
      `irsend send_once philipstv 0 1`;
      `irsend send_once Yamaha DVD`;
      sleep 1;
      `irsend send_once philipstv Input`;
      sleep 1;
      `irsend send_once philipstv Input`;
    }
    else # single keys go to VDR remote
    {
      print "Received " . $datagram . "\n";
      if (!$debug)
      {      
        print $sock $datagram;
        $sock->flush();
      }
    }

  }

  print "Client disconnected!\n";
  close $client;
  unlink "last_datagram";
} 

#print "Script closing\n";

close($server);
close($sock);