Commit c78bbfc2 authored by Andrey Filippov's avatar Andrey Filippov

added named camog.disk copies for navigation

parent 01b565e2
......@@ -112,7 +112,8 @@ pthread_mutex_t print_mutex = PTHREAD_MUTEX_INITIALIZER;
*/
typedef enum {
RAW_PATH,
FILE_PATH
FILE_PATH,
RAW_STATE
} path_type;
enum sysfs_path_type {
......@@ -355,8 +356,16 @@ int camogm_start(camogm_state *state)
D0(fprintf(debug_file, "Raw device write initiated, but file format is not JPEG. Will not start\n"));
return CAMOGM_FRAME_OTHER;
}
if (state->rawdev_op){
copy_state_file(state); // copy camogm.disk to named state file, fill be used when downloading data as file_start parameter
D1(fprintf(debug_file, "Starting raw data recording, marked %s, state->path='%s'\n", get_state_path(state), state->path));
D1(syslog (LOG_INFO, "Starting raw data recording, marked %s", get_state_path(state)));
next_state_path(state); // increment path so next time will use different one.
} else {
D1(fprintf(debug_file, "Starting file system recording to %s\n", state->path));
D1(syslog (LOG_INFO, "Starting file system recording to %s", state->path));
D1(fprintf(debug_file, "Starting recording\n"));
}
double dtime_stamp;
state->frameno = 0;
......@@ -890,6 +899,7 @@ int camogm_stop(camogm_state *state)
pthread_mutex_lock(&state->mutex);
state->prog_state = STATE_STOPPED;
pthread_mutex_unlock(&state->mutex);
D1(fprintf(debug_file, "Ended recording\n"));
DFLUSH;
return 0;
}
......@@ -1006,11 +1016,25 @@ void camogm_set_dummy_read(camogm_state *state, int d)
* the file name as is.
* @param[in] type the type of prefix, can be one of #path_type
*/
void camogm_set_prefix(camogm_state *state, const char * p, path_type type)
void camogm_set_prefix(camogm_state *state, const char * p, path_type type) // may use cookies to remember file
{
if (type == FILE_PATH) {
strncpy(state->path_prefix, p, sizeof(state->path_prefix) - 1);
state->path_prefix[sizeof(state->path_prefix) - 1] = '\0';
D1(fprintf(debug_file, "Set prefix: '%s', mode=%d\n", p, (int) type));
D1(syslog (LOG_INFO, "Set prefix: '%s', mode=%d", p, (int) type)); // RAW_STATE
if (type == RAW_STATE) { // path to state files for raw recording
if (state->rawdev_op) { // only for raw mode
// 07.02.2023 - use the same name as a template for camogm.disk copy
set_state_file_from_prefix(state, p); // will also set state->path_prefix as an absolute path
}
} else if (type == FILE_PATH) {
// if (state->rawdev_op) {
// // 07.02.2023 - use the same name as a template for camogm.disk copy
// set_state_file_from_prefix(state, p); // will also set state->path_prefix as an absolute path
// } else {
strncpy(state->path_prefix, p, sizeof(state->path_prefix) - 1); // cut off trailing "/"?
state->path_prefix[sizeof(state->path_prefix) - 1] = '\0';
// }
//int set_state_file_from_prefix(rawdev_buffer *rawdev, const char * 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';
......@@ -1539,8 +1563,11 @@ 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, FILE_PATH);
if (args) camogm_set_prefix(state, args, FILE_PATH); //RAW_STATE
return 6;
} else if (strcmp(cmd, "prefix_raw") == 0) {
if (args) camogm_set_prefix(state, args, RAW_STATE);
return 31;
} else if (strcmp(cmd, "status") == 0) {
camogm_status(state, args, 0);
return 7;
......@@ -1680,6 +1707,8 @@ int parse_cmd(camogm_state *state, FILE* npipe)
return -1;
}
/**
* @brief This function closes open files, terminates reading thread and deletes allocated memory.
* @param[in] state pointer to #camogm_state structure for a particular sensor channel
......@@ -2423,9 +2452,12 @@ int main(int argc, char *argv[])
if (str_len > 0) {
strncpy(sstate.rawdev.state_path, (const char *)state_name_str, str_len + 1);
}
ret = get_state_directory(&sstate);
D2(syslog (LOG_INFO, "%s:line %d : get_state_directory() -> %d @ %07d\n", \
__FILE__, __LINE__, ret, get_fpga_usec(sstate.fd_fparmsall[0], 0)));
ret = listener_loop(&sstate);
return ret;
......
......@@ -228,6 +228,11 @@ typedef struct {
unsigned char *disk_mmap;
int sysfs_fd;
char state_path[ELPHEL_PATH_MAX];
// char state_directory[ELPHEL_PATH_MAX];
// copy state file (camogm.disk) to the same directory when starting record. Can be used
// "<last_state_prefix>_<last_state_index>
char state_prefix[ELPHEL_PATH_MAX]; // absolute
int state_index;
} rawdev_buffer;
/**
......
......@@ -16,6 +16,7 @@
*/
/** @brief This define is needed to use lseek64 and should be set before includes */
#define THREADS_MODE 2 // 1 // 0 - how it was befor 07.01.2023
#define _LARGEFILE64_SOURCE
//#define __USE_GNU // for O_DIRECT
#define _GNU_SOURCE // for O_DIRECT
......@@ -30,6 +31,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <dirent.h>
#include <time.h>
#include <elphel/c313a.h>
#include <elphel/ahci_cmd.h>
......@@ -200,6 +202,202 @@ static int find_state(FILE *f, uint64_t *pos, const rawdev_buffer *rawdev)
return -3;
}
int get_state_directory(camogm_state *state) { //rawdev_buffer *rawdev){
rawdev_buffer *rawdev = &state->rawdev;
int dirlen, preflen; // length of directory path including trailing '/'
char * cp;
char pathname[ELPHEL_PATH_MAX];
char last_path[ELPHEL_PATH_MAX];
char state_directory[ELPHEL_PATH_MAX];
DIR *d;
struct dirent *dir;
struct stat fstat;
__time_t tsec = 0;
strncpy(state_directory, rawdev->state_path, ELPHEL_PATH_MAX);
cp=strrchr(state_directory,'/');
if (!cp) {
return -1;
}
*cp=0; // truncate
dirlen = strlen(state_directory);
preflen = dirlen+1; // counts '/'
strcpy(pathname,state_directory);
cp = pathname + dirlen;
*cp = '/';
cp++;
*cp=0;
// return rawdev->state_directory;
// get latest
strcpy(rawdev->state_prefix, state_directory);
rawdev->state_index = 0;
cp = rawdev->state_prefix + strlen(rawdev->state_prefix); // right after '/'
*cp++='/';
strncpy(cp, STATE_PREF_DFLT,ELPHEL_PATH_MAX - dirlen - strlen(STATE_PREF_DFLT) - 1);
D3(syslog (LOG_INFO, "_s00_ state_path='%s' state_directory='%s'", \
rawdev->state_path, state_directory));
d = opendir(state_directory);
if (d) {
while ((dir = readdir(d)) != NULL) {
// printf("%s\n", dir->d_name);
// STATE_EXT
if (!strcmp(STATE_EXT, dir->d_name +(strlen(dir->d_name) - strlen(STATE_EXT)))) { // same extension
strncpy(pathname+preflen, dir->d_name, ELPHEL_PATH_MAX-preflen-strlen(dir->d_name) - 1);
if (strcmp(pathname, rawdev->state_path)) { // skip camogm.disk itself
if (!stat(pathname, &fstat)) {
if (S_ISREG(fstat.st_mode) && (fstat.st_mtim.tv_sec > tsec)) {
tsec = fstat.st_mtim.tv_sec;
strcpy (last_path,pathname);
}
D3(syslog (LOG_INFO,"_s01_ pathname='%s' last_path='%s',fstat.st_mtim.tv_sec=%ld, tsec=%ld", \
pathname, last_path, fstat.st_mtim.tv_sec, tsec));
}
}
}
}
closedir(d);
}
if (tsec > 0 ) { // at least one exists)
cp = strrchr(last_path,'_'); // find last '_'
if (!cp || strchr(cp,'/')){ //'_' in the directory name
cp = last_path+strlen(last_path)-strlen(STATE_EXT); // truncate at '.'
} else {
sscanf(cp+1, "%d",&rawdev->state_index);
}
*cp = '\0';
strcpy(rawdev->state_prefix, last_path);
rawdev->state_index++;
}
//state->path
preflen = sprintf(state->path,STATE_FMT,rawdev->state_prefix,rawdev->state_index);
D2(syslog (LOG_INFO,"_s02_ prefix='%s',index=%d, preflen=%d, state->path=%s", \
rawdev->state_prefix, rawdev->state_index, preflen, state->path));
return 0;
}
int set_state_file_from_prefix(camogm_state *state, const char * prefix){ // prefix is relative to /dev/sda1 (where camogm.disk is)
rawdev_buffer *rawdev = &state->rawdev;
char last_path[ELPHEL_PATH_MAX];
char * cp, *cp1;
int preflen, len, i;
strcpy(last_path,prefix); // may be either relative to camogm.disk directory or absolute
if (!strcmp(last_path + (strlen(last_path)-strlen(STATE_EXT)),STATE_EXT)) { // ends with .disk
last_path[strlen(last_path)-strlen(STATE_EXT)] = '\0'; // truncate at .
}
rawdev->state_index = 0;
cp = strrchr(last_path,'_'); // find last '_'
if (!cp || strchr(cp,'/')){ //'_' in the directory name
cp = last_path+strlen(last_path); // full string w/o optional extension
} else {
cp1 = cp+1;
len = strlen(cp1);
for (i = 0; i < len; i++) {
if ((cp1[i] < '0') || (cp1[i] > '9')) {
cp = NULL;
break;
}
}
D2(syslog (LOG_INFO,"_s030_ len=%d, cp=0x%08x, cp1=%s", \
len, (int) cp, cp1));
if (cp) {
sscanf(cp+1, "%d",&rawdev->state_index);
} else {
cp = last_path+strlen(last_path);
}
}
*cp = '\0';
strcpy(rawdev->state_prefix, last_path);
preflen = snprintf(state->path, ELPHEL_PATH_MAX, STATE_FMT, rawdev->state_prefix ,rawdev->state_index);
D2(syslog (LOG_INFO,"_s03_ prefix='%s', rawdev->state_prefix='%s', index=%d, preflen=%d, state->path=%s", \
prefix, rawdev->state_prefix, rawdev->state_index, preflen, state->path));
return 0;
}
char * get_state_path(camogm_state *state){
// int preflen;
rawdev_buffer *rawdev = &state->rawdev;
// preflen =
snprintf(state->path, ELPHEL_PATH_MAX, STATE_FMT, rawdev->state_prefix, rawdev->state_index);
return state->path;
}
void next_state_path(camogm_state *state){
// int preflen;
rawdev_buffer *rawdev = &state->rawdev;
rawdev->state_index++;
// preflen =
// snprintf(state->path, ELPHEL_PATH_MAX, STATE_FMT, rawdev->state_prefix, rawdev->state_index);
// return state->path;
}
int copy_state_file(camogm_state *state){
// rawdev->state_path-> get_state_path(state); increment - separately
rawdev_buffer *rawdev = &state->rawdev;
D2(syslog (LOG_INFO,"_s05_ Copying state files: '%s' -> %s", \
rawdev->state_path, get_state_path(state)));
return copy_file(rawdev->state_path, get_state_path(state));
}
int copy_file(const char *from, const char *to){
int fd_to, fd_from;
char buf[4096];
ssize_t nread;
int saved_errno;
fd_from = open(from, O_RDONLY);
if (fd_from < 0)
return -1;
fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (fd_to < 0)
goto out_error;
while ((nread = read(fd_from, buf, sizeof buf)), nread > 0)
{
char *out_ptr = buf;
ssize_t nwritten;
do {
nwritten = write(fd_to, out_ptr, nread);
if (nwritten >= 0)
{
nread -= nwritten;
out_ptr += nwritten;
}
else if (errno != EINTR)
{
goto out_error;
}
} while (nread > 0);
}
if (nread == 0)
{
if (close(fd_to) < 0)
{
fd_to = -1;
goto out_error;
}
close(fd_from);
/* Success! */
return 0;
}
out_error:
saved_errno = errno;
close(fd_from);
if (fd_to >= 0)
close(fd_to);
errno = saved_errno;
return -1;
}
/** Read state from file and restore disk write pointer */
int open_state_file(const rawdev_buffer *rawdev, uint64_t *current_lba)
{
......@@ -261,6 +459,9 @@ static int save_state_file(const camogm_state *state)
return ret;
}
/**
* @brief Initialize synchronization resources for disk writing thread and then start this thread. This function
* is call each time JPEG format is set or changed, thus we need to check the state of writing thread before
......@@ -404,8 +605,8 @@ int camogm_start_jpeg(camogm_state *state)
state->writer_params.lba_start, current_lba, state->writer_params.lba_end, state->writer_params.next_segment_pos)); // incorrect
params->next_segment_pos = lba_to_offset(current_lba - params->lba_start);
D3(syslog (LOG_INFO, "start_jpeg(): lba_start = %lld, lba_end=%lld, current_lba=%lld",\
params->lba_start, params->lba_end, get_lba_next(params)));
D3(syslog (LOG_INFO, "start_jpeg(): lba_start = %lld, lba_end=%lld, current_lba=%lld, state->path=%s",\
params->lba_start, params->lba_end, get_lba_next(params), state->path));
D2(fprintf(debug_file, "First write to block device: %s, will start with offset in bytes: %llu\n", \
state->rawdev.rawdev_path, params->next_segment_pos));
......@@ -448,12 +649,12 @@ int camogm_frame_jpeg(camogm_state *state)
struct writer_params *params = &state->writer_params;
int seg_page = params->chunk_page_prep;
uint64_t disk_size = (params->lba_end - params->lba_start) * PHY_BLOCK_SIZE;
if (is_tiff) {
sprintf(state->path, "%s%d_%010ld_%06ld.tiff", state->path_prefix, port, state->this_frame_params[port].timestamp_sec, state->this_frame_params[port].timestamp_usec);
} else {
sprintf(state->path, "%s%d_%010ld_%06ld.jpeg", state->path_prefix, port, state->this_frame_params[port].timestamp_sec, state->this_frame_params[port].timestamp_usec);
}
if (!state->rawdev_op) {
if (is_tiff) {
sprintf(state->path, "%s%d_%010ld_%06ld.tiff", state->path_prefix, port, state->this_frame_params[port].timestamp_sec, state->this_frame_params[port].timestamp_usec);
} else {
sprintf(state->path, "%s%d_%010ld_%06ld.jpeg", state->path_prefix, port, state->this_frame_params[port].timestamp_sec, state->this_frame_params[port].timestamp_usec);
}
l = 0;
for (i = 0; i < (state->chunk_index) - 1; i++) {
chunks_iovec[i].iov_base = state->packetchunks[i + 1].chunk;
......@@ -504,12 +705,23 @@ int camogm_frame_jpeg(camogm_state *state)
// do not run ahead by >= FILE_CHUNKS_PAGES (0 or 1 for just FILE_CHUNKS_PAGES == 2)
// either buffer is completely empty (state->writer_params->chunk_page_prep == state->writer_params->chunk_page_write)
// or it is not full and writev_run is active
#if THREADS_MODE == 0
while (((i = get_num_empty(params)) < NUM_NEED_EMPTY) && !params->exit_write_threads) { // get_num_empty(params)< 3?
D6(fprintf(debug_file, "_13b_: waiting for empty buffer (%d):[%d%d:%d%d] @ %07d\n",\
params->chunk_page_prep, params->writev_run[0], params->writev_run[1], \
params->write_waits_sig[0], params->write_waits_sig[1], get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_cond_wait(&params->main_cond, &params->writer_mutex);
} // pthread_cond_signal, pthread_cond_broadcast - signal or broadcast a condition
#elif THREADS_MODE > 0
while ((((i = get_num_empty(params)) < NUM_NEED_EMPTY)
// || ()
) && !params->exit_write_threads) { // get_num_empty(params)< 3?
D6(fprintf(debug_file, "_13b_: waiting for empty buffer (%d):[%d%d:%d%d] @ %07d\n",\
params->chunk_page_prep, params->writev_run[0], params->writev_run[1], \
params->write_waits_sig[0], params->write_waits_sig[1], get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_cond_wait(&params->main_cond, &params->writer_mutex);
} // pthread_cond_signal, pthread_cond_broadcast - signal or broadcast a condition
#endif
pthread_mutex_unlock(&params->writer_mutex);
D3(dbg_wait=get_fpga_usec(state->fd_fparmsall[0], 0) - dbg_start_wait; if (dbg_wait <0) dbg_wait+=10000000;
......@@ -602,7 +814,7 @@ int camogm_frame_jpeg(camogm_state *state)
int camogm_end_jpeg(camogm_state *state)
{
int ret = 0;
int i, ret = 0;
int bytes, ceil_size;
struct writer_params *params = &state->writer_params;
int seg_page = params->chunk_page_prep;
......@@ -613,39 +825,64 @@ int camogm_end_jpeg(camogm_state *state)
ceil_size = vectaligntail(&params->glue_carry_vec);
D1(fprintf(debug_file, "Write last block of data, size = %d, full size = %d\n", bytes, ceil_size));
pthread_mutex_lock(&params->writer_mutex);
D6(fprintf(debug_file, "_x13a_: waiting for empty buffer (%d):[%d%d:%d%d] @ %07d\n",\
params->chunk_page_prep, params->writev_run[0], params->writev_run[1], \
params->write_waits_sig[0], params->write_waits_sig[1], get_fpga_usec(state->fd_fparmsall[0], 0)));
// Wait for the segment buffer (same as for the next frame)
while ((params->chunk_page_state[params->chunk_page_prep] != SEGPAGE_EMPTY) || // next page is busy, can not go ahead
// (!params->writev_run && (get_write_page(params) >= 0))) {
// TODO: Update?
params->circbuf_many = true; // finish slowly?
D3(fprintf(debug_file, \
"_x13a_: waiting for empty buffer (%d): [%d%d%d%d%d%d%d%d] LOCK [%d%d:%d%d:%d%d] @ %07d\n",\
params->chunk_page_prep, \
params->chunk_page_state[0],params->chunk_page_state[1],params->chunk_page_state[2],params->chunk_page_state[3], \
params->chunk_page_state[4],params->chunk_page_state[5],params->chunk_page_state[6],params->chunk_page_state[7], \
params->writev_run[0], params->writev_run[1], \
params->write_waits_sig[0], params->write_waits_sig[1], \
params->write_go[0], params->write_go[1], \
get_fpga_usec(state->fd_fparmsall[0], 0)));
// Wait for the segment buffer (same as for the next frame)
#if 0
while ((params->chunk_page_state[params->chunk_page_prep] != SEGPAGE_EMPTY) || // next page is busy, can not go ahead
// TODO: Update?
(!params->writev_run[0] && !params->writev_run[1] && (get_write_page(params) >= 0))) {
D6(fprintf(debug_file, "_x13b_: waiting for empty buffer (%d):[%d%d:%d%d] @ %07d\n", \
D3(fprintf(debug_file, "_x13b_: waiting for empty buffer (%d):[%d%d:%d%d] @ %07d\n", \
params->chunk_page_prep, params->writev_run[0], params->writev_run[1], \
params->write_waits_sig[0], params->write_waits_sig[1], get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_cond_wait(&params->main_cond, &params->writer_mutex);
}
}
#endif
#if THREADS_MODE == 0
while (((i = get_num_empty(params)) < NUM_NEED_EMPTY) && !params->exit_write_threads) { // get_num_empty(params)< 3?
D3(fprintf(debug_file, "_x13b_: waiting for empty buffer (%d):[%d%d:%d%d] @ %07d\n",\
params->chunk_page_prep, params->writev_run[0], params->writev_run[1], \
params->write_waits_sig[0], params->write_waits_sig[1], get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_cond_wait(&params->main_cond, &params->writer_mutex);
} // pthread_cond_signal, pthread_cond_broadcast - signal or broadcast a condition
#elif THREADS_MODE > 0
while ((((i = get_num_empty(params)) < NUM_NEED_EMPTY)
) && !params->exit_write_threads) { // get_num_empty(params)< 3?
D3(fprintf(debug_file, "_x13b_: waiting for empty buffer (%d):[%d%d:%d%d] @ %07d\n",\
params->chunk_page_prep, params->writev_run[0], params->writev_run[1], \
params->write_waits_sig[0], params->write_waits_sig[1], get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_cond_wait(&params->main_cond, &params->writer_mutex);
} // pthread_cond_signal, pthread_cond_broadcast - signal or broadcast a condition
#endif
pthread_mutex_unlock(&params->writer_mutex);
// prepare last segment, increment segment page
params->data_segments[seg_page][SEGMENT_GLUE].iov_base = params->glue_carry_vec.iov_base;
params->data_segments[seg_page][SEGMENT_GLUE].iov_len = params->glue_carry_vec.iov_len;
params->data_segments[seg_page][SEGMENT_FIRST].iov_len = 0; // check iov_len first before using iov_base
params->data_segments[seg_page][SEGMENT_SECOND].iov_len = 0; // check iov_len first before using iov_base
params->segment_pos[seg_page] = params->next_segment_pos;
params->next_segment_pos += params->data_segments[seg_page][SEGMENT_GLUE].iov_len;
// wrap over file size
if (params->next_segment_pos >= disk_size){
params->next_segment_pos -= disk_size;
}
D6(fprintf(debug_file, "_x13d_:frame aligned @ %07d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_mutex_lock(&params->writer_mutex);
params->chunk_page_state[params->chunk_page_prep] = SEGPAGE_FULL;
params->chunk_page_prep = (params->chunk_page_prep + 1) % SEGMENTS_PAGES; // ***************** Here NEXT SEGMENT (last time)
params->exit_write_threads = true; // finish job and exit
pthread_cond_broadcast(&params->writer_cond);
D6(fprintf(debug_file, "_13e1_: chunk_page_prep = %d, signal writer_cond @ %07d\n",params->chunk_page_prep, get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_mutex_unlock(&params->writer_mutex);
params->segment_pos[seg_page] = params->next_segment_pos;
params->next_segment_pos += params->data_segments[seg_page][SEGMENT_GLUE].iov_len;
// wrap over file size
if (params->next_segment_pos >= disk_size){
params->next_segment_pos -= disk_size;
}
D3(fprintf(debug_file, "_x13d_:frame aligned @ %07d\n",get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_mutex_lock(&params->writer_mutex);
params->chunk_page_state[params->chunk_page_prep] = SEGPAGE_FULL;
params->chunk_page_prep = (params->chunk_page_prep + 1) % SEGMENTS_PAGES; // ***************** Here NEXT SEGMENT (last time)
params->exit_write_threads = true; // finish job and exit
pthread_cond_broadcast(&params->writer_cond);
D3(fprintf(debug_file, "_x13e1_: chunk_page_prep = %d, signal writer_cond @ %07d\n",params->chunk_page_prep, get_fpga_usec(state->fd_fparmsall[0], 0)));
pthread_mutex_unlock(&params->writer_mutex);
} // if (bytes > 0) {
D2(fprintf(debug_file, "_x13f0_: will run save_state_file @ %07d\n", get_fpga_usec(state->fd_fparmsall[0], 0)));
save_state_file(state);
......@@ -767,12 +1004,33 @@ void *jpeg_writer(void *thread_args)
// will not start if there are less than 3 (num threads+1) ready pages so the latest one that have DMA open
// will not be touched (its header can return zeros)
// finishing off the remaining pages (slow) is done when no other write threads may be still running DMA
#if THREADS_MODE == 0
while ((((wpage = get_write_page(params)) < 0) ||
(params->circbuf_many ?
((i = get_num_empty(params)) >= (SEGMENTS_PAGES - NUM_WRITER_THREADS)) : // FULL+BYSY >= (threads+1)
((i = get_num_busy(params)) > 0) ) // one-by-one
|| (!params->write_waits_sig[1 - this_thread_index] && !params->write_go[this_thread_index]) // other write thread is not waiting, not already set go
) && !params->exit_write_threads) {
#if 1
if (get_num_empty(params) >= (NUM_NEED_EMPTY + 2)){
pthread_cond_signal(&params->main_cond); // signal to main thread that prepares data
D3(fprintf(debug_file, "%s_w00.2_: signaling main while waiting to start write [%d%d:%d%d:%d%d] @ %07d\n", \
dbg_pref, \
params->writev_run[0], params->writev_run[1], \
params->write_waits_sig[0], params->write_waits_sig[1], \
params->write_go[0], params->write_go[1], \
get_fpga_usec(state->fd_fparmsall[0], 0)));
}
#endif
pthread_cond_wait(&params->writer_cond, &params->writer_mutex); // They are called with mutex locked by the calling thread or undefined behaviour will result.
}
#elif THREADS_MODE > 0
while ((((wpage = get_write_page(params)) < 0) ||
(params->circbuf_many ?
((i = get_num_empty(params)) >= (SEGMENTS_PAGES - NUM_WRITER_THREADS)) : // FULL+BYSY >= (threads+1)
((i = get_num_busy(params)) > 0) ) || // one-by-one
(!params->write_waits_sig[1 - this_thread_index] && !params->write_go[this_thread_index]) // other write thread is not waiting, not already set go
) && !params->exit_write_threads) {
((i = get_num_busy(params)) > 0) ) // one-by-one
// || (!params->write_waits_sig[1 - this_thread_index] && !params->write_go[this_thread_index]) // other write thread is not waiting, not already set go
) && !params->exit_write_threads) {
// Wake up main thread while waiting
#if 1
if (get_num_empty(params) >= (NUM_NEED_EMPTY + 2)){
......@@ -787,6 +1045,7 @@ void *jpeg_writer(void *thread_args)
#endif
pthread_cond_wait(&params->writer_cond, &params->writer_mutex); // They are called with mutex locked by the calling thread or undefined behaviour will result.
}
#endif
D3(dbg_time= get_fpga_usec(state->fd_fparmsall[0], 0); dbg_wait= dbg_time - dbg_start_wait; if (dbg_wait <0) dbg_wait+=10000000; \
fprintf(debug_file, "%s_w00.3_: (%d, %d), empty/busy:%d many=%d thread ID=%ld got S+D [%d%d:%d%d:%d%d] @ %07d (+%07d)\n", dbg_pref,\
......@@ -795,10 +1054,17 @@ void *jpeg_writer(void *thread_args)
params->write_waits_sig[0], params->write_waits_sig[1], \
params->write_go[0], params->write_go[1], \
dbg_time, dbg_wait)); // dbg_time
#if THREADS_MODE == 0
if (params->write_waits_sig[1 - this_thread_index]) { // still waiting?
params->write_go[1 - this_thread_index] = true;
pthread_cond_broadcast(&params->writer_cond); // signal to other writer thread waiting for this one to finish writing
}
#elif THREADS_MODE > 0
if (params->write_waits_sig[1 - this_thread_index]) { // still waiting?
params->write_go[1 - this_thread_index] = true;
pthread_cond_broadcast(&params->writer_cond); // signal to other writer thread waiting for this one to finish writing
}
#endif
params->write_go[this_thread_index] = false;
params->write_waits_sig[this_thread_index] = false;
if (wpage>=0) {
......@@ -815,7 +1081,7 @@ void *jpeg_writer(void *thread_args)
reset_rem = 0;
params->last_ret_val = 0;
// inputs from params->data_chunks, returns number of result chunks
#define MAX_SEGM_PAGES 0xa0
#define MAX_SEGM_PAGES 0xa0 // for large JPEG - there is some me introduced bug in the kernel that limits chunk size. maybe 0xff - OK?
#define MAX_SEGM_LENGTH (MAX_SEGM_PAGES * PAGE_PHYS) // 0xa0000 // multiple of
// Seems that I introduced a bug into kernel - it can not handle too longsegments
......@@ -853,28 +1119,13 @@ void *jpeg_writer(void *thread_args)
debug_file,"%slseek64()->-1, errno=%d(%s)", dbg_pref,errno, strerror(errno)));
D6(fprintf(debug_file, "%s_w02_: starting emul_writev@ %07d\n", dbg_pref, dbg_us1));
#if 0
if ((params->writev_run[1 - this_thread_index]) && // other is writing already
(get_num_empty(params) >= NUM_NEED_EMPTY)){
pthread_mutex_lock(&params->writer_mutex);
pthread_cond_signal(&params->main_cond); // signal to main thread that prepares data
pthread_mutex_unlock(&params->writer_mutex);
D3(fprintf(debug_file, "%s_w02a_: starting emul_writev and signaling main @ %07d\n", dbg_pref, get_fpga_usec(state->fd_fparmsall[0], 0)));
}
#endif
params->writev_run[this_thread_index] = true;
// pthread_cond_signal(&params->main_cond); // was always
dbg_pos64=lseek64(blockdev_fd, params->segment_pos[wpage], SEEK_SET);
if (dbg_pos64 < 0){
D0(fprintf(debug_file, "%slseek64(%d, %lld, %d)->%lld, errno=%d(%s)\n", dbg_pref,\
blockdev_fd, params->segment_pos[wpage], SEEK_SET, dbg_pos64, errno, strerror(errno)));
}
/// pthread_mutex_lock(&params->writer_mutex);
/// if (get_write_page(params)) { // ??
/// pthread_cond_broadcast(&params->writer_cond); // wake up other writer threads?
/// }
/// pthread_mutex_unlock(&params->writer_mutex);
// iovlen = emul_writev(blockdev_fd, write_segments, num_write_segments);
iovlen = 0;
for (i = 0; i < num_write_segments; i++){
params->writev_run_segm[this_thread_index] = i;
......@@ -891,21 +1142,37 @@ void *jpeg_writer(void *thread_args)
if (write_segments[i].iov_len > 0) {
if (i == 1) { // only for segment 1, if other write thread also is writing second (large) segment
pthread_mutex_lock(&params->writer_mutex); // maybe it will not be needed - mutex
#if THREADS_MODE == 0
if (params->writev_run[1 - this_thread_index] &&
(params->writev_run_segm[1-this_thread_index] >0) &&
(params->writev_run_segm[1-this_thread_index] > 0) &&
(get_num_empty(params) >= NUM_NEED_EMPTY)){
pthread_cond_signal(&params->main_cond); // signal to main thread that prepares data
D3(dbg_us=get_fpga_usec(state->fd_fparmsall[0], 0);fprintf(debug_file, \
"%s_w02a_: starting second (large) write and signaling main <- @ %07d (+%d)\n", \
dbg_pref, dbg_us, ( dbg_us - dbg_us1)));
}
#elif THREADS_MODE == 1
if (((params->writev_run[1 - this_thread_index] && // other is writing big chunk
(params->writev_run_segm[1-this_thread_index] > 0))
||(params->write_waits_sig[1 - this_thread_index]) // or it is waiting
) &&
(get_num_empty(params) >= NUM_NEED_EMPTY)){
pthread_cond_signal(&params->main_cond); // signal to main thread that prepares data
D3(dbg_us=get_fpga_usec(state->fd_fparmsall[0], 0);fprintf(debug_file, \
"%s_w02a_: starting second (large) write and signaling main <- @ %07d (+%d)\n", \
dbg_pref, dbg_us, ( dbg_us - dbg_us1)));
}
#elif THREADS_MODE > 0
// do nothing. Or do if it really wants?
#endif
pthread_mutex_unlock(&params->writer_mutex);
}
writev_wlen = write (blockdev_fd, write_segments[i].iov_base, write_segments[i].iov_len);
// if (i == 1) { // only for segment 1, if other write thread also is writing second (large) segment
D3(fprintf(debug_file, \
"%s_w02x_: i=%d start =0x%08x, len=0x%08x\n", dbg_pref, i, (int)write_segments[i].iov_base, (int)write_segments[i].iov_len));
"%s_w02x_: i=%d @ %07d : start =0x%08x, len=0x%08x\n",\
dbg_pref, i, get_fpga_usec(state->fd_fparmsall[0], 0), (int)write_segments[i].iov_base, (int)write_segments[i].iov_len));
// }
if (writev_wlen < 0) {
D0(fprintf(debug_file, "Error %d while trying direct writing of %d bytes from %p, data = 0x%llx, segment=%d\n",\
......@@ -933,9 +1200,6 @@ void *jpeg_writer(void *thread_args)
params->last_ret_val = -CAMOGM_FRAME_FILE_ERR;
reset_rem = 1;
} else {
// update statistic
// state->rawdev.last_jpeg_size = l;
// state->rawdev.total_rec_len += state->rawdev.last_jpeg_size;
D6(fprintf(debug_file, "%sCurrent position in block device: %lld\n", dbg_pref, lseek64(blockdev_fd, 0, SEEK_CUR)));
}
} else { // Split into two writes: to the end of partition and startion from the beginning
......@@ -959,7 +1223,6 @@ void *jpeg_writer(void *thread_args)
i0++; // include split chunk in the first write
}
// write the first group (before rollover)
/// params->lba_current = params->lba_start;
params->writev_run[this_thread_index] = true;
pthread_cond_signal(&params->main_cond);
......@@ -991,15 +1254,11 @@ void *jpeg_writer(void *thread_args)
lseek64(blockdev_fd, 0, SEEK_SET);
iovlen = emul_writev(blockdev_fd, write_segments, num_write_segments - i1);
params->writev_run[this_thread_index] = false;
/// params->lba_current = params->lba_start + l1 / PHY_BLOCK_SIZE;
if (iovlen < l1) {
D0(fprintf(debug_file, "%s(2 of 2) emul_writev error: %s (returned %i, expected %i)\n", dbg_pref, strerror(errno), iovlen, l1));
params->last_ret_val = -CAMOGM_FRAME_FILE_ERR;
reset_rem = 1;
} else {
/// // update statistic (for both parts of the split write)
/// state->rawdev.last_jpeg_size = l;
/// state->rawdev.total_rec_len += state->rawdev.last_jpeg_size;
D6(fprintf(debug_file, "%s(2 of 2) Current position in block device: %lld\n", dbg_pref, lseek64(blockdev_fd, 0, SEEK_CUR)));
}
}
......@@ -1021,11 +1280,25 @@ void *jpeg_writer(void *thread_args)
// release main thread
reset_segments(state, reset_rem, wpage);
pthread_mutex_lock(&params->writer_mutex);
#if THREADS_MODE == 2
// signal main when one just ended all writes, and the other is either writing big or waiting
if (((params->writev_run[1 - this_thread_index] && (params->writev_run_segm[1-this_thread_index] > 0))// other is writing big chunk
||(params->write_waits_sig[1 - this_thread_index]) // or it is waiting
) &&
(get_num_empty(params) >= NUM_NEED_EMPTY)){
pthread_cond_signal(&params->main_cond); // signal to main thread that prepares data
D3(dbg_us=get_fpga_usec(state->fd_fparmsall[0], 0);fprintf(debug_file, \
"%s_w031_: finished, other is writing second (large), signaling main <- @ %07d (+%d)\n", \
dbg_pref, dbg_us, ( dbg_us - dbg_us1)));
}
#endif
params->chunk_page_state[wpage] = SEGPAGE_EMPTY;
// update statistics right here !
state->rawdev.last_jpeg_size = image_len_padded;
state->rawdev.total_rec_len += state->rawdev.last_jpeg_size;
D3(fprintf(debug_file, "%sl=%d, total_rec_len=%lld\n",dbg_pref, image_len_padded, state->rawdev.total_rec_len));
D4(fprintf(debug_file, "%sl=%d, total_rec_len=%lld\n",dbg_pref, image_len_padded, state->rawdev.total_rec_len));
// D6(fprintf(debug_file, "%sCurrent position in block device: %lld\n", dbg_pref, lseek64(blockdev_fd, 0, SEEK_CUR)));
// moved to while waiting
......@@ -1040,8 +1313,6 @@ void *jpeg_writer(void *thread_args)
break;
}
}
}
params->state = STATE_STOPPED;
if (close(blockdev_fd) <0) {
......
......@@ -31,7 +31,18 @@ ssize_t emul_writev (int fd, const struct iovec *iovec, int count);
int get_write_page(struct writer_params *wparams);
int get_num_empty(struct writer_params *wparams);
int get_num_busy(struct writer_params *wparams);
int get_state_directory(camogm_state *state); // rawdev_buffer *rawdev);
int set_state_file_from_prefix(camogm_state *state, const char * prefix);
char * get_state_path(camogm_state *state);
void next_state_path(camogm_state *state);
int copy_state_file(camogm_state *state);
int copy_file(const char *from, const char *to);
#define STATE_EXT ".disk"
//#define STATE_FMT "%s_%04d"STATE_EXT
#define STATE_FMT "%s_%04d.disk"
#define STATE_SFMT "%s %d"
#define STATE_PREF_DFLT "test"
#endif /* _CAMOGM_JPEG_H */
......@@ -638,7 +638,11 @@ else
fprintf($fcmd, "prefix=%s;\n", $prefix);
// setcookie("directory", $prefix);
break;
case "set_prefix_raw": // path to camogm.disk for raw recording. Does not use cookies
$prefix_raw = $_GET['prefix'];
fprintf($fcmd, "prefix_raw=%s;\n", $prefix_raw);
break;
case "set_debuglev":
$debuglev = $_GET['debuglev'];
fprintf($fcmd, "debuglev=%s;\n", $debuglev);
......
......@@ -430,6 +430,9 @@ function process_recording(xmldoc) {
clearTimeout(update_intvl);
update_intvl = setTimeout(update_state, frame_period);
}
// this variable is injected into web page from camogmgui.php
var sensor_ports = parseInt(document.getElementById('sensor_ports').textContent, 10);
file_duration /= sensor_ports; // 07/01/2023: It was combined duration of all channels, so wrong data rate
//Update HTML
document.getElementById('ajax_state').innerHTML = state.substring(1, state.length-1);
document.getElementById('ajax_file_duration').innerHTML = Math.round(file_duration*100)/100 + " seconds / " + frame_number + " frames";
......@@ -447,7 +450,7 @@ function process_recording(xmldoc) {
var buffers_used = xmldoc.getElementsByTagName('buffer_used');
var buffer_size;
// this variable is injected into web page from camogmgui.php
var sensor_ports = parseInt(document.getElementById('sensor_ports').textContent, 10);
// var sensor_ports = parseInt(document.getElementById('sensor_ports').textContent, 10);
var max_bar_len = 370;
for (var i = 0; i < sensor_ports; i++) {
free_sz = buffers_free[i].firstChild.data;
......
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