Commit b4d4414a authored by Andrey Filippov's avatar Andrey Filippov

Intermediate step - with 4K sectors, better threads handling

parent 6be06d67
...@@ -163,6 +163,7 @@ static int get_disk_range(const char *name, struct range *rng); ...@@ -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 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); 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);
...@@ -280,7 +281,12 @@ void camogm_init(camogm_state *state, char *pipe_name, uint16_t port_num) ...@@ -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->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.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.exit_thread = false;
state->writer_params.state = STATE_STOPPED; state->writer_params.state = STATE_STOPPED;
...@@ -692,7 +698,7 @@ int sendImageFrame(camogm_state *state) ...@@ -692,7 +698,7 @@ int sendImageFrame(camogm_state *state)
state->writer_params.segments = 1; state->writer_params.segments = 1;
} }
D3(fprintf(debug_file, "\tcirbuf_rp[%d] = 0x%x\t", port, state->cirbuf_rp[port])); 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 if (state->this_frame_params[port].color != COLORMODE_RAW) { // Tiff
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;
...@@ -701,6 +707,7 @@ int sendImageFrame(camogm_state *state) ...@@ -701,6 +707,7 @@ int sendImageFrame(camogm_state *state)
dbg_show_packetchunks(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) { switch (state->format) {
case CAMOGM_FORMAT_NONE: rslt = 0; break; case CAMOGM_FORMAT_NONE: rslt = 0; break;
...@@ -741,14 +748,14 @@ int sendImageFrame(camogm_state *state) ...@@ -741,14 +748,14 @@ int sendImageFrame(camogm_state *state)
// end_time.tv_sec, end_time.tv_usec, // end_time.tv_sec, end_time.tv_usec,
// state->rawdev.last_jpeg_size)); // state->rawdev.last_jpeg_size));
// D6(fprintf(debug_file, "Write speed: %d MB/s\n", mbps)); // 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; return 0;
} }
static void dbg_show_packetchunks(camogm_state *state) static void dbg_show_packetchunks(camogm_state *state)
{ {
int i; 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)); D4(fprintf(debug_file, "packetchunk[%d]: ptr = %p, size = %d\n", i, state->packetchunks[i].chunk, state->packetchunks[i].bytes));
} }
} }
...@@ -1386,7 +1393,7 @@ int parse_cmd(camogm_state *state, FILE* npipe) ...@@ -1386,7 +1393,7 @@ int parse_cmd(camogm_state *state, FILE* npipe)
//skip empty commands //skip empty commands
while (((cmd = getLineFromPipe(npipe))) && !cmd[0]) ; while (((cmd = getLineFromPipe(npipe))) && !cmd[0]) ;
if (!cmd) return 0; // nothing in the pipe 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 // 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); // GLOBALPARS(state->port_num, G_DAEMON_ERR + lastDaemonBit[state->port_num]) = GLOBALPARS(state->port_num, G_THIS_FRAME);
...@@ -1655,6 +1662,7 @@ int listener_loop(camogm_state *state) ...@@ -1655,6 +1662,7 @@ int listener_loop(camogm_state *state)
// enter main processing loop // enter main processing loop
while (process) { while (process) {
D6(fprintf(debug_file, "--------------- Listener loop @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
curr_port = select_port(state); curr_port = select_port(state);
state->port_num = curr_port; state->port_num = curr_port;
// look at command queue first // look at command queue first
...@@ -1666,16 +1674,21 @@ int listener_loop(camogm_state *state) ...@@ -1666,16 +1674,21 @@ int listener_loop(camogm_state *state)
} }
if (pfd.revents & POLLIN){ if (pfd.revents & POLLIN){
#endif #endif
cmd = parse_cmd(state, cmd_file); cmd = parse_cmd(state, cmd_file);
if (cmd) { 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")); if (cmd < 0) D0(fprintf(debug_file, "Unrecognized command\n"));
#ifdef USE_POLL #ifdef USE_POLL
} }
#endif #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 ")); D6(fprintf(debug_file, "state->prog_state == STATE_RUNNING "));
rslt = -sendImageFrame(state); 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) { switch (rslt) {
case 0: case 0:
break; // frame sent OK, nothing to do (TODO: check file length/duration) break; // frame sent OK, nothing to do (TODO: check file length/duration)
...@@ -1692,6 +1705,7 @@ int listener_loop(camogm_state *state) ...@@ -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)); 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; rslt = CAMOGM_FRAME_BROKEN;
} else { } 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; break;
} }
} }
...@@ -1760,10 +1774,14 @@ int listener_loop(camogm_state *state) ...@@ -1760,10 +1774,14 @@ int listener_loop(camogm_state *state)
// add port number to error code to facilitate debugging // add port number to error code to facilitate debugging
state->last_error_code = rslt + 100 * state->port_num; state->last_error_code = rslt + 100 * state->port_num;
} else if (state->prog_state == STATE_READING) { } 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); 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 } else { // not running, not starting
state->rawdev.thread_state = STATE_RUNNING; 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? 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 #ifdef USE_POLL
// } // if pfd.revents & POLLIN // } // if pfd.revents & POLLIN
...@@ -2265,3 +2283,14 @@ struct timeval get_fpga_time(const int fd_fparsall, unsigned int port) ...@@ -2265,3 +2283,14 @@ struct timeval get_fpga_time(const int fd_fparsall, unsigned int port)
return tv; 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);
}
...@@ -67,7 +67,9 @@ ...@@ -67,7 +67,9 @@
#define COMMAND_LOOP_DELAY 500000 #define COMMAND_LOOP_DELAY 500000
/** @brief File can be split up to this number of chunks */ /** @brief File can be split up to this number of chunks */
#define FILE_CHUNKS_NUM 8 #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 * @enum state_flags
* @brief Program state flags * @brief Program state flags
...@@ -145,25 +147,32 @@ struct writer_params { ...@@ -145,25 +147,32 @@ struct writer_params {
pthread_mutex_t writer_mutex; ///< synchronization mutex for main and writing threads 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 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 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 // 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 // ///< must be protected with #writer_mutex. Set this flag in main thread and reset in
///< disk writing thread. // ///< 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) 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 bool exit_thread; ///< flag indicating that the writing thread should terminate
int state; ///< the state of disk writing thread int state; ///< the state of disk writing thread
int segments; ///< the number of segments in frame int segments; ///< the number of segments in frame
struct iovec *data_chunks; ///< a set of vectors pointing to aligned frame data buffers 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 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 *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 *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_start; ///< disk starting LBA
uint64_t lba_current; ///< current write position in LBAs uint64_t lba_current; ///< current write position in LBAs
uint64_t lba_end; ///< disk last LBA uint64_t lba_end; ///< disk last LBA
time_t stat_update; ///< time when status file was updated 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 * @struct camogm_state
...@@ -272,5 +281,6 @@ void setGValue(unsigned int port, unsigned long GNumber, unsigned long value); ...@@ -272,5 +281,6 @@ void setGValue(unsigned int port, unsigned long GNumber, unsigned long value);
int waitDaemonEnabled(unsigned int port, int daemonBit); int waitDaemonEnabled(unsigned int port, int daemonBit);
int isDaemonEnabled(unsigned int port, int daemonBit); int isDaemonEnabled(unsigned int port, int daemonBit);
int is_fd_valid(int fd); int is_fd_valid(int fd);
int get_fpga_usec(const int fd_fparsall, unsigned int port);
#endif /* _CAMOGM_H */ #endif /* _CAMOGM_H */
...@@ -26,9 +26,12 @@ ...@@ -26,9 +26,12 @@
#include "camogm_align.h" #include "camogm_align.h"
#ifndef ALIGN_INTERFRAME
static unsigned char app15[ALIGNMENT_SIZE] = {0xff, 0xef}; static unsigned char app15[ALIGNMENT_SIZE] = {0xff, 0xef};
#endif
static inline size_t get_size_from(const struct iovec *vects, int index, size_t offset, int all); //static inline size_t get_size_from(const struct iovec *vects, int index, size_t offset, int all); // will not be used
static inline size_t get_size_from_paged(camogm_state *state, int index, int all);
static inline size_t align_bytes_num(size_t data_len, size_t align_len); static inline size_t align_bytes_num(size_t data_len, size_t align_len);
static inline void vectcpy(struct iovec *dest, void *src, size_t len); static inline void vectcpy(struct iovec *dest, void *src, size_t len);
static inline void vectset(struct iovec *dest, int src, size_t len); static inline void vectset(struct iovec *dest, int src, size_t len);
...@@ -39,7 +42,7 @@ static inline unsigned char *vectrpos(struct iovec *vec, size_t offset); ...@@ -39,7 +42,7 @@ static inline unsigned char *vectrpos(struct iovec *vec, size_t offset);
static void remap_vectors(camogm_state *state, struct iovec *chunks); static void remap_vectors(camogm_state *state, struct iovec *chunks);
static size_t get_blocks_num(struct iovec *sgl, size_t n_elem); static size_t get_blocks_num(struct iovec *sgl, size_t n_elem);
/* debug functions */ /* debug functions */
static int check_chunks(struct iovec *vects); static int check_chunks(struct iovec *vects, int page);
static void dev_dbg(const char *prefix, const char *format, ...); static void dev_dbg(const char *prefix, const char *format, ...);
...@@ -99,19 +102,20 @@ static inline unsigned char *vectrpos(struct iovec *vec, size_t offset) ...@@ -99,19 +102,20 @@ static inline unsigned char *vectrpos(struct iovec *vec, size_t offset)
return (unsigned char *)vec->iov_base + (vec->iov_len - offset); return (unsigned char *)vec->iov_base + (vec->iov_len - offset);
} }
#if 0
/** Calculate the size of current frame in bytes starting from vector and offset given */ /** Calculate the size of current frame in bytes starting from vector and offset given */
static inline size_t get_size_from(const struct iovec *vects, int index, size_t offset, int all) static inline size_t get_size_from(const struct iovec *vects, int index, size_t offset, int all) // offset, index - always 0
{ {
int i; int i;
// int page_offs = FILE_CHUNKS_NUM + page;
size_t total = 0; size_t total = 0;
if (index >= MAX_DATA_CHUNKS || offset > vects[index].iov_len) { if (index >= MAX_DATA_CHUNKS || offset > vects[index].iov_len) {
return 0; return 0;
} }
for (i = index; i < MAX_DATA_CHUNKS; i++) { for (i = index; i < MAX_DATA_CHUNKS; i++) {
if (i == CHUNK_REM && all == EXCLUDE_REM) if (i == CHUNK_REM && all == EXCLUDE_REM)
/* remainder should not be processed */ // remainder should not be processed
continue; continue;
if (i == index) if (i == index)
total += vects[i].iov_len - offset; total += vects[i].iov_len - offset;
...@@ -121,6 +125,29 @@ static inline size_t get_size_from(const struct iovec *vects, int index, size_t ...@@ -121,6 +125,29 @@ static inline size_t get_size_from(const struct iovec *vects, int index, size_t
return total; return total;
} }
#endif
//camogm_state *state
/** Calculate the size of current frame in bytes starting from vector and offset given */
static inline size_t get_size_from_paged(camogm_state *state, int index, int all)
{
int i;
struct iovec *chunks = state->writer_params.data_chunks;
struct iovec *cbuff = &chunks[CHUNK_COMMON];
int page_offs = (state->writer_params.chunk_page_prep % FILE_CHUNKS_PAGES) * FILE_CHUNKS_NUM;
size_t total = 0;
for (i = page_offs + index; i < (FILE_CHUNKS_NUM + page_offs); i++) {
total += chunks[i].iov_len;
}
if (all) {
total += state->writer_params.was_CHUNK_REM.iov_len;
}
return total;
}
/** Return the number of bytes needed to be inserted to align @e data_len to @e align_len boundary */ /** Return the number of bytes needed to be inserted to align @e data_len to @e align_len boundary */
static inline size_t align_bytes_num(size_t data_len, size_t align_len) static inline size_t align_bytes_num(size_t data_len, size_t align_len)
...@@ -137,79 +164,96 @@ static void remap_vectors(camogm_state *state, struct iovec *chunks) ...@@ -137,79 +164,96 @@ static void remap_vectors(camogm_state *state, struct iovec *chunks)
{ {
int chunk_index = 1; int chunk_index = 1;
int is_tiff = state->this_frame_params[state->port_num].color == COLORMODE_RAW; int is_tiff = state->this_frame_params[state->port_num].color == COLORMODE_RAW;
int chunk_offset = (state->writer_params.chunk_page_prep % FILE_CHUNKS_PAGES) * FILE_CHUNKS_NUM;
int paged_CHUNK_LEADER = chunk_offset + CHUNK_LEADER;
int paged_CHUNK_EXIF = chunk_offset + CHUNK_EXIF;
int paged_CHUNK_HEADER = chunk_offset + CHUNK_HEADER;
int paged_CHUNK_COMMON = chunk_offset + CHUNK_COMMON;
int paged_CHUNK_DATA_0 = chunk_offset + CHUNK_DATA_0;
int paged_CHUNK_DATA_1 = chunk_offset + CHUNK_DATA_1;
int paged_CHUNK_TRAILER = chunk_offset + CHUNK_TRAILER;
int paged_CHUNK_ALIGN = chunk_offset + CHUNK_ALIGN;
if (state->exif > 0) { if (state->exif > 0) {
if (is_tiff) { // Tiff if (is_tiff) { // Tiff
chunks[CHUNK_EXIF].iov_base = (void *)state->packetchunks[chunk_index].chunk; chunks[paged_CHUNK_EXIF].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[CHUNK_EXIF].iov_len = state->packetchunks[chunk_index++].bytes; chunks[paged_CHUNK_EXIF].iov_len = state->packetchunks[chunk_index++].bytes;
// set length of unused chunks to zero, and pointer to any valid pointer // set length of unused chunks to zero, and pointer to any valid pointer
chunks[CHUNK_LEADER].iov_base = chunks[CHUNK_EXIF].iov_base; chunks[paged_CHUNK_LEADER].iov_base = chunks[paged_CHUNK_EXIF].iov_base;
chunks[CHUNK_LEADER].iov_len = 0; chunks[paged_CHUNK_LEADER].iov_len = 0;
chunks[CHUNK_HEADER].iov_base = chunks[CHUNK_EXIF].iov_base; chunks[paged_CHUNK_HEADER].iov_base = chunks[paged_CHUNK_EXIF].iov_base;
chunks[CHUNK_HEADER].iov_len = 0; chunks[paged_CHUNK_HEADER].iov_len = 0;
} else { // JPEG/JP4 } else { // JPEG/JP4
chunks[CHUNK_LEADER].iov_base = (void *)state->packetchunks[chunk_index].chunk; chunks[paged_CHUNK_LEADER].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[CHUNK_LEADER].iov_len = state->packetchunks[chunk_index++].bytes; chunks[paged_CHUNK_LEADER].iov_len = state->packetchunks[chunk_index++].bytes;
chunks[CHUNK_EXIF].iov_base = (void *)state->packetchunks[chunk_index].chunk; chunks[paged_CHUNK_EXIF].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[CHUNK_EXIF].iov_len = state->packetchunks[chunk_index++].bytes; chunks[paged_CHUNK_EXIF].iov_len = state->packetchunks[chunk_index++].bytes;
chunks[CHUNK_HEADER].iov_base = (void *)state->packetchunks[chunk_index].chunk; chunks[paged_CHUNK_HEADER].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[CHUNK_HEADER].iov_len = state->packetchunks[chunk_index++].bytes; chunks[paged_CHUNK_HEADER].iov_len = state->packetchunks[chunk_index++].bytes;
} }
} else { } else {
chunks[CHUNK_LEADER].iov_base = (void *)state->packetchunks[chunk_index].chunk; chunks[paged_CHUNK_LEADER].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[CHUNK_LEADER].iov_len = JPEG_MARKER_LEN; chunks[paged_CHUNK_LEADER].iov_len = JPEG_MARKER_LEN;
chunks[CHUNK_HEADER].iov_base = (void *)(state->packetchunks[chunk_index].chunk + JPEG_MARKER_LEN); chunks[paged_CHUNK_HEADER].iov_base = (void *)(state->packetchunks[chunk_index].chunk + JPEG_MARKER_LEN);
chunks[CHUNK_HEADER].iov_len = state->packetchunks[chunk_index++].bytes - JPEG_MARKER_LEN; chunks[paged_CHUNK_HEADER].iov_len = state->packetchunks[chunk_index++].bytes - JPEG_MARKER_LEN;
// set to zero length and valid pointer // set to zero length and valid pointer
chunks[CHUNK_EXIF].iov_base = chunks[CHUNK_HEADER].iov_base; chunks[paged_CHUNK_EXIF].iov_base = chunks[paged_CHUNK_HEADER].iov_base;
chunks[CHUNK_EXIF].iov_len = 0; chunks[paged_CHUNK_EXIF].iov_len = 0;
} }
chunks[CHUNK_DATA_0].iov_base = (void *)state->packetchunks[chunk_index].chunk; chunks[paged_CHUNK_DATA_0].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[CHUNK_DATA_0].iov_len = state->packetchunks[chunk_index++].bytes; chunks[paged_CHUNK_DATA_0].iov_len = state->packetchunks[chunk_index++].bytes;
if (state->writer_params.segments == 2) { if (state->writer_params.segments == 2) {
chunks[CHUNK_DATA_1].iov_base = (void *)state->packetchunks[chunk_index].chunk; chunks[paged_CHUNK_DATA_1].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[CHUNK_DATA_1].iov_len = state->packetchunks[chunk_index++].bytes; chunks[paged_CHUNK_DATA_1].iov_len = state->packetchunks[chunk_index++].bytes;
} else{ } else{
chunks[CHUNK_DATA_1].iov_base = chunks[CHUNK_DATA_0].iov_base; chunks[paged_CHUNK_DATA_1].iov_base = chunks[paged_CHUNK_DATA_0].iov_base;
chunks[CHUNK_DATA_1].iov_len = 0; chunks[paged_CHUNK_DATA_1].iov_len = 0;
} }
// chunks[CHUNK_TRAILER].iov_base = (void *)state->packetchunks[chunk_index].chunk; // chunks[CHUNK_TRAILER].iov_base = (void *)state->packetchunks[chunk_index].chunk;
if (is_tiff) { // Tiff if (is_tiff) { // Tiff
chunks[CHUNK_TRAILER].iov_base = (void *)state->packetchunks[chunk_index-1].chunk; // last used chunk (valid) chunks[paged_CHUNK_TRAILER].iov_base = (void *)state->packetchunks[chunk_index-1].chunk; // last used chunk (valid)
chunks[CHUNK_TRAILER].iov_len = 0; chunks[paged_CHUNK_TRAILER].iov_len = 0;
} else { } else {
chunks[CHUNK_TRAILER].iov_base = (void *)state->packetchunks[chunk_index].chunk; chunks[paged_CHUNK_TRAILER].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[CHUNK_TRAILER].iov_len = state->packetchunks[chunk_index].bytes; chunks[paged_CHUNK_TRAILER].iov_len = state->packetchunks[chunk_index].bytes;
} }
/* some data may be left from previous frame, copy it to special buffer */ /* some data may be left from previous frame, copy it to special buffer */
/*
if (chunks[CHUNK_REM].iov_len != 0) { if (chunks[CHUNK_REM].iov_len != 0) {
vectcpy(&state->writer_params.prev_rem_vect, chunks[CHUNK_REM].iov_base, chunks[CHUNK_REM].iov_len); vectcpy(&state->writer_params.prev_rem_vect, chunks[CHUNK_REM].iov_base, chunks[CHUNK_REM].iov_len);
vectshrink(&chunks[CHUNK_REM], chunks[CHUNK_REM].iov_len); vectshrink(chunk_rem, chunks[CHUNK_REM].iov_len);
}
*/
if (state->writer_params.was_CHUNK_REM.iov_len != 0) {
vectcpy(&state->writer_params.prev_rem_vect, state->writer_params.was_CHUNK_REM.iov_base, state->writer_params.was_CHUNK_REM.iov_len);
vectshrink(&(state->writer_params.was_CHUNK_REM), state->writer_params.was_CHUNK_REM.iov_len); // VERIFY !!! &()
} }
} }
/** Debug function, checks frame alignment */ /** Debug function, checks frame alignment */
static int check_chunks(struct iovec *vects) static int check_chunks(struct iovec *vects, int page)
{ {
int i; int i;
int ret = 0; int ret = 0;
size_t sz = 0; size_t sz = 0;
for (i = 0; i < MAX_DATA_CHUNKS; i++) { int chunk_offset = page * FILE_CHUNKS_NUM;
if (i != CHUNK_REM) { for (i = chunk_offset; i < FILE_CHUNKS_NUM + chunk_offset; i++) {
// if (i != CHUNK_REM) {
sz += vects[i].iov_len; sz += vects[i].iov_len;
if ((vects[i].iov_len % ALIGNMENT_SIZE) != 0) { if ((vects[i].iov_len % ALIGNMENT_SIZE) != 0) {
dev_dbg(NULL, "ERROR: unaligned write from slot %d, length %u\n", i, vects[i].iov_len); dev_dbg(NULL, "ERROR: unaligned write from slot %d, length %u\n", i, vects[i].iov_len);
ret = -1; ret = -1;
} }
} // }
dev_dbg(NULL, "chunk[%d]: ptr = %p, size = %d\n", i, vects[i].iov_base, vects[i].iov_len); dev_dbg(NULL, "chunk[%02d]: ptr = %p, size = %d\n", i, vects[i].iov_base, vects[i].iov_len);
} }
if ((sz % PHY_BLOCK_SIZE) != 0) { if ((sz % PHY_BLOCK_SIZE) != 0) {
dev_dbg(NULL, "ERROR: total length of the transaction is not aligned to sector boundary, total length %u\n", sz); dev_dbg(NULL, "ERROR: total length of the transaction is not aligned to sector boundary, total length %u\n", sz);
ret = -1; ret = -1;
} else { } else {
dev_dbg(NULL, "===== frame is OK =====\n"); dev_dbg(NULL, "===== frame is OK =====\n");
} }
return ret; return ret;
} }
...@@ -234,14 +278,18 @@ static size_t get_blocks_num(struct iovec *sgl, size_t n_elem) ...@@ -234,14 +278,18 @@ static size_t get_blocks_num(struct iovec *sgl, size_t n_elem)
/** Allocate and initialize buffers for frame alignment */ /** Allocate and initialize buffers for frame alignment */
int init_align_buffers(camogm_state *state) int init_align_buffers(camogm_state *state)
{ {
state->writer_params.data_chunks = (struct iovec *)malloc(MAX_DATA_CHUNKS * sizeof(struct iovec)); int i;
// state->writer_params.data_chunks = (struct iovec *)malloc(MAX_DATA_CHUNKS * sizeof(struct iovec));
state->writer_params.data_chunks = (struct iovec *)malloc(FILE_CHUNKS_TOTAL * sizeof(struct iovec)); // does not include CHUNK_REM
if (state->writer_params.data_chunks == NULL) { if (state->writer_params.data_chunks == NULL) {
return -1; return -1;
} }
state->writer_params.common_buff = (unsigned char *)malloc(COMMON_BUFF_SZ); for (i= 0; i < FILE_CHUNKS_PAGES; i++) {
if (state->writer_params.common_buff == NULL) { state->writer_params.common_buffs[i] = (unsigned char *)malloc(COMMON_BUFF_SZ);
deinit_align_buffers(state); if (state->writer_params.common_buffs[i] == NULL) {
return -1; deinit_align_buffers(state);
return -1;
}
} }
state->writer_params.rem_buff = (unsigned char *)malloc(REM_BUFF_SZ); state->writer_params.rem_buff = (unsigned char *)malloc(REM_BUFF_SZ);
if (state->writer_params.rem_buff == NULL) { if (state->writer_params.rem_buff == NULL) {
...@@ -253,12 +301,16 @@ int init_align_buffers(camogm_state *state) ...@@ -253,12 +301,16 @@ int init_align_buffers(camogm_state *state)
deinit_align_buffers(state); deinit_align_buffers(state);
return -1; return -1;
} }
for (i= 0; i < FILE_CHUNKS_PAGES; i++) {
state->writer_params.data_chunks[CHUNK_COMMON].iov_base = (void *)state->writer_params.common_buff; state->writer_params.data_chunks[FILE_CHUNKS_NUM* i + CHUNK_COMMON].iov_base = (void *)state->writer_params.common_buffs[i];
state->writer_params.data_chunks[CHUNK_COMMON].iov_len = 0; state->writer_params.data_chunks[FILE_CHUNKS_NUM* i + CHUNK_COMMON].iov_len = 0;
}
state->writer_params.data_chunks[CHUNK_REM].iov_base = (void *)state->writer_params.rem_buff; //was_CHUNK_REM
state->writer_params.data_chunks[CHUNK_REM].iov_len = 0; // state->writer_params.data_chunks[CHUNK_REM].iov_base = (void *)state->writer_params.rem_buff;
// state->writer_params.data_chunks[CHUNK_REM].iov_len = 0;
// this is a single array
state->writer_params.was_CHUNK_REM.iov_base = (void *)state->writer_params.rem_buff;
state->writer_params.was_CHUNK_REM.iov_len = 0;
state->writer_params.prev_rem_vect.iov_base = (void *)state->writer_params.prev_rem_buff; state->writer_params.prev_rem_vect.iov_base = (void *)state->writer_params.prev_rem_buff;
state->writer_params.prev_rem_vect.iov_len = 0; state->writer_params.prev_rem_vect.iov_len = 0;
...@@ -270,14 +322,16 @@ int init_align_buffers(camogm_state *state) ...@@ -270,14 +322,16 @@ int init_align_buffers(camogm_state *state)
void deinit_align_buffers(camogm_state *state) void deinit_align_buffers(camogm_state *state)
{ {
struct writer_params *params = &state->writer_params; struct writer_params *params = &state->writer_params;
int i;
if (params->data_chunks) { if (params->data_chunks) {
free(params->data_chunks); free(params->data_chunks);
params->data_chunks = NULL; params->data_chunks = NULL;
} }
if (params->common_buff) { for (i= 0; i < FILE_CHUNKS_PAGES; i++) {
free(params->common_buff); if (params->common_buffs[i]) {
params->common_buff = NULL; free(params->common_buffs[i]);
params->common_buffs[i] = NULL;
}
} }
if (params->rem_buff) { if (params->rem_buff) {
free(params->rem_buff); free(params->rem_buff);
...@@ -295,35 +349,61 @@ void align_frame(camogm_state *state) ...@@ -295,35 +349,61 @@ void align_frame(camogm_state *state)
const char *dev = NULL; const char *dev = NULL;
unsigned char *src; unsigned char *src;
size_t len, total_sz, data_len; size_t len, total_sz, data_len;
struct iovec *chunks = state->writer_params.data_chunks; int page = state->writer_params.chunk_page_prep % FILE_CHUNKS_PAGES;
struct iovec *cbuff = &chunks[CHUNK_COMMON]; int chunk_offset = page * FILE_CHUNKS_NUM;
int paged_CHUNK_LEADER = chunk_offset + CHUNK_LEADER;
int paged_CHUNK_EXIF = chunk_offset + CHUNK_EXIF;
int paged_CHUNK_HEADER = chunk_offset + CHUNK_HEADER;
int paged_CHUNK_COMMON = chunk_offset + CHUNK_COMMON;
int paged_CHUNK_DATA_0 = chunk_offset + CHUNK_DATA_0;
int paged_CHUNK_DATA_1 = chunk_offset + CHUNK_DATA_1;
int paged_CHUNK_TRAILER = chunk_offset + CHUNK_TRAILER;
int paged_CHUNK_ALIGN = chunk_offset + CHUNK_ALIGN;
struct iovec *chunks = state->writer_params.data_chunks;
struct iovec *chunk_rem = &(state->writer_params.was_CHUNK_REM);
struct iovec *cbuff = &chunks[paged_CHUNK_COMMON];
struct iovec *rbuff = &state->writer_params.prev_rem_vect; struct iovec *rbuff = &state->writer_params.prev_rem_vect;
remap_vectors(state, chunks); remap_vectors(state, chunks); // now multi-page
total_sz = get_size_from(chunks, 0, 0, INCLUDE_REM) + rbuff->iov_len; // total_sz = get_size_from(chunks, 0, 0, INCLUDE_REM) + rbuff->iov_len;
total_sz = get_size_from_paged(state, 0, INCLUDE_REM) + rbuff->iov_len;
D4(fprintf(debug_file, "total_sz = %d, rbuff->iov_len=%d\n", total_sz, (int)(rbuff->iov_len))); D4(fprintf(debug_file, "total_sz = %d, rbuff->iov_len=%d\n", total_sz, (int)(rbuff->iov_len)));
if (total_sz < PHY_BLOCK_SIZE) { if (total_sz < PHY_BLOCK_SIZE) {
/* the frame length is less than sector size, delay this frame */ /* the frame length is less than sector size, delay this frame */
if (rbuff->iov_len != 0) { if (rbuff->iov_len != 0) {
/* some data may be left from previous frame */ /* some data may be left from previous frame */
vectcpy(&chunks[CHUNK_REM], rbuff->iov_base, rbuff->iov_len); // vectcpy(&chunks[CHUNK_REM], rbuff->iov_base, rbuff->iov_len);
vectcpy(chunk_rem, rbuff->iov_base, rbuff->iov_len);
//state->writer_params.was_CHUNK_REM
vectshrink(rbuff, rbuff->iov_len); vectshrink(rbuff, rbuff->iov_len);
D4(fprintf(debug_file, "copied rbuff->iov_len = %d\n", rbuff->iov_len)); D4(fprintf(debug_file, "copied rbuff->iov_len = %d\n", rbuff->iov_len));
} }
dev_dbg(dev, "frame size is less than sector size: %u bytes; delay recording\n", total_sz); dev_dbg(dev, "frame size is less than sector size: %u bytes; delay recording\n", total_sz);
vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_LEADER].iov_base, chunks[CHUNK_LEADER].iov_len); // vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_LEADER].iov_base, chunks[CHUNK_LEADER].iov_len);
vectshrink (&chunks[CHUNK_LEADER], chunks[CHUNK_LEADER].iov_len); // vectshrink (&chunks[CHUNK_LEADER], chunks[CHUNK_LEADER].iov_len);
vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_EXIF].iov_base, chunks[CHUNK_EXIF].iov_len); // vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_EXIF].iov_base, chunks[CHUNK_EXIF].iov_len);
vectshrink (&chunks[CHUNK_EXIF], chunks[CHUNK_EXIF].iov_len); // vectshrink (&chunks[CHUNK_EXIF], chunks[CHUNK_EXIF].iov_len);
vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_HEADER].iov_base, chunks[CHUNK_HEADER].iov_len); // vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_HEADER].iov_base, chunks[CHUNK_HEADER].iov_len);
vectshrink (&chunks[CHUNK_HEADER], chunks[CHUNK_HEADER].iov_len); // vectshrink (&chunks[CHUNK_HEADER], chunks[CHUNK_HEADER].iov_len);
vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_DATA_0].iov_base, chunks[CHUNK_DATA_0].iov_len); // vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_DATA_0].iov_base, chunks[CHUNK_DATA_0].iov_len);
vectshrink (&chunks[CHUNK_DATA_0], chunks[CHUNK_DATA_0].iov_len); // vectshrink (&chunks[CHUNK_DATA_0], chunks[CHUNK_DATA_0].iov_len);
vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_DATA_1].iov_base, chunks[CHUNK_DATA_1].iov_len); // vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_DATA_1].iov_base, chunks[CHUNK_DATA_1].iov_len);
vectshrink (&chunks[CHUNK_DATA_1], chunks[CHUNK_DATA_1].iov_len); // vectshrink (&chunks[CHUNK_DATA_1], chunks[CHUNK_DATA_1].iov_len);
vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_TRAILER].iov_base, chunks[CHUNK_TRAILER].iov_len); // vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_TRAILER].iov_base, chunks[CHUNK_TRAILER].iov_len);
vectshrink (&chunks[CHUNK_TRAILER], chunks[CHUNK_TRAILER].iov_len); // vectshrink (&chunks[CHUNK_TRAILER], chunks[CHUNK_TRAILER].iov_len);
vectcpy (chunk_rem, chunks[paged_CHUNK_LEADER].iov_base, chunks[paged_CHUNK_LEADER].iov_len);
vectshrink (&chunks[paged_CHUNK_LEADER], chunks[paged_CHUNK_LEADER].iov_len);
vectcpy (chunk_rem, chunks[paged_CHUNK_EXIF].iov_base, chunks[paged_CHUNK_EXIF].iov_len);
vectshrink (&chunks[paged_CHUNK_EXIF], chunks[paged_CHUNK_EXIF].iov_len);
vectcpy (chunk_rem, chunks[paged_CHUNK_HEADER].iov_base, chunks[paged_CHUNK_HEADER].iov_len);
vectshrink (&chunks[paged_CHUNK_HEADER], chunks[paged_CHUNK_HEADER].iov_len);
vectcpy (chunk_rem, chunks[paged_CHUNK_DATA_0].iov_base, chunks[paged_CHUNK_DATA_0].iov_len);
vectshrink (&chunks[paged_CHUNK_DATA_0], chunks[paged_CHUNK_DATA_0].iov_len);
vectcpy (chunk_rem, chunks[paged_CHUNK_DATA_1].iov_base, chunks[paged_CHUNK_DATA_1].iov_len);
vectshrink (&chunks[paged_CHUNK_DATA_1], chunks[paged_CHUNK_DATA_1].iov_len);
vectcpy (chunk_rem, chunks[paged_CHUNK_TRAILER].iov_base, chunks[paged_CHUNK_TRAILER].iov_len);
vectshrink (&chunks[paged_CHUNK_TRAILER], chunks[paged_CHUNK_TRAILER].iov_len);
return; return;
} }
...@@ -338,39 +418,39 @@ void align_frame(camogm_state *state) ...@@ -338,39 +418,39 @@ void align_frame(camogm_state *state)
/*Calculate alignment size and add zeros here*/ /*Calculate alignment size and add zeros here*/
#ifdef ALIGN_INTERFRAME #ifdef ALIGN_INTERFRAME
// calculate length after adding CHUNK_LEADER, CHUNK_EXIF and CHUNK_HEADER to the current cbuf // calculate length after adding CHUNK_LEADER, CHUNK_EXIF and CHUNK_HEADER to the current cbuf
data_len = cbuff->iov_len + chunks[CHUNK_LEADER].iov_len + chunks[CHUNK_EXIF].iov_len+ chunks[CHUNK_HEADER].iov_len; data_len = cbuff->iov_len + chunks[paged_CHUNK_LEADER].iov_len + chunks[paged_CHUNK_EXIF].iov_len+ chunks[paged_CHUNK_HEADER].iov_len;
len = align_bytes_num(data_len, ALIGNMENT_SIZE); len = align_bytes_num(data_len, ALIGNMENT_SIZE);
dev_dbg(dev, "total number of stuffing bytes between frames: %u\n", len); dev_dbg(dev, "total number of stuffing bytes between frames: %u\n", len);
vectset(cbuff, 0, len); vectset(cbuff, 0, len);
#endif #endif
/* copy JPEG marker if present */ /* copy JPEG marker if present */
if (chunks[CHUNK_LEADER].iov_len != 0) { if (chunks[paged_CHUNK_LEADER].iov_len != 0) {
len = chunks[CHUNK_LEADER].iov_len; len = chunks[paged_CHUNK_LEADER].iov_len;
dev_dbg(dev, "copy %u bytes from LEADER to common buffer\n", len); dev_dbg(dev, "copy %u bytes from LEADER to common buffer\n", len);
vectcpy(cbuff, chunks[CHUNK_LEADER].iov_base, len); vectcpy(cbuff, chunks[paged_CHUNK_LEADER].iov_base, len);
vectshrink(&chunks[CHUNK_LEADER], chunks[CHUNK_LEADER].iov_len); vectshrink(&chunks[paged_CHUNK_LEADER], chunks[paged_CHUNK_LEADER].iov_len);
} }
/* copy Exif if present */ /* copy Exif if present */
if (chunks[CHUNK_EXIF].iov_len != 0) { if (chunks[paged_CHUNK_EXIF].iov_len != 0) {
len = chunks[CHUNK_EXIF].iov_len; len = chunks[paged_CHUNK_EXIF].iov_len;
dev_dbg(dev, "copy %u bytes from EXIF to common buffer\n", len); dev_dbg(dev, "copy %u bytes from EXIF to common buffer\n", len);
vectcpy(cbuff, chunks[CHUNK_EXIF].iov_base, len); vectcpy(cbuff, chunks[paged_CHUNK_EXIF].iov_base, len);
vectshrink(&chunks[CHUNK_EXIF], chunks[CHUNK_EXIF].iov_len); vectshrink(&chunks[paged_CHUNK_EXIF], chunks[paged_CHUNK_EXIF].iov_len);
} }
#ifdef ALIGN_INTERFRAME #ifdef ALIGN_INTERFRAME
/* copy JPEG JPEG header data excluding leading marker if present */ /* copy JPEG JPEG header data excluding leading marker if present */
if (chunks[CHUNK_HEADER].iov_len != 0) { if (chunks[paged_CHUNK_HEADER].iov_len != 0) {
len = chunks[CHUNK_HEADER].iov_len; len = chunks[paged_CHUNK_HEADER].iov_len;
dev_dbg(dev, "copy %u bytes from LEADER to common buffer\n", len); dev_dbg(dev, "copy %u bytes from LEADER to common buffer\n", len);
vectcpy(cbuff, chunks[CHUNK_HEADER].iov_base, len); vectcpy(cbuff, chunks[paged_CHUNK_HEADER].iov_base, len);
vectshrink(&chunks[CHUNK_HEADER], chunks[CHUNK_HEADER].iov_len); vectshrink(&chunks[paged_CHUNK_HEADER], chunks[paged_CHUNK_HEADER].iov_len);
} }
#else // old way with app15 #else // old way with app15
if (chunks[CHUNK_HEADER].iov_len != 0){ // only if it is not TIFF if (chunks[paged_CHUNK_HEADER].iov_len != 0){ // only if it is not TIFF
/* align common buffer to ALIGNMENT boundary, APP15 marker should be placed before header data */ /* align common buffer to ALIGNMENT boundary, APP15 marker should be placed before header data */
data_len = cbuff->iov_len + chunks[CHUNK_HEADER].iov_len; data_len = cbuff->iov_len + chunks[paged_CHUNK_HEADER].iov_len;
len = align_bytes_num(data_len, ALIGNMENT_SIZE); len = align_bytes_num(data_len, ALIGNMENT_SIZE);
if (len < (JPEG_MARKER_LEN + JPEG_SIZE_LEN) && len != 0) { if (len < (JPEG_MARKER_LEN + JPEG_SIZE_LEN) && len != 0) {
...@@ -381,160 +461,174 @@ void align_frame(camogm_state *state) ...@@ -381,160 +461,174 @@ void align_frame(camogm_state *state)
app15[3] = len - JPEG_MARKER_LEN; app15[3] = len - JPEG_MARKER_LEN;
vectcpy(cbuff, app15, len); vectcpy(cbuff, app15, len);
/* copy JPEG header */ /* copy JPEG header */
len = chunks[CHUNK_HEADER].iov_len; len = chunks[paged_CHUNK_HEADER].iov_len;
dev_dbg(dev, "copy %u bytes from HEADER to common buffer\n", len); dev_dbg(dev, "copy %u bytes from HEADER to common buffer\n", len);
vectcpy(cbuff, chunks[CHUNK_HEADER].iov_base, len); vectcpy(cbuff, chunks[paged_CHUNK_HEADER].iov_base, len);
vectshrink(&chunks[CHUNK_HEADER], chunks[CHUNK_HEADER].iov_len); vectshrink(&chunks[paged_CHUNK_HEADER], chunks[paged_CHUNK_HEADER].iov_len);
} else { // for Tiff (may be the same for Jpeg too - borrow data from the image data, copy up to 31 bytes to the end of the common buffer, } else { // for Tiff (may be the same for Jpeg too - borrow data from the image data, copy up to 31 bytes to the end of the common buffer,
// move start of the data_0 accordingly // move start of the data_0 accordingly
data_len = cbuff->iov_len; data_len = cbuff->iov_len;
len = align_bytes_num(data_len, ALIGNMENT_SIZE); len = align_bytes_num(data_len, ALIGNMENT_SIZE);
if (len){ // assuming image data > 32 bits if (len){ // assuming image data > 32 bits
vectcpy(cbuff, chunks[CHUNK_DATA_0].iov_base, len); vectcpy(cbuff, chunks[paged_CHUNK_DATA_0].iov_base, len);
vectshrinkhead(&chunks[CHUNK_DATA_0],len); vectshrinkhead(&chunks[paged_CHUNK_DATA_0],len);
} }
} }
#endif #endif
/* check if there is enough data to continue - JPEG data length can be too short */ /* check if there is enough data to continue - JPEG data length can be too short */
len = get_size_from(chunks, CHUNK_DATA_0, 0, EXCLUDE_REM); // len = get_size_from (chunks, CHUNK_DATA_0, 0, EXCLUDE_REM);
len = get_size_from_paged(state, CHUNK_DATA_0, EXCLUDE_REM); // here not paged_CHUNK_DATA_0, offset will be added in get_size_from_paged
if (len < PHY_BLOCK_SIZE) { if (len < PHY_BLOCK_SIZE) {
size_t num = align_bytes_num(cbuff->iov_len, PHY_BLOCK_SIZE); size_t num = align_bytes_num(cbuff->iov_len, PHY_BLOCK_SIZE);
dev_dbg(dev, "jpeg data is too short, delay this frame\n"); // never happened? dev_dbg(dev, "jpeg data is too short, delay this frame\n"); // never happened?
if (len >= num) { if (len >= num) {
/* there is enough data to align common buffer to sector boundary */ /* there is enough data to align common buffer to sector boundary */
if (num >= chunks[CHUNK_DATA_0].iov_len) { if (num >= chunks[paged_CHUNK_DATA_0].iov_len) {
vectcpy(cbuff, chunks[CHUNK_DATA_0].iov_base, chunks[CHUNK_DATA_0].iov_len); vectcpy(cbuff, chunks[paged_CHUNK_DATA_0].iov_base, chunks[paged_CHUNK_DATA_0].iov_len);
num -= chunks[CHUNK_DATA_0].iov_len; num -= chunks[paged_CHUNK_DATA_0].iov_len;
vectshrink(&chunks[CHUNK_DATA_0], chunks[CHUNK_DATA_0].iov_len); vectshrink(&chunks[paged_CHUNK_DATA_0], chunks[paged_CHUNK_DATA_0].iov_len);
} else { } else {
src = vectrpos(&chunks[CHUNK_DATA_0], num); src = vectrpos(&chunks[paged_CHUNK_DATA_0], num);
vectcpy(cbuff, chunks[CHUNK_DATA_0].iov_base, num); vectcpy(cbuff, chunks[paged_CHUNK_DATA_0].iov_base, num);
vectshrink(&chunks[CHUNK_DATA_0], num); vectshrink(&chunks[paged_CHUNK_DATA_0], num);
num = 0; num = 0;
} }
if (num >= chunks[CHUNK_DATA_1].iov_len) { if (chunks[paged_CHUNK_DATA_1].iov_len > 0) {
vectcpy(cbuff, chunks[CHUNK_DATA_1].iov_base, chunks[CHUNK_DATA_1].iov_len); if (num >= chunks[paged_CHUNK_DATA_1].iov_len) {
num -= chunks[CHUNK_DATA_1].iov_len; vectcpy(cbuff, chunks[paged_CHUNK_DATA_1].iov_base, chunks[paged_CHUNK_DATA_1].iov_len);
vectshrink(&chunks[CHUNK_DATA_1], chunks[CHUNK_DATA_1].iov_len); num -= chunks[paged_CHUNK_DATA_1].iov_len;
} else { vectshrink(&chunks[paged_CHUNK_DATA_1], chunks[paged_CHUNK_DATA_1].iov_len);
src = vectrpos(&chunks[CHUNK_DATA_1], num); } else {
vectcpy(cbuff, chunks[CHUNK_DATA_1].iov_base, num); src = vectrpos(&chunks[paged_CHUNK_DATA_1], num);
vectshrink(&chunks[CHUNK_DATA_1], num); vectcpy(cbuff, chunks[paged_CHUNK_DATA_1].iov_base, num);
num = 0; vectshrink(&chunks[paged_CHUNK_DATA_1], num);
num = 0;
}
} }
if (num >= chunks[CHUNK_TRAILER].iov_len) { if (chunks[paged_CHUNK_TRAILER].iov_len > 0) {
vectcpy(cbuff, chunks[CHUNK_TRAILER].iov_base, chunks[CHUNK_TRAILER].iov_len); if (num >= chunks[paged_CHUNK_TRAILER].iov_len) {
num -= chunks[CHUNK_TRAILER].iov_len; vectcpy(cbuff, chunks[paged_CHUNK_TRAILER].iov_base, chunks[paged_CHUNK_TRAILER].iov_len);
vectshrink(&chunks[CHUNK_TRAILER], chunks[CHUNK_TRAILER].iov_len); num -= chunks[paged_CHUNK_TRAILER].iov_len;
} else { vectshrink(&chunks[paged_CHUNK_TRAILER], chunks[paged_CHUNK_TRAILER].iov_len);
src = vectrpos(&chunks[CHUNK_TRAILER], num); } else {
vectcpy(cbuff, chunks[CHUNK_TRAILER].iov_base, num); src = vectrpos(&chunks[paged_CHUNK_TRAILER], num);
vectshrink(&chunks[CHUNK_TRAILER], num); vectcpy(cbuff, chunks[paged_CHUNK_TRAILER].iov_base, num);
num = 0; vectshrink(&chunks[paged_CHUNK_TRAILER], num);
num = 0;
}
} }
} else { } else {
/* there is not enough data to align common buffer to sector boundary, truncate common buffer */ /* there is not enough data to align common buffer to sector boundary, truncate common buffer */
data_len = cbuff->iov_len % PHY_BLOCK_SIZE; data_len = cbuff->iov_len % PHY_BLOCK_SIZE;
src = vectrpos(cbuff, data_len); src = vectrpos(cbuff, data_len);
vectcpy(&chunks[CHUNK_REM], src, data_len); vectcpy(chunk_rem, src, data_len);
vectshrink(cbuff, data_len); vectshrink(cbuff, data_len);
} }
vectcpy(&chunks[CHUNK_REM], chunks[CHUNK_DATA_0].iov_base, chunks[CHUNK_DATA_0].iov_len); vectcpy(chunk_rem, chunks[paged_CHUNK_DATA_0].iov_base, chunks[paged_CHUNK_DATA_0].iov_len);
vectshrink(&chunks[CHUNK_DATA_0], chunks[CHUNK_DATA_0].iov_len); vectshrink(&chunks[paged_CHUNK_DATA_0], chunks[paged_CHUNK_DATA_0].iov_len);
vectcpy(&chunks[CHUNK_REM], chunks[CHUNK_DATA_1].iov_base, chunks[CHUNK_DATA_1].iov_len); vectcpy(chunk_rem, chunks[CHUNK_DATA_1].iov_base, chunks[paged_CHUNK_DATA_1].iov_len);
vectshrink(&chunks[CHUNK_DATA_1], chunks[CHUNK_DATA_1].iov_len); vectshrink(&chunks[paged_CHUNK_DATA_1], chunks[CHUNK_DATA_1].iov_len);
vectcpy(&chunks[CHUNK_REM], chunks[CHUNK_TRAILER].iov_base, chunks[CHUNK_TRAILER].iov_len); vectcpy(chunk_rem, chunks[CHUNK_TRAILER].iov_base, chunks[paged_CHUNK_TRAILER].iov_len);
vectshrink(&chunks[CHUNK_TRAILER], chunks[CHUNK_TRAILER].iov_len); vectshrink(&chunks[paged_CHUNK_TRAILER], chunks[paged_CHUNK_TRAILER].iov_len);
return; return;
} }
/* align frame to sector size boundary; total size could have changed by the moment - recalculate */ /* align frame to sector size boundary; total size could have changed by the moment - recalculate */
total_sz = get_size_from(chunks, 0, 0, INCLUDE_REM); // total_sz = get_size_from (chunks, 0, 0, INCLUDE_REM);
total_sz = get_size_from_paged(state, 0, INCLUDE_REM);
len = total_sz % PHY_BLOCK_SIZE; len = total_sz % PHY_BLOCK_SIZE;
dev_dbg(dev, "number of bytes crossing sector boundary: %u\n", len); dev_dbg(dev, "number of bytes crossing sector boundary: %u\n", len);
if (len != 0) { if (len != 0) {
if (len >= (chunks[CHUNK_DATA_1].iov_len + chunks[CHUNK_TRAILER].iov_len)) { if (len >= (chunks[paged_CHUNK_DATA_1].iov_len + chunks[paged_CHUNK_TRAILER].iov_len)) {
/* current frame is not split or the second part of JPEG data is too short */ /* current frame is not split or the second part of JPEG data is too short */
data_len = len - chunks[CHUNK_DATA_1].iov_len - chunks[CHUNK_TRAILER].iov_len; data_len = len - chunks[paged_CHUNK_DATA_1].iov_len - chunks[paged_CHUNK_TRAILER].iov_len;
src = vectrpos(&chunks[CHUNK_DATA_0], data_len); src = vectrpos(&chunks[paged_CHUNK_DATA_0], data_len);
vectcpy(&chunks[CHUNK_REM], src, data_len); vectcpy(chunk_rem, src, data_len);
vectshrink(&chunks[CHUNK_DATA_0], data_len); vectshrink(&chunks[paged_CHUNK_DATA_0], data_len);
vectcpy(&chunks[CHUNK_REM], chunks[CHUNK_DATA_1].iov_base, chunks[CHUNK_DATA_1].iov_len); vectcpy(chunk_rem, chunks[paged_CHUNK_DATA_1].iov_base, chunks[paged_CHUNK_DATA_1].iov_len);
vectshrink(&chunks[CHUNK_DATA_1], chunks[CHUNK_DATA_1].iov_len); vectshrink(&chunks[paged_CHUNK_DATA_1], chunks[paged_CHUNK_DATA_1].iov_len);
vectcpy(&chunks[CHUNK_REM], chunks[CHUNK_TRAILER].iov_base, chunks[CHUNK_TRAILER].iov_len); vectcpy(chunk_rem, chunks[paged_CHUNK_TRAILER].iov_base, chunks[paged_CHUNK_TRAILER].iov_len);
vectshrink(&chunks[CHUNK_TRAILER], chunks[CHUNK_TRAILER].iov_len); vectshrink(&chunks[paged_CHUNK_TRAILER], chunks[paged_CHUNK_TRAILER].iov_len);
} else if (len >= chunks[CHUNK_TRAILER].iov_len) { } else if (len >= chunks[paged_CHUNK_TRAILER].iov_len) {
/* there is enough data in second part to align the frame */ /* there is enough data in second part to align the frame */
data_len = len - chunks[CHUNK_TRAILER].iov_len; data_len = len - chunks[paged_CHUNK_TRAILER].iov_len;
src = vectrpos(&chunks[CHUNK_DATA_1], data_len); src = vectrpos(&chunks[paged_CHUNK_DATA_1], data_len);
vectcpy(&chunks[CHUNK_REM], src, data_len); vectcpy(chunk_rem, src, data_len);
vectshrink(&chunks[CHUNK_DATA_1], data_len); vectshrink(&chunks[paged_CHUNK_DATA_1], data_len);
vectcpy(&chunks[CHUNK_REM], chunks[CHUNK_TRAILER].iov_base, chunks[CHUNK_TRAILER].iov_len); vectcpy(chunk_rem, chunks[paged_CHUNK_TRAILER].iov_base, chunks[paged_CHUNK_TRAILER].iov_len);
vectshrink(&chunks[CHUNK_TRAILER], chunks[CHUNK_TRAILER].iov_len); vectshrink(&chunks[paged_CHUNK_TRAILER], chunks[paged_CHUNK_TRAILER].iov_len);
} else { } else {
/* the trailing marker is split by sector boundary, copy (PHY_BLOCK_SIZE - 1) bytes from /* the trailing marker is split by sector boundary, copy (PHY_BLOCK_SIZE - 1) bytes from
* JPEG data block(s) to remainder buffer and then add trailing marker */ * JPEG data block(s) to remainder buffer and then add trailing marker */
data_len = PHY_BLOCK_SIZE - (chunks[CHUNK_TRAILER].iov_len - len); data_len = PHY_BLOCK_SIZE - (chunks[paged_CHUNK_TRAILER].iov_len - len);
if (data_len >= chunks[CHUNK_DATA_1].iov_len) { if (data_len >= chunks[paged_CHUNK_DATA_1].iov_len) {
size_t cut_len = data_len - chunks[CHUNK_DATA_1].iov_len; size_t cut_len = data_len - chunks[paged_CHUNK_DATA_1].iov_len;
src = vectrpos(&chunks[CHUNK_DATA_0], cut_len); src = vectrpos(&chunks[paged_CHUNK_DATA_0], cut_len);
vectcpy(&chunks[CHUNK_REM], src, cut_len); vectcpy(chunk_rem, src, cut_len);
vectshrink(&chunks[CHUNK_DATA_0], cut_len); vectshrink(&chunks[paged_CHUNK_DATA_0], cut_len);
vectcpy(&chunks[CHUNK_REM], chunks[CHUNK_DATA_1].iov_base, chunks[CHUNK_DATA_1].iov_len); vectcpy(chunk_rem, chunks[paged_CHUNK_DATA_1].iov_base, chunks[paged_CHUNK_DATA_1].iov_len);
vectshrink(&chunks[CHUNK_DATA_1], chunks[CHUNK_DATA_1].iov_len); vectshrink(&chunks[paged_CHUNK_DATA_1], chunks[paged_CHUNK_DATA_1].iov_len);
vectcpy(&chunks[CHUNK_REM], chunks[CHUNK_TRAILER].iov_base, chunks[CHUNK_TRAILER].iov_len); vectcpy(chunk_rem, chunks[paged_CHUNK_TRAILER].iov_base, chunks[paged_CHUNK_TRAILER].iov_len);
vectshrink(&chunks[CHUNK_TRAILER], chunks[CHUNK_TRAILER].iov_len); vectshrink(&chunks[paged_CHUNK_TRAILER], chunks[paged_CHUNK_TRAILER].iov_len);
} else { } else {
src = vectrpos(&chunks[CHUNK_DATA_1], data_len); src = vectrpos(&chunks[paged_CHUNK_DATA_1], data_len);
vectcpy(&chunks[CHUNK_REM], src, data_len); vectcpy(chunk_rem, src, data_len);
vectshrink(&chunks[CHUNK_DATA_1], data_len); vectshrink(&chunks[paged_CHUNK_DATA_1], data_len);
vectcpy(&chunks[CHUNK_REM], chunks[CHUNK_TRAILER].iov_base, chunks[CHUNK_TRAILER].iov_len); vectcpy(&chunks[CHUNK_REM], chunks[paged_CHUNK_TRAILER].iov_base, chunks[paged_CHUNK_TRAILER].iov_len);
vectshrink(&chunks[CHUNK_TRAILER], chunks[CHUNK_TRAILER].iov_len); vectshrink(&chunks[paged_CHUNK_TRAILER], chunks[paged_CHUNK_TRAILER].iov_len);
} }
} }
} else { } else {
/* the frame is aligned to sector boundary but some buffers may be not */ /* the frame is aligned to sector boundary but some buffers may be not */
chunks[CHUNK_ALIGN].iov_base = vectrpos(cbuff, 0); chunks[paged_CHUNK_ALIGN].iov_base = vectrpos(cbuff, 0);
chunks[CHUNK_ALIGN].iov_len = 0; chunks[paged_CHUNK_ALIGN].iov_len = 0;
if (chunks[CHUNK_DATA_1].iov_len == 0) { if (chunks[paged_CHUNK_DATA_1].iov_len == 0) {
data_len = chunks[CHUNK_DATA_0].iov_len % ALIGNMENT_SIZE; data_len = chunks[paged_CHUNK_DATA_0].iov_len % ALIGNMENT_SIZE;
src = vectrpos(&chunks[CHUNK_DATA_0], data_len); src = vectrpos(&chunks[CHUNK_DATA_0], data_len);
vectcpy(&chunks[CHUNK_ALIGN], src, data_len); vectcpy(&chunks[paged_CHUNK_ALIGN], src, data_len);
vectshrink(&chunks[CHUNK_DATA_0], data_len); vectshrink(&chunks[paged_CHUNK_DATA_0], data_len);
} else { } else {
data_len = chunks[CHUNK_DATA_1].iov_len % ALIGNMENT_SIZE; data_len = chunks[paged_CHUNK_DATA_1].iov_len % ALIGNMENT_SIZE;
src = vectrpos(&chunks[CHUNK_DATA_1], data_len); src = vectrpos(&chunks[paged_CHUNK_DATA_1], data_len);
vectcpy(&chunks[CHUNK_ALIGN], src, data_len); vectcpy(&chunks[paged_CHUNK_ALIGN], src, data_len);
vectshrink(&chunks[CHUNK_DATA_1], data_len); vectshrink(&chunks[paged_CHUNK_DATA_1], data_len);
} }
vectcpy(&chunks[CHUNK_ALIGN], chunks[CHUNK_TRAILER].iov_base, chunks[CHUNK_TRAILER].iov_len); vectcpy(&chunks[paged_CHUNK_ALIGN], chunks[paged_CHUNK_TRAILER].iov_base, chunks[paged_CHUNK_TRAILER].iov_len);
vectshrink(&chunks[CHUNK_TRAILER], chunks[CHUNK_TRAILER].iov_len); vectshrink(&chunks[paged_CHUNK_TRAILER], chunks[paged_CHUNK_TRAILER].iov_len);
} }
/* debug sanity check, should not happen */ /* debug sanity check, should not happen */
if (cbuff->iov_len >= COMMON_BUFF_SZ) { if (cbuff->iov_len >= COMMON_BUFF_SZ) {
dev_dbg(NULL, "ERROR: the number of bytes copied to common buffer exceeds its size\n"); dev_dbg(NULL, "ERROR: the number of bytes copied to common buffer exceeds its size\n");
} }
check_chunks(chunks); check_chunks(chunks, page);
D6(fprintf(debug_file, "align_frame() DONE @ %06d\n", get_fpga_usec(state->fd_fparmsall[0], 0)));
} }
/** Discard buffer pointers which makes the command slot marked as empty */ /** Discard buffer pointers making the command slot marked as empty */
void reset_chunks(struct iovec *vects, int all) //void reset_chunks(struct iovec *vects, int all, int page)
void reset_chunks(camogm_state *state, int all, int page)
{ {
int i; int i;
struct iovec *vects = state->writer_params.data_chunks;
for (i = 0; i < MAX_DATA_CHUNKS; i++) { int chunk_offset = page * FILE_CHUNKS_NUM;
if (i != CHUNK_REM) for (i = chunk_offset; i < (chunk_offset + FILE_CHUNKS_NUM); i++) {
vects[i].iov_len = 0; vects[i].iov_len = 0;
} }
if (all) { if (all) {
vects[CHUNK_REM].iov_len = 0; // vects[CHUNK_REM].iov_len = 0;
state->writer_params.was_CHUNK_REM.iov_len = 0;
} }
} }
/** Calculate and update LBA offsets, do not count remainder buffer. Return 1 if file position should be reset to the start */ /** Calculate and update LBA offsets, do not count remainder buffer. Return 1 if file position should be reset to the start */
// WRONG calculation - should be split?
/*
int update_lba(camogm_state *state) int update_lba(camogm_state *state)
{ {
int ret = 0; int ret = 0;
...@@ -551,18 +645,19 @@ int update_lba(camogm_state *state) ...@@ -551,18 +645,19 @@ int update_lba(camogm_state *state)
return ret; return ret;
} }
*/
/** Go through all data buffers and pick only mapped ones excluding remainder buffer */ /** Go through all data buffers and pick only mapped ones excluding remainder buffer */
int get_data_buffers(camogm_state *state, struct iovec *mapped, size_t mapped_sz) int get_data_buffers(camogm_state *state, struct iovec *mapped, size_t mapped_sz, int page)
{ {
int ret = 0; int ret = 0;
struct iovec *all = state->writer_params.data_chunks; struct iovec *all = state->writer_params.data_chunks;
int chunk_offset = page * FILE_CHUNKS_NUM;
if (mapped_sz <= 0) if (mapped_sz <= 0)
return ret; return ret;
for (int i = 0, j = 0; i < MAX_DATA_CHUNKS; i++) { for (int i = chunk_offset, j = 0; i < (chunk_offset + FILE_CHUNKS_NUM); i++) {
if (i != CHUNK_REM && all[i].iov_len != 0) { // if (i != CHUNK_REM && all[i].iov_len != 0) {
if (all[i].iov_len != 0) {
if (j < mapped_sz) { if (j < mapped_sz) {
mapped[j++] = all[i]; mapped[j++] = all[i];
ret = j; ret = j;
...@@ -572,18 +667,18 @@ int get_data_buffers(camogm_state *state, struct iovec *mapped, size_t mapped_sz ...@@ -572,18 +667,18 @@ int get_data_buffers(camogm_state *state, struct iovec *mapped, size_t mapped_sz
} }
} }
} }
return ret; return ret;
} }
/** Prepare the last remaining block of data for recording, return the number of bytes ready for recording */ /** Prepare the last remaining block of data for recording, return the number of bytes ready for recording */
int prep_last_block(camogm_state *state) int prep_last_block(camogm_state *state, int page)
{ {
int ret = 0; int ret = 0;
size_t stuff_len; size_t stuff_len;
unsigned char *src; unsigned char *src;
struct iovec *cvect = &state->writer_params.data_chunks[CHUNK_COMMON]; int chunk_offset = page * FILE_CHUNKS_NUM;
struct iovec *rvect = &state->writer_params.data_chunks[CHUNK_REM]; struct iovec *cvect = &state->writer_params.data_chunks[chunk_offset + CHUNK_COMMON];
struct iovec *rvect = &state->writer_params.was_CHUNK_REM;
if (rvect->iov_len != 0) { if (rvect->iov_len != 0) {
stuff_len = PHY_BLOCK_SIZE - rvect->iov_len; stuff_len = PHY_BLOCK_SIZE - rvect->iov_len;
......
...@@ -22,8 +22,9 @@ ...@@ -22,8 +22,9 @@
#include <sys/types.h> #include <sys/types.h>
#include "camogm.h" #include "camogm.h"
// TODO: Change PHY_BLOCK_SIZE to 4096 as it is 4096!
#define PHY_BLOCK_SIZE 512 ///< Physical disk block size //#define PHY_BLOCK_SIZE 512 ///< Physical disk block size
#define PHY_BLOCK_SIZE 4096 ///< Physical disk block size
#define JPEG_MARKER_LEN 2 ///< The size in bytes of JPEG marker #define JPEG_MARKER_LEN 2 ///< The size in bytes of JPEG marker
#define JPEG_SIZE_LEN 2 ///< The size in bytes of JPEG marker length field #define JPEG_SIZE_LEN 2 ///< The size in bytes of JPEG marker length field
#define INCLUDE_REM 1 ///< Include REM buffer to total size calculation #define INCLUDE_REM 1 ///< Include REM buffer to total size calculation
...@@ -73,10 +74,10 @@ enum { ...@@ -73,10 +74,10 @@ enum {
int init_align_buffers(camogm_state *state); int init_align_buffers(camogm_state *state);
void deinit_align_buffers(camogm_state *state); void deinit_align_buffers(camogm_state *state);
void align_frame(camogm_state *state); void align_frame(camogm_state *state);
void reset_chunks(struct iovec *vects, int all); void reset_chunks(camogm_state *state, int all, int page);
int update_lba(camogm_state *state); //int update_lba(camogm_state *state);
int get_data_buffers(camogm_state *state, struct iovec *mapped, size_t all_sz); int get_data_buffers(camogm_state *state, struct iovec *mapped, size_t mapped_sz, int page);
int prep_last_block(camogm_state *state); int prep_last_block(camogm_state *state, int page);
off64_t lba_to_offset(uint64_t lba); off64_t lba_to_offset(uint64_t lba);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "camogm_read.h" #include "camogm_read.h"
#include "camogm_align.h" #include "camogm_align.h"
/** State file record format. It includes device path in /dev, starting, current and ending LBAs */ /** State file record format. It includes device path in /dev, starting, current and ending LBAs */
#define STATE_FILE_FORMAT "%s\t%llu\t%llu\t%llu\n" #define STATE_FILE_FORMAT "%s\t%llu\t%llu\t%llu\n"
/** Status file update period, in seconds */ /** Status file update period, in seconds */
...@@ -322,35 +323,43 @@ int camogm_frame_jpeg(camogm_state *state) ...@@ -322,35 +323,43 @@ int camogm_frame_jpeg(camogm_state *state)
for (int i = 0; i < state->chunk_index - 1; i++) { for (int i = 0; i < state->chunk_index - 1; i++) {
D6(fprintf(debug_file, "ptr: %p, length: %ld\n", state->packetchunks[i + 1].chunk, state->packetchunks[i + 1].bytes)); D6(fprintf(debug_file, "ptr: %p, length: %ld\n", state->packetchunks[i + 1].chunk, state->packetchunks[i + 1].bytes));
} }
D6(fprintf(debug_file, "waiting for empty buffer @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
// next frame is ready for recording, signal this to the writer thread // next frame is ready for recording, signal this to the writer thread
pthread_mutex_lock(&state->writer_params.writer_mutex); pthread_mutex_lock(&state->writer_params.writer_mutex);
while (state->writer_params.data_ready) // while (state->writer_params.data_ready)
// pthread_cond_wait(&state->writer_params.main_cond, &state->writer_params.writer_mutex);
// do not run ahead by >= FILE_CHUNKS_PAGES (0 or 1 for just FILE_CHUNKS_PAGES == 2)
while ((state->writer_params.chunk_page_prep - state->writer_params.chunk_page_write + (2 * FILE_CHUNKS_PAGES)) % (2 * FILE_CHUNKS_PAGES) >= FILE_CHUNKS_PAGES)
pthread_cond_wait(&state->writer_params.main_cond, &state->writer_params.writer_mutex); pthread_cond_wait(&state->writer_params.main_cond, &state->writer_params.writer_mutex);
D6(fprintf(debug_file, "_13a_")); pthread_mutex_unlock(&state->writer_params.writer_mutex);
D6(fprintf(debug_file, "_13a_: got empty buffer @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
D6(fprintf(debug_file, "\n"));
align_frame(state); align_frame(state);
/* // Moved to write thread
if (update_lba(state) == 1) { if (update_lba(state) == 1) {
D0(fprintf(debug_file, "The end of block device reached, continue recording from start\n")); D0(fprintf(debug_file, "The end of block device reached, continue recording from start\n"));
lseek(state->writer_params.blockdev_fd, 0, SEEK_SET); lseek(state->writer_params.blockdev_fd, 0, SEEK_SET);
} }
D6(fprintf(debug_file, "Block device positions: start = %llu, current = %llu, end = %llu\n", D6(fprintf(debug_file, "Block device positions: start = %llu, current = %llu, end = %llu\n",
state->writer_params.lba_start, state->writer_params.lba_current, state->writer_params.lba_end)); state->writer_params.lba_start, state->writer_params.lba_current, state->writer_params.lba_end));
*/
// proceed if last frame was recorded without errors // proceed if last frame was recorded without errors
D6(fprintf(debug_file, "_13a1_:frame aligned @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_mutex_lock(&state->writer_params.writer_mutex);
if (state->writer_params.last_ret_val == 0) { if (state->writer_params.last_ret_val == 0) {
state->writer_params.data_ready = true; state->writer_params.chunk_page_prep = (state->writer_params.chunk_page_prep + 1) % (2 * FILE_CHUNKS_PAGES);
// state->writer_params.data_ready = true;
pthread_cond_signal(&state->writer_params.writer_cond); pthread_cond_signal(&state->writer_params.writer_cond);
D6(fprintf(debug_file, "_13b_: chunk_page_prep = %d (%d), signal writer_cond @ %06d\n",state->writer_params.chunk_page_prep, state->writer_params.chunk_page_write, get_fpga_usec(state->fd_fparmsall[0], 0)));
} }
pthread_mutex_unlock(&state->writer_params.writer_mutex); pthread_mutex_unlock(&state->writer_params.writer_mutex);
if (state->writer_params.last_ret_val != 0) { if (state->writer_params.last_ret_val != 0) {
return state->writer_params.last_ret_val; return state->writer_params.last_ret_val;
} }
// update status file if time has come // update status file if time has come
curr_time = time(NULL); curr_time = time(NULL);
if (difftime(curr_time, state->writer_params.stat_update) > STAT_UPDATE_PERIOD) { if (difftime(curr_time, state->writer_params.stat_update) > STAT_UPDATE_PERIOD) {
save_state_file(state); save_state_file(state);
D6(fprintf(debug_file, "_13c_: saved state file @ %06d\n", get_fpga_usec(state->fd_fparmsall[0], 0)));
} }
} }
...@@ -364,7 +373,7 @@ int camogm_frame_jpeg(camogm_state *state) ...@@ -364,7 +373,7 @@ int camogm_frame_jpeg(camogm_state *state)
* @param state a pointer to a structure containing current state * @param state a pointer to a structure containing current state
* @return 0 if the device was closed successfully and -1 otherwise * @return 0 if the device was closed successfully and -1 otherwise
*/ */
int camogm_end_jpeg(camogm_state *state) int camogm_end_jpeg(camogm_state *state) // TODO: Resolve multippage !
{ {
int ret = 0; int ret = 0;
int bytes; int bytes;
...@@ -373,14 +382,18 @@ int camogm_end_jpeg(camogm_state *state) ...@@ -373,14 +382,18 @@ int camogm_end_jpeg(camogm_state *state)
if (state->rawdev_op) { if (state->rawdev_op) {
// write any remaining data, do not use writer thread as there can be only one block left CHUNK_REM buffer // write any remaining data, do not use writer thread as there can be only one block left CHUNK_REM buffer
pthread_mutex_lock(&state->writer_params.writer_mutex); pthread_mutex_lock(&state->writer_params.writer_mutex);
while (state->writer_params.data_ready)
// while (state->writer_params.data_ready)
while (state->writer_params.chunk_page_prep != state->writer_params.chunk_page_write)
// wait for previous frame to be recorded first if it has not be recorded by the moment // wait for previous frame to be recorded first if it has not be recorded by the moment
pthread_cond_wait(&state->writer_params.main_cond, &state->writer_params.writer_mutex); pthread_cond_wait(&state->writer_params.main_cond, &state->writer_params.writer_mutex);
bytes = prep_last_block(state);
bytes = prep_last_block(state, state->writer_params.chunk_page_prep % FILE_CHUNKS_PAGES);
if (bytes > 0) { if (bytes > 0) {
D6(fprintf(debug_file, "Write last block of data, size = %d\n", bytes)); D6(fprintf(debug_file, "Write last block of data, size = %d\n", bytes));
// the remaining data block is placed in CHUNK_COMMON buffer, write just this buffer // the remaining data block is placed in CHUNK_COMMON buffer, write just this buffer
iovlen = writev(state->writer_params.blockdev_fd, &state->writer_params.data_chunks[CHUNK_COMMON], 1); iovlen = writev(state->writer_params.blockdev_fd,
&state->writer_params.data_chunks[CHUNK_COMMON + (state->writer_params.chunk_page_prep % FILE_CHUNKS_PAGES) * FILE_CHUNKS_NUM], 1);
if (iovlen < bytes) { if (iovlen < bytes) {
D0(fprintf(debug_file, "writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, bytes)); D0(fprintf(debug_file, "writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, bytes));
state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR; state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR;
...@@ -389,7 +402,9 @@ int camogm_end_jpeg(camogm_state *state) ...@@ -389,7 +402,9 @@ int camogm_end_jpeg(camogm_state *state)
state->writer_params.lba_current += 1; state->writer_params.lba_current += 1;
state->rawdev.total_rec_len += bytes; state->rawdev.total_rec_len += bytes;
} }
reset_chunks(state->writer_params.data_chunks, 1); // reset_chunks(state->writer_params.data_chunks, 1);
//*************** See if another buffer(s) must be cleared too? or even use chunk_page_write
reset_chunks(state, 1, state->writer_params.chunk_page_prep % FILE_CHUNKS_PAGES);
} }
pthread_mutex_unlock(&state->writer_params.writer_mutex); pthread_mutex_unlock(&state->writer_params.writer_mutex);
...@@ -411,28 +426,46 @@ int camogm_end_jpeg(camogm_state *state) ...@@ -411,28 +426,46 @@ int camogm_end_jpeg(camogm_state *state)
*/ */
void *jpeg_writer(void *thread_args) void *jpeg_writer(void *thread_args)
{ {
int dbg_us1, dbg_us2, dbg_us; // save usec for difference
int reset_rem; int reset_rem;
int chunk_index; int chunk_index, i0, i1;
ssize_t iovlen, l; ssize_t iovlen, l, ll, l0, l1, blocks_write, wpage;
bool process = true; bool process = true, has_data_to_write = false;
struct iovec chunks_iovec[FILE_CHUNKS_NUM]; struct iovec chunks_iovec[FILE_CHUNKS_PAGES][FILE_CHUNKS_NUM];
struct iovec split_chunk;
camogm_state *state = (camogm_state *)thread_args; camogm_state *state = (camogm_state *)thread_args;
struct writer_params *params = &state->writer_params; struct writer_params *params = &state->writer_params;
unsigned char dummy_buff[PHY_BLOCK_SIZE]; unsigned char dummy_buff[PHY_BLOCK_SIZE];
memset((void *)chunks_iovec, 0, sizeof(struct iovec) * FILE_CHUNKS_NUM); memset((void *)chunks_iovec, 0, sizeof(struct iovec) * FILE_CHUNKS_PAGES * FILE_CHUNKS_NUM);
pthread_mutex_lock(&params->writer_mutex); // pthread_mutex_lock(&params->writer_mutex);
params->state = STATE_RUNNING; params->state = STATE_RUNNING;
D6(fprintf(debug_file, "_w000_: Before jpeg_writer loop @ %06d\n", get_fpga_usec(state->fd_fparmsall[0], 0))); // before the debug file is set !
while (process) { while (process) {
/*
while (!params->data_ready && !params->exit_thread) { while (!params->data_ready && !params->exit_thread) {
pthread_cond_wait(&params->writer_cond, &params->writer_mutex); pthread_cond_wait(&params->writer_cond, &params->writer_mutex);
} // get rid of params->data_ready
*/
pthread_mutex_lock(&params->writer_mutex); // first time before the debug file is set !
D6(fprintf(debug_file, "_w00_: (%d, %d) @ %06d\n", params->chunk_page_prep, params->chunk_page_write, get_fpga_usec(state->fd_fparmsall[0], 0)));
while ((params->chunk_page_prep == params->chunk_page_write) && !params->exit_thread) {
pthread_cond_wait(&params->writer_cond, &params->writer_mutex);
} }
if (params->exit_thread) { if (params->exit_thread) {
process = false; process = false;
} }
if (params->data_ready) { has_data_to_write = params->chunk_page_prep != params->chunk_page_write;
pthread_mutex_unlock(&params->writer_mutex);
D6(fprintf(debug_file, "_w00.5_: (%d, %d) @ %06d\n", params->chunk_page_prep, params->chunk_page_write,get_fpga_usec(state->fd_fparmsall[0], 0)));
// if (params->data_ready) {
if (has_data_to_write) {
D6(fprintf(debug_file, "_w01_: got write data (%d > %d) @ %06d\n", params->chunk_page_prep, params->chunk_page_write,get_fpga_usec(state->fd_fparmsall[0], 0)));
/* dummy read cycle from (approximately) the beginning of previous frame; /* dummy read cycle from (approximately) the beginning of previous frame;
* this is a debug feature used to find disk errors */ * this is a debug feature used to find disk errors */
/*//temporary disable for simplicity 05/21/2023
if (state->writer_params.dummy_read) { if (state->writer_params.dummy_read) {
ssize_t data_len; ssize_t data_len;
off64_t curr_offset = lseek64(state->writer_params.blockdev_fd, 0, SEEK_CUR); off64_t curr_offset = lseek64(state->writer_params.blockdev_fd, 0, SEEK_CUR);
...@@ -445,26 +478,102 @@ void *jpeg_writer(void *thread_args) ...@@ -445,26 +478,102 @@ void *jpeg_writer(void *thread_args)
} }
lseek64(state->writer_params.blockdev_fd, curr_offset, SEEK_SET); lseek64(state->writer_params.blockdev_fd, curr_offset, SEEK_SET);
} }
*/
/* end of dummy read cycle */ /* end of dummy read cycle */
l = 0; l = 0;
reset_rem = 0; reset_rem = 0;
state->writer_params.last_ret_val = 0; state->writer_params.last_ret_val = 0;
chunk_index = get_data_buffers(state, chunks_iovec, FILE_CHUNKS_NUM); // inputs from state->writer_params.data_chunks, returns number of result chunks
wpage = state->writer_params.chunk_page_write % FILE_CHUNKS_PAGES;
chunk_index = get_data_buffers(state, chunks_iovec[wpage], FILE_CHUNKS_NUM, wpage);
// assuming write is block-aligned
if (chunk_index > 0) { if (chunk_index > 0) {
for (int i = 0; i < chunk_index; i++) for (int i = 0; i < chunk_index; i++)
l += chunks_iovec[i].iov_len; l += chunks_iovec[wpage][i].iov_len;
iovlen = writev(state->writer_params.blockdev_fd, chunks_iovec, chunk_index); // Moved rollover here
if (iovlen < l) { blocks_write = l / PHY_BLOCK_SIZE;
D0(fprintf(debug_file, "writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, l)); if (state->writer_params.lba_current + blocks_write <= state->writer_params.lba_end) { // almost always - single write
state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR; state->writer_params.lba_current += blocks_write;
reset_rem = 1; // D6(fprintf(debug_file, "_w02_: starting writev @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
} else { D6(dbg_us1=get_fpga_usec(state->fd_fparmsall[0], 0); fprintf(debug_file, "_w02_: starting writev @ %06d\n",dbg_us1));
// update statistic iovlen = writev(state->writer_params.blockdev_fd, chunks_iovec[wpage], chunk_index);
state->rawdev.last_jpeg_size = l; // D6(fprintf(debug_file, "_w03_: finished writev @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
state->rawdev.total_rec_len += state->rawdev.last_jpeg_size; D6(dbg_us=get_fpga_usec(state->fd_fparmsall[0], 0); fprintf(debug_file, "_w03_: finished writev @ %06d (+ %06d, +%06d)\n",dbg_us, (dbg_us-dbg_us1), (dbg_us-dbg_us2)); dbg_us2=dbg_us);
D6(fprintf(debug_file, "Current position in block device: %lld\n", lseek64(state->writer_params.blockdev_fd, 0, SEEK_CUR))); if (iovlen < l) {
D0(fprintf(debug_file, "writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, l));
state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR;
reset_rem = 1;
lseek(state->writer_params.blockdev_fd,
(state->writer_params.lba_current - state->writer_params.lba_start) * PHY_BLOCK_SIZE,
SEEK_SET); // update as if written?
} else {
// update statistic
state->rawdev.last_jpeg_size = l;
state->rawdev.total_rec_len += state->rawdev.last_jpeg_size;
D6(fprintf(debug_file, "Current position in block device: %lld\n", lseek64(state->writer_params.blockdev_fd, 0, SEEK_CUR)));
}
} else { // Split into two writes: to the end of partition and startion from the beginning
l0 = (state->writer_params.lba_end - state->writer_params.lba_current) * PHY_BLOCK_SIZE; // remaining to be written before rollover
l1 = l - l0; // remaining to be written after rollover
i1 = 0; // start of the second write
if (l0 > 0) { // should be always
ll = 0;
for (i0 = 0; i0 < chunk_index; i0++){
if (ll + chunks_iovec[wpage][i0].iov_len > l0){
break;
}
ll += chunks_iovec[wpage][i0].iov_len;
}
// save split chunk
split_chunk.iov_base = chunks_iovec[wpage][i0].iov_base;
split_chunk.iov_len = chunks_iovec[wpage][i0].iov_len;
i1 = i0; // index of the first chunk in a second write
if (ll < l0) { // is it a partial chunk?
chunks_iovec[wpage][i0].iov_len = l0 - ll;
i0++; // include split chunk in the first write
}
// write the first group (before rollover)
state->writer_params.lba_current = state->writer_params.lba_start;
iovlen = writev(state->writer_params.blockdev_fd, chunks_iovec[wpage], i0);
lseek(state->writer_params.blockdev_fd, 0, SEEK_SET); // regardless of error - rewind
if (iovlen < l0) {
D0(fprintf(debug_file, "(1 of 2) writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, l0));
state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR;
reset_rem = 1;
} else {
// do not update statistic after the first writed, do it after the second
D6(fprintf(debug_file, "(1 of 2) Current position in block device: %lld\n", lseek64(state->writer_params.blockdev_fd, 0, SEEK_CUR)));
// update split chunk to use its second part, shift chunks
if (l1 > 0) { // length to be written after rollover
if (chunks_iovec[wpage][i1].iov_len != split_chunk.iov_len) { // it was split
D0(fprintf(debug_file, "chunk %d was split, full length = %d, writtren = %d\n", i1, split_chunk.iov_len, chunks_iovec[wpage][i1].iov_len));
chunks_iovec[wpage][i1].iov_base += chunks_iovec[wpage][i1].iov_len;
chunks_iovec[wpage][i1].iov_len = split_chunk.iov_len - chunks_iovec[wpage][i1].iov_len;
}
// shift chunks
for (i0 = i1; i0 < chunk_index; i0++){
chunks_iovec[wpage][i0 - i1] = chunks_iovec[wpage][i0];
}
iovlen = writev(state->writer_params.blockdev_fd, chunks_iovec[wpage], chunk_index - i1);
state->writer_params.lba_current = state->writer_params.lba_start + l1 / PHY_BLOCK_SIZE;
if (iovlen < l1) {
D0(fprintf(debug_file, "(2 of 2) writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, l1));
state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR;
reset_rem = 1;
} else {
// update statistic (for both parts of the split write)
state->rawdev.last_jpeg_size = l;
state->rawdev.total_rec_len += state->rawdev.last_jpeg_size;
D6(fprintf(debug_file, "(1 of 2) Current position in block device: %lld\n", lseek64(state->writer_params.blockdev_fd, 0, SEEK_CUR)));
}
}
}
}
} }
D6(fprintf(debug_file, "_w04: wrote data @ %06d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
D6(fprintf(debug_file, "_w05_: Block device positions: start = %llu, current = %llu, end = %llu\n",
state->writer_params.lba_start, state->writer_params.lba_current, state->writer_params.lba_end));
} else { } else {
D0(fprintf(debug_file, "data vector mapping error: %d)\n", chunk_index)); D0(fprintf(debug_file, "data vector mapping error: %d)\n", chunk_index));
state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR; state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR;
...@@ -472,14 +581,25 @@ void *jpeg_writer(void *thread_args) ...@@ -472,14 +581,25 @@ void *jpeg_writer(void *thread_args)
} }
// release main thread // release main thread
reset_chunks(state->writer_params.data_chunks, reset_rem); // reset_chunks(state->writer_params.data_chunks, reset_rem);
params->data_ready = false; reset_chunks(state, reset_rem, state->writer_params.chunk_page_write % FILE_CHUNKS_PAGES);
pthread_cond_signal(&params->main_cond);
pthread_mutex_lock(&params->writer_mutex);
params->chunk_page_write = (params->chunk_page_write + 1) % (2 * FILE_CHUNKS_PAGES);
// params->data_ready = false;
if (params->chunk_page_prep == params->chunk_page_write) {
pthread_cond_signal(&params->main_cond); // ********** Do not signal if can write more !
D6(fprintf(debug_file, "_w06_: wrote data (%d , %d), buffer empty, signal main thread @ %06d\n", params->chunk_page_prep, params->chunk_page_write,get_fpga_usec(state->fd_fparmsall[0], 0)));
} else {
D6(fprintf(debug_file, "_w06a_: wrote data (%d , %d), has more to write, do not signal! @ %06d\n", params->chunk_page_prep, params->chunk_page_write,get_fpga_usec(state->fd_fparmsall[0], 0)));
}
pthread_mutex_unlock(&params->writer_mutex); // do not release untill waiting for writev() or waiting for data to write
} }
} }
params->state = STATE_STOPPED; params->state = STATE_STOPPED;
pthread_mutex_unlock(&state->writer_params.writer_mutex); // pthread_mutex_unlock(&state->writer_params.writer_mutex);
D5(fprintf(debug_file, "Exit from recording thread\n")); D5(fprintf(debug_file, "_w07_: Exit from recording thread\n")); // never?
return NULL; return NULL;
} }
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