summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2011-12-08 03:47:23 +0100
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2011-12-08 03:47:23 +0100
commit869ed99dbc3a645fee6de36e97e1e12127068f10 (patch)
treefa4a4e7ef977a3d3621ff5e96fb664e6fbc9e6fe
parentddc77c1e819eee03a13efff4a9aa3161485f3f1f (diff)
downloadipecamera-869ed99dbc3a645fee6de36e97e1e12127068f10.tar.gz
ipecamera-869ed99dbc3a645fee6de36e97e1e12127068f10.tar.bz2
ipecamera-869ed99dbc3a645fee6de36e97e1e12127068f10.tar.xz
ipecamera-869ed99dbc3a645fee6de36e97e1e12127068f10.zip
new event architecture, first trial
-rw-r--r--Makefile7
-rw-r--r--NOTES42
-rw-r--r--cli.c274
-rw-r--r--dma.c13
-rw-r--r--dma/nwl_engine.c24
-rw-r--r--error.h3
-rw-r--r--event.c196
-rw-r--r--event.h34
-rw-r--r--ipecamera/image.c783
-rw-r--r--ipecamera/image.h11
-rw-r--r--ipecamera/ipecamera.h3
-rw-r--r--ipecamera/model.h16
-rw-r--r--pci.c4
-rw-r--r--pci.h6
-rw-r--r--pcilib.h91
-rw-r--r--pcitool/sysinfo.c173
-rw-r--r--pcitool/sysinfo.h7
-rwxr-xr-xtests/grab.sh2
-rw-r--r--tools.c39
-rw-r--r--tools.h5
20 files changed, 1215 insertions, 518 deletions
diff --git a/Makefile b/Makefile
index 0640194..394328f 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,8 @@ BINARIES += pci
INCDIR += ./
LDINC += $(addprefix -L ,$(LIBDIR))
-LDFLAGS +=
+LDFLAGS += -pthread
+CFLAGS += -pthread
DESTDIR ?= /usr/local
all: $(BINARIES)
@@ -14,13 +15,13 @@ include common.mk
###############################################################
# Target definitions
-OBJECTS = pci.o register.o kmem.o irq.o dma.o event.o default.o tools.o dma/nwl.o dma/nwl_register.o dma/nwl_irq.o dma/nwl_engine.o dma/nwl_loopback.o ipecamera/model.o ipecamera/image.o
+OBJECTS = pci.o pcitool/sysinfo.o register.o kmem.o irq.o dma.o event.o default.o tools.o dma/nwl.o dma/nwl_register.o dma/nwl_irq.o dma/nwl_engine.o dma/nwl_loopback.o ipecamera/model.o ipecamera/image.o
libpcilib.so: $(OBJECTS)
echo -e "LD \t$@"
$(Q)$(CC) $(LDINC) $(LDFLAGS) $(CFLAGS) -shared -o $@ $(OBJECTS)
-pci: cli.o libpcilib.so
+pci: cli.o pcitool/sysinfo.o libpcilib.so
echo -e "LD \t$@"
$(Q)$(CC) $(LDINC) $(LDFLAGS) $(CFLAGS) -L. -lpcilib -o $@ $<
diff --git a/NOTES b/NOTES
index 94e4e95..36411d3 100644
--- a/NOTES
+++ b/NOTES
@@ -157,19 +157,47 @@ exact read: read exactly specified number of bytes (should be
error should be returned)
ignore packets: autoterminate each buffer, depends on engine
configuration
-autogrow: automatic memory allocation, only through streaming
+
+ To handle differnt cases, the value returned by callback function instructs
+the DMA library how long to wait for the next data to appear before timing
+out. The following variants are possible:
+terminate: just bail out
+check: no timeout, just check if there is data, otherwise
+ terminate
+timeout: standard DMA timeout, normaly used while receiving
+ fragments of packet: in this case it is expected
+ that device has already prepared data and only
+ the performance of DMA engine limits transfer speed
+wait: wait until the data is prepared by the device, this
+ timeout is specified as argument to the dma_stream
+ function (standard DMA timeout is used by default)
first | new_pkt | bufer
--------------------------
-standard wait | term | wait
-multiple packets wait | check | wait - DMA_READ_FLAG_MULTIPACKET
-waiting multipacket wait | wait | wait - DMA_READ_FLAG_WAIT
-exact wait | wait/term | wait - limited by size parameter
-ignore packets wait | check | check - just autoterminated
-autogrow
+standard wait | term | timeout
+multiple packets wait | check | timeout - DMA_READ_FLAG_MULTIPACKET
+waiting multipacket wait | wait | timeout - DMA_READ_FLAG_WAIT
+exact wait | wait/term | timeout - limited by size parameter
+ignore packets wait | wait/check| wait/check - just autoterminated
Shall we do a special handling in case of overflow?
+
+Buffering
+=========
+ The DMA addresses are limited to 32 bits (~4GB for everything). This means we
+ can't really use DMA pages are sole buffers. Therefore,
+ 1. In streaming mode a second thread will be spawned copying the data from the
+ DMA pages into the allocated buffers. On duration expiration this thread
+ will be stopped but processing will continue until all copyied data is
+ passed to the callbacks.
+ 2. In synchronous mode, a single event will be extracted from the the DMA
+ memory.
+
+ - Actually, we can make another in-module buffering. But this hopefully can
+ be avoided.
+
+
Register Access Synchronization
===============================
We need to serialize access to the registers by the different running
diff --git a/cli.c b/cli.c
index 04a31e1..fdfc78f 100644
--- a/cli.c
+++ b/cli.c
@@ -16,9 +16,12 @@
#include <arpa/inet.h>
#include <sys/types.h>
#include <dirent.h>
+#include <pthread.h>
#include <getopt.h>
+#include "pcitool/sysinfo.h"
+
//#include "pci.h"
#include "tools.h"
#include "kernel.h"
@@ -46,6 +49,11 @@
typedef uint8_t access_t;
typedef enum {
+ GRAB_MODE_GRAB = 1,
+ GRAB_MODE_TRIGGER = 2
+} GRAB_MODE;
+
+typedef enum {
MODE_INVALID,
MODE_INFO,
MODE_LIST,
@@ -78,6 +86,19 @@ typedef enum {
FLAG_WAIT = 2
} FLAGS;
+
+typedef enum {
+ FORMAT_RAW,
+ FORMAT_HEADER,
+ FORMAT_RINGFS
+} FORMAT;
+
+typedef enum {
+ PARTITION_UNKNOWN,
+ PARTITION_RAW,
+ PARTITION_EXT4
+} PARTITION;
+
typedef enum {
OPT_DEVICE = 'd',
OPT_MODEL = 'm',
@@ -96,6 +117,14 @@ typedef enum {
OPT_HELP = 'h',
OPT_RESET = 128,
OPT_BENCHMARK,
+ OPT_TRIGGER,
+ OPT_DATA_TYPE,
+ OPT_EVENT,
+ OPT_TRIGGER_RATE,
+ OPT_TRIGGER_TIME,
+ OPT_RUN_TIME,
+ OPT_FORMAT,
+ OPT_BUFFER,
OPT_LIST_DMA,
OPT_LIST_DMA_BUFFERS,
OPT_READ_DMA_BUFFER,
@@ -128,6 +157,14 @@ static struct option long_options[] = {
{"read", optional_argument, 0, OPT_READ },
{"write", optional_argument, 0, OPT_WRITE },
{"grab", optional_argument, 0, OPT_GRAB },
+ {"trigger", optional_argument, 0, OPT_TRIGGER },
+ {"data", required_argument, 0, OPT_DATA_TYPE },
+ {"event", required_argument, 0, OPT_EVENT },
+ {"run-time", required_argument, 0, OPT_RUN_TIME },
+ {"trigger-rate", required_argument, 0, OPT_TRIGGER_RATE },
+ {"trigger-time", required_argument, 0, OPT_TRIGGER_TIME },
+ {"format", required_argument, 0, OPT_FORMAT },
+ {"buffer", optional_argument, 0, OPT_BUFFER },
{"start-dma", required_argument, 0, OPT_START_DMA },
{"stop-dma", optional_argument, 0, OPT_STOP_DMA },
{"list-dma-engines", no_argument, 0, OPT_LIST_DMA },
@@ -168,11 +205,14 @@ void Usage(int argc, char *argv[], const char *format, ...) {
" -l[l] - List (detailed) Data Banks & Registers\n"
" -r <addr|reg|dmaX> - Read Data/Register\n"
" -w <addr|reg|dmaX> - Write Data/Register\n"
-" -g [event] - Grab Event\n"
" --benchmark <barX|dmaX> - Performance Evaluation\n"
" --reset - Reset board\n"
" --help - Help message\n"
"\n"
+" Event Modes:\n"
+" --trigger [event] - Trigger Events\n"
+" -g [event] - Grab Events\n"
+"\n"
" DMA Modes:\n"
" --start-dma <num>[r|w] - Start specified DMA engine\n"
" --stop-dma [num[r|w]] - Stop specified engine or DMA subsystem\n"
@@ -183,7 +223,7 @@ void Usage(int argc, char *argv[], const char *format, ...) {
"\n"
" Kernel Modes:\n"
" --list-kernel-memory - List kernel buffers\n"
-" --read-kernel-memory <blk> - Read the specified block of the kernel memory,\n"
+" --read-kernel-memory <blk> - Read the specified block of the kernel memory\n"
" block is specified as: use:block_number\n"
" --free-kernel-memory <use> - Cleans lost kernel space buffers (DANGEROUS)\n"
" dma - Remove all buffers allocated by DMA subsystem\n"
@@ -203,6 +243,19 @@ void Usage(int argc, char *argv[], const char *format, ...) {
" -o <file> - Append output to file (default: stdout)\n"
" -t <timeout> - Timeout in microseconds\n"
"\n"
+" Event Options:\n"
+" --event <evt> - Specifies event for trigger and grab modes\n"
+" --data <type> - Data type to request for the events\n"
+" --run-time <us> - Grab/trigger events during the specified time\n"
+" --trigger-rate <tps> - Generate tps triggers per second\n"
+" --trigger-time <us> - Specifies delay between triggers in microseconds\n"
+" -s <num|unlimited> - Number of events to grab and trigger\n"
+" --format [type] - Specifies how event data should be stored\n"
+" raw - Just write all events sequentially\n"
+" add_header - Prefix events with 256 bit header\n"
+" ringfs - Write to RingFS\n"
+" --buffer [size] - Request data buffering, size in MB\n"
+"\n"
" DMA Options:\n"
" --multipacket - Read multiple packets\n"
" --wait - Wait until data arrives\n"
@@ -237,10 +290,11 @@ void Silence(const char *format, ...) {
}
void List(pcilib_t *handle, pcilib_model_description_t *model_info, const char *bank, int details) {
- int i;
+ int i,j;
pcilib_register_bank_description_t *banks;
pcilib_register_description_t *registers;
pcilib_event_description_t *events;
+ pcilib_event_data_type_description_t *types;
const pcilib_board_info_t *board_info = pcilib_get_board_info(handle);
const pcilib_dma_info_t *dma_info = pcilib_get_dma_info(handle);
@@ -358,7 +412,10 @@ void List(pcilib_t *handle, pcilib_model_description_t *model_info, const char *
}
if (bank == (char*)-1) events = NULL;
- else events = model_info->events;
+ else {
+ events = model_info->events;
+ types = model_info->data_types;
+ }
if (events) {
printf("Events: \n");
@@ -367,6 +424,17 @@ void List(pcilib_t *handle, pcilib_model_description_t *model_info, const char *
if ((events[i].description)&&(events[i].description[0])) {
printf(": %s", events[i].description);
}
+
+ if (types) {
+ for (j = 0; types[j].name; j++) {
+ if (types[j].evid & events[i].evid) {
+ printf("\n %s", types[j].name);
+ if ((types[j].description)&&(types[j].description[0])) {
+ printf(": %s", types[j].description);
+ }
+ }
+ }
+ }
}
printf("\n");
}
@@ -998,18 +1066,29 @@ int WriteRegister(pcilib_t *handle, pcilib_model_description_t *model_info, cons
return 0;
}
-int Grab(pcilib_t *handle, const char *event, FILE *o) {
- int err;
+typedef struct {
+ pcilib_t *handle;
+ pcilib_event_t event;
+ pcilib_event_data_type_t data;
+ FILE *output;
+
+ size_t run_time;
+ size_t trigger_time;
- void *data = NULL;
+ int run_flag;
+} GRABContext;
+
+int GrabCallback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user) {
+/* int err;
+ void *data;
size_t size, written;
- // ignoring event for now
-
- err = pcilib_grab(handle, PCILIB_EVENTS_ALL, &size, &data, PCILIB_TIMEOUT_TRIGGER);
- if (err) {
- Error("Grabbing event is failed");
- }
+ GRABContext *ctx = (GRABContext*)user;
+ pcilib_t *handle = ctx->handle;
+ FILE *o = ctx->output;
+
+ data = pcilib_get_data(handle, ctx->event, ctx->data, &size);
+ if (!data) Error("Internal Error: No data is provided to event callback");
if (o) printf("Writting %zu bytes into file...\n", size);
else o = stdout;
@@ -1020,10 +1099,75 @@ int Grab(pcilib_t *handle, const char *event, FILE *o) {
else Error("Write failed");
}
- return 0;
+ pcilib_return_data(handle, ctx->event, data);
+*/
+
+ printf("data callback: %lu\n", event_id);
}
+int raw_data(pcilib_event_id_t event_id, pcilib_event_info_t *info, pcilib_event_flags_t flags, size_t size, void *data, void *user) {
+// printf("%i\n", event_id);
+}
+void *Trigger(void *user) {
+ GRABContext *ctx = (GRABContext*)user;
+
+ pcilib_trigger(ctx->handle, PCILIB_EVENT0, 0, NULL);
+ usleep(3000);
+ pcilib_trigger(ctx->handle, PCILIB_EVENT0, 0, NULL);
+
+ return NULL;
+}
+
+int TriggerAndGrab(pcilib_t *handle, GRAB_MODE grab_mode, const char *event, const char *data_type, size_t num, size_t run_time, size_t trigger_time, PARTITION partition, FORMAT format, size_t buffer_size, FILE *ofile) {
+ int err;
+ GRABContext ctx;
+ void *data = NULL;
+ size_t size, written;
+
+ pthread_t trigger_thread;
+
+ ctx.handle = handle;
+ ctx.output = ofile;
+ ctx.event = PCILIB_EVENT0;
+ ctx.run_time = run_time;
+ ctx.trigger_time = trigger_time;
+
+ ctx.run_flag = 1;
+
+ // ignoring event for now
+ pcilib_configure_autostop(handle, 2, 1000000);//PCILIB_TIMEOUT_TRIGGER);
+ pcilib_configure_rawdata_callback(handle, &raw_data, NULL);
+
+ err = pcilib_start(handle, PCILIB_EVENTS_ALL, PCILIB_EVENT_FLAGS_DEFAULT);
+ if (err) Error("Failed to start event engine, error %i", err);
+
+ if (pthread_create(&trigger_thread, NULL, Trigger, (void*)&ctx))
+ Error("Error starting trigger thread");
+
+// sleep(1);
+ err = pcilib_stream(handle, &GrabCallback, &ctx);
+ if (err) Error("Error streaming events, error %i", err);
+
+ pcilib_stop(handle, PCILIB_EVENT_FLAGS_DEFAULT);
+
+/*
+ err = pcilib_grab(handle, PCILIB_EVENTS_ALL, &size, &data, PCILIB_TIMEOUT_TRIGGER);
+ if (err) {
+ Error("Grabbing event is failed");
+ }
+*/
+ ctx.run_flag = 0;
+ pthread_join(trigger_thread, NULL);
+
+ return 0;
+}
+
+/*
+int Trigger(pcilib_t *handle, const char *event, size_t triggers, size_t run_time, size_t trigger_time) {
+ //
+}
+*/
int StartStopDMA(pcilib_t *handle, pcilib_model_description_t *model_info, pcilib_dma_engine_addr_t dma, pcilib_dma_direction_t dma_direction, int start) {
int err;
pcilib_dma_engine_t dmaid;
@@ -1479,8 +1623,10 @@ int main(int argc, char **argv) {
int i;
long itmp;
unsigned long utmp;
+ size_t ztmp;
unsigned char c;
+ const char *stmp;
const char *num_offset;
int details = 0;
@@ -1490,6 +1636,12 @@ int main(int argc, char **argv) {
pcilib_model_t model = PCILIB_MODEL_DETECT;
pcilib_model_description_t *model_info;
MODE mode = MODE_INVALID;
+ GRAB_MODE grab_mode = 0;
+ size_t trigger_time = 0;
+ size_t run_time = 0;
+ size_t buffer = 0;
+ FORMAT format = FORMAT_RAW;
+ PARTITION partition = PARTITION_UNKNOWN;
FLAGS flags = 0;
const char *type = NULL;
ACCESS_MODE amode = ACCESS_BAR;
@@ -1500,6 +1652,7 @@ int main(int argc, char **argv) {
const char *bank = NULL;
char **data = NULL;
const char *event = NULL;
+ const char *data_type = NULL;
const char *dma_channel = NULL;
const char *use = NULL;
pcilib_kmem_use_t use_id;
@@ -1568,11 +1721,34 @@ int main(int argc, char **argv) {
else if ((optind < argc)&&(argv[optind][0] != '-')) addr = argv[optind++];
break;
case OPT_GRAB:
- if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
+ if ((mode != MODE_INVALID)&&((mode != MODE_GRAB)||(grab_mode&GRAB_MODE_GRAB))) Usage(argc, argv, "Multiple operations are not supported");
mode = MODE_GRAB;
- if (optarg) event = optarg;
- else if ((optind < argc)&&(argv[optind][0] != '-')) event = argv[optind++];
+ grab_mode |= GRAB_MODE_GRAB;
+
+ stmp = NULL;
+ if (optarg) stmp = optarg;
+ else if ((optind < argc)&&(argv[optind][0] != '-')) stmp = argv[optind++];
+
+ if (stmp) {
+ if ((event)&&(strcasecmp(stmp,event))) Usage(argc, argv, "Redefinition of considered event");
+ event = stmp;
+ }
+ break;
+ case OPT_TRIGGER:
+ if ((mode != MODE_INVALID)&&((mode != MODE_GRAB)||(grab_mode&GRAB_MODE_TRIGGER))) Usage(argc, argv, "Multiple operations are not supported");
+
+ mode = MODE_GRAB;
+ grab_mode |= GRAB_MODE_TRIGGER;
+
+ stmp = NULL;
+ if (optarg) stmp = optarg;
+ else if ((optind < argc)&&(argv[optind][0] != '-')) stmp = argv[optind++];
+
+ if (stmp) {
+ if ((event)&&(strcasecmp(stmp,event))) Usage(argc, argv, "Redefinition of considered event");
+ event = stmp;
+ }
break;
case OPT_LIST_DMA:
if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
@@ -1708,7 +1884,11 @@ int main(int argc, char **argv) {
break;
case OPT_SIZE:
if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &size) != 1))
- Usage(argc, argv, "Invalid size is specified (%s)", optarg);
+ if (strcasecmp(optarg, "unlimited"))
+ Usage(argc, argv, "Invalid size is specified (%s)", optarg);
+ else
+ size = (size_t)-1;
+
size_set = 1;
break;
case OPT_ENDIANESS:
@@ -1733,6 +1913,47 @@ int main(int argc, char **argv) {
if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &iterations) != 1))
Usage(argc, argv, "Invalid number of iterations is specified (%s)", optarg);
break;
+ case OPT_EVENT:
+ event = optarg;
+ break;
+ case OPT_DATA_TYPE:
+ data_type = optarg;
+ break;
+ case OPT_RUN_TIME:
+ if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &run_time) != 1))
+ Usage(argc, argv, "Invalid timeout is specified (%s)", optarg);
+ break;
+ case OPT_TRIGGER_TIME:
+ if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &trigger_time) != 1))
+ Usage(argc, argv, "Invalid trigger-time is specified (%s)", optarg);
+ break;
+ case OPT_TRIGGER_RATE:
+ if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &ztmp) != 1))
+ Usage(argc, argv, "Invalid trigger-rate is specified (%s)", optarg);
+
+ trigger_time = 1000000 / ztmp + (1000000 % ztmp)?1:0;
+ break;
+ case OPT_BUFFER:
+ if (optarg) num_offset = optarg;
+ else if ((optind < argc)&&(argv[optind][0] != '-')) num_offset = argv[optind++];
+ else num_offset = NULL;
+
+ if (num_offset) {
+ if ((!isnumber(num_offset))||(sscanf(num_offset, "%zu", &buffer) != 1))
+ Usage(argc, argv, "Invalid buffer size is specified (%s)", num_offset);
+ buffer *= 1024 * 1024;
+ } else {
+ buffer = get_free_memory();
+ if (buffer < 256) Error("Not enough free memory (%lz MB) for buffering", buffer / 1024 / 1024);
+
+ buffer -= 128 + buffer/16;
+ }
+ break;
+ case OPT_FORMAT:
+ if (!strcasecmp(optarg, "add_header")) format = FORMAT_HEADER;
+ else if (!strcasecmp(optarg, "ringfs")) format = FORMAT_RINGFS;
+ else if (strcasecmp(optarg, "raw")) Error("Invalid format (%s) is specified", optarg);
+ break;
case OPT_QUIETE:
quiete = 1;
break;
@@ -1869,6 +2090,21 @@ int main(int argc, char **argv) {
}
}
}
+
+ if (mode == MODE_GRAB) {
+ if (output) {
+ char fsname[128];
+ if (!get_file_fs(output, 127, fsname)) {
+ if (!strcmp(fsname, "ext4")) partition = PARTITION_EXT4;
+ else if (!strcmp(fsname, "raw")) partition = PARTITION_RAW;
+ }
+ }
+ }
+
+ if (mode != MODE_GRAB) {
+ if (size == (size_t)-1)
+ Usage(argc, argv, "Unlimited size is not supported in selected operation mode");
+ }
if ((bank)&&(amode == ACCESS_DMA)) {
@@ -1931,7 +2167,7 @@ int main(int argc, char **argv) {
pcilib_reset(handle);
break;
case MODE_GRAB:
- Grab(handle, event, ofile);
+ TriggerAndGrab(handle, grab_mode, event, data_type, size, run_time, trigger_time, partition, format, buffer, ofile);
break;
case MODE_LIST_DMA:
ListDMA(handle, fpga_device, model_info);
diff --git a/dma.c b/dma.c
index 216aa60..24dd89e 100644
--- a/dma.c
+++ b/dma.c
@@ -186,12 +186,13 @@ static int pcilib_dma_read_callback(void *arg, pcilib_dma_flags_t flags, size_t
if (flags & PCILIB_DMA_FLAG_EOP) {
if ((ctx->pos < ctx->size)&&(ctx->flags&PCILIB_DMA_FLAG_MULTIPACKET)) {
- if (ctx->flags&PCILIB_DMA_FLAG_WAIT) return 2;
- else return 3;
+ if (ctx->flags&PCILIB_DMA_FLAG_WAIT) return PCILIB_STREAMING_WAIT;
+ else return PCILIB_STREAMING_CONTINUE;
}
- return 0;
+ return PCILIB_STREAMING_STOP;
}
- return 1;
+
+ return PCILIB_STREAMING_REQ_FRAGMENT;
}
static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
@@ -200,10 +201,10 @@ static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t
if (tv) {
gettimeofday(&cur, NULL);
- if ((cur.tv_sec > tv->tv_sec)||((cur.tv_sec == tv->tv_sec)&&(cur.tv_usec > tv->tv_usec))) return 0;
+ if ((cur.tv_sec > tv->tv_sec)||((cur.tv_sec == tv->tv_sec)&&(cur.tv_usec > tv->tv_usec))) return PCILIB_STREAMING_STOP;
}
- return 1;
+ return PCILIB_STREAMING_REQ_PACKET;
}
int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr) {
diff --git a/dma/nwl_engine.c b/dma/nwl_engine.c
index 806173d..ac87f08 100644
--- a/dma/nwl_engine.c
+++ b/dma/nwl_engine.c
@@ -266,10 +266,12 @@ int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma,
}
int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr) {
- int err, ret = 1;
+ int err, ret = PCILIB_STREAMING_REQ_PACKET;
size_t res = 0;
size_t bufnum;
size_t bufsize;
+ pcilib_timeout_t wait;
+
nwl_dma_t *ctx = (nwl_dma_t*)vctx;
size_t buf_size;
@@ -281,15 +283,15 @@ int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uin
if (err) return err;
do {
- if (ret > 2) {
- bufnum = dma_nwl_wait_buffer(ctx, info, &bufsize, &eop, 0);
- if (bufnum == PCILIB_DMA_BUFFER_INVALID) return 0;
- } else {
- bufnum = dma_nwl_wait_buffer(ctx, info, &bufsize, &eop, timeout);
- if (bufnum == PCILIB_DMA_BUFFER_INVALID) {
- if (ret == 1) return PCILIB_ERROR_TIMEOUT;
- return 0;
- }
+ switch (ret&PCILIB_STREAMING_TIMEOUT_MASK) {
+ case PCILIB_STREAMING_CONTINUE: wait = PCILIB_DMA_TIMEOUT; break;
+ case PCILIB_STREAMING_WAIT: wait = timeout; break;
+ case PCILIB_STREAMING_CHECK: wait = 0; break;
+ }
+
+ bufnum = dma_nwl_wait_buffer(ctx, info, &bufsize, &eop, wait);
+ if (bufnum == PCILIB_DMA_BUFFER_INVALID) {
+ return (ret&PCILIB_STREAMING_FAIL)?PCILIB_ERROR_TIMEOUT:0;
}
// EOP is not respected in IPE Camera
@@ -300,8 +302,8 @@ int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uin
ret = cb(cbattr, (eop?PCILIB_DMA_FLAG_EOP:0), bufsize, buf);
// DS: Fixme, it looks like we can avoid calling this for the sake of performance
// pcilib_kmem_sync_block(ctx->pcilib, info->pages, PCILIB_KMEM_SYNC_TODEVICE, bufnum);
- if (ret < 0) return -ret;
dma_nwl_return_buffer(ctx, info);
+ if (ret < 0) return -ret;
res += bufsize;
diff --git a/error.h b/error.h
index 5b46ae5..a5a9493 100644
--- a/error.h
+++ b/error.h
@@ -17,7 +17,8 @@ enum {
PCILIB_ERROR_OUTOFRANGE,
PCILIB_ERROR_NOTAVAILABLE,
PCILIB_ERROR_NOTINITIALIZED,
- PCILIB_ERROR_TOOBIG
+ PCILIB_ERROR_TOOBIG,
+ PCILIB_ERROR_THREAD
} pcilib_errot_t;
diff --git a/event.c b/event.c
index 2f85b4f..1711400 100644
--- a/event.c
+++ b/event.c
@@ -36,12 +36,43 @@ pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event) {
pcilib_event_description_t *events = model_info->events;
for (i = 0; events[i].name; i++) {
- if (!strcasecmp(events[i].name, event)) return (1<<i);
+ if (!strcasecmp(events[i].name, event)) return events[i].evid;
}
return (pcilib_event_t)-1;
}
+pcilib_event_data_type_t pcilib_find_event_data_type(pcilib_t *ctx, pcilib_event_t event, const char *data_type) {
+ int i;
+ pcilib_register_bank_t res;
+ unsigned long addr;
+
+ pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
+ pcilib_event_data_type_description_t *data_types = model_info->data_types;
+
+ for (i = 0; data_types[i].name; i++) {
+ if ((data_types[i].evid&event)&&(!strcasecmp(data_types[i].name, data_type))) return data_types[i].data_type;
+ }
+
+ return (pcilib_event_data_type_t)-1;
+}
+
+int pcilib_init_event_engine(pcilib_t *ctx) {
+ pcilib_event_api_description_t *api;
+ pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
+
+ api = model_info->event_api;
+
+// api = pcilib_model[model].event_api;
+ if ((api)&&(api->init)) {
+ ctx->event_ctx = api->init(ctx);
+ if (ctx->event_ctx) {
+ ctx->event_ctx->pcilib = ctx;
+ }
+ }
+
+ return 0;
+}
int pcilib_reset(pcilib_t *ctx) {
pcilib_event_api_description_t *api;
@@ -60,7 +91,41 @@ int pcilib_reset(pcilib_t *ctx) {
return 0;
}
-int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, void *callback, void *user) {
+int pcilib_configure_rawdata_callback(pcilib_t *ctx, pcilib_event_rawdata_callback_t callback, void *user) {
+ pcilib_event_api_description_t *api;
+
+ pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
+
+ api = model_info->event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ ctx->event_ctx->params.rawdata.callback = callback;
+ ctx->event_ctx->params.rawdata.user = user;
+
+ return 0;
+}
+
+int pcilib_configure_autostop(pcilib_t *ctx, size_t max_events, pcilib_timeout_t duration) {
+ pcilib_event_api_description_t *api;
+
+ pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
+
+ api = model_info->event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ ctx->event_ctx->params.autostop.max_events = max_events;
+ ctx->event_ctx->params.autostop.duration = duration;
+
+ return 0;
+}
+
+int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags) {
pcilib_event_api_description_t *api;
pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
@@ -72,12 +137,12 @@ int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, void *callback, void
}
if (api->start)
- return api->start(ctx->event_ctx, event_mask, callback, user);
+ return api->start(ctx->event_ctx, event_mask, flags);
return 0;
}
-int pcilib_stop(pcilib_t *ctx) {
+int pcilib_stop(pcilib_t *ctx, pcilib_event_flags_t flags) {
pcilib_event_api_description_t *api;
pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
@@ -89,13 +154,49 @@ int pcilib_stop(pcilib_t *ctx) {
}
if (api->stop)
- return api->stop(ctx->event_ctx);
+ return api->stop(ctx->event_ctx, flags);
return 0;
}
-pcilib_event_id_t pcilib_get_next_event(pcilib_t *ctx, pcilib_event_t event_mask, pcilib_timeout_t timeout) {
+int pcilib_stream(pcilib_t *ctx, pcilib_event_callback_t callback, void *user) {
+ pcilib_event_api_description_t *api;
+
+ pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
+
+ api = model_info->event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ if (api->stream)
+ return api->stream(ctx->event_ctx, callback, user);
+
+ if (api->next_event) {
+ pcilib_error("Streaming using next_event API is not implemented yet");
+ }
+
+ pcilib_error("Event enumeration is not suppored by API");
+ return PCILIB_ERROR_NOTSUPPORTED;
+}
+/*
+typedef struct {
+ pcilib_event_id_t event_id;
+ pcilib_event_info_t *info;
+} pcilib_return_event_callback_context_t;
+
+static int pcilib_return_event_callback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user) {
+ pcilib_return_event_callback_context_t *ctx = (pcilib_return_event_callback_context_t*)user;
+ ctx->event_id = event_id;
+ ctx->info = info;
+}
+*/
+
+int pcilib_get_next_event(pcilib_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, pcilib_event_info_t **info) {
+ int err;
pcilib_event_api_description_t *api;
+// pcilib_return_event_callback_context_t user;
pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
@@ -106,10 +207,22 @@ pcilib_event_id_t pcilib_get_next_event(pcilib_t *ctx, pcilib_event_t event_mask
}
if (api->next_event)
- return api->next_event(ctx->event_ctx, event_mask, timeout);
+ return api->next_event(ctx->event_ctx, timeout, evid, info);
+
+/*
+ if (api->stream) {
+ err = api->stream(ctx->event_ctx, 1, timeout, pcilib_return_event_callback, &user);
+ if (err) return err;
+
+ if (evid) *evid = user->event_id;
+ if (info) *info = user->info;
+
+ return 0;
+ }
+*/
pcilib_error("Event enumeration is not suppored by API");
- return PCILIB_EVENT_ID_INVALID;
+ return PCILIB_ERROR_NOTSUPPORTED;
}
int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
@@ -141,11 +254,33 @@ void *pcilib_get_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, p
}
if (api->get_data)
- return api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, size);
+ return api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, size, NULL);
return NULL;
}
+int pcilib_copy_data_with_argument(pcilib_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, size_t *retsize) {
+ void *res;
+ pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
+
+ pcilib_event_api_description_t *api = model_info->event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ if (api->get_data) {
+ res = api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, &size, buf);
+ if (!res) return PCILIB_ERROR_FAILED;
+
+ if (retsize) *retsize = size;
+ return 0;
+ }
+
+ return PCILIB_ERROR_NOTSUPPORTED;
+}
+
+
void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) {
pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
@@ -156,12 +291,33 @@ void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_da
}
if (api->get_data)
- return api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, size);
+ return api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, size, NULL);
return NULL;
}
-int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id) {
+int pcilib_copy_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t size, void *buf, size_t *ret_size) {
+ void *res;
+ pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
+
+ pcilib_event_api_description_t *api = model_info->event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ if (api->get_data) {
+ res = api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, &size, buf);
+ if (!res) return PCILIB_ERROR_FAILED;
+
+ if (ret_size) *ret_size = size;
+ return 0;
+ }
+
+ return PCILIB_ERROR_NOTSUPPORTED;
+}
+
+int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id, void *data) {
pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
pcilib_event_api_description_t *api = model_info->event_api;
@@ -171,7 +327,7 @@ int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id) {
}
if (api->return_data)
- return api->return_data(ctx->event_ctx, event_id);
+ return api->return_data(ctx->event_ctx, event_id, data);
return 0;
}
@@ -184,6 +340,7 @@ typedef struct {
void **data;
} pcilib_grab_callback_user_data_t;
+
static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id, void *vuser) {
int err;
void *data;
@@ -217,7 +374,7 @@ static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id
memcpy(*(user->data), data, size);
- err = pcilib_return_data(user->ctx, event_id);
+ err = pcilib_return_data(user->ctx, event_id, data);
if (err) {
if (allocated) {
free(*(user->data));
@@ -233,17 +390,16 @@ static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id
int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, pcilib_timeout_t timeout) {
int err;
struct timespec ts;
+ pcilib_event_id_t eid;
pcilib_grab_callback_user_data_t user = {ctx, size, data};
- err = pcilib_start(ctx, event_mask, pcilib_grab_callback, &user);
+ err = pcilib_start(ctx, event_mask, PCILIB_EVENT_FLAGS_DEFAULT);
+ if (!err) err = pcilib_trigger(ctx, event_mask, 0, NULL);
if (!err) {
- if (timeout) {
- ts.tv_sec = timeout / 1000000;
- ts.tv_nsec = 1000 * (timeout % 1000000);
- nanosleep(&ts, NULL);
- } else err = pcilib_trigger(ctx, event_mask, 0, NULL);
+ err = pcilib_get_next_event(ctx, timeout, &eid, NULL);
+ if (!err) pcilib_grab_callback(event_mask, eid, &user);
}
- pcilib_stop(ctx);
+ pcilib_stop(ctx, PCILIB_EVENT_FLAGS_DEFAULT);
return err;
}
diff --git a/event.h b/event.h
index 7c1f1cd..7a1810a 100644
--- a/event.h
+++ b/event.h
@@ -9,17 +9,41 @@ struct pcilib_event_api_description_s {
int (*reset)(pcilib_context_t *ctx);
- int (*start)(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_event_callback_t callback, void *user);
- int (*stop)(pcilib_context_t *ctx);
+ int (*start)(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags);
+ int (*stop)(pcilib_context_t *ctx, pcilib_event_flags_t flags);
int (*trigger)(pcilib_context_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data);
- pcilib_event_id_t (*next_event)(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_timeout_t timeout);
- void* (*get_data)(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);
- int (*return_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id);
+ int (*stream)(pcilib_context_t *ctx, pcilib_event_callback_t callback, void *user);
+ pcilib_event_id_t (*next_event)(pcilib_context_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, pcilib_event_info_t **info);
+
+ void* (*get_data)(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 *data);
+ int (*return_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id, void *data);
pcilib_dma_context_t *(*init_dma)(pcilib_context_t *ctx);
+};
+
+
+typedef struct {
+ size_t max_events;
+ pcilib_timeout_t duration;
+} pcilib_autostop_parameters_t;
+typedef struct {
+ pcilib_event_rawdata_callback_t callback;
+ void *user;
+} pcilib_rawdata_parameters_t;
+
+typedef struct {
+ pcilib_autostop_parameters_t autostop;
+ pcilib_rawdata_parameters_t rawdata;
+} pcilib_event_parameters_t;
+
+struct pcilib_event_context_s {
+ pcilib_event_parameters_t params;
+ pcilib_t *pcilib;
};
+int pcilib_init_event_engine(pcilib_t *ctx);
+
#endif /* _PCILIB_EVENT_H */
diff --git a/ipecamera/image.c b/ipecamera/image.c
index 29ca9c1..4b060b6 100644
--- a/ipecamera/image.c
+++ b/ipecamera/image.c
@@ -6,6 +6,7 @@
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
+#include <pthread.h>
#include <assert.h>
#include "../tools.h"
@@ -14,6 +15,7 @@
#include "pcilib.h"
#include "model.h"
+#include "event.h"
#include "image.h"
#include "dma/nwl_dma.h"
@@ -23,27 +25,35 @@
#endif /* IPECAMERA_DEBUG */
-#define IPECAMERA_SLEEP_TIME 250000 // Michele thinks 250 should be enough, but reset failing in this case
-#define IPECAMERA_NEXT_FRAME_DELAY 30000 // please don't change this value --> sync between End Of Readout and next Frame Req, by Michele
-#define IPECAMERA_WAIT_FRAME_RCVD_TIME 0 /* by Uros ,wait 6 ms */
+#define IPECAMERA_BUG_EXTRA_DATA
+
+#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_DEFAULT_BUFFER_SIZE 10
#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 //1088
+/*
+#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
@@ -60,8 +70,17 @@ int ipecamera_channel_order[IPECAMERA_MAX_CHANNELS] = { 15, 13, 14, 12, 10, 8, 1
typedef uint32_t ipecamera_payload_t;
+typedef struct {
+ pcilib_event_info_t info;
+} ipecamera_event_info_t;
+
+typedef struct {
+ pcilib_event_id_t evid;
+ struct timeval timestamp;
+} ipecamera_autostop_t;
+
struct ipecamera_s {
- pcilib_t *pcilib;
+ pcilib_context_t event;
#ifndef IPECAMERA_DMA_ADDRESS
char *data;
@@ -86,16 +105,42 @@ struct ipecamera_s {
pcilib_register_t exposure_reg;
pcilib_register_t flip_reg;
- int started;
- int buffer_size;
- int buf_ptr;
+ 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;
+// int ready; /**< New frame is ready */
+// int check_time; /**< Streaming is time-limited */
+
+ 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 stream_count; /**< Number of images read so far */
+// size_t stream_max; /**< Maximum number of images to read */
+// struct timeval stream_stop; /**< Time to stop streaming */
+ 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;
- ipecamera_pixel_t *buffer;
+
+// void *raw_buffer;
+ void *buffer;
ipecamera_change_mask_t *cmask;
+ ipecamera_event_info_t *frame_info;
+
ipecamera_image_dimensions_t dim;
+
+ pthread_t rthread;
};
@@ -156,8 +201,6 @@ pcilib_context_t *ipecamera_init(pcilib_t *pcilib) {
if (ctx) {
memset(ctx, 0, sizeof(ipecamera_t));
- ctx->pcilib = pcilib;
-
ctx->buffer_size = IPECAMERA_DEFAULT_BUFFER_SIZE;
ctx->dim.bpp = sizeof(ipecamera_pixel_t) * 8;
@@ -181,7 +224,7 @@ pcilib_context_t *ipecamera_init(pcilib_t *pcilib) {
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;
@@ -198,7 +241,7 @@ pcilib_context_t *ipecamera_init(pcilib_t *pcilib) {
void ipecamera_free(pcilib_context_t *vctx) {
if (vctx) {
ipecamera_t *ctx = (ipecamera_t*)vctx;
- ipecamera_stop(vctx);
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
free(ctx);
}
}
@@ -206,7 +249,7 @@ void ipecamera_free(pcilib_context_t *vctx) {
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(ctx->pcilib);
+ 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;
@@ -214,9 +257,9 @@ pcilib_dma_context_t *ipecamera_init_dma(pcilib_context_t *vctx) {
#ifdef IPECAMERA_DMA_R3
- return model_info->dma_api->init(ctx->pcilib, PCILIB_NWL_MODIFICATION_IPECAMERA, NULL);
+ return model_info->dma_api->init(vctx->pcilib, PCILIB_NWL_MODIFICATION_IPECAMERA, NULL);
#else
- return model_info->dma_api->init(ctx->pcilib, PCILIB_DMA_MODIFICATION_DEFAULT, NULL);
+ return model_info->dma_api->init(vctx->pcilib, PCILIB_DMA_MODIFICATION_DEFAULT, NULL);
#endif
}
@@ -227,21 +270,24 @@ int ipecamera_set_buffer_size(ipecamera_t *ctx, int size) {
return PCILIB_ERROR_INVALID_REQUEST;
}
- if (ctx->size < 1) {
+ 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;
- pcilib_t *pcilib;
+ int err = 0;
ipecamera_t *ctx = (ipecamera_t*)vctx;
+ pcilib_t *pcilib = vctx->pcilib;
pcilib_register_t control, status;
pcilib_register_value_t value;
@@ -251,14 +297,14 @@ int ipecamera_reset(pcilib_context_t *vctx) {
return PCILIB_ERROR_NOTINITIALIZED;
}
- pcilib = ctx->pcilib;
+ 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 CMOSIS reset bit");
+ pcilib_error("Error setting FPGA reset bit");
return err;
}
usleep(IPECAMERA_SLEEP_TIME);
@@ -266,7 +312,7 @@ int ipecamera_reset(pcilib_context_t *vctx) {
// Remove Reset bit to CMOSIS
err = pcilib_write_register_by_id(pcilib, control, 0x1e1);
if (err) {
- pcilib_error("Error reseting CMOSIS reset bit");
+ pcilib_error("Error reseting FPGA reset bit");
return err;
}
usleep(IPECAMERA_SLEEP_TIME);
@@ -287,11 +333,15 @@ int ipecamera_reset(pcilib_context_t *vctx) {
usleep(IPECAMERA_SLEEP_TIME);
// Set default parameters
- SET_REG(control_reg, IPECAMERA_IDLE);
- if (err) return err;
-
+ 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");
@@ -306,12 +356,121 @@ int ipecamera_reset(pcilib_context_t *vctx) {
return 0;
}
-int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_event_callback_t cb, void *user) {
+// 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 void ipecamera_new_frame(ipecamera_t *ctx) {
+ ctx->buffer_pos = (++ctx->event_id) % ctx->buffer_size;
+ ctx->cur_size = 0;
+
+ ctx->frame_info[ctx->buffer_pos].info.type = PCILIB_EVENT0;
+// memset(ctx->cmask + ctx->buffer_pos * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t));
+}
+
+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;
+ ipecamera_t *ctx = (ipecamera_t*)user;
+
+
+ if ((bufsize >= 8)&&(!memcmp(buf, frame_magic, sizeof(frame_magic)))) {
+ //if (ctx->cur_size) ipecamera_new_frame(ctx);
+ 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);
+ }
+
+ 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) {
+ ipecamera_new_frame(ctx);
+
+ if ((ctx->event_id == ctx->autostop.evid)&&(ctx->event_id)) {
+ ctx->run_reader = 0;
+ return PCILIB_STREAMING_STOP;
+ }
+
+ if (check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) {
+ ctx->run_reader = 0;
+ return PCILIB_STREAMING_STOP;
+ }
+ }
+
+ 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 (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);
+ }
+
+ 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 = ctx->pcilib;
+ 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;
+ const size_t footer_size = 8;
+ 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;
@@ -322,48 +481,66 @@ int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_ev
return PCILIB_ERROR_INVALID_REQUEST;
}
- // if left in FRAME_REQUEST mode
- SET_REG(control_reg, IPECAMERA_IDLE);
+
+ // 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;
-//#ifdef IPECAMERA_DMA_ADDRESS
-// SET_REG(packet_len_reg, IPECAMERA_DMA_PACKET_LENGTH);
-// if (err) return err;
-//#endif /* IPECAMERA_DMA_ADDRESS */
-
- ctx->cb = cb;
- ctx->cb_user = user;
-
ctx->event_id = 0;
ctx->reported_id = 0;
- ctx->buf_ptr = 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;
- ctx->dim.height = IPECAMERA_HEIGHT; //GET_REG(lines_reg, lines);
+ 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 * sizeof(ipecamera_pixel_t);
+ 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->buffer = malloc(ctx->dim.width * ctx->dim.height * ctx->buffer_size * sizeof(ipecamera_pixel_t));
+ 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");
+ pcilib_error("Unable to allocate ring buffer (%lu bytes)", ctx->padded_size * ctx->buffer_size);
+ 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;
}
#ifdef IPECAMERA_DMA_ADDRESS
if (!err) {
- ctx->rdma = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_FROM_DEVICE, IPECAMERA_DMA_ADDRESS);
+ 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(ctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT);
+ 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);
@@ -373,12 +550,12 @@ int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_ev
/*
if (!err) {
- ctx->wdma = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_TO_DEVICE, IPECAMERA_DMA_ADDRESS);
+ 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(ctx->pcilib, ctx->wdma, PCILIB_DMA_FLAGS_DEFAULT);
+ 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);
@@ -386,20 +563,68 @@ int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_ev
}
}
*/
+
+/*
+ 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;
+ }
+
#endif /* IPECAMERA_DMA_ADDRESS */
if (err) {
- ipecamera_stop(vctx);
+ 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;
- return 0;
+ 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) {
+int ipecamera_stop(pcilib_context_t *vctx, pcilib_event_flags_t flags) {
+ int err;
+ void *retcode;
ipecamera_t *ctx = (ipecamera_t*)vctx;
if (!ctx) {
@@ -407,20 +632,29 @@ int ipecamera_stop(pcilib_context_t *vctx) {
return PCILIB_ERROR_NOTINITIALIZED;
}
- ctx->started = 0;
+ if (ctx->started) {
+ ctx->run_reader = 0;
+ err = pthread_join(ctx->rthread, &retcode);
+ if (err) pcilib_error("Error joining the reader thread");
+ }
#ifdef IPECAMERA_DMA_ADDRESS
if (ctx->wdma != PCILIB_DMA_ENGINE_INVALID) {
- pcilib_stop_dma(ctx->pcilib, ctx->wdma, PCILIB_DMA_FLAGS_DEFAULT);
+ 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(ctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT);
+ pcilib_stop_dma(vctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT);
ctx->rdma = PCILIB_DMA_ENGINE_INVALID;
}
#endif /* IPECAMERA_DMA_ADDRESS */
+ if (ctx->frame_info) {
+ free(ctx->frame_info);
+ ctx->frame_info = NULL;
+ }
+
if (ctx->buffer) {
free(ctx->buffer);
ctx->buffer = NULL;
@@ -431,421 +665,143 @@ int ipecamera_stop(pcilib_context_t *vctx) {
ctx->cmask = NULL;
}
+ memset(&ctx->autostop, 0, sizeof(ipecamera_autostop_t));
ctx->event_id = 0;
ctx->reported_id = 0;
- ctx->buf_ptr = 0;
+ ctx->buffer_pos = 0;
+ ctx->started = 0;
return 0;
}
-static int ipecamera_get_payload(ipecamera_t *ctx, ipecamera_pixel_t *pbuf, ipecamera_change_mask_t *cbuf, int line_req, pcilib_register_value_t size, ipecamera_payload_t *payload, pcilib_register_value_t *advance) {
- int i, j;
- int ppw;
- int err = 0;
-
- ipecamera_payload_t info = payload[0];
- int channel = info&0x0F; // 4 bits
- const int line = (info>>4)&0x7FF; // 11 bits
- // 1 bit is reserved
- const int bpp = (info>>16)&0x0F; // 4 bits
- const int pixels = (info>>20)&0xFF; // 8 bits
- // 2 bits are reserved
- int header = (info>>30)&0x03; // 2 bits
-
- int bytes;
-
- int pix;
- int pix_offset = 0;
-
- const int chan_offset = channel * IPECAMERA_PIXELS_PER_CHANNEL;
-
- ipecamera_payload_t data;
-
-#ifdef IPECAMERA_REORDER_CHANNELS
- channel = ipecamera_channel_order[channel];
-#endif
-// printf("payload, channel: %i, magick: %i, all: %lx\n", channel, header, info);
-
- //printf("channel[%x] = %x (line: %i, pixels: %i)\n", info, channel, line_req, pixels);
- CHECK_FLAG("payload header magick", header == 2, header);
- CHECK_FLAG("pixel size, only 10 bits are supported", bpp == 10, bpp);
- CHECK_FLAG("row number, should be %li", line == line_req, line, line_req);
- CHECK_FLAG("channel, limited by %li output channels", channel < IPECAMERA_MAX_CHANNELS, channel, IPECAMERA_MAX_CHANNELS);
- CHECK_FLAG("channel, duplicate entry for channel", ((*cbuf)&(1<<channel)) == 0, channel);
-
- // Fixing first lines bug
- // Matthias: Using unlikely() saves 1ms
- if ((line < 2)&&(pixels == (IPECAMERA_PIXELS_PER_CHANNEL - 1))) {
- pix_offset = 1;
- pbuf[chan_offset] = 0;
- } else {
- CHECK_FLAG("number of pixels, %li is expected", pixels == IPECAMERA_PIXELS_PER_CHANNEL, pixels, IPECAMERA_PIXELS_PER_CHANNEL);
- }
-
- bytes = pixels / 3;
- ppw = pixels - bytes * 3;
- if (ppw) ++bytes;
-
- CHECK_FLAG("payload data bytes, at least %i are expected", bytes < size, size, bytes);
-
- if (err) return err;
-
- for (i = 1, pix = pix_offset; i < bytes; i++) {
- data = payload[i];
- header = (data >> 30) & 0x03;
-
- CHECK_FLAG("payload data magick", header == 3, header);
- if (err) return err;
-
- // DS: Unroll
- for (j = 0; j < 3; j++, pix++) {
- pbuf[chan_offset + pix] = (data >> (10 * (2 - j))) & 0x3FF;
- }
- }
-
- data = payload[bytes];
- header = (data >> 30) & 0x03;
-
- CHECK_FLAG("payload data magick", header == 3, header);
- CHECK_FLAG("payload footer magick", (data&0x3FF) == 0x55, (data&0x3FF));
- if (err) return err;
-
- ppw = pixels%3;
- assert(ppw < 3);
-
- for (j = 0; j < ppw; j++, pix++) {
-// pbuf[channel*IPECAMERA_PIXELS_PER_CHANNEL + pix] = (data >> (10 * (ppw - j - 1))) & 0x3FF;
- pbuf[chan_offset + pix] = (data >> (10 * (ppw - j))) & 0x3FF;
- }
-
- *cbuf |= (1 << channel);
- *advance = bytes + 1;
-
- return 0;
-}
-
-static int ipecamera_parse_image(ipecamera_t *ctx, ipecamera_pixel_t *pbuf, ipecamera_change_mask_t *cbuf, int first_line, int n_lines, pcilib_register_value_t size, ipecamera_payload_t *linebuf) {
+int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
int err = 0;
- pcilib_t *pcilib = ctx->pcilib;
-
- int line = first_line;
- pcilib_register_value_t pos, advance;
-
- if (size < 16) {
- pcilib_error("The payload is tool small, we should have at least 8 header dwords and 8 footer.");
- return PCILIB_ERROR_INVALID_DATA;
- }
-
- CHECK_VALUE(linebuf[0], 0x51111111);
- CHECK_VALUE(linebuf[1], 0x52222222);
- CHECK_VALUE(linebuf[2], 0x53333333);
- CHECK_VALUE(linebuf[3], 0x54444444);
- CHECK_VALUE(linebuf[4], 0x55555555);
- CHECK_VALUE(linebuf[5], 0x56666666);
- CHECK_VALUE(linebuf[6], 0x57777777);
- CHECK_VALUE(linebuf[7], 0x58888888);
- if (err) return err;
+ pcilib_register_value_t value;
- pos = 8;
- size -= 16;
+ ipecamera_t *ctx = (ipecamera_t*)vctx;
+ pcilib_t *pcilib = vctx->pcilib;
- while (size > 0) {
- err = ipecamera_get_payload(ctx, pbuf + line * ctx->dim.width, cbuf + line, line - first_line, size, linebuf + pos, &advance);
- if (err) return err;
-
- pos += advance;
- size -= advance;
-
- if (cbuf[line] == ((1<<IPECAMERA_MAX_CHANNELS)-1)) ++line;
+ if (!ctx) {
+ pcilib_error("IPECamera imaging is not initialized");
+ return PCILIB_ERROR_NOTINITIALIZED;
}
- CHECK_FLAG("lines read, we expect to read exactly %li lines", line == (first_line + n_lines), line - first_line, n_lines);
-
- CHECK_VALUE(linebuf[pos ], 0x0AAAAAAA);
- CHECK_VALUE(linebuf[pos+1], 0x0BBBBBBB);
- CHECK_VALUE(linebuf[pos+2], 0x0CCCCCCC);
- CHECK_VALUE(linebuf[pos+3], 0x0DDDDDDD);
- CHECK_VALUE(linebuf[pos+4], 0x0EEEEEEE);
- CHECK_VALUE(linebuf[pos+5], 0x0FFFFFFF);
- CHECK_VALUE(linebuf[pos+6], 0x00000000);
- CHECK_VALUE(linebuf[pos+7], 0x01111111);
-
- return err;
-}
-
-static int ipecamera_get_image(ipecamera_t *ctx) {
- int err;
- int i;
- int buf_ptr;
- size_t bytes_read;
- pcilib_t *pcilib = ctx->pcilib;
-
- int num_lines;
- const int max_lines = IPECAMERA_MAX_LINES;
- const size_t line_size = (IPECAMERA_MAX_CHANNELS * (2 + IPECAMERA_PIXELS_PER_CHANNEL / 3));
- const size_t hf_size = 16;
- const size_t max_size = hf_size + max_lines * line_size;
- const size_t dma_packet_len = IPECAMERA_DMA_PACKET_LENGTH / sizeof(ipecamera_payload_t);
- size_t max_packet_size;
-
- pcilib_register_value_t ptr, size, pos, advance, value;
-
- ipecamera_payload_t *linebuf;
-
- if (max_size%dma_packet_len) max_packet_size = max_size + dma_packet_len - (max_size%dma_packet_len);
- else max_packet_size = max_size;
-
- max_packet_size += 4096; // Some extra data?
-
-
- linebuf = (ipecamera_payload_t*)malloc(max_packet_size * sizeof(ipecamera_payload_t));
- if (!linebuf) return PCILIB_ERROR_MEMORY;
-
- // DS: test
- err = pcilib_skip_dma(ctx->pcilib, ctx->rdma);
- if (err) {
- pcilib_error("Can't start benchmark, devices continuously writes unexpected data using DMA engine");
- return err;
+ 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);
-#ifdef IPECAMERA_WRITE_RAW
- FILE *f = fopen("raw/image.raw", "w");
- if (f) fclose(f);
-#endif
-
- //atomic
- buf_ptr = ctx->buf_ptr;
- if (ctx->buf_ptr++ == ctx->buffer_size) ctx->buf_ptr = 0;
- if (ctx->event_id++ == 0) ctx->event_id = 1;
-
- //const size_t image_size = ctx->dim.width * ctx->dim.height;
- //memset(ctx->buffer + buf_ptr * image_size, 0, image_size * sizeof(ipecamera_pixel_t));
- memset(ctx->cmask + buf_ptr * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t));
-
-
- for (i = 0; i < ctx->dim.height; i += max_lines) {
- num_lines = ctx->dim.height - i;
- if (num_lines > max_lines) num_lines = max_lines;
-
- SET_REG(n_lines_reg, num_lines);
- SET_REG(line_reg, i);
-
- SET_REG(control_reg, IPECAMERA_FRAME_REQUEST);
- usleep(IPECAMERA_WAIT_FRAME_RCVD_TIME);
- CHECK_REG(status_reg, IPECAMERA_EXPECTED_STATUS);
- SET_REG(control_reg, IPECAMERA_IDLE);
-
-#ifndef IPECAMERA_DMA_ADDRESS
- GET_REG(start_reg, ptr);
- GET_REG(end_reg, size);
-
- size -= ptr;
- size *= 2;
-
- CHECK_FLAG("data size", (size > 0)&&(size <= max_size), size);
-#endif /* IPECAMERA_DMA_ADDRESS */
-
-
- if (err) break;
-
- SET_REG(control_reg, IPECAMERA_READOUT);
- // sync between End Of Readout and next Frame Req
- usleep(IPECAMERA_NEXT_FRAME_DELAY);
-
-// usleep(1000000);
-
-// pcilib_start_dma(ctx->pcilib, ctx->rdma, PCILIB_DMA_FLAG_PERSISTENT);
-// pcilib_stop_dma(ctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT);
-// pcilib_start_dma(ctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT);
-
-
-#ifdef IPECAMERA_DMA_ADDRESS
- size = 0;
- do {
- err = pcilib_read_dma(ctx->pcilib, ctx->rdma, 0, max_packet_size * sizeof(ipecamera_payload_t) - size, ((uint8_t*)linebuf) + size, &bytes_read);
- size += bytes_read;
-// printf("%lu %lu\n", bytes_read, size);
- } while ((err == 0)&&(size < max_packet_size * sizeof(ipecamera_payload_t)));
-
-
-#ifdef DEBUG_HARDWARE
- uint32_t regval;
- printf("===========Lines: %i - %i =========================\n", i, i + num_lines - 1);
- err = pcilib_read_register(ctx->pcilib, NULL, "status", &regval);
- printf("Status1: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "start_address", &regval);
- printf("Start address: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "end_address", &regval);
- printf("End address: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "last_write_address", &regval);
- printf("Status2: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "last_write_value", &regval);
- printf("Status3: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", &regval);
- printf("Add_rd_ddr: %i 0x%lx\n", err, regval);
-#endif /* DEBUG_HARDWARE */
-
- if (err) {
- if (err == PCILIB_ERROR_TIMEOUT) {
- if (size > 0) err = 0;
- else {
-#ifdef IPECAMERA_DEBUG
- pcilib_warning("There is no data received from IPE Camera for lines: %i to %i", i, i + num_lines - 1);
- err = 0;
- SET_REG(control_reg, IPECAMERA_IDLE);
- continue;
-#else /* IPECAMERA_DEBUG */
- pcilib_error("There is no data received from IPE Camera");
- return err;
-#endif /* IPECAMERA_DEBUG */
- }
- } else pcilib_error("DMA read from IPE Camera have failed");
- } else if (!size) {
-#ifdef IPECAMERA_DEBUG
- pcilib_warning("There is no data received from IPE Camera for lines: %i to %i", i, i + num_lines - 1);
- SET_REG(control_reg, IPECAMERA_IDLE);
- continue;
-#else /* IPECAMERA_DEBUG */
- pcilib_warning("There is no data received from IPE Camera for lines: %i to %i", i, i + num_lines - 1);
- return err;
-#endif /* IPECAMERA_DEBUG */
- }
-
- pcilib_warning("Reading lines %i to %i: got %i bytes from DMA", i, i + num_lines - 1, size);
-#else /* IPECAMERA_DMA_ADDRESS */
- pcilib_warning("Reading lines %i to %i: %i %i", i, i + num_lines - 1, ptr, size);
- pcilib_datacpy(linebuf, ctx->data + ptr, sizeof(ipecamera_payload_t), size, pcilib_model[PCILIB_MODEL_IPECAMERA].endianess);
-#endif /* IPECAMERA_DMA_ADDRESS */
-
- SET_REG(control_reg, IPECAMERA_IDLE);
-// usleep(IPECAMERA_SLEEP_TIME);
- CHECK_REG(status_reg, IPECAMERA_EXPECTED_STATUS);
-
- if (err) break;
-#ifdef IPECAMERA_WRITE_RAW
- char fname[256];
- sprintf(fname, "raw/line%04i", i);
- FILE *f = fopen(fname, "w");
- if (f) {
-#ifdef IPECAMERA_DMA_ADDRESS
- (void)fwrite(linebuf, sizeof(ipecamera_payload_t), size / sizeof(ipecamera_payload_t), f);
-#else /* IPECAMERA_DMA_ADDRESS */
- (void)fwrite(linebuf, sizeof(ipecamera_payload_t), size, f);
-#endif /* IPECAMERA_DMA_ADDRESS */
- fclose(f);
- }
-#endif
+// SET_REG(control_reg, IPECAMERA_READOUT);
+ usleep(IPECAMERA_NEXT_FRAME_DELAY); // minimum delay between End Of Readout and next Frame Req
-#ifdef IPECAMERA_DMA_ADDRESS
- if (size < (hf_size + max_lines * line_size) * sizeof(ipecamera_payload_t)) {
- pcilib_error("We are expecting at least %zu bytes, but only %lu are read", (hf_size + num_lines * line_size)*sizeof(ipecamera_payload_t), size);
- err = PCILIB_ERROR_INVALID_DATA;
- }
+ // DS: check for overflow
+/*
- bytes_read = size;
- size = hf_size + max_lines * line_size;
-#endif /* IPECAMERA_DMA_ADDRESS */
-
-
- err = ipecamera_parse_image(ctx, ctx->buffer + buf_ptr * ctx->dim.width * ctx->dim.height, ctx->cmask + buf_ptr * ctx->dim.height, i, num_lines, size, linebuf);
- if (err) break;
-
-#ifdef IPECAMERA_WRITE_RAW
- f = fopen("raw/image.raw", "a+");
- if (f) {
- fwrite(ctx->buffer + buf_ptr * ctx->dim.width * ctx->dim.height + i * ctx->dim.width, sizeof(ipecamera_pixel_t), num_lines * ctx->dim.width, f);
- fclose(f);
+ err = ipecamera_get_image(ctx);
+ if (!err) {
+ if (ctx->cb) {
+ err = ctx->cb(event, ctx->event_id, ctx->cb_user);
+ ctx->reported_id = ctx->event_id;
}
-#endif
}
- free(linebuf);
-
return err;
+*/
}
-
-int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
- int err;
- pcilib_t *pcilib;
+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) {
- pcilib_error("Can't trigger while not grabbing is not started");
- return PCILIB_ERROR_INVALID_REQUEST;
+ 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;
}
- err = ipecamera_get_image(ctx);
- if (!err) {
- if (ctx->cb) {
- err = ctx->cb(event, ctx->event_id, ctx->cb_user);
- ctx->reported_id = ctx->event_id;
+ // 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%ctx->buffer_size)), user);
}
+ usleep(IPECAMERA_NOFRAME_SLEEP);
}
- return err;
-}
+ ctx->streaming = 0;
-static int ipecamera_resolve_event_id(ipecamera_t *ctx, pcilib_event_id_t evid) {
- int buf_ptr, diff;
+ if (do_stop) {
+ ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
+ }
- if ((!evid)||(evid > ctx->event_id)) return -1;
- diff = ctx->event_id - evid;
- buf_ptr = ctx->buf_ptr - diff - 1;
- if (buf_ptr < 0) {
- buf_ptr += ctx->buffer_size;
- if (buf_ptr < 0) return -1;
- }
- return buf_ptr;
+ return err;
}
-pcilib_event_id_t ipecamera_next_event(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_timeout_t timeout) {
- int buf_ptr;
- pcilib_event_id_t reported;
+
+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_EVENT_ID_INVALID;
+ return PCILIB_ERROR_NOTINITIALIZED;
}
if (!ctx->started) {
- pcilib_error("IPECamera is not in grabbing state");
- return PCILIB_EVENT_ID_INVALID;
+ pcilib_error("IPECamera is not in grabbing mode");
+ return PCILIB_ERROR_INVALID_REQUEST;
}
- if ((!ctx->event_id)||(ctx->reported_id == ctx->event_id)) {
+ if (ctx->reported_id == ctx->event_id) {
if (timeout) {
- // We should wait here for the specified timeout
+ calc_deadline(&tv, timeout);
+
+ while ((calc_time_to_deadline(&tv) > 0)&&(ctx->reported_id == ctx->event_id))
+ usleep(IPECAMERA_NOFRAME_SLEEP);
}
- return PCILIB_EVENT_ID_INVALID;
+
+ if (ctx->reported_id == ctx->event_id) return PCILIB_ERROR_TIMEOUT;
}
- // We had an overflow in event counting
- if (ctx->reported_id > ctx->event_id) {
- do {
- if (++ctx->reported_id == 0) ctx->reported_id = 1;
- } while (ipecamera_resolve_event_id(ctx, ctx->reported_id) < 0);
- } else {
- if ((ctx->event_id - ctx->reported_id) > ctx->buffer_size) ctx->reported_id = ctx->event_id - (ctx->buffer_size - 1);
- else ++ctx->reported_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;
+
return ctx->reported_id;
}
-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* 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 buf_ptr;
ipecamera_t *ctx = (ipecamera_t*)vctx;
@@ -856,9 +812,6 @@ void* ipecamera_get(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_e
buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
-
- //printf("%i %i %i\n", ctx->event_id, event_id, buf_ptr);
-
if (buf_ptr < 0) return NULL;
switch ((ipecamera_data_type_t)data_type) {
@@ -886,7 +839,7 @@ void* ipecamera_get(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_e
-int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id) {
+int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id, void *data) {
ipecamera_t *ctx = (ipecamera_t*)vctx;
if (!ctx) {
diff --git a/ipecamera/image.h b/ipecamera/image.h
index b414f74..c311b4d 100644
--- a/ipecamera/image.h
+++ b/ipecamera/image.h
@@ -10,13 +10,14 @@ pcilib_context_t *ipecamera_init(pcilib_t *pcilib);
void ipecamera_free(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_callback_t cb, void *user);
-int ipecamera_stop(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);
-pcilib_event_id_t ipecamera_next_event(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_timeout_t timeout);
+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);
-int ipecamera_return(pcilib_context_t *ctx, pcilib_event_id_t event_id);
+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);
diff --git a/ipecamera/ipecamera.h b/ipecamera/ipecamera.h
index 49afe0c..d15d1f2 100644
--- a/ipecamera/ipecamera.h
+++ b/ipecamera/ipecamera.h
@@ -10,7 +10,8 @@ typedef struct {
} ipecamera_image_dimensions_t;
typedef enum {
- IPECAMERA_IMAGE_DATA = 0,
+ IPECAMERA_RAW_DATA = 0,
+ IPECAMERA_IMAGE_DATA = 1,
IPECAMERA_DIMENSIONS = 0x8000,
IPECAMERA_IMAGE_REGION = 0x8010,
IPECAMERA_PACKED_IMAGE = 0x8020,
diff --git a/ipecamera/model.h b/ipecamera/model.h
index fb0559c..615494a 100644
--- a/ipecamera/model.h
+++ b/ipecamera/model.h
@@ -10,7 +10,7 @@
#define IPECAMERA_DMA_R3
#define IPECAMERA_DMA_ADDRESS 1
-#define IPECAMERA_DMA_PACKET_LENGTH 4096
+#define IPECAMERA_DMA_PACKET_LENGTH 4096
//#define IPECAMERA_REGISTER_SPACE 0xfeaffc00
#define IPECAMERA_REGISTER_SPACE 0x9000
@@ -96,8 +96,14 @@ pcilib_register_range_t ipecamera_register_ranges[] = {
};
pcilib_event_description_t ipecamera_events[] = {
- {"new_frame", ""},
- {NULL, NULL}
+ {PCILIB_EVENT0, "new_frame", ""},
+ {0, NULL, NULL}
+};
+
+pcilib_event_data_type_description_t ipecamera_data_types[] = {
+ {IPECAMERA_IMAGE_DATA, PCILIB_EVENT0, "image", "16 bit pixel data" },
+ {IPECAMERA_RAW_DATA, PCILIB_EVENT0, "raw", "raw data from camera" },
+ {0, 0, NULL, NULL}
};
#else
@@ -105,6 +111,7 @@ extern pcilib_register_description_t ipecamera_registers[];
extern pcilib_register_bank_description_t ipecamera_register_banks[];
extern pcilib_register_range_t ipecamera_register_ranges[];
extern pcilib_event_description_t ipecamera_events[];
+extern pcilib_event_data_type_description_t ipecamera_data_types[];
#endif
#ifdef _IPECAMERA_IMAGE_C
@@ -117,7 +124,8 @@ pcilib_event_api_description_t ipecamera_image_api = {
ipecamera_stop,
ipecamera_trigger,
- ipecamera_next_event,
+ ipecamera_stream,
+ NULL, //ipecamera_next_event,
ipecamera_get,
ipecamera_return,
ipecamera_init_dma
diff --git a/pci.c b/pci.c
index d2d5843..59b354e 100644
--- a/pci.c
+++ b/pci.c
@@ -45,7 +45,6 @@ int pcilib_set_error_handler(void (*err)(const char *msg, ...), void (*warn)(con
}
pcilib_t *pcilib_open(const char *device, pcilib_model_t model) {
- pcilib_event_api_description_t *api;
pcilib_t *ctx = malloc(sizeof(pcilib_t));
if (ctx) {
@@ -65,8 +64,7 @@ pcilib_t *pcilib_open(const char *device, pcilib_model_t model) {
memcpy(&ctx->model_info, pcilib_model + model, sizeof(pcilib_model_description_t));
- api = pcilib_model[model].event_api;
- if ((api)&&(api->init)) ctx->event_ctx = api->init(ctx);
+ pcilib_init_event_engine(ctx);
}
return ctx;
diff --git a/pci.h b/pci.h
index cdd380b..30c1bfe 100644
--- a/pci.h
+++ b/pci.h
@@ -53,9 +53,9 @@ struct pcilib_s {
# include "default.h"
pcilib_model_description_t pcilib_model[3] = {
- { 4, PCILIB_HOST_ENDIAN, NULL, NULL, NULL, NULL, NULL },
- { 4, PCILIB_HOST_ENDIAN, NULL, NULL, NULL, NULL, NULL },
- { 4, PCILIB_LITTLE_ENDIAN, ipecamera_registers, ipecamera_register_banks, ipecamera_register_ranges, ipecamera_events, &nwl_dma_api, &ipecamera_image_api }
+ { 4, PCILIB_HOST_ENDIAN, NULL, NULL, NULL, NULL, NULL, NULL },
+ { 4, PCILIB_HOST_ENDIAN, NULL, NULL, NULL, NULL, NULL, NULL },
+ { 4, PCILIB_LITTLE_ENDIAN, ipecamera_registers, ipecamera_register_banks, ipecamera_register_ranges, ipecamera_events, ipecamera_data_types, &nwl_dma_api, &ipecamera_image_api }
};
pcilib_protocol_description_t pcilib_protocol[3] = {
diff --git a/pcilib.h b/pcilib.h
index ee5323e..a51b050 100644
--- a/pcilib.h
+++ b/pcilib.h
@@ -4,13 +4,14 @@
#define PCILIB_MAX_BANKS 6
#define PCILIB_MAX_DMA_ENGINES 32
+#include <sys/time.h>
#include <stdint.h>
#define pcilib_memcpy pcilib_memcpy32
#define pcilib_datacpy pcilib_datacpy32
typedef struct pcilib_s pcilib_t;
-typedef void pcilib_context_t;
+typedef struct pcilib_event_context_s pcilib_context_t;
typedef struct pcilib_dma_context_s pcilib_dma_context_t;
@@ -72,6 +73,24 @@ typedef enum {
} pcilib_dma_flags_t;
typedef enum {
+ PCILIB_STREAMING_STOP = 0, /**< stop streaming */
+ PCILIB_STREAMING_CONTINUE = 1, /**< wait the default DMA timeout for a new data */
+ PCILIB_STREAMING_WAIT = 2, /**< wait the specified timeout for a new data */
+ PCILIB_STREAMING_CHECK = 3, /**< do not wait for the data, bail out imideatly if no data ready */
+ PCILIB_STREAMING_FAIL = 4, /**< fail if data is not available on timeout */
+ PCILIB_STREAMING_REQ_FRAGMENT = 5, /**< only fragment of a packet is read, wait for next fragment and fail if no data during DMA timeout */
+ PCILIB_STREAMING_REQ_PACKET = 6, /**< wait for next packet and fail if no data during the specified timeout */
+ PCILIB_STREAMING_TIMEOUT_MASK = 3 /**< mask specifying all timeout modes */
+} pcilib_streaming_action;
+
+
+typedef enum {
+ PCILIB_EVENT_FLAGS_DEFAULT = 0,
+ PCILIB_EVENT_FLAG_RAW_DATA_ONLY = 1,
+ PCILIB_EVENT_FLAG_EOF = 2
+} pcilib_event_flags_t;
+
+typedef enum {
PCILIB_REGISTER_STANDARD = 0,
PCILIB_REGISTER_FIFO,
PCILIB_REGISTER_BITS
@@ -99,12 +118,20 @@ typedef enum {
#define PCILIB_EVENT3 8
#define PCILIB_EVENTS_ALL ((pcilib_event_t)-1)
#define PCILIB_EVENT_INVALID ((pcilib_event_t)-1)
-#define PCILIB_EVENT_ID_INVALID 0
+//#define PCILIB_EVENT_ID_INVALID 0
#define PCILIB_TIMEOUT_INFINITE ((pcilib_timeout_t)-1)
#define PCILIB_TIMEOUT_IMMEDIATE 0
#define PCILIB_TIMEOUT_TRIGGER 0
#define PCILIB_IRQ_SOURCE_DEFAULT 0
+
+typedef struct {
+ pcilib_event_t type;
+ uint64_t seqnum; /* we will add seqnum_overflow if required */
+ uint64_t offset; /* nanoseconds */
+ struct timeval timestamp; /* most accurate timestamp */
+} pcilib_event_info_t;
+
/**<
* Callback function called when new data is read by DMA streaming function
* @ctx - DMA Engine context
@@ -113,13 +140,16 @@ typedef enum {
* @buf - data
* @returns
* <0 - error, stop streaming (the value is negative error code)
- * 0 - stop streaming
- * 1 - wait & read next buffer, fail if no data
- * 2 - wait & read next buffer, but don't fail if timeout expired
- * 3 - read next buffer if available (don't wait), don't fail
+ * 0 - stop streaming (PCILIB_STREAMING_STOP)
+ * 1 - wait DMA timeout and return gracefuly if no data (PCILIB_STREAMING_CONTINUE)
+ * 2 - wait the specified timeout and return gracefuly if no data (PCILIB_STREAMING_WAIT)
+ * 3 - check if more data is available without waiting, return gracefuly if not (PCILIB_STREAMING_CHECK)
+ * 5 - wait DMA timeout and fail if no data (PCILIB_STREAMING_REQ_FRAGMENT)
+ * 6 - wait the specified timeout and fail if no data (PCILIB_STREAMING_REQ_PACKET)
*/
typedef int (*pcilib_dma_callback_t)(void *ctx, pcilib_dma_flags_t flags, size_t bufsize, void *buf);
-typedef int (*pcilib_event_callback_t)(pcilib_event_t event, pcilib_event_id_t event_id, void *user);
+typedef int (*pcilib_event_callback_t)(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user);
+typedef int (*pcilib_event_rawdata_callback_t)(pcilib_event_id_t event_id, pcilib_event_info_t *info, pcilib_event_flags_t flags, size_t size, void *data, void *user);
typedef struct {
pcilib_register_bank_addr_t addr;
@@ -167,10 +197,18 @@ typedef struct {
} pcilib_register_range_t;
typedef struct {
+ pcilib_event_t evid;
const char *name;
const char *description;
} pcilib_event_description_t;
+typedef struct {
+ pcilib_event_data_type_t data_type;
+ pcilib_event_t evid;
+ const char *name;
+ const char *description;
+} pcilib_event_data_type_description_t;
+
typedef enum {
PCILIB_DMA_IRQ = 1,
PCILIB_EVENT_IRQ = 2
@@ -207,6 +245,7 @@ typedef struct {
pcilib_register_bank_description_t *banks;
pcilib_register_range_t *ranges;
pcilib_event_description_t *events;
+ pcilib_event_data_type_description_t *data_types;
pcilib_dma_api_description_t *dma_api;
pcilib_event_api_description_t *event_api;
@@ -242,6 +281,7 @@ pcilib_register_bank_t pcilib_find_bank_by_name(pcilib_t *ctx, const char *bankn
pcilib_register_bank_t pcilib_find_bank(pcilib_t *ctx, const char *bank);
pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const char *reg);
pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event);
+pcilib_event_data_type_t pcilib_find_event_data_type(pcilib_t *ctx, pcilib_event_t event, const char *data_type);
pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_engine_addr_t dma);
int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf);
@@ -265,19 +305,44 @@ int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, p
int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value);
int pcilib_reset(pcilib_t *ctx);
-int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, void *callback, void *user);
-int pcilib_stop(pcilib_t *ctx);
-
int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data);
-pcilib_event_id_t pcilib_get_next_event(pcilib_t *ctx, pcilib_event_t event_mask, pcilib_timeout_t timeout);
+/*
+ * The recording of new events will be stopped after reaching max_events records
+ * or when the specified amount of time is elapsed. However, the @pcilib_stop
+ * function should be called still.
+ * NOTE: This options may not be respected if the PCILIB_EVENT_FLAG_RAW_DATA_ONLY
+ * is specified.
+ */
+int pcilib_configure_autostop(pcilib_t *ctx, size_t max_events, pcilib_timeout_t duration);
+/*
+ * Request streaming the rawdata from the event engine. It is fastest way to acuqire data.
+ * No memory copies will be performed and DMA buffers will be directly passed to the user
+ * callback. However, to prevent data loss, no processing should be done on the data. The
+ * user callback is only expected to copy data into the appropriate place and return control
+ * to the event engine.
+ * The performance can be boosted further by disabling any data processing within the event
+ * engine. Just pass PCILIB_EVENT_FLAG_RAW_DATA_ONLY flag to the @pcilib_start function.
+ */
+int pcilib_configure_rawdata_callback(pcilib_t *ctx, pcilib_event_rawdata_callback_t callback, void *user);
+
+int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags);
+int pcilib_stop(pcilib_t *ctx, pcilib_event_flags_t flags);
+int pcilib_stream(pcilib_t *ctx, pcilib_event_callback_t callback, void *user);
+
+int pcilib_get_next_event(pcilib_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, pcilib_event_info_t **info);
+int pcilib_copy_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t size, void *buf, size_t *retsize);
+int pcilib_copy_data_with_argument(pcilib_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, size_t *retsize);
void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size);
void *pcilib_get_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size);
+
/*
* This function is provided to find potentially corrupted data. If the data is overwritten by
- * the time return_data is called it will return error.
+ * the time return_data is called it will return error.
*/
-int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id);
+int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id, void *data);
+
+
/*
* @param data - will be allocated and shuld be freed if NULL, otherwise used and size should contain correct size.
diff --git a/pcitool/sysinfo.c b/pcitool/sysinfo.c
new file mode 100644
index 0000000..51e7566
--- /dev/null
+++ b/pcitool/sysinfo.c
@@ -0,0 +1,173 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+
+#define MEMINFO_FILE "/proc/meminfo"
+#define MTAB_FILE "/etc/mtab"
+
+#define BAD_OPEN_MESSAGE \
+"Error: /proc must be mounted\n" \
+" To mount /proc at boot you need an /etc/fstab line like:\n" \
+" /proc /proc proc defaults\n" \
+" In the meantime, run \"mount /proc /proc -t proc\"\n"
+
+/* This macro opens filename only if necessary and seeks to 0 so
+ * that successive calls to the functions are more efficient.
+ * It also reads the current contents of the file into the global buf.
+ */
+#define FILE_TO_BUF(filename) do{ \
+ static int fd, local_n; \
+ if ((fd = open(filename, O_RDONLY)) == -1) { \
+ fputs(BAD_OPEN_MESSAGE, stderr); \
+ fflush(NULL); \
+ _exit(102); \
+ } \
+ lseek(fd, 0L, SEEK_SET); \
+ if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) { \
+ perror(filename); \
+ fflush(NULL); \
+ _exit(103); \
+ } \
+ buf[local_n] = '\0'; \
+ close(fd); \
+}while(0)
+
+
+typedef struct mem_table_struct {
+ const char *name; /* memory type name */
+ unsigned long *slot; /* slot in return struct */
+} mem_table_struct;
+
+static int compare_mem_table_structs(const void *a, const void *b){
+ return strcmp(((const mem_table_struct*)a)->name,((const mem_table_struct*)b)->name);
+}
+
+size_t get_free_memory(void){
+ char buf[4096];
+ unsigned long kb_main_buffers, kb_main_cached, kb_main_free;
+ char namebuf[16]; /* big enough to hold any row name */
+ mem_table_struct findme = { namebuf, NULL};
+ mem_table_struct *found;
+ char *head;
+ char *tail;
+
+ const mem_table_struct mem_table[] = {
+ {"Buffers", &kb_main_buffers}, // important
+ {"Cached", &kb_main_cached}, // important
+ {"MemFree", &kb_main_free}, // important
+ };
+ const int mem_table_count = sizeof(mem_table)/sizeof(mem_table_struct);
+
+ FILE_TO_BUF(MEMINFO_FILE);
+
+ head = buf;
+ for(;;){
+ tail = strchr(head, ':');
+ if(!tail) break;
+ *tail = '\0';
+ if(strlen(head) >= sizeof(namebuf)){
+ head = tail+1;
+ goto nextline;
+ }
+ strcpy(namebuf,head);
+ found = bsearch(&findme, mem_table, mem_table_count,
+ sizeof(mem_table_struct), compare_mem_table_structs
+ );
+ head = tail+1;
+ if(!found) goto nextline;
+ *(found->slot) = strtoul(head,&tail,10);
+nextline:
+ tail = strchr(head, '\n');
+ if(!tail) break;
+ head = tail+1;
+ }
+
+ return (kb_main_buffers + kb_main_cached + kb_main_free) * 1024;
+}
+
+
+int get_file_fs(const char *fname, size_t size, char *fs) {
+ int err = 0;
+ char buf[4096];
+ char *fn;
+
+ char *head;
+ char *tail;
+
+ size_t len, max = 0;
+ struct stat st;
+
+ if ((!fname)||(!fs)||(size < 3)) return -1;
+
+ if (*fn == '/') {
+ fn = (char*)fname;
+ } else {
+ if (!getcwd(buf, 4095)) return -1;
+ fn = malloc(strlen(fname) + strlen(buf) + 2);
+ if (!fn) return -1;
+ sprintf(fn, "%s/%s", buf, fname);
+ }
+
+ if (!stat(fn, &st)) {
+ if (S_ISBLK(st.st_mode)) {
+ strcpy(fs, "raw");
+ goto clean;
+ }
+ }
+
+ FILE_TO_BUF(MTAB_FILE);
+
+ head = buf;
+ for(;;){
+ head = strchr(head, ' ');
+ if(!head) break;
+
+ head += 1;
+ tail = strchr(head, ' ');
+ if(!tail) break;
+
+ *tail = '\0';
+
+ len = strlen(head);
+ if((len <= max)||(strncmp(head, fn, len))) {
+ head = tail+1;
+ goto nextline;
+ }
+
+ head = tail + 1;
+ tail = strchr(head, ' ');
+ if(!tail) break;
+
+ *tail = '\0';
+
+ if (!strncasecmp(head,"root",4)) {
+ head = tail+1;
+ goto nextline;
+ }
+
+ max = len;
+
+ if (strlen(head) >= size) err = -1;
+ else {
+ err = 0;
+ strcpy(fs, head);
+ }
+
+ head = tail+1;
+nextline:
+ tail = strchr(head, '\n');
+ if(!tail) break;
+ head = tail+1;
+ }
+
+clean:
+ if (fn != fname) free(fn);
+
+puts(fs);
+ return err;
+}
diff --git a/pcitool/sysinfo.h b/pcitool/sysinfo.h
new file mode 100644
index 0000000..d5636a7
--- /dev/null
+++ b/pcitool/sysinfo.h
@@ -0,0 +1,7 @@
+#ifndef _PCITOOL_SYSINFO_H
+#define _PCITOOL_SYSINFO_H
+
+size_t get_free_memory();
+int get_file_fs(const char *fname, size_t size, char *fs);
+
+#endif /* _PCITOOL_SYSINFO_H */
diff --git a/tests/grab.sh b/tests/grab.sh
index 3d2b03f..35e690b 100755
--- a/tests/grab.sh
+++ b/tests/grab.sh
@@ -5,7 +5,7 @@ function pci {
LD_LIBRARY_PATH="$PCILIB_PATH" $PCILIB_PATH/pci $*
}
-rm image.raw
+rm -f image.raw
echo "Reset..."
pci --reset
diff --git a/tools.c b/tools.c
index 8b39669..c2d8bd7 100644
--- a/tools.c
+++ b/tools.c
@@ -5,6 +5,7 @@
#include <assert.h>
#include <ctype.h>
#include <arpa/inet.h>
+#include <sys/time.h>
#include "tools.h"
@@ -238,7 +239,6 @@ void *pcilib_datacpy32(void * dst, void const * src, uint8_t size, size_t n, pci
}
}
-
int pcilib_get_page_mask() {
int pagesize,pagemask,temp;
@@ -250,3 +250,40 @@ int pcilib_get_page_mask() {
}
return pagemask;
}
+
+int calc_deadline(struct timeval *tv, pcilib_timeout_t timeout) {
+ gettimeofday(tv, NULL);
+ tv->tv_usec += timeout%1000000;
+ if (tv->tv_usec > 999999) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec = 1 + timeout/1000000;
+ } else {
+ tv->tv_sec = timeout/1000000;
+ }
+
+ return 0;
+}
+
+int check_deadline(struct timeval *tve, pcilib_timeout_t timeout) {
+ int64_t res;
+ struct timeval tvs;
+
+ if (!tve->tv_sec) return 0;
+
+ gettimeofday(&tvs, NULL);
+ res = ((tve->tv_sec - tvs.tv_sec)*1000000 + (tve->tv_usec - tvs.tv_usec));
+ if (res < timeout) return 1;
+
+ return 0;
+}
+
+pcilib_timeout_t calc_time_to_deadline(struct timeval *tve) {
+ int64_t res;
+ struct timeval tvs;
+
+ gettimeofday(&tvs, NULL);
+ res = ((tve->tv_sec - tvs.tv_sec)*1000000 + (tve->tv_usec - tvs.tv_usec));
+
+ if (res < 0) return 0;
+ return res;
+}
diff --git a/tools.h b/tools.h
index 9068ad5..6ab58f9 100644
--- a/tools.h
+++ b/tools.h
@@ -33,4 +33,9 @@ void * pcilib_datacpy32(void * dst, void const * src, uint8_t size, size_t n, pc
int pcilib_get_page_mask();
+
+int calc_deadline(struct timeval *tv, pcilib_timeout_t timeout);
+int check_deadline(struct timeval *tve, pcilib_timeout_t timeout);
+pcilib_timeout_t calc_time_to_deadline(struct timeval *tve);
+
#endif /* _PCITOOL_TOOS_H */