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

working on fast write

parent e4468ac7
Loading
Loading
Loading
Loading
+37 −32
Original line number Original line Diff line number Diff line
@@ -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)
{
{
	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,7 +504,7 @@ 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;
@@ -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)
/* 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)
		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)
{
{
	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
 */
 */
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)
		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)
	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)
	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)
		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 < min_sz && free_sz >= 0) || min_sz == -1) {
					if (free_sz < CAMOGM_MIN_BUF_FRAMES * state->image_size[i]) {
					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]));
						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;
						chn = -1; // i;
						break;
						break;
					}
					}
				if ((free_sz < min_sz && free_sz >= 0) || min_sz == -1) {
					min_sz = free_sz;
					min_sz = free_sz;
					chn = i;
					chn = i;
				}
				}
@@ -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)
			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)
	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];
}
+72 −18
Original line number Original line Diff line number Diff line
@@ -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 @@
#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 @@
#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 @@
#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 @@
/** @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 {
	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 {
	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 {
	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);
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 */
Loading