Преглед изворни кода

Infrastructure for event API

Suren A. Chilingaryan пре 13 година
родитељ
комит
39b33ce4be
14 измењених фајлова са 866 додато и 117 уклоњено
  1. 2 1
      Makefile
  2. 84 8
      cli.c
  3. 3 0
      common.mk
  4. 1 0
      driver/base.c
  5. 1 0
      error.h
  6. 0 86
      ipecamera.h
  7. 287 0
      ipecamera/image.c
  8. 22 0
      ipecamera/image.h
  9. 6 0
      ipecamera/ipecamera.h
  10. 13 5
      ipecamera/model.c
  11. 110 0
      ipecamera/model.h
  12. 276 11
      pci.c
  13. 4 4
      pci.h
  14. 57 2
      pcilib.h

+ 2 - 1
Makefile

@@ -14,7 +14,7 @@ include common.mk
 ###############################################################
 # Target definitions
 
-OBJECTS = pci.o ipecamera.o default.o tools.o
+OBJECTS = pci.o  default.o tools.o ipecamera/model.o ipecamera/image.o
 
 libpcilib.so: $(OBJECTS)
 	echo -e "LD \t$@"
@@ -26,6 +26,7 @@ pci: cli.o libpcilib.so
 
 install: pci
 	install -m 644 pcilib.h $(DESTDIR)/include
+	install -m 644 ipecamera/ipecamera.h $(DESTDIR)/include
 	if [ -d $(DESTDIR)/lib64 ]; then install -m 755 libpcilib.so $(DESTDIR)/lib64; else install -m 755 libpcilib.so $(DESTDIR)/lib; fi
 	install -m 755 pci $(DESTDIR)/bin
 	ldconfig

+ 84 - 8
cli.c

@@ -18,7 +18,6 @@
 #include <getopt.h>
 
 #include "pci.h"
-#include "ipecamera.h"
 #include "tools.h"
 #include "kernel.h"
 
@@ -50,7 +49,9 @@ typedef enum {
     MODE_READ,
     MODE_READ_REGISTER,
     MODE_WRITE,
-    MODE_WRITE_REGISTER
+    MODE_WRITE_REGISTER,
+    MODE_RESET,
+    MODE_GRAB
 } MODE;
 
 typedef enum {
@@ -60,11 +61,14 @@ typedef enum {
     OPT_ACCESS = 'a',
     OPT_ENDIANESS = 'e',
     OPT_SIZE = 's',
+    OPT_OUTPUT = 'o',
     OPT_INFO = 'i',
     OPT_BENCHMARK = 'p',
     OPT_LIST = 'l',
     OPT_READ = 'r',
     OPT_WRITE = 'w',
+    OPT_GRAB = 'g',
+    OPT_RESET = 128,
     OPT_HELP = 'h',
 } OPTIONS;
 
@@ -75,11 +79,14 @@ static struct option long_options[] = {
     {"access",			required_argument, 0, OPT_ACCESS },
     {"endianess",		required_argument, 0, OPT_ENDIANESS },
     {"size",			required_argument, 0, OPT_SIZE },
+    {"size",			required_argument, 0, OPT_OUTPUT },
     {"info",			no_argument, 0, OPT_INFO },
     {"list",			no_argument, 0, OPT_LIST },
+    {"reset",			no_argument, 0, OPT_RESET },
     {"benchmark",		no_argument, 0, OPT_BENCHMARK },
     {"read",			optional_argument, 0, OPT_READ },
     {"write",			optional_argument, 0, OPT_WRITE },
+    {"grab",			optional_argument, 0, OPT_GRAB },
     {"help",			no_argument, 0, OPT_HELP },
     { 0, 0, 0, 0 }
 };
@@ -108,6 +115,8 @@ void Usage(int argc, char *argv[], const char *format, ...) {
 "	-p		- Performance Evaluation\n"
 "	-r <addr|reg>	- Read Data/Register\n"
 "	-w <addr|reg>	- Write Data/Register\n"
+"	-g <event>	- Grab Event\n"
+"	--reset		- Reset board\n"
 "	--help		- Help message\n"
 "\n"
 "  Addressing:\n"
@@ -121,6 +130,7 @@ void Usage(int argc, char *argv[], const char *format, ...) {
 "	-s <size>	- Number of words (default: 1)\n"
 "	-a <bitness>	- Bits per word (default: 32)\n"
 "	-e <l|b>	- Endianess Little/Big (default: host)\n"
+"	-o <file>	- Output to file (default: stdout)\n"
 "\n"
 "  Data:\n"
 "	Data can be specified as sequence of hexdecimal number or\n"
@@ -557,6 +567,38 @@ int WriteRegister(pcilib_t *handle, pcilib_model_t model, const char *bank, cons
     return 0;
 }
 
+int Grab(pcilib_t *handle, const char *output) {
+    int err;
+    
+    void *data = NULL;
+    size_t size, written;
+    
+    FILE *o;
+    
+    err = pcilib_grab(handle, PCILIB_ALL_EVENTS, &size, &data, NULL);
+    if (err) {
+	Error("Grabbing event is failed");
+    }
+
+    if (output) {    
+	o = fopen(output, "w");
+	if (!o) {
+	    Error("Failed to open file \"%s\"", output);
+	}
+	
+	printf("Writting %i bytes into %s...\n", size, output);
+    } else o = stdout;
+    
+    written = fwrite(data, 1, size, o);
+    if (written != size) {
+	if (written > 0) Error("Write failed, only %z bytes out of %z are stored", written, size);
+	else Error("Write failed");
+    }
+    
+    if (o != stdout) fclose(o);
+
+    return 0;
+}
 
 int main(int argc, char **argv) {
     int i;
@@ -571,16 +613,18 @@ int main(int argc, char **argv) {
     const char *reg = NULL;
     const char *bank = NULL;
     char **data = NULL;
+    const char *event = NULL;
     
     uintptr_t start = -1;
     size_t size = 1;
     access_t access = 4;
     int skip = 0;
     int endianess = 0;
+    const char *output = NULL;
 
     pcilib_t *handle;
     
-    while ((c = getopt_long(argc, argv, "hilpr::w::d:m:b:a:s:e:", long_options, NULL)) != (unsigned char)-1) {
+    while ((c = getopt_long(argc, argv, "hilpr::w::d:m:b:a:s:e:g:", long_options, NULL)) != (unsigned char)-1) {
 	extern int optind;
 	switch (c) {
 	    case OPT_HELP:
@@ -596,6 +640,11 @@ int main(int argc, char **argv) {
 
 		mode = MODE_LIST;
 	    break;
+	    case OPT_RESET:
+		if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
+
+		mode = MODE_RESET;
+	    break;
 	    case OPT_BENCHMARK:
 		if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
 
@@ -615,6 +664,13 @@ int main(int argc, char **argv) {
 		if (optarg) addr = optarg;
 		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");
+
+		mode = MODE_GRAB;
+		if (optarg) event = optarg;
+		else if ((optind < argc)&&(argv[optind][0] != '-')) event = argv[optind++];
+	    break;
 	    case OPT_DEVICE:
 		fpga_device = optarg;
 	    break;
@@ -652,6 +708,9 @@ int main(int argc, char **argv) {
 		} else Usage(argc, argv, "Invalid endianess is specified (%s)", optarg);
 		
 	    break;
+	    case OPT_OUTPUT:
+		output = optarg;
+	    break;
 	    default:
 		Usage(argc, argv, "Unknown option (%s)", argv[optind]);
 	}
@@ -674,11 +733,22 @@ int main(int argc, char **argv) {
         if (!addr) Usage(argc, argv, "The address is not specified");
         if (((argc - optind) == 1)&&(*argv[optind] == '*')) {
     	    int vallen = strlen(argv[optind]);
-	    data = (char**)malloc(size * (vallen + sizeof(char*)));
-	    if (!data) Error("Error allocating memory for data array");
-	    for (i = 0; i < size; i++) {
-		data[i] = ((char*)data) + size * sizeof(char*) + i * vallen;
-		strcpy(data[i], argv[optind] + 1);
+    	    if (vallen > 1) {
+		data = (char**)malloc(size * (vallen + sizeof(char*)));
+		if (!data) Error("Error allocating memory for data array");
+
+		for (i = 0; i < size; i++) {
+		    data[i] = ((char*)data) + size * sizeof(char*) + i * vallen;
+		    strcpy(data[i], argv[optind] + 1);
+		}
+	    } else {
+		data = (char**)malloc(size * (9 + sizeof(char*)));
+		if (!data) Error("Error allocating memory for data array");
+		
+		for (i = 0; i < size; i++) {
+		    data[i] = ((char*)data) + size * sizeof(char*) + i * 9;
+		    sprintf(data[i], "%x", i);
+		}
 	    }
         } else if ((argc - optind) == size) data = argv + optind;
         else Usage(argc, argv, "The %i data values is specified, but %i required", argc - optind, size);
@@ -757,6 +827,12 @@ int main(int argc, char **argv) {
         if (reg) WriteRegister(handle, model, bank, reg, data);
 	else WriteRegisterRange(handle, model, bank, start, size, data);
      break;
+     case MODE_RESET:
+        pcilib_reset(handle);
+     break;
+     case MODE_GRAB:
+        Grab(handle, output);
+     break;
     }
 
     pcilib_close(handle);

+ 3 - 0
common.mk

@@ -19,6 +19,9 @@ CFLAGS += $(addprefix -I ,$(INCDIR)) -fPIC -std=c99
 SRC = $(wildcard *.cpp)
 SRCC = $(wildcard *.c)
 
+SRC += $(wildcard ipecamera/*.cpp)
+SRCC += $(wildcard ipecamera/*.c)
+
 # Corresponding object files 
 OBJ = $(addprefix $(OBJDIR)/,$(SRC:.cpp=.o))
 OBJ += $(addprefix $(OBJDIR)/,$(SRCC:.c=.o))

+ 1 - 0
driver/base.c

@@ -626,6 +626,7 @@ int pcidriver_mmap_pci(pcidriver_privdata_t *privdata, struct vm_area_struct *vm
 
 	/* Check sizes */
 	vma_size = (vmap->vm_end - vmap->vm_start);
+
 	if ((vma_size != bar_length) &&
 	   ((bar_length < PAGE_SIZE) && (vma_size != PAGE_SIZE))) {
 		mod_info( "mmap size is not correct! bar: %lu - vma: %lu\n", bar_length, vma_size );

+ 1 - 0
error.h

@@ -12,6 +12,7 @@ enum {
     PCILIB_ERROR_NOTSUPPORTED,
     PCILIB_ERROR_NOTFOUND,
     PCILIB_ERROR_OUTOFRANGE,
+    PCILIB_ERROR_NOTINITIALIZED
 } pcilib_errot_t;
 
 

+ 0 - 86
ipecamera.h

@@ -1,86 +0,0 @@
-#ifndef _IPECAMERA_H
-#define _IPECAMERA_H
-
-#include <stdio.h>
-
-#include "pcilib.h"
-
-#define IPECAMERA_REGISTER_SPACE 0xfeaffc00
-#define IPECAMERA_REGISTER_WRITE (IPECAMERA_REGISTER_SPACE + 0)
-#define IPECAMERA_REGISTER_READ (IPECAMERA_REGISTER_WRITE + 4)
-
-#ifdef _IPECAMERA_C
-pcilib_register_bank_description_t ipecamera_register_banks[] = {
-    { PCILIB_REGISTER_BANK0, 128, IPECAMERA_REGISTER_PROTOCOL, IPECAMERA_REGISTER_READ,	IPECAMERA_REGISTER_WRITE, PCILIB_BIG_ENDIAN, 8, PCILIB_LITTLE_ENDIAN, "cmosis", "CMOSIS CMV2000 Registers" },
-    { PCILIB_REGISTER_BANK1, 64, PCILIB_DEFAULT_PROTOCOL, IPECAMERA_REGISTER_SPACE, IPECAMERA_REGISTER_SPACE, PCILIB_BIG_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "fpga", "IPECamera Registers" },
-    { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL }
-};
-
-pcilib_register_description_t ipecamera_registers[] = {
-{1, 	16, 	1088, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines",  ""},
-{3, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start1", ""},
-{5, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start2", ""},
-{7, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start3", ""},
-{9, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start4", ""},
-{11,	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start5", ""},
-{13, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start6", ""},
-{15, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start7", ""},
-{17, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start8", ""},
-{19, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines1", ""},
-{21, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines2", ""},
-{23, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines3", ""},
-{25, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines4", ""},
-{27, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines5", ""},
-{29, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines6", ""},
-{31, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines7", ""},
-{33, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines8", ""},
-{35, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "sub_s", ""},
-{37, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "sub_a", ""},
-{39, 	1, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "color", ""},
-{40, 	2, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "image_flipping", ""},
-{41, 	2, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_flags", ""},
-{42, 	24, 	1088, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_time", ""},
-{45, 	24, 	1088, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_step", ""},
-{48, 	24, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_kp1", ""},
-{51, 	24, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_kp2", ""},
-{54, 	2, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "nr_slopes", ""},
-{55, 	8, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_seq", ""},
-{56, 	24, 	1088, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_time2", ""},
-{59, 	24, 	1088, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_step2", ""},
-{68, 	2, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "nr_slopes2", ""},
-{69, 	8, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_seq2", ""},
-{70, 	16, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_frames", ""},
-{72, 	2, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "output_mode", ""},
-{78, 	12, 	85, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "training_pattern", ""},
-{80, 	18, 	0x3FFFF,PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "channel_en", ""},
-{89, 	8, 	96, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "vlow2", ""},
-{90, 	8, 	96, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "vlow3", ""},
-{100, 	14, 	16260, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "offset", ""},
-{102, 	2, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "pga", ""},
-{103, 	8, 	32, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "adc_gain", ""},
-{111, 	1, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "bit_mode", ""},
-{112, 	2, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "adc_resolution", ""},
-{126, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "temp", ""},
-{0,	32,	0,	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "spi_conf_input", ""},
-{1,	32,	0,	PCILIB_REGISTER_R,  PCILIB_REGISTER_BANK1, "spi_conf_output", ""},
-{2,	32,	0,	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "spi_clk_speed", ""},
-{3,	32,	0,	PCILIB_REGISTER_R,  PCILIB_REGISTER_BANK1, "firmware_version", ""},
-{6,	16,	0,	PCILIB_REGISTER_R,  PCILIB_REGISTER_BANK1, "cmosis_temperature", ""},
-{7,	32,	0,	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "temperature_sample_timing", ""},
-{0,	0,	0,	0,                  0,                     NULL, NULL}
-};
-
-pcilib_register_range_t ipecamera_register_ranges[] = {
-    {0, 128, PCILIB_REGISTER_BANK0}, {0, 0, 0}
-};
-
-#else
-extern pcilib_register_description_t ipecamera_registers[];
-extern pcilib_register_bank_description_t ipecamera_register_banks[];
-extern pcilib_register_range_t ipecamera_register_ranges[];
-#endif 
-
-int ipecamera_read(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t *value);
-int ipecamera_write(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t value);
-
-#endif /* _IPECAMERA_H */

+ 287 - 0
ipecamera/image.c

@@ -0,0 +1,287 @@
+#define _IPECAMERA_IMAGE_C
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <assert.h>
+
+#include "../tools.h"
+#include "../error.h"
+
+#include "pcilib.h"
+
+#include "model.h"
+#include "image.h"
+
+#define IPECAMERA_SLEEP_TIME 250000
+
+struct ipecamera_s {
+    pcilib_t *pcilib;
+
+    char *data;
+    size_t size;
+
+    pcilib_callback_t cb;
+    void *cb_user;
+    
+    int width;
+    int height;
+
+    pcilib_event_id_t event_id;
+
+    pcilib_register_t control_reg, status_reg;
+    pcilib_register_t start_reg, end_reg;
+    pcilib_register_t lines_reg;
+    pcilib_register_t exposure_reg;
+
+    void *buffer;    
+};
+
+
+#define FIND_REG(var, bank, name)  \
+        ctx->var = pcilib_find_register(pcilib, bank, name); \
+	if (ctx->var ==  PCILIB_REGISTER_INVALID) { \
+	    err = -1; \
+	    pcilib_error("Unable to find a %s register", name); \
+	}
+    
+
+#define GET_REG(reg, var) \
+    err = pcilib_read_register_by_id(pcilib, ctx->reg, &var); \
+    if (err) { \
+	pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \
+	return err; \
+    }
+
+#define SET_REG(reg, val) \
+    err = pcilib_write_register_by_id(pcilib, ctx->reg, val); \
+    if (err) { \
+	pcilib_error("Error writting %s register", ipecamera_registers[ctx->reg].name); \
+	return err; \
+    }
+
+#define CHECK_REG(reg, check) \
+    err = pcilib_read_register_by_id(pcilib, ctx->reg, &value); \
+    if (err) { \
+	pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \
+	return err; \
+    } \
+    if (!(check)) { \
+	pcilib_error("Unexpected value (%li) of register %s", value, ipecamera_registers[ctx->reg].name); \
+	return err; \
+    }
+
+
+void *ipecamera_init(pcilib_t *pcilib) {
+    int err = 0; 
+    
+    ipecamera_t *ctx = malloc(sizeof(ipecamera_t));
+
+    if (ctx) {
+	ctx->pcilib = pcilib;
+
+	ctx->data = pcilib_resolve_data_space(pcilib, 0, &ctx->size);
+	if (!ctx->data) {
+	    err = -1;
+	    pcilib_error("Unable to resolve the data space");
+	}
+	
+	ctx->buffer = malloc(1088 * 2048 * 2);
+	if (!ctx->buffer) {
+	    err = -1;
+	    pcilib_error("Unable to allocate ring buffer");
+	}
+	
+	FIND_REG(status_reg, "fpga", "status");
+	FIND_REG(control_reg, "fpga", "control");
+	FIND_REG(start_reg, "fpga", "start_address");
+	FIND_REG(end_reg, "fpga", "end_address");
+
+	FIND_REG(lines_reg, "cmosis", "number_lines");
+	FIND_REG(exposure_reg, "cmosis", "exp_time");
+
+	if (err) {
+	    free(ctx);
+	    return NULL;
+	}
+    }
+    
+    return (void*)ctx;
+}
+
+void ipecamera_free(void *vctx) {
+    if (vctx) {
+	ipecamera_t *ctx = (ipecamera_t*)vctx;
+	
+	if (ctx->buffer) free(ctx->buffer);
+	free(ctx);
+    }
+}
+
+int ipecamera_reset(void *vctx) {
+    int err;
+    pcilib_t *pcilib;
+    ipecamera_t *ctx = (ipecamera_t*)vctx;
+
+    pcilib_register_t control, status;
+    pcilib_register_value_t value;
+    
+    if (!ctx) {
+	pcilib_error("IPECamera imaging is not initialized");
+	return PCILIB_ERROR_NOTINITIALIZED;
+    }
+    
+    pcilib = ctx->pcilib;
+    control = ctx->control_reg;
+    status = ctx->status_reg;
+
+	// Set Reset bit to CMOSIS
+    err = pcilib_write_register_by_id(pcilib, control, 5);
+    if (err) {
+	pcilib_error("Error setting CMOSIS reset bit");
+	return err;
+    }
+    usleep(IPECAMERA_SLEEP_TIME);
+
+	// Remove Reset bit to CMOSIS
+    err = pcilib_write_register_by_id(pcilib, control, 1);
+    if (err) {
+	pcilib_error("Error reseting CMOSIS reset bit");
+	return err;
+    }
+    usleep(IPECAMERA_SLEEP_TIME);
+
+	// Special settings for CMOSIS v.2
+    value = 01; err = pcilib_write_register_space(pcilib, "cmosis", 115, 1, &value);
+    if (err) {
+	pcilib_error("Error setting CMOSIS configuration");
+	return err;
+    }
+    usleep(IPECAMERA_SLEEP_TIME);
+    
+    value = 07; err = pcilib_write_register_space(pcilib, "cmosis", 82, 1, &value);
+    if (err) {
+	pcilib_error("Error setting CMOSIS configuration");
+	return err;
+    }
+    usleep(IPECAMERA_SLEEP_TIME);
+
+	// This is temporary for verification purposes
+    memset(ctx->data, 0, ctx->size);
+
+    err = pcilib_read_register_by_id(pcilib, status, &value);
+    if (err) {
+	pcilib_error("Error reading status register");
+	return err;
+    }
+
+    if (value != 0x0849FFFF) {
+	pcilib_error("Unexpected value (%lx) of status register", value);
+	return PCILIB_ERROR_VERIFY;
+    }
+
+    return 0;    
+}
+
+int ipecamera_start(void *vctx, pcilib_event_t event_mask, pcilib_callback_t cb, void *user) {
+    ipecamera_t *ctx = (ipecamera_t*)vctx;
+
+    if (!ctx) {
+	pcilib_error("IPECamera imaging is not initialized");
+	return PCILIB_ERROR_NOTINITIALIZED;
+    }
+    
+    ctx->cb = cb;
+    ctx->cb_user = user;
+    
+    
+    ctx->event_id = 0;
+    
+    ctx->width = 1270;
+    ctx->height = 1088; //GET_REG(lines_reg, lines);
+
+    // allocate memory
+    
+    return 0;
+}
+
+
+int ipecamera_stop(void *vctx) {
+    ipecamera_t *ctx = (ipecamera_t*)vctx;
+
+    if (!ctx) {
+	pcilib_error("IPECamera imaging is not initialized");
+	return PCILIB_ERROR_NOTINITIALIZED;
+    }
+    
+    return 0;
+}
+
+
+static int ipecamera_get_line(ipecamera_t *ctx, int line) {
+    int err;
+    pcilib_t *pcilib = ctx->pcilib;
+    pcilib_register_value_t ptr, size, value;
+
+    ipecamera_reset((void*)ctx);
+
+    SET_REG(lines_reg, 1);
+    
+    SET_REG(control_reg, 149);
+    usleep(IPECAMERA_SLEEP_TIME);
+    CHECK_REG(status_reg, 0x0849FFFF);
+    
+    GET_REG(start_reg, ptr);
+    GET_REG(end_reg, size);
+    size -= ptr;
+
+    printf("%i: %i %i\n", line, ptr, size);    
+    
+    SET_REG(control_reg, 141);
+    usleep(IPECAMERA_SLEEP_TIME);
+    CHECK_REG(status_reg, 0x0849FFFF);
+}
+
+
+static int ipecamera_get_image(ipecamera_t *ctx) {
+    int err;
+    int i;
+    pcilib_t *pcilib = ctx->pcilib;
+
+    for (i = 0; i < 1088; i++) {
+	ipecamera_get_line(ctx, i);
+    }
+    
+    ctx->event_id++;
+}
+
+
+int ipecamera_trigger(void *vctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
+    int err;
+    pcilib_t *pcilib;
+    ipecamera_t *ctx = (ipecamera_t*)vctx;
+
+    if (!ctx) {
+	pcilib_error("IPECamera imaging is not initialized");
+	return PCILIB_ERROR_NOTINITIALIZED;
+
+    }
+    
+    err = ipecamera_get_image(ctx);
+    if (!err) err = ctx->cb(event, ctx->event_id, ctx->cb_user);
+
+    return err;
+}
+
+
+void* ipecamera_get(void *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) {
+    if (size) *size = ctx->width * ctx->height * 2;
+    return ctx->buffer;
+}
+
+int ipecamera_return(void *ctx, pcilib_event_id_t event_id) {
+    return 0;
+}

+ 22 - 0
ipecamera/image.h

@@ -0,0 +1,22 @@
+#ifndef _IPECAMERA_IMAGE_H
+#define _IPECAMERA_IMAGE_H
+
+#include <stdio.h>
+
+#include "pcilib.h"
+
+typedef struct ipecamera_s ipecamera_t;
+
+void *ipecamera_init(pcilib_t *pcilib);
+void ipecamera_free(void *ctx);
+
+int ipecamera_reset(void *ctx);
+int ipecamera_start(void *ctx, pcilib_event_t event_mask, pcilib_callback_t cb, void *user);
+int ipecamera_stop(void *ctx);
+int ipecamera_trigger(void *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data);
+
+void* ipecamera_get(void *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size);
+int ipecamera_return(void *ctx, pcilib_event_id_t event_id);
+
+
+#endif /* _IPECAMERA_IMAGE_H */

+ 6 - 0
ipecamera/ipecamera.h

@@ -0,0 +1,6 @@
+#ifndef _IPECAMERA_H
+#define _IPECAMERA_H
+
+
+
+#endif /* _IPECAMERA_H */

+ 13 - 5
ipecamera.c → ipecamera/model.c

@@ -1,10 +1,10 @@
-#define _IPECAMERA_C
+#define _IPECAMERA_MODEL_C
 #include <sys/time.h>
 #include <assert.h>
 
-#include "tools.h"
-#include "ipecamera.h"
-#include "error.h"
+#include "../tools.h"
+#include "../error.h"
+#include "model.h"
 
 #define ADDR_MASK 0x7F00
 #define WRITE_BIT 0x8000
@@ -110,6 +110,11 @@ retry:
     }
 
     if ((val & READ_READY_BIT) == 0) {
+	if (--retries > 0) {
+	    pcilib_warning("Timeout occured during register write, retrying (try %i of %i)...", RETRIES - retries, RETRIES);
+	    goto retry;
+	}
+
 	pcilib_error("Timeout writting register value");
 	return PCILIB_ERROR_TIMEOUT;
     }
@@ -121,7 +126,7 @@ retry:
 
     if (((val&ADDR_MASK) >> 8) != addr) {
 	if (--retries > 0) {
-	    pcilib_warning("Address verification failed during register read, retrying (try %i of %i)...", RETRIES - retries, RETRIES);
+	    pcilib_warning("Address verification failed during register write, retrying (try %i of %i)...", RETRIES - retries, RETRIES);
 	    goto retry;
 	}
 	pcilib_error("Address verification failed during register write");
@@ -137,3 +142,6 @@ retry:
 
     return 0;
 }
+
+
+

+ 110 - 0
ipecamera/model.h

@@ -0,0 +1,110 @@
+#ifndef _IPECAMERA_MODEL_H
+#define _IPECAMERA_MODEL_H
+
+#include <stdio.h>
+
+#include "pcilib.h"
+#include "image.h"
+
+#define IPECAMERA_REGISTER_SPACE 0xfeaffc00
+#define IPECAMERA_REGISTER_WRITE (IPECAMERA_REGISTER_SPACE + 0)
+#define IPECAMERA_REGISTER_READ (IPECAMERA_REGISTER_WRITE + 4)
+
+#ifdef _IPECAMERA_MODEL_C
+pcilib_register_bank_description_t ipecamera_register_banks[] = {
+    { PCILIB_REGISTER_BANK0, 128, IPECAMERA_REGISTER_PROTOCOL, IPECAMERA_REGISTER_READ,	IPECAMERA_REGISTER_WRITE, PCILIB_BIG_ENDIAN, 8, PCILIB_LITTLE_ENDIAN, "cmosis", "CMOSIS CMV2000 Registers" },
+    { PCILIB_REGISTER_BANK1, 64, PCILIB_DEFAULT_PROTOCOL, IPECAMERA_REGISTER_SPACE, IPECAMERA_REGISTER_SPACE, PCILIB_BIG_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "fpga", "IPECamera Registers" },
+    { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL }
+};
+
+pcilib_register_description_t ipecamera_registers[] = {
+{1, 	0, 	16, 	1088, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines",  ""},
+{3, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start1", ""},
+{5, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start2", ""},
+{7, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start3", ""},
+{9, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start4", ""},
+{11,	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start5", ""},
+{13, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start6", ""},
+{15, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start7", ""},
+{17, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start8", ""},
+{19, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines1", ""},
+{21, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines2", ""},
+{23, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines3", ""},
+{25, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines4", ""},
+{27, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines5", ""},
+{29, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines6", ""},
+{31, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines7", ""},
+{33, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines8", ""},
+{35, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "sub_s", ""},
+{37, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "sub_a", ""},
+{39, 	0, 	1, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "color", ""},
+{40, 	0, 	2, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "image_flipping", ""},
+{41, 	0, 	2, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_flags", ""},
+{42, 	0, 	24, 	1088, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_time", ""},
+{45, 	0, 	24, 	1088, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_step", ""},
+{48, 	0, 	24, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_kp1", ""},
+{51, 	0, 	24, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_kp2", ""},
+{54, 	0, 	2, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "nr_slopes", ""},
+{55, 	0, 	8, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_seq", ""},
+{56, 	0, 	24, 	1088, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_time2", ""},
+{59, 	0, 	24, 	1088, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_step2", ""},
+{68, 	0, 	2, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "nr_slopes2", ""},
+{69, 	0, 	8, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_seq2", ""},
+{70, 	0, 	16, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_frames", ""},
+{72, 	0, 	2, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "output_mode", ""},
+{78, 	0, 	12, 	85, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "training_pattern", ""},
+{80, 	0, 	18, 	0x3FFFF,PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "channel_en", ""},
+{89, 	0, 	8, 	96, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "vlow2", ""},
+{90, 	0, 	8, 	96, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "vlow3", ""},
+{100, 	0, 	14, 	16260, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "offset", ""},
+{102, 	0, 	2, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "pga", ""},
+{103, 	0, 	8, 	32, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "adc_gain", ""},
+{111, 	0, 	1, 	1, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "bit_mode", ""},
+{112, 	0, 	2, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "adc_resolution", ""},
+{126, 	0, 	16, 	0, 	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "temp", ""},
+{0,	0, 	32,	0,	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "spi_conf_input", ""},
+{1,	0, 	32,	0,	PCILIB_REGISTER_R,  PCILIB_REGISTER_BANK1, "spi_conf_output", ""},
+{2,	0, 	32,	0,	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "spi_clk_speed", ""},
+{3,	0, 	32,	0,	PCILIB_REGISTER_R,  PCILIB_REGISTER_BANK1, "firmware_version", ""},
+{4,	0, 	32, 	0,	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "control", ""},
+{5,	0, 	32, 	0,	PCILIB_REGISTER_R,  PCILIB_REGISTER_BANK1, "status", ""},
+{6,	0, 	16,	0,	PCILIB_REGISTER_R,  PCILIB_REGISTER_BANK1, "cmosis_temperature", ""},
+{7,	0, 	32,	0,	PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "temperature_sample_timing", ""},
+{8,	0, 	32, 	0,	PCILIB_REGISTER_R,  PCILIB_REGISTER_BANK1, "start_address", ""},
+{9,	0, 	32, 	0,	PCILIB_REGISTER_R,  PCILIB_REGISTER_BANK1, "end_address", ""},
+{10,	0, 	32, 	0,	PCILIB_REGISTER_R,  PCILIB_REGISTER_BANK1, "last_write_address", ""},
+{11,	0, 	32, 	0,	PCILIB_REGISTER_R,  PCILIB_REGISTER_BANK1, "last_write_value", ""},
+{0,	0,	0,	0,	0,                  0,                     NULL, NULL}
+};
+
+pcilib_register_range_t ipecamera_register_ranges[] = {
+    {0, 128, PCILIB_REGISTER_BANK0}, {0, 0, 0}
+};
+
+#else
+extern pcilib_register_description_t ipecamera_registers[];
+extern pcilib_register_bank_description_t ipecamera_register_banks[];
+extern pcilib_register_range_t ipecamera_register_ranges[];
+#endif 
+
+#ifdef _IPECAMERA_IMAGE_C
+pcilib_event_api_description_t ipecamera_image_api = {
+    ipecamera_init,
+    ipecamera_free,
+
+    ipecamera_reset,
+    ipecamera_start,
+    ipecamera_stop,
+    ipecamera_trigger,
+    
+    ipecamera_get,
+    ipecamera_return
+};
+#else
+extern pcilib_event_api_description_t ipecamera_image_api;
+#endif
+
+int ipecamera_read(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t *value);
+int ipecamera_write(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t value);
+
+#endif /* _IPECAMERA_MODEL_H */

+ 276 - 11
pci.c

@@ -1,4 +1,5 @@
 #define _PCILIB_PCI_C
+#define _POSIX_C_SOURCE 199309L
 
 #include <stdio.h>
 #include <string.h>
@@ -17,7 +18,7 @@
 #include "tools.h"
 
 #include "pci.h"
-#include "ipecamera.h"
+#include "ipecamera/model.h"
 #include "error.h"
 
 #define BIT_MASK(bits) ((1l << (bits)) - 1)
@@ -34,6 +35,12 @@ struct pcilib_s {
 
     pcilib_bar_t reg_bar;
     char *reg_space;
+
+    pcilib_bar_t data_bar;
+    char *data_space;
+    size_t data_size;
+    
+    void *event_ctx;
     
 #ifdef PCILIB_FILE_IO
     int file_io_handle;
@@ -60,6 +67,7 @@ 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) {
@@ -67,6 +75,10 @@ pcilib_t *pcilib_open(const char *device, pcilib_model_t model) {
 	ctx->page_mask = (uintptr_t)-1;
 	ctx->model = model;
 	ctx->reg_space = NULL;
+
+	if (!model) model = pcilib_get_model(ctx);
+	api = pcilib_model[model].event_api;
+        if ((api)&&(api->init)) ctx->event_ctx = api->init(ctx);
     }
 
     return ctx;
@@ -297,12 +309,67 @@ static int pcilib_map_register_space(pcilib_t *ctx) {
 	    }
 	}
 	
-	return -1;
+	return PCILIB_ERROR_NOTFOUND;
     }
     
     return 0;
 }
+
+static int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr) {
+    int err;
+    int i;
+    
+    if (!ctx->data_space) {
+        const pci_board_info *board_info = pcilib_get_board_info(ctx);
+
+	err = pcilib_map_register_space(ctx);
+	if (err) {
+	    pcilib_error("Error mapping register space");
+	    return err;
+	}
+	
+	if (addr) {
+	}
+	
+	int data_bar = -1;	
+	
+	for (i = 0; i < PCILIB_MAX_BANKS; i++) {
+	    if ((i == ctx->reg_bar)||(!board_info->bar_length[i])) continue;
+	    
+	    if (addr) {
+	        if (board_info->bar_start[i] == addr) {
+		    data_bar = i;
+		    break;
+		}
+	    } else {
+		if (data_bar >= 0) {
+		    data_bar = -1;
+		    break;
+		}
+		
+		data_bar = i;
+	    }
+	}
 	    
+
+	if (data_bar < 0) {
+	    if (addr) pcilib_error("Unable to find the specified data space (%lx)", addr);
+	    else pcilib_error("Unable to find the data space");
+	    return PCILIB_ERROR_NOTFOUND;
+	}
+	
+	ctx->data_bar = data_bar;
+	ctx->data_space = pcilib_map_bar(ctx, data_bar);
+	ctx->data_size = board_info->bar_length[data_bar];
+	
+	if (!ctx->data_space) {
+	    pcilib_error("Unable to map the data space");
+	    return PCILIB_ERROR_FAILED;
+	}
+    }
+    
+    return 0;
+}
 	
 static void pcilib_unmap_register_space(pcilib_t *ctx) {
     if (ctx->reg_space) {
@@ -311,6 +378,13 @@ static void pcilib_unmap_register_space(pcilib_t *ctx) {
     }
 }
 
+static void pcilib_unmap_data_space(pcilib_t *ctx) {
+    if (ctx->data_space) {
+	pcilib_unmap_bar(ctx, ctx->data_bar, ctx->data_space);
+	ctx->data_space = NULL;
+    }
+}
+
 char  *pcilib_resolve_register_address(pcilib_t *ctx, uintptr_t addr) {
     size_t offset = addr - ctx->board_info.bar_start[ctx->reg_bar];
     if (offset < ctx->board_info.bar_length[ctx->reg_bar]) {
@@ -319,11 +393,31 @@ char  *pcilib_resolve_register_address(pcilib_t *ctx, uintptr_t addr) {
     return NULL;
 }
 
+char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size) {
+    int err;
+    
+    err = pcilib_map_data_space(ctx, addr);
+    if (err) {
+	pcilib_error("Failed to map the specified address space (%lx)", addr);
+	return NULL;
+    }
+    
+    if (size) *size = ctx->data_size;    
+    
+    return ctx->data_space + (ctx->board_info.bar_start[ctx->data_bar] & ctx->page_mask);
+}
+
 
 void pcilib_close(pcilib_t *ctx) {
     if (ctx) {
+	pcilib_model_t model = pcilib_get_model(ctx);
+	pcilib_event_api_description_t *api = pcilib_model[model].event_api;
+    
+        if ((api)&&(api->free)) api->free(ctx->event_ctx);
+	if (ctx->data_space) pcilib_unmap_data_space(ctx);
 	if (ctx->reg_space) pcilib_unmap_register_space(ctx);
 	close(ctx->handle);
+	
 	free(ctx);
     }
 }
@@ -491,17 +585,21 @@ int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_reg
 	pcilib_error("Big-endian byte order support is not implemented");
 	return PCILIB_ERROR_NOTSUPPORTED;
     } else {
-	for (i = 0, res = value; (res > 0)&&(i <= n); ++i) {
-	    buf[i] = res & BIT_MASK(b->access);
-	    res >>= b->access;
-	}
+	if (b->access == sizeof(res) * 8) {
+	    buf[i] = res;
+	} else {
+	    for (i = 0, res = value; (res > 0)&&(i <= n); ++i) {
+		buf[i] = res & BIT_MASK(b->access);
+	        res >>= b->access;
+	    }
 	
-	if (res) {
-	    pcilib_error("Value %i is to big to fit in the register %s", value, r->name);
-	    return PCILIB_ERROR_OUTOFRANGE;
+	    if (res) {
+		pcilib_error("Value %i is too big to fit in the register %s", value, r->name);
+		return PCILIB_ERROR_OUTOFRANGE;
+	    }
 	}
     }
-    
+
     err = pcilib_write_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
     return err;
 }
@@ -511,8 +609,175 @@ int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname,
     int reg;
     
     reg = pcilib_find_register(ctx, bank, regname);
-    if (reg < 0) pcilib_error("Register (%s) is not found", regname);
+    if (reg < 0) {
+	pcilib_error("Register (%s) is not found", regname);
+	return PCILIB_ERROR_NOTFOUND;
+    }
 
     return pcilib_write_register_by_id(ctx, reg, value);
 }
 
+
+int pcilib_reset(pcilib_t *ctx) {
+    pcilib_event_api_description_t *api;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+
+    api = pcilib_model[model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+    
+    if (api->reset) 
+	return api->reset(ctx->event_ctx);
+	
+    return 0;
+}
+
+int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, void *callback, void *user) {
+    pcilib_event_api_description_t *api;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+
+    api = pcilib_model[model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    if (api->start) 
+	return api->start(ctx->event_ctx, event_mask, callback, user);
+
+    return 0;
+}
+
+int pcilib_stop(pcilib_t *ctx) {
+    pcilib_event_api_description_t *api;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+
+    api = pcilib_model[model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    if (api->stop) 
+	return api->stop(ctx->event_ctx);
+
+    return 0;
+}
+
+int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
+    pcilib_event_api_description_t *api;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+
+    api = pcilib_model[model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    if (api->trigger) 
+	return api->trigger(ctx->event_ctx, event, trigger_size, trigger_data);
+
+    pcilib_error("Self triggering is not supported by the selected model");
+    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_event_api_description_t *api = pcilib_model[ctx->model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return NULL;
+    }
+
+    if (api->get_data) 
+	return api->get_data(ctx->event_ctx, event_id, data_type, size);
+
+    return NULL;
+}
+
+int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id) {
+    pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    if (api->return_data) 
+	return api->return_data(ctx->event_ctx, event_id);
+
+    return 0;
+}
+
+
+typedef struct {
+    pcilib_t *ctx;
+    
+    size_t *size;
+    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;
+    size_t size;
+    int allocated = 0;
+
+    pcilib_grab_callback_user_data_t *user = (pcilib_grab_callback_user_data_t*)vuser;
+
+    data = pcilib_get_data(user->ctx, event_id, PCILIB_EVENT_DATA, &size);
+    if (!data) {
+	pcilib_error("Error getting event data");
+	return PCILIB_ERROR_FAILED;
+    }
+    
+    if (*(user->data)) {
+	if ((user->size)&&(*(user->size) < size)) {
+	    pcilib_error("The supplied buffer does not have enough space to hold the event data. Buffer size is %z, but %z is required", user->size, size);
+	    return PCILIB_ERROR_MEMORY;
+	}
+
+	*(user->size) = size;
+    } else {
+	*(user->data) = malloc(size);
+	if (!*(user->data)) {
+	    pcilib_error("Memory allocation (%i bytes) for event data is failed");
+	    return PCILIB_ERROR_MEMORY;
+	}
+	if (*(user->size)) *(user->size) = size;
+	allocated = 1;
+    }
+    
+    memcpy(*(user->data), data, size);
+    
+    err = pcilib_return_data(user->ctx, event_id);
+    if (err) {
+	if (allocated) {
+	    free(*(user->data));
+	    *(user->data) = NULL;
+	}
+	pcilib_error("The event data had been overwritten before it was returned, data corruption may occur");
+	return err;
+    }
+    
+    return 0;
+}
+
+int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, const struct timespec *timeout) {
+    int err;
+    
+    pcilib_grab_callback_user_data_t user = {ctx, size, data};
+    
+    err = pcilib_start(ctx, event_mask, pcilib_grab_callback, &user);
+    if (!err) {
+	if (timeout) nanosleep(timeout, NULL);
+        else err = pcilib_trigger(ctx, event_mask, 0, NULL);
+    }
+    pcilib_stop(ctx);
+    return 0;
+}

+ 4 - 4
pci.h

@@ -11,13 +11,13 @@
 const pci_board_info *pcilib_get_board_info(pcilib_t *ctx);
 
 #ifdef _PCILIB_PCI_C
-# include "ipecamera.h"
+# include "ipecamera/model.h"
 # include "default.h"
 
 pcilib_model_description_t pcilib_model[3] = {
-    { NULL, NULL, NULL },
-    { NULL, NULL, NULL },
-    { ipecamera_registers, ipecamera_register_banks, ipecamera_register_ranges }
+    { NULL, NULL, NULL, NULL },
+    { NULL, NULL, NULL, NULL },
+    { ipecamera_registers, ipecamera_register_banks, ipecamera_register_ranges, &ipecamera_image_api }
 };
 
 pcilib_protocol_description_t pcilib_protocol[3] = {

+ 57 - 2
pcilib.h

@@ -3,8 +3,16 @@
 
 #define PCILIB_MAX_BANKS 6
 
+#include <time.h>
 #include <stdint.h>
 
+#ifndef __timespec_defined
+struct timespec {
+    time_t tv_sec;
+    long tv_nsec;
+};
+#endif /* __timespec_defined */
+
 #define pcilib_memcpy pcilib_memcpy32
 #define pcilib_datacpy pcilib_datacpy32
 
@@ -17,6 +25,9 @@ typedef uint8_t pcilib_register_bank_t;		/**< Type holding the register bank num
 typedef uint8_t pcilib_register_bank_addr_t;	/**< Type holding the register bank number */
 typedef uint8_t pcilib_register_size_t;		/**< Type holding the size in bits of the register */
 typedef uint32_t pcilib_register_value_t;	/**< Type holding the register value */
+typedef uint64_t pcilib_event_id_t;
+
+typedef uint32_t pcilib_event_t;
 
 typedef enum {
     PCILIB_LITTLE_ENDIAN = 0,
@@ -35,12 +46,15 @@ typedef enum {
     PCILIB_REGISTER_RW = 3
 } pcilib_register_mode_t;
 
-
 typedef enum {
     PCILIB_DEFAULT_PROTOCOL,
     IPECAMERA_REGISTER_PROTOCOL
 } pcilib_register_protocol_t;
 
+typedef enum {
+    PCILIB_EVENT_DATA
+} pcilib_event_data_type_t;
+
 #define PCILIB_BAR_DETECT 		((pcilib_bar_t)-1)
 #define PCILIB_REGISTER_INVALID		((pcilib_register_t)-1)
 #define PCILIB_ADDRESS_INVALID		((uintptr_t)-1)
@@ -49,6 +63,7 @@ typedef enum {
 #define PCILIB_REGISTER_BANK1 		1
 #define PCILIB_REGISTER_BANK2 		2
 #define PCILIB_REGISTER_BANK3 		3
+#define PCILIB_ALL_EVENTS		((pcilib_event_t)-1)
 
 typedef struct {
     pcilib_register_bank_addr_t addr;
@@ -69,6 +84,7 @@ typedef struct {
 
 typedef struct {
     pcilib_register_addr_t addr;
+    pcilib_register_size_t offset;
     pcilib_register_size_t bits;
     pcilib_register_value_t defvalue;
     pcilib_register_mode_t mode;
@@ -93,10 +109,28 @@ typedef struct {
     int (*write)(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t value);
 } pcilib_protocol_description_t;
 
+
+typedef int (*pcilib_callback_t)(pcilib_event_t event, pcilib_event_id_t event_id, void *user);
+
+typedef struct {
+    void *(*init)(pcilib_t *ctx);
+    void (*free)(void *ctx);
+
+    int (*reset)(void *ctx);
+
+    int (*start)(void *ctx, pcilib_event_t event_mask, pcilib_callback_t callback, void *user);
+    int (*stop)(void *ctx);
+    int (*trigger)(void *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data);
+    void* (*get_data)(void *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size);
+    int (*return_data)(void *ctx, pcilib_event_id_t event_id);
+} pcilib_event_api_description_t;
+
 typedef struct {
     pcilib_register_description_t *registers;
     pcilib_register_bank_description_t *banks;
     pcilib_register_range_t *ranges;
+    
+    pcilib_event_api_description_t *event_api;
 } pcilib_model_description_t;
 
 #ifndef _PCILIB_PCI_C
@@ -112,7 +146,8 @@ void pcilib_close(pcilib_t *ctx);
 
 void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar);
 void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data);
-char  *pcilib_resolve_register_address(pcilib_t *ctx, uintptr_t addr);
+char *pcilib_resolve_register_address(pcilib_t *ctx, uintptr_t addr);
+char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size);
 
 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);
@@ -127,4 +162,24 @@ int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_reg
 int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value);
 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);
+
+void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, 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.
+ */
+int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id);
+
+/*
+ * @param data - will be allocated and shuld be freed if NULL, otherwise used and size should contain correct size.
+ *   In case of failure the content of data is undefined.
+ * @param timeout - will be autotriggered if NULL
+ */
+int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, const struct timespec *timeout);
+
 #endif /* _PCITOOL_PCILIB_H */