summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2011-12-09 07:12:44 +0100
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2011-12-09 07:12:44 +0100
commit1ac7751e5b9df5f09500aca9e5b34bb9cfa912b4 (patch)
tree42e3705aa8b20fc7f03025cb83ae2f928350174d
parentc3812d3569aa98e23953eea323d980912580e659 (diff)
downloadipecamera-1ac7751e5b9df5f09500aca9e5b34bb9cfa912b4.tar.gz
ipecamera-1ac7751e5b9df5f09500aca9e5b34bb9cfa912b4.tar.bz2
ipecamera-1ac7751e5b9df5f09500aca9e5b34bb9cfa912b4.tar.xz
ipecamera-1ac7751e5b9df5f09500aca9e5b34bb9cfa912b4.zip
Initial support of event streaming in cli
-rw-r--r--BUGS18
-rw-r--r--ToDo9
-rw-r--r--cli.c221
-rw-r--r--ipecamera/image.c83
-rw-r--r--ipecamera/ipecamera.h4
-rw-r--r--pci.h2
-rw-r--r--pcilib.h19
-rw-r--r--tools.c46
-rw-r--r--tools.h9
9 files changed, 327 insertions, 84 deletions
diff --git a/BUGS b/BUGS
new file mode 100644
index 0000000..9adf21c
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,18 @@
+IPECamera Hardware Bugs
+=======================
+ 1. Strange sequence writting CMOSIS registers
+ 2. Extra 8 byte padding in the end of frames
+ 3. Solve the conflict between DMA packet_length register and FPGA registers
+
+
+Incomplete Frames
+-----------------
+ If I'm trying to stream the data, the camera from time to time returns
+ incomplete frames. The provided part of the frame is coherent. But instead
+ of at least 3063824 bytes (just full frame without padding, normally I get
+ more due to the padding) I get only 3063808 bytes. This number 3063808 looks
+ like to be constant.
+
+ If I send another frame request, however, it looks I got the missing data with
+ the next frame.
+
diff --git a/ToDo b/ToDo
index dc3a5c4..4d6d286 100644
--- a/ToDo
+++ b/ToDo
@@ -15,11 +15,16 @@ Normal Priority (it would make just few things a bit easier)
2. Support FIFO reads/writes from/to registers
3. Provide OR and AND operations on registers in cli
4. Support writting a data from a binary file in cli
- 5. Use bus-addresses instead of physcial addresses for DMA
-
+ 5. Use bus-addresses instead of physcial addresses for DMA
+ 6. Instead of waiting in the end of trigger function to satisfy delay required
+ between consequent triggers, measure the timestamp when next trigger is
+ allowed and check it in the beginning of the trigger function.
+
Low Priority (only as generalization for other projects)
============
1. XML configurations describing registers (and DMA engines?)
2. Access register/bank lookups using hash tables
3. Support for Network Registers and Network DMA
4. Define a syntax for register dependencies / delays (?)
+
+ \ No newline at end of file
diff --git a/cli.c b/cli.c
index fdfc78f..cfe59dd 100644
--- a/cli.c
+++ b/cli.c
@@ -1,4 +1,5 @@
#define _POSIX_C_SOURCE 200112L
+#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
@@ -241,14 +242,15 @@ void Usage(int argc, char *argv[], const char *format, ...) {
" -a [fifo|dma]<bits> - Access type and bits per word (default: 32)\n"
" -e <l|b> - Endianess Little/Big (default: host)\n"
" -o <file> - Append output to file (default: stdout)\n"
-" -t <timeout> - Timeout in microseconds\n"
+" -t <timeout|unlimited> - 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"
+" --run-time <us> - Limit time to grab/trigger events\n"
+" -t <timeout|unlimited> - Timeout to stop if no events triggered\n"
+" --trigger-rate <tps> - Generate tps triggers per second\n"
+" --trigger-time <us> - Specifies delay between triggers (us)\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"
@@ -1072,19 +1074,41 @@ typedef struct {
pcilib_event_data_type_t data;
FILE *output;
+ pcilib_timeout_t timeout;
size_t run_time;
size_t trigger_time;
+ size_t max_triggers;
+
+ int event_pending; /**< Used to detect that we have read previously triggered event */
+ int trigger_thread_started; /**< Indicates that trigger thread is ready and we can't procced to start event recording */
+ int started; /**< Indicates that recording is started */
int run_flag;
+
+ struct timeval last_frame;
+ size_t trigger_count;
+ size_t frame_count;
+ size_t broken_count;
+
+ struct timeval stop_time;
} GRABContext;
int GrabCallback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user) {
-/* int err;
+ int err;
void *data;
size_t size, written;
GRABContext *ctx = (GRABContext*)user;
pcilib_t *handle = ctx->handle;
+
+ gettimeofday(&ctx->last_frame, NULL);
+
+ ctx->event_pending = 0;
+ ctx->frame_count++;
+
+ if (info->flags&PCILIB_EVENT_INFO_FLAG_BROKEN) ctx->broken_count++;
+
+/*
FILE *o = ctx->output;
data = pcilib_get_data(handle, ctx->event, ctx->data, &size);
@@ -1109,47 +1133,171 @@ int raw_data(pcilib_event_id_t event_id, pcilib_event_info_t *info, pcilib_event
// printf("%i\n", event_id);
}
+
void *Trigger(void *user) {
+ struct timeval start;
+
GRABContext *ctx = (GRABContext*)user;
+ size_t trigger_time = ctx->trigger_time;
+ size_t max_triggers = ctx->max_triggers;
- pcilib_trigger(ctx->handle, PCILIB_EVENT0, 0, NULL);
- usleep(3000);
- pcilib_trigger(ctx->handle, PCILIB_EVENT0, 0, NULL);
+ ctx->trigger_thread_started = 1;
+ ctx->event_pending = 1;
+ while (!ctx->started);
+
+ gettimeofday(&start, NULL);
+ do {
+ pcilib_trigger(ctx->handle, PCILIB_EVENT0, 0, NULL);
+ if ((++ctx->trigger_count == max_triggers)&&(max_triggers)) break;
+
+ if (trigger_time) {
+ pcilib_add_timeout(&start, trigger_time);
+ if ((ctx->stop_time.tv_sec)&&(pcilib_timecmp(&start, &ctx->stop_time)>0)) break;
+ pcilib_sleep_until_deadline(&start);
+ } else {
+ while ((ctx->event_pending)&&(ctx->run_flag)) usleep(10);
+ ctx->event_pending = 1;
+ }
+ } while (ctx->run_flag);
+
+ ctx->trigger_thread_started = 0;
+
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) {
+void *Monitor(void *user) {
+ struct timeval deadline;
+
+ GRABContext *ctx = (GRABContext*)user;
+ pcilib_timeout_t timeout = ctx->timeout;
+
+ if (timeout == PCILIB_TIMEOUT_INFINITE) timeout = 0;
+
+// while (!ctx->started);
+
+ if (timeout) {
+ memcpy(&deadline, &ctx->last_frame, sizeof(struct timeval));
+ pcilib_add_timeout(&deadline, timeout);
+ }
+
+ while (ctx->run_flag) {
+ if (timeout) {
+ if (pcilib_calc_time_to_deadline(&deadline) == 0) {
+ memcpy(&deadline, &ctx->last_frame, sizeof(struct timeval));
+ pcilib_add_timeout(&deadline, timeout);
+
+ if (pcilib_calc_time_to_deadline(&deadline) == 0) {
+ pcilib_stop(ctx->handle, PCILIB_EVENT_FLAG_STOP_ONLY);
+ break;
+ }
+ }
+ }
+
+ usleep(100000);
+ }
+
+ 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, pcilib_timeout_t timeout, PARTITION partition, FORMAT format, size_t buffer_size, FILE *ofile) {
int err;
GRABContext ctx;
void *data = NULL;
size_t size, written;
+ pthread_t monitor_thread;
pthread_t trigger_thread;
+ pthread_attr_t attr;
+ struct sched_param sched;
+
+ struct timeval start, end;
+ pcilib_event_flags_t flags;
ctx.handle = handle;
ctx.output = ofile;
ctx.event = PCILIB_EVENT0;
ctx.run_time = run_time;
- ctx.trigger_time = trigger_time;
+ ctx.timeout = timeout;
+ ctx.frame_count = 0;
+
+ ctx.started = 0;
+ ctx.trigger_thread_started = 0;
ctx.run_flag = 1;
- // ignoring event for now
- pcilib_configure_autostop(handle, 2, 1000000);//PCILIB_TIMEOUT_TRIGGER);
+ memset(&ctx.stop_time, 0, sizeof(struct timeval));
+
+// printf("Limits: %lu %lu %lu\n", num, run_time, timeout);
+ pcilib_configure_autostop(handle, num, run_time);//PCILIB_TIMEOUT_TRIGGER);
pcilib_configure_rawdata_callback(handle, &raw_data, NULL);
+
+ flags = PCILIB_EVENT_FLAGS_DEFAULT;
+ // PCILIB_EVENT_FLAG_RAW_DATA_ONLY
+
+ if (grab_mode&GRAB_MODE_TRIGGER) {
+ if (!trigger_time) {
+ // Otherwise, we will trigger next event after previous one is read
+ if (((grab_mode&GRAB_MODE_GRAB) == 0)&&((flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY)==0)) trigger_time = PCILIB_TRIGGER_TIMEOUT;
+ }
+
+ ctx.max_triggers = num;
+ ctx.trigger_count = 0;
+ ctx.trigger_time = trigger_time;
+
+ // We don't really care if RT priority is imposible
+ pthread_attr_init(&attr);
+ if (!pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) {
+ sched.sched_priority = sched_get_priority_min(SCHED_FIFO);
+ pthread_attr_setschedparam(&attr, &sched);
+ }
+
+ // Start triggering thread and wait until it is schedulled
+ if (pthread_create(&trigger_thread, &attr, Trigger, (void*)&ctx))
+ Error("Error spawning trigger thread");
+
+ while (!ctx.trigger_thread_started) usleep(10);
+ }
+
+ gettimeofday(&start, NULL);
+
+ if (grab_mode&GRAB_MODE_GRAB) {
+ err = pcilib_start(handle, PCILIB_EVENTS_ALL, PCILIB_EVENT_FLAGS_DEFAULT);
+ if (err) Error("Failed to start event engine, error %i", err);
+ }
+
+ ctx.started = 1;
+
+ if (run_time) {
+ ctx.stop_time.tv_usec = start.tv_usec + run_time%1000000;
+ if (ctx.stop_time.tv_usec > 999999) {
+ ctx.stop_time.tv_usec -= 1000000;
+ __sync_synchronize();
+ ctx.stop_time.tv_sec = start.tv_sec + 1 + run_time / 1000000;
+ } else {
+ __sync_synchronize();
+ ctx.stop_time.tv_sec = start.tv_sec + run_time / 1000000;
+ }
+ }
+
+ memcpy(&ctx.last_frame, &start, sizeof(struct timeval));
+ if (pthread_create(&monitor_thread, NULL, Monitor, (void*)&ctx))
+ Error("Error spawning monitoring thread");
- err = pcilib_start(handle, PCILIB_EVENTS_ALL, PCILIB_EVENT_FLAGS_DEFAULT);
- if (err) Error("Failed to start event engine, error %i", err);
+ if (grab_mode&GRAB_MODE_GRAB) {
+ err = pcilib_stream(handle, &GrabCallback, &ctx);
+ if (err) Error("Error streaming events, error %i", err);
+ }
- if (pthread_create(&trigger_thread, NULL, Trigger, (void*)&ctx))
- Error("Error starting trigger thread");
+ ctx.run_flag = 0;
-// sleep(1);
- err = pcilib_stream(handle, &GrabCallback, &ctx);
- if (err) Error("Error streaming events, error %i", err);
+ if (grab_mode&GRAB_MODE_TRIGGER) {
+ while (ctx.trigger_thread_started) usleep(10);
+ }
- pcilib_stop(handle, PCILIB_EVENT_FLAGS_DEFAULT);
+ if (grab_mode&GRAB_MODE_GRAB) {
+ pcilib_stop(handle, PCILIB_EVENT_FLAGS_DEFAULT);
+ }
/*
err = pcilib_grab(handle, PCILIB_EVENTS_ALL, &size, &data, PCILIB_TIMEOUT_TRIGGER);
@@ -1157,8 +1305,14 @@ int TriggerAndGrab(pcilib_t *handle, GRAB_MODE grab_mode, const char *event, con
Error("Grabbing event is failed");
}
*/
- ctx.run_flag = 0;
- pthread_join(trigger_thread, NULL);
+
+ pthread_join(monitor_thread, NULL);
+
+ if (grab_mode&GRAB_MODE_TRIGGER) {
+ pthread_join(trigger_thread, NULL);
+ }
+
+ // print information
return 0;
}
@@ -1675,6 +1829,7 @@ int main(int argc, char **argv) {
int size_set = 0;
int timeout_set = 0;
+ int run_time_set = 0;
while ((c = getopt_long(argc, argv, "hqilr::w::g::d:m:t:b:a:s:e:o:", long_options, NULL)) != (unsigned char)-1) {
extern int optind;
@@ -1887,7 +2042,7 @@ int main(int argc, char **argv) {
if (strcasecmp(optarg, "unlimited"))
Usage(argc, argv, "Invalid size is specified (%s)", optarg);
else
- size = (size_t)-1;
+ size = 0;//(size_t)-1;
size_set = 1;
break;
@@ -1903,7 +2058,10 @@ int main(int argc, char **argv) {
break;
case OPT_TIMEOUT:
if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &timeout) != 1))
- Usage(argc, argv, "Invalid timeout is specified (%s)", optarg);
+ if (strcasecmp(optarg, "unlimited"))
+ Usage(argc, argv, "Invalid timeout is specified (%s)", optarg);
+ else
+ timeout = PCILIB_TIMEOUT_INFINITE;
timeout_set = 1;
break;
case OPT_OUTPUT:
@@ -1921,7 +2079,11 @@ int main(int argc, char **argv) {
break;
case OPT_RUN_TIME:
if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &run_time) != 1))
- Usage(argc, argv, "Invalid timeout is specified (%s)", optarg);
+ if (strcasecmp(optarg, "unlimited"))
+ Usage(argc, argv, "Invalid run-time is specified (%s)", optarg);
+ else
+ run_time = 0;
+ run_time_set = 1;
break;
case OPT_TRIGGER_TIME:
if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &trigger_time) != 1))
@@ -1931,7 +2093,7 @@ int main(int argc, char **argv) {
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;
+ trigger_time = (1000000 / ztmp) + ((1000000 % ztmp)?1:0);
break;
case OPT_BUFFER:
if (optarg) num_offset = optarg;
@@ -2099,6 +2261,11 @@ int main(int argc, char **argv) {
else if (!strcmp(fsname, "raw")) partition = PARTITION_RAW;
}
}
+
+ if (!timeout_set) {
+ if (run_time) timeout = PCILIB_TIMEOUT_INFINITE;
+ else timeout = PCILIB_EVENT_TIMEOUT;
+ }
}
if (mode != MODE_GRAB) {
@@ -2167,7 +2334,7 @@ int main(int argc, char **argv) {
pcilib_reset(handle);
break;
case MODE_GRAB:
- TriggerAndGrab(handle, grab_mode, event, data_type, size, run_time, trigger_time, partition, format, buffer, ofile);
+ TriggerAndGrab(handle, grab_mode, event, data_type, size, run_time, trigger_time, timeout, partition, format, buffer, ofile);
break;
case MODE_LIST_DMA:
ListDMA(handle, fpga_device, model_info);
diff --git a/ipecamera/image.c b/ipecamera/image.c
index ad99246..3b3c9df 100644
--- a/ipecamera/image.c
+++ b/ipecamera/image.c
@@ -70,9 +70,6 @@ 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;
@@ -114,14 +111,9 @@ struct ipecamera_s {
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 */
@@ -373,10 +365,14 @@ static int ipecamera_resolve_event_id(ipecamera_t *ctx, pcilib_event_id_t evid)
}
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;
// memset(ctx->cmask + ctx->buffer_pos * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t));
if ((ctx->event_id == ctx->autostop.evid)&&(ctx->event_id)) {
@@ -384,7 +380,7 @@ static inline int ipecamera_new_frame(ipecamera_t *ctx) {
return 1;
}
- if (check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) {
+ if (pcilib_check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) {
ctx->run_reader = 0;
return 1;
}
@@ -395,6 +391,7 @@ static inline int ipecamera_new_frame(ipecamera_t *ctx) {
static uint32_t frame_magic[6] = { 0x51111111, 0x52222222, 0x53333333, 0x54444444, 0x55555555, 0x56666666 };
#define IPECAMERA_BUG_MULTIFRAME_PACKETS
+#define IPECAMERA_BUG_INCOMPLETE_PACKETS
static int ipecamera_data_callback(void *user, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
int eof = 0;
@@ -405,12 +402,28 @@ static int ipecamera_data_callback(void *user, pcilib_dma_flags_t flags, size_t
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)))) {
- //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 ((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);
+ } else {
+// pcilib_warning("Frame magic is not found, ignoring broken data...");
+ return PCILIB_STREAMING_CONTINUE;
+ }
}
#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS
@@ -423,9 +436,12 @@ static int ipecamera_data_callback(void *user, pcilib_dma_flags_t flags, size_t
if (need < bufsize) {
extra_data = bufsize - need;
- bufsize = need;
+ //bufsize = need;
eof = 1;
}
+
+ // just rip of padding
+ bufsize = ctx->raw_size - ctx->cur_size;
}
#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */
@@ -471,15 +487,18 @@ static void *ipecamera_reader_thread(void *user) {
if (err) {
if (err == PCILIB_ERROR_TIMEOUT) {
if (ctx->cur_size > ctx->raw_size) ipecamera_new_frame(ctx);
- if (check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) {
+#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);
+ //usleep(1000);
}
ctx->run_streamer = 0;
@@ -667,6 +686,11 @@ int ipecamera_stop(pcilib_context_t *vctx, pcilib_event_flags_t flags) {
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);
@@ -734,22 +758,10 @@ int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigg
SET_REG(control_reg, IPECAMERA_IDLE|IPECAMERA_READOUT_FLAG);
-// SET_REG(control_reg, IPECAMERA_READOUT);
+ // 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
- // DS: check for overflow
-/*
-
- 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;
- }
- }
-
- return err;
-*/
+ return 0;
}
int ipecamera_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, void *user) {
@@ -798,8 +810,7 @@ int ipecamera_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, v
ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
}
-
-
+
return err;
}
@@ -820,9 +831,9 @@ int ipecamera_next_event(pcilib_context_t *vctx, pcilib_event_t event_mask, pcil
if (ctx->reported_id == ctx->event_id) {
if (timeout) {
- calc_deadline(&tv, timeout);
+ pcilib_calc_deadline(&tv, timeout);
- while ((calc_time_to_deadline(&tv) > 0)&&(ctx->reported_id == ctx->event_id))
+ while ((pcilib_calc_time_to_deadline(&tv) > 0)&&(ctx->reported_id == ctx->event_id))
usleep(IPECAMERA_NOFRAME_SLEEP);
}
diff --git a/ipecamera/ipecamera.h b/ipecamera/ipecamera.h
index d15d1f2..c89c6c9 100644
--- a/ipecamera/ipecamera.h
+++ b/ipecamera/ipecamera.h
@@ -23,6 +23,10 @@ typedef enum {
typedef uint16_t ipecamera_change_mask_t;
typedef uint16_t ipecamera_pixel_t;
+typedef struct {
+ pcilib_event_info_t info;
+ 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/pci.h b/pci.h
index 30c1bfe..f3ced74 100644
--- a/pci.h
+++ b/pci.h
@@ -1,6 +1,8 @@
#ifndef _PCITOOL_PCI_H
#define _PCITOOL_PCI_H
+#define PCILIB_EVENT_TIMEOUT 1000000 /**< us */
+#define PCILIB_TRIGGER_TIMEOUT 100000 /**< us */
#define PCILIB_DMA_TIMEOUT 10000 /**< us */
#define PCILIB_DMA_SKIP_TIMEOUT 1000000 /**< us */
#define PCILIB_REGISTER_TIMEOUT 10000 /**< us */
diff --git a/pcilib.h b/pcilib.h
index a51b050..18806f9 100644
--- a/pcilib.h
+++ b/pcilib.h
@@ -86,11 +86,16 @@ typedef enum {
typedef enum {
PCILIB_EVENT_FLAGS_DEFAULT = 0,
- PCILIB_EVENT_FLAG_RAW_DATA_ONLY = 1,
- PCILIB_EVENT_FLAG_EOF = 2
+ PCILIB_EVENT_FLAG_RAW_DATA_ONLY = 1, /**< Do not parse data, just read raw and pass it to rawdata callback */
+ PCILIB_EVENT_FLAG_STOP_ONLY = 1, /**< Do not cleanup, just stop acquiring new frames, the cleanup should be requested afterwards */
+ PCILIB_EVENT_FLAG_EOF = 2 /**< Indicates that it is the last part of the frame (not required) */
} pcilib_event_flags_t;
typedef enum {
+ PCILIB_EVENT_INFO_FLAG_BROKEN = 1 /**< Indicates broken frames (if this flag is fales, the frame still can be broken) */
+} pcilib_event_info_flags_t;
+
+typedef enum {
PCILIB_REGISTER_STANDARD = 0,
PCILIB_REGISTER_FIFO,
PCILIB_REGISTER_BITS
@@ -118,18 +123,16 @@ 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_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 */
+ uint64_t seqnum; /**< we will add seqnum_overflow if required */
+ uint64_t offset; /**< nanoseconds */
+ struct timeval timestamp; /**< most accurate timestamp */
+ pcilib_event_info_flags_t flags; /**< flags */
} pcilib_event_info_t;
/**<
diff --git a/tools.c b/tools.c
index c2d8bd7..4874f7f 100644
--- a/tools.c
+++ b/tools.c
@@ -1,9 +1,12 @@
+#define _POSIX_C_SOURCE 200112L
+
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <assert.h>
#include <ctype.h>
+#include <time.h>
#include <arpa/inet.h>
#include <sys/time.h>
@@ -251,20 +254,24 @@ int pcilib_get_page_mask() {
return pagemask;
}
-int calc_deadline(struct timeval *tv, pcilib_timeout_t timeout) {
- gettimeofday(tv, NULL);
+int pcilib_add_timeout(struct timeval *tv, pcilib_timeout_t timeout) {
tv->tv_usec += timeout%1000000;
if (tv->tv_usec > 999999) {
tv->tv_usec -= 1000000;
- tv->tv_sec = 1 + timeout/1000000;
+ tv->tv_sec += 1 + timeout/1000000;
} else {
- tv->tv_sec = timeout/1000000;
+ tv->tv_sec += timeout/1000000;
}
-
+}
+
+int pcilib_calc_deadline(struct timeval *tv, pcilib_timeout_t timeout) {
+ gettimeofday(tv, NULL);
+ pcilib_add_timeout(tv, timeout);
+
return 0;
}
-int check_deadline(struct timeval *tve, pcilib_timeout_t timeout) {
+int pcilib_check_deadline(struct timeval *tve, pcilib_timeout_t timeout) {
int64_t res;
struct timeval tvs;
@@ -272,12 +279,15 @@ int check_deadline(struct timeval *tve, pcilib_timeout_t timeout) {
gettimeofday(&tvs, NULL);
res = ((tve->tv_sec - tvs.tv_sec)*1000000 + (tve->tv_usec - tvs.tv_usec));
- if (res < timeout) return 1;
+ // Hm... Some problems comparing signed and unsigned. So, sign check first
+ if ((res < 0)||(res < timeout)) {
+ return 1;
+ }
return 0;
}
-pcilib_timeout_t calc_time_to_deadline(struct timeval *tve) {
+pcilib_timeout_t pcilib_calc_time_to_deadline(struct timeval *tve) {
int64_t res;
struct timeval tvs;
@@ -287,3 +297,23 @@ pcilib_timeout_t calc_time_to_deadline(struct timeval *tve) {
if (res < 0) return 0;
return res;
}
+
+int pcilib_sleep_until_deadline(struct timeval *tv) {
+ struct timespec wait;
+ pcilib_timeout_t duration;
+
+ duration = pcilib_calc_time_to_deadline(tv);
+ wait.tv_sec = duration / 1000000;
+ wait.tv_nsec = 1000 * (duration % 1000000);
+ nanosleep(&wait, NULL);
+
+ return 0;
+}
+
+int pcilib_timecmp(struct timeval *tv1, struct timeval *tv2) {
+ if (tv1->tv_sec > tv2->tv_sec) return 1;
+ else if (tv1->tv_sec > tv2->tv_sec) return -1;
+ else if (tv1->tv_usec > tv2->tv_usec) return 1;
+ else if (tv1->tv_usec < tv2->tv_usec) return -1;
+ return 0;
+}
diff --git a/tools.h b/tools.h
index 6ab58f9..8ab931d 100644
--- a/tools.h
+++ b/tools.h
@@ -34,8 +34,11 @@ 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);
+int pcilib_add_timeout(struct timeval *tv, pcilib_timeout_t timeout);
+int pcilib_calc_deadline(struct timeval *tv, pcilib_timeout_t timeout);
+int pcilib_check_deadline(struct timeval *tve, pcilib_timeout_t timeout);
+pcilib_timeout_t pcilib_calc_time_to_deadline(struct timeval *tve);
+int pcilib_sleep_until_deadline(struct timeval *tv);
+int pcilib_timecmp(struct timeval *tv1, struct timeval *tv2);
#endif /* _PCITOOL_TOOS_H */