Commit 4567a7bf authored by Mikhail Karpenko's avatar Mikhail Karpenko
Browse files

Move main loop to separate function, spawn processes

parent 38f6a374
Loading
Loading
Loading
Loading
+167 −154
Original line number Original line Diff line number Diff line
@@ -145,6 +145,7 @@


/* end of debug code */
/* end of debug code */


#define COMMAND_LOOP_DELAY 500000 //0.5sec
#define DEFAULT_DEBUG_LVL 6
#define DEFAULT_DEBUG_LVL 6
#define TRAILER_SIZE   0x02
#define TRAILER_SIZE   0x02
#define MAP_OPTIONS MAP_FILE | MAP_PRIVATE
#define MAP_OPTIONS MAP_FILE | MAP_PRIVATE
@@ -194,7 +195,7 @@ camogm_state sstate[SENSOR_PORTS];
int debug_level;
int debug_level;
FILE* debug_file;
FILE* debug_file;


int camogm_init(camogm_state *state, unsigned int port);
void camogm_init(camogm_state *state, unsigned int port, char *pipe_name);
int camogm_start(camogm_state *state);
int camogm_start(camogm_state *state);
int camogm_stop(camogm_state *state);
int camogm_stop(camogm_state *state);
int camogm_reset(camogm_state *state); //! reset circbuf read pointer
int camogm_reset(camogm_state *state); //! reset circbuf read pointer
@@ -269,7 +270,14 @@ void put_uint64(void *buf, u_int64_t val)
	tmp[7] = (val >>= 8) & 0xff;
	tmp[7] = (val >>= 8) & 0xff;
}
}


int camogm_init(camogm_state *state, unsigned int port)
/**
 * @brief Initialize state for a particular sensor port.
 * @param[in]   state   pointer to #camogm_state structure for a particular sensor channel
 * @param[in]   port    sensor port number
 * @param[in]   pipe_name pointer to command pipe name string
 * @return      none
 */
void camogm_init(camogm_state *state, unsigned int port, char *pipe_name)
{
{
	const char sserial[] = "elp0";
	const char sserial[] = "elp0";
	int * ipser = (int*)sserial;
	int * ipser = (int*)sserial;
@@ -283,17 +291,17 @@ int camogm_init(camogm_state *state, unsigned int port)
	camogm_set_ignore_fps(state, DEFAULT_IGNORE_FPS);
	camogm_set_ignore_fps(state, DEFAULT_IGNORE_FPS);
	camogm_set_max_frames(state, DEFAULT_FRAMES);
	camogm_set_max_frames(state, DEFAULT_FRAMES);
	camogm_set_frames_per_chunk(state, DEFAULT_FRAMES_PER_CHUNK);
	camogm_set_frames_per_chunk(state, DEFAULT_FRAMES_PER_CHUNK);
	camogm_set_start_after_timestamp(state, 0.0); /// start any time
	camogm_set_start_after_timestamp(state, 0.0); // start any time
	camogm_set_prefix(state, "\0");
	camogm_set_prefix(state, "\0");
	camogm_set_save_gp(state, 0);
	camogm_set_save_gp(state, 0);
	camogm_reset(state); //! sets    state->buf_overruns=-1; //!first does not count
	camogm_reset(state);                    // sets state->buf_overruns =- 1
	state->serialno = ipser[0];
	state->serialno = ipser[0];
	state->last = 0;
	state->last = 0;
	debug_file = stderr;
	debug_file = stderr;
	camogm_debug_level(DEFAULT_DEBUG_LVL);
	camogm_debug_level(DEFAULT_DEBUG_LVL);
	strcpy(state->debug_name, "stderr");
	strcpy(state->debug_name, "stderr");
	camogm_set_timescale(state, 1.0);
	camogm_set_timescale(state, 1.0);
	camogm_set_frames_skip(state, 0); //! don't skip
	camogm_set_frames_skip(state, 0);       // don't skip
	camogm_set_format(state, CAMOGM_FORMAT_OGM);
	camogm_set_format(state, CAMOGM_FORMAT_OGM);
	state->exifSize = 0;
	state->exifSize = 0;
	state->exif = DEFAULT_EXIF;
	state->exif = DEFAULT_EXIF;
@@ -302,7 +310,7 @@ int camogm_init(camogm_state *state, unsigned int port)
	state->formats = 0;
	state->formats = 0;
	state->last_error_code = 0;
	state->last_error_code = 0;


///kml stuff
	// kml stuff
	camogm_kml_set_enable(state, 0);
	camogm_kml_set_enable(state, 0);
	state->kml_file = NULL;
	state->kml_file = NULL;
	camogm_kml_set_horHalfFov(state, 20.0);
	camogm_kml_set_horHalfFov(state, 20.0);
@@ -314,8 +322,7 @@ int camogm_init(camogm_state *state, unsigned int port)
	state->kml_path[0] = '\0';
	state->kml_path[0] = '\0';


	state->port_num = port;
	state->port_num = port;

	state->pipe_name = pipe_name;
	return 0;
}
}




@@ -1280,16 +1287,22 @@ int create_pipe_names(const char *pipe_name, char **names)
		names[i] = name;
		names[i] = name;
	}
	}


	if (ret < 0) {
		for (int i = 0; i < SENSOR_PORTS; i++) {
			free(names[i]);
			names[i] = NULL;
		}
	}

	return ret;
	return ret;
}
}


/**
/**
 * @brief This function closes open files and deletes allocated memory.
 * @brief This function closes open files and deletes allocated memory.
 * @param[in]   state   pointer to #camogm_state structure for a particular sensor channel
 * @param[in]   state   pointer to #camogm_state structure for a particular sensor channel
 * @param[in]   names   list of strings containing control pipe names
 * return       none
 * return       none
 */
 */
void clean_up(camogm_state *state, char **names)
void clean_up(camogm_state *state)
{
{
	if (state->fd_exif > 0)
	if (state->fd_exif > 0)
		close(state->fd_exif);
		close(state->fd_exif);
@@ -1299,177 +1312,130 @@ void clean_up(camogm_state *state, char **names)
		close(state->fd_circ);
		close(state->fd_circ);
	if (state->fd_fparmsall)
	if (state->fd_fparmsall)
		close(state->fd_fparmsall);
		close(state->fd_fparmsall);
	for (int i = 0; i < SENSOR_PORTS; i++) {
	free(state->pipe_name);
		free(names[i]);
	state->pipe_name = NULL;
		names[i] = NULL;
	}
}
}


int main(int argc, char *argv[])
/**
 * @brief Main processing loop
 *
 * If recording is on, this function will check for new commands in command pipe after each frame. If recording is
 * turn off, it will poll command pipe each #COMMAND_LOOP_DELAYS microseconds and then sleep.
 * @param[in]   state   #camogm_state structure associated with a single port
 * @return      normally this function loops indefinitely processing commands but will return negative exit code in case
 * of error and \e EXIT_SUCCESS it eventually terminates in normal way.
 */
int listener_loop(camogm_state *state)
{
{
//     int fd_circ;
	FILE *cmd_file;
	FILE *cmd_file;
	const char usage[] =   "This program allows recording of the video/images acquired by Elphel camera to the storage media.\n" \
	int rslt, ret, cmd;
			     "It is designed to run in the background and accept commands through a named pipe.\n\n" \
	int fp0, fp1;
			     "Usage:\n\n" \
	int process = 1;
			     "%s <named_pipe_name>\n\n"	\
	unsigned int port = state->port_num;
			     "i.e.:\n\n" \
	const char *pipe_name = state->pipe_name;
			     "%s /var/state/camogm_cmd\n\n" \
			     "When the program is runninig you may send commands by writing strings to the command file\n" \
			     "(/var/state/camogm_cmd in the example above). The complete list of available commands is available\n" \
			     "on Elphel Wiki (http://wiki.elphel.com/index.php?title=Camogm), here is the example of usage\n" \
			     "from the shell prompt in the camera:\n\n"	\
			     "echo \"status; exif=1; format=jpeg;status=/var/tmp/camogm.status\" > /var/state/camogm_cmd\n\n" \
			     "That will print status information on the standard output (may not be visible if the program was not\n" \
			     "started from the same session), set exif mode on (each frame will have the full Exif header including\n" \
			     "a precise time stamp), set output format to a series of individual JPEG files, and then send status\n" \
			     "information to a file /var/tmp/camogm.status in the camera file system.\n\n" \
			     "This program does not control the process of acquisition of the video/images to the camera internal\n" \
			     "buffer, it only retrieves that data from the buffer (waiting when needed), packages it to selected\n" \
			     "format and stores the result files.\n\n";
	int go = 1;
	int cmd;
	int i, rslt;
	int fp0, fp1;           // debugging
	/* debug code follows */
	unsigned int port = 2;
	/*end of debug code */
	camogm_state *state = &sstate[port];
	char *pipe_names[SENSOR_PORTS] = {0};

//	state = &sstate;        //extern
//! no command line options processing yet
	if ((argc < 2) || (argv[1][1] == '-')) {
		printf(usage, argv[0], argv[0]);
		clean_up(state, pipe_names);
		return 0;
	}
	camogm_init(state, port);
	create_pipe_names(argv[1], pipe_names);


//! open Exif header file
	// open Exif header file
#ifdef DISABLE_CODE
#ifdef DISABLE_CODE
	state->fd_exif = open(exifFileNames[port], O_RDONLY);
	state->fd_exif = open(exifFileNames[port], O_RDONLY);
	if (state->fd_exif < 0) { // check control OK
	if (state->fd_exif < 0) { // check control OK
		D0(fprintf(debug_file, "Error opening %s\n", exifFileNames[port]));
		D0(fprintf(debug_file, "Error opening %s\n", exifFileNames[port]));
		clean_up(state);
		return -1;
		return -1;
	}
	}
#endif /* DESABLE_CODE */
#endif /* DESABLE_CODE */


//! open JPEG header file
	// open JPEG header file
	state->fd_head = open(headFileNames[port], O_RDWR);
	state->fd_head = open(headFileNames[port], O_RDWR);
	if (state->fd_head < 0) { // check control OK
	if (state->fd_head < 0) { // check control OK
		D0(fprintf(debug_file, "Error opening %s\n", headFileNames[port]));
		D0(fprintf(debug_file, "Error opening %s\n", headFileNames[port]));
		clean_up(state, pipe_names);
		clean_up(state);
		return -1;
		return -1;
	}
	}
	state->head_size = lseek(state->fd_head, 0, SEEK_END);
	state->head_size = lseek(state->fd_head, 0, SEEK_END);
	if (state->head_size > JPEG_HEADER_MAXSIZE) {
	if (state->head_size > JPEG_HEADER_MAXSIZE) {
		D0(fprintf(debug_file, "%s:%d: Too big JPEG header (%d > %d)", __FILE__, __LINE__, state->head_size, JPEG_HEADER_MAXSIZE ));
		D0(fprintf(debug_file, "%s:%d: Too big JPEG header (%d > %d)", __FILE__, __LINE__, state->head_size, JPEG_HEADER_MAXSIZE ));
		clean_up(state, pipe_names);
		clean_up(state);
		return -2;
		return -2;
	}
	}


//! open circbuf and mmap it (once at startup)
	// open circbuf and mmap it (once at startup)
	state->fd_circ = open(circbufFileNames[port], O_RDWR);
	state->fd_circ = open(circbufFileNames[port], O_RDWR);
	if (state->fd_circ < 0) { // check control OK
	if (state->fd_circ < 0) { // check control OK
		D0(fprintf(debug_file, "Error opening %s\n", circbufFileNames[port]));
		D0(fprintf(debug_file, "Error opening %s\n", circbufFileNames[port]));
		clean_up(state, pipe_names);
		clean_up(state);
		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
	state->circ_buff_size = lseek(state->fd_circ, 0, SEEK_END);
	state->circ_buff_size = lseek(state->fd_circ, 0, SEEK_END);
	ccam_dma_buf[port] = (unsigned long*)mmap(0, state->circ_buff_size, PROT_READ, MAP_SHARED, state->fd_circ, 0);
	ccam_dma_buf[port] = (unsigned long*)mmap(0, state->circ_buff_size, PROT_READ, MAP_SHARED, state->fd_circ, 0);
	if ((int)ccam_dma_buf[port] == -1) {
	if ((int)ccam_dma_buf[port] == -1) {
		D0(fprintf(debug_file, "Error in mmap of %s\n", circbufFileNames[port]));
		D0(fprintf(debug_file, "Error in mmap of %s\n", circbufFileNames[port]));
		clean_up(state, pipe_names);
		clean_up(state);
		return -3;
		return -3;
	}
	}


//! Now open/mmap file to read sensor/compressor parameters (currently - just free memory in circbuf and compressor state)
	// now open/mmap file to read sensor/compressor parameters (currently - just free memory in circbuf and compressor state)

//! open circbuf and mmap it (once at startup)
#ifdef DISABLE_CODE
#ifdef DISABLE_CODE
	state->fd_fparmsall = open(ctlFileNames[port], O_RDWR);
	state->fd_fparmsall = open(ctlFileNames[port], O_RDWR);
	if (state->fd_fparmsall < 0) { // check control OK
	if (state->fd_fparmsall < 0) { // check control OK
		D0(fprintf(debug_file, "%s:%d:%s: Error opening %s\n", __FILE__, __LINE__, __FUNCTION__, ctlFileNames[port]));
		D0(fprintf(debug_file, "%s:%d:%s: Error opening %s\n", __FILE__, __LINE__, __FUNCTION__, ctlFileNames[port]));
		clean_up(state, pipe_names);
		clean_up(state);
		return -2;
		return -2;
	}
	}


//! now try to mmap
	// now try to mmap
///    frameParsAll = (struct framepars_all_t *) mmap(0, sizeof (struct framepars_all_t) , PROT_READ, MAP_SHARED, state->fd_fparmsall, 0);
	// PROT_WRITE - only to write acknowledge
/// PROT_WRITE - only to write acknowledge
	frameParsAll[port] = (struct framepars_all_t*)mmap(0, sizeof(struct framepars_all_t), PROT_READ | PROT_WRITE, MAP_SHARED, state->fd_fparmsall, 0);
	frameParsAll[port] = (struct framepars_all_t*)mmap(0, sizeof(struct framepars_all_t), PROT_READ | PROT_WRITE, MAP_SHARED, state->fd_fparmsall, 0);
	if ((int)frameParsAll[port] == -1) {
	if ((int)frameParsAll[port] == -1) {
		D0(fprintf(debug_file, "%s:%d:%s: Error in mmap in %s\n", __FILE__, __LINE__, __FUNCTION__, ctlFileNames[port]));
		D0(fprintf(debug_file, "%s:%d:%s: Error in mmap in %s\n", __FILE__, __LINE__, __FUNCTION__, ctlFileNames[port]));
		clean_up(state, pipe_names);
		clean_up(state);
		return -3;
		return -3;
	}
	}
	framePars[port] = frameParsAll[port]->framePars;
	framePars[port] = frameParsAll[port]->framePars;
	globalPars[port] = frameParsAll[port]->globalPars;
	globalPars[port] = frameParsAll[port]->globalPars;
#endif /* DESABLE_CODE */
#endif /* DESABLE_CODE */


//!create a named pipe
	// create a named pipe
//!always delete the pipe if it existed, start a fresh one
	// always delete the pipe if it existed, start a fresh one
	i = unlink(pipe_names[port]);
	ret = unlink(pipe_name);
	if (i) {
	if (ret) {
		D1(fprintf(debug_file, "Unlink %s returned %d, errno=%d \n", pipe_names[port], i, errno));
		D1(fprintf(debug_file, "Unlink %s returned %d, errno=%d \n", pipe_name, ret, errno));
	}
	}
	i = mkfifo(pipe_names[port], 0777); //EEXIST
	ret = mkfifo(pipe_name, 0777); //EEXIST
//! now should not exist
	// now should not exist
	if (i) {
	if (ret) {
		if (errno == EEXIST) {
		if (errno == EEXIST) {
			D1(fprintf(debug_file, "Named pipe %s already exists, will use it.\n", pipe_names[port]));
			D1(fprintf(debug_file, "Named pipe %s already exists, will use it.\n", pipe_name));
		} else {
		} else {
			D0(fprintf(debug_file, "Can not create a named pipe %s, errno=%d \n", pipe_names[port], errno));
			D0(fprintf(debug_file, "Can not create a named pipe %s, errno=%d \n", pipe_name, errno));
			clean_up(state, pipe_names);
			clean_up(state);
			return -4;
			return -4;
		}
		}
	}
	}


//!now open the pipe - will block until something will be written (or just open for writing
	// now open the pipe - will block until something will be written (or just open for writing,
//!Reads themselves will not block
	// reads themselves will not block)
	if (!((cmd_file = fopen(pipe_names[port], "r")))) {
	if (!((cmd_file = fopen(pipe_name, "r")))) {
		D0(fprintf(debug_file, "Can not open command file %s\n", pipe_names[port]));
		D0(fprintf(debug_file, "Can not open command file %s\n", pipe_name));
		clean_up(state, pipe_names);
		clean_up(state);
		return -5;
		return -5;
	}
	}
//   D1(fprintf (debug_file,"Pipe %s open for reading\n",argv[1]));
	D0(fprintf(debug_file, "Pipe %s open for reading\n", pipe_name)); // to make sure something is sent out
	D0(fprintf(debug_file, "Pipe %s open for reading\n", pipe_names[port])); // to make sure something is sent out

//! Here is a main loop. If recording is on, it will check for commands after each frame, if it is off - poll with fixed usleep
#define COMMAND_LOOP_DELAY 500000 //0.5sec

	while (go) {
//   D3(fprintf (debug_file,"%s:%d: format=%d, set_format=%d\n",__FILE__,__LINE__, state->format, state->set_format));


//! look at command queue first
	// enter main processing loop
	while (process) {
		// look at command queue first
		cmd = parse_cmd(state, cmd_file);
		cmd = parse_cmd(state, cmd_file);
		if (cmd) {
		if (cmd) {
			if (cmd < 0) D0(fprintf(debug_file, "Unrecognized command\n"));
			if (cmd < 0) D0(fprintf(debug_file, "Unrecognized command\n"));
/// Acknowledge received command by copying frame number to per-daemon parameter
		} else if (state->running) { // no commands in queue, started
//      GLOBALPARS(G_DAEMON_ERR+lastDaemonBit)=GLOBALPARS(G_THIS_FRAME);

		} else if (state->running) { //!no commands in queue, started
//   D3(fprintf (debug_file,"%s:%d: format=%d, set_format=%d\n",__FILE__,__LINE__, state->format, state->set_format));


			switch ((rslt = -sendImageFrame(state))) {
			switch ((rslt = -sendImageFrame(state))) {
			case 0:
			case 0:
/*
				break;                      // frame sent OK, nothing to do (TODO: check file length/duration)
          D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned %d\n" \
			case CAMOGM_FRAME_NOT_READY:    // just wait for the frame to appear at the current pointer
                                  "state->cirbuf_rp= 0x%x\n",__FILE__,__LINE__,rslt,state->cirbuf_rp));
				// we'll wait for a frame, not to waste resources. But if the compressor is stopped this program will not respond to any commands
 */
				// TODO - add another wait with (short) timeout?
				break;                  //! frame sent OK, nothing to do (TODO: check file length/duration)
			case CAMOGM_FRAME_NOT_READY:    //!  just wait for the frame to appear at the current pointer
//! we'll wait for a frame, not to waste resources. But if the compressor is stopped this program will not respond to any commands
//! TODO - add another wait with (short) timeout?
//     D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned -%d\n",__FILE__,__LINE__,rslt));
/*
     D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned -%d\n" \
                                  "state->cirbuf_rp= 0x%x\n",__FILE__,__LINE__,rslt,state->cirbuf_rp));
 */
//                lseek(state->fd_circ,LSEEK_CIRC_WAIT,SEEK_END);
				fp0 = lseek(state->fd_circ, 0, SEEK_CUR);
				fp0 = lseek(state->fd_circ, 0, SEEK_CUR);
				if (fp0 < 0) {
				if (fp0 < 0) {
					D0(fprintf(debug_file, "%s:line %d got broken frame (%d) before waiting for ready\n", __FILE__, __LINE__, fp0));
					D0(fprintf(debug_file, "%s:line %d got broken frame (%d) before waiting for ready\n", __FILE__, __LINE__, fp0));
@@ -1483,64 +1449,111 @@ int main(int argc, char *argv[])
						break;
						break;
					}
					}
				}
				}
//                break;
				// no break
			case  CAMOGM_FRAME_CHANGED:     //! frame parameters have changed
			case  CAMOGM_FRAME_CHANGED:     // frame parameters have changed
			case  CAMOGM_FRAME_NEXTFILE:    //! next file needed (need to switch to a new file (time/size exceeded limit)
			case  CAMOGM_FRAME_NEXTFILE:    // next file needed (need to switch to a new file (time/size exceeded limit)
			case  CAMOGM_FRAME_INVALID:     //! invalid frame pointer
			case  CAMOGM_FRAME_INVALID:     // invalid frame pointer
			case  CAMOGM_FRAME_BROKEN:      //! frame broken (buffer overrun)
			case  CAMOGM_FRAME_BROKEN:      // frame broken (buffer overrun)
//! restart the file
				// restart the file
//     D3(fprintf (debug_file,"%s:line %d - sendImageFrame() returned -%d\n",__FILE__,__LINE__,rslt));
				D3(fprintf(debug_file,"%s:line %d - sendImageFrame() returned -%d\n", __FILE__, __LINE__, rslt));
				camogm_stop(state);
				camogm_stop(state);
				camogm_start(state);
				camogm_start(state);
				break;
				break;
			case  CAMOGM_FRAME_FILE_ERR:    //! error with file I/O
			case  CAMOGM_FRAME_FILE_ERR:    // error with file I/O
			case  CAMOGM_FRAME_OTHER:       //! other errors
			case  CAMOGM_FRAME_OTHER:       // other errors
				D0(fprintf(debug_file, "%s:line %d - error=%d\n", __FILE__, __LINE__, rslt));
				D0(fprintf(debug_file, "%s:line %d - error=%d\n", __FILE__, __LINE__, rslt));
				break;
				break;
			default:
			default:
				D0(fprintf(debug_file, "%s:line %d - should not get here (rslt=%d)\n", __FILE__, __LINE__, rslt));
				D0(fprintf(debug_file, "%s:line %d - should not get here (rslt=%d)\n", __FILE__, __LINE__, rslt));
				clean_up(state, pipe_names);
				clean_up(state);
				exit(-1);
				exit(-1);
			} //switch
			} // switch sendImageFrame()

			if ((rslt != 0) && (rslt != CAMOGM_FRAME_NOT_READY) && (rslt != CAMOGM_FRAME_CHANGED)) state->last_error_code = rslt;
			if ((rslt != 0) && (rslt != CAMOGM_FRAME_NOT_READY) && (rslt != CAMOGM_FRAME_CHANGED)) state->last_error_code = rslt;
		} else if (state->starting) { //!no commands in queue,starting (but not started yet)
		} else if (state->starting) { // no commands in queue,starting (but not started yet)
//   D3(fprintf (debug_file,"%s:%d: format=%d, set_format=%d\n",__FILE__,__LINE__, state->format, state->set_format));


//!retry starting
			// retry starting
			switch ((rslt = -camogm_start(state))) {
			switch ((rslt = -camogm_start(state))) {
			case 0:                       break;                            //! file started OK, nothing to do
			case 0:
				break;                      // file started OK, nothing to do
			case CAMOGM_TOO_EARLY:
			case CAMOGM_TOO_EARLY:
				lseek(state->fd_circ, LSEEK_CIRC_TOWP, SEEK_END);       /// set pointer to the frame to wait for
				lseek(state->fd_circ, LSEEK_CIRC_TOWP, SEEK_END);       // set pointer to the frame to wait for
				lseek(state->fd_circ, LSEEK_CIRC_WAIT, SEEK_END);       /// It already passed CAMOGM_FRAME_NOT_READY, so compressor may be running already
				lseek(state->fd_circ, LSEEK_CIRC_WAIT, SEEK_END);       // It already passed CAMOGM_FRAME_NOT_READY, so compressor may be running already
				break;                                                  /// no need to wait extra
				break;                                                  // no need to wait extra
			case CAMOGM_FRAME_NOT_READY:                                    //!  just wait for the frame to appear at the current pointer
			case CAMOGM_FRAME_NOT_READY:                                // just wait for the frame to appear at the current pointer
//! we'll wait for a frame, not to waste resources. But if the compressor is stopped this program will not respond to any commands
			// we'll wait for a frame, not to waste resources. But if the compressor is stopped this program will not respond to any commands
//! TODO - add another wait with (short) timeout?
			// TODO - add another wait with (short) timeout?
//                lseek(state->fd_circ,LSEEK_CIRC_WAIT,SEEK_END);
			case  CAMOGM_FRAME_CHANGED:     // frame parameters have changed
			case  CAMOGM_FRAME_CHANGED:             //! frame parameters have changed
			case  CAMOGM_FRAME_NEXTFILE:
			case  CAMOGM_FRAME_NEXTFILE:
			case  CAMOGM_FRAME_INVALID:             //! invalid frame pointer
			case  CAMOGM_FRAME_INVALID:     // invalid frame pointer
			case  CAMOGM_FRAME_BROKEN:              //! frame broken (buffer overrun)
			case  CAMOGM_FRAME_BROKEN:      // frame broken (buffer overrun)
//     D3(fprintf (debug_file,"%s:line %d - camogm_start() returned -%d,  state->cirbuf_rp= 0x%x\n", __FILE__,__LINE__,rslt,state->cirbuf_rp));
				usleep(COMMAND_LOOP_DELAY); // it should be not too long so empty buffer will not be overrun
				usleep( COMMAND_LOOP_DELAY);    //! it should be not too long so empty buffer will not be overrun
				break;
				break;
			case  CAMOGM_FRAME_FILE_ERR:            //! error with file I/O
			case  CAMOGM_FRAME_FILE_ERR:    // error with file I/O
			case  CAMOGM_FRAME_OTHER:               //! other errors
			case  CAMOGM_FRAME_OTHER:       // other errors
				D0(fprintf(debug_file, "%s:line %d - error=%d\n", __FILE__, __LINE__, rslt));
				D0(fprintf(debug_file, "%s:line %d - error=%d\n", __FILE__, __LINE__, rslt));
				break;
				break;
			default:
			default:
				D0(fprintf(debug_file, "%s:line %d - should not get here (rslt=%d)\n", __FILE__, __LINE__, rslt));
				D0(fprintf(debug_file, "%s:line %d - should not get here (rslt=%d)\n", __FILE__, __LINE__, rslt));
				clean_up(state, pipe_names);
				clean_up(state);
				exit(-1);
				exit(-1);
			} //switch
			} // switch camogm_start()
			if ((rslt != 0) && (rslt != CAMOGM_TOO_EARLY) && (rslt != CAMOGM_FRAME_NOT_READY) && (rslt != CAMOGM_FRAME_CHANGED) ) state->last_error_code = rslt;
			if ((rslt != 0) && (rslt != CAMOGM_TOO_EARLY) && (rslt != CAMOGM_FRAME_NOT_READY) && (rslt != CAMOGM_FRAME_CHANGED) ) state->last_error_code = rslt;


		} else {                                //! not running, not starting
		} else {                            // not running, not starting
			usleep( COMMAND_LOOP_DELAY);    //! make it longer but interruptible by signals?
			usleep(COMMAND_LOOP_DELAY);     // make it longer but interruptible by signals?
		}
		}
	} // while (process)

	// normally, we should not be here
	clean_up(state);
	return EXIT_SUCCESS;
}
}
	clean_up(state, pipe_names);

	return 0;
int main(int argc, char *argv[])
{
	const char usage[] =   "This program allows recording of the video/images acquired by Elphel camera to the storage media.\n" \
			     "It is designed to run in the background and accept commands through a named pipe.\n\n" \
			     "Usage:\n\n" \
			     "%s <named_pipe_name>\n\n"	\
			     "i.e.:\n\n" \
			     "%s /var/state/camogm_cmd\n\n" \
			     "When the program is runninig you may send commands by writing strings to the command file\n" \
			     "(/var/state/camogm_cmd in the example above). The complete list of available commands is available\n" \
			     "on Elphel Wiki (http://wiki.elphel.com/index.php?title=Camogm), here is the example of usage\n" \
			     "from the shell prompt in the camera:\n\n"	\
			     "echo \"status; exif=1; format=jpeg;status=/var/tmp/camogm.status\" > /var/state/camogm_cmd\n\n" \
			     "That will print status information on the standard output (may not be visible if the program was not\n" \
			     "started from the same session), set exif mode on (each frame will have the full Exif header including\n" \
			     "a precise time stamp), set output format to a series of individual JPEG files, and then send status\n" \
			     "information to a file /var/tmp/camogm.status in the camera file system.\n\n" \
			     "This program does not control the process of acquisition of the video/images to the camera internal\n" \
			     "buffer, it only retrieves that data from the buffer (waiting when needed), packages it to selected\n" \
			     "format and stores the result files.\n\n";

	char *pipe_names[SENSOR_PORTS] = {0};
	int ret;

	// no command line options processing yet
	if ((argc < 2) || (argv[1][1] == '-')) {
		printf(usage, argv[0], argv[0]);
		return EXIT_SUCCESS;
	}
	if (create_pipe_names(argv[1], pipe_names) < 0) {
		printf("Error: unable to allocate memory for command pipe name\n");
		return EXIT_FAILURE;
	}

	// spawn a process for each sensor port
	for (int i = 0; i < SENSOR_PORTS; i++) {
		camogm_init(&sstate[i], i, pipe_names[i]);
		if (fork() == 0) {
			ret = listener_loop(&sstate[i]);
			exit(ret);
		}
	}

	return EXIT_SUCCESS;
}
}


/**
/**
+3 −2
Original line number Original line Diff line number Diff line
@@ -87,7 +87,7 @@ typedef struct {
	int fd_fparmsall;               //! file descriptor for sensor/compressor parameters
	int fd_fparmsall;               //! file descriptor for sensor/compressor parameters
	int fd_exif;                    //! file descriptor for Exif data
	int fd_exif;                    //! file descriptor for Exif data
	int head_size;                  //! JPEG header size
	int head_size;                  //! JPEG header size
	char jpegHeader [JPEG_HEADER_MAXSIZE];
	unsigned char jpegHeader [JPEG_HEADER_MAXSIZE];
	int metadata_start;
	int metadata_start;
	struct interframe_params_t frame_params;
	struct interframe_params_t frame_params;
	struct interframe_params_t this_frame_params;
	struct interframe_params_t this_frame_params;
@@ -158,7 +158,8 @@ typedef struct {
	int kml_last_uts;                                       //! last generated kml file timestamp, microseconds
	int kml_last_uts;                                       //! last generated kml file timestamp, microseconds
	struct exif_dir_table_t kml_exif[ExifKmlNumber];        //! store locations of the fields needed for KML generations in the Exif block
	struct exif_dir_table_t kml_exif[ExifKmlNumber];        //! store locations of the fields needed for KML generations in the Exif block


	unsigned int port_num;
	unsigned int port_num;                                  // sensor port this state assigned to
	char *pipe_name;                                        // command pipe name for this sensor port
} camogm_state;
} camogm_state;


extern int debug_level;
extern int debug_level;