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

Add new command to set raw device path

parent 8856f31f
Loading
Loading
Loading
Loading
+65 −40
Original line number Diff line number Diff line
@@ -183,6 +183,11 @@ unsigned long *aglobalPars[SENSOR_PORTS]; /// parameters that are not
camogm_state sstate;
//camogm_state * state;

typedef enum {
	RAW_PATH,
	FILE_PATH
} path_type;

int debug_level;
FILE* debug_file;

@@ -198,7 +203,7 @@ void camogm_set_greedy(camogm_state *state, int d);
void  camogm_set_ignore_fps(camogm_state *state, int d);

void  camogm_set_save_gp(camogm_state *state, int d);
void  camogm_set_prefix(camogm_state *state, const char * p);
void  camogm_set_prefix(camogm_state *state, const char * p, path_type type);
void  camogm_set_exif(camogm_state *state, int d);
void  camogm_set_timescale(camogm_state *state, double d);   //! set timescale, default=1.0
void  camogm_set_frames_skip(camogm_state *state, int d);    //! set number of frames to skip, if negative - seconds between frames
@@ -280,52 +285,53 @@ void camogm_init(camogm_state *state, unsigned int port, char *pipe_name)
	const char sserial[] = "elp0";
	int * ipser = (int*)sserial;

	state->running = 0;                     // mo
	state->starting = 0;                    // mo
	state->vf = NULL;
	memset(state, 0, sizeof(camogm_state));
//	state->running = 0;                     // mo
//	state->starting = 0;                    // mo
//	state->vf = NULL;
	camogm_set_segment_duration(state, DEFAULT_DURATION);
	camogm_set_segment_length(state, DEFAULT_LENGTH);
	camogm_set_greedy(state, DEFAULT_GREEDY);
	camogm_set_ignore_fps(state, DEFAULT_IGNORE_FPS);
	camogm_set_max_frames(state, DEFAULT_FRAMES);
	camogm_set_frames_per_chunk(state, DEFAULT_FRAMES_PER_CHUNK);
	camogm_set_start_after_timestamp(state, 0.0); // start any time
	camogm_set_prefix(state, "\0");
	camogm_set_save_gp(state, 0);
//	camogm_set_start_after_timestamp(state, 0.0); // start any time
//	camogm_set_prefix(state, "\0", FILE_PATH);
//	camogm_set_save_gp(state, 0);
	camogm_reset(state);                    // sets state->buf_overruns =- 1
	state->serialno = ipser[0];
	state->last = 0;
//	state->last = 0;
	debug_file = stderr;
	camogm_debug_level(DEFAULT_DEBUG_LVL);
	strcpy(state->debug_name, "stderr");
	camogm_set_timescale(state, 1.0);
	camogm_set_frames_skip(state, 0);       // don't skip
	camogm_set_format(state, CAMOGM_FORMAT_MOV);
	FOR_EACH_PORT(int, chn) {state->exifSize[chn] = 0;}
//	FOR_EACH_PORT(int, chn) {state->exifSize[chn] = 0;}
	state->exif = DEFAULT_EXIF;
	state->frame_lengths = NULL;
	state->frameno = 0;
	state->formats = 0;
	state->last_error_code = 0;
//	state->frameno = 0;
//	state->formats = 0;
//	state->last_error_code = 0;

	// kml stuff
	camogm_kml_set_enable(state, 0);
	state->kml_file = NULL;
//	camogm_kml_set_enable(state, 0);
//	state->kml_file = NULL;
	camogm_kml_set_horHalfFov(state, 20.0);
	camogm_kml_set_vertHalfFov(state, 15.0);
	camogm_kml_set_height_mode(state, 0);
	camogm_kml_set_height(state, 10.0);
	camogm_kml_set_period(state, 2);        // 2 sec
	camogm_kml_set_near(state, 40.0);       // 40 m (distance to PhotoOverlay)
	state->kml_path[0] = '\0';
//	state->kml_path[0] = '\0';

	state->port_num = port;
	state->pipe_name = pipe_name;
	state->rawdev.start_pos = RAWDEV_START_OFFSET;
	state->rawdev.end_pos = state->rawdev.start_pos;
	state->rawdev.curr_pos = state->rawdev.start_pos;
	state->rawdev.overrun = 0;
	state->rawdev_op = 0;
//	state->rawdev.overrun = 0;
//	state->rawdev_op = 0;
	state->active_chn = ALL_CHN_ACTIVE;
}

@@ -366,8 +372,12 @@ int camogm_start(camogm_state *state)
	int port = state->port_num;

	if (state->active_chn == ALL_CHN_INACTIVE) {
		D1(fprintf(debug_file, "All channels are disabled, will not start\n"));
		return 0;
		D0(fprintf(debug_file, "All channels are disabled, will not start\n"));
		return CAMOGM_FRAME_OTHER;
	}
	if (state->rawdev_op && state->format != CAMOGM_FORMAT_JPEG) {
		D0(fprintf(debug_file, "Raw device write initiated, but file format is not JPEG. Will not start\n"));
		return CAMOGM_FRAME_OTHER;
	}

	D1(fprintf(debug_file, "Starting recording\n"));
@@ -384,7 +394,7 @@ int camogm_start(camogm_state *state)
		switch (state->format) {
		case CAMOGM_FORMAT_NONE: rslt = 0; break;
		case CAMOGM_FORMAT_OGM:  rslt = camogm_init_ogm(); break;
		case CAMOGM_FORMAT_JPEG: rslt = camogm_init_jpeg(); break;
		case CAMOGM_FORMAT_JPEG: rslt = camogm_init_jpeg(state); break;
		case CAMOGM_FORMAT_MOV:  rslt = camogm_init_mov(); break;
		}
		state->formats |= 1 << (state->format);
@@ -841,26 +851,27 @@ void camogm_set_ignore_fps(camogm_state *state, int d)
	state->ignore_fps =   d ? 1 : 0;
}

void  camogm_set_prefix(camogm_state *state, const char * p)
void  camogm_set_prefix(camogm_state *state, const char * p, path_type type)
{
	if (type == FILE_PATH) {
		strncpy(state->path_prefix, p, sizeof(state->path_prefix) - 1);
		state->path_prefix[sizeof(state->path_prefix) - 1] = '\0';
	// check if we are going to write to raw device
	if (strncmp("/dev/", state->path_prefix, 5) == 0) {
		state->rawdev.end_pos = get_disk_size(state->path_prefix);
	} else if (type == RAW_PATH && (strncmp(p, "/dev/", 5) == 0)) {
		strncpy(state->rawdev.rawdev_path, p, sizeof(state->rawdev.rawdev_path) - 1);
		state->rawdev.rawdev_path[sizeof(state->rawdev.rawdev_path) - 1] = '\0';
		state->rawdev.end_pos = get_disk_size(state->rawdev.rawdev_path);
		if (state->rawdev.end_pos == 0) {
			state->rawdev_op = 0;
			state->rawdev.end_pos = state->rawdev.start_pos;
			state->path_prefix[0] = '\0';
			printf("ERROR: unable to initiate raw device operation\n");
			state->rawdev.rawdev_path[0] = '\0';
			D0(fprintf(debug_file, "ERROR: unable to initiate raw device operation\n"));
		} else {
			printf("WARNING: raw device write initiated\n");
			D0(fprintf(debug_file, "WARNING: raw device write initiated\n"));
			state->rawdev_op = 1;
			/* debug code follows */
			state->rawdev.end_pos = state->rawdev.start_pos + 10485760; // 10Mib size
			state->rawdev.end_pos =  20971520; // 20Mib size
			/* end of debug code */
		}
	} else {
		state->rawdev_op = 0;
	}
}

@@ -892,7 +903,7 @@ void camogm_set_format(camogm_state *state, int d)
		switch (state->format) {
		case CAMOGM_FORMAT_NONE: rslt = 0; break;
		case CAMOGM_FORMAT_OGM:  rslt = camogm_init_ogm(); break;
		case CAMOGM_FORMAT_JPEG: rslt = camogm_init_jpeg(); break;
		case CAMOGM_FORMAT_JPEG: rslt = camogm_init_jpeg(state); break;
		case CAMOGM_FORMAT_MOV:  rslt = camogm_init_mov(); break;
		}
		if (rslt) {
@@ -1021,7 +1032,9 @@ void camogm_status(camogm_state *state, char * fn, int xml)
			"  <kml_period>%d</kml_period>\n" \
			"  <kml_last_ts>%d.%06d</kml_last_ts>\n" \
			"  <greedy>\"%s\"</greedy>\n" \
			"  <ignore_fps>\"%s\"</ignore_fps>\n",
			"  <ignore_fps>\"%s\"</ignore_fps>\n" \
			"  <raw_device_path>\"%s\"</raw_device_path>\n" \
			"  <raw_device_overruns>%d</raw_device_overruns>\n",
			_state,  state->path, state->frameno, state->start_after_timestamp, _dur, _udur, _len, \
			_frames_skip, _sec_skip, \
			state->width, state->height, _output_format, _using_exif, \
@@ -1030,7 +1043,8 @@ void camogm_status(camogm_state *state, char * fn, int xml)
			state->debug_name, debug_level, _using_global_pointer, \
			_kml_enable, _kml_used, state->kml_path, state->kml_horHalfFov, state->kml_vertHalfFov, state->kml_near, \
			_kml_height_mode, state->kml_height, state->kml_period, state->kml_last_ts, state->kml_last_uts, \
			state->greedy ? "yes" : "no", state->ignore_fps ? "yes" : "no");
			state->greedy ? "yes" : "no", state->ignore_fps ? "yes" : "no", state->rawdev.rawdev_path,
			state->rawdev.overrun);

		FOR_EACH_PORT(int, chn) {
			char *_active = is_chn_active(state, chn) ? "yes" : "no";
@@ -1076,9 +1090,11 @@ void camogm_status(camogm_state *state, char * fn, int xml)
		fprintf(f, "\n");
		fprintf(f, "output format      \t%s\n",        _output_format);
		fprintf(f, "using exif         \t%s\n",        _using_exif);
		fprintf(f, "path prefix:       \t%s\n",        state->path_prefix);
		fprintf(f, "max file duration: \t%d sec\n",    state->segment_duration);
		fprintf(f, "max file length:   \t%d B\n",      state->segment_length);
		fprintf(f, "path prefix        \t%s\n",        state->path_prefix);
		fprintf(f, "raw device path    \t%s\n",        state->rawdev.rawdev_path);
		fprintf(f, "raw device overruns\t%d\n",        state->rawdev.overrun);
		fprintf(f, "max file duration  \t%d sec\n",    state->segment_duration);
		fprintf(f, "max file length    \t%d B\n",      state->segment_length);
		fprintf(f, "max frames         \t%d\n",        state->max_frames);
		fprintf(f, "timescale          \t%f\n",        state->timescale);
		fprintf(f, "frames per chunk   \t%d\n",        state->frames_per_chunk);
@@ -1217,7 +1233,7 @@ int parse_cmd(camogm_state *state, FILE* npipe)
		camogm_set_segment_length(state, d);
		return 5;
	} else if (strcmp(cmd, "prefix") == 0) {
		if (args) camogm_set_prefix(state, args);
		if (args) camogm_set_prefix(state, args, FILE_PATH);
		return 6;
	} else if (strcmp(cmd, "status") == 0) {
		camogm_status(state, args, 0);
@@ -1319,6 +1335,14 @@ int parse_cmd(camogm_state *state, FILE* npipe)
		d = strtol(args, NULL, 10);
		set_chn_state(state, d, 0);
		return 27;
	} else if (strcmp(cmd, "rawdev_path") == 0) {
		if (args) {
			camogm_set_prefix(state, args, RAW_PATH);
		} else {
			state->rawdev_op = 0;
			state->rawdev.rawdev_path[0] = '\0';
		}
		return 28;
	}

	return -1;
@@ -1547,12 +1571,13 @@ inline int is_chn_active(camogm_state *s, unsigned int port)
 */
inline void set_chn_state(camogm_state *s, unsigned int port, unsigned int new_state)
{
	if (port >= 0 && port < SENSOR_PORTS)
	if (port >= 0 && port < SENSOR_PORTS) {
		if (new_state)
			s->active_chn |= 1 << port;
		else
			s->active_chn &= ~(1 << port);
	}
}

/**
 * @brief Open files provided by circbuf driver.
+5 −2
Original line number Diff line number Diff line
@@ -75,9 +75,12 @@

/** @brief Offset from the beginning of raw device buffer. Must be aligned to physical sector size */
#define RAWDEV_START_OFFSET       1024
/** @brief Maximum length of file or raw device path */
#define ELPHEL_PATH_MAX           300

typedef struct {
	int rawdev_fd;
	char rawdev_path[ELPHEL_PATH_MAX];
	uint32_t overrun;
	uint64_t start_pos;
	uint64_t end_pos;
@@ -91,7 +94,7 @@ typedef struct {
	int ignore_fps;
	int save_gp;                    //if non zero, current circbuf pointer will be saved to global pointer, so imgsrv can report /pointers
	char path_prefix[256];
	char path[300];
	char path[ELPHEL_PATH_MAX];
	int cirbuf_rp[SENSOR_PORTS];    //!-1 - invalid
	int fd_circ[SENSOR_PORTS];      //! file descriptor for circbuf
	int fd_head[SENSOR_PORTS];      //! file descriptor for JPEG header
+74 −48
Original line number Diff line number Diff line
@@ -59,41 +59,31 @@

#include <c313a.h>
#include <asm/byteorder.h>
#include <assert.h>

#include <ogg/ogg.h>    // has to be before ogmstreams.h
#include "ogmstreams.h" // move it to <>?

#include "camogm_jpeg.h"

/** @brief Size of iovec structures holding data to be written */
#define IOVEC_SIZE      10

/** @brief File starting marker, contains "stelphel" string in ASCII symbols */
unsigned char elphelst[] = {0x73, 0x74, 0x65, 0x6c, 0x70, 0x68, 0x65, 0x6c};
/** @brief File ending marker, contains "enelphel" string in ASCII symbols */
unsigned char elphelen[] = {0x65, 0x6e, 0x65, 0x6c, 0x70, 0x68, 0x65, 0x6c};
static struct iovec start_marker = {
		.iov_base = elphelst,
		.iov_len = sizeof(elphelst)
};
static struct iovec end_marker = {
		.iov_base = elphelen,
		.iov_len = sizeof(elphelen)
};

//! may add something - called first time format is changed to this one (only once) recording is stopped
int camogm_init_jpeg(void)
int camogm_init_jpeg(camogm_state *state)
{
	return 0;
}

void camogm_free_jpeg(void)
{
}

/**
 * @brief Called every time the JPEG files recording is started.
 *
 * This function checks if the raw device write is initiated and tries to open the device specified. The device
 * will be closed in #camogm_end_jpeg function.
 * @param[in]   state   a pointer to a structure containing current state
 * @return      0 if the device was opened successfully and negative error code otherwise
 */
int camogm_start_jpeg(camogm_state *state)
{
//!TODO: make directory if it does not exist (find the last "/" in the state->path
	char * slash;
	int rslt;

@@ -113,22 +103,32 @@ int camogm_start_jpeg(camogm_state *state)
			}
		}
	} else {
		state->ivf = open(state->path_prefix, O_RDWR);
		if (state->ivf < 0) {
		if (state->rawdev_op) {
			state->rawdev.rawdev_fd = open(state->rawdev.rawdev_path, O_RDWR);
			if (state->rawdev.rawdev_fd < 0) {
				D0(perror(__func__));
			D0(fprintf(debug_file, "Error opening raw device %s\n", state->path));
				D0(fprintf(debug_file, "Error opening raw device %s\n", state->rawdev.rawdev_path));
				return -CAMOGM_FRAME_FILE_ERR;
			}
		D0(fprintf(debug_file, "Open raw device %s; start_pos = %llu, end_pos = %llu, curr_pos = %llu\n", state->path,
			D3(fprintf(debug_file, "Open raw device %s; start_pos = %llu, end_pos = %llu, curr_pos = %llu\n", state->rawdev.rawdev_path,
					state->rawdev.start_pos, state->rawdev.end_pos, state->rawdev.curr_pos));
		lseek64(state->ivf, state->rawdev.curr_pos, SEEK_SET);
			lseek64(state->rawdev.rawdev_fd, state->rawdev.curr_pos, SEEK_SET);
		}
	}

	return 0;
}

/**
 * @brief Write single JPEG frame
 *
 * This function will write single JPEG file
 * @param   state   a pointer to a structure containing current state
 * @return
 */
int camogm_frame_jpeg(camogm_state *state)
{
	int i, j, split_index;
	int i, j, k, split_index;
	int chunks_used = state->chunk_index - 1;
	ssize_t iovlen, l = 0;
	struct iovec chunks_iovec[8];
@@ -160,7 +160,6 @@ int camogm_frame_jpeg(camogm_state *state)
	} else {
		D0(fprintf(debug_file, "\n%s: current pointers start_pos = %llu, end_pos = %llu, curr_pos = %llu, data in buffer %d\n", __func__,
				state->rawdev.start_pos, state->rawdev.end_pos, state->rawdev.curr_pos, l));
		l = 0;
		split_index = -1;
		for (int i = 0, total_len = 0; i < state->chunk_index - 1; i++) {
			total_len += state->packetchunks[i + 1].bytes;
@@ -171,34 +170,36 @@ int camogm_frame_jpeg(camogm_state *state)
				break;
			}
		}
		chunks_iovec[0] = start_marker;
		l += start_marker.iov_len;
		chunks_used++;
		for (int i = 1; i < chunks_used; i++) {
		k = 0;
		l = 0;
		for (int i = 0; i < chunks_used; i++) {
			++k;
			if (i == split_index) {
				// one of the chunks rolls over the end of the raw storage, split it into two segments and
				// use additional chunk in chunks_iovec for this additional segment
				split_cntr = state->rawdev.end_pos - (l + state->rawdev.curr_pos);
				split_ptr = state->packetchunks[i].chunk + split_cntr;
				split_ptr = state->packetchunks[k].chunk + split_cntr;

				fprintf(debug_file, "Splitting chunk #%d: total chunk size = %ld, start address = 0x%p\n",
						i, state->packetchunks[k].bytes, state->packetchunks[k].chunk);

				// be careful with indexes here
				chunks_iovec[i].iov_base = state->packetchunks[i].chunk;
				chunks_iovec[i].iov_base = state->packetchunks[k].chunk;
				chunks_iovec[i].iov_len = split_cntr;
				l += chunks_iovec[i].iov_len;
				chunks_iovec[++i].iov_base = split_ptr + 1;
				chunks_iovec[i].iov_len = state->packetchunks[i].bytes - split_cntr;
				chunks_iovec[i].iov_len = state->packetchunks[k].bytes - split_cntr;
				l += chunks_iovec[i].iov_len;

				fprintf(debug_file, "Lump 1: size = %ld, start address = 0x%p\n", chunks_iovec[i - 1].iov_len, chunks_iovec[i - 1].iov_base);
				fprintf(debug_file, "Lump 2: size = %ld, start address = 0x%p\n\n", chunks_iovec[i].iov_len, chunks_iovec[i].iov_base);

			} else {
				chunks_iovec[i].iov_base = state->packetchunks[i].chunk;
				chunks_iovec[i].iov_len = state->packetchunks[i].bytes;
				chunks_iovec[i].iov_base = state->packetchunks[k].chunk;
				chunks_iovec[i].iov_len = state->packetchunks[k].bytes;
				l += chunks_iovec[i].iov_len;
			}
		}
		// consider start_marker here and increment chunks_used
		assert(chunks_used < IOVEC_SIZE);
		chunks_iovec[chunks_used] = end_marker;
		l += end_marker.iov_len;
		chunks_used++;

		/* debug code follows */
		fprintf(debug_file, "\n=== raw device write, iovec dump ===\n");
@@ -209,9 +210,24 @@ int camogm_frame_jpeg(camogm_state *state)
		fprintf(debug_file, "total len = %d\n======\n", l);
		/* end of debug code */

		iovlen = writev(state->ivf, chunks_iovec, chunks_used);
		if (split_index < 0) {
			iovlen = writev(state->rawdev.rawdev_fd, chunks_iovec, chunks_used);
		} else {
			iovlen = writev(state->rawdev.rawdev_fd, chunks_iovec, split_index + 1);
			fprintf(debug_file, "write first part: split_index = %d, %d bytes written\n", split_index, iovlen);
			if (lseek64(state->rawdev.rawdev_fd, state->rawdev.start_pos, SEEK_SET) != state->rawdev.start_pos) {
				perror(__func__);
				D0(fprintf(debug_file, "error positioning file pointer to the beginning of raw device\n"));
				return -CAMOGM_FRAME_FILE_ERR;
			}
			state->rawdev.overrun++;
			iovlen += writev(state->rawdev.rawdev_fd, &chunks_iovec[split_index + 1], chunks_used - split_index);
			fprintf(debug_file, "write second part: split_index + 1 = %d, chunks_used - split_index = %d, %d bytes written in total\n",
					split_index + 1, chunks_used - split_index, iovlen);
		}
		if (iovlen < l) {
			j = errno;
			perror(__func__);
			D0(fprintf(debug_file, "writev error %d (returned %d, expected %d)\n", j, iovlen, l));
			return -CAMOGM_FRAME_FILE_ERR;
		}
@@ -224,9 +240,19 @@ int camogm_frame_jpeg(camogm_state *state)
	return 0;
}

/**
 * @brief Finish JPEG file write operation
 *
 * This function checks whether raw device write was on and closes raw device file.
 * @param   state   a pointer to a structure containing current state
 * @return  0 if the device was closed successfully and -1 otherwise
 */
int camogm_end_jpeg(camogm_state *state)
{
	close(state->ivf);
	D0(fprintf(debug_file, "Closing raw device %s\n", state->path_prefix));
	return 0;
	int ret = 0;
	if (state->rawdev_op) {
		ret = close(state->rawdev.rawdev_fd);
		D0(fprintf(debug_file, "Closing raw device %s\n", state->rawdev.rawdev_path));
	}
	return ret;
}
+1 −1
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@

#include "camogm.h"

int camogm_init_jpeg(void);
int camogm_init_jpeg(camogm_state *state);
int camogm_start_jpeg(camogm_state *state);
int camogm_frame_jpeg(camogm_state *state);
int camogm_end_jpeg(camogm_state *state);
+2 −2
Original line number Diff line number Diff line
@@ -73,7 +73,7 @@ int camogm_start_ogm(camogm_state *state)
	char vendor[] = "ElphelOgm v 0.1";
	int pos;
	stream_header sh;
	unsigned char hdbuf[sizeof(sh) + 1];
	char hdbuf[sizeof(sh) + 1];
	ogg_packet ogg_header;

	sprintf(state->path, "%s%010ld_%06ld.ogm", state->path_prefix, state->frame_params[state->port_num].timestamp_sec, state->frame_params[state->port_num].timestamp_usec);
@@ -133,7 +133,7 @@ int camogm_start_ogm(camogm_state *state)
	pos += 4;
	hdbuf[pos++] = 1;
//! put it into Ogg stream
	ogg_header.packet = hdbuf;
	ogg_header.packet = (unsigned char *)hdbuf;
	ogg_header.bytes = pos;
	ogg_header.b_o_s = 0;
	ogg_header.e_o_s = 0;