Commit 6481a514 authored by Mikhail Karpenko's avatar Mikhail Karpenko

Save and restore write pointer reported by driver

parent e5342921
......@@ -1872,9 +1872,9 @@ int main(int argc, char *argv[])
const char usage[] = "This program allows recording of the video/images acquired by Elphel camera to the storage media.\n" \
"It is designed to run in the background and accept commands through a named pipe or a socket.\n\n" \
"Usage:\n\n" \
"%s -n <named_pipe_name> -p <port_number>\n\n" \
"%s -n <named_pipe_name> -p <port_number> [-s state_file_name]\n\n" \
"i.e.:\n\n" \
"%s -n /var/state/camogm_cmd -p 1234\n\n" \
"%s -n /var/state/camogm_cmd -p 1234 -s /mnt/sda1/write_pos\n\n" \
"When the program is running you may send commands by writing strings to the command file\n" \
"(/var/state/camogm_cmd in the example above) or to the socket. The complete list of available commands is available\n" \
"on Elphel Wiki (http://wiki.elphel.com/index.php?title=Camogm), here is the example of usage\n" \
......@@ -1890,13 +1890,15 @@ int main(int argc, char *argv[])
int ret;
int opt;
uint16_t port_num = 0;
size_t str_len;
char pipe_name_str[ELPHEL_PATH_MAX] = {0};
char state_name_str[ELPHEL_PATH_MAX] = {0};
if ((argc < 5) || (argv[1][1] == '-')) {
printf(usage, argv[0], argv[0]);
return EXIT_SUCCESS;
}
while ((opt = getopt(argc, argv, "n:p:h")) != -1) {
while ((opt = getopt(argc, argv, "n:p:s:h")) != -1) {
switch (opt) {
case 'n':
strncpy(pipe_name_str, (const char *)optarg, ELPHEL_PATH_MAX - 1);
......@@ -1907,6 +1909,9 @@ int main(int argc, char *argv[])
case 'h':
printf(usage, argv[0], argv[0]);
return EXIT_SUCCESS;
case 's':
strncpy(state_name_str, (const char *)optarg, ELPHEL_PATH_MAX - 1);
break;
}
}
......@@ -1926,6 +1931,10 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
sstate.rawdev.thread_state = STATE_RUNNING;
str_len = strlen(state_name_str);
if (str_len > 0) {
strncpy(&sstate.rawdev.state_path, state_name_str, str_len + 1);
}
ret = listener_loop(&sstate);
......
......@@ -128,6 +128,7 @@ typedef struct {
volatile int thread_state;
unsigned char *disk_mmap;
int sysfs_fd;
char state_path[ELPHEL_PATH_MAX];
} rawdev_buffer;
/**
......
......@@ -31,6 +31,134 @@
#include <elphel/ahci_cmd.h>
#include "camogm_jpeg.h"
#include "camogm_read.h"
/** State file record format. It includes device path in /dev, starting, current and ending LBAs */
#define STATE_FILE_FORMAT "%s\t%llu\t%llu\t%llu\n"
/** Get starting and endign LBAs of the partition specified as raw device buffer */
static int get_disk_range(struct range *range)
{
FILE *f;
// get raw device buffer starting postion on disk
f = fopen(SYSFS_AHCI_LBA_START, "r");
if (f == NULL) {
return -1;
}
fscanf(f, "%llu\n", &range->from);
fclose(f);
// get raw device buffer ending postion on disk
f = fopen(SYSFS_AHCI_LBA_END, "r");
if (f == NULL) {
return -1;
}
fscanf(f, "%llu\n", &range->to);
fclose(f);
return 0;
}
/** Get write pointer from a file. This functions check not only the name of a partition, but
* its geometry as well */
static int find_state(FILE *f, uint64_t *pos, const rawdev_buffer *rawdev)
{
size_t len;
uint64_t start_pos, curr_pos, end_pos;
struct range range;
char buff[ELPHEL_PATH_MAX];
char dev_name[ELPHEL_PATH_MAX];
if (f == NULL || pos == NULL)
return -1;
if (get_disk_range(&range) != 0) {
return -1;
}
// skip first line containing file header
fgets(buff, ELPHEL_PATH_MAX, f);
while (fgets(buff, ELPHEL_PATH_MAX, f) != NULL) {
sscanf(buff, STATE_FILE_FORMAT, dev_name, &start_pos, &curr_pos, &end_pos);
len = strlen(dev_name);
if (strncmp(rawdev->rawdev_path, dev_name, len) == 0 &&
range.from == start_pos &&
range.to == end_pos) {
*pos = curr_pos;
break;
}
}
return 0;
}
/** Read state from file and restore disk write pointer */
static int open_state_file(const rawdev_buffer *rawdev)
{
int fd, len;
FILE *f;
int ret = 0;
uint64_t curr_pos;
char buff[SMALL_BUFF_LEN] = {0};
if (strlen(rawdev->state_path) == 0) {
return ret;
}
f = fopen(rawdev->state_path, "r");
if (f != NULL) {
if (find_state(f, &curr_pos, rawdev) != -1) {
fd = open(SYSFS_AHCI_LBA_CURRENT, O_WRONLY);
if (fd >= 0) {
len = snprintf(buff, SMALL_BUFF_LEN, "%llu", curr_pos);
write(fd, buff, len + 1);
close(fd);
} else {
ret = -1;
}
}
fclose(f);
} else {
ret = -1;
}
return ret;
}
/** Save current position of the disk write pointer */
static int save_state_file(const rawdev_buffer *rawdev)
{
int ret = 0;
FILE *f;
struct range range;
uint64_t curr_pos;
if (strlen(rawdev->state_path) == 0) {
return ret;
}
if (get_disk_range(&range) != 0) {
return -1;
}
// get raw device buffer current postion on disk, this position indicates where recording has stopped
f = fopen(SYSFS_AHCI_LBA_CURRENT, "r");
if (f == NULL) {
return -1;
}
fscanf(f, "%llu\n", &curr_pos);
fclose(f);
// save pointers to a regular file
f = fopen(rawdev->state_path, "w");
if (f == NULL) {
return -1;
}
fprintf(f, "Device\t\tStart LBA\tCurrent LBA\tEnd LBA\n");
fprintf(f, STATE_FILE_FORMAT, rawdev->rawdev_path, range.from, curr_pos, range.to);
fclose(f);
return ret;
}
int camogm_init_jpeg(camogm_state *state)
{
......@@ -82,13 +210,15 @@ int camogm_start_jpeg(camogm_state *state)
}
}
} else {
if (state->rawdev_op) {
state->rawdev.sysfs_fd = open(SYSFS_AHCI_WRITE, O_WRONLY);
fprintf(debug_file, "Open sysfs file: %s\n", SYSFS_AHCI_WRITE);
if (state->rawdev.sysfs_fd < 0) {
D0(fprintf(debug_file, "Error opening sysfs file: %s\n", SYSFS_AHCI_WRITE));
return -CAMOGM_FRAME_FILE_ERR;
}
if (open_state_file(&state->rawdev) != 0) {
D0(fprintf(debug_file, "Could not set write pointer via sysfs, recording will start from the beginning of partition: "
"%s\n", state->rawdev.rawdev_path));
}
state->rawdev.sysfs_fd = open(SYSFS_AHCI_WRITE, O_WRONLY);
D6(fprintf(debug_file, "Open sysfs file: %s\n", SYSFS_AHCI_WRITE));
if (state->rawdev.sysfs_fd < 0) {
D0(fprintf(debug_file, "Error opening sysfs file: %s\n", SYSFS_AHCI_WRITE));
return -CAMOGM_FRAME_FILE_ERR;
}
}
......@@ -171,10 +301,12 @@ int camogm_end_jpeg(camogm_state *state)
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));
D6(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)));
save_state_file(&state->rawdev);
}
return ret;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment