#!/usr/bin/perl use FindBin; # find the script's directory use lib $FindBin::Bin; # add that directory to the library path use xPL::common; ################################################################################ # constants # $vendor_id = 'dspc'; # from xplproject.org $device_id = 'scrPana'; # max 8 chars $class_id = 'screen'; # max 8 chars $separator = '-' x 80; $indent = ' ' x 2; #------------------------------------------------------------------------------- # global variables # my %configuration; $configuration{serialPort} = 'loungeScreen'; ################################################################################ # Input arguments # use Getopt::Std; my %opts; getopts('hvp:n:s:t:w:', \%opts); die("\n". "Usage: $0 [options]\n". "\n". "Options:\n". "${indent}-h display this help message\n". "${indent}-v verbose\n". "${indent}-p port the base UDP port\n". "${indent}-n id the instance id (max. 12 chars)\n". "${indent}-s str the serial port xPL client name\n". "${indent}-t mins the heartbeat interval in minutes\n". "${indent}-w secs the startup sleep interval\n". "\n". "Controls a Panasonic plasma screen or projector.\n". "\n". "More information with: perldoc $0\n". "\n". "" ) if ($opts{h}); my $verbose = $opts{v}; my $client_base_port = $opts{'p'} || 50000; my $instance_id = $opts{'n'} || xpl_build_automatic_instance_id; my $heartbeat_interval = $opts{'t'} || 5; my $startup_sleep_time = $opts{'w'} || 0; $configuration{serialPort} = $opts{'s'} || $configuration{serialPort}; my $serial_port_id = "$vendor_id-serPort.$configuration{serialPort}"; ################################################################################ # Internal functions # #------------------------------------------------------------------------------- # Translate a command to the corresponding crontrols for the serial port client # sub build_screen_control { my (%body) = @_; my @commands = (); # interpret commands foreach $control (keys(%body)) { my $value = lc($body{$control}); #print "$control -> \"$value\"\n"; # power if ($control eq 'power') { if ($value eq 'on') { push(@commands, 'PON'); } elsif ($value eq 'off') { push(@commands, 'POF'); } } # input source if ($control eq 'input') { if ($value eq 'composite') { push(@commands, 'IIS:VID'); } elsif ($value eq 'component') { push(@commands, 'IIS:YP1'); } elsif ($value eq 'vga') { push(@commands, 'IIS:RG1'); } elsif ($value eq 'next') { push(@commands, 'IIS'); } } # aspect and zoom elsif ($control eq 'aspect') { if ( ($value eq '4:3') or ($value eq '43') ) { push(@commands, 'DAM:NORM'); } elsif ($value eq 'zoom') { push(@commands, 'DAM:ZOOM'); } if ( ($value eq '16:9') or ($value eq '169') ) { push(@commands, 'DAM:FULL'); } elsif ($value eq 'full') { push(@commands, 'DAM:JUST'); } elsif ($value eq 'auto') { push(@commands, 'DAM:SELF'); } elsif ($value eq 'next') { push(@commands, 'DAM'); } } } return(@commands) } #------------------------------------------------------------------------------- # Translate a serial port message to the corresponding status # sub build_status { my ($message) = @_; my %status = (); # interpret commands if ($message eq 'PON') { %status = (power => 'on'); } elsif ($message eq 'POF') { %status = (power => 'off'); } return(%status) } ################################################################################ # Catch control-C interrupt # $SIG{INT} = sub{ $xpl_end++ }; ################################################################################ # Main script # sleep($startup_sleep_time); # xPL parameters my $xpl_id = xpl_build_id($vendor_id, $device_id, $instance_id); my $xpl_ip = xpl_find_ip; # create xPL socket my ($client_port, $xpl_socket) = xpl_open_socket($xpl_port, $client_base_port); # display working parameters if ($verbose == 1) { system("clear"); print("$separator\n"); print("Controlling a Panasonic screen via serial port xPL client \"$configuration{serialPort}\".\n"); print($indent . "class id: $class_id\n"); print($indent . "instance id: $instance_id\n"); print("\n"); } #------------------------------------------------------------------------------- # Main loop # my $timeout = 1; my $last_heartbeat_time = 0; while ( (defined($xpl_socket)) && ($xpl_end == 0) ) { # check time and send heartbeat $last_heartbeat_time = xpl_send_heartbeat( $xpl_socket, $xpl_id, $xpl_ip, $client_port, $heartbeat_interval, $last_heartbeat_time ); # get xpl-UDP message with timeout my ($xpl_message) = xpl_get_message($xpl_socket, $timeout); # process XPL message if ($xpl_message) { my ($type, $source, $target, $schema, %body) = xpl_get_message_elements($xpl_message); if ( xpl_is_for_me($xpl_id, $target) ) { # process commands if ($schema eq "$class_id.basic") { if ($type eq 'xpl-cmnd') { my $command = $body{'command'}; if ($verbose > 0) { print("\n"); print("Received command from \"$source\"\n"); } my @commands = build_screen_control(%body); if (@commands ne ()) { foreach $command (@commands) { if ($verbose == 1) { print $indent, "sending $command\n"; } xpl_send_message( $xpl_socket, $xpl_port, 'xpl-cmnd', $xpl_id, $serial_port_id, 'serPort.basic', ('command' => $command) ); } } } } # process replies if ($schema eq "serPort.response") { if ($source eq $serial_port_id) { my $status = $body{status}; if ($verbose == 1) { print "Received status $status\n"; } my %body = build_status($status); xpl_send_message( $xpl_socket, $xpl_port, 'xpl-trig', $xpl_id, '*', "$class_id.status", %body ); } } } } } xpl_disconnect($xpl_socket, $xpl_id, $xpl_ip, $client_port); ################################################################################ # Documentation (access it with: perldoc ) # __END__ =head1 NAME xpl-screen-pana.pl - Controls a Panasonic plasma screen or projector =head1 SYNOPSIS xpl-screen-pana.pl [options] =head1 DESCRIPTION This xPL client sends commands to an C in order to control a Panasonic plasma screen or projector. The C commands allow to control following items: =over 8 =item B Can be C or C. =item B Can be C, C, C or C. To do: the Panasonic commands differ from one model to another. =item B Can be C<4:3>, C<43>, C, C<16:9>, C<169>, C or C. =back =head1 OPTIONS =over 8 =item B<-h> Display a help message. =item B<-v> Be verbose. =item B<-p port> Specify the base port from which the client searches for a free port. If not specified, the client will take a default value. =item B<-n id> Specify the instance id (name). The id is limited to 12 characters. If not specified, it is constructed from the host name and the serial port controller name. =item B<-s str> Specify the C target's id. =item B<-t mins> Specify the number of minutes between two heartbeat messages. =item B<-w secs> Specify the number of seconds before sending the first heartbeat. This allows to start the client after the hub, thus eliminating an prospective startup delay of one heartbeat interval. =back =head1 SERIAL PORT CLIENT The C must be configured as: =over 8 =item B -b '\x02' -e '\x03' =item B baudrate 9600 databits 8 parity none stopbits 1 handshake none =back =head1 TEST Connect the screen to the PC's first serial port C. Make sure you have an C running on the machine. Start the serial port controller: C. Start the screen controller: C. Start C in another terminal window. Power the screen off with the remote control and launch the command C. The screen should power on and C display the control message, the C command, the C status and the C status. =head1 AUTHOR Francois Corthay, DSPC =head1 VERSION 2.0, 2012 =cut