Commit f0587888 authored by Mikhail Karpenko's avatar Mikhail Karpenko
Browse files

Merge branch 'multithreaded_aligned'

 Conflicts:
	src/camogm.c
	src/camogm.h
parents 676ade6a 7e3873de
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -11,7 +11,7 @@ IMAGES = $(GUIDIR)/images/filebrowser-01.gif $(GUIDIR)/images/filebrowser-bo
             $(GUIDIR)/images/rec_folder.png $(GUIDIR)/images/up_folder.gif $(GUIDIR)/images/play_audio.png $(GUIDIR)/images/hdd.png
             $(GUIDIR)/images/rec_folder.png $(GUIDIR)/images/up_folder.gif $(GUIDIR)/images/play_audio.png $(GUIDIR)/images/hdd.png




SRCS = camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c camogm_read.c index_list.c
SRCS = camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c camogm_read.c index_list.c camogm_align.c
TEST_SRC = camogm_test.c
TEST_SRC = camogm_test.c
OBJS = $(SRCS:.c=.o)
OBJS = $(SRCS:.c=.o)


@@ -31,7 +31,7 @@ IMAGEDIR = $(WWW_PAGES)/images
all: $(PROGS) $(TEST_PROG)
all: $(PROGS) $(TEST_PROG)


$(PROGS): $(OBJS)
$(PROGS): $(OBJS)
	$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
	$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@


$(TEST_PROG): $(TEST_SRC:.c=.o)
$(TEST_PROG): $(TEST_SRC:.c=.o)


+47 −18
Original line number Original line Diff line number Diff line
@@ -64,21 +64,6 @@


char trailer[TRAILER_SIZE] = { 0xff, 0xd9 };
char trailer[TRAILER_SIZE] = { 0xff, 0xd9 };


#if 0
const char *exifFileNames[] = { "/dev/exif_exif0", "/dev/exif_exif1",
                                "/dev/exif_exif2", "/dev/exif_exif3"
};

const char *headFileNames[] = { "/dev/jpeghead0", "/dev/jpeghead1",
                                "/dev/jpeghead2", "/dev/jpeghead3"
};
const char *ctlFileNames[] = {   "/dev/frameparsall0", "/dev/frameparsall1",
                                "/dev/frameparsall2", "/de/framepars3"
};
const char *circbufFileNames[] = {"/dev/circbuf0", "/dev/circbuf1",
                                "/dev/circbuf2", "/dev/circbuf3"
};
#else
const char *exifFileNames[] = { DEV393_PATH(DEV393_EXIF0), DEV393_PATH(DEV393_EXIF1),
const char *exifFileNames[] = { DEV393_PATH(DEV393_EXIF0), DEV393_PATH(DEV393_EXIF1),
                                DEV393_PATH(DEV393_EXIF2), DEV393_PATH(DEV393_EXIF3)
                                DEV393_PATH(DEV393_EXIF2), DEV393_PATH(DEV393_EXIF3)
};
};
@@ -92,7 +77,6 @@ const char *ctlFileNames[] = { DEV393_PATH(DEV393_FRAMEPARS0), DEV393_PATH(DEV3
const char *circbufFileNames[] = {DEV393_PATH(DEV393_CIRCBUF0), DEV393_PATH(DEV393_CIRCBUF1),
const char *circbufFileNames[] = {DEV393_PATH(DEV393_CIRCBUF0), DEV393_PATH(DEV393_CIRCBUF1),
                                  DEV393_PATH(DEV393_CIRCBUF2), DEV393_PATH(DEV393_CIRCBUF3)
                                  DEV393_PATH(DEV393_CIRCBUF2), DEV393_PATH(DEV393_CIRCBUF3)
};
};
#endif


int lastDaemonBit[SENSOR_PORTS] = {DAEMON_BIT_CAMOGM};
int lastDaemonBit[SENSOR_PORTS] = {DAEMON_BIT_CAMOGM};
struct framepars_all_t   *frameParsAll[SENSOR_PORTS];
struct framepars_all_t   *frameParsAll[SENSOR_PORTS];
@@ -167,6 +151,7 @@ static int get_sysfs_name(const char *dev_name, char *sys_name, size_t str_sz, i
static int get_disk_range(const char *name, struct range *rng);
static int get_disk_range(const char *name, struct range *rng);
static int set_disk_range(const struct range *rng);
static int set_disk_range(const struct range *rng);
static void get_disk_info(camogm_state *state);
static void get_disk_info(camogm_state *state);
static struct timeval get_fpga_time(const int fd_fparsall, unsigned int port);
int open_files(camogm_state *state);
int open_files(camogm_state *state);
unsigned long getGPValue(unsigned int port, unsigned long GPNumber);
unsigned long getGPValue(unsigned int port, unsigned long GPNumber);
void setGValue(unsigned int port, unsigned long GNumber, unsigned long value);
void setGValue(unsigned int port, unsigned long GNumber, unsigned long value);
@@ -279,6 +264,10 @@ void camogm_init(camogm_state *state, char *pipe_name, uint16_t port_num)
	state->active_chn = ALL_CHN_INACTIVE;
	state->active_chn = ALL_CHN_INACTIVE;
	state->rawdev.mmap_default_size = MMAP_CHUNK_SIZE;
	state->rawdev.mmap_default_size = MMAP_CHUNK_SIZE;
	state->sock_port = port_num;
	state->sock_port = port_num;

	state->writer_params.data_ready = false;
	state->writer_params.exit_thread = false;
	state->writer_params.state = STATE_STOPPED;
}
}


/**
/**
@@ -366,6 +355,7 @@ int camogm_start(camogm_state *state)
		if (is_chn_active(state, chn)) {
		if (is_chn_active(state, chn)) {
			// Check/set circbuf read pointer
			// Check/set circbuf read pointer
			D3(fprintf(debug_file, "1: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn]));
			D3(fprintf(debug_file, "1: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn]));
			D3(fprintf(debug_file, "1a: compressed frame number = %li\n", lseek(state->fd_circ[chn], LSEEK_CIRC_GETFRAME, SEEK_END)));
			if ((state->cirbuf_rp[chn] < 0) || (lseek(state->fd_circ[chn], state->cirbuf_rp[chn], SEEK_SET) < 0) || (lseek(state->fd_circ[chn], LSEEK_CIRC_VALID, SEEK_END) < 0 )) {
			if ((state->cirbuf_rp[chn] < 0) || (lseek(state->fd_circ[chn], state->cirbuf_rp[chn], SEEK_SET) < 0) || (lseek(state->fd_circ[chn], LSEEK_CIRC_VALID, SEEK_END) < 0 )) {
				D3(fprintf(debug_file, "2: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn]));
				D3(fprintf(debug_file, "2: state->cirbuf_rp=0x%x\n", state->cirbuf_rp[chn]));
				/* In "greedy" mode try to save as many frames from the circbuf as possible */
				/* In "greedy" mode try to save as many frames from the circbuf as possible */
@@ -526,6 +516,9 @@ int sendImageFrame(camogm_state *state)
	int * ifp_this = (int*)&(state->this_frame_params[state->port_num]);
	int * ifp_this = (int*)&(state->this_frame_params[state->port_num]);
	int fp;
	int fp;
	int port = state->port_num;
	int port = state->port_num;
	struct timeval start_time, end_time;

//	start_time = get_fpga_time(state->fd_fparmsall[port], port);


// This is probably needed only for Quicktime (not to exceed already allocated frame index)
// This is probably needed only for Quicktime (not to exceed already allocated frame index)
	if (!state->rawdev_op && (state->frameno >= (state->max_frames))) {
	if (!state->rawdev_op && (state->frameno >= (state->max_frames))) {
@@ -656,13 +649,16 @@ int sendImageFrame(camogm_state *state)
/* copy from the beginning of the buffer to the end of the frame */
/* copy from the beginning of the buffer to the end of the frame */
		state->packetchunks[state->chunk_index  ].bytes = state->jpeg_len - (state->circ_buff_size[port] - state->cirbuf_rp[port]);
		state->packetchunks[state->chunk_index  ].bytes = state->jpeg_len - (state->circ_buff_size[port] - state->cirbuf_rp[port]);
		state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][0];
		state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][0];
		state->writer_params.segments = 2;
	} else { // single segment
	} else { // single segment
		D3(fprintf(debug_file, "_11_"));
		D3(fprintf(debug_file, "_11_"));


/* copy from the beginning of the frame to the end of the frame (no buffer rollovers) */
/* copy from the beginning of the frame to the end of the frame (no buffer rollovers) */
		state->packetchunks[state->chunk_index  ].bytes = state->jpeg_len;
		state->packetchunks[state->chunk_index  ].bytes = state->jpeg_len;
		state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][state->cirbuf_rp[port] >> 2];
		state->packetchunks[state->chunk_index++].chunk = (unsigned char*)&ccam_dma_buf[state->port_num][state->cirbuf_rp[port] >> 2];
		state->writer_params.segments = 1;
	}
	}
	D3(fprintf(debug_file, "\tcirbuf_rp = 0x%x\t", state->cirbuf_rp[port]));
	D3(fprintf(debug_file, "_12_"));
	D3(fprintf(debug_file, "_12_"));
	state->packetchunks[state->chunk_index  ].bytes = 2;
	state->packetchunks[state->chunk_index  ].bytes = 2;
	state->packetchunks[state->chunk_index++].chunk = (unsigned char*)trailer;
	state->packetchunks[state->chunk_index++].chunk = (unsigned char*)trailer;
@@ -685,6 +681,7 @@ int sendImageFrame(camogm_state *state)
// advance frame pointer
// advance frame pointer
	state->frameno++;
	state->frameno++;
	state->cirbuf_rp[port] = lseek(state->fd_circ[port], LSEEK_CIRC_NEXT, SEEK_END);
	state->cirbuf_rp[port] = lseek(state->fd_circ[port], LSEEK_CIRC_NEXT, SEEK_END);
	D3(fprintf(debug_file, "\tcompressed frame number: %li\t", lseek(state->fd_circ[port], LSEEK_CIRC_GETFRAME, SEEK_END)));
// optionally save it to global read pointer (i.e. for debugging with imgsrv "/pointers")
// optionally save it to global read pointer (i.e. for debugging with imgsrv "/pointers")
	if (state->save_gp) lseek(state->fd_circ[port], LSEEK_CIRC_SETP, SEEK_END);
	if (state->save_gp) lseek(state->fd_circ[port], LSEEK_CIRC_SETP, SEEK_END);
	D3(fprintf(debug_file, "_15_\n"));
	D3(fprintf(debug_file, "_15_\n"));
@@ -693,6 +690,19 @@ int sendImageFrame(camogm_state *state)
	} else if (state->frames_skip < 0) {
	} else if (state->frames_skip < 0) {
		state->frames_skip_left[port] += -(state->frames_skip);
		state->frames_skip_left[port] += -(state->frames_skip);
	}
	}
	D3(fprintf(debug_file,"cirbuf_rp to next frame = 0x%x\n", state->cirbuf_rp[port]));

//	end_time = get_fpga_time(state->fd_fparmsall[port], port);
//	unsigned int mbps; // write speed, MB/s
//	unsigned long long time_diff; // time elapsed, in microseconds
//	time_diff = ((end_time.tv_sec * 1000000 + end_time.tv_usec) - (start_time.tv_sec * 1000000 + start_time.tv_usec));
//	mbps = ((double)state->rawdev.last_jpeg_size / (double)1048576) / ((double)time_diff / (double)1000000);
//	D6(fprintf(debug_file, "Frame start time: %ld:%ld; frame end time: %ld:%ld; last frame size: %lu\n",
//			start_time.tv_sec, start_time.tv_usec,
//			end_time.tv_sec, end_time.tv_usec,
//			state->rawdev.last_jpeg_size));
//	D6(fprintf(debug_file, "Write speed: %d MB/s\n", mbps));

	return 0;
	return 0;
}
}


@@ -750,7 +760,7 @@ void camogm_free(camogm_state *state)
			switch (f) {
			switch (f) {
			case CAMOGM_FORMAT_NONE: break;
			case CAMOGM_FORMAT_NONE: break;
			case CAMOGM_FORMAT_OGM:  camogm_free_ogm(); break;
			case CAMOGM_FORMAT_OGM:  camogm_free_ogm(); break;
			case CAMOGM_FORMAT_JPEG: camogm_free_jpeg(); break;
			case CAMOGM_FORMAT_JPEG: camogm_free_jpeg(state); break;
			case CAMOGM_FORMAT_MOV:  camogm_free_mov(); break;
			case CAMOGM_FORMAT_MOV:  camogm_free_mov(); break;
			}
			}
		}
		}
@@ -875,6 +885,9 @@ void get_disk_info(camogm_state *state)
	}
	}


	if (get_disk_range(state->rawdev.rawdev_path, &rng) == 0) {
	if (get_disk_range(state->rawdev.rawdev_path, &rng) == 0) {
		state->writer_params.lba_start = rng.from;
		state->writer_params.lba_end = rng.to;
		state->writer_params.lba_current = state->writer_params.lba_start;
		set_disk_range(&rng);
		set_disk_range(&rng);
	} else {
	} else {
		D0(fprintf(debug_file, "ERROR: unable to get disk size and starting sector\n"));
		D0(fprintf(debug_file, "ERROR: unable to get disk size and starting sector\n"));
@@ -2029,7 +2042,7 @@ int main(int argc, char *argv[])
	sstate.rawdev.thread_state = STATE_RUNNING;
	sstate.rawdev.thread_state = STATE_RUNNING;
	str_len = strlen(state_name_str);
	str_len = strlen(state_name_str);
	if (str_len > 0) {
	if (str_len > 0) {
		strncpy(sstate.rawdev.state_path, state_name_str, str_len + 1);
		strncpy(sstate.rawdev.state_path, (const char *)state_name_str, str_len + 1);
	}
	}


	ret = listener_loop(&sstate);
	ret = listener_loop(&sstate);
@@ -2104,3 +2117,19 @@ inline int is_fd_valid(int fd)
{
{
	return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
	return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}
}

/**
 * @brief Get current FPGA time
 * @return   Time value in \e timeval structure
 */
struct timeval get_fpga_time(const int fd_fparsall, unsigned int port)
{
	struct timeval tv;
	unsigned long write_data[] = {FRAMEPARS_GETFPGATIME, 0};

	write(fd_fparsall, write_data, sizeof(unsigned long) * 2);
	tv.tv_sec = getGPValue(port, G_SECONDS);
	tv.tv_usec = getGPValue(port, G_MICROSECONDS);

	return tv;
}
+32 −3
Original line number Original line Diff line number Diff line
@@ -27,7 +27,6 @@
#include <elphel/c313a.h>
#include <elphel/c313a.h>
#include <elphel/x393_devices.h>
#include <elphel/x393_devices.h>



#define CAMOGM_FRAME_NOT_READY    1        ///< frame pointer valid, but not yet acquired
#define CAMOGM_FRAME_NOT_READY    1        ///< frame pointer valid, but not yet acquired
#define CAMOGM_FRAME_INVALID      2        ///< invalid frame pointer
#define CAMOGM_FRAME_INVALID      2        ///< invalid frame pointer
#define CAMOGM_FRAME_CHANGED      3        ///< frame parameters have changed
#define CAMOGM_FRAME_CHANGED      3        ///< frame parameters have changed
@@ -66,6 +65,8 @@
#define MMAP_CHUNK_SIZE           10485760
#define MMAP_CHUNK_SIZE           10485760
/** @brief Time interval (in microseconds) for processing commands */
/** @brief Time interval (in microseconds) for processing commands */
#define COMMAND_LOOP_DELAY        500000
#define COMMAND_LOOP_DELAY        500000
/** @brief File can be split up to this number of chunks */
#define FILE_CHUNKS_NUM           8


/**
/**
 * @enum state_flags
 * @enum state_flags
@@ -125,6 +126,7 @@ typedef struct {
	uint64_t mmap_offset;
	uint64_t mmap_offset;
	uint64_t file_start;
	uint64_t file_start;
	int64_t total_rec_len;
	int64_t total_rec_len;
	unsigned long last_jpeg_size;
	pthread_t tid;
	pthread_t tid;
	volatile int thread_state;
	volatile int thread_state;
	unsigned char *disk_mmap;
	unsigned char *disk_mmap;
@@ -132,6 +134,33 @@ typedef struct {
	char state_path[ELPHEL_PATH_MAX];
	char state_path[ELPHEL_PATH_MAX];
} rawdev_buffer;
} rawdev_buffer;


/**
 * @struct writer_params
 * @brief Contains mutexes and conditional variables associated with disk writing thread
 */
struct writer_params {
	int blockdev_fd;                                        ///< file descriptor for open block device where frame will be recorded
	pthread_t writer_thread;                                ///< disk writing thread
	pthread_mutex_t writer_mutex;                           ///< synchronization mutex for main and writing threads
	pthread_cond_t writer_cond;                             ///< conditional variable indicating that writer thread can proceed with new frame
	pthread_cond_t main_cond;                               ///< conditional variable indicating that main thread can update write pointers
	bool data_ready;                                        ///< flag indicating that new frame is ready for recording, access to this flag
	                                                        ///< must be protected with #writer_mutex. Set this flag in main thread and reset in
	                                                        ///< disk writing thread.
	int last_ret_val;                                       ///< error value return during last frame recording (if any occurred)
	bool exit_thread;                                       ///< flag indicating that the writing thread should terminate
	int state;                                              ///< the state of disk writing thread
	int segments;                                           ///< the number of segments in frame

	struct iovec *data_chunks;                              ///< a set of vectors pointing to aligned frame data buffers
	struct iovec prev_rem_vect;                             ///< vector pointing to the remainder of the previous frame
	unsigned char *rem_buff;                                ///< buffer containing the unaligned remainder of the current frame
	unsigned char *prev_rem_buff;                           ///< buffer containing the unaligned remainder of the previous frame
	unsigned char *common_buff;                             ///< buffer for aligned JPEG header
	uint64_t lba_start;                                     ///< disk starting LBA
	uint64_t lba_current;                                   ///< current write position in LBAs
	uint64_t lba_end;                                       ///< disk last LBA
};
/**
/**
 * @struct camogm_state
 * @struct camogm_state
 * @brief Holds current state of the running program
 * @brief Holds current state of the running program
@@ -192,7 +221,7 @@ typedef struct {
	int formats;                                            ///< bitmask of used (initialized) formats
	int formats;                                            ///< bitmask of used (initialized) formats
	int format;                                             ///< output file format
	int format;                                             ///< output file format
	int set_format;                                         ///< output format to set (will be updated after stop)
	int set_format;                                         ///< output format to set (will be updated after stop)
	elph_packet_chunk packetchunks[8];
	elph_packet_chunk packetchunks[FILE_CHUNKS_NUM];
	int chunk_index;
	int chunk_index;
	int buf_overruns[SENSOR_PORTS];
	int buf_overruns[SENSOR_PORTS];
	int buf_min[SENSOR_PORTS];
	int buf_min[SENSOR_PORTS];
@@ -222,7 +251,7 @@ typedef struct {
	rawdev_buffer rawdev;                                   ///< contains pointers to raw device buffer
	rawdev_buffer rawdev;                                   ///< contains pointers to raw device buffer
	unsigned int active_chn;                                ///< bitmask of active sensor ports
	unsigned int active_chn;                                ///< bitmask of active sensor ports
	uint16_t sock_port; 									///< command socket port number
	uint16_t sock_port; 									///< command socket port number

	struct writer_params writer_params;                     ///< contains control parameters for writing thread
	unsigned int error_stat[SENSOR_PORTS][CAMOGM_ERRNUM];   ///< collect statistics about errors
	unsigned int error_stat[SENSOR_PORTS][CAMOGM_ERRNUM];   ///< collect statistics about errors
} camogm_state;
} camogm_state;


Loading