From: hadeshyp Date: Mon, 25 May 2009 14:59:35 +0000 (+0000) Subject: added libtrbnet X-Git-Tag: v6.0~428 X-Git-Url: https://jspc29.x-matter.uni-frankfurt.de/git/?a=commitdiff_plain;h=541730248ae3c5f7a1e10fc6f222dcaec6701320;p=trbnettools.git added libtrbnet --- 541730248ae3c5f7a1e10fc6f222dcaec6701320 diff --git a/libtrbnet/.target-makefrag b/libtrbnet/.target-makefrag new file mode 100644 index 0000000..6a73bd7 --- /dev/null +++ b/libtrbnet/.target-makefrag @@ -0,0 +1 @@ +AXIS_BUILDTYPE=crisv32-axis-linux-gnu diff --git a/libtrbnet/HowTo_ADCM_v2.txt b/libtrbnet/HowTo_ADCM_v2.txt new file mode 100644 index 0000000..d0726f1 --- /dev/null +++ b/libtrbnet/HowTo_ADCM_v2.txt @@ -0,0 +1,94 @@ +HowTo ADCM_v2 +============= + +Alle Skripte / Software befindet sich im TRB0 /home/hadaq/mboehmer/ ! + +Anschalten: Board zieht ca. 2A in Vollbestückung, im konfigurierten Betrieb ca. 2.8A. Netzteil wird heiss! + +TRB: ./load_xilinx.sh + +Initialisieren: ./setaddress_sn000 -> TRBnet-Adresse 0x42 wird zugewiesen + +APVs klarmachen: ./init_apvs + +APVs syncen: ./trbbang T 3 0 aa bb cccc + +Sync-Event abholen: ./trbbang I 0 aa bb cccc + +Triggern: ./trbbang T 0 X aa bb cccc + +X: 0 -> RAW128 mode (all channels raw) + 1 -> PED128 mode (all channels pedestal corrected) + 2 -> PED128THR mode (mode 1 + threshold comparison) + 3 -> reserved + 4 -> NC64PED64 + 5 -> NC64 + 6 -> NC64GOOD + 7 -> NC64THR + +############################################################################################ + +Datenformat: + +D[31] 0 -> Daten, 1 -> Debug +D[30:28] sector number +D[27:25] module number +D[24:21] APV number +D[20:14] channel number +D[13:0] ADC data + +Debug: + +D[30:28] sector number +D[27:25] module number +D[24:21] APV number +D[20] bad buffer +D[19] buffer not valid +D[18] frame counter error +D[17] row error +D[16] APV error bit set +D[15:12] number of frames requested +D[11:8] current frame number +D[7:0] row information (if available) + + + + + + +############################################################################################ + +Es gibt vier Kontrollregister im APV, die die Boardkonfiguration beeinflussen: + +0xc0: [31] RESET_SYS + [30] RESET_APV + [29] RESET_ADC + [26] POWERDOWN_ADC1 + [25] POWERDOWN_ADC0 + [24] reserved, do not use + [16] LED auf Backplane :-) + [15:0] APV_ON + +0xc1: [31] reset PLL ADC1 + [27:24] Phase PLL ADC1 + [23] reset PLL ADC0 + [19:16] Phase PLL ADC0 + [14:12] debug output select ADC1 + [10:8] debug output select ADC0 + [7] reset PLL 40MHz + [3:0] Phase CLK ADC / APV + +0xc2: [31:28] maximum number of APV frames / event (= 0x3) + [23:20] TODO hardware trigger 2 + [19:16] DELAY hardware trigger 2 + [15:12] TODO hardware trigger 1 + [11:8] DELAY hardware trigger 1 + [7:4] TODO hardware trigger 0 + [3:0] DELAY hardware trigger 0 + +0xc3: [31:24] BitHigh setting + [23:16] BitLow setting + [15:8] FlatHigh setting + [7:0] FlatLow setting + + diff --git a/libtrbnet/Makefile b/libtrbnet/Makefile new file mode 100644 index 0000000..cae868f --- /dev/null +++ b/libtrbnet/Makefile @@ -0,0 +1,95 @@ +AXIS_USABLE_LIBS = UCLIBC GLIBC +include $(AXIS_TOP_DIR)/tools/build/Rules.axis + +#CFLAGS = -pipe -g -ansi -pedantic -Wall +CFLAGS = -pipe -g -Wall -Winline -O3 -finline-functions -finline-limit=600000 #-DHEXMODE + +CPPFLAGS = + +INCDIR = -I. + +LDFLAGS = +LIBDIR = -L. +LOADLIBES = -ltrbnet + +# ------------ Libaries ------------------------------------------------ + +AR = ar-cris +ARFLAGS = -srv + +# ------------ Install ------------------------------------------------- + +BIN.OBJS = +LIB.OBJS = +INC.OBJS = + +BIN_DIR = +LIB_DIR = +INC_DIR = + +# ------------ Objects ------------------------------------------------- + +TARGETS = trbcmd pulser + +trbcmd.OBJS = trbcmd.o + +pulser.OBJS = pulser.o + +# ------------ Library-Objects ---------------------------------------- + +LIB_TARGETS = libtrbnet.a + +libtrbnet.OBJS = port.o fs_fpga_int_mem.o trberror.o trbnet.o + +# ------------ Suffix Rules ------------------------------------------- + +.SUFFIXES: + +# ----- C Code --------- +%.o: %.c + $(CC) $< -c $(CPPFLAGS) $(CFLAGS) $(INCDIR) -o $@ + +.SUFFIXES: .o .c + +# ------------ Targets ------------------------------------------------- + +all: $(TARGETS) $(LIB_TARGETS) + +trbcmd: $(trbcmd.OBJS) libtrbnet.a + @echo LINKING $@ + $(CC) $(trbcmd.OBJS) $(LDFLAGS) $(LIBDIR) $(LOADLIBES) -o $@ + @echo DONE! + +pulser: $(pulser.OBJS) libtrbnet.a + @echo LINKING $@ + $(CC) $(pulser.OBJS) $(LDFLAGS) $(LIBDIR) $(LOADLIBES) -o $@ + @echo DONE! + +libtrbnet.a: $(libtrbnet.OBJS) + @echo CREATING library $@ + $(AR) $(ARFLAGS) $@ $^ + @echo DONE! + +lib: $(LIB_TARGETS) + +distclean: clean + rm -f $(TARGETS) $(LIB_TARGETS) + rcsclean -u + +clean: + rm -f *.o core core.* + rcsclean + +# ------------ Dependencies -------------------------------------------- + +port.o: port.h port.c + +fs_fpga_int_mem.o: fs_fpga_int_mem.h fs_fpga_int_mem.c port.h + +trberror.o: trberror.h trberror.c + +trbnet.o: trbnet.h trbnet.c trberror.h fs_fpga_int_mem.h port.h + +trbcmd.o: trbcmd.c trbnet.h port.h trberror.h fs_fpga_int_mem.h + +pulser.o: pulser.c trbnet.h port.h trberror.h diff --git a/libtrbnet/fs_fpga_int_mem.c b/libtrbnet/fs_fpga_int_mem.c new file mode 100644 index 0000000..0e38ec4 --- /dev/null +++ b/libtrbnet/fs_fpga_int_mem.c @@ -0,0 +1,69 @@ +#include +#include + +#include "fs_fpga_int_mem.h" + +/* clean exit when Ctrl-C is pressed */ +void ctrl_c_catched() +{ + close_ports(); +#if DEBUG + fprintf(stderr, "got ctrl-c and close gpio\n"); +#endif + exit(0); +} + +/* writes a 32bit word to a given address on a given device */ +void write32_to_FPGA(uint16_t address, uint32_t value) +{ + /* set address RW_WRITE */ + set_value_single(address & 0x7fff); + set_value(value); + writePC(0x10000); + writePC(0); +} + +/* reads a 32bit word from a given address on a given device */ +int read32_from_FPGA(uint16_t address, uint32_t* value) +{ + /* set address RW_WRITE */ + set_value_single(address | 0x8000); + + *value = ((readPB() << 16)); + writePC(0x10000); + writePC(0); + writePC(0x10000); + writePC(0); + *value |= (readPB() & 0xffff); + writePC(0x10000); + writePC(0); + + return 0; +} + +/* reads a 32bit word from a given address on a given device */ +int read32_from_FPGA_dma(uint16_t fifo_address, + uint32_t* values, + uint32_t size) +{ + uint32_t tmp; + uint32_t *start = NULL; + + /* write maximum length to control register of fifo */ + write32_to_FPGA(fifo_address, size); + + /* set address RW_WRITE */ + set_value_single(fifo_address | 0x8000); + + start = values; + do { + tmp = readPB() << 16; + strobe(); + strobe(); /* (will be optimized away) */ + tmp |= (readPB() & 0xffff); + strobe(); + *values++ = tmp; + } while(tmp & 0x01000000); + + return (values - start) - 1; +} diff --git a/libtrbnet/fs_fpga_int_mem.h b/libtrbnet/fs_fpga_int_mem.h new file mode 100644 index 0000000..3081efb --- /dev/null +++ b/libtrbnet/fs_fpga_int_mem.h @@ -0,0 +1,104 @@ +#ifndef FS_FPGA_INT_H +#define FS_FPGA_INT_H + +#include +#include + +#define RW_READ 1 +#define RW_WRITE 0 + +void ctrl_c_catched(); +void write32_to_FPGA(uint16_t address, uint32_t value); +int read32_from_FPGA(uint16_t address, uint32_t* value); +int read32_from_FPGA_dma(uint16_t fifo_address, + uint32_t* values, + uint32_t size); + +/* rw strobe. Raises PC(16) for a short time */ +static inline void strobe() +{ + setbitsPC(0x10000); + clrbitsPC(0x10000); +} + +/* sends reset for communication logic PC(17,16)=11 */ +static inline void com_reset() +{ + setbitsPC(0x30000); + clrbitsPC(0x30000); +} + +/* waits until PB(16) goes high, maximum 100 cycles */ +static inline int wait_for_valid() +{ + unsigned int timeout = 0; + +#if DEBUG + fprintf(stderr, "is_valid PORT_B\n"); +#endif + + do { + if ((readPB() & 0x10000) != 0) { + return 0; + } + } while (timeout++ < 100); + + com_reset(); +#if DEBUG + fprintf(stderr, "Error, I didnt get 'is_valid'\n"); +#endif + + return -1; +} + +/* waits until PB(16) goes low, maximum 100 cycles */ +static inline int wait_for_not_valid() +{ + unsigned int timeout = 0; + +#if DEBUG + fprintf(stderr, "is_not_valid PORT_B\n"); +#endif + + do { + if ((readPB() & 0x10000) == 0) { + return 0; + } + } while (timeout++ < 100); + + com_reset(); +#if DEBUG + fprintf(stderr, "Error, I didnt get 'is_not_valid'\n"); +#endif + + return -1; +} + +/* sends two strobes, hsb then lsb of value */ +static inline void set_value(uint32_t value) +{ + writePC((value>>16)+0x10000); + writePC(0); + writePC((value & 0xffff) + 0x10000); + writePC(0); +} + +/* sends one strobe, lsb of value only */ +static inline void set_value_single(uint16_t value) +{ + writePC(value + 0x10000); + writePC(0); +} + +/* sends address to device, wrapper for set_value */ +static inline void set_address(uint8_t dir, uint16_t address) +{ + + if (dir == RW_READ) { + set_value_single(address | 0x8000); + } else { + set_value_single(address & 0x7fff); + } +} + +#endif diff --git a/libtrbnet/port.c b/libtrbnet/port.c new file mode 100644 index 0000000..4740ff7 --- /dev/null +++ b/libtrbnet/port.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "port.h" + +/* SET OE[1-read/write, 0 - only read] + pA - 8bits, pB,C,D,E-18bits */ +#define GPIOB_OE_PINS 0x0 +#define GPIOC_OE_PINS 0x3ffff +#define GPIO_OFFSET (0x1a000 / sizeof(uint32_t)) + +volatile uint32_t* GPIO_PTR = NULL; +volatile uint32_t* GPIOA_OUT_OFFSET = NULL; +volatile uint32_t* GPIOA_IN_OFFSET = NULL; +volatile uint32_t* GPIOA_OE_OFFSET = NULL; +volatile uint32_t* GPIOB_OUT_OFFSET = NULL; +volatile uint32_t* GPIOB_IN_OFFSET = NULL; +volatile uint32_t* GPIOB_OE_OFFSET = NULL; +volatile uint32_t* GPIOC_OUT_OFFSET = NULL; +volatile uint32_t* GPIOC_IN_OFFSET = NULL; +volatile uint32_t* GPIOC_OE_OFFSET = NULL; +volatile uint32_t* GPIOD_OUT_OFFSET = NULL; +volatile uint32_t* GPIOD_IN_OFFSET = NULL; +volatile uint32_t* GPIOD_OE_OFFSET = NULL; +volatile uint32_t* GPIOE_OUT_OFFSET = NULL; +volatile uint32_t* GPIOE_IN_OFFSET = NULL; +volatile uint32_t* GPIOE_OE_OFFSET = NULL; + +int init_ports() +{ + int memfd; + uint32_t *mem = NULL; + + memfd = open("/dev/mem", O_RDWR); + if (memfd < 0) { + perror("Cant open memory device"); + return -1; + } + + mem = mmap((void*)0, + 2 * 4 * 4 * 8192, + PROT_READ | PROT_WRITE, + MAP_SHARED, + memfd, + 0xb0000000); + + if ((void*)mem == MAP_FAILED) { + perror("Error mem-map"); + return -1; + } + + /* GPIO */ + GPIO_PTR = mem + GPIO_OFFSET; + + GPIOA_OUT_OFFSET = (0x00 + GPIO_PTR); + GPIOA_IN_OFFSET = (0x04 / sizeof(uint32_t)) + GPIO_PTR; + GPIOA_OE_OFFSET = (0x08 / sizeof(uint32_t)) + GPIO_PTR; + GPIOB_OUT_OFFSET = (0x20 / sizeof(uint32_t)) + GPIO_PTR; + GPIOB_IN_OFFSET = (0x24 / sizeof(uint32_t)) + GPIO_PTR; + GPIOB_OE_OFFSET = (0x28 / sizeof(uint32_t)) + GPIO_PTR; + GPIOC_OUT_OFFSET = (0x30 / sizeof(uint32_t)) + GPIO_PTR; + GPIOC_IN_OFFSET = (0x34 / sizeof(uint32_t)) + GPIO_PTR; + GPIOC_OE_OFFSET = (0x38 / sizeof(uint32_t)) + GPIO_PTR; + GPIOD_OUT_OFFSET = (0x40 / sizeof(uint32_t)) + GPIO_PTR; + GPIOD_IN_OFFSET = (0x44 / sizeof(uint32_t)) + GPIO_PTR; + GPIOD_OE_OFFSET = (0x48 / sizeof(uint32_t)) + GPIO_PTR; + GPIOE_OUT_OFFSET = (0x50 / sizeof(uint32_t)) + GPIO_PTR; + GPIOE_IN_OFFSET = (0x54 / sizeof(uint32_t)) + GPIO_PTR; + GPIOE_OE_OFFSET = (0x58 / sizeof(uint32_t)) + GPIO_PTR; + + close(memfd); + + /* set Output Enable */ + /* read all bits on portB */ + *(GPIOB_OE_OFFSET) = GPIOB_OE_PINS; + /* write portC[17-0] */ + *(GPIOC_OE_OFFSET) = GPIOC_OE_PINS; + + return 0; +} + +void close_ports() +{ + *(GPIOB_OE_OFFSET) = 0x0; + *(GPIOC_OE_OFFSET) = 0x0; + + GPIO_PTR = NULL; + GPIOA_OUT_OFFSET = NULL; + GPIOA_IN_OFFSET = NULL; + GPIOA_OE_OFFSET = NULL; + GPIOB_OUT_OFFSET = NULL; + GPIOB_IN_OFFSET = NULL; + GPIOB_OE_OFFSET = NULL; + GPIOC_OUT_OFFSET = NULL; + GPIOC_IN_OFFSET = NULL; + GPIOC_OE_OFFSET = NULL; + GPIOD_OUT_OFFSET = NULL; + GPIOD_IN_OFFSET = NULL; + GPIOD_OE_OFFSET = NULL; + GPIOE_OUT_OFFSET = NULL; + GPIOE_IN_OFFSET = NULL; + GPIOE_OE_OFFSET = NULL; +} diff --git a/libtrbnet/port.h b/libtrbnet/port.h new file mode 100644 index 0000000..efb321a --- /dev/null +++ b/libtrbnet/port.h @@ -0,0 +1,175 @@ +#ifndef PORT_H +#define PORT_H + +#include + +extern volatile uint32_t* GPIO_PTR; + +extern volatile uint32_t* GPIOA_OUT_OFFSET; +extern volatile uint32_t* GPIOA_IN_OFFSET; +extern volatile uint32_t* GPIOA_OE_OFFSET; + +extern volatile uint32_t* GPIOB_OUT_OFFSET; +extern volatile uint32_t* GPIOB_IN_OFFSET; +extern volatile uint32_t* GPIOB_OE_OFFSET; + +extern volatile uint32_t* GPIOC_OUT_OFFSET; +extern volatile uint32_t* GPIOC_IN_OFFSET; +extern volatile uint32_t* GPIOC_OE_OFFSET; + +extern volatile uint32_t* GPIOD_OUT_OFFSET; +extern volatile uint32_t* GPIOD_IN_OFFSET; +extern volatile uint32_t* GPIOD_OE_OFFSET; + +extern volatile uint32_t* GPIOE_OUT_OFFSET; +extern volatile uint32_t* GPIOE_IN_OFFSET; +extern volatile uint32_t* GPIOE_OE_OFFSET; + +#define GPIO_PA 0x00 +#define GPIO_PB 0x20 / sizeof(uint32_t) +#define GPIO_PC 0x30 / sizeof(uint32_t) +#define GPIO_PD 0x40 / sizeof(uint32_t) +#define GPIO_PE 0x50 / sizeof(uint32_t) + +int init_ports(); +void close_ports(); + +static inline void close_ports_special(uint32_t portBOE, uint32_t portCOE) +{ + *GPIOB_OE_OFFSET = portBOE; + *GPIOC_OE_OFFSET = portCOE; +} + +static inline uint32_t readPA() +{ + return (*GPIOA_IN_OFFSET ); +} + +static inline void writePA(uint8_t data) +{ + *GPIOA_OUT_OFFSET = data; +} + +static inline void setbitsPA(uint32_t bitmask) +{ + *GPIOA_OUT_OFFSET |= (bitmask ); +} + +static inline void clrbitsPA(uint32_t bitmask) +{ + *GPIOA_OUT_OFFSET &= ~(bitmask ); +} + + +static inline uint32_t readPB() +{ + return (*GPIOB_IN_OFFSET ); +} + +static inline void writePB(uint32_t data) +{ + *GPIOB_OUT_OFFSET = (data ); +} + +static inline void setbitsPB(uint32_t bitmask) +{ + *GPIOB_OUT_OFFSET |= (bitmask); +} + +static inline void clrbitsPB(uint32_t bitmask) +{ + *GPIOB_OUT_OFFSET &= ~(bitmask); +} + + +static inline uint32_t readPC() +{ + return (*GPIOC_IN_OFFSET ); +} + +static inline void writePC(uint32_t data) +{ + *GPIOC_OUT_OFFSET = (data ); +} + +static inline void setbitsPC(uint32_t bitmask) +{ + *GPIOC_OUT_OFFSET |= (bitmask ); +} + +static inline void clrbitsPC(uint32_t bitmask) +{ + *GPIOC_OUT_OFFSET &= ~(bitmask); +} + +static inline uint32_t readPD() +{ + return (*GPIOD_IN_OFFSET ); +} + +static inline void writePD(uint32_t data) +{ + *GPIOD_OUT_OFFSET = (data ); +} + +static inline void setbitsPD(uint32_t bitmask) +{ + *GPIOD_OUT_OFFSET |= (bitmask ); +} + +static inline void clrbitsPD(uint32_t bitmask) +{ + *GPIOD_OUT_OFFSET &= ~(bitmask ); +} + + +static inline uint32_t readPE() +{ + return (*GPIOE_IN_OFFSET ); +} + +static inline void writePE(uint32_t data) +{ + *GPIOE_OUT_OFFSET = (data ); +} + +static inline void setbitsPE(uint32_t bitmask) +{ + *GPIOE_OUT_OFFSET |= (bitmask ); +} + +static inline void clrbitsPE(uint32_t bitmask) +{ + *GPIOE_OUT_OFFSET &= ~(bitmask ); +} + + +static inline uint32_t readPort(uint32_t port) +{ + return *(GPIO_PTR + port + 4 / sizeof(uint32_t)); +} + +static inline void writePort(uint32_t port, uint32_t value) +{ + *(GPIO_PTR + port) = (value ); +} + +static inline void setbitsPort(uint32_t port, uint32_t bitmask) +{ + *(GPIO_PTR + port) |= (bitmask); +} + +static inline void clrbitsPort(uint32_t port, uint32_t bitmask) +{ + *(GPIO_PTR + port) &= ~(bitmask); +} + +static inline void microdelay(unsigned int del) +{ + unsigned int i; + unsigned int calibrated_del = del * 10; + for (i = 0; i < calibrated_del; i++) { + } +} + +#endif diff --git a/libtrbnet/pulser.c b/libtrbnet/pulser.c new file mode 100644 index 0000000..59f0a3f --- /dev/null +++ b/libtrbnet/pulser.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define bufferSize 16385 + +/* ------ MAIN ---------------------------------------------------------- */ + +static FILE *hldFile = NULL; +static unsigned int evtCounter = 0; + +static void atexit0() +{ + if (hldFile != NULL) { + fclose(hldFile); + } + + fprintf(stderr, "%d Triggers were send\n", evtCounter); +} + +static void sigHandler(int sig) +{ + if (sig == SIGTERM) fprintf(stderr, "caught SIGTERM\n"); + if (sig == SIGINT) fprintf(stderr, "caught SIGINT\n"); + + exit(128 + sig); +} + +void usage(const char *progName) +{ + printf("Usage: %s [-h] [-d level] [-f outFileName] [-n numEvents]\n", + progName); + printf("Options:\n"); + printf(" -h give this help\n"); + printf(" -d turn on Debugging Information\n"); + printf(" -f outFileName\n"); + printf(" -n process numEvents triggers\n"); +} + +int main(int argc, char ** argv) +{ + char hldFileName[256] = "pulser.hld"; + uint16_t trgNumber = 0; + unsigned int numEvts = UINT_MAX; + uint32_t buffer[bufferSize]; + sigset_t blockSet; + int size; + int writeToStdout = 0; + int i; + + trb_debug = 0; + + /* Parse Arguments */ + while ((i = getopt(argc, argv, "+hd:f:n:")) != -1) { + switch (i) { + case '?': + usage(basename(argv[0])); + exit(EXIT_FAILURE); + case 'h': + usage(basename(argv[0])); + exit(EXIT_SUCCESS); + case 'd': + trb_debug = strtoul(optarg, NULL, 0); + break; + case 'f': + strncpy(hldFileName, optarg, 256); + break; + case 'n': + numEvts = strtoul(optarg, NULL, 0); + break; + default: + break; + } + } + + /* open port */ + init_ports(); + + /* Open HLD-File */ + if (strncmp(hldFileName, "stdout", 256) != 0) { + hldFile = fopen(hldFileName, "w"); + if (hldFile == NULL) { + perror("File Open"); + } + } else { + writeToStdout = 1; + } + + /* Set Signalhandler */ + atexit(atexit0); + signal(SIGINT, sigHandler); + signal(SIGTERM, sigHandler); + + /* Set signal mask for blocking */ + sigemptyset(&blockSet); + sigaddset(&blockSet, SIGINT); + sigaddset(&blockSet, SIGTERM); + + /* Loop Triggers */ + while(evtCounter < numEvts) { + /* Block signals */ + sigprocmask(SIG_BLOCK, &blockSet, NULL); + + /* Send Trigger and get Data */ + if (trb_send_trigger(0, 0, 0xcc, 0xdd, 0xaabb) != -1) { + exit(EXIT_FAILURE); + } + + size = trb_ipu_data_read(0, 0xcc, 0xdd, 0xaabb, buffer, bufferSize); + if (size == -1) { + exit(EXIT_FAILURE); + } + + if (writeToStdout == 1) { + fprintf(stdout, "Trigger# %d\n", trgNumber); + for (i = 0; i < size; i++) { + fprintf(stdout, "0x%08x\n", buffer[i]); + } + } else { + if (fwrite((void*)buffer, 4, size, hldFile) != size) { + perror("Writing to File failed"); + exit(EXIT_FAILURE); + } + } + + /* Unblock signals */ + sigprocmask(SIG_UNBLOCK, &blockSet, NULL); + + trgNumber++; + evtCounter++; + if (evtCounter % 100 == 0) { + fprintf(stderr, "%d triggers send\n", trgNumber); + } + } + + exit(EXIT_SUCCESS); +} diff --git a/libtrbnet/trb.txt b/libtrbnet/trb.txt new file mode 100644 index 0000000..cc8f334 --- /dev/null +++ b/libtrbnet/trb.txt @@ -0,0 +1,22 @@ +mboehmer load_xilix.sh for reset + +adcmodule addresse: 0xfa00 oder 0x42 +lesetest: 0x8021 +schreibtest: 0x8000 +schreibtest: 0x8002 +invalid: 0x8001 + +Blocktranfer: 0xa000 - 0xbfff lesen und schreiben + +#Test in Frankfurt: trb128 + + +# Daten Auslesen: +#Init: +./trbnet -d1 T 3 0 0xaa 0xbb 0x0008 +./trbnet -d1 I 0 0xaa 0xbb 0x0008 + +#Hier loop machen, dabei Trigger hochzaehlen, trigger = 9, 10, 11, 12, ... +./trbnet -d1 T 0 0 0xaa 0xbb 0xtrigger +./trbnet -d1 I 0 0xaa 0xbb 0x0trigger + diff --git a/libtrbnet/trbcmd.c b/libtrbnet/trbcmd.c new file mode 100644 index 0000000..2b32427 --- /dev/null +++ b/libtrbnet/trbcmd.c @@ -0,0 +1,518 @@ +#define _GNU_SOURCE +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifndef HEXMODE +#define HEXMODE 0 +#endif + +static int hexMode = HEXMODE; + +/* ------ MAIN ---------------------------------------------------------- */ + +void usage(const char *progName) +{ + printf("Usage: %s [-h] [-n number] [-d level] [-H] \n", progName); + printf("Options:\n"); + printf(" -h give this help\n"); + printf(" -n repeat COMMAND number times, -1 = endless loop\n"); + printf(" -d turn on Debugging Information\n"); + printf(" level 1: TRB_Package debugging\n"); + printf(" level 2: +FIFO debugging\n"); + printf(" -D FIFO DMA-Mode\n"); + printf(" -l lazy-mode: skip most consistency-checks of packages\n"); + printf(" -H hex-mode: all following arguments will be interpreted " + "as hexadecimal\n numbers\n"); + printf("Commands:\n"); + printf(" r -> read register\n"); + printf(" w -> write register\n"); + printf(" rm " + "-> read register-memory\n"); + printf(" wm " + "-> write to register-memory from ASCII-file ('-' = stdin)\n"); + printf(" i -> read unique ID\n"); + printf(" s -> set trb-address\n"); + printf(" T -> trigger by " + "slowcontrol\n"); + printf(" I -> read IPU data " + "slowcontrol\n"); + printf(" f -> flush FIFO of " + "channel\n"); + printf(" R -> " + "read register of the FPGA" + " \n"); + printf(" W -> " + "write to register of the FPGA" + " \n"); +} + +int main(int argc, char ** argv) +{ + uint16_t trb_address = 0; + uint16_t reg_address = 0; + int cmdCtr = 0; + int repeat = 1; + int i; + + trb_debug = 0; + trb_lazy = 0; + + /* Parse Arguments */ + while ((i = getopt(argc, argv, "+hn:d:DlH")) != -1) { + switch (i) { + case '?': + usage(basename(argv[0])); + exit(EXIT_FAILURE); + case 'h': + usage(basename(argv[0])); + exit(EXIT_SUCCESS); + case 'n': + repeat = strtol(optarg, NULL, 0); + break; + case 'd': + trb_debug = strtoul(optarg, NULL, 0); + break; + case 'D': + trb_dma = 1; + break; + case 'l': + trb_lazy = 1; + break; + case 'H': + hexMode = 1; + break; + default: + break; + } + } + + /* open port */ + init_ports(); + + if (argc - optind < 1) { + usage(basename(argv[0])); + exit(EXIT_FAILURE); + } + + while ((repeat == -1) || (cmdCtr++ < repeat)) { + + if (strcmp(argv[optind], "w") == 0) { + + /*******************************************/ + /* Register Write */ + /*******************************************/ + + uint32_t value = 0; + + if (argc - optind != 4) { + usage(basename(argv[0])); + exit(EXIT_FAILURE); + } + + trb_address = strtoul(argv[optind + 1], NULL, hexMode == 1 ? 16 : 0); + reg_address = strtoul(argv[optind + 2], NULL, hexMode == 1 ? 16 : 0); + value = strtoul(argv[optind + 3], NULL, hexMode == 1 ? 16 : 0); + + /* DEBUG Info */ + if (trb_debug > 0) { + fprintf(stderr, + "Command: WRITE: trb_address: 0x%04x, reg_address: 0x%04x, " + "value: 0x%08x\n", + trb_address, reg_address, value); + } + + if (trb_register_write(trb_address, reg_address, value) == -1) { + trb_error("write failed"); + exit(EXIT_FAILURE); + } + } else if (strcmp(argv[optind], "r") == 0) { + + /*******************************************/ + /* Register Read */ + /*******************************************/ + + int status = 0; + uint32_t data[256]; + + if (argc - optind != 3) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + trb_address = strtoul(argv[optind + 1], NULL, hexMode == 1 ? 16 : 0); + reg_address = strtoul(argv[optind + 2], NULL, hexMode == 1 ? 16 : 0); + + /* DEBUG Info */ + if (trb_debug > 0) { + fprintf(stderr, + "Command: READ: trb_address: 0x%04x, " + "reg_address: 0x%04x\n", + trb_address, reg_address); + } + + status = trb_register_read(trb_address, reg_address, data, 256); + if (status == -1) { + trb_error("read failed"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < status; i += 2) { + fprintf(stdout, "%s%04x %s%08x\n", + hexMode == 1 ? "" : "0x", + data[i], + hexMode == 1 ? "" : "0x", + data[i + 1]); + } + } else if (strcmp(argv[optind], "rm") == 0) { + + /*******************************************/ + /* Register Read Memory */ + /*******************************************/ + + uint32_t *data = NULL; + uint16_t size = 0; + uint8_t option = 0; + int status; + unsigned int i; + + if (argc - optind != 5) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + trb_address = strtoul(argv[optind + 1], NULL, hexMode == 1 ? 16 : 0); + reg_address = strtoul(argv[optind + 2], NULL, hexMode == 1 ? 16 : 0); + size = strtoul(argv[optind + 3], NULL, hexMode == 1 ? 16 : 0); + option = strtoul(argv[optind + 4], NULL, hexMode == 1 ? 16 : 0); + + /* DEBUG Info */ + if (trb_debug > 0) { + fprintf(stderr, + "Command: READ_MEM: trb_address: 0x%04x, " + "reg_address: 0x%04x, " + "size: 0x%04x, " + "option: %d\n", + trb_address, reg_address, size, option); + } + + if ((data = malloc(sizeof(uint32_t) * size)) == NULL) abort(); + + status = + trb_register_read_mem(trb_address, reg_address, option, data, size); + if (status == -1) { + trb_error("read_mem failed"); + if (data != NULL) free(data); + exit(EXIT_FAILURE); + } + + for (i = 0; i < status; i++) { + fprintf(stdout, "%s%04x %s%08x\n", + hexMode == 1 ? "" : "0x", reg_address + i, + hexMode == 1 ? "" : "0x", data[i]); + } + + if (data != NULL) free(data); + } else if (strcmp(argv[optind], "wm") == 0) { + + /*******************************************/ + /* Register Write Memory */ + /*******************************************/ + + FILE *file = NULL; + uint32_t *data = NULL; + unsigned int dataSize = 64; + char *buffer = NULL; + size_t len = 0; + char *fileName = NULL; + uint8_t option = 0; + unsigned int size = 0; + int status; + + if (argc - optind != 5) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + trb_address = strtoul(argv[optind + 1], NULL, hexMode == 1 ? 16 : 0); + reg_address = strtoul(argv[optind + 2], NULL, hexMode == 1 ? 16 : 0); + option = strtoul(argv[optind + 3], NULL, hexMode == 1 ? 16 : 0); + fileName = argv[optind + 4]; + + /* Open inputFile and read Data into buffer */ + if (strcmp(fileName, "-") == 0) { + file = stdin; + } else { + file = fopen(fileName, "r"); + if (file == NULL) { + perror("Error opening file"); + exit(EXIT_FAILURE); + } + } + + if ((data = malloc(sizeof(uint32_t) * dataSize)) == NULL) abort(); + while (getline(&buffer, &len, file) != -1) { + if (size >= dataSize) { + dataSize += 64; + if ((data = realloc(data, sizeof(uint32_t) * dataSize)) == NULL) { + abort(); + } + } + data[size++] = strtoul(buffer, NULL, hexMode == 1 ? 16 : 0); + } + if (buffer != NULL) free(buffer); + + /* DEBUG Info */ + if (trb_debug > 0) { + fprintf(stderr, + "Command: WRITE_MEM: trb_address: 0x%04x, " + "reg_address: 0x%04x, " + "option: %d, " + "size: 0x%04x\n", + trb_address, reg_address, option, size); + } + + status = trb_register_write_mem(trb_address, reg_address, option, + data, size); + if (data != NULL) free(data); + + if (status == -1) { + trb_error("write register-memory failed"); + exit(EXIT_FAILURE); + } + } else if (strcmp(argv[optind], "i") == 0) { + + /*******************************************/ + /* ReadUId */ + /*******************************************/ + + uint32_t uidBuffer[128]; + unsigned int size; + + if (argc - optind != 2) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + trb_address = strtoul(argv[optind + 1], NULL, hexMode == 1 ? 16 : 0); + + /* DEBUG Info */ + if (trb_debug > 0) { + fprintf(stderr, + "Command: READ_UID: trb_address: 0x%04x\n", + trb_address); + } + + size = trb_read_uid(trb_address, uidBuffer, 128); + if (size == -1) { + trb_error("read_uid failed"); + exit(EXIT_FAILURE); + } + + for (i = 0; (i < size) && (i < 128); i += 3) { + fprintf(stdout, "%s%08x%08x %s%02x\n", + hexMode == 1 ? "" : "0x", + uidBuffer[i], + uidBuffer[i + 1], + hexMode == 1 ? "" : "0x", + uidBuffer[i + 2]); + } + } else if (strcmp(argv[optind], "s") == 0) { + + /*******************************************/ + /* SetAddress */ + /*******************************************/ + + uint64_t uid = 0; + uint8_t endpoint = 0; + uint16_t trb_address = 0; + + if (argc - optind != 4) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + uid = strtoull(argv[optind + 1], NULL, hexMode == 1 ? 16 : 0); + endpoint = strtoul(argv[optind + 2], NULL, hexMode == 1 ? 16 : 0); + trb_address = strtoul(argv[optind + 3], NULL, hexMode == 1 ? 16 : 0); + + /* DEBUG Info */ + if (trb_debug > 0) { + fprintf(stderr, + "Command: SET_ADDRESS: " + "uid: 0x%016llx, " + "endpoint: 0x%02x, " + "trb_address: 0x%04x\n", + uid, endpoint, trb_address); + } + + if (trb_set_address(uid, endpoint, trb_address) == -1) { + trb_error("set_address failed"); + exit(EXIT_FAILURE); + } + } else if (strcmp(argv[optind], "T") == 0) { + + /*******************************************/ + /* Fake trigger function (ADCM specific) */ + /*******************************************/ + + uint8_t input = 0; + uint8_t type = 0; + uint8_t random = 0; + uint8_t info = 0; + uint16_t number = 0; + + if (argc - optind != 6) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + input = strtoul(argv[optind + 1], NULL, hexMode == 1 ? 16 : 0) & 0x03; + type = strtoul(argv[optind + 2], NULL, hexMode == 1 ? 16 : 0) & 0x0f; + random = strtoul(argv[optind + 3], NULL, hexMode == 1 ? 16 : 0); + info = strtoul(argv[optind + 4], NULL, hexMode == 1 ? 16 : 0); + number = strtoul(argv[optind + 5], NULL, hexMode == 1 ? 16 : 0); + + /* DEBUG Info */ + if (trb_debug > 0) { + fprintf(stderr, + "Command: SEND_TRIGGER: " + "input: 0x%01x, " + "type: 0x%01x, " + "random: 0x%02x, " + "info: 0x%02x, " + "number: 0x%04x\n", + input, type, random, info, number); + } + + if (trb_send_trigger(input, type, info, random, number) == -1) { + trb_error("send trigger failed"); + exit(EXIT_FAILURE); + } + } else if (strcmp(argv[optind], "I") == 0) { + + /*******************************************/ + /* IPU channel readout */ + /*******************************************/ + + uint32_t buffer[4096]; + uint8_t type = 0; + uint8_t random = 0; + uint8_t info = 0; + uint16_t number = 0; + int size = 0; + + if (argc - optind != 5) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + type = strtoul(argv[optind + 1], NULL, hexMode == 1 ? 16 : 0) & 0x0f; + random = strtoul(argv[optind + 2], NULL, hexMode == 1 ? 16 : 0); + info = strtoul(argv[optind + 3], NULL, hexMode == 1 ? 16 : 0); + number = strtoul(argv[optind + 4], NULL, hexMode == 1 ? 16 : 0); + + /* DEBUG Info */ + if (trb_debug > 0) { + fprintf(stderr, + "Command: READ_IPU_DATA: " + "type: 0x%01x, " + "random: 0x%02x, " + "info: 0x%02x, " + "number: 0x%04x\n", + type, random, info, number); + } + size = trb_ipu_data_read(type, info, random, number, buffer, 4096); + if (size == -1) { + trb_error("ipu read data failed"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < size; i++) { + fprintf(stdout, "0x%08x\n", buffer[i]); + } + } else if (strcmp(argv[optind], "f") == 0) { + + /*******************************************/ + /* Flush FIFO Channel */ + /*******************************************/ + + int status; + uint8_t channel = 0; + + if (argc - optind != 2) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + channel = strtoul(argv[optind + 1], NULL, hexMode == 1 ? 16 : 0); + if (trb_debug > 0) { + fprintf(stderr, "Command: FIFO_FLUSH_CHANNEL #%d\n", channel); + } + + status = trb_fifo_flush(channel); + if (status == -1) { + trb_error("flush channel failed"); + exit(EXIT_FAILURE); + } + } else if (strcmp(argv[optind], "R") == 0) { + + /*******************************************/ + /* Read FIFO Register */ + /*******************************************/ + + uint32_t value = 0; + uint16_t reg_address = 0; + + if (argc - optind != 2) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + reg_address = strtoul(argv[optind + 1], NULL, hexMode == 1 ? 16 : 0); + + read32_from_FPGA(reg_address, &value); + fprintf(stdout, "%s%04x %s%04x\n", + hexMode == 1 ? "" : "0x", reg_address, + hexMode == 1 ? "" : "0x", value); + + } else if (strcmp(argv[optind], "W") == 0) { + + /*******************************************/ + /* Write FIFO Register */ + /*******************************************/ + + uint32_t value = 0; + uint16_t reg_address = 0; + + if (argc - optind != 3) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + reg_address = strtoul(argv[optind + 1], NULL, hexMode == 1 ? 16 : 0); + value = strtoul(argv[optind + 2], NULL, hexMode == 1 ? 16 : 0); + + write32_to_FPGA(reg_address, value); + + /* + fprintf(stdout, "%s%04x %s%04x\n", + hexMode == 1 ? "" : "0x", reg_address, + hexMode == 1 ? "" : "0x", value); + */ + } else { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + + } /* end repeat loop */ + + exit(EXIT_SUCCESS); +} diff --git a/libtrbnet/trberror.c b/libtrbnet/trberror.c new file mode 100644 index 0000000..ef6bb1d --- /dev/null +++ b/libtrbnet/trberror.c @@ -0,0 +1,140 @@ +#include +#include +#include + +#include "trberror.h" + +/* Error Handling */ + +int trb_errno = TRB_NONE; +uint64_t trb_statusbits = 0; + +void trb_error(const char *s) +{ + if (s != NULL) { + fprintf(stderr, "%s: %s\n", s, trb_strerror(trb_errno)); + } else { + fprintf(stderr, "%s\n", trb_strerror(trb_errno)); + } + + /* Print Statusbits */ + if (trb_errno == TRB_TERM_ERRBIT) { + fprintf(stderr, "%s\n", trb_statusbits_str(trb_statusbits)); + } +} + +const char* trb_strerror(int errno) +{ + static const char errorstring[][80] = { + "No Error", + "TX Busy", + "FIFO Not Empty", + "FIFO Timeout", + "FIFO Error, invalid H0 header(s)", + "FIFO Error, invalid sequenze-number", + "FIFO Error, invalid read-data-mode", + "FIFO Broken-Package", + "FIFO Invalid-Content (no TERMINATION)", + "FAILED WAIT_IS_VALID", + "FAILED WAIT_IS_NOT_VALID", + "User-Buffer Overflow", + "Invalid Channel", + "Invalid number of Packages returned", + "TERMINATION ErrorBit(s) set", + "Invalid TRB-Address", + "Invalid Data-Buffer Length", + "Endpoint not reached" + }; + + if (errno < 18) { + return errorstring[errno]; + } else { + return "Unknown Errno"; + } +} + +const char* trb_statusbits_str(uint64_t statusbits) +{ + static const char commonStatusBits[16][64] = { + "Endpoint not reached", + "Coll: collision detected", + "WordMiss: word missing", + "Checksum: checksum error", + "DontKnow: dont understand", + "BufferMatch: buffer mismatch", + "", "", "", "", "", "", "", "", "", "" + }; + + static const char ch0StatusBits[16][64] = { + "Ch0_TrigCtr: trigger counter mismatch", + "", + "", + "", + "Ch0_BufferHalfFull: data-buffers half full", + "Ch0_BuffersFull: data-buffers almost full" + "", "", "", "", "", "", "", "", "", "" + }; + + static const char ch1StatusBits[16][64] = { + "Ch1_TrigNum: trigger number mismatch", + "Ch1_TrigCode: trigger code / random mismatch", + "Ch1_Length: wrong length", + "Ch1_NoAnswer: answer missing", + "", + "", + "", + "", + "Ch1_NotFound: not found" + "", "", "", "", "", "", "", "" + }; + + static const char ch2StatusBits[16][64] = { + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "" + }; + + static const char ch3StatusBits[16][64] = { + "Ch3_Address: unknown address", + "Ch3_TimeOut: timeout error", + "Ch3_NoData: no more data" + "", "", "", "", "", "", "", "", "", "", "", "", "" + }; + + static const char *chStatusBits[4] = { + &ch0StatusBits[0][0], + &ch1StatusBits[0][0], + &ch2StatusBits[0][0], + &ch3StatusBits[0][0] + }; + + static char buffer[2048] = ""; + unsigned int i; + uint8_t channel = (statusbits & 0x700000000LL) >> 32; + + if (channel >= 4) { + snprintf(buffer, 2048, "INVALID ChannelId %d", channel); + return buffer; + } + + snprintf(buffer, 2048, + "CommonStatusBits: 0x%04x, Channel#%d StatusBits: 0x%04x\n", + (uint16_t)(statusbits & 0x0000ffffLL), + channel, + (uint16_t)((statusbits & 0xffff0000LL) >> 16)); + for (i = 0; i < 16; i++) { + if (((statusbits & 0xffffLL) & (0x01LL << i)) != (i != 0 ? 0 : 1)) { + strncat(buffer, " ", 2048); + strncat(buffer, commonStatusBits[i], 2048); + strncat(buffer, "\n", 2048); + } + } + for (i = 0; i < 16; i++) { + if ((((statusbits & 0xffff0000LL) >> 16) & (0x01LL << i)) != 0) { + strncat(buffer, " ", 2048); + strncat(buffer, chStatusBits[channel] + 64 * i, 2048); + strncat(buffer, "\n", 2048); + } + } + + return buffer; +} diff --git a/libtrbnet/trberror.h b/libtrbnet/trberror.h new file mode 100644 index 0000000..bf75584 --- /dev/null +++ b/libtrbnet/trberror.h @@ -0,0 +1,37 @@ +#ifndef TRBERROR_H +#define TRBERROR_H + +#include + +typedef enum { + TRB_NONE = 0, + TRB_TX_BUSY = 1, + TRB_FIFO_NOT_EMPTY = 2, + TRB_FIFO_TIMEOUT = 3, + TRB_FIFO_HEADERS = 4, + TRB_FIFO_SEQUENZ = 5, + TRB_FIFO_INVALID_MODE = 6, + TRB_FIFO_BROKEN_PACKAGE = 7, + TRB_FIFO_INVALID_CONTENT = 8, + TRB_FAILED_WAIT_IS_VALID = 9, + TRB_FAILED_WAIT_IS_NOT_VALID = 10, + TRB_USER_BUFFER_OVF = 11, + TRB_INVALID_CHANNEL = 12, + TRB_INVALID_PKG_NUMBER = 13, + TRB_TERM_ERRBIT = 14, + TRB_INVALID_ADDRESS = 15, + TRB_INVALID_LENGTH = 16, + TRB_ENDPOINT_NOT_REACHED = 17 +} TRB_ERROR; + +extern int trb_errno; + +extern uint64_t trb_statusbits; + +void trb_error(const char *s); + +const char* trb_strerror(int errno); + +const char* trb_statusbits_str(uint64_t statusbits); + +#endif diff --git a/libtrbnet/trbnet.c b/libtrbnet/trbnet.c new file mode 100644 index 0000000..120624e --- /dev/null +++ b/libtrbnet/trbnet.c @@ -0,0 +1,1076 @@ +#include +#include +#include +#include + +#include "trbnet.h" + +/* TRBNet Header word definitions */ +#define SHIFT_HEADER_TYPE 0x0000 +#define MASK_HEADER_TYPE (0x0007 << SHIFT_HEADER_TYPE) +#define SHIFT_HEADER_REPLY 0x0003 +#define MASK_HEADER_REPLY (0x0001 << SHIFT_HEADER_REPLY) +#define SHIFT_HEADER_CHANNEL 0x0004 +#define MASK_HEADER_CHANNEL (0x0003 << SHIFT_HEADER_CHANNEL) + +/* TRBNet Header types */ +#define HEADER_DAT 0x0000 +#define HEADER_HDR 0x0001 +#define HEADER_EOB 0x0002 +#define HEADER_TRM 0x0003 +#define HEADER_EXT 0x0004 +#define HEADER_ACK 0x0005 +#define HEADER_SIG 0x0006 +#define HEADER_ILL 0x0007 + +/* Header Word definitions */ +#define SHIFT_SEQNR 4 +#define MASK_SEQNR (0xff << SHIFT_SEQNR) +#define SHIFT_DATATYPE 0 +#define MASK_DATATYPE (0xf << SHIFT_DATATYPE) + +/* FIFO Masks */ +#define SHIFT_FIFO_VALID 24 +#define MASK_FIFO_VALID (0x1 << SHIFT_FIFO_VALID) +#define SHIFT_FIFO_TYPE 16 +#define MASK_FIFO_TYPE (0x3 << SHIFT_FIFO_TYPE) + +/* FIFO Types */ +#define FIFO_TYPE_IS_HEADER 2 + +/* FIFO STATUS definitions */ +#define MASK_FIFO_FULL (0x01 << 16) +#define MASK_FIFO_EMPTY (0x01 << 17) +#define MASK_FIFO_LEVEL 0x03ff + +/* Channel Registers */ + +/* Registers inside Virtex FPGA -> TRBnet endpoint (channel N) */ +#define CHANNEL_N_START_WRITE 0x0100 +#define CHANNEL_N_TARGET_ADDRESS 0x0101 +#define CHANNEL_N_SENDER_ERROR 0x0102 +#define CHANNEL_N_SENDER_DATA 0x0103 +#define CHANNEL_N_SENDER_FIFO_STATUS 0x0104 +#define CHANNEL_N_SENDER_STATUS 0x010f +#define CHANNEL_N_RECEIVER_DATA 0x0203 +#define CHANNEL_N_RECEIVER_FIFO_STATUS 0x0204 +#define CHANNEL_N_API_STATUS 0x0300 + +/* Registers inside Virtex FPGA -> TRBnet endpoint (channel 0) */ +#define CHANNEL_0_SENDER_CONTROL 0x0110 +#define CHANNEL_0_TARGET_ADDRESS 0x0111 +#define CHANNEL_0_SENDER_ERROR 0x0112 +#define CHANNEL_0_SENDER_DATA 0x0113 +#define CHANNEL_0_SENDER_FIFO_STATUS 0x0114 +#define CHANNEL_0_SENDER_STATUS 0x011f +#define CHANNEL_0_RECEIVER_DATA 0x0213 +#define CHANNEL_0_RECEIVER_FIFO_STATUS 0x0214 +#define CHANNEL_0_API_STATUS 0x0310 + +/* Registers inside Virtex FPGA -> TRBnet endpoint (channel 1) */ +#define CHANNEL_1_SENDER_CONTROL 0x0130 +#define CHANNEL_1_TARGET_ADDRESS 0x0131 +#define CHANNEL_1_SENDER_ERROR 0x0132 +#define CHANNEL_1_SENDER_DATA 0x0133 +#define CHANNEL_1_SENDER_FIFO_STATUS 0x0134 +#define CHANNEL_1_SENDER_STATUS 0x013f +#define CHANNEL_1_RECEIVER_DATA 0x0233 +#define CHANNEL_1_RECEIVER_FIFO_STATUS 0x0234 +#define CHANNEL_1_API_STATUS 0x0330 + +/* Registers inside Virtex FPGA -> TRBnet endpoint (channel 2) */ +#define CHANNEL_2_SENDER_CONTROL 0x0150 +#define CHANNEL_2_TARGET_ADDRESS 0x0151 +#define CHANNEL_2_SENDER_ERROR 0x0152 +#define CHANNEL_2_SENDER_DATA 0x0153 +#define CHANNEL_2_SENDER_FIFO_STATUS 0x0154 +#define CHANNEL_2_SENDER_STATUS 0x015f +#define CHANNEL_2_RECEIVER_DATA 0x0253 +#define CHANNEL_2_RECEIVER_FIFO_STATUS 0x0254 +#define CHANNEL_2_API_STATUS 0x0350 + +/* Registers inside Virtex FPGA -> TRBnet endpoint (channel 3) */ +#define CHANNEL_3_SENDER_CONTROL 0x0170 +#define CHANNEL_3_TARGET_ADDRESS 0x0171 +#define CHANNEL_3_SENDER_ERROR 0x0172 +#define CHANNEL_3_SENDER_DATA 0x0173 +#define CHANNEL_3_SENDER_FIFO_STATUS 0x0174 +#define CHANNEL_3_SENDER_STATUS 0x017f +#define CHANNEL_3_RECEIVER_DATA 0x0273 +#define CHANNEL_3_RECEIVER_FIFO_STATUS 0x0274 +#define CHANNEL_3_API_STATUS 0x0370 + +/* SENDER_STATUS definitions */ +#define MASK_TX_RUNNING 0x00000001 + +/* Commands supported for packages */ +#define CMD_REGISTER_READ 0x08 +#define CMD_REGISTER_READ_MEM 0x0a +#define CMD_REGISTER_WRITE 0x09 +#define CMD_REGISTER_WRITE_MEM 0x0b +#define CMD_NETADMINISTRATION 0x0f + +/* Network administration commands */ +#define NET_READUNIQUEID 0x5e1d +#define NET_SETADDRESS 0x5ead +#define NET_ACKADDRESS 0xacad +#define SHORT_TRANSFER 0x0100 + +/* Other */ +#define MAX_TIME_OUT 500 +#define DATA_BUFFER_SIZE 8192 + + +/* ---------------------------------------------------------------------- */ + +unsigned int trb_debug = 0; +unsigned int trb_lazy = 0; +unsigned int trb_dma = 0; + +/* Declaration of a TRB-Package */ + +typedef struct { + uint16_t H0; + uint16_t F0; + uint16_t F1; + uint16_t F2; + uint16_t F3; +} TRB_Package; + +/* Status-Bit definitions */ + +typedef enum { + Status_C_EndReached = 0, /* endpoint reached */ + Status_C_Coll = 1, /* collision detected, */ + Status_C_WordMiss = 2, /* word missing, */ + Status_C_Checksum = 3, /* checksum error, */ + Status_C_DontKnow = 4, /* dont understand, */ + Status_C_BufferMatch = 5 /* buffer mismatch */ +} Status_Common; + +typedef enum { + Status_Ch0_TrigCtr = 0, /* trigger counter mismatch */ + Status_Ch0_BufferHalfFull = 4, /* buffers half full */ + Status_Ch0_BuffersFull = 5 /* buffers almost full */ +} Status_CH0; + +typedef enum { + Status_Ch1_TrigNum = 0, /* trigger number mismatch */ + Status_Ch1_TrigCode = 1, /* trigger code / random mismatch */ + Status_Ch1_Length = 2, /* wrong length */ + Status_Ch1_NoAnswer = 3, /* answer missing */ + Status_Ch1_NotFound = 8 /* not found */ +} Status_CH1; + +typedef enum { + Status_Ch2_NONE = 0 +} Status_CH2; + +typedef enum { + Status_Ch3_Address = 0, /* unknown address */ + Status_Ch3_TimeOut = 4, /* timeout */ + Status_Ch3_NoData = 5 /* nomoredata */ +} Status_CH3; + +/* ------ Internal Functions -------------------------------------------- */ + +static void TRB_Package_dump(const TRB_Package* pkg) +{ + switch ((pkg->H0 & MASK_HEADER_TYPE) >> SHIFT_HEADER_TYPE) { + case HEADER_DAT: + fprintf(stderr, "H0: 0x%04x --> DATA channel: %01d reply: %01d\n", + pkg->H0, + (pkg->H0 & MASK_HEADER_CHANNEL) >> SHIFT_HEADER_CHANNEL, + (pkg->H0 & MASK_HEADER_REPLY) >> SHIFT_HEADER_REPLY); + fprintf(stderr, "F0: 0x%04x --> data0\n", pkg->F0); + fprintf(stderr, "F1: 0x%04x --> data1\n", pkg->F1); + fprintf(stderr, "F2: 0x%04x --> data2\n", pkg->F2); + fprintf(stderr, "F3: 0x%04x --> data3\n", pkg->F3); + break; + + case HEADER_HDR: + fprintf(stderr, "H0: 0x%04x --> HEADER channel: %01d reply: %01d\n", + pkg->H0, + (pkg->H0 & MASK_HEADER_CHANNEL) >> SHIFT_HEADER_CHANNEL, + (pkg->H0 & MASK_HEADER_REPLY) >> SHIFT_HEADER_REPLY); + fprintf(stderr, "F0: 0x%04x --> source address\n", pkg->F0); + fprintf(stderr, "F1: 0x%04x --> target address\n", pkg->F1); + fprintf(stderr, "F2: 0x%04x --> reserved\n", pkg->F2); + fprintf(stderr, "F3: 0x%04x --> sequence: 0x%02x datatype: 0x%01x\n", + pkg->F3, + (pkg->F3 & MASK_SEQNR) >> SHIFT_SEQNR, + (pkg->F3 & MASK_DATATYPE) >> SHIFT_DATATYPE); + break; + + case HEADER_EOB: + fprintf(stderr, "H0: 0x%04x --> EOB channel: %01d reply: %01d\n", + pkg->H0, + (pkg->H0 & MASK_HEADER_CHANNEL) >> SHIFT_HEADER_CHANNEL, + (pkg->H0 & MASK_HEADER_REPLY) >> SHIFT_HEADER_REPLY); + fprintf(stderr, "F0: 0x%04x --> checksum\n", pkg->F0); + fprintf(stderr, "F1: 0x%04x --> reseved\n", pkg->F1); + fprintf(stderr, "F2: 0x%04x --> data count\n", pkg->F2); + fprintf(stderr, "F3: 0x%04x --> buffer number\n", pkg->F3); + break; + + case HEADER_TRM: + fprintf(stderr, "H0: 0x%04x --> TERM channel: %01d reply: %01d\n", + pkg->H0, + (pkg->H0 & MASK_HEADER_CHANNEL) >> SHIFT_HEADER_CHANNEL, + (pkg->H0 & MASK_HEADER_REPLY) >> SHIFT_HEADER_REPLY); + fprintf(stderr, "F0: 0x%04x --> checksum\n", pkg->F0); + fprintf(stderr, "F1: 0x%04x --> statusbits channel\n", pkg->F1); + fprintf(stderr, "F2: 0x%04x --> statusbits common\n", pkg->F2); + fprintf(stderr, "F3: 0x%04x --> sequence: 0x%02x datatype: 0x%01x\n", + pkg->F3, + (pkg->F3 & MASK_SEQNR) >> SHIFT_SEQNR, + (pkg->F3 & MASK_DATATYPE) >> SHIFT_DATATYPE); + break; + + case HEADER_EXT: + fprintf(stderr, "H0: 0x%04x --> EXT channel: %01d reply: %01d\n", + pkg->H0, + (pkg->H0 & MASK_HEADER_CHANNEL) >> SHIFT_HEADER_CHANNEL, + (pkg->H0 & MASK_HEADER_REPLY) >> SHIFT_HEADER_REPLY); + fprintf(stderr, "F0: 0x%04x --> reserved\n", pkg->F0); + fprintf(stderr, "F1: 0x%04x --> reserved\n", pkg->F1); + fprintf(stderr, "F2: 0x%04x --> reserved\n", pkg->F2); + fprintf(stderr, "F2: 0x%04x --> reserved\n", pkg->F3); + break; + + case HEADER_ACK: + fprintf(stderr, "H0: 0x%04x --> ACK channel: %01d reply: %01d\n", + pkg->H0, + (pkg->H0 & MASK_HEADER_CHANNEL) >> SHIFT_HEADER_CHANNEL, + (pkg->H0 & MASK_HEADER_REPLY) >> SHIFT_HEADER_REPLY); + fprintf(stderr, "F0: 0x%04x --> reserved\n", pkg->F0); + fprintf(stderr, "F1: 0x%04x --> lenght of buffer\n", pkg->F1); + fprintf(stderr, "F2: 0x%04x --> reserved\n", pkg->F2); + fprintf(stderr, "F2: 0x%04x --> buffer number\n", pkg->F3); + break; + + case HEADER_SIG: + fprintf(stderr, "H0: 0x%04x --> SIGNAL channel: %01d reply: %01d\n", + pkg->H0, + (pkg->H0 & MASK_HEADER_CHANNEL) >> SHIFT_HEADER_CHANNEL, + (pkg->H0 & MASK_HEADER_REPLY) >> SHIFT_HEADER_REPLY); + fprintf(stderr, "F0: 0x%04x --> reserved\n", pkg->F0); + fprintf(stderr, "F1: 0x%04x --> reserved\n", pkg->F1); + fprintf(stderr, "F2: 0x%04x --> reserved\n", pkg->F2); + fprintf(stderr, "F2: 0x%04x --> reserved\n", pkg->F3); + break; + + case HEADER_ILL: + fprintf(stderr, "H0: 0x%04x --> ILLEGAL channel: %01d reply: %01d\n", + pkg->H0, + (pkg->H0 & MASK_HEADER_CHANNEL) >> SHIFT_HEADER_CHANNEL, + (pkg->H0 & MASK_HEADER_REPLY) >> SHIFT_HEADER_REPLY); + fprintf(stderr, "F0: 0x%04x --> ignore\n", pkg->F0); + fprintf(stderr, "F1: 0x%04x --> ignore\n", pkg->F1); + fprintf(stderr, "F2: 0x%04x --> ignore\n", pkg->F2); + fprintf(stderr, "F2: 0x%04x --> ignore\n", pkg->F3); + break; + + default: + fprintf(stderr, "INVALID\n"); + } +} + +static int trb_wait_tx_not_busy(uint8_t channel) +{ + uint32_t tmp = 0; + unsigned int timeout = 0; + + if (channel >= 4) { + trb_errno = TRB_INVALID_CHANNEL; + return -1; + } + + while (timeout < MAX_TIME_OUT) { + read32_from_FPGA(CHANNEL_N_SENDER_STATUS | ((channel * 2 + 1) << 4), &tmp); + if ((tmp & MASK_TX_RUNNING) == 0) { + return 0; + } + timeout++; + } + + /* timeout occurred */ + trb_errno = TRB_TX_BUSY; + return -1; +} + +static int trb_init_transfer(uint8_t channel) +{ + uint32_t tmp = 0; + + if (channel >= 4) { + trb_errno = TRB_INVALID_CHANNEL; + return -1; + } + + /* Check for TX not Busy, wait MAX_TIMEOUT */ + if (trb_wait_tx_not_busy(3) == -1) { + return -1; + } + + /* Check receiver FIFO empty*/ + read32_from_FPGA(CHANNEL_N_RECEIVER_FIFO_STATUS | ((channel * 2 + 1) << 4), + &tmp); + if ((tmp & MASK_FIFO_EMPTY) == 0) { + trb_errno = TRB_FIFO_NOT_EMPTY; + /* clear fifo ???*/ + return -1; + } + + /* No Errors */ + return 0; +} + +enum FIFO_READ_MODE { + FIFO_MODE_NONE, + FIFO_MODE_REG_READ, + FIFO_MODE_REG_READ_MEM, + FIFO_MODE_REG_WRITE, + FIFO_MODE_IPU_DATA, + FIFO_MODE_UID, + FIFO_MODE_SET_ADDRESS +}; + +static int trb_fifo_read(uint8_t channel, + int mode, + uint32_t data[], + unsigned int size) +{ + static uint32_t dataBuffer[DATA_BUFFER_SIZE]; + uint32_t *tmp = dataBuffer; + int dma_size; + + TRB_Package package; + int headerType = 0; + uint32_t fifoBuffer = 0; + unsigned int counter = 0; + unsigned int dataCtr = 0; + int packageCtr = -1; + unsigned int endPointCtr = 0; + + unsigned int timeout = 0; + + /* Determin FIFO-Address */ + if (channel >= 4) { + trb_errno = TRB_INVALID_CHANNEL; + return -1; + } + fifoBuffer = CHANNEL_N_RECEIVER_DATA | ((channel * 2 + 1) << 4); + + /* Check for FIFO Ready */ + timeout = 0; + + if (trb_dma == 1) { + /* DMA-Readout */ + do { + dma_size = + read32_from_FPGA_dma(fifoBuffer, tmp, DATA_BUFFER_SIZE); + } while ((dma_size == 0) && (++timeout < MAX_TIME_OUT)); + } else { + /* Standard */ + do { + read32_from_FPGA(fifoBuffer, tmp); + } while (((*tmp & MASK_FIFO_VALID) == 0) && (++timeout < MAX_TIME_OUT)); + } + + if (timeout >= MAX_TIME_OUT) { + trb_errno = TRB_FIFO_TIMEOUT; + return -1; + } + + /* Read FIFO-Buffer, copy to User-Buffer */ + while ((*tmp & MASK_FIFO_VALID) != 0) { + if (((*tmp & MASK_FIFO_TYPE) >> SHIFT_FIFO_TYPE) + == FIFO_TYPE_IS_HEADER) { + if ((counter % 5) == 0) { + /* New Package begins */ + if (trb_debug > 0) { + fprintf(stderr, + "-------------------------------------------------\n"); + } + packageCtr++; + counter = 0; + } else { + /* Error: invalid buffer content, flush FIFO-BUFFER and exit */ + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_BROKEN_PACKAGE; + return -1; + } + } else { + /* Data Word */ + if ((trb_lazy == 0) && + (((*tmp & MASK_FIFO_TYPE) >> SHIFT_FIFO_TYPE) != + (counter - 1) % 2)) { + /* Error: invalid sequence (not 0, 1, .), flush FIFO-BUFFER and exit */ + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_BROKEN_PACKAGE; + return -1; + } + } + + switch (counter) { + case 0: + package.H0 = *tmp; + break; + case 1: + package.F0 = *tmp; + break; + case 2: + package.F1 = *tmp; + break; + case 3: + package.F2 = *tmp; + break; + case 4: + package.F3 = *tmp; + break; + default: + abort(); + } + + /* DEBUG INFO */ + if (trb_debug > 1) { + fprintf(stderr, "FIFO_%03d: 0x%08x\n", + packageCtr * 5 + counter, *tmp); + } + + counter++; + + if (counter % 5 == 0) { + /* End of Package, validate package and retrieve data */ + + /* Determine H0 HeaderType */ + headerType = (package.H0 & MASK_HEADER_TYPE) >> SHIFT_HEADER_TYPE; + + /* DEBUG INFO */ + if (trb_debug > 0) { + TRB_Package_dump(&package); + fprintf(stderr, "-------------------------------------------------\n"); + } + + /* First package (TRB-Header), headerType must be HDR or TRM */ + if (trb_lazy == 0) { + if (packageCtr == 0) { + if (!((headerType == HEADER_HDR) | (headerType == HEADER_TRM))) { + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_INVALID_CONTENT; + return -1; + } + } + + /* Check Header H0 */ + if (((package.H0 & MASK_HEADER_REPLY) >> SHIFT_HEADER_REPLY + != 0x01) || + ((package.H0 & MASK_HEADER_CHANNEL) >> SHIFT_HEADER_CHANNEL + != channel)) { + + /* Error Package inconsistencies, flush FIFO-BUFFER and exit */ + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_HEADERS; + return -1; + } + } + + /* Get Data F0 - F3 and store it in User-Data-Buffer if requested */ + if (headerType != HEADER_TRM) { + switch (mode) { + + case FIFO_MODE_NONE: + break; + + case FIFO_MODE_REG_READ: + + switch (headerType) { + case HEADER_HDR: + if ((packageCtr - endPointCtr * 2) != 0) { + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_INVALID_CONTENT; + return -1; + } + if (dataCtr < size) { + data[dataCtr++] = (uint32_t)package.F0; + } else { + trb_fifo_flush(channel); + trb_errno = TRB_USER_BUFFER_OVF; + return -1; + } + break; + + case HEADER_DAT: + if ((packageCtr - endPointCtr * 2) != 1) { + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_INVALID_CONTENT; + } + if (dataCtr < size) { + data[dataCtr++] = (((uint32_t)package.F1 << 16) | + ((uint32_t)package.F2)); + endPointCtr++; + } else { + trb_fifo_flush(channel); + trb_errno = TRB_USER_BUFFER_OVF; + return -1; + } + break; + + default: + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_INVALID_CONTENT; + return -1; + } + + break; + + case FIFO_MODE_REG_READ_MEM: + if (packageCtr > 0) { + if (headerType != HEADER_DAT) { + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_INVALID_CONTENT; + return -1; + } + if (dataCtr < size) { + data[dataCtr++] = (((uint32_t)package.F1 << 16) | + ((uint32_t)package.F2)); + } else { + trb_fifo_flush(channel); + trb_errno = TRB_USER_BUFFER_OVF; + return -1; + } + } + break; + + case FIFO_MODE_REG_WRITE: + if (packageCtr > 1) { + trb_fifo_flush(channel); + trb_errno = TRB_INVALID_PKG_NUMBER; + return -1; + } + break; + + case FIFO_MODE_IPU_DATA: + if (packageCtr > 0) { + if (headerType != HEADER_DAT) { + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_INVALID_CONTENT; + return -1; + } + if ((dataCtr + 1) < size) { + data[dataCtr++] = (((uint32_t)package.F0 << 16) | + ((uint32_t)package.F1)); + data[dataCtr++] = (((uint32_t)package.F2 << 16) | + ((uint32_t)package.F3)); + } else { + trb_fifo_flush(channel); + trb_errno = TRB_USER_BUFFER_OVF; + return -1; + } + } + break; + + case FIFO_MODE_UID: + { + static uint32_t uidLow; + static uint32_t uidHigh; + + switch (headerType) { + case HEADER_HDR: + if ((packageCtr - endPointCtr * 3) != 0) { + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_INVALID_CONTENT; + return -1; + } + break; + + case HEADER_DAT: + if ((packageCtr - endPointCtr * 3) == 1) { + uidHigh = (((uint32_t)package.F0 << 0) | + ((uint32_t)package.F1 << 16)); + uidLow = (((uint32_t)package.F2 << 0) | + ((uint32_t)package.F3 << 16)); + break; + } + + if ((packageCtr - endPointCtr * 3) == 2) { + if ((dataCtr + 3) < size) { + /* store uid and endPoint in userDataBuffer */ + data[dataCtr++] = uidLow; + data[dataCtr++] = uidHigh; + data[dataCtr++] = (uint32_t)package.F0; + endPointCtr++; + } else { + trb_fifo_flush(channel); + trb_errno = TRB_USER_BUFFER_OVF; + return -1; + } + break; + } + + default: + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_INVALID_CONTENT; + return -1; + } + } + break; + + case FIFO_MODE_SET_ADDRESS: + if ((packageCtr == 1) && (headerType == HEADER_DAT)) { + if (package.F0 != NET_ACKADDRESS) { + trb_fifo_flush(channel); + return -1; + } + } + + if (packageCtr > 1) { + trb_fifo_flush(channel); + trb_errno = TRB_INVALID_PKG_NUMBER; + return -1; + } + + dataCtr++; + break; + + default: + trb_fifo_flush(channel); + trb_errno = TRB_FIFO_INVALID_MODE; + return -1; + } + } + } + + /* Read Next Word */ + if (trb_dma == 1) { + tmp++; + } else { + read32_from_FPGA(fifoBuffer, tmp); + } + } + + if (trb_lazy == 0) { + /* Check whether last package is complete */ + if ((packageCtr >= 0) && (counter != 5)) { + trb_errno = TRB_FIFO_BROKEN_PACKAGE; + return -1; + } + + /* Check whether last package is a TERMINATION Package */ + if (headerType != HEADER_TRM) { + trb_errno = TRB_FIFO_INVALID_CONTENT; + return -1; + } + + /* Check StatusBits of TerminationPackage */ + if ((package.F2 != 0x0001) || + (package.F1 != 0x0000)) { + + trb_statusbits = + ((uint64_t)channel << 32) | + ((uint64_t)package.F1 << 16) | + ((uint64_t)package.F2 << 0); + trb_errno = TRB_TERM_ERRBIT; + return -1; + } + } + + return dataCtr; +} + +/* ----- Global Functions ----------------------------------------------- */ + +int trb_fifo_flush(uint8_t channel) +{ + uint32_t tmp; + uint32_t fifoAddress; + unsigned int counter = 0; + + if (channel >= 4) { + trb_errno = TRB_INVALID_CHANNEL; + return -1; + } + + /* DEBUG INFO */ + if (trb_debug > 1) { + fprintf(stderr, "Flushing FIFO of channel# %d\n", channel); + } + + fifoAddress = CHANNEL_N_RECEIVER_DATA | ((channel * 2 + 1) << 4); + do { + read32_from_FPGA(fifoAddress, &tmp); + /* DEBUG INFO */ + if ((trb_debug > 1) && ((tmp & MASK_FIFO_VALID) != 0)) { + fprintf(stderr, "FIFO_%03d: 0x%08x\n", counter, tmp); + counter++; + } + } while ((tmp & MASK_FIFO_VALID) != 0); + + return 0; +} + +int trb_register_read(uint16_t trb_address, + uint16_t reg_address, + uint32_t *data, + unsigned int size) +{ + int status = 0; + + /* Init transfer */ + if (trb_init_transfer(3) == -1) { + return -1; + } + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "Init_Transfer done.\n"); + } + + /* Build up package and start transfer */ + write32_to_FPGA(CHANNEL_3_TARGET_ADDRESS, trb_address); + write32_to_FPGA(CHANNEL_3_SENDER_ERROR, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, reg_address); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_CONTROL, CMD_REGISTER_READ); + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "CMD_REGISTER_READ started.\n"); + } + + status = trb_fifo_read(3, FIFO_MODE_REG_READ, data, size); + + if ((status > 0) && (status % 2 != 0)) { + trb_errno = TRB_INVALID_PKG_NUMBER; + return -1; + } + + return status; +} + +int trb_register_read_mem(uint16_t trb_address, + uint16_t reg_address, + uint8_t option, + uint32_t *data, + uint16_t size) +{ + uint16_t length; + + /* Do not allow broadcasts within this function */ + if (trb_address >= 0xff00) { + trb_errno = TRB_INVALID_ADDRESS; + return -1; + } + + /* check size and set reading-mode */ + length = size & 0x7fff; + if ((size == 0) || (size != length)) { + trb_errno = TRB_INVALID_LENGTH; + return -1; + } + length = length | (option == 0 ? 0x8000 : 0x0000); + + /* Init transfer */ + if (trb_init_transfer(3) == -1) { + return -1; + } + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "Init_Tranfer done.\n"); + } + + /* Build up package and start transfer */ + write32_to_FPGA(CHANNEL_3_TARGET_ADDRESS, trb_address); + write32_to_FPGA(CHANNEL_3_SENDER_ERROR, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, reg_address); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, length); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_CONTROL, CMD_REGISTER_READ_MEM); + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "CMD_REGISTER_READ_MEM started.\n"); + } + + return trb_fifo_read(3, FIFO_MODE_REG_READ_MEM, data, size); +} + +int trb_register_write(uint16_t trb_address, + uint16_t reg_address, + uint32_t value) +{ + /* Init transfer */ + if (trb_init_transfer(3) == -1) { + return -1; + } + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "Init_Transfer done.\n"); + } + + /* Build up package */ + write32_to_FPGA(CHANNEL_3_TARGET_ADDRESS, trb_address); + write32_to_FPGA(CHANNEL_3_SENDER_ERROR, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, reg_address); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, (value >> 16) & 0xffff); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, value & 0xffff); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_CONTROL, CMD_REGISTER_WRITE); + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "CMD_REGISTER_WRITE started.\n"); + } + + return trb_fifo_read(3, FIFO_MODE_REG_WRITE, NULL, 0); +} + +int trb_register_write_mem(uint16_t trb_address, + uint16_t reg_address, + uint8_t option, + const uint32_t *data, + uint16_t size) +{ + uint16_t config; + uint16_t i; + + /* check size and set write-mode */ + config = size & 0x7fff; + if ((size == 0) || (size != config)) { + trb_errno = TRB_INVALID_LENGTH; + return -1; + } + config = config | (option == 0 ? 0x8000 : 0x0000); + + /* Init transfer */ + if (trb_init_transfer(3) == -1) { + return -1; + } + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "Init_Transfer done.\n"); + } + + /* Build up package */ + write32_to_FPGA(CHANNEL_3_TARGET_ADDRESS, trb_address); + write32_to_FPGA(CHANNEL_3_SENDER_ERROR, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, reg_address); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, config); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + for (i = 0; i < size; i++) { + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, (data[i] >> 16) & 0xffff); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, data[i] & 0xffff); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + } + write32_to_FPGA(CHANNEL_3_SENDER_CONTROL, CMD_REGISTER_WRITE_MEM); + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "CMD_REGISTER_WRITE_MEM started.\n"); + } + + return trb_fifo_read(3, FIFO_MODE_REG_WRITE, NULL, 0); +} + +int trb_read_uid(uint16_t trb_address, + uint32_t* uidBuffer, + unsigned int size) +{ + int status; + + /* Init transfer */ + if (trb_init_transfer(3) == -1) { + return -1; + } + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "Init_Transfer done.\n"); + } + + /* Build up package and start transfer */ + write32_to_FPGA(CHANNEL_3_TARGET_ADDRESS, trb_address); + write32_to_FPGA(CHANNEL_3_SENDER_ERROR, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, NET_READUNIQUEID); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_CONTROL, CMD_NETADMINISTRATION); + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "CMD_READ_UNIQUE_ID started.\n"); + } + + status = trb_fifo_read(3, FIFO_MODE_UID, (uint32_t*)uidBuffer, size); + + if ((status > 0) && (status % 3 != 0)) { + trb_errno = TRB_INVALID_PKG_NUMBER; + return -1; + } + + return status; +} + + +int trb_set_address(uint64_t uid, + uint8_t endpoint, + uint16_t trb_address) +{ + int status; + + /* check for valid TRBnet address to be assigned */ + if (trb_address >= 0xff00 ) { + trb_errno = TRB_INVALID_ADDRESS; + return -1; + } + + /* Init transfer */ + if (trb_init_transfer(3) == -1) { + return -1; + } + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "Init_Transfer done.\n"); + } + + /* Build up package and start transfer */ + write32_to_FPGA(CHANNEL_3_TARGET_ADDRESS, 0xffff); /* always broadcast */ + write32_to_FPGA(CHANNEL_3_SENDER_ERROR, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, NET_SETADDRESS); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, (uint16_t)(uid)); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, (uint16_t)(uid >> 16)); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, (uint16_t)(uid >> 32)); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, (uint16_t)(uid >> 48)); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, endpoint); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, trb_address); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_CONTROL, CMD_NETADMINISTRATION); + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "CMD_SETADDRESS started.\n"); + } + + status = trb_fifo_read(3, FIFO_MODE_SET_ADDRESS, NULL, 0); + if (status == -1) return -1; + + if (status != 2) { + trb_errno = TRB_ENDPOINT_NOT_REACHED; + return -1; + } + + + return 0; +} + +int trb_ipu_data_read(uint8_t type, + uint8_t trg_info, + uint8_t trg_random, + uint16_t trg_number, + uint32_t *data, + unsigned int size) +{ + int status; + + if (data == NULL) return -1; + + /* Init transfer IPU Channel */ + if (trb_init_transfer(1) == -1) { + return -1; + } + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "Init_Transfer done.\n"); + } + + /* Prepare IPU channel */ + write32_to_FPGA(CHANNEL_1_SENDER_ERROR, (((uint32_t)trg_info << 24) | + ((uint32_t)trg_random << 16) | + ((uint32_t)trg_number) + )); + write32_to_FPGA(CHANNEL_1_SENDER_CONTROL, + SHORT_TRANSFER | (uint32_t)(type & 0x0f)); + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "CMD_IPU_DATA_READ started.\n"); + } + + status = trb_fifo_read(1, FIFO_MODE_IPU_DATA, data, size); + + return status; +} + + +int trb_send_trigger(uint8_t trg_input, + uint8_t type, + uint8_t trg_info, + uint8_t trg_random, + uint16_t trg_number) +{ + int status; + + /* Init transfer slowcontrol */ + if (trb_init_transfer(3) == -1) { + return -1; + } + + /* Init transfer trigger */ + if (trb_init_transfer(0) == -1) { + return -1; + } + + /* DEBUG INFO */ + if (trb_debug > 0) { + fprintf(stderr, "Init_Transfer done.\n"); + } + + /* Prepare trigger channel */ + write32_to_FPGA(CHANNEL_0_SENDER_ERROR, (((uint32_t)trg_info << 24) | + ((uint32_t)trg_random << 16) | + ((uint32_t)trg_number) + )); + + /* Prepare slowcontrol channel */ + write32_to_FPGA(CHANNEL_3_TARGET_ADDRESS, 0x0000ffff);/* all boards */ + write32_to_FPGA(CHANNEL_3_SENDER_ERROR, 0x00000000); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, (0x8080 | (uint32_t)trg_input)); + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x0000dead); /*fake data is */ + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x0000beef); /* discarded at ADCM */ + write32_to_FPGA(CHANNEL_3_SENDER_DATA, 0x00000000); + + /* Send both fake trigger and LVL1 information */ + write32_to_FPGA(CHANNEL_3_SENDER_CONTROL, CMD_REGISTER_WRITE); + write32_to_FPGA(CHANNEL_0_SENDER_CONTROL, + SHORT_TRANSFER | (uint32_t)(type & 0x0f)); + + if (trb_debug > 0) { + fprintf(stderr, "trigger started.\n"); + } + + /* Check for replay packets (slowcontrol) */ + status = trb_fifo_read(3, FIFO_MODE_NONE, NULL, 0); + if (status == -1) { + trb_fifo_flush(0); + return -1; + } + + /* Check for replay packets (trigger) */ + status = trb_fifo_read(0, FIFO_MODE_NONE, NULL, 0); + if (status == -1) return -1; + + return 0; +} + diff --git a/libtrbnet/trbnet.h b/libtrbnet/trbnet.h new file mode 100644 index 0000000..3eee0b8 --- /dev/null +++ b/libtrbnet/trbnet.h @@ -0,0 +1,113 @@ +#ifndef TRBNET_H +#define TRBNET_H + +#include +#include + +extern unsigned int trb_debug; +extern unsigned int trb_lazy; +extern unsigned int trb_dma; + +/* ---------------------------------------------------------------------- */ + +int trb_fifo_flush(uint8_t channel); + +int trb_register_read(uint16_t trb_address, + uint16_t reg_address, + uint32_t* data, + unsigned int size); + +int trb_register_read_mem(uint16_t trb_address, + uint16_t reg_address, + uint8_t option, + uint32_t* data, + uint16_t size); + +int trb_register_write(uint16_t trb_address, + uint16_t reg_address, + uint32_t value); + +int trb_register_write_mem(uint16_t trb_address, + uint16_t reg_address, + uint8_t option, + const uint32_t* data, + uint16_t size); + +int trb_read_uid(uint16_t trb_address, + uint32_t* uidBuffer, + unsigned int size); + +int trb_set_address(uint64_t uid, + uint8_t endpoint, + uint16_t trb_address); + + +int trb_ipu_data_read(uint8_t type, + uint8_t trg_info, + uint8_t trg_random, + uint16_t trg_number, + uint32_t* data, + unsigned int size); + + +int trb_send_trigger(uint8_t input, + uint8_t type, + uint8_t info, + uint8_t random, + uint16_t number); + +/* ---------------------------------------------------------------------- */ + +/************************************************************************/ +/* In case of an error trb_errno is set, see trberror.h for details. */ +/************************************************************************/ + + +/************************************************************************/ +/* int trb_register_read(uint16_t trb_address, + uint16_t reg_address, + uint32_t* data, + unsigned int size); + + trb_address: TRB-Address of TRB-Endpoint + reg_address: Register-Address to be read + data: Pointer to uint32_t Data-Buffer + size: Size of the Data-Buffer in units of 32bit-words + + ReturnValue: == -1 on error + >= 0 number of 32bit-words which were stored in Data-Buffer + + TRB-Channel used: slow control (3) + + reads the register reg_address of a TRB-Endpoint with address + trb_address. The received data is stored in the Data-Buffer data. + The format of the Data-Buffer is: + first word: TRB-Address of sender + second word: register value + + --> Data-Buffer-Size size must be at least 2 + +*/ + +/* int trb_register_write(uint16_t trb_address, + uint16_t reg_address, + uint32_t value); + + trb_address: TRB-Address of TRB-Endpoint + reg_address: Register-Address to be written + value: 32bit-word to write to register + + ReturnValue: == -1 on error + >= 0 number of 32bit-words which were stored in Data-Buffer + + TRB-Channel used: slow control (3) + + writes value to the register reg_address of a TRB-Endpoint with address + trb_address. +*/ + + + + + +#endif