Commit 8eee4caa authored by Andrey Filippov's avatar Andrey Filippov

working on fast write

parent e4468ac7
...@@ -278,7 +278,7 @@ void camogm_init(camogm_state *state, char *pipe_name, uint16_t port_num) ...@@ -278,7 +278,7 @@ void camogm_init(camogm_state *state, char *pipe_name, uint16_t port_num)
state->rawdev.curr_pos_w = state->rawdev.start_pos; state->rawdev.curr_pos_w = state->rawdev.start_pos;
state->rawdev.curr_pos_r = state->rawdev.start_pos; state->rawdev.curr_pos_r = state->rawdev.start_pos;
state->active_chn = ALL_CHN_INACTIVE; state->active_chn = ALL_CHN_INACTIVE;
state->rawdev.mmap_default_size = MMAP_CHUNK_SIZE; state->rawdev.mmap_default_size = MMAP_CHUNK_SIZE; // only used for camogm_read
state->sock_port = port_num; state->sock_port = port_num;
// state->writer_params.data_ready = false; // state->writer_params.data_ready = false;
...@@ -337,6 +337,7 @@ int camogm_start(camogm_state *state) ...@@ -337,6 +337,7 @@ int camogm_start(camogm_state *state)
{ {
int timestamp_start; int timestamp_start;
int rslt; int rslt;
int dummy;
int next_metadata_start, next_jpeg_len, fp; int next_metadata_start, next_jpeg_len, fp;
int port = state->port_num; int port = state->port_num;
...@@ -503,12 +504,12 @@ int camogm_start(camogm_state *state) ...@@ -503,12 +504,12 @@ int camogm_start(camogm_state *state)
} }
// and read it // and read it
lseek(state->fd_head[chn], 0, 0); lseek(state->fd_head[chn], 0, 0);
read(state->fd_head[chn], state->jpegHeader[chn], state->head_size[chn]); dummy=read(state->fd_head[chn], state->jpegHeader[chn], state->head_size[chn]); //?
// Restore read pointer to the original (now there may be no frame ready there yet) // Restore read pointer to the original (now there may be no frame ready there yet)
lseek(state->fd_circ[chn], state->cirbuf_rp[chn], SEEK_SET); lseek(state->fd_circ[chn], state->cirbuf_rp[chn], SEEK_SET);
state->image_size[chn] = 0; state->image_size[chn] = 0;
} }
} }
// here we are ready to initialize Ogm (or other) file // here we are ready to initialize Ogm (or other) file
switch (state->format) { switch (state->format) {
...@@ -661,31 +662,32 @@ int sendImageFrame(camogm_state *state) ...@@ -661,31 +662,32 @@ int sendImageFrame(camogm_state *state)
// prepare a packet to be sent (a lst of memory chunks) // prepare a packet to be sent (a lst of memory chunks)
state->chunk_index = 0; state->chunk_index = 0;
state->packetchunks[state->chunk_index ].bytes = 1; state->packetchunks[state->chunk_index ].bytes = 1;
state->packetchunks[state->chunk_index++].chunk = &frame_packet_type; state->packetchunks[state->chunk_index++].chunk = &frame_packet_type; // [0]
if (state->exif > 0) { // insert Exif/Tiff if (state->exif > 0) { // insert Exif/Tiff
D4(fprintf(debug_file, "_7_")); D4(fprintf(debug_file, "_7_"));
if (state->this_frame_params[port].color == COLORMODE_RAW) { // Tiff if (state->this_frame_params[port].color == COLORMODE_RAW) { // Tiff
D4(fprintf(debug_file, "_8a_")); D4(fprintf(debug_file, "_8a_"));
state->packetchunks[state->chunk_index ].bytes = state->exifSize[port]; // Tiff Header length state->packetchunks[state->chunk_index ].bytes = state->exifSize[port]; // Tiff Header length [1]
state->packetchunks[state->chunk_index++].chunk = state->ed[port]; // Tiff Header state->packetchunks[state->chunk_index++].chunk = state->ed[port]; // Tiff Header
} else { // JPEG/JP4 } else { // JPEG/JP4
D4(fprintf(debug_file, "_8b_")); D4(fprintf(debug_file, "_8b_"));
state->packetchunks[state->chunk_index ].bytes = 2; state->packetchunks[state->chunk_index ].bytes = 2;
state->packetchunks[state->chunk_index++].chunk = state->jpegHeader[port]; state->packetchunks[state->chunk_index++].chunk = state->jpegHeader[port]; // [1] jpeg marker
state->packetchunks[state->chunk_index ].bytes = state->exifSize[port]; state->packetchunks[state->chunk_index ].bytes = state->exifSize[port];
state->packetchunks[state->chunk_index++].chunk = state->ed[port]; state->packetchunks[state->chunk_index++].chunk = state->ed[port]; // [2] exif
state->packetchunks[state->chunk_index ].bytes = state->head_size[port] - 2; state->packetchunks[state->chunk_index ].bytes = state->head_size[port] - 2;
state->packetchunks[state->chunk_index++].chunk = &(state->jpegHeader[port][2]); state->packetchunks[state->chunk_index++].chunk = &(state->jpegHeader[port][2]); // [3] rest of jpeg header
} }
} else { } else {
D4(fprintf(debug_file, "_8_")); D4(fprintf(debug_file, "_8_"));
state->packetchunks[state->chunk_index ].bytes = state->head_size[port]; state->packetchunks[state->chunk_index ].bytes = state->head_size[port];
state->packetchunks[state->chunk_index++].chunk = state->jpegHeader[port]; state->packetchunks[state->chunk_index++].chunk = state->jpegHeader[port]; // [1] all of jpeg marker
} }
D4(fprintf(debug_file, "_9_")); D4(fprintf(debug_file, "_9_"));
/* Jpeg/Tiff image data may be split in two segments (rolled over buffer end) - process both variants */ /* Jpeg/Tiff image data may be split in two segments (rolled over buffer end) - process both variants */
state->chunk_data_index = state->chunk_index; // index of the first data segment
if ((state->cirbuf_rp[port] + state->jpeg_len) > state->circ_buff_size[port]) { // two segments if ((state->cirbuf_rp[port] + state->jpeg_len) > state->circ_buff_size[port]) { // two segments
/* copy from the beginning of the frame to the end of the buffer */ /* copy from the beginning of the frame to the end of the buffer */
D4(fprintf(debug_file, "_10_")); D4(fprintf(debug_file, "_10_"));
...@@ -694,14 +696,13 @@ int sendImageFrame(camogm_state *state) ...@@ -694,14 +696,13 @@ int sendImageFrame(camogm_state *state)
/* copy from the beginning of the buffer to the end of the frame */ /* copy from the beginning of the buffer to the end of the frame */
state->packetchunks[state->chunk_index ].bytes = state->jpeg_len - (state->circ_buff_size[port] - state->cirbuf_rp[port]); state->packetchunks[state->chunk_index ].bytes = state->jpeg_len - (state->circ_buff_size[port] - state->cirbuf_rp[port]);
state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][0]; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][0];
state->writer_params.segments = 2; state->data_segments = 2;
} else { // single segment } else { // single segment
D4(fprintf(debug_file, "_11_")); D4(fprintf(debug_file, "_11_"));
/* copy from the beginning of the frame to the end of the frame (no buffer rollovers) */ /* copy from the beginning of the frame to the end of the frame (no buffer rollovers) */
state->packetchunks[state->chunk_index ].bytes = state->jpeg_len; state->packetchunks[state->chunk_index ].bytes = state->jpeg_len;
state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][state->cirbuf_rp[port] >> 2]; state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][state->cirbuf_rp[port] >> 2];
state->writer_params.segments = 1; state->data_segments = 1;
} }
D4(fprintf(debug_file, "\tcirbuf_rp[%d] = 0x%x\t", port, state->cirbuf_rp[port])); D4(fprintf(debug_file, "\tcirbuf_rp[%d] = 0x%x\t", port, state->cirbuf_rp[port]));
D5(fprintf(debug_file, "_12_\n")); D5(fprintf(debug_file, "_12_\n"));
...@@ -709,10 +710,8 @@ int sendImageFrame(camogm_state *state) ...@@ -709,10 +710,8 @@ int sendImageFrame(camogm_state *state)
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;
} }
dbg_show_packetchunks(state); dbg_show_packetchunks(state);
D6(fprintf(debug_file, "_12.5_ before CAMOGM_FORMAT_XXX @ %07d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); D6(fprintf(debug_file, "_12.5_ before CAMOGM_FORMAT_XXX @ %07d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
switch (state->format) { switch (state->format) {
...@@ -768,7 +767,7 @@ static void dbg_show_packetchunks(camogm_state *state) ...@@ -768,7 +767,7 @@ static void dbg_show_packetchunks(camogm_state *state)
{ {
int i; int i;
for (i = 0; i < state->chunk_index; 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 = %ld\n", i, state->packetchunks[i].chunk, state->packetchunks[i].bytes));
} }
} }
...@@ -1918,7 +1917,7 @@ static int get_sysfs_name(const char *dev_name, char *sys_name, size_t str_sz, i ...@@ -1918,7 +1917,7 @@ static int get_sysfs_name(const char *dev_name, char *sys_name, size_t str_sz, i
*/ */
static int get_disk_range(const char *name, struct range *rng) static int get_disk_range(const char *name, struct range *rng)
{ {
int ret = 0; int ret = 0, dummy;
int fd; int fd;
uint64_t val; uint64_t val;
char data[SMALL_BUFF_LEN] = {0}; char data[SMALL_BUFF_LEN] = {0};
...@@ -1929,7 +1928,7 @@ static int get_disk_range(const char *name, struct range *rng) ...@@ -1929,7 +1928,7 @@ static int get_disk_range(const char *name, struct range *rng)
if (strlen(sysfs_name) > 0) { if (strlen(sysfs_name) > 0) {
fd = open(sysfs_name, O_RDONLY); fd = open(sysfs_name, O_RDONLY);
if (fd >= 0) { if (fd >= 0) {
read(fd, data, SMALL_BUFF_LEN); dummy=read(fd, data, SMALL_BUFF_LEN);
if ((val = strtoull(data, NULL, 10)) != 0) if ((val = strtoull(data, NULL, 10)) != 0)
rng->from = val; rng->from = val;
else else
...@@ -1945,7 +1944,7 @@ static int get_disk_range(const char *name, struct range *rng) ...@@ -1945,7 +1944,7 @@ static int get_disk_range(const char *name, struct range *rng)
if (get_sysfs_name(name, sysfs_name, ELPHEL_PATH_MAX, TYPE_SIZE) > 0) { if (get_sysfs_name(name, sysfs_name, ELPHEL_PATH_MAX, TYPE_SIZE) > 0) {
fd = open(sysfs_name, O_RDONLY); fd = open(sysfs_name, O_RDONLY);
if (fd >= 0) { if (fd >= 0) {
read(fd, data, SMALL_BUFF_LEN); dummy=read(fd, data, SMALL_BUFF_LEN);
if ((val = strtoull(data, NULL, 10)) != 0) if ((val = strtoull(data, NULL, 10)) != 0)
rng->to = rng->from + val; rng->to = rng->from + val;
else else
...@@ -1974,19 +1973,20 @@ static int set_disk_range(const struct range *rng) ...@@ -1974,19 +1973,20 @@ static int set_disk_range(const struct range *rng)
int ret = 0; int ret = 0;
char buff[SMALL_BUFF_LEN] = {0}; char buff[SMALL_BUFF_LEN] = {0};
int len; int len;
int dummy;
fd = open(SYSFS_AHCI_LBA_START, O_WRONLY); fd = open(SYSFS_AHCI_LBA_START, O_WRONLY);
if (fd < 0) if (fd < 0)
return -1; return -1;
len = snprintf(buff, SMALL_BUFF_LEN, "%llu", rng->from); len = snprintf(buff, SMALL_BUFF_LEN, "%llu", rng->from);
write(fd, buff, len + 1); dummy=write(fd, buff, len + 1);
close(fd); close(fd);
fd = open(SYSFS_AHCI_LBA_END, O_WRONLY); fd = open(SYSFS_AHCI_LBA_END, O_WRONLY);
if (fd < 0) if (fd < 0)
return -1; return -1;
len = snprintf(buff, SMALL_BUFF_LEN, "%llu", rng->to); len = snprintf(buff, SMALL_BUFF_LEN, "%llu", rng->to);
write(fd, buff, len + 1); dummy=write(fd, buff, len + 1);
close(fd); close(fd);
return ret; return ret;
...@@ -2019,16 +2019,17 @@ unsigned int select_port(camogm_state *state) ...@@ -2019,16 +2019,17 @@ unsigned int select_port(camogm_state *state)
if (is_chn_active(state, i)) { if (is_chn_active(state, i)) {
file_pos = lseek(state->fd_circ[i], 0, SEEK_CUR); file_pos = lseek(state->fd_circ[i], 0, SEEK_CUR);
if (file_pos != -1) { if (file_pos != -1) {
free_sz = lseek(state->fd_circ[i], LSEEK_CIRC_FREE, SEEK_END); free_sz = lseek(state->fd_circ[i], LSEEK_CIRC_FREE, SEEK_END); // maybe ==-1 if new frame is not yet ready?
lseek(state->fd_circ[i], file_pos, SEEK_SET); lseek(state->fd_circ[i], file_pos, SEEK_SET);
if (state->prog_state == STATE_STARTING || state->prog_state == STATE_RUNNING) if (state->prog_state == STATE_STARTING || state->prog_state == STATE_RUNNING)
D6(fprintf(debug_file, "port %i = %li, ", i, free_sz)); D6(fprintf(debug_file, "port %i = %li, ", i, free_sz));
if (free_sz < CAMOGM_MIN_BUF_FRAMES * state->image_size[i]) {
D3(fprintf(debug_file, "port %i has too little free space (<CAMOGM_MIN_BUF_FRAMES * %d), considered BROKEN", i, state->image_size[i]));
chn = -1; // i;
break;
}
if ((free_sz < min_sz && free_sz >= 0) || min_sz == -1) { if ((free_sz < min_sz && free_sz >= 0) || min_sz == -1) {
if (free_sz < CAMOGM_MIN_BUF_FRAMES * state->image_size[i]) {
D3(fprintf(debug_file, "port %i has too little free space (%ld <CAMOGM_MIN_BUF_FRAMES * %d), considered BROKEN, state=%d", \
i, free_sz, state->image_size[i], state->prog_state));
chn = -1; // i;
break;
}
min_sz = free_sz; min_sz = free_sz;
chn = i; chn = i;
} }
...@@ -2049,7 +2050,7 @@ unsigned int select_port(camogm_state *state) ...@@ -2049,7 +2050,7 @@ unsigned int select_port(camogm_state *state)
if ((state->prog_state == STATE_STARTING) || (state->prog_state == STATE_RUNNING)) { if ((state->prog_state == STATE_STARTING) || (state->prog_state == STATE_RUNNING)) {
// if (lseek(state->fd_circ[port], LSEEK_CIRC_READY, SEEK_END) < 0) { // if (lseek(state->fd_circ[port], LSEEK_CIRC_READY, SEEK_END) < 0) {
D3(if ((chn >=0) && (lseek(state->fd_circ[chn], LSEEK_CIRC_READY, SEEK_END) >= 0)) \ D3(if ((chn >=0) && (lseek(state->fd_circ[chn], LSEEK_CIRC_READY, SEEK_END) >= 0)) \
fprintf(debug_file, "selected port: %i, min free size = %d @ %07d\n", chn, min_sz, get_fpga_usec(state->fd_fparmsall[0], 0)); \ fprintf(debug_file, "selected port: %i, min free size = %08ld @ %07d\n", chn, min_sz, get_fpga_usec(state->fd_fparmsall[0], 0)); \
else if (debug_level >= 6) fprintf(debug_file,"no port is ready @ %07d\n", get_fpga_usec(state->fd_fparmsall[0], 0))); else if (debug_level >= 6) fprintf(debug_file,"no port is ready @ %07d\n", get_fpga_usec(state->fd_fparmsall[0], 0)));
} }
...@@ -2139,6 +2140,8 @@ int open_files(camogm_state *state) ...@@ -2139,6 +2140,8 @@ int open_files(camogm_state *state)
clean_up(state); clean_up(state);
return -3; return -3;
} }
syslog (LOG_INFO, "open_files(): ccam_dma_buf[%d] = %p", port, ccam_dma_buf[port]);
// now open/mmap file to read sensor/compressor parameters (currently - just free memory in circbuf and compressor state) // now open/mmap file to read sensor/compressor parameters (currently - just free memory in circbuf and compressor state)
state->fd_fparmsall[port] = open(ctlFileNames[port], O_RDWR); state->fd_fparmsall[port] = open(ctlFileNames[port], O_RDWR);
...@@ -2340,5 +2343,7 @@ inline void wait_frame_sync(const int fd_fparsall) ...@@ -2340,5 +2343,7 @@ inline void wait_frame_sync(const int fd_fparsall)
lseek(fd_fparsall, LSEEK_FRAME_WAIT_REL + 1, SEEK_END); lseek(fd_fparsall, LSEEK_FRAME_WAIT_REL + 1, SEEK_END);
} }
unsigned long *get_ccam_dma_buf(int port){
return ccam_dma_buf[port];
}
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#ifndef _CAMOGM_H #ifndef _CAMOGM_H
#define _CAMOGM_H #define _CAMOGM_H
#define __USE_GNU // for O_DIRECT
//#define USE_POLL //#define USE_POLL
#include <pthread.h> #include <pthread.h>
#include <stdbool.h> #include <stdbool.h>
...@@ -27,7 +28,9 @@ ...@@ -27,7 +28,9 @@
#include <elphel/c313a.h> #include <elphel/c313a.h>
#include <elphel/x393_devices.h> #include <elphel/x393_devices.h>
#include <syslog.h> #include <syslog.h>
#include <malloc.h> // debugging
//#define NODEBUG
#define CAMOGM_FRAME_NOT_READY 1 ///< frame pointer valid, but not yet acquired #define CAMOGM_FRAME_NOT_READY 1 ///< frame pointer valid, but not yet acquired
#define CAMOGM_FRAME_INVALID 2 ///< invalid frame pointer #define CAMOGM_FRAME_INVALID 2 ///< invalid frame pointer
#define CAMOGM_FRAME_CHANGED 3 ///< frame parameters have changed #define CAMOGM_FRAME_CHANGED 3 ///< frame parameters have changed
...@@ -46,6 +49,18 @@ ...@@ -46,6 +49,18 @@
#define CAMOGM_FORMAT_MOV 3 ///< output as Apple Quicktime #define CAMOGM_FORMAT_MOV 3 ///< output as Apple Quicktime
#define CAMOGM_MIN_BUF_FRAMES 2 ///< buffer should accomodate at list this number of frames #define CAMOGM_MIN_BUF_FRAMES 2 ///< buffer should accomodate at list this number of frames
#ifdef NODEBUG
#define D(x)
#define D0(x)
#define D1(x)
#define D2(x)
#define D3(x)
#define D4(x)
#define D5(x)
#define D6(x)
#define D7(x)
#define DD(x)
#else
#define D(x) { if (debug_file && debug_level) { x; fflush(debug_file); } } #define D(x) { if (debug_file && debug_level) { x; fflush(debug_file); } }
#define D0(x) { if (debug_file) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } } #define D0(x) { if (debug_file) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
#define D1(x) { if (debug_file && (debug_level > 0)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } } #define D1(x) { if (debug_file && (debug_level > 0)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
...@@ -54,14 +69,15 @@ ...@@ -54,14 +69,15 @@
#define D4(x) { if (debug_file && (debug_level > 3)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } } #define D4(x) { if (debug_file && (debug_level > 3)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
#define D5(x) { if (debug_file && (debug_level > 4)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } } #define D5(x) { if (debug_file && (debug_level > 4)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
#define D6(x) { if (debug_file && (debug_level > 5)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } } #define D6(x) { if (debug_file && (debug_level > 5)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
//#define D7(x) { if (debug_file && (debug_level > 6)) { pthread_mutex_lock(&print_mutex); x; fflush(debug_file); pthread_mutex_unlock(&print_mutex); } }
//#define DD(x) #define D7(x)
#define DD(x) { if (debug_file) { fprintf(debug_file, "%s:%d:", __FILE__, __LINE__); x; fflush(debug_file); } } #define DD(x) { if (debug_file) { fprintf(debug_file, "%s:%d:", __FILE__, __LINE__); x; fflush(debug_file); } }
#endif
/** @brief HEADER_SIZE is defined to be larger than actual header (with EXIF) to use compile-time buffer */ /** @brief HEADER_SIZE is defined to be larger than actual header (with EXIF) to use compile-time buffer */
#define JPEG_HEADER_MAXSIZE 0x300 #define JPEG_HEADER_MAXSIZE 0x300
/** @brief Offset from the beginning of raw device buffer. Must be aligned to physical sector size */ /** @brief Offset from the beginning of raw device buffer. Must be aligned to physical sector size */
#define RAWDEV_START_OFFSET 1024 #define RAWDEV_START_OFFSET 1024 // ????
/** @brief Maximum length of file or raw device path */ /** @brief Maximum length of file or raw device path */
#define ELPHEL_PATH_MAX 300 #define ELPHEL_PATH_MAX 300
#define MMAP_CHUNK_SIZE 10485760 #define MMAP_CHUNK_SIZE 10485760
...@@ -72,6 +88,50 @@ ...@@ -72,6 +88,50 @@
/** @brief Number of chunk pages to overlap preparation with SSD raw write */ /** @brief Number of chunk pages to overlap preparation with SSD raw write */
#define FILE_CHUNKS_PAGES 4 // 2 #define FILE_CHUNKS_PAGES 4 // 2
#define FILE_CHUNKS_TOTAL ((FILE_CHUNKS_NUM) * (FILE_CHUNKS_PAGES)) #define FILE_CHUNKS_TOTAL ((FILE_CHUNKS_NUM) * (FILE_CHUNKS_PAGES))
#define JPEG_MARKER_LEN 2 ///< The size in bytes of JPEG marker
#define JPEG_TRAILER_LEN 2 ///< The size in bytes of JPEG trailer
#define CIRCBUF_ALIGNMENT_SIZE 32 ///< Align of CIRCBUF entries
// Switching CHUNK -> SEGMENT
#define PAGE_PHYS 4096 // 512 // alignment size for O_DIRECT, may be different from LBA block size that is 512
enum segments {
SEGMENT_GLUE, ///< pointer to a page-aligned buffer to accommodate over-page of data, trailer, zeros, header and start of the data
SEGMENT_FIRST, ///< first (or the only) continuous page-aligned data segment that does not need to be copied (may start with ofset to PAGE_PHYS-aligned)
SEGMENT_SECOND, ///< optional second part of the data buffer, end PAGE_PHYS-aligned
SEGMENTS_NUMBER ///< Just to get number of segment types
};
#define SEGMENTS_PAGES 4 // 2
#define SEGMENTS_TOTAL ((SEGMENTS_NUMBER) * (SEGMENTS_PAGES))
/** Glue buffer should be large enough to contain:
* 1: alignment of the circbuf data that does not fit into PAGE_PHYS-aligned area (up to PAGE_PHYS-1)
* 2: optional JPEG trailer (2 bytes)
* 3: JPEG marker
* 4: EXIF/TIFF,
* 5: JPEG HEADER,
* 6: portion of the circbuf data up to PAGE_PHYS alignment (up to PAGE_PHYS-1)
* Trailer alignments (1,2) and header align,ents may share a common page (if they do not overlap)
* Remaining gap should be zero-filled to avoid stray match of the frame start (JPEG or TIFF)
* */
///< Trim address/char pointer to PAGE_PHYS alignment
/// convert to inline functions?
#define PAGE_PHYS_TRIM(x) ((x) & -(PAGE_PHYS))
///< Extend address/char pointer to PAGE_PHYS alignment
#define PAGE_PHYS_CEIL(x) (((x) + (PAGE_PHYS - 1)) & -(PAGE_PHYS))
///< Number of PAGE_PHYS pages to accommodate (x) bytes
#define PAGE_PHYS_NUMBER(x) (((x) + (PAGE_PHYS) - 1) / (PAGE_PHYS))
///< Number of pages needed for the glue segments
/// 512: 12, 4096:4
#define GLUE_SEGMENTS PAGE_PHYS_NUMBER(((PAGE_PHYS)-1) + \
(JPEG_TRAILER_LEN) + \
(JPEG_MARKER_LEN) + \
(MAX_EXIF_SIZE) + \
(JPEG_HEADER_MAXSIZE) +\
(PAGE_PHYS - CIRCBUF_ALIGNMENT_SIZE))
//#define COMMON_BUFF_SZ MAX_EXIF_SIZE + JPEG_HEADER_MAXSIZE + ALIGNMENT_SIZE + 2 * PHY_BLOCK_SIZE
//#define REM_BUFF_SZ 2 * PHY_BLOCK_SIZE
/** /**
* @enum state_flags * @enum state_flags
* @brief Program state flags * @brief Program state flags
...@@ -126,7 +186,7 @@ typedef struct { ...@@ -126,7 +186,7 @@ typedef struct {
uint64_t end_pos; uint64_t end_pos;
volatile uint64_t curr_pos_r; volatile uint64_t curr_pos_r;
uint64_t curr_pos_w; uint64_t curr_pos_w;
uint64_t mmap_default_size; uint64_t mmap_default_size; // only used for camogm_read
uint64_t mmap_current_size; uint64_t mmap_current_size;
uint64_t mmap_offset; uint64_t mmap_offset;
uint64_t file_start; uint64_t file_start;
...@@ -149,27 +209,17 @@ struct writer_params { ...@@ -149,27 +209,17 @@ 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
// ///< 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_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 chunk_page_write; ///< page of chunks to write. Incremented (mod) after recording to disk
bool writev_run; ///< writev() is active (enable main thread if buffer not full and writew or buf empty) bool writev_run; ///< writev() is active (enable main thread if buffer not full and writew or buf empty)
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 struct iovec *data_segments[SEGMENTS_PAGES]; ///< a set of vectors sets 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
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
// 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? unsigned char *common_buffs[FILE_CHUNKS_PAGES]; ///< buffer for aligned JPEG header // make multiple?
unsigned char *glue_buffs[SEGMENTS_PAGES + 1]; ///< glue buffer (end of previous frame + start of this one
// unsigned char *glue_buffs_carry; ///< extra glue buffer to pass from the previous to the next frame
struct iovec glue_carry_vec; ///< current tail pointer of the carry glue segment
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
...@@ -241,6 +291,8 @@ typedef struct { ...@@ -241,6 +291,8 @@ typedef struct {
int set_format; ///< output format to set (will be updated after stop) int set_format; ///< output format to set (will be updated after stop)
elph_packet_chunk packetchunks[FILE_CHUNKS_NUM]; elph_packet_chunk packetchunks[FILE_CHUNKS_NUM];
int chunk_index; int chunk_index;
int chunk_data_index; ///< segment index corresponding to first(only) data one
int data_segments; ///< the number of segments in frame
int buf_overruns[SENSOR_PORTS]; int buf_overruns[SENSOR_PORTS];
int buf_min[SENSOR_PORTS]; int buf_min[SENSOR_PORTS];
int set_frames_skip; ///< will be copied to frames_skip if stopped or at start int set_frames_skip; ///< will be copied to frames_skip if stopped or at start
...@@ -287,5 +339,7 @@ int isDaemonEnabled(unsigned int port, int daemonBit); ...@@ -287,5 +339,7 @@ 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); int get_fpga_usec(const int fd_fparsall, unsigned int port);
inline void wait_frame_sync(const int fd_fparsall); inline void wait_frame_sync(const int fd_fparsall);
unsigned long *get_ccam_dma_buf(int port);
#endif /* _CAMOGM_H */ #endif /* _CAMOGM_H */
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
/** @brief This define is needed to use lseek64 and should be set before includes */ /** @brief This define is needed to use lseek64 and should be set before includes */
#define _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE
#define ALIGN_INTERFRAME // New alignment mode - add zeros between frames (TIFF also), not inside JPEG with app15 (JPEG only)
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
...@@ -26,23 +25,12 @@ ...@@ -26,23 +25,12 @@
#include "camogm_align.h" #include "camogm_align.h"
#ifndef ALIGN_INTERFRAME
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); // 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 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);
static inline void vectshrink(struct iovec *vec, size_t len); static inline void vectshrink(struct iovec *vec, size_t len);
static inline void vectshrinkhead(struct iovec *vec, size_t len); static inline void vectshrinkhead(struct iovec *vec, size_t len);
static inline unsigned char *vectrpos(struct iovec *vec, size_t offset); static inline unsigned char *vectrpos(struct iovec *vec, size_t offset);
//static void dev_dbg(const char *prefix, const char *format, ...);
static void remap_vectors(camogm_state *state, struct iovec *chunks);
static size_t get_blocks_num(struct iovec *sgl, size_t n_elem);
/* debug functions */ /* debug functions */
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, ...);
...@@ -60,7 +48,7 @@ static void dev_dbg(const char *prefix, const char *format, ...) ...@@ -60,7 +48,7 @@ static void dev_dbg(const char *prefix, const char *format, ...)
static inline void vectcpy(struct iovec *dest, void *src, size_t len) static inline void vectcpy(struct iovec *dest, void *src, size_t len)
{ {
unsigned char *d = (unsigned char *)dest->iov_base; unsigned char *d = (unsigned char *)dest->iov_base;
if (len <= 0) return;
memcpy(d + dest->iov_len, src, len); memcpy(d + dest->iov_len, src, len);
dest->iov_len += len; dest->iov_len += len;
} }
...@@ -69,7 +57,9 @@ static inline void vectcpy(struct iovec *dest, void *src, size_t len) ...@@ -69,7 +57,9 @@ 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)
{ {
unsigned char *d = (unsigned char *)dest->iov_base; unsigned char *d = (unsigned char *)dest->iov_base;
D6(fprintf(debug_file, "_13c06a?_:vectset() d=%p, src=%d len=%d\n", d, src, len ));
if (len <= 0) return;
memset(d + dest->iov_len, src, len); memset(d + dest->iov_len, src, len);
dest->iov_len += len; dest->iov_len += len;
} }
...@@ -102,218 +92,192 @@ static inline unsigned char *vectrpos(struct iovec *vec, size_t offset) ...@@ -102,218 +92,192 @@ 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 /** Remap vectors pointing to various buffers with frame data to vectors used during frame alignment
/** Calculate the size of current frame in bytes starting from vector and offset given */ * Setup state->writer_params.data_segments[seg_page] ([SEGMENT_GLUE, SEGMENT_FIRST, SEGMENT_SECOND] and
static inline size_t get_size_from(const struct iovec *vects, int index, size_t offset, int all) // offset, index - always 0 * use /setup next state->writer_params.glue_carry_vec
{ * [SEGMENT_GLUE] may heve zero lengtgh - check all lengths before writev()
int i; * */
// int page_offs = FILE_CHUNKS_NUM + page; size_t remap_vectors(camogm_state *state) // , struct iovec *chunks)
size_t total = 0;
if (index >= MAX_DATA_CHUNKS || offset > vects[index].iov_len) {
return 0;
}
for (i = index; i < MAX_DATA_CHUNKS; i++) {
if (i == CHUNK_REM && all == EXCLUDE_REM)
// remainder should not be processed
continue;
if (i == index)
total += vects[i].iov_len - offset;
else
total += vects[i].iov_len;
}
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; // state->writer_params.glue_carry_vec has data for the the trailer of the previous frame. swap it with the
struct iovec *chunks = state->writer_params.data_chunks; // state->writer_params.glue_buffs[seg_page][SEGMENT_GLUE]
struct iovec *cbuff = &chunks[CHUNK_COMMON]; size_t total_sz;
int page_offs = (state->writer_params.chunk_page_prep % FILE_CHUNKS_PAGES) * FILE_CHUNKS_NUM; int seg_page = (state->writer_params.chunk_page_prep % FILE_CHUNKS_PAGES);
size_t total = 0; long head_bytes, tail_bytes, trimmed_bytes;
for (i = page_offs + index; i < (FILE_CHUNKS_NUM + page_offs); i++) { int i, data_index, data_pre, num_glue_pages, trim_segment, circbuff_offs;
total += chunks[i].iov_len; int gap_size;
} unsigned char * aligned_data;
if (all) { struct iovec glue_vec;
total += state->writer_params.was_CHUNK_REM.iov_len; struct iovec * glue_vec_p; // = &glue_vec;
} glue_vec.iov_base = state->writer_params.glue_carry_vec.iov_base;
return total; glue_vec.iov_len = state->writer_params.glue_carry_vec.iov_len;
D7(fprintf(debug_file, "_13c01_:remap_vectors @ %07d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
} state->writer_params.glue_carry_vec.iov_base = state->writer_params.data_segments[seg_page][SEGMENT_GLUE].iov_base;
state->writer_params.glue_carry_vec.iov_len = 0; // state->writer_params.data_segments[seg_page][SEGMENT_GLUE].iov_len;
state->writer_params.data_segments[seg_page][SEGMENT_GLUE].iov_base = glue_vec.iov_base;
state->writer_params.data_segments[seg_page][SEGMENT_GLUE].iov_len = glue_vec.iov_len;
state->writer_params.data_segments[seg_page][SEGMENT_FIRST].iov_len = 0; // check iov_len first before using iov_base
/** Return the number of bytes needed to be inserted to align @e data_len to @e align_len boundary */ state->writer_params.data_segments[seg_page][SEGMENT_SECOND].iov_len = 0; // check iov_len first before using iov_base
static inline size_t align_bytes_num(size_t data_len, size_t align_len) // calculate total header size
{ head_bytes = 0;
size_t rem = data_len % align_len; for (i = 0; i < state->chunk_data_index; i++){
if (rem == 0) head_bytes += state->packetchunks[i].bytes;
return 0; }
else D7(fprintf(debug_file, "_13c02_:remap_vectors, head_bytes=%ld @ %07d\n", head_bytes,get_fpga_usec(state->fd_fparmsall[0], 0)));
return align_len - rem;
} // find out how much should be cut from the beginning of the first data segment (circbuf itself is page-aligned)
// in an unlikely case that image is smaller that a page ...
/** Remap vectors pointing to various buffers with frame data to vectors used during frame alignment */ // state->port_num
static void remap_vectors(camogm_state *state, struct iovec *chunks) data_index = state->chunk_data_index;
{ circbuff_offs = (int) state->packetchunks[data_index].chunk;
int chunk_index = 1; aligned_data = state->packetchunks[data_index].chunk+ (PAGE_PHYS_CEIL(circbuff_offs) - circbuff_offs);
int is_tiff = state->this_frame_params[state->port_num].color == COLORMODE_RAW; data_pre = aligned_data - state->packetchunks[data_index].chunk;
int chunk_offset = (state->writer_params.chunk_page_prep % FILE_CHUNKS_PAGES) * FILE_CHUNKS_NUM; glue_vec_p = &state->writer_params.data_segments[seg_page][SEGMENT_GLUE];
int paged_CHUNK_LEADER = chunk_offset + CHUNK_LEADER; D7(fprintf(debug_file, "_13c03_:remap_vectors, circbuff_offs=0x%x aligned_data=%p data_pre=0x%x @ %07d\n", circbuff_offs, aligned_data, data_pre, get_fpga_usec(state->fd_fparmsall[0], 0)));
int paged_CHUNK_EXIF = chunk_offset + CHUNK_EXIF; D7(fprintf(debug_file, "_13c04_:remap_vectors, state->packetchunks[state->chunk_data_index].bytes=%ld @ %07d\n", state->packetchunks[state->chunk_data_index].bytes, get_fpga_usec(state->fd_fparmsall[0], 0)));
int paged_CHUNK_HEADER = chunk_offset + CHUNK_HEADER; if (state->packetchunks[state->chunk_data_index].bytes < data_pre) {
int paged_CHUNK_COMMON = chunk_offset + CHUNK_COMMON; // Too short frame data - special treatment with zero data, moving some to carry, and possibly outputing some from the GLUE
int paged_CHUNK_DATA_0 = chunk_offset + CHUNK_DATA_0; // there is definitely no second data - otherwise the first segment would end at page boundary
int paged_CHUNK_DATA_1 = chunk_offset + CHUNK_DATA_1; // copy everything to state->writer_params.data_segments[seg_page][SEGMENT_GLUE], trim to pages, pass residual to
int paged_CHUNK_TRAILER = chunk_offset + CHUNK_TRAILER; // state->writer_params.glue_carry_vec
int paged_CHUNK_ALIGN = chunk_offset + CHUNK_ALIGN; // copy header data, no gap
if (state->exif > 0) { for (i = 0; i <= state->chunk_index; i++){ // including data and trailer
if (is_tiff) { // Tiff vectcpy(glue_vec_p, state->packetchunks[i].chunk, state->packetchunks[i].bytes);
chunks[paged_CHUNK_EXIF].iov_base = (void *)state->packetchunks[chunk_index].chunk; }
chunks[paged_CHUNK_EXIF].iov_len = state->packetchunks[chunk_index++].bytes; trimmed_bytes = PAGE_PHYS_TRIM(glue_vec_p->iov_len);
// set length of unused chunks to zero, and pointer to any valid pointer D7(fprintf(debug_file, "_13c05_:remap_vectors, trimmed_bytes=%ld @ %07d\n", trimmed_bytes, get_fpga_usec(state->fd_fparmsall[0], 0)));
chunks[paged_CHUNK_LEADER].iov_base = chunks[paged_CHUNK_EXIF].iov_base; if ((glue_vec_p->iov_len - trimmed_bytes) > 0){
chunks[paged_CHUNK_LEADER].iov_len = 0; vectcpy(&state->writer_params.glue_carry_vec,
chunks[paged_CHUNK_HEADER].iov_base = chunks[paged_CHUNK_EXIF].iov_base; ((char *) glue_vec_p->iov_base) + trimmed_bytes,
chunks[paged_CHUNK_HEADER].iov_len = 0; glue_vec_p->iov_len - trimmed_bytes);
} else { // JPEG/JP4 glue_vec_p->iov_len = trimmed_bytes; // may be 0
chunks[paged_CHUNK_LEADER].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[paged_CHUNK_LEADER].iov_len = state->packetchunks[chunk_index++].bytes;
chunks[paged_CHUNK_EXIF].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[paged_CHUNK_EXIF].iov_len = state->packetchunks[chunk_index++].bytes;
chunks[paged_CHUNK_HEADER].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[paged_CHUNK_HEADER].iov_len = state->packetchunks[chunk_index++].bytes;
} }
} else { } else {
chunks[paged_CHUNK_LEADER].iov_base = (void *)state->packetchunks[chunk_index].chunk; head_bytes += data_pre;
chunks[paged_CHUNK_LEADER].iov_len = JPEG_MARKER_LEN; tail_bytes = glue_vec_p->iov_len;
chunks[paged_CHUNK_HEADER].iov_base = (void *)(state->packetchunks[chunk_index].chunk + JPEG_MARKER_LEN); num_glue_pages = PAGE_PHYS_NUMBER(tail_bytes + head_bytes);
chunks[paged_CHUNK_HEADER].iov_len = state->packetchunks[chunk_index++].bytes - JPEG_MARKER_LEN; gap_size = num_glue_pages * PAGE_PHYS - tail_bytes - head_bytes;
// set to zero length and valid pointer D7(fprintf(debug_file, "_13c06_:remap_vectors, head_bytes=%ld, tail_bytes=%ld, num_glue_pages=%d, gap_size=%d @ %07d\n", head_bytes, tail_bytes, num_glue_pages, gap_size, get_fpga_usec(state->fd_fparmsall[0], 0)));
chunks[paged_CHUNK_EXIF].iov_base = chunks[paged_CHUNK_HEADER].iov_base; // fill gap with zeros
chunks[paged_CHUNK_EXIF].iov_len = 0; D7(fprintf(debug_file, "_13c06a_:remap_vectors, glue_vec_p=%p, gap_size=%d glue_vec_p->iov_base=0x%p, glue_vec_p->iov_len=%d @ %07d\n",\
} glue_vec_p, gap_size, glue_vec_p->iov_base, glue_vec_p->iov_len, get_fpga_usec(state->fd_fparmsall[0], 0)));
chunks[paged_CHUNK_DATA_0].iov_base = (void *)state->packetchunks[chunk_index].chunk; D7(fprintf(debug_file, "_13c06a0_:malloc_usable_size(glue_vec_p->iov_base) = %d @ %07d\n", malloc_usable_size(glue_vec_p->iov_base), get_fpga_usec(state->fd_fparmsall[0], 0)));
chunks[paged_CHUNK_DATA_0].iov_len = state->packetchunks[chunk_index++].bytes; for (i = 0; i < SEGMENTS_PAGES; i++){
if (state->writer_params.segments == 2) { D7(fprintf(debug_file, "_13c06a1_: malloc_usable_size([%d][SEGMENT_GLUE]) = %d @ %07d\n",\
chunks[paged_CHUNK_DATA_1].iov_base = (void *)state->packetchunks[chunk_index].chunk; i, malloc_usable_size(state->writer_params.data_segments[i][SEGMENT_GLUE].iov_base), get_fpga_usec(state->fd_fparmsall[0], 0)));
chunks[paged_CHUNK_DATA_1].iov_len = state->packetchunks[chunk_index++].bytes; }
} else{
chunks[paged_CHUNK_DATA_1].iov_base = chunks[paged_CHUNK_DATA_0].iov_base;
chunks[paged_CHUNK_DATA_1].iov_len = 0;
}
// chunks[CHUNK_TRAILER].iov_base = (void *)state->packetchunks[chunk_index].chunk;
if (is_tiff) { // Tiff
chunks[paged_CHUNK_TRAILER].iov_base = (void *)state->packetchunks[chunk_index-1].chunk; // last used chunk (valid)
chunks[paged_CHUNK_TRAILER].iov_len = 0;
} else {
chunks[paged_CHUNK_TRAILER].iov_base = (void *)state->packetchunks[chunk_index].chunk;
chunks[paged_CHUNK_TRAILER].iov_len = state->packetchunks[chunk_index].bytes;
}
/* some data may be left from previous frame, copy it to special buffer */
/*
if (chunks[CHUNK_REM].iov_len != 0) {
vectcpy(&state->writer_params.prev_rem_vect, chunks[CHUNK_REM].iov_base, 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 */ // size_t malloc_usable_size(void *ptr);
static int check_chunks(struct iovec *vects, int page) vectset(glue_vec_p, 0, gap_size);
{ D7(fprintf(debug_file, "_13c06a2_:remap_vectors, glue_vec_p=%p, gap_size=%d glue_vec_p->iov_base=0x%p, glue_vec_p->iov_len=%d @ %07d\n",\
int i; glue_vec_p, gap_size, glue_vec_p->iov_base, glue_vec_p->iov_len, get_fpga_usec(state->fd_fparmsall[0], 0)));
int ret = 0; // copy header data after the gap
size_t sz = 0; for (i = 0; i < state->chunk_data_index; i++){
int chunk_offset = page * FILE_CHUNKS_NUM; D7(fprintf(debug_file, "_13c06b_:remap_vectors, i=%d glue_vec_p=%p, gap_size=%d glue_vec_p->iov_base=0x%p, glue_vec_p->iov_len=%d state->packetchunks[i].chunk=%p, state->packetchunks[i].bytes=%ld @ %07d\n", \
for (i = chunk_offset; i < FILE_CHUNKS_NUM + chunk_offset; i++) { i, glue_vec_p, gap_size, glue_vec_p->iov_base, glue_vec_p->iov_len, \
// if (i != CHUNK_REM) { state->packetchunks[i].chunk, state->packetchunks[i].bytes, \
sz += vects[i].iov_len; get_fpga_usec(state->fd_fparmsall[0], 0)));
if ((vects[i].iov_len % ALIGNMENT_SIZE) != 0) { vectcpy(glue_vec_p, state->packetchunks[i].chunk, state->packetchunks[i].bytes);
dev_dbg(NULL, "ERROR: unaligned write from slot %d, length %u\n", i, vects[i].iov_len); }
ret = -1; // copy (unaligned) beginning of the data segment
vectcpy(glue_vec_p, state->packetchunks[state->chunk_data_index].chunk, data_pre);
// TODO: verify that glue_vec_p->iov_len is multiple of PAGE_PHYS
trim_segment = SEGMENT_FIRST;
state->writer_params.data_segments[seg_page][SEGMENT_FIRST].iov_base = ((char *) state->packetchunks[state->chunk_data_index].chunk) + data_pre;
state->writer_params.data_segments[seg_page][SEGMENT_FIRST].iov_len = state->packetchunks[state->chunk_data_index].bytes - data_pre;
D7(fprintf(debug_file, "_13c07_:remap_vectors @ %07d\n", get_fpga_usec(state->fd_fparmsall[0], 0)));
if (state->writer_params.data_segments[seg_page][SEGMENT_FIRST].iov_len == 0) {
// nothing left of data segment 1 - move segment2 to segment1 (or skip both)
if (state->data_segments > 1) { // move second segment to first
state->writer_params.data_segments[seg_page][SEGMENT_FIRST].iov_base = ((char *) state->packetchunks[state->chunk_data_index + 1].chunk);
state->writer_params.data_segments[seg_page][SEGMENT_FIRST].iov_len = state->packetchunks[state->chunk_data_index + 1].bytes ;
} }
// } } else if (state->data_segments > 1) {
dev_dbg(NULL, "chunk[%02d]: ptr = %p, size = %d\n", i, vects[i].iov_base, vects[i].iov_len); state->writer_params.data_segments[seg_page][SEGMENT_SECOND].iov_base = ((char *) state->packetchunks[state->chunk_data_index + 1].chunk);
} state->writer_params.data_segments[seg_page][SEGMENT_SECOND].iov_len = state->packetchunks[state->chunk_data_index + 1].bytes ;
if ((sz % PHY_BLOCK_SIZE) != 0) { trim_segment = SEGMENT_SECOND;
dev_dbg(NULL, "ERROR: total length of the transaction is not aligned to sector boundary, total length %u\n", sz); }
ret = -1; D7(fprintf(debug_file, "_13c08_:remap_vectors,[SEGMENT_GLUE].iov_len=%d, [SEGMENT_FIRST].iov_len=%d, [SEGMENT_SECOND].iov_len=%d @ %07d\n", \
} else { state->writer_params.data_segments[seg_page][SEGMENT_GLUE].iov_len, \
dev_dbg(NULL, "===== frame is OK =====\n"); state->writer_params.data_segments[seg_page][SEGMENT_FIRST].iov_len, \
state->writer_params.data_segments[seg_page][SEGMENT_SECOND].iov_len, \
get_fpga_usec(state->fd_fparmsall[0], 0)));
// Trim last data segment to PAGE_PHYS (it may make its length zero - OK), copy remaining
// data to the buffer pointed by state->writer_params.glue_carry_vec.iov_base, set state->writer_params.glue_carry_vec.iov_len
trimmed_bytes = PAGE_PHYS_TRIM(state->writer_params.data_segments[seg_page][trim_segment].iov_len);
D7(fprintf(debug_file, "_13c09_:remap_vectors, trimmed_bytes=%ld @ %07d\n", trimmed_bytes, get_fpga_usec(state->fd_fparmsall[0], 0)));
if (state->writer_params.data_segments[seg_page][trim_segment].iov_len > trimmed_bytes) {
D6(fprintf(debug_file, "_13c09a:remap_vectors, trim_segment=%d, dest = %p, dest_len=%d src=%p, copy_len = %ld @ %07d\n", \
trim_segment,
&state->writer_params.glue_carry_vec, \
state->writer_params.glue_carry_vec.iov_len, \
((char *) state->writer_params.data_segments[seg_page][trim_segment].iov_base) + trimmed_bytes, \
state->writer_params.data_segments[seg_page][trim_segment].iov_len - trimmed_bytes, \
get_fpga_usec(state->fd_fparmsall[0], 0)));
vectcpy(&state->writer_params.glue_carry_vec,
((char *) state->writer_params.data_segments[seg_page][trim_segment].iov_base) + trimmed_bytes,
state->writer_params.data_segments[seg_page][trim_segment].iov_len - trimmed_bytes);
state->writer_params.data_segments[seg_page][trim_segment].iov_len = trimmed_bytes; // reduce data segment length
}
D7(fprintf(debug_file, "_13c09b_:remap_vectors, tail_segm=%d, chunk_index=%d @ %07d\n", \
state->chunk_data_index + state->data_segments, \
state->chunk_index, \
get_fpga_usec(state->fd_fparmsall[0], 0)));
// FIXME: next can only be tested with JPEG/JP4 !
for (i = state->chunk_data_index + state->data_segments; i < state->chunk_index; i++){ // trailer if it exists
D7(fprintf(debug_file, "_13c09c_:remap_vectors, i=%d, dest = %p, dest_len=%d src=%p, len =%ld @ %07d\n", \
i, \
&state->writer_params.glue_carry_vec, \
state->writer_params.glue_carry_vec.iov_len, \
state->packetchunks[i].chunk, \
state->packetchunks[i].bytes, \
get_fpga_usec(state->fd_fparmsall[0], 0)));
vectcpy(&state->writer_params.glue_carry_vec,
state->packetchunks[i].chunk,
state->packetchunks[i].bytes);
}
} }
return ret; D7(fprintf(debug_file, "_13c10_:remap_vectors @ %07d\n", get_fpga_usec(state->fd_fparmsall[0], 0)));
} total_sz = 0; // get_size_from_paged(state, 0, INCLUDE_REM) + rbuff->iov_len;
for (i = 0; i < SEGMENTS_NUMBER; i++){
total_sz += state->writer_params.data_segments[seg_page][i].iov_len;
/** Calculate the number of blocks this frame will occupy. The frame must be aligned to block size */
static size_t get_blocks_num(struct iovec *sgl, size_t n_elem)
{
int num;
size_t total = 0;
for (num = 0; num < n_elem; num++) {
total += sgl[num].iov_len;
} }
//port_num
return total / PHY_BLOCK_SIZE; state->image_size[state->port_num] = total_sz;
D4(fprintf(debug_file, "total_sz = %d\n", total_sz));
return total_sz;
} }
/** 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)
{ {
int i; D3(fprintf(debug_file, "GLUE_SEGMENTS = %d pages of %d bytes each\n", GLUE_SEGMENTS, PAGE_PHYS));
// state->writer_params.data_chunks = (struct iovec *)malloc(MAX_DATA_CHUNKS * sizeof(struct iovec)); int seg_page;
state->writer_params.data_chunks = (struct iovec *)malloc(FILE_CHUNKS_TOTAL * sizeof(struct iovec)); // does not include CHUNK_REM for (seg_page = 0; seg_page < SEGMENTS_PAGES + 1; seg_page++){
if (state->writer_params.data_chunks == NULL) { // allocate SEGMENT_GLUE buffer that will contain data copied from non-pagfe aligned segments
return -1; state->writer_params.glue_buffs[seg_page] = (unsigned char *) aligned_alloc (PAGE_PHYS, GLUE_SEGMENTS * PAGE_PHYS);
} if (state->writer_params.glue_buffs[seg_page] == NULL) {
for (i= 0; i < FILE_CHUNKS_PAGES; i++) {
state->writer_params.common_buffs[i] = (unsigned char *)malloc(COMMON_BUFF_SZ);
if (state->writer_params.common_buffs[i] == NULL) {
deinit_align_buffers(state);
return -1; return -1;
} }
D6(fprintf(debug_file, "init_align_buffers(), state->writer_params.glue_buffs[%d]=%p @ %07d\n", \
seg_page, state->writer_params.glue_buffs[seg_page], get_fpga_usec(state->fd_fparmsall[0], 0)));
} }
state->writer_params.rem_buff = (unsigned char *)malloc(REM_BUFF_SZ); for (seg_page = 0; seg_page < SEGMENTS_PAGES; seg_page++){
if (state->writer_params.rem_buff == NULL) { state->writer_params.data_segments[seg_page] = (struct iovec *)malloc(SEGMENTS_NUMBER * sizeof(struct iovec));
deinit_align_buffers(state); if (state->writer_params.data_segments[seg_page] == NULL) {
return -1; return -1;
} }
state->writer_params.prev_rem_buff = (unsigned char *)malloc(REM_BUFF_SZ); D6(fprintf(debug_file, "init_align_buffers(), seg_page=%d, state->writer_params.data_segments[seg_page]=%p @ %07d\n", \
if (state->writer_params.prev_rem_buff == NULL) { seg_page, state->writer_params.data_segments[seg_page], get_fpga_usec(state->fd_fparmsall[0], 0)));
deinit_align_buffers(state);
return -1;
}
for (i= 0; i < FILE_CHUNKS_PAGES; i++) {
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[FILE_CHUNKS_NUM* i + CHUNK_COMMON].iov_len = 0;
}
//was_CHUNK_REM
// 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.data_segments[seg_page][SEGMENT_GLUE].iov_base = state->writer_params.glue_buffs[seg_page];
state->writer_params.prev_rem_vect.iov_len = 0; state->writer_params.data_segments[seg_page][SEGMENT_GLUE].iov_len = 0;
}
state->writer_params.glue_carry_vec.iov_base = state->writer_params.glue_buffs[SEGMENTS_PAGES];
state->writer_params.glue_carry_vec.iov_len = 0; // nothing there fro the first frame (TODO: need same for start write?)
return 0; return 0;
} }
...@@ -321,384 +285,27 @@ int init_align_buffers(camogm_state *state) ...@@ -321,384 +285,27 @@ int init_align_buffers(camogm_state *state)
/** Delete buffers for frame alignment */ /** Delete buffers for frame alignment */
void deinit_align_buffers(camogm_state *state) void deinit_align_buffers(camogm_state *state)
{ {
struct writer_params *params = &state->writer_params; int seg_page;
int i; for (seg_page = 0; seg_page < SEGMENTS_PAGES+1; seg_page++){
if (params->data_chunks) { free (state->writer_params.glue_buffs[seg_page]);
free(params->data_chunks); state->writer_params.glue_buffs[seg_page] = NULL;
params->data_chunks = NULL;
}
for (i= 0; i < FILE_CHUNKS_PAGES; i++) {
if (params->common_buffs[i]) {
free(params->common_buffs[i]);
params->common_buffs[i] = NULL;
}
}
if (params->rem_buff) {
free(params->rem_buff);
params->rem_buff = NULL;
} }
if (params->prev_rem_buff) { for (seg_page = 0; seg_page < SEGMENTS_PAGES; seg_page++){
free(params->prev_rem_buff); free(state->writer_params.data_segments[seg_page]);
params->prev_rem_buff = NULL; state->writer_params.data_segments[seg_page] = NULL;
} }
} }
/** Align current frame to disk sector boundary and each individual buffer to #ALIGNMENT_SIZE boundary */ void reset_segments(camogm_state *state, int all, int page)
void align_frame(camogm_state *state)
{
const char *dev = NULL;
unsigned char *src;
size_t len, total_sz, data_len;
int page = state->writer_params.chunk_page_prep % FILE_CHUNKS_PAGES;
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;
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_paged(state, 0, INCLUDE_REM) + rbuff->iov_len;
//port_num
state->image_size[state->port_num] = total_sz;
D4(fprintf(debug_file, "total_sz = %d, rbuff->iov_len=%d\n", total_sz, (int)(rbuff->iov_len)));
if (total_sz < PHY_BLOCK_SIZE) {
/* the frame length is less than sector size, delay this frame */
if (rbuff->iov_len != 0) {
/* some data may be left from previous frame */
// 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);
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);
// vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_LEADER].iov_base, 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);
// vectshrink (&chunks[CHUNK_EXIF], chunks[CHUNK_EXIF].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);
// 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);
// 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);
// vectcpy (&chunks[CHUNK_REM], chunks[CHUNK_TRAILER].iov_base, 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;
}
/* copy remainder of previous frame to the beginning of common buffer */
if (rbuff->iov_len != 0) {
len = rbuff->iov_len;
dev_dbg(dev, "copy %u bytes from REM to common buffer\n", len);
vectcpy(cbuff, rbuff->iov_base, len);
vectshrink(rbuff, rbuff->iov_len);
}
/*Calculate alignment size and add zeros here*/
#ifdef ALIGN_INTERFRAME
// calculate length after adding CHUNK_LEADER, CHUNK_EXIF and CHUNK_HEADER to the current cbuf
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);
dev_dbg(dev, "total number of stuffing bytes between frames: %u\n", len);
vectset(cbuff, 0, len);
#endif
/* copy JPEG marker if present */
if (chunks[paged_CHUNK_LEADER].iov_len != 0) {
len = chunks[paged_CHUNK_LEADER].iov_len;
dev_dbg(dev, "copy %u bytes from LEADER to common buffer\n", len);
vectcpy(cbuff, chunks[paged_CHUNK_LEADER].iov_base, len);
vectshrink(&chunks[paged_CHUNK_LEADER], chunks[paged_CHUNK_LEADER].iov_len);
}
/* copy Exif if present */
if (chunks[paged_CHUNK_EXIF].iov_len != 0) {
len = chunks[paged_CHUNK_EXIF].iov_len;
dev_dbg(dev, "copy %u bytes from EXIF to common buffer\n", len);
vectcpy(cbuff, chunks[paged_CHUNK_EXIF].iov_base, len);
vectshrink(&chunks[paged_CHUNK_EXIF], chunks[paged_CHUNK_EXIF].iov_len);
}
#ifdef ALIGN_INTERFRAME
/* copy JPEG JPEG header data excluding leading marker if present */
if (chunks[paged_CHUNK_HEADER].iov_len != 0) {
len = chunks[paged_CHUNK_HEADER].iov_len;
dev_dbg(dev, "copy %u bytes from LEADER to common buffer\n", len);
vectcpy(cbuff, chunks[paged_CHUNK_HEADER].iov_base, len);
vectshrink(&chunks[paged_CHUNK_HEADER], chunks[paged_CHUNK_HEADER].iov_len);
}
#else // old way with app15
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 */
data_len = cbuff->iov_len + chunks[paged_CHUNK_HEADER].iov_len;
len = align_bytes_num(data_len, ALIGNMENT_SIZE);
if (len < (JPEG_MARKER_LEN + JPEG_SIZE_LEN) && len != 0) {
/* the number of bytes needed for alignment is less than the length of the marker itself, increase the number of stuffing bytes */
len += ALIGNMENT_SIZE;
}
dev_dbg(dev, "total number of stuffing bytes in APP15 marker: %u\n", len);
app15[3] = len - JPEG_MARKER_LEN;
vectcpy(cbuff, app15, len);
/* copy JPEG header */
len = chunks[paged_CHUNK_HEADER].iov_len;
dev_dbg(dev, "copy %u bytes from HEADER to common buffer\n", len);
vectcpy(cbuff, chunks[paged_CHUNK_HEADER].iov_base, 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,
// move start of the data_0 accordingly
data_len = cbuff->iov_len;
len = align_bytes_num(data_len, ALIGNMENT_SIZE);
if (len){ // assuming image data > 32 bits
vectcpy(cbuff, chunks[paged_CHUNK_DATA_0].iov_base, len);
vectshrinkhead(&chunks[paged_CHUNK_DATA_0],len);
}
}
#endif
/* 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_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) {
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?
if (len >= num) {
/* there is enough data to align common buffer to sector boundary */
if (num >= chunks[paged_CHUNK_DATA_0].iov_len) {
vectcpy(cbuff, chunks[paged_CHUNK_DATA_0].iov_base, chunks[paged_CHUNK_DATA_0].iov_len);
num -= chunks[paged_CHUNK_DATA_0].iov_len;
vectshrink(&chunks[paged_CHUNK_DATA_0], chunks[paged_CHUNK_DATA_0].iov_len);
} else {
src = vectrpos(&chunks[paged_CHUNK_DATA_0], num);
vectcpy(cbuff, chunks[paged_CHUNK_DATA_0].iov_base, num);
vectshrink(&chunks[paged_CHUNK_DATA_0], num);
num = 0;
}
if (chunks[paged_CHUNK_DATA_1].iov_len > 0) {
if (num >= chunks[paged_CHUNK_DATA_1].iov_len) {
vectcpy(cbuff, chunks[paged_CHUNK_DATA_1].iov_base, chunks[paged_CHUNK_DATA_1].iov_len);
num -= chunks[paged_CHUNK_DATA_1].iov_len;
vectshrink(&chunks[paged_CHUNK_DATA_1], chunks[paged_CHUNK_DATA_1].iov_len);
} else {
src = vectrpos(&chunks[paged_CHUNK_DATA_1], num);
vectcpy(cbuff, chunks[paged_CHUNK_DATA_1].iov_base, num);
vectshrink(&chunks[paged_CHUNK_DATA_1], num);
num = 0;
}
}
if (chunks[paged_CHUNK_TRAILER].iov_len > 0) {
if (num >= chunks[paged_CHUNK_TRAILER].iov_len) {
vectcpy(cbuff, chunks[paged_CHUNK_TRAILER].iov_base, chunks[paged_CHUNK_TRAILER].iov_len);
num -= chunks[paged_CHUNK_TRAILER].iov_len;
vectshrink(&chunks[paged_CHUNK_TRAILER], chunks[paged_CHUNK_TRAILER].iov_len);
} else {
src = vectrpos(&chunks[paged_CHUNK_TRAILER], num);
vectcpy(cbuff, chunks[paged_CHUNK_TRAILER].iov_base, num);
vectshrink(&chunks[paged_CHUNK_TRAILER], num);
num = 0;
}
}
} else {
/* there is not enough data to align common buffer to sector boundary, truncate common buffer */
data_len = cbuff->iov_len % PHY_BLOCK_SIZE;
src = vectrpos(cbuff, data_len);
vectcpy(chunk_rem, src, data_len);
vectshrink(cbuff, data_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[CHUNK_DATA_1].iov_base, chunks[paged_CHUNK_DATA_1].iov_len);
vectshrink(&chunks[paged_CHUNK_DATA_1], chunks[CHUNK_DATA_1].iov_len);
vectcpy(chunk_rem, chunks[CHUNK_TRAILER].iov_base, chunks[paged_CHUNK_TRAILER].iov_len);
vectshrink(&chunks[paged_CHUNK_TRAILER], chunks[paged_CHUNK_TRAILER].iov_len);
return;
}
/* 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_paged(state, 0, INCLUDE_REM);
len = total_sz % PHY_BLOCK_SIZE;
dev_dbg(dev, "number of bytes crossing sector boundary: %u\n", len);
if (len != 0) {
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 */
data_len = len - chunks[paged_CHUNK_DATA_1].iov_len - chunks[paged_CHUNK_TRAILER].iov_len;
D6(fprintf(debug_file, "_algn002: data_len=%d, copy %d short JPEG @ %07d\n", data_len, chunks[paged_CHUNK_DATA_1].iov_len, get_fpga_usec(state->fd_fparmsall[0], 0)));
src = vectrpos(&chunks[paged_CHUNK_DATA_0], data_len);
vectcpy(chunk_rem, src, data_len);
vectshrink(&chunks[paged_CHUNK_DATA_0], data_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);
} else if (len >= chunks[paged_CHUNK_TRAILER].iov_len) {
/* there is enough data in second part to align the frame */
data_len = len - chunks[paged_CHUNK_TRAILER].iov_len;
D6(fprintf(debug_file, "_algn003: data_len=%d, copy %d short JPEG @ %07d\n", data_len, chunks[paged_CHUNK_DATA_1].iov_len, get_fpga_usec(state->fd_fparmsall[0], 0)));
src = vectrpos(&chunks[paged_CHUNK_DATA_1], data_len);
vectcpy(chunk_rem, src, data_len);
vectshrink(&chunks[paged_CHUNK_DATA_1], data_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);
} else {
/* 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 */
data_len = PHY_BLOCK_SIZE - (chunks[paged_CHUNK_TRAILER].iov_len - len);
if (data_len >= chunks[paged_CHUNK_DATA_1].iov_len) {
size_t cut_len = data_len - chunks[paged_CHUNK_DATA_1].iov_len;
D6(fprintf(debug_file, "_algn004: cut_len=%d, copy %d short JPEG @ %07d\n", cut_len, chunks[paged_CHUNK_DATA_1].iov_len, get_fpga_usec(state->fd_fparmsall[0], 0)));
src = vectrpos(&chunks[paged_CHUNK_DATA_0], cut_len);
vectcpy(chunk_rem, src, cut_len);
vectshrink(&chunks[paged_CHUNK_DATA_0], cut_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);
} else {
D6(fprintf(debug_file, "_algn005: data_len=%d, @ %07d\n", data_len, get_fpga_usec(state->fd_fparmsall[0], 0)));
src = vectrpos(&chunks[paged_CHUNK_DATA_1], data_len);
vectcpy(chunk_rem, src, data_len);
vectshrink(&chunks[paged_CHUNK_DATA_1], data_len);
vectcpy(&chunks[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);
}
}
} else {
/* the frame is aligned to sector boundary but some buffers may be not */
chunks[paged_CHUNK_ALIGN].iov_base = vectrpos(cbuff, 0);
chunks[paged_CHUNK_ALIGN].iov_len = 0;
if (chunks[paged_CHUNK_DATA_1].iov_len == 0) {
data_len = chunks[paged_CHUNK_DATA_0].iov_len % ALIGNMENT_SIZE;
D6(fprintf(debug_file, "_algn006: data_len=%d, @ %07d\n", data_len, get_fpga_usec(state->fd_fparmsall[0], 0)));
src = vectrpos(&chunks[CHUNK_DATA_0], data_len);
vectcpy(&chunks[paged_CHUNK_ALIGN], src, data_len);
vectshrink(&chunks[paged_CHUNK_DATA_0], data_len);
} else {
data_len = chunks[paged_CHUNK_DATA_1].iov_len % ALIGNMENT_SIZE;
D6(fprintf(debug_file, "_algn007: data_len=%d, @ %07d\n", data_len, get_fpga_usec(state->fd_fparmsall[0], 0)));
src = vectrpos(&chunks[paged_CHUNK_DATA_1], data_len);
vectcpy(&chunks[paged_CHUNK_ALIGN], src, data_len);
vectshrink(&chunks[paged_CHUNK_DATA_1], data_len);
}
vectcpy(&chunks[paged_CHUNK_ALIGN], chunks[paged_CHUNK_TRAILER].iov_base, chunks[paged_CHUNK_TRAILER].iov_len);
vectshrink(&chunks[paged_CHUNK_TRAILER], chunks[paged_CHUNK_TRAILER].iov_len);
}
/* debug sanity check, should not happen */
if (cbuff->iov_len >= COMMON_BUFF_SZ) {
dev_dbg(NULL, "ERROR: the number of bytes copied to common buffer exceeds its size\n");
}
check_chunks(chunks, page);
D6(fprintf(debug_file, "align_frame() DONE @ %07d\n", get_fpga_usec(state->fd_fparmsall[0], 0)));
}
/** Discard buffer pointers making the command slot marked as empty */
//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; struct iovec *vects = state->writer_params.data_segments[page];
int chunk_offset = page * FILE_CHUNKS_NUM; for (i = 0; i < SEGMENTS_NUMBER; i++) {
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; state->writer_params.glue_carry_vec.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 */
// WRONG calculation - should be split?
/*
int update_lba(camogm_state *state)
{
int ret = 0;
size_t total_sz;
struct iovec *chunks = state->writer_params.data_chunks;
total_sz = get_blocks_num(chunks, MAX_DATA_CHUNKS - 1);
if (state->writer_params.lba_current + total_sz <= state->writer_params.lba_end) {
state->writer_params.lba_current += total_sz;
} else {
state->writer_params.lba_current = state->writer_params.lba_start + total_sz;
ret = 1;
} }
return ret;
}
*/
/** 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 page)
{
int ret = 0;
struct iovec *all = state->writer_params.data_chunks;
int chunk_offset = page * FILE_CHUNKS_NUM;
if (mapped_sz <= 0)
return ret;
for (int i = chunk_offset, j = 0; i < (chunk_offset + FILE_CHUNKS_NUM); i++) {
// if (i != CHUNK_REM && all[i].iov_len != 0) {
if (all[i].iov_len != 0) {
if (j < mapped_sz) {
mapped[j++] = all[i];
ret = j;
} else {
ret = -1;
break;
}
}
}
return ret;
}
/** 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 page)
{
int ret = 0;
size_t stuff_len;
unsigned char *src;
int chunk_offset = page * FILE_CHUNKS_NUM;
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) {
stuff_len = PHY_BLOCK_SIZE - rvect->iov_len;
src = vectrpos(rvect, 0);
memset(src, 0, stuff_len);
rvect->iov_len += stuff_len;
ret = rvect->iov_len;
vectcpy(cvect, rvect->iov_base, rvect->iov_len);
vectshrink(rvect, rvect->iov_len);
}
return ret;
} }
/** Convert LBA to byte offset used for lseek */ /** Convert LBA to byte offset used for lseek */
......
...@@ -25,37 +25,23 @@ ...@@ -25,37 +25,23 @@
// TODO: Change PHY_BLOCK_SIZE to 4096 as it is 4096 - no, most SSDs are still 512 // TODO: Change PHY_BLOCK_SIZE to 4096 as it is 4096 - no, most SSDs are still 512
#define PHY_BLOCK_SIZE 512 ///< Physical disk block size - still 512 even for the OS with 4096 #define PHY_BLOCK_SIZE 512 ///< Physical disk block size - still 512 even for the OS with 4096
//#define PHY_BLOCK_SIZE 4096 ///< 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
#define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation #define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation
#if 0
#define MAX_DATA_CHUNKS 9 ///< An array or JPEG frame chunks contains pointers to JPEG leading marker, #define MAX_DATA_CHUNKS 9 ///< An array or JPEG frame chunks contains pointers to JPEG leading marker,
///< JPEG header, Exif data if present, stuffing bytes chunk which aligns ///< JPEG header, Exif data if present, stuffing bytes chunk which aligns
///< the frame size to disk sector boundary, JPEG data which ///< the frame size to disk sector boundary, JPEG data which
///< can be split into two chunks, align buffers, JPEG ///< can be split into two chunks, align buffers, JPEG
///< trailing marker, and pointer to a buffer containing the remainder of a ///< trailing marker, and pointer to a buffer containing the remainder of a
///< frame. Nine chunks of data in total. ///< frame. Nine chunks of data in total.
///
#define ALIGNMENT_SIZE 32 ///< Align buffers length to this amount of bytes #define ALIGNMENT_SIZE 32 ///< Align buffers length to this amount of bytes
/** Common buffer should be large enough to contain JPEG header, Exif, some alignment bytes and remainder from previous frame */ /** Common buffer should be large enough to contain JPEG header, Exif, some alignment bytes and remainder from previous frame */
#define COMMON_BUFF_SZ MAX_EXIF_SIZE + JPEG_HEADER_MAXSIZE + ALIGNMENT_SIZE + 2 * PHY_BLOCK_SIZE #define COMMON_BUFF_SZ MAX_EXIF_SIZE + JPEG_HEADER_MAXSIZE + ALIGNMENT_SIZE + 2 * PHY_BLOCK_SIZE
#define REM_BUFF_SZ 2 * PHY_BLOCK_SIZE #define REM_BUFF_SZ 2 * PHY_BLOCK_SIZE
#endif
///** This structure holds raw device buffer pointers */
//struct drv_pointers {
// uint64_t lba_start; ///< raw buffer starting LBA
// uint64_t lba_end; ///< raw buffer ending LBA
// uint64_t lba_write; ///< current write pointer inside raw buffer
// uint16_t wr_count; ///< the number of LBA to write next time
//};
/** Container structure for frame buffers */
//struct frame_buffers {
// struct fvec exif_buff; ///< Exif buffer
// struct fvec jpheader_buff; ///< JPEG header buffer
// struct fvec trailer_buff; ///< buffer for trailing marker
// struct fvec common_buff; ///< common buffer where other parts are combined
// struct fvec rem_buff; ///< remainder from previous frame
//};
/** Symbolic names for slots in buffer pointers. Buffer alignment function relies on the order of these names, so /** Symbolic names for slots in buffer pointers. Buffer alignment function relies on the order of these names, so
* new names can be added but the overall order should not be changed */ * new names can be added but the overall order should not be changed */
...@@ -71,16 +57,12 @@ enum { ...@@ -71,16 +57,12 @@ enum {
CHUNK_REM ///< pointer to buffer containing the remainder of current frame. It will be recorded during next transaction CHUNK_REM ///< pointer to buffer containing the remainder of current frame. It will be recorded during next transaction
}; };
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 reset_segments(camogm_state *state, int all, int page);
void reset_chunks(camogm_state *state, int all, int page); size_t remap_vectors(camogm_state *state); //, struct iovec *chunks);
//int update_lba(camogm_state *state);
int get_data_buffers(camogm_state *state, struct iovec *mapped, size_t mapped_sz, int page);
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);
//uint64_t lba_to_offset(uint64_t lba);
#endif /* _CAMOGM_ALIGN_H */ #endif /* _CAMOGM_ALIGN_H */
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
/** @brief This define is needed to use lseek64 and should be set before includes */ /** @brief This define is needed to use lseek64 and should be set before includes */
#define _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE
#define __USE_GNU // for O_DIRECT
#include <linux/raw.h> // for O_DIRECT
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -34,8 +35,8 @@ ...@@ -34,8 +35,8 @@
#include "camogm_jpeg.h" #include "camogm_jpeg.h"
#include "camogm_read.h" #include "camogm_read.h"
#include "camogm_align.h" #include "camogm_align.h"
#define BUFFER_KVEC
#define MAX_IMAGE_ALIGNED (4096*256)
/** 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 */
...@@ -45,6 +46,56 @@ ...@@ -45,6 +46,56 @@
static void *jpeg_writer(void *thread_args); static void *jpeg_writer(void *thread_args);
static int save_state_file(const camogm_state *state); static int save_state_file(const camogm_state *state);
#ifdef BUFFER_KVEC
static unsigned char * image_ubuffer = NULL;
#endif
/**
* Emulate writev() by consecutive write()
* @param __fd
* @param __iovec
* @param __count
* @return
*/
ssize_t emul_writev (int fd, const struct iovec *iovec, int count) {
int i;
ssize_t wlen, tot_len = 0;
for (i = 0; i < count; i++) {
if (iovec[i].iov_len > 0) {
#ifdef BUFFER_KVEC
D6(fprintf(debug_file, "Trying direct writing of %d bytes from %p, data = 0x%llx\n",\
iovec[i].iov_len, iovec[i].iov_base, ((uint64_t*) iovec[i].iov_base)[0]));
D6(syslog (LOG_INFO, "Trying direct writing of %d bytes from %p, data = 0x%llx\n",\
iovec[i].iov_len, iovec[i].iov_base, ((uint64_t*) iovec[i].iov_base)[0]));
wlen = write (fd, iovec[i].iov_base, iovec[i].iov_len);
if (wlen < 0) {
D6(fprintf(debug_file, "Got write error = %d, copying %d bytes from %p to %p\n",\
-wlen, iovec[i].iov_len, iovec[i].iov_base, image_ubuffer));
if (iovec[i].iov_len > MAX_IMAGE_ALIGNED){
D0(fprintf(debug_file, "image too big: %d > %d\n", iovec[i].iov_len, MAX_IMAGE_ALIGNED));
return -1;
}
memcpy(image_ubuffer, iovec[i].iov_base, iovec[i].iov_len);
D6(fprintf(debug_file, "data=0x%llx\n", ((uint64_t*) image_ubuffer)[0]));
D6(syslog (LOG_INFO, "data = 0x%llx\n",((uint64_t*) image_ubuffer)[0]));
wlen = write (fd,image_ubuffer, iovec[i].iov_len);
}
#else
wlen = write (fd, iovec[i].iov_base, iovec[i].iov_len);
#endif
if (wlen < 0) {
return wlen;
} else if (wlen < iovec[i].iov_len) {
return tot_len + wlen;
} else {
tot_len += wlen;
}
}
}
return tot_len;
}
/** Get starting and endign LBAs of the partition specified as raw device buffer */ /** Get starting and endign LBAs of the partition specified as raw device buffer */
static int get_disk_range(struct range *range) static int get_disk_range(struct range *range)
{ {
...@@ -190,7 +241,18 @@ int camogm_init_jpeg(camogm_state *state) ...@@ -190,7 +241,18 @@ int camogm_init_jpeg(camogm_state *state)
if (ret_val != 0) { if (ret_val != 0) {
D0(fprintf(debug_file, "Can not initialize alignment buffers\n")); D0(fprintf(debug_file, "Can not initialize alignment buffers\n"));
ret = -1; ret = -1;
return ret;
}
#ifdef BUFFER_KVEC
image_ubuffer = (unsigned char *) aligned_alloc (PAGE_PHYS, MAX_IMAGE_ALIGNED);
if (image_ubuffer == NULL){
D0(fprintf(debug_file, "Can not initialize image_ubuffer\n"));
ret = -1;
} else {
D3(fprintf(debug_file, "Allocated image buffer for copying kernel data @ %p size= %d bytes\n", image_ubuffer, MAX_IMAGE_ALIGNED));
} }
#endif
} }
return ret; return ret;
...@@ -216,6 +278,13 @@ void camogm_free_jpeg(camogm_state *state) ...@@ -216,6 +278,13 @@ void camogm_free_jpeg(camogm_state *state)
state->writer_params.exit_thread = false; state->writer_params.exit_thread = false;
deinit_align_buffers(state); deinit_align_buffers(state);
#ifdef BUFFER_KVEC
if (image_ubuffer != NULL){
D3(fprintf(debug_file, "Deallcating image buffer for copying kernel data @ %p size= %d bytes\n", image_ubuffer, MAX_IMAGE_ALIGNED));
free (image_ubuffer);
image_ubuffer = NULL;
}
#endif
} }
/** Calculate the total length of current frame */ /** Calculate the total length of current frame */
...@@ -264,7 +333,7 @@ int camogm_start_jpeg(camogm_state *state) ...@@ -264,7 +333,7 @@ int camogm_start_jpeg(camogm_state *state)
D0(fprintf(debug_file, "Could not get write pointer from state file, recording will start from the beginning of partition: " D0(fprintf(debug_file, "Could not get write pointer from state file, recording will start from the beginning of partition: "
"%s\n", state->rawdev.rawdev_path)); "%s\n", state->rawdev.rawdev_path));
} }
state->writer_params.blockdev_fd = open(state->rawdev.rawdev_path, O_RDWR); state->writer_params.blockdev_fd = open(state->rawdev.rawdev_path, O_RDWR | __O_DIRECT); // __O_DIRECT);
if (state->writer_params.blockdev_fd < 0) { if (state->writer_params.blockdev_fd < 0) {
D0(fprintf(debug_file, "Error opening block device: %s\n", state->rawdev.rawdev_path)); D0(fprintf(debug_file, "Error opening block device: %s\n", state->rawdev.rawdev_path));
return -CAMOGM_FRAME_FILE_ERR; return -CAMOGM_FRAME_FILE_ERR;
...@@ -309,43 +378,45 @@ int camogm_frame_jpeg(camogm_state *state) ...@@ -309,43 +378,45 @@ int camogm_frame_jpeg(camogm_state *state)
D0(fprintf(debug_file, "Error opening %s for writing, returned %d, errno=%d\n", state->path, state->ivf, errno)); D0(fprintf(debug_file, "Error opening %s for writing, returned %d, errno=%d\n", state->path, state->ivf, errno));
return -CAMOGM_FRAME_FILE_ERR; return -CAMOGM_FRAME_FILE_ERR;
} }
iovlen = writev(state->ivf, chunks_iovec, (state->chunk_index) - 1); iovlen = emul_writev(state->ivf, chunks_iovec, (state->chunk_index) - 1); // FIXME! Remove gaps?
if (iovlen < l) { if (iovlen < l) {
j = errno; j = errno;
D0(fprintf(debug_file, "writev error %d (returned %d, expected %d)\n", j, iovlen, l)); D0(fprintf(debug_file, "emul_writev error %d (returned %d, expected %d)\n", j, iovlen, l));
close(state->ivf); close(state->ivf);
return -CAMOGM_FRAME_FILE_ERR; return -CAMOGM_FRAME_FILE_ERR;
} }
state->rawdev.last_jpeg_size = l; state->rawdev.last_jpeg_size = l;
close(state->ivf); close(state->ivf);
} else { } else {
D6(fprintf(debug_file, "ccam_dma_buf[%d] = %p\n",port, get_ccam_dma_buf(port)));
D3(fprintf(debug_file, "_12.7_ camogm_frame_jpeg(): %ld.%06ld:%d @ %07d\n",state->this_frame_params[port].timestamp_sec, state->this_frame_params[port].timestamp_usec, port, get_fpga_usec(state->fd_fparmsall[0], 0))); D3(fprintf(debug_file, "_12.7_ camogm_frame_jpeg(): %ld.%06ld:%d @ %07d\n",state->this_frame_params[port].timestamp_sec, state->this_frame_params[port].timestamp_usec, port, get_fpga_usec(state->fd_fparmsall[0], 0)));
D6(fprintf(debug_file, "\ndump iovect array for port %u\n", state->port_num)); D6(fprintf(debug_file, "\ndump iovect array for port %u, chunk_index=%u, chunk_data_index=%u, data_segments=%u\n", state->port_num, state->chunk_index, state->chunk_data_index, state->data_segments));
for (int i = 0; i < state->chunk_index - 1; i++) { for (int i = 0; i < state->chunk_index; 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].chunk, state->packetchunks[i].bytes));
} }
// next frame is ready for recording, signal this to the writer thread // next frame is ready for recording, signal this to the writer thread
D6(fprintf(debug_file, "_13__: Yielding thread before getting a lock (%d, %d):%d @ %07d\n", state->writer_params.chunk_page_prep, state->writer_params.chunk_page_write, state->writer_params.writev_run, get_fpga_usec(state->fd_fparmsall[0], 0))); D6(fprintf(debug_file, "_13_: Yielding thread before getting a lock (%d, %d):%d @ %07d\n", state->writer_params.chunk_page_prep, state->writer_params.chunk_page_write, state->writer_params.writev_run, get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_yield(); pthread_yield();
pthread_mutex_lock(&state->writer_params.writer_mutex); pthread_mutex_lock(&state->writer_params.writer_mutex);
D6(fprintf(debug_file, "_13a_: waiting for empty buffer (%d, %d):%d @ %07d\n", state->writer_params.chunk_page_prep, state->writer_params.chunk_page_write, state->writer_params.writev_run, get_fpga_usec(state->fd_fparmsall[0], 0))); D6(fprintf(debug_file, "_13a_: waiting for empty buffer (%d, %d):%d @ %07d\n", state->writer_params.chunk_page_prep, state->writer_params.chunk_page_write, state->writer_params.writev_run, get_fpga_usec(state->fd_fparmsall[0], 0)));
// do not run ahead by >= FILE_CHUNKS_PAGES (0 or 1 for just FILE_CHUNKS_PAGES == 2) // do not run ahead by >= FILE_CHUNKS_PAGES (0 or 1 for just FILE_CHUNKS_PAGES == 2)
// either buffer is completely empty (state->writer_params->chunk_page_prep == state->writer_params->chunk_page_write) // either buffer is completely empty (state->writer_params->chunk_page_prep == state->writer_params->chunk_page_write)
// or it is not full and writev_run is active // or it is not full and writev_run is active
while (((state->writer_params.chunk_page_prep - state->writer_params.chunk_page_write + (2 * FILE_CHUNKS_PAGES)) while (((state->writer_params.chunk_page_prep - state->writer_params.chunk_page_write + (2 * SEGMENTS_PAGES))
% (2 * FILE_CHUNKS_PAGES) >= FILE_CHUNKS_PAGES) || % (2 * SEGMENTS_PAGES) >= SEGMENTS_PAGES) ||
(!state->writer_params.writev_run && (state->writer_params.chunk_page_prep != state->writer_params.chunk_page_write))) { (!state->writer_params.writev_run && (state->writer_params.chunk_page_prep != state->writer_params.chunk_page_write))) {
D6(fprintf(debug_file, "_13b_: waiting for empty buffer (%d, %d):%d @ %07d\n", state->writer_params.chunk_page_prep, state->writer_params.chunk_page_write, state->writer_params.writev_run, get_fpga_usec(state->fd_fparmsall[0], 0))); D6(fprintf(debug_file, "_13b_: waiting for empty buffer (%d, %d):%d @ %07d\n", state->writer_params.chunk_page_prep, state->writer_params.chunk_page_write, state->writer_params.writev_run, get_fpga_usec(state->fd_fparmsall[0], 0)));
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);
} }
pthread_mutex_unlock(&state->writer_params.writer_mutex); pthread_mutex_unlock(&state->writer_params.writer_mutex);
D6(fprintf(debug_file, "_13c_: got empty buffer (%d, %d):%d @ %07d\n", state->writer_params.chunk_page_prep, state->writer_params.chunk_page_write, state->writer_params.writev_run, get_fpga_usec(state->fd_fparmsall[0], 0))); D6(fprintf(debug_file, "_13c_: got empty buffer (%d, %d):%d @ %07d\n", state->writer_params.chunk_page_prep, state->writer_params.chunk_page_write, state->writer_params.writev_run, get_fpga_usec(state->fd_fparmsall[0], 0)));
align_frame(state); remap_vectors(state); // now can be used instead of align_frame(state), returns total length
// align_frame(state);
// proceed if last frame was recorded without errors // proceed if last frame was recorded without errors
D6(fprintf(debug_file, "_13d_:frame aligned @ %07d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); D6(fprintf(debug_file, "_13d_:frame aligned @ %07d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_mutex_lock(&state->writer_params.writer_mutex); 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.chunk_page_prep = (state->writer_params.chunk_page_prep + 1) % (2 * FILE_CHUNKS_PAGES); state->writer_params.chunk_page_prep = (state->writer_params.chunk_page_prep + 1) % (2 * SEGMENTS_PAGES);
// state->writer_params.data_ready = true; // 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, "_13e_: chunk_page_prep = %d (%d), signal writer_cond @ %07d\n",state->writer_params.chunk_page_prep, state->writer_params.chunk_page_write, get_fpga_usec(state->fd_fparmsall[0], 0))); D6(fprintf(debug_file, "_13e_: chunk_page_prep = %d (%d), signal writer_cond @ %07d\n",state->writer_params.chunk_page_prep, state->writer_params.chunk_page_write, get_fpga_usec(state->fd_fparmsall[0], 0)));
...@@ -382,19 +453,37 @@ int camogm_end_jpeg(camogm_state *state) // TODO: Resolve multippage ! ...@@ -382,19 +453,37 @@ int camogm_end_jpeg(camogm_state *state) // TODO: Resolve multippage !
// 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.chunk_page_prep != state->writer_params.chunk_page_write) 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 = state->writer_params.glue_carry_vec.iov_len;
bytes = prep_last_block(state, state->writer_params.chunk_page_prep % FILE_CHUNKS_PAGES); if (bytes > 0) {
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
iovlen = emul_writev(state->writer_params.blockdev_fd,
&state->writer_params.glue_carry_vec,
1);
if (iovlen < bytes) {
D0(fprintf(debug_file, "emul_writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, bytes));
state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR;
} else {
// update statistic, just one block written
state->writer_params.lba_current += 1;
state->rawdev.total_rec_len += bytes;
}
// reset_chunks(state->writer_params.data_chunks, 1);
//*************** See if another buffer(s) must be cleared too? or even use chunk_page_write
reset_segments(state, 1, state->writer_params.chunk_page_prep % SEGMENTS_PAGES);
}
#if 0
bytes = prep_last_block(state, state->writer_params.chunk_page_prep % SEGMENTS_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, iovlen = emul_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); &state->writer_params.data_chunks[CHUNK_COMMON + (state->writer_params.chunk_page_prep % SEGMENTS_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, "emul_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;
} else { } else {
// update statistic, just one block written // update statistic, just one block written
...@@ -403,15 +492,15 @@ int camogm_end_jpeg(camogm_state *state) // TODO: Resolve multippage ! ...@@ -403,15 +492,15 @@ int camogm_end_jpeg(camogm_state *state) // TODO: Resolve multippage !
} }
// 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 //*************** 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); reset_segments(state, 1, state->writer_params.chunk_page_prep % SEGMENTS_PAGES);
} }
#endif
pthread_mutex_unlock(&state->writer_params.writer_mutex); pthread_mutex_unlock(&state->writer_params.writer_mutex);
D6(fprintf(debug_file, "Closing block device %s\n", state->rawdev.rawdev_path)); D6(fprintf(debug_file, "Closing block device %s\n", state->rawdev.rawdev_path));
ret = close(state->writer_params.blockdev_fd); ret = close(state->writer_params.blockdev_fd);
if (ret == -1) if (ret == -1)
D0(fprintf(debug_file, "Error: %s\n", strerror(errno))); D0(fprintf(debug_file, "Error: %s\n", strerror(errno)));
save_state_file(state); save_state_file(state);
} }
return ret; return ret;
...@@ -425,30 +514,28 @@ int camogm_end_jpeg(camogm_state *state) // TODO: Resolve multippage ! ...@@ -425,30 +514,28 @@ int camogm_end_jpeg(camogm_state *state) // TODO: Resolve multippage !
*/ */
void *jpeg_writer(void *thread_args) void *jpeg_writer(void *thread_args)
{ {
int dbg_us1, dbg_us2, dbg_us; // save usec for difference struct iovec write_segments[SEGMENTS_NUMBER];// 3
int num_write_segments, seg_len;
int dbg_us1=0, dbg_us2=0, dbg_us; // save usec for difference
long dbg_pos; long dbg_pos;
int reset_rem; int reset_rem;
int chunk_index, i0, i1; // int chunk_index, i, i0, i1;
int i, i0, i1;
ssize_t iovlen, l, ll, l0, l1, blocks_write, wpage; ssize_t iovlen, l, ll, l0, l1, blocks_write, wpage;
bool process = true, has_data_to_write = false; bool process = true, has_data_to_write = false;
struct iovec chunks_iovec[FILE_CHUNKS_PAGES][FILE_CHUNKS_NUM]; // struct iovec chunks_iovec[SEGMENTS_PAGES][FILE_CHUNKS_NUM];
struct iovec split_chunk; 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_PAGES * FILE_CHUNKS_NUM); // memset((void *)chunks_iovec, 0, sizeof(struct iovec) * SEGMENTS_PAGES * FILE_CHUNKS_NUM);
// lock, will only allow main thread while a) waiting for write buffer, and b) waiting for writev // lock, will only allow main thread while a) waiting for write buffer, and b) waiting for emul_writev
//// 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 @ %07d\n", get_fpga_usec(state->fd_fparmsall[0], 0))); // before the debug file is set ! D6(fprintf(debug_file, "_w000_: Before jpeg_writer loop @ %07d\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) {
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 ! pthread_mutex_lock(&params->writer_mutex); // first time before the debug file is set !
D6(fprintf(debug_file, "_w00_: (%d, %d) @ %07d\n", params->chunk_page_prep, params->chunk_page_write, get_fpga_usec(state->fd_fparmsall[0], 0))); D6(fprintf(debug_file, "_w00_: (%d, %d) @ %07d\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) { while ((params->chunk_page_prep == params->chunk_page_write) && !params->exit_thread) {
...@@ -486,31 +573,39 @@ void *jpeg_writer(void *thread_args) ...@@ -486,31 +573,39 @@ void *jpeg_writer(void *thread_args)
reset_rem = 0; reset_rem = 0;
state->writer_params.last_ret_val = 0; state->writer_params.last_ret_val = 0;
// inputs from state->writer_params.data_chunks, returns number of result chunks // inputs from state->writer_params.data_chunks, returns number of result chunks
wpage = state->writer_params.chunk_page_write % FILE_CHUNKS_PAGES; wpage = state->writer_params.chunk_page_write % SEGMENTS_PAGES;
chunk_index = get_data_buffers(state, chunks_iovec[wpage], FILE_CHUNKS_NUM, wpage); num_write_segments = 0;
for (i = 0; i < SEGMENTS_NUMBER; i++){
seg_len = state->writer_params.data_segments[wpage][i].iov_len;
if (seg_len > 0){
write_segments[num_write_segments++] = state->writer_params.data_segments[wpage][i];
l+=seg_len;
}
}
// chunk_index = get_data_buffers(state, chunks_iovec[wpage], FILE_CHUNKS_NUM, wpage);
// assuming write is block-aligned // assuming write is block-aligned
if (chunk_index > 0) { if (num_write_segments > 0) {
for (int i = 0; i < chunk_index; i++) #if 0
for (i = 0; i < chunk_index; i++)
l += chunks_iovec[wpage][i].iov_len; l += chunks_iovec[wpage][i].iov_len;
#endif
// Moved rollover here // Moved rollover here
blocks_write = l / PHY_BLOCK_SIZE; blocks_write = l / PHY_BLOCK_SIZE; // here LBA, 512
if (state->writer_params.lba_current + blocks_write <= state->writer_params.lba_end) { // almost always - single write if (state->writer_params.lba_current + blocks_write <= state->writer_params.lba_end) { // almost always - single write
state->writer_params.lba_current += blocks_write; state->writer_params.lba_current += blocks_write;
// D6(fprintf(debug_file, "_w02_: starting writev @ %07d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
// D3(dbg_us1=get_fpga_usec(state->fd_fparmsall[0], 0); dbg_pos = lseek(state->writer_params.blockdev_fd, 0, SEEK_CUR));
D3(dbg_us1=get_fpga_usec(state->fd_fparmsall[0], 0)); D3(dbg_us1=get_fpga_usec(state->fd_fparmsall[0], 0));
D6(dbg_pos = lseek(state->writer_params.blockdev_fd, 0, SEEK_CUR)); D6(dbg_pos = lseek(state->writer_params.blockdev_fd, 0, SEEK_CUR));
D6(fprintf(debug_file, "_w02_: starting writev@ %07d\n", dbg_us1)); D6(fprintf(debug_file, "_w02_: starting emul_writev@ %07d\n", dbg_us1));
state->writer_params.writev_run = true; state->writer_params.writev_run = true;
pthread_cond_signal(&params->main_cond); pthread_cond_signal(&params->main_cond);
iovlen = writev(state->writer_params.blockdev_fd, chunks_iovec[wpage], chunk_index); // iovlen = emul_writev(state->writer_params.blockdev_fd, chunks_iovec[wpage], chunk_index);
iovlen = emul_writev(state->writer_params.blockdev_fd, write_segments, num_write_segments);
state->writer_params.writev_run = false; state->writer_params.writev_run = false;
// D6(fprintf(debug_file, "_w03_: finished writev @ %07d\n",get_fpga_usec(state->fd_fparmsall[0], 0))); D3(dbg_us=get_fpga_usec(state->fd_fparmsall[0], 0); fprintf(debug_file, "_w03_: finished emul_writev, pos%%block = %ld, pos= %ld @ %07d (+ %07d, +%07d)\n",dbg_pos % PHY_BLOCK_SIZE, dbg_pos,dbg_us, (dbg_us-dbg_us1), (dbg_us-dbg_us2)));
D3(dbg_us=get_fpga_usec(state->fd_fparmsall[0], 0); fprintf(debug_file, "_w03_: finished writev, pos%%block = %ld, pos= %ld @ %07d (+ %07d, +%07d)\n",dbg_pos % PHY_BLOCK_SIZE, dbg_pos,dbg_us, (dbg_us-dbg_us1), (dbg_us-dbg_us2))); D3(syslog (LOG_INFO, "_w03_: finished emul_writev, pos= %ld, len = %d(0x%x) @ %07d (+ %07d, +%07d)", dbg_pos, iovlen, iovlen, dbg_us, (dbg_us-dbg_us1), (dbg_us-dbg_us2)));
D3(syslog (LOG_INFO, "_w03_: finished writev, pos= %ld @ %07d (+ %07d, +%07d)", dbg_pos, dbg_us, (dbg_us-dbg_us1), (dbg_us-dbg_us2)));
D3(dbg_us2=dbg_us); D3(dbg_us2=dbg_us);
if (iovlen < l) { if (iovlen < l) {
D0(fprintf(debug_file, "writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, l)); D0(fprintf(debug_file, "emul_writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, l));
state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR; state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR;
reset_rem = 1; reset_rem = 1;
lseek(state->writer_params.blockdev_fd, lseek(state->writer_params.blockdev_fd,
...@@ -528,36 +623,40 @@ void *jpeg_writer(void *thread_args) ...@@ -528,36 +623,40 @@ void *jpeg_writer(void *thread_args)
i1 = 0; // start of the second write i1 = 0; // start of the second write
if (l0 > 0) { // should be always if (l0 > 0) { // should be always
ll = 0; ll = 0;
for (i0 = 0; i0 < chunk_index; i0++){ for (i0 = 0; i0 < num_write_segments; i0++){
if (ll + chunks_iovec[wpage][i0].iov_len > l0){ if (ll + write_segments[i0].iov_len > l0){
break; break;
} }
ll += chunks_iovec[wpage][i0].iov_len; ll += write_segments[i0].iov_len;
} }
// save split chunk // save split chunk
split_chunk.iov_base = chunks_iovec[wpage][i0].iov_base; /// split_chunk.iov_base = chunks_iovec[wpage][i0].iov_base;
split_chunk.iov_len = chunks_iovec[wpage][i0].iov_len; /// split_chunk.iov_len = chunks_iovec[wpage][i0].iov_len;
split_chunk.iov_base = write_segments[i0].iov_base;
split_chunk.iov_len = write_segments[i0].iov_len;
i1 = i0; // index of the first chunk in a second write i1 = i0; // index of the first chunk in a second write
if (ll < l0) { // is it a partial chunk? if (ll < l0) { // is it a partial chunk?
chunks_iovec[wpage][i0].iov_len = l0 - ll; write_segments[i0].iov_len = l0 - ll;
i0++; // include split chunk in the first write i0++; // include split chunk in the first write
} }
// write the first group (before rollover) // write the first group (before rollover)
state->writer_params.lba_current = state->writer_params.lba_start; state->writer_params.lba_current = state->writer_params.lba_start;
state->writer_params.writev_run = true; state->writer_params.writev_run = true;
pthread_cond_signal(&params->main_cond); pthread_cond_signal(&params->main_cond);
iovlen = writev(state->writer_params.blockdev_fd, chunks_iovec[wpage], i0); /// iovlen = emul_writev(state->writer_params.blockdev_fd, chunks_iovec[wpage], i0);
iovlen = emul_writev(state->writer_params.blockdev_fd, write_segments, i0);
state->writer_params.writev_run = false; state->writer_params.writev_run = false;
lseek(state->writer_params.blockdev_fd, 0, SEEK_SET); // regardless of error - rewind lseek(state->writer_params.blockdev_fd, 0, SEEK_SET); // regardless of error - rewind
if (iovlen < l0) { if (iovlen < l0) {
D0(fprintf(debug_file, "(1 of 2) writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, l0)); D0(fprintf(debug_file, "(1 of 2) emul_writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, l0));
state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR; state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR;
reset_rem = 1; reset_rem = 1;
} else { } else {
// do not update statistic after the first writev(), do it after the second // do not update statistic after the first emul_writev(), 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))); 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 // update split chunk to use its second part, shift chunks
if (l1 > 0) { // length to be written after rollover if (l1 > 0) { // length to be written after rollover
#if 0
if (chunks_iovec[wpage][i1].iov_len != split_chunk.iov_len) { // it was split 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)); 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_base += chunks_iovec[wpage][i1].iov_len;
...@@ -569,12 +668,28 @@ void *jpeg_writer(void *thread_args) ...@@ -569,12 +668,28 @@ void *jpeg_writer(void *thread_args)
} }
state->writer_params.writev_run = true; state->writer_params.writev_run = true;
pthread_cond_signal(&params->main_cond); pthread_cond_signal(&params->main_cond);
iovlen = writev(state->writer_params.blockdev_fd, chunks_iovec[wpage], chunk_index - i1); iovlen = emul_writev(state->writer_params.blockdev_fd, chunks_iovec[wpage], chunk_index - i1);
state->writer_params.writev_run = false;
#endif
if (write_segments[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, write_segments[i1].iov_len));
write_segments[i1].iov_base += write_segments[i1].iov_len;
write_segments[i1].iov_len = split_chunk.iov_len - write_segments[i1].iov_len;
}
// shift chunks
for (i0 = i1; i0 < num_write_segments; i0++){
/// write_segments[i0 - i1] = write_segments[i0];
write_segments[i0 - i1].iov_base = write_segments[i0].iov_base;
write_segments[i0 - i1].iov_len = write_segments[i0].iov_len;
}
state->writer_params.writev_run = true;
pthread_cond_signal(&params->main_cond);
iovlen = emul_writev(state->writer_params.blockdev_fd, write_segments, num_write_segments - i1);
state->writer_params.writev_run = false; state->writer_params.writev_run = false;
state->writer_params.lba_current = state->writer_params.lba_start + l1 / PHY_BLOCK_SIZE; state->writer_params.lba_current = state->writer_params.lba_start + l1 / PHY_BLOCK_SIZE;
if (iovlen < l1) { if (iovlen < l1) {
D0(fprintf(debug_file, "(2 of 2) writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, l1)); D0(fprintf(debug_file, "(2 of 2) emul_writev error: %s (returned %i, expected %i)\n", strerror(errno), iovlen, l1));
state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR; state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR;
reset_rem = 1; reset_rem = 1;
} else { } else {
...@@ -591,18 +706,15 @@ void *jpeg_writer(void *thread_args) ...@@ -591,18 +706,15 @@ void *jpeg_writer(void *thread_args)
D6(fprintf(debug_file, "_w05_: Block device positions: start = %llu, current = %llu, end = %llu\n", 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)); 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", num_write_segments));
state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR; state->writer_params.last_ret_val = -CAMOGM_FRAME_FILE_ERR;
reset_rem = 1; reset_rem = 1;
} }
// release main thread // release main thread
// reset_chunks(state->writer_params.data_chunks, reset_rem); /// reset_chunks(state, reset_rem, state->writer_params.chunk_page_write % SEGMENTS_PAGES);
reset_chunks(state, reset_rem, state->writer_params.chunk_page_write % FILE_CHUNKS_PAGES); reset_segments(state, reset_rem, state->writer_params.chunk_page_write % SEGMENTS_PAGES);
pthread_mutex_lock(&params->writer_mutex); pthread_mutex_lock(&params->writer_mutex);
params->chunk_page_write = (params->chunk_page_write + 1) % (2 * FILE_CHUNKS_PAGES); params->chunk_page_write = (params->chunk_page_write + 1) % (2 * SEGMENTS_PAGES);
// params->data_ready = false;
if (params->chunk_page_prep == params->chunk_page_write) { if (params->chunk_page_prep == params->chunk_page_write) {
pthread_cond_signal(&params->main_cond); // ********** Do not signal if can write more ! 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 @ %07d\n", params->chunk_page_prep, params->chunk_page_write,get_fpga_usec(state->fd_fparmsall[0], 0))); D6(fprintf(debug_file, "_w06_: wrote data (%d , %d), buffer empty, signal main thread @ %07d\n", params->chunk_page_prep, params->chunk_page_write,get_fpga_usec(state->fd_fparmsall[0], 0)));
...@@ -610,7 +722,7 @@ void *jpeg_writer(void *thread_args) ...@@ -610,7 +722,7 @@ void *jpeg_writer(void *thread_args)
D6(fprintf(debug_file, "_w06a_: wrote data (%d , %d), has more to write, do not signal! @ %07d\n", params->chunk_page_prep, params->chunk_page_write,get_fpga_usec(state->fd_fparmsall[0], 0))); D6(fprintf(debug_file, "_w06a_: wrote data (%d , %d), has more to write, do not signal! @ %07d\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 pthread_mutex_unlock(&params->writer_mutex); // do not release untill waiting for emul_writev() or waiting for data to write
} }
} }
params->state = STATE_STOPPED; params->state = STATE_STOPPED;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#ifndef _CAMOGM_JPEG_H #ifndef _CAMOGM_JPEG_H
#define _CAMOGM_JPEG_H #define _CAMOGM_JPEG_H
#define __USE_GNU // for O_DIRECT
#include "camogm.h" #include "camogm.h"
...@@ -26,5 +27,7 @@ int camogm_frame_jpeg(camogm_state *state); ...@@ -26,5 +27,7 @@ int camogm_frame_jpeg(camogm_state *state);
int camogm_end_jpeg(camogm_state *state); int camogm_end_jpeg(camogm_state *state);
void camogm_free_jpeg(camogm_state *state); void camogm_free_jpeg(camogm_state *state);
int open_state_file(const rawdev_buffer *rawdev, uint64_t *current_pos); int open_state_file(const rawdev_buffer *rawdev, uint64_t *current_pos);
ssize_t emul_writev (int fd, const struct iovec *iovec, int count);
#endif /* _CAMOGM_JPEG_H */ #endif /* _CAMOGM_JPEG_H */
...@@ -417,7 +417,7 @@ static int read_index(rawdev_buffer *rawdev, struct disk_index **indx) ...@@ -417,7 +417,7 @@ static int read_index(rawdev_buffer *rawdev, struct disk_index **indx)
unsigned char read_buff[TIFF_HDR_OFFSET] = {0}; unsigned char read_buff[TIFF_HDR_OFFSET] = {0};
char str_buff[SMALL_BUFF_LEN] = {0}; char str_buff[SMALL_BUFF_LEN] = {0};
uint64_t save_pos = lseek64(rawdev->rawdev_fd, 0, SEEK_CUR); uint64_t save_pos = lseek64(rawdev->rawdev_fd, 0, SEEK_CUR);
int dummy;
if (indx == NULL) if (indx == NULL)
return -1; return -1;
...@@ -429,16 +429,16 @@ static int read_index(rawdev_buffer *rawdev, struct disk_index **indx) ...@@ -429,16 +429,16 @@ static int read_index(rawdev_buffer *rawdev, struct disk_index **indx)
} }
if (read_buff[2] == 0xff && read_buff[3] == 0xe1) { if (read_buff[2] == 0xff && read_buff[3] == 0xe1) {
// get IFD0 offset from TIFF header // get IFD0 offset from TIFF header
read(rawdev->rawdev_fd, &hdr, sizeof(struct tiff_hdr)); dummy=read(rawdev->rawdev_fd, &hdr, sizeof(struct tiff_hdr));
hdr_byte_order(&hdr); hdr_byte_order(&hdr);
curr_pos = rawdev->file_start + TIFF_HDR_OFFSET + hdr.offset; curr_pos = rawdev->file_start + TIFF_HDR_OFFSET + hdr.offset;
lseek64(rawdev->rawdev_fd, curr_pos, SEEK_SET); lseek64(rawdev->rawdev_fd, curr_pos, SEEK_SET);
// process IFD0 and SubIFD fields // process IFD0 and SubIFD fields
do { do {
read(rawdev->rawdev_fd, &num_entries, sizeof(num_entries)); dummy=read(rawdev->rawdev_fd, &num_entries, sizeof(num_entries));
num_entries = __be16_to_cpu(num_entries); num_entries = __be16_to_cpu(num_entries);
for (int i = 0; i < num_entries; i++) { for (int i = 0; i < num_entries; i++) {
read(rawdev->rawdev_fd, &ifd, sizeof(struct ifd_entry)); dummy=read(rawdev->rawdev_fd, &ifd, sizeof(struct ifd_entry));
ifd_byte_order(&ifd); ifd_byte_order(&ifd);
switch (ifd.tag) { switch (ifd.tag) {
case Exif_Image_PageNumber: case Exif_Image_PageNumber:
...@@ -457,7 +457,7 @@ static int read_index(rawdev_buffer *rawdev, struct disk_index **indx) ...@@ -457,7 +457,7 @@ static int read_index(rawdev_buffer *rawdev, struct disk_index **indx)
} }
// ensure that IFD0 finished correctly (0x00000000 in the end), set file pointer to SubIFD and // ensure that IFD0 finished correctly (0x00000000 in the end), set file pointer to SubIFD and
// process remaining fields // process remaining fields
read(rawdev->rawdev_fd, &data32, sizeof(data32)); dummy=read(rawdev->rawdev_fd, &data32, sizeof(data32));
process -= (subifd_offset == 0 || data32 != 0) ? 2 : 1; process -= (subifd_offset == 0 || data32 != 0) ? 2 : 1;
curr_pos = rawdev->file_start + TIFF_HDR_OFFSET + subifd_offset; curr_pos = rawdev->file_start + TIFF_HDR_OFFSET + subifd_offset;
lseek64(rawdev->rawdev_fd, curr_pos, SEEK_SET); lseek64(rawdev->rawdev_fd, curr_pos, SEEK_SET);
...@@ -815,10 +815,11 @@ static void send_fnum(int sockfd, size_t num) ...@@ -815,10 +815,11 @@ static void send_fnum(int sockfd, size_t num)
{ {
char buff[SMALL_BUFF_LEN] = {0}; char buff[SMALL_BUFF_LEN] = {0};
int len; int len;
int dummy;
len = snprintf(buff, SMALL_BUFF_LEN - 1, "Number of files: %d\n", num); len = snprintf(buff, SMALL_BUFF_LEN - 1, "Number of files: %d\n", num);
buff[len] = '\0'; buff[len] = '\0';
write(sockfd, buff, len); dummy=write(sockfd, buff, len);
} }
/** /**
...@@ -1017,6 +1018,7 @@ void *reader(void *arg) ...@@ -1017,6 +1018,7 @@ void *reader(void *arg)
.sockfd_const = &sockfd, .sockfd_const = &sockfd,
.sockfd_temp = &fd .sockfd_temp = &fd
}; };
int dummy;
memset(&index_dir, 0, sizeof(struct disk_idir)); memset(&index_dir, 0, sizeof(struct disk_idir));
memset(&index_sparse, 0, sizeof(struct disk_idir)); memset(&index_sparse, 0, sizeof(struct disk_idir));
...@@ -1059,7 +1061,7 @@ void *reader(void *arg) ...@@ -1059,7 +1061,7 @@ void *reader(void *arg)
len = snprintf(send_buff, CMD_BUFF_LEN - 1, INDEX_FORMAT_STR, len = snprintf(send_buff, CMD_BUFF_LEN - 1, INDEX_FORMAT_STR,
disk_indx->port, disk_indx->rawtime, disk_indx->usec, disk_indx->f_offset, disk_indx->f_size); disk_indx->port, disk_indx->rawtime, disk_indx->usec, disk_indx->f_offset, disk_indx->f_size);
send_buff[len] = '\0'; send_buff[len] = '\0';
write(fd, send_buff, len); dummy=write(fd, send_buff, len);
disk_indx = disk_indx->next; disk_indx = disk_indx->next;
} }
} else { } else {
......
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