sudo /usr/bin/zmcontrol.pl --panspeed=35 --autostop --command=moveConRight --id=4
and the output i get is nothing.
Code: Select all
sudo /usr/bin/zmcontrol.pl --panspeed=35 --autostop --command=moveConRight --id=4
Code: Select all
sudo /usr/bin/zmcontrol.pl --panspeed=35 --autostop --command=moveConRight --id=4
Code: Select all
stty 4800 -cstopb cs8 -parenb -crtscts -echo -F /dev/ttyS0
Code: Select all
stty -a -F /dev/ttyS0speed 4800 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 0; time = 244;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt
-echoctl -echoke
Code: Select all
# ==========================================================================
#
# ZoneMinder Pelco-P Control Protocol Module, $Date$, $Revision$
# Copyright (C) 2001-2008 Philip Coombes
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ==========================================================================
#
# This module contains the implementation of the Pelco-P camera control
# protocol
#
package ZoneMinder::Control::PelcoP;
use 5.006;
use strict;
use warnings;
require ZoneMinder::Base;
require ZoneMinder::Control;
our @ISA = qw(ZoneMinder::Control);
# ==========================================================================
#
# Pelco-P Control Protocol
#
# ==========================================================================
use ZoneMinder::Logger qw(:all);
use Time::HiRes qw( usleep );
use constant STX => 0xa0;
use constant ETX => 0xaf;
use constant COMMAND_GAP => 100000; # In ms
sub new
{
my $class = shift;
my $id = shift;
my $self = ZoneMinder::Control->new( $id );
bless( $self, $class );
srand( time() );
return $self;
}
our $AUTOLOAD;
sub AUTOLOAD
{
my $self = shift;
my $class = ref($self) || croak( "$self not object" );
my $name = $AUTOLOAD;
$name =~ s/.*://;
if ( exists($self->{$name}) )
{
return( $self->{$name} );
}
Fatal( "Can't access $name member of object of class $class" );
}
sub open
{
my $self = shift;
$self->loadMonitor();
use Device::SerialPort;
$self->{port} = new Device::SerialPort( $self->{Monitor}->{ControlDevice} );
$self->{port}->baudrate(4800);
$self->{port}->databits(8);
$self->{port}->parity('none');
$self->{port}->stopbits(1);
$self->{port}->handshake('none');
$self->{port}->read_const_time(50);
$self->{port}->read_char_time(10);
$self->{state} = 'open';
}
sub close
{
my $self = shift;
$self->{state} = 'closed';
$self->{port}->close();
}
sub printMsg
{
if ( logDebugging() )
{
my $self = shift;
my $msg = shift;
my $prefix = shift || "";
$prefix = $prefix.": " if ( $prefix );
my $line_length = 16;
my $msg_len = int(@$msg);
my $msg_str = $prefix;
for ( my $i = 0; $i < $msg_len; $i++ )
{
if ( ($i > 0) && ($i%$line_length == 0) && ($i != ($msg_len-1)) )
{
$msg_str .= sprintf( "\n%*s", length($prefix), "" );
}
$msg_str .= sprintf( "%02x ", $msg->[$i] );
}
$msg_str .= "[".$msg_len."]";
Debug( $msg_str );
}
}
sub sendCmd
{
my $self = shift;
my $cmd = shift;
my $ack = shift || 0;
my $result = undef;
my $checksum = 0x00;
for ( my $i = 1; $i < int(@$cmd); $i++ )
{
$checksum ^= $cmd->[$i];
}
$checksum &= 0xff;
push( @$cmd, $checksum );
$self->printMsg( $cmd, "Tx" );
my $id = $cmd->[0] & 0xf;
my $tx_msg = pack( "C*", @$cmd );
#print( "Tx: ".length( $tx_msg )." bytes\n" );
my $n_bytes = $self->{port}->write( $tx_msg );
if ( !$n_bytes )
{
Error( "Write failed: $!" );
}
if ( $n_bytes != length($tx_msg) )
{
Error( "Incomplete write, only ".$n_bytes." of ".length($tx_msg)." written: $!" );
}
if ( $ack )
{
Debug( "Waiting for ack" );
my $max_wait = 3;
my $now = time();
while( 1 )
{
my ( $count, $rx_msg ) = $self->{port}->read(4);
if ( $count )
{
#print( "Rx1: ".$count." bytes\n" );
my @resp = unpack( "C*", $rx_msg );
printMsg( \@resp, "Rx" );
if ( $resp[0] = 0x80 + ($id<<4) )
{
if ( ($resp[1] & 0xf0) == 0x40 )
{
my $socket = $resp[1] & 0x0f;
Debug( "Got ack for socket $socket" );
$result = !undef;
}
else
{
Error( "Got bogus response" );
}
last;
}
else
{
Error( "Got message for camera ".(($resp[0]-0x80)>>4) );
}
}
if ( (time() - $now) > $max_wait )
{
Warning( "Response timeout" );
last;
}
}
}
}
sub remoteReset
{
my $self = shift;
Debug( "Remote Reset" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x0f, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
}
sub resetDefaults
{
my $self = shift;
Debug( "Reset Defaults" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x29, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
}
sub cameraOff
{
my $self = shift;
Debug( "Camera Off" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x08, 0x00, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
}
sub cameraOn
{
my $self = shift;
Debug( "Camera On" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x88, 0x00, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
}
sub autoScan
{
my $self = shift;
Debug( "Auto Scan" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x90, 0x00, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
}
sub manScan
{
my $self = shift;
Debug( "Manual Scan" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x10, 0x00, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
}
sub stop
{
my $self = shift;
Debug( "Stop" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x00, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
}
sub moveConUp
{
my $self = shift;
my $params = shift;
my $speed = $self->getParam( $params, 'tiltspeed' );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Move Up" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x08, 0x00, $speed, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->stop( $params );
}
}
sub moveConDown
{
my $self = shift;
my $params = shift;
my $speed = $self->getParam( $params, 'tiltspeed' );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Move Down" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x10, 0x00, $speed, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->stop();
}
}
sub moveConLeft
{
my $self = shift;
my $params = shift;
my $speed = $self->getParam( $params, 'panspeed' );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Move Left" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x04, $speed, 0x00, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->stop();
}
}
sub moveConRight
{
my $self = shift;
my $params = shift;
my $speed = $self->getParam( $params, 'panspeed' );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Move Right" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x02, $speed, 0x00, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->stop();
}
}
sub moveConUpLeft
{
my $self = shift;
my $params = shift;
my $panspeed = $self->getParam( $params, 'panspeed', 0x3f );
my $tiltspeed = $self->getParam( $params, 'tiltspeed', 0x3f );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Move Up/Left" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x0c, $panspeed, $tiltspeed, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->stop();
}
}
sub moveConUpRight
{
my $self = shift;
my $params = shift;
my $panspeed = $self->getParam( $params, 'panspeed', 0x3f );
my $tiltspeed = $self->getParam( $params, 'tiltspeed', 0x3f );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Move Up/Right" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x0a, $panspeed, $tiltspeed, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->stop();
}
}
sub moveConDownLeft
{
my $self = shift;
my $params = shift;
my $panspeed = $self->getParam( $params, 'panspeed', 0x3f );
my $tiltspeed = $self->getParam( $params, 'tiltspeed', 0x3f );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Move Down/Left" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x14, $panspeed, $tiltspeed, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->stop();
}
}
sub moveConDownRight
{
my $self = shift;
my $params = shift;
my $panspeed = $self->getParam( $params, 'panspeed', 0x3f );
my $tiltspeed = $self->getParam( $params, 'tiltspeed', 0x3f );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Move Down/Right" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x12, $panspeed, $tiltspeed, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->stop();
}
}
sub moveStop
{
my $self = shift;
Debug( "Move Stop" );
$self->stop();
}
sub flip180
{
my $self = shift;
Debug( "Flip 180" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x07, 0x00, 0x21, ETX );
$self->sendCmd( \@msg );
}
sub zeroPan
{
my $self = shift;
Debug( "Zero Pan" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x07, 0x00, 0x22, ETX );
$self->sendCmd( \@msg );
}
sub _setZoomSpeed
{
my $self = shift;
my $speed = shift;
Debug( "Set Zoom Speed $speed" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x25, 0x00, $speed, ETX );
$self->sendCmd( \@msg );
}
sub zoomStop
{
my $self = shift;
Debug( "Zoom Stop" );
$self->stop();
$self->_setZoomSpeed( 0 );
}
sub zoomConTele
{
my $self = shift;
my $params = shift;
my $speed = $self->getParam( $params, 'speed', 0x01 );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Zoom Tele" );
$self->_setZoomSpeed( $speed );
usleep( COMMAND_GAP );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x20, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->zoomStop();
}
}
sub zoomConWide
{
my $self = shift;
my $params = shift;
my $speed = $self->getParam( $params, 'speed', 0x01 );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Zoom Wide" );
$self->_setZoomSpeed( $speed );
usleep( COMMAND_GAP );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x40, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->zoomStop();
}
}
sub _setFocusSpeed
{
my $self = shift;
my $speed = shift;
Debug( "Set Focus Speed $speed" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x27, 0x00, $speed, ETX );
$self->sendCmd( \@msg );
}
sub focusConNear
{
my $self = shift;
my $params = shift;
my $speed = $self->getParam( $params, 'speed', 0x03 );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Focus Near" );
$self->_setFocusSpeed( $speed );
usleep( COMMAND_GAP );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x01, 0x00, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->_setFocusSpeed( 0 );
}
}
sub focusConFar
{
my $self = shift;
my $params = shift;
my $speed = $self->getParam( $params, 'speed', 0x03 );
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Focus Far" );
$self->_setFocusSpeed( $speed );
usleep( COMMAND_GAP );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x80, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->_setFocusSpeed( 0 );
}
}
sub focusStop
{
my $self = shift;
Debug( "Focus Stop" );
$self->stop();
$self->_setFocusSpeed( 0 );
}
sub focusAuto
{
my $self = shift;
Debug( "Focus Auto" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x2b, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
}
sub focusMan
{
my $self = shift;
Debug( "Focus Man" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x2b, 0x00, 0x02, ETX );
$self->sendCmd( \@msg );
}
sub _setIrisSpeed
{
my $self = shift;
my $speed = shift;
Debug( "Set Iris Speed $speed" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x27, 0x00, $speed, ETX );
$self->sendCmd( \@msg );
}
sub irisConClose
{
my $self = shift;
my $params = shift;
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Iris Close" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x04, 0x00, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->_setIrisSpeed( 0 );
}
}
sub irisConOpen
{
my $self = shift;
my $params = shift;
my $autostop = $self->getParam( $params, 'autostop', 0 );
Debug( "Iris Open" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x02, 0x80, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
if( $autostop && $self->{Monitor}->{AutoStopTimeout} )
{
usleep( $self->{Monitor}->{AutoStopTimeout} );
$self->_setIrisSpeed( 0 );
}
}
sub irisStop
{
my $self = shift;
Debug( "Iris Stop" );
$self->stop();
$self->_setIrisSpeed( 0 );
}
sub irisAuto
{
my $self = shift;
Debug( "Iris Auto" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x2d, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
}
sub irisMan
{
my $self = shift;
Debug( "Iris Man" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x2d, 0x00, 0x02, ETX );
$self->sendCmd( \@msg );
}
sub writeScreen
{
my $self = shift;
my $params = shift;
my $string = $self->getParam( $params, 'string' );
Debug( "Writing '$string' to screen" );
my @chars = unpack( "C*", $string );
for ( my $i = 0; $i < length($string); $i++ )
{
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x15, $i, $chars[$i], ETX );
$self->sendCmd( \@msg );
usleep( COMMAND_GAP );
}
}
sub clearScreen
{
my $self = shift;
Debug( "Clear Screen" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x17, 0x00, 0x00, ETX );
$self->sendCmd( \@msg );
}
sub clearPreset
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset', 1 );
Debug( "Clear Preset $preset" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x05, 0x00, $preset, ETX );
$self->sendCmd( \@msg );
}
sub presetSet
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset', 1 );
Debug( "Set Preset $preset" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x03, 0x00, $preset, ETX );
$self->sendCmd( \@msg );
}
sub presetGoto
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset', 1 );
Debug( "Goto Preset $preset" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x07, 0x00, $preset, ETX );
$self->sendCmd( \@msg );
}
sub presetHome
{
my $self = shift;
Debug( "Home Preset" );
my @msg = ( STX, $self->{Monitor}->{ControlAddress}, 0x00, 0x07, 0x00, 0x22, ETX );
$self->sendCmd( \@msg );
}
sub reset
{
my $self = shift;
Debug( "Reset" );
$self->remoteReset();
$self->resetDefaults();
}
sub wake
{
my $self = shift;
Debug( "Wake" );
$self->cameraOn();
}
sub sleep
{
my $self = shift;
Debug( "Sleep" );
$self->cameraOff();
}
1;
__END__
# Below is stub documentation for your module. You'd better edit it!
=head1 NAME
ZoneMinder::Database - Perl extension for blah blah blah
=head1 SYNOPSIS
use ZoneMinder::Database;
blah blah blah
=head1 DESCRIPTION
Stub documentation for ZoneMinder, created by h2xs. It looks like the
author of the extension was negligent enough to leave the stub
unedited.
Blah blah blah.
=head2 EXPORT
None by default.
=head1 SEE ALSO
Mention other useful documentation such as the documentation of
related modules or operating system documentation (such as man pages
in UNIX), or any relevant external documentation such as RFCs or
standards.
If you have a mailing list set up for your module, mention it here.
If you have a web site set up for your module, mention it here.
=head1 AUTHOR
Philip Coombes, E<lt>philip.coombes@zoneminder.comE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2001-2008 Philip Coombes
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.3 or,
at your option, any later version of Perl 5 you may have available.
=cut
I am using Pelco-D and my camera is set to 1, same as ZM.Zmptz wrote:Thanks for your reply
I've set the Control address to 0,1,2 and 3. The camera Address is set to 1
I read somewhere on this forum that Pelco D and P add +1 to the address??
In a serial terminal software I can send theses command to control the camera.
Pan Left at normal speed: A0 00 00 04 20 00 AF 2B
Pan Right at normal speed: A0 00 00 02 20 00 AF 2D
Tilt Up at normal speed: A0 00 00 08 00 20 AF 27
Tilt Down at normal speed: A0 00 00 10 00 20 AF 3F
Stop all actions (Pan/Tilt/Zoom/Iris etc.): A0 00 00 00 00 00 AF 0F
Code: Select all
Info($var);
Code: Select all
ls -l /dev/ttyS0
crw-rw---- 1 root dialout 4, 64 Dec 31 19:47 /dev/ttyS0
Code: Select all
sudo -u www-data zmcontrol.pl --id=4 --panspeed=32 --command=moveConRight
Code: Select all
sudo -u www-data zmcontrol.pl --id=4 --panspeed=32 --command=moveConLeft
Code: Select all
sudo -u www-data zmcontrol.pl -info($var); --id=4 --panspeed=32 --command=moveConLeft
-bash: syntax error near unexpected token `('
Yeah, I actually meant you can edit zmcontrol.pl and substitute one of the program variables for $var. I tend to forget not everyone is a programmerZmptz wrote:Thanks
how do you add debugging when i add Info($var); to the command above i get a -bash errorI know might be doing something wrong here.Code: Select all
sudo -u www-data zmcontrol.pl -info($var); --id=4 --panspeed=32 --command=moveConLeft -bash: syntax error near unexpected token `('
Code: Select all
#!/usr/bin/perl -wT
#
# ==========================================================================
#
# ZoneMinder Control Script, $Date$, $Revision$
# Copyright (C) 2001-2008 Philip Coombes
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ==========================================================================
#
# This script continuously monitors the recorded events for the given
# monitor and applies any filters which would delete and/or upload
# matching events
#
use strict;
use lib '/usr/share/perl/5.20.2'; # Include custom perl install path
use ZoneMinder;
use Getopt::Long;
use POSIX qw/strftime EPIPE/;
use Socket;
#use Data::Dumper;
use Module::Load::Conditional qw{can_load};;
use constant MAX_CONNECT_DELAY => 10;
use constant MAX_COMMAND_WAIT => 1800;
$| = 1;
$ENV{PATH} = '/bin:/usr/bin';
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
sub Usage
{
print( "
Usage: zmcontrol.pl --id <monitor_id> --command=<command> <various options>
");
exit();
}
logInit();
my $arg_string = join( " ", @ARGV );
my $id;
my %options;
if ( !GetOptions(
'id=i'=>\$id,
'command=s'=>\$options{command},
'xcoord=i'=>\$options{xcoord},
'ycoord=i'=>\$options{ycoord},
'speed=i'=>\$options{speed},
'step=i'=>\$options{step},
'panspeed=i'=>\$options{panspeed},
'tiltspeed=i'=>\$options{tiltspeed},
'panstep=i'=>\$options{panstep},
'tiltstep=i'=>\$options{tiltstep},
'preset=i'=>\$options{preset},
'autostop'=>\$options{autostop},
)
)
{
Usage();
}
if ( !$id || !$options{command} )
{
print( STDERR "Please give a valid monitor id and command\n" );
Usage();
}
( $id ) = $id =~ /^(\w+)$/;
Debug( $arg_string );
my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock';
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
my $saddr = sockaddr_un( $sock_file );
my $server_up = connect( CLIENT, $saddr );
if ( !$server_up )
{
# The server isn't there
my $monitor = zmDbGetMonitorAndControl( $id );
if ( !$monitor )
{
Fatal( "Unable to load control data for monitor $id" );
}
my $protocol = $monitor->{Protocol};
if ( -x $protocol )
{
# Protocol is actually a script!
# Holdover from previous versions
my $command .= $protocol.' '.$arg_string;
Debug( $command."\n" );
my $output = qx($command);
my $status = $? >> 8;
if ( $status || logDebugging() )
{
chomp( $output );
Debug( "Output: $output\n" );
}
if ( $status )
{
Error( "Command '$command' exited with status: $status\n" );
exit( $status );
}
exit( 0 );
}
Info( "Starting control server $id/$protocol" );
close( CLIENT );
if ( ! can_load( modules => { "ZoneMinder::Control::$protocol" => undef } ) ) {
Fatal("Can't load ZoneMinder::Control::$protocol");
}
if ( my $cpid = fork() )
{
logReinit();
# Parent process just sleep and fall through
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or die( "Can't open socket: $!" );
my $attempts = 0;
while (!connect( CLIENT, $saddr ))
{
$attempts++;
Fatal( "Can't connect: $!" ) if ($attempts > MAX_CONNECT_DELAY);
sleep(1);
}
}
elsif ( defined($cpid) )
{
close( STDOUT );
close( STDERR );
setpgrp();
logReinit();
Info( "Control server $id/$protocol starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() ) );
$0 = $0." --id $id";
my $control = "ZoneMinder::Control::$protocol"->new( $id );
my $control_key = $control->getKey();
$control->loadMonitor();
$control->open();
socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
unlink( $sock_file );
bind( SERVER, $saddr ) or Fatal( "Can't bind: $!" );
listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" );
my $rin = '';
vec( $rin, fileno(SERVER), 1 ) = 1;
my $win = $rin;
my $ein = $win;
my $timeout = MAX_COMMAND_WAIT;
while( 1 )
{
my $nfound = select( my $rout = $rin, undef, undef, $timeout );
if ( $nfound > 0 )
{
if ( vec( $rout, fileno(SERVER), 1 ) )
{
my $paddr = accept( CLIENT, SERVER );
my $message = <CLIENT>;
next if ( !$message );
my $params = jsonDecode( $message );
#Debug( Dumper( $params ) );
my $command = $params->{command};
$control->$command( $params );
close( CLIENT );
}
else
{
Fatal( "Bogus descriptor" );
}
}
elsif ( $nfound < 0 )
{
if ( $! == EPIPE )
{
Error( "Can't select: $!" );
}
else
{
Fatal( "Can't select: $!" );
}
}
else
{
#print( "Select timed out\n" );
last;
}
}
Info( "Control server $id/$protocol exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() ) );
unlink( $sock_file );
$control->close();
exit( 0 );
}
else
{
Fatal( "Can't fork: $!" );
}
}
# The server is there, connect to it
#print( "Writing commands\n" );
CLIENT->autoflush();
my $message = jsonEncode( \%options );
print( CLIENT $message );
shutdown( CLIENT, 1 );
exit( 0 );
Code: Select all
Tx: a0 01 00 00 00 00 af ae [8] zmcontrol.pl
2016-01-02 11:18:47.476110 zmcontrol 13787 DBG Stop zmcontrol.pl
2016-01-02 11:18:46.919110 zmcontrol 13787 DBG Tx: a0 01 00 04 1b 00 af b1 [8] zmcontrol.pl
2016-01-02 11:18:46.861080 zmcontrol 13787 DBG Move Left zmcontrol.pl
2016-01-02 11:18:46.195870 zmcontrol 13787 DBG Tx: a0 01 00 00 00 00 af ae [8] zmcontrol.pl
2016-01-02 11:18:46.139910 zmcontrol 13787 DBG Stop zmcontrol.pl
2016-01-02 11:18:45.583770 zmcontrol 13787 DBG Tx: a0 01 00 10 00 25 af 9b [8] zmcontrol.pl
2016-01-02 11:18:45.535750 zmcontrol 13787 DBG Move Down zmcontrol.pl
2016-01-02 11:18:44.849310 zmcontrol 13787 DBG Tx: a0 01 00 00 00 00 af ae [8] zmcontrol.pl
2016-01-02 11:18:44.804430 zmcontrol 13787 DBG Stop zmcontrol.pl
2016-01-02 11:18:44.259450 zmcontrol 13787 DBG Tx: a0 01 00 02 1b 00 af b7 [8] zmcontrol.pl
2016-01-02 11:18:44.220340 zmcontrol 13787 DBG Move Right zmcontrol.pl
2016-01-02 11:18:43.858370 zmcontrol 13787 DBG Tx: a0 01 00 00 00 00 af ae [8] zmcontrol.pl
2016-01-02 11:18:43.802410 zmcontrol 13787 DBG Stop zmcontrol.pl
2016-01-02 11:18:43.246280 zmcontrol 13787 DBG Tx: a0 01 00 08 00 16 af b0 [8] zmcontrol.pl
2016-01-02 11:18:43.190940 zmcontrol 13787 DBG Move Up zmcontrol.pl
2016-01-02 11:09:13.819150 zmcontrol 13787 DBG Tx: a0 01 00 00 00 00 af ae [8]
Byte 1 STX
Byte 2 Camera Address
Byte 3 Data 1
Byte 4 Data 2
Byte 5 Data 3
Byte 6 Data 4
Byte 7 ETX
Byte 8 Checksum
Code: Select all
Tx: a0 00 00 00 00 00 af af [8] zmcontrol.pl
2016-01-02 11:30:24.627610 zmcontrol 13932 DBG Stop zmcontrol.pl
2016-01-02 11:30:24.071370 zmcontrol 13932 DBG Tx: a0 00 00 04 19 00 af b2 [8] zmcontrol.pl
2016-01-02 11:30:24.015500 zmcontrol 13932 DBG Move Left zmcontrol.pl
2016-01-02 11:30:23.959360 zmcontrol 13932 DBG Tx: a0 00 00 00 00 00 af af [8] zmcontrol.pl
2016-01-02 11:30:23.903320 zmcontrol 13932 DBG Stop zmcontrol.pl
2016-01-02 11:30:23.347280 zmcontrol 13932 DBG Tx: a0 00 00 10 00 1d af a2 [8] zmcontrol.pl
2016-01-02 11:30:23.291380 zmcontrol 13932 DBG Move Down zmcontrol.pl
2016-01-02 11:30:23.235270 zmcontrol 13932 DBG Tx: a0 00 00 00 00 00 af af [8] zmcontrol.pl
2016-01-02 11:30:23.179260 zmcontrol 13932 DBG Stop zmcontrol.pl
2016-01-02 11:30:22.623080 zmcontrol 13932 DBG Tx: a0 00 00 02 27 00 af 8a [8] zmcontrol.pl
2016-01-02 11:30:22.567310 zmcontrol 13932 DBG Move Right zmcontrol.pl
2016-01-02 11:30:22.511140 zmcontrol 13932 DBG Tx: a0 00 00 00 00 00 af af [8] zmcontrol.pl
2016-01-02 11:30:22.455150 zmcontrol 13932 DBG Stop zmcontrol.pl
2016-01-02 11:30:21.898970 zmcontrol 13932 DBG Tx: a0 00 00 08 00 22 af 85 [8] zmcontrol.pl
2016-01-02 11:30:21.842220 zmcontrol 13932 DBG Move Up
Code: Select all
sub sendCmd
{
my $self = shift;
my $cmd = shift;
my $ack = shift || 0;
my $result = undef;
my $checksum = 0x00;
for ( my $i = 1; $i < int(@$cmd); $i++ )
{
$checksum ^= $cmd->[$i];
}
$checksum &= 0xff;
push( @$cmd, $checksum );
$self->printMsg( $cmd, "Tx" );
my $id = $cmd->[0] & 0xf;
my $tx_msg = pack( "C*", @$cmd );
#print( "Tx: ".length( $tx_msg )." bytes\n" );
my $n_bytes = $self->{port}->write( $tx_msg );
if ( !$n_bytes )
{
Error( "Write failed: $!" );
}
if ( $n_bytes != length($tx_msg) )
{
Error( "Incomplete write, only ".$n_bytes." of ".length($tx_msg)." written: $!" );
}
if ( $ack )
{
Debug( "Waiting for ack" );
my $max_wait = 3;
my $now = time();
while( 1 )
{
my ( $count, $rx_msg ) = $self->{port}->read(4);
if ( $count )
{
#print( "Rx1: ".$count." bytes\n" );
my @resp = unpack( "C*", $rx_msg );
printMsg( \@resp, "Rx" );
if ( $resp[0] = 0x80 + ($id<<4) )
{
if ( ($resp[1] & 0xf0) == 0x40 )
{
my $socket = $resp[1] & 0x0f;
Debug( "Got ack for socket $socket" );
$result = !undef;
}
else
{
Error( "Got bogus response" );
}
last;
}
else
{
Error( "Got message for camera ".(($resp[0]-0x80)>>4) );
}
}
if ( (time() - $now) > $max_wait )
{
Warning( "Response timeout" );
last;
}
}
}
}