summaryrefslogtreecommitdiffstats
path: root/ipecamera
diff options
context:
space:
mode:
Diffstat (limited to 'ipecamera')
-rw-r--r--ipecamera/CMakeLists.txt8
-rw-r--r--ipecamera/data.c270
-rw-r--r--ipecamera/data.h6
-rw-r--r--ipecamera/events.c121
-rw-r--r--ipecamera/events.h5
-rw-r--r--ipecamera/image.c971
-rw-r--r--ipecamera/ipecamera.c597
-rw-r--r--ipecamera/ipecamera.h9
-rw-r--r--ipecamera/model.c4
-rw-r--r--ipecamera/model.h4
-rw-r--r--ipecamera/private.h121
-rw-r--r--ipecamera/public.h (renamed from ipecamera/image.h)18
-rw-r--r--ipecamera/reader.c170
-rw-r--r--ipecamera/reader.h6
14 files changed, 1322 insertions, 988 deletions
diff --git a/ipecamera/CMakeLists.txt b/ipecamera/CMakeLists.txt
new file mode 100644
index 0000000..029993c
--- /dev/null
+++ b/ipecamera/CMakeLists.txt
@@ -0,0 +1,8 @@
+include_directories(
+ ${CMAKE_SOURCE_DIR}
+)
+
+set(HEADERS ${HEADERS} ipecamera.h model.h reader.h events.h data.h public.h private.h)
+
+add_library(ipecamera STATIC ipecamera.c model.c reader.c events.c data.c)
+
diff --git a/ipecamera/data.c b/ipecamera/data.c
new file mode 100644
index 0000000..5de6617
--- /dev/null
+++ b/ipecamera/data.c
@@ -0,0 +1,270 @@
+#define _IPECAMERA_IMAGE_C
+#define _BSD_SOURCE
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <assert.h>
+
+#include <ufodecode.h>
+
+#include "../tools.h"
+#include "../error.h"
+
+#include "pcilib.h"
+#include "private.h"
+#include "data.h"
+
+// DS: Currently, on event_id overflow we are assuming the buffer is lost
+static int ipecamera_resolve_event_id(ipecamera_t *ctx, pcilib_event_id_t evid) {
+ pcilib_event_id_t diff;
+
+ if (evid > ctx->event_id) {
+ diff = (((pcilib_event_id_t)-1) - ctx->event_id) + evid;
+ if (diff >= ctx->buffer_size) return -1;
+ } else {
+ diff = ctx->event_id - evid;
+ if (diff >= ctx->buffer_size) return -1;
+ }
+
+ // DS: Request buffer_size to be power of 2 and replace to shifts (just recompute in set_buffer_size)
+ return (evid - 1) % ctx->buffer_size;
+}
+
+inline static int ipecamera_decode_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) {
+ int err = 0;
+ uint32_t tmp;
+ uint16_t *pixels;
+
+ int buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
+ if (buf_ptr < 0) return PCILIB_ERROR_TIMEOUT;
+
+ if (ctx->frame[buf_ptr].event.image_ready) return 0;
+
+ if (ctx->frame[buf_ptr].event.info.flags&PCILIB_EVENT_INFO_FLAG_BROKEN) {
+ ctx->frame[buf_ptr].event.image_broken = 1;
+ err = PCILIB_ERROR_INVALID_DATA;
+ goto ready;
+ }
+
+
+ pixels = ctx->image + buf_ptr * ctx->image_size;
+ memset(ctx->cmask + ctx->buffer_pos * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t));
+ err = ufo_decoder_decode_frame(ctx->ipedec, ctx->buffer + buf_ptr * ctx->padded_size, ctx->raw_size, pixels, &tmp, &tmp, ctx->cmask + ctx->buffer_pos * ctx->dim.height);
+ if (err) {
+ ctx->frame[buf_ptr].event.image_broken = 1;
+ err = PCILIB_ERROR_FAILED;
+ goto ready;
+ }
+
+ ctx->frame[buf_ptr].event.image_broken = 0;
+
+ready:
+ ctx->frame[buf_ptr].event.image_ready = 1;
+
+ if (ipecamera_resolve_event_id(ctx, event_id) < 0) {
+ ctx->frame[buf_ptr].event.image_ready = 0;
+ return PCILIB_ERROR_TIMEOUT;
+ }
+
+ return err;
+}
+
+static int ipecamera_get_next_buffer_to_process(ipecamera_t *ctx, pcilib_event_id_t *evid) {
+ int res;
+
+ if (ctx->preproc_id == ctx->event_id) return -1;
+
+ if (ctx->preproc)
+ pthread_mutex_lock(&ctx->preproc_mutex);
+
+ if (ctx->preproc_id == ctx->event_id) {
+ if (ctx->preproc)
+ pthread_mutex_unlock(&ctx->preproc_mutex);
+ return -1;
+ }
+
+ if ((ctx->event_id - ctx->preproc_id) > (ctx->buffer_size - IPECAMERA_RESERVE_BUFFERS)) ctx->preproc_id = ctx->event_id - (ctx->buffer_size - 1) - IPECAMERA_RESERVE_BUFFERS - 1;
+
+ res = ctx->preproc_id%ctx->buffer_size;
+
+ if (pthread_rwlock_trywrlock(&ctx->frame[res].mutex)) {
+ pthread_mutex_unlock(&ctx->preproc_mutex);
+ return -1;
+ }
+
+ *evid = ++ctx->preproc_id;
+
+ if (ctx->preproc)
+ pthread_mutex_unlock(&ctx->preproc_mutex);
+
+ return res;
+}
+
+
+void *ipecamera_preproc_thread(void *user) {
+ int buf_ptr;
+ pcilib_event_id_t evid;
+
+ ipecamera_preprocessor_t *preproc = (ipecamera_preprocessor_t*)user;
+ ipecamera_t *ctx = preproc->ipecamera;
+
+ while (ctx->run_preprocessors) {
+ buf_ptr = ipecamera_get_next_buffer_to_process(ctx, &evid);
+ if (buf_ptr < 0) {
+ usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP);
+ continue;
+ }
+
+ ipecamera_decode_frame(ctx, evid);
+
+ pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
+ }
+
+ return NULL;
+}
+
+static int ipecamera_get_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) {
+ int err;
+ int buf_ptr = (event_id - 1) % ctx->buffer_size;
+
+ if (!ctx->preproc) {
+ pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex);
+
+ err = ipecamera_decode_frame(ctx, event_id);
+
+ if (err) {
+ pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
+ return err;
+ }
+
+ return 0;
+ }
+
+
+ while (!ctx->frame[buf_ptr].event.image_ready) {
+ usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP);
+
+ buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
+ if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN;
+ }
+
+ pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex);
+
+ buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
+ if ((buf_ptr < 0)||(!ctx->frame[buf_ptr].event.image_ready)) {
+ pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
+ return PCILIB_ERROR_OVERWRITTEN;
+ }
+
+ return 0;
+}
+
+
+/*
+ We will lock the data for non-raw data to prevent ocasional overwritting. The
+ raw data will be overwritten by the reader thread anyway and we can't do
+ anything to prevent it for performance reasons.
+*/
+int ipecamera_get(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size, void **ret) {
+ int err;
+ int buf_ptr;
+ size_t raw_size;
+ ipecamera_t *ctx = (ipecamera_t*)vctx;
+
+ void *data = *ret;
+
+ if (!ctx) {
+ pcilib_error("IPECamera imaging is not initialized");
+ return PCILIB_ERROR_NOTINITIALIZED;
+ }
+
+ buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
+ if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN;
+
+ switch ((ipecamera_data_type_t)data_type) {
+ case IPECAMERA_RAW_DATA:
+ raw_size = ctx->frame[buf_ptr].event.raw_size;
+ if (data) {
+ if ((!size)||(*size < raw_size)) return PCILIB_ERROR_TOOBIG;
+ memcpy(data, ctx->buffer + buf_ptr * ctx->padded_size, raw_size);
+ if (ipecamera_resolve_event_id(ctx, event_id) < 0) return PCILIB_ERROR_OVERWRITTEN;
+ *size = raw_size;
+ return 0;
+ }
+ if (size) *size = raw_size;
+ *ret = ctx->buffer + buf_ptr * ctx->padded_size;
+ return 0;
+ case IPECAMERA_IMAGE_DATA:
+ err = ipecamera_get_frame(ctx, event_id);
+ if (err) return err;
+
+ if (data) {
+ if ((!size)||(*size < ctx->image_size * sizeof(ipecamera_pixel_t))) return PCILIB_ERROR_TOOBIG;
+ memcpy(data, ctx->image + buf_ptr * ctx->image_size, ctx->image_size * sizeof(ipecamera_pixel_t));
+ pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
+ *size = ctx->image_size * sizeof(ipecamera_pixel_t);
+ return 0;
+ }
+
+ if (size) *size = ctx->image_size * sizeof(ipecamera_pixel_t);
+ *ret = ctx->image + buf_ptr * ctx->image_size;
+ return 0;
+ case IPECAMERA_CHANGE_MASK:
+ err = ipecamera_get_frame(ctx, event_id);
+ if (err) return err;
+
+ if (data) {
+ if ((!size)||(*size < ctx->dim.height * sizeof(ipecamera_change_mask_t))) return PCILIB_ERROR_TOOBIG;
+ memcpy(data, ctx->image + buf_ptr * ctx->dim.height, ctx->dim.height * sizeof(ipecamera_change_mask_t));
+ pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
+ *size = ctx->dim.height * sizeof(ipecamera_change_mask_t);
+ return 0;
+ }
+
+ if (size) *size = ctx->dim.height * sizeof(ipecamera_change_mask_t);
+ *ret = ctx->cmask + buf_ptr * ctx->dim.height;
+ return 0;
+ case IPECAMERA_DIMENSIONS:
+ if (size) *size = sizeof(ipecamera_image_dimensions_t);
+ ret = (void*)&ctx->dim;
+ return 0;
+ case IPECAMERA_IMAGE_REGION:
+ case IPECAMERA_PACKED_IMAGE:
+ // Shall we return complete image or only changed parts?
+ case IPECAMERA_PACKED_LINE:
+ case IPECAMERA_PACKED_PAYLOAD:
+ pcilib_error("Support for data type (%li) is not implemented yet", data_type);
+ return PCILIB_ERROR_NOTSUPPORTED;
+ default:
+ pcilib_error("Unknown data type (%li) is requested", data_type);
+ return PCILIB_ERROR_INVALID_REQUEST;
+ }
+}
+
+
+/*
+ We will unlock non-raw data and check if the raw data is not overwritten yet
+*/
+int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data) {
+ ipecamera_t *ctx = (ipecamera_t*)vctx;
+
+ if (!ctx) {
+ pcilib_error("IPECamera imaging is not initialized");
+ return PCILIB_ERROR_NOTINITIALIZED;
+
+ }
+
+ if ((ipecamera_data_type_t)data_type == IPECAMERA_RAW_DATA) {
+ if (ipecamera_resolve_event_id(ctx, event_id) < 0) return PCILIB_ERROR_OVERWRITTEN;
+ } else {
+ int buf_ptr = (event_id - 1) % ctx->buffer_size;
+ pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
+ }
+
+ return 0;
+}
diff --git a/ipecamera/data.h b/ipecamera/data.h
new file mode 100644
index 0000000..846cb78
--- /dev/null
+++ b/ipecamera/data.h
@@ -0,0 +1,6 @@
+#ifndef _IPECAMERA_DATA_H
+#define _IPECAMERA_DATA_H
+
+void *ipecamera_preproc_thread(void *user);
+
+#endif /* _IPECAMERA_DATA_H */
diff --git a/ipecamera/events.c b/ipecamera/events.c
new file mode 100644
index 0000000..58d2971
--- /dev/null
+++ b/ipecamera/events.c
@@ -0,0 +1,121 @@
+#define _IPECAMERA_IMAGE_C
+#define _BSD_SOURCE
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <assert.h>
+
+#include <ufodecode.h>
+
+#include "../tools.h"
+#include "../error.h"
+
+#include "pcilib.h"
+#include "public.h"
+#include "private.h"
+#include "events.h"
+
+int ipecamera_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, void *user) {
+ int err = 0;
+ int do_stop = 0;
+
+ ipecamera_event_info_t info;
+ ipecamera_t *ctx = (ipecamera_t*)vctx;
+
+ if (!ctx) {
+ pcilib_error("IPECamera imaging is not initialized");
+ return PCILIB_ERROR_NOTINITIALIZED;
+ }
+
+ ctx->streaming = 1;
+ ctx->run_streamer = 1;
+
+ if (!ctx->started) {
+ err = ipecamera_start(vctx, PCILIB_EVENTS_ALL, PCILIB_EVENT_FLAGS_DEFAULT);
+ if (err) {
+ ctx->streaming = 0;
+ return err;
+ }
+
+ do_stop = 1;
+ }
+
+ // This loop iterates while the generation
+ while ((ctx->run_streamer)||(ctx->reported_id != ctx->event_id)) {
+ while (ctx->reported_id != ctx->event_id) {
+ if ((ctx->event_id - ctx->reported_id) > (ctx->buffer_size - IPECAMERA_RESERVE_BUFFERS)) ctx->reported_id = ctx->event_id - (ctx->buffer_size - 1) - IPECAMERA_RESERVE_BUFFERS;
+ else ++ctx->reported_id;
+
+ memcpy(&info, ctx->frame + ((ctx->reported_id-1)%ctx->buffer_size), sizeof(ipecamera_event_info_t));
+
+ if ((ctx->event_id - ctx->reported_id) < ctx->buffer_size) {
+ err = callback(ctx->reported_id, (pcilib_event_info_t*)&info, user);
+ if (err <= 0) {
+ if (err < 0) err = -err;
+ break;
+ }
+ }
+ }
+ usleep(IPECAMERA_NOFRAME_SLEEP);
+ }
+
+ ctx->streaming = 0;
+
+ if (do_stop) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ }
+
+
+ return err;
+}
+
+int ipecamera_next_event(pcilib_context_t *vctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info) {
+ struct timeval tv;
+ ipecamera_t *ctx = (ipecamera_t*)vctx;
+
+ if (!ctx) {
+ pcilib_error("IPECamera imaging is not initialized");
+ return PCILIB_ERROR_NOTINITIALIZED;
+ }
+
+ if (!ctx->started) {
+ pcilib_error("IPECamera is not in grabbing mode");
+ return PCILIB_ERROR_INVALID_REQUEST;
+ }
+
+ if (ctx->reported_id == ctx->event_id) {
+ if (timeout) {
+ pcilib_calc_deadline(&tv, timeout);
+
+ while ((pcilib_calc_time_to_deadline(&tv) > 0)&&(ctx->reported_id == ctx->event_id))
+ usleep(IPECAMERA_NOFRAME_SLEEP);
+ }
+
+ if (ctx->reported_id == ctx->event_id) return PCILIB_ERROR_TIMEOUT;
+ }
+
+retry:
+ if ((ctx->event_id - ctx->reported_id) > (ctx->buffer_size - IPECAMERA_RESERVE_BUFFERS)) ctx->reported_id = ctx->event_id - (ctx->buffer_size - 1) - IPECAMERA_RESERVE_BUFFERS;
+ else ++ctx->reported_id;
+
+ if (evid) *evid = ctx->reported_id;
+
+ if (info) {
+ if (info_size >= sizeof(ipecamera_event_info_t))
+ memcpy(info, ctx->frame + ((ctx->reported_id-1)%ctx->buffer_size), sizeof(ipecamera_event_info_t));
+ else if (info_size >= sizeof(pcilib_event_info_t))
+ memcpy(info, ctx->frame + ((ctx->reported_id-1)%ctx->buffer_size), sizeof(pcilib_event_info_t));
+ else
+ return PCILIB_ERROR_INVALID_ARGUMENT;
+ }
+
+ if ((ctx->event_id - ctx->reported_id) >= ctx->buffer_size) goto retry;
+
+ return 0;
+}
+
diff --git a/ipecamera/events.h b/ipecamera/events.h
new file mode 100644
index 0000000..5268c81
--- /dev/null
+++ b/ipecamera/events.h
@@ -0,0 +1,5 @@
+#ifndef _IPECAMERA_EVENTS_H
+#define _IPECAMERA_EVENTS_H
+
+
+#endif /* _IPECAMERA_EVENTS_H */
diff --git a/ipecamera/image.c b/ipecamera/image.c
deleted file mode 100644
index e60bbf2..0000000
--- a/ipecamera/image.c
+++ /dev/null
@@ -1,971 +0,0 @@
-#define _IPECAMERA_IMAGE_C
-#define _BSD_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/time.h>
-#include <pthread.h>
-#include <assert.h>
-
-#include <ufodecode.h>
-
-#include "../tools.h"
-#include "../error.h"
-
-#include "pcilib.h"
-
-#include "model.h"
-#include "event.h"
-#include "image.h"
-
-#include "dma/nwl_dma.h"
-
-#ifdef IPECAMERA_DEBUG
-#include "dma/nwl.h"
-#endif /* IPECAMERA_DEBUG */
-
-
-#define IPECAMERA_BUG_EXTRA_DATA
-#define IPECAMERA_BUG_MULTIFRAME_PACKETS
-#define IPECAMERA_BUG_INCOMPLETE_PACKETS
-
-#define IPECAMERA_DEFAULT_BUFFER_SIZE 64 //**< should be power of 2 */
-#define IPECAMERA_RESERVE_BUFFERS 2 //**< Return Frame is Lost error, if requested frame will be overwritten after specified number of frames
-#define IPECAMERA_SLEEP_TIME 250000 //**< Michele thinks 250 should be enough, but reset failing in this case */
-#define IPECAMERA_NEXT_FRAME_DELAY 1000 //**< Michele requires 30000 to sync between End Of Readout and next Frame Req */
-#define IPECAMERA_WAIT_FRAME_RCVD_TIME 0 //**< by Uros ,wait 6 ms */
-#define IPECAMERA_NOFRAME_SLEEP 100
-
-#define IPECAMERA_MAX_LINES 1088
-#define IPECAMERA_EXPECTED_STATUS 0x08409FFFF
-#define IPECAMERA_END_OF_SEQUENCE 0x1F001001
-
-#define IPECAMERA_MAX_CHANNELS 16
-#define IPECAMERA_PIXELS_PER_CHANNEL 128
-#define IPECAMERA_WIDTH (IPECAMERA_MAX_CHANNELS * IPECAMERA_PIXELS_PER_CHANNEL)
-
-/*
-#define IPECAMERA_HEIGHT 1088
-#if IPECAMERA_HEIGHT < IPECAMERA_MAX_LINES
-# undef IPECAMERA_MAX_LINES
-# define IPECAMERA_MAX_LINES IPECAMERA_HEIGHT
-#endif
-*/
-
-//#define IPECAMERA_MEMORY
-
-#define IPECAMERA_FRAME_REQUEST 0x1E9
-#define IPECAMERA_READOUT_FLAG 0x200
-#define IPECAMERA_READOUT 0x3E1
-#define IPECAMERA_IDLE 0x1E1
-#define IPECAMERA_START_INTERNAL_STIMULI 0x1F1
-
-
-typedef uint32_t ipecamera_payload_t;
-
-typedef struct {
- pcilib_event_id_t evid;
- struct timeval timestamp;
-} ipecamera_autostop_t;
-
-struct ipecamera_s {
- pcilib_context_t event;
- ufo_decoder ipedec;
-
- char *data;
- ipecamera_pixel_t *image;
- size_t size;
-
- pcilib_event_callback_t cb;
- void *cb_user;
-
- pcilib_event_id_t event_id;
- pcilib_event_id_t reported_id;
-
- pcilib_dma_engine_t rdma, wdma;
-
- pcilib_register_t packet_len_reg;
- pcilib_register_t control_reg, status_reg;
- pcilib_register_t start_reg, end_reg;
- pcilib_register_t n_lines_reg;
- uint16_t line_reg;
- pcilib_register_t exposure_reg;
- pcilib_register_t flip_reg;
-
- int started; /**< Camera is in grabbing mode (start function is called) */
- int streaming; /**< Camera is in streaming mode (we are within stream call) */
- int parse_data; /**< Indicates if some processing of the data is required, otherwise only rawdata_callback will be called */
-
- int run_reader; /**< Instructs the reader thread to stop processing */
- int run_streamer; /**< Indicates request to stop streaming events and can be set by reader_thread upon exit or by user request */
- ipecamera_autostop_t autostop;
-
- struct timeval autostop_time;
-
- size_t buffer_size; /**< How many images to store */
- size_t buffer_pos; /**< Current image offset in the buffer, due to synchronization reasons should not be used outside of reader_thread */
- size_t cur_size; /**< Already written part of data in bytes */
- size_t raw_size; /**< Size of raw data in bytes */
- size_t full_size; /**< Size of raw data including the padding */
- size_t padded_size; /**< Size of buffer for raw data, including the padding for performance */
-
- size_t image_size; /**< Size of a single image in bytes */
-
- int width, height;
-
-
-// void *raw_buffer;
- void *buffer;
- ipecamera_change_mask_t *cmask;
- ipecamera_event_info_t *frame_info;
-
-
- ipecamera_image_dimensions_t dim;
-
- pthread_t rthread;
-};
-
-
-#define FIND_REG(var, bank, name) \
- ctx->var = pcilib_find_register(pcilib, bank, name); \
- if (ctx->var == PCILIB_REGISTER_INVALID) { \
- err = PCILIB_ERROR_NOTFOUND; \
- pcilib_error("Unable to find a %s register", name); \
- }
-
-
-#define GET_REG(reg, var) \
- if (!err) { \
- err = pcilib_read_register_by_id(pcilib, ctx->reg, &var); \
- if (err) { \
- pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \
- } \
- }
-
-#define SET_REG(reg, val) \
- if (!err) { \
- err = pcilib_write_register_by_id(pcilib, ctx->reg, val); \
- if (err) { \
- pcilib_error("Error writting %s register", ipecamera_registers[ctx->reg].name); \
- } \
- }
-
-#define CHECK_REG(reg, check) \
- if (!err) { \
- err = pcilib_read_register_by_id(pcilib, ctx->reg, &value); \
- if (err) { \
- pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \
- } \
- if (!(check)) { \
- pcilib_error("Unexpected value (%li) of register %s", value, ipecamera_registers[ctx->reg].name); \
- err = PCILIB_ERROR_INVALID_DATA; \
- } \
- }
-
-#define CHECK_VALUE(value, val) \
- if ((!err)&&(value != val)) { \
- pcilib_error("Unexpected value (0x%x) in data stream (0x%x is expected)", value, val); \
- err = PCILIB_ERROR_INVALID_DATA; \
- }
-
-#define CHECK_FLAG(flag, check, ...) \
- if ((!err)&&(!(check))) { \
- pcilib_error("Unexpected value (0x%x) of " flag, __VA_ARGS__); \
- err = PCILIB_ERROR_INVALID_DATA; \
- }
-
-
-pcilib_context_t *ipecamera_init(pcilib_t *pcilib) {
- int err = 0;
-
- ipecamera_t *ctx = malloc(sizeof(ipecamera_t));
-
- if (ctx) {
- memset(ctx, 0, sizeof(ipecamera_t));
-
- ctx->buffer_size = IPECAMERA_DEFAULT_BUFFER_SIZE;
- ctx->dim.bpp = sizeof(ipecamera_pixel_t) * 8;
-
- // We need DMA engine initialized to resolve DMA registers
-// FIND_REG(packet_len_reg, "fpga", "xrawdata_packet_length");
-
- FIND_REG(status_reg, "fpga", "status");
- FIND_REG(control_reg, "fpga", "control");
- FIND_REG(start_reg, "fpga", "start_address");
- FIND_REG(end_reg, "fpga", "end_address");
-
- FIND_REG(n_lines_reg, "cmosis", "number_lines");
- FIND_REG(line_reg, "cmosis", "start1");
- FIND_REG(exposure_reg, "cmosis", "exp_time");
- FIND_REG(flip_reg, "cmosis", "image_flipping");
-
- ctx->rdma = PCILIB_DMA_ENGINE_INVALID;
- ctx->wdma = PCILIB_DMA_ENGINE_INVALID;
-
- if (err) {
- free(ctx);
- return NULL;
- }
- }
-
- return (pcilib_context_t*)ctx;
-}
-
-void ipecamera_free(pcilib_context_t *vctx) {
- if (vctx) {
- ipecamera_t *ctx = (ipecamera_t*)vctx;
- ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
- free(ctx);
- }
-}
-
-pcilib_dma_context_t *ipecamera_init_dma(pcilib_context_t *vctx) {
- ipecamera_t *ctx = (ipecamera_t*)vctx;
-
- pcilib_model_description_t *model_info = pcilib_get_model_description(vctx->pcilib);
- if ((!model_info->dma_api)||(!model_info->dma_api->init)) {
- pcilib_error("The DMA engine is not configured in model");
- return NULL;
- }
-
-
-#ifdef IPECAMERA_DMA_R3
- return model_info->dma_api->init(vctx->pcilib, PCILIB_NWL_MODIFICATION_IPECAMERA, NULL);
-#else
- return model_info->dma_api->init(vctx->pcilib, PCILIB_DMA_MODIFICATION_DEFAULT, NULL);
-#endif
-}
-
-
-int ipecamera_set_buffer_size(ipecamera_t *ctx, int size) {
- if (ctx->started) {
- pcilib_error("Can't change buffer size while grabbing");
- return PCILIB_ERROR_INVALID_REQUEST;
- }
-
- if (size < 2) {
- pcilib_error("The buffer size is too small");
- return PCILIB_ERROR_INVALID_REQUEST;
- }
-
- if (((size^(size-1)) < size) < size) {
- pcilib_error("The buffer size is not power of 2");
- }
-
- ctx->buffer_size = size;
-
- return 0;
-}
-
-int ipecamera_reset(pcilib_context_t *vctx) {
- int err = 0;
- ipecamera_t *ctx = (ipecamera_t*)vctx;
- pcilib_t *pcilib = vctx->pcilib;
-
- pcilib_register_t control, status;
- pcilib_register_value_t value;
-
- if (!ctx) {
- pcilib_error("IPECamera imaging is not initialized");
- return PCILIB_ERROR_NOTINITIALIZED;
- }
-
- pcilib = vctx->pcilib;
- control = ctx->control_reg;
- status = ctx->status_reg;
-
- // Set Reset bit to CMOSIS
- err = pcilib_write_register_by_id(pcilib, control, 0x1e4);
- if (err) {
- pcilib_error("Error setting FPGA reset bit");
- return err;
- }
- usleep(IPECAMERA_SLEEP_TIME);
-
- // Remove Reset bit to CMOSIS
- err = pcilib_write_register_by_id(pcilib, control, 0x1e1);
- if (err) {
- pcilib_error("Error reseting FPGA reset bit");
- return err;
- }
- usleep(IPECAMERA_SLEEP_TIME);
-
- // Special settings for CMOSIS v.2
- value = 01; err = pcilib_write_register_space(pcilib, "cmosis", 115, 1, &value);
- if (err) {
- pcilib_error("Error setting CMOSIS configuration");
- return err;
- }
- usleep(IPECAMERA_SLEEP_TIME);
-
- value = 07; err = pcilib_write_register_space(pcilib, "cmosis", 82, 1, &value);
- if (err) {
- pcilib_error("Error setting CMOSIS configuration");
- return err;
- }
- usleep(IPECAMERA_SLEEP_TIME);
-
- // Set default parameters
- err = pcilib_write_register_by_id(pcilib, control, IPECAMERA_IDLE);
- if (err) {
- pcilib_error("Error bringing FPGA in default mode");
- return err;
- }
-
- usleep(10000);
-
-
- err = pcilib_read_register_by_id(pcilib, status, &value);
- if (err) {
- pcilib_error("Error reading status register");
- return err;
- }
-
- if (value != IPECAMERA_EXPECTED_STATUS) {
- pcilib_error("Unexpected value (%lx) of status register, expected %lx", value, IPECAMERA_EXPECTED_STATUS);
- return PCILIB_ERROR_VERIFY;
- }
-
- return 0;
-}
-
-// DS: Currently, on event_id overflow we are assuming the buffer is lost
-static int ipecamera_resolve_event_id(ipecamera_t *ctx, pcilib_event_id_t evid) {
- pcilib_event_id_t diff;
-
- if (evid > ctx->event_id) {
- diff = (((pcilib_event_id_t)-1) - ctx->event_id) + evid;
- if (diff >= ctx->buffer_size) return -1;
- } else {
- diff = ctx->event_id - evid;
- if (diff >= ctx->buffer_size) return -1;
- }
-
- // DS: Request buffer_size to be power of 2 and replace to shifts (just recompute in set_buffer_size)
- return (evid - 1) % ctx->buffer_size;
-}
-
-static inline int ipecamera_new_frame(ipecamera_t *ctx) {
- ctx->frame_info[ctx->buffer_pos].raw_size = ctx->cur_size;
-
- if (ctx->cur_size < ctx->raw_size) ctx->frame_info[ctx->buffer_pos].info.flags |= PCILIB_EVENT_INFO_FLAG_BROKEN;
-
- ctx->buffer_pos = (++ctx->event_id) % ctx->buffer_size;
- ctx->cur_size = 0;
-
- ctx->frame_info[ctx->buffer_pos].info.type = PCILIB_EVENT0;
- ctx->frame_info[ctx->buffer_pos].info.flags = 0;
- ctx->frame_info[ctx->buffer_pos].image_ready = 0;
-
- if ((ctx->event_id == ctx->autostop.evid)&&(ctx->event_id)) {
- ctx->run_reader = 0;
- return 1;
- }
-
- if (pcilib_check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) {
- ctx->run_reader = 0;
- return 1;
- }
-
- return 0;
-}
-
-static uint32_t frame_magic[6] = { 0x51111111, 0x52222222, 0x53333333, 0x54444444, 0x55555555, 0x56666666 };
-
-static int ipecamera_data_callback(void *user, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
- int eof = 0;
-
-#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS
- size_t extra_data = 0;
-#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */
-
- ipecamera_t *ctx = (ipecamera_t*)user;
-
- if (!ctx->cur_size) {
-#if defined(IPECAMERA_BUG_INCOMPLETE_PACKETS)||defined(IPECAMERA_BUG_MULTIFRAME_PACKETS)
- size_t startpos;
- for (startpos = 0; (startpos + 8) < bufsize; startpos++) {
- if (!memcmp(buf + startpos, frame_magic, sizeof(frame_magic))) break;
- }
-
- if (startpos) {
- buf += startpos;
- bufsize -= startpos;
- }
-#endif /* IPECAMERA_BUG_INCOMPLETE_PACKETS */
-
- if ((bufsize >= 8)&&(!memcmp(buf, frame_magic, sizeof(frame_magic)))) {
-/*
- // Not implemented in hardware yet
- ctx->frame_info[ctx->buffer_pos].info.seqnum = ((uint32_t*)buf)[6] & 0xF0000000;
- ctx->frame_info[ctx->buffer_pos].info.offset = ((uint32_t*)buf)[7] & 0xF0000000;
-*/
- gettimeofday(&ctx->frame_info[ctx->buffer_pos].info.timestamp, NULL);
- } else {
-// pcilib_warning("Frame magic is not found, ignoring broken data...");
- return PCILIB_STREAMING_CONTINUE;
- }
- }
-
-#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS
- if (ctx->cur_size + bufsize > ctx->raw_size) {
- size_t need;
-
- for (need = ctx->raw_size - ctx->cur_size; need < bufsize; need += sizeof(uint32_t)) {
- if (*(uint32_t*)(buf + need) == frame_magic[0]) break;
- }
-
- if (need < bufsize) {
- extra_data = bufsize - need;
- //bufsize = need;
- eof = 1;
- }
-
- // just rip of padding
- bufsize = ctx->raw_size - ctx->cur_size;
- }
-#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */
-
- if (ctx->parse_data) {
- if (ctx->cur_size + bufsize > ctx->full_size) {
- pcilib_error("Unexpected event data, we are expecting at maximum (%zu) bytes, but (%zu) already read", ctx->full_size, ctx->cur_size + bufsize);
- return -PCILIB_ERROR_TOOBIG;
- }
-
- memcpy(ctx->buffer + ctx->buffer_pos * ctx->padded_size + ctx->cur_size, buf, bufsize);
- }
-
- ctx->cur_size += bufsize;
-// printf("%i: %i %i\n", ctx->buffer_pos, ctx->cur_size, bufsize);
-
- if (ctx->cur_size >= ctx->full_size) eof = 1;
-
- if (ctx->event.params.rawdata.callback) {
- ctx->event.params.rawdata.callback(ctx->event_id, (pcilib_event_info_t*)(ctx->frame_info + ctx->buffer_pos), (eof?PCILIB_EVENT_FLAG_EOF:PCILIB_EVENT_FLAGS_DEFAULT), bufsize, buf, ctx->event.params.rawdata.user);
- }
-
- if (eof) {
- if (ipecamera_new_frame(ctx)) {
- return PCILIB_STREAMING_STOP;
- }
-
-#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS
- if (extra_data) {
- return ipecamera_data_callback(user, flags, extra_data, buf + bufsize);
- }
-#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */
- }
-
- return PCILIB_STREAMING_REQ_FRAGMENT;
-}
-
-static void *ipecamera_reader_thread(void *user) {
- int err;
- ipecamera_t *ctx = (ipecamera_t*)user;
-
- while (ctx->run_reader) {
- err = pcilib_stream_dma(ctx->event.pcilib, ctx->rdma, 0, 0, PCILIB_DMA_FLAG_MULTIPACKET, PCILIB_DMA_TIMEOUT, &ipecamera_data_callback, user);
- if (err) {
- if (err == PCILIB_ERROR_TIMEOUT) {
- if (ctx->cur_size > ctx->raw_size) ipecamera_new_frame(ctx);
-#ifdef IPECAMERA_BUG_INCOMPLETE_PACKETS
- else if (ctx->cur_size > 0) ipecamera_new_frame(ctx);
-#endif /* IPECAMERA_BUG_INCOMPLETE_PACKETS */
- if (pcilib_check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) {
- ctx->run_reader = 0;
- break;
- }
- usleep(IPECAMERA_NOFRAME_SLEEP);
- } else pcilib_error("DMA error while reading IPECamera frames, error: %i", err);
- } else printf("no error\n");
-
- //usleep(1000);
- }
-
- ctx->run_streamer = 0;
-
- if (ctx->cur_size)
- pcilib_error("partialy read frame after stop signal, %zu bytes in the buffer", ctx->cur_size);
-
- return NULL;
-}
-
-int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_event_flags_t flags) {
- int err = 0;
- ipecamera_t *ctx = (ipecamera_t*)vctx;
- pcilib_t *pcilib = vctx->pcilib;
- pcilib_register_value_t value;
-
- const size_t chan_size = (2 + IPECAMERA_PIXELS_PER_CHANNEL / 3) * sizeof(ipecamera_payload_t);
- const size_t line_size = (IPECAMERA_MAX_CHANNELS * chan_size);
- const size_t header_size = 8 * sizeof(ipecamera_payload_t);
- const size_t footer_size = 8 * sizeof(ipecamera_payload_t);
- size_t raw_size;
- size_t padded_blocks;
-
- pthread_attr_t attr;
- struct sched_param sched;
-
- if (!ctx) {
- pcilib_error("IPECamera imaging is not initialized");
- return PCILIB_ERROR_NOTINITIALIZED;
- }
-
- if (ctx->started) {
- pcilib_error("IPECamera grabbing is already started");
- return PCILIB_ERROR_INVALID_REQUEST;
- }
-
-
- // Allow readout and clean the FRAME_REQUEST mode if set for some reason
- SET_REG(control_reg, IPECAMERA_IDLE|IPECAMERA_READOUT_FLAG);
- usleep(IPECAMERA_SLEEP_TIME);
- CHECK_REG(status_reg, IPECAMERA_EXPECTED_STATUS);
- if (err) return err;
-
-
- ctx->event_id = 0;
- ctx->reported_id = 0;
- ctx->buffer_pos = 0;
- ctx->parse_data = (flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY)?0:1;
- ctx->cur_size = 0;
-
- ctx->dim.width = IPECAMERA_WIDTH;
- GET_REG(n_lines_reg, ctx->dim.height);
-
- raw_size = header_size + ctx->dim.height * line_size + footer_size;
- padded_blocks = raw_size / IPECAMERA_DMA_PACKET_LENGTH + ((raw_size % IPECAMERA_DMA_PACKET_LENGTH)?1:0);
-
- ctx->image_size = ctx->dim.width * ctx->dim.height;
- ctx->raw_size = raw_size;
- ctx->full_size = padded_blocks * IPECAMERA_DMA_PACKET_LENGTH;
-
-#ifdef IPECAMERA_BUG_EXTRA_DATA
- ctx->full_size += 8;
- padded_blocks ++;
-#endif /* IPECAMERA_BUG_EXTRA_DATA */
-
- ctx->padded_size = padded_blocks * IPECAMERA_DMA_PACKET_LENGTH;
-
- ctx->buffer = malloc(ctx->padded_size * ctx->buffer_size);
- if (!ctx->buffer) {
- err = PCILIB_ERROR_MEMORY;
- pcilib_error("Unable to allocate ring buffer (%lu bytes)", ctx->padded_size * ctx->buffer_size);
- return err;
- }
-
- ctx->image = (ipecamera_pixel_t*)malloc(ctx->image_size * ctx->buffer_size * sizeof(ipecamera_pixel_t));
- if (!ctx->image) {
- err = PCILIB_ERROR_MEMORY;
- pcilib_error("Unable to allocate image buffer (%lu bytes)", ctx->image_size * ctx->buffer_size * sizeof(ipecamera_pixel_t));
- return err;
- }
-
- ctx->cmask = malloc(ctx->dim.height * ctx->buffer_size * sizeof(ipecamera_change_mask_t));
- if (!ctx->cmask) {
- err = PCILIB_ERROR_MEMORY;
- pcilib_error("Unable to allocate change-mask buffer");
- return err;
- }
-
- ctx->frame_info = malloc(ctx->buffer_size * sizeof(ipecamera_event_info_t));
- if (!ctx->frame_info) {
- err = PCILIB_ERROR_MEMORY;
- pcilib_error("Unable to allocate frame-info buffer");
- return err;
- }
-
- ctx->ipedec = ufo_decoder_new(ctx->dim.height, ctx->dim.width, NULL, 0);
- if (!ctx->ipedec) {
- pcilib_error("Unable to initialize IPECamera decoder library");
- return PCILIB_ERROR_FAILED;
- }
-
- if (!err) {
- ctx->rdma = pcilib_find_dma_by_addr(vctx->pcilib, PCILIB_DMA_FROM_DEVICE, IPECAMERA_DMA_ADDRESS);
- if (ctx->rdma == PCILIB_DMA_ENGINE_INVALID) {
- err = PCILIB_ERROR_NOTFOUND;
- pcilib_error("The C2S channel of IPECamera DMA Engine (%u) is not found", IPECAMERA_DMA_ADDRESS);
- } else {
- err = pcilib_start_dma(vctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT);
- if (err) {
- ctx->rdma = PCILIB_DMA_ENGINE_INVALID;
- pcilib_error("Failed to initialize C2S channel of IPECamera DMA Engine (%u)", IPECAMERA_DMA_ADDRESS);
- }
- }
- }
-
-/*
- if (!err) {
- ctx->wdma = pcilib_find_dma_by_addr(vctx->pcilib, PCILIB_DMA_TO_DEVICE, IPECAMERA_DMA_ADDRESS);
- if (ctx->wdma == PCILIB_DMA_ENGINE_INVALID) {
- err = PCILIB_ERROR_NOTFOUND;
- pcilib_error("The S2C channel of IPECamera DMA Engine (%u) is not found", IPECAMERA_DMA_ADDRESS);
- } else {
- err = pcilib_start_dma(vctx->pcilib, ctx->wdma, PCILIB_DMA_FLAGS_DEFAULT);
- if (err) {
- ctx->wdma = PCILIB_DMA_ENGINE_INVALID;
- pcilib_error("Failed to initialize S2C channel of IPECamera DMA Engine (%u)", IPECAMERA_DMA_ADDRESS);
- }
- }
- }
-*/
-
-/*
- SET_REG(packet_len_reg, IPECAMERA_DMA_PACKET_LENGTH);
- if (err) return err;
-*/
-
- // Clean DMA
- err = pcilib_skip_dma(vctx->pcilib, ctx->rdma);
- if (err) {
- pcilib_error("Can't start grabbing, device continuously writes unexpected data using DMA engine");
- return err;
- }
-
- if (err) {
- ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
- return err;
- }
-
- if (vctx->params.autostop.duration) {
- gettimeofday(&ctx->autostop.timestamp, NULL);
- ctx->autostop.timestamp.tv_usec += vctx->params.autostop.duration % 1000000;
- if (ctx->autostop.timestamp.tv_usec > 999999) {
- ctx->autostop.timestamp.tv_sec += 1 + vctx->params.autostop.duration / 1000000;
- ctx->autostop.timestamp.tv_usec -= 1000000;
- } else {
- ctx->autostop.timestamp.tv_sec += vctx->params.autostop.duration / 1000000;
- }
- }
-
- if (vctx->params.autostop.max_events) {
- ctx->autostop.evid = vctx->params.autostop.max_events;
- }
-
- ctx->started = 1;
- ctx->run_reader = 1;
-
- pthread_attr_init(&attr);
-
- if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) {
- pcilib_warning("Can't schedule a real-time thread, you may consider running as root");
- } else {
- sched.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1; // Let 1 priority for something really critcial
- pthread_attr_setschedparam(&attr, &sched);
- }
-
- if (pthread_create(&ctx->rthread, &attr, &ipecamera_reader_thread, (void*)ctx)) {
- ctx->started = 0;
- ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
- err = PCILIB_ERROR_THREAD;
- }
-
- pthread_attr_destroy(&attr);
-
- return err;
-}
-
-
-int ipecamera_stop(pcilib_context_t *vctx, pcilib_event_flags_t flags) {
- int err;
- void *retcode;
- ipecamera_t *ctx = (ipecamera_t*)vctx;
-
- if (!ctx) {
- pcilib_error("IPECamera imaging is not initialized");
- return PCILIB_ERROR_NOTINITIALIZED;
- }
-
- if (flags&PCILIB_EVENT_FLAG_STOP_ONLY) {
- ctx->run_reader = 0;
- return 0;
- }
-
- if (ctx->started) {
- ctx->run_reader = 0;
- err = pthread_join(ctx->rthread, &retcode);
- if (err) pcilib_error("Error joining the reader thread");
- }
-
- if (ctx->wdma != PCILIB_DMA_ENGINE_INVALID) {
- pcilib_stop_dma(vctx->pcilib, ctx->wdma, PCILIB_DMA_FLAGS_DEFAULT);
- ctx->wdma = PCILIB_DMA_ENGINE_INVALID;
- }
-
- if (ctx->rdma != PCILIB_DMA_ENGINE_INVALID) {
- pcilib_stop_dma(vctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT);
- ctx->rdma = PCILIB_DMA_ENGINE_INVALID;
- }
-
- if (ctx->ipedec) {
- ufo_decoder_free(ctx->ipedec);
- ctx->ipedec = NULL;
- }
-
- if (ctx->frame_info) {
- free(ctx->frame_info);
- ctx->frame_info = NULL;
- }
-
- if (ctx->cmask) {
- free(ctx->cmask);
- ctx->cmask = NULL;
- }
-
- if (ctx->image) {
- free(ctx->image);
- ctx->image = NULL;
- }
-
- if (ctx->buffer) {
- free(ctx->buffer);
- ctx->buffer = NULL;
- }
-
-
- memset(&ctx->autostop, 0, sizeof(ipecamera_autostop_t));
-
- ctx->event_id = 0;
- ctx->reported_id = 0;
- ctx->buffer_pos = 0;
- ctx->started = 0;
-
- return 0;
-}
-
-
-int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
- int err = 0;
- pcilib_register_value_t value;
-
- ipecamera_t *ctx = (ipecamera_t*)vctx;
- pcilib_t *pcilib = vctx->pcilib;
-
- if (!ctx) {
- pcilib_error("IPECamera imaging is not initialized");
- return PCILIB_ERROR_NOTINITIALIZED;
- }
-
- if (!ctx->started) {
- pcilib_error("Can't trigger while grabbing is not started");
- return PCILIB_ERROR_INVALID_REQUEST;
- }
-
- SET_REG(control_reg, IPECAMERA_FRAME_REQUEST|IPECAMERA_READOUT_FLAG);
- usleep(IPECAMERA_WAIT_FRAME_RCVD_TIME);
- CHECK_REG(status_reg, IPECAMERA_EXPECTED_STATUS);
- SET_REG(control_reg, IPECAMERA_IDLE|IPECAMERA_READOUT_FLAG);
-
-
- // DS: Just measure when next trigger is allowed instead and wait in the beginning
- usleep(IPECAMERA_NEXT_FRAME_DELAY); // minimum delay between End Of Readout and next Frame Req
-
- return 0;
-}
-
-int ipecamera_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, void *user) {
- int err = 0;
- int do_stop = 0;
- pcilib_event_id_t reported;
- ipecamera_t *ctx = (ipecamera_t*)vctx;
-
- size_t events = 0;
-
- struct timeval stream_stop;
-
- if (!ctx) {
- pcilib_error("IPECamera imaging is not initialized");
- return PCILIB_ERROR_NOTINITIALIZED;
- }
-
- ctx->streaming = 1;
- ctx->run_streamer = 1;
-
- if (!ctx->started) {
- err = ipecamera_start(vctx, PCILIB_EVENTS_ALL, PCILIB_EVENT_FLAGS_DEFAULT);
- if (err) {
- ctx->streaming = 0;
- pcilib_error("IPECamera is not in grabbing state");
- return PCILIB_ERROR_INVALID_STATE;
- }
-
- do_stop = 1;
- }
-
- // This loop iterates while the generation
- while ((ctx->run_streamer)||(ctx->reported_id != ctx->event_id)) {
- while (ctx->reported_id != ctx->event_id) {
- if ((ctx->event_id - ctx->reported_id) > (ctx->buffer_size - IPECAMERA_RESERVE_BUFFERS)) ctx->reported_id = ctx->event_id - (ctx->buffer_size - 1) - IPECAMERA_RESERVE_BUFFERS;
- else ++ctx->reported_id;
-
- callback(ctx->reported_id, (pcilib_event_info_t*)(ctx->frame_info + ((ctx->reported_id-1)%ctx->buffer_size)), user);
- }
- usleep(IPECAMERA_NOFRAME_SLEEP);
- }
-
- ctx->streaming = 0;
-
- if (do_stop) {
- ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
- }
-
-
- return err;
-}
-
-int ipecamera_next_event(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_timeout_t timeout, pcilib_event_id_t *evid, pcilib_event_info_t **info) {
- struct timeval tv;
- ipecamera_t *ctx = (ipecamera_t*)vctx;
-
- if (!ctx) {
- pcilib_error("IPECamera imaging is not initialized");
- return PCILIB_ERROR_NOTINITIALIZED;
- }
-
- if (!ctx->started) {
- pcilib_error("IPECamera is not in grabbing mode");
- return PCILIB_ERROR_INVALID_REQUEST;
- }
-
- if (ctx->reported_id == ctx->event_id) {
- if (timeout) {
- pcilib_calc_deadline(&tv, timeout);
-
- while ((pcilib_calc_time_to_deadline(&tv) > 0)&&(ctx->reported_id == ctx->event_id))
- usleep(IPECAMERA_NOFRAME_SLEEP);
- }
-
- if (ctx->reported_id == ctx->event_id) return PCILIB_ERROR_TIMEOUT;
- }
-
- if ((ctx->event_id - ctx->reported_id) > (ctx->buffer_size - IPECAMERA_RESERVE_BUFFERS)) ctx->reported_id = ctx->event_id - (ctx->buffer_size - 1) - IPECAMERA_RESERVE_BUFFERS;
- else ++ctx->reported_id;
-
- if (evid) *evid = ctx->reported_id;
- if (info) *info = (pcilib_event_info_t*)(ctx->frame_info + ((ctx->reported_id-1)%ctx->buffer_size));
-
- return 0;
-}
-
-
-inline static int ipecamera_decode_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) {
- int err;
- uint32_t tmp;
- uint16_t *pixels;
-
- int buf_ptr = (event_id - 1) % ctx->buffer_size;
-
- if (!ctx->frame_info[buf_ptr].image_ready) {
- if (ctx->frame_info[buf_ptr].info.flags&PCILIB_EVENT_INFO_FLAG_BROKEN) return PCILIB_ERROR_INVALID_DATA;
-
- ufo_decoder_set_raw_data(ctx->ipedec, ctx->buffer + buf_ptr * ctx->padded_size, ctx->raw_size);
-
- pixels = ctx->image + buf_ptr * ctx->image_size;
- memset(ctx->cmask + ctx->buffer_pos * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t));
- err = ufo_decoder_get_next_frame(ctx->ipedec, &pixels, &tmp, &tmp, ctx->cmask + ctx->buffer_pos * ctx->dim.height);
- if (err) return PCILIB_ERROR_FAILED;
-
- ctx->frame_info[buf_ptr].image_ready = 1;
-
- if (ipecamera_resolve_event_id(ctx, event_id) < 0) {
- ctx->frame_info[buf_ptr].image_ready = 0;
- return PCILIB_ERROR_TIMEOUT;
- }
- }
-
- return 0;
-}
-
-void* ipecamera_get(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size, void *data) {
- int err;
- int buf_ptr;
- size_t raw_size;
- ipecamera_t *ctx = (ipecamera_t*)vctx;
- uint16_t *pixels;
-
- if (!ctx) {
- pcilib_error("IPECamera imaging is not initialized");
- return NULL;
- }
-
-
- buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
- if (buf_ptr < 0) return NULL;
-
- switch ((ipecamera_data_type_t)data_type) {
- case IPECAMERA_RAW_DATA:
- raw_size = ctx->frame_info[buf_ptr].raw_size;
- if (data) {
- if ((!size)||(*size < raw_size)) return NULL;
- memcpy(data, ctx->buffer + buf_ptr * ctx->padded_size, raw_size);
- if (ipecamera_resolve_event_id(ctx, event_id) < 0) return NULL;
- *size = raw_size;
- return data;
- }
- if (size) *size = raw_size;
- return ctx->buffer + buf_ptr * ctx->padded_size;
- case IPECAMERA_IMAGE_DATA:
- err = ipecamera_decode_frame(ctx, event_id);
- if (err) return NULL;
-
- if (data) {
- if ((!size)||(*size < ctx->image_size * sizeof(ipecamera_pixel_t))) return NULL;
- memcpy(data, ctx->image + buf_ptr * ctx->image_size, ctx->image_size * sizeof(ipecamera_pixel_t));
- if (ipecamera_resolve_event_id(ctx, event_id) < 0) return NULL;
- *size = ctx->image_size * sizeof(ipecamera_pixel_t);
- return data;
- }
-
- if (size) *size = ctx->image_size * sizeof(ipecamera_pixel_t);
- return ctx->image + buf_ptr * ctx->image_size;
- case IPECAMERA_CHANGE_MASK:
- err = ipecamera_decode_frame(ctx, event_id);
- if (err) return NULL;
-
- if (data) {
- if ((!size)||(*size < ctx->dim.height * sizeof(ipecamera_change_mask_t))) return NULL;
- memcpy(data, ctx->image + buf_ptr * ctx->dim.height, ctx->dim.height * sizeof(ipecamera_change_mask_t));
- if (ipecamera_resolve_event_id(ctx, event_id) < 0) return NULL;
- *size = ctx->dim.height * sizeof(ipecamera_change_mask_t);
-
- return data;
- }
-
- if (size) *size = ctx->dim.height * sizeof(ipecamera_change_mask_t);
- return ctx->cmask + buf_ptr * ctx->dim.height;
- case IPECAMERA_DIMENSIONS:
- if (size) *size = sizeof(ipecamera_image_dimensions_t);
- return &ctx->dim;
- case IPECAMERA_IMAGE_REGION:
- case IPECAMERA_PACKED_IMAGE:
- // Shall we return complete image or only changed parts?
- case IPECAMERA_PACKED_LINE:
- case IPECAMERA_PACKED_PAYLOAD:
- pcilib_error("Support for data type (%li) is not implemented yet", data_type);
- return NULL;
- default:
- pcilib_error("Unknown data type (%li) is requested", data_type);
- return NULL;
- }
-}
-
-
-
-int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id, void *data) {
- ipecamera_t *ctx = (ipecamera_t*)vctx;
-
- if (!ctx) {
- pcilib_error("IPECamera imaging is not initialized");
- return PCILIB_ERROR_NOTINITIALIZED;
-
- }
-
- if (ipecamera_resolve_event_id(ctx, event_id) < 0) {
- return PCILIB_ERROR_NOTAVAILABLE;
- }
-
- return 0;
-}
diff --git a/ipecamera/ipecamera.c b/ipecamera/ipecamera.c
new file mode 100644
index 0000000..0819284
--- /dev/null
+++ b/ipecamera/ipecamera.c
@@ -0,0 +1,597 @@
+#define _IPECAMERA_IMAGE_C
+#define _BSD_SOURCE
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <assert.h>
+
+#include <ufodecode.h>
+
+#include "../tools.h"
+#include "../error.h"
+#include "../event.h"
+
+#include "pcilib.h"
+#include "private.h"
+#include "model.h"
+#include "reader.h"
+#include "events.h"
+#include "data.h"
+
+#include "dma/nwl_dma.h"
+
+#ifdef IPECAMERA_DEBUG
+#include "dma/nwl.h"
+#endif /* IPECAMERA_DEBUG */
+
+
+#define FIND_REG(var, bank, name) \
+ ctx->var = pcilib_find_register(pcilib, bank, name); \
+ if (ctx->var == PCILIB_REGISTER_INVALID) { \
+ err = PCILIB_ERROR_NOTFOUND; \
+ pcilib_error("Unable to find a %s register", name); \
+ }
+
+
+#define GET_REG(reg, var) \
+ if (!err) { \
+ err = pcilib_read_register_by_id(pcilib, ctx->reg, &var); \
+ if (err) { \
+ pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \
+ } \
+ }
+
+#define SET_REG(reg, val) \
+ if (!err) { \
+ err = pcilib_write_register_by_id(pcilib, ctx->reg, val); \
+ if (err) { \
+ pcilib_error("Error writting %s register", ipecamera_registers[ctx->reg].name); \
+ } \
+ }
+
+#define CHECK_REG(reg, check) \
+ if (!err) { \
+ err = pcilib_read_register_by_id(pcilib, ctx->reg, &value); \
+ if (err) { \
+ pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \
+ } \
+ if (!(check)) { \
+ pcilib_error("Unexpected value (%li) of register %s", value, ipecamera_registers[ctx->reg].name); \
+ err = PCILIB_ERROR_INVALID_DATA; \
+ } \
+ }
+
+#define CHECK_VALUE(value, val) \
+ if ((!err)&&(value != val)) { \
+ pcilib_error("Unexpected value (0x%x) in data stream (0x%x is expected)", value, val); \
+ err = PCILIB_ERROR_INVALID_DATA; \
+ }
+
+#define CHECK_FLAG(flag, check, ...) \
+ if ((!err)&&(!(check))) { \
+ pcilib_error("Unexpected value (0x%x) of " flag, __VA_ARGS__); \
+ err = PCILIB_ERROR_INVALID_DATA; \
+ }
+
+
+pcilib_context_t *ipecamera_init(pcilib_t *pcilib) {
+ int err = 0;
+
+ ipecamera_t *ctx = malloc(sizeof(ipecamera_t));
+
+ if (ctx) {
+ memset(ctx, 0, sizeof(ipecamera_t));
+
+ ctx->buffer_size = IPECAMERA_DEFAULT_BUFFER_SIZE;
+ ctx->dim.bpp = sizeof(ipecamera_pixel_t) * 8;
+
+ // We need DMA engine initialized to resolve DMA registers
+// FIND_REG(packet_len_reg, "fpga", "xrawdata_packet_length");
+
+ FIND_REG(status_reg, "fpga", "status");
+ FIND_REG(control_reg, "fpga", "control");
+ FIND_REG(start_reg, "fpga", "start_address");
+ FIND_REG(end_reg, "fpga", "end_address");
+
+ FIND_REG(n_lines_reg, "cmosis", "number_lines");
+ FIND_REG(line_reg, "cmosis", "start1");
+ FIND_REG(exposure_reg, "cmosis", "exp_time");
+ FIND_REG(flip_reg, "cmosis", "image_flipping");
+
+ ctx->rdma = PCILIB_DMA_ENGINE_INVALID;
+ ctx->wdma = PCILIB_DMA_ENGINE_INVALID;
+
+ if (err) {
+ free(ctx);
+ return NULL;
+ }
+ }
+
+ return (pcilib_context_t*)ctx;
+}
+
+void ipecamera_free(pcilib_context_t *vctx) {
+ if (vctx) {
+ ipecamera_t *ctx = (ipecamera_t*)vctx;
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ free(ctx);
+ }
+}
+
+pcilib_dma_context_t *ipecamera_init_dma(pcilib_context_t *vctx) {
+// ipecamera_t *ctx = (ipecamera_t*)vctx;
+
+ pcilib_model_description_t *model_info = pcilib_get_model_description(vctx->pcilib);
+ if ((!model_info->dma_api)||(!model_info->dma_api->init)) {
+ pcilib_error("The DMA engine is not configured in model");
+ return NULL;
+ }
+
+
+#ifdef IPECAMERA_DMA_R3
+ return model_info->dma_api->init(vctx->pcilib, PCILIB_NWL_MODIFICATION_IPECAMERA, NULL);
+#else
+ return model_info->dma_api->init(vctx->pcilib, PCILIB_DMA_MODIFICATION_DEFAULT, NULL);
+#endif
+}
+
+
+int ipecamera_set_buffer_size(ipecamera_t *ctx, int size) {
+ if (ctx->started) {
+ pcilib_error("Can't change buffer size while grabbing");
+ return PCILIB_ERROR_INVALID_REQUEST;
+ }
+
+ if (size < 2) {
+ pcilib_error("The buffer size is too small");
+ return PCILIB_ERROR_INVALID_REQUEST;
+ }
+
+ if (((size^(size-1)) < size) < size) {
+ pcilib_error("The buffer size is not power of 2");
+ }
+
+ ctx->buffer_size = size;
+
+ return 0;
+}
+
+int ipecamera_reset(pcilib_context_t *vctx) {
+ int err = 0;
+ ipecamera_t *ctx = (ipecamera_t*)vctx;
+ pcilib_t *pcilib = vctx->pcilib;
+
+ pcilib_register_t control, status;
+ pcilib_register_value_t value;
+
+ if (!ctx) {
+ pcilib_error("IPECamera imaging is not initialized");
+ return PCILIB_ERROR_NOTINITIALIZED;
+ }
+
+ pcilib = vctx->pcilib;
+ control = ctx->control_reg;
+ status = ctx->status_reg;
+
+ // Set Reset bit to CMOSIS
+ err = pcilib_write_register_by_id(pcilib, control, 0x1e4);
+ if (err) {
+ pcilib_error("Error setting FPGA reset bit");
+ return err;
+ }
+ usleep(IPECAMERA_SLEEP_TIME);
+
+ // Remove Reset bit to CMOSIS
+ err = pcilib_write_register_by_id(pcilib, control, 0x1e1);
+ if (err) {
+ pcilib_error("Error reseting FPGA reset bit");
+ return err;
+ }
+ usleep(IPECAMERA_SLEEP_TIME);
+
+ // Special settings for CMOSIS v.2
+ value = 01; err = pcilib_write_register_space(pcilib, "cmosis", 115, 1, &value);
+ if (err) {
+ pcilib_error("Error setting CMOSIS configuration");
+ return err;
+ }
+ usleep(IPECAMERA_SLEEP_TIME);
+
+ value = 07; err = pcilib_write_register_space(pcilib, "cmosis", 82, 1, &value);
+ if (err) {
+ pcilib_error("Error setting CMOSIS configuration");
+ return err;
+ }
+ usleep(IPECAMERA_SLEEP_TIME);
+
+ // Set default parameters
+ err = pcilib_write_register_by_id(pcilib, control, IPECAMERA_IDLE);
+ if (err) {
+ pcilib_error("Error bringing FPGA in default mode");
+ return err;
+ }
+
+ usleep(10000);
+
+
+ err = pcilib_read_register_by_id(pcilib, status, &value);
+ if (err) {
+ pcilib_error("Error reading status register");
+ return err;
+ }
+
+ if (value != IPECAMERA_EXPECTED_STATUS) {
+ pcilib_error("Unexpected value (%lx) of status register, expected %lx", value, IPECAMERA_EXPECTED_STATUS);
+ return PCILIB_ERROR_VERIFY;
+ }
+
+ return 0;
+}
+
+
+int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_event_flags_t flags) {
+ int i;
+ int err = 0;
+ ipecamera_t *ctx = (ipecamera_t*)vctx;
+ pcilib_t *pcilib = vctx->pcilib;
+ pcilib_register_value_t value;
+
+ const size_t chan_size = (2 + IPECAMERA_PIXELS_PER_CHANNEL / 3) * sizeof(ipecamera_payload_t);
+ const size_t line_size = (IPECAMERA_MAX_CHANNELS * chan_size);
+ const size_t header_size = 8 * sizeof(ipecamera_payload_t);
+ const size_t footer_size = 8 * sizeof(ipecamera_payload_t);
+ size_t raw_size;
+ size_t padded_blocks;
+
+ pthread_attr_t attr;
+ struct sched_param sched;
+
+ if (!ctx) {
+ pcilib_error("IPECamera imaging is not initialized");
+ return PCILIB_ERROR_NOTINITIALIZED;
+ }
+
+ if (ctx->started) {
+ pcilib_error("IPECamera grabbing is already started");
+ return PCILIB_ERROR_INVALID_REQUEST;
+ }
+
+
+ // Allow readout and clean the FRAME_REQUEST mode if set for some reason
+ SET_REG(control_reg, IPECAMERA_IDLE|IPECAMERA_READOUT_FLAG);
+ usleep(IPECAMERA_SLEEP_TIME);
+ CHECK_REG(status_reg, IPECAMERA_EXPECTED_STATUS);
+ if (err) return err;
+
+
+ ctx->event_id = 0;
+ ctx->preproc_id = 0;
+ ctx->reported_id = 0;
+ ctx->buffer_pos = 0;
+ ctx->parse_data = (flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY)?0:1;
+ ctx->cur_size = 0;
+
+ ctx->dim.width = IPECAMERA_WIDTH;
+ GET_REG(n_lines_reg, ctx->dim.height);
+
+ raw_size = header_size + ctx->dim.height * line_size + footer_size;
+ padded_blocks = raw_size / IPECAMERA_DMA_PACKET_LENGTH + ((raw_size % IPECAMERA_DMA_PACKET_LENGTH)?1:0);
+
+ ctx->image_size = ctx->dim.width * ctx->dim.height;
+ ctx->raw_size = raw_size;
+ ctx->full_size = padded_blocks * IPECAMERA_DMA_PACKET_LENGTH;
+
+#ifdef IPECAMERA_BUG_EXTRA_DATA
+ ctx->full_size += 8;
+ padded_blocks ++;
+#endif /* IPECAMERA_BUG_EXTRA_DATA */
+
+ ctx->padded_size = padded_blocks * IPECAMERA_DMA_PACKET_LENGTH;
+
+ ctx->buffer = malloc(ctx->padded_size * ctx->buffer_size);
+ if (!ctx->buffer) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ pcilib_error("Unable to allocate ring buffer (%lu bytes)", ctx->padded_size * ctx->buffer_size);
+ return PCILIB_ERROR_MEMORY;
+ }
+
+ ctx->image = (ipecamera_pixel_t*)malloc(ctx->image_size * ctx->buffer_size * sizeof(ipecamera_pixel_t));
+ if (!ctx->image) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ pcilib_error("Unable to allocate image buffer (%lu bytes)", ctx->image_size * ctx->buffer_size * sizeof(ipecamera_pixel_t));
+ return PCILIB_ERROR_MEMORY;
+ }
+
+ ctx->cmask = malloc(ctx->dim.height * ctx->buffer_size * sizeof(ipecamera_change_mask_t));
+ if (!ctx->cmask) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ pcilib_error("Unable to allocate change-mask buffer");
+ return PCILIB_ERROR_MEMORY;
+ }
+
+ ctx->frame = (ipecamera_frame_t*)malloc(ctx->buffer_size * sizeof(ipecamera_frame_t));
+ if (!ctx->frame) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ pcilib_error("Unable to allocate frame-info buffer");
+ return PCILIB_ERROR_MEMORY;
+ }
+
+ memset(ctx->frame, 0, ctx->buffer_size * sizeof(ipecamera_frame_t));
+
+ for (i = 0; i < ctx->buffer_size; i++) {
+ err = pthread_rwlock_init(&ctx->frame[i].mutex, NULL);
+ if (err) break;
+ }
+
+ ctx->frame_mutex_destroy = i;
+
+ if (err) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ pcilib_error("Initialization of rwlock mutexes for frame synchronization has failed");
+ return PCILIB_ERROR_FAILED;
+ }
+
+ ctx->ipedec = ufo_decoder_new(ctx->dim.height, ctx->dim.width, NULL, 0);
+ if (!ctx->ipedec) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ pcilib_error("Unable to initialize IPECamera decoder library");
+ return PCILIB_ERROR_FAILED;
+ }
+
+ if (!err) {
+ ctx->rdma = pcilib_find_dma_by_addr(vctx->pcilib, PCILIB_DMA_FROM_DEVICE, IPECAMERA_DMA_ADDRESS);
+ if (ctx->rdma == PCILIB_DMA_ENGINE_INVALID) {
+ err = PCILIB_ERROR_NOTFOUND;
+ pcilib_error("The C2S channel of IPECamera DMA Engine (%u) is not found", IPECAMERA_DMA_ADDRESS);
+ } else {
+ err = pcilib_start_dma(vctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT);
+ if (err) {
+ ctx->rdma = PCILIB_DMA_ENGINE_INVALID;
+ pcilib_error("Failed to initialize C2S channel of IPECamera DMA Engine (%u)", IPECAMERA_DMA_ADDRESS);
+ }
+ }
+ }
+
+/*
+ if (!err) {
+ ctx->wdma = pcilib_find_dma_by_addr(vctx->pcilib, PCILIB_DMA_TO_DEVICE, IPECAMERA_DMA_ADDRESS);
+ if (ctx->wdma == PCILIB_DMA_ENGINE_INVALID) {
+ err = PCILIB_ERROR_NOTFOUND;
+ pcilib_error("The S2C channel of IPECamera DMA Engine (%u) is not found", IPECAMERA_DMA_ADDRESS);
+ } else {
+ err = pcilib_start_dma(vctx->pcilib, ctx->wdma, PCILIB_DMA_FLAGS_DEFAULT);
+ if (err) {
+ ctx->wdma = PCILIB_DMA_ENGINE_INVALID;
+ pcilib_error("Failed to initialize S2C channel of IPECamera DMA Engine (%u)", IPECAMERA_DMA_ADDRESS);
+ }
+ }
+ }
+*/
+
+/*
+ SET_REG(packet_len_reg, IPECAMERA_DMA_PACKET_LENGTH);
+*/
+
+ if (err) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ return err;
+ }
+
+ // Clean DMA
+ err = pcilib_skip_dma(vctx->pcilib, ctx->rdma);
+ if (err) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ pcilib_error("Can't start grabbing, device continuously writes unexpected data using DMA engine");
+ return err;
+ }
+
+ if (vctx->params.autostop.duration) {
+ gettimeofday(&ctx->autostop.timestamp, NULL);
+ ctx->autostop.timestamp.tv_usec += vctx->params.autostop.duration % 1000000;
+ if (ctx->autostop.timestamp.tv_usec > 999999) {
+ ctx->autostop.timestamp.tv_sec += 1 + vctx->params.autostop.duration / 1000000;
+ ctx->autostop.timestamp.tv_usec -= 1000000;
+ } else {
+ ctx->autostop.timestamp.tv_sec += vctx->params.autostop.duration / 1000000;
+ }
+ }
+
+ if (vctx->params.autostop.max_events) {
+ ctx->autostop.evid = vctx->params.autostop.max_events;
+ }
+
+ if (flags&PCILIB_EVENT_FLAG_PREPROCESS) {
+ ctx->n_preproc = pcilib_get_cpu_count();
+ switch (ctx->n_preproc) {
+ case 1: break;
+ case 2-3: ctx->n_preproc -= 1; break;
+ default: ctx->n_preproc -= 2; break;
+ }
+
+ ctx->preproc = (ipecamera_preprocessor_t*)malloc(ctx->n_preproc * sizeof(ipecamera_preprocessor_t));
+ if (!ctx->preproc) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ pcilib_error("Unable to allocate memory for preprocessor contexts");
+ return PCILIB_ERROR_MEMORY;
+ }
+
+ memset(ctx->preproc, 0, ctx->n_preproc * sizeof(ipecamera_preprocessor_t));
+
+ err = pthread_mutex_init(&ctx->preproc_mutex, NULL);
+ if (err) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ pcilib_error("Failed to initialize event mutex");
+ return PCILIB_ERROR_FAILED;
+ }
+ ctx->preproc_mutex_destroy = 1;
+
+
+ ctx->run_preprocessors = 1;
+ for (i = 0; i < ctx->n_preproc; i++) {
+ ctx->preproc[i].i = i;
+ ctx->preproc[i].ipecamera = ctx;
+ err = pthread_create(&ctx->preproc[i].thread, NULL, ipecamera_preproc_thread, ctx->preproc + i);
+ if (err) {
+ err = PCILIB_ERROR_FAILED;
+ break;
+ } else {
+ ctx->preproc[i].started = 1;
+ }
+ }
+
+ if (err) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ pcilib_error("Failed to schedule some of the preprocessor threads");
+ return err;
+ }
+ } else {
+ ctx->n_preproc = 0;
+ }
+
+ ctx->started = 1;
+ ctx->run_reader = 1;
+
+ pthread_attr_init(&attr);
+
+ if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) {
+ pcilib_warning("Can't schedule a real-time thread, you may consider running as root");
+ } else {
+ sched.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1; // Let 1 priority for something really critcial
+ pthread_attr_setschedparam(&attr, &sched);
+ }
+
+ if (pthread_create(&ctx->rthread, &attr, &ipecamera_reader_thread, (void*)ctx)) {
+ ctx->started = 0;
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ err = PCILIB_ERROR_FAILED;
+ }
+
+ pthread_attr_destroy(&attr);
+
+ return err;
+}
+
+
+int ipecamera_stop(pcilib_context_t *vctx, pcilib_event_flags_t flags) {
+ int i;
+ int err;
+ void *retcode;
+ ipecamera_t *ctx = (ipecamera_t*)vctx;
+
+ if (!ctx) {
+ pcilib_error("IPECamera imaging is not initialized");
+ return PCILIB_ERROR_NOTINITIALIZED;
+ }
+
+ if (flags&PCILIB_EVENT_FLAG_STOP_ONLY) {
+ ctx->run_reader = 0;
+ return 0;
+ }
+
+ if (ctx->started) {
+ ctx->run_reader = 0;
+ err = pthread_join(ctx->rthread, &retcode);
+ if (err) pcilib_error("Error joining the reader thread");
+ }
+
+ if (ctx->preproc) {
+ ctx->run_preprocessors = 0;
+
+ for (i = 0; i < ctx->n_preproc; i++) {
+ if (ctx->preproc[i].started) {
+ pthread_join(ctx->preproc[i].thread, &retcode);
+ ctx->preproc[i].started = 0;
+ }
+ }
+
+ if (ctx->preproc_mutex_destroy) {
+ pthread_mutex_destroy(&ctx->preproc_mutex);
+ ctx->preproc_mutex_destroy = 0;
+ }
+
+ free(ctx->preproc);
+ ctx->preproc = NULL;
+ }
+
+ if (ctx->frame_mutex_destroy) {
+ for (i = 0; i < ctx->frame_mutex_destroy; i++) {
+ pthread_rwlock_destroy(&ctx->frame[i].mutex);
+ }
+ ctx->frame_mutex_destroy = 0;
+ }
+
+ if (ctx->wdma != PCILIB_DMA_ENGINE_INVALID) {
+ pcilib_stop_dma(vctx->pcilib, ctx->wdma, PCILIB_DMA_FLAGS_DEFAULT);
+ ctx->wdma = PCILIB_DMA_ENGINE_INVALID;
+ }
+
+ if (ctx->rdma != PCILIB_DMA_ENGINE_INVALID) {
+ pcilib_stop_dma(vctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT);
+ ctx->rdma = PCILIB_DMA_ENGINE_INVALID;
+ }
+
+ if (ctx->ipedec) {
+ ufo_decoder_free(ctx->ipedec);
+ ctx->ipedec = NULL;
+ }
+
+ if (ctx->frame) {
+ free(ctx->frame);
+ ctx->frame = NULL;
+ }
+
+ if (ctx->cmask) {
+ free(ctx->cmask);
+ ctx->cmask = NULL;
+ }
+
+ if (ctx->image) {
+ free(ctx->image);
+ ctx->image = NULL;
+ }
+
+ if (ctx->buffer) {
+ free(ctx->buffer);
+ ctx->buffer = NULL;
+ }
+
+
+ memset(&ctx->autostop, 0, sizeof(ipecamera_autostop_t));
+
+ ctx->event_id = 0;
+ ctx->reported_id = 0;
+ ctx->buffer_pos = 0;
+ ctx->started = 0;
+
+ return 0;
+}
+
+
+int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
+ int err = 0;
+ pcilib_register_value_t value;
+
+ ipecamera_t *ctx = (ipecamera_t*)vctx;
+ pcilib_t *pcilib = vctx->pcilib;
+
+ if (!ctx) {
+ pcilib_error("IPECamera imaging is not initialized");
+ return PCILIB_ERROR_NOTINITIALIZED;
+ }
+
+ SET_REG(control_reg, IPECAMERA_FRAME_REQUEST|IPECAMERA_READOUT_FLAG);
+ usleep(IPECAMERA_WAIT_FRAME_RCVD_TIME);
+ CHECK_REG(status_reg, IPECAMERA_EXPECTED_STATUS);
+ SET_REG(control_reg, IPECAMERA_IDLE|IPECAMERA_READOUT_FLAG);
+
+
+ // DS: Just measure when next trigger is allowed instead and wait in the beginning
+ usleep(IPECAMERA_NEXT_FRAME_DELAY); // minimum delay between End Of Readout and next Frame Req
+
+ return 0;
+}
diff --git a/ipecamera/ipecamera.h b/ipecamera/ipecamera.h
index 3abcf25..19c123b 100644
--- a/ipecamera/ipecamera.h
+++ b/ipecamera/ipecamera.h
@@ -4,9 +4,9 @@
typedef struct ipecamera_s ipecamera_t;
typedef struct {
- int bpp; /*<< Bits per pixel (8, 16, or 32) as returned by IPECAMERA_IMAGE_DATA */
- int real_bpp; /*<< Bits per pixel as returned by camera and IPECAMERA_PACKED_IMAGE */
- int width, height;
+ unsigned int bpp; /*<< Bits per pixel (8, 16, or 32) as returned by IPECAMERA_IMAGE_DATA */
+ unsigned int real_bpp; /*<< Bits per pixel as returned by camera and IPECAMERA_PACKED_IMAGE */
+ unsigned int width, height;
} ipecamera_image_dimensions_t;
typedef enum {
@@ -25,8 +25,9 @@ typedef uint16_t ipecamera_pixel_t;
typedef struct {
pcilib_event_info_t info;
- size_t raw_size; /**< Indicates the actual size of raw data */
int image_ready; /**< Indicates if image data is parsed */
+ int image_broken; /**< Unlike the info.flags this is bound to the reconstructed image (i.e. is not updated on rawdata overwrite) */
+ size_t raw_size; /**< Indicates the actual size of raw data */
} ipecamera_event_info_t;
int ipecamera_set_buffer_size(ipecamera_t *ctx, int size);
diff --git a/ipecamera/model.c b/ipecamera/model.c
index ddf9ee6..e60561b 100644
--- a/ipecamera/model.c
+++ b/ipecamera/model.c
@@ -26,7 +26,7 @@
int ipecamera_read(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, pcilib_register_value_t *value) {
uint32_t val, tmp[4];
char *wr, *rd;
- struct timeval start, cur;
+ struct timeval start;//, cur;
int retries = RETRIES;
assert(addr < 128);
@@ -116,7 +116,7 @@ retry:
int ipecamera_write(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, pcilib_register_value_t value) {
uint32_t val, tmp[4];
char *wr, *rd;
- struct timeval start, cur;
+ struct timeval start;//, cur;
int retries = RETRIES;
assert(addr < 128);
diff --git a/ipecamera/model.h b/ipecamera/model.h
index b9c3b32..4a0fc8c 100644
--- a/ipecamera/model.h
+++ b/ipecamera/model.h
@@ -4,7 +4,7 @@
#include <stdio.h>
#include "pcilib.h"
-#include "image.h"
+#include "public.h"
//#define IPECAMERA_DEBUG
@@ -126,7 +126,7 @@ pcilib_event_api_description_t ipecamera_image_api = {
ipecamera_trigger,
ipecamera_stream,
- NULL, //ipecamera_next_event,
+ ipecamera_next_event,
ipecamera_get,
ipecamera_return,
ipecamera_init_dma
diff --git a/ipecamera/private.h b/ipecamera/private.h
new file mode 100644
index 0000000..b583f38
--- /dev/null
+++ b/ipecamera/private.h
@@ -0,0 +1,121 @@
+#ifndef _IPECAMERA_PRIVATE_H
+#define _IPECAMERA_PRIVATE_H
+
+#include "ipecamera.h"
+
+#define IPECAMERA_BUG_EXTRA_DATA
+#define IPECAMERA_BUG_MULTIFRAME_PACKETS
+#define IPECAMERA_BUG_INCOMPLETE_PACKETS
+
+#define IPECAMERA_DEFAULT_BUFFER_SIZE 64 //**< should be power of 2 */
+#define IPECAMERA_RESERVE_BUFFERS 2 //**< Return Frame is Lost error, if requested frame will be overwritten after specified number of frames
+#define IPECAMERA_SLEEP_TIME 250000 //**< Michele thinks 250 should be enough, but reset failing in this case */
+#define IPECAMERA_NEXT_FRAME_DELAY 1000 //**< Michele requires 30000 to sync between End Of Readout and next Frame Req */
+#define IPECAMERA_WAIT_FRAME_RCVD_TIME 0 //**< by Uros ,wait 6 ms */
+#define IPECAMERA_NOFRAME_SLEEP 100
+#define IPECAMERA_NOFRAME_PREPROC_SLEEP 100
+
+#define IPECAMERA_MAX_LINES 1088
+#define IPECAMERA_EXPECTED_STATUS 0x08409FFFF
+#define IPECAMERA_END_OF_SEQUENCE 0x1F001001
+
+#define IPECAMERA_MAX_CHANNELS 16
+#define IPECAMERA_PIXELS_PER_CHANNEL 128
+#define IPECAMERA_WIDTH (IPECAMERA_MAX_CHANNELS * IPECAMERA_PIXELS_PER_CHANNEL)
+
+#define IPECAMERA_FRAME_REQUEST 0x1E9
+#define IPECAMERA_READOUT_FLAG 0x200
+#define IPECAMERA_READOUT 0x3E1
+#define IPECAMERA_IDLE 0x1E1
+#define IPECAMERA_START_INTERNAL_STIMULI 0x1F1
+
+
+typedef uint32_t ipecamera_payload_t;
+
+typedef struct {
+ pcilib_event_id_t evid;
+ struct timeval timestamp;
+} ipecamera_autostop_t;
+
+typedef struct {
+ size_t i;
+ pthread_t thread;
+ ipecamera_t *ipecamera;
+
+ int started; /**< flag indicating that join & cleanup is required */
+} ipecamera_preprocessor_t;
+
+
+typedef struct {
+ ipecamera_event_info_t event; /**< this structure is overwritten by the reader thread, we need a copy */
+ pthread_rwlock_t mutex; /**< this mutex protects reconstructed buffers only, the raw data, event_info, etc. will be overwritten by reader thread anyway */
+} ipecamera_frame_t;
+
+struct ipecamera_s {
+ pcilib_context_t event;
+ ufo_decoder ipedec;
+
+ char *data;
+ ipecamera_pixel_t *image;
+ size_t size;
+
+ pcilib_event_callback_t cb;
+ void *cb_user;
+
+ pcilib_event_id_t event_id;
+ pcilib_event_id_t preproc_id;
+ pcilib_event_id_t reported_id;
+
+ pcilib_dma_engine_t rdma, wdma;
+
+ pcilib_register_t packet_len_reg;
+ pcilib_register_t control_reg, status_reg;
+ pcilib_register_t start_reg, end_reg;
+ pcilib_register_t n_lines_reg;
+ uint16_t line_reg;
+ pcilib_register_t exposure_reg;
+ pcilib_register_t flip_reg;
+
+ int started; /**< Camera is in grabbing mode (start function is called) */
+ int streaming; /**< Camera is in streaming mode (we are within stream call) */
+ int parse_data; /**< Indicates if some processing of the data is required, otherwise only rawdata_callback will be called */
+
+ int run_reader; /**< Instructs the reader thread to stop processing */
+ int run_streamer; /**< Indicates request to stop streaming events and can be set by reader_thread upon exit or by user request */
+ int run_preprocessors; /**< Instructs preprocessors to exit */
+
+ ipecamera_autostop_t autostop;
+
+ struct timeval autostop_time;
+
+ size_t buffer_size; /**< How many images to store */
+ size_t buffer_pos; /**< Current image offset in the buffer, due to synchronization reasons should not be used outside of reader_thread */
+ size_t cur_size; /**< Already written part of data in bytes */
+ size_t raw_size; /**< Size of raw data in bytes */
+ size_t full_size; /**< Size of raw data including the padding */
+ size_t padded_size; /**< Size of buffer for raw data, including the padding for performance */
+
+ size_t image_size; /**< Size of a single image in bytes */
+
+ int width, height;
+
+
+// void *raw_buffer;
+ void *buffer;
+ ipecamera_change_mask_t *cmask;
+ ipecamera_frame_t *frame;
+
+
+ ipecamera_image_dimensions_t dim;
+
+ pthread_t rthread;
+
+ size_t n_preproc;
+ ipecamera_preprocessor_t *preproc;
+ pthread_mutex_t preproc_mutex;
+
+ int preproc_mutex_destroy;
+ int frame_mutex_destroy;
+};
+
+#endif /* _IPECAMERA_PRIVATE_H */
diff --git a/ipecamera/image.h b/ipecamera/public.h
index c311b4d..b745d6c 100644
--- a/ipecamera/image.h
+++ b/ipecamera/public.h
@@ -1,25 +1,25 @@
-#ifndef _IPECAMERA_IMAGE_H
-#define _IPECAMERA_IMAGE_H
+#ifndef _IPECAMERA_PUBLIC_H
+#define _IPECAMERA_PUBLIC_H
#include <stdio.h>
#include "ipecamera.h"
#include "pcilib.h"
+
pcilib_context_t *ipecamera_init(pcilib_t *pcilib);
void ipecamera_free(pcilib_context_t *ctx);
+pcilib_dma_context_t *ipecamera_init_dma(pcilib_context_t *ctx);
+
int ipecamera_reset(pcilib_context_t *ctx);
int ipecamera_start(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags);
int ipecamera_stop(pcilib_context_t *ctx, pcilib_event_flags_t flags);
int ipecamera_trigger(pcilib_context_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data);
int ipecamera_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, void *user);
-//pcilib_event_id_t ipecamera_next_event(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_timeout_t timeout);
-
-void* ipecamera_get(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size, void *buf);
-int ipecamera_return(pcilib_context_t *ctx, pcilib_event_id_t event_id, void *data);
-
-pcilib_dma_context_t *ipecamera_init_dma(pcilib_context_t *ctx);
+int ipecamera_next_event(pcilib_context_t *vctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info);
+int ipecamera_get(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size, void **buf);
+int ipecamera_return(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data);
-#endif /* _IPECAMERA_IMAGE_H */
+#endif /* _IPECAMERA_PUBLIC_H */
diff --git a/ipecamera/reader.c b/ipecamera/reader.c
new file mode 100644
index 0000000..f02df0f
--- /dev/null
+++ b/ipecamera/reader.c
@@ -0,0 +1,170 @@
+#define _IPECAMERA_IMAGE_C
+#define _BSD_SOURCE
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <assert.h>
+
+#include <ufodecode.h>
+
+#include "../tools.h"
+#include "../error.h"
+
+#include "pcilib.h"
+#include "private.h"
+#include "reader.h"
+
+static inline int ipecamera_new_frame(ipecamera_t *ctx) {
+ ctx->frame[ctx->buffer_pos].event.raw_size = ctx->cur_size;
+
+ if (ctx->cur_size < ctx->raw_size) ctx->frame[ctx->buffer_pos].event.info.flags |= PCILIB_EVENT_INFO_FLAG_BROKEN;
+
+ ctx->buffer_pos = (++ctx->event_id) % ctx->buffer_size;
+ ctx->cur_size = 0;
+
+ ctx->frame[ctx->buffer_pos].event.info.type = PCILIB_EVENT0;
+ ctx->frame[ctx->buffer_pos].event.info.flags = 0;
+ ctx->frame[ctx->buffer_pos].event.image_ready = 0;
+
+ if ((ctx->event_id == ctx->autostop.evid)&&(ctx->event_id)) {
+ ctx->run_reader = 0;
+ return 1;
+ }
+
+ if (pcilib_check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) {
+ ctx->run_reader = 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+static uint32_t frame_magic[6] = { 0x51111111, 0x52222222, 0x53333333, 0x54444444, 0x55555555, 0x56666666 };
+
+static int ipecamera_data_callback(void *user, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
+ int res;
+ int eof = 0;
+
+#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS
+ size_t extra_data = 0;
+#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */
+
+ ipecamera_t *ctx = (ipecamera_t*)user;
+
+ if (!ctx->cur_size) {
+#if defined(IPECAMERA_BUG_INCOMPLETE_PACKETS)||defined(IPECAMERA_BUG_MULTIFRAME_PACKETS)
+ size_t startpos;
+ for (startpos = 0; (startpos + 8) < bufsize; startpos++) {
+ if (!memcmp(buf + startpos, frame_magic, sizeof(frame_magic))) break;
+ }
+
+ if (startpos) {
+ buf += startpos;
+ bufsize -= startpos;
+ }
+#endif /* IPECAMERA_BUG_INCOMPLETE_PACKETS */
+
+ if ((bufsize >= 8)&&(!memcmp(buf, frame_magic, sizeof(frame_magic)))) {
+/*
+ // Not implemented in hardware yet
+ ctx->frame[ctx->buffer_pos].event.info.seqnum = ((uint32_t*)buf)[6] & 0xF0000000;
+ ctx->frame[ctx->buffer_pos].event.info.offset = ((uint32_t*)buf)[7] & 0xF0000000;
+*/
+ gettimeofday(&ctx->frame[ctx->buffer_pos].event.info.timestamp, NULL);
+ } else {
+// pcilib_warning("Frame magic is not found, ignoring broken data...");
+ return PCILIB_STREAMING_CONTINUE;
+ }
+ }
+
+#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS
+ if (ctx->cur_size + bufsize > ctx->raw_size) {
+ size_t need;
+
+ for (need = ctx->raw_size - ctx->cur_size; need < bufsize; need += sizeof(uint32_t)) {
+ if (*(uint32_t*)(buf + need) == frame_magic[0]) break;
+ }
+
+ if (need < bufsize) {
+ extra_data = bufsize - need;
+ //bufsize = need;
+ eof = 1;
+ }
+
+ // just rip of padding
+ bufsize = ctx->raw_size - ctx->cur_size;
+ }
+#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */
+
+ if (ctx->parse_data) {
+ if (ctx->cur_size + bufsize > ctx->full_size) {
+ pcilib_error("Unexpected event data, we are expecting at maximum (%zu) bytes, but (%zu) already read", ctx->full_size, ctx->cur_size + bufsize);
+ return -PCILIB_ERROR_TOOBIG;
+ }
+
+ memcpy(ctx->buffer + ctx->buffer_pos * ctx->padded_size + ctx->cur_size, buf, bufsize);
+ }
+
+ ctx->cur_size += bufsize;
+// printf("%i: %i %i\n", ctx->buffer_pos, ctx->cur_size, bufsize);
+
+ if (ctx->cur_size >= ctx->full_size) eof = 1;
+
+ if (ctx->event.params.rawdata.callback) {
+ res = ctx->event.params.rawdata.callback(ctx->event_id, (pcilib_event_info_t*)(ctx->frame + ctx->buffer_pos), (eof?PCILIB_EVENT_FLAG_EOF:PCILIB_EVENT_FLAGS_DEFAULT), bufsize, buf, ctx->event.params.rawdata.user);
+ if (res <= 0) {
+ if (res < 0) return res;
+ ctx->run_reader = 0;
+ }
+ }
+
+ if (eof) {
+ if (ipecamera_new_frame(ctx)) {
+ return PCILIB_STREAMING_STOP;
+ }
+
+#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS
+ if (extra_data) {
+ return ipecamera_data_callback(user, flags, extra_data, buf + bufsize);
+ }
+#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */
+ }
+
+ return PCILIB_STREAMING_REQ_FRAGMENT;
+}
+
+void *ipecamera_reader_thread(void *user) {
+ int err;
+ ipecamera_t *ctx = (ipecamera_t*)user;
+
+ while (ctx->run_reader) {
+ err = pcilib_stream_dma(ctx->event.pcilib, ctx->rdma, 0, 0, PCILIB_DMA_FLAG_MULTIPACKET, PCILIB_DMA_TIMEOUT, &ipecamera_data_callback, user);
+ if (err) {
+ if (err == PCILIB_ERROR_TIMEOUT) {
+ if (ctx->cur_size > ctx->raw_size) ipecamera_new_frame(ctx);
+#ifdef IPECAMERA_BUG_INCOMPLETE_PACKETS
+ else if (ctx->cur_size > 0) ipecamera_new_frame(ctx);
+#endif /* IPECAMERA_BUG_INCOMPLETE_PACKETS */
+ if (pcilib_check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) {
+ ctx->run_reader = 0;
+ break;
+ }
+ usleep(IPECAMERA_NOFRAME_SLEEP);
+ } else pcilib_error("DMA error while reading IPECamera frames, error: %i", err);
+ } else printf("no error\n");
+
+ //usleep(1000);
+ }
+
+ ctx->run_streamer = 0;
+
+ if (ctx->cur_size)
+ pcilib_error("partialy read frame after stop signal, %zu bytes in the buffer", ctx->cur_size);
+
+ return NULL;
+}
diff --git a/ipecamera/reader.h b/ipecamera/reader.h
new file mode 100644
index 0000000..738d742
--- /dev/null
+++ b/ipecamera/reader.h
@@ -0,0 +1,6 @@
+#ifndef _IPECAMERA_READER_H
+#define _IPECAMERA_READER_H
+
+void *ipecamera_reader_thread(void *user);
+
+#endif /* _IPECAMERA_READER_H */