#ifndef __FD_LIB_H #define __FD_LIB_H #include /* Number of fractional bits in the timestamps/time definitions. Must be consistent with the HDL bitstream. */ #define FDELAY_FRAC_BITS 12 /* fdelay_get_timing_status() return values: */ #define FDELAY_FREE_RUNNING 0x10 /* local oscillator is free running */ #define FDELAY_WR_OFFLINE 0x8 /* attached WR core is offline */ #define FDELAY_WR_READY 0x1 /* attached WR core is synchronized, we can sync the fine delay core anytime */ #define FDELAY_WR_SYNCING 0x2 /* local oscillator is being synchronized with WR clock */ #define FDELAY_WR_SYNCED 0x4 /* we are synced. */ #define FDELAY_WR_NOT_PRESENT 0x20 /* No WR Core present */ /* fdelay_configure_sync() flags */ #define FDELAY_SYNC_LOCAL 0x1 /* use local oscillator */ #define FDELAY_SYNC_WR 0x2 /* use White Rabbit */ /* fdelay_init() flags */ #define FDELAY_RAW_READOUT 0x1 #define FDELAY_PERFORM_LONG_TESTS 0x2 /* Hardware "handle" structure */ typedef struct fdelay_device { /* Base address of the FD core (relative to the beginning of local writel/readl address spaces) */ uint32_t base_addr; /* Bus-specific readl/writel functions - so the same library can be used both with RawRabbit, VME and Etherbone backends */ void (*writel)(void *priv, uint32_t data, uint32_t addr); uint32_t (*readl)(void *priv, uint32_t addr); void *priv_fd; /* pointer to Fine Delay library private data */ void *priv_io; /* pointer to the I/O routines private data */ } fdelay_device_t; typedef struct { int64_t utc, utc_sh; int32_t coarse, coarse_sh; int32_t start_offset; int32_t subcycle_offset; int32_t frac; uint32_t tsbcr; } fdelay_raw_time_t; typedef struct { int64_t utc; /* TAI seconds */ /* FIXME: replace all UTCs with TAIs or seconds for clarity */ int32_t coarse; /* 125 MHz counter cycles */ int32_t frac; /* Fractional part (<8ns) */ uint16_t seq_id; /* Sequence ID to detect missed timestamps */ fdelay_raw_time_t raw; } fdelay_time_t; /* -------------------- PUBLIC API -------------------- */ fdelay_device_t *fdelay_create(); /* Creates a local instance of Fine Delay Core at address base_addr on the SPEC at bus/devfn. Returns 0 on success, negative on error. */ int spec_fdelay_create_bd(fdelay_device_t *dev, int bus, int dev_fn, uint32_t base); /* A shortcut for test program, parsing the card base/location from command line args */ int spec_fdelay_create(fdelay_device_t *dev, int argc, char *argv[]); /* Helper functions - converting FD timestamp format from/to plain picoseconds */ fdelay_time_t fdelay_from_picos(const uint64_t ps); int64_t fdelay_to_picos(const fdelay_time_t t); /* Enables/disables raw timestamp readout mode (debugging only) */ int fdelay_raw_readout(fdelay_device_t *dev, int raw_moide); /* Initializes and calibrates the device. 0 = success, negative = error */ int fdelay_init(fdelay_device_t *dev, int init_flags); /* Disables and releases the resources for a given FD Card */ int fdelay_release(fdelay_device_t *dev); /* Returns an explaination of the last error occured on device dev (TBI) */ char *fdelay_strerror(fdelay_device_t *dev); /* Sets the timing reference for the card (ref source). Currently there are two choices: - FDELAY_SYNC_LOCAL - use local oscillator - FDELAY_SYNC_WR - use White Rabbit */ int fdelay_set_timing_reference(fdelay_device_t *dev, int ref_source); /* Polls the current status of the timing source. Returns a combination of .... SYNCED flags. wait_mask can enable/disable waiting for a change of a particular flag or set of flags. For example, calling fdelay_get_timing_status(dev, FDELAY_WR_SYNCED) will wait until a change of FDELAY_WR_SYNCED bit. */ int fdelay_get_timing_status(fdelay_device_t *dev, int wait_mask); /* Configures the trigger input (TDC/Delay modes). enable enables the input, termination switches on/off the built-in 50 Ohm termination resistor */ int fdelay_configure_trigger(fdelay_device_t *dev, int enable, int termination); /* Configures timestamp buffer capture: enable = TS buffer enabled, channel mask: channels to time tag (bit 0 = TDC, bits 1..4 = outputs 1..4) */ int fdelay_configure_capture (fdelay_device_t *dev, int enable, int channel_mask); /* Reads how_many timestamps from the buffer. Blocking */ /* TODO: non-blocking version? */ int fdelay_read (fdelay_device_t *dev, fdelay_time_t *timestamps, int how_many); int fdelay_configure_output(fdelay_device_t *dev, int channel, int enable, int64_t delay_ps, int64_t width_ps, int64_t delta_ps, int rep_count) ; /* (delay mode only) Configures output(s) selected in channel_mask to work in delay mode. Delta_ps = spacing between the rising edges of subsequent pulses. */ int fdelay_configure_delay (fdelay_device_t *dev, int channel_mask, int enable, int64_t delay_ps, int64_t width_ps, int64_t delta_ps, int repeat_count); /* (pulse mode only) Configures output(s) selected in channel_mask to produce pulse(s) starting at (start) with appropriate width/spacing/repeat_count */ int fdelay_configure_pulse_gen(fdelay_device_t *dev, int channel_mask, int enable, fdelay_time_t start, int64_t width_ps, int64_t delta_ps, int repeat_count); /* (pulse mode only) Returns non-0 when all of the channels in channel mask have produced their programmed pulses */ int fdelay_outputs_triggered(fdelay_device_t *dev, int channel_mask, int blocking); void fdelay_set_user_offset(fdelay_device_t *dev,int input, int64_t offset); int fdelay_get_time(fdelay_device_t *dev, fdelay_time_t *t); int fdelay_set_time(fdelay_device_t *dev, const fdelay_time_t t); int fdelay_dmtd_calibration(fdelay_device_t *dev, double *offsets); float fdelay_get_board_temperature(fdelay_device_t *dev); #endif