diff options
author | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-12-12 05:45:35 +0100 |
---|---|---|
committer | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-12-12 05:45:35 +0100 |
commit | 2e4e8a00b27182a155cb10f0a00e44977bfcd5cf (patch) | |
tree | 86afd1b7ceb834dbb3cedf8d55c3ac0734947333 | |
parent | 7a4cfb9e546c496792d3fe0c61c822c66ad0128f (diff) | |
download | pcitool-2e4e8a00b27182a155cb10f0a00e44977bfcd5cf.tar.gz pcitool-2e4e8a00b27182a155cb10f0a00e44977bfcd5cf.tar.bz2 pcitool-2e4e8a00b27182a155cb10f0a00e44977bfcd5cf.tar.xz pcitool-2e4e8a00b27182a155cb10f0a00e44977bfcd5cf.zip |
multithread preprocessing of ipecamera frames and code reorganization
43 files changed, 1699 insertions, 1266 deletions
@@ -12,3 +12,8 @@ ipecamera.d pci.d tools.d *.d +CMakeCache.txt +CMakeFiles +cmake_install.cmake +Makefile +*.so.* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7664481 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,38 @@ +project(pcitool) + +set(PCILIB_VERSION "0.0.1") +set(PCILIB_ABI_VERSION "0") + +cmake_minimum_required(VERSION 2.8) + +find_package(PkgConfig REQUIRED) + +#Check in sibling directory +pkg_check_modules(UFODECODE ufodecode REQUIRED) + +set(HEADERS pcilib.h pci.h register.h kmem.h irq.h dma.h event.h default.h tools.h error.h) +add_definitions("-fPIC --std=c99 -Wall -O2 -pthread") + +add_subdirectory(dma) +add_subdirectory(ipecamera) +add_subdirectory(pcitool) + +add_library(pcilib SHARED pci.c register.c kmem.c irq.c dma.c event.c default.c tools.c error.c) +target_link_libraries(pcilib ufodecode dma ipecamera) +add_dependencies(pcilib dma ipecamera) + +set_target_properties(pcilib PROPERTIES + VERSION ${PCILIB_VERSION} + SOVERSION ${PCILIB_ABI_VERSION} + LINK_FLAGS "-pthread" +# LINK_FLAGS "-pthread -Wl,--whole-archive,dma/libdma.a,ipecamera/libipecamera.a,--no-whole-archive" +) + +add_executable(pci cli.c) +add_dependencies(pci pcitool) +target_link_libraries(pci pcilib pcitool) + +#set_target_properties(pci PROPERTIES +# LINK_FLAGS "-Wl,pcitool/libpcitool.a" +#) + diff --git a/Makefile b/Makefile deleted file mode 100644 index f510ac3..0000000 --- a/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -BINARIES += pci - -INCDIR += ./ -LDINC += $(addprefix -L ,$(LIBDIR)) -LDFLAGS += -pthread -lufodecode -CFLAGS += -pthread -DESTDIR ?= /usr/local - -all: $(BINARIES) - -.PHONY: all depend clean - -include common.mk - -############################################################### -# Target definitions - -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 pcitool/sysinfo.o libpcilib.so - echo -e "LD \t$@" - $(Q)$(CC) $(LDINC) $(LDFLAGS) $(CFLAGS) -L. -lpcilib -o $@ $< - -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 - -clean: - @echo -e "CLEAN \t$(shell pwd)" - -$(Q)rm -f $(addprefix $(BINDIR)/,$(BINARIES)) - -$(Q)rm -f $(OBJ) - -$(Q)rm -f $(DEPEND) @@ -186,16 +186,32 @@ 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. + can't really use DMA pages are sole buffers. Therefore, a second thread, with + a realtime scheduling policy if possible, will be spawned and will copy the + data from the DMA pages into the allocated buffers. On expiration of duration + or number of events set by autostop call, this thread will be stopped but + processing in streaming mode will continue until all copyied data is passed + to the callbacks. - - Actually, we can make another in-module buffering. But this hopefully can - be avoided. + To avoid stalls, the IPECamera requires data to be read continuously read out. + For this reason, there is no locks in the readout thread. It will simplify + overwrite the old frames if data is not copied out timely. To handle this case + after getting the data and processing it, the calling application should use + return_data function and check return code. This function may return error + indicating that the data was overwritten meanwhile. Hence, the data is + corrupted and shoud be droped by the application. The copy_data function + performs this check and user application can be sure it get coherent data + in this case. + + There is a way to avoid this problem. For raw data, the rawdata callback + can be requested. This callback blocks execution of readout thread and + data may be treated safely by calling application. However, this may + cause problems to electronics. Therefore, only memcpy should be performed + on the data normally. + + The reconstructed data, however, may be safely accessed. As described above, + the raw data will be continuously overwritten by the reader thread. However, + reconstructed data, upon the get_data call, will be protected by the mutex. Register Access Synchronization @@ -345,6 +345,8 @@ void List(pcilib_t *handle, pcilib_model_description_t *model_info, const char * case PCILIB_DMA_TYPE_PACKET: printf("Packet"); break; + default: + printf("Unknown"); } printf(", Address Width: %02lu bits\n", engine->addr_bits); @@ -371,7 +373,7 @@ void List(pcilib_t *handle, pcilib_model_description_t *model_info, const char * else registers = model_info->registers; if (registers) { - pcilib_register_bank_addr_t bank_addr; + pcilib_register_bank_addr_t bank_addr = 0; if (bank) { pcilib_register_bank_t bank_id = pcilib_find_bank(handle, bank); pcilib_register_bank_description_t *b = model_info->banks + bank_id; @@ -458,7 +460,7 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, int err; int i, j, errors; void *data, *buf, *check; - void *fifo; + void *fifo = NULL; struct timeval start, end; unsigned long time; size_t size, min_size, max_size; @@ -483,7 +485,7 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, err = pcilib_wait_irq(handle, 0, 0, &irqs); if (err) irqs = 0; - printf("%8i KB - ", size / 1024); + printf("%8zu KB - ", size / 1024); printf("RW: "); if (mbs < 0) printf("failed ... "); @@ -571,7 +573,7 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, gettimeofday(&end,NULL); time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); - printf("%8i bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); + printf("%8zu bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); fflush(0); @@ -611,7 +613,7 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, gettimeofday(&end,NULL); time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); - printf("%8i bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); + printf("%8zu bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); fflush(0); @@ -651,6 +653,8 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, free(check); free(buf); + + return 0; } #define pci2host16(endianess, value) endianess? @@ -793,7 +797,7 @@ int ReadRegister(pcilib_t *handle, pcilib_model_description_t *model_info, const const char *format; pcilib_register_bank_t bank_id; - pcilib_register_bank_addr_t bank_addr; + pcilib_register_bank_addr_t bank_addr = 0; pcilib_register_value_t value; @@ -871,7 +875,7 @@ int ReadRegisterRange(pcilib_t *handle, pcilib_model_description_t *model_info, } int access = banks[bank_id].access / 8; - int size = n * abs(access); +// int size = n * abs(access); int block_width, blocks_per_line; int numbers_per_block, numbers_per_line; @@ -918,7 +922,7 @@ int ReadRegisterRange(pcilib_t *handle, pcilib_model_description_t *model_info, int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, char ** data) { int read_back = 0; void *buf, *check; - int res, i, err; + int res = 0, i, err; int size = n * abs(access); size_t ret; pcilib_dma_engine_t dmaid; @@ -933,6 +937,7 @@ int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, case 2: res = sscanf(data[i], "%hx", ((uint16_t*)buf)+i); break; case 4: res = sscanf(data[i], "%x", ((uint32_t*)buf)+i); break; case 8: res = sscanf(data[i], "%lx", ((uint64_t*)buf)+i); break; + default: Error("Unexpected data size (%lu)", access); } if ((res != 1)||(!isxnumber(data[i]))) Error("Can't parse data value at poition %i, (%s) is not valid hex number", i, data[i]); } @@ -1010,12 +1015,11 @@ int WriteRegisterRange(pcilib_t *handle, pcilib_model_description_t *model_info, int WriteRegister(pcilib_t *handle, pcilib_model_description_t *model_info, const char *bank, const char *reg, char ** data) { int err; - int i; unsigned long val; pcilib_register_value_t value; - const char *format; + const char *format = NULL; pcilib_register_t regid = pcilib_find_register(handle, bank, reg); if (regid == PCILIB_REGISTER_INVALID) Error("Can't find register (%s) from bank (%s)", reg, bank?bank:"autodetected"); @@ -1118,13 +1122,13 @@ int GrabCallback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *us if (info->flags&PCILIB_EVENT_INFO_FLAG_BROKEN) { ctx->broken_count++; - return 0; + return PCILIB_STREAMING_CONTINUE; } data = pcilib_get_data(handle, event_id, ctx->data, &size); if (!data) { ctx->broken_count++; - return 0; + return PCILIB_STREAMING_CONTINUE; } @@ -1136,7 +1140,7 @@ int GrabCallback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *us else Error("Write failed"); } - pcilib_return_data(handle, event_id, data); + pcilib_return_data(handle, event_id, ctx->data, data); // printf("%lu %lu\n", info->seqnum, info->offset); @@ -1161,11 +1165,12 @@ int GrabCallback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *us */ // printf("data callback: %lu\n", event_id); - return 0; + return PCILIB_STREAMING_CONTINUE; } 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); + return PCILIB_STREAMING_CONTINUE; } @@ -1204,7 +1209,7 @@ void *Trigger(void *user) { void GrabStats(GRABContext *ctx, struct timeval *end_time) { pcilib_timeout_t duration, fps_duration; struct timeval cur; - double fps; + double fps = 0; if (!end_time) { gettimeofday(&cur, NULL); @@ -1532,11 +1537,11 @@ int ListKMEM(pcilib_t *handle, const char *device) { while ((entry = readdir(dir)) != NULL) { FILE *f; - unsigned long use; - unsigned long size; - unsigned long refs; - unsigned long mode; - unsigned long hwref; + unsigned long use = 0; + unsigned long size = 0; + unsigned long refs = 0; + unsigned long mode = 0; + unsigned long hwref = 0; if (strncmp(entry->d_name, "kbuf", 4)) continue; if (!isnumber(entry->d_name+4)) continue; @@ -1581,9 +1586,9 @@ int ListKMEM(pcilib_t *handle, const char *device) { printf("%08lx ", uses[i].use); if (!i) printf("All Others "); - else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_RING) printf("DMA%u %s Ring ", uses[i].use&0x7F, ((uses[i].use&0x80)?"S2C":"C2S")); - else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_PAGES) printf("DMA%u %s Pages ", uses[i].use&0x7F, ((uses[i].use&0x80)?"S2C":"C2S")); - else printf (" ", uses[i].use); + else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_RING) printf("DMA%lu %s Ring ", uses[i].use&0x7F, ((uses[i].use&0x80)?"S2C":"C2S")); + else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_PAGES) printf("DMA%lu %s Pages ", uses[i].use&0x7F, ((uses[i].use&0x80)?"S2C":"C2S")); + else printf (" "); printf(" "); printf("% 6lu", uses[i].count); printf(" "); @@ -1611,13 +1616,13 @@ int ReadKMEM(pcilib_t *handle, const char *device, pcilib_kmem_use_t use, size_t void *data; size_t size; pcilib_kmem_handle_t *kbuf; - + kbuf = pcilib_alloc_kernel_memory(handle, 0, block + 1, 0, 0, use, PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_TRY); if (!kbuf) { printf("The specified kernel buffer is not allocated\n"); return 0; } - + data = pcilib_kmem_get_block_ua(handle, kbuf, block); if (data) { size = pcilib_kmem_get_block_size(handle, kbuf, block); @@ -1626,16 +1631,18 @@ int ReadKMEM(pcilib_t *handle, const char *device, pcilib_kmem_use_t use, size_t } else { printf("The specified block is not existing\n"); } - + pcilib_free_kernel_memory(handle, kbuf, KMEM_FLAG_REUSE); + + return 0; } int FreeKMEM(pcilib_t *handle, const char *device, const char *use, int force) { int err; int i; - + unsigned long useid; - + pcilib_kmem_flags_t flags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT|PCILIB_KMEM_FLAG_EXCLUSIVE; if (force) flags |= PCILIB_KMEM_FLAG_FORCE; // this will ignore mmap locks as well. @@ -1653,12 +1660,12 @@ int FreeKMEM(pcilib_t *handle, const char *device, const char *use, int force) { return 0; } - + if ((!isxnumber(use))||(sscanf(use, "%lx", &useid) != 1)) Error("Invalid use (%s) is specified", use); - + err = pcilib_clean_kernel_memory(handle, useid, flags); if (err) Error("Error cleaning kernel buffers for use (0x%lx)", useid); - + return 0; } @@ -1689,11 +1696,11 @@ int ListDMA(pcilib_t *handle, const char *device, pcilib_model_description_t *mo printf("--------------------------------------------------------------------------------\n"); while ((entry = readdir(dir)) != NULL) { FILE *f; - unsigned long use; - unsigned long size; - unsigned long refs; - unsigned long mode; - unsigned long hwref; + unsigned long use = 0; + unsigned long size = 0; + unsigned long refs = 0; + unsigned long mode = 0; + unsigned long hwref = 0; if (strncmp(entry->d_name, "kbuf", 4)) continue; if (!isnumber(entry->d_name+4)) continue; @@ -1724,7 +1731,7 @@ int ListDMA(pcilib_t *handle, const char *device, pcilib_model_description_t *mo if (dmaid == PCILIB_DMA_ENGINE_INVALID) continue; - printf("DMA%u %s ", use&0x7F, (use&0x80)?"S2C":"C2S"); + printf("DMA%lu %s ", use&0x7F, (use&0x80)?"S2C":"C2S"); err = pcilib_start_dma(handle, dmaid, 0); if (err) { printf("-- Wrong state, start is failed\n"); @@ -1773,47 +1780,46 @@ int ListBuffers(pcilib_t *handle, const char *device, pcilib_model_description_t dmaid = pcilib_find_dma_by_addr(handle, dma_direction, dma); if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("The specified DMA engine is not found"); - + err = pcilib_start_dma(handle, dmaid, 0); if (err) Error("Error starting the specified DMA engine"); - + err = pcilib_get_dma_status(handle, dmaid, &status, 0, NULL); if (err) Error("Failed to obtain status of the specified DMA engine"); - + buffer = (pcilib_dma_buffer_status_t*)malloc(status.ring_size*sizeof(pcilib_dma_buffer_status_t)); if (!buffer) Error("Failed to allocate memory for status buffer"); - + err = pcilib_get_dma_status(handle, dmaid, &status, status.ring_size, buffer); if (err) Error("Failed to obtain extended status of the specified DMA engine"); - - + + printf("Buffer Status Total Size \n"); printf("--------------------------------------------------------------------------------\n"); - + for (i = 0; i < status.ring_size; i++) { printf("%8zu ", i); printf("%c%c %c%c ", buffer[i].used?'U':' ', buffer[i].error?'E':' ', buffer[i].first?'F':' ', buffer[i].last?'L':' '); printf("% 10s", PrintSize(stmp, buffer[i].size)); printf("\n"); } - + printf("--------------------------------------------------------------------------------\n"); printf("U - Used, E - Error, F - First block, L - Last Block\n"); - + free(buffer); pcilib_stop_dma(handle, dmaid, 0); + return 0; } int ReadBuffer(pcilib_t *handle, const char *device, pcilib_model_description_t *model_info, pcilib_dma_engine_addr_t dma, pcilib_dma_direction_t dma_direction, size_t block, FILE *o) { int err; - size_t i; pcilib_dma_engine_t dmaid; pcilib_dma_engine_status_t status; pcilib_dma_buffer_status_t *buffer; size_t size; - char stmp[256]; dmaid = pcilib_find_dma_by_addr(handle, dma_direction, dma); if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("The specified DMA engine is not found"); @@ -1902,9 +1908,9 @@ int main(int argc, char **argv) { const char *data_type = NULL; const char *dma_channel = NULL; const char *use = NULL; - pcilib_kmem_use_t use_id; + pcilib_kmem_use_t use_id = 0; size_t block = 0; - pcilib_irq_hw_source_t irq_source; + pcilib_irq_hw_source_t irq_source = PCILIB_IRQ_SOURCE_DEFAULT; pcilib_dma_direction_t dma_direction = PCILIB_DMA_BIDIRECTIONAL; pcilib_dma_engine_addr_t dma = PCILIB_DMA_ENGINE_ADDR_INVALID; @@ -1912,7 +1918,7 @@ int main(int argc, char **argv) { uintptr_t start = -1; size_t size = 1; access_t access = 4; - int skip = 0; +// int skip = 0; int endianess = 0; size_t timeout = 0; const char *output = NULL; @@ -1920,7 +1926,7 @@ int main(int argc, char **argv) { size_t iterations = BENCHMARK_ITERATIONS; pcilib_t *handle; - + int size_set = 0; int timeout_set = 0; int run_time_set = 0; @@ -2046,11 +2052,14 @@ int main(int argc, char **argv) { mode = MODE_WAIT_IRQ; if (optarg) num_offset = optarg; else if ((optind < argc)&&(argv[optind][0] != '-')) num_offset = argv[optind++]; + else num_offset = NULL; - if ((!isnumber(num_offset))||(sscanf(num_offset, "%li", &itmp) != 1)) - Usage(argc, argv, "Invalid IRQ source is specified (%s)", num_offset); + if (num_offset) { + if ((!isnumber(num_offset))||(sscanf(num_offset, "%li", &itmp) != 1)) + Usage(argc, argv, "Invalid IRQ source is specified (%s)", num_offset); - irq_source = itmp; + irq_source = itmp; + } break; case OPT_LIST_KMEM: if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); @@ -2132,11 +2141,12 @@ int main(int argc, char **argv) { } break; case OPT_SIZE: - if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &size) != 1)) + if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &size) != 1)) { if (strcasecmp(optarg, "unlimited")) Usage(argc, argv, "Invalid size is specified (%s)", optarg); else size = 0;//(size_t)-1; + } size_set = 1; break; @@ -2151,11 +2161,12 @@ int main(int argc, char **argv) { break; case OPT_TIMEOUT: - if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &timeout) != 1)) + if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &timeout) != 1)) { if (strcasecmp(optarg, "unlimited")) Usage(argc, argv, "Invalid timeout is specified (%s)", optarg); else timeout = PCILIB_TIMEOUT_INFINITE; + } timeout_set = 1; break; case OPT_OUTPUT: @@ -2172,11 +2183,12 @@ int main(int argc, char **argv) { data_type = optarg; break; case OPT_RUN_TIME: - if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &run_time) != 1)) + if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &run_time) != 1)) { if (strcasecmp(optarg, "unlimited")) Usage(argc, argv, "Invalid run-time is specified (%s)", optarg); else run_time = 0; + } run_time_set = 1; break; case OPT_TRIGGER_TIME: @@ -2461,6 +2473,8 @@ int main(int argc, char **argv) { case MODE_FREE_KMEM: FreeKMEM(handle, fpga_device, use, force); break; + case MODE_INVALID: + break; } if (ofile) fclose(ofile); @@ -9,15 +9,13 @@ #define default_datacpy(dst, src, access, bank) pcilib_datacpy(dst, src, access, 1, bank->raw_endianess) int pcilib_default_read(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, pcilib_register_value_t *value) { - int err; - char *ptr; pcilib_register_value_t val = 0; int access = bank->access / 8; ptr = pcilib_resolve_register_address(ctx, bank->bar, bank->read_addr + addr); default_datacpy(&val, ptr, access, bank); - + // *value = val&BIT_MASK(bits); *value = val; @@ -26,8 +24,6 @@ int pcilib_default_read(pcilib_t *ctx, pcilib_register_bank_description_t *bank, int pcilib_default_write(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, pcilib_register_value_t value) { - int err; - char *ptr; int access = bank->access / 8; @@ -55,11 +55,11 @@ pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_ int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_engine_t engine, pcilib_dma_engine_description_t *desc) { ctx->dma_info.engines[engine] = desc; + + return 0; } int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { - int err; - const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); if (!info) { pcilib_error("DMA is not supported by the device"); @@ -79,8 +79,6 @@ int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t } int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { - int err; - const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); if (!info) { pcilib_error("DMA is not supported by the device"); @@ -100,8 +98,6 @@ int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t f } int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags) { - int err; - const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); if (!info) { pcilib_error("DMA is not supported by the device"); @@ -121,8 +117,6 @@ int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flag } int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) { - int err; - const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); if (!info) { pcilib_error("DMA is not supported by the device"); @@ -142,8 +136,6 @@ int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) { } int pcilib_acknowledge_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source) { - int err; - const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); if (!info) { pcilib_error("DMA is not supported by the device"); @@ -208,8 +200,6 @@ static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t } 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) { - int err; - const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); if (!info) { pcilib_error("DMA is not supported by the device"); @@ -231,7 +221,7 @@ int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, si return PCILIB_ERROR_NOTAVAILABLE; } - if (info->engines[dma]->direction&PCILIB_DMA_FROM_DEVICE == 0) { + if ((info->engines[dma]->direction&PCILIB_DMA_FROM_DEVICE) == 0) { pcilib_error("The selected engine (%i) is S2C-only and does not support reading", dma); return PCILIB_ERROR_NOTSUPPORTED; } @@ -286,8 +276,6 @@ int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma) { int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written) { - int err; - const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); if (!info) { pcilib_error("DMA is not supported by the device"); @@ -309,7 +297,7 @@ int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size return PCILIB_ERROR_NOTAVAILABLE; } - if (info->engines[dma]->direction&PCILIB_DMA_TO_DEVICE == 0) { + if ((info->engines[dma]->direction&PCILIB_DMA_TO_DEVICE) == 0) { pcilib_error("The selected engine (%i) is C2S-only and does not support writes", dma); return PCILIB_ERROR_NOTSUPPORTED; } @@ -323,8 +311,6 @@ int pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, siz } double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) { - int err; - const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); if (!info) { pcilib_error("DMA is not supported by the device"); @@ -350,8 +336,6 @@ double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr } int pcilib_get_dma_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) { - int err; - const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); if (!info) { pcilib_error("DMA is not supported by the device"); @@ -374,5 +358,4 @@ int pcilib_get_dma_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_eng } return ctx->model_info.dma_api->status(ctx->dma_ctx, dma, status, n_buffers, buffers); - } diff --git a/dma/CMakeLists.txt b/dma/CMakeLists.txt new file mode 100644 index 0000000..3d4226a --- /dev/null +++ b/dma/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories( + ${CMAKE_SOURCE_DIR} +) + + +set(HEADERS ${HEADERS} nwl.h nwl_dma.h nwl_engine.h nwl_irq.h nwl_loopback.h nwl_register.h) + +add_library(dma STATIC nwl.c nwl_engine.c nwl_irq.c nwl_loopback.c nwl_register.c) + @@ -77,7 +77,6 @@ int dma_nwl_stop(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib, pcilib_dma_modification_t type, void *arg) { int i; int err; - uint32_t val; pcilib_dma_engine_t n_engines; pcilib_model_description_t *model_info = pcilib_get_model_description(pcilib); @@ -128,9 +127,6 @@ pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib, pcilib_dma_modification_t t } void dma_nwl_free(pcilib_dma_context_t *vctx) { - int err; - - pcilib_dma_engine_t i; nwl_dma_t *ctx = (nwl_dma_t*)vctx; if (ctx) { diff --git a/dma/nwl_defines.h b/dma/nwl_defines.h index c1ff2eb..ce3b686 100644 --- a/dma/nwl_defines.h +++ b/dma/nwl_defines.h @@ -33,7 +33,7 @@ -#define DMA_BD_MINIMUM_ALIGNMENT 0x40 /**< Minimum byte alignment +#define DMA_BD_MINIMUM_ALIGNMENT 0x40 /**< Minimum byte alignment */ /* Common DMA registers */ #define REG_DMA_CTRL_STATUS 0x4000 /**< DMA Common Ctrl & Status */ diff --git a/dma/nwl_engine.c b/dma/nwl_engine.c index ac87f08..fc07ccd 100644 --- a/dma/nwl_engine.c +++ b/dma/nwl_engine.c @@ -267,14 +267,13 @@ 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 = PCILIB_STREAMING_REQ_PACKET; + pcilib_timeout_t wait = 0; 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; int eop; pcilib_nwl_engine_description_t *info = ctx->engines + dma; @@ -286,7 +285,7 @@ int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uin 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; +// case PCILIB_STREAMING_CHECK: wait = 0; break; } bufnum = dma_nwl_wait_buffer(ctx, info, &bufsize, &eop, wait); diff --git a/dma/nwl_engine_buffers.h b/dma/nwl_engine_buffers.h index b97e469..191a2a6 100644 --- a/dma/nwl_engine_buffers.h +++ b/dma/nwl_engine_buffers.h @@ -3,7 +3,6 @@ #define NWL_RING_UPDATE(data, offset, mask, val) *(uint32_t*)(((char*)(data)) + (offset)) = ((*(uint32_t*)(((char*)(data)) + (offset)))&(mask))|(val) static int dma_nwl_compute_read_s2c_pointers(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, unsigned char *ring, uint32_t ring_pa) { - size_t pos; uint32_t val; char *base = info->base_addr; @@ -42,13 +41,10 @@ static int dma_nwl_compute_read_s2c_pointers(nwl_dma_t *ctx, pcilib_nwl_engine_d } static int dma_nwl_compute_read_c2s_pointers(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, unsigned char *ring, uint32_t ring_pa) { - size_t pos; uint32_t val; - size_t prev; char *base = info->base_addr; - nwl_read_register(val, ctx, base, REG_SW_NEXT_BD); if ((val < ring_pa)||((val - ring_pa) % PCILIB_NWL_DMA_DESCRIPTOR_SIZE)) { if (val < ring_pa) pcilib_warning("Inconsistent C2S DMA Ring buffer is found (REG_SW_NEXT_BD register value (%lx) is below start of the ring [%lx,%lx])", val, ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE); @@ -112,8 +108,8 @@ static int dma_nwl_allocate_engine_buffers(nwl_dma_t *ctx, pcilib_nwl_engine_des if (reuse_ring == reuse_pages) { if (reuse_ring & PCILIB_KMEM_REUSE_PARTIAL) pcilib_warning("Inconsistent DMA buffers are found (only part of required buffers is available), reinitializing..."); else if (reuse_ring & PCILIB_KMEM_REUSE_REUSED) { - if (reuse_ring & PCILIB_KMEM_REUSE_PERSISTENT == 0) pcilib_warning("Lost DMA buffers are found (non-persistent mode), reinitializing..."); - else if (reuse_ring & PCILIB_KMEM_REUSE_HARDWARE == 0) pcilib_warning("Lost DMA buffers are found (missing HW reference), reinitializing..."); + if ((reuse_ring & PCILIB_KMEM_REUSE_PERSISTENT) == 0) pcilib_warning("Lost DMA buffers are found (non-persistent mode), reinitializing..."); + else if ((reuse_ring & PCILIB_KMEM_REUSE_HARDWARE) == 0) pcilib_warning("Lost DMA buffers are found (missing HW reference), reinitializing..."); else { nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_CTRL_STATUS); @@ -174,7 +170,7 @@ static int dma_nwl_allocate_engine_buffers(nwl_dma_t *ctx, pcilib_nwl_engine_des static size_t dma_nwl_clean_buffers(nwl_dma_t * ctx, pcilib_nwl_engine_description_t *info) { size_t res = 0; - uint32_t status, control; + uint32_t status; unsigned char *ring = pcilib_kmem_get_ua(ctx->pcilib, info->ring); ring += info->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE; @@ -282,9 +278,8 @@ static int dma_nwl_push_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t * static size_t dma_nwl_wait_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, size_t *size, int *eop, pcilib_timeout_t timeout) { - uint32_t val; struct timeval start, cur; - uint32_t status_size, status, control; + uint32_t status_size, status; unsigned char *ring = pcilib_kmem_get_ua(ctx->pcilib, info->ring); @@ -325,6 +320,8 @@ static size_t dma_nwl_wait_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_ return (size_t)-1; } +/* + // This function is not used now, but we may need it in the future static int dma_nwl_is_overflown(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info) { uint32_t status; unsigned char *ring = pcilib_kmem_get_ua(ctx->pcilib, info->ring); @@ -334,6 +331,7 @@ static int dma_nwl_is_overflown(nwl_dma_t *ctx, pcilib_nwl_engine_description_t status = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET); return status&DMA_BD_COMP_MASK?1:0; } +*/ static int dma_nwl_return_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info) { uint32_t val; @@ -357,6 +355,8 @@ static int dma_nwl_return_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t info->tail++; if (info->tail == info->ring_size) info->tail = 0; + + return 0; } int dma_nwl_get_status(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) { @@ -375,7 +375,7 @@ int dma_nwl_get_status(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcil status->ring_tail = info->tail; if (info->desc.direction == PCILIB_DMA_FROM_DEVICE) { - size_t pos; + size_t pos = 0; for (i = 0; i < info->ring_size; i++) { pos = status->ring_tail + i; if (pos >= info->ring_size) pos -= info->ring_size; diff --git a/dma/nwl_loopback.c b/dma/nwl_loopback.c index 11f7f34..ce0844f 100644 --- a/dma/nwl_loopback.c +++ b/dma/nwl_loopback.c @@ -66,13 +66,10 @@ int dma_nwl_stop_loopback(nwl_dma_t *ctx) { double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) { int iter, i; - int res; int err; size_t bytes, rbytes; - uint32_t val; uint32_t *buf, *cmp; const char *error = NULL; - pcilib_register_value_t regval; size_t packet_size, blocks; size_t us = 0; @@ -83,9 +80,6 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm pcilib_dma_engine_t readid = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_FROM_DEVICE, dma); pcilib_dma_engine_t writeid = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_TO_DEVICE, dma); - char *read_base = ctx->engines[readid].base_addr; - char *write_base = ctx->engines[writeid].base_addr; - if (size%sizeof(uint32_t)) size = 1 + size / sizeof(uint32_t); else size /= sizeof(uint32_t); @@ -214,8 +208,7 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm #ifndef NWL_BUG_EXTRA_DATA if (direction == PCILIB_DMA_BIDIRECTIONAL) { - res = memcmp(buf, cmp, size * sizeof(uint32_t)); - if (res) { + if (memcmp(buf, cmp, size * sizeof(uint32_t))) { for (i = 0; i < size; i++) if (buf[i] != cmp[i]) break; diff --git a/dma/nwl_register.c b/dma/nwl_register.c index 95b981a..5f94e4d 100644 --- a/dma/nwl_register.c +++ b/dma/nwl_register.c @@ -1,3 +1,5 @@ +#define _PCILIB_NWL_REGISTER_C + #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/dma/nwl_register.h b/dma/nwl_register.h index 2f465bd..a71942b 100644 --- a/dma/nwl_register.h +++ b/dma/nwl_register.h @@ -1,6 +1,7 @@ #ifndef _PCILIB_NWL_REGISTERS_H #define _PCILIB_NWL_REGISTERS_H +#ifdef _PCILIB_NWL_REGISTER_C // DMA static pcilib_register_description_t nwl_dma_registers[] = { {0x4000, 0, 32, 0, 0x00000011, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "dma_control_and_status", ""}, @@ -89,5 +90,8 @@ static pcilib_register_description_t nwl_xrawdata_registers[] = { {0, 0, 0, 0, 0x00000000, 0, 0, 0, NULL, NULL} }; +#endif /* _PCILIB_NWL_REGISTERS_C */ + int nwl_add_registers(nwl_dma_t *ctx); + #endif /* _PCILIB_NWL_REGISTERS_H */ diff --git a/driver/pciDriver.h b/driver/pciDriver.h index 3ffe8b7..159f6ad 100644 --- a/driver/pciDriver.h +++ b/driver/pciDriver.h @@ -57,7 +57,7 @@ */ #include <linux/ioctl.h> -#include "pcilib_types.h" +#include "../pcilib_types.h" /* Identifies the PCI-E Xilinx ML605 */ #define PCIE_XILINX_VENDOR_ID 0x10ee @@ -0,0 +1,27 @@ +#define _PCILIB_ERROR_C + +#include <stdio.h> +#include <stdarg.h> + +#include "error.h" + +static void pcilib_print_error(const char *msg, ...) { + va_list va; + + va_start(va, msg); + vprintf(msg, va); + va_end(va); + printf("\n"); +} + +void (*pcilib_error)(const char *msg, ...) = pcilib_print_error; +void (*pcilib_warning)(const char *msg, ...) = pcilib_print_error; + +int pcilib_set_error_handler(void (*err)(const char *msg, ...), void (*warn)(const char *msg, ...)) { + if (err) pcilib_error = err; + else pcilib_error = pcilib_print_error; + if (warn) pcilib_warning = warn; + else pcilib_warning = pcilib_print_error; + + return 0; +} @@ -1,25 +1,33 @@ #ifndef _PCILIB_ERROR_H #define _PCILIB_ERROR_H + +#include <errno.h> enum { PCILIB_ERROR_SUCCESS = 0, - PCILIB_ERROR_MEMORY, - PCILIB_ERROR_INVALID_REQUEST, - PCILIB_ERROR_INVALID_ADDRESS, - PCILIB_ERROR_INVALID_BANK, - PCILIB_ERROR_INVALID_DATA, - PCILIB_ERROR_INVALID_STATE, - PCILIB_ERROR_TIMEOUT, - PCILIB_ERROR_FAILED, - PCILIB_ERROR_VERIFY, - PCILIB_ERROR_NOTSUPPORTED, - PCILIB_ERROR_NOTFOUND, - PCILIB_ERROR_OUTOFRANGE, - PCILIB_ERROR_NOTAVAILABLE, - PCILIB_ERROR_NOTINITIALIZED, - PCILIB_ERROR_TOOBIG, - PCILIB_ERROR_THREAD + PCILIB_ERROR_MEMORY = ENOMEM, + PCILIB_ERROR_INVALID_REQUEST = EBADR, + PCILIB_ERROR_INVALID_ADDRESS = EFAULT, + PCILIB_ERROR_INVALID_BANK = ENOENT, + PCILIB_ERROR_INVALID_DATA = EILSEQ, + PCILIB_ERROR_INVALID_STATE = EBADFD, + PCILIB_ERROR_INVALID_ARGUMENT = EINVAL, + PCILIB_ERROR_TIMEOUT = ETIME, + PCILIB_ERROR_FAILED = EBADE, + PCILIB_ERROR_VERIFY = EREMOTEIO, + PCILIB_ERROR_NOTSUPPORTED = ENOTSUP, + PCILIB_ERROR_NOTFOUND = ESRCH, + PCILIB_ERROR_OUTOFRANGE = ERANGE, + PCILIB_ERROR_NOTAVAILABLE = ENAVAIL, + PCILIB_ERROR_NOTINITIALIZED = EBADFD, + PCILIB_ERROR_TOOBIG = EFBIG, + PCILIB_ERROR_OVERWRITTEN = ESTALE } pcilib_errot_t; +#ifndef _PCILIB_ERROR_C +extern void (*pcilib_error)(const char *msg, ...); +extern void (*pcilib_warning)(const char *msg, ...); +#endif /* _PCILIB_ERROR_C */ + #endif /* _PCILIB_ERROR_H */ @@ -29,12 +29,10 @@ struct timespec { pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event) { int i; - pcilib_register_bank_t res; - unsigned long addr; - + pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); pcilib_event_description_t *events = model_info->events; - + for (i = 0; events[i].name; i++) { if (!strcasecmp(events[i].name, event)) return events[i].evid; } @@ -44,8 +42,6 @@ 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) { 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; @@ -193,8 +189,7 @@ static int pcilib_return_event_callback(pcilib_event_id_t event_id, pcilib_event } */ -int pcilib_get_next_event(pcilib_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, pcilib_event_info_t **info) { - int err; +int pcilib_get_next_event(pcilib_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info) { pcilib_event_api_description_t *api; // pcilib_return_event_callback_context_t user; @@ -207,7 +202,7 @@ int pcilib_get_next_event(pcilib_t *ctx, pcilib_timeout_t timeout, pcilib_event_ } if (api->next_event) - return api->next_event(ctx->event_ctx, timeout, evid, info); + return api->next_event(ctx->event_ctx, timeout, evid, info_size, info); /* if (api->stream) { @@ -245,22 +240,33 @@ int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, voi 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) { + int err; + void *res = NULL; pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); pcilib_event_api_description_t *api = model_info->event_api; if (!api) { + if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; 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, arg_size, arg, size, NULL); - + if (api->get_data) { + err = api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, size, &res); + if (err) { + if (size) *size = (size_t)err; + return NULL; + } + return res; + } + + if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; 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; + int err; + void *res = buf; pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); pcilib_event_api_description_t *api = model_info->event_api; @@ -270,8 +276,10 @@ int pcilib_copy_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pc } 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; + err = api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, &size, &res); + if (err) return err; + + if (buf != res) memcpy(buf, res, size); if (retsize) *retsize = size; return 0; @@ -282,22 +290,33 @@ int pcilib_copy_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pc void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) { + int err; + void *res = NULL; 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"); + if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; return NULL; } - if (api->get_data) - return api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, size, NULL); + if (api->get_data) { + err = api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, size, &res); + if (err) { + if (size) *size = (size_t)err; + return NULL; + } + return res; + } + if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; return NULL; } 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; + int err; + void *res = buf; pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); pcilib_event_api_description_t *api = model_info->event_api; @@ -307,9 +326,11 @@ int pcilib_copy_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_dat } 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; + err = api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, &size, &res); + if (err) return err; + if (buf != res) memcpy(buf, res, size); + if (ret_size) *ret_size = size; return 0; } @@ -317,7 +338,7 @@ int pcilib_copy_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_dat return PCILIB_ERROR_NOTSUPPORTED; } -int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id, void *data) { +int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data) { pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); pcilib_event_api_description_t *api = model_info->event_api; @@ -327,7 +348,7 @@ int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id, void *data) { } if (api->return_data) - return api->return_data(ctx->event_ctx, event_id, data); + return api->return_data(ctx->event_ctx, event_id, data_type, data); return 0; } @@ -352,13 +373,13 @@ static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id data = pcilib_get_data(user->ctx, event_id, PCILIB_EVENT_DATA, &size); if (!data) { pcilib_error("Error getting event data"); - return PCILIB_ERROR_FAILED; + return -(int)size; } 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; + return -PCILIB_ERROR_MEMORY; } *(user->size) = size; @@ -366,7 +387,7 @@ static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id *(user->data) = malloc(size); if (!*(user->data)) { pcilib_error("Memory allocation (%i bytes) for event data is failed"); - return PCILIB_ERROR_MEMORY; + return -PCILIB_ERROR_MEMORY; } if (*(user->size)) *(user->size) = size; allocated = 1; @@ -374,22 +395,21 @@ 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, data); + err = pcilib_return_data(user->ctx, event_id, PCILIB_EVENT_DATA, data); 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 -err; } - return 0; + return PCILIB_STREAMING_CONTINUE; } 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}; @@ -397,7 +417,7 @@ int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **d err = pcilib_start(ctx, event_mask, PCILIB_EVENT_FLAGS_DEFAULT); if (!err) err = pcilib_trigger(ctx, event_mask, 0, NULL); if (!err) { - err = pcilib_get_next_event(ctx, timeout, &eid, NULL); + err = pcilib_get_next_event(ctx, timeout, &eid, 0, NULL); if (!err) pcilib_grab_callback(event_mask, eid, &user); } pcilib_stop(ctx, PCILIB_EVENT_FLAGS_DEFAULT); @@ -3,6 +3,19 @@ #include "pcilib.h" + +/* + * get_data: This call is used by get_data and copy_data functions of public + * interface. When copy_data is the caller, the data parameter will be passed. + * Therefore, depending on data the parameter, the function should behave + * diferently. If get get_data function is used (buf == NULL), the caller is + * expected to call return_data afterwards. Otherwise, if buf != NULL and + * copy_data is used, the return call will not be executed. + * Still, the get_data function is not obliged to return the data in the + * passed buf, but a reference to the staticaly allocated memory may be + * returned instead. The copy can be managed by the envelope function. + */ + struct pcilib_event_api_description_s { pcilib_context_t *(*init)(pcilib_t *ctx); void (*free)(pcilib_context_t *ctx); @@ -14,10 +27,10 @@ struct pcilib_event_api_description_s { int (*trigger)(pcilib_context_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data); 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); + int (*next_event)(pcilib_context_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, 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); + int (*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, pcilib_event_data_type_t data_type, void *data); pcilib_dma_context_t *(*init_dma)(pcilib_context_t *ctx); }; diff --git a/ipecamera/CMakeLists.txt b/ipecamera/CMakeLists.txt new file mode 100644 index 0000000..029993c --- /dev/null +++ b/ipecamera/CMakeLists.txt @@ -0,0 +1,8 @@ +include_directories( + ${CMAKE_SOURCE_DIR} +) + +set(HEADERS ${HEADERS} ipecamera.h model.h reader.h events.h data.h public.h private.h) + +add_library(ipecamera STATIC ipecamera.c model.c reader.c events.c data.c) + diff --git a/ipecamera/data.c b/ipecamera/data.c new file mode 100644 index 0000000..5de6617 --- /dev/null +++ b/ipecamera/data.c @@ -0,0 +1,270 @@ +#define _IPECAMERA_IMAGE_C +#define _BSD_SOURCE +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/time.h> +#include <pthread.h> +#include <assert.h> + +#include <ufodecode.h> + +#include "../tools.h" +#include "../error.h" + +#include "pcilib.h" +#include "private.h" +#include "data.h" + +// 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; +} + +inline static int ipecamera_decode_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) { + int err = 0; + uint32_t tmp; + uint16_t *pixels; + + int buf_ptr = ipecamera_resolve_event_id(ctx, event_id); + if (buf_ptr < 0) return PCILIB_ERROR_TIMEOUT; + + if (ctx->frame[buf_ptr].event.image_ready) return 0; + + if (ctx->frame[buf_ptr].event.info.flags&PCILIB_EVENT_INFO_FLAG_BROKEN) { + ctx->frame[buf_ptr].event.image_broken = 1; + err = PCILIB_ERROR_INVALID_DATA; + goto ready; + } + + + pixels = ctx->image + buf_ptr * ctx->image_size; + memset(ctx->cmask + ctx->buffer_pos * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t)); + err = ufo_decoder_decode_frame(ctx->ipedec, ctx->buffer + buf_ptr * ctx->padded_size, ctx->raw_size, pixels, &tmp, &tmp, ctx->cmask + ctx->buffer_pos * ctx->dim.height); + if (err) { + ctx->frame[buf_ptr].event.image_broken = 1; + err = PCILIB_ERROR_FAILED; + goto ready; + } + + ctx->frame[buf_ptr].event.image_broken = 0; + +ready: + ctx->frame[buf_ptr].event.image_ready = 1; + + if (ipecamera_resolve_event_id(ctx, event_id) < 0) { + ctx->frame[buf_ptr].event.image_ready = 0; + return PCILIB_ERROR_TIMEOUT; + } + + return err; +} + +static int ipecamera_get_next_buffer_to_process(ipecamera_t *ctx, pcilib_event_id_t *evid) { + int res; + + if (ctx->preproc_id == ctx->event_id) return -1; + + if (ctx->preproc) + pthread_mutex_lock(&ctx->preproc_mutex); + + if (ctx->preproc_id == ctx->event_id) { + if (ctx->preproc) + pthread_mutex_unlock(&ctx->preproc_mutex); + return -1; + } + + if ((ctx->event_id - ctx->preproc_id) > (ctx->buffer_size - IPECAMERA_RESERVE_BUFFERS)) ctx->preproc_id = ctx->event_id - (ctx->buffer_size - 1) - IPECAMERA_RESERVE_BUFFERS - 1; + + res = ctx->preproc_id%ctx->buffer_size; + + if (pthread_rwlock_trywrlock(&ctx->frame[res].mutex)) { + pthread_mutex_unlock(&ctx->preproc_mutex); + return -1; + } + + *evid = ++ctx->preproc_id; + + if (ctx->preproc) + pthread_mutex_unlock(&ctx->preproc_mutex); + + return res; +} + + +void *ipecamera_preproc_thread(void *user) { + int buf_ptr; + pcilib_event_id_t evid; + + ipecamera_preprocessor_t *preproc = (ipecamera_preprocessor_t*)user; + ipecamera_t *ctx = preproc->ipecamera; + + while (ctx->run_preprocessors) { + buf_ptr = ipecamera_get_next_buffer_to_process(ctx, &evid); + if (buf_ptr < 0) { + usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP); + continue; + } + + ipecamera_decode_frame(ctx, evid); + + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + } + + return NULL; +} + +static int ipecamera_get_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) { + int err; + int buf_ptr = (event_id - 1) % ctx->buffer_size; + + if (!ctx->preproc) { + pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex); + + err = ipecamera_decode_frame(ctx, event_id); + + if (err) { + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + return err; + } + + return 0; + } + + + while (!ctx->frame[buf_ptr].event.image_ready) { + usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP); + + buf_ptr = ipecamera_resolve_event_id(ctx, event_id); + if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN; + } + + pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex); + + buf_ptr = ipecamera_resolve_event_id(ctx, event_id); + if ((buf_ptr < 0)||(!ctx->frame[buf_ptr].event.image_ready)) { + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + return PCILIB_ERROR_OVERWRITTEN; + } + + return 0; +} + + +/* + We will lock the data for non-raw data to prevent ocasional overwritting. The + raw data will be overwritten by the reader thread anyway and we can't do + anything to prevent it for performance reasons. +*/ +int 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 **ret) { + int err; + int buf_ptr; + size_t raw_size; + ipecamera_t *ctx = (ipecamera_t*)vctx; + + void *data = *ret; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + } + + buf_ptr = ipecamera_resolve_event_id(ctx, event_id); + if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN; + + switch ((ipecamera_data_type_t)data_type) { + case IPECAMERA_RAW_DATA: + raw_size = ctx->frame[buf_ptr].event.raw_size; + if (data) { + if ((!size)||(*size < raw_size)) return PCILIB_ERROR_TOOBIG; + memcpy(data, ctx->buffer + buf_ptr * ctx->padded_size, raw_size); + if (ipecamera_resolve_event_id(ctx, event_id) < 0) return PCILIB_ERROR_OVERWRITTEN; + *size = raw_size; + return 0; + } + if (size) *size = raw_size; + *ret = ctx->buffer + buf_ptr * ctx->padded_size; + return 0; + case IPECAMERA_IMAGE_DATA: + err = ipecamera_get_frame(ctx, event_id); + if (err) return err; + + if (data) { + if ((!size)||(*size < ctx->image_size * sizeof(ipecamera_pixel_t))) return PCILIB_ERROR_TOOBIG; + memcpy(data, ctx->image + buf_ptr * ctx->image_size, ctx->image_size * sizeof(ipecamera_pixel_t)); + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + *size = ctx->image_size * sizeof(ipecamera_pixel_t); + return 0; + } + + if (size) *size = ctx->image_size * sizeof(ipecamera_pixel_t); + *ret = ctx->image + buf_ptr * ctx->image_size; + return 0; + case IPECAMERA_CHANGE_MASK: + err = ipecamera_get_frame(ctx, event_id); + if (err) return err; + + if (data) { + if ((!size)||(*size < ctx->dim.height * sizeof(ipecamera_change_mask_t))) return PCILIB_ERROR_TOOBIG; + memcpy(data, ctx->image + buf_ptr * ctx->dim.height, ctx->dim.height * sizeof(ipecamera_change_mask_t)); + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + *size = ctx->dim.height * sizeof(ipecamera_change_mask_t); + return 0; + } + + if (size) *size = ctx->dim.height * sizeof(ipecamera_change_mask_t); + *ret = ctx->cmask + buf_ptr * ctx->dim.height; + return 0; + case IPECAMERA_DIMENSIONS: + if (size) *size = sizeof(ipecamera_image_dimensions_t); + ret = (void*)&ctx->dim; + return 0; + case IPECAMERA_IMAGE_REGION: + case IPECAMERA_PACKED_IMAGE: + // Shall we return complete image or only changed parts? + case IPECAMERA_PACKED_LINE: + case IPECAMERA_PACKED_PAYLOAD: + pcilib_error("Support for data type (%li) is not implemented yet", data_type); + return PCILIB_ERROR_NOTSUPPORTED; + default: + pcilib_error("Unknown data type (%li) is requested", data_type); + return PCILIB_ERROR_INVALID_REQUEST; + } +} + + +/* + We will unlock non-raw data and check if the raw data is not overwritten yet +*/ +int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data) { + ipecamera_t *ctx = (ipecamera_t*)vctx; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + + } + + if ((ipecamera_data_type_t)data_type == IPECAMERA_RAW_DATA) { + if (ipecamera_resolve_event_id(ctx, event_id) < 0) return PCILIB_ERROR_OVERWRITTEN; + } else { + int buf_ptr = (event_id - 1) % ctx->buffer_size; + pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex); + } + + return 0; +} diff --git a/ipecamera/data.h b/ipecamera/data.h new file mode 100644 index 0000000..846cb78 --- /dev/null +++ b/ipecamera/data.h @@ -0,0 +1,6 @@ +#ifndef _IPECAMERA_DATA_H +#define _IPECAMERA_DATA_H + +void *ipecamera_preproc_thread(void *user); + +#endif /* _IPECAMERA_DATA_H */ diff --git a/ipecamera/events.c b/ipecamera/events.c new file mode 100644 index 0000000..58d2971 --- /dev/null +++ b/ipecamera/events.c @@ -0,0 +1,121 @@ +#define _IPECAMERA_IMAGE_C +#define _BSD_SOURCE +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/time.h> +#include <pthread.h> +#include <assert.h> + +#include <ufodecode.h> + +#include "../tools.h" +#include "../error.h" + +#include "pcilib.h" +#include "public.h" +#include "private.h" +#include "events.h" + +int ipecamera_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, void *user) { + int err = 0; + int do_stop = 0; + + ipecamera_event_info_t info; + ipecamera_t *ctx = (ipecamera_t*)vctx; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + } + + ctx->streaming = 1; + ctx->run_streamer = 1; + + if (!ctx->started) { + err = ipecamera_start(vctx, PCILIB_EVENTS_ALL, PCILIB_EVENT_FLAGS_DEFAULT); + if (err) { + ctx->streaming = 0; + return err; + } + + do_stop = 1; + } + + // 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; + + memcpy(&info, ctx->frame + ((ctx->reported_id-1)%ctx->buffer_size), sizeof(ipecamera_event_info_t)); + + if ((ctx->event_id - ctx->reported_id) < ctx->buffer_size) { + err = callback(ctx->reported_id, (pcilib_event_info_t*)&info, user); + if (err <= 0) { + if (err < 0) err = -err; + break; + } + } + } + usleep(IPECAMERA_NOFRAME_SLEEP); + } + + ctx->streaming = 0; + + if (do_stop) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + } + + + return err; +} + +int ipecamera_next_event(pcilib_context_t *vctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, 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_ERROR_NOTINITIALIZED; + } + + if (!ctx->started) { + pcilib_error("IPECamera is not in grabbing mode"); + return PCILIB_ERROR_INVALID_REQUEST; + } + + if (ctx->reported_id == ctx->event_id) { + if (timeout) { + pcilib_calc_deadline(&tv, timeout); + + while ((pcilib_calc_time_to_deadline(&tv) > 0)&&(ctx->reported_id == ctx->event_id)) + usleep(IPECAMERA_NOFRAME_SLEEP); + } + + if (ctx->reported_id == ctx->event_id) return PCILIB_ERROR_TIMEOUT; + } + +retry: + 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; + + if (evid) *evid = ctx->reported_id; + + if (info) { + if (info_size >= sizeof(ipecamera_event_info_t)) + memcpy(info, ctx->frame + ((ctx->reported_id-1)%ctx->buffer_size), sizeof(ipecamera_event_info_t)); + else if (info_size >= sizeof(pcilib_event_info_t)) + memcpy(info, ctx->frame + ((ctx->reported_id-1)%ctx->buffer_size), sizeof(pcilib_event_info_t)); + else + return PCILIB_ERROR_INVALID_ARGUMENT; + } + + if ((ctx->event_id - ctx->reported_id) >= ctx->buffer_size) goto retry; + + return 0; +} + diff --git a/ipecamera/events.h b/ipecamera/events.h new file mode 100644 index 0000000..5268c81 --- /dev/null +++ b/ipecamera/events.h @@ -0,0 +1,5 @@ +#ifndef _IPECAMERA_EVENTS_H +#define _IPECAMERA_EVENTS_H + + +#endif /* _IPECAMERA_EVENTS_H */ diff --git a/ipecamera/image.c b/ipecamera/image.c deleted file mode 100644 index e60bbf2..0000000 --- a/ipecamera/image.c +++ /dev/null @@ -1,971 +0,0 @@ -#define _IPECAMERA_IMAGE_C -#define _BSD_SOURCE - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <sys/time.h> -#include <pthread.h> -#include <assert.h> - -#include <ufodecode.h> - -#include "../tools.h" -#include "../error.h" - -#include "pcilib.h" - -#include "model.h" -#include "event.h" -#include "image.h" - -#include "dma/nwl_dma.h" - -#ifdef IPECAMERA_DEBUG -#include "dma/nwl.h" -#endif /* IPECAMERA_DEBUG */ - - -#define IPECAMERA_BUG_EXTRA_DATA -#define IPECAMERA_BUG_MULTIFRAME_PACKETS -#define IPECAMERA_BUG_INCOMPLETE_PACKETS - -#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_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 -#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 - - -typedef uint32_t ipecamera_payload_t; - -typedef struct { - pcilib_event_id_t evid; - struct timeval timestamp; -} ipecamera_autostop_t; - -struct ipecamera_s { - pcilib_context_t event; - ufo_decoder ipedec; - - char *data; - ipecamera_pixel_t *image; - size_t size; - - pcilib_event_callback_t cb; - void *cb_user; - - pcilib_event_id_t event_id; - pcilib_event_id_t reported_id; - - pcilib_dma_engine_t rdma, wdma; - - pcilib_register_t packet_len_reg; - pcilib_register_t control_reg, status_reg; - pcilib_register_t start_reg, end_reg; - pcilib_register_t n_lines_reg; - uint16_t line_reg; - pcilib_register_t exposure_reg; - pcilib_register_t flip_reg; - - 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; - - 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 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; - - -// void *raw_buffer; - void *buffer; - ipecamera_change_mask_t *cmask; - ipecamera_event_info_t *frame_info; - - - ipecamera_image_dimensions_t dim; - - pthread_t rthread; -}; - - -#define FIND_REG(var, bank, name) \ - ctx->var = pcilib_find_register(pcilib, bank, name); \ - if (ctx->var == PCILIB_REGISTER_INVALID) { \ - err = PCILIB_ERROR_NOTFOUND; \ - pcilib_error("Unable to find a %s register", name); \ - } - - -#define GET_REG(reg, var) \ - if (!err) { \ - err = pcilib_read_register_by_id(pcilib, ctx->reg, &var); \ - if (err) { \ - pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \ - } \ - } - -#define SET_REG(reg, val) \ - if (!err) { \ - err = pcilib_write_register_by_id(pcilib, ctx->reg, val); \ - if (err) { \ - pcilib_error("Error writting %s register", ipecamera_registers[ctx->reg].name); \ - } \ - } - -#define CHECK_REG(reg, check) \ - if (!err) { \ - err = pcilib_read_register_by_id(pcilib, ctx->reg, &value); \ - if (err) { \ - pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \ - } \ - if (!(check)) { \ - pcilib_error("Unexpected value (%li) of register %s", value, ipecamera_registers[ctx->reg].name); \ - err = PCILIB_ERROR_INVALID_DATA; \ - } \ - } - -#define CHECK_VALUE(value, val) \ - if ((!err)&&(value != val)) { \ - pcilib_error("Unexpected value (0x%x) in data stream (0x%x is expected)", value, val); \ - err = PCILIB_ERROR_INVALID_DATA; \ - } - -#define CHECK_FLAG(flag, check, ...) \ - if ((!err)&&(!(check))) { \ - pcilib_error("Unexpected value (0x%x) of " flag, __VA_ARGS__); \ - err = PCILIB_ERROR_INVALID_DATA; \ - } - - -pcilib_context_t *ipecamera_init(pcilib_t *pcilib) { - int err = 0; - - ipecamera_t *ctx = malloc(sizeof(ipecamera_t)); - - if (ctx) { - memset(ctx, 0, sizeof(ipecamera_t)); - - ctx->buffer_size = IPECAMERA_DEFAULT_BUFFER_SIZE; - ctx->dim.bpp = sizeof(ipecamera_pixel_t) * 8; - - // We need DMA engine initialized to resolve DMA registers -// FIND_REG(packet_len_reg, "fpga", "xrawdata_packet_length"); - - 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(n_lines_reg, "cmosis", "number_lines"); - 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; - - if (err) { - free(ctx); - return NULL; - } - } - - return (pcilib_context_t*)ctx; -} - -void ipecamera_free(pcilib_context_t *vctx) { - if (vctx) { - ipecamera_t *ctx = (ipecamera_t*)vctx; - ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); - free(ctx); - } -} - -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(vctx->pcilib); - if ((!model_info->dma_api)||(!model_info->dma_api->init)) { - pcilib_error("The DMA engine is not configured in model"); - return NULL; - } - - -#ifdef IPECAMERA_DMA_R3 - return model_info->dma_api->init(vctx->pcilib, PCILIB_NWL_MODIFICATION_IPECAMERA, NULL); -#else - return model_info->dma_api->init(vctx->pcilib, PCILIB_DMA_MODIFICATION_DEFAULT, NULL); -#endif -} - - -int ipecamera_set_buffer_size(ipecamera_t *ctx, int size) { - if (ctx->started) { - pcilib_error("Can't change buffer size while grabbing"); - return PCILIB_ERROR_INVALID_REQUEST; - } - - 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 = 0; - ipecamera_t *ctx = (ipecamera_t*)vctx; - pcilib_t *pcilib = vctx->pcilib; - - pcilib_register_t control, status; - pcilib_register_value_t value; - - if (!ctx) { - pcilib_error("IPECamera imaging is not initialized"); - return PCILIB_ERROR_NOTINITIALIZED; - } - - 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 FPGA reset bit"); - return err; - } - usleep(IPECAMERA_SLEEP_TIME); - - // Remove Reset bit to CMOSIS - err = pcilib_write_register_by_id(pcilib, control, 0x1e1); - if (err) { - pcilib_error("Error reseting FPGA 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); - - // Set default parameters - 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"); - return err; - } - - if (value != IPECAMERA_EXPECTED_STATUS) { - pcilib_error("Unexpected value (%lx) of status register, expected %lx", value, IPECAMERA_EXPECTED_STATUS); - return PCILIB_ERROR_VERIFY; - } - - return 0; -} - -// 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 int ipecamera_new_frame(ipecamera_t *ctx) { - ctx->frame_info[ctx->buffer_pos].raw_size = ctx->cur_size; - - if (ctx->cur_size < ctx->raw_size) ctx->frame_info[ctx->buffer_pos].info.flags |= PCILIB_EVENT_INFO_FLAG_BROKEN; - - ctx->buffer_pos = (++ctx->event_id) % ctx->buffer_size; - ctx->cur_size = 0; - - ctx->frame_info[ctx->buffer_pos].info.type = PCILIB_EVENT0; - ctx->frame_info[ctx->buffer_pos].info.flags = 0; - ctx->frame_info[ctx->buffer_pos].image_ready = 0; - - if ((ctx->event_id == ctx->autostop.evid)&&(ctx->event_id)) { - ctx->run_reader = 0; - return 1; - } - - if (pcilib_check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) { - ctx->run_reader = 0; - return 1; - } - - return 0; -} - -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; - -#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS - size_t extra_data = 0; -#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */ - - ipecamera_t *ctx = (ipecamera_t*)user; - - if (!ctx->cur_size) { -#if defined(IPECAMERA_BUG_INCOMPLETE_PACKETS)||defined(IPECAMERA_BUG_MULTIFRAME_PACKETS) - size_t startpos; - for (startpos = 0; (startpos + 8) < bufsize; startpos++) { - if (!memcmp(buf + startpos, frame_magic, sizeof(frame_magic))) break; - } - - if (startpos) { - buf += startpos; - bufsize -= startpos; - } -#endif /* IPECAMERA_BUG_INCOMPLETE_PACKETS */ - - if ((bufsize >= 8)&&(!memcmp(buf, frame_magic, sizeof(frame_magic)))) { -/* - // Not implemented in hardware yet - ctx->frame_info[ctx->buffer_pos].info.seqnum = ((uint32_t*)buf)[6] & 0xF0000000; - ctx->frame_info[ctx->buffer_pos].info.offset = ((uint32_t*)buf)[7] & 0xF0000000; -*/ - gettimeofday(&ctx->frame_info[ctx->buffer_pos].info.timestamp, NULL); - } else { -// pcilib_warning("Frame magic is not found, ignoring broken data..."); - return PCILIB_STREAMING_CONTINUE; - } - } - -#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS - if (ctx->cur_size + bufsize > ctx->raw_size) { - size_t need; - - for (need = ctx->raw_size - ctx->cur_size; need < bufsize; need += sizeof(uint32_t)) { - if (*(uint32_t*)(buf + need) == frame_magic[0]) break; - } - - if (need < bufsize) { - extra_data = bufsize - need; - //bufsize = need; - eof = 1; - } - - // just rip of padding - bufsize = ctx->raw_size - ctx->cur_size; - } -#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */ - - 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) { - if (ipecamera_new_frame(ctx)) { - return PCILIB_STREAMING_STOP; - } - -#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS - if (extra_data) { - return ipecamera_data_callback(user, flags, extra_data, buf + bufsize); - } -#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */ - } - - 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 (ctx->cur_size > ctx->raw_size) ipecamera_new_frame(ctx); -#ifdef IPECAMERA_BUG_INCOMPLETE_PACKETS - else if (ctx->cur_size > 0) ipecamera_new_frame(ctx); -#endif /* IPECAMERA_BUG_INCOMPLETE_PACKETS */ - if (pcilib_check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) { - ctx->run_reader = 0; - break; - } - usleep(IPECAMERA_NOFRAME_SLEEP); - } else pcilib_error("DMA error while reading IPECamera frames, error: %i", err); - } else printf("no error\n"); - - //usleep(1000); - } - - 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 = 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 * sizeof(ipecamera_payload_t); - const size_t footer_size = 8 * sizeof(ipecamera_payload_t); - 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; - } - - if (ctx->started) { - pcilib_error("IPECamera grabbing is already started"); - return PCILIB_ERROR_INVALID_REQUEST; - } - - - // 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; - - - ctx->event_id = 0; - ctx->reported_id = 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; - 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; - 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->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 (%lu bytes)", ctx->padded_size * ctx->buffer_size); - return err; - } - - ctx->image = (ipecamera_pixel_t*)malloc(ctx->image_size * ctx->buffer_size * sizeof(ipecamera_pixel_t)); - if (!ctx->image) { - err = PCILIB_ERROR_MEMORY; - pcilib_error("Unable to allocate image buffer (%lu bytes)", ctx->image_size * ctx->buffer_size * sizeof(ipecamera_pixel_t)); - 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; - } - - ctx->ipedec = ufo_decoder_new(ctx->dim.height, ctx->dim.width, NULL, 0); - if (!ctx->ipedec) { - pcilib_error("Unable to initialize IPECamera decoder library"); - return PCILIB_ERROR_FAILED; - } - - if (!err) { - 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(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); - } - } - } - -/* - if (!err) { - 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(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); - } - } - } -*/ - -/* - 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; - } - - if (err) { - 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; - - 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, pcilib_event_flags_t flags) { - int err; - void *retcode; - ipecamera_t *ctx = (ipecamera_t*)vctx; - - if (!ctx) { - pcilib_error("IPECamera imaging is not initialized"); - return PCILIB_ERROR_NOTINITIALIZED; - } - - if (flags&PCILIB_EVENT_FLAG_STOP_ONLY) { - ctx->run_reader = 0; - return 0; - } - - if (ctx->started) { - ctx->run_reader = 0; - err = pthread_join(ctx->rthread, &retcode); - if (err) pcilib_error("Error joining the reader thread"); - } - - if (ctx->wdma != PCILIB_DMA_ENGINE_INVALID) { - 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(vctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT); - ctx->rdma = PCILIB_DMA_ENGINE_INVALID; - } - - if (ctx->ipedec) { - ufo_decoder_free(ctx->ipedec); - ctx->ipedec = NULL; - } - - if (ctx->frame_info) { - free(ctx->frame_info); - ctx->frame_info = NULL; - } - - if (ctx->cmask) { - free(ctx->cmask); - ctx->cmask = NULL; - } - - if (ctx->image) { - free(ctx->image); - ctx->image = NULL; - } - - if (ctx->buffer) { - free(ctx->buffer); - ctx->buffer = NULL; - } - - - memset(&ctx->autostop, 0, sizeof(ipecamera_autostop_t)); - - ctx->event_id = 0; - ctx->reported_id = 0; - ctx->buffer_pos = 0; - ctx->started = 0; - - return 0; -} - - -int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) { - int err = 0; - pcilib_register_value_t value; - - ipecamera_t *ctx = (ipecamera_t*)vctx; - pcilib_t *pcilib = vctx->pcilib; - - if (!ctx) { - pcilib_error("IPECamera imaging is not initialized"); - return PCILIB_ERROR_NOTINITIALIZED; - } - - 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); - - - // DS: Just measure when next trigger is allowed instead and wait in the beginning - usleep(IPECAMERA_NEXT_FRAME_DELAY); // minimum delay between End Of Readout and next Frame Req - - return 0; -} - -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) { - 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; - } - - // 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-1)%ctx->buffer_size)), user); - } - usleep(IPECAMERA_NOFRAME_SLEEP); - } - - ctx->streaming = 0; - - if (do_stop) { - ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); - } - - - return err; -} - -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_ERROR_NOTINITIALIZED; - } - - if (!ctx->started) { - pcilib_error("IPECamera is not in grabbing mode"); - return PCILIB_ERROR_INVALID_REQUEST; - } - - if (ctx->reported_id == ctx->event_id) { - if (timeout) { - pcilib_calc_deadline(&tv, timeout); - - while ((pcilib_calc_time_to_deadline(&tv) > 0)&&(ctx->reported_id == ctx->event_id)) - usleep(IPECAMERA_NOFRAME_SLEEP); - } - - if (ctx->reported_id == ctx->event_id) return PCILIB_ERROR_TIMEOUT; - } - - 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; - - if (evid) *evid = ctx->reported_id; - if (info) *info = (pcilib_event_info_t*)(ctx->frame_info + ((ctx->reported_id-1)%ctx->buffer_size)); - - return 0; -} - - -inline static int ipecamera_decode_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) { - int err; - uint32_t tmp; - uint16_t *pixels; - - int buf_ptr = (event_id - 1) % ctx->buffer_size; - - if (!ctx->frame_info[buf_ptr].image_ready) { - if (ctx->frame_info[buf_ptr].info.flags&PCILIB_EVENT_INFO_FLAG_BROKEN) return PCILIB_ERROR_INVALID_DATA; - - ufo_decoder_set_raw_data(ctx->ipedec, ctx->buffer + buf_ptr * ctx->padded_size, ctx->raw_size); - - pixels = ctx->image + buf_ptr * ctx->image_size; - memset(ctx->cmask + ctx->buffer_pos * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t)); - err = ufo_decoder_get_next_frame(ctx->ipedec, &pixels, &tmp, &tmp, ctx->cmask + ctx->buffer_pos * ctx->dim.height); - if (err) return PCILIB_ERROR_FAILED; - - ctx->frame_info[buf_ptr].image_ready = 1; - - if (ipecamera_resolve_event_id(ctx, event_id) < 0) { - ctx->frame_info[buf_ptr].image_ready = 0; - return PCILIB_ERROR_TIMEOUT; - } - } - - return 0; -} - -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 err; - int buf_ptr; - size_t raw_size; - ipecamera_t *ctx = (ipecamera_t*)vctx; - uint16_t *pixels; - - if (!ctx) { - pcilib_error("IPECamera imaging is not initialized"); - return NULL; - } - - - buf_ptr = ipecamera_resolve_event_id(ctx, event_id); - if (buf_ptr < 0) return NULL; - - switch ((ipecamera_data_type_t)data_type) { - case IPECAMERA_RAW_DATA: - raw_size = ctx->frame_info[buf_ptr].raw_size; - if (data) { - if ((!size)||(*size < raw_size)) return NULL; - memcpy(data, ctx->buffer + buf_ptr * ctx->padded_size, raw_size); - if (ipecamera_resolve_event_id(ctx, event_id) < 0) return NULL; - *size = raw_size; - return data; - } - if (size) *size = raw_size; - return ctx->buffer + buf_ptr * ctx->padded_size; - case IPECAMERA_IMAGE_DATA: - err = ipecamera_decode_frame(ctx, event_id); - if (err) return NULL; - - if (data) { - if ((!size)||(*size < ctx->image_size * sizeof(ipecamera_pixel_t))) return NULL; - memcpy(data, ctx->image + buf_ptr * ctx->image_size, ctx->image_size * sizeof(ipecamera_pixel_t)); - if (ipecamera_resolve_event_id(ctx, event_id) < 0) return NULL; - *size = ctx->image_size * sizeof(ipecamera_pixel_t); - return data; - } - - if (size) *size = ctx->image_size * sizeof(ipecamera_pixel_t); - return ctx->image + buf_ptr * ctx->image_size; - case IPECAMERA_CHANGE_MASK: - err = ipecamera_decode_frame(ctx, event_id); - if (err) return NULL; - - if (data) { - if ((!size)||(*size < ctx->dim.height * sizeof(ipecamera_change_mask_t))) return NULL; - memcpy(data, ctx->image + buf_ptr * ctx->dim.height, ctx->dim.height * sizeof(ipecamera_change_mask_t)); - if (ipecamera_resolve_event_id(ctx, event_id) < 0) return NULL; - *size = ctx->dim.height * sizeof(ipecamera_change_mask_t); - - return data; - } - - if (size) *size = ctx->dim.height * sizeof(ipecamera_change_mask_t); - return ctx->cmask + buf_ptr * ctx->dim.height; - case IPECAMERA_DIMENSIONS: - if (size) *size = sizeof(ipecamera_image_dimensions_t); - return &ctx->dim; - case IPECAMERA_IMAGE_REGION: - case IPECAMERA_PACKED_IMAGE: - // Shall we return complete image or only changed parts? - case IPECAMERA_PACKED_LINE: - case IPECAMERA_PACKED_PAYLOAD: - pcilib_error("Support for data type (%li) is not implemented yet", data_type); - return NULL; - default: - pcilib_error("Unknown data type (%li) is requested", data_type); - return NULL; - } -} - - - -int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id, void *data) { - ipecamera_t *ctx = (ipecamera_t*)vctx; - - if (!ctx) { - pcilib_error("IPECamera imaging is not initialized"); - return PCILIB_ERROR_NOTINITIALIZED; - - } - - if (ipecamera_resolve_event_id(ctx, event_id) < 0) { - return PCILIB_ERROR_NOTAVAILABLE; - } - - return 0; -} diff --git a/ipecamera/ipecamera.c b/ipecamera/ipecamera.c new file mode 100644 index 0000000..0819284 --- /dev/null +++ b/ipecamera/ipecamera.c @@ -0,0 +1,597 @@ +#define _IPECAMERA_IMAGE_C +#define _BSD_SOURCE +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/time.h> +#include <pthread.h> +#include <assert.h> + +#include <ufodecode.h> + +#include "../tools.h" +#include "../error.h" +#include "../event.h" + +#include "pcilib.h" +#include "private.h" +#include "model.h" +#include "reader.h" +#include "events.h" +#include "data.h" + +#include "dma/nwl_dma.h" + +#ifdef IPECAMERA_DEBUG +#include "dma/nwl.h" +#endif /* IPECAMERA_DEBUG */ + + +#define FIND_REG(var, bank, name) \ + ctx->var = pcilib_find_register(pcilib, bank, name); \ + if (ctx->var == PCILIB_REGISTER_INVALID) { \ + err = PCILIB_ERROR_NOTFOUND; \ + pcilib_error("Unable to find a %s register", name); \ + } + + +#define GET_REG(reg, var) \ + if (!err) { \ + err = pcilib_read_register_by_id(pcilib, ctx->reg, &var); \ + if (err) { \ + pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \ + } \ + } + +#define SET_REG(reg, val) \ + if (!err) { \ + err = pcilib_write_register_by_id(pcilib, ctx->reg, val); \ + if (err) { \ + pcilib_error("Error writting %s register", ipecamera_registers[ctx->reg].name); \ + } \ + } + +#define CHECK_REG(reg, check) \ + if (!err) { \ + err = pcilib_read_register_by_id(pcilib, ctx->reg, &value); \ + if (err) { \ + pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \ + } \ + if (!(check)) { \ + pcilib_error("Unexpected value (%li) of register %s", value, ipecamera_registers[ctx->reg].name); \ + err = PCILIB_ERROR_INVALID_DATA; \ + } \ + } + +#define CHECK_VALUE(value, val) \ + if ((!err)&&(value != val)) { \ + pcilib_error("Unexpected value (0x%x) in data stream (0x%x is expected)", value, val); \ + err = PCILIB_ERROR_INVALID_DATA; \ + } + +#define CHECK_FLAG(flag, check, ...) \ + if ((!err)&&(!(check))) { \ + pcilib_error("Unexpected value (0x%x) of " flag, __VA_ARGS__); \ + err = PCILIB_ERROR_INVALID_DATA; \ + } + + +pcilib_context_t *ipecamera_init(pcilib_t *pcilib) { + int err = 0; + + ipecamera_t *ctx = malloc(sizeof(ipecamera_t)); + + if (ctx) { + memset(ctx, 0, sizeof(ipecamera_t)); + + ctx->buffer_size = IPECAMERA_DEFAULT_BUFFER_SIZE; + ctx->dim.bpp = sizeof(ipecamera_pixel_t) * 8; + + // We need DMA engine initialized to resolve DMA registers +// FIND_REG(packet_len_reg, "fpga", "xrawdata_packet_length"); + + 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(n_lines_reg, "cmosis", "number_lines"); + 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; + + if (err) { + free(ctx); + return NULL; + } + } + + return (pcilib_context_t*)ctx; +} + +void ipecamera_free(pcilib_context_t *vctx) { + if (vctx) { + ipecamera_t *ctx = (ipecamera_t*)vctx; + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + free(ctx); + } +} + +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(vctx->pcilib); + if ((!model_info->dma_api)||(!model_info->dma_api->init)) { + pcilib_error("The DMA engine is not configured in model"); + return NULL; + } + + +#ifdef IPECAMERA_DMA_R3 + return model_info->dma_api->init(vctx->pcilib, PCILIB_NWL_MODIFICATION_IPECAMERA, NULL); +#else + return model_info->dma_api->init(vctx->pcilib, PCILIB_DMA_MODIFICATION_DEFAULT, NULL); +#endif +} + + +int ipecamera_set_buffer_size(ipecamera_t *ctx, int size) { + if (ctx->started) { + pcilib_error("Can't change buffer size while grabbing"); + return PCILIB_ERROR_INVALID_REQUEST; + } + + 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 = 0; + ipecamera_t *ctx = (ipecamera_t*)vctx; + pcilib_t *pcilib = vctx->pcilib; + + pcilib_register_t control, status; + pcilib_register_value_t value; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + } + + 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 FPGA reset bit"); + return err; + } + usleep(IPECAMERA_SLEEP_TIME); + + // Remove Reset bit to CMOSIS + err = pcilib_write_register_by_id(pcilib, control, 0x1e1); + if (err) { + pcilib_error("Error reseting FPGA 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); + + // Set default parameters + 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"); + return err; + } + + if (value != IPECAMERA_EXPECTED_STATUS) { + pcilib_error("Unexpected value (%lx) of status register, expected %lx", value, IPECAMERA_EXPECTED_STATUS); + return PCILIB_ERROR_VERIFY; + } + + return 0; +} + + +int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_event_flags_t flags) { + int i; + int err = 0; + ipecamera_t *ctx = (ipecamera_t*)vctx; + 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 * sizeof(ipecamera_payload_t); + const size_t footer_size = 8 * sizeof(ipecamera_payload_t); + 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; + } + + if (ctx->started) { + pcilib_error("IPECamera grabbing is already started"); + return PCILIB_ERROR_INVALID_REQUEST; + } + + + // 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; + + + ctx->event_id = 0; + ctx->preproc_id = 0; + ctx->reported_id = 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; + 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; + 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->padded_size = padded_blocks * IPECAMERA_DMA_PACKET_LENGTH; + + ctx->buffer = malloc(ctx->padded_size * ctx->buffer_size); + if (!ctx->buffer) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + pcilib_error("Unable to allocate ring buffer (%lu bytes)", ctx->padded_size * ctx->buffer_size); + return PCILIB_ERROR_MEMORY; + } + + ctx->image = (ipecamera_pixel_t*)malloc(ctx->image_size * ctx->buffer_size * sizeof(ipecamera_pixel_t)); + if (!ctx->image) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + pcilib_error("Unable to allocate image buffer (%lu bytes)", ctx->image_size * ctx->buffer_size * sizeof(ipecamera_pixel_t)); + return PCILIB_ERROR_MEMORY; + } + + ctx->cmask = malloc(ctx->dim.height * ctx->buffer_size * sizeof(ipecamera_change_mask_t)); + if (!ctx->cmask) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + pcilib_error("Unable to allocate change-mask buffer"); + return PCILIB_ERROR_MEMORY; + } + + ctx->frame = (ipecamera_frame_t*)malloc(ctx->buffer_size * sizeof(ipecamera_frame_t)); + if (!ctx->frame) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + pcilib_error("Unable to allocate frame-info buffer"); + return PCILIB_ERROR_MEMORY; + } + + memset(ctx->frame, 0, ctx->buffer_size * sizeof(ipecamera_frame_t)); + + for (i = 0; i < ctx->buffer_size; i++) { + err = pthread_rwlock_init(&ctx->frame[i].mutex, NULL); + if (err) break; + } + + ctx->frame_mutex_destroy = i; + + if (err) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + pcilib_error("Initialization of rwlock mutexes for frame synchronization has failed"); + return PCILIB_ERROR_FAILED; + } + + ctx->ipedec = ufo_decoder_new(ctx->dim.height, ctx->dim.width, NULL, 0); + if (!ctx->ipedec) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + pcilib_error("Unable to initialize IPECamera decoder library"); + return PCILIB_ERROR_FAILED; + } + + if (!err) { + 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(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); + } + } + } + +/* + if (!err) { + 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(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); + } + } + } +*/ + +/* + SET_REG(packet_len_reg, IPECAMERA_DMA_PACKET_LENGTH); +*/ + + if (err) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + return err; + } + + // Clean DMA + err = pcilib_skip_dma(vctx->pcilib, ctx->rdma); + if (err) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + pcilib_error("Can't start grabbing, device continuously writes unexpected data using DMA engine"); + 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; + } + + if (flags&PCILIB_EVENT_FLAG_PREPROCESS) { + ctx->n_preproc = pcilib_get_cpu_count(); + switch (ctx->n_preproc) { + case 1: break; + case 2-3: ctx->n_preproc -= 1; break; + default: ctx->n_preproc -= 2; break; + } + + ctx->preproc = (ipecamera_preprocessor_t*)malloc(ctx->n_preproc * sizeof(ipecamera_preprocessor_t)); + if (!ctx->preproc) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + pcilib_error("Unable to allocate memory for preprocessor contexts"); + return PCILIB_ERROR_MEMORY; + } + + memset(ctx->preproc, 0, ctx->n_preproc * sizeof(ipecamera_preprocessor_t)); + + err = pthread_mutex_init(&ctx->preproc_mutex, NULL); + if (err) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + pcilib_error("Failed to initialize event mutex"); + return PCILIB_ERROR_FAILED; + } + ctx->preproc_mutex_destroy = 1; + + + ctx->run_preprocessors = 1; + for (i = 0; i < ctx->n_preproc; i++) { + ctx->preproc[i].i = i; + ctx->preproc[i].ipecamera = ctx; + err = pthread_create(&ctx->preproc[i].thread, NULL, ipecamera_preproc_thread, ctx->preproc + i); + if (err) { + err = PCILIB_ERROR_FAILED; + break; + } else { + ctx->preproc[i].started = 1; + } + } + + if (err) { + ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + pcilib_error("Failed to schedule some of the preprocessor threads"); + return err; + } + } else { + ctx->n_preproc = 0; + } + + ctx->started = 1; + ctx->run_reader = 1; + + 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_FAILED; + } + + pthread_attr_destroy(&attr); + + return err; +} + + +int ipecamera_stop(pcilib_context_t *vctx, pcilib_event_flags_t flags) { + int i; + int err; + void *retcode; + ipecamera_t *ctx = (ipecamera_t*)vctx; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + } + + if (flags&PCILIB_EVENT_FLAG_STOP_ONLY) { + ctx->run_reader = 0; + return 0; + } + + if (ctx->started) { + ctx->run_reader = 0; + err = pthread_join(ctx->rthread, &retcode); + if (err) pcilib_error("Error joining the reader thread"); + } + + if (ctx->preproc) { + ctx->run_preprocessors = 0; + + for (i = 0; i < ctx->n_preproc; i++) { + if (ctx->preproc[i].started) { + pthread_join(ctx->preproc[i].thread, &retcode); + ctx->preproc[i].started = 0; + } + } + + if (ctx->preproc_mutex_destroy) { + pthread_mutex_destroy(&ctx->preproc_mutex); + ctx->preproc_mutex_destroy = 0; + } + + free(ctx->preproc); + ctx->preproc = NULL; + } + + if (ctx->frame_mutex_destroy) { + for (i = 0; i < ctx->frame_mutex_destroy; i++) { + pthread_rwlock_destroy(&ctx->frame[i].mutex); + } + ctx->frame_mutex_destroy = 0; + } + + if (ctx->wdma != PCILIB_DMA_ENGINE_INVALID) { + 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(vctx->pcilib, ctx->rdma, PCILIB_DMA_FLAGS_DEFAULT); + ctx->rdma = PCILIB_DMA_ENGINE_INVALID; + } + + if (ctx->ipedec) { + ufo_decoder_free(ctx->ipedec); + ctx->ipedec = NULL; + } + + if (ctx->frame) { + free(ctx->frame); + ctx->frame = NULL; + } + + if (ctx->cmask) { + free(ctx->cmask); + ctx->cmask = NULL; + } + + if (ctx->image) { + free(ctx->image); + ctx->image = NULL; + } + + if (ctx->buffer) { + free(ctx->buffer); + ctx->buffer = NULL; + } + + + memset(&ctx->autostop, 0, sizeof(ipecamera_autostop_t)); + + ctx->event_id = 0; + ctx->reported_id = 0; + ctx->buffer_pos = 0; + ctx->started = 0; + + return 0; +} + + +int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) { + int err = 0; + pcilib_register_value_t value; + + ipecamera_t *ctx = (ipecamera_t*)vctx; + pcilib_t *pcilib = vctx->pcilib; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + } + + 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); + + + // DS: Just measure when next trigger is allowed instead and wait in the beginning + usleep(IPECAMERA_NEXT_FRAME_DELAY); // minimum delay between End Of Readout and next Frame Req + + return 0; +} diff --git a/ipecamera/ipecamera.h b/ipecamera/ipecamera.h index 3abcf25..19c123b 100644 --- a/ipecamera/ipecamera.h +++ b/ipecamera/ipecamera.h @@ -4,9 +4,9 @@ typedef struct ipecamera_s ipecamera_t; typedef struct { - int bpp; /*<< Bits per pixel (8, 16, or 32) as returned by IPECAMERA_IMAGE_DATA */ - int real_bpp; /*<< Bits per pixel as returned by camera and IPECAMERA_PACKED_IMAGE */ - int width, height; + unsigned int bpp; /*<< Bits per pixel (8, 16, or 32) as returned by IPECAMERA_IMAGE_DATA */ + unsigned int real_bpp; /*<< Bits per pixel as returned by camera and IPECAMERA_PACKED_IMAGE */ + unsigned int width, height; } ipecamera_image_dimensions_t; typedef enum { @@ -25,8 +25,9 @@ typedef uint16_t ipecamera_pixel_t; typedef struct { pcilib_event_info_t info; - size_t raw_size; /**< Indicates the actual size of raw data */ int image_ready; /**< Indicates if image data is parsed */ + int image_broken; /**< Unlike the info.flags this is bound to the reconstructed image (i.e. is not updated on rawdata overwrite) */ + size_t raw_size; /**< Indicates the actual size of raw data */ } ipecamera_event_info_t; int ipecamera_set_buffer_size(ipecamera_t *ctx, int size); diff --git a/ipecamera/model.c b/ipecamera/model.c index ddf9ee6..e60561b 100644 --- a/ipecamera/model.c +++ b/ipecamera/model.c @@ -26,7 +26,7 @@ int ipecamera_read(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, pcilib_register_value_t *value) { uint32_t val, tmp[4]; char *wr, *rd; - struct timeval start, cur; + struct timeval start;//, cur; int retries = RETRIES; assert(addr < 128); @@ -116,7 +116,7 @@ retry: int ipecamera_write(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, pcilib_register_value_t value) { uint32_t val, tmp[4]; char *wr, *rd; - struct timeval start, cur; + struct timeval start;//, cur; int retries = RETRIES; assert(addr < 128); diff --git a/ipecamera/model.h b/ipecamera/model.h index b9c3b32..4a0fc8c 100644 --- a/ipecamera/model.h +++ b/ipecamera/model.h @@ -4,7 +4,7 @@ #include <stdio.h> #include "pcilib.h" -#include "image.h" +#include "public.h" //#define IPECAMERA_DEBUG @@ -126,7 +126,7 @@ pcilib_event_api_description_t ipecamera_image_api = { ipecamera_trigger, ipecamera_stream, - NULL, //ipecamera_next_event, + ipecamera_next_event, ipecamera_get, ipecamera_return, ipecamera_init_dma diff --git a/ipecamera/private.h b/ipecamera/private.h new file mode 100644 index 0000000..b583f38 --- /dev/null +++ b/ipecamera/private.h @@ -0,0 +1,121 @@ +#ifndef _IPECAMERA_PRIVATE_H +#define _IPECAMERA_PRIVATE_H + +#include "ipecamera.h" + +#define IPECAMERA_BUG_EXTRA_DATA +#define IPECAMERA_BUG_MULTIFRAME_PACKETS +#define IPECAMERA_BUG_INCOMPLETE_PACKETS + +#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_NOFRAME_PREPROC_SLEEP 100 + +#define IPECAMERA_MAX_LINES 1088 +#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_FRAME_REQUEST 0x1E9 +#define IPECAMERA_READOUT_FLAG 0x200 +#define IPECAMERA_READOUT 0x3E1 +#define IPECAMERA_IDLE 0x1E1 +#define IPECAMERA_START_INTERNAL_STIMULI 0x1F1 + + +typedef uint32_t ipecamera_payload_t; + +typedef struct { + pcilib_event_id_t evid; + struct timeval timestamp; +} ipecamera_autostop_t; + +typedef struct { + size_t i; + pthread_t thread; + ipecamera_t *ipecamera; + + int started; /**< flag indicating that join & cleanup is required */ +} ipecamera_preprocessor_t; + + +typedef struct { + ipecamera_event_info_t event; /**< this structure is overwritten by the reader thread, we need a copy */ + pthread_rwlock_t mutex; /**< this mutex protects reconstructed buffers only, the raw data, event_info, etc. will be overwritten by reader thread anyway */ +} ipecamera_frame_t; + +struct ipecamera_s { + pcilib_context_t event; + ufo_decoder ipedec; + + char *data; + ipecamera_pixel_t *image; + size_t size; + + pcilib_event_callback_t cb; + void *cb_user; + + pcilib_event_id_t event_id; + pcilib_event_id_t preproc_id; + pcilib_event_id_t reported_id; + + pcilib_dma_engine_t rdma, wdma; + + pcilib_register_t packet_len_reg; + pcilib_register_t control_reg, status_reg; + pcilib_register_t start_reg, end_reg; + pcilib_register_t n_lines_reg; + uint16_t line_reg; + pcilib_register_t exposure_reg; + pcilib_register_t flip_reg; + + 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 */ + int run_preprocessors; /**< Instructs preprocessors to exit */ + + ipecamera_autostop_t autostop; + + struct timeval autostop_time; + + 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 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; + + +// void *raw_buffer; + void *buffer; + ipecamera_change_mask_t *cmask; + ipecamera_frame_t *frame; + + + ipecamera_image_dimensions_t dim; + + pthread_t rthread; + + size_t n_preproc; + ipecamera_preprocessor_t *preproc; + pthread_mutex_t preproc_mutex; + + int preproc_mutex_destroy; + int frame_mutex_destroy; +}; + +#endif /* _IPECAMERA_PRIVATE_H */ diff --git a/ipecamera/image.h b/ipecamera/public.h index c311b4d..b745d6c 100644 --- a/ipecamera/image.h +++ b/ipecamera/public.h @@ -1,25 +1,25 @@ -#ifndef _IPECAMERA_IMAGE_H -#define _IPECAMERA_IMAGE_H +#ifndef _IPECAMERA_PUBLIC_H +#define _IPECAMERA_PUBLIC_H #include <stdio.h> #include "ipecamera.h" #include "pcilib.h" + pcilib_context_t *ipecamera_init(pcilib_t *pcilib); void ipecamera_free(pcilib_context_t *ctx); +pcilib_dma_context_t *ipecamera_init_dma(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_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); 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, 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); +int ipecamera_next_event(pcilib_context_t *vctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info); +int 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, pcilib_event_data_type_t data_type, void *data); -#endif /* _IPECAMERA_IMAGE_H */ +#endif /* _IPECAMERA_PUBLIC_H */ diff --git a/ipecamera/reader.c b/ipecamera/reader.c new file mode 100644 index 0000000..f02df0f --- /dev/null +++ b/ipecamera/reader.c @@ -0,0 +1,170 @@ +#define _IPECAMERA_IMAGE_C +#define _BSD_SOURCE +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/time.h> +#include <pthread.h> +#include <assert.h> + +#include <ufodecode.h> + +#include "../tools.h" +#include "../error.h" + +#include "pcilib.h" +#include "private.h" +#include "reader.h" + +static inline int ipecamera_new_frame(ipecamera_t *ctx) { + ctx->frame[ctx->buffer_pos].event.raw_size = ctx->cur_size; + + if (ctx->cur_size < ctx->raw_size) ctx->frame[ctx->buffer_pos].event.info.flags |= PCILIB_EVENT_INFO_FLAG_BROKEN; + + ctx->buffer_pos = (++ctx->event_id) % ctx->buffer_size; + ctx->cur_size = 0; + + ctx->frame[ctx->buffer_pos].event.info.type = PCILIB_EVENT0; + ctx->frame[ctx->buffer_pos].event.info.flags = 0; + ctx->frame[ctx->buffer_pos].event.image_ready = 0; + + if ((ctx->event_id == ctx->autostop.evid)&&(ctx->event_id)) { + ctx->run_reader = 0; + return 1; + } + + if (pcilib_check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) { + ctx->run_reader = 0; + return 1; + } + + return 0; +} + +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 res; + int eof = 0; + +#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS + size_t extra_data = 0; +#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */ + + ipecamera_t *ctx = (ipecamera_t*)user; + + if (!ctx->cur_size) { +#if defined(IPECAMERA_BUG_INCOMPLETE_PACKETS)||defined(IPECAMERA_BUG_MULTIFRAME_PACKETS) + size_t startpos; + for (startpos = 0; (startpos + 8) < bufsize; startpos++) { + if (!memcmp(buf + startpos, frame_magic, sizeof(frame_magic))) break; + } + + if (startpos) { + buf += startpos; + bufsize -= startpos; + } +#endif /* IPECAMERA_BUG_INCOMPLETE_PACKETS */ + + if ((bufsize >= 8)&&(!memcmp(buf, frame_magic, sizeof(frame_magic)))) { +/* + // Not implemented in hardware yet + ctx->frame[ctx->buffer_pos].event.info.seqnum = ((uint32_t*)buf)[6] & 0xF0000000; + ctx->frame[ctx->buffer_pos].event.info.offset = ((uint32_t*)buf)[7] & 0xF0000000; +*/ + gettimeofday(&ctx->frame[ctx->buffer_pos].event.info.timestamp, NULL); + } else { +// pcilib_warning("Frame magic is not found, ignoring broken data..."); + return PCILIB_STREAMING_CONTINUE; + } + } + +#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS + if (ctx->cur_size + bufsize > ctx->raw_size) { + size_t need; + + for (need = ctx->raw_size - ctx->cur_size; need < bufsize; need += sizeof(uint32_t)) { + if (*(uint32_t*)(buf + need) == frame_magic[0]) break; + } + + if (need < bufsize) { + extra_data = bufsize - need; + //bufsize = need; + eof = 1; + } + + // just rip of padding + bufsize = ctx->raw_size - ctx->cur_size; + } +#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */ + + 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) { + res = ctx->event.params.rawdata.callback(ctx->event_id, (pcilib_event_info_t*)(ctx->frame + ctx->buffer_pos), (eof?PCILIB_EVENT_FLAG_EOF:PCILIB_EVENT_FLAGS_DEFAULT), bufsize, buf, ctx->event.params.rawdata.user); + if (res <= 0) { + if (res < 0) return res; + ctx->run_reader = 0; + } + } + + if (eof) { + if (ipecamera_new_frame(ctx)) { + return PCILIB_STREAMING_STOP; + } + +#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS + if (extra_data) { + return ipecamera_data_callback(user, flags, extra_data, buf + bufsize); + } +#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */ + } + + return PCILIB_STREAMING_REQ_FRAGMENT; +} + +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 (ctx->cur_size > ctx->raw_size) ipecamera_new_frame(ctx); +#ifdef IPECAMERA_BUG_INCOMPLETE_PACKETS + else if (ctx->cur_size > 0) ipecamera_new_frame(ctx); +#endif /* IPECAMERA_BUG_INCOMPLETE_PACKETS */ + if (pcilib_check_deadline(&ctx->autostop.timestamp, PCILIB_DMA_TIMEOUT)) { + ctx->run_reader = 0; + break; + } + usleep(IPECAMERA_NOFRAME_SLEEP); + } else pcilib_error("DMA error while reading IPECamera frames, error: %i", err); + } else printf("no error\n"); + + //usleep(1000); + } + + 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; +} diff --git a/ipecamera/reader.h b/ipecamera/reader.h new file mode 100644 index 0000000..738d742 --- /dev/null +++ b/ipecamera/reader.h @@ -0,0 +1,6 @@ +#ifndef _IPECAMERA_READER_H +#define _IPECAMERA_READER_H + +void *ipecamera_reader_thread(void *user); + +#endif /* _IPECAMERA_READER_H */ @@ -119,24 +119,24 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type if (persistent) { if (persistent < 0) { - if ((flags&PCILIB_KMEM_FLAG_PERSISTENT == 0)&&(kh.flags&KMEM_FLAG_REUSED_PERSISTENT)) err = PCILIB_ERROR_INVALID_STATE; + if (((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)&&(kh.flags&KMEM_FLAG_REUSED_PERSISTENT)) err = PCILIB_ERROR_INVALID_STATE; else persistent = (kh.flags&KMEM_FLAG_REUSED_PERSISTENT)?1:0; - } else if (kh.flags&KMEM_FLAG_REUSED_PERSISTENT == 0) err = PCILIB_ERROR_INVALID_STATE; + } else if ((kh.flags&KMEM_FLAG_REUSED_PERSISTENT) == 0) err = PCILIB_ERROR_INVALID_STATE; } else if (kh.flags&KMEM_FLAG_REUSED_PERSISTENT) err = PCILIB_ERROR_INVALID_STATE; if (hardware) { if (hardware < 0) { - if ((flags&PCILIB_KMEM_FLAG_HARDWARE == 0)&&(kh.flags&KMEM_FLAG_REUSED_HW)) err = PCILIB_ERROR_INVALID_STATE; + if (((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)&&(kh.flags&KMEM_FLAG_REUSED_HW)) err = PCILIB_ERROR_INVALID_STATE; else hardware = (kh.flags&KMEM_FLAG_REUSED_HW)?1:0; - } else if (kh.flags&KMEM_FLAG_REUSED_HW == 0) err = PCILIB_ERROR_INVALID_STATE; + } else if ((kh.flags&KMEM_FLAG_REUSED_HW) == 0) err = PCILIB_ERROR_INVALID_STATE; } else if (kh.flags&KMEM_FLAG_REUSED_HW) err = PCILIB_ERROR_INVALID_STATE; } else { if (!i) reused = PCILIB_TRISTATE_NO; else if (reused) reused = PCILIB_TRISTATE_PARTIAL; - if ((persistent > 0)&&(flags&PCILIB_KMEM_FLAG_PERSISTENT == 0)) err = PCILIB_ERROR_INVALID_STATE; - if ((hardware > 0)&&(flags&PCILIB_KMEM_FLAG_HARDWARE == 0)) err = PCILIB_ERROR_INVALID_STATE; + if ((persistent > 0)&&((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)) err = PCILIB_ERROR_INVALID_STATE; + if ((hardware > 0)&&((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)) err = PCILIB_ERROR_INVALID_STATE; } if (err) { @@ -205,7 +205,6 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_flags_t flags) { int ret, err = 0; int i; - kmem_handle_t kh = {0}; pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; // if linked in to the list @@ -7,7 +7,6 @@ #include <strings.h> #include <stdlib.h> #include <stdint.h> -#include <stdarg.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> @@ -16,8 +15,8 @@ #include <errno.h> #include <assert.h> +#include "pcilib.h" #include "pci.h" - #include "kernel.h" #include "tools.h" #include "error.h" @@ -25,25 +24,6 @@ #include "ipecamera/model.h" -static void pcilib_print_error(const char *msg, ...) { - va_list va; - - va_start(va, msg); - vprintf(msg, va); - va_end(va); - printf("\n"); -} - -void (*pcilib_error)(const char *msg, ...) = pcilib_print_error; -void (*pcilib_warning)(const char *msg, ...) = pcilib_print_error; - -int pcilib_set_error_handler(void (*err)(const char *msg, ...), void (*warn)(const char *msg, ...)) { - if (err) pcilib_error = err; - else pcilib_error = pcilib_print_error; - if (warn) pcilib_warning = warn; - else pcilib_warning = pcilib_print_error; -} - pcilib_t *pcilib_open(const char *device, pcilib_model_t model) { pcilib_t *ctx = malloc(sizeof(pcilib_t)); @@ -98,8 +78,8 @@ pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx) { pcilib_model_t pcilib_get_model(pcilib_t *ctx) { if (ctx->model == PCILIB_MODEL_DETECT) { - unsigned short vendor_id; - unsigned short device_id; +// unsigned short vendor_id; +// unsigned short device_id; //return PCILIB_MODEL_PCI; @@ -421,42 +401,46 @@ void pcilib_close(pcilib_t *ctx) { } int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) { - int i; void *data; pcilib_detect_address(ctx, &bar, &addr, size); data = pcilib_map_bar(ctx, bar); pcilib_memcpy(buf, data + addr, size); - - pcilib_unmap_bar(ctx, bar, data); + + pcilib_unmap_bar(ctx, bar, data); + + return 0; } int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) { - int i; void *data; pcilib_detect_address(ctx, &bar, &addr, size); data = pcilib_map_bar(ctx, bar); pcilib_memcpy(data + addr, buf, size); - - pcilib_unmap_bar(ctx, bar, data); + + pcilib_unmap_bar(ctx, bar, data); + + return 0; } int pcilib_read_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) { int i; void *data; - + pcilib_detect_address(ctx, &bar, &addr, fifo_size); data = pcilib_map_bar(ctx, bar); for (i = 0; i < n; i++) { pcilib_memcpy(buf + i * fifo_size, data + addr, fifo_size); } - - pcilib_unmap_bar(ctx, bar, data); + + pcilib_unmap_bar(ctx, bar, data); + + return 0; } int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) { @@ -470,6 +454,7 @@ int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t f pcilib_memcpy(data + addr, buf + i * fifo_size, fifo_size); } - pcilib_unmap_bar(ctx, bar, data); -} + pcilib_unmap_bar(ctx, bar, data); + return 0; +} @@ -1,6 +1,7 @@ #ifndef _PCITOOL_PCI_H #define _PCITOOL_PCI_H +#define PCILIB_DEFAULT_CPU_COUNT 2 #define PCILIB_EVENT_TIMEOUT 1000000 /**< us */ #define PCILIB_TRIGGER_TIMEOUT 100000 /**< us */ #define PCILIB_DMA_TIMEOUT 10000 /**< us */ @@ -67,10 +68,6 @@ pcilib_protocol_description_t pcilib_protocol[3] = { }; #else extern pcilib_model_description_t pcilib_model[]; - -extern void (*pcilib_error)(const char *msg, ...); -extern void (*pcilib_warning)(const char *msg, ...); - extern pcilib_protocol_description_t pcilib_protocol[]; #endif /* _PCILIB_PCI_C */ @@ -82,14 +82,15 @@ typedef enum { 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; +} pcilib_streaming_action_t; typedef enum { PCILIB_EVENT_FLAGS_DEFAULT = 0, PCILIB_EVENT_FLAG_RAW_DATA_ONLY = 1, /**< Do not parse data, just read raw and pass it to rawdata callback */ PCILIB_EVENT_FLAG_STOP_ONLY = 1, /**< Do not cleanup, just stop acquiring new frames, the cleanup should be requested afterwards */ - PCILIB_EVENT_FLAG_EOF = 2 /**< Indicates that it is the last part of the frame (not required) */ + PCILIB_EVENT_FLAG_EOF = 2, /**< Indicates that it is the last part of the frame (not required) */ + PCILIB_EVENT_FLAG_PREPROCESS = 4 /**< Enables preprocessing of the raw data (decoding frames, etc.) */ } pcilib_event_flags_t; typedef enum { @@ -333,19 +334,20 @@ int pcilib_configure_rawdata_callback(pcilib_t *ctx, pcilib_event_rawdata_callba 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, size_t info_size, pcilib_event_info_t *info); -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); +void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size_or_err); +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_or_err); /* * 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, void *data); +int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data); diff --git a/pcitool/CMakeLists.txt b/pcitool/CMakeLists.txt new file mode 100644 index 0000000..ad2cb4e --- /dev/null +++ b/pcitool/CMakeLists.txt @@ -0,0 +1,8 @@ +include_directories( + ${CMAKE_SOURCE_DIR} +) + +set(HEADERS ${HEADERS} sysinfo.h) + +add_library(pcitool STATIC sysinfo.c) + diff --git a/pcitool/sysinfo.c b/pcitool/sysinfo.c index 7b25972..d6f57fe 100644 --- a/pcitool/sysinfo.c +++ b/pcitool/sysinfo.c @@ -104,7 +104,7 @@ int get_file_fs(const char *fname, size_t size, char *fs) { if ((!fname)||(!fs)||(size < 3)) return -1; - if (*fn == '/') { + if (*fname == '/') { fn = (char*)fname; } else { if (!getcwd(buf, 4095)) return -1; @@ -19,15 +19,13 @@ int pcilib_add_registers(pcilib_t *ctx, size_t n, pcilib_register_description_t *registers) { pcilib_register_description_t *regs; - size_t size, n_present, n_new; + size_t size, n_present = 0; if (!n) { for (n = 0; registers[n].bits; n++); } - if (pcilib_model[ctx->model].registers) - if (ctx->model_info.registers == pcilib_model[ctx->model].registers) { for (n_present = 0; ctx->model_info.registers[n_present].bits; n_present++); for (size = 1024; size < 2 * (n + n_present + 1); size<<=1); @@ -46,17 +44,17 @@ int pcilib_add_registers(pcilib_t *ctx, size_t n, pcilib_register_description_t regs = (pcilib_register_description_t*)realloc(ctx->model_info.registers, size * sizeof(pcilib_register_description_t)); if (!regs) return PCILIB_ERROR_MEMORY; - - ctx->model_info.registers = regs; + + ctx->model_info.registers = regs; ctx->alloc_reg = size; } ctx->num_reg += n; } - + memcpy(ctx->model_info.registers + ctx->num_reg, ctx->model_info.registers + n_present, sizeof(pcilib_register_description_t)); memcpy(ctx->model_info.registers + n_present, registers, n * sizeof(pcilib_register_description_t)); - - return 0; + + return 0; } pcilib_register_bank_t pcilib_find_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) { @@ -66,7 +64,7 @@ pcilib_register_bank_t pcilib_find_bank_by_addr(pcilib_t *ctx, pcilib_register_b for (i = 0; banks[i].access; i++) if (banks[i].addr == bank) return i; - + return -1; } @@ -77,7 +75,7 @@ pcilib_register_bank_t pcilib_find_bank_by_name(pcilib_t *ctx, const char *bankn for (i = 0; banks[i].access; i++) if (!strcasecmp(banks[i].name, bankname)) return i; - + return -1; } @@ -104,7 +102,7 @@ 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_register_t i; pcilib_register_bank_t bank_id; - pcilib_register_bank_addr_t bank_addr; + pcilib_register_bank_addr_t bank_addr = 0; pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); pcilib_register_description_t *registers = model_info->registers; @@ -136,7 +134,6 @@ pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const ch static int pcilib_read_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, pcilib_register_size_t offset, pcilib_register_size_t bits, pcilib_register_value_t *buf) { int err; - int rest; size_t i; pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); @@ -231,7 +228,6 @@ int pcilib_read_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_regi int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value) { - int err; int reg; reg = pcilib_find_register(ctx, bank, regname); @@ -246,7 +242,6 @@ int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, p static int pcilib_write_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, pcilib_register_size_t offset, pcilib_register_size_t bits, pcilib_register_value_t rwmask, pcilib_register_value_t *buf) { int err; - int rest; size_t i; pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); @@ -356,7 +351,6 @@ int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_reg } int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value) { - int err; int reg; reg = pcilib_find_register(ctx, bank, regname); @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200112L +#define _GNU_SOURCE #include <stdio.h> #include <string.h> @@ -7,10 +8,12 @@ #include <assert.h> #include <ctype.h> #include <time.h> +#include <sched.h> #include <arpa/inet.h> #include <sys/time.h> #include "tools.h" +#include "error.h" int pcilib_isnumber(const char *str) { int i = 0; @@ -240,6 +243,8 @@ void *pcilib_datacpy32(void * dst, void const * src, uint8_t size, size_t n, pci --n; } } + + return dst; } int pcilib_get_page_mask() { @@ -254,6 +259,28 @@ int pcilib_get_page_mask() { return pagemask; } +int pcilib_get_cpu_count() { + int err; + + int cpu_count; + cpu_set_t mask; + + err = sched_getaffinity(getpid(), sizeof(mask), &mask); + if (err) return 1; + +#ifdef CPU_COUNT + cpu_count = CPU_COUNT(&mask); +#else + for (cpu_count = 0; cpu_count < CPU_SETSIZE; cpu_count++) { + if (!CPU_ISSET(cpu_count, &mask)) break; + } +#endif + + if (!cpu_count) cpu_count = PCILIB_DEFAULT_CPU_COUNT; + return cpu_count; +} + + int pcilib_add_timeout(struct timeval *tv, pcilib_timeout_t timeout) { tv->tv_usec += timeout%1000000; if (tv->tv_usec > 999999) { @@ -262,21 +289,23 @@ int pcilib_add_timeout(struct timeval *tv, pcilib_timeout_t timeout) { } else { tv->tv_sec += timeout/1000000; } + + return 0; } int pcilib_calc_deadline(struct timeval *tv, pcilib_timeout_t timeout) { gettimeofday(tv, NULL); pcilib_add_timeout(tv, timeout); - + return 0; } int pcilib_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)); // Hm... Some problems comparing signed and unsigned. So, sign check first @@ -32,6 +32,7 @@ void * pcilib_memcpy64(void * dst, void const * src, size_t len); void * pcilib_datacpy32(void * dst, void const * src, uint8_t size, size_t n, pcilib_endianess_t endianess); int pcilib_get_page_mask(); +int pcilib_get_cpu_count(); int pcilib_add_timeout(struct timeval *tv, pcilib_timeout_t timeout); |