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

Merge branch 'test'

 Conflicts resolved:
	imgsrv.c
parents 1fa52b3a a3eb9430
......@@ -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"/>
<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">
<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"/>
</tool>
<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"/>
</tool>
<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/sysroots/elphel393/usr/include}&quot;"/>
</option>
......
......@@ -9,6 +9,9 @@
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
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>
<Image>
......@@ -22,9 +25,10 @@
<DateTime tag="0x0132" format="ASCII" count="20" seq="1" dlen="20">
<value>2001:06:21 12:00:00</value>
</DateTime>
<HostComputer tag="0x013c" format="ASCII" function="SERIAL"/>
<FrameNumber tag="0x83bb" format="LONG" count="1" seq="25" dlen="4"/>
<CameraSerialNumber tag="0xc62f" format="ASCII" function="SERIAL"/>
<ImageNumber tag="0x9211" format="LONG" count="1" seq="25" dlen="4"/>
<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"/>
<GPSTag tag="0x08825" format="LONG" function="GPSTAG"/>
</Image>
......
......@@ -2,9 +2,30 @@
PORT=2323
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
if [ $1 == "nodebug" ]; 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
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
mknod /dev/circbuf0 c 135 32
......
#!/usr/local/sbin/php -q
#!/usr/bin/env php
<?php
/*!
*! FILE NAME : exif.php
*! 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
*! of Exif headers.
*! 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
*! init - program Exif with default /etc/Exif_template.xml
*! init=path - program Exif with alternative file
*! noGPS - don't include GPS-related fields
*! nocompass - don't include compass-related fields
*! template - print currently loaded template data (hex dump)
*! 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=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
*! -----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*! $Log: exif.php,v $
*! 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)
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.2 2008/08/11 19:11:32 elphel
*! comments
*!
*! Revision 1.1 2008/04/07 09:12:14 elphel
*! New Exif template generation
*!
*! $Log: exif.php,v $
*! 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)
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.2 2008/08/11 19:11:32 elphel
*! comments
*!
*! Revision 1.1 2008/04/07 09:12:14 elphel
*! New Exif template generation
*!
*! Revision 1.1.1.1 2007/10/03 19:05:53 elphel
*! This is a fresh tree based on elphel353-2.10
*!
*! Revision 1.6 2007/10/03 19:05:53 elphel
*! cosmetic
*!
*! Revision 1.5 2007/10/03 18:37:53 elphel
*! Made nice html output to see the result data
*!
*! Revision 1.4 2007/10/03 06:33:31 elphel
*! fixed wrong copyright year
*!
*! 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)
*!
*! Revision 1.2 2007/09/25 23:34:02 elphel
*! Fixed time strings to the right length
*!
*! Revision 1.1 2007/09/24 07:27:57 elphel
*! Started php script that prepares Exif header information for serving images by imgsrv
*!
*/
*! FILE NAME : exif.php
*! 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
*! of Exif headers.
*! 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
*! init - program Exif with default /etc/Exif_template.xml
*! init=path - program Exif with alternative file
*! noGPS - don't include GPS-related fields
*! nocompass - don't include compass-related fields
*! template - print currently loaded template data (hex dump)
*! 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=NNN - print one of the Exif pages in the buffer (debug feature, current buffer pointer is not known here)
*!
*! Copyright (C) 2007-2016 Elphel, Inc
*! -----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*! $Log: exif.php,v $
*! 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)
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.2 2008/08/11 19:11:32 elphel
*! comments
*!
*! Revision 1.1 2008/04/07 09:12:14 elphel
*! New Exif template generation
*!
*! $Log: exif.php,v $
*! 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)
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.2 2008/08/11 19:11:32 elphel
*! comments
*!
*! Revision 1.1 2008/04/07 09:12:14 elphel
*! New Exif template generation
*!
*! Revision 1.1.1.1 2007/10/03 19:05:53 elphel
*! This is a fresh tree based on elphel353-2.10
*!
*! Revision 1.6 2007/10/03 19:05:53 elphel
*! cosmetic
*!
*! Revision 1.5 2007/10/03 18:37:53 elphel
*! Made nice html output to see the result data
*!
*! Revision 1.4 2007/10/03 06:33:31 elphel
*! fixed wrong copyright year
*!
*! 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)
*!
*! Revision 1.2 2007/09/25 23:34:02 elphel
*! Fixed time strings to the right length
*!
*! Revision 1.1 2007/09/24 07:27:57 elphel
*! 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.
// 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
......@@ -90,6 +90,10 @@ $ExifDeviceMetadirFilename= "/dev/exif_metadir";
$ExifDeviceExifFilename= "/dev/exif_exif";
$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,
//! through CGI - accepts more parameters
......@@ -138,10 +142,10 @@ define("EXIF_SRATIONAL",10);
define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
/// ===== init/init= CGI parameters or command line mode =======
if ($init) { // configure Exif data
if ($init) { // configure Exif data
$exif_head= array (
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
0x45,0x78,0x69,0x66,0x00,0x00); // Exif header
$Exif_length_offset= 2; // put total length here (big endian, 2 bytes)
......@@ -152,7 +156,7 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
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);
if ($xml_exif->GPSInfo) {
/// remove all tags named "Compass..."
/// remove all tags named "Compass..."
if ($nocompass) {
$tounset=array();
foreach ($xml_exif->GPSInfo->children() as $entry) if (strpos ($entry->getName() , "Compass" )!==false) $tounset[]=$entry->getName();
......@@ -176,7 +180,7 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
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->Photo->children() as $entry) substitute_value($entry);
if ($xml_exif->GPSInfo) {
......@@ -211,7 +215,7 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
fwrite ($Exif_file,$Exif_str); /// will disable and invalidate Exif data
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_entries=array();
......@@ -234,7 +238,7 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
fwrite ($Exif_meta_file,$Exif_str); /// will disable and invalidate Exif data
fclose($Exif_meta_file);
///Rebuild buffer and enable Exif generation/output:
///Rebuild buffer and enable Exif generation/output:
$Exif_file = fopen($ExifDeviceTemplateFilename, 'w');
fseek ($Exif_file, EXIF_LSEEK_ENABLE, SEEK_END) ;
......@@ -249,12 +253,12 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
echo "<hr/>\n";
test_print_directory();
}
} //if ($init) // configure Exif data
} //if ($init) // configure Exif data
/// ===== processing optional parameters =======
/// ===== 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');
fseek ($Exif_file, 0, SEEK_END) ;
......@@ -282,9 +286,9 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
var_dump($descr_was); echo "<br/>\n";
break;
}
}
}
/// ===== read template =======
if ($_GET["template"]!==NULL) {
if ($_GET["template"]!==NULL) {
$Exif_file = fopen($ExifDeviceTemplateFilename, 'r');
fseek ($Exif_file, 0, SEEK_END) ;
echo "<hr/>\n";
......@@ -294,9 +298,9 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
fclose($Exif_file);
echo "read ".strlen($template)." bytes<br/>\n";
hexdump($template);
}
}
/// ===== read meta directory =======
if ($_GET["metadir"]!==NULL) {
if ($_GET["metadir"]!==NULL) {
$Exif_file = fopen($ExifDeviceMetadirFilename, 'r');
fseek ($Exif_file, 0, SEEK_END) ;
echo "<hr/>\n";
......@@ -310,9 +314,9 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
$dir_entries[]=unpack("V*",substr($metadir,$i,16));
}
print_directory($dir_entries);
}
}
/// ===== read one of the Exif pages (0 - current, 1..512 - buffer) =======
if ($_GET["exif"]!==NULL) {
if ($_GET["exif"]!==NULL) {
$frame=$_GET["exif"]+0;
echo "<hr/>\n";
printf ("Reading frame %d, ",$frame);
......@@ -326,8 +330,8 @@ define("EXIF_LSEEK_ENABLE", 2); // rebuild buffer
fclose($Exif_file);
echo "read ".strlen($exif_data)." bytes<br/>\n";
hexdump($exif_data);
}
exit(0);
}
exit(0);
/// ======================================= Functions ======================================
function hexdump($data) {
global $exif_head, $exif_data;
......@@ -419,13 +423,13 @@ function test_print_directory() {
function start_ifd($count) {
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 & 0xff; // may apply & 0xff in the end to all elements
}
function finish_ifd() { // we do not have additional IFDs
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;
......@@ -439,14 +443,14 @@ function addDirEntry($ifd_entry) {
$lh=count($exif_head);
$attrs = $ifd_entry->attributes();
// var_dump($attrs);
// if (array_key_exists ( "seq" , $attrs )) {
// var_dump($attrs);
// if (array_key_exists ( "seq" , $attrs )) {
if ($attrs["seq"]) {
// echo $attrs["seq"].;
// echo $attrs["seq"].;
$dir_sequence[]=((string) $attrs["seq"])+0;
$len= (integer) $ifd_entry->value_length;
$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);
$dir_entries[]=array("ltag"=>((integer)$ifd_entry->ltag),"dst"=>$offs,"len"=>$len);
}
......@@ -454,11 +458,12 @@ function addDirEntry($ifd_entry) {
function substitute_value($ifd_entry) {
global $SUB_IFD_offset,$GPSInfo_offset;
global $DeviceSNFilename, $DeviceRevisionFilename, $DeviceBrand, $DeviceModel;
$attrs = $ifd_entry->attributes();
switch ($attrs["function"]) {
case "BRAND":
$ifd_entry->addChild ('value',exec("bootblocktool -x BRAND"));
$ifd_entry->addChild('value', $DeviceBrand);
break;
case "MODEL":
if (file_exists ('/var/state/APPLICATION')) {
......@@ -467,17 +472,20 @@ function substitute_value($ifd_entry) {
$model.=' CHN'.file_get_contents('/var/state/APPLICATION_MODE');
}
} else {
$model= exec("bootblocktool -x MODEL").exec("bootblocktool -x REVISION");
$model = $DeviceModel;
}
/// $ifd_entry->addChild ('value',exec("bootblocktool -x MODEL").exec("bootblocktool -x REVISION"));
$ifd_entry->addChild ('value',$model);
break;
case "SOFTWARE":
if (file_exists("/usr/html/docs/")) {
$ifd_entry->addChild ('value',exec("ls /usr/html/docs/")); // filter
}
break;
case "SERIAL":
$s=exec("bootblocktool -x SERNO");
$s = "";
if (file_exists($DeviceSNFilename)) {
$s = exec('cat '.$DeviceSNFilename);
}
$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));
break;
case "EXIFTAG":
......@@ -496,14 +504,14 @@ function process_ifd_entry($ifd_entry, $group) {
$ifd_tag= ((string) $attrs["tag"])+0;
$ifd_format=constant("EXIF_".$attrs["format"]);
$ifd_count= $attrs["count"];
// echo "\nifd_tag=$ifd_tag, entry=";print_r($ifd_entry);
// echo "\nifd_count=$ifd_count";
// echo "\nifd_bytes:";var_dump($ifd_bytes);
// echo "\nifd_tag=$ifd_tag, entry=";print_r($ifd_entry);
// echo "\nifd_count=$ifd_count";
// echo "\nifd_bytes:";var_dump($ifd_bytes);
if (!$ifd_count) {
if($ifd_format==EXIF_ASCII) $ifd_count=strlen($ifd_entry->value)+1;
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 & 0xff;
$exif_data[$ifd_pointer++]= ($ifd_format >> 8 ) & 0xff;
......@@ -524,7 +532,7 @@ function process_ifd_entry($ifd_entry, $group) {
default: $ifd_bytes=1; //1,2,6,7
}
$ifd_bytes=$ifd_bytes*$ifd_count;
// now prepare ifd_data - array of bytes
// now prepare ifd_data - array of bytes
switch ($ifd_format) {
case EXIF_BYTE:
case EXIF_SBYTE:
......@@ -558,9 +566,9 @@ echo "\n";
var_dump($denom);
echo "\n";
//exit(0);
*/
*/
for ($i=0;$i<count($nom);$i++) {
// echo "i=$i\n";
// echo "i=$i\n";
// echo "\nnom=";var_dump($nom[$i]);
// echo "\ndenom=";var_dump($denom[$i]);
$ifd_data=array_merge($ifd_data,$nom[$i],$denom[$i]);
......@@ -571,14 +579,14 @@ echo "\n";
$ifd_data= array_fill(0,$ifd_bytes,0); // will just fill with "0"-s
break;
}
// echo "\nifd_tag=$ifd_tag, entry=";print_r($i=$ifd_entry->value);
// echo "\nifd_data:";var_dump($ifd_data);
// echo "\nifd_bytes:";var_dump($ifd_bytes);
// echo "\nifd_tag=$ifd_tag, entry=";print_r($i=$ifd_entry->value);
// echo "\nifd_data:";var_dump($ifd_data);
// echo "\nifd_bytes:";var_dump($ifd_bytes);
$ifd_data=array_pad($ifd_data,$ifd_bytes,0);
$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;
else $ltag= $ifd_tag+($group<<16) ;
$ifd_entry->addChild ("ltag",$ltag );
......
......@@ -174,30 +174,23 @@
#undef ELPHEL_DEBUG
#if ELPHEL_DEBUG
#define ELPHEL_DEBUG_THIS 1
#define ELPHEL_DEBUG_THIS 1
#else
#define ELPHEL_DEBUG_THIS 0
#define ELPHEL_DEBUG_THIS 0
#endif
#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
#define D(x)
#define D(x)
#endif
//#define USEHTTP10(x)
#define USEHTTP10(x) x
// HEADER_SIZE is defined to be larger than actual header (later - with EXIF) to use compile-time buffer
//#define JPEG_HEADER_SIZE 0x26f // will not change
#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
/** @brief the length of MakerNote buffer in @e long */
#define MAKERNOTE_LEN 16
struct file_set {
unsigned short port_num;
......@@ -205,26 +198,29 @@ struct file_set {
int circbuf_fd;
const char *jphead_fn;
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 */
char trailer[TRAILER_SIZE] = { 0xff, 0xd9 };
const char *circbuf_fnames[] = {
"/dev/circbuf0",
"/dev/circbuf1",
"/dev/circbuf2",
"/dev/circbuf3"
};
const char *jhead_fnames[] = {
"/dev/jpeghead0",
"/dev/jpeghead1",
"/dev/jpeghead2",
"/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" \
"Start image server, bind it to ports <port_number_1> <port_number_2> <port_number_3> <port_number_4>\n" \
......@@ -262,22 +258,20 @@ const char url_args[] = "This server supports sequence of commands entered in th
" 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"
" 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 listener_loop(int port, const char *circbuf_fname);
void listener_loop(struct file_set *fset);
void errorMsgXML(char * msg);
int framePointersXML(int fd_circ);
int metaXML(int fd_circ, int mode); /// mode: 0 - new (send headers), 1 - continue, 2 - finish
int printExifXML(int exif_page);
int framePointersXML(struct file_set *fset);
int metaXML(struct file_set *fset, int mode); /// mode: 0 - new (send headers), 1 - continue, 2 - finish
int printExifXML(int exif_page, struct file_set *fset);
int out1x1gif(void);
void waitFrameSync();
unsigned long getCurrentFrameNumber();
#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;
long numfields = 0;
......@@ -285,8 +279,8 @@ int printExifXML(int exif_page)
int fd_exifdir;
struct exif_dir_table_t exif_dir[ExifKmlNumber]; /// store locations of the fields needed for KML generations in the Exif block
/// Create Exif directory
/// Read the size of the Exif data
/// Create Exif directory
/// Read the size of the Exif data
fd_exifdir = open(EXIFDIR_DEV_NAME, O_RDONLY);
if (fd_exifdir < 0) {
printf("<error>\"Opening %s\"</error>\n", EXIFDIR_DEV_NAME);
......@@ -296,7 +290,7 @@ int printExifXML(int exif_page)
while (read(fd_exifdir, &dir_table_entry, sizeof(dir_table_entry)) > 0) {
switch (dir_table_entry.ltag) {
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_SubSecTimeOriginal: indx = Exif_Photo_SubSecTimeOriginal_Index; break;
case Exif_Photo_ExposureTime: indx = Exif_Photo_ExposureTime_Index; break;
......@@ -317,6 +311,7 @@ int printExifXML(int exif_page)
case Exif_GPSInfo_CompassPitch: indx = Exif_GPSInfo_CompassPitch_Index; break;
case Exif_GPSInfo_CompassRollRef: indx = Exif_GPSInfo_CompassRollRef_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;
}
if (indx >= 0) {
......@@ -325,28 +320,29 @@ int printExifXML(int exif_page)
}
}
close(fd_exifdir);
/// Create XML files iteslf
/// Create XML files itself
long rational3[6];
long makerNote[14];
long makerNote[MAKERNOTE_LEN];
long exif_page_start;
char val[256];
int hours = 0, minutes = 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;
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) {
printf("<error>\"Opening %s\"</error>\n", EXIF_DEV_NAME);
printf("<error>\"Opening %s\"</error>\n", fset->exif_dev_name);
return -3;
}
fset->exif_dev_fd = fd_exif;
exif_page_start = lseek(fd_exif, exif_page, SEEK_END); /// select specified Exif page
if (exif_page_start < 0) {
printf("<error>\"Exif page (%d) is out of range\"</error>\n", exif_page);
close(fd_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
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Image_ImageDescription_Index].dst,
......@@ -354,17 +350,17 @@ int printExifXML(int exif_page)
saferead255(fd_exif, val, exif_dir[Exif_Image_ImageDescription_Index].len);
printf("<ImageDescription>\"%s\"</ImageDescription>\n", val);
}
///Exif_Image_FrameNumber_Index 0x13
if (exif_dir[Exif_Image_FrameNumber_Index].ltag == Exif_Image_FrameNumber) { // Exif_Image_FrameNumber_Index is present in template
///Exif_Image_ImageNumber_Index 0x13
if (exif_dir[Exif_Image_ImageNumber_Index].ltag == Exif_Image_ImageNumber) { // Exif_Image_ImageNumber_Index is present in template
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);
read(fd_exif, rational3, 4);
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
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Image_Orientation_Index].dst,
......@@ -375,7 +371,18 @@ int printExifXML(int exif_page)
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) {
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Photo_DateTimeOriginal_Index].dst,
......@@ -392,7 +399,7 @@ int printExifXML(int exif_page)
}
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
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Photo_ExposureTime_Index].dst,
......@@ -403,7 +410,7 @@ int printExifXML(int exif_page)
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
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Photo_MakerNote_Index].dst,
......@@ -430,8 +437,7 @@ int printExifXML(int exif_page)
printf("<MakerNote>\"%s\"</MakerNote>\n", val);
}
/// GPS measure mode
/// GPS measure mode
if (exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].ltag == Exif_GPSInfo_GPSMeasureMode) {
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].dst,
......@@ -440,7 +446,8 @@ int printExifXML(int exif_page)
val[1] = '\0';
printf("<GPSMeasureMode>\"%s\"</GPSMeasureMode>\n", val);
}
///GPS date/time
///GPS date/time
if (exif_dir[Exif_GPSInfo_GPSDateStamp_Index].ltag == Exif_GPSInfo_GPSDateStamp) {
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSDateStamp_Index].dst,
......@@ -460,8 +467,8 @@ int printExifXML(int exif_page)
printf("<GPSDateTime>\"%s\"</GPSDateTime>\n", val);
}
/// knowing format provided from GPS - degrees and minutes only, no seconds:
///GPS Longitude
/// knowing format provided from GPS - degrees and minutes only, no seconds:
///GPS Longitude
if (exif_dir[Exif_GPSInfo_GPSLongitude_Index].ltag == Exif_GPSInfo_GPSLongitude) { // Exif_GPSInfo_GPSLongitude is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSLongitude_Index].dst,
......@@ -478,7 +485,7 @@ int printExifXML(int exif_page)
sprintf(val, "%f", longitude);
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
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSLatitude_Index].dst,
......@@ -495,7 +502,7 @@ int printExifXML(int exif_page)
sprintf(val, "%f", latitude);
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
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSAltitude_Index].dst,
......@@ -513,7 +520,7 @@ int printExifXML(int exif_page)
sprintf(val, "%f", altitude);
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
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_CompassDirection_Index].dst,
......@@ -523,8 +530,8 @@ int printExifXML(int exif_page)
sprintf(val, "%f", heading);
printf("<CompassDirection>\"%s\"</CompassDirection>\n", val);
}
///Processing 'hacked' pitch and roll (made of Exif destination latitude/longitude)
///Compass Roll
///Processing 'hacked' pitch and roll (made of Exif destination latitude/longitude)
///Compass Roll
if (exif_dir[Exif_GPSInfo_CompassRoll_Index].ltag == Exif_GPSInfo_CompassRoll) { // Exif_GPSInfo_CompassRoll is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_CompassRoll_Index].dst,
......@@ -543,7 +550,7 @@ int printExifXML(int exif_page)
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
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_CompassPitch_Index].dst,
......@@ -565,13 +572,12 @@ int printExifXML(int exif_page)
return 0;
}
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 frameParamPointer = 0;
struct interframe_params_t frame_params;
int jpeg_len, jpeg_start, buff_size, timestamp_start;
int fd_circ = fset->circbuf_fd;
if (mode == 2) { /// just close the xml file
printf("</meta>\n");
......@@ -593,18 +599,18 @@ int metaXML(int fd_circ, int mode) /// mode: 0 - new (send headers), 1 - con
return -1;
}
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);
frameParamPointer = jpeg_start - 32;
if (frameParamPointer < 0) frameParamPointer += buff_size;
memcpy(&frame_params, (unsigned long* )&ccam_dma_buf[frameParamPointer >> 2], 32); /// ccam_dma_buf - global
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
if (timestamp_start >= buff_size) timestamp_start-=buff_size;
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" \
"<start> 0x%x </start>\n" \
"<hash32_r> 0x%x </hash32_r>\n" \
......@@ -634,17 +640,17 @@ int metaXML(int fd_circ, int mode) /// mode: 0 - new (send headers), 1 - con
, frame_params.timestamp_usec
, (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 frame_length ; //! JPEG frame length in circular buffer, bytes
/// };
///32-35 unsigned long timestamp_usec; //! number of microseconds to add
///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
/// };
///32-35 unsigned long timestamp_usec; //! number of microseconds to add
if (frame_params.signffff !=0xffff) {
printf("<error>\"wrong signature (should be 0xffff)\"</error>\n");
} else {
///Put Exif data here
///Put Exif data here
printf ("<Exif>\n");
printExifXML(frame_params.meta_index);
printExifXML(frame_params.meta_index, fset);
printf ("</Exif>\n");
}
printf ("</frame>\n");
......@@ -670,7 +676,7 @@ void waitFrameSync()
close(fd_fparmsall);
}
int framePointersXML(int fd_circ)
int framePointersXML(struct file_set *fset)
{
const char ctlFileName[] = "/dev/frameparsall";
int fd_fparmsall;
......@@ -683,10 +689,10 @@ int framePointersXML(int fd_circ)
int frame8, frame_number, sensor_state, compressor_state;
char *cp_sensor_state, *cp_compressor_state;
struct framepars_all_t *frameParsAll;
struct framepars_t *framePars;
unsigned long *globalPars;
struct framepars_all_t **frameParsAll;
struct framepars_t *aframePars[SENSOR_PORTS];
unsigned long *aglobalPars[SENSOR_PORTS];
int fd_circ = fset->circbuf_fd;
fd_fparmsall = open(ctlFileName, O_RDWR);
if (fd_fparmsall < 0) { // check control OK
......@@ -695,8 +701,8 @@ int framePointersXML(int fd_circ)
return -1;
}
//! now try to mmap
frameParsAll = (struct framepars_all_t*)mmap(0, sizeof(struct framepars_all_t), PROT_READ, MAP_SHARED, fd_fparmsall, 0);
//! now try to mmap
frameParsAll = (struct framepars_all_t**)mmap(0, sizeof(struct framepars_all_t), PROT_READ, MAP_SHARED, fd_fparmsall, 0);
if ((int)frameParsAll == -1) {
frameParsAll = NULL;
printf("Error in mmap /dev/frameparsall");
......@@ -705,15 +711,16 @@ int framePointersXML(int fd_circ)
fd_fparmsall = -1;
return -1;
}
framePars = frameParsAll->framePars;
globalPars = frameParsAll->globalPars;
for (int j = 0; j < SENSOR_PORTS; j++) {
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 );
frame8 = frame_number & PARS_FRAMES_MASK;
// printf ("Current frame number is %d\n",frame_number);
sensor_state = framePars[frame8].pars[P_SENSOR_RUN];
compressor_state = framePars[frame8].pars[P_COMPRESSOR_RUN];
sensor_state = aframePars[fset->port_num][frame8].pars[P_SENSOR_RUN];
compressor_state = aframePars[fset->port_num][frame8].pars[P_COMPRESSOR_RUN];
cp_sensor_state = (sensor_state == 0) ?
"SENSOR_RUN_STOP" :
((sensor_state == 1) ?
......@@ -734,8 +741,8 @@ int framePointersXML(int fd_circ)
p = lseek(fd_circ, LSEEK_CIRC_PREV, SEEK_END);
nf++;
}
buf_free = GLOBALPARS(G_FREECIRCBUF);
frame_size = GLOBALPARS(G_FRAME_SIZE);
buf_free = GLOBALPARS(fset->port_num, G_FREECIRCBUF);
frame_size = GLOBALPARS(fset->port_num, G_FRAME_SIZE);
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
......@@ -775,12 +782,13 @@ int framePointersXML(int fd_circ)
printf("Pragma: no-cache\r\n");
printf("\r\n");
printf(s);
//! No need to unmap?
munmap(frameParsAll, sizeof(struct framepars_all_t));
close(fd_fparmsall);
D(fprintf(stderr, ">%s< [%d bytes]\n", s, strlen(s)));
return 0;
}
//fwrite (&cbuffer[offset],1,bytesLeft,stdout);
int out1x1gif(void)
{
char s[] = "HTTP/1.0 200 OK\r\n" \
......@@ -798,7 +806,7 @@ int out1x1gif(void)
void errorMsgXML(char * msg)
{
char s[1024]; // was 701 acrtually
char s[1024];
sprintf(s, "<?xml version=\"1.0\"?>\n" \
"<frame_params>\n" \
......@@ -821,15 +829,11 @@ void errorMsgXML(char * msg)
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 exifIndexPointer=0;
int frameParamPointer = 0;
struct interframe_params_t frame_params;
/// struct frame_exif_t frame_exif; //just 8 bytes
int buff_size;
int jpeg_len; //bytes
int jpeg_len; // bytes
int jpeg_start; // bytes
int fd_head;
int fd_exif;
......@@ -841,7 +845,6 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
char * mime_type;
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
D(fprintf(stderr, "jpeg_start (long) = 0x%x\n", jpeg_start));
fd_head = open(fset->jphead_fn, O_RDWR);
......@@ -850,21 +853,20 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
return -1;
}
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);
if (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);
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);
/*! restore file poinetr after lseek-ing the end */
/*! restore file poinetr after lseek-ing the end */
lseek(fset->circbuf_fd, jpeg_start, SEEK_SET);
D(fprintf(stderr, "position (longs) = 0x%x\n", (int)lseek(fset->circbuf_fd, 0, SEEK_CUR)));
/*! now let's try mmap itself */
/// exifIndexPointer=jpeg_start-8;
/*! now let's try mmap itself */
frameParamPointer = jpeg_start - sizeof(struct interframe_params_t) + 4;
if (frameParamPointer < 0)
frameParamPointer += buff_size;
......@@ -875,16 +877,19 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
color_mode = frame_params.color;
if (frame_params.signffff != 0xffff) {
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);
return -4;
}
if (use_Exif) {
//D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
/// read Exif to buffer:
fd_exif = open(ExifFileName, O_RDONLY);
D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
/// read Exif to buffer:
fd_exif = open(fset->exif_dev_name, O_RDONLY);
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);
return -5;
}
......@@ -892,24 +897,24 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
if (exifDataSize < 0) exifDataSize = 0; // error from lseek;
if (!exifDataSize) close(fd_exif);
} else {
//frame_params.meta_index=0;
frame_params.meta_index=0;
fd_exif = -1;
}
///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)
/// Now we always malloc buffer, before - only for bimg, using fixed-size header buffer - was it faster?
///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)
/// 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;
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);
if (bufferImageData) jpeg_this_size = jpeg_full_size; /// header+frame
else jpeg_this_size = head_size + exifDataSize; /// only header
if (bufferImageData) jpeg_this_size = jpeg_full_size; // header+frame
else jpeg_this_size = head_size + exifDataSize; // only header
jpeg_copy = malloc(jpeg_this_size);
if (!jpeg_copy) {
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++) {
usleep(((jpeg_this_size & 0x3ff) + 5) * 100); // up to 0.1 sec
jpeg_copy = malloc(jpeg_this_size);
......@@ -925,21 +930,21 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
lseek(fd_head, 0, 0);
read(fd_head, &jpeg_copy[exifDataSize], head_size);
close(fd_head);
if (exifDataSize > 0) { //! insert 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)
read(fd_exif, &jpeg_copy[2], exifDataSize); //! Insert Exif itself
if (exifDataSize > 0) { // insert 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)
read(fd_exif, &jpeg_copy[2], exifDataSize); // Insert Exif itself
close(fd_exif);
}
switch (color_mode) {
// case COLORMODE_MONO6: //! monochrome, (4:2:0),
// case COLORMODE_COLOR: //! color, 4:2:0, 18x18(old)
// case COLORMODE_MONO6: //! monochrome, (4:2:0),
// case COLORMODE_COLOR: //! color, 4:2:0, 18x18(old)
case COLORMODE_JP46: //! jp4, original (4:2:0)
case COLORMODE_JP46DC: //! jp4, dc -improved (4:2:0)
mime_type = "jp46";
extension = "jp46";
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_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
......@@ -949,15 +954,15 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
mime_type = "jp4";
extension = "jp4";
break;
// case COLORMODE_MONO4: //! monochrome, 4 blocks (but still with 2x2 macroblocks)
// case COLORMODE_MONO4: //! monochrome, 4 blocks (but still with 2x2 macroblocks)
default:
mime_type = "jpeg";
extension = "jpeg";
}
// char * mime_type;
// char * extension;
/*
// char * mime_type;
// char * extension;
/*
#define COLORMODE_MONO6 0 // monochrome, (4:2:0),
#define COLORMODE_COLOR 1 // color, 4:2:0, 18x18(old)
#define COLORMODE_JP46 2 // jp4, original (4:2:0)
......@@ -977,8 +982,12 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
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) */
#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;
/*! 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
memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], 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
} else { /*! single segment */
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);
printf("Content-Length: %d\r\n", jpeg_full_size);
printf("\r\n");
......@@ -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("\r\n");
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
/*! 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);
/*! 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));
} 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(trailer, 2);
}
free(jpeg_copy);
return 0;
}
/*! repeat writes to stdout until all data is sent */
void sendBuffer(void * buffer, int len)
{
......@@ -1030,13 +1041,9 @@ void sendBuffer(void * buffer, int len)
}
}
void listener_loop(struct file_set *fset)
{
char errormsg[1024];
//const char circbufFileName[] = "/dev/circbuf0";
int fd_circ;
int this_p; //! current frame pointer (bytes)
int rslt;
......@@ -1066,22 +1073,22 @@ void listener_loop(struct file_set *fset)
if (fd == -1) continue;
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) {
close(res);
/*! setup stdin and stdout */
/*! setup stdin and stdout */
fflush(stdout);
fflush(stderr);
dup2(fd, 0);
dup2(fd, 1);
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);
cp = buf;
strsep(&cp, "/?"); // ignore everything before first "/" or "?"
if (cp) {
//! 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
//! 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
cp1 = strchr(cp, ' ');
if (cp1) cp1[0] = '\0';
}
......@@ -1095,7 +1102,7 @@ void listener_loop(struct file_set *fset)
fflush(stdout);
_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, "wframe", 6) == 0) waitFrameSync();
printf("HTTP/1.0 200 OK\r\n");
......@@ -1107,7 +1114,7 @@ void listener_loop(struct file_set *fset)
fflush(stdout);
_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);
if (fd_circ < 0) { // check control OK
fprintf(stderr, "Error opening %s\n", fset->cirbuf_fn);
......@@ -1116,10 +1123,10 @@ void listener_loop(struct file_set *fset)
_exit(0);
}
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);
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);
if ((int)ccam_dma_buf == -1) {
fprintf(stderr, "Error in mmap\n");
......@@ -1130,11 +1137,9 @@ void listener_loop(struct file_set *fset)
}
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));
//!continue with iterating through the commands
// continue with iterating through the commands
while ((cp1 = strsep(&cp, "/?&"))) {
// printf ("1->%s", cp1);
// fprintf (stderr, "1->%s",cp1);
//!if the first caracter is digit,it is a file pointer
// if the first character is a digit, it is a file pointer
if (strchr("0123456789", cp1[0])) {
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)) {
......@@ -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
///multipart - always last
// multipart - always last
} 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 (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();
else {
//TODO:
//TODO:
buf_images = (strncmp(cp1, "mimg", 4) == 0) ? 0 : 1;
cp2 = cp1 + (buf_images ? 5 : 4);
slow = strtol(cp2, NULL, 10);
......@@ -1187,7 +1192,7 @@ void listener_loop(struct file_set *fset)
fflush(stdout);
if (rslt >= 0) for (skip = 0; skip < slow; skip++) {
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
(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
......@@ -1199,12 +1204,12 @@ void listener_loop(struct file_set *fset)
}
} else if (strcmp(cp1, "pointers") == 0) {
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;
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) {
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;
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) {
......@@ -1233,18 +1238,18 @@ void listener_loop(struct file_set *fset)
(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);
} else if (strcmp(cp1, "trig") == 0) {
// printf ("trig argument\n");
// printf ("trig argument\n");
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) {
//int aaa;
//int aaa;
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;
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);
}
} else if (strcmp(cp1, "favicon.ico") == 0) {
......@@ -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
out1x1gif();
} 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
......@@ -1315,6 +1320,10 @@ void init_file_set(struct file_set *fset, int fset_sz)
fset[i].circbuf_fd = -1;
fset[i].jphead_fn = jhead_fnames[i];
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;
}
}
......@@ -1324,8 +1333,8 @@ int main(int argc, char *argv[])
{
int res = 0;
init_file_set(files, IMAGE_CHN_NUM);
res = parse_cmd_line(argc, (const char **)argv, files, IMAGE_CHN_NUM);
init_file_set(files, SENSOR_PORTS);
res = parse_cmd_line(argc, (const char **)argv, files, SENSOR_PORTS);
if (res < 0)
return EXIT_FAILURE;
......@@ -1336,7 +1345,7 @@ int main(int argc, char *argv[])
}
// 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) {
listener_loop(&files[i]);
_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