Browse Source

new event architecture, first trial

Suren A. Chilingaryan 12 years ago
parent
commit
869ed99dbc
20 changed files with 1214 additions and 514 deletions
  1. 4 3
      Makefile
  2. 35 7
      NOTES
  3. 255 19
      cli.c
  4. 7 6
      dma.c
  5. 13 11
      dma/nwl_engine.c
  6. 2 1
      error.h
  7. 176 20
      event.c
  8. 29 5
      event.h
  9. 367 411
      ipecamera/image.c
  10. 6 5
      ipecamera/image.h
  11. 2 1
      ipecamera/ipecamera.h
  12. 12 4
      ipecamera/model.h
  13. 1 3
      pci.c
  14. 3 3
      pci.h
  15. 78 13
      pcilib.h
  16. 173 0
      pcitool/sysinfo.c
  17. 7 0
      pcitool/sysinfo.h
  18. 1 1
      tests/grab.sh
  19. 38 1
      tools.c
  20. 5 0
      tools.h

+ 4 - 3
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 $@ $<
 

+ 35 - 7
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 

+ 255 - 19
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"
@@ -45,6 +48,11 @@
 
 typedef uint8_t access_t;
 
+typedef enum {
+    GRAB_MODE_GRAB = 1,
+    GRAB_MODE_TRIGGER = 2
+} GRAB_MODE;
+
 typedef enum {
     MODE_INVALID,
     MODE_INFO,
@@ -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);

+ 7 - 6
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) {

+ 13 - 11
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;
 

+ 2 - 1
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;
 
 

+ 176 - 20
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;
 }

+ 29 - 5
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 */

File diff suppressed because it is too large
+ 367 - 411
ipecamera/image.c


+ 6 - 5
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);
 

+ 2 - 1
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,

+ 12 - 4
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

+ 1 - 3
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;

+ 3 - 3
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] = {

+ 78 - 13
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;
 
 
@@ -71,6 +72,24 @@ typedef enum {
     PCILIB_DMA_FLAG_IGNORE_ERRORS = 16	/**< do not crash on errors, but return appropriate error codes */
 } 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,
@@ -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.

+ 173 - 0
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;
+}

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

+ 1 - 1
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

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

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

Some files were not shown because too many files changed in this diff