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

Move main loop to separate function, spawn processes

parent 38f6a374
...@@ -145,6 +145,7 @@ ...@@ -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]; ...@@ -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,13 +270,20 @@ void put_uint64(void *buf, u_int64_t val) ...@@ -269,13 +270,20 @@ 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;
state->running = 0; // mo state->running = 0; // mo
state->starting = 0; // mo state->starting = 0; // mo
state->vf = NULL; state->vf = NULL;
camogm_set_segment_duration(state, DEFAULT_DURATION); camogm_set_segment_duration(state, DEFAULT_DURATION);
camogm_set_segment_length(state, DEFAULT_LENGTH); camogm_set_segment_length(state, DEFAULT_LENGTH);
...@@ -283,17 +291,17 @@ int camogm_init(camogm_state *state, unsigned int port) ...@@ -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,20 +310,19 @@ int camogm_init(camogm_state *state, unsigned int port) ...@@ -302,20 +310,19 @@ 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);
camogm_kml_set_vertHalfFov(state, 15.0); camogm_kml_set_vertHalfFov(state, 15.0);
camogm_kml_set_height_mode(state, 0); camogm_kml_set_height_mode(state, 0);
camogm_kml_set_height(state, 10.0); camogm_kml_set_height(state, 10.0);
camogm_kml_set_period(state, 2); // 2 sec camogm_kml_set_period(state, 2); // 2 sec
camogm_kml_set_near(state, 40.0); // 40 m (distance to PhotoOverlay) camogm_kml_set_near(state, 40.0); // 40 m (distance to PhotoOverlay)
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) ...@@ -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) ...@@ -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; int rslt, ret, cmd;
const char usage[] = "This program allows recording of the video/images acquired by Elphel camera to the storage media.\n" \ int fp0, fp1;
"It is designed to run in the background and accept commands through a named pipe.\n\n" \ int process = 1;
"Usage:\n\n" \ unsigned int port = state->port_num;
"%s <named_pipe_name>\n\n" \ const char *pipe_name = state->pipe_name;
"i.e.:\n\n" \
"%s /var/state/camogm_cmd\n\n" \ // open Exif header file
"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
#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 // enter main processing loop
#define COMMAND_LOOP_DELAY 500000 //0.5sec while (process) {
// look at command queue first
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
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[]) ...@@ -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;
}
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);
} }
} }
clean_up(state, pipe_names);
return 0; return EXIT_SUCCESS;
} }
/** /**
......
...@@ -87,7 +87,7 @@ typedef struct { ...@@ -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 { ...@@ -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;
......
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