Commit 6393936e authored by Mikhail Karpenko's avatar Mikhail Karpenko
Browse files

Add PageNumber field to Exif and process it

This field corresponds to sensor port number
parent 11711b85
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -29,8 +29,8 @@
							</tool>
							</tool>
							<tool id="org.eclipse.cdt.build.core.settings.holder.176385540" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
							<tool id="org.eclipse.cdt.build.core.settings.holder.176385540" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
								<option id="org.eclipse.cdt.build.core.settings.holder.incpaths.1931881995" name="Include Paths" 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/sysroots/elphel393/usr/include}&quot;"/>
									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/linux-elphel/linux/source/include/elphel}&quot;"/>
									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/linux-elphel/linux/source/include/elphel}&quot;"/>
									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/linux-elphel/sysroots/elphel393/usr/include}&quot;"/>
								</option>
								</option>
								<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1408747788" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
								<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1408747788" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
							</tool>
							</tool>
+1 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@
   <HostComputer tag="0x013c" format="ASCII" function="SERIAL"/>
   <HostComputer tag="0x013c" format="ASCII" function="SERIAL"/>
   <FrameNumber  tag="0x83bb" format="LONG" count="1"  seq="25" dlen="4"/>
   <FrameNumber  tag="0x83bb" format="LONG" count="1"  seq="25" dlen="4"/>
   <Orientation  tag="0x112"  format="SHORT" count="1"  seq="27" dlen="2"/>
   <Orientation  tag="0x112"  format="SHORT" count="1"  seq="27" dlen="2"/>
   <PageNumber   tag="0x129"  format="SHORT" count="1"  seq="28" dlen="2"/>
   <ExifTag tag="0x8769" format="LONG" function="EXIFTAG"/>
   <ExifTag tag="0x8769" format="LONG" function="EXIFTAG"/>
   <GPSTag tag="0x08825" format="LONG" function="GPSTAG"/>
   <GPSTag tag="0x08825" format="LONG" function="GPSTAG"/>
 </Image>
 </Image>
+498 −517
Original line number Original line Diff line number Diff line
@@ -185,46 +185,41 @@
#define D(x)
#define D(x)
#endif
#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
// 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 JPEG_HEADER_MAXSIZE       0x300 // will not change

#define TRAILER_SIZE              0x02
#define TRAILER_SIZE              0x02
#define MAP_OPTIONS MAP_FILE | MAP_PRIVATE
/** @brief the length of MakerNote buffer in @e long */
//#define GLOBALPARS(x) globalPars[(x)-FRAMEPAR_GLOBALS] // should work in drivers and application
#define MAKERNOTE_LEN             16

#define IMAGE_CHN_NUM 4


struct file_set {
struct file_set {
	unsigned short port_num;
	unsigned short port_num;
	unsigned char  sensor_num;
	const char     *cirbuf_fn;
	const char     *cirbuf_fn;
	int            circbuf_fd;
	int            circbuf_fd;
	const char     *jphead_fn;
	const char     *jphead_fn;
	int            jphead_fd;
	int            jphead_fd;
	const char     *exif_dev_name;
	int            exif_dev_fd;
	const char     *exifmeta_dev_name;
	int            exifmeta_dev_fd;
};
};
static struct file_set  files[IMAGE_CHN_NUM];
static struct file_set  files[SENSOR_PORTS];


unsigned long * ccam_dma_buf;           /* mmapped array */
unsigned long * ccam_dma_buf;           /* mmapped array */

char trailer[TRAILER_SIZE] = { 0xff, 0xd9 };
char trailer[TRAILER_SIZE] = { 0xff, 0xd9 };

const char *circbuf_fnames[] = {
const char *circbuf_fnames[] = {
		"/dev/circbuf0",
		"/dev/circbuf0",
		"/dev/circbuf1",
		"/dev/circbuf1",
		"/dev/circbuf2",
		"/dev/circbuf2",
		"/dev/circbuf3"
		"/dev/circbuf3"
};
};

const char *jhead_fnames[] = {
const char *jhead_fnames[] = {
		"/dev/jpeghead0",
		"/dev/jpeghead0",
		"/dev/jpeghead1",
		"/dev/jpeghead1",
		"/dev/jpeghead2",
		"/dev/jpeghead2",
		"/dev/jpeghead3",
		"/dev/jpeghead3",
};
};
static const char *exif_dev_names[SENSOR_PORTS] = { EXIF_DEV_NAMES };
static const char *exifmeta_dev_names[SENSOR_PORTS] = { EXIFMETA_DEV_NAMES };


const char app_args[] = "Usage:\n%s -p <port_number_1> [<port_number_2> <port_number_3> <port_number_4>]\n" \
const char app_args[] = "Usage:\n%s -p <port_number_1> [<port_number_2> <port_number_3> <port_number_4>]\n" \
		"Start image server, bind it to ports <port_number_1> <port_number_2> <port_number_3> <port_number_4>\n" \
		"Start image server, bind it to ports <port_number_1> <port_number_2> <port_number_3> <port_number_4>\n" \
@@ -262,22 +257,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"
		"         In this special mode autoexposure/white balance will not work in most cases,\n"
		"         camera should be set in triggered mode (TRIG=4), internal (TRIG_CONDITION=0).\n"
		"         camera should be set in triggered mode (TRIG=4), internal (TRIG_CONDITION=0).\n"
		"         No effect on free-running or \"slave\" cameras, so it is OK to send it to all.";
		"         No effect on free-running or \"slave\" cameras, so it is OK to send it to all.";
//int  sendImage(int bufferImageData, int fd_circ, int use_Exif);

//int  sendImage(int bufferImageData, int fd_circ, int use_Exif, int saveImage);
int  sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int saveImage);
void sendBuffer(void * buffer, int len);
void sendBuffer(void * buffer, int len);
//void listener_loop(int port, const char *circbuf_fname);
void listener_loop(struct file_set *fset);
void errorMsgXML(char * msg);
void errorMsgXML(char * msg);
int  framePointersXML(int fd_circ);
int  framePointersXML(struct file_set *fset);
int  metaXML(int fd_circ, int mode); ///  mode: 0 - new (send headers), 1 - continue, 2 - finish
int  metaXML(struct file_set *fset, int mode); ///  mode: 0 - new (send headers), 1 - continue, 2 - finish
int  printExifXML(int exif_page);
int  printExifXML(int exif_page, struct file_set *fset);

int  out1x1gif(void);
int  out1x1gif(void);
void waitFrameSync();
void waitFrameSync();
unsigned long  getCurrentFrameNumber();
unsigned long  getCurrentFrameNumber();



#define saferead255(f, d, l) read(f, d, ((l) < 256) ? (l) : 255)
#define saferead255(f, d, l) read(f, d, ((l) < 256) ? (l) : 255)
int printExifXML(int exif_page)
int printExifXML(int exif_page, struct file_set *fset)
{
{
	int indx;
	int indx;
	long numfields = 0;
	long numfields = 0;
@@ -317,6 +310,7 @@ int printExifXML(int exif_page)
		case Exif_GPSInfo_CompassPitch:        indx = Exif_GPSInfo_CompassPitch_Index; break;
		case Exif_GPSInfo_CompassPitch:        indx = Exif_GPSInfo_CompassPitch_Index; break;
		case Exif_GPSInfo_CompassRollRef:      indx = Exif_GPSInfo_CompassRollRef_Index; break;
		case Exif_GPSInfo_CompassRollRef:      indx = Exif_GPSInfo_CompassRollRef_Index; break;
		case Exif_GPSInfo_CompassRoll:         indx = Exif_GPSInfo_CompassRoll_Index; break;
		case Exif_GPSInfo_CompassRoll:         indx = Exif_GPSInfo_CompassRoll_Index; break;
		case Exif_Image_PageNumber:            indx = Exif_Image_PageNumber_Index; break;
		default: indx = -1;
		default: indx = -1;
		}
		}
		if (indx >= 0) {
		if (indx >= 0) {
@@ -325,21 +319,22 @@ int printExifXML(int exif_page)
		}
		}
	}
	}
	close(fd_exifdir);
	close(fd_exifdir);
/// Create XML files iteslf


	/// Create XML files itself
	long rational3[6];
	long rational3[6];
	long makerNote[14];
	long makerNote[MAKERNOTE_LEN];
	long exif_page_start;
	long exif_page_start;
	char val[256];
	char val[256];
	int hours = 0, minutes = 0;
	int hours = 0, minutes = 0;
	double seconds = 0.0;
	double seconds = 0.0;
	double longitude = 0.0, latitude = 0.0,  altitude = 0.0,  heading = 0.0,  roll = 0.0, pitch = 0.0, exposure = 0.0;
	double longitude = 0.0, latitude = 0.0,  altitude = 0.0,  heading = 0.0,  roll = 0.0, pitch = 0.0, exposure = 0.0;
	val[255] = '\0';
	val[255] = '\0';
	int fd_exif = open(EXIF_DEV_NAME, O_RDONLY);
	int fd_exif = open(fset->exif_dev_name, O_RDONLY);
	if (fd_exif < 0) {
	if (fd_exif < 0) {
		printf("<error>\"Opening %s\"</error>\n", EXIF_DEV_NAME);
		printf("<error>\"Opening %s\"</error>\n", fset->exif_dev_name);
		return -3;
		return -3;
	}
	}
	fset->exif_dev_fd = fd_exif;
	exif_page_start = lseek(fd_exif, exif_page, SEEK_END); /// select specified Exif page
	exif_page_start = lseek(fd_exif, exif_page, SEEK_END); /// select specified Exif page
	if (exif_page_start < 0) {
	if (exif_page_start < 0) {
		printf("<error>\"Exif page (%d) is out of range\"</error>\n", exif_page);
		printf("<error>\"Exif page (%d) is out of range\"</error>\n", exif_page);
@@ -364,7 +359,7 @@ int printExifXML(int exif_page)
		printf("<FrameNumber>\"%s\"</FrameNumber>\n", val);
		printf("<FrameNumber>\"%s\"</FrameNumber>\n", val);
	}
	}


///Exif_Image_Orientation_Index           0x15
	///Exif_Image_Orientation_Index           0x14
	if (exif_dir[Exif_Image_Orientation_Index].ltag == Exif_Image_Orientation) { // Exif_Image_Orientation_Index is present in template
	if (exif_dir[Exif_Image_Orientation_Index].ltag == Exif_Image_Orientation) { // Exif_Image_Orientation_Index is present in template
		lseek(fd_exif,
		lseek(fd_exif,
				exif_page_start + exif_dir[Exif_Image_Orientation_Index].dst,
				exif_page_start + exif_dir[Exif_Image_Orientation_Index].dst,
@@ -375,6 +370,17 @@ int printExifXML(int exif_page)
		printf("<Orientation>\"%s\"</Orientation>\n", val);
		printf("<Orientation>\"%s\"</Orientation>\n", val);
	}
	}


	// 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)
	///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,
@@ -430,7 +436,6 @@ int printExifXML(int exif_page)
		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,
@@ -440,6 +445,7 @@ int printExifXML(int exif_page)
		val[1] = '\0';
		val[1] = '\0';
		printf("<GPSMeasureMode>\"%s\"</GPSMeasureMode>\n", val);
		printf("<GPSMeasureMode>\"%s\"</GPSMeasureMode>\n", val);
	}
	}

	///GPS date/time
	///GPS date/time
	if (exif_dir[Exif_GPSInfo_GPSDateStamp_Index].ltag == Exif_GPSInfo_GPSDateStamp) {
	if (exif_dir[Exif_GPSInfo_GPSDateStamp_Index].ltag == Exif_GPSInfo_GPSDateStamp) {
		lseek(fd_exif,
		lseek(fd_exif,
@@ -565,13 +571,12 @@ int printExifXML(int exif_page)
	return 0;
	return 0;
}
}



int  metaXML(struct file_set *fset, int mode)   ///  mode: 0 - new (send headers), 1 - continue, 2 - finish

int  metaXML(int fd_circ, int mode)   ///  mode: 0 - new (send headers), 1 - continue, 2 - finish
{
{
	int frameParamPointer = 0;
	int frameParamPointer = 0;
	struct interframe_params_t frame_params;
	struct interframe_params_t frame_params;
	int jpeg_len, jpeg_start, buff_size, timestamp_start;
	int jpeg_len, jpeg_start, buff_size, timestamp_start;
	int fd_circ = fset->circbuf_fd;


	if (mode == 2) { /// just close the xml file
	if (mode == 2) { /// just close the xml file
		printf("</meta>\n");
		printf("</meta>\n");
@@ -644,7 +649,7 @@ int metaXML(int fd_circ, int mode) /// mode: 0 - new (send headers), 1 - con
	} else {
	} else {
		///Put Exif data here
		///Put Exif data here
		printf ("<Exif>\n");
		printf ("<Exif>\n");
     printExifXML(frame_params.meta_index);
		printExifXML(frame_params.meta_index, fset);
		printf ("</Exif>\n");
		printf ("</Exif>\n");
	}
	}
	printf ("</frame>\n");
	printf ("</frame>\n");
@@ -670,7 +675,7 @@ void waitFrameSync()
	close(fd_fparmsall);
	close(fd_fparmsall);
}
}


int framePointersXML(int fd_circ)
int framePointersXML(struct file_set *fset)
{
{
	const char ctlFileName[] = "/dev/frameparsall";
	const char ctlFileName[] = "/dev/frameparsall";
	int fd_fparmsall;
	int fd_fparmsall;
@@ -683,10 +688,10 @@ int framePointersXML(int fd_circ)
	int frame8, frame_number, sensor_state, compressor_state;
	int frame8, frame_number, sensor_state, compressor_state;
	char *cp_sensor_state, *cp_compressor_state;
	char *cp_sensor_state, *cp_compressor_state;


	struct framepars_all_t   *frameParsAll;
	struct framepars_all_t   **frameParsAll;
	struct framepars_t       *framePars;
	struct framepars_t       *aframePars[SENSOR_PORTS];
	unsigned long            *globalPars;
	unsigned long            *aglobalPars[SENSOR_PORTS];

	int fd_circ = fset->circbuf_fd;


	fd_fparmsall = open(ctlFileName, O_RDWR);
	fd_fparmsall = open(ctlFileName, O_RDWR);
	if (fd_fparmsall < 0) { // check control OK
	if (fd_fparmsall < 0) { // check control OK
@@ -696,7 +701,7 @@ int framePointersXML(int fd_circ)
	}
	}


	//! now try to mmap
	//! now try to mmap
	frameParsAll = (struct framepars_all_t*)mmap(0, sizeof(struct framepars_all_t), PROT_READ, MAP_SHARED, fd_fparmsall, 0);
	frameParsAll = (struct framepars_all_t**)mmap(0, sizeof(struct framepars_all_t), PROT_READ, MAP_SHARED, fd_fparmsall, 0);
	if ((int)frameParsAll == -1) {
	if ((int)frameParsAll == -1) {
		frameParsAll = NULL;
		frameParsAll = NULL;
		printf("Error in mmap /dev/frameparsall");
		printf("Error in mmap /dev/frameparsall");
@@ -705,15 +710,16 @@ int framePointersXML(int fd_circ)
		fd_fparmsall = -1;
		fd_fparmsall = -1;
		return -1;
		return -1;
	}
	}
	framePars = frameParsAll->framePars;
	for (int j = 0; j < SENSOR_PORTS; j++) {
	globalPars = frameParsAll->globalPars;
		aframePars[j] = frameParsAll[j]->framePars;
		aglobalPars[j] = frameParsAll[j]->globalPars;
	}


	// Read current sensor state - defined in c313a.h
	// Read current sensor state - defined in c313a.h
	frame_number = lseek(fd_fparmsall, 0, SEEK_CUR );
	frame_number = lseek(fd_fparmsall, 0, SEEK_CUR );
	frame8 = frame_number & PARS_FRAMES_MASK;
	frame8 = frame_number & PARS_FRAMES_MASK;
//    printf ("Current frame number is %d\n",frame_number);
	sensor_state = aframePars[fset->port_num][frame8].pars[P_SENSOR_RUN];
	sensor_state = framePars[frame8].pars[P_SENSOR_RUN];
	compressor_state = aframePars[fset->port_num][frame8].pars[P_COMPRESSOR_RUN];
	compressor_state = framePars[frame8].pars[P_COMPRESSOR_RUN];
	cp_sensor_state =     (sensor_state == 0) ?
	cp_sensor_state =     (sensor_state == 0) ?
			"SENSOR_RUN_STOP" :
			"SENSOR_RUN_STOP" :
			((sensor_state == 1) ?
			((sensor_state == 1) ?
@@ -734,8 +740,8 @@ int framePointersXML(int fd_circ)
		p = lseek(fd_circ, LSEEK_CIRC_PREV, SEEK_END);
		p = lseek(fd_circ, LSEEK_CIRC_PREV, SEEK_END);
		nf++;
		nf++;
	}
	}
	buf_free = GLOBALPARS(G_FREECIRCBUF);
	buf_free = GLOBALPARS(fset->port_num, G_FREECIRCBUF);
	frame_size = GLOBALPARS(G_FRAME_SIZE);
	frame_size = GLOBALPARS(fset->port_num, G_FRAME_SIZE);


	lseek(fd_circ, save_p, SEEK_SET);                       //! restore file pointer after temporarily moving it
	lseek(fd_circ, save_p, SEEK_SET);                       //! restore file pointer after temporarily moving it
	buf_free = lseek(fd_circ, LSEEK_CIRC_FREE, SEEK_END);   //! will change file pointer
	buf_free = lseek(fd_circ, LSEEK_CIRC_FREE, SEEK_END);   //! will change file pointer
@@ -775,12 +781,13 @@ int framePointersXML(int fd_circ)
	printf("Pragma: no-cache\r\n");
	printf("Pragma: no-cache\r\n");
	printf("\r\n");
	printf("\r\n");
	printf(s);
	printf(s);
//! No need to unmap?

	munmap(frameParsAll, sizeof(struct framepars_all_t));
	close(fd_fparmsall);
	close(fd_fparmsall);
	D(fprintf(stderr, ">%s< [%d bytes]\n", s, strlen(s)));
	D(fprintf(stderr, ">%s< [%d bytes]\n", s, strlen(s)));
	return 0;
	return 0;
}
}
//fwrite (&cbuffer[offset],1,bytesLeft,stdout);

int out1x1gif(void)
int out1x1gif(void)
{
{
	char s[] = "HTTP/1.0 200 OK\r\n" \
	char s[] = "HTTP/1.0 200 OK\r\n" \
@@ -798,7 +805,7 @@ int out1x1gif(void)


void errorMsgXML(char * msg)
void errorMsgXML(char * msg)
{
{
	char s[1024]; // was 701 acrtually
	char s[1024];


	sprintf(s, "<?xml version=\"1.0\"?>\n" \
	sprintf(s, "<?xml version=\"1.0\"?>\n" \
			"<frame_params>\n" \
			"<frame_params>\n" \
@@ -821,13 +828,9 @@ void errorMsgXML(char * msg)


int  sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int saveImage)
int  sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int saveImage)
{
{
	//const char HeadFileName[] = "/dev/jpeghead0";
	const char ExifFileName[] = "/dev/exif_exif";
	int exifDataSize = 0;
	int exifDataSize = 0;
///   int  exifIndexPointer=0;
	int frameParamPointer = 0;
	int frameParamPointer = 0;
	struct interframe_params_t frame_params;
	struct interframe_params_t frame_params;
///   struct frame_exif_t frame_exif; //just 8 bytes
	int buff_size;
	int buff_size;
	int jpeg_len;   // bytes
	int jpeg_len;   // bytes
	int jpeg_start; // bytes
	int jpeg_start; // bytes
@@ -841,7 +844,6 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
	char * mime_type;
	char * mime_type;
	char * extension;
	char * extension;


///   int metadata_start; //metadata pointer (in bytes, from the start of the ccam_dma_buf)
	jpeg_start = lseek(fset->circbuf_fd, 0, SEEK_CUR);     //get the current read pointer
	jpeg_start = lseek(fset->circbuf_fd, 0, SEEK_CUR);     //get the current read pointer
	D(fprintf(stderr, "jpeg_start (long) = 0x%x\n", jpeg_start));
	D(fprintf(stderr, "jpeg_start (long) = 0x%x\n", jpeg_start));
	fd_head = open(fset->jphead_fn, O_RDWR);
	fd_head = open(fset->jphead_fn, O_RDWR);
@@ -850,7 +852,7 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
		return -1;
		return -1;
	}
	}
	fset->jphead_fd = fd_head;
	fset->jphead_fd = fd_head;
	lseek(fd_head, jpeg_start + 1, SEEK_END); /// create JPEG header, find out it's size TODO:
	lseek(fd_head, jpeg_start + 1, SEEK_END);              // create JPEG header, find out it's size
	head_size = lseek(fd_head, 0, SEEK_END);
	head_size = lseek(fd_head, 0, SEEK_END);
	if (head_size > JPEG_HEADER_MAXSIZE) {
	if (head_size > JPEG_HEADER_MAXSIZE) {
		fprintf(stderr, "%s:%d: Too big JPEG header (%d > %d)", __FILE__, __LINE__, head_size, JPEG_HEADER_MAXSIZE );
		fprintf(stderr, "%s:%d: Too big JPEG header (%d > %d)", __FILE__, __LINE__, head_size, JPEG_HEADER_MAXSIZE );
@@ -864,7 +866,6 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
	D(fprintf(stderr, "position (longs) = 0x%x\n", (int)lseek(fset->circbuf_fd, 0, SEEK_CUR)));
	D(fprintf(stderr, "position (longs) = 0x%x\n", (int)lseek(fset->circbuf_fd, 0, SEEK_CUR)));


	/*! now let's try mmap itself */
	/*! now let's try mmap itself */
///   exifIndexPointer=jpeg_start-8;
	frameParamPointer = jpeg_start - sizeof(struct interframe_params_t) + 4;
	frameParamPointer = jpeg_start - sizeof(struct interframe_params_t) + 4;
	if (frameParamPointer < 0)
	if (frameParamPointer < 0)
		frameParamPointer += buff_size;
		frameParamPointer += buff_size;
@@ -875,17 +876,19 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
	color_mode = frame_params.color;
	color_mode = frame_params.color;
	if (frame_params.signffff != 0xffff) {
	if (frame_params.signffff != 0xffff) {
		fprintf(stderr, "wrong signature signff = 0x%x \n", (int)frame_params.signffff);
		fprintf(stderr, "wrong signature signff = 0x%x \n", (int)frame_params.signffff);
#ifdef ELPHEL_DEBUG_THIS
		lseek(fset->circbuf_fd, LSEEK_CIRC_STOP_COMPRESSOR, SEEK_END);
		lseek(fset->circbuf_fd, LSEEK_CIRC_STOP_COMPRESSOR, SEEK_END);
#endif
		close(fd_head);
		close(fd_head);
		return -4;
		return -4;
	}
	}


	if (use_Exif) {
	if (use_Exif) {
		//D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
		D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
		/// read Exif to buffer:
		/// read Exif to buffer:
		fd_exif = open(ExifFileName, O_RDONLY);
		fd_exif = open(fset->exif_dev_name, O_RDONLY);
		if (fd_exif < 0) {                                 // check control OK
		if (fd_exif < 0) {                                 // check control OK
			fprintf(stderr, "Error opening %s\n", ExifFileName);
			fprintf(stderr, "Error opening %s\n", fset->exif_dev_name);
			close(fd_head);
			close(fd_head);
			return -5;
			return -5;
		}
		}
@@ -893,7 +896,7 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
		if (exifDataSize < 0) exifDataSize = 0;            // error from lseek;
		if (exifDataSize < 0) exifDataSize = 0;            // error from lseek;
		if (!exifDataSize) close(fd_exif);
		if (!exifDataSize) close(fd_exif);
	} else {
	} else {
		//frame_params.meta_index=0;
		frame_params.meta_index=0;
		fd_exif = -1;
		fd_exif = -1;
	}
	}
	///Maybe make buffer that will fit both Exif and JPEG?
	///Maybe make buffer that will fit both Exif and JPEG?
@@ -905,8 +908,8 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
	fprintf(stderr, "jpeg_len = 0x%x, head_size = 0x%x, exifDataSize = 0x%x, jpeg_full_size = 0x%x\n",
	fprintf(stderr, "jpeg_len = 0x%x, head_size = 0x%x, exifDataSize = 0x%x, jpeg_full_size = 0x%x\n",
			jpeg_len, head_size, exifDataSize, jpeg_full_size);
			jpeg_len, head_size, exifDataSize, jpeg_full_size);


	if (bufferImageData) jpeg_this_size = jpeg_full_size;           /// header+frame
	if (bufferImageData) jpeg_this_size = jpeg_full_size;  // header+frame
	else jpeg_this_size = head_size + exifDataSize;                 /// only header
	else jpeg_this_size = head_size + exifDataSize;        // only header
	jpeg_copy = malloc(jpeg_this_size);
	jpeg_copy = malloc(jpeg_this_size);
	if (!jpeg_copy) {
	if (!jpeg_copy) {
		syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__, __LINE__, jpeg_this_size);
		syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__, __LINE__, jpeg_this_size);
@@ -926,10 +929,10 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
	lseek(fd_head, 0, 0);
	lseek(fd_head, 0, 0);
	read(fd_head, &jpeg_copy[exifDataSize], head_size);
	read(fd_head, &jpeg_copy[exifDataSize], head_size);
	close(fd_head);
	close(fd_head);
	if (exifDataSize > 0) {                                 //! insert Exif
	if (exifDataSize > 0) {                                // insert Exif
		memcpy(jpeg_copy, &jpeg_copy[exifDataSize], 2); //! copy first 2 bytes of the JFIF header before Exif
		memcpy(jpeg_copy, &jpeg_copy[exifDataSize], 2);    // copy first 2 bytes of the JFIF header before Exif
		//lseek(fd_exif,frame_params.meta_index,SEEK_END); //! select meta page to use (matching frame)
		lseek(fd_exif,frame_params.meta_index,SEEK_END);   // select meta page to use (matching frame)
		read(fd_exif, &jpeg_copy[2], exifDataSize);     //! Insert Exif itself
		read(fd_exif, &jpeg_copy[2], exifDataSize);        // Insert Exif itself
		close(fd_exif);
		close(fd_exif);
	}
	}
	switch (color_mode) {
	switch (color_mode) {
@@ -978,28 +981,10 @@ 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
	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) */
		// tell driver to flush CPU caches
#ifdef ELPHEL_DEBUG_THIS
		const char *fname = "/sys/devices/soc0/elphel393-mem@0/flush_cpu_cache";
		char cmd[128] = {0};
		int jpeg_end;
		int cmd_len;
//		int fd_sys = open(fname, O_RDWR);
		unsigned long start_time, end_time;
		unsigned long start_time, end_time;

//		if (fd_sys < 0) {
//			fprintf(stderr, "unable to open sysfs entry: %s\n", fname);
//		} else {
////			jpeg_end = jpeg_start + jpeg_len;
//			jpeg_end = jpeg_start + (sizeof(struct interframe_params_t) - 4) * 512;
//			if (jpeg_end > buff_size)
//				jpeg_end -= buff_size;
//			cmd_len = snprintf(cmd, 127, "%u:%d:%d", fset->sensor_num, jpeg_start, jpeg_end);
//			if (write(fd_sys, cmd, cmd_len) == -1)
//				fprintf(stderr, "failed to write to sysfs\n");
//			close(fd_sys);
//		}

		start_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END);
		start_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END);
#endif
		l = head_size + exifDataSize;
		l = head_size + exifDataSize;
		/*! JPEG image data may be split in two segments (rolled over buffer end) - process both variants */
		/*! JPEG image data may be split in two segments (rolled over buffer end) - process both variants */
		if ((jpeg_start + jpeg_len) > buff_size) { // two segments
		if ((jpeg_start + jpeg_len) > buff_size) { // two segments
@@ -1009,9 +994,10 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
		} else { /*! single segment */
		} else { /*! single segment */
			memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], jpeg_len);
			memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], jpeg_len);
		}
		}
#ifdef ELPHEL_DEBUG_THIS
		end_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END);
		end_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END);
		fprintf(stderr, "memcpy time = %lu\n", end_time - start_time);
		D(fprintf(stderr, "memcpy time = %lu\n", end_time - start_time));

#endif
		memcpy(&jpeg_copy[jpeg_len + head_size + exifDataSize], trailer, 2);
		memcpy(&jpeg_copy[jpeg_len + head_size + exifDataSize], trailer, 2);
		printf("Content-Length: %d\r\n", jpeg_full_size);
		printf("Content-Length: %d\r\n", jpeg_full_size);
		printf("\r\n");
		printf("\r\n");
@@ -1034,10 +1020,8 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
	}
	}
	free(jpeg_copy);
	free(jpeg_copy);
	return 0;
	return 0;

}
}



/*! repeat writes to stdout until all data is sent */
/*! repeat writes to stdout until all data is sent */
void sendBuffer(void * buffer, int len)
void sendBuffer(void * buffer, int len)
{
{
@@ -1056,13 +1040,9 @@ void sendBuffer(void * buffer, int len)
	}
	}
}
}





void listener_loop(struct file_set *fset)
void listener_loop(struct file_set *fset)
{
{
	char errormsg[1024];
	char errormsg[1024];
	//const char circbufFileName[] = "/dev/circbuf0";
	int fd_circ;
	int fd_circ;
	int this_p; //! current frame pointer (bytes)
	int this_p; //! current frame pointer (bytes)
	int rslt;
	int rslt;
@@ -1156,11 +1136,9 @@ void listener_loop(struct file_set *fset)
			}
			}
			this_p = lseek(fd_circ, LSEEK_CIRC_LAST, SEEK_END);
			this_p = lseek(fd_circ, LSEEK_CIRC_LAST, SEEK_END);
			D(fprintf(stderr, "%s: current frame pointer this_p (in bytes): 0x%x\n", __func__, this_p));
			D(fprintf(stderr, "%s: current frame pointer this_p (in bytes): 0x%x\n", __func__, this_p));
//!continue with iterating through the commands
			// continue with iterating through the commands
			while ((cp1 = strsep(&cp, "/?&"))) {
			while ((cp1 = strsep(&cp, "/?&"))) {
//     printf ("1->%s", cp1);
				// if the first character is a digit, it is a file pointer
//     fprintf (stderr, "1->%s",cp1);
//!if the first caracter is digit,it is a file pointer
				if (strchr("0123456789", cp1[0])) {
				if (strchr("0123456789", cp1[0])) {
					this_p = lseek(fd_circ, strtol(cp1, NULL, 10), SEEK_SET);
					this_p = lseek(fd_circ, strtol(cp1, NULL, 10), SEEK_SET);
				} else if ((strcmp(cp1, "img") == 0) || (strcmp(cp1, "bimg") == 0) || (strcmp(cp1, "simg") == 0) || (strcmp(cp1, "sbimg") == 0)) {
				} else if ((strcmp(cp1, "img") == 0) || (strcmp(cp1, "bimg") == 0) || (strcmp(cp1, "simg") == 0) || (strcmp(cp1, "sbimg") == 0)) {
@@ -1189,7 +1167,7 @@ void listener_loop(struct file_set *fset)
					}
					}
					fflush(stdout); //! let's not keep client waiting - anyway we've sent it all even when more commands  maybe left
					fflush(stdout); //! let's not keep client waiting - anyway we've sent it all even when more commands  maybe left


///multipart - always last
				// multipart - always last
				} else if ((strncmp(cp1, "mimg", 4) == 0) || (strncmp(cp1, "bmimg", 5) == 0) || (strncmp(cp1, "mbimg", 5) == 0)) {
				} else if ((strncmp(cp1, "mimg", 4) == 0) || (strncmp(cp1, "bmimg", 5) == 0) || (strncmp(cp1, "mbimg", 5) == 0)) {
					if (sent2socket > 0) break;                             //! image/xmldata was already sent to socket, ignore
					if (sent2socket > 0) break;                             //! image/xmldata was already sent to socket, ignore
					if (lseek(fd_circ, LSEEK_CIRC_READY, SEEK_END) < 0)     //! here passes OK, some not ready error is later, in sendimage (make it return different numbers)
					if (lseek(fd_circ, LSEEK_CIRC_READY, SEEK_END) < 0)     //! here passes OK, some not ready error is later, in sendimage (make it return different numbers)
@@ -1225,12 +1203,12 @@ void listener_loop(struct file_set *fset)
					}
					}
				} else if (strcmp(cp1, "pointers") == 0) {
				} else if (strcmp(cp1, "pointers") == 0) {
					if (sent2socket > 0) break;                             //! image/xmldata was already sent to socket, ignore
					if (sent2socket > 0) break;                             //! image/xmldata was already sent to socket, ignore
					framePointersXML(fd_circ);                              //! will restore file pointer after itself
					framePointersXML(fset);                                 //! will restore file pointer after itself
					sent2socket = 3;
					sent2socket = 3;
					fflush(stdout);                                         //! let's not keep client waiting - anyway we've sent it all even when more commands  maybe left
					fflush(stdout);                                         //! let's not keep client waiting - anyway we've sent it all even when more commands  maybe left
				} else if (strcmp(cp1, "meta") == 0) {
				} else if (strcmp(cp1, "meta") == 0) {
					if ((sent2socket > 0) && (sent2socket != 2)) break;     //! image/xmldata was already sent to socket, ignore
					if ((sent2socket > 0) && (sent2socket != 2)) break;     //! image/xmldata was already sent to socket, ignore
					metaXML(fd_circ, (sent2socket > 0) ? 1 : 0);            /// 0 - new (send headers), 1 - continue, 2 - finish
					metaXML(fset, (sent2socket > 0) ? 1 : 0);            /// 0 - new (send headers), 1 - continue, 2 - finish
					sent2socket = 2;
					sent2socket = 2;
					fflush(stdout);                                         //! let's not keep client waiting - anyway we've sent it all even when more commands  maybe left
					fflush(stdout);                                         //! let's not keep client waiting - anyway we've sent it all even when more commands  maybe left
				} else if (strcmp(cp1, "noexif") == 0) {
				} else if (strcmp(cp1, "noexif") == 0) {
@@ -1282,7 +1260,7 @@ void listener_loop(struct file_set *fset)
			if (sent2socket <= 0) { //! Nothing was sent to the client so far and the command line is over. Let's return 1x1 pixel gif
			if (sent2socket <= 0) { //! Nothing was sent to the client so far and the command line is over. Let's return 1x1 pixel gif
				out1x1gif();
				out1x1gif();
			} else if (sent2socket == 2) {
			} else if (sent2socket == 2) {
				metaXML(fd_circ, 2); /// 0 - new (send headers), 1 - continue, 2 - finish
				metaXML(fset, 2); /// 0 - new (send headers), 1 - continue, 2 - finish
			}
			}


			fflush(stdout); // probably it is not needed anymore, just in case
			fflush(stdout); // probably it is not needed anymore, just in case
@@ -1341,8 +1319,11 @@ void init_file_set(struct file_set *fset, int fset_sz)
		fset[i].circbuf_fd = -1;
		fset[i].circbuf_fd = -1;
		fset[i].jphead_fn = jhead_fnames[i];
		fset[i].jphead_fn = jhead_fnames[i];
		fset[i].jphead_fd = -1;
		fset[i].jphead_fd = -1;
		fset[i].exif_dev_name = exif_dev_names[i];
		fset[i].exif_dev_fd = -1;
		fset[i].exifmeta_dev_name = exifmeta_dev_names[i];
		fset[i].exifmeta_dev_fd = -1;
		fset[i].port_num = 0;
		fset[i].port_num = 0;
		fset[i].sensor_num = i;
	}
	}
}
}


@@ -1351,8 +1332,8 @@ int main(int argc, char *argv[])
{
{
	int res = 0;
	int res = 0;


	init_file_set(files, IMAGE_CHN_NUM);
	init_file_set(files, SENSOR_PORTS);
	res = parse_cmd_line(argc, (const char **)argv, files, IMAGE_CHN_NUM);
	res = parse_cmd_line(argc, (const char **)argv, files, SENSOR_PORTS);
	if (res < 0)
	if (res < 0)
		return EXIT_FAILURE;
		return EXIT_FAILURE;


@@ -1363,7 +1344,7 @@ int main(int argc, char *argv[])
	}
	}


	// spawn a process for each port
	// spawn a process for each port
	for (int i = 0; i < IMAGE_CHN_NUM; i++) {
	for (int i = 0; i < SENSOR_PORTS; i++) {
		if (fork() == 0) {
		if (fork() == 0) {
			listener_loop(&files[i]);
			listener_loop(&files[i]);
			_exit(0);               // should not get here?
			_exit(0);               // should not get here?