How can I setup serial RS 422 PTZ in ZM

Forum for questions and support relating to the 1.28.x releases only.
Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

I've ran this command:
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
Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

Update:
I've found out in the PelcoP.pm script the first couple line the script was referring to Pelco D after immediate changing this. I had the dainostic leds woking again but no movement. Next I changed the comm port to :

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
Still getting the same results.
I can use cutecom to control the cam successfully with the serial set to 4800, Parity None, Stopbit 1, 8 bit. but nothing from Zoneminder.
Heres my standard Pelcop.pm from directory /usr/share/perl5/ZoneMinder/Control/PelcoP.pm

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
Zoneminder settings are:
Device Path /dev/video0
Capture Method Video For Linux version 2
Device Channel 1
Device Format PAL
Capture Palette Auto
Multi Buffering Use Config Value
Captures Per Frame
25
Target Colorspace 24 bit
Capture Width (pixels)
640
Capture Height (pixels)
480
Preserve Aspect Ratio
Orientation NO
Deinterlacing NO

Controllable
Control Type Pelco-P Edit
Control Device /dev/ttyS0
Control Address 0 ( I tried both 0 and 1 My camera physical address is set to 1)
Auto Stop Timeout 0.50
Track Motion NO
Track Delay 0
Return Location None
Return Delay 0

Please Please Please help!!!!!!
AndyNY
Posts: 10
Joined: Sat Jan 10, 2015 3:36 pm

Re: How can I setup serial RS 422 PTZ in ZM

Post by AndyNY »

If your Control Address is still set to zero, try setting it to one. Each PTZ camera has a way to set it's control address so you can control more than one from the same interface. There is no zero on any camera I have used, most default to one.
Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

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
AndyNY
Posts: 10
Joined: Sat Jan 10, 2015 3:36 pm

Re: How can I setup serial RS 422 PTZ in ZM

Post by AndyNY »

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
I am using Pelco-D and my camera is set to 1, same as ZM.

Are you saying that when you send with the terminal s/w it works, but not from ZM?

Actually, I didn't see in this thread where you checked the permissions. What group is /dev/ttyS0? Usually it's dialup, make sure it is rw, and that your web server user (www-data) is in the group dialup. I realize you may have checked it already, but if you are running the terminal s/w as root and it works, it may be the issue. Try su - www-data and see if the terminal method still works to rule that out.

You can also add some debugging to zmcontrol.pl - just add:

Code: Select all

Info($var);
which will write to /var/log/messages. You are obviously close.
Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

Thanks
I've changed the address to 1
done the following commands

Code: Select all

ls -l /dev/ttyS0
crw-rw---- 1 root dialout 4, 64 Dec 31 19:47 /dev/ttyS0
Next I sent this command to Pan right

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
In return Nothing moved and no error on the log within ZM

how do you add debugging when i add Info($var); to the command above i get a -bash error

Code: Select all

sudo -u www-data zmcontrol.pl -info($var); --id=4 --panspeed=32 --command=moveConLeft
-bash: syntax error near unexpected token `('
I know might be doing something wrong here. :?:
AndyNY
Posts: 10
Joined: Sat Jan 10, 2015 3:36 pm

Re: How can I setup serial RS 422 PTZ in ZM

Post by AndyNY »

Zmptz wrote:Thanks
how do you add debugging when i add Info($var); to the command above i get a -bash error

Code: Select all

sudo -u www-data zmcontrol.pl -info($var); --id=4 --panspeed=32 --command=moveConLeft
-bash: syntax error near unexpected token `('
I know might be doing something wrong here. :?:
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 programmer :D

Other than that, it looks like you are doing everything exactly right...
Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

At the moment my zmcontrol.pl script looks like this:

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 );
where do i enter or edit $var?
I'm just a engineer :D
Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

Hello Happy New Year.

Right back to work.
So I managed to set Debugging via the option logging route. this is what i found out.

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]
Pan Left at normal speed: A0 00 00 04 20 00 AF 2B (what it should be) = (what ZM is sending out) a0 01 00 04 1b 00 af b1 [8]
Pan Right at normal speed: A0 00 00 02 20 00 AF 2D (what it should be) = (what ZM is sending out) a0 01 00 02 1b 00 af b7 [8
Tilt Up at normal speed: A0 00 00 08 00 20 AF 27 (what it should be) = (what ZM is sending out) a0 01 00 08 00 16 af b0 [8]
Tilt Down at normal speed: A0 00 00 10 00 20 AF 3F (what it should be) = (what ZM is sending out) a0 01 00 10 00 25 af 9b
Stop all actions (Pan/Tilt/Zoom/Iris etc.): A0 00 00 00 00 00 AF 0F = a0 01 00 00 00 00 af ae [8]

now according to this:
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

Byte 1 (STX) - Start of Text, fixed to A0
Byte 2 (Camera Address) - logical address of the camera being controlled (Address 1 is 00)
Byte 3 & 6 (Data 1 to 4) - see http://www.commfront.com/rs232_examples ... orial2.htm second table.
Byte 7 (ETX) - End of Text, fixed to AF
Byte 8 (Checksum) - xOR sum of Bytes 1 to 7


This shows byte 2 the camera address ZM add +1 which mean I need to set it to 0. its now giving this result.

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
Notice the coding is some what off on the PelcoP.pm file posted eariler.
Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

can someone help?
Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

Not sure if the checksum is correct, but I need it to be xOr byte 1 through to 7 can anyone verify this above?
Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

Please anyone programmer really struggling here
Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

why does the PelcoP script generate an AF checksum instead of 0F on the Stop command

a0 00 00 00 00 00 af af
ZM stop all action

Operands format Hex and Operator xOr

a0 00 00 00 00 00 af 0f

any smart guy who can solve this problem.
Zmptz
Posts: 38
Joined: Thu Dec 10, 2015 9:08 am

Re: How can I setup serial RS 422 PTZ in ZM

Post by Zmptz »

greeting again.

I found what's happening with the checksum and how its being calculated.

for example Move Right

A0,00,00,02,08,00,AF, = checksum 05 if I manually type this it will work it moves to the right slowly
however the reality with PelcoP.pm in Zoneminder it calculates the checksum differently giving a different checksum.

for example Move Right

00,00,02,08,00,AF = Checksum A5 this does Not work if entered manually.

So all i need to do is add the STX into the formula to make it work.

Anyone know how?

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;
            }
        }
    }
}
Locked