Browse Source

new event architecture, first trial

Suren A. Chilingaryan 12 năm trước cách đây
mục cha
commit
869ed99dbc
20 tập tin đã thay đổi với 1214 bổ sung514 xóa
  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 */

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 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 */

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác