Loading src/Makefile +2 −2 Original line number Original line Diff line number Diff line Loading @@ -11,7 +11,7 @@ IMAGES = $(GUIDIR)/images/filebrowser-01.gif $(GUIDIR)/images/filebrowser-bo $(GUIDIR)/images/rec_folder.png $(GUIDIR)/images/up_folder.gif $(GUIDIR)/images/play_audio.png $(GUIDIR)/images/hdd.png $(GUIDIR)/images/rec_folder.png $(GUIDIR)/images/up_folder.gif $(GUIDIR)/images/play_audio.png $(GUIDIR)/images/hdd.png SRCS = camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c camogm_read.c index_list.c SRCS = camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c camogm_read.c index_list.c camogm_align.c TEST_SRC = camogm_test.c TEST_SRC = camogm_test.c OBJS = $(SRCS:.c=.o) OBJS = $(SRCS:.c=.o) Loading @@ -31,7 +31,7 @@ IMAGEDIR = $(WWW_PAGES)/images all: $(PROGS) $(TEST_PROG) all: $(PROGS) $(TEST_PROG) $(PROGS): $(OBJS) $(PROGS): $(OBJS) $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ $(TEST_PROG): $(TEST_SRC:.c=.o) $(TEST_PROG): $(TEST_SRC:.c=.o) Loading src/camogm.c +47 −18 Original line number Original line Diff line number Diff line Loading @@ -64,21 +64,6 @@ char trailer[TRAILER_SIZE] = { 0xff, 0xd9 }; char trailer[TRAILER_SIZE] = { 0xff, 0xd9 }; #if 0 const char *exifFileNames[] = { "/dev/exif_exif0", "/dev/exif_exif1", "/dev/exif_exif2", "/dev/exif_exif3" }; const char *headFileNames[] = { "/dev/jpeghead0", "/dev/jpeghead1", "/dev/jpeghead2", "/dev/jpeghead3" }; const char *ctlFileNames[] = { "/dev/frameparsall0", "/dev/frameparsall1", "/dev/frameparsall2", "/de/framepars3" }; const char *circbufFileNames[] = {"/dev/circbuf0", "/dev/circbuf1", "/dev/circbuf2", "/dev/circbuf3" }; #else const char *exifFileNames[] = { DEV393_PATH(DEV393_EXIF0), DEV393_PATH(DEV393_EXIF1), const char *exifFileNames[] = { DEV393_PATH(DEV393_EXIF0), DEV393_PATH(DEV393_EXIF1), DEV393_PATH(DEV393_EXIF2), DEV393_PATH(DEV393_EXIF3) DEV393_PATH(DEV393_EXIF2), DEV393_PATH(DEV393_EXIF3) }; }; Loading @@ -92,7 +77,6 @@ const char *ctlFileNames[] = { DEV393_PATH(DEV393_FRAMEPARS0), DEV393_PATH(DEV3 const char *circbufFileNames[] = {DEV393_PATH(DEV393_CIRCBUF0), DEV393_PATH(DEV393_CIRCBUF1), const char *circbufFileNames[] = {DEV393_PATH(DEV393_CIRCBUF0), DEV393_PATH(DEV393_CIRCBUF1), DEV393_PATH(DEV393_CIRCBUF2), DEV393_PATH(DEV393_CIRCBUF3) DEV393_PATH(DEV393_CIRCBUF2), DEV393_PATH(DEV393_CIRCBUF3) }; }; #endif int lastDaemonBit[SENSOR_PORTS] = {DAEMON_BIT_CAMOGM}; int lastDaemonBit[SENSOR_PORTS] = {DAEMON_BIT_CAMOGM}; struct framepars_all_t *frameParsAll[SENSOR_PORTS]; struct framepars_all_t *frameParsAll[SENSOR_PORTS]; Loading Loading @@ -167,6 +151,7 @@ static int get_sysfs_name(const char *dev_name, char *sys_name, size_t str_sz, i static int get_disk_range(const char *name, struct range *rng); static int get_disk_range(const char *name, struct range *rng); static int set_disk_range(const struct range *rng); static int set_disk_range(const struct range *rng); static void get_disk_info(camogm_state *state); static void get_disk_info(camogm_state *state); static struct timeval get_fpga_time(const int fd_fparsall, unsigned int port); int open_files(camogm_state *state); int open_files(camogm_state *state); unsigned long getGPValue(unsigned int port, unsigned long GPNumber); unsigned long getGPValue(unsigned int port, unsigned long GPNumber); void setGValue(unsigned int port, unsigned long GNumber, unsigned long value); void setGValue(unsigned int port, unsigned long GNumber, unsigned long value); Loading Loading @@ -279,6 +264,10 @@ void camogm_init(camogm_state *state, char *pipe_name, uint16_t port_num) state->active_chn = ALL_CHN_INACTIVE; state->active_chn = ALL_CHN_INACTIVE; state->rawdev.mmap_default_size = MMAP_CHUNK_SIZE; state->rawdev.mmap_default_size = MMAP_CHUNK_SIZE; state->sock_port = port_num; state->sock_port = port_num; state->writer_params.data_ready = false; state->writer_params.exit_thread = false; state->writer_params.state = STATE_STOPPED; } } /** /** Loading Loading @@ -366,6 +355,7 @@ int camogm_start(camogm_state *state) if (is_chn_active(state, chn)) { if (is_chn_active(state, chn)) { // Check/set circbuf read pointer // Check/set circbuf read pointer D3(fprintf(debug_file, "1: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn])); D3(fprintf(debug_file, "1: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn])); D3(fprintf(debug_file, "1a: compressed frame number = %li\n", lseek(state->fd_circ[chn], LSEEK_CIRC_GETFRAME, SEEK_END))); if ((state->cirbuf_rp[chn] < 0) || (lseek(state->fd_circ[chn], state->cirbuf_rp[chn], SEEK_SET) < 0) || (lseek(state->fd_circ[chn], LSEEK_CIRC_VALID, SEEK_END) < 0 )) { if ((state->cirbuf_rp[chn] < 0) || (lseek(state->fd_circ[chn], state->cirbuf_rp[chn], SEEK_SET) < 0) || (lseek(state->fd_circ[chn], LSEEK_CIRC_VALID, SEEK_END) < 0 )) { D3(fprintf(debug_file, "2: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn])); D3(fprintf(debug_file, "2: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn])); /* In "greedy" mode try to save as many frames from the circbuf as possible */ /* In "greedy" mode try to save as many frames from the circbuf as possible */ Loading Loading @@ -526,6 +516,9 @@ int sendImageFrame(camogm_state *state) int * ifp_this = (int*)&(state->this_frame_params[state->port_num]); int * ifp_this = (int*)&(state->this_frame_params[state->port_num]); int fp; int fp; int port = state->port_num; int port = state->port_num; struct timeval start_time, end_time; // start_time = get_fpga_time(state->fd_fparmsall[port], port); // This is probably needed only for Quicktime (not to exceed already allocated frame index) // This is probably needed only for Quicktime (not to exceed already allocated frame index) if (!state->rawdev_op && (state->frameno >= (state->max_frames))) { if (!state->rawdev_op && (state->frameno >= (state->max_frames))) { Loading Loading @@ -656,13 +649,16 @@ int sendImageFrame(camogm_state *state) /* 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 */ state->packetchunks[state->chunk_index ].bytes = state->jpeg_len - (state->circ_buff_size[port] - state->cirbuf_rp[port]); state->packetchunks[state->chunk_index ].bytes = state->jpeg_len - (state->circ_buff_size[port] - state->cirbuf_rp[port]); state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][0]; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][0]; state->writer_params.segments = 2; } else { // single segment } else { // single segment D3(fprintf(debug_file, "_11_")); D3(fprintf(debug_file, "_11_")); /* 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) */ state->packetchunks[state->chunk_index ].bytes = state->jpeg_len; state->packetchunks[state->chunk_index ].bytes = state->jpeg_len; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][state->cirbuf_rp[port] >> 2]; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][state->cirbuf_rp[port] >> 2]; state->writer_params.segments = 1; } } D3(fprintf(debug_file, "\tcirbuf_rp = 0x%x\t", state->cirbuf_rp[port])); D3(fprintf(debug_file, "_12_")); D3(fprintf(debug_file, "_12_")); state->packetchunks[state->chunk_index ].bytes = 2; state->packetchunks[state->chunk_index ].bytes = 2; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)trailer; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)trailer; Loading @@ -685,6 +681,7 @@ int sendImageFrame(camogm_state *state) // advance frame pointer // advance frame pointer state->frameno++; state->frameno++; state->cirbuf_rp[port] = lseek(state->fd_circ[port], LSEEK_CIRC_NEXT, SEEK_END); state->cirbuf_rp[port] = lseek(state->fd_circ[port], LSEEK_CIRC_NEXT, SEEK_END); D3(fprintf(debug_file, "\tcompressed frame number: %li\t", lseek(state->fd_circ[port], LSEEK_CIRC_GETFRAME, SEEK_END))); // optionally save it to global read pointer (i.e. for debugging with imgsrv "/pointers") // optionally save it to global read pointer (i.e. for debugging with imgsrv "/pointers") if (state->save_gp) lseek(state->fd_circ[port], LSEEK_CIRC_SETP, SEEK_END); if (state->save_gp) lseek(state->fd_circ[port], LSEEK_CIRC_SETP, SEEK_END); D3(fprintf(debug_file, "_15_\n")); D3(fprintf(debug_file, "_15_\n")); Loading @@ -693,6 +690,19 @@ int sendImageFrame(camogm_state *state) } else if (state->frames_skip < 0) { } else if (state->frames_skip < 0) { state->frames_skip_left[port] += -(state->frames_skip); state->frames_skip_left[port] += -(state->frames_skip); } } D3(fprintf(debug_file,"cirbuf_rp to next frame = 0x%x\n", state->cirbuf_rp[port])); // end_time = get_fpga_time(state->fd_fparmsall[port], port); // unsigned int mbps; // write speed, MB/s // unsigned long long time_diff; // time elapsed, in microseconds // time_diff = ((end_time.tv_sec * 1000000 + end_time.tv_usec) - (start_time.tv_sec * 1000000 + start_time.tv_usec)); // mbps = ((double)state->rawdev.last_jpeg_size / (double)1048576) / ((double)time_diff / (double)1000000); // D6(fprintf(debug_file, "Frame start time: %ld:%ld; frame end time: %ld:%ld; last frame size: %lu\n", // start_time.tv_sec, start_time.tv_usec, // end_time.tv_sec, end_time.tv_usec, // state->rawdev.last_jpeg_size)); // D6(fprintf(debug_file, "Write speed: %d MB/s\n", mbps)); return 0; return 0; } } Loading Loading @@ -750,7 +760,7 @@ void camogm_free(camogm_state *state) switch (f) { switch (f) { case CAMOGM_FORMAT_NONE: break; case CAMOGM_FORMAT_NONE: break; case CAMOGM_FORMAT_OGM: camogm_free_ogm(); break; case CAMOGM_FORMAT_OGM: camogm_free_ogm(); break; case CAMOGM_FORMAT_JPEG: camogm_free_jpeg(); break; case CAMOGM_FORMAT_JPEG: camogm_free_jpeg(state); break; case CAMOGM_FORMAT_MOV: camogm_free_mov(); break; case CAMOGM_FORMAT_MOV: camogm_free_mov(); break; } } } } Loading Loading @@ -875,6 +885,9 @@ void get_disk_info(camogm_state *state) } } if (get_disk_range(state->rawdev.rawdev_path, &rng) == 0) { if (get_disk_range(state->rawdev.rawdev_path, &rng) == 0) { state->writer_params.lba_start = rng.from; state->writer_params.lba_end = rng.to; state->writer_params.lba_current = state->writer_params.lba_start; set_disk_range(&rng); set_disk_range(&rng); } else { } else { D0(fprintf(debug_file, "ERROR: unable to get disk size and starting sector\n")); D0(fprintf(debug_file, "ERROR: unable to get disk size and starting sector\n")); Loading Loading @@ -2029,7 +2042,7 @@ int main(int argc, char *argv[]) sstate.rawdev.thread_state = STATE_RUNNING; sstate.rawdev.thread_state = STATE_RUNNING; str_len = strlen(state_name_str); str_len = strlen(state_name_str); if (str_len > 0) { if (str_len > 0) { strncpy(sstate.rawdev.state_path, state_name_str, str_len + 1); strncpy(sstate.rawdev.state_path, (const char *)state_name_str, str_len + 1); } } ret = listener_loop(&sstate); ret = listener_loop(&sstate); Loading Loading @@ -2104,3 +2117,19 @@ inline int is_fd_valid(int fd) { { return fcntl(fd, F_GETFD) != -1 || errno != EBADF; return fcntl(fd, F_GETFD) != -1 || errno != EBADF; } } /** * @brief Get current FPGA time * @return Time value in \e timeval structure */ struct timeval get_fpga_time(const int fd_fparsall, unsigned int port) { struct timeval tv; unsigned long write_data[] = {FRAMEPARS_GETFPGATIME, 0}; write(fd_fparsall, write_data, sizeof(unsigned long) * 2); tv.tv_sec = getGPValue(port, G_SECONDS); tv.tv_usec = getGPValue(port, G_MICROSECONDS); return tv; } src/camogm.h +32 −3 Original line number Original line Diff line number Diff line Loading @@ -27,7 +27,6 @@ #include <elphel/c313a.h> #include <elphel/c313a.h> #include <elphel/x393_devices.h> #include <elphel/x393_devices.h> #define CAMOGM_FRAME_NOT_READY 1 ///< frame pointer valid, but not yet acquired #define CAMOGM_FRAME_NOT_READY 1 ///< frame pointer valid, but not yet acquired #define CAMOGM_FRAME_INVALID 2 ///< invalid frame pointer #define CAMOGM_FRAME_INVALID 2 ///< invalid frame pointer #define CAMOGM_FRAME_CHANGED 3 ///< frame parameters have changed #define CAMOGM_FRAME_CHANGED 3 ///< frame parameters have changed Loading Loading @@ -66,6 +65,8 @@ #define MMAP_CHUNK_SIZE 10485760 #define MMAP_CHUNK_SIZE 10485760 /** @brief Time interval (in microseconds) for processing commands */ /** @brief Time interval (in microseconds) for processing commands */ #define COMMAND_LOOP_DELAY 500000 #define COMMAND_LOOP_DELAY 500000 /** @brief File can be split up to this number of chunks */ #define FILE_CHUNKS_NUM 8 /** /** * @enum state_flags * @enum state_flags Loading Loading @@ -125,6 +126,7 @@ typedef struct { uint64_t mmap_offset; uint64_t mmap_offset; uint64_t file_start; uint64_t file_start; int64_t total_rec_len; int64_t total_rec_len; unsigned long last_jpeg_size; pthread_t tid; pthread_t tid; volatile int thread_state; volatile int thread_state; unsigned char *disk_mmap; unsigned char *disk_mmap; Loading @@ -132,6 +134,33 @@ typedef struct { char state_path[ELPHEL_PATH_MAX]; char state_path[ELPHEL_PATH_MAX]; } rawdev_buffer; } rawdev_buffer; /** * @struct writer_params * @brief Contains mutexes and conditional variables associated with disk writing thread */ struct writer_params { int blockdev_fd; ///< file descriptor for open block device where frame will be recorded pthread_t writer_thread; ///< disk writing thread pthread_mutex_t writer_mutex; ///< synchronization mutex for main and writing threads pthread_cond_t writer_cond; ///< conditional variable indicating that writer thread can proceed with new frame pthread_cond_t main_cond; ///< conditional variable indicating that main thread can update write pointers bool data_ready; ///< flag indicating that new frame is ready for recording, access to this flag ///< must be protected with #writer_mutex. Set this flag in main thread and reset in ///< disk writing thread. int last_ret_val; ///< error value return during last frame recording (if any occurred) bool exit_thread; ///< flag indicating that the writing thread should terminate int state; ///< the state of disk writing thread int segments; ///< the number of segments in frame struct iovec *data_chunks; ///< a set of vectors pointing to aligned frame data buffers struct iovec prev_rem_vect; ///< vector pointing to the remainder of the previous frame unsigned char *rem_buff; ///< buffer containing the unaligned remainder of the current frame unsigned char *prev_rem_buff; ///< buffer containing the unaligned remainder of the previous frame unsigned char *common_buff; ///< buffer for aligned JPEG header uint64_t lba_start; ///< disk starting LBA uint64_t lba_current; ///< current write position in LBAs uint64_t lba_end; ///< disk last LBA }; /** /** * @struct camogm_state * @struct camogm_state * @brief Holds current state of the running program * @brief Holds current state of the running program Loading Loading @@ -192,7 +221,7 @@ typedef struct { int formats; ///< bitmask of used (initialized) formats int formats; ///< bitmask of used (initialized) formats int format; ///< output file format int format; ///< output file format int set_format; ///< output format to set (will be updated after stop) int set_format; ///< output format to set (will be updated after stop) elph_packet_chunk packetchunks[8]; elph_packet_chunk packetchunks[FILE_CHUNKS_NUM]; int chunk_index; int chunk_index; int buf_overruns[SENSOR_PORTS]; int buf_overruns[SENSOR_PORTS]; int buf_min[SENSOR_PORTS]; int buf_min[SENSOR_PORTS]; Loading Loading @@ -222,7 +251,7 @@ typedef struct { rawdev_buffer rawdev; ///< contains pointers to raw device buffer rawdev_buffer rawdev; ///< contains pointers to raw device buffer unsigned int active_chn; ///< bitmask of active sensor ports unsigned int active_chn; ///< bitmask of active sensor ports uint16_t sock_port; ///< command socket port number uint16_t sock_port; ///< command socket port number struct writer_params writer_params; ///< contains control parameters for writing thread unsigned int error_stat[SENSOR_PORTS][CAMOGM_ERRNUM]; ///< collect statistics about errors unsigned int error_stat[SENSOR_PORTS][CAMOGM_ERRNUM]; ///< collect statistics about errors } camogm_state; } camogm_state; Loading Loading
src/Makefile +2 −2 Original line number Original line Diff line number Diff line Loading @@ -11,7 +11,7 @@ IMAGES = $(GUIDIR)/images/filebrowser-01.gif $(GUIDIR)/images/filebrowser-bo $(GUIDIR)/images/rec_folder.png $(GUIDIR)/images/up_folder.gif $(GUIDIR)/images/play_audio.png $(GUIDIR)/images/hdd.png $(GUIDIR)/images/rec_folder.png $(GUIDIR)/images/up_folder.gif $(GUIDIR)/images/play_audio.png $(GUIDIR)/images/hdd.png SRCS = camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c camogm_read.c index_list.c SRCS = camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c camogm_read.c index_list.c camogm_align.c TEST_SRC = camogm_test.c TEST_SRC = camogm_test.c OBJS = $(SRCS:.c=.o) OBJS = $(SRCS:.c=.o) Loading @@ -31,7 +31,7 @@ IMAGEDIR = $(WWW_PAGES)/images all: $(PROGS) $(TEST_PROG) all: $(PROGS) $(TEST_PROG) $(PROGS): $(OBJS) $(PROGS): $(OBJS) $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ $(TEST_PROG): $(TEST_SRC:.c=.o) $(TEST_PROG): $(TEST_SRC:.c=.o) Loading
src/camogm.c +47 −18 Original line number Original line Diff line number Diff line Loading @@ -64,21 +64,6 @@ char trailer[TRAILER_SIZE] = { 0xff, 0xd9 }; char trailer[TRAILER_SIZE] = { 0xff, 0xd9 }; #if 0 const char *exifFileNames[] = { "/dev/exif_exif0", "/dev/exif_exif1", "/dev/exif_exif2", "/dev/exif_exif3" }; const char *headFileNames[] = { "/dev/jpeghead0", "/dev/jpeghead1", "/dev/jpeghead2", "/dev/jpeghead3" }; const char *ctlFileNames[] = { "/dev/frameparsall0", "/dev/frameparsall1", "/dev/frameparsall2", "/de/framepars3" }; const char *circbufFileNames[] = {"/dev/circbuf0", "/dev/circbuf1", "/dev/circbuf2", "/dev/circbuf3" }; #else const char *exifFileNames[] = { DEV393_PATH(DEV393_EXIF0), DEV393_PATH(DEV393_EXIF1), const char *exifFileNames[] = { DEV393_PATH(DEV393_EXIF0), DEV393_PATH(DEV393_EXIF1), DEV393_PATH(DEV393_EXIF2), DEV393_PATH(DEV393_EXIF3) DEV393_PATH(DEV393_EXIF2), DEV393_PATH(DEV393_EXIF3) }; }; Loading @@ -92,7 +77,6 @@ const char *ctlFileNames[] = { DEV393_PATH(DEV393_FRAMEPARS0), DEV393_PATH(DEV3 const char *circbufFileNames[] = {DEV393_PATH(DEV393_CIRCBUF0), DEV393_PATH(DEV393_CIRCBUF1), const char *circbufFileNames[] = {DEV393_PATH(DEV393_CIRCBUF0), DEV393_PATH(DEV393_CIRCBUF1), DEV393_PATH(DEV393_CIRCBUF2), DEV393_PATH(DEV393_CIRCBUF3) DEV393_PATH(DEV393_CIRCBUF2), DEV393_PATH(DEV393_CIRCBUF3) }; }; #endif int lastDaemonBit[SENSOR_PORTS] = {DAEMON_BIT_CAMOGM}; int lastDaemonBit[SENSOR_PORTS] = {DAEMON_BIT_CAMOGM}; struct framepars_all_t *frameParsAll[SENSOR_PORTS]; struct framepars_all_t *frameParsAll[SENSOR_PORTS]; Loading Loading @@ -167,6 +151,7 @@ static int get_sysfs_name(const char *dev_name, char *sys_name, size_t str_sz, i static int get_disk_range(const char *name, struct range *rng); static int get_disk_range(const char *name, struct range *rng); static int set_disk_range(const struct range *rng); static int set_disk_range(const struct range *rng); static void get_disk_info(camogm_state *state); static void get_disk_info(camogm_state *state); static struct timeval get_fpga_time(const int fd_fparsall, unsigned int port); int open_files(camogm_state *state); int open_files(camogm_state *state); unsigned long getGPValue(unsigned int port, unsigned long GPNumber); unsigned long getGPValue(unsigned int port, unsigned long GPNumber); void setGValue(unsigned int port, unsigned long GNumber, unsigned long value); void setGValue(unsigned int port, unsigned long GNumber, unsigned long value); Loading Loading @@ -279,6 +264,10 @@ void camogm_init(camogm_state *state, char *pipe_name, uint16_t port_num) state->active_chn = ALL_CHN_INACTIVE; state->active_chn = ALL_CHN_INACTIVE; state->rawdev.mmap_default_size = MMAP_CHUNK_SIZE; state->rawdev.mmap_default_size = MMAP_CHUNK_SIZE; state->sock_port = port_num; state->sock_port = port_num; state->writer_params.data_ready = false; state->writer_params.exit_thread = false; state->writer_params.state = STATE_STOPPED; } } /** /** Loading Loading @@ -366,6 +355,7 @@ int camogm_start(camogm_state *state) if (is_chn_active(state, chn)) { if (is_chn_active(state, chn)) { // Check/set circbuf read pointer // Check/set circbuf read pointer D3(fprintf(debug_file, "1: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn])); D3(fprintf(debug_file, "1: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn])); D3(fprintf(debug_file, "1a: compressed frame number = %li\n", lseek(state->fd_circ[chn], LSEEK_CIRC_GETFRAME, SEEK_END))); if ((state->cirbuf_rp[chn] < 0) || (lseek(state->fd_circ[chn], state->cirbuf_rp[chn], SEEK_SET) < 0) || (lseek(state->fd_circ[chn], LSEEK_CIRC_VALID, SEEK_END) < 0 )) { if ((state->cirbuf_rp[chn] < 0) || (lseek(state->fd_circ[chn], state->cirbuf_rp[chn], SEEK_SET) < 0) || (lseek(state->fd_circ[chn], LSEEK_CIRC_VALID, SEEK_END) < 0 )) { D3(fprintf(debug_file, "2: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn])); D3(fprintf(debug_file, "2: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn])); /* In "greedy" mode try to save as many frames from the circbuf as possible */ /* In "greedy" mode try to save as many frames from the circbuf as possible */ Loading Loading @@ -526,6 +516,9 @@ int sendImageFrame(camogm_state *state) int * ifp_this = (int*)&(state->this_frame_params[state->port_num]); int * ifp_this = (int*)&(state->this_frame_params[state->port_num]); int fp; int fp; int port = state->port_num; int port = state->port_num; struct timeval start_time, end_time; // start_time = get_fpga_time(state->fd_fparmsall[port], port); // This is probably needed only for Quicktime (not to exceed already allocated frame index) // This is probably needed only for Quicktime (not to exceed already allocated frame index) if (!state->rawdev_op && (state->frameno >= (state->max_frames))) { if (!state->rawdev_op && (state->frameno >= (state->max_frames))) { Loading Loading @@ -656,13 +649,16 @@ int sendImageFrame(camogm_state *state) /* 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 */ state->packetchunks[state->chunk_index ].bytes = state->jpeg_len - (state->circ_buff_size[port] - state->cirbuf_rp[port]); state->packetchunks[state->chunk_index ].bytes = state->jpeg_len - (state->circ_buff_size[port] - state->cirbuf_rp[port]); state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][0]; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][0]; state->writer_params.segments = 2; } else { // single segment } else { // single segment D3(fprintf(debug_file, "_11_")); D3(fprintf(debug_file, "_11_")); /* 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) */ state->packetchunks[state->chunk_index ].bytes = state->jpeg_len; state->packetchunks[state->chunk_index ].bytes = state->jpeg_len; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][state->cirbuf_rp[port] >> 2]; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][state->cirbuf_rp[port] >> 2]; state->writer_params.segments = 1; } } D3(fprintf(debug_file, "\tcirbuf_rp = 0x%x\t", state->cirbuf_rp[port])); D3(fprintf(debug_file, "_12_")); D3(fprintf(debug_file, "_12_")); state->packetchunks[state->chunk_index ].bytes = 2; state->packetchunks[state->chunk_index ].bytes = 2; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)trailer; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)trailer; Loading @@ -685,6 +681,7 @@ int sendImageFrame(camogm_state *state) // advance frame pointer // advance frame pointer state->frameno++; state->frameno++; state->cirbuf_rp[port] = lseek(state->fd_circ[port], LSEEK_CIRC_NEXT, SEEK_END); state->cirbuf_rp[port] = lseek(state->fd_circ[port], LSEEK_CIRC_NEXT, SEEK_END); D3(fprintf(debug_file, "\tcompressed frame number: %li\t", lseek(state->fd_circ[port], LSEEK_CIRC_GETFRAME, SEEK_END))); // optionally save it to global read pointer (i.e. for debugging with imgsrv "/pointers") // optionally save it to global read pointer (i.e. for debugging with imgsrv "/pointers") if (state->save_gp) lseek(state->fd_circ[port], LSEEK_CIRC_SETP, SEEK_END); if (state->save_gp) lseek(state->fd_circ[port], LSEEK_CIRC_SETP, SEEK_END); D3(fprintf(debug_file, "_15_\n")); D3(fprintf(debug_file, "_15_\n")); Loading @@ -693,6 +690,19 @@ int sendImageFrame(camogm_state *state) } else if (state->frames_skip < 0) { } else if (state->frames_skip < 0) { state->frames_skip_left[port] += -(state->frames_skip); state->frames_skip_left[port] += -(state->frames_skip); } } D3(fprintf(debug_file,"cirbuf_rp to next frame = 0x%x\n", state->cirbuf_rp[port])); // end_time = get_fpga_time(state->fd_fparmsall[port], port); // unsigned int mbps; // write speed, MB/s // unsigned long long time_diff; // time elapsed, in microseconds // time_diff = ((end_time.tv_sec * 1000000 + end_time.tv_usec) - (start_time.tv_sec * 1000000 + start_time.tv_usec)); // mbps = ((double)state->rawdev.last_jpeg_size / (double)1048576) / ((double)time_diff / (double)1000000); // D6(fprintf(debug_file, "Frame start time: %ld:%ld; frame end time: %ld:%ld; last frame size: %lu\n", // start_time.tv_sec, start_time.tv_usec, // end_time.tv_sec, end_time.tv_usec, // state->rawdev.last_jpeg_size)); // D6(fprintf(debug_file, "Write speed: %d MB/s\n", mbps)); return 0; return 0; } } Loading Loading @@ -750,7 +760,7 @@ void camogm_free(camogm_state *state) switch (f) { switch (f) { case CAMOGM_FORMAT_NONE: break; case CAMOGM_FORMAT_NONE: break; case CAMOGM_FORMAT_OGM: camogm_free_ogm(); break; case CAMOGM_FORMAT_OGM: camogm_free_ogm(); break; case CAMOGM_FORMAT_JPEG: camogm_free_jpeg(); break; case CAMOGM_FORMAT_JPEG: camogm_free_jpeg(state); break; case CAMOGM_FORMAT_MOV: camogm_free_mov(); break; case CAMOGM_FORMAT_MOV: camogm_free_mov(); break; } } } } Loading Loading @@ -875,6 +885,9 @@ void get_disk_info(camogm_state *state) } } if (get_disk_range(state->rawdev.rawdev_path, &rng) == 0) { if (get_disk_range(state->rawdev.rawdev_path, &rng) == 0) { state->writer_params.lba_start = rng.from; state->writer_params.lba_end = rng.to; state->writer_params.lba_current = state->writer_params.lba_start; set_disk_range(&rng); set_disk_range(&rng); } else { } else { D0(fprintf(debug_file, "ERROR: unable to get disk size and starting sector\n")); D0(fprintf(debug_file, "ERROR: unable to get disk size and starting sector\n")); Loading Loading @@ -2029,7 +2042,7 @@ int main(int argc, char *argv[]) sstate.rawdev.thread_state = STATE_RUNNING; sstate.rawdev.thread_state = STATE_RUNNING; str_len = strlen(state_name_str); str_len = strlen(state_name_str); if (str_len > 0) { if (str_len > 0) { strncpy(sstate.rawdev.state_path, state_name_str, str_len + 1); strncpy(sstate.rawdev.state_path, (const char *)state_name_str, str_len + 1); } } ret = listener_loop(&sstate); ret = listener_loop(&sstate); Loading Loading @@ -2104,3 +2117,19 @@ inline int is_fd_valid(int fd) { { return fcntl(fd, F_GETFD) != -1 || errno != EBADF; return fcntl(fd, F_GETFD) != -1 || errno != EBADF; } } /** * @brief Get current FPGA time * @return Time value in \e timeval structure */ struct timeval get_fpga_time(const int fd_fparsall, unsigned int port) { struct timeval tv; unsigned long write_data[] = {FRAMEPARS_GETFPGATIME, 0}; write(fd_fparsall, write_data, sizeof(unsigned long) * 2); tv.tv_sec = getGPValue(port, G_SECONDS); tv.tv_usec = getGPValue(port, G_MICROSECONDS); return tv; }
src/camogm.h +32 −3 Original line number Original line Diff line number Diff line Loading @@ -27,7 +27,6 @@ #include <elphel/c313a.h> #include <elphel/c313a.h> #include <elphel/x393_devices.h> #include <elphel/x393_devices.h> #define CAMOGM_FRAME_NOT_READY 1 ///< frame pointer valid, but not yet acquired #define CAMOGM_FRAME_NOT_READY 1 ///< frame pointer valid, but not yet acquired #define CAMOGM_FRAME_INVALID 2 ///< invalid frame pointer #define CAMOGM_FRAME_INVALID 2 ///< invalid frame pointer #define CAMOGM_FRAME_CHANGED 3 ///< frame parameters have changed #define CAMOGM_FRAME_CHANGED 3 ///< frame parameters have changed Loading Loading @@ -66,6 +65,8 @@ #define MMAP_CHUNK_SIZE 10485760 #define MMAP_CHUNK_SIZE 10485760 /** @brief Time interval (in microseconds) for processing commands */ /** @brief Time interval (in microseconds) for processing commands */ #define COMMAND_LOOP_DELAY 500000 #define COMMAND_LOOP_DELAY 500000 /** @brief File can be split up to this number of chunks */ #define FILE_CHUNKS_NUM 8 /** /** * @enum state_flags * @enum state_flags Loading Loading @@ -125,6 +126,7 @@ typedef struct { uint64_t mmap_offset; uint64_t mmap_offset; uint64_t file_start; uint64_t file_start; int64_t total_rec_len; int64_t total_rec_len; unsigned long last_jpeg_size; pthread_t tid; pthread_t tid; volatile int thread_state; volatile int thread_state; unsigned char *disk_mmap; unsigned char *disk_mmap; Loading @@ -132,6 +134,33 @@ typedef struct { char state_path[ELPHEL_PATH_MAX]; char state_path[ELPHEL_PATH_MAX]; } rawdev_buffer; } rawdev_buffer; /** * @struct writer_params * @brief Contains mutexes and conditional variables associated with disk writing thread */ struct writer_params { int blockdev_fd; ///< file descriptor for open block device where frame will be recorded pthread_t writer_thread; ///< disk writing thread pthread_mutex_t writer_mutex; ///< synchronization mutex for main and writing threads pthread_cond_t writer_cond; ///< conditional variable indicating that writer thread can proceed with new frame pthread_cond_t main_cond; ///< conditional variable indicating that main thread can update write pointers bool data_ready; ///< flag indicating that new frame is ready for recording, access to this flag ///< must be protected with #writer_mutex. Set this flag in main thread and reset in ///< disk writing thread. int last_ret_val; ///< error value return during last frame recording (if any occurred) bool exit_thread; ///< flag indicating that the writing thread should terminate int state; ///< the state of disk writing thread int segments; ///< the number of segments in frame struct iovec *data_chunks; ///< a set of vectors pointing to aligned frame data buffers struct iovec prev_rem_vect; ///< vector pointing to the remainder of the previous frame unsigned char *rem_buff; ///< buffer containing the unaligned remainder of the current frame unsigned char *prev_rem_buff; ///< buffer containing the unaligned remainder of the previous frame unsigned char *common_buff; ///< buffer for aligned JPEG header uint64_t lba_start; ///< disk starting LBA uint64_t lba_current; ///< current write position in LBAs uint64_t lba_end; ///< disk last LBA }; /** /** * @struct camogm_state * @struct camogm_state * @brief Holds current state of the running program * @brief Holds current state of the running program Loading Loading @@ -192,7 +221,7 @@ typedef struct { int formats; ///< bitmask of used (initialized) formats int formats; ///< bitmask of used (initialized) formats int format; ///< output file format int format; ///< output file format int set_format; ///< output format to set (will be updated after stop) int set_format; ///< output format to set (will be updated after stop) elph_packet_chunk packetchunks[8]; elph_packet_chunk packetchunks[FILE_CHUNKS_NUM]; int chunk_index; int chunk_index; int buf_overruns[SENSOR_PORTS]; int buf_overruns[SENSOR_PORTS]; int buf_min[SENSOR_PORTS]; int buf_min[SENSOR_PORTS]; Loading Loading @@ -222,7 +251,7 @@ typedef struct { rawdev_buffer rawdev; ///< contains pointers to raw device buffer rawdev_buffer rawdev; ///< contains pointers to raw device buffer unsigned int active_chn; ///< bitmask of active sensor ports unsigned int active_chn; ///< bitmask of active sensor ports uint16_t sock_port; ///< command socket port number uint16_t sock_port; ///< command socket port number struct writer_params writer_params; ///< contains control parameters for writing thread unsigned int error_stat[SENSOR_PORTS][CAMOGM_ERRNUM]; ///< collect statistics about errors unsigned int error_stat[SENSOR_PORTS][CAMOGM_ERRNUM]; ///< collect statistics about errors } camogm_state; } camogm_state; Loading