#ifndef __LIBWR2RF__API__H_
#define __LIBWR2RF__API__H_

#include "io.h"

/* Using libwr2rf:

   1. Get an handle to the board using libwr2rf_host_init_by_slot from host.h.
   2. Check the board is present using libwr2rf_check_hwversion.
   3. Enable and check the VCXO.  If necessary, wait until the temperature
      is stabilized.  Use libwr2rf_enable_check_ocxo.
   4. Initialize pll, clocks: libwr2rf_clock_init
   5. TBD: Load WRC firmware if necessary
   6. Check WRC link: libwr2rf_check_link_time
   7. DDS init + DAC init: libwr2rf_rf_init
   8. Enable rf-out output: libwr2rf_set_rf_out

   20. Configure diag units
   21. Configure trigger units
*/

/* Errors */
/* Incorrect identifier (for channel, vtu, diag, lemo...).  */
#define LIBWR2RF_ERROR_BAD_ID     (-1)
/* Incorrect parameter.  */
#define LIBWR2RF_ERROR_BAD_PARAM  (-2)
/* VTU is alreay programmed.  Need to invalidate the VTU before reprogramming
   it.  */
#define LIBWR2RF_ERROR_VTU_SET    (-3)
/* Hardware probing error.  */
#define LIBWR2RF_ERROR_HW         (-4)

/* Read FW version.  */
unsigned libwr2rf_read_fwversion(struct libwr2rf_dev *dev);

/* Check presence of the board and FW version.
   Returns 0 in case of success.  */
int libwr2rf_check_fwversion(struct libwr2rf_dev *dev);

struct libwr2rf_nco_ipinfo_t {
    uint32_t std_ver;
    uint32_t ident;
    uint32_t fw_ver;
    uint32_t mem_map_ver;
};

/* Return ipinfo for NCO.  */
void libwr2rf_read_nco_ipinfo(struct libwr2rf_dev *dev,
                             struct libwr2rf_nco_ipinfo_t* pinfo);

/* Enable OCXO and return the remaining warmup time in seconds.
   Return 0 if already warmed.  */
int libwr2rf_enable_check_ocxo(struct libwr2rf_dev *dev);

/* Initialize PLL, enable WR.  */
void libwr2rf_clock_init(struct libwr2rf_dev *dev);

/* Return iff WR time is valid.  */
int libwr2rf_wrc_time_valid(struct libwr2rf_dev *dev);

/* Return true if both the WR link and time are OK.  */
int libwr2rf_check_link_time(struct libwr2rf_dev *dev);

/* Read the mac address (6 bytes).  Can be used as unique id.  */
int libwr2rf_get_mac(struct libwr2rf_dev *dev, unsigned char *mac);

/* Set DAC amplitude and phase.  Amplitude must be between 0.0 and 1.0,
   phase must be between -360.0 and 360.0
   Do a smooth transition in case of phase jump.  */
int libwr2rf_dac_phase_amp(struct libwr2rf_dev *dev, unsigned ch,
                           float amplitude, float phase);

/* Like the previous function but apply immediately.  Can only be used
   when the trigger units are not enabled.  */
int libwr2rf_dac_reset_phase_amp(struct libwr2rf_dev *dev, unsigned ch,
                                 float amplitude, float phase);

/* Mask (or not mask) NCO resets.  */
int libwr2rf_nco_reset(struct libwr2rf_dev *dev, unsigned ch, unsigned en);

/* RF-out SMA connectors.  */
#define LIBWR2RF_RF_OUT_GND	0
#define LIBWR2RF_RF_OUT_MIXER	1
#define LIBWR2RF_RF_OUT_DDS	2
int libwr2rf_set_rf_out(struct libwr2rf_dev *dev, unsigned ch, unsigned cfg);

/* Initialize RF (DDS and DAC).  */
int libwr2rf_rf_init (struct libwr2rf_dev *dev);

/* Post WR full initialization.  */
int libwr2rf_api_init (struct libwr2rf_dev *dev);

/* tmg-io connector.  */
//#define LIBWR2RF_TMGIO_OUT_RFSYNC      0  /* For channels 1 & 2  */
//#define LIBWR2RF_TMGIO_OUT_FREV        1  /* For channels 1 & 2  */
//#define LIBWR2RF_TMGIO_OUT_FREV_MAIN   2  /* For channels 1 & 2  */
int libwr2rf_configure_tmgio(struct libwr2rf_dev *dev, unsigned lemo,
                             unsigned oe, unsigned term);
int libwr2rf_configure_tmgclk(struct libwr2rf_dev *dev, unsigned lemo,
                              unsigned oe, unsigned term);


/* Diagnostic units.  */
#define LIBWR2RF_DIAG_ID_RF_1        0
#define LIBWR2RF_DIAG_ID_RF_2        1
#define LIBWR2RF_DIAG_ID_RF_1_TRIG_1 2
#define LIBWR2RF_DIAG_ID_RF_1_TRIG_2 3
#define LIBWR2RF_DIAG_ID_RF_2_TRIG_1 4
#define LIBWR2RF_DIAG_ID_RF_2_TRIG_2 5

/* Configure and enable diagnostic unit ID.
   WINDOW_US is the time window (in microsec) used to compute the frequency.
   Available values are 5us, 500us, 50ms, 5s, 20s.
   GENERATION returns the generation value for the previous configuration.
   So results for this generation are not correct.
   Returns 0 in case of success.  Possible errors are bad ID or bad WINDOW_US.
*/
int libwr2rf_enable_diag(struct libwr2rf_dev *dev, unsigned id,
                         unsigned window_us, unsigned *generation);

/* Read diagnostic unit ID.
   FREQ is the number of pulses for the previous generation, while COUNT is
   the total number of pulses since the board started.
   So to compute the real frequency, you need to divide by the window period.
   GENERATION is incremented after each window.
   When you change the configuration, you have to skip 2 generations: skip
   one for the results of the previous config, and skip another one to get
   the first result of the new config.  */
int libwr2rf_read_diag(struct libwr2rf_dev *dev, unsigned id,
                       unsigned *freq, unsigned *count, unsigned *generation);

#define LIBWR2RF_RF1_CHANNEL_ID 1
#define LIBWR2RF_RF2_CHANNEL_ID 2

/* Trigger units.  */
#define LIBWR2RF_TRIG_ID_RF_1_TRIG_1 0
#define LIBWR2RF_TRIG_ID_RF_1_TRIG_2 1
#define LIBWR2RF_TRIG_ID_RF_2_TRIG_1 2
#define LIBWR2RF_TRIG_ID_RF_2_TRIG_2 3

/* LEMO names.  */
#define LIBWR2RF_LEMO_NONE   0
#define LIBWR2RF_LEMO_TMGIO1 1
#define LIBWR2RF_LEMO_TMGIO2 2
#define LIBWR2RF_LEMO_TMGIO3 3
#define LIBWR2RF_LEMO_TMGIO4 4
#define LIBWR2RF_LEMO_TMGCLK1 5
#define LIBWR2RF_LEMO_TMGCLK2 6

/* Debug names */
#define LIBWR2RF_LEMO_DBG_NCO_RESET              0
#define LIBWR2RF_LEMO_DBG_RF1_NCO_RESET_CDELAYED 1
#define LIBWR2RF_LEMO_DBG_RF2_NCO_RESET_CDELAYED 2
#define LIBWR2RF_LEMO_DBG_RF1_FREV               3
#define LIBWR2RF_LEMO_DBG_RF1_FREV_MAIN          4
#define LIBWR2RF_LEMO_DBG_RF2_FREV               5
#define LIBWR2RF_LEMO_DBG_RF2_FREV_MAIN          6
#define LIBWR2RF_LEMO_DBG_WRS_RX_VALID           7
#define LIBWR2RF_LEMO_DBG_WRS_TX_VALID           8
#define LIBWR2RF_LEMO_DBG_WRS_GPIO1              9
#define LIBWR2RF_LEMO_DBG_WRS_GPIO2              10
#define LIBWR2RF_LEMO_DBG_WRS_RF_RST             11
#define LIBWR2RF_LEMO_DBG_WRS_SOFTSTOP           12
#define LIBWR2RF_LEMO_DBG_WRS_SOFTSTART          13
#define LIBWR2RF_LEMO_DBG_NONE                   14


/* LEMO front panel debug selection */
int libwr2rf_configure_lemo_debug(struct libwr2rf_dev *dev,
                                  unsigned lemo, unsigned dbg);

/* Configuration for soft stop + start output to front panel */
#define LIBWR2RF_SOFTSTOP_NONE_SEL   0x0
#define LIBWR2RF_RF1T1_SOFTSTOP_SEL  0x1
#define LIBWR2RF_RF1T2_SOFTSTOP_SEL  0x2
#define LIBWR2RF_RF2T1_SOFTSTOP_SEL  0x4
#define LIBWR2RF_RF2T2_SOFTSTOP_SEL  0x8


#define LIBWR2RF_SOFTSTART_NONE_SEL  0x0
#define LIBWR2RF_RF1T1_SOFTSTART_SEL 0x1
#define LIBWR2RF_RF1T2_SOFTSTART_SEL 0x2
#define LIBWR2RF_RF2T1_SOFTSTART_SEL 0x4
#define LIBWR2RF_RF2T2_SOFTSTART_SEL 0x8
int libwr2rf_configure_softstart_sel(struct libwr2rf_dev *dev, unsigned sel);
int libwr2rf_configure_softstop_sel(struct libwr2rf_dev *dev, unsigned sel);

/* Trigger unit programmation.
   The functions always set the offline configuration.  */

/* Select which lemo is used for start/stop input for trigger ID.  */
int libwr2rf_vtu_start_lemo(struct libwr2rf_dev *dev, unsigned id,
                            unsigned lemo);
int libwr2rf_vtu_stop_lemo(struct libwr2rf_dev *dev, unsigned id,
                            unsigned lemo);

/* Put VTU in/out of reset.  */
int libwr2rf_vtu_reset (struct libwr2rf_dev *dev, unsigned id, unsigned rst);

/* Software stop/start of a VTU. */
int libwr2rf_vtu_softstop (struct libwr2rf_dev *dev, unsigned id);
int libwr2rf_vtu_softstart (struct libwr2rf_dev *dev, unsigned id);

/* Program the delay line of a VTU. VAL is the delay (TBD).  */
int libwr2rf_vtu_output_ff_delay(struct libwr2rf_dev *dev, unsigned id,
                              unsigned val);

/* Program the pad delay for VTU ID.
   HC is 0/1 in RF period / 2, ODELAY is 0..31 in ~78ps steps.  */
int libwr2rf_vtu_output_pad_delay(struct libwr2rf_dev *dev, unsigned id,
                                  unsigned hc, unsigned odelay);

/* Enable the VTU output.  */
int libwr2rf_vtu_output_enable(struct libwr2rf_dev *dev, unsigned id,
                               unsigned en);

/* Enable the VTU pulse shaper.  */
int libwr2rf_vtu_output_shaper(struct libwr2rf_dev *dev, unsigned id,
                               unsigned en);

/* Hold trigger output in reset or not.  */
int libwr2rf_vtu_output_reset(struct libwr2rf_dev *dev, unsigned id,
                              unsigned rst);

/* Program a single pulse on TU ID after B clock cycles.  */
int libwr2rf_vtu_program_pulse (struct libwr2rf_dev *dev, unsigned id,
                                uint64_t b);

/* Program periodic pulses (evey HT clock cycles) after B clock cycles.  */
int libwr2rf_vtu_program_infinite (struct libwr2rf_dev *dev, unsigned id,
                                   uint64_t b, unsigned ht);

/* Program high frequency division (factor DIV) after B clock cycles.
   DIV is 2 .. 16.  */
int libwr2rf_vtu_program_highfreq (struct libwr2rf_dev *dev, unsigned id,
                                   uint64_t b, unsigned div);

/* Program W periodic pulses (evey HT clock cycles) after B clock cycles.  */
int libwr2rf_vtu_program_window (struct libwr2rf_dev *dev, unsigned id,
                                 uint64_t b, unsigned ht, unsigned w);

/* Invalidate the programmation.  If the programmation was already applied
   (with a start pulse of a softstart), this has no effect.  */
int libwr2rf_vtu_program_invalidate (struct libwr2rf_dev *dev, unsigned id);

/* Specify the delay between the NCO reset (from WR) and the sync input of
   trig ID.
   CDELAY in 0..127 in 16ns steps,
   FDELAY in 0..15ns,
   ODELAY in 0..31 in ~78ps steps.  */
int libwr2rf_vtu_nco_reset_delay (struct libwr2rf_dev *dev, unsigned id,
                                  unsigned cdelay, unsigned fdelay,
                                  unsigned odelay);

#define LIBWR2RF_VTU_CH1_CDELAY 75
#define LIBWR2RF_VTU_CH1_FDELAY  5
#define LIBWR2RF_VTU_CH1_ODELAY 10
#define LIBWR2RF_VTU_CH2_CDELAY 75
#define LIBWR2RF_VTU_CH2_FDELAY  4
#define LIBWR2RF_VTU_CH2_ODELAY 20
/* Obtain the delays used for T1 trigger units to sync after an nco_reset. The ref
   argument may be used to obtain the calibrated values, in the absence of this the
   current values are returned.
   CDELAY in 0..127 in 16ns steps,
   FDELAY in 0..15ns,
   ODELAY in 0..31 in ~78ps steps.  */
int libwr2rf_vtu_sync_delays (struct libwr2rf_dev *dev, unsigned id,
                             unsigned *cdelay, unsigned *fdelay, unsigned *odelay,
                             unsigned ref );

/* Program the RFNCO to enable/disable local FTW configuration, rather than from the network.
   lcfg is enable(1)/disable(0)
   ftw  is the 48 bit frev value. */
int libwr2rf_nco_lcfg (struct libwr2rf_dev *dev, unsigned lcfg,
                       unsigned long long ftw_rfnco1,
                       unsigned long long ftw_rfnco2 );

/* Dump (on stdout) the state of VTU ID.  Return < 0 in case of error (bad ID).
   This is a debug function.  */
int libwr2rf_vtu_dump (struct libwr2rf_dev *dev, unsigned id);

/* Specify the ioupdate fine delay and ODELAY values.
   FDELAY is 0..15ns, ODELAY is 0..31 in step of ~78ps.  */
int libwr2rf_ioupdate_delay (struct libwr2rf_dev *dev, unsigned fdelay, unsigned odelay);

/* Set WR streamer fixed latency: the delay between the sent time and the apply
   time (in WR cycles ie 16ns).  */
void libwr2rf_set_wrs_fixed_latency (struct libwr2rf_dev *dev,
                                     unsigned wr_cycles);
unsigned libwr2rf_get_wrs_fixed_latency (struct libwr2rf_dev *dev);

/* Set WR streamer timeout latency: the maximum time the packet arrive in advance.
   Too early coming packets are discarded.  In WR cyckes ie 16ns.  */
void libwr2rf_set_wrs_timeout_latency (struct libwr2rf_dev *dev, unsigned wr_cycles);
unsigned libwr2rf_get_wrs_timeout_latency (struct libwr2rf_dev *dev);

/* Ignore NCO reset from WR if IGNORE is set.  */
void libwr2rf_set_nco_reset_ignore (struct libwr2rf_dev *dev, unsigned ignore);

#define LIBWR2RF_RFFRAME_TS           0
#define LIBWR2RF_RFFRAME_TS_NCO_RESET 1
/* Read the timestamp that is recorded for each incoming RF frame. If ts_nco_reset=1,
then the timestamp will reflect the last RF frame. TAI reflects the number of seconds
that have elapsed in the current TAI epoch and cycles is the number of WR clock cycles
(16 ns) that have elapsed within the current second. */
int libwr2rf_rfframerx_ts (struct libwr2rf_dev *dev, unsigned ts_nco_reset, uint64_t *ts_tai, uint32_t *ts_cycles);

#define LIBWR2RF_LEAPSEC 37
/* Read the current leapsecond value utilised by White Rabbit. This is the offset between
   the TAI seconds and UTC seconds, such that; utc = tai + leapsecs */
int libwr2rf_wr_leapsec (struct libwr2rf_dev *dev, uint32_t *ts_leapsec);

/* Returns timestamps of the first VTU trigger output after a start pulse and also a
   timestamp of the last trigger pulse output from the VTU. Timestamps have two components:
   tai in seconds and cycles in 8 ns*/
int libwr2rf_vtu_timestamps (struct libwr2rf_dev *dev, unsigned id,
                             uint64_t *ts_vtu_tai_first, uint32_t *ts_vtu_cycles_first,
                             uint64_t *ts_vtu_tai_last,  uint32_t *ts_vtu_cycles_last);

/* Read VTU global status, read bits are cleared.
   Returns 0 on success. */
#define LIBWR2RF_GBL_RF1T1_START (1 << 0)
#define LIBWR2RF_GBL_RF1T2_START (1 << 1)
#define LIBWR2RF_GBL_RF2T1_START (1 << 2)
#define LIBWR2RF_GBL_RF2T2_START (1 << 3)
int libwr2rf_vtu_global_status_read(struct libwr2rf_dev *dev, unsigned *res);

/* Read the fault status for vtu ID.
   Other bits are not defined.
   The register is updated at every start.
   MISSIDLE can be set even if the start is successful (if forced)
   Return 0 on success. */
#define LIBWR2RF_VTU_FAULT_MISSIDLE 0x400  /* Start while still running */
#define LIBWR2RF_VTU_FAULT_MISSVALID 0x200 /* Start while param not valid */
#define LIBWR2RF_VTU_FAULT_MISSREADY 0x100 /* Start while no RF clock */
int libwr2rf_vtu_fault_read(struct libwr2rf_dev *dev, unsigned id,
                            unsigned *fault);

/* Set flags of vtu ID. */
#define LIBWR2RF_VTU_FLAGS_FORCE_VALID_OFFLINE 0x1 /* Params always valid */
#define LIBWR2RF_VTU_FLAGS_START_AS_STOP 0x2      /* Implicit stop on start */
int libwr2rf_vtu_set_flags(struct libwr2rf_dev *dev, unsigned id,
                           unsigned flags);

#endif /* __LIBWR2RF__API__H_ */
