Loading Makefile +2 −2 Original line number Original line Diff line number Diff line Loading @@ -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/ Loading camogm.c +174 −3 Original line number Original line Diff line number Diff line Loading @@ -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" Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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]); Loading Loading @@ -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 */ } } } } Loading Loading @@ -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; Loading @@ -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. Loading Loading @@ -1566,6 +1736,7 @@ unsigned int select_port(camogm_state *state) } } } } } } return chn; return chn; } } Loading camogm.h +2 −1 Original line number Original line Diff line number Diff line Loading @@ -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; /** /** Loading Loading @@ -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]; Loading camogm_jpeg.c +30 −73 Original line number Original line Diff line number Diff line Loading @@ -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" Loading Loading @@ -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); } } } } Loading @@ -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; Loading @@ -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; Loading @@ -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; } } camogm_read.c +0 −2 Original line number Original line Diff line number Diff line Loading @@ -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 Loading
Makefile +2 −2 Original line number Original line Diff line number Diff line Loading @@ -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/ Loading
camogm.c +174 −3 Original line number Original line Diff line number Diff line Loading @@ -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" Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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]); Loading Loading @@ -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 */ } } } } Loading Loading @@ -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; Loading @@ -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. Loading Loading @@ -1566,6 +1736,7 @@ unsigned int select_port(camogm_state *state) } } } } } } return chn; return chn; } } Loading
camogm.h +2 −1 Original line number Original line Diff line number Diff line Loading @@ -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; /** /** Loading Loading @@ -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]; Loading
camogm_jpeg.c +30 −73 Original line number Original line Diff line number Diff line Loading @@ -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" Loading Loading @@ -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); } } } } Loading @@ -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; Loading @@ -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; Loading @@ -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; } }
camogm_read.c +0 −2 Original line number Original line Diff line number Diff line Loading @@ -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