#!/usr/bin/perl -w
#  $Id: probe 29580 2013-09-30 13:57:20Z teetov $
# -----------------------------------------------------------------------------
#  Purpose:
#    - probe the camera
#    - pre-tune camera befor for retriever (RC and Audio)
# -----------------------------------------------------------------------------
#  Call:
#    probe DEVID=123
#    probe DEVID=123 PROBE=FAST
#    probe DEVID=123 DEVIP=192.168.17.177 [ ... ]
#    probe DEVIP=192.168.17.177 USRNAME=admin PASSWD=pass PROBE=DEFINE
# -----------------------------------------------------------------------------
#  Does:
#   0. can be called without DEVID argument.
#      In this case DEVIP,USRNAME,PASSWD should be provided in command line
#   1. load $APL_CONF/<DEVID>/conf if DEVID is provided
#   2. combine conf and args into one hash
#   3. connect to camera over http and read MODELID and FIRMWARE
#   4. report MODELID|FIRMWARE|STATUS to $APL_CONF/<DEVID>/conf.probe and stdout
#   5. if PROBE=DEFINE then get
#         IMAGESIZE_LIST,MEDIA_FORMAT_LIST
#         AUDIO_LIST,AUDIO_FORMAT_LIST
#         SNAPSHOT (picture)
#   6. set RC camera attributes    if mpeg4 | h264
#   7. set AUDIO camera attributes if AUDIO is on
#   8. example output:
#       AUDIO_SET=OK
#       FIRMWARE=5.02
#       MODELID=Q1755
#       RC_SET=OK
#       STATUS=OK
#       -------------
#       AUDIO_SET=NONE
#       FIRMWARE=5.02
#       MODELID=Q1755
#       RC_SET=NONE
#       STATUS=OK
#       SNAPSHOT=/tmp/probe/192.168.17.177-12367576123.jpg
#       IMAGESIZE_LIST=640x480,480x360,320x240,240x180,176x144,160x120
#       MEDIA_FORMAT_LIST=mjpeg,h264
#       AUDIO_LIST=off,on
#       AUDIO_FORMAT_LIST=g711,g726,aac
#	CAMERA_LIST=1,2,3,4
#   9. sample errors:
#       STATUS=ERROR: PCE-0001 [101] configuration is not found
#       STATUS=ERROR: PCE-0002 [101] USRNAME and PASSWD should provided
#       STATUS=ERROR: PCE-0003 [101] DEVIP is not defined
#       STATUS=ERROR: PCE-0500 [101] Device does not respond (http://207.107.163.123:80)
#       STATUS=ERROR: PCE-0401 [101] Authorization error
#       STATUS=ERROR: PCE-0403 [101] Forbidden
#       STATUS=ERROR: PCE-0030 [101] Cannot get MODELID
#       note: [101] is DEVID
#  10. warnings:
#       STATUS=WARNING: PCW-0001 [101] MODELID does not match configuration
#       STATUS=WARNING: PCW-0002 [101] FIRMWARE does not match configuration
#       STATUS=WARNING: PCW-0009 [101] PROBE=RESET is not supported
#
# -----------------------------------------------------------------------------
#  Note:
#   1. CAMERAMODEL file is obsolite. ptz_axisv2.pl & ptz_udp.pl has to be modified
#   2. Script mast be in the directory .../camera/<BRAND>/bin/
# -----------------------------------------------------------------------------
#  Author: teetov, 03/22/10
#  Edited by:
#  QA by:
#  Copyright: videoNEXT Network Solutions, Inc, 2010
# -----------------------------------------------------------------------------
#
use strict;
use Device::Conf ":all";
#use Data::Dumper;
# cons -------------------------------------------------------------------------
my @VERSION_URL = (
       {'URL','/axis-cgi/view/param.cgi?action=list&group=Properties.Firmware.Version,brand.ProdShortName', 'PROD','brand.ProdShortName=AXIS\s+(\w?\d+\w?-?\w?)', 'FW','Firmware.Version=(\d+\.\d+)' },
       {'URL','/support/releasenotes.shtml', 'PROD','Software\srelease\sAXIS\s(\d+)\+?\sVideo', 'FW','Video\sServer\s(\d+\.\d+)\.?\d*\s?\<BR' },
       {'URL','/support/releasenotes.shtml', 'PROD','Software\srelease\sAXIS\s(\d+)', 'FW','Network\sCamera\s(\d+\.\d+)\.?\d*\s?\<BR' }
);
my $AXISCTL="$ENV{APL}/cam/bin/cam_axis_ctl.pl";

# --------- check required parameters: DEVID,USRNAME,PASSWD,
my $conf=ProbeInit();  # uses <BRAND> from path and ARGV
ProbeErr("PCE-0001","configuration is not found") if not defined $conf->{DEVID};
ProbeErr("PCE-0003","DEVIP is not defined")       if not defined $conf->{DEVIP};
ProbeErr("PCE-0002","USRNAME and PASSWD should be provided")
                 if not defined $conf->{USRNAME} or not defined $conf->{PASSWD};
ProbeWarn("PCW-0009","PROBE=RESET is not supported") if $conf->{PROBE} eq 'RESET';
#------------------------------------------------------------------------------
# Probe camera MODELID & FIRMWARE
#------------------------------------------------------------------------------
my %result=(MODELID=>'0',FIRMWARE=>'0.0',STATUS=>'OK',RC_SET=>'NONE',AUDIO_SET=>'NONE');
my $postmortem;

UA()->timeout(5);
foreach my $def (@VERSION_URL) {             # check different models
    my $respond = ProbeRequest($def->{URL});
    if($respond!~ /^HTTP ERROR/) {
       $result{MODELID}      = $1 if $respond=~/$def->{PROD}/i;
       $result{FIRMWARE}     = $1 if $respond=~/$def->{FW}/i;
       last;
    }
    my ($err)= $respond=~/^HTTP ERROR \[(\d+)\]/;
    $postmortem .= "$respond\n";
    ProbeErr("PCE-0500","Device does not respond",$respond) if $err=~/^5\d\d/;
    ProbeErr("PCE-0401","Authorization error",    $respond) if $err==401;
} # foreach

ProbeErr("PCE-0030","Cannot get MODELID or FIRMWARE",$postmortem) if ! $result{MODELID};

# Check MODELID & FIRMWARE ---------------------------------------------------
if(defined $conf->{MODELID} and $result{MODELID} ne $conf->{MODELID}) {
  $result{STATUS}="WARNING: PCW-0001 [$conf->{DEVID}] MODELID does not match configuration";
}elsif(defined $conf->{CAMERAFIRMWARE} and $result{FIRMWARE} ne $conf->{CAMERAFIRMWARE}) {
  $result{STATUS}="WARNING: PCW-0001 [$conf->{DEVID}] FIRMWARE does not match configuration";
}

#------------------------------------------------------------------------------
# get video and audio properties ( only firmware 4.x 5.x)
#------------------------------------------------------------------------------
if($conf->{PROBE} eq 'DEFINE') {
	%result=(%result,(IMAGESIZE_LIST=>'CIF',MEDIA_FORMAT_LIST=>'mjpg',AUDIO_FORMAT_LIST=>'',AUDIO_LIST=>'disable:DISABLE',CAMERA_LIST=>'1'));
	my $req = "/axis-cgi/admin/param.cgi?action=list&group=Properties.Image,Properties.Audio,root.ImageSource,root.PTZ";
	my $res = ProbeRequest($req);
	if ($res =~ /^HTTP ERROR/) {
		# one more try
		sleep 1;
		$res = ProbeRequest($req);
	}

	if($res !~ /^HTTP ERROR/) {
		my %properties;
		foreach(split /\n/,$res) { # check each row separately
			next if not /^([\w|\.]+)=(.+)$/;
			my ($key, $val) = ($1, $2);
			$properties{$key} = $val;
		}

		# TODO: can be several channels with ptz
		# $result{PTZ_ZOOM_ABSOLUTE} = $val if $key eq properties{'root.PTZ.Support.S1.AbsoluteZoom';
		# $result{PTZ_ZOOM_ENABLED}  = $val if $key eq properties{'root.PTZ.Various.V1.ZoomEnabled';
		# zoom min and max related from camera config, if max step > 9999, then zoom is digital

		$result{PTZ_PAN_MIN}  = $properties{'root.PTZ.Limit.L1.MinPan'};
		$result{PTZ_PAN_MAX}  = $properties{'root.PTZ.Limit.L1.MaxPan'};
		$result{PTZ_TILT_MIN} = $properties{'root.PTZ.Limit.L1.MinTilt'};
		$result{PTZ_TILT_MAX} = $properties{'root.PTZ.Limit.L1.MaxTilt'};

		if ($properties{'root.PTZ.Limit.L1.MaxFieldAngle'} > 180)
		{
			$result{PTZ_HFOV_MAX} = $properties{'root.PTZ.Limit.L1.MaxFieldAngle'} / 10;
			$result{PTZ_HFOV_MIN} = $properties{'root.PTZ.Limit.L1.MinFieldAngle'} / 10;
		} else {
			$result{PTZ_HFOV_MAX} = $properties{'root.PTZ.Limit.L1.MaxFieldAngle'};
			$result{PTZ_HFOV_MIN} = $properties{'root.PTZ.Limit.L1.MinFieldAngle'};
		}

		$result{IMAGESIZE_LIST}    = $properties{'root.Properties.Image.Resolution'};
		$result{AUDIO_FORMAT_LIST} = $properties{'root.Properties.Audio.Format'};
		$result{AUDIO_LIST}        = 'off,on' if $properties{'root.Properties.Audio.Audio'} eq 'yes';
		$result{CAMERA_LIST}       = join(',', 1..$properties{'root.ImageSource.NbrOfSources'}) if $properties{'root.ImageSource.NbrOfSources'} > 0;

		$conf->{CAMERA_LIST} = $result{CAMERA_LIST}; # for snapshots

		my @f_list = map{s/mjpeg/mjpg/;$_} grep {/^(mjpeg|mpeg4|h264)$/} split(/,/, $properties{'root.Properties.Image.Format'});
		$result{MEDIA_FORMAT_LIST} = join(',', @f_list);
	}
}

#------------------------------------------------------------------------------
# get Sample picture
#------------------------------------------------------------------------------
if($conf->{PROBE} eq 'DEFINE') {
    $result{SNAPSHOT_LIST}=ProbeSnapshotList;
}
#------------------------------------------------------------------------------
# interim report & exit
#------------------------------------------------------------------------------
ProbeResult(\%result)  if $conf->{PROBE} =~ /^(DEFINE|FAST)$/;
ProbeResult(\%result)  if $conf->{DEVID} eq '0';

#------------------------------------------------------------------------------
# set RC (rate control) parameters
#------------------------------------------------------------------------------
if($conf->{MEDIA_FORMAT}=~/^(mpeg4|h264)/){ # only if media format is mpeg4 or h264
   my $in=$conf->{CAMERA}-1;           # inpit number for multicamera encoders
   $in=0 if $in <0;                    # correct if CAMERA not defined (single encoder)
   my $resolution=$conf->{IMAGESIZE};               # fullsize
   my $re=join('|',split(/,/,$conf->{IMAGESIZE_LIST}));
   if ($resolution!~/^($re)$/) {# If current IMAGESIZE can't be passed directly to the camera
      $resolution='CIF';
      if ($conf->{IMAGESIZE} =~ /S([0-9]+x[0-9]+)/) {
	  $resolution = $1;
      } else {
          $resolution='4CIF'        if $conf->{IMAGESIZE} eq 'hugesize';
          $resolution='QCIF'        if $conf->{IMAGESIZE} eq 'halfsize';
      }
   }
   my $pcount=$conf->{GOV};
   if (defined $pcount) {
      $pcount=$pcount=~/^\d+$/ ? ($pcount<=0?0:$pcount-1) : undef;
   }
   my $tbr=$conf->{RC_TARGETBITRATE};
   my $mbr=$conf->{RC_MAXBITRATE};
   my $vbp=$conf->{RC_PRIORITY};
   $tbr=0 if $tbr eq 'unlimited' or $tbr eq '';
   $mbr=0 if $mbr eq 'unlimited' or $mbr eq '';
   my $rc=($conf->{RC_MODE})?"Image.I$in.RateControl.Mode=$conf->{RC_MODE}":'';
   $rc.=" Image.I$in.RateControl.TargetBitrate=$tbr" if $tbr ne 'cam-defined';
   $rc.=" Image.I$in.RateControl.MaxBitrate=$mbr"    if $mbr ne 'cam-defined';
   $rc.=" Image.I$in.RateControl.Priority=$vbp"      if defined $vbp and $vbp ne 'cam-defined';
   $rc.=" Image.I$in.MPEG.PCount=$pcount"            if defined $pcount;
   $rc.=" Image.I$in.Appearance.Resolution=$resolution";
   my $ret=join "\n#",split(/\n/,`$AXISCTL devid=$conf->{DEVID}  $rc`);
   $result{RC_SET}="OK\n#$ret";   # add output from axisctl as comments
}
#------------------------------------------------------------------------------
# set AudioParams
#------------------------------------------------------------------------------
if (exists $conf->{AUDIO} and $conf->{AUDIO} eq 'on' ) {
   my $in=$conf->{CAMERA}-1;           # inpit number for multicamera encoders
   $in=0 if $in <0;                    # correct if CAMERA not defined (single encoder)
                        # checking what audio formats are supported by device
   my $supported_formats = `$AXISCTL devid=$conf->{DEVID} Properties.Audio`;
   if ($supported_formats =~ /error/i) {
      $result{AUDIO_SET}="WARNING: Audio is not supported by Axis $result{MODELID} $result{FIRMWARE}";
   }else {
      my $audio_params = "Audio.A$in.Enabled=yes AudioSource.A$in.AudioSupport=yes";
      if (defined $conf->{AUDIO_TWO_WAY} and $conf->{AUDIO_TWO_WAY} eq 'on') {
          $audio_params .= " Audio.DuplexMode=full";
      }
      if (index($supported_formats, "aac") != -1
          and $conf->{PROTO} eq 'RTSP'                                                      # aac over http is not implemented
          and (not defined $conf->{AUDIO_TWO_WAY} or $conf->{AUDIO_TWO_WAY} eq 'off')){# aac for two-way is not implemented
              $audio_params .= " AudioSource.A$in.AudioEncoding=aac AudioSource.A$in.SampleRate=8000 AudioSource.A$in.BitRate=16000";
      }else {          # force g711 which must be supported by any axis encoder
              $audio_params .= " AudioSource.A$in.AudioEncoding=g711";
      }
      my $ret=join "\n#",split(/\n/,`$AXISCTL devid=$conf->{DEVID}  $audio_params`);
      $result{AUDIO_SET}="OK\n#$ret";   # add output from axisctl as comments
   }
}
# final report-----------------------------------------------------------------------
ProbeResult(\%result);
