Commit 5534527a authored by Mikhail Karpenko's avatar Mikhail Karpenko

Merge branch 'test'

 Conflicts resolved:
	imgsrv.c
parents 1fa52b3a a3eb9430
...@@ -21,14 +21,14 @@ ...@@ -21,14 +21,14 @@
<builder id="org.eclipse.cdt.build.core.settings.default.builder.580164057" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/> <builder id="org.eclipse.cdt.build.core.settings.default.builder.580164057" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.2129855326" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/> <tool id="org.eclipse.cdt.build.core.settings.holder.libs.2129855326" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.745731625" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder"> <tool id="org.eclipse.cdt.build.core.settings.holder.745731625" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.incpaths.1859993711" name="Include Paths" superClass="org.eclipse.cdt.build.core.settings.holder.incpaths" valueType="includePath"/> <option id="org.eclipse.cdt.build.core.settings.holder.incpaths.1859993711" name="Include Paths" superClass="org.eclipse.cdt.build.core.settings.holder.incpaths"/>
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.58661368" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/> <inputType id="org.eclipse.cdt.build.core.settings.holder.inType.58661368" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool> </tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.1227611439" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder"> <tool id="org.eclipse.cdt.build.core.settings.holder.1227611439" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1739426241" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/> <inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1739426241" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool> </tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.176385540" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder"> <tool id="org.eclipse.cdt.build.core.settings.holder.176385540" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.incpaths.1931881995" superClass="org.eclipse.cdt.build.core.settings.holder.incpaths" valueType="includePath"> <option id="org.eclipse.cdt.build.core.settings.holder.incpaths.1931881995" name="Include Paths" superClass="org.eclipse.cdt.build.core.settings.holder.incpaths" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/linux-elphel/linux/source/include/elphel}&quot;"/> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/linux-elphel/linux/source/include/elphel}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/linux-elphel/sysroots/elphel393/usr/include}&quot;"/> <listOptionValue builtIn="false" value="&quot;${workspace_loc:/linux-elphel/sysroots/elphel393/usr/include}&quot;"/>
</option> </option>
......
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
dlen: length of a variable data field, stored in frame buffer dlen: length of a variable data field, stored in frame buffer
ltag: Exif_tag+(group<<16). If specified, is used by the software, while the Exif output will still have tag ltag: Exif_tag+(group<<16). If specified, is used by the software, while the Exif output will still have tag
SubSecTimeOriginal should go immediately after DateTimeOriginal (in the sequence numbers, not in the Exif templete) SubSecTimeOriginal should go immediately after DateTimeOriginal (in the sequence numbers, not in the Exif templete)
Update, June 2016: PageNumber field is used as sensor port number, HostComputer field is replaced with CameraSerialNumber and
FrameNumber field (which actually was IPTCNAA field) is replaced with standart ImageNumber field.
--> -->
<Exif> <Exif>
<Image> <Image>
...@@ -22,9 +25,10 @@ ...@@ -22,9 +25,10 @@
<DateTime tag="0x0132" format="ASCII" count="20" seq="1" dlen="20"> <DateTime tag="0x0132" format="ASCII" count="20" seq="1" dlen="20">
<value>2001:06:21 12:00:00</value> <value>2001:06:21 12:00:00</value>
</DateTime> </DateTime>
<HostComputer tag="0x013c" format="ASCII" function="SERIAL"/> <CameraSerialNumber tag="0xc62f" format="ASCII" function="SERIAL"/>
<FrameNumber tag="0x83bb" format="LONG" count="1" seq="25" dlen="4"/> <ImageNumber tag="0x9211" format="LONG" count="1" seq="25" dlen="4"/>
<Orientation tag="0x112" format="SHORT" count="1" seq="27" dlen="2"/> <Orientation tag="0x112" format="SHORT" count="1" seq="27" dlen="2"/>
<PageNumber tag="0x129" format="SHORT" count="1" seq="28" dlen="2"/>
<ExifTag tag="0x8769" format="LONG" function="EXIFTAG"/> <ExifTag tag="0x8769" format="LONG" function="EXIFTAG"/>
<GPSTag tag="0x08825" format="LONG" function="GPSTAG"/> <GPSTag tag="0x08825" format="LONG" function="GPSTAG"/>
</Image> </Image>
......
...@@ -2,10 +2,31 @@ ...@@ -2,10 +2,31 @@
PORT=2323 PORT=2323
echo file circbuf.c +pfl > /sys/kernel/debug/dynamic_debug/control if [ $1 == "nodebug" ]; then
echo file sensor_common.c +pfl > /sys/kernel/debug/dynamic_debug/control echo file circbuf.c -pfl > /sys/kernel/debug/dynamic_debug/control
echo file jpeghead.c +pfl > /sys/kernel/debug/dynamic_debug/control echo file sensor_common.c -pfl > /sys/kernel/debug/dynamic_debug/control
echo file jpeghead.c -pfl > /sys/kernel/debug/dynamic_debug/control
exit 0
elif [ $1 == "dump_state" ]; then
echo "func circbuf_valid_ptr +p" > /sys/kernel/debug/dynamic_debug/control
echo "func get_image_length +p" > /sys/kernel/debug/dynamic_debug/control
echo "func dump_interframe_params +p" > /sys/kernel/debug/dynamic_debug/control
echo "func dump_state +p" > /sys/kernel/debug/dynamic_debug/control
exit 0
elif [ $1 == "full_debug" ]; then
echo file circbuf.c +pfl > /sys/kernel/debug/dynamic_debug/control
echo file sensor_common.c +pfl > /sys/kernel/debug/dynamic_debug/control
echo file jpeghead.c +pfl > /sys/kernel/debug/dynamic_debug/control
exit 0
else
# default, turn off all
echo file circbuf.c -pfl > /sys/kernel/debug/dynamic_debug/control
echo file sensor_common.c -pfl > /sys/kernel/debug/dynamic_debug/control
echo file jpeghead.c -pfl > /sys/kernel/debug/dynamic_debug/control
fi
if [ ! -e /dev/circbuf0 ]; then if [ ! -e /dev/circbuf0 ]; then
mknod /dev/circbuf0 c 135 32 mknod /dev/circbuf0 c 135 32
fi fi
......
#!/usr/local/sbin/php -q #!/usr/bin/env php
<?php <?php
/*! /*!
*! FILE NAME : exif.php *! FILE NAME : exif.php
*! DESCRIPTION: This program collects information about the camera (version, software, sensor) *! DESCRIPTION: This program collects information about the camera (version, software, sensor)
*! and combines it with the Exif template (default is /etc/Exif_template.xml) to prepare generation *! and combines it with the Exif template (default is /etc/Exif_template.xml) to prepare generation
*! of Exif headers. *! of Exif headers.
*! It works in a command line with a single optional parameter - location of the template file and *! It works in a command line with a single optional parameter - location of the template file and
*! trough the CGI interface. In that case it accepts the following parameter *! trough the CGI interface. In that case it accepts the following parameter
*! init - program Exif with default /etc/Exif_template.xml *! init - program Exif with default /etc/Exif_template.xml
*! init=path - program Exif with alternative file *! init=path - program Exif with alternative file
*! noGPS - don't include GPS-related fields *! noGPS - don't include GPS-related fields
*! nocompass - don't include compass-related fields *! nocompass - don't include compass-related fields
*! template - print currently loaded template data (hex dump) *! template - print currently loaded template data (hex dump)
*! metadir - print currently loaded meta directory that matches variable Exif fields with the template *! metadir - print currently loaded meta directory that matches variable Exif fields with the template
*! exif=0 - print current Exif page (updated in real time) *! exif=0 - print current Exif page (updated in real time)
*! exif=NNN - print one of the Exif pages in the buffer (debug feature, current buffer pointer is not known here) *! exif=NNN - print one of the Exif pages in the buffer (debug feature, current buffer pointer is not known here)
*! *!
*! Copyright (C) 2007-2008 Elphel, Inc *! Copyright (C) 2007-2016 Elphel, Inc
*! -----------------------------------------------------------------------------** *! -----------------------------------------------------------------------------**
*! *!
*! This program is free software: you can redistribute it and/or modify *! 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 *! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or *! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version. *! (at your option) any later version.
*! *!
*! This program is distributed in the hope that it will be useful, *! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of *! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details. *! GNU General Public License for more details.
*! *!
*! You should have received a copy of the GNU General Public License *! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>. *! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------** *! -----------------------------------------------------------------------------**
*! $Log: exif.php,v $ *! $Log: exif.php,v $
*! Revision 1.2 2010/08/10 21:14:31 elphel *! Revision 1.2 2010/08/10 21:14:31 elphel
*! 8.0.8.39 - added EEPROM support for multiplexor and sensor boards, so autocampars.php uses application-specific defaults. Exif Orientation tag support, camera Model reflects application and optional mode (i.e. camera number in Eyesis) *! 8.0.8.39 - added EEPROM support for multiplexor and sensor boards, so autocampars.php uses application-specific defaults. Exif Orientation tag support, camera Model reflects application and optional mode (i.e. camera number in Eyesis)
*! *!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel *! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*! *!
*! *!
*! Revision 1.2 2008/08/11 19:11:32 elphel *! Revision 1.2 2008/08/11 19:11:32 elphel
*! comments *! comments
*! *!
*! Revision 1.1 2008/04/07 09:12:14 elphel *! Revision 1.1 2008/04/07 09:12:14 elphel
*! New Exif template generation *! New Exif template generation
*! *!
*! $Log: exif.php,v $ *! $Log: exif.php,v $
*! Revision 1.2 2010/08/10 21:14:31 elphel *! Revision 1.2 2010/08/10 21:14:31 elphel
*! 8.0.8.39 - added EEPROM support for multiplexor and sensor boards, so autocampars.php uses application-specific defaults. Exif Orientation tag support, camera Model reflects application and optional mode (i.e. camera number in Eyesis) *! 8.0.8.39 - added EEPROM support for multiplexor and sensor boards, so autocampars.php uses application-specific defaults. Exif Orientation tag support, camera Model reflects application and optional mode (i.e. camera number in Eyesis)
*! *!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel *! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*! *!
*! *!
*! Revision 1.2 2008/08/11 19:11:32 elphel *! Revision 1.2 2008/08/11 19:11:32 elphel
*! comments *! comments
*! *!
*! Revision 1.1 2008/04/07 09:12:14 elphel *! Revision 1.1 2008/04/07 09:12:14 elphel
*! New Exif template generation *! New Exif template generation
*! *!
*! Revision 1.1.1.1 2007/10/03 19:05:53 elphel *! Revision 1.1.1.1 2007/10/03 19:05:53 elphel
*! This is a fresh tree based on elphel353-2.10 *! This is a fresh tree based on elphel353-2.10
*! *!
*! Revision 1.6 2007/10/03 19:05:53 elphel *! Revision 1.6 2007/10/03 19:05:53 elphel
*! cosmetic *! cosmetic
*! *!
*! Revision 1.5 2007/10/03 18:37:53 elphel *! Revision 1.5 2007/10/03 18:37:53 elphel
*! Made nice html output to see the result data *! Made nice html output to see the result data
*! *!
*! Revision 1.4 2007/10/03 06:33:31 elphel *! Revision 1.4 2007/10/03 06:33:31 elphel
*! fixed wrong copyright year *! fixed wrong copyright year
*! *!
*! Revision 1.3 2007/10/02 19:44:03 elphel *! Revision 1.3 2007/10/02 19:44:03 elphel
*! minor bug fixes, added "manufacturer note" field for raw frame metadata (36 bytes - /include/asm-cris/c313.h frame_params_t) *! minor bug fixes, added "manufacturer note" field for raw frame metadata (36 bytes - /include/asm-cris/c313.h frame_params_t)
*! *!
*! Revision 1.2 2007/09/25 23:34:02 elphel *! Revision 1.2 2007/09/25 23:34:02 elphel
*! Fixed time strings to the right length *! Fixed time strings to the right length
*! *!
*! Revision 1.1 2007/09/24 07:27:57 elphel *! Revision 1.1 2007/09/24 07:27:57 elphel
*! Started php script that prepares Exif header information for serving images by imgsrv *! Started php script that prepares Exif header information for serving images by imgsrv
*! *!
*/ */
//TODO: Decide with the start sequence, more data is availble after the sensor is initialized. //TODO: Decide with the start sequence, more data is availble after the sensor is initialized.
// Or leave it to imgsrv (it still needs sensor to start first), just put placeholders // Or leave it to imgsrv (it still needs sensor to start first), just put placeholders
// use http://www.exiv2.org/tags.html for reference of the Exif fields if you need to add modify // use http://www.exiv2.org/tags.html for reference of the Exif fields if you need to add modify
...@@ -90,6 +90,10 @@ $ExifDeviceMetadirFilename= "/dev/exif_metadir"; ...@@ -90,6 +90,10 @@ $ExifDeviceMetadirFilename= "/dev/exif_metadir";
$ExifDeviceExifFilename= "/dev/exif_exif"; $ExifDeviceExifFilename= "/dev/exif_exif";
$ExifDeviceMetaFilename= "/dev/exif_meta"; $ExifDeviceMetaFilename= "/dev/exif_meta";
$DeviceSNFilename = "/sys/devices/soc0/elphel393-init/serial";
$DeviceRevisionFilename = "/sys/devices/soc0/elphel393-init/revision";
$DeviceBrand = "Elphel";
$DeviceModel = "Elphel393";
//! if called from the command line - accepts just one parameter - configuration file, //! if called from the command line - accepts just one parameter - configuration file,
//! through CGI - accepts more parameters //! through CGI - accepts more parameters
...@@ -97,31 +101,31 @@ $ExifDeviceMetaFilename= "/dev/exif_meta"; ...@@ -97,31 +101,31 @@ $ExifDeviceMetaFilename= "/dev/exif_meta";
$ExifXMLName="/etc/Exif_template.xml"; $ExifXMLName="/etc/Exif_template.xml";
$init=false; $init=false;
if ($_SERVER['REQUEST_METHOD']=="GET") { if ($_SERVER['REQUEST_METHOD']=="GET") {
if ($_GET["init"]!==NULL) { if ($_GET["init"]!==NULL) {
if ($_GET["init"]) $ExifXMLName=$_GET["init"]; if ($_GET["init"]) $ExifXMLName=$_GET["init"];
$init=true; // in any case - filename specified or not $init=true; // in any case - filename specified or not
$noGPS= ($_GET["noGPS"]!==NULL); $noGPS= ($_GET["noGPS"]!==NULL);
$nocompass= ($_GET["nocompass"]!==NULL); $nocompass= ($_GET["nocompass"]!==NULL);
} }
} else { } else {
foreach ($_SERVER['argv'] as $param) if (substr($param,0,4)=="init") { foreach ($_SERVER['argv'] as $param) if (substr($param,0,4)=="init") {
$param=substr($param,5); $param=substr($param,5);
if (strlen($param)>0) $ExifXMLName=$param; if (strlen($param)>0) $ExifXMLName=$param;
$init=true; // $init=true; //
break; break;
} }
if ($init) { if ($init) {
$noGPS= in_array ('noGPS' , $_SERVER['argv']); $noGPS= in_array ('noGPS' , $_SERVER['argv']);
$nocompass= in_array ('nocompass', $_SERVER['argv']); $nocompass= in_array ('nocompass', $_SERVER['argv']);
} else { } else {
echo <<<USAGE echo <<<USAGE
Usage: {$_SERVER['argv'][0]} [init[=filename.xml] [noGPS] [nocompass]] Usage: {$_SERVER['argv'][0]} [init[=filename.xml] [noGPS] [nocompass]]
USAGE; USAGE;
exit (0); exit (0);
} }
} }
define("EXIF_BYTE", 1); define("EXIF_BYTE", 1);
...@@ -138,464 +142,468 @@ define("EXIF_SRATIONAL",10); ...@@ -138,464 +142,468 @@ define("EXIF_SRATIONAL",10);
define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
/// ===== init/init= CGI parameters or command line mode ======= /// ===== init/init= CGI parameters or command line mode =======
if ($init) { // configure Exif data if ($init) { // configure Exif data
$exif_head= array ( $exif_head= array (
0xff, 0xe1, // APP1 marker 0xff, 0xe1, // APP1 marker
// offset=2 - start of Exif header // offset=2 - start of Exif header
0x00, 0x00, // - length of the Exif header (including this length bytes) - we'll fill it later, we do not know it yet 0x00, 0x00, // - length of the Exif header (including this length bytes) - we'll fill it later, we do not know it yet
0x45,0x78,0x69,0x66,0x00,0x00); // Exif header 0x45,0x78,0x69,0x66,0x00,0x00); // Exif header
$Exif_length_offset= 2; // put total length here (big endian, 2 bytes) $Exif_length_offset= 2; // put total length here (big endian, 2 bytes)
$exif_data= array (// start of TIFF Header, data offsets will match indexes in this array $exif_data= array (// start of TIFF Header, data offsets will match indexes in this array
0x4d,0x4d, // (MM) Big endian, MSB goes first in multi-byte data 0x4d,0x4d, // (MM) Big endian, MSB goes first in multi-byte data
0x00,0x2a, // Tag Mark 0x00,0x2a, // Tag Mark
0x00,0x00,0x00,0x08); //offset to first IDF (from the beginning of the TIFF header, so 8 is minimum) 0x00,0x00,0x00,0x08); //offset to first IDF (from the beginning of the TIFF header, so 8 is minimum)
$xml_exif = simplexml_load_file($ExifXMLName); $xml_exif = simplexml_load_file($ExifXMLName);
if ($xml_exif->GPSInfo) { if ($xml_exif->GPSInfo) {
/// remove all tags named "Compass..." /// remove all tags named "Compass..."
if ($nocompass) { if ($nocompass) {
$tounset=array(); $tounset=array();
foreach ($xml_exif->GPSInfo->children() as $entry) if (strpos ($entry->getName() , "Compass" )!==false) $tounset[]=$entry->getName(); foreach ($xml_exif->GPSInfo->children() as $entry) if (strpos ($entry->getName() , "Compass" )!==false) $tounset[]=$entry->getName();
foreach ($tounset as $entry) unset ($xml_exif->GPSInfo->{$entry}); foreach ($tounset as $entry) unset ($xml_exif->GPSInfo->{$entry});
} }
if ($noGPS) { if ($noGPS) {
unset($xml_exif->GPSInfo); unset($xml_exif->GPSInfo);
unset($xml_exif->Image->GPSTag); unset($xml_exif->Image->GPSTag);
} }
} }
$IFD_offset= count($exif_data); $IFD_offset= count($exif_data);
$SUB_IFD_offset= 12*count($xml_exif->Image->children())+2+4+$IFD_offset; $SUB_IFD_offset= 12*count($xml_exif->Image->children())+2+4+$IFD_offset;
$GPSInfo_offset= 12*count($xml_exif->Photo->children())+2+4+$SUB_IFD_offset; $GPSInfo_offset= 12*count($xml_exif->Photo->children())+2+4+$SUB_IFD_offset;
$data_offset= $GPSInfo_offset+(($xml_exif->GPSInfo)?(12*count($xml_exif->GPSInfo->children())+2+4):0); //$GPSInfo is optional $data_offset= $GPSInfo_offset+(($xml_exif->GPSInfo)?(12*count($xml_exif->GPSInfo->children())+2+4):0); //$GPSInfo is optional
if ($_SERVER['REQUEST_METHOD']) { if ($_SERVER['REQUEST_METHOD']) {
echo "<pre>"; echo "<pre>";
printf ("IFD_offset=0x%x\n",$IFD_offset); printf ("IFD_offset=0x%x\n",$IFD_offset);
printf ("SUB_IFD_offset=0x%x\n",$SUB_IFD_offset); printf ("SUB_IFD_offset=0x%x\n",$SUB_IFD_offset);
printf ("GPSInfo_offset=0x%x\n",$GPSInfo_offset); printf ("GPSInfo_offset=0x%x\n",$GPSInfo_offset);
printf ("data_offset=0x%x\n",$data_offset); printf ("data_offset=0x%x\n",$data_offset);
} }
/// Now modify variable fields substituting values /// Now modify variable fields substituting values
foreach ($xml_exif->Image->children() as $entry) substitute_value($entry); foreach ($xml_exif->Image->children() as $entry) substitute_value($entry);
foreach ($xml_exif->Photo->children() as $entry) substitute_value($entry); foreach ($xml_exif->Photo->children() as $entry) substitute_value($entry);
if ($xml_exif->GPSInfo) { if ($xml_exif->GPSInfo) {
foreach ($xml_exif->GPSInfo->children() as $entry) substitute_value($entry); foreach ($xml_exif->GPSInfo->children() as $entry) substitute_value($entry);
} }
$ifd_pointer=$IFD_offset; $ifd_pointer=$IFD_offset;
$data_pointer=$data_offset; $data_pointer=$data_offset;
start_ifd(count($xml_exif->Image->children())); start_ifd(count($xml_exif->Image->children()));
foreach ($xml_exif->Image->children() as $entry) process_ifd_entry($entry,0); foreach ($xml_exif->Image->children() as $entry) process_ifd_entry($entry,0);
finish_ifd(); finish_ifd();
$ifd_pointer=$SUB_IFD_offset; $ifd_pointer=$SUB_IFD_offset;
start_ifd(count($xml_exif->Photo->children())); start_ifd(count($xml_exif->Photo->children()));
foreach ($xml_exif->Photo->children() as $entry) process_ifd_entry($entry,1); foreach ($xml_exif->Photo->children() as $entry) process_ifd_entry($entry,1);
finish_ifd(); finish_ifd();
if ($xml_exif->GPSInfo) { if ($xml_exif->GPSInfo) {
$ifd_pointer=$GPSInfo_offset; $ifd_pointer=$GPSInfo_offset;
start_ifd(count($xml_exif->GPSInfo->children())); start_ifd(count($xml_exif->GPSInfo->children()));
foreach ($xml_exif->GPSInfo->children() as $entry) process_ifd_entry($entry,2); foreach ($xml_exif->GPSInfo->children() as $entry) process_ifd_entry($entry,2);
finish_ifd(); finish_ifd();
} }
$exif_len=count($exif_head)+count($exif_data)-$Exif_length_offset; $exif_len=count($exif_head)+count($exif_data)-$Exif_length_offset;
$exif_head[$Exif_length_offset]= ($exif_len >> 8) & 0xff; $exif_head[$Exif_length_offset]= ($exif_len >> 8) & 0xff;
$exif_head[$Exif_length_offset+1]= $exif_len & 0xff; $exif_head[$Exif_length_offset+1]= $exif_len & 0xff;
$Exif_str=""; $Exif_str="";
for ($i=0; $i<count($exif_head);$i++) $Exif_str.= chr ($exif_head[$i]); for ($i=0; $i<count($exif_head);$i++) $Exif_str.= chr ($exif_head[$i]);
for ($i=0; $i<count($exif_data);$i++) $Exif_str.= chr ($exif_data[$i]); for ($i=0; $i<count($exif_data);$i++) $Exif_str.= chr ($exif_data[$i]);
$Exif_file = fopen($ExifDeviceTemplateFilename, 'w'); $Exif_file = fopen($ExifDeviceTemplateFilename, 'w');
fwrite ($Exif_file,$Exif_str); /// will disable and invalidate Exif data fwrite ($Exif_file,$Exif_str); /// will disable and invalidate Exif data
fclose($Exif_file); fclose($Exif_file);
///Exif template is done, now we need a directory to map frame meta data to fields in the template. ///Exif template is done, now we need a directory to map frame meta data to fields in the template.
$dir_sequence=array(); $dir_sequence=array();
$dir_entries=array(); $dir_entries=array();
foreach ($xml_exif->Image->children() as $entry) addDirEntry($entry); foreach ($xml_exif->Image->children() as $entry) addDirEntry($entry);
foreach ($xml_exif->Photo->children() as $entry) addDirEntry($entry); foreach ($xml_exif->Photo->children() as $entry) addDirEntry($entry);
if ($xml_exif->GPSInfo) { if ($xml_exif->GPSInfo) {
foreach ($xml_exif->GPSInfo->children() as $entry) addDirEntry($entry); foreach ($xml_exif->GPSInfo->children() as $entry) addDirEntry($entry);
} }
array_multisort($dir_sequence,$dir_entries); array_multisort($dir_sequence,$dir_entries);
$frame_meta_size=0; $frame_meta_size=0;
for ($i=0;$i<count($dir_entries);$i++) { for ($i=0;$i<count($dir_entries);$i++) {
$dir_entries[$i]["src"]=$frame_meta_size; $dir_entries[$i]["src"]=$frame_meta_size;
$frame_meta_size+=$dir_entries[$i]["len"]; $frame_meta_size+=$dir_entries[$i]["len"];
} }
$Exif_str=""; $Exif_str="";
foreach ($dir_entries as $entry) $Exif_str.=pack("V*",$entry["ltag"],$entry["len"],$entry["src"],$entry["dst"]); foreach ($dir_entries as $entry) $Exif_str.=pack("V*",$entry["ltag"],$entry["len"],$entry["src"],$entry["dst"]);
$Exif_meta_file = fopen($ExifDeviceMetadirFilename, 'w'); $Exif_meta_file = fopen($ExifDeviceMetadirFilename, 'w');
fwrite ($Exif_meta_file,$Exif_str); /// will disable and invalidate Exif data fwrite ($Exif_meta_file,$Exif_str); /// will disable and invalidate Exif data
fclose($Exif_meta_file); fclose($Exif_meta_file);
///Rebuild buffer and enable Exif generation/output: ///Rebuild buffer and enable Exif generation/output:
$Exif_file = fopen($ExifDeviceTemplateFilename, 'w'); $Exif_file = fopen($ExifDeviceTemplateFilename, 'w');
fseek ($Exif_file, EXIF_LSEEK_ENABLE, SEEK_END) ; fseek ($Exif_file, EXIF_LSEEK_ENABLE, SEEK_END) ;
fclose($Exif_file); fclose($Exif_file);
if ($_SERVER['REQUEST_METHOD']) { if ($_SERVER['REQUEST_METHOD']) {
echo "</pre>"; echo "</pre>";
} }
if ($_SERVER['REQUEST_METHOD']) { if ($_SERVER['REQUEST_METHOD']) {
echo "<hr/>\n"; echo "<hr/>\n";
test_print_header(); test_print_header();
echo "<hr/>\n"; echo "<hr/>\n";
test_print_directory(); test_print_directory();
} }
} //if ($init) // configure Exif data } //if ($init) // configure Exif data
/// ===== processing optional parameters ======= /// ===== processing optional parameters =======
/// ===== read template ======= /// ===== read template =======
if ($_GET["description"]!==NULL) { if ($_GET["description"]!==NULL) {
/// Read metadir to find the length of the description field /// Read metadir to find the length of the description field
$Exif_file = fopen($ExifDeviceMetadirFilename, 'r'); $Exif_file = fopen($ExifDeviceMetadirFilename, 'r');
fseek ($Exif_file, 0, SEEK_END) ; fseek ($Exif_file, 0, SEEK_END) ;
fseek ($Exif_file, 0, SEEK_SET) ; fseek ($Exif_file, 0, SEEK_SET) ;
$metadir=fread ($Exif_file, 4096); $metadir=fread ($Exif_file, 4096);
fclose($Exif_file); fclose($Exif_file);
$dir_entries=array(); $dir_entries=array();
for ($i=0; $i<strlen($metadir);$i+=16) { for ($i=0; $i<strlen($metadir);$i+=16) {
$dir_entries[]=unpack("V*",substr($metadir,$i,16)); $dir_entries[]=unpack("V*",substr($metadir,$i,16));
} }
foreach ($dir_entries as $entry) foreach ($dir_entries as $entry)
if ($entry[1]==0x010e) { if ($entry[1]==0x010e) {
$descr=$_GET["description"]; $descr=$_GET["description"];
$Exif_file = fopen($ExifDeviceMetaFilename, 'w+'); $Exif_file = fopen($ExifDeviceMetaFilename, 'w+');
fseek ($Exif_file, $entry[3], SEEK_SET) ; fseek ($Exif_file, $entry[3], SEEK_SET) ;
$descr_was=fread ($Exif_file, $entry[2]); $descr_was=fread ($Exif_file, $entry[2]);
$zero=strpos($descr_was,chr(0)); $zero=strpos($descr_was,chr(0));
if ($zero!==false) $descr_was=substr($descr_was,0, $zero); if ($zero!==false) $descr_was=substr($descr_was,0, $zero);
if ($descr) { if ($descr) {
$descr= str_pad($descr, $entry[2], chr(0)); $descr= str_pad($descr, $entry[2], chr(0));
fseek ($Exif_file, $entry[3], SEEK_SET) ; fseek ($Exif_file, $entry[3], SEEK_SET) ;
fwrite($Exif_file, $descr,$entry[2]); fwrite($Exif_file, $descr,$entry[2]);
} }
fclose($Exif_file); fclose($Exif_file);
var_dump($descr_was); echo "<br/>\n"; var_dump($descr_was); echo "<br/>\n";
break; break;
} }
} }
/// ===== read template ======= /// ===== read template =======
if ($_GET["template"]!==NULL) { if ($_GET["template"]!==NULL) {
$Exif_file = fopen($ExifDeviceTemplateFilename, 'r'); $Exif_file = fopen($ExifDeviceTemplateFilename, 'r');
fseek ($Exif_file, 0, SEEK_END) ; fseek ($Exif_file, 0, SEEK_END) ;
echo "<hr/>\n"; echo "<hr/>\n";
echo "ftell()=".ftell($Exif_file).", "; echo "ftell()=".ftell($Exif_file).", ";
fseek ($Exif_file, 0, SEEK_SET) ; fseek ($Exif_file, 0, SEEK_SET) ;
$template=fread ($Exif_file, 4096); $template=fread ($Exif_file, 4096);
fclose($Exif_file); fclose($Exif_file);
echo "read ".strlen($template)." bytes<br/>\n"; echo "read ".strlen($template)." bytes<br/>\n";
hexdump($template); hexdump($template);
} }
/// ===== read meta directory ======= /// ===== read meta directory =======
if ($_GET["metadir"]!==NULL) { if ($_GET["metadir"]!==NULL) {
$Exif_file = fopen($ExifDeviceMetadirFilename, 'r'); $Exif_file = fopen($ExifDeviceMetadirFilename, 'r');
fseek ($Exif_file, 0, SEEK_END) ; fseek ($Exif_file, 0, SEEK_END) ;
echo "<hr/>\n"; echo "<hr/>\n";
echo "ftell()=".ftell($Exif_file).", "; echo "ftell()=".ftell($Exif_file).", ";
fseek ($Exif_file, 0, SEEK_SET) ; fseek ($Exif_file, 0, SEEK_SET) ;
$metadir=fread ($Exif_file, 4096); $metadir=fread ($Exif_file, 4096);
fclose($Exif_file); fclose($Exif_file);
echo "read ".strlen($metadir)." bytes<br/>\n"; echo "read ".strlen($metadir)." bytes<br/>\n";
$dir_entries=array(); $dir_entries=array();
for ($i=0; $i<strlen($metadir);$i+=16) { for ($i=0; $i<strlen($metadir);$i+=16) {
$dir_entries[]=unpack("V*",substr($metadir,$i,16)); $dir_entries[]=unpack("V*",substr($metadir,$i,16));
} }
print_directory($dir_entries); print_directory($dir_entries);
} }
/// ===== read one of the Exif pages (0 - current, 1..512 - buffer) ======= /// ===== read one of the Exif pages (0 - current, 1..512 - buffer) =======
if ($_GET["exif"]!==NULL) { if ($_GET["exif"]!==NULL) {
$frame=$_GET["exif"]+0; $frame=$_GET["exif"]+0;
echo "<hr/>\n"; echo "<hr/>\n";
printf ("Reading frame %d, ",$frame); printf ("Reading frame %d, ",$frame);
$Exif_file = fopen($ExifDeviceExifFilename, 'r'); $Exif_file = fopen($ExifDeviceExifFilename, 'r');
fseek ($Exif_file, 1, SEEK_END) ; fseek ($Exif_file, 1, SEEK_END) ;
$exif_size=ftell($Exif_file); $exif_size=ftell($Exif_file);
if ($frame) fseek ($Exif_file, $frame, SEEK_END) ; if ($frame) fseek ($Exif_file, $frame, SEEK_END) ;
else fseek ($Exif_file, 0, SEEK_SET) ; else fseek ($Exif_file, 0, SEEK_SET) ;
echo "ftell()=".ftell($Exif_file).", "; echo "ftell()=".ftell($Exif_file).", ";
$exif_data=fread ($Exif_file, $exif_size); $exif_data=fread ($Exif_file, $exif_size);
fclose($Exif_file); fclose($Exif_file);
echo "read ".strlen($exif_data)." bytes<br/>\n"; echo "read ".strlen($exif_data)." bytes<br/>\n";
hexdump($exif_data); hexdump($exif_data);
} }
exit(0); exit(0);
/// ======================================= Functions ====================================== /// ======================================= Functions ======================================
function hexdump($data) { function hexdump($data) {
global $exif_head, $exif_data; global $exif_head, $exif_data;
$l=strlen($data); $l=strlen($data);
printf ("<h2>Exif size=%d bytes</h2>\n",$l); printf ("<h2>Exif size=%d bytes</h2>\n",$l);
printf ("<table border=\"0\">\n"); printf ("<table border=\"0\">\n");
for ($i=0; $i<$l;$i=$i+16) { for ($i=0; $i<$l;$i=$i+16) {
printf("<tr><td>%03x</td><td>|</td>\n",$i); printf("<tr><td>%03x</td><td>|</td>\n",$i);
for ($j=$i; $j<$i+16;$j++) { for ($j=$i; $j<$i+16;$j++) {
printf("<td>"); printf("<td>");
if ($j<$l) { if ($j<$l) {
$d=ord($data[$j]); $d=ord($data[$j]);
printf(" %02x",$d); printf(" %02x",$d);
} else printf (" "); } else printf (" ");
printf("</td>"); printf("</td>");
} }
printf("<td>|</td>"); printf("<td>|</td>");
for ($j=$i; $j< ($i+16);$j++) { for ($j=$i; $j< ($i+16);$j++) {
printf("<td>"); printf("<td>");
if ($j<$l) { if ($j<$l) {
$d=ord($data[$j]); $d=ord($data[$j]);
if ($d<32 or $d>126) printf("."); if ($d<32 or $d>126) printf(".");
else printf ("%c",$d); else printf ("%c",$d);
} else printf (" "); } else printf (" ");
printf("</td>"); printf("</td>");
} }
printf("</tr>\n"); printf("</tr>\n");
} }
printf ("</table>"); printf ("</table>");
} }
function print_directory($dir_entries) { function print_directory($dir_entries) {
$meta_size=0; $meta_size=0;
foreach ($dir_entries as $entry) if (($entry[3]+$entry[2])>$meta_size) $meta_size=$entry[3]+$entry[2]; foreach ($dir_entries as $entry) if (($entry[3]+$entry[2])>$meta_size) $meta_size=$entry[3]+$entry[2];
printf ("<h2>Frame meta data size=%d bytes</h2>\n",$meta_size); printf ("<h2>Frame meta data size=%d bytes</h2>\n",$meta_size);
printf ("<table border=\"1\">\n"); printf ("<table border=\"1\">\n");
printf ("<tr><td>ltag</td><td>meta offset</td><td>Exif offset</td><td>length</td></tr>\n"); printf ("<tr><td>ltag</td><td>meta offset</td><td>Exif offset</td><td>length</td></tr>\n");
foreach ($dir_entries as $entry) { foreach ($dir_entries as $entry) {
printf ("<tr><td>0x%x</td><td>0x%x</td><td>0x%x</td><td>0x%x</td></tr>\n",$entry[1],$entry[3],$entry[4],$entry[2]); printf ("<tr><td>0x%x</td><td>0x%x</td><td>0x%x</td><td>0x%x</td></tr>\n",$entry[1],$entry[3],$entry[4],$entry[2]);
} }
printf ("</table>"); printf ("</table>");
} }
function test_print_header() { function test_print_header() {
global $exif_head, $exif_data; global $exif_head, $exif_data;
$lh=count($exif_head); $lh=count($exif_head);
$ld=count($exif_data); $ld=count($exif_data);
printf ("<h2>Exif size=%d bytes (head=%d, data=%d)</h2>\n",$lh+$ld,$lh,$ld); printf ("<h2>Exif size=%d bytes (head=%d, data=%d)</h2>\n",$lh+$ld,$lh,$ld);
printf ("<table border=\"0\">\n"); printf ("<table border=\"0\">\n");
for ($i=0; $i<$lh+$ld;$i=$i+16) { for ($i=0; $i<$lh+$ld;$i=$i+16) {
printf("<tr><td>%03x</td><td>|</td>\n",$i); printf("<tr><td>%03x</td><td>|</td>\n",$i);
for ($j=$i; $j<$i+16;$j++) { for ($j=$i; $j<$i+16;$j++) {
printf("<td>"); printf("<td>");
if ($j<($lh+$ld)) { if ($j<($lh+$ld)) {
$d=($j<$lh)?$exif_head[$j]:$exif_data[$j-$lh]; $d=($j<$lh)?$exif_head[$j]:$exif_data[$j-$lh];
printf(" %02x",$d); printf(" %02x",$d);
} else printf (" "); } else printf (" ");
printf("</td>"); printf("</td>");
} }
printf("<td>|</td>"); printf("<td>|</td>");
for ($j=$i; $j< ($i+16);$j++) { for ($j=$i; $j< ($i+16);$j++) {
printf("<td>"); printf("<td>");
if ($j<($lh+$ld)) { if ($j<($lh+$ld)) {
$d=($j<$lh)?$exif_head[$j]:$exif_data[$j-$lh]; $d=($j<$lh)?$exif_head[$j]:$exif_data[$j-$lh];
if ($d<32 or $d>126) printf("."); if ($d<32 or $d>126) printf(".");
else printf ("%c",$d); else printf ("%c",$d);
} else printf (" "); } else printf (" ");
printf("</td>"); printf("</td>");
} }
printf("</tr>\n"); printf("</tr>\n");
} }
printf ("</table>"); printf ("</table>");
} }
function test_print_directory() { function test_print_directory() {
global $dir_entries,$frame_meta_size; global $dir_entries,$frame_meta_size;
printf ("<h2>Frame meta data size=%d bytes</h2>\n",$frame_meta_size); printf ("<h2>Frame meta data size=%d bytes</h2>\n",$frame_meta_size);
printf ("<table border=\"1\">\n"); printf ("<table border=\"1\">\n");
printf ("<tr><td>ltag</td><td>meta offset</td><td>Exif offset</td><td>length</td></tr>\n"); printf ("<tr><td>ltag</td><td>meta offset</td><td>Exif offset</td><td>length</td></tr>\n");
foreach ($dir_entries as $entry) foreach ($dir_entries as $entry)
printf ("<tr><td>0x%x</td><td>0x%x</td><td>0x%x</td><td>0x%x</td></tr>\n",$entry["ltag"],$entry["src"],$entry["dst"],$entry["len"]); printf ("<tr><td>0x%x</td><td>0x%x</td><td>0x%x</td><td>0x%x</td></tr>\n",$entry["ltag"],$entry["src"],$entry["dst"],$entry["len"]);
printf ("</table>"); printf ("</table>");
} }
function start_ifd($count) { function start_ifd($count) {
global $exif_data, $ifd_pointer; global $exif_data, $ifd_pointer;
// printf("start_ifd: ifd_pointer=0x%04x \n", $ifd_pointer); // printf("start_ifd: ifd_pointer=0x%04x \n", $ifd_pointer);
$exif_data[$ifd_pointer++]= ($count >> 8) & 0xff; $exif_data[$ifd_pointer++]= ($count >> 8) & 0xff;
$exif_data[$ifd_pointer++]= $count & 0xff; // may apply & 0xff in the end to all elements $exif_data[$ifd_pointer++]= $count & 0xff; // may apply & 0xff in the end to all elements
} }
function finish_ifd() { // we do not have additional IFDs function finish_ifd() { // we do not have additional IFDs
global $exif_data, $ifd_pointer; global $exif_data, $ifd_pointer;
// printf("finish_ifd: ifd_pointer=0x%04x \n", $ifd_pointer); // printf("finish_ifd: ifd_pointer=0x%04x \n", $ifd_pointer);
$exif_data[$ifd_pointer++]=0; $exif_data[$ifd_pointer++]=0;
$exif_data[$ifd_pointer++]=0; $exif_data[$ifd_pointer++]=0;
$exif_data[$ifd_pointer++]=0; $exif_data[$ifd_pointer++]=0;
$exif_data[$ifd_pointer++]=0; $exif_data[$ifd_pointer++]=0;
} }
//pass2 - building map from frame meta to Exif template //pass2 - building map from frame meta to Exif template
function addDirEntry($ifd_entry) { function addDirEntry($ifd_entry) {
global $dir_sequence,$dir_entries,$exif_head; global $dir_sequence,$dir_entries,$exif_head;
$lh=count($exif_head); $lh=count($exif_head);
$attrs = $ifd_entry->attributes(); $attrs = $ifd_entry->attributes();
// var_dump($attrs); // var_dump($attrs);
// if (array_key_exists ( "seq" , $attrs )) { // if (array_key_exists ( "seq" , $attrs )) {
if ($attrs["seq"]) { if ($attrs["seq"]) {
// echo $attrs["seq"].; // echo $attrs["seq"].;
$dir_sequence[]=((string) $attrs["seq"])+0; $dir_sequence[]=((string) $attrs["seq"])+0;
$len= (integer) $ifd_entry->value_length; $len= (integer) $ifd_entry->value_length;
$offs=$lh+(integer) $ifd_entry->value_offest; $offs=$lh+(integer) $ifd_entry->value_offest;
// if (array_key_exists ( "dlen" , $attrs )) // if (array_key_exists ( "dlen" , $attrs ))
if ($attrs["dlen"]) $len=min($len,((string) $attrs["dlen"])+0); if ($attrs["dlen"]) $len=min($len,((string) $attrs["dlen"])+0);
$dir_entries[]=array("ltag"=>((integer)$ifd_entry->ltag),"dst"=>$offs,"len"=>$len); $dir_entries[]=array("ltag"=>((integer)$ifd_entry->ltag),"dst"=>$offs,"len"=>$len);
} }
} }
function substitute_value($ifd_entry) { function substitute_value($ifd_entry) {
global $SUB_IFD_offset,$GPSInfo_offset; global $SUB_IFD_offset,$GPSInfo_offset;
$attrs = $ifd_entry->attributes(); global $DeviceSNFilename, $DeviceRevisionFilename, $DeviceBrand, $DeviceModel;
$attrs = $ifd_entry->attributes();
switch ($attrs["function"]) {
case "BRAND": switch ($attrs["function"]) {
$ifd_entry->addChild ('value',exec("bootblocktool -x BRAND")); case "BRAND":
break; $ifd_entry->addChild('value', $DeviceBrand);
case "MODEL": break;
if (file_exists ('/var/state/APPLICATION')) { case "MODEL":
$model= file_get_contents('/var/state/APPLICATION'); if (file_exists ('/var/state/APPLICATION')) {
if (file_exists ('/var/state/APPLICATION_MODE')) { $model= file_get_contents('/var/state/APPLICATION');
$model.=' CHN'.file_get_contents('/var/state/APPLICATION_MODE'); if (file_exists ('/var/state/APPLICATION_MODE')) {
} $model.=' CHN'.file_get_contents('/var/state/APPLICATION_MODE');
} else { }
$model= exec("bootblocktool -x MODEL").exec("bootblocktool -x REVISION"); } else {
} $model = $DeviceModel;
/// $ifd_entry->addChild ('value',exec("bootblocktool -x MODEL").exec("bootblocktool -x REVISION")); }
$ifd_entry->addChild ('value',$model); $ifd_entry->addChild ('value',$model);
break;
break; case "SOFTWARE":
case "SOFTWARE": if (file_exists("/usr/html/docs/")) {
$ifd_entry->addChild ('value',exec("ls /usr/html/docs/")); // filter $ifd_entry->addChild ('value',exec("ls /usr/html/docs/")); // filter
break; }
case "SERIAL": break;
$s=exec("bootblocktool -x SERNO"); case "SERIAL":
$ifd_entry->addChild ('value',substr($s,0,2).":".substr($s,2,2).":".substr($s,4,2).":".substr($s,6,2).":".substr($s,8,2).":".substr($s,10,2)); $s = "";
break; if (file_exists($DeviceSNFilename)) {
case "EXIFTAG": $s = exec('cat '.$DeviceSNFilename);
$ifd_entry->addChild ('value',$SUB_IFD_offset); }
break; $ifd_entry->addChild ('value',substr($s,0,2).":".substr($s,2,2).":".substr($s,4,2).":".substr($s,6,2).":".substr($s,8,2).":".substr($s,10,2));
case "GPSTAG": break;
$ifd_entry->addChild ('value',$GPSInfo_offset); case "EXIFTAG":
break; $ifd_entry->addChild ('value',$SUB_IFD_offset);
} break;
case "GPSTAG":
$ifd_entry->addChild ('value',$GPSInfo_offset);
break;
}
} }
function process_ifd_entry($ifd_entry, $group) { function process_ifd_entry($ifd_entry, $group) {
global $exif_data, $ifd_pointer, $data_pointer,$SUB_IFD_offset,$GPSInfo_offset; global $exif_data, $ifd_pointer, $data_pointer,$SUB_IFD_offset,$GPSInfo_offset;
$attrs = $ifd_entry->attributes(); $attrs = $ifd_entry->attributes();
$ifd_tag= ((string) $attrs["tag"])+0; $ifd_tag= ((string) $attrs["tag"])+0;
$ifd_format=constant("EXIF_".$attrs["format"]); $ifd_format=constant("EXIF_".$attrs["format"]);
$ifd_count= $attrs["count"]; $ifd_count= $attrs["count"];
// echo "\nifd_tag=$ifd_tag, entry=";print_r($ifd_entry); // echo "\nifd_tag=$ifd_tag, entry=";print_r($ifd_entry);
// echo "\nifd_count=$ifd_count"; // echo "\nifd_count=$ifd_count";
// echo "\nifd_bytes:";var_dump($ifd_bytes); // echo "\nifd_bytes:";var_dump($ifd_bytes);
if (!$ifd_count) { if (!$ifd_count) {
if($ifd_format==EXIF_ASCII) $ifd_count=strlen($ifd_entry->value)+1; if($ifd_format==EXIF_ASCII) $ifd_count=strlen($ifd_entry->value)+1;
else $ifd_count=1 ; /// may change? else $ifd_count=1 ; /// may change?
} }
//echo "\nifd_count=$ifd_count"; //echo "\nifd_count=$ifd_count";
$exif_data[$ifd_pointer++]= ($ifd_tag >> 8) & 0xff; $exif_data[$ifd_pointer++]= ($ifd_tag >> 8) & 0xff;
$exif_data[$ifd_pointer++]= $ifd_tag & 0xff; $exif_data[$ifd_pointer++]= $ifd_tag & 0xff;
$exif_data[$ifd_pointer++]= ($ifd_format >> 8 ) & 0xff; $exif_data[$ifd_pointer++]= ($ifd_format >> 8 ) & 0xff;
$exif_data[$ifd_pointer++]= $ifd_format & 0xff; $exif_data[$ifd_pointer++]= $ifd_format & 0xff;
$exif_data[$ifd_pointer++]= ($ifd_count >> 24) & 0xff; $exif_data[$ifd_pointer++]= ($ifd_count >> 24) & 0xff;
$exif_data[$ifd_pointer++]= ($ifd_count >> 16) & 0xff; $exif_data[$ifd_pointer++]= ($ifd_count >> 16) & 0xff;
$exif_data[$ifd_pointer++]= ($ifd_count >> 8) & 0xff; $exif_data[$ifd_pointer++]= ($ifd_count >> 8) & 0xff;
$exif_data[$ifd_pointer++]= $ifd_count & 0xff; $exif_data[$ifd_pointer++]= $ifd_count & 0xff;
$ifd_bytes=0; $ifd_bytes=0;
switch ($ifd_format) { switch ($ifd_format) {
case EXIF_SHORT: case EXIF_SHORT:
case EXIF_SSHORT: $ifd_bytes=2; break; case EXIF_SSHORT: $ifd_bytes=2; break;
case EXIF_LONG: case EXIF_LONG:
case EXIF_SLONG: $ifd_bytes=4; break; case EXIF_SLONG: $ifd_bytes=4; break;
case EXIF_RATIONAL: case EXIF_RATIONAL:
case EXIF_SRATIONAL: $ifd_bytes=8; break; case EXIF_SRATIONAL: $ifd_bytes=8; break;
default: $ifd_bytes=1; //1,2,6,7 default: $ifd_bytes=1; //1,2,6,7
} }
$ifd_bytes=$ifd_bytes*$ifd_count; $ifd_bytes=$ifd_bytes*$ifd_count;
// now prepare ifd_data - array of bytes // now prepare ifd_data - array of bytes
switch ($ifd_format) { switch ($ifd_format) {
case EXIF_BYTE: case EXIF_BYTE:
case EXIF_SBYTE: case EXIF_SBYTE:
$ifd_data= array (); $ifd_data= array ();
foreach ($ifd_entry->value as $a) $ifd_data[]= $a & 0xff; foreach ($ifd_entry->value as $a) $ifd_data[]= $a & 0xff;
break; break;
case EXIF_ASCII: case EXIF_ASCII:
$ifd_data= str_split($ifd_entry->value); $ifd_data= str_split($ifd_entry->value);
foreach($ifd_data as &$d) $d=ord($d); foreach($ifd_data as &$d) $d=ord($d);
break; break;
case EXIF_SHORT: case EXIF_SHORT:
case EXIF_SSHORT: case EXIF_SSHORT:
$ifd_data= array (); $ifd_data= array ();
foreach ($ifd_entry->value as $a) $ifd_data=array_merge($ifd_data,array(($a >> 8) & 0xff, $a & 0xff)); foreach ($ifd_entry->value as $a) $ifd_data=array_merge($ifd_data,array(($a >> 8) & 0xff, $a & 0xff));
break; break;
case EXIF_LONG: case EXIF_LONG:
case EXIF_SLONG: case EXIF_SLONG:
$ifd_data= array (); $ifd_data= array ();
foreach ($ifd_entry->value as $a) $ifd_data=array_merge($ifd_data,array(($a >> 24) & 0xff,($a >> 16) & 0xff,($a >> 8) & 0xff, $a & 0xff)); foreach ($ifd_entry->value as $a) $ifd_data=array_merge($ifd_data,array(($a >> 24) & 0xff,($a >> 16) & 0xff,($a >> 8) & 0xff, $a & 0xff));
break; break;
case EXIF_RATIONAL: case EXIF_RATIONAL:
case EXIF_SRATIONAL: case EXIF_SRATIONAL:
$nom= array (); $nom= array ();
foreach ($ifd_entry->nominator as $a) $nom[]= array(($a >> 24) & 0xff,($a >> 16) & 0xff,($a >> 8) & 0xff, $a & 0xff); foreach ($ifd_entry->nominator as $a) $nom[]= array(($a >> 24) & 0xff,($a >> 16) & 0xff,($a >> 8) & 0xff, $a & 0xff);
$denom= array (); $denom= array ();
foreach ($ifd_entry->denominator as $a) $denom[]=array(($a >> 24) & 0xff,($a >> 16) & 0xff,($a >> 8) & 0xff, $a & 0xff); foreach ($ifd_entry->denominator as $a) $denom[]=array(($a >> 24) & 0xff,($a >> 16) & 0xff,($a >> 8) & 0xff, $a & 0xff);
$ifd_data= array (); $ifd_data= array ();
/* /*
var_dump($nom); var_dump($nom);
echo "\n"; echo "\n";
var_dump($denom); var_dump($denom);
echo "\n"; echo "\n";
//exit(0); //exit(0);
*/ */
for ($i=0;$i<count($nom);$i++) { for ($i=0;$i<count($nom);$i++) {
// echo "i=$i\n"; // echo "i=$i\n";
// echo "\nnom=";var_dump($nom[$i]); // echo "\nnom=";var_dump($nom[$i]);
// echo "\ndenom=";var_dump($denom[$i]); // echo "\ndenom=";var_dump($denom[$i]);
$ifd_data=array_merge($ifd_data,$nom[$i],$denom[$i]); $ifd_data=array_merge($ifd_data,$nom[$i],$denom[$i]);
} }
break; // rational, (un)signed break; // rational, (un)signed
case EXIF_UNDEFINED: // undefined case EXIF_UNDEFINED: // undefined
$ifd_data= array_fill(0,$ifd_bytes,0); // will just fill with "0"-s $ifd_data= array_fill(0,$ifd_bytes,0); // will just fill with "0"-s
break; break;
} }
// echo "\nifd_tag=$ifd_tag, entry=";print_r($i=$ifd_entry->value); // echo "\nifd_tag=$ifd_tag, entry=";print_r($i=$ifd_entry->value);
// echo "\nifd_data:";var_dump($ifd_data); // echo "\nifd_data:";var_dump($ifd_data);
// echo "\nifd_bytes:";var_dump($ifd_bytes); // echo "\nifd_bytes:";var_dump($ifd_bytes);
$ifd_data=array_pad($ifd_data,$ifd_bytes,0); $ifd_data=array_pad($ifd_data,$ifd_bytes,0);
$ifd_entry->addChild ('value_length',count($ifd_data)); $ifd_entry->addChild ('value_length',count($ifd_data));
// if (array_key_exists ( "ltag" , $attrs )) $ltag= ((string) $attrs["ltag"])+0; // if (array_key_exists ( "ltag" , $attrs )) $ltag= ((string) $attrs["ltag"])+0;
if ($attr["ltag"]) $ltag= ((string) $attrs["ltag"])+0; if ($attr["ltag"]) $ltag= ((string) $attrs["ltag"])+0;
else $ltag= $ifd_tag+($group<<16) ; else $ltag= $ifd_tag+($group<<16) ;
$ifd_entry->addChild ("ltag",$ltag ); $ifd_entry->addChild ("ltag",$ltag );
if (count($ifd_data) <=4) { if (count($ifd_data) <=4) {
$ifd_entry->addChild ('value_offest',$ifd_pointer); $ifd_entry->addChild ('value_offest',$ifd_pointer);
$ifd_data= array_pad($ifd_data,-4,0); // add leading zeroes if <4 bytes $ifd_data= array_pad($ifd_data,-4,0); // add leading zeroes if <4 bytes
for ($i=0;$i<4;$i++) $exif_data[$ifd_pointer++]=$ifd_data[$i]; for ($i=0;$i<4;$i++) $exif_data[$ifd_pointer++]=$ifd_data[$i];
} else { //pointer, not data } else { //pointer, not data
$ifd_entry->addChild ('value_offest',$data_pointer); $ifd_entry->addChild ('value_offest',$data_pointer);
$exif_data[$ifd_pointer++]= ($data_pointer >> 24) & 0xff; $exif_data[$ifd_pointer++]= ($data_pointer >> 24) & 0xff;
$exif_data[$ifd_pointer++]= ($data_pointer >> 16) & 0xff; $exif_data[$ifd_pointer++]= ($data_pointer >> 16) & 0xff;
$exif_data[$ifd_pointer++]= ($data_pointer >> 8) & 0xff; $exif_data[$ifd_pointer++]= ($data_pointer >> 8) & 0xff;
$exif_data[$ifd_pointer++]= $data_pointer & 0xff; $exif_data[$ifd_pointer++]= $data_pointer & 0xff;
for ($i=0;$i<count($ifd_data);$i++) { for ($i=0;$i<count($ifd_data);$i++) {
$exif_data[$data_pointer++]=$ifd_data[$i]; $exif_data[$data_pointer++]=$ifd_data[$i];
} }
} }
} }
?> ?>
/*!*************************************************************************** /*!***************************************************************************
*! FILE NAME : imgsrv.c *! FILE NAME : imgsrv.c
*! DESCRIPTION: Simple and fast HTTP server to send camera still images *! DESCRIPTION: Simple and fast HTTP server to send camera still images
*! Copyright (C) 2007-2008 Elphel, Inc. *! Copyright (C) 2007-2008 Elphel, Inc.
*! -----------------------------------------------------------------------------** *! -----------------------------------------------------------------------------**
*! This program is free software: you can redistribute it and/or modify *! 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 *! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or *! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version. *! (at your option) any later version.
*! *!
*! This program is distributed in the hope that it will be useful, *! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of *! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details. *! GNU General Public License for more details.
*! *!
*! You should have received a copy of the GNU General Public License *! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>. *! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------** *! -----------------------------------------------------------------------------**
*! *!
*! $Log: imgsrv.c,v $ *! $Log: imgsrv.c,v $
*! Revision 1.15 2014/06/25 23:32:26 dzhimiev *! Revision 1.15 2014/06/25 23:32:26 dzhimiev
*! 1. fixed imgsrv /n -> /r/n *! 1. fixed imgsrv /n -> /r/n
*! 2. updated revision number *! 2. updated revision number
*! *!
*! Revision 1.14 2012/04/08 04:11:28 elphel *! Revision 1.14 2012/04/08 04:11:28 elphel
*! 8.2.2 changes related to temperatures measurement and embedding in the Exif MakerNote *! 8.2.2 changes related to temperatures measurement and embedding in the Exif MakerNote
*! *!
*! Revision 1.13 2011/12/22 05:33:06 elphel *! Revision 1.13 2011/12/22 05:33:06 elphel
*! Added trigger command *! Added trigger command
*! *!
*! Revision 1.12 2010/08/16 17:10:24 elphel *! Revision 1.12 2010/08/16 17:10:24 elphel
*! added reporting frame number (for inter-camera synchronization) *! added reporting frame number (for inter-camera synchronization)
*! *!
*! Revision 1.11 2010/08/10 21:14:31 elphel *! Revision 1.11 2010/08/10 21:14:31 elphel
*! 8.0.8.39 - added EEPROM support for multiplexor and sensor boards, so autocampars.php uses application-specific defaults. Exif Orientation tag support, camera Model reflects application and optional mode (i.e. camera number in Eyesis) *! 8.0.8.39 - added EEPROM support for multiplexor and sensor boards, so autocampars.php uses application-specific defaults. Exif Orientation tag support, camera Model reflects application and optional mode (i.e. camera number in Eyesis)
*! *!
*! Revision 1.10 2010/08/03 06:13:51 elphel *! Revision 1.10 2010/08/03 06:13:51 elphel
*! bugfix - was not copying last 8 bytes of MakerNote *! bugfix - was not copying last 8 bytes of MakerNote
*! *!
*! Revision 1.9 2010/08/01 19:30:24 elphel *! Revision 1.9 2010/08/01 19:30:24 elphel
*! new readonly parameter FRAME_SIZE and it support in the applications *! new readonly parameter FRAME_SIZE and it support in the applications
*! *!
*! Revision 1.8 2010/07/20 20:13:34 elphel *! Revision 1.8 2010/07/20 20:13:34 elphel
*! 8.0.8.33 - added MakerNote info for composite images made with multisensor cameras (with 10359 board) *! 8.0.8.33 - added MakerNote info for composite images made with multisensor cameras (with 10359 board)
*! *!
*! Revision 1.7 2010/03/04 06:41:40 elphel *! Revision 1.7 2010/03/04 06:41:40 elphel
*! 8.0.7.3 - more data to makerNote *! 8.0.7.3 - more data to makerNote
*! *!
*! Revision 1.6 2010/02/18 22:59:26 elphel *! Revision 1.6 2010/02/18 22:59:26 elphel
*! 8.0.7.1 - file extension/mime type depends on color mode now (*.jpeg, *.jp4, *.jp46) *! 8.0.7.1 - file extension/mime type depends on color mode now (*.jpeg, *.jp4, *.jp46)
*! *!
*! Revision 1.5 2009/12/28 06:24:17 elphel *! Revision 1.5 2009/12/28 06:24:17 elphel
*! 8.0.6.6 - added MakerNote to Exif, it icludes channels gains and gammas/black levels *! 8.0.6.6 - added MakerNote to Exif, it icludes channels gains and gammas/black levels
*! *!
*! Revision 1.4 2009/10/12 19:20:23 elphel *! Revision 1.4 2009/10/12 19:20:23 elphel
*! Added "Content-Disposition" support to suggest filenames to save images *! Added "Content-Disposition" support to suggest filenames to save images
*! *!
*! Revision 1.3 2009/02/25 17:47:51 spectr_rain *! Revision 1.3 2009/02/25 17:47:51 spectr_rain
*! removed deprecated dependency *! removed deprecated dependency
*! *!
*! Revision 1.2 2009/02/18 06:25:41 elphel *! Revision 1.2 2009/02/18 06:25:41 elphel
*! fixed unterminated string of 1 character (GPS mode - 2/3) *! fixed unterminated string of 1 character (GPS mode - 2/3)
*! *!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel *! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*! *!
*! *!
*! Revision 1.11 2008/11/03 18:42:21 elphel *! Revision 1.11 2008/11/03 18:42:21 elphel
*! comment typo *! comment typo
*! *!
*! Revision 1.10 2008/10/29 04:18:28 elphel *! Revision 1.10 2008/10/29 04:18:28 elphel
*! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue) *! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
*! *!
*! Revision 1.9 2008/10/25 19:51:40 elphel *! Revision 1.9 2008/10/25 19:51:40 elphel
*! updated copyright year *! updated copyright year
*! *!
*! Revision 1.8 2008/10/21 21:28:52 elphel *! Revision 1.8 2008/10/21 21:28:52 elphel
*! support for xml meta output *! support for xml meta output
*! *!
*! Revision 1.7 2008/10/13 16:55:53 elphel *! Revision 1.7 2008/10/13 16:55:53 elphel
*! removed (some) obsolete P_* parameters, renamed CIRCLSEEK to LSEEK_CIRC constants (same as other similar) *! removed (some) obsolete P_* parameters, renamed CIRCLSEEK to LSEEK_CIRC constants (same as other similar)
*! *!
*! Revision 1.6 2008/10/11 18:46:07 elphel *! Revision 1.6 2008/10/11 18:46:07 elphel
*! snapshot *! snapshot
*! *!
*! Revision 1.5 2008/10/06 08:31:08 elphel *! Revision 1.5 2008/10/06 08:31:08 elphel
*! snapshot, first images *! snapshot, first images
*! *!
*! Revision 1.4 2008/09/07 19:48:08 elphel *! Revision 1.4 2008/09/07 19:48:08 elphel
*! snapshot *! snapshot
*! *!
*! Revision 1.3 2008/08/11 19:10:45 elphel *! Revision 1.3 2008/08/11 19:10:45 elphel
*! reduced syntax "complaints" from KDevelop *! reduced syntax "complaints" from KDevelop
*! *!
*! Revision 1.2 2008/05/16 06:06:54 elphel *! Revision 1.2 2008/05/16 06:06:54 elphel
*! supporting variable JPEG header length *! supporting variable JPEG header length
*! *!
*! Revision 1.14 2008/04/22 22:14:56 elphel *! Revision 1.14 2008/04/22 22:14:56 elphel
*! Added malloc failures handling, syslog logging of such events *! Added malloc failures handling, syslog logging of such events
*! *!
*! Revision 1.13 2008/04/16 20:30:33 elphel *! Revision 1.13 2008/04/16 20:30:33 elphel
*! added optional fps reduction to multipart JPEGs *! added optional fps reduction to multipart JPEGs
*! *!
*! Revision 1.11 2008/04/07 09:13:35 elphel *! Revision 1.11 2008/04/07 09:13:35 elphel
*! Changes related to new Exif generation/processing *! Changes related to new Exif generation/processing
*! *!
*! Revision 1.10 2008/03/22 04:39:53 elphel *! Revision 1.10 2008/03/22 04:39:53 elphel
*! remove complaints about "&_time=..." *! remove complaints about "&_time=..."
*! *!
*! Revision 1.9 2007/12/03 08:28:45 elphel *! Revision 1.9 2007/12/03 08:28:45 elphel
*! Multiple changes, mostly cleanup *! Multiple changes, mostly cleanup
*! *!
*! Revision 1.8 2007/11/16 08:56:19 elphel *! Revision 1.8 2007/11/16 08:56:19 elphel
*! Added support for 2 additional commands to check circbuf usage *! Added support for 2 additional commands to check circbuf usage
*! *!
*! Revision 1.7 2007/11/04 23:25:16 elphel *! Revision 1.7 2007/11/04 23:25:16 elphel
*! removed extra (used during debug) munmap that caused segfault after sending "img" (so no /nxt/save) *! removed extra (used during debug) munmap that caused segfault after sending "img" (so no /nxt/save)
*! *!
*! Revision 1.6 2007/11/04 05:47:40 elphel *! Revision 1.6 2007/11/04 05:47:40 elphel
*! Cleaned up from debug code inserted to fight mmap/caching bug (fixed by now) *! Cleaned up from debug code inserted to fight mmap/caching bug (fixed by now)
*! *!
*! Revision 1.5 2007/11/01 18:59:37 elphel *! Revision 1.5 2007/11/01 18:59:37 elphel
*! debugging mmap/caching problems *! debugging mmap/caching problems
*! *!
*! Revision 1.4 2007/10/30 16:56:06 elphel *! Revision 1.4 2007/10/30 16:56:06 elphel
*! release 7.1.4.5 - working on "can not find 0xffff in frame parameters" bug. Temporary fix *! release 7.1.4.5 - working on "can not find 0xffff in frame parameters" bug. Temporary fix
*! *!
*! Revision 1.3 2007/10/27 00:55:32 elphel *! Revision 1.3 2007/10/27 00:55:32 elphel
*! untested revision - need to go *! untested revision - need to go
*! *!
*! Revision 1.2 2007/10/11 06:42:28 elphel *! Revision 1.2 2007/10/11 06:42:28 elphel
*! Fixed bug - /meta command should return trivial xml file, not 1x1 pixel gif *! Fixed bug - /meta command should return trivial xml file, not 1x1 pixel gif
*! *!
*! Revision 1.1.1.1 2007/10/02 19:44:54 elphel *! Revision 1.1.1.1 2007/10/02 19:44:54 elphel
*! This is a fresh tree based on elphel353-2.10 *! This is a fresh tree based on elphel353-2.10
*! *!
*! Revision 1.4 2007/10/02 19:44:54 elphel *! Revision 1.4 2007/10/02 19:44:54 elphel
*! More functionality (buffer manipulation commands, clean interface, xml responces) *! More functionality (buffer manipulation commands, clean interface, xml responces)
*! *!
*! Revision 1.3 2007/09/29 16:21:25 elphel *! Revision 1.3 2007/09/29 16:21:25 elphel
*! removed IOCTL usage from /dev/circbuf, improved comments, other minor changes *! removed IOCTL usage from /dev/circbuf, improved comments, other minor changes
*! *!
*! Revision 1.2 2007/09/25 23:35:16 elphel *! Revision 1.2 2007/09/25 23:35:16 elphel
*! added Exif initialization, made it to work in background mode *! added Exif initialization, made it to work in background mode
*! *!
*! Revision 1.1 2007/09/23 06:49:10 elphel *! Revision 1.1 2007/09/23 06:49:10 elphel
*! Simple web server designed for particular task - serving camera JPEG images. It is faster, than through any of the web servers tested. Only some of the functionality is implemented (no Exif yet, no synchronization with the camera) *! Simple web server designed for particular task - serving camera JPEG images. It is faster, than through any of the web servers tested. Only some of the functionality is implemented (no Exif yet, no synchronization with the camera)
*! *!
*! *!
*/ */
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
...@@ -174,30 +174,23 @@ ...@@ -174,30 +174,23 @@
#undef ELPHEL_DEBUG #undef ELPHEL_DEBUG
#if ELPHEL_DEBUG #if ELPHEL_DEBUG
#define ELPHEL_DEBUG_THIS 1 #define ELPHEL_DEBUG_THIS 1
#else #else
#define ELPHEL_DEBUG_THIS 0 #define ELPHEL_DEBUG_THIS 0
#endif #endif
#if ELPHEL_DEBUG_THIS #if ELPHEL_DEBUG_THIS
#define D(x) fprintf(stderr, "%s:%d:%s: ", __FILE__, __LINE__, __FUNCTION__); x #define D(x) fprintf(stderr, "%s:%d:%s: ", __FILE__, __LINE__, __FUNCTION__); x
#else #else
#define D(x) #define D(x)
#endif #endif
//#define USEHTTP10(x) // HEADER_SIZE is defined to be larger than actual header (later - with EXIF) to use compile-time buffer
#define USEHTTP10(x) x #define JPEG_HEADER_MAXSIZE 0x300 // will not change
#define TRAILER_SIZE 0x02
// HEADER_SIZE is defined to be larger than actual header (later - with EXIF) to use compile-time buffer /** @brief the length of MakerNote buffer in @e long */
//#define JPEG_HEADER_SIZE 0x26f // will not change #define MAKERNOTE_LEN 16
#define JPEG_HEADER_MAXSIZE 0x300 // will not change
#define TRAILER_SIZE 0x02
#define MAP_OPTIONS MAP_FILE | MAP_PRIVATE
//#define GLOBALPARS(x) globalPars[(x)-FRAMEPAR_GLOBALS] // should work in drivers and application
#define IMAGE_CHN_NUM 4
struct file_set { struct file_set {
unsigned short port_num; unsigned short port_num;
...@@ -205,79 +198,80 @@ struct file_set { ...@@ -205,79 +198,80 @@ struct file_set {
int circbuf_fd; int circbuf_fd;
const char *jphead_fn; const char *jphead_fn;
int jphead_fd; int jphead_fd;
const char *exif_dev_name;
int exif_dev_fd;
const char *exifmeta_dev_name;
int exifmeta_dev_fd;
}; };
static struct file_set files[IMAGE_CHN_NUM]; static struct file_set files[SENSOR_PORTS];
unsigned long * ccam_dma_buf; /* mmapped array */ unsigned long * ccam_dma_buf; /* mmapped array */
char trailer[TRAILER_SIZE] = { 0xff, 0xd9 }; char trailer[TRAILER_SIZE] = { 0xff, 0xd9 };
const char *circbuf_fnames[] = { const char *circbuf_fnames[] = {
"/dev/circbuf0", "/dev/circbuf0",
"/dev/circbuf1", "/dev/circbuf1",
"/dev/circbuf2", "/dev/circbuf2",
"/dev/circbuf3" "/dev/circbuf3"
}; };
const char *jhead_fnames[] = { const char *jhead_fnames[] = {
"/dev/jpeghead0", "/dev/jpeghead0",
"/dev/jpeghead1", "/dev/jpeghead1",
"/dev/jpeghead2", "/dev/jpeghead2",
"/dev/jpeghead3", "/dev/jpeghead3",
}; };
static const char *exif_dev_names[SENSOR_PORTS] = { EXIF_DEV_NAMES };
static const char *exifmeta_dev_names[SENSOR_PORTS] = { EXIFMETA_DEV_NAMES };
const char app_args[] = "Usage:\n%s -p <port_number_1> [<port_number_2> <port_number_3> <port_number_4>]\n" \ const char app_args[] = "Usage:\n%s -p <port_number_1> [<port_number_2> <port_number_3> <port_number_4>]\n" \
"Start image server, bind it to ports <port_number_1> <port_number_2> <port_number_3> <port_number_4>\n" \ "Start image server, bind it to ports <port_number_1> <port_number_2> <port_number_3> <port_number_4>\n" \
"or to ports <port_number_1> <port_number_1 + 1> <port_number_1 + 2> <port_number_1 + 3> if " \ "or to ports <port_number_1> <port_number_1 + 1> <port_number_1 + 2> <port_number_1 + 3> if " \
"<port_number_2>, <port_number_3> and <port_number_4> are not provided\n"; "<port_number_2>, <port_number_3> and <port_number_4> are not provided\n";
const char url_args[] = "This server supports sequence of commands entered in the URL (separated by \"/\", case sensitive )\n" const char url_args[] = "This server supports sequence of commands entered in the URL (separated by \"/\", case sensitive )\n"
"executing them from left to right as they appear in the URL\n" "executing them from left to right as they appear in the URL\n"
"img - send image at the current pointer (if it is first command - use last acquired image, if none availabe - send 1x1 gif)\n" "img - send image at the current pointer (if it is first command - use last acquired image, if none availabe - send 1x1 gif)\n"
"bimg - same as above, but save the whole image in the memory before sending - useful to avoid overruns with slow connection \n" "bimg - same as above, but save the whole image in the memory before sending - useful to avoid overruns with slow connection \n"
"simg, sbimg - similar to img, bimg but will imemdiately suggest to save instead of opening image in the browser\n" "simg, sbimg - similar to img, bimg but will imemdiately suggest to save instead of opening image in the browser\n"
"mimg[n] - send images as a multipart JPEG (all commands after will be ignored), possible to specify optional fps reduction\n" "mimg[n] - send images as a multipart JPEG (all commands after will be ignored), possible to specify optional fps reduction\n"
" i.e. mimg4 - skip 3 frames for each frame output (1/4 fps) \n" " i.e. mimg4 - skip 3 frames for each frame output (1/4 fps) \n"
"bmimg[n] - same as above, buffered\n" "bmimg[n] - same as above, buffered\n"
"pointers - send XML-formatted data about frames available in the camera circular buffer)\n" "pointers - send XML-formatted data about frames available in the camera circular buffer)\n"
"frame - return current frame number as plain text\n" "frame - return current frame number as plain text\n"
"wframe - wait for the next frame sync, return current frame number as plain text\n\n" "wframe - wait for the next frame sync, return current frame number as plain text\n\n"
"Any of the 7 commands above can appear only once in the URL string, the second instance will be ignored. If none of the 5\n" "Any of the 7 commands above can appear only once in the URL string, the second instance will be ignored. If none of the 5\n"
"are present in the URL 1x1 pixel gif will be returned to the client after executing the URL command.\n\n" "are present in the URL 1x1 pixel gif will be returned to the client after executing the URL command.\n\n"
"torp - set frame pointer to global read pointer, maintained by the camera driver. If frame at that pointer\n" "torp - set frame pointer to global read pointer, maintained by the camera driver. If frame at that pointer\n"
" is invalid, use scnd (see below)\n" " is invalid, use scnd (see below)\n"
"towp - set frame pointer to hardware write pointer - position where next frame will be aquired\n" "towp - set frame pointer to hardware write pointer - position where next frame will be aquired\n"
"prev - move to previous frame in buffer, nop if there are none\n" "prev - move to previous frame in buffer, nop if there are none\n"
"next - move to the next frame in buffer (will stop at write pointer, see towp above)\n" "next - move to the next frame in buffer (will stop at write pointer, see towp above)\n"
"last - move to the most recently acquired frame, or to write pointer if there are none.\n" "last - move to the most recently acquired frame, or to write pointer if there are none.\n"
" this command is implied at the start of the url command sequence.\n" " this command is implied at the start of the url command sequence.\n"
"first - move to the oldest frame still available in the buffer. It is not safe to rely on it if\n" "first - move to the oldest frame still available in the buffer. It is not safe to rely on it if\n"
" more frames are expected - data might be overwritten at any moment and the output will be corrupted.\n" " more frames are expected - data might be overwritten at any moment and the output will be corrupted.\n"
"second - move to the second oldest frame in the buffer - somewhat safer than \"first\" - there will be time for\n" "second - move to the second oldest frame in the buffer - somewhat safer than \"first\" - there will be time for\n"
" \"next\" command at least before frame data (and pointer structures) will be overwritten.\n" " \"next\" command at least before frame data (and pointer structures) will be overwritten.\n"
"save - save current frame pointer as a global read pointer that holds it values between server requests.\n" "save - save current frame pointer as a global read pointer that holds it values between server requests.\n"
" This pointer is shared between all the clients and applications that use it.\n" " This pointer is shared between all the clients and applications that use it.\n"
"wait - Wait until there will be a frame at current pointer ready\n" "wait - Wait until there will be a frame at current pointer ready\n"
"trig - send a single internal trigger (and puts internal trigger in single-shot mode\n" "trig - send a single internal trigger (and puts internal trigger in single-shot mode\n"
" In this special mode autoexposure/white balance will not work in most cases,\n" " In this special mode autoexposure/white balance will not work in most cases,\n"
" camera should be set in triggered mode (TRIG=4), internal (TRIG_CONDITION=0).\n" " camera should be set in triggered mode (TRIG=4), internal (TRIG_CONDITION=0).\n"
" No effect on free-running or \"slave\" cameras, so it is OK to send it to all."; " No effect on free-running or \"slave\" cameras, so it is OK to send it to all.";
//int sendImage(int bufferImageData, int fd_circ, int use_Exif);
//int sendImage(int bufferImageData, int fd_circ, int use_Exif, int saveImage); int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int saveImage);
void sendBuffer(void * buffer, int len); void sendBuffer(void * buffer, int len);
//void listener_loop(int port, const char *circbuf_fname); void listener_loop(struct file_set *fset);
void errorMsgXML(char * msg); void errorMsgXML(char * msg);
int framePointersXML(int fd_circ); int framePointersXML(struct file_set *fset);
int metaXML(int fd_circ, int mode); /// mode: 0 - new (send headers), 1 - continue, 2 - finish int metaXML(struct file_set *fset, int mode); /// mode: 0 - new (send headers), 1 - continue, 2 - finish
int printExifXML(int exif_page); int printExifXML(int exif_page, struct file_set *fset);
int out1x1gif(void); int out1x1gif(void);
void waitFrameSync(); void waitFrameSync();
unsigned long getCurrentFrameNumber(); unsigned long getCurrentFrameNumber();
#define saferead255(f, d, l) read(f, d, ((l) < 256) ? (l) : 255) #define saferead255(f, d, l) read(f, d, ((l) < 256) ? (l) : 255)
int printExifXML(int exif_page) int printExifXML(int exif_page, struct file_set *fset)
{ {
int indx; int indx;
long numfields = 0; long numfields = 0;
...@@ -285,8 +279,8 @@ int printExifXML(int exif_page) ...@@ -285,8 +279,8 @@ int printExifXML(int exif_page)
int fd_exifdir; int fd_exifdir;
struct exif_dir_table_t exif_dir[ExifKmlNumber]; /// store locations of the fields needed for KML generations in the Exif block struct exif_dir_table_t exif_dir[ExifKmlNumber]; /// store locations of the fields needed for KML generations in the Exif block
/// Create Exif directory /// Create Exif directory
/// Read the size of the Exif data /// Read the size of the Exif data
fd_exifdir = open(EXIFDIR_DEV_NAME, O_RDONLY); fd_exifdir = open(EXIFDIR_DEV_NAME, O_RDONLY);
if (fd_exifdir < 0) { if (fd_exifdir < 0) {
printf("<error>\"Opening %s\"</error>\n", EXIFDIR_DEV_NAME); printf("<error>\"Opening %s\"</error>\n", EXIFDIR_DEV_NAME);
...@@ -296,7 +290,7 @@ int printExifXML(int exif_page) ...@@ -296,7 +290,7 @@ int printExifXML(int exif_page)
while (read(fd_exifdir, &dir_table_entry, sizeof(dir_table_entry)) > 0) { while (read(fd_exifdir, &dir_table_entry, sizeof(dir_table_entry)) > 0) {
switch (dir_table_entry.ltag) { switch (dir_table_entry.ltag) {
case Exif_Image_ImageDescription: indx = Exif_Image_ImageDescription_Index; break; case Exif_Image_ImageDescription: indx = Exif_Image_ImageDescription_Index; break;
case Exif_Image_FrameNumber: indx = Exif_Image_FrameNumber_Index; break; case Exif_Image_ImageNumber: indx = Exif_Image_ImageNumber_Index; break;
case Exif_Photo_DateTimeOriginal: indx = Exif_Photo_DateTimeOriginal_Index; break; case Exif_Photo_DateTimeOriginal: indx = Exif_Photo_DateTimeOriginal_Index; break;
case Exif_Photo_SubSecTimeOriginal: indx = Exif_Photo_SubSecTimeOriginal_Index; break; case Exif_Photo_SubSecTimeOriginal: indx = Exif_Photo_SubSecTimeOriginal_Index; break;
case Exif_Photo_ExposureTime: indx = Exif_Photo_ExposureTime_Index; break; case Exif_Photo_ExposureTime: indx = Exif_Photo_ExposureTime_Index; break;
...@@ -317,6 +311,7 @@ int printExifXML(int exif_page) ...@@ -317,6 +311,7 @@ int printExifXML(int exif_page)
case Exif_GPSInfo_CompassPitch: indx = Exif_GPSInfo_CompassPitch_Index; break; case Exif_GPSInfo_CompassPitch: indx = Exif_GPSInfo_CompassPitch_Index; break;
case Exif_GPSInfo_CompassRollRef: indx = Exif_GPSInfo_CompassRollRef_Index; break; case Exif_GPSInfo_CompassRollRef: indx = Exif_GPSInfo_CompassRollRef_Index; break;
case Exif_GPSInfo_CompassRoll: indx = Exif_GPSInfo_CompassRoll_Index; break; case Exif_GPSInfo_CompassRoll: indx = Exif_GPSInfo_CompassRoll_Index; break;
case Exif_Image_PageNumber: indx = Exif_Image_PageNumber_Index; break;
default: indx = -1; default: indx = -1;
} }
if (indx >= 0) { if (indx >= 0) {
...@@ -325,132 +320,144 @@ int printExifXML(int exif_page) ...@@ -325,132 +320,144 @@ int printExifXML(int exif_page)
} }
} }
close(fd_exifdir); close(fd_exifdir);
/// Create XML files iteslf
/// Create XML files itself
long rational3[6]; long rational3[6];
long makerNote[14]; long makerNote[MAKERNOTE_LEN];
long exif_page_start; long exif_page_start;
char val[256]; char val[256];
int hours = 0, minutes = 0; int hours = 0, minutes = 0;
double seconds = 0.0; double seconds = 0.0;
double longitude = 0.0, latitude = 0.0, altitude = 0.0, heading = 0.0, roll = 0.0, pitch = 0.0, exposure = 0.0; double longitude = 0.0, latitude = 0.0, altitude = 0.0, heading = 0.0, roll = 0.0, pitch = 0.0, exposure = 0.0;
val[255] = '\0'; val[255] = '\0';
int fd_exif = open(EXIF_DEV_NAME, O_RDONLY); int fd_exif = open(fset->exif_dev_name, O_RDONLY);
if (fd_exif < 0) { if (fd_exif < 0) {
printf("<error>\"Opening %s\"</error>\n", EXIF_DEV_NAME); printf("<error>\"Opening %s\"</error>\n", fset->exif_dev_name);
return -3; return -3;
} }
fset->exif_dev_fd = fd_exif;
exif_page_start = lseek(fd_exif, exif_page, SEEK_END); /// select specified Exif page exif_page_start = lseek(fd_exif, exif_page, SEEK_END); /// select specified Exif page
if (exif_page_start < 0) { if (exif_page_start < 0) {
printf("<error>\"Exif page (%d) is out of range\"</error>\n", exif_page); printf("<error>\"Exif page (%d) is out of range\"</error>\n", exif_page);
close(fd_exif); close(fd_exif);
return -1; /// Error opening Exif return -1; /// Error opening Exif
} }
///Image Description ///Image Description
if (exif_dir[Exif_Image_ImageDescription_Index].ltag == Exif_Image_ImageDescription) { // Exif_Image_ImageDescription is present in template if (exif_dir[Exif_Image_ImageDescription_Index].ltag == Exif_Image_ImageDescription) { // Exif_Image_ImageDescription is present in template
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_Image_ImageDescription_Index].dst, exif_page_start + exif_dir[Exif_Image_ImageDescription_Index].dst,
SEEK_SET); SEEK_SET);
saferead255(fd_exif, val, exif_dir[Exif_Image_ImageDescription_Index].len); saferead255(fd_exif, val, exif_dir[Exif_Image_ImageDescription_Index].len);
printf("<ImageDescription>\"%s\"</ImageDescription>\n", val); printf("<ImageDescription>\"%s\"</ImageDescription>\n", val);
} }
///Exif_Image_FrameNumber_Index 0x13 ///Exif_Image_ImageNumber_Index 0x13
if (exif_dir[Exif_Image_FrameNumber_Index].ltag == Exif_Image_FrameNumber) { // Exif_Image_FrameNumber_Index is present in template if (exif_dir[Exif_Image_ImageNumber_Index].ltag == Exif_Image_ImageNumber) { // Exif_Image_ImageNumber_Index is present in template
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_Image_FrameNumber_Index].dst, exif_page_start + exif_dir[Exif_Image_ImageNumber_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, rational3, 4); read(fd_exif, rational3, 4);
sprintf(val, "%ld", (long)__cpu_to_be32( rational3[0])); sprintf(val, "%ld", (long)__cpu_to_be32( rational3[0]));
printf("<FrameNumber>\"%s\"</FrameNumber>\n", val); printf("<ImageNumber>\"%s\"</ImageNumber>\n", val);
} }
///Exif_Image_Orientation_Index 0x15 ///Exif_Image_Orientation_Index 0x14
if (exif_dir[Exif_Image_Orientation_Index].ltag == Exif_Image_Orientation) { // Exif_Image_Orientation_Index is present in template if (exif_dir[Exif_Image_Orientation_Index].ltag == Exif_Image_Orientation) { // Exif_Image_Orientation_Index is present in template
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_Image_Orientation_Index].dst, exif_page_start + exif_dir[Exif_Image_Orientation_Index].dst,
SEEK_SET); SEEK_SET);
rational3[0] = 0; rational3[0] = 0;
read(fd_exif, rational3, 2); read(fd_exif, rational3, 2);
sprintf(val, "%ld", (long)( rational3[0] >> 8)); sprintf(val, "%ld", (long)( rational3[0] >> 8));
printf("<Orientation>\"%s\"</Orientation>\n", val); printf("<Orientation>\"%s\"</Orientation>\n", val);
} }
///DateTimeOriginal (with subseconds) // Exif_Image_PageNumber
if (exif_dir[Exif_Image_PageNumber_Index].ltag == Exif_Image_PageNumber) { // Exif_Image_Orientation_Index is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Image_PageNumber_Index].dst,
SEEK_SET);
rational3[0] = 0;
read(fd_exif, rational3, 2);
sprintf(val, "%u", __cpu_to_be16(rational3[0]));
printf("<SensorNumber>\"%s\"</SensorNumber>\n", val);
}
///DateTimeOriginal (with subseconds)
if (exif_dir[Exif_Photo_DateTimeOriginal_Index].ltag == Exif_Photo_DateTimeOriginal) { if (exif_dir[Exif_Photo_DateTimeOriginal_Index].ltag == Exif_Photo_DateTimeOriginal) {
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_Photo_DateTimeOriginal_Index].dst, exif_page_start + exif_dir[Exif_Photo_DateTimeOriginal_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, val, 19); read(fd_exif, val, 19);
val[19] = '\0'; val[19] = '\0';
if (exif_dir[Exif_Photo_SubSecTimeOriginal_Index].ltag == Exif_Photo_SubSecTimeOriginal) { if (exif_dir[Exif_Photo_SubSecTimeOriginal_Index].ltag == Exif_Photo_SubSecTimeOriginal) {
val[19] = '.'; val[19] = '.';
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_Photo_SubSecTimeOriginal_Index].dst, exif_page_start + exif_dir[Exif_Photo_SubSecTimeOriginal_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, &val[20], 7); read(fd_exif, &val[20], 7);
val[27] = '\0'; val[27] = '\0';
} }
printf("<DateTimeOriginal>\"%s\"</DateTimeOriginal>\n", val); printf("<DateTimeOriginal>\"%s\"</DateTimeOriginal>\n", val);
} }
///Exif_Photo_ExposureTime ///Exif_Photo_ExposureTime
if (exif_dir[Exif_Photo_ExposureTime_Index].ltag == Exif_Photo_ExposureTime) { // Exif_Photo_ExposureTime is present in template if (exif_dir[Exif_Photo_ExposureTime_Index].ltag == Exif_Photo_ExposureTime) { // Exif_Photo_ExposureTime is present in template
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_Photo_ExposureTime_Index].dst, exif_page_start + exif_dir[Exif_Photo_ExposureTime_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, rational3, 8); read(fd_exif, rational3, 8);
exposure = (1.0 * __cpu_to_be32( rational3[0])) / __cpu_to_be32( rational3[1]); exposure = (1.0 * __cpu_to_be32( rational3[0])) / __cpu_to_be32( rational3[1]);
sprintf(val, "%f", exposure); sprintf(val, "%f", exposure);
printf("<ExposureTime>\"%s\"</ExposureTime>\n", val); printf("<ExposureTime>\"%s\"</ExposureTime>\n", val);
} }
///Exif_Photo_MakerNote ///Exif_Photo_MakerNote
if (exif_dir[Exif_Photo_MakerNote_Index].ltag == Exif_Photo_MakerNote) { // Exif_Photo_MakerNote is present in template if (exif_dir[Exif_Photo_MakerNote_Index].ltag == Exif_Photo_MakerNote) { // Exif_Photo_MakerNote is present in template
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_Photo_MakerNote_Index].dst, exif_page_start + exif_dir[Exif_Photo_MakerNote_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, makerNote, 64); read(fd_exif, makerNote, 64);
sprintf(val, sprintf(val,
"0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx", "0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx,0x%08lx",
(long)__cpu_to_be32(makerNote[0]), (long)__cpu_to_be32(makerNote[0]),
(long)__cpu_to_be32(makerNote[1]), (long)__cpu_to_be32(makerNote[1]),
(long)__cpu_to_be32(makerNote[2]), (long)__cpu_to_be32(makerNote[2]),
(long)__cpu_to_be32(makerNote[3]), (long)__cpu_to_be32(makerNote[3]),
(long)__cpu_to_be32(makerNote[4]), (long)__cpu_to_be32(makerNote[4]),
(long)__cpu_to_be32(makerNote[5]), (long)__cpu_to_be32(makerNote[5]),
(long)__cpu_to_be32(makerNote[6]), (long)__cpu_to_be32(makerNote[6]),
(long)__cpu_to_be32(makerNote[7]), (long)__cpu_to_be32(makerNote[7]),
(long)__cpu_to_be32(makerNote[8]), (long)__cpu_to_be32(makerNote[8]),
(long)__cpu_to_be32(makerNote[9]), (long)__cpu_to_be32(makerNote[9]),
(long)__cpu_to_be32(makerNote[10]), (long)__cpu_to_be32(makerNote[10]),
(long)__cpu_to_be32(makerNote[11]), (long)__cpu_to_be32(makerNote[11]),
(long)__cpu_to_be32(makerNote[12]), (long)__cpu_to_be32(makerNote[12]),
(long)__cpu_to_be32(makerNote[13]), (long)__cpu_to_be32(makerNote[13]),
(long)__cpu_to_be32(makerNote[14]), (long)__cpu_to_be32(makerNote[14]),
(long)__cpu_to_be32(makerNote[15])); (long)__cpu_to_be32(makerNote[15]));
printf("<MakerNote>\"%s\"</MakerNote>\n", val); printf("<MakerNote>\"%s\"</MakerNote>\n", val);
} }
/// GPS measure mode
/// GPS measure mode
if (exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].ltag == Exif_GPSInfo_GPSMeasureMode) { if (exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].ltag == Exif_GPSInfo_GPSMeasureMode) {
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, val, 1); read(fd_exif, val, 1);
val[1] = '\0'; val[1] = '\0';
printf("<GPSMeasureMode>\"%s\"</GPSMeasureMode>\n", val); printf("<GPSMeasureMode>\"%s\"</GPSMeasureMode>\n", val);
} }
///GPS date/time
///GPS date/time
if (exif_dir[Exif_GPSInfo_GPSDateStamp_Index].ltag == Exif_GPSInfo_GPSDateStamp) { if (exif_dir[Exif_GPSInfo_GPSDateStamp_Index].ltag == Exif_GPSInfo_GPSDateStamp) {
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSDateStamp_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_GPSDateStamp_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, val, 10); read(fd_exif, val, 10);
val[10] = '\0'; val[10] = '\0';
if (exif_dir[Exif_GPSInfo_GPSTimeStamp_Index].ltag == Exif_GPSInfo_GPSTimeStamp) { if (exif_dir[Exif_GPSInfo_GPSTimeStamp_Index].ltag == Exif_GPSInfo_GPSTimeStamp) {
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSTimeStamp_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_GPSTimeStamp_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, rational3, 24); read(fd_exif, rational3, 24);
hours = __cpu_to_be32( rational3[0]); hours = __cpu_to_be32( rational3[0]);
minutes = __cpu_to_be32( rational3[2]); minutes = __cpu_to_be32( rational3[2]);
...@@ -460,82 +467,82 @@ int printExifXML(int exif_page) ...@@ -460,82 +467,82 @@ int printExifXML(int exif_page)
printf("<GPSDateTime>\"%s\"</GPSDateTime>\n", val); printf("<GPSDateTime>\"%s\"</GPSDateTime>\n", val);
} }
/// knowing format provided from GPS - degrees and minutes only, no seconds: /// knowing format provided from GPS - degrees and minutes only, no seconds:
///GPS Longitude ///GPS Longitude
if (exif_dir[Exif_GPSInfo_GPSLongitude_Index].ltag == Exif_GPSInfo_GPSLongitude) { // Exif_GPSInfo_GPSLongitude is present in template if (exif_dir[Exif_GPSInfo_GPSLongitude_Index].ltag == Exif_GPSInfo_GPSLongitude) { // Exif_GPSInfo_GPSLongitude is present in template
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSLongitude_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_GPSLongitude_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, rational3, 24); read(fd_exif, rational3, 24);
longitude = __cpu_to_be32( rational3[0]) / (1.0 * __cpu_to_be32( rational3[1])) + __cpu_to_be32( rational3[2]) / (60.0 * __cpu_to_be32( rational3[3])); longitude = __cpu_to_be32( rational3[0]) / (1.0 * __cpu_to_be32( rational3[1])) + __cpu_to_be32( rational3[2]) / (60.0 * __cpu_to_be32( rational3[3]));
if (exif_dir[Exif_GPSInfo_GPSLongitudeRef_Index].ltag == Exif_GPSInfo_GPSLongitudeRef) { if (exif_dir[Exif_GPSInfo_GPSLongitudeRef_Index].ltag == Exif_GPSInfo_GPSLongitudeRef) {
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSLongitudeRef_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_GPSLongitudeRef_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, val, 1); read(fd_exif, val, 1);
if (val[0] != 'E') longitude = -longitude; if (val[0] != 'E') longitude = -longitude;
} }
sprintf(val, "%f", longitude); sprintf(val, "%f", longitude);
printf("<GPSLongitude>\"%s\"</GPSLongitude>\n", val); printf("<GPSLongitude>\"%s\"</GPSLongitude>\n", val);
} }
///GPS Latitude ///GPS Latitude
if (exif_dir[Exif_GPSInfo_GPSLatitude_Index].ltag == Exif_GPSInfo_GPSLatitude) { // Exif_GPSInfo_GPSLatitude is present in template if (exif_dir[Exif_GPSInfo_GPSLatitude_Index].ltag == Exif_GPSInfo_GPSLatitude) { // Exif_GPSInfo_GPSLatitude is present in template
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSLatitude_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_GPSLatitude_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, rational3, 24); read(fd_exif, rational3, 24);
latitude = __cpu_to_be32( rational3[0]) / (1.0 * __cpu_to_be32( rational3[1])) + __cpu_to_be32( rational3[2]) / (60.0 * __cpu_to_be32( rational3[3])); latitude = __cpu_to_be32( rational3[0]) / (1.0 * __cpu_to_be32( rational3[1])) + __cpu_to_be32( rational3[2]) / (60.0 * __cpu_to_be32( rational3[3]));
if (exif_dir[Exif_GPSInfo_GPSLatitudeRef_Index].ltag == Exif_GPSInfo_GPSLatitudeRef) { if (exif_dir[Exif_GPSInfo_GPSLatitudeRef_Index].ltag == Exif_GPSInfo_GPSLatitudeRef) {
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSLatitudeRef_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_GPSLatitudeRef_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, val, 1); read(fd_exif, val, 1);
if (val[0] != 'N') latitude = -latitude; if (val[0] != 'N') latitude = -latitude;
} }
sprintf(val, "%f", latitude); sprintf(val, "%f", latitude);
printf("<GPSLatitude>\"%s\"</GPSLatitude>\n", val); printf("<GPSLatitude>\"%s\"</GPSLatitude>\n", val);
} }
///GPS Altitude ///GPS Altitude
if (exif_dir[Exif_GPSInfo_GPSAltitude_Index].ltag == Exif_GPSInfo_GPSAltitude) { // Exif_GPSInfo_GPSAltitude is present in template if (exif_dir[Exif_GPSInfo_GPSAltitude_Index].ltag == Exif_GPSInfo_GPSAltitude) { // Exif_GPSInfo_GPSAltitude is present in template
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSAltitude_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_GPSAltitude_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, rational3, 8); read(fd_exif, rational3, 8);
altitude = (1.0 * __cpu_to_be32( rational3[0])) / __cpu_to_be32( rational3[1]); altitude = (1.0 * __cpu_to_be32( rational3[0])) / __cpu_to_be32( rational3[1]);
if (exif_dir[Exif_GPSInfo_GPSAltitudeRef_Index].ltag == Exif_GPSInfo_GPSAltitudeRef) { if (exif_dir[Exif_GPSInfo_GPSAltitudeRef_Index].ltag == Exif_GPSInfo_GPSAltitudeRef) {
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSAltitudeRef_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_GPSAltitudeRef_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, val, 1); read(fd_exif, val, 1);
if (val[0] != '\0') altitude = -altitude; if (val[0] != '\0') altitude = -altitude;
} }
sprintf(val, "%f", altitude); sprintf(val, "%f", altitude);
printf("<GPSAltitude>\"%s\"</GPSAltitude>\n", val); printf("<GPSAltitude>\"%s\"</GPSAltitude>\n", val);
} }
///Compass Direction (magnetic) ///Compass Direction (magnetic)
if (exif_dir[Exif_GPSInfo_CompassDirection_Index].ltag == Exif_GPSInfo_CompassDirection) { // Exif_GPSInfo_CompassDirection is present in template if (exif_dir[Exif_GPSInfo_CompassDirection_Index].ltag == Exif_GPSInfo_CompassDirection) { // Exif_GPSInfo_CompassDirection is present in template
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_CompassDirection_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_CompassDirection_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, rational3, 8); read(fd_exif, rational3, 8);
heading = (1.0 * __cpu_to_be32( rational3[0])) / __cpu_to_be32( rational3[1]); heading = (1.0 * __cpu_to_be32( rational3[0])) / __cpu_to_be32( rational3[1]);
sprintf(val, "%f", heading); sprintf(val, "%f", heading);
printf("<CompassDirection>\"%s\"</CompassDirection>\n", val); printf("<CompassDirection>\"%s\"</CompassDirection>\n", val);
} }
///Processing 'hacked' pitch and roll (made of Exif destination latitude/longitude) ///Processing 'hacked' pitch and roll (made of Exif destination latitude/longitude)
///Compass Roll ///Compass Roll
if (exif_dir[Exif_GPSInfo_CompassRoll_Index].ltag == Exif_GPSInfo_CompassRoll) { // Exif_GPSInfo_CompassRoll is present in template if (exif_dir[Exif_GPSInfo_CompassRoll_Index].ltag == Exif_GPSInfo_CompassRoll) { // Exif_GPSInfo_CompassRoll is present in template
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_CompassRoll_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_CompassRoll_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, rational3, 8); read(fd_exif, rational3, 8);
roll = (1.0 * __cpu_to_be32( rational3[0])) / __cpu_to_be32( rational3[1]); roll = (1.0 * __cpu_to_be32( rational3[0])) / __cpu_to_be32( rational3[1]);
if (exif_dir[Exif_GPSInfo_CompassRollRef_Index].ltag == Exif_GPSInfo_CompassRollRef) { if (exif_dir[Exif_GPSInfo_CompassRollRef_Index].ltag == Exif_GPSInfo_CompassRollRef) {
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_CompassRollRef_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_CompassRollRef_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, val, 1); read(fd_exif, val, 1);
if (val[0] != EXIF_COMPASS_ROLL_ASCII[0]) roll = -roll; if (val[0] != EXIF_COMPASS_ROLL_ASCII[0]) roll = -roll;
} }
...@@ -543,18 +550,18 @@ int printExifXML(int exif_page) ...@@ -543,18 +550,18 @@ int printExifXML(int exif_page)
printf("<CompassRoll>\"%s\"</CompassRoll>\n", val); printf("<CompassRoll>\"%s\"</CompassRoll>\n", val);
} }
///Compass Pitch ///Compass Pitch
if (exif_dir[Exif_GPSInfo_CompassPitch_Index].ltag == Exif_GPSInfo_CompassPitch) { // Exif_GPSInfo_CompassPitch is present in template if (exif_dir[Exif_GPSInfo_CompassPitch_Index].ltag == Exif_GPSInfo_CompassPitch) { // Exif_GPSInfo_CompassPitch is present in template
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_CompassPitch_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_CompassPitch_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, rational3, 8); read(fd_exif, rational3, 8);
pitch = (1.0 * __cpu_to_be32( rational3[0])) / __cpu_to_be32( rational3[1]); pitch = (1.0 * __cpu_to_be32( rational3[0])) / __cpu_to_be32( rational3[1]);
if (exif_dir[Exif_GPSInfo_CompassPitchRef_Index].ltag == Exif_GPSInfo_CompassPitchRef) { if (exif_dir[Exif_GPSInfo_CompassPitchRef_Index].ltag == Exif_GPSInfo_CompassPitchRef) {
lseek(fd_exif, lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_CompassPitchRef_Index].dst, exif_page_start + exif_dir[Exif_GPSInfo_CompassPitchRef_Index].dst,
SEEK_SET); SEEK_SET);
read(fd_exif, val, 1); read(fd_exif, val, 1);
if (val[0] != EXIF_COMPASS_PITCH_ASCII[0]) pitch = -pitch; if (val[0] != EXIF_COMPASS_PITCH_ASCII[0]) pitch = -pitch;
} }
...@@ -565,13 +572,12 @@ int printExifXML(int exif_page) ...@@ -565,13 +572,12 @@ int printExifXML(int exif_page)
return 0; return 0;
} }
int metaXML(struct file_set *fset, int mode) /// mode: 0 - new (send headers), 1 - continue, 2 - finish
int metaXML(int fd_circ, int mode) /// mode: 0 - new (send headers), 1 - continue, 2 - finish
{ {
int frameParamPointer = 0; int frameParamPointer = 0;
struct interframe_params_t frame_params; struct interframe_params_t frame_params;
int jpeg_len, jpeg_start, buff_size, timestamp_start; int jpeg_len, jpeg_start, buff_size, timestamp_start;
int fd_circ = fset->circbuf_fd;
if (mode == 2) { /// just close the xml file if (mode == 2) { /// just close the xml file
printf("</meta>\n"); printf("</meta>\n");
...@@ -583,7 +589,7 @@ int metaXML(int fd_circ, int mode) /// mode: 0 - new (send headers), 1 - con ...@@ -583,7 +589,7 @@ int metaXML(int fd_circ, int mode) /// mode: 0 - new (send headers), 1 - con
printf("Pragma: no-cache\r\n"); printf("Pragma: no-cache\r\n");
printf("\r\n"); printf("\r\n");
printf("<?xml version=\"1.0\"?>\n" \ printf("<?xml version=\"1.0\"?>\n" \
"<meta>\n"); "<meta>\n");
} }
jpeg_start = lseek(fd_circ, 0, SEEK_CUR); //get the current read pointer jpeg_start = lseek(fd_circ, 0, SEEK_CUR); //get the current read pointer
...@@ -593,61 +599,61 @@ int metaXML(int fd_circ, int mode) /// mode: 0 - new (send headers), 1 - con ...@@ -593,61 +599,61 @@ int metaXML(int fd_circ, int mode) /// mode: 0 - new (send headers), 1 - con
return -1; return -1;
} }
buff_size = lseek(fd_circ, 0, SEEK_END); buff_size = lseek(fd_circ, 0, SEEK_END);
/// restore file poinetr after lseek-ing the end /// restore file poinetr after lseek-ing the end
lseek(fd_circ, jpeg_start, SEEK_SET); lseek(fd_circ, jpeg_start, SEEK_SET);
frameParamPointer = jpeg_start - 32; frameParamPointer = jpeg_start - 32;
if (frameParamPointer < 0) frameParamPointer += buff_size; if (frameParamPointer < 0) frameParamPointer += buff_size;
memcpy(&frame_params, (unsigned long* )&ccam_dma_buf[frameParamPointer >> 2], 32); /// ccam_dma_buf - global memcpy(&frame_params, (unsigned long* )&ccam_dma_buf[frameParamPointer >> 2], 32); /// ccam_dma_buf - global
jpeg_len=frame_params.frame_length; jpeg_len=frame_params.frame_length;
/// Copy timestamp (goes after the image data) /// Copy timestamp (goes after the image data)
timestamp_start=jpeg_start+((jpeg_len+CCAM_MMAP_META+3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC; //! magic shift - should index first byte of the time stamp timestamp_start=jpeg_start+((jpeg_len+CCAM_MMAP_META+3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC; //! magic shift - should index first byte of the time stamp
if (timestamp_start >= buff_size) timestamp_start-=buff_size; if (timestamp_start >= buff_size) timestamp_start-=buff_size;
memcpy (&(frame_params.timestamp_sec), (unsigned long * ) &ccam_dma_buf[timestamp_start>>2],8); memcpy (&(frame_params.timestamp_sec), (unsigned long * ) &ccam_dma_buf[timestamp_start>>2],8);
///TODO: Parse Exif data if available and add here ///TODO: Parse Exif data if available and add here
printf ("<frame>\n" \ printf ("<frame>\n" \
"<start> 0x%x </start>\n" \ "<start> 0x%x </start>\n" \
"<hash32_r> 0x%x </hash32_r>\n" \ "<hash32_r> 0x%x </hash32_r>\n" \
"<hash32_g> 0x%x </hash32_g>\n" \ "<hash32_g> 0x%x </hash32_g>\n" \
"<hash32_gb>0x%x </hash32_gb>\n" \ "<hash32_gb>0x%x </hash32_gb>\n" \
"<hash32_b> 0x%x </hash32_b>\n" \ "<hash32_b> 0x%x </hash32_b>\n" \
"<quality2> 0x%x </quality2>\n" \ "<quality2> 0x%x </quality2>\n" \
"<color> 0x%x </color>\n" \ "<color> 0x%x </color>\n" \
"<byrshift> 0x%x </byrshift>\n" \ "<byrshift> 0x%x </byrshift>\n" \
"<width> 0x%x </width>\n" \ "<width> 0x%x </width>\n" \
"<height> 0x%x </height>\n" \ "<height> 0x%x </height>\n" \
"<meta_index> 0x%x </meta_index>\n" \ "<meta_index> 0x%x </meta_index>\n" \
"<timestamp> %ld.%06ld</timestamp>\n" \ "<timestamp> %ld.%06ld</timestamp>\n" \
"<signffff> 0x%x </signffff>\n" "<signffff> 0x%x </signffff>\n"
, (int) jpeg_start , (int) jpeg_start
, (int) frame_params.hash32_r , (int) frame_params.hash32_r
, (int) frame_params.hash32_g , (int) frame_params.hash32_g
, (int) frame_params.hash32_gb , (int) frame_params.hash32_gb
, (int) frame_params.hash32_b , (int) frame_params.hash32_b
, (int) frame_params.quality2 , (int) frame_params.quality2
, (int) frame_params.color /// color mode //18 , (int) frame_params.color /// color mode //18
, (int) frame_params.byrshift /// bayer shift in compressor //19 , (int) frame_params.byrshift /// bayer shift in compressor //19
, (int) frame_params.width /// frame width, pixels 20-21 - NOTE: should be 20-21 , (int) frame_params.width /// frame width, pixels 20-21 - NOTE: should be 20-21
, (int) frame_params.height /// frame height, pixels 22-23 , (int) frame_params.height /// frame height, pixels 22-23
, (int) frame_params.meta_index //! index of the linked meta page , (int) frame_params.meta_index //! index of the linked meta page
, frame_params.timestamp_sec , frame_params.timestamp_sec
, frame_params.timestamp_usec , frame_params.timestamp_usec
, (int) frame_params.signffff , (int) frame_params.signffff
); );
///28-31 unsigned long timestamp_sec ; //! number of seconds since 1970 till the start of the frame exposure ///28-31 unsigned long timestamp_sec ; //! number of seconds since 1970 till the start of the frame exposure
///28-31 unsigned long frame_length ; //! JPEG frame length in circular buffer, bytes ///28-31 unsigned long frame_length ; //! JPEG frame length in circular buffer, bytes
/// }; /// };
///32-35 unsigned long timestamp_usec; //! number of microseconds to add ///32-35 unsigned long timestamp_usec; //! number of microseconds to add
if (frame_params.signffff !=0xffff) { if (frame_params.signffff !=0xffff) {
printf("<error>\"wrong signature (should be 0xffff)\"</error>\n"); printf("<error>\"wrong signature (should be 0xffff)\"</error>\n");
} else { } else {
///Put Exif data here ///Put Exif data here
printf ("<Exif>\n"); printf ("<Exif>\n");
printExifXML(frame_params.meta_index); printExifXML(frame_params.meta_index, fset);
printf ("</Exif>\n"); printf ("</Exif>\n");
} }
printf ("</frame>\n"); printf ("</frame>\n");
return 0; return 0;
} }
...@@ -670,7 +676,7 @@ void waitFrameSync() ...@@ -670,7 +676,7 @@ void waitFrameSync()
close(fd_fparmsall); close(fd_fparmsall);
} }
int framePointersXML(int fd_circ) int framePointersXML(struct file_set *fset)
{ {
const char ctlFileName[] = "/dev/frameparsall"; const char ctlFileName[] = "/dev/frameparsall";
int fd_fparmsall; int fd_fparmsall;
...@@ -683,10 +689,10 @@ int framePointersXML(int fd_circ) ...@@ -683,10 +689,10 @@ int framePointersXML(int fd_circ)
int frame8, frame_number, sensor_state, compressor_state; int frame8, frame_number, sensor_state, compressor_state;
char *cp_sensor_state, *cp_compressor_state; char *cp_sensor_state, *cp_compressor_state;
struct framepars_all_t *frameParsAll; struct framepars_all_t **frameParsAll;
struct framepars_t *framePars; struct framepars_t *aframePars[SENSOR_PORTS];
unsigned long *globalPars; unsigned long *aglobalPars[SENSOR_PORTS];
int fd_circ = fset->circbuf_fd;
fd_fparmsall = open(ctlFileName, O_RDWR); fd_fparmsall = open(ctlFileName, O_RDWR);
if (fd_fparmsall < 0) { // check control OK if (fd_fparmsall < 0) { // check control OK
...@@ -695,8 +701,8 @@ int framePointersXML(int fd_circ) ...@@ -695,8 +701,8 @@ int framePointersXML(int fd_circ)
return -1; return -1;
} }
//! now try to mmap //! now try to mmap
frameParsAll = (struct framepars_all_t*)mmap(0, sizeof(struct framepars_all_t), PROT_READ, MAP_SHARED, fd_fparmsall, 0); frameParsAll = (struct framepars_all_t**)mmap(0, sizeof(struct framepars_all_t), PROT_READ, MAP_SHARED, fd_fparmsall, 0);
if ((int)frameParsAll == -1) { if ((int)frameParsAll == -1) {
frameParsAll = NULL; frameParsAll = NULL;
printf("Error in mmap /dev/frameparsall"); printf("Error in mmap /dev/frameparsall");
...@@ -705,25 +711,26 @@ int framePointersXML(int fd_circ) ...@@ -705,25 +711,26 @@ int framePointersXML(int fd_circ)
fd_fparmsall = -1; fd_fparmsall = -1;
return -1; return -1;
} }
framePars = frameParsAll->framePars; for (int j = 0; j < SENSOR_PORTS; j++) {
globalPars = frameParsAll->globalPars; aframePars[j] = frameParsAll[j]->framePars;
aglobalPars[j] = frameParsAll[j]->globalPars;
}
// Read current sensor state - defined in c313a.h // Read current sensor state - defined in c313a.h
frame_number = lseek(fd_fparmsall, 0, SEEK_CUR ); frame_number = lseek(fd_fparmsall, 0, SEEK_CUR );
frame8 = frame_number & PARS_FRAMES_MASK; frame8 = frame_number & PARS_FRAMES_MASK;
// printf ("Current frame number is %d\n",frame_number); sensor_state = aframePars[fset->port_num][frame8].pars[P_SENSOR_RUN];
sensor_state = framePars[frame8].pars[P_SENSOR_RUN]; compressor_state = aframePars[fset->port_num][frame8].pars[P_COMPRESSOR_RUN];
compressor_state = framePars[frame8].pars[P_COMPRESSOR_RUN];
cp_sensor_state = (sensor_state == 0) ? cp_sensor_state = (sensor_state == 0) ?
"SENSOR_RUN_STOP" : "SENSOR_RUN_STOP" :
((sensor_state == 1) ? ((sensor_state == 1) ?
"SENSOR_RUN_SINGLE" : "SENSOR_RUN_SINGLE" :
((sensor_state == 2) ? "SENSOR_RUN_CONT" : "UNKNOWN")); ((sensor_state == 2) ? "SENSOR_RUN_CONT" : "UNKNOWN"));
cp_compressor_state = (compressor_state == 0) ? cp_compressor_state = (compressor_state == 0) ?
"COMPRESSOR_RUN_STOP" : "COMPRESSOR_RUN_STOP" :
((compressor_state == 1) ? ((compressor_state == 1) ?
"COMPRESSOR_RUN_SINGLE" : "COMPRESSOR_RUN_SINGLE" :
((compressor_state == 2) ? "COMPRESSOR_RUN_CONT" : "UNKNOWN")); ((compressor_state == 2) ? "COMPRESSOR_RUN_CONT" : "UNKNOWN"));
save_p = lseek(fd_circ, 0, SEEK_CUR); //!save current file pointer before temporarily moving it save_p = lseek(fd_circ, 0, SEEK_CUR); //!save current file pointer before temporarily moving it
rp = lseek(fd_circ, LSEEK_CIRC_TORP, SEEK_END); //! set current rp global rp (may be invalid <0) rp = lseek(fd_circ, LSEEK_CIRC_TORP, SEEK_END); //! set current rp global rp (may be invalid <0)
...@@ -734,8 +741,8 @@ int framePointersXML(int fd_circ) ...@@ -734,8 +741,8 @@ int framePointersXML(int fd_circ)
p = lseek(fd_circ, LSEEK_CIRC_PREV, SEEK_END); p = lseek(fd_circ, LSEEK_CIRC_PREV, SEEK_END);
nf++; nf++;
} }
buf_free = GLOBALPARS(G_FREECIRCBUF); buf_free = GLOBALPARS(fset->port_num, G_FREECIRCBUF);
frame_size = GLOBALPARS(G_FRAME_SIZE); frame_size = GLOBALPARS(fset->port_num, G_FRAME_SIZE);
lseek(fd_circ, save_p, SEEK_SET); //! restore file pointer after temporarily moving it lseek(fd_circ, save_p, SEEK_SET); //! restore file pointer after temporarily moving it
buf_free = lseek(fd_circ, LSEEK_CIRC_FREE, SEEK_END); //! will change file pointer buf_free = lseek(fd_circ, LSEEK_CIRC_FREE, SEEK_END); //! will change file pointer
...@@ -744,30 +751,30 @@ int framePointersXML(int fd_circ) ...@@ -744,30 +751,30 @@ int framePointersXML(int fd_circ)
lseek(fd_circ, save_p, SEEK_SET); //! restore file pointer after temporarily moving it lseek(fd_circ, save_p, SEEK_SET); //! restore file pointer after temporarily moving it
sprintf(s, "<?xml version=\"1.0\"?>\n" \ sprintf(s, "<?xml version=\"1.0\"?>\n" \
"<frame_pointers>\n" \ "<frame_pointers>\n" \
" <this>%d</this>\n" \ " <this>%d</this>\n" \
" <write>%d</write>\n" \ " <write>%d</write>\n" \
" <read>%d</read>\n" \ " <read>%d</read>\n" \
" <frames>%d</frames>\n" \ " <frames>%d</frames>\n" \
" <left>%d</left>\n" \ " <left>%d</left>\n" \
" <free>%d</free>\n" \ " <free>%d</free>\n" \
" <used>%d</used>\n" \ " <used>%d</used>\n" \
" <frame>%d</frame>\n" \ " <frame>%d</frame>\n" \
" <frame_size>%d</frame_size>\n" \ " <frame_size>%d</frame_size>\n" \
" <sensor_state>\"%s\"</sensor_state>\n" \ " <sensor_state>\"%s\"</sensor_state>\n" \
" <compressor_state>\"%s\"</compressor_state>\n" \ " <compressor_state>\"%s\"</compressor_state>\n" \
"</frame_pointers>\n", "</frame_pointers>\n",
save_p, save_p,
wp, wp,
rp, rp,
nf - 1, nf - 1,
nfl, nfl,
buf_free, buf_free,
buf_used, buf_used,
frame_number, frame_number,
frame_size, frame_size,
cp_sensor_state, cp_sensor_state,
cp_compressor_state); cp_compressor_state);
printf("HTTP/1.0 200 OK\r\n"); printf("HTTP/1.0 200 OK\r\n");
printf("Server: Elphel Imgsrv\r\n"); printf("Server: Elphel Imgsrv\r\n");
printf("Content-Length: %d\r\n", strlen(s)); printf("Content-Length: %d\r\n", strlen(s));
...@@ -775,22 +782,23 @@ int framePointersXML(int fd_circ) ...@@ -775,22 +782,23 @@ int framePointersXML(int fd_circ)
printf("Pragma: no-cache\r\n"); printf("Pragma: no-cache\r\n");
printf("\r\n"); printf("\r\n");
printf(s); printf(s);
//! No need to unmap?
munmap(frameParsAll, sizeof(struct framepars_all_t));
close(fd_fparmsall); close(fd_fparmsall);
D(fprintf(stderr, ">%s< [%d bytes]\n", s, strlen(s))); D(fprintf(stderr, ">%s< [%d bytes]\n", s, strlen(s)));
return 0; return 0;
} }
//fwrite (&cbuffer[offset],1,bytesLeft,stdout);
int out1x1gif(void) int out1x1gif(void)
{ {
char s[] = "HTTP/1.0 200 OK\r\n" \ char s[] = "HTTP/1.0 200 OK\r\n" \
"Server: Elphel Imgsrv\r\n" \ "Server: Elphel Imgsrv\r\n" \
"Content-Length: 35\r\n" \ "Content-Length: 35\r\n" \
"Content-Type: image/gif\r\n" \ "Content-Type: image/gif\r\n" \
"\r\n" \ "\r\n" \
"GIF87a\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00" \ "GIF87a\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00" \
"\xff\xff\xff\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x4c" \ "\xff\xff\xff\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x4c" \
"\x01\x00\x3b"; "\x01\x00\x3b";
fwrite(s, 1, sizeof(s), stdout); //! we have zeros in the string fwrite(s, 1, sizeof(s), stdout); //! we have zeros in the string
return 0; //! always good return 0; //! always good
...@@ -798,12 +806,12 @@ int out1x1gif(void) ...@@ -798,12 +806,12 @@ int out1x1gif(void)
void errorMsgXML(char * msg) void errorMsgXML(char * msg)
{ {
char s[1024]; // was 701 acrtually char s[1024];
sprintf(s, "<?xml version=\"1.0\"?>\n" \ sprintf(s, "<?xml version=\"1.0\"?>\n" \
"<frame_params>\n" \ "<frame_params>\n" \
"<error>%s</error>\n" \ "<error>%s</error>\n" \
"</frame_params>\n", msg); "</frame_params>\n", msg);
D(fprintf(stderr, ">%s< [%d bytes]", s, strlen(s))); D(fprintf(stderr, ">%s< [%d bytes]", s, strlen(s)));
printf("HTTP/1.0 200 OK\r\n"); printf("HTTP/1.0 200 OK\r\n");
printf("Server: Elphel Imgsrv\r\n"); printf("Server: Elphel Imgsrv\r\n");
...@@ -821,15 +829,11 @@ void errorMsgXML(char * msg) ...@@ -821,15 +829,11 @@ void errorMsgXML(char * msg)
int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int saveImage) int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int saveImage)
{ {
//const char HeadFileName[] = "/dev/jpeghead0";
const char ExifFileName[] = "/dev/exif_exif";
int exifDataSize = 0; int exifDataSize = 0;
/// int exifIndexPointer=0;
int frameParamPointer = 0; int frameParamPointer = 0;
struct interframe_params_t frame_params; struct interframe_params_t frame_params;
/// struct frame_exif_t frame_exif; //just 8 bytes
int buff_size; int buff_size;
int jpeg_len; //bytes int jpeg_len; // bytes
int jpeg_start; // bytes int jpeg_start; // bytes
int fd_head; int fd_head;
int fd_exif; int fd_exif;
...@@ -841,8 +845,7 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -841,8 +845,7 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
char * mime_type; char * mime_type;
char * extension; char * extension;
/// int metadata_start; //metadata pointer (in bytes, from the start of the ccam_dma_buf) jpeg_start = lseek(fset->circbuf_fd, 0, SEEK_CUR); //get the current read pointer
jpeg_start = lseek(fset->circbuf_fd, 0, SEEK_CUR); //get the current read pointer
D(fprintf(stderr, "jpeg_start (long) = 0x%x\n", jpeg_start)); D(fprintf(stderr, "jpeg_start (long) = 0x%x\n", jpeg_start));
fd_head = open(fset->jphead_fn, O_RDWR); fd_head = open(fset->jphead_fn, O_RDWR);
if (fd_head < 0) { // check control OK if (fd_head < 0) { // check control OK
...@@ -850,68 +853,70 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -850,68 +853,70 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
return -1; return -1;
} }
fset->jphead_fd = fd_head; fset->jphead_fd = fd_head;
lseek(fd_head, jpeg_start + 1, SEEK_END); /// create JPEG header, find out it's size TODO: lseek(fd_head, jpeg_start + 1, SEEK_END); // create JPEG header, find out it's size
head_size = lseek(fd_head, 0, SEEK_END); head_size = lseek(fd_head, 0, SEEK_END);
if (head_size > JPEG_HEADER_MAXSIZE) { if (head_size > JPEG_HEADER_MAXSIZE) {
fprintf(stderr, "%s:%d: Too big JPEG header (%d > %d)", __FILE__, __LINE__, head_size, JPEG_HEADER_MAXSIZE ); fprintf(stderr, "%s:%d: Too big JPEG header (%d > %d)", __FILE__, __LINE__, head_size, JPEG_HEADER_MAXSIZE );
close(fd_head); close(fd_head);
return -2; return -2;
} }
/*! find total buffer length (it is in defines, actually in c313a.h */ /*! find total buffer length (it is in defines, actually in c313a.h */
buff_size = lseek(fset->circbuf_fd, 0, SEEK_END); buff_size = lseek(fset->circbuf_fd, 0, SEEK_END);
/*! restore file poinetr after lseek-ing the end */ /*! restore file poinetr after lseek-ing the end */
lseek(fset->circbuf_fd, jpeg_start, SEEK_SET); lseek(fset->circbuf_fd, jpeg_start, SEEK_SET);
D(fprintf(stderr, "position (longs) = 0x%x\n", (int)lseek(fset->circbuf_fd, 0, SEEK_CUR))); D(fprintf(stderr, "position (longs) = 0x%x\n", (int)lseek(fset->circbuf_fd, 0, SEEK_CUR)));
/*! now let's try mmap itself */ /*! now let's try mmap itself */
/// exifIndexPointer=jpeg_start-8;
frameParamPointer = jpeg_start - sizeof(struct interframe_params_t) + 4; frameParamPointer = jpeg_start - sizeof(struct interframe_params_t) + 4;
if (frameParamPointer < 0) if (frameParamPointer < 0)
frameParamPointer += buff_size; frameParamPointer += buff_size;
fprintf(stderr, "frameParamPointer = 0x%x, jpeg_start = 0x%x, buff_size = 0x%x\n", fprintf(stderr, "frameParamPointer = 0x%x, jpeg_start = 0x%x, buff_size = 0x%x\n",
frameParamPointer, jpeg_start, buff_size); frameParamPointer, jpeg_start, buff_size);
memcpy(&frame_params, (unsigned long*)&ccam_dma_buf[frameParamPointer >> 2], sizeof(struct interframe_params_t) - 4); memcpy(&frame_params, (unsigned long*)&ccam_dma_buf[frameParamPointer >> 2], sizeof(struct interframe_params_t) - 4);
jpeg_len = frame_params.frame_length; jpeg_len = frame_params.frame_length;
color_mode = frame_params.color; color_mode = frame_params.color;
if (frame_params.signffff != 0xffff) { if (frame_params.signffff != 0xffff) {
fprintf(stderr, "wrong signature signff = 0x%x \n", (int)frame_params.signffff); fprintf(stderr, "wrong signature signff = 0x%x \n", (int)frame_params.signffff);
#ifdef ELPHEL_DEBUG_THIS
lseek(fset->circbuf_fd, LSEEK_CIRC_STOP_COMPRESSOR, SEEK_END);
#endif
close(fd_head); close(fd_head);
return -4; return -4;
} }
if (use_Exif) { if (use_Exif) {
//D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index)); D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
/// read Exif to buffer: /// read Exif to buffer:
fd_exif = open(ExifFileName, O_RDONLY); fd_exif = open(fset->exif_dev_name, O_RDONLY);
if (fd_exif < 0) { // check control OK if (fd_exif < 0) { // check control OK
fprintf(stderr, "Error opening %s\n", ExifFileName); fprintf(stderr, "Error opening %s\n", fset->exif_dev_name);
close(fd_head); close(fd_head);
return -5; return -5;
} }
exifDataSize = lseek(fd_exif, 1, SEEK_END); // at the beginning of page 1 - position == page length exifDataSize = lseek(fd_exif, 1, SEEK_END); // at the beginning of page 1 - position == page length
if (exifDataSize < 0) exifDataSize = 0; // error from lseek; if (exifDataSize < 0) exifDataSize = 0; // error from lseek;
if (!exifDataSize) close(fd_exif); if (!exifDataSize) close(fd_exif);
} else { } else {
//frame_params.meta_index=0; frame_params.meta_index=0;
fd_exif = -1; fd_exif = -1;
} }
///Maybe make buffer that will fit both Exif and JPEG? ///Maybe make buffer that will fit both Exif and JPEG?
//!Get metadata, update Exif and JFIF headers if ep and ed poinetrs are non-zero (NULL will generate files with JFIF-only headers) //!Get metadata, update Exif and JFIF headers if ep and ed poinetrs are non-zero (NULL will generate files with JFIF-only headers)
/// Now we always malloc buffer, before - only for bimg, using fixed-size header buffer - was it faster? /// Now we always malloc buffer, before - only for bimg, using fixed-size header buffer - was it faster?
jpeg_full_size = jpeg_len + head_size + 2 + exifDataSize; jpeg_full_size = jpeg_len + head_size + 2 + exifDataSize;
fprintf(stderr, "jpeg_len = 0x%x, head_size = 0x%x, exifDataSize = 0x%x, jpeg_full_size = 0x%x\n", fprintf(stderr, "jpeg_len = 0x%x, head_size = 0x%x, exifDataSize = 0x%x, jpeg_full_size = 0x%x\n",
jpeg_len, head_size, exifDataSize, jpeg_full_size); jpeg_len, head_size, exifDataSize, jpeg_full_size);
if (bufferImageData) jpeg_this_size = jpeg_full_size; /// header+frame if (bufferImageData) jpeg_this_size = jpeg_full_size; // header+frame
else jpeg_this_size = head_size + exifDataSize; /// only header else jpeg_this_size = head_size + exifDataSize; // only header
jpeg_copy = malloc(jpeg_this_size); jpeg_copy = malloc(jpeg_this_size);
if (!jpeg_copy) { if (!jpeg_copy) {
syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__, __LINE__, jpeg_this_size); syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__, __LINE__, jpeg_this_size);
/// If we really want it, but don't get it - let's try more /// If we really want it, but don't get it - let's try more
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
usleep(((jpeg_this_size & 0x3ff) + 5) * 100); // up to 0.1 sec usleep(((jpeg_this_size & 0x3ff) + 5) * 100); // up to 0.1 sec
jpeg_copy = malloc(jpeg_this_size); jpeg_copy = malloc(jpeg_this_size);
if (jpeg_copy) break; if (jpeg_copy) break;
syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__, __LINE__, jpeg_this_size); syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__, __LINE__, jpeg_this_size);
...@@ -925,21 +930,21 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -925,21 +930,21 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
lseek(fd_head, 0, 0); lseek(fd_head, 0, 0);
read(fd_head, &jpeg_copy[exifDataSize], head_size); read(fd_head, &jpeg_copy[exifDataSize], head_size);
close(fd_head); close(fd_head);
if (exifDataSize > 0) { //! insert Exif if (exifDataSize > 0) { // insert Exif
memcpy(jpeg_copy, &jpeg_copy[exifDataSize], 2); //! copy first 2 bytes of the JFIF header before Exif memcpy(jpeg_copy, &jpeg_copy[exifDataSize], 2); // copy first 2 bytes of the JFIF header before Exif
//lseek(fd_exif,frame_params.meta_index,SEEK_END); //! select meta page to use (matching frame) lseek(fd_exif,frame_params.meta_index,SEEK_END); // select meta page to use (matching frame)
read(fd_exif, &jpeg_copy[2], exifDataSize); //! Insert Exif itself read(fd_exif, &jpeg_copy[2], exifDataSize); // Insert Exif itself
close(fd_exif); close(fd_exif);
} }
switch (color_mode) { switch (color_mode) {
// case COLORMODE_MONO6: //! monochrome, (4:2:0), // case COLORMODE_MONO6: //! monochrome, (4:2:0),
// case COLORMODE_COLOR: //! color, 4:2:0, 18x18(old) // case COLORMODE_COLOR: //! color, 4:2:0, 18x18(old)
case COLORMODE_JP46: //! jp4, original (4:2:0) case COLORMODE_JP46: //! jp4, original (4:2:0)
case COLORMODE_JP46DC: //! jp4, dc -improved (4:2:0) case COLORMODE_JP46DC: //! jp4, dc -improved (4:2:0)
mime_type = "jp46"; mime_type = "jp46";
extension = "jp46"; extension = "jp46";
break; break;
// case COLORMODE_COLOR20: //! color, 4:2:0, 20x20, middle of the tile (not yet implemented) // case COLORMODE_COLOR20: //! color, 4:2:0, 20x20, middle of the tile (not yet implemented)
case COLORMODE_JP4: //! jp4, 4 blocks, (legacy) case COLORMODE_JP4: //! jp4, 4 blocks, (legacy)
case COLORMODE_JP4DC: //! jp4, 4 blocks, dc -improved case COLORMODE_JP4DC: //! jp4, 4 blocks, dc -improved
case COLORMODE_JP4DIFF: //! jp4, 4 blocks, differential red := (R-G1), blue:=(B-G1), green=G1, green2 (G2-G1). G1 is defined by Bayer shift, any pixel can be used case COLORMODE_JP4DIFF: //! jp4, 4 blocks, differential red := (R-G1), blue:=(B-G1), green=G1, green2 (G2-G1). G1 is defined by Bayer shift, any pixel can be used
...@@ -949,15 +954,15 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -949,15 +954,15 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
mime_type = "jp4"; mime_type = "jp4";
extension = "jp4"; extension = "jp4";
break; break;
// case COLORMODE_MONO4: //! monochrome, 4 blocks (but still with 2x2 macroblocks) // case COLORMODE_MONO4: //! monochrome, 4 blocks (but still with 2x2 macroblocks)
default: default:
mime_type = "jpeg"; mime_type = "jpeg";
extension = "jpeg"; extension = "jpeg";
} }
// char * mime_type; // char * mime_type;
// char * extension; // char * extension;
/* /*
#define COLORMODE_MONO6 0 // monochrome, (4:2:0), #define COLORMODE_MONO6 0 // monochrome, (4:2:0),
#define COLORMODE_COLOR 1 // color, 4:2:0, 18x18(old) #define COLORMODE_COLOR 1 // color, 4:2:0, 18x18(old)
#define COLORMODE_JP46 2 // jp4, original (4:2:0) #define COLORMODE_JP46 2 // jp4, original (4:2:0)
...@@ -971,14 +976,18 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -971,14 +976,18 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
#define COLORMODE_JP4HDR2 10 // jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2), #define COLORMODE_JP4HDR2 10 // jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2),
#define COLORMODE_MONO4 14 // monochrome, 4 blocks (but still with 2x2 macroblocks) #define COLORMODE_MONO4 14 // monochrome, 4 blocks (but still with 2x2 macroblocks)
*/ */
printf("Content-Type: image/%s\r\n", mime_type); printf("Content-Type: image/%s\r\n", mime_type);
if (saveImage) printf("Content-Disposition: attachment; filename=\"elphelimg_%ld.%s\"\r\n", frame_params.timestamp_sec, extension); /// does not open, asks for filename to save if (saveImage) printf("Content-Disposition: attachment; filename=\"elphelimg_%ld.%s\"\r\n", frame_params.timestamp_sec, extension); /// does not open, asks for filename to save
else printf("Content-Disposition: inline; filename=\"elphelimg_%ld.%s\"\r\n", frame_params.timestamp_sec, extension); /// opens in browser, asks to save on right-click else printf("Content-Disposition: inline; filename=\"elphelimg_%ld.%s\"\r\n", frame_params.timestamp_sec, extension); /// opens in browser, asks to save on right-click
if (bufferImageData) { /*! Buffer the whole file before sending over the network to make sure it will not be corrupted if the circular buffer will be overrun) */ if (bufferImageData) { /*! Buffer the whole file before sending over the network to make sure it will not be corrupted if the circular buffer will be overrun) */
#ifdef ELPHEL_DEBUG_THIS
unsigned long start_time, end_time;
start_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END);
#endif
l = head_size + exifDataSize; l = head_size + exifDataSize;
/*! JPEG image data may be split in two segments (rolled over buffer end) - process both variants */ /*! JPEG image data may be split in two segments (rolled over buffer end) - process both variants */
if ((jpeg_start + jpeg_len) > buff_size) { // two segments if ((jpeg_start + jpeg_len) > buff_size) { // two segments
memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], buff_size - jpeg_start); memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], buff_size - jpeg_start);
l += buff_size - jpeg_start; l += buff_size - jpeg_start;
...@@ -986,6 +995,10 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -986,6 +995,10 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
} else { /*! single segment */ } else { /*! single segment */
memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], jpeg_len); memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], jpeg_len);
} }
#ifdef ELPHEL_DEBUG_THIS
end_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END);
D(fprintf(stderr, "memcpy time = %lu\n", end_time - start_time));
#endif
memcpy(&jpeg_copy[jpeg_len + head_size + exifDataSize], trailer, 2); memcpy(&jpeg_copy[jpeg_len + head_size + exifDataSize], trailer, 2);
printf("Content-Length: %d\r\n", jpeg_full_size); printf("Content-Length: %d\r\n", jpeg_full_size);
printf("\r\n"); printf("\r\n");
...@@ -994,24 +1007,22 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -994,24 +1007,22 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
printf("Content-Length: %d\r\n", jpeg_full_size); printf("Content-Length: %d\r\n", jpeg_full_size);
printf("\r\n"); printf("\r\n");
sendBuffer(jpeg_copy, head_size + exifDataSize); //JPEG+Exif sendBuffer(jpeg_copy, head_size + exifDataSize); //JPEG+Exif
/*! JPEG image data may be split in two segments (rolled over buffer end) - process both variants */ /*! JPEG image data may be split in two segments (rolled over buffer end) - process both variants */
if ((jpeg_start + jpeg_len) > buff_size) { // two segments if ((jpeg_start + jpeg_len) > buff_size) { // two segments
/*! copy from the beginning of the frame to the end of the buffer */ /*! copy from the beginning of the frame to the end of the buffer */
sendBuffer((void*)&ccam_dma_buf[jpeg_start >> 2], buff_size - jpeg_start); sendBuffer((void*)&ccam_dma_buf[jpeg_start >> 2], buff_size - jpeg_start);
/*! copy from the beginning of the buffer to the end of the frame */ /*! copy from the beginning of the buffer to the end of the frame */
sendBuffer((void*)&ccam_dma_buf[0], jpeg_len - (buff_size - jpeg_start)); sendBuffer((void*)&ccam_dma_buf[0], jpeg_len - (buff_size - jpeg_start));
} else { // single segment } else { // single segment
/*! copy from the beginning of the frame to the end of the frame (no buffer rollovers) */ /*! copy from the beginning of the frame to the end of the frame (no buffer rollovers) */
sendBuffer((void*)&ccam_dma_buf[jpeg_start >> 2], jpeg_len); sendBuffer((void*)&ccam_dma_buf[jpeg_start >> 2], jpeg_len);
} }
sendBuffer(trailer, 2); sendBuffer(trailer, 2);
} }
free(jpeg_copy); free(jpeg_copy);
return 0; return 0;
} }
/*! repeat writes to stdout until all data is sent */ /*! repeat writes to stdout until all data is sent */
void sendBuffer(void * buffer, int len) void sendBuffer(void * buffer, int len)
{ {
...@@ -1030,13 +1041,9 @@ void sendBuffer(void * buffer, int len) ...@@ -1030,13 +1041,9 @@ void sendBuffer(void * buffer, int len)
} }
} }
void listener_loop(struct file_set *fset) void listener_loop(struct file_set *fset)
{ {
char errormsg[1024]; char errormsg[1024];
//const char circbufFileName[] = "/dev/circbuf0";
int fd_circ; int fd_circ;
int this_p; //! current frame pointer (bytes) int this_p; //! current frame pointer (bytes)
int rslt; int rslt;
...@@ -1066,22 +1073,22 @@ void listener_loop(struct file_set *fset) ...@@ -1066,22 +1073,22 @@ void listener_loop(struct file_set *fset)
if (fd == -1) continue; if (fd == -1) continue;
signal(SIGCHLD, SIG_IGN); // no zombies, please! signal(SIGCHLD, SIG_IGN); // no zombies, please!
/*! do we need any fork at all if we now serve images to one client at a time? */ /*! do we need any fork at all if we now serve images to one client at a time? */
if (fork() == 0) { if (fork() == 0) {
close(res); close(res);
/*! setup stdin and stdout */ /*! setup stdin and stdout */
fflush(stdout); fflush(stdout);
fflush(stderr); fflush(stderr);
dup2(fd, 0); dup2(fd, 0);
dup2(fd, 1); dup2(fd, 1);
close(fd); close(fd);
/*! We need just the first line of the GET to read parameters */ /*! We need just the first line of the GET to read parameters */
if (fgets(buf, sizeof(buf) - 1, stdin)) len = strlen(buf); if (fgets(buf, sizeof(buf) - 1, stdin)) len = strlen(buf);
cp = buf; cp = buf;
strsep(&cp, "/?"); // ignore everything before first "/" or "?" strsep(&cp, "/?"); // ignore everything before first "/" or "?"
if (cp) { if (cp) {
//! Now cp points to the first character after the first "/" or "?" in the url //! Now cp points to the first character after the first "/" or "?" in the url
//! we need to remove everything after (and including) the first space //! we need to remove everything after (and including) the first space
cp1 = strchr(cp, ' '); cp1 = strchr(cp, ' ');
if (cp1) cp1[0] = '\0'; if (cp1) cp1[0] = '\0';
} }
...@@ -1095,7 +1102,7 @@ void listener_loop(struct file_set *fset) ...@@ -1095,7 +1102,7 @@ void listener_loop(struct file_set *fset)
fflush(stdout); fflush(stdout);
_exit(0); _exit(0);
} }
/// Process 'frame' and 'wframe' commands - theys do not need circbuf /// Process 'frame' and 'wframe' commands - theys do not need circbuf
if ((strncmp(cp, "frame", 5) == 0) || (strncmp(cp, "wframe", 6) == 0)) { if ((strncmp(cp, "frame", 5) == 0) || (strncmp(cp, "wframe", 6) == 0)) {
if (strncmp(cp, "wframe", 6) == 0) waitFrameSync(); if (strncmp(cp, "wframe", 6) == 0) waitFrameSync();
printf("HTTP/1.0 200 OK\r\n"); printf("HTTP/1.0 200 OK\r\n");
...@@ -1107,7 +1114,7 @@ void listener_loop(struct file_set *fset) ...@@ -1107,7 +1114,7 @@ void listener_loop(struct file_set *fset)
fflush(stdout); fflush(stdout);
_exit(0); _exit(0);
} }
//!now process the commands one at a time, but first - open the circbuf file and setup the pointer //!now process the commands one at a time, but first - open the circbuf file and setup the pointer
fd_circ = open(fset->cirbuf_fn, O_RDWR); fd_circ = open(fset->cirbuf_fn, O_RDWR);
if (fd_circ < 0) { // check control OK if (fd_circ < 0) { // check control OK
fprintf(stderr, "Error opening %s\n", fset->cirbuf_fn); fprintf(stderr, "Error opening %s\n", fset->cirbuf_fn);
...@@ -1116,10 +1123,10 @@ void listener_loop(struct file_set *fset) ...@@ -1116,10 +1123,10 @@ void listener_loop(struct file_set *fset)
_exit(0); _exit(0);
} }
fset->circbuf_fd = fd_circ; fset->circbuf_fd = fd_circ;
/*! find total buffer length (it is in defines, actually in c313a.h */ /*! find total buffer length (it is in defines, actually in c313a.h */
buff_size = lseek(fd_circ, 0, SEEK_END); buff_size = lseek(fd_circ, 0, SEEK_END);
fprintf(stderr, "%s: read circbuf size: %d\n", __func__, buff_size); fprintf(stderr, "%s: read circbuf size: %d\n", __func__, buff_size);
/*! now let's try mmap itself */ /*! now let's try mmap itself */
ccam_dma_buf = (unsigned long*)mmap(0, buff_size, PROT_READ, MAP_SHARED, fd_circ, 0); ccam_dma_buf = (unsigned long*)mmap(0, buff_size, PROT_READ, MAP_SHARED, fd_circ, 0);
if ((int)ccam_dma_buf == -1) { if ((int)ccam_dma_buf == -1) {
fprintf(stderr, "Error in mmap\n"); fprintf(stderr, "Error in mmap\n");
...@@ -1130,11 +1137,9 @@ void listener_loop(struct file_set *fset) ...@@ -1130,11 +1137,9 @@ void listener_loop(struct file_set *fset)
} }
this_p = lseek(fd_circ, LSEEK_CIRC_LAST, SEEK_END); this_p = lseek(fd_circ, LSEEK_CIRC_LAST, SEEK_END);
D(fprintf(stderr, "%s: current frame pointer this_p (in bytes): 0x%x\n", __func__, this_p)); D(fprintf(stderr, "%s: current frame pointer this_p (in bytes): 0x%x\n", __func__, this_p));
//!continue with iterating through the commands // continue with iterating through the commands
while ((cp1 = strsep(&cp, "/?&"))) { while ((cp1 = strsep(&cp, "/?&"))) {
// printf ("1->%s", cp1); // if the first character is a digit, it is a file pointer
// fprintf (stderr, "1->%s",cp1);
//!if the first caracter is digit,it is a file pointer
if (strchr("0123456789", cp1[0])) { if (strchr("0123456789", cp1[0])) {
this_p = lseek(fd_circ, strtol(cp1, NULL, 10), SEEK_SET); this_p = lseek(fd_circ, strtol(cp1, NULL, 10), SEEK_SET);
} else if ((strcmp(cp1, "img") == 0) || (strcmp(cp1, "bimg") == 0) || (strcmp(cp1, "simg") == 0) || (strcmp(cp1, "sbimg") == 0)) { } else if ((strcmp(cp1, "img") == 0) || (strcmp(cp1, "bimg") == 0) || (strcmp(cp1, "simg") == 0) || (strcmp(cp1, "sbimg") == 0)) {
...@@ -1163,13 +1168,13 @@ void listener_loop(struct file_set *fset) ...@@ -1163,13 +1168,13 @@ void listener_loop(struct file_set *fset)
} }
fflush(stdout); //! let's not keep client waiting - anyway we've sent it all even when more commands maybe left fflush(stdout); //! let's not keep client waiting - anyway we've sent it all even when more commands maybe left
///multipart - always last // multipart - always last
} else if ((strncmp(cp1, "mimg", 4) == 0) || (strncmp(cp1, "bmimg", 5) == 0) || (strncmp(cp1, "mbimg", 5) == 0)) { } else if ((strncmp(cp1, "mimg", 4) == 0) || (strncmp(cp1, "bmimg", 5) == 0) || (strncmp(cp1, "mbimg", 5) == 0)) {
if (sent2socket > 0) break; //! image/xmldata was already sent to socket, ignore if (sent2socket > 0) break; //! image/xmldata was already sent to socket, ignore
if (lseek(fd_circ, LSEEK_CIRC_READY, SEEK_END) < 0) //! here passes OK, some not ready error is later, in sendimage (make it return different numbers) if (lseek(fd_circ, LSEEK_CIRC_READY, SEEK_END) < 0) //! here passes OK, some not ready error is later, in sendimage (make it return different numbers)
rslt = out1x1gif(); rslt = out1x1gif();
else { else {
//TODO: //TODO:
buf_images = (strncmp(cp1, "mimg", 4) == 0) ? 0 : 1; buf_images = (strncmp(cp1, "mimg", 4) == 0) ? 0 : 1;
cp2 = cp1 + (buf_images ? 5 : 4); cp2 = cp1 + (buf_images ? 5 : 4);
slow = strtol(cp2, NULL, 10); slow = strtol(cp2, NULL, 10);
...@@ -1186,25 +1191,25 @@ void listener_loop(struct file_set *fset) ...@@ -1186,25 +1191,25 @@ void listener_loop(struct file_set *fset)
rslt = sendImage(fset, buf_images, exif_enable, 0); //! verify driver that file pointer did not move rslt = sendImage(fset, buf_images, exif_enable, 0); //! verify driver that file pointer did not move
fflush(stdout); fflush(stdout);
if (rslt >= 0) for (skip = 0; skip < slow; skip++) { if (rslt >= 0) for (skip = 0; skip < slow; skip++) {
this_p = lseek(fd_circ, LSEEK_CIRC_NEXT, SEEK_END); this_p = lseek(fd_circ, LSEEK_CIRC_NEXT, SEEK_END);
/// If these "next" is not ready yet - wait, else - use latest image /// If these "next" is not ready yet - wait, else - use latest image
if ((lseek(fd_circ, LSEEK_CIRC_VALID, SEEK_END) >= 0) && //! no sense to wait if the pointer is invalid if ((lseek(fd_circ, LSEEK_CIRC_VALID, SEEK_END) >= 0) && //! no sense to wait if the pointer is invalid
(lseek(fd_circ, LSEEK_CIRC_READY, SEEK_END) < 0) && //! or the frame is already ready (lseek(fd_circ, LSEEK_CIRC_READY, SEEK_END) < 0) && //! or the frame is already ready
(lseek(fd_circ, LSEEK_CIRC_VALID, SEEK_END) >= 0)) //! test valid once again, after not ready - it might change (lseek(fd_circ, LSEEK_CIRC_VALID, SEEK_END) >= 0)) //! test valid once again, after not ready - it might change
this_p = lseek(fd_circ, LSEEK_CIRC_WAIT, SEEK_END); this_p = lseek(fd_circ, LSEEK_CIRC_WAIT, SEEK_END);
else this_p = lseek(fd_circ, LSEEK_CIRC_LAST, SEEK_END); else this_p = lseek(fd_circ, LSEEK_CIRC_LAST, SEEK_END);
} }
} }
_exit(0); _exit(0);
} }
} else if (strcmp(cp1, "pointers") == 0) { } else if (strcmp(cp1, "pointers") == 0) {
if (sent2socket > 0) break; //! image/xmldata was already sent to socket, ignore if (sent2socket > 0) break; //! image/xmldata was already sent to socket, ignore
framePointersXML(fd_circ); //! will restore file pointer after itself framePointersXML(fset); //! will restore file pointer after itself
sent2socket = 3; sent2socket = 3;
fflush(stdout); //! let's not keep client waiting - anyway we've sent it all even when more commands maybe left fflush(stdout); //! let's not keep client waiting - anyway we've sent it all even when more commands maybe left
} else if (strcmp(cp1, "meta") == 0) { } else if (strcmp(cp1, "meta") == 0) {
if ((sent2socket > 0) && (sent2socket != 2)) break; //! image/xmldata was already sent to socket, ignore if ((sent2socket > 0) && (sent2socket != 2)) break; //! image/xmldata was already sent to socket, ignore
metaXML(fd_circ, (sent2socket > 0) ? 1 : 0); /// 0 - new (send headers), 1 - continue, 2 - finish metaXML(fset, (sent2socket > 0) ? 1 : 0); /// 0 - new (send headers), 1 - continue, 2 - finish
sent2socket = 2; sent2socket = 2;
fflush(stdout); //! let's not keep client waiting - anyway we've sent it all even when more commands maybe left fflush(stdout); //! let's not keep client waiting - anyway we've sent it all even when more commands maybe left
} else if (strcmp(cp1, "noexif") == 0) { } else if (strcmp(cp1, "noexif") == 0) {
...@@ -1229,22 +1234,22 @@ void listener_loop(struct file_set *fset) ...@@ -1229,22 +1234,22 @@ void listener_loop(struct file_set *fset)
this_p = lseek(fd_circ, LSEEK_CIRC_SETP, SEEK_END); this_p = lseek(fd_circ, LSEEK_CIRC_SETP, SEEK_END);
} else if (strcmp(cp1, "wait") == 0) { } else if (strcmp(cp1, "wait") == 0) {
if ((lseek(fd_circ, LSEEK_CIRC_VALID, SEEK_END) >= 0) && //! no sense to wait if the pointer is invalid if ((lseek(fd_circ, LSEEK_CIRC_VALID, SEEK_END) >= 0) && //! no sense to wait if the pointer is invalid
(lseek(fd_circ, LSEEK_CIRC_READY, SEEK_END) < 0) && //! or the frame is already ready (lseek(fd_circ, LSEEK_CIRC_READY, SEEK_END) < 0) && //! or the frame is already ready
(lseek(fd_circ, LSEEK_CIRC_VALID, SEEK_END) >= 0)) //! test valid once again, after not ready - it might change (lseek(fd_circ, LSEEK_CIRC_VALID, SEEK_END) >= 0)) //! test valid once again, after not ready - it might change
this_p = lseek(fd_circ, LSEEK_CIRC_WAIT, SEEK_END); this_p = lseek(fd_circ, LSEEK_CIRC_WAIT, SEEK_END);
} else if (strcmp(cp1, "trig") == 0) { } else if (strcmp(cp1, "trig") == 0) {
// printf ("trig argument\n"); // printf ("trig argument\n");
int fd_fpga = open("/dev/fpgaio", O_RDWR); int fd_fpga = open("/dev/fpgaio", O_RDWR);
// printf ("fd_fpga = 0x%x\n",fd_fpga); // printf ("fd_fpga = 0x%x\n",fd_fpga);
if (fd_fpga >= 0) { if (fd_fpga >= 0) {
//int aaa; //int aaa;
lseek(fd_fpga, 0x7b, SEEK_SET); //!TODO: remove absolute register address from user application! 32-bit registers, not bytes lseek(fd_fpga, 0x7b, SEEK_SET); //!TODO: remove absolute register address from user application! 32-bit registers, not bytes
//printf ("lseek()-> 0x%x\n",aaa); //printf ("lseek()-> 0x%x\n",aaa);
long data = 1; long data = 1;
write(fd_fpga, &data, 4); // actually send the trigger pulse (will leave camera in single-shot mode) write(fd_fpga, &data, 4); // actually send the trigger pulse (will leave camera in single-shot mode)
//printf ("write()-> 0x%x\n",aaa); //printf ("write()-> 0x%x\n",aaa);
close(fd_fpga); close(fd_fpga);
} }
} else if (strcmp(cp1, "favicon.ico") == 0) { } else if (strcmp(cp1, "favicon.ico") == 0) {
...@@ -1256,7 +1261,7 @@ void listener_loop(struct file_set *fset) ...@@ -1256,7 +1261,7 @@ void listener_loop(struct file_set *fset)
if (sent2socket <= 0) { //! Nothing was sent to the client so far and the command line is over. Let's return 1x1 pixel gif if (sent2socket <= 0) { //! Nothing was sent to the client so far and the command line is over. Let's return 1x1 pixel gif
out1x1gif(); out1x1gif();
} else if (sent2socket == 2) { } else if (sent2socket == 2) {
metaXML(fd_circ, 2); /// 0 - new (send headers), 1 - continue, 2 - finish metaXML(fset, 2); /// 0 - new (send headers), 1 - continue, 2 - finish
} }
fflush(stdout); // probably it is not needed anymore, just in case fflush(stdout); // probably it is not needed anymore, just in case
...@@ -1315,6 +1320,10 @@ void init_file_set(struct file_set *fset, int fset_sz) ...@@ -1315,6 +1320,10 @@ void init_file_set(struct file_set *fset, int fset_sz)
fset[i].circbuf_fd = -1; fset[i].circbuf_fd = -1;
fset[i].jphead_fn = jhead_fnames[i]; fset[i].jphead_fn = jhead_fnames[i];
fset[i].jphead_fd = -1; fset[i].jphead_fd = -1;
fset[i].exif_dev_name = exif_dev_names[i];
fset[i].exif_dev_fd = -1;
fset[i].exifmeta_dev_name = exifmeta_dev_names[i];
fset[i].exifmeta_dev_fd = -1;
fset[i].port_num = 0; fset[i].port_num = 0;
} }
} }
...@@ -1324,8 +1333,8 @@ int main(int argc, char *argv[]) ...@@ -1324,8 +1333,8 @@ int main(int argc, char *argv[])
{ {
int res = 0; int res = 0;
init_file_set(files, IMAGE_CHN_NUM); init_file_set(files, SENSOR_PORTS);
res = parse_cmd_line(argc, (const char **)argv, files, IMAGE_CHN_NUM); res = parse_cmd_line(argc, (const char **)argv, files, SENSOR_PORTS);
if (res < 0) if (res < 0)
return EXIT_FAILURE; return EXIT_FAILURE;
...@@ -1336,7 +1345,7 @@ int main(int argc, char *argv[]) ...@@ -1336,7 +1345,7 @@ int main(int argc, char *argv[])
} }
// spawn a process for each port // spawn a process for each port
for (int i = 0; i < IMAGE_CHN_NUM; i++) { for (int i = 0; i < SENSOR_PORTS; i++) {
if (fork() == 0) { if (fork() == 0) {
listener_loop(&files[i]); listener_loop(&files[i]);
_exit(0); // should not get here? _exit(0); // should not get here?
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment