1) Made shared memory 16 byte aligned and identical size and layout for all platforms.

2) Fixed a bug in zmwatch.pl: Not freeing shared memory handles between iterations.
3) Modified default monitor options to simplify new monitor creation.
pull/49/head
Kfir Itzhak 2011-05-10 13:50:54 +03:00
parent ea3a1a9072
commit b0bc227232
5 changed files with 115 additions and 78 deletions

View File

@ -134,30 +134,35 @@ our $mem_seq = 0;
our $mem_data = our $mem_data =
{ {
"shared_data" => { "type"=>"SharedData", "seq"=>$mem_seq++, "contents"=> { "shared_data" => { "type"=>"SharedData", "seq"=>$mem_seq++, "contents"=> {
"size" => { "type"=>"int", "seq"=>$mem_seq++ }, "size" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"valid" => { "type"=>"bool1", "seq"=>$mem_seq++ }, "last_write_index" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"active" => { "type"=>"bool1", "seq"=>$mem_seq++ }, "last_read_index" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"signal" => { "type"=>"bool1", "seq"=>$mem_seq++ }, "state" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"state" => { "type"=>"enum", "seq"=>$mem_seq++}, "last_event" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"last_write_index" => { "type"=>"int", "seq"=>$mem_seq++ }, "action" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"last_read_index" => { "type"=>"int", "seq"=>$mem_seq++ }, "brightness" => { "type"=>"int32", "seq"=>$mem_seq++ },
"last_write_time" => { "type"=>"time_t", "seq"=>$mem_seq++ }, "hue" => { "type"=>"int32", "seq"=>$mem_seq++ },
"last_read_time" => { "type"=>"time_t", "seq"=>$mem_seq++ }, "colour" => { "type"=>"int32", "seq"=>$mem_seq++ },
"last_event" => { "type"=>"int", "seq"=>$mem_seq++ }, "contrast" => { "type"=>"int32", "seq"=>$mem_seq++ },
"action" => { "type"=>"enum", "seq"=>$mem_seq++ }, "alarm_x" => { "type"=>"int32", "seq"=>$mem_seq++ },
"brightness" => { "type"=>"int", "seq"=>$mem_seq++ }, "alarm_y" => { "type"=>"int32", "seq"=>$mem_seq++ },
"hue" => { "type"=>"int", "seq"=>$mem_seq++ }, "valid" => { "type"=>"uchar", "seq"=>$mem_seq++ },
"colour" => { "type"=>"int", "seq"=>$mem_seq++ }, "active" => { "type"=>"uchar", "seq"=>$mem_seq++ },
"contrast" => { "type"=>"int", "seq"=>$mem_seq++ }, "signal" => { "type"=>"uchar", "seq"=>$mem_seq++ },
"alarm_x" => { "type"=>"int", "seq"=>$mem_seq++ }, "bpadding" => { "type"=>"uchar", "seq"=>$mem_seq++ },
"alarm_y" => { "type"=>"int", "seq"=>$mem_seq++ }, "epadding1" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"epadding2" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"epadding3" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"last_write_time" => { "type"=>"time_t64", "seq"=>$mem_seq++ },
"last_read_time" => { "type"=>"time_t64", "seq"=>$mem_seq++ },
"control_state" => { "type"=>"uchar[256]", "seq"=>$mem_seq++ }, "control_state" => { "type"=>"uchar[256]", "seq"=>$mem_seq++ },
} }
}, },
"trigger_data" => { "type"=>"TriggerData", "seq"=>$mem_seq++, "contents"=> { "trigger_data" => { "type"=>"TriggerData", "seq"=>$mem_seq++, "contents"=> {
"size" => { "type"=>"int", "seq"=>$mem_seq++ }, "size" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"trigger_state" => { "type"=>"enum", "seq"=>$mem_seq++ }, "trigger_state" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"trigger_score" => { "type"=>"int", "seq"=>$mem_seq++ }, "trigger_score" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"padding" => { "type"=>"uint32", "seq"=>$mem_seq++ },
"trigger_cause" => { "type"=>"char[32]", "seq"=>$mem_seq++ }, "trigger_cause" => { "type"=>"char[32]", "seq"=>$mem_seq++ },
"trigger_text" => { "type"=>"char[256]", "seq"=>$mem_seq++ }, "trigger_text" => { "type"=>"char[256]", "seq"=>$mem_seq++ },
"trigger_showtext" => { "type"=>"char[256]", "seq"=>$mem_seq++ }, "trigger_showtext" => { "type"=>"char[256]", "seq"=>$mem_seq++ },
@ -176,7 +181,7 @@ sub zmMemInit
foreach my $section_data ( sort { $a->{seq} <=> $b->{seq} } values( %$mem_data ) ) foreach my $section_data ( sort { $a->{seq} <=> $b->{seq} } values( %$mem_data ) )
{ {
$section_data->{offset} = $offset; $section_data->{offset} = $offset;
$section_data->{align} = 4; $section_data->{align} = 0;
if ( $section_data->{align} > 1 ) if ( $section_data->{align} > 1 )
{ {
@ -188,11 +193,15 @@ sub zmMemInit
} }
foreach my $member_data ( sort { $a->{seq} <=> $b->{seq} } values( %{$section_data->{contents}} ) ) foreach my $member_data ( sort { $a->{seq} <=> $b->{seq} } values( %{$section_data->{contents}} ) )
{ {
if ( $member_data->{type} eq "long" || $member_data->{type} eq "time_t" || $member_data->{type} eq "size_t" || $member_data->{type} eq "bool8" ) if ( $member_data->{type} eq "long" || $member_data->{type} eq "ulong" || $member_data->{type} eq "size_t")
{ {
$member_data->{size} = $member_data->{align} = $native; $member_data->{size} = $member_data->{align} = $native;
} }
elsif ( $member_data->{type} eq "int" || $member_data->{type} eq "enum" || $member_data->{type} eq "bool4" ) elsif( $member_data->{type} eq "int64" || $member_data->{type} eq "uint64" || $member_data->{type} eq "time_t64")
{
$member_data->{size} = $member_data->{align} = 8;
}
elsif ( $member_data->{type} eq "int32" || $member_data->{type} eq "uint32" || $member_data->{type} eq "bool4" )
{ {
$member_data->{size} = $member_data->{align} = 4; $member_data->{size} = $member_data->{align} = 4;
} }
@ -200,7 +209,7 @@ sub zmMemInit
{ {
$member_data->{size} = $member_data->{align} = 2; $member_data->{size} = $member_data->{align} = 2;
} }
elsif ( $member_data->{type} =~ "/^u?char$/" || $member_data->{type} eq "bool1" ) elsif ( $member_data->{type} eq "char" || $member_data->{type} eq "uchar" || $member_data->{type} eq "bool1" )
{ {
$member_data->{size} = $member_data->{align} = 1; $member_data->{size} = $member_data->{align} = 1;
} }
@ -304,11 +313,16 @@ sub zmMemRead( $$;$ )
return( undef ); return( undef );
} }
my $value; my $value;
if ( $type eq "long" || $type eq "time_t" || $type eq "size_t" || $type eq "bool8" ) if ( $type eq "long" || $type eq "ulong" || $type eq "size_t")
{ {
( $value ) = unpack( "l!", $data ); ( $value ) = unpack( "l!", $data );
} }
elsif ( $type eq "int" || $type eq "enum" || $type eq "bool4" ) elsif ( $type eq "int64" || $type eq "uint64" || $type eq "time_t64" )
{
# The "q" type is only available on 64bit platforms.
( $value ) = unpack( "l!", $data );
}
elsif ( $type eq "int32" || $type eq "uint32" || $type eq "bool4" )
{ {
( $value ) = unpack( "l", $data ); ( $value ) = unpack( "l", $data );
} }
@ -382,11 +396,16 @@ sub zmMemWrite( $$;$ )
my $size = $mem_data->{$section}->{contents}->{$element}->{size}; my $size = $mem_data->{$section}->{contents}->{$element}->{size};
my $data; my $data;
if ( $type eq "long" || $type eq "time_t" || $type eq "size_t" || $type eq "bool8" ) if ( $type eq "long" || $type eq "ulong" || $type eq "size_t")
{ {
$data = pack( "l!", $value ); $data = pack( "l!", $value );
} }
elsif ( $type eq "int" || $type eq "enum" || $type eq "bool4" ) elsif ( $type eq "int64" || $type eq "uint64" || $type eq "time_t64" )
{
# The "q" type is only available on 64bit platforms.
$data = pack( "l!", $value );
}
elsif ( $type eq "int32" || $type eq "uint32" || $type eq "bool4" )
{ {
$data = pack( "l", $value ); $data = pack( "l", $value );
} }

View File

@ -87,6 +87,7 @@ while( 1 )
{ {
# Check we have got an image recently # Check we have got an image recently
my $image_time = zmGetLastWriteTime( $monitor ); my $image_time = zmGetLastWriteTime( $monitor );
zmMemInvalidate( $monitor );
next if ( !defined($image_time) ); # Can't read from shared data next if ( !defined($image_time) ); # Can't read from shared data
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died. next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.
@ -95,9 +96,9 @@ while( 1 )
Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" ); Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" );
if ( $image_delay > $max_image_delay ) if ( $image_delay > $max_image_delay )
{ {
Info( "Restarting capture daemon for ".$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n" ); Info( "Restarting capture daemon for ".$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n" );
$restart = 1; $restart = 1;
} }
} }
else else
{ {
@ -124,6 +125,7 @@ while( 1 )
{ {
# Check we have got an image recently # Check we have got an image recently
my $image_time = zmGetLastReadTime( $monitor ); my $image_time = zmGetLastReadTime( $monitor );
zmMemInvalidate( $monitor );
next if ( !defined($image_time) ); # Can't read from shared data next if ( !defined($image_time) ); # Can't read from shared data
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died. next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.

View File

@ -394,8 +394,10 @@ Monitor::Monitor(
struct timeval *shared_timestamps = (struct timeval *)((char *)trigger_data + sizeof(TriggerData)); struct timeval *shared_timestamps = (struct timeval *)((char *)trigger_data + sizeof(TriggerData));
unsigned char *shared_images = (unsigned char *)((char *)shared_timestamps + (image_buffer_count*sizeof(struct timeval))); unsigned char *shared_images = (unsigned char *)((char *)shared_timestamps + (image_buffer_count*sizeof(struct timeval)));
/* This shouldn't be needed if the shared memory start address is multiple of 16, but just in case */
if(((unsigned long)shared_images % 16) != 0) { if(((unsigned long)shared_images % 16) != 0) {
/* Align images buffer to nearest 16 byte boundary */ /* Align images buffer to nearest 16 byte boundary */
Debug(3,"Aligning shared memory images to the next 16 byte boundary");
shared_images = (uint8_t*)((unsigned long)shared_images + (16 - ((unsigned long)shared_images % 16))); shared_images = (uint8_t*)((unsigned long)shared_images + (16 - ((unsigned long)shared_images % 16)));
} }
@ -585,7 +587,7 @@ void Monitor::AddZones( int p_n_zones, Zone *p_zones[] )
Monitor::State Monitor::GetState() const Monitor::State Monitor::GetState() const
{ {
return( shared_data->state ); return( (State)shared_data->state );
} }
int Monitor::GetImage( int index, int scale ) const int Monitor::GetImage( int index, int scale ) const

View File

@ -29,6 +29,7 @@
#include "zm_camera.h" #include "zm_camera.h"
#include <sys/time.h> #include <sys/time.h>
#include <stdint.h>
#define SIGNAL_CAUSE "Signal" #define SIGNAL_CAUSE "Signal"
#define MOTION_CAUSE "Motion" #define MOTION_CAUSE "Motion"
@ -86,43 +87,64 @@ protected:
typedef enum { CLOSE_TIME, CLOSE_IDLE, CLOSE_ALARM } EventCloseMode; typedef enum { CLOSE_TIME, CLOSE_IDLE, CLOSE_ALARM } EventCloseMode;
/* sizeof(SharedData) expected to be 336 bytes on 32bit and 64bit */
typedef struct typedef struct
{ {
int size; uint32_t size; /* +0 */
bool valid; uint32_t last_write_index; /* +4 */
bool active; uint32_t last_read_index; /* +8 */
bool signal; uint32_t state; /* +12 */
State state; uint32_t last_event; /* +16 */
int last_write_index; uint32_t action; /* +20 */
int last_read_index; int32_t brightness; /* +24 */
time_t last_write_time; int32_t hue; /* +28 */
time_t last_read_time; int32_t colour; /* +32 */
int last_event; int32_t contrast; /* +36 */
unsigned int action; int32_t alarm_x; /* +40 */
int brightness; int32_t alarm_y; /* +44 */
int hue; uint8_t valid; /* +48 */
int colour; uint8_t active; /* +49 */
int contrast; uint8_t signal; /* +50 */
int alarm_x; uint8_t bpadding; /* +51 */
int alarm_y; uint32_t epadding1; /* +52 */
char control_state[256]; uint32_t epadding2; /* +56 */
uint32_t epadding3; /* +60 */
/*
** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038.
** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16.
*/
union { /* +64 */
time_t last_write_time;
uint64_t extrapad1;
};
union { /* +72 */
time_t last_read_time;
uint64_t extrapad2;
};
uint8_t control_state[256]; /* +80 */
} SharedData; } SharedData;
typedef enum { TRIGGER_CANCEL, TRIGGER_ON, TRIGGER_OFF } TriggerState; typedef enum { TRIGGER_CANCEL, TRIGGER_ON, TRIGGER_OFF } TriggerState;
/* sizeof(TriggerData) expected to be 560 on 32bit & and 64bit */
typedef struct typedef struct
{ {
int size; uint32_t size;
TriggerState trigger_state; uint32_t trigger_state;
int trigger_score; uint32_t trigger_score;
uint32_t padding;
char trigger_cause[32]; char trigger_cause[32];
char trigger_text[256]; char trigger_text[256];
char trigger_showtext[256]; char trigger_showtext[256];
} TriggerData; } TriggerData;
/* sizeof(Snapshot) expected to be 16 bytes on 32bit and 32 bytes on 64bit */
struct Snapshot struct Snapshot
{ {
struct timeval *timestamp; struct timeval *timestamp;
Image *image; Image *image;
void* padding;
}; };
class MonitorLink class MonitorLink
@ -317,7 +339,7 @@ public:
void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" ); void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" );
void ForceAlarmOff(); void ForceAlarmOff();
void CancelForced(); void CancelForced();
TriggerState GetTriggerState() const { return( trigger_data?trigger_data->trigger_state:TRIGGER_CANCEL ); } TriggerState GetTriggerState() const { return( (TriggerState)(trigger_data?trigger_data->trigger_state:TRIGGER_CANCEL )); }
void actionReload(); void actionReload();
void actionEnable(); void actionEnable();

View File

@ -56,26 +56,26 @@ else
'Enabled' => true, 'Enabled' => true,
'LinkedMonitors' => "", 'LinkedMonitors' => "",
'Type' => "", 'Type' => "",
'Device' => "/dev/video", 'Device' => "/dev/video0",
'Channel' => "0", 'Channel' => "0",
'Format' => "", 'Format' => 0x000000ff,
'Protocol' => "", 'Protocol' => "",
'Method' => "", 'Method' => "",
'Host' => "", 'Host' => "",
'Path' => "", 'Path' => "",
'Port' => "80", 'Port' => "80",
'Colours' => "", 'Colours' => 4,
'Palette' => "", 'Palette' => fourcc('B','G','R','4'),
'Width' => "", 'Width' => "320",
'Height' => "", 'Height' => "240",
'Orientation' => "0", 'Orientation' => "0",
'LabelFormat' => '%N - %y/%m/%d %H:%M:%S', 'LabelFormat' => '%N - %d/%m/%y %H:%M:%S',
'LabelX' => 0, 'LabelX' => 0,
'LabelY' => 0, 'LabelY' => 0,
'ImageBufferCount' => 40, 'ImageBufferCount' => 60,
'WarmupCount' => 25, 'WarmupCount' => 25,
'PreEventCount' => 10, 'PreEventCount' => 25,
'PostEventCount' => 10, 'PostEventCount' => 25,
'StreamReplayBuffer' => 1000, 'StreamReplayBuffer' => 1000,
'AlarmFrameCount' => 1, 'AlarmFrameCount' => 1,
'Controllable' => 0, 'Controllable' => 0,
@ -91,14 +91,14 @@ else
'SectionLength' => 600, 'SectionLength' => 600,
'FrameSkip' => 0, 'FrameSkip' => 0,
'EventPrefix' => 'Event-', 'EventPrefix' => 'Event-',
'MaxFPS' => "", 'MaxFPS' => "5",
'AlarmMaxFPS' => "", 'AlarmMaxFPS' => "5",
'FPSReportInterval' => 1000, 'FPSReportInterval' => 1000,
'RefBlendPerc' => 7, 'RefBlendPerc' => 7,
'DefaultView' => 'Events', 'DefaultView' => 'Events',
'DefaultRate' => '100', 'DefaultRate' => '100',
'DefaultScale' => '100', 'DefaultScale' => '100',
'SignalCheckColour' => '#0100BE', 'SignalCheckColour' => '#0000C0',
'WebColour' => 'red', 'WebColour' => 'red',
'Triggers' => "", 'Triggers' => "",
); );
@ -328,8 +328,8 @@ if ( ZM_HAS_V4L2 )
//"SBGGR16" => fourcc('B','Y','R','2'), /* 16 BGBG.. GRGR.. */ //"SBGGR16" => fourcc('B','Y','R','2'), /* 16 BGBG.. GRGR.. */
/* compressed formats */ /* compressed formats */
//"MJPEG" => fourcc('M','J','P','G'), /* Motion-JPEG */ "*JPEG" => fourcc('J','P','E','G'), /* JFIF JPEG */
"JPEG" => fourcc('J','P','E','G'), /* JFIF JPEG */ "*MJPEG" => fourcc('M','J','P','G'), /* Motion-JPEG */
//"DV" => fourcc('d','v','s','d'), /* 1394 */ //"DV" => fourcc('d','v','s','d'), /* 1394 */
//"MPEG" => fourcc('M','P','E','G'), /* MPEG-1/2/4 */ //"MPEG" => fourcc('M','P','E','G'), /* MPEG-1/2/4 */
@ -608,14 +608,6 @@ switch ( $tab )
} }
case 'source' : case 'source' :
{ {
// Set up initial palette value
if ( $newMonitor['Palette'] == '' )
{
if ( ZM_HAS_V4L && $newMonitor['Type'] == 'Local' )
$newMonitor['Palette'] = 4;
else
$newMonitor['Palette'] = 3;
}
if ( ZM_HAS_V4L && $newMonitor['Type'] == "Local" ) if ( ZM_HAS_V4L && $newMonitor['Type'] == "Local" )
{ {
?> ?>
@ -630,7 +622,7 @@ switch ( $tab )
<tr><td><?= $SLANG['CapturePalette'] ?></td><td><select name="newMonitor[Palette]"><?php foreach ( $v4l1LocalPalettes as $name => $value ) { ?><option value="<?= $value ?>"<?php if ( $value == $newMonitor['Palette'] ) { ?> selected="selected"<?php } ?>><?= $name ?></option><?php } ?></select></td></tr> <tr><td><?= $SLANG['CapturePalette'] ?></td><td><select name="newMonitor[Palette]"><?php foreach ( $v4l1LocalPalettes as $name => $value ) { ?><option value="<?= $value ?>"<?php if ( $value == $newMonitor['Palette'] ) { ?> selected="selected"<?php } ?>><?= $name ?></option><?php } ?></select></td></tr>
<?php <?php
} }
else if ( ZM_HAS_V4L2 && $newMonitor['Method'] == 'v4l2' ) else
{ {
?> ?>
<tr><td><?= $SLANG['DeviceChannel'] ?></td><td><select name="newMonitor[Channel]"><?php foreach ( $v4l2DeviceChannels as $name => $value ) { ?><option value="<?= $value ?>"<?php if ( $value == $newMonitor['Channel'] ) { ?> selected="selected"<?php } ?>><?= $name ?></option><?php } ?></select></td></tr> <tr><td><?= $SLANG['DeviceChannel'] ?></td><td><select name="newMonitor[Channel]"><?php foreach ( $v4l2DeviceChannels as $name => $value ) { ?><option value="<?= $value ?>"<?php if ( $value == $newMonitor['Channel'] ) { ?> selected="selected"<?php } ?>><?= $name ?></option><?php } ?></select></td></tr>