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

Merge branch with AHCI driver control

parents 7b8b1871 40500893
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -3,9 +3,9 @@ PHPFILES = camogmstate.php
CONFIGS    = qt_source
CONFIGS    = qt_source


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
OBJS = camogm.o camogm_ogm.o camogm_jpeg.o camogm_mov.o camogm_kml.o camogm_read.o index_list.o
OBJS = $(SRCS:.c=.o)


CFLAGS    += -Wall -I$(STAGING_KERNEL_DIR)/include/elphel
CFLAGS    += -Wall -I$(STAGING_KERNEL_DIR)/include/elphel -I$(STAGING_DIR_HOST)/usr/include-uapi
LDLIBS    += -logg -pthread -lm
LDLIBS    += -logg -pthread -lm


SYSCONFDIR = /etc/
SYSCONFDIR = /etc/
+174 −3
Original line number Original line Diff line number Diff line
@@ -27,6 +27,8 @@
#include <sys/stat.h>
#include <sys/stat.h>
#include <string.h>
#include <string.h>
#include <getopt.h>
#include <getopt.h>
#include <ctype.h>
#include <elphel/ahci_cmd.h>


#include "camogm_ogm.h"
#include "camogm_ogm.h"
#include "camogm_jpeg.h"
#include "camogm_jpeg.h"
@@ -101,6 +103,11 @@ typedef enum {
	FILE_PATH
	FILE_PATH
} path_type;
} path_type;


enum sysfs_path_type {
	TYPE_START,
	TYPE_SIZE
};

int debug_level;
int debug_level;
FILE* debug_file;
FILE* debug_file;


@@ -139,7 +146,10 @@ void camogm_set_start_after_timestamp(camogm_state *state, double d);
void  camogm_set_max_frames(camogm_state *state, int d);
void  camogm_set_max_frames(camogm_state *state, int d);
void  camogm_set_frames_per_chunk(camogm_state *state, int d);
void  camogm_set_frames_per_chunk(camogm_state *state, int d);


uint64_t get_disk_size(const char *name);
static uint64_t get_disk_size(const char *name);
static int get_sysfs_name(const char *dev_name, char *sys_name, size_t str_sz, int type);
static int get_disk_range(const char *name, struct range *rng);
static int set_disk_range(const struct range *rng);
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);
@@ -571,7 +581,7 @@ int sendImageFrame(camogm_state *state)
		D3(fprintf(debug_file, "_5_"));
		D3(fprintf(debug_file, "_5_"));
// update the Exif header with the current frame metadata
// update the Exif header with the current frame metadata
		state->exifSize[port] = lseek(state->fd_exif[port], 1, SEEK_END); // at the beginning of page 1 - position == page length
		state->exifSize[port] = lseek(state->fd_exif[port], 1, SEEK_END); // at the beginning of page 1 - position == page length
		if (state->exifSize > 0) {
		if (state->exifSize[port] > 0) {
//state->this_frame_params.meta_index
//state->this_frame_params.meta_index
			lseek(state->fd_exif[port], state->this_frame_params[port].meta_index, SEEK_END); // select meta page to use (matching frame)
			lseek(state->fd_exif[port], state->this_frame_params[port].meta_index, SEEK_END); // select meta page to use (matching frame)
			rslt = read(state->fd_exif[port], state->ed[port], state->exifSize[port]);
			rslt = read(state->fd_exif[port], state->ed[port], state->exifSize[port]);
@@ -815,6 +825,18 @@ void camogm_set_prefix(camogm_state *state, const char * p, path_type type)
			D0(fprintf(debug_file, "WARNING: raw device write initiated\n"));
			D0(fprintf(debug_file, "WARNING: raw device write initiated\n"));
			state->rawdev_op = 1;
			state->rawdev_op = 1;
		}
		}

		/* debug code follows*/
		struct range rng = {
				.from = 0,
				.to = 0
		};
		if (get_disk_range(state->rawdev.rawdev_path, &rng) == 0) {
			set_disk_range(&rng);
		} else {
			D0(fprintf(debug_file, "ERROR: unable to get disk size and starting sector\n"));
		}
		/* end of debug code */
	}
	}
}
}


@@ -1521,7 +1543,7 @@ int listener_loop(camogm_state *state)
 * @param   name   pointer to disk name string
 * @param   name   pointer to disk name string
 * @return  disk size in bytes if it was read correctly and 0 otherwise
 * @return  disk size in bytes if it was read correctly and 0 otherwise
 */
 */
uint64_t get_disk_size(const char *name)
static uint64_t get_disk_size(const char *name)
{
{
	int fd;
	int fd;
	uint64_t dev_sz;
	uint64_t dev_sz;
@@ -1539,6 +1561,154 @@ uint64_t get_disk_size(const char *name)
	return dev_sz;
	return dev_sz;
}
}


/**
 * @brief Make sysfs path from disk name in accordance with the type provided.
 * The 'start' file does not exist for full disk path (/dev/sda) and this function
 * returns empty string in @e sys_name and non-zero return value.
 * @param[in]   dev_name   pointer to a string containing device name
 * @param[out]  sys_name   pointer to a string where sysfs path will be stored
 * @param[in]   str_sz     the size of @e dname and @e sname strings including the
 * terminating null byte
 * @param[in]   type    the type of sysfs path required. Can be one of #sysfs_path_type
 * @return      The number of characters in resulting path, including the terminating
 * null byte, or a negative value in case of an error.
 */
static int get_sysfs_name(const char *dev_name, char *sys_name, size_t str_sz, int type)
{
	int ret = -1;
	const char prefix[] = "/sys/block/";
	char size_name[] = "size";
	char start_name[] = "start";
	char device_name[ELPHEL_PATH_MAX] = {0};
	char disk_name[ELPHEL_PATH_MAX] = {0};
	char part_name[ELPHEL_PATH_MAX] = {0};
	char *postfix = NULL;
	char *ptr = NULL;
	size_t dname_sz = strlen(dev_name) - 1;

	strncpy(device_name, dev_name, ELPHEL_PATH_MAX);

	// strip trailing slash
	if (device_name[dname_sz] == '/') {
		device_name[dname_sz] = '\0';
		dname_sz--;
	}

	// get partition and disk names
	ptr = strrchr(device_name, '/');
	if (ptr == NULL) {
		D0(fprintf(debug_file, "%s: the path specified is invalid\n", __func__));
		return ret;
	}
	strcpy(part_name, ptr + 1);
	strcpy(disk_name, ptr + 1);
	if (strlen(disk_name) > 0)
		disk_name[strlen(disk_name) - 1] = '\0';

	if (type == TYPE_SIZE)
		postfix = size_name;
	else if (type == TYPE_START)
		postfix = start_name;

	if (isdigit(device_name[dname_sz])) {
		// we've got partition
		ret = snprintf(sys_name, str_sz, "%s%s/%s/%s", prefix, disk_name, part_name, postfix);
	} else {
		// we've got entire disk
		ret = snprintf(sys_name, str_sz, "%s%s/%s", prefix, part_name, postfix);
		if (type == TYPE_START)
			// the 'start' does not exist for full disk, notify caller
			// that we've got this situation here
			sys_name[0] = '\0';
	}

	return ret;
}

/**
 * @brief Get disk start and end sectors. If the name specified is the name of a disk instead of
 * the name of a partition on that disk (i.e /dev/sda instead /dev/sda2), then the full size of the
 * disk is returned. This function is used with #set_disk_range to allocate raw device buffer on a disk.
 * @param[in]   name   pointer to disk name string
 * @param[out]  rng    pointer to the structure containing disk size
 * @return      0 if disk size was retrieved successfully and -1 in case of an error
 */
static int get_disk_range(const char *name, struct range *rng)
{
	int ret = 0;
	int fd;
	uint64_t val;
	char data[SMALL_BUFF_LEN] = {0};
	char sysfs_name[ELPHEL_PATH_MAX] = {0};

	// read start LBA
	if (get_sysfs_name(name, sysfs_name, ELPHEL_PATH_MAX, TYPE_START) > 0) {
		if (strlen(sysfs_name) > 0) {
			fd = open(sysfs_name, O_RDONLY);
			if (fd >= 0) {
				read(fd, data, SMALL_BUFF_LEN);
				if ((val = strtoull(data, NULL, 10)) != 0)
					rng->from = val;
				else
					ret = -1;
				close(fd);
			}
		} else {
			rng->from = 0;
		}
	}

	// read disk size in LBA
	if (get_sysfs_name(name, sysfs_name, ELPHEL_PATH_MAX, TYPE_SIZE) > 0) {
		fd = open(sysfs_name, O_RDONLY);
		if (fd >= 0) {
			read(fd, data, SMALL_BUFF_LEN);
			if ((val = strtoull(data, NULL, 10)) != 0)
				rng->to = rng->from + val;
			else
				ret = -1;
			close(fd);
		}
	}

	// sanity check
	if (rng->from >= rng->to)
		ret = -1;

	return ret;
}

/**
 * @brief Pass raw device buffer start and end LBAs to driver via its files in
 * sysfs. This function is used with #get_disk_range to allocate raw device buffer on a disk.
 * @param[in]   name   path to sysfs disk driver entry
 * @param[in]   rng    pointer to structure containing disk size
 * @return      0 if the values from @e rng were set successfully and -1 in case of an error
 */
static int set_disk_range(const struct range *rng)
{
	int fd;
	int ret = 0;
	char buff[SMALL_BUFF_LEN] = {0};
	int len;

	fd = open(SYSFS_AHCI_LBA_START, O_WRONLY);
	if (fd < 0)
		return -1;
	len = snprintf(buff, SMALL_BUFF_LEN, "%llu", rng->from);
	write(fd, buff, len + 1);
	close(fd);

	fd = open(SYSFS_AHCI_LBA_END, O_WRONLY);
	if (fd < 0)
		return -1;
	len = snprintf(buff, SMALL_BUFF_LEN, "%llu", rng->to);
	write(fd, buff, len + 1);
	close(fd);

	return ret;
}

/**
/**
 * @brief Select a sensor channel with minimum free space left in the buffer. The channel will
 * @brief Select a sensor channel with minimum free space left in the buffer. The channel will
 * be selected from the list of active channels.
 * be selected from the list of active channels.
@@ -1566,6 +1736,7 @@ unsigned int select_port(camogm_state *state)
			}
			}
		}
		}
	}
	}

	return chn;
	return chn;
}
}


+2 −1
Original line number Original line Diff line number Diff line
@@ -124,6 +124,7 @@ typedef struct {
	pthread_t tid;
	pthread_t tid;
	volatile int thread_state;
	volatile int thread_state;
	unsigned char *disk_mmap;
	unsigned char *disk_mmap;
	int sysfs_fd;
} rawdev_buffer;
} rawdev_buffer;


/**
/**
@@ -186,7 +187,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[7];
	elph_packet_chunk packetchunks[8];
	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];
+30 −73
Original line number Original line Diff line number Diff line
@@ -27,6 +27,8 @@
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/types.h>
#include <string.h>
#include <string.h>
#include <c313a.h>
#include <elphel/ahci_cmd.h>


#include "camogm_jpeg.h"
#include "camogm_jpeg.h"


@@ -69,15 +71,12 @@ int camogm_start_jpeg(camogm_state *state)
		}
		}
	} else {
	} else {
		if (state->rawdev_op) {
		if (state->rawdev_op) {
			state->rawdev.rawdev_fd = open(state->rawdev.rawdev_path, O_RDWR);
			state->rawdev.sysfs_fd = open(SYSFS_AHCI_WRITE, O_WRONLY);
			if (state->rawdev.rawdev_fd < 0) {
			fprintf(debug_file, "Open sysfs file: %s\n", SYSFS_AHCI_WRITE);
				D0(perror(__func__));
			if (state->rawdev.sysfs_fd < 0) {
				D0(fprintf(debug_file, "Error opening raw device %s\n", state->rawdev.rawdev_path));
				D0(fprintf(debug_file, "Error opening sysfs file: %s\n", SYSFS_AHCI_WRITE));
				return -CAMOGM_FRAME_FILE_ERR;
				return -CAMOGM_FRAME_FILE_ERR;
			}
			}
			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_w));
			lseek64(state->rawdev.rawdev_fd, state->rawdev.curr_pos_w, SEEK_SET);
		}
		}
	}
	}


@@ -93,13 +92,11 @@ int camogm_start_jpeg(camogm_state *state)
 */
 */
int camogm_frame_jpeg(camogm_state *state)
int camogm_frame_jpeg(camogm_state *state)
{
{
	int i, j, k, split_index;
	int i, j;
	int chunks_used = state->chunk_index - 1;
	ssize_t iovlen, l = 0;
	ssize_t iovlen, l = 0;
	struct iovec chunks_iovec[8];
	struct iovec chunks_iovec[8];
	unsigned char *split_ptr = NULL;
	long split_cntr = 0;
	int port = state->port_num;
	int port = state->port_num;
	struct frame_data fdata = {0};


	if (!state->rawdev_op) {
	if (!state->rawdev_op) {
		l = 0;
		l = 0;
@@ -122,70 +119,22 @@ int camogm_frame_jpeg(camogm_state *state)
		}
		}
		close(state->ivf);
		close(state->ivf);
	} else {
	} else {
		D0(fprintf(debug_file, "\n%s: current pointers start_pos = %llu, end_pos = %llu, curr_pos = %llu, data in buffer %d\n", __func__,
		fprintf(debug_file, "dump iovect array\n");
				state->rawdev.start_pos, state->rawdev.end_pos, state->rawdev.curr_pos_w, l));
		for (int i = 0; i < state->chunk_index - 1; i++) {
		split_index = -1;
			fprintf(debug_file, "ptr: %p, length: %ld\n", state->packetchunks[i + 1].chunk, state->packetchunks[i + 1].bytes);
		for (int i = 0, total_len = 0; i < state->chunk_index - 1; i++) {
		}
			total_len += state->packetchunks[i + 1].bytes;
		fdata.sensor_port = port;
			if (total_len + state->rawdev.curr_pos_w > state->rawdev.end_pos) {
		fdata.cirbuf_ptr = state->cirbuf_rp[port];
				split_index = i;
		fdata.jpeg_len = state->jpeg_len;
				chunks_used++;
		if (state->exif) {
				D0(fprintf(debug_file, "\n>>> raw storage roll over detected\n"));
			fdata.meta_index = state->this_frame_params[port].meta_index;
				break;
			fdata.cmd |= DRV_CMD_EXIF;
			}
		}
		}
		fdata.cmd |= DRV_CMD_WRITE;
		k = 0;
		if (write(state->rawdev.sysfs_fd, &fdata, sizeof(struct frame_data)) < 0) {
		l = 0;
			D0(fprintf(debug_file, "Can not pass IO vector to driver: %s\n", strerror(errno)));
		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_w);
				split_ptr = state->packetchunks[k].chunk + split_cntr;

				D3(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[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[k].bytes - split_cntr;
				l += chunks_iovec[i].iov_len;
			} else {
				chunks_iovec[i].iov_base = state->packetchunks[k].chunk;
				chunks_iovec[i].iov_len = state->packetchunks[k].bytes;
				l += chunks_iovec[i].iov_len;
			}
		}

		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;
			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;
		}
		state->rawdev.curr_pos_w += l;
		if (state->rawdev.curr_pos_w > state->rawdev.end_pos)
			state->rawdev.curr_pos_w = state->rawdev.curr_pos_w - state->rawdev.end_pos + state->rawdev.start_pos;
		D0(fprintf(debug_file, "%d bytes written, curr_pos = %llu\n", l, state->rawdev.curr_pos_w));
	}
	}


	return 0;
	return 0;
@@ -201,9 +150,17 @@ int camogm_frame_jpeg(camogm_state *state)
int camogm_end_jpeg(camogm_state *state)
int camogm_end_jpeg(camogm_state *state)
{
{
	int ret = 0;
	int ret = 0;
	struct frame_data fdata = {0};

	if (state->rawdev_op) {
	if (state->rawdev_op) {
		ret = close(state->rawdev.rawdev_fd);
		fdata.cmd = DRV_CMD_FINISH;
		D0(fprintf(debug_file, "Closing raw device %s\n", state->rawdev.rawdev_path));
		if (write(state->rawdev.sysfs_fd, &fdata, sizeof(struct frame_data)) < 0) {
			D0(fprintf(debug_file, "Error sending 'finish' command to driver\n"));
		}
		D0(fprintf(debug_file, "Closing sysfs file %s\n", SYSFS_AHCI_WRITE));
		ret = close(state->rawdev.sysfs_fd);
		if (ret == -1)
			D0(fprintf(debug_file, "Error: %s\n", strerror(errno)));
	}
	}
	return ret;
	return ret;
}
}
+0 −2
Original line number Original line Diff line number Diff line
@@ -61,8 +61,6 @@
#define CMD_DELIMITER             "/?"
#define CMD_DELIMITER             "/?"
/** @brief The length of a buffer for command string */
/** @brief The length of a buffer for command string */
#define CMD_BUFF_LEN              1024
#define CMD_BUFF_LEN              1024
/** @brief The length of a buffer for string formatting */
#define SMALL_BUFF_LEN            32
/** @brief 64 bit mask to align offsets to 4 kb page boundary */
/** @brief 64 bit mask to align offsets to 4 kb page boundary */
#define PAGE_BOUNDARY_MASK        0xffffffffffffe000
#define PAGE_BOUNDARY_MASK        0xffffffffffffe000
/** @brief The size of read buffer in bytes. The data will be read from disk in blocks of this size */
/** @brief The size of read buffer in bytes. The data will be read from disk in blocks of this size */
Loading