Loading src/camogm.c +38 −9 Original line number Diff line number Diff line Loading @@ -163,6 +163,7 @@ static int get_disk_range(const char *name, struct range *rng); static int set_disk_range(const struct range *rng); 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); unsigned long getGPValue(unsigned int port, unsigned long GPNumber); void setGValue(unsigned int port, unsigned long GNumber, unsigned long value); Loading Loading @@ -280,7 +281,12 @@ void camogm_init(camogm_state *state, char *pipe_name, uint16_t port_num) state->rawdev.mmap_default_size = MMAP_CHUNK_SIZE; state->sock_port = port_num; state->writer_params.data_ready = false; // state->writer_params.data_ready = false; state->writer_params.chunk_page_prep = 0; // will prepare page 0 state->writer_params.chunk_page_write = 0; // will write page 0 state->writer_params.exit_thread = false; state->writer_params.state = STATE_STOPPED; Loading Loading @@ -692,7 +698,7 @@ int sendImageFrame(camogm_state *state) state->writer_params.segments = 1; } D3(fprintf(debug_file, "\tcirbuf_rp[%d] = 0x%x\t", port, state->cirbuf_rp[port])); D3(fprintf(debug_file, "_12_")); D3(fprintf(debug_file, "_12_\n")); if (state->this_frame_params[port].color != COLORMODE_RAW) { // Tiff state->packetchunks[state->chunk_index ].bytes = 2; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)trailer; Loading @@ -701,6 +707,7 @@ int sendImageFrame(camogm_state *state) dbg_show_packetchunks(state); D6(fprintf(debug_file, "_12.5_ before CAMOGM_FORMAT_XXX @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); switch (state->format) { case CAMOGM_FORMAT_NONE: rslt = 0; break; Loading Loading @@ -741,14 +748,14 @@ int sendImageFrame(camogm_state *state) // end_time.tv_sec, end_time.tv_usec, // state->rawdev.last_jpeg_size)); // D6(fprintf(debug_file, "Write speed: %d MB/s\n", mbps)); D6(fprintf(debug_file, "Exit sendImageFrame() OK @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); return 0; } static void dbg_show_packetchunks(camogm_state *state) { int i; for (i = 0; i < FILE_CHUNKS_NUM; i++) { for (i = 0; i < state->chunk_index; i++) { D4(fprintf(debug_file, "packetchunk[%d]: ptr = %p, size = %d\n", i, state->packetchunks[i].chunk, state->packetchunks[i].bytes)); } } Loading Loading @@ -1386,7 +1393,7 @@ int parse_cmd(camogm_state *state, FILE* npipe) //skip empty commands while (((cmd = getLineFromPipe(npipe))) && !cmd[0]) ; if (!cmd) return 0; // nothing in the pipe D2(fprintf(debug_file, "Got command: '%s'\n", cmd)); D2(fprintf(debug_file, "Got command: '%s' @ %06d -> ", cmd, get_fpga_usec(state->fd_fparmsall[0], 0))); // Acknowledge received command by copying frame number to per-daemon parameter // GLOBALPARS(state->port_num, G_DAEMON_ERR + lastDaemonBit[state->port_num]) = GLOBALPARS(state->port_num, G_THIS_FRAME); Loading Loading @@ -1655,6 +1662,7 @@ int listener_loop(camogm_state *state) // enter main processing loop while (process) { D6(fprintf(debug_file, "--------------- Listener loop @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); curr_port = select_port(state); state->port_num = curr_port; // look at command queue first Loading @@ -1668,14 +1676,19 @@ int listener_loop(camogm_state *state) #endif cmd = parse_cmd(state, cmd_file); if (cmd) { D2(fprintf(debug_file, "DONE command @ %06d\n", get_fpga_usec(state->fd_fparmsall[0], 0))); if (cmd < 0) D0(fprintf(debug_file, "Unrecognized command\n")); #ifdef USE_POLL } #endif } else if (state->prog_state == STATE_RUNNING) { // no commands in queue, started continue; // } else if (state->prog_state == STATE_RUNNING) { // no commands in queue, started } if (state->prog_state == STATE_RUNNING) { // no commands in queue, started D6(fprintf(debug_file, "state->prog_state == STATE_RUNNING ")); rslt = -sendImageFrame(state); D6(fprintf(debug_file, " ==> %d",rslt)); D6(fprintf(debug_file, " ==> %d @ %06d\n",rslt,get_fpga_usec(state->fd_fparmsall[0], 0))); switch (rslt) { case 0: break; // frame sent OK, nothing to do (TODO: check file length/duration) Loading @@ -1692,6 +1705,7 @@ int listener_loop(camogm_state *state) D0(fprintf(debug_file, "%s:line %d got broken frame (%d) while waiting for ready. Before that fp0=0x%x\n", __FILE__, __LINE__, fp1, fp0)); rslt = CAMOGM_FRAME_BROKEN; } else { D6(fprintf(debug_file, "No compressed frame ready, skipped 1 frame sync for port %d @ %06d\n",curr_port,get_fpga_usec(state->fd_fparmsall[0], 0))); break; } } Loading Loading @@ -1760,10 +1774,14 @@ int listener_loop(camogm_state *state) // add port number to error code to facilitate debugging state->last_error_code = rslt + 100 * state->port_num; } else if (state->prog_state == STATE_READING) { D6(fprintf(debug_file, "COMMAND_LOOP_DELAY start for STATE_READING@ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); usleep(COMMAND_LOOP_DELAY); D6(fprintf(debug_file, "COMMAND_LOOP_DELAY end for STATE_READING@ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); } else { // not running, not starting state->rawdev.thread_state = STATE_RUNNING; D6(fprintf(debug_file, "COMMAND_LOOP_DELAY start for STATE_RUNNING@ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); usleep(COMMAND_LOOP_DELAY); // make it longer but interruptible by signals? D6(fprintf(debug_file, "COMMAND_LOOP_DELAY end for STATE_RUNNING@ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); } #ifdef USE_POLL // } // if pfd.revents & POLLIN Loading Loading @@ -2265,3 +2283,14 @@ struct timeval get_fpga_time(const int fd_fparsall, unsigned int port) return tv; } /** * @brief Get current FPGA microseconds of time to use for timing of the code * @return FPGA current microseconds */ inline int get_fpga_usec(const int fd_fparsall, unsigned int port) { lseek(fd_fparsall, LSEEK_GET_FPGA_TIME, SEEK_END); // return (int) getGPValue(port, G_MICROSECONDS); return (int) GLOBALPARS(port, G_MICROSECONDS); } src/camogm.h +16 −6 Original line number Diff line number Diff line Loading @@ -67,7 +67,9 @@ #define COMMAND_LOOP_DELAY 500000 /** @brief File can be split up to this number of chunks */ #define FILE_CHUNKS_NUM 8 /** @brief Number of chunk pages to overlap preparation with SSD raw write */ #define FILE_CHUNKS_PAGES 2 #define FILE_CHUNKS_TOTAL ((FILE_CHUNKS_NUM) * (FILE_CHUNKS_PAGES)) /** * @enum state_flags * @brief Program state flags Loading Loading @@ -145,25 +147,32 @@ struct writer_params { 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. // 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. // ///< For overlapping disk raw writes with chunks preparation (should be atomic - use #writer_mutex) int chunk_page_prep; ///< page of chunks being prepared. Incremented (mod) after data is prepared for raw write int chunk_page_write; ///< page of chunks to write. Incremented (mod) after recording to disk 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 was_CHUNK_REM; ///< extracting to a separate entity data_chunks[CHUNK_REM] // struct iovec *was_CHUNK_COMMON; ///< extracting to a separate entity data_chunks[CHUNK_COMMON] 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 // get rid of common_buff // unsigned char *common_buff; ///< buffer for aligned JPEG header // make multiple? unsigned char *common_buffs[FILE_CHUNKS_PAGES]; ///< buffer for aligned JPEG header // make multiple? uint64_t lba_start; ///< disk starting LBA uint64_t lba_current; ///< current write position in LBAs uint64_t lba_end; ///< disk last LBA time_t stat_update; ///< time when status file was updated bool dummy_read; ///< inable dummy read cycle (debug feature) bool dummy_read; ///< enable dummy read cycle (debug feature) }; /** * @struct camogm_state Loading Loading @@ -272,5 +281,6 @@ void setGValue(unsigned int port, unsigned long GNumber, unsigned long value); int waitDaemonEnabled(unsigned int port, int daemonBit); int isDaemonEnabled(unsigned int port, int daemonBit); int is_fd_valid(int fd); int get_fpga_usec(const int fd_fparsall, unsigned int port); #endif /* _CAMOGM_H */ Loading
src/camogm.c +38 −9 Original line number Diff line number Diff line Loading @@ -163,6 +163,7 @@ static int get_disk_range(const char *name, struct range *rng); static int set_disk_range(const struct range *rng); 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); unsigned long getGPValue(unsigned int port, unsigned long GPNumber); void setGValue(unsigned int port, unsigned long GNumber, unsigned long value); Loading Loading @@ -280,7 +281,12 @@ void camogm_init(camogm_state *state, char *pipe_name, uint16_t port_num) state->rawdev.mmap_default_size = MMAP_CHUNK_SIZE; state->sock_port = port_num; state->writer_params.data_ready = false; // state->writer_params.data_ready = false; state->writer_params.chunk_page_prep = 0; // will prepare page 0 state->writer_params.chunk_page_write = 0; // will write page 0 state->writer_params.exit_thread = false; state->writer_params.state = STATE_STOPPED; Loading Loading @@ -692,7 +698,7 @@ int sendImageFrame(camogm_state *state) state->writer_params.segments = 1; } D3(fprintf(debug_file, "\tcirbuf_rp[%d] = 0x%x\t", port, state->cirbuf_rp[port])); D3(fprintf(debug_file, "_12_")); D3(fprintf(debug_file, "_12_\n")); if (state->this_frame_params[port].color != COLORMODE_RAW) { // Tiff state->packetchunks[state->chunk_index ].bytes = 2; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)trailer; Loading @@ -701,6 +707,7 @@ int sendImageFrame(camogm_state *state) dbg_show_packetchunks(state); D6(fprintf(debug_file, "_12.5_ before CAMOGM_FORMAT_XXX @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); switch (state->format) { case CAMOGM_FORMAT_NONE: rslt = 0; break; Loading Loading @@ -741,14 +748,14 @@ int sendImageFrame(camogm_state *state) // end_time.tv_sec, end_time.tv_usec, // state->rawdev.last_jpeg_size)); // D6(fprintf(debug_file, "Write speed: %d MB/s\n", mbps)); D6(fprintf(debug_file, "Exit sendImageFrame() OK @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); return 0; } static void dbg_show_packetchunks(camogm_state *state) { int i; for (i = 0; i < FILE_CHUNKS_NUM; i++) { for (i = 0; i < state->chunk_index; i++) { D4(fprintf(debug_file, "packetchunk[%d]: ptr = %p, size = %d\n", i, state->packetchunks[i].chunk, state->packetchunks[i].bytes)); } } Loading Loading @@ -1386,7 +1393,7 @@ int parse_cmd(camogm_state *state, FILE* npipe) //skip empty commands while (((cmd = getLineFromPipe(npipe))) && !cmd[0]) ; if (!cmd) return 0; // nothing in the pipe D2(fprintf(debug_file, "Got command: '%s'\n", cmd)); D2(fprintf(debug_file, "Got command: '%s' @ %06d -> ", cmd, get_fpga_usec(state->fd_fparmsall[0], 0))); // Acknowledge received command by copying frame number to per-daemon parameter // GLOBALPARS(state->port_num, G_DAEMON_ERR + lastDaemonBit[state->port_num]) = GLOBALPARS(state->port_num, G_THIS_FRAME); Loading Loading @@ -1655,6 +1662,7 @@ int listener_loop(camogm_state *state) // enter main processing loop while (process) { D6(fprintf(debug_file, "--------------- Listener loop @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); curr_port = select_port(state); state->port_num = curr_port; // look at command queue first Loading @@ -1668,14 +1676,19 @@ int listener_loop(camogm_state *state) #endif cmd = parse_cmd(state, cmd_file); if (cmd) { D2(fprintf(debug_file, "DONE command @ %06d\n", get_fpga_usec(state->fd_fparmsall[0], 0))); if (cmd < 0) D0(fprintf(debug_file, "Unrecognized command\n")); #ifdef USE_POLL } #endif } else if (state->prog_state == STATE_RUNNING) { // no commands in queue, started continue; // } else if (state->prog_state == STATE_RUNNING) { // no commands in queue, started } if (state->prog_state == STATE_RUNNING) { // no commands in queue, started D6(fprintf(debug_file, "state->prog_state == STATE_RUNNING ")); rslt = -sendImageFrame(state); D6(fprintf(debug_file, " ==> %d",rslt)); D6(fprintf(debug_file, " ==> %d @ %06d\n",rslt,get_fpga_usec(state->fd_fparmsall[0], 0))); switch (rslt) { case 0: break; // frame sent OK, nothing to do (TODO: check file length/duration) Loading @@ -1692,6 +1705,7 @@ int listener_loop(camogm_state *state) D0(fprintf(debug_file, "%s:line %d got broken frame (%d) while waiting for ready. Before that fp0=0x%x\n", __FILE__, __LINE__, fp1, fp0)); rslt = CAMOGM_FRAME_BROKEN; } else { D6(fprintf(debug_file, "No compressed frame ready, skipped 1 frame sync for port %d @ %06d\n",curr_port,get_fpga_usec(state->fd_fparmsall[0], 0))); break; } } Loading Loading @@ -1760,10 +1774,14 @@ int listener_loop(camogm_state *state) // add port number to error code to facilitate debugging state->last_error_code = rslt + 100 * state->port_num; } else if (state->prog_state == STATE_READING) { D6(fprintf(debug_file, "COMMAND_LOOP_DELAY start for STATE_READING@ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); usleep(COMMAND_LOOP_DELAY); D6(fprintf(debug_file, "COMMAND_LOOP_DELAY end for STATE_READING@ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); } else { // not running, not starting state->rawdev.thread_state = STATE_RUNNING; D6(fprintf(debug_file, "COMMAND_LOOP_DELAY start for STATE_RUNNING@ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); usleep(COMMAND_LOOP_DELAY); // make it longer but interruptible by signals? D6(fprintf(debug_file, "COMMAND_LOOP_DELAY end for STATE_RUNNING@ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); } #ifdef USE_POLL // } // if pfd.revents & POLLIN Loading Loading @@ -2265,3 +2283,14 @@ struct timeval get_fpga_time(const int fd_fparsall, unsigned int port) return tv; } /** * @brief Get current FPGA microseconds of time to use for timing of the code * @return FPGA current microseconds */ inline int get_fpga_usec(const int fd_fparsall, unsigned int port) { lseek(fd_fparsall, LSEEK_GET_FPGA_TIME, SEEK_END); // return (int) getGPValue(port, G_MICROSECONDS); return (int) GLOBALPARS(port, G_MICROSECONDS); }
src/camogm.h +16 −6 Original line number Diff line number Diff line Loading @@ -67,7 +67,9 @@ #define COMMAND_LOOP_DELAY 500000 /** @brief File can be split up to this number of chunks */ #define FILE_CHUNKS_NUM 8 /** @brief Number of chunk pages to overlap preparation with SSD raw write */ #define FILE_CHUNKS_PAGES 2 #define FILE_CHUNKS_TOTAL ((FILE_CHUNKS_NUM) * (FILE_CHUNKS_PAGES)) /** * @enum state_flags * @brief Program state flags Loading Loading @@ -145,25 +147,32 @@ struct writer_params { 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. // 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. // ///< For overlapping disk raw writes with chunks preparation (should be atomic - use #writer_mutex) int chunk_page_prep; ///< page of chunks being prepared. Incremented (mod) after data is prepared for raw write int chunk_page_write; ///< page of chunks to write. Incremented (mod) after recording to disk 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 was_CHUNK_REM; ///< extracting to a separate entity data_chunks[CHUNK_REM] // struct iovec *was_CHUNK_COMMON; ///< extracting to a separate entity data_chunks[CHUNK_COMMON] 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 // get rid of common_buff // unsigned char *common_buff; ///< buffer for aligned JPEG header // make multiple? unsigned char *common_buffs[FILE_CHUNKS_PAGES]; ///< buffer for aligned JPEG header // make multiple? uint64_t lba_start; ///< disk starting LBA uint64_t lba_current; ///< current write position in LBAs uint64_t lba_end; ///< disk last LBA time_t stat_update; ///< time when status file was updated bool dummy_read; ///< inable dummy read cycle (debug feature) bool dummy_read; ///< enable dummy read cycle (debug feature) }; /** * @struct camogm_state Loading Loading @@ -272,5 +281,6 @@ void setGValue(unsigned int port, unsigned long GNumber, unsigned long value); int waitDaemonEnabled(unsigned int port, int daemonBit); int isDaemonEnabled(unsigned int port, int daemonBit); int is_fd_valid(int fd); int get_fpga_usec(const int fd_fparsall, unsigned int port); #endif /* _CAMOGM_H */