Commit 423a8a31 authored by Mikhail Karpenko's avatar Mikhail Karpenko

Update doxygen documentation

parent 4ebcb359
...@@ -51,5 +51,14 @@ ...@@ -51,5 +51,14 @@
</scannerConfigBuildInfo> </scannerConfigBuildInfo>
</storageModule> </storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/> <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
<storageModule moduleId="refreshScope"/> <storageModule moduleId="refreshScope" versionNumber="2">
<configuration configurationName="Default">
<resource resourceType="PROJECT" workspacePath="/elphel-apps-imgsrv"/>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings">
<doc-comment-owner id="org.eclipse.cdt.ui.doxygen">
<path value=""/>
</doc-comment-owner>
</storageModule>
</cproject> </cproject>
This source diff could not be displayed because it is too large. You can view the blob instead.
/*!*************************************************************************** /** @file imgsrv.c
*! FILE NAME : imgsrv.c * @brief Simple and fast HTTP server to send camera still images
*! DESCRIPTION: Simple and fast HTTP server to send camera still images * @copyright Copyright (C) 2007-2016 Elphel, Inc.
*! Copyright (C) 2007-2008 Elphel, Inc. *
*! -----------------------------------------------------------------------------** * @par <b>License</b>
*! 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
*! * along with this program. If not, see <http://www.gnu.org/licenses/>.
*! 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: imgsrv.c,v $
*! Revision 1.15 2014/06/25 23:32:26 dzhimiev
*! 1. fixed imgsrv /n -> /r/n
*! 2. updated revision number
*!
*! Revision 1.14 2012/04/08 04:11:28 elphel
*! 8.2.2 changes related to temperatures measurement and embedding in the Exif MakerNote
*!
*! Revision 1.13 2011/12/22 05:33:06 elphel
*! Added trigger command
*!
*! Revision 1.12 2010/08/16 17:10:24 elphel
*! added reporting frame number (for inter-camera synchronization)
*!
*! 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)
*!
*! Revision 1.10 2010/08/03 06:13:51 elphel
*! bugfix - was not copying last 8 bytes of MakerNote
*!
*! Revision 1.9 2010/08/01 19:30:24 elphel
*! new readonly parameter FRAME_SIZE and it support in the applications
*!
*! 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)
*!
*! Revision 1.7 2010/03/04 06:41:40 elphel
*! 8.0.7.3 - more data to makerNote
*!
*! 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)
*!
*! 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
*!
*! Revision 1.4 2009/10/12 19:20:23 elphel
*! Added "Content-Disposition" support to suggest filenames to save images
*!
*! Revision 1.3 2009/02/25 17:47:51 spectr_rain
*! removed deprecated dependency
*!
*! Revision 1.2 2009/02/18 06:25:41 elphel
*! fixed unterminated string of 1 character (GPS mode - 2/3)
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.11 2008/11/03 18:42:21 elphel
*! comment typo
*!
*! 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)
*!
*! Revision 1.9 2008/10/25 19:51:40 elphel
*! updated copyright year
*!
*! Revision 1.8 2008/10/21 21:28:52 elphel
*! support for xml meta output
*!
*! 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)
*!
*! Revision 1.6 2008/10/11 18:46:07 elphel
*! snapshot
*!
*! Revision 1.5 2008/10/06 08:31:08 elphel
*! snapshot, first images
*!
*! Revision 1.4 2008/09/07 19:48:08 elphel
*! snapshot
*!
*! Revision 1.3 2008/08/11 19:10:45 elphel
*! reduced syntax "complaints" from KDevelop
*!
*! Revision 1.2 2008/05/16 06:06:54 elphel
*! supporting variable JPEG header length
*!
*! Revision 1.14 2008/04/22 22:14:56 elphel
*! Added malloc failures handling, syslog logging of such events
*!
*! Revision 1.13 2008/04/16 20:30:33 elphel
*! added optional fps reduction to multipart JPEGs
*!
*! Revision 1.11 2008/04/07 09:13:35 elphel
*! Changes related to new Exif generation/processing
*!
*! Revision 1.10 2008/03/22 04:39:53 elphel
*! remove complaints about "&_time=..."
*!
*! Revision 1.9 2007/12/03 08:28:45 elphel
*! Multiple changes, mostly cleanup
*!
*! Revision 1.8 2007/11/16 08:56:19 elphel
*! Added support for 2 additional commands to check circbuf usage
*!
*! 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)
*!
*! Revision 1.6 2007/11/04 05:47:40 elphel
*! Cleaned up from debug code inserted to fight mmap/caching bug (fixed by now)
*!
*! Revision 1.5 2007/11/01 18:59:37 elphel
*! debugging mmap/caching problems
*!
*! 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
*!
*! Revision 1.3 2007/10/27 00:55:32 elphel
*! untested revision - need to go
*!
*! Revision 1.2 2007/10/11 06:42:28 elphel
*! 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
*! This is a fresh tree based on elphel353-2.10
*!
*! Revision 1.4 2007/10/02 19:44:54 elphel
*! More functionality (buffer manipulation commands, clean interface, xml responces)
*!
*! Revision 1.3 2007/09/29 16:21:25 elphel
*! removed IOCTL usage from /dev/circbuf, improved comments, other minor changes
*!
*! Revision 1.2 2007/09/25 23:35:16 elphel
*! added Exif initialization, made it to work in background mode
*!
*! 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)
*!
*!
*/ */
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -163,7 +31,7 @@ ...@@ -163,7 +31,7 @@
#include <syslog.h> #include <syslog.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/mman.h> /* mmap */ #include <sys/mman.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
//#include <elphel/c313a.h> //#include <elphel/c313a.h>
...@@ -186,12 +54,36 @@ ...@@ -186,12 +54,36 @@
#define D(x) #define D(x)
#endif #endif
// HEADER_SIZE is defined to be larger than actual header (later - with EXIF) to use compile-time buffer /** @brief HEADER_SIZE is defined to be larger than actual header (with EXIF) to use compile-time buffer */
#define JPEG_HEADER_MAXSIZE 0x300 // will not change #define JPEG_HEADER_MAXSIZE 0x300
/** @brief The size of trailing marker */
#define TRAILER_SIZE 0x02 #define TRAILER_SIZE 0x02
/** @brief the length of MakerNote buffer in @e long */ /** @brief The length of MakerNote buffer in @e long */
#define MAKERNOTE_LEN 16 #define MAKERNOTE_LEN 16
/**
* @struct file_set
* This structure holds a set of file names and file descriptors corresponding to
* one sensor port.
* @var file_set::port_num
* Sensor port number this set corresponds to
* @var file_set::cirbuf_fn
* The file name of circular buffer
* @var file_set::circbuf_fd
* The file descriptor of circular buffer
* @var file_set::jphead_fn
* The file name of JPEG header buffer
* @var file_set::jphead_fd
* The file descriptor of JPEG header buffer
* @var file_set::exif_dev_name
* The file name of Exif buffer
* @var file_set::exif_dev_fd
* The file descriptor of Exif buffer
* @var file_set::exifmeta_dev_name
* The file name of Exif meta buffer
* @var file_set::exifmeta_dev_fd
* The file descriptor of Exif meta buffer
*/
struct file_set { struct file_set {
unsigned short port_num; unsigned short port_num;
const char *cirbuf_fn; const char *cirbuf_fn;
...@@ -205,7 +97,7 @@ struct file_set { ...@@ -205,7 +97,7 @@ struct file_set {
}; };
static struct file_set files[SENSOR_PORTS]; static struct file_set files[SENSOR_PORTS];
unsigned long * ccam_dma_buf; /* mmapped array */ unsigned long * ccam_dma_buf;
char trailer[TRAILER_SIZE] = { 0xff, 0xd9 }; char trailer[TRAILER_SIZE] = { 0xff, 0xd9 };
const char *circbuf_fnames[] = { const char *circbuf_fnames[] = {
"/dev/circbuf0", "/dev/circbuf0",
...@@ -229,9 +121,9 @@ const char app_args[] = "Usage:\n%s -p <port_number_1> [<port_number_2> <port_nu ...@@ -229,9 +121,9 @@ const char app_args[] = "Usage:\n%s -p <port_number_1> [<port_number_2> <port_nu
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 available - 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 immediately 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"
...@@ -242,7 +134,7 @@ const char url_args[] = "This server supports sequence of commands entered in th ...@@ -242,7 +134,7 @@ const char url_args[] = "This server supports sequence of commands entered in th
"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 acquired\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"
...@@ -264,27 +156,35 @@ void sendBuffer(void * buffer, int len); ...@@ -264,27 +156,35 @@ void sendBuffer(void * buffer, int len);
void listener_loop(struct file_set *fset); void listener_loop(struct file_set *fset);
void errorMsgXML(char * msg); void errorMsgXML(char * msg);
int framePointersXML(struct file_set *fset); int framePointersXML(struct file_set *fset);
int metaXML(struct file_set *fset, 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, struct file_set *fset); 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();
/** @brief Read no more then 255 bytes from file */
#define saferead255(f, d, l) read(f, d, ((l) < 256) ? (l) : 255) #define saferead255(f, d, l) read(f, d, ((l) < 256) ? (l) : 255)
/**
* @brief Print Exif data in XML format to @e stdout
* @param[in] exif_page page number in Exif buffer
* @param[in] fset file set for which the data should be printed
* @return 0 if data was extracted successfully and negative error code otherwise
*/
int printExifXML(int exif_page, struct file_set *fset) int printExifXML(int exif_page, struct file_set *fset)
{ {
int indx; int indx;
long numfields = 0; long numfields = 0;
struct exif_dir_table_t dir_table_entry; struct exif_dir_table_t dir_table_entry;
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);
return -2; /// Error opening Exif directory return -2; // Error opening Exif directory
} }
for (indx = 0; indx < ExifKmlNumber; indx++) exif_dir[indx].ltag = 0; for (indx = 0; indx < ExifKmlNumber; indx++) exif_dir[indx].ltag = 0;
while (read(fd_exifdir, &dir_table_entry, sizeof(dir_table_entry)) > 0) { while (read(fd_exifdir, &dir_table_entry, sizeof(dir_table_entry)) > 0) {
...@@ -321,7 +221,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -321,7 +221,7 @@ int printExifXML(int exif_page, struct file_set *fset)
} }
close(fd_exifdir); close(fd_exifdir);
/// Create XML files itself // Create XML files itself
long rational3[6]; long rational3[6];
long makerNote[MAKERNOTE_LEN]; long makerNote[MAKERNOTE_LEN];
long exif_page_start; long exif_page_start;
...@@ -336,13 +236,13 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -336,13 +236,13 @@ int printExifXML(int exif_page, struct file_set *fset)
return -3; return -3;
} }
fset->exif_dev_fd = fd_exif; 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,
...@@ -350,7 +250,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -350,7 +250,7 @@ int printExifXML(int exif_page, struct file_set *fset)
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_ImageNumber_Index 0x13 // Exif_Image_ImageNumber_Index 0x13
if (exif_dir[Exif_Image_ImageNumber_Index].ltag == Exif_Image_ImageNumber) { // Exif_Image_ImageNumber_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_ImageNumber_Index].dst, exif_page_start + exif_dir[Exif_Image_ImageNumber_Index].dst,
...@@ -360,7 +260,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -360,7 +260,7 @@ int printExifXML(int exif_page, struct file_set *fset)
printf("<ImageNumber>\"%s\"</ImageNumber>\n", val); printf("<ImageNumber>\"%s\"</ImageNumber>\n", val);
} }
///Exif_Image_Orientation_Index 0x14 // 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,
...@@ -382,7 +282,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -382,7 +282,7 @@ int printExifXML(int exif_page, struct file_set *fset)
printf("<SensorNumber>\"%s\"</SensorNumber>\n", val); printf("<SensorNumber>\"%s\"</SensorNumber>\n", val);
} }
///DateTimeOriginal (with subseconds) // 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,
...@@ -399,7 +299,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -399,7 +299,7 @@ int printExifXML(int exif_page, struct file_set *fset)
} }
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,
...@@ -410,7 +310,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -410,7 +310,7 @@ int printExifXML(int exif_page, struct file_set *fset)
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,
...@@ -437,7 +337,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -437,7 +337,7 @@ int printExifXML(int exif_page, struct file_set *fset)
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,
...@@ -447,7 +347,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -447,7 +347,7 @@ int printExifXML(int exif_page, struct file_set *fset)
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,
...@@ -461,14 +361,14 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -461,14 +361,14 @@ int printExifXML(int exif_page, struct file_set *fset)
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]);
seconds = (1.0 * (__cpu_to_be32( rational3[4]) + 1)) / __cpu_to_be32( rational3[5]); /// GPS likes ".999", let's inc by one - anyway will round that out seconds = (1.0 * (__cpu_to_be32( rational3[4]) + 1)) / __cpu_to_be32( rational3[5]); // GPS likes ".999", let's inc by one - anyway will round that out
sprintf(&val[10], " %02d:%02d:%05.2f", hours, minutes, seconds); sprintf(&val[10], " %02d:%02d:%05.2f", hours, minutes, seconds);
} }
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,
...@@ -485,7 +385,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -485,7 +385,7 @@ int printExifXML(int exif_page, struct file_set *fset)
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,
...@@ -502,7 +402,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -502,7 +402,7 @@ int printExifXML(int exif_page, struct file_set *fset)
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,
...@@ -520,7 +420,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -520,7 +420,7 @@ int printExifXML(int exif_page, struct file_set *fset)
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,
...@@ -530,8 +430,8 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -530,8 +430,8 @@ int printExifXML(int exif_page, struct file_set *fset)
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,
...@@ -550,7 +450,7 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -550,7 +450,7 @@ int printExifXML(int exif_page, struct file_set *fset)
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,
...@@ -572,17 +472,29 @@ int printExifXML(int exif_page, struct file_set *fset) ...@@ -572,17 +472,29 @@ int printExifXML(int exif_page, struct file_set *fset)
return 0; return 0;
} }
int metaXML(struct file_set *fset, int mode) /// mode: 0 - new (send headers), 1 - continue, 2 - finish /**
* @brief Print frame parameters and Exif data to @e stdout
* @param[in] fset file set for which the data should be printed
* @param[in] mode mode of operation. Can be one of the following:
* mode | action
* -----|-------
* 0 | send new page including HTTP header
* 1 | continue sending XML tags
* 2 | finish and send closing XML tag
* @return 0 if data was sent successfully and -1 if a frame was not found at
* the location pointer by JPEG pointer
*/
int metaXML(struct file_set *fset, int mode)
{ {
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; 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");
return 0; return 0;
} else if (mode == 0) { /// open the XML output (length is undefined - multiple frames meta data might be output) } else if (mode == 0) { // open the XML output (length is undefined - multiple frames meta data might be output)
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-Type: text/xml\r\n"); printf("Content-Type: text/xml\r\n");
...@@ -599,18 +511,17 @@ int metaXML(struct file_set *fset, int mode) /// mode: 0 - new (send headers ...@@ -599,18 +511,17 @@ int metaXML(struct file_set *fset, int mode) /// mode: 0 - new (send headers
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 pointer 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
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" \
...@@ -631,24 +542,24 @@ int metaXML(struct file_set *fset, int mode) /// mode: 0 - new (send headers ...@@ -631,24 +542,24 @@ int metaXML(struct file_set *fset, int mode) /// mode: 0 - new (send headers
, (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, fset); printExifXML(frame_params.meta_index, fset);
printf ("</Exif>\n"); printf ("</Exif>\n");
...@@ -657,6 +568,10 @@ int metaXML(struct file_set *fset, int mode) /// mode: 0 - new (send headers ...@@ -657,6 +568,10 @@ int metaXML(struct file_set *fset, int mode) /// mode: 0 - new (send headers
return 0; return 0;
} }
/**
* @brief Read current frame number from frame parameters buffer
* @return frame number
*/
unsigned long getCurrentFrameNumber() unsigned long getCurrentFrameNumber()
{ {
const char ctlFileName[] = "/dev/frameparsall"; const char ctlFileName[] = "/dev/frameparsall";
...@@ -667,15 +582,24 @@ unsigned long getCurrentFrameNumber() ...@@ -667,15 +582,24 @@ unsigned long getCurrentFrameNumber()
return frame_number; return frame_number;
} }
/**
* @brief Wait for the next frame to be captured
* @return None
*/
void waitFrameSync() void waitFrameSync()
{ {
const char ctlFileName[] = "/dev/frameparsall"; const char ctlFileName[] = "/dev/frameparsall";
int fd_fparmsall = open(ctlFileName, O_RDWR); int fd_fparmsall = open(ctlFileName, O_RDWR);
lseek(fd_fparmsall, LSEEK_FRAME_WAIT_REL + 1, SEEK_END); /// skip 1 frame before returning lseek(fd_fparmsall, LSEEK_FRAME_WAIT_REL + 1, SEEK_END); // skip 1 frame before returning
close(fd_fparmsall); close(fd_fparmsall);
} }
/**
* @brief Read circular buffer pointers and write them to @e stdout in XML format
* @param[in] fset file set for which the data should be printed
* @return 0 if data was sent successfully and -1 in case of an error
*/
int framePointersXML(struct file_set *fset) int framePointersXML(struct file_set *fset)
{ {
const char ctlFileName[] = "/dev/frameparsall"; const char ctlFileName[] = "/dev/frameparsall";
...@@ -685,7 +609,7 @@ int framePointersXML(struct file_set *fset) ...@@ -685,7 +609,7 @@ int framePointersXML(struct file_set *fset)
int nf = 0; int nf = 0;
int nfl = 0; int nfl = 0;
int buf_free, buf_used, frame_size; int buf_free, buf_used, frame_size;
int save_p; //! save current file pointer, then restore it before return int save_p; // save current file pointer, then restore it before return
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;
...@@ -701,7 +625,7 @@ int framePointersXML(struct file_set *fset) ...@@ -701,7 +625,7 @@ int framePointersXML(struct file_set *fset)
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;
...@@ -732,9 +656,9 @@ int framePointersXML(struct file_set *fset) ...@@ -732,9 +656,9 @@ int framePointersXML(struct file_set *fset)
"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)
wp = lseek(fd_circ, LSEEK_CIRC_TOWP, SEEK_END); //! set current rp pointer to FPGA write pointer wp = lseek(fd_circ, LSEEK_CIRC_TOWP, SEEK_END); // set current rp pointer to FPGA write pointer
p = wp; p = wp;
while ((p >= 0) & (nf < 500)) { while ((p >= 0) & (nf < 500)) {
if (p == rp) nfl = nf; if (p == rp) nfl = nf;
...@@ -744,11 +668,11 @@ int framePointersXML(struct file_set *fset) ...@@ -744,11 +668,11 @@ int framePointersXML(struct file_set *fset)
buf_free = GLOBALPARS(fset->port_num, G_FREECIRCBUF); buf_free = GLOBALPARS(fset->port_num, G_FREECIRCBUF);
frame_size = GLOBALPARS(fset->port_num, 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
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_used = lseek(fd_circ, LSEEK_CIRC_USED, SEEK_END); //! will change file pointer buf_used = lseek(fd_circ, LSEEK_CIRC_USED, SEEK_END); // will change file pointer
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" \
...@@ -789,6 +713,10 @@ int framePointersXML(struct file_set *fset) ...@@ -789,6 +713,10 @@ int framePointersXML(struct file_set *fset)
return 0; return 0;
} }
/**
* @brief Send 1x1 pixel GIF file as indication of an error
* @return this function always returns 0
*/
int out1x1gif(void) int out1x1gif(void)
{ {
char s[] = "HTTP/1.0 200 OK\r\n" \ char s[] = "HTTP/1.0 200 OK\r\n" \
...@@ -800,10 +728,15 @@ int out1x1gif(void) ...@@ -800,10 +728,15 @@ int out1x1gif(void)
"\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
} }
/**
* @brief Print error message to @e stdout in XML format
* @param[in] msg error message string
* @return None
*/
void errorMsgXML(char * msg) void errorMsgXML(char * msg)
{ {
char s[1024]; char s[1024];
...@@ -822,11 +755,18 @@ void errorMsgXML(char * msg) ...@@ -822,11 +755,18 @@ void errorMsgXML(char * msg)
printf(s); printf(s);
} }
/**
* @brief Read, prepare and send single image file
//! read pointer in fd_circ should be at the start of the frame to be sent *
//! mmap will be opened in this function * This function reads image file data from circular buffer, JPEG header data from
* JPEG header buffer and optionally Exif data from Exif buffer and then sends
* prepared JPEG file to @e stdout
* @param[in] fset file set for which the data should be obtained
* @param[in] bufferImageData write image data to buffer before sending
* @param[in] use_Exif flag indicating that Exif should be used
* @param[in] saveImage open file save dialog in web browser
* @return 0 if file was successfully sent and negative error code otherwise
*/
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)
{ {
int exifDataSize = 0; int exifDataSize = 0;
...@@ -860,13 +800,13 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -860,13 +800,13 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
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 */
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;
...@@ -886,7 +826,7 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -886,7 +826,7 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
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(fset->exif_dev_name, 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", fset->exif_dev_name); fprintf(stderr, "Error opening %s\n", fset->exif_dev_name);
...@@ -900,9 +840,9 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -900,9 +840,9 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
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 pointers 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;
...@@ -914,7 +854,7 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -914,7 +854,7 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
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);
...@@ -939,18 +879,18 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -939,18 +879,18 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
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
case COLORMODE_JP4HDR: //! jp4, 4 blocks, differential HDR: red := (R-G1), blue:=(B-G1), green=G1, green2 (high gain)=G2) (G1 and G2 - diagonally opposite) case COLORMODE_JP4HDR: // jp4, 4 blocks, differential HDR: red := (R-G1), blue:=(B-G1), green=G1, green2 (high gain)=G2) (G1 and G2 - diagonally opposite)
case COLORMODE_JP4DIFF2: //! jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2 case COLORMODE_JP4DIFF2: // jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2
case COLORMODE_JP4HDR2: //! jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2), case COLORMODE_JP4HDR2: // jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2),
mime_type = "jp4"; mime_type = "jp4";
extension = "jp4"; extension = "jp4";
break; break;
...@@ -975,24 +915,23 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -975,24 +915,23 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
#define COLORMODE_JP4DIFF2 9 // jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2 #define COLORMODE_JP4DIFF2 9 // jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2
#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 #ifdef ELPHEL_DEBUG_THIS
unsigned long start_time, end_time; unsigned long start_time, end_time;
start_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END); start_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END);
#endif #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;
memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[0], jpeg_len - (buff_size - jpeg_start)); memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[0], jpeg_len - (buff_size - jpeg_start));
} 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 #ifdef ELPHEL_DEBUG_THIS
...@@ -1003,18 +942,18 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -1003,18 +942,18 @@ 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, jpeg_full_size); sendBuffer(jpeg_copy, jpeg_full_size);
} else { /*! fast connection, no need to buffer image, so we'll try to run it faster */ } else { /* fast connection, no need to buffer image, so we'll try to run it faster */
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);
...@@ -1023,7 +962,13 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav ...@@ -1023,7 +962,13 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
return 0; return 0;
} }
/*! repeat writes to stdout until all data is sent */ /**
* @brief Send data from buffer to @e stdout. The writes are repeated until
* all data is sent.
* @param[in] buffer pointer to data buffer
* @param[in] len the length of data buffer
* @return None
*/
void sendBuffer(void * buffer, int len) void sendBuffer(void * buffer, int len)
{ {
int bytesLeft = len; int bytesLeft = len;
...@@ -1041,11 +986,17 @@ void sendBuffer(void * buffer, int len) ...@@ -1041,11 +986,17 @@ void sendBuffer(void * buffer, int len)
} }
} }
/**
* @brief Main processing function. Parent process forks into this function,
* listens to commands sent over socket and sends data back.
* @param[in] fset file set for which the data should be processed
* @return None, this function should not return
*/
void listener_loop(struct file_set *fset) void listener_loop(struct file_set *fset)
{ {
char errormsg[1024]; char errormsg[1024];
int fd_circ; int fd_circ;
int this_p; //! current frame pointer (bytes) int this_p; // current frame pointer (bytes)
int rslt; int rslt;
int buf_images = 0; int buf_images = 0;
int suggest_save_images = 0; int suggest_save_images = 0;
...@@ -1073,26 +1024,26 @@ void listener_loop(struct file_set *fset) ...@@ -1073,26 +1024,26 @@ 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';
} }
if (!cp || (strlen(cp) == 0)) { //!no url commands - probably the server url was manually entered if (!cp || (strlen(cp) == 0)) { // no url commands - probably the server url was manually entered
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(url_args)); printf("Content-Length: %d\r\n", strlen(url_args));
...@@ -1102,7 +1053,7 @@ void listener_loop(struct file_set *fset) ...@@ -1102,7 +1053,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");
...@@ -1114,7 +1065,7 @@ void listener_loop(struct file_set *fset) ...@@ -1114,7 +1065,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);
...@@ -1123,10 +1074,10 @@ void listener_loop(struct file_set *fset) ...@@ -1123,10 +1074,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");
...@@ -1144,8 +1095,8 @@ void listener_loop(struct file_set *fset) ...@@ -1144,8 +1095,8 @@ void listener_loop(struct file_set *fset)
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)) {
fprintf(stderr, "%s: processing img command\n", __func__); fprintf(stderr, "%s: processing img command\n", __func__);
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();
fprintf(stderr, "%s: no frame is available\n", __func__); fprintf(stderr, "%s: no frame is available\n", __func__);
} else { } else {
...@@ -1156,7 +1107,7 @@ void listener_loop(struct file_set *fset) ...@@ -1156,7 +1107,7 @@ void listener_loop(struct file_set *fset)
buf_images = ((strcmp(cp1, "img") == 0) || (strcmp(cp1, "simg") == 0)) ? 0 : 1; buf_images = ((strcmp(cp1, "img") == 0) || (strcmp(cp1, "simg") == 0)) ? 0 : 1;
suggest_save_images = ((strcmp(cp1, "simg") == 0) || (strcmp(cp1, "sbimg") == 0)) ? 1 : 0; suggest_save_images = ((strcmp(cp1, "simg") == 0) || (strcmp(cp1, "sbimg") == 0)) ? 1 : 0;
fprintf(stderr, "%s: sending image\n", __func__); fprintf(stderr, "%s: sending image\n", __func__);
rslt = sendImage(fset, buf_images, exif_enable, suggest_save_images); //! verify driver that file pointer did not move rslt = sendImage(fset, buf_images, exif_enable, suggest_save_images); // verify driver that file pointer did not move
} }
sent2socket = 1; sent2socket = 1;
if (rslt < 0) { if (rslt < 0) {
...@@ -1166,15 +1117,14 @@ void listener_loop(struct file_set *fset) ...@@ -1166,15 +1117,14 @@ void listener_loop(struct file_set *fset)
errorMsgXML(errormsg); errorMsgXML(errormsg);
} }
} }
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:
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);
...@@ -1188,14 +1138,14 @@ void listener_loop(struct file_set *fset) ...@@ -1188,14 +1138,14 @@ void listener_loop(struct file_set *fset)
rslt = 0; rslt = 0;
while (rslt >= 0) { while (rslt >= 0) {
printf("\r\n--ElphelMultipartJPEGBoundary\r\n"); printf("\r\n--ElphelMultipartJPEGBoundary\r\n");
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);
} }
...@@ -1203,15 +1153,15 @@ void listener_loop(struct file_set *fset) ...@@ -1203,15 +1153,15 @@ void listener_loop(struct file_set *fset)
_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(fset); //! 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(fset, (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) {
exif_enable = 0; exif_enable = 0;
} else if (strcmp(cp1, "exif") == 0) { } else if (strcmp(cp1, "exif") == 0) {
...@@ -1233,35 +1183,28 @@ void listener_loop(struct file_set *fset) ...@@ -1233,35 +1183,28 @@ void listener_loop(struct file_set *fset)
} else if (strcmp(cp1, "save") == 0) { } else if (strcmp(cp1, "save") == 0) {
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");
int fd_fpga = open("/dev/fpgaio", O_RDWR); int fd_fpga = open("/dev/fpgaio", O_RDWR);
// printf ("fd_fpga = 0x%x\n",fd_fpga);
if (fd_fpga >= 0) { if (fd_fpga >= 0) {
//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);
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);
close(fd_fpga); close(fd_fpga);
} }
} else if (strcmp(cp1, "favicon.ico") == 0) { } else if (strcmp(cp1, "favicon.ico") == 0) {
///ignore silently - for now, later make an icon? // ignore silently - for now, later make an icon?
} else { } else {
if (cp1[0] != '_') fprintf(stderr, "Unrecognized URL command: \"%s\" - ignoring\n", cp1); //!allow "&_time=..." be silently ignored - needed for javascript image reload if (cp1[0] != '_') fprintf(stderr, "Unrecognized URL command: \"%s\" - ignoring\n", cp1); // allow "&_time=..." be silently ignored - needed for javascript image reload
} }
} //!while ((cp1=strsep(&cp, "/?&"))) } // while ((cp1=strsep(&cp, "/?&")))
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(fset, 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
...@@ -1271,6 +1214,16 @@ void listener_loop(struct file_set *fset) ...@@ -1271,6 +1214,16 @@ void listener_loop(struct file_set *fset)
} // while (1) } // while (1)
} }
/**
* @brief Parse command line options
* @param[in] argc the number of command line arguments; passed from main()
* @param[in] argv array of pointers to command line arguments; passed from main()
* @param[in,out] fset array of #file_set structures; this function will set port
* numbers in the structures
* @param[in] fset_sz the number of elements in @e fset
* @return 0 if command line options were successfully processed and
* -1 in case of an error
*/
int parse_cmd_line(int argc, const char *argv[], struct file_set *fset, int fset_sz) int parse_cmd_line(int argc, const char *argv[], struct file_set *fset, int fset_sz)
{ {
int port; int port;
...@@ -1313,6 +1266,12 @@ int parse_cmd_line(int argc, const char *argv[], struct file_set *fset, int fset ...@@ -1313,6 +1266,12 @@ int parse_cmd_line(int argc, const char *argv[], struct file_set *fset, int fset
return 0; return 0;
} }
/**
* @brief Initialize a file set with predefined values
* @param[in,out] fset file set which should be initialized
* @param[in] fset_sz the number of elements in @e fset
* @return None
*/
void init_file_set(struct file_set *fset, int fset_sz) void init_file_set(struct file_set *fset, int fset_sz)
{ {
for (int i = 0; i < fset_sz; i++) { for (int i = 0; i < fset_sz; i++) {
...@@ -1328,7 +1287,10 @@ void init_file_set(struct file_set *fset, int fset_sz) ...@@ -1328,7 +1287,10 @@ void init_file_set(struct file_set *fset, int fset_sz)
} }
} }
/*! set port, start listening/answering HTTP requests */ /**
* @brief Set port numbers, fork a separate process for each sensor port and
* start listening/answering HTTP requests
*/
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int res = 0; int res = 0;
...@@ -1348,7 +1310,7 @@ int main(int argc, char *argv[]) ...@@ -1348,7 +1310,7 @@ int main(int argc, char *argv[])
for (int i = 0; i < SENSOR_PORTS; 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);
} }
} }
......
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