diff options
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | NOTES | 42 | ||||
-rw-r--r-- | cli.c | 274 | ||||
-rw-r--r-- | dma.c | 13 | ||||
-rw-r--r-- | dma/nwl_engine.c | 24 | ||||
-rw-r--r-- | error.h | 3 | ||||
-rw-r--r-- | event.c | 196 | ||||
-rw-r--r-- | event.h | 34 | ||||
-rw-r--r-- | ipecamera/image.c | 783 | ||||
-rw-r--r-- | ipecamera/image.h | 11 | ||||
-rw-r--r-- | ipecamera/ipecamera.h | 3 | ||||
-rw-r--r-- | ipecamera/model.h | 16 | ||||
-rw-r--r-- | pci.c | 4 | ||||
-rw-r--r-- | pci.h | 6 | ||||
-rw-r--r-- | pcilib.h | 91 | ||||
-rw-r--r-- | pcitool/sysinfo.c | 173 | ||||
-rw-r--r-- | pcitool/sysinfo.h | 7 | ||||
-rwxr-xr-x | tests/grab.sh | 2 | ||||
-rw-r--r-- | tools.c | 39 | ||||
-rw-r--r-- | tools.h | 5 |
20 files changed, 1215 insertions, 518 deletions
@@ -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 $@ $< @@ -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 @@ -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" @@ -46,6 +49,11 @@ typedef uint8_t access_t; typedef enum { + GRAB_MODE_GRAB = 1, + GRAB_MODE_TRIGGER = 2 +} GRAB_MODE; + +typedef enum { MODE_INVALID, MODE_INFO, MODE_LIST, @@ -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); @@ -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) { diff --git a/dma/nwl_engine.c b/dma/nwl_engine.c index 806173d..ac87f08 100644 --- a/dma/nwl_engine.c +++ b/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; @@ -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; @@ -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; } @@ -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 */ diff --git a/ipecamera/image.c b/ipecamera/image.c index 29ca9c1..4b060b6 100644 --- a/ipecamera/image.c +++ b/ipecamera/image.c @@ -6,6 +6,7 @@ #include <unistd.h> #include <string.h> #include <sys/time.h> +#include <pthread.h> #include <assert.h> #include "../tools.h" @@ -14,6 +15,7 @@ #include "pcilib.h" #include "model.h" +#include "event.h" #include "image.h" #include "dma/nwl_dma.h" @@ -23,27 +25,35 @@ #endif /* IPECAMERA_DEBUG */ -#define IPECAMERA_SLEEP_TIME 250000 // Michele thinks 250 should be enough, but reset failing in this case -#define IPECAMERA_NEXT_FRAME_DELAY 30000 // please don't change this value --> sync between End Of Readout and next Frame Req, by Michele -#define IPECAMERA_WAIT_FRAME_RCVD_TIME 0 /* by Uros ,wait 6 ms */ +#define IPECAMERA_BUG_EXTRA_DATA + +#define IPECAMERA_DEFAULT_BUFFER_SIZE 64 //**< should be power of 2 */ +#define IPECAMERA_RESERVE_BUFFERS 2 //**< Return Frame is Lost error, if requested frame will be overwritten after specified number of frames +#define IPECAMERA_SLEEP_TIME 250000 //**< Michele thinks 250 should be enough, but reset failing in this case */ +#define IPECAMERA_NEXT_FRAME_DELAY 1000 //**< Michele requires 30000 to sync between End Of Readout and next Frame Req */ +#define IPECAMERA_WAIT_FRAME_RCVD_TIME 0 //**< by Uros ,wait 6 ms */ +#define IPECAMERA_NOFRAME_SLEEP 100 + #define IPECAMERA_MAX_LINES 1088 -#define IPECAMERA_DEFAULT_BUFFER_SIZE 10 #define IPECAMERA_EXPECTED_STATUS 0x08409FFFF #define IPECAMERA_END_OF_SEQUENCE 0x1F001001 #define IPECAMERA_MAX_CHANNELS 16 #define IPECAMERA_PIXELS_PER_CHANNEL 128 #define IPECAMERA_WIDTH (IPECAMERA_MAX_CHANNELS * IPECAMERA_PIXELS_PER_CHANNEL) -#define IPECAMERA_HEIGHT 1088 //1088 +/* +#define IPECAMERA_HEIGHT 1088 #if IPECAMERA_HEIGHT < IPECAMERA_MAX_LINES # undef IPECAMERA_MAX_LINES # define IPECAMERA_MAX_LINES IPECAMERA_HEIGHT #endif +*/ //#define IPECAMERA_MEMORY #define IPECAMERA_FRAME_REQUEST 0x1E9 +#define IPECAMERA_READOUT_FLAG 0x200 #define IPECAMERA_READOUT 0x3E1 #define IPECAMERA_IDLE 0x1E1 #define IPECAMERA_START_INTERNAL_STIMULI 0x1F1 @@ -60,8 +70,17 @@ int ipecamera_channel_order[IPECAMERA_MAX_CHANNELS] = { 15, 13, 14, 12, 10, 8, 1 typedef uint32_t ipecamera_payload_t; +typedef struct { + pcilib_event_info_t info; +} ipecamera_event_info_t; + +typedef struct { + pcilib_event_id_t evid; + struct timeval timestamp; +} ipecamera_autostop_t; + struct ipecamera_s { - pcilib_t *pcilib; + pcilib_context_t event; #ifndef IPECAMERA_DMA_ADDRESS char *data; @@ -86,16 +105,42 @@ struct ipecamera_s { pcilib_register_t exposure_reg; pcilib_register_t flip_reg; - int started; - int buffer_size; - int buf_ptr; + int started; /**< Camera is in grabbing mode (start function is called) */ + int streaming; /**< Camera is in streaming mode (we are within stream call) */ + int parse_data; /**< Indicates if some processing of the data is required, otherwise only rawdata_callback will be called */ + + int run_reader; /**< Instructs the reader thread to stop processing */ + int run_streamer; /**< Indicates request to stop streaming events and can be set by reader_thread upon exit or by user request */ + ipecamera_autostop_t autostop; + + struct timeval autostop_time; +// int ready; /**< New frame is ready */ +// int check_time; /**< Streaming is time-limited */ + + size_t buffer_size; /**< How many images to store */ + size_t buffer_pos; /**< Current image offset in the buffer, due to synchronization reasons should not be used outside of reader_thread */ +// size_t stream_count; /**< Number of images read so far */ +// size_t stream_max; /**< Maximum number of images to read */ +// struct timeval stream_stop; /**< Time to stop streaming */ + size_t cur_size; /**< Already written part of data in bytes */ + size_t raw_size; /**< Size of raw data in bytes */ + size_t full_size; /**< Size of raw data including the padding */ + size_t padded_size; /**< Size of buffer for raw data, including the padding for performance */ + + size_t image_size; /**< Size of a single image in bytes */ int width, height; - ipecamera_pixel_t *buffer; + +// void *raw_buffer; + void *buffer; ipecamera_change_mask_t *cmask; + ipecamera_event_info_t *frame_info; + ipecamera_image_dimensions_t dim; + + pthread_t rthread; }; @@ -156,8 +201,6 @@ pcilib_context_t *ipecamera_init(pcilib_t *pcilib) { if (ctx) { memset(ctx, 0, sizeof(ipecamera_t)); - ctx->pcilib = pcilib; - ctx->buffer_size = IPECAMERA_DEFAULT_BUFFER_SIZE; ctx->dim.bpp = sizeof(ipecamera_pixel_t) * 8; @@ -181,7 +224,7 @@ pcilib_context_t *ipecamera_init(pcilib_t *pcilib) { FIND_REG(line_reg, "cmosis", "start1"); FIND_REG(exposure_reg, "cmosis", "exp_time"); FIND_REG(flip_reg, "cmosis", "image_flipping"); - + ctx->rdma = PCILIB_DMA_ENGINE_INVALID; ctx->wdma = PCILIB_DMA_ENGINE_INVALID; @@ -198,7 +241,7 @@ pcilib_context_t *ipecamera_init(pcilib_t *pcilib) { void ipecamera_free(pcilib_context_t *vctx) { if (vctx) { ipecamera_t *ctx = (ipecamera_t*)vctx; - ipecamera_stop(vctx); + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); free(ctx); } } @@ -206,7 +249,7 @@ void ipecamera_free(pcilib_context_t *vctx) { pcilib_dma_context_t *ipecamera_init_dma(pcilib_context_t *vctx) { ipecamera_t *ctx = (ipecamera_t*)vctx; - pcilib_model_description_t *model_info = pcilib_get_model_description(ctx->pcilib); + pcilib_model_description_t *model_info = pcilib_get_model_description(vctx->pcilib); if ((!model_info->dma_api)||(!model_info->dma_api->init)) { pcilib_error("The DMA engine is not configured in model"); return NULL; @@ -214,9 +257,9 @@ pcilib_dma_context_t *ipecamera_init_dma(pcilib_context_t *vctx) { #ifdef IPECAMERA_DMA_R3 - return model_info->dma_api->init(ctx->pcilib, PCILIB_NWL_MODIFICATION_IPECAMERA, NULL); + return model_info->dma_api->init(vctx->pcilib, PCILIB_NWL_MODIFICATION_IPECAMERA, NULL); #else - return model_info->dma_api->init(ctx->pcilib, PCILIB_DMA_MODIFICATION_DEFAULT, NULL); + return model_info->dma_api->init(vctx->pcilib, PCILIB_DMA_MODIFICATION_DEFAULT, NULL); #endif } @@ -227,21 +270,24 @@ int ipecamera_set_buffer_size(ipecamera_t *ctx, int size) { return PCILIB_ERROR_INVALID_REQUEST; } - if (ctx->size < 1) { + if (size < 2) { pcilib_error("The buffer size is too small"); return PCILIB_ERROR_INVALID_REQUEST; } - + + if (((size^(size-1)) < size) < size) { + pcilib_error("The buffer size is not power of 2"); + } + ctx->buffer_size = size; return 0; } - int ipecamera_reset(pcilib_context_t *vctx) { - int err; - pcilib_t *pcilib; + int err = 0; ipecamera_t *ctx = (ipecamera_t*)vctx; + pcilib_t *pcilib = vctx->pcilib; pcilib_register_t control, status; pcilib_register_value_t value; @@ -251,14 +297,14 @@ int ipecamera_reset(pcilib_context_t *vctx) { return PCILIB_ERROR_NOTINITIALIZED; } - pcilib = ctx->pcilib; + pcilib = vctx->pcilib; control = ctx->control_reg; status = ctx->status_reg; // Set Reset bit to CMOSIS err = pcilib_write_register_by_id(pcilib, control, 0x1e4); if (err) { - pcilib_error("Error setting CMOSIS reset bit"); + pcilib_error("Error setting FPGA reset bit"); return err; } usleep(IPECAMERA_SLEEP_TIME); @@ -266,7 +312,7 @@ int ipecamera_reset(pcilib_context_t *vctx) { // Remove Reset bit to CMOSIS err = pcilib_write_register_by_id(pcilib, control, 0x1e1); if (err) { - pcilib_error("Error reseting CMOSIS reset bit"); + pcilib_error("Error reseting FPGA reset bit"); return err; } usleep(IPECAMERA_SLEEP_TIME); @@ -287,11 +333,15 @@ int ipecamera_reset(pcilib_context_t *vctx) { usleep(IPECAMERA_SLEEP_TIME); // Set default parameters - SET_REG(control_reg, IPECAMERA_IDLE); - if (err) return err; - + err = pcilib_write_register_by_id(pcilib, control, IPECAMERA_IDLE); + if (err) { + pcilib_error("Error bringing FPGA in default mode"); + return err; + } + usleep(10000); - + + err = pcilib_read_register_by_id(pcilib, status, &value); if (err) { pcilib_error("Error reading status register"); @@ -306,12 +356,121 @@ int ipecamera_reset(pcilib_context_t *vctx) { return 0; } -int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_event_callback_t cb, void *user) { +// DS: Currently, on event_id overflow we are assuming the buffer is lost +static int ipecamera_resolve_event_id(ipecamera_t *ctx, pcilib_event_id_t evid) { + pcilib_event_id_t diff; + + if (evid > ctx->event_id) { + diff = (((pcilib_event_id_t)-1) - ctx->event_id) + evid; + if (diff >= ctx->buffer_size) return -1; + } else { + diff = ctx->event_id - evid; + if (diff >= ctx->buffer_size) return -1; + } + + // DS: Request buffer_size to be power of 2 and replace to shifts (just recompute in set_buffer_size) + return (evid - 1) % ctx->buffer_size; +} + +static inline void ipecamera_new_frame(ipecamera_t *ctx) { + ctx->buffer_pos = (++ctx->event_id) % ctx->buffer_size; + ctx->cur_size = 0; + + ctx->frame_info[ctx->buffer_pos].info.type = PCILIB_EVENT0; +// memset(ctx->cmask + ctx->buffer_pos * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t)); +} + +static uint32_t frame_magic[6] = { 0x51111111, 0x52222222, 0x53333333, 0x54444444, 0x55555555, 0x56666666 }; + +static int ipecamera_data_callback(void *user, pcilib_dma_flags_t flags, size_t bufsize, void *buf) { + int eof = 0; + ipecamera_t *ctx = (ipecamera_t*)user; + + + if ((bufsize >= 8)&&(!memcmp(buf, frame_magic, sizeof(frame_magic)))) { + //if (ctx->cur_size) ipecamera_new_frame(ctx); + ctx->frame_info[ctx->buffer_pos].info.seqnum = ((uint32_t*)buf)[6] & 0xF0000000; + ctx->frame_info[ctx->buffer_pos].info.offset = ((uint32_t*)buf)[7] & 0xF0000000; + gettimeofday(&ctx->frame_info[ctx->buffer_pos].info.timestamp, NULL); + } + + if (ctx->parse_data) { + if (ctx->cur_size + bufsize > ctx->full_size) { + pcilib_error("Unexpected event data, we are expecting at maximum (%zu) bytes, but (%zu) already read", ctx->full_size, ctx->cur_size + bufsize); + return -PCILIB_ERROR_TOOBIG; + } + + memcpy(ctx->buffer + ctx->buffer_pos * ctx->padded_size + ctx->cur_size, buf, bufsize); + } + + ctx->cur_size += bufsize; +// printf("%i: %i %i\n", ctx->buffer_pos, ctx->cur_size, bufsize); + + if (ctx->cur_size >= ctx->full_size) eof = 1; + + if (ctx->event.params.rawdata.callback) { + ctx->event.params.rawdata.callback(ctx->event_id, (pcilib_event_info_t*)(ctx->frame_info + ctx->buffer_pos), (eof?PCILIB_EVENT_FLAG_EOF:PCILIB_EVENT_FLAGS_DEFAULT), bufsize, buf, ctx->event.params.rawdata.user); + } + + if (eof) { + ipecamera_new_frame(ctx); + + if ((ctx->event_id == ctx->autostop.evid)&&(ctx->event_id)) { + ctx->run_reader = 0; + return PCILIB_STREAMING_STOP; + } + + if (check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) { + ctx->run_reader = 0; + return PCILIB_STREAMING_STOP; + } + } + + return PCILIB_STREAMING_REQ_FRAGMENT; +} + +static void *ipecamera_reader_thread(void *user) { + int err; + ipecamera_t *ctx = (ipecamera_t*)user; + + while (ctx->run_reader) { + err = pcilib_stream_dma(ctx->event.pcilib, ctx->rdma, 0, 0, PCILIB_DMA_FLAG_MULTIPACKET, PCILIB_DMA_TIMEOUT, &ipecamera_data_callback, user); + if (err) { + if (err == PCILIB_ERROR_TIMEOUT) { + if (check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) { + ctx->run_reader = 0; + break; + } + usleep(IPECAMERA_NOFRAME_SLEEP); + } else pcilib_error("DMA error while reading IPECamera frames, error: %i", err); + } + + usleep(1000); + } + + ctx->run_streamer = 0; + + if (ctx->cur_size) pcilib_error("partialy read frame after stop signal, %zu bytes in the buffer", ctx->cur_size); + + return NULL; +} + +int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_event_flags_t flags) { int err = 0; ipecamera_t *ctx = (ipecamera_t*)vctx; - pcilib_t *pcilib = ctx->pcilib; + pcilib_t *pcilib = vctx->pcilib; pcilib_register_value_t value; - + + const size_t chan_size = (2 + IPECAMERA_PIXELS_PER_CHANNEL / 3) * sizeof(ipecamera_payload_t); + const size_t line_size = (IPECAMERA_MAX_CHANNELS * chan_size); + const size_t header_size = 8; + const size_t footer_size = 8; + size_t raw_size; + size_t padded_blocks; + + pthread_attr_t attr; + struct sched_param sched; + if (!ctx) { pcilib_error("IPECamera imaging is not initialized"); return PCILIB_ERROR_NOTINITIALIZED; @@ -322,48 +481,66 @@ int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_ev return PCILIB_ERROR_INVALID_REQUEST; } - // if left in FRAME_REQUEST mode - SET_REG(control_reg, IPECAMERA_IDLE); + + // Allow readout and clean the FRAME_REQUEST mode if set for some reason + SET_REG(control_reg, IPECAMERA_IDLE|IPECAMERA_READOUT_FLAG); usleep(IPECAMERA_SLEEP_TIME); CHECK_REG(status_reg, IPECAMERA_EXPECTED_STATUS); if (err) return err; -//#ifdef IPECAMERA_DMA_ADDRESS -// SET_REG(packet_len_reg, IPECAMERA_DMA_PACKET_LENGTH); -// if (err) return err; -//#endif /* IPECAMERA_DMA_ADDRESS */ - - ctx->cb = cb; - ctx->cb_user = user; - ctx->event_id = 0; ctx->reported_id = 0; - ctx->buf_ptr = 0; + ctx->buffer_pos = 0; + ctx->parse_data = (flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY)?0:1; + ctx->cur_size = 0; ctx->dim.width = IPECAMERA_WIDTH; - ctx->dim.height = IPECAMERA_HEIGHT; //GET_REG(lines_reg, lines); + GET_REG(n_lines_reg, ctx->dim.height); + + raw_size = header_size + ctx->dim.height * line_size + footer_size; + padded_blocks = raw_size / IPECAMERA_DMA_PACKET_LENGTH + ((raw_size % IPECAMERA_DMA_PACKET_LENGTH)?1:0); + + ctx->image_size = ctx->dim.width * ctx->dim.height * sizeof(ipecamera_pixel_t); + ctx->raw_size = raw_size; + ctx->full_size = padded_blocks * IPECAMERA_DMA_PACKET_LENGTH; + +#ifdef IPECAMERA_BUG_EXTRA_DATA + ctx->full_size += 8; + padded_blocks ++; +#endif /* IPECAMERA_BUG_EXTRA_DATA */ - ctx->buffer = malloc(ctx->dim.width * ctx->dim.height * ctx->buffer_size * sizeof(ipecamera_pixel_t)); + ctx->padded_size = padded_blocks * IPECAMERA_DMA_PACKET_LENGTH; + + ctx->buffer = malloc(ctx->padded_size * ctx->buffer_size); if (!ctx->buffer) { err = PCILIB_ERROR_MEMORY; - pcilib_error("Unable to allocate ring buffer"); + pcilib_error("Unable to allocate ring buffer (%lu bytes)", ctx->padded_size * ctx->buffer_size); + return err; } ctx->cmask = malloc(ctx->dim.height * ctx->buffer_size * sizeof(ipecamera_change_mask_t)); if (!ctx->cmask) { err = PCILIB_ERROR_MEMORY; pcilib_error("Unable to allocate change-mask buffer"); + return err; + } + + ctx->frame_info = malloc(ctx->buffer_size * sizeof(ipecamera_event_info_t)); + if (!ctx->frame_info) { + err = PCILIB_ERROR_MEMORY; + pcilib_error("Unable to allocate frame-info buffer"); + return err; } #ifdef IPECAMERA_DMA_ADDRESS if (!err) { - ctx->rdma = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_FROM_DEVICE, IPECAMERA_DMA_ADDRESS); + ctx->rdma = pcilib_find_dma_by_addr(vctx->pcilib, PCILIB_DMA_FROM_DEVICE, IPECAMERA_DMA_ADDRESS); if (ctx->rdma == PCILIB_DMA_ENGINE_INVALID) { err = PCILIB_ERROR_NOTFOUND; pcilib_error("The C2S channel of IPECamera DMA Engine (%u) is not found", IPECAMERA_DMA_ADDRESS); } else { - err = pcilib_start_dma(ctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT); + err = pcilib_start_dma(vctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT); if (err) { ctx->rdma = PCILIB_DMA_ENGINE_INVALID; pcilib_error("Failed to initialize C2S channel of IPECamera DMA Engine (%u)", IPECAMERA_DMA_ADDRESS); @@ -373,12 +550,12 @@ int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_ev /* if (!err) { - ctx->wdma = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_TO_DEVICE, IPECAMERA_DMA_ADDRESS); + ctx->wdma = pcilib_find_dma_by_addr(vctx->pcilib, PCILIB_DMA_TO_DEVICE, IPECAMERA_DMA_ADDRESS); if (ctx->wdma == PCILIB_DMA_ENGINE_INVALID) { err = PCILIB_ERROR_NOTFOUND; pcilib_error("The S2C channel of IPECamera DMA Engine (%u) is not found", IPECAMERA_DMA_ADDRESS); } else { - err = pcilib_start_dma(ctx->pcilib, ctx->wdma, PCILIB_DMA_FLAGS_DEFAULT); + err = pcilib_start_dma(vctx->pcilib, ctx->wdma, PCILIB_DMA_FLAGS_DEFAULT); if (err) { ctx->wdma = PCILIB_DMA_ENGINE_INVALID; pcilib_error("Failed to initialize S2C channel of IPECamera DMA Engine (%u)", IPECAMERA_DMA_ADDRESS); @@ -386,20 +563,68 @@ int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_ev } } */ + +/* + SET_REG(packet_len_reg, IPECAMERA_DMA_PACKET_LENGTH); + if (err) return err; +*/ + + // Clean DMA + err = pcilib_skip_dma(vctx->pcilib, ctx->rdma); + if (err) { + pcilib_error("Can't start grabbing, device continuously writes unexpected data using DMA engine"); + return err; + } + #endif /* IPECAMERA_DMA_ADDRESS */ if (err) { - ipecamera_stop(vctx); + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); return err; } + + if (vctx->params.autostop.duration) { + gettimeofday(&ctx->autostop.timestamp, NULL); + ctx->autostop.timestamp.tv_usec += vctx->params.autostop.duration % 1000000; + if (ctx->autostop.timestamp.tv_usec > 999999) { + ctx->autostop.timestamp.tv_sec += 1 + vctx->params.autostop.duration / 1000000; + ctx->autostop.timestamp.tv_usec -= 1000000; + } else { + ctx->autostop.timestamp.tv_sec += vctx->params.autostop.duration / 1000000; + } + } + + if (vctx->params.autostop.max_events) { + ctx->autostop.evid = vctx->params.autostop.max_events; + } ctx->started = 1; + ctx->run_reader = 1; - return 0; + pthread_attr_init(&attr); + + if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) { + pcilib_warning("Can't schedule a real-time thread, you may consider running as root"); + } else { + sched.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1; // Let 1 priority for something really critcial + pthread_attr_setschedparam(&attr, &sched); + } + + if (pthread_create(&ctx->rthread, &attr, &ipecamera_reader_thread, (void*)ctx)) { + ctx->started = 0; + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + err = PCILIB_ERROR_THREAD; + } + + pthread_attr_destroy(&attr); + + return err; } -int ipecamera_stop(pcilib_context_t *vctx) { +int ipecamera_stop(pcilib_context_t *vctx, pcilib_event_flags_t flags) { + int err; + void *retcode; ipecamera_t *ctx = (ipecamera_t*)vctx; if (!ctx) { @@ -407,20 +632,29 @@ int ipecamera_stop(pcilib_context_t *vctx) { return PCILIB_ERROR_NOTINITIALIZED; } - ctx->started = 0; + if (ctx->started) { + ctx->run_reader = 0; + err = pthread_join(ctx->rthread, &retcode); + if (err) pcilib_error("Error joining the reader thread"); + } #ifdef IPECAMERA_DMA_ADDRESS if (ctx->wdma != PCILIB_DMA_ENGINE_INVALID) { - pcilib_stop_dma(ctx->pcilib, ctx->wdma, PCILIB_DMA_FLAGS_DEFAULT); + pcilib_stop_dma(vctx->pcilib, ctx->wdma, PCILIB_DMA_FLAGS_DEFAULT); ctx->wdma = PCILIB_DMA_ENGINE_INVALID; } if (ctx->rdma != PCILIB_DMA_ENGINE_INVALID) { - pcilib_stop_dma(ctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT); + pcilib_stop_dma(vctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT); ctx->rdma = PCILIB_DMA_ENGINE_INVALID; } #endif /* IPECAMERA_DMA_ADDRESS */ + if (ctx->frame_info) { + free(ctx->frame_info); + ctx->frame_info = NULL; + } + if (ctx->buffer) { free(ctx->buffer); ctx->buffer = NULL; @@ -431,421 +665,143 @@ int ipecamera_stop(pcilib_context_t *vctx) { ctx->cmask = NULL; } + memset(&ctx->autostop, 0, sizeof(ipecamera_autostop_t)); ctx->event_id = 0; ctx->reported_id = 0; - ctx->buf_ptr = 0; + ctx->buffer_pos = 0; + ctx->started = 0; return 0; } -static int ipecamera_get_payload(ipecamera_t *ctx, ipecamera_pixel_t *pbuf, ipecamera_change_mask_t *cbuf, int line_req, pcilib_register_value_t size, ipecamera_payload_t *payload, pcilib_register_value_t *advance) { - int i, j; - int ppw; - int err = 0; - - ipecamera_payload_t info = payload[0]; - int channel = info&0x0F; // 4 bits - const int line = (info>>4)&0x7FF; // 11 bits - // 1 bit is reserved - const int bpp = (info>>16)&0x0F; // 4 bits - const int pixels = (info>>20)&0xFF; // 8 bits - // 2 bits are reserved - int header = (info>>30)&0x03; // 2 bits - - int bytes; - - int pix; - int pix_offset = 0; - - const int chan_offset = channel * IPECAMERA_PIXELS_PER_CHANNEL; - - ipecamera_payload_t data; - -#ifdef IPECAMERA_REORDER_CHANNELS - channel = ipecamera_channel_order[channel]; -#endif -// printf("payload, channel: %i, magick: %i, all: %lx\n", channel, header, info); - - //printf("channel[%x] = %x (line: %i, pixels: %i)\n", info, channel, line_req, pixels); - CHECK_FLAG("payload header magick", header == 2, header); - CHECK_FLAG("pixel size, only 10 bits are supported", bpp == 10, bpp); - CHECK_FLAG("row number, should be %li", line == line_req, line, line_req); - CHECK_FLAG("channel, limited by %li output channels", channel < IPECAMERA_MAX_CHANNELS, channel, IPECAMERA_MAX_CHANNELS); - CHECK_FLAG("channel, duplicate entry for channel", ((*cbuf)&(1<<channel)) == 0, channel); - - // Fixing first lines bug - // Matthias: Using unlikely() saves 1ms - if ((line < 2)&&(pixels == (IPECAMERA_PIXELS_PER_CHANNEL - 1))) { - pix_offset = 1; - pbuf[chan_offset] = 0; - } else { - CHECK_FLAG("number of pixels, %li is expected", pixels == IPECAMERA_PIXELS_PER_CHANNEL, pixels, IPECAMERA_PIXELS_PER_CHANNEL); - } - - bytes = pixels / 3; - ppw = pixels - bytes * 3; - if (ppw) ++bytes; - - CHECK_FLAG("payload data bytes, at least %i are expected", bytes < size, size, bytes); - - if (err) return err; - - for (i = 1, pix = pix_offset; i < bytes; i++) { - data = payload[i]; - header = (data >> 30) & 0x03; - - CHECK_FLAG("payload data magick", header == 3, header); - if (err) return err; - - // DS: Unroll - for (j = 0; j < 3; j++, pix++) { - pbuf[chan_offset + pix] = (data >> (10 * (2 - j))) & 0x3FF; - } - } - - data = payload[bytes]; - header = (data >> 30) & 0x03; - - CHECK_FLAG("payload data magick", header == 3, header); - CHECK_FLAG("payload footer magick", (data&0x3FF) == 0x55, (data&0x3FF)); - if (err) return err; - - ppw = pixels%3; - assert(ppw < 3); - - for (j = 0; j < ppw; j++, pix++) { -// pbuf[channel*IPECAMERA_PIXELS_PER_CHANNEL + pix] = (data >> (10 * (ppw - j - 1))) & 0x3FF; - pbuf[chan_offset + pix] = (data >> (10 * (ppw - j))) & 0x3FF; - } - - *cbuf |= (1 << channel); - *advance = bytes + 1; - - return 0; -} - -static int ipecamera_parse_image(ipecamera_t *ctx, ipecamera_pixel_t *pbuf, ipecamera_change_mask_t *cbuf, int first_line, int n_lines, pcilib_register_value_t size, ipecamera_payload_t *linebuf) { +int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) { int err = 0; - pcilib_t *pcilib = ctx->pcilib; - - int line = first_line; - pcilib_register_value_t pos, advance; - - if (size < 16) { - pcilib_error("The payload is tool small, we should have at least 8 header dwords and 8 footer."); - return PCILIB_ERROR_INVALID_DATA; - } - - CHECK_VALUE(linebuf[0], 0x51111111); - CHECK_VALUE(linebuf[1], 0x52222222); - CHECK_VALUE(linebuf[2], 0x53333333); - CHECK_VALUE(linebuf[3], 0x54444444); - CHECK_VALUE(linebuf[4], 0x55555555); - CHECK_VALUE(linebuf[5], 0x56666666); - CHECK_VALUE(linebuf[6], 0x57777777); - CHECK_VALUE(linebuf[7], 0x58888888); - if (err) return err; + pcilib_register_value_t value; - pos = 8; - size -= 16; + ipecamera_t *ctx = (ipecamera_t*)vctx; + pcilib_t *pcilib = vctx->pcilib; - while (size > 0) { - err = ipecamera_get_payload(ctx, pbuf + line * ctx->dim.width, cbuf + line, line - first_line, size, linebuf + pos, &advance); - if (err) return err; - - pos += advance; - size -= advance; - - if (cbuf[line] == ((1<<IPECAMERA_MAX_CHANNELS)-1)) ++line; + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; } - CHECK_FLAG("lines read, we expect to read exactly %li lines", line == (first_line + n_lines), line - first_line, n_lines); - - CHECK_VALUE(linebuf[pos ], 0x0AAAAAAA); - CHECK_VALUE(linebuf[pos+1], 0x0BBBBBBB); - CHECK_VALUE(linebuf[pos+2], 0x0CCCCCCC); - CHECK_VALUE(linebuf[pos+3], 0x0DDDDDDD); - CHECK_VALUE(linebuf[pos+4], 0x0EEEEEEE); - CHECK_VALUE(linebuf[pos+5], 0x0FFFFFFF); - CHECK_VALUE(linebuf[pos+6], 0x00000000); - CHECK_VALUE(linebuf[pos+7], 0x01111111); - - return err; -} - -static int ipecamera_get_image(ipecamera_t *ctx) { - int err; - int i; - int buf_ptr; - size_t bytes_read; - pcilib_t *pcilib = ctx->pcilib; - - int num_lines; - const int max_lines = IPECAMERA_MAX_LINES; - const size_t line_size = (IPECAMERA_MAX_CHANNELS * (2 + IPECAMERA_PIXELS_PER_CHANNEL / 3)); - const size_t hf_size = 16; - const size_t max_size = hf_size + max_lines * line_size; - const size_t dma_packet_len = IPECAMERA_DMA_PACKET_LENGTH / sizeof(ipecamera_payload_t); - size_t max_packet_size; - - pcilib_register_value_t ptr, size, pos, advance, value; - - ipecamera_payload_t *linebuf; - - if (max_size%dma_packet_len) max_packet_size = max_size + dma_packet_len - (max_size%dma_packet_len); - else max_packet_size = max_size; - - max_packet_size += 4096; // Some extra data? - - - linebuf = (ipecamera_payload_t*)malloc(max_packet_size * sizeof(ipecamera_payload_t)); - if (!linebuf) return PCILIB_ERROR_MEMORY; - - // DS: test - err = pcilib_skip_dma(ctx->pcilib, ctx->rdma); - if (err) { - pcilib_error("Can't start benchmark, devices continuously writes unexpected data using DMA engine"); - return err; + if (!ctx->started) { + pcilib_error("Can't trigger while grabbing is not started"); + return PCILIB_ERROR_INVALID_REQUEST; } + SET_REG(control_reg, IPECAMERA_FRAME_REQUEST|IPECAMERA_READOUT_FLAG); + usleep(IPECAMERA_WAIT_FRAME_RCVD_TIME); + CHECK_REG(status_reg, IPECAMERA_EXPECTED_STATUS); + SET_REG(control_reg, IPECAMERA_IDLE|IPECAMERA_READOUT_FLAG); -#ifdef IPECAMERA_WRITE_RAW - FILE *f = fopen("raw/image.raw", "w"); - if (f) fclose(f); -#endif - - //atomic - buf_ptr = ctx->buf_ptr; - if (ctx->buf_ptr++ == ctx->buffer_size) ctx->buf_ptr = 0; - if (ctx->event_id++ == 0) ctx->event_id = 1; - - //const size_t image_size = ctx->dim.width * ctx->dim.height; - //memset(ctx->buffer + buf_ptr * image_size, 0, image_size * sizeof(ipecamera_pixel_t)); - memset(ctx->cmask + buf_ptr * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t)); - - - for (i = 0; i < ctx->dim.height; i += max_lines) { - num_lines = ctx->dim.height - i; - if (num_lines > max_lines) num_lines = max_lines; - - SET_REG(n_lines_reg, num_lines); - SET_REG(line_reg, i); - - SET_REG(control_reg, IPECAMERA_FRAME_REQUEST); - usleep(IPECAMERA_WAIT_FRAME_RCVD_TIME); - CHECK_REG(status_reg, IPECAMERA_EXPECTED_STATUS); - SET_REG(control_reg, IPECAMERA_IDLE); - -#ifndef IPECAMERA_DMA_ADDRESS - GET_REG(start_reg, ptr); - GET_REG(end_reg, size); - - size -= ptr; - size *= 2; - - CHECK_FLAG("data size", (size > 0)&&(size <= max_size), size); -#endif /* IPECAMERA_DMA_ADDRESS */ - - - if (err) break; - - SET_REG(control_reg, IPECAMERA_READOUT); - // sync between End Of Readout and next Frame Req - usleep(IPECAMERA_NEXT_FRAME_DELAY); - -// usleep(1000000); - -// pcilib_start_dma(ctx->pcilib, ctx->rdma, PCILIB_DMA_FLAG_PERSISTENT); -// pcilib_stop_dma(ctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT); -// pcilib_start_dma(ctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT); - - -#ifdef IPECAMERA_DMA_ADDRESS - size = 0; - do { - err = pcilib_read_dma(ctx->pcilib, ctx->rdma, 0, max_packet_size * sizeof(ipecamera_payload_t) - size, ((uint8_t*)linebuf) + size, &bytes_read); - size += bytes_read; -// printf("%lu %lu\n", bytes_read, size); - } while ((err == 0)&&(size < max_packet_size * sizeof(ipecamera_payload_t))); - - -#ifdef DEBUG_HARDWARE - uint32_t regval; - printf("===========Lines: %i - %i =========================\n", i, i + num_lines - 1); - err = pcilib_read_register(ctx->pcilib, NULL, "status", ®val); - printf("Status1: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "start_address", ®val); - printf("Start address: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "end_address", ®val); - printf("End address: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "last_write_address", ®val); - printf("Status2: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "last_write_value", ®val); - printf("Status3: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", ®val); - printf("Add_rd_ddr: %i 0x%lx\n", err, regval); -#endif /* DEBUG_HARDWARE */ - - if (err) { - if (err == PCILIB_ERROR_TIMEOUT) { - if (size > 0) err = 0; - else { -#ifdef IPECAMERA_DEBUG - pcilib_warning("There is no data received from IPE Camera for lines: %i to %i", i, i + num_lines - 1); - err = 0; - SET_REG(control_reg, IPECAMERA_IDLE); - continue; -#else /* IPECAMERA_DEBUG */ - pcilib_error("There is no data received from IPE Camera"); - return err; -#endif /* IPECAMERA_DEBUG */ - } - } else pcilib_error("DMA read from IPE Camera have failed"); - } else if (!size) { -#ifdef IPECAMERA_DEBUG - pcilib_warning("There is no data received from IPE Camera for lines: %i to %i", i, i + num_lines - 1); - SET_REG(control_reg, IPECAMERA_IDLE); - continue; -#else /* IPECAMERA_DEBUG */ - pcilib_warning("There is no data received from IPE Camera for lines: %i to %i", i, i + num_lines - 1); - return err; -#endif /* IPECAMERA_DEBUG */ - } - - pcilib_warning("Reading lines %i to %i: got %i bytes from DMA", i, i + num_lines - 1, size); -#else /* IPECAMERA_DMA_ADDRESS */ - pcilib_warning("Reading lines %i to %i: %i %i", i, i + num_lines - 1, ptr, size); - pcilib_datacpy(linebuf, ctx->data + ptr, sizeof(ipecamera_payload_t), size, pcilib_model[PCILIB_MODEL_IPECAMERA].endianess); -#endif /* IPECAMERA_DMA_ADDRESS */ - - SET_REG(control_reg, IPECAMERA_IDLE); -// usleep(IPECAMERA_SLEEP_TIME); - CHECK_REG(status_reg, IPECAMERA_EXPECTED_STATUS); - - if (err) break; -#ifdef IPECAMERA_WRITE_RAW - char fname[256]; - sprintf(fname, "raw/line%04i", i); - FILE *f = fopen(fname, "w"); - if (f) { -#ifdef IPECAMERA_DMA_ADDRESS - (void)fwrite(linebuf, sizeof(ipecamera_payload_t), size / sizeof(ipecamera_payload_t), f); -#else /* IPECAMERA_DMA_ADDRESS */ - (void)fwrite(linebuf, sizeof(ipecamera_payload_t), size, f); -#endif /* IPECAMERA_DMA_ADDRESS */ - fclose(f); - } -#endif +// SET_REG(control_reg, IPECAMERA_READOUT); + usleep(IPECAMERA_NEXT_FRAME_DELAY); // minimum delay between End Of Readout and next Frame Req -#ifdef IPECAMERA_DMA_ADDRESS - if (size < (hf_size + max_lines * line_size) * sizeof(ipecamera_payload_t)) { - pcilib_error("We are expecting at least %zu bytes, but only %lu are read", (hf_size + num_lines * line_size)*sizeof(ipecamera_payload_t), size); - err = PCILIB_ERROR_INVALID_DATA; - } + // DS: check for overflow +/* - bytes_read = size; - size = hf_size + max_lines * line_size; -#endif /* IPECAMERA_DMA_ADDRESS */ - - - err = ipecamera_parse_image(ctx, ctx->buffer + buf_ptr * ctx->dim.width * ctx->dim.height, ctx->cmask + buf_ptr * ctx->dim.height, i, num_lines, size, linebuf); - if (err) break; - -#ifdef IPECAMERA_WRITE_RAW - f = fopen("raw/image.raw", "a+"); - if (f) { - fwrite(ctx->buffer + buf_ptr * ctx->dim.width * ctx->dim.height + i * ctx->dim.width, sizeof(ipecamera_pixel_t), num_lines * ctx->dim.width, f); - fclose(f); + err = ipecamera_get_image(ctx); + if (!err) { + if (ctx->cb) { + err = ctx->cb(event, ctx->event_id, ctx->cb_user); + ctx->reported_id = ctx->event_id; } -#endif } - free(linebuf); - return err; +*/ } - -int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) { - int err; - pcilib_t *pcilib; +int ipecamera_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, void *user) { + int err = 0; + int do_stop = 0; + pcilib_event_id_t reported; ipecamera_t *ctx = (ipecamera_t*)vctx; + size_t events = 0; + + struct timeval stream_stop; + if (!ctx) { pcilib_error("IPECamera imaging is not initialized"); return PCILIB_ERROR_NOTINITIALIZED; } + ctx->streaming = 1; + ctx->run_streamer = 1; + if (!ctx->started) { - pcilib_error("Can't trigger while not grabbing is not started"); - return PCILIB_ERROR_INVALID_REQUEST; + err = ipecamera_start(vctx, PCILIB_EVENTS_ALL, PCILIB_EVENT_FLAGS_DEFAULT); + if (err) { + ctx->streaming = 0; + pcilib_error("IPECamera is not in grabbing state"); + return PCILIB_ERROR_INVALID_STATE; + } + + do_stop = 1; } - err = ipecamera_get_image(ctx); - if (!err) { - if (ctx->cb) { - err = ctx->cb(event, ctx->event_id, ctx->cb_user); - ctx->reported_id = ctx->event_id; + // This loop iterates while the generation + while ((ctx->run_streamer)||(ctx->reported_id != ctx->event_id)) { + while (ctx->reported_id != ctx->event_id) { + if ((ctx->event_id - ctx->reported_id) > (ctx->buffer_size - IPECAMERA_RESERVE_BUFFERS)) ctx->reported_id = ctx->event_id - (ctx->buffer_size - 1) - IPECAMERA_RESERVE_BUFFERS; + else ++ctx->reported_id; + + callback(ctx->reported_id, (pcilib_event_info_t*)(ctx->frame_info + (ctx->reported_id%ctx->buffer_size)), user); } + usleep(IPECAMERA_NOFRAME_SLEEP); } - return err; -} + ctx->streaming = 0; -static int ipecamera_resolve_event_id(ipecamera_t *ctx, pcilib_event_id_t evid) { - int buf_ptr, diff; + if (do_stop) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + } - if ((!evid)||(evid > ctx->event_id)) return -1; - diff = ctx->event_id - evid; - buf_ptr = ctx->buf_ptr - diff - 1; - if (buf_ptr < 0) { - buf_ptr += ctx->buffer_size; - if (buf_ptr < 0) return -1; - } - return buf_ptr; + return err; } -pcilib_event_id_t ipecamera_next_event(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_timeout_t timeout) { - int buf_ptr; - pcilib_event_id_t reported; + +int ipecamera_next_event(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_timeout_t timeout, pcilib_event_id_t *evid, pcilib_event_info_t **info) { + struct timeval tv; ipecamera_t *ctx = (ipecamera_t*)vctx; if (!ctx) { pcilib_error("IPECamera imaging is not initialized"); - return PCILIB_EVENT_ID_INVALID; + return PCILIB_ERROR_NOTINITIALIZED; } if (!ctx->started) { - pcilib_error("IPECamera is not in grabbing state"); - return PCILIB_EVENT_ID_INVALID; + pcilib_error("IPECamera is not in grabbing mode"); + return PCILIB_ERROR_INVALID_REQUEST; } - if ((!ctx->event_id)||(ctx->reported_id == ctx->event_id)) { + if (ctx->reported_id == ctx->event_id) { if (timeout) { - // We should wait here for the specified timeout + calc_deadline(&tv, timeout); + + while ((calc_time_to_deadline(&tv) > 0)&&(ctx->reported_id == ctx->event_id)) + usleep(IPECAMERA_NOFRAME_SLEEP); } - return PCILIB_EVENT_ID_INVALID; + + if (ctx->reported_id == ctx->event_id) return PCILIB_ERROR_TIMEOUT; } - // We had an overflow in event counting - if (ctx->reported_id > ctx->event_id) { - do { - if (++ctx->reported_id == 0) ctx->reported_id = 1; - } while (ipecamera_resolve_event_id(ctx, ctx->reported_id) < 0); - } else { - if ((ctx->event_id - ctx->reported_id) > ctx->buffer_size) ctx->reported_id = ctx->event_id - (ctx->buffer_size - 1); - else ++ctx->reported_id; - } - + if ((ctx->event_id - ctx->reported_id) > (ctx->buffer_size - IPECAMERA_RESERVE_BUFFERS)) ctx->reported_id = ctx->event_id - (ctx->buffer_size - 1) - IPECAMERA_RESERVE_BUFFERS; + else ++ctx->reported_id; + return ctx->reported_id; } -void* ipecamera_get(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size) { + +void* ipecamera_get(pcilib_context_t *vctx, 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 buf_ptr; ipecamera_t *ctx = (ipecamera_t*)vctx; @@ -856,9 +812,6 @@ void* ipecamera_get(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_e buf_ptr = ipecamera_resolve_event_id(ctx, event_id); - - //printf("%i %i %i\n", ctx->event_id, event_id, buf_ptr); - if (buf_ptr < 0) return NULL; switch ((ipecamera_data_type_t)data_type) { @@ -886,7 +839,7 @@ void* ipecamera_get(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_e -int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id) { +int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id, void *data) { ipecamera_t *ctx = (ipecamera_t*)vctx; if (!ctx) { diff --git a/ipecamera/image.h b/ipecamera/image.h index b414f74..c311b4d 100644 --- a/ipecamera/image.h +++ b/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); diff --git a/ipecamera/ipecamera.h b/ipecamera/ipecamera.h index 49afe0c..d15d1f2 100644 --- a/ipecamera/ipecamera.h +++ b/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, diff --git a/ipecamera/model.h b/ipecamera/model.h index fb0559c..615494a 100644 --- a/ipecamera/model.h +++ b/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 @@ -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; @@ -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] = { @@ -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; @@ -72,6 +73,24 @@ typedef enum { } 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, PCILIB_REGISTER_BITS @@ -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. diff --git a/pcitool/sysinfo.c b/pcitool/sysinfo.c new file mode 100644 index 0000000..51e7566 --- /dev/null +++ b/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; +} diff --git a/pcitool/sysinfo.h b/pcitool/sysinfo.h new file mode 100644 index 0000000..d5636a7 --- /dev/null +++ b/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 */ diff --git a/tests/grab.sh b/tests/grab.sh index 3d2b03f..35e690b 100755 --- a/tests/grab.sh +++ b/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 @@ -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; +} @@ -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 */ |