Explorar o código

Initial support of event streaming in cli

Suren A. Chilingaryan %!s(int64=12) %!d(string=hai) anos
pai
achega
1ac7751e5b
Modificáronse 9 ficheiros con 327 adicións e 84 borrados
  1. 18 0
      BUGS
  2. 7 2
      ToDo
  3. 194 27
      cli.c
  4. 47 36
      ipecamera/image.c
  5. 4 0
      ipecamera/ipecamera.h
  6. 2 0
      pci.h
  7. 11 8
      pcilib.h
  8. 38 8
      tools.c
  9. 6 3
      tools.h

+ 18 - 0
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.
+

+ 7 - 2
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 (?)
+
+ 

+ 194 - 27
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);

+ 47 - 36
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);
 	}
 	

+ 4 - 0
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);
 

+ 2 - 0
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 */

+ 11 - 8
pcilib.h

@@ -86,10 +86,15 @@ 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,
@@ -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;
 
 /**<

+ 38 - 8
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;
+}

+ 6 - 3
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 */