/**
 * @file libbladeRF.h
 *
 * @brief bladeRF library
 *
 * Copyright (C) 2013-2016 Nuand LLC
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */
#ifndef BLADERF_H_
#define BLADERF_H_

#include <stdint.h>
#include <stdlib.h>

/**
 * @ingroup FN_MISC
 *
 * libbladeRF API version
 *
 * As of libbladeRF v1.5.0, this macro is defined to assist with feature
 * detection. Generally, this will be used as follows:
 *
 * @code
 * #if defined(LIBBLADERF_API_VERSION) && (LIBBLADERF_API_VERSION >= 0x01050000)
 *      // ...  Use features added in libbladeRF v1.5.0 ...
 * #endif
 * @endcode
 *
 * This value is defined as follows:
 *      `(major << 24) | (minor << 16) | (patch << 8) | (reserved << 0)`
 *
 * The reserved field may be used at a later date to denote additions between
 * releases. It will be set to zero when not used.
 *
 * This value is intended to track the values returned by bladerf_version().
 * Fields are updated per the scheme defined here:
 *
 *  https://github.com/Nuand/bladeRF/blob/master/doc/development/versioning.md
 */
#define LIBBLADERF_API_VERSION (0x01080000)

#ifdef __cplusplus
extern "C" {
#else
/* stdbool.h is not applicable for C++ programs, as the language inherently
 * provides the bool type.
 *
 * Users of Visual Studio 2012 and earlier will need to supply a stdbool.h
 * implementation, as it is not included with the toolchain. One is provided
 * with the bladeRF source code. Visual Studio 2013 onward supplies this header.
 */
#include <stdbool.h>
#endif

#if defined _WIN32 || defined __CYGWIN__
#   include <windows.h>
#   define CALL_CONV __cdecl
#   ifdef __GNUC__
#       define API_EXPORT __attribute__ ((dllexport))
#   else
#       define API_EXPORT __declspec(dllexport)
#   endif
#elif defined _DOXYGEN_ONLY_ || defined MATLAB_LINUX_THUNK_BUILD_
    /** Marks an API routine to be made visible to the dynamic loader.
     *  This is OS and/or compiler-specific. */
#   define API_EXPORT
    /** Specifies calling convention, if necessary.
     *  This is OS and/or compiler-specific. */
#   define CALL_CONV
#else
#   define API_EXPORT __attribute__ ((visibility ("default")))
#   define CALL_CONV
#endif

/**
 * @defgroup FN_INIT    Initialization and deinitialization
 *
 * The functions in this section provide the ability query and inspect available
 * devices, initialize them, and deinitialize them.
 *
 * See the
 * <a class="el" href="boilerplate.html">Device configuration boilerplate</a>
 * page for an overview on how to open and configure a device.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/** This structure is an opaque device handle */
struct bladerf;


/**
 * Backend by which the host communicates with the device
 */
typedef enum {
    BLADERF_BACKEND_ANY,    /**< "Don't Care" -- use any available backend */
    BLADERF_BACKEND_LINUX,  /**< Linux kernel driver */
    BLADERF_BACKEND_LIBUSB, /**< libusb */
    BLADERF_BACKEND_CYPRESS, /**< CyAPI */
    BLADERF_BACKEND_DUMMY = 100, /**< Dummy used for development purposes */
} bladerf_backend;

/** Length of device serial number string, including NUL-terminator */
#define BLADERF_SERIAL_LENGTH   33

/**
 * Information about a bladeRF attached to the system
 */
struct bladerf_devinfo {
    bladerf_backend backend;    /**< Backend to use when connecting to device */
    char serial[BLADERF_SERIAL_LENGTH]; /**< Device serial number string */
    uint8_t usb_bus;            /**< Bus # device is attached to */
    uint8_t usb_addr;           /**< Device address on bus */
    unsigned int instance;      /**< Device instance or ID */
};

/**
 * Obtain a list of bladeRF devices attached to the system
 *
 * @param[out]  devices
 *
 * @return number of items in returned device list, or value from
 *         \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_device_list(struct bladerf_devinfo **devices);

/**
 * Free device list returned by bladerf_get_device_list()
 *
 * @param   devices     List of available devices
 */
API_EXPORT
void CALL_CONV bladerf_free_device_list(struct bladerf_devinfo *devices);

/**
 * Initialize a device identifier information structure to a "wildcard" state.
 * The values in each field will match any value for that field.
 *
 * Passing a bladerf_devinfo initialized with this function to
 * bladerf_open_with_devinfo() will match the first device found.
 */
API_EXPORT
void CALL_CONV bladerf_init_devinfo(struct bladerf_devinfo *info);

/**
 * Fill out a provided bladerf_devinfo structure, given an open device handle.
 *
 * @pre dev must be a valid device handle.
 *
 * @param[in]    dev     Device handle previously obtained with bladerf_open()
 * @param[out]   info    Device information populated by this function
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_devinfo(struct bladerf *dev,
                                  struct bladerf_devinfo *info);

/**
 * Populate a device identifier information structure using the provided
 * device identifier string.
 jjk*
 * @param[in]   devstr  Device identifier string, formated as described
 *                      in the bladerf_open() documentation
 *
 * @param[out]  info    Upon success, this will be filled out according to the
 *                      provided device identifier string, with wildcards for
 *                      any fields that were not provided.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_devinfo_from_str(const char *devstr,
                                           struct bladerf_devinfo *info);

/**
 * Test whether two device identifier information structures match, taking
 * wildcard values into account.
 */
API_EXPORT
bool CALL_CONV bladerf_devinfo_matches(const struct bladerf_devinfo *a,
                                       const struct bladerf_devinfo *b);

/**
 * Test whether a provided device string matches a device described by
 * the provided bladerf_devinfo structure
 *
 * @param[in]   dev_str     Devices string, formated as described in the
 *                          the documentation of bladerf_open
 *
 * @param[in]   info        Device info to compare with
 *
 * @return  true upon a match, false otherwise
 */
API_EXPORT
bool CALL_CONV bladerf_devstr_matches(const char *dev_str,
                                      struct bladerf_devinfo *info);

/**
 * Opens device specified by provided bladerf_devinfo structure
 *
 * This function is generally preferred over bladerf_open() when a device
 * identifier string is not already provided.
 *
 * The most common uses of this function are to:
 *  - Open a device based upon the results of bladerf_get_device_list()
 *  - Open a specific device based upon its serial number
 *
 * Below is an example of how to use this function to open a device with a
 * specific serial number:
 *
 * @snippet open_via_serial.c example_snippet
 *
 * @param[out]  device      Update with device handle on success
 * @param[in]   devinfo     Device specification. If NULL, any available
 *                          device will be opened.
 *
 * @return 0 on success, or value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_open_with_devinfo(struct bladerf **device,
                                        struct bladerf_devinfo *devinfo);

/**
 * Open specified device using a device identifier string. See
 * bladerf_open_with_devinfo() if a device identifier string is not readily
 * available.
 *
 * The general form of the device identifier string is;
 * @code{.txt}
 *      <backend>:[device=<bus>:<addr>] [instance=<n>] [serial=<serial>]
 * @endcode
 *
 * An empty ("") or NULL device identifier will result in the first
 * encountered device being opened (using the first discovered backend)
 *
 * The 'backend' describes the mechanism used to communicate with the device,
 * and may be one of the following:
 *   - *:       Any available backend
 *   - libusb:  libusb (See libusb changelog notes for required version, given
 *   your OS and controller)
 *   - cypress: Cypress CyUSB/CyAPI backend (Windows only)
 *
 * If no arguments are provided after the backend, the first encountered
 * device on the specified backend will be opened. Note that a backend is
 * required, if any arguments are to be provided.
 *
 * Next, any provided arguments are provide as used to find the desired device.
 * Be sure not to over constrain the search. Generally, only one of the above
 * is required -- providing all of these may over constrain the search for the
 * desired device (e.g., if a serial number matches, but not on the specified
 * bus and address.)
 *
 *   - device=\<bus\>:\<addr\>
 *      - Specifies USB bus and address. Decimal or hex prefixed by '0x' is
 *        permitted.
 *   - instance=\<n\>
 *      - Nth instance encountered, 0-indexed
 *   - serial=\<serial\>
 *      - Device's serial number.
 *
 * Below is an example of how to open a device with a specific serial
 * number, using any avaiable backend supported by libbladeRF:
 *
 * @code {.c}
 * struct bladerf *dev;
 * int status = bladerf_open(&dev, "*:serial=f12ce1037830a1b27f3ceeba1f521413");
 * if (status != 0) {
 *      fprintf(stderr, "Unable to open device: %s\n",
 *              bladerf_strerror(status));
 *      return status;
 * }
 * @endcode
 *
 * @param[out]  device             Update with device handle on success
 * @param[in]   device_identifier  Device identifier, formatted as described
 *                                 above
 *
 * @return 0 on success, or value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_open(struct bladerf **device,
                           const char *device_identifier);

/**
 * Close device
 *
 * @note    Failing to close a device will result in memory leaks.
 *
 * @post    device is deallocated and may no longer be used.
 *
 * @param   device  Device handle previously obtained by bladerf_open(). This
 *                  function does nothing if device is NULL.
 */
API_EXPORT
void CALL_CONV bladerf_close(struct bladerf *device);

/**
 * Enable or disable USB device reset operation upon opening a device for
 * future bladerf_open() and bladerf_open_with_devinfo() calls.
 *
 * This operation has been found to be necessary on Linux-based systems for
 * some USB 3.0 controllers on Linux.
 *
 * This <b>does not</b> reset the state of the device in terms of its frequency,
 * gain, samplerate, etc. settings.
 *
 * @param   enabled     Set true to enable the use of the USB device reset,
 *                      and false otherwise.
 */
API_EXPORT
void CALL_CONV bladerf_set_usb_reset_on_open(bool enabled);

/** @} (End FN_INIT) */

/**
 * @defgroup FN_INFO    Device properties and information
 *
 * These functions provide the ability to query various pieces of information
 * from an attached device.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/**
 * Version structure for FPGA, firmware, libbladeRF, and associated utilities
 */
struct bladerf_version {
    uint16_t major;             /**< Major version */
    uint16_t minor;             /**< Minor version */
    uint16_t patch;             /**< Patch version */
    const char *describe;       /**< Version string with any additional suffix
                                 *   information.
                                 *
                                 *   @warning Do not attempt to modify or
                                 *            free() this string. */
};

/**
 * FPGA device variant (size)
 */
typedef enum {
    BLADERF_FPGA_UNKNOWN = 0,   /**< Unable to determine FPGA variant */
    BLADERF_FPGA_40KLE = 40,    /**< 40 kLE FPGA */
    BLADERF_FPGA_115KLE = 115   /**< 115 kLE FPGA */
} bladerf_fpga_size;

/**
 * This enum describes the USB Speed at which the bladeRF is connected.
 * Speeds not listed here are not supported.
 */
typedef enum {
    BLADERF_DEVICE_SPEED_UNKNOWN,
    BLADERF_DEVICE_SPEED_HIGH,
    BLADERF_DEVICE_SPEED_SUPER,
} bladerf_dev_speed;

/**
 * Query a device's serial number
 *
 * @param[in]   dev     Device handle
 * @param[out]  serial  This user-supplied buffer, which <b>must be at least
 *                      ::BLADERF_SERIAL_LENGTH bytes</b>, will be updated to
 *                      contain a NUL-terminated serial number string. If an
 *                      error occurs (as indicated by a non-zero return value),
 *                      no data will be written to this pointer.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_serial(struct bladerf *dev, char *serial);

/**
 * Query a device's VCTCXO calibration trim
 *
 * @param[in]   dev     Device handle
 * @param[out]  trim    Will be updated with the factory DAC trim value. If an
 *                      error occurs, no data will be written to this pointer.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_vctcxo_trim(struct bladerf *dev, uint16_t *trim);

/**
 * Query a device's FPGA size
 *
 * @param[in]   dev     Device handle
 * @param[out]  size    Will be updated with the on-board FPGA's size. If an
 *                      error occurs, no data will be written to this pointer.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_fpga_size(struct bladerf *dev,
                                    bladerf_fpga_size *size);

/**
 * Query firmware version
 *
 * @param[in]   dev         Device handle
 * @param[out]  version     Updated to contain firmware version
 *
 * @return 0 on success, value from \ref RETCODES list upon failing to retrieve
 *         this information from the device.
 */
API_EXPORT
int CALL_CONV bladerf_fw_version(struct bladerf *dev,
                                 struct bladerf_version *version);

/**
 * Check FPGA configuration status
 *
 * @param   dev     Device handle
 *
 * @return  1 if FPGA is configured,
 *          0 if it is not,
 *          and value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_is_fpga_configured(struct bladerf *dev);

/**
 * Query FPGA version
 *
 * @param[in]   dev         Device handle
 * @param[out]  version     Updated to contain firmware version
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_fpga_version(struct bladerf *dev,
                                   struct bladerf_version *version);

/**
 * Obtain the bus speed at which the device is operating
 *
 * @param       dev     Device handle
 * @return      speed   Device speed
 */
API_EXPORT
bladerf_dev_speed CALL_CONV bladerf_device_speed(struct bladerf *dev);

/** @} (End FN_INFO) */



/**
 * @defgroup FN_MODULE RX & TX module control
 *
 * The RX and TX modules are independently configurable. As such,
 * many libbladeRF functions require a ::bladerf_module parameter
 * to specify which module to operate on.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/**
 * Module selection for those which have both RX and TX constituents
 */
typedef enum
{
    BLADERF_MODULE_INVALID = -1,    /**< Invalid module entry */
    BLADERF_MODULE_RX,              /**< Receive Module */
    BLADERF_MODULE_TX               /**< Transmit Module */
} bladerf_module;


/**
 * Enable or disable the specified RX/TX module.
 *
 * RX and TX modules must always be enabled prior to streaming samples
 * on the associated interface.
 *
 * When a synchronous stream is associated with the specified module, this
 * will shut down the underlying asynchronous stream when `enable` = false.
 *
 * When transmitting samples, be sure to provide ample time for TX samples reach
 * the RF front-end before calling this function with `enable` = false. (This
 * can be achieved easily when using metadata, as shown on
 * <a class="el" href="sync_tx_meta_bursts.html">this page</a>.)
 *
 * @param       dev     Device handle
 * @param       m       Device module
 * @param       enable  true to enable, false to disable
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_enable_module(struct bladerf *dev,
                                    bladerf_module m, bool enable);

/** @} (End of FN_MODULE) */

/**
 * @defgroup FN_GAIN    Gain control
 *
 * These functions provide control over the device's RX and TX gain stages.
 *
 * In general, the gains should be incremented in the following order
 * (and decremented in the reverse order).
 *
 * <b>TX:</b> `TXVGA1`, `TXVGA2`
 *
 * <b>RX:</b> `LNA`, `RXVGA`, `RXVGA2`
 *
 * These functions are thread-safe.
 *
 * @{
 */

/** Minimum RXVGA1 gain, in dB */
#define BLADERF_RXVGA1_GAIN_MIN     5

/** Maximum RXVGA1 gain, in dB */
#define BLADERF_RXVGA1_GAIN_MAX     30

/** Minimum RXVGA2 gain, in dB */
#define BLADERF_RXVGA2_GAIN_MIN     0

/** Maximum RXVGA2 gain, in dB */
#define BLADERF_RXVGA2_GAIN_MAX     30

/** Minimum TXVGA1 gain, in dB */
#define BLADERF_TXVGA1_GAIN_MIN     (-35)

/** Maximum TXVGA1 gain, in dB */
#define BLADERF_TXVGA1_GAIN_MAX     (-4)

/** Minimum TXVGA2 gain, in dB */
#define BLADERF_TXVGA2_GAIN_MIN     0

/** Maximum TXVGA2 gain, in dB */
#define BLADERF_TXVGA2_GAIN_MAX     25

/**
 * LNA gain options
 */
typedef enum {
    BLADERF_LNA_GAIN_UNKNOWN,    /**< Invalid LNA gain */
    BLADERF_LNA_GAIN_BYPASS,     /**< LNA bypassed - 0dB gain */
    BLADERF_LNA_GAIN_MID,        /**< LNA Mid Gain (MAX-6dB) */
    BLADERF_LNA_GAIN_MAX         /**< LNA Max Gain */
} bladerf_lna_gain;

#define BLADERF_LNA_GAIN_MID_DB    3 /**< Gain in dB of the LNA at mid setting */
#define BLADERF_LNA_GAIN_MAX_DB    6 /**< Gain in db of the LNA at max setting */

/**
 * Set the PA gain in dB
 *
 * Values outside the range of
 * [ \ref BLADERF_TXVGA2_GAIN_MIN, \ref BLADERF_TXVGA2_GAIN_MAX ]
 * will be clamped.
 *
 * @param       dev         Device handle
 * @param       gain        Desired gain
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_txvga2(struct bladerf *dev, int gain);

/**
 * Get the PA gain in dB
 *
 * @param       dev         Device handle
 * @param       gain        Pointer to returned gain
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT int
CALL_CONV bladerf_get_txvga2(struct bladerf *dev, int *gain);

/**
 * Set the post-LPF gain in dB
 *
 * Values outside the range of
 * [ \ref BLADERF_TXVGA1_GAIN_MIN, \ref BLADERF_TXVGA1_GAIN_MAX ]
 * will be clamped.
 *
 * @param       dev         Device handle
 * @param       gain        Desired gain
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_txvga1(struct bladerf *dev, int gain);

/**
 * Get the post-LPF gain in dB
 *
 * @param       dev         Device handle
 * @param       gain        Pointer to returned gain
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_txvga1(struct bladerf *dev, int *gain);

/**
 * Set the LNA gain
 *
 * @param       dev         Device handle
 * @param       gain        Desired gain level
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_lna_gain(struct bladerf *dev, bladerf_lna_gain gain);

/**
 * Get the LNA gain
 *
 * @param       dev         Device handle
 * @param       gain        Pointer to the set gain level
 */
API_EXPORT
int CALL_CONV bladerf_get_lna_gain(struct bladerf *dev, bladerf_lna_gain *gain);

/**
 * Set the pre-LPF VGA gain
 *
 * Values outside the range of
 * [ \ref BLADERF_RXVGA1_GAIN_MIN, \ref BLADERF_RXVGA1_GAIN_MAX ]
 * will be clamped.
 *
 * @param       dev         Device handle
 * @param       gain        Desired gain
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_rxvga1(struct bladerf *dev, int gain);

/**
 * Get the pre-LPF VGA gain
 *
 * @param       dev         Device handle
 * @param       gain        Pointer to the set gain level
 */
API_EXPORT
int CALL_CONV bladerf_get_rxvga1(struct bladerf *dev, int *gain);

/**
 * Set the post-LPF VGA gain
 *
 * Values outside the range of
 * [ \ref BLADERF_RXVGA2_GAIN_MIN, \ref BLADERF_RXVGA2_GAIN_MAX ]
 * will be clamped.
 *
 * @param       dev         Device handle
 * @param       gain        Desired gain
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_rxvga2(struct bladerf *dev, int gain);

/**
 * Get the post-LPF VGA gain
 *
 * @param       dev         Device handle
 * @param       gain        Pointer to the set gain level
 */
API_EXPORT
int CALL_CONV bladerf_get_rxvga2(struct bladerf *dev, int *gain);

/**
 * Set combined gain values
 *
 * This function computes the optimal LNA, RXVGA1, and RVGA2 gains for a
 * requested amount of RX gain, and computes the optimal TXVGA1 and TXVGA2 gains
 * for a requested amount of TX gain.
 *
 * Values outside the valid gain range will be clipped.
 *
 * @param       dev         Device handle
 * @param       mod         Module
 * @param       gain        Desired gain
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_gain(struct bladerf *dev, bladerf_module mod, int gain);

/**
 * Gain control modes
 */
typedef enum  {
    BLADERF_GAIN_AUTOMATIC,      /**< Device-specific default */
    BLADERF_GAIN_MANUAL          /**< Manual gain control */
} bladerf_gain_mode;

/**
 * Set gain mode
 *
 * Sets the mode for hardware AGC in the case of RX
 *
 * @param       dev         Device handle
 * @param       mod         Module
 * @param       mode        Desired gain mode
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_gain_mode(struct bladerf *dev, bladerf_module mod,
                                    bladerf_gain_mode mode);

/**
 * Get gain mode
 *
 * Gets the current mode for hardware AGC in the case of RX
 *
 * @param       dev         Device handle
 * @param       mod         Module
 * @param       mode        Gain mode
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_gain_mode(struct bladerf *dev, bladerf_module mod,
                                    bladerf_gain_mode *mode);


/** @} (End of FN_GAIN) */

/**
 * @defgroup FN_SAMPLING Sampling control
 *
 * This section presents functionality pertaining to configuring the
 * sample rate and mode of the device's RX and TX modules.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/** Minimum sample rate, in Hz */
#define BLADERF_SAMPLERATE_MIN      80000u

/**
 * Maximum recommended sample rate, in Hz.
 *
 * The max sample rate of the LMS6002D is 40 MHz, but this API allows for larger
 * values to allow users to leverage FPGA customizations (e.g., to generate
 * test samples or mux other data into the sample stream).
 *
 * If you are not performing such customizations, treat this as the max allowed
 * values.
 */
#define BLADERF_SAMPLERATE_REC_MAX  40000000u

/**
 * RX Mux modes
 *
 * These values describe the source of samples to the RX FIFOs in the FPGA.
 * They map directly to rx_mux_mode_t inside the FPGA's source code.
 */
typedef enum {
    /**
     * Invalid RX Mux mode selection
     */
    BLADERF_RX_MUX_INVALID = -1,

    /**
     * Read baseband samples from the LMS6002D. This is the default mode
     * of operation.
     */
    BLADERF_RX_MUX_BASEBAND_LMS  = 0x0,

    /**
     * Read samples from 12 bit counters.
     *
     * The I channel counts up while the Q channel counts down.
     */
    BLADERF_RX_MUX_12BIT_COUNTER = 0x1,

    /**
     * Read samples from a 32 bit up-counter.
     *
     * I and Q form a little-endian value.
     */
    BLADERF_RX_MUX_32BIT_COUNTER = 0x2,

    /* RX_MUX setting 0x3 is reserved for future use */

    /**
     * Read samples from the baseband TX input to the FPGA (from the host)
     */
    BLADERF_RX_MUX_DIGITAL_LOOPBACK = 0x4,

} bladerf_rx_mux;

/**
 * Rational sample rate representation
 */
struct bladerf_rational_rate {
    uint64_t integer;           /**< Integer portion */
    uint64_t num;               /**< Numerator in fractional portion */
    uint64_t den;               /**< Denominator in fractional portion. This
                                     must be > 0. */
};

/**
 * Sampling connection
 */
typedef enum {
    BLADERF_SAMPLING_UNKNOWN,  /**< Unable to determine connection type */
    BLADERF_SAMPLING_INTERNAL, /**< Sample from RX/TX connector */
    BLADERF_SAMPLING_EXTERNAL  /**< Sample from J60 or J61 */
} bladerf_sampling;

/**
 * Configure the device's sample rate, in Hz.  Note this requires the sample
 * rate is an integer value of Hz.  Use bladerf_set_rational_sample_rate()
 * for more arbitrary values.
 *
 * The sample rate must be greater than or equal to \ref BLADERF_SAMPLERATE_MIN.
 * Values above \ref BLADERF_SAMPLERATE_REC_MAX are allowed, but not
 * recommended. Setting the sample rates higher than recommended max may yield
 * errors and unexpected results.
 *
 * @param[in]   dev         Device handle
 * @param[in]   module      Module to change
 * @param[in]   rate        Sample rate
 * @param[out]  actual      If non-NULL. this is written with the actual
 *                          sample rate achieved.
 *
 * @return 0 on success,
 *         BLADERF_ERR_INVAL for an invalid sample rate,
 *         or a value from \ref RETCODES list on other failures
 */
API_EXPORT
int CALL_CONV bladerf_set_sample_rate(struct bladerf *dev,
                                      bladerf_module module,
                                      unsigned int rate,
                                      unsigned int *actual);

/**
 * Configure the device's sample rate as a rational fraction of Hz.
 * Sample rates are in the form of integer + num/denom.
 *
 * @param[in]   dev         Device handle
 * @param[in]   module      Module to change
 * @param[in]   rate        Rational sample rate
 * @param[out]  actual      If non-NULL, this is written with the actual
 *                          rational sample rate achieved.
 *
 * The sample rate must be greater than or equal to \ref BLADERF_SAMPLERATE_MIN.
 * Values above \ref BLADERF_SAMPLERATE_REC_MAX are allowed, but not
 * recommended. Setting the sample rates higher than recommended max may yield
 * errors and unexpected results.
 *
 * @return 0 on success,
 *         BLADERF_ERR_INVAL for an invalid sample rate,
 *         or a value from \ref RETCODES list on other failures
 */
API_EXPORT
int CALL_CONV bladerf_set_rational_sample_rate(
                                        struct bladerf *dev,
                                        bladerf_module module,
                                        struct bladerf_rational_rate *rate,
                                        struct bladerf_rational_rate *actual);
/**
 * Read the device's sample rate in Hz
 *
 * @param[in]   dev         Device handle
 * @param[in]   module      Module to query
 * @param[out]  rate        Pointer to returned sample rate
 *
 * @return 0 on success, value from \ref RETCODES list upon failure
 */
API_EXPORT
int CALL_CONV bladerf_get_sample_rate(struct bladerf *dev,
                                      bladerf_module module,
                                      unsigned int *rate);

/**
 * Read the device's sample rate in rational Hz
 *
 * @param[in]   dev         Device handle
 * @param[in]   module      Module to query
 * @param[out]  rate        Pointer to returned rational sample rate
 *
 * @return 0 on success, value from \ref RETCODES list upon failure
 */
API_EXPORT
int CALL_CONV bladerf_get_rational_sample_rate(
                                        struct bladerf *dev,
                                        bladerf_module module,
                                        struct bladerf_rational_rate *rate);

/**
 * Configure the sampling of the LMS6002D to be either internal or
 * external.  Internal sampling will read from the RXVGA2 driver internal
 * to the chip.  External sampling will connect the ADC inputs to the
 * external inputs for direct sampling.
 *
 * @param[in]   dev         Device handle
 * @param[in]   sampling    Sampling connection
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_sampling(struct bladerf *dev,
                                   bladerf_sampling sampling);

/**
 * Set the current RX Mux mode
 *
 * @param       dev     Device handle
 * @param       mux     Mux mode.
 *
 * @returns 0 on success, value from \ref RETCODES list on failure.
 */
API_EXPORT
int CALL_CONV bladerf_set_rx_mux(struct bladerf *dev, bladerf_rx_mux mux);


/**
 * Gets the current RX Mux mode
 *
 * @param[in]   dev     Device handle
 * @param[out]  mode    Current RX Mux mode
 *
 * @returns 0 on success, value from \ref RETCODES list on failure.
 */
API_EXPORT
int CALL_CONV bladerf_get_rx_mux(struct bladerf *dev, bladerf_rx_mux *mode);

/**
 * Read the device's current state of RXVGA2 and ADC pin connection
 * to figure out which sampling mode it is currently configured in.
 *
 * @param[in]   dev         Device handle
 * @param[out]  sampling    Sampling connection
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_sampling(struct bladerf *dev,
                                   bladerf_sampling *sampling);

/** @} (End of FN_SAMPLING) */

/**
 * @defgroup FN_BANDWIDTH Bandwidth configuration
 *
 * This section defines functionality for configuring the device's
 * LPF bandwidth. In most cases, one should define the bandwidth to
 * be less than the sample rate to minimize the impact of aliases.
 *
 * To determine the required bandwidth setting for a desired sample rate
 * (or vice versa), review the TX/RX LPF amplitude response plots in
 * the LMS6002D datasheet. (This was Figure 6 as of datasheet v1.2r0.)
 *
 * These functions are thread-safe.
 *
 * @{
 */

/** Minimum bandwidth, in Hz */
#define BLADERF_BANDWIDTH_MIN       1500000u

/** Maximum bandwidth, in Hz */
#define BLADERF_BANDWIDTH_MAX       28000000u

/**
 * Low-Pass Filter (LPF) mode
 */
typedef enum {
    BLADERF_LPF_NORMAL,     /**< LPF connected and enabled */
    BLADERF_LPF_BYPASSED,   /**< LPF bypassed */
    BLADERF_LPF_DISABLED    /**< LPF disabled */
} bladerf_lpf_mode;

/**
 * Set the bandwidth of the LMS LPF to specified value in Hz
 *
 * The underlying device is capable of a discrete set of bandwidth values. The
 * caller should check the `actual` parameter to determine which of these
 * discrete bandwidth values is actually used for the requested bandwidth.
 *
 * Values outside the range of
 * [ \ref BLADERF_BANDWIDTH_MIN, \ref BLADERF_BANDWIDTH_MAX ]
 * will be clamped.
 *
 * @param[in]   dev                 Device handle
 * @param[in]   module              Module for bandwidth request
 * @param[in]   bandwidth           Desired bandwidth
 * @param[out]  actual              If non-NULL, written with the actual
 *                                  bandwidth that the device was able to
 *                                  achieve.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_bandwidth(struct bladerf *dev, bladerf_module module,
                                    unsigned int bandwidth,
                                    unsigned int *actual);

/**
 * Get the bandwidth of the LMS LPF
 *
 * @param       dev                 Device Handle
 * @param       module              Module for bandwidth request
 * @param       bandwidth           Actual bandwidth in Hz
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_bandwidth(struct bladerf *dev, bladerf_module module,
                                    unsigned int *bandwidth);

/**
 * Set the LMS LPF mode to bypass or disable it
 *
 * @param       dev         Device handle
 * @param       module      Module for mode request
 * @param       mode        Mode to be set
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_lpf_mode(struct bladerf *dev, bladerf_module module,
                                   bladerf_lpf_mode mode);

/**
 * Get the current mode of the LMS LPF
 *
 * @param       dev         Device handle
 * @param       module      Module for mode request
 * @param       mode        Current mode of the LPF
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_lpf_mode(struct bladerf *dev, bladerf_module module,
                                   bladerf_lpf_mode *mode);


/** @} (End of FN_BANDWIDTH) */

/**
 * @defgroup FN_TUNING  Frequency tuning
 *
 * These functions provide the ability to tune the RX and TX modules.
 *
 * See <a class="el" href="tuning.html">this page</a> for more detailed
 * information about how the API performs this tuning, and for example
 * code snippets.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/**
 * Minimum tunable frequency (with an XB-200 attached), in HZ.
 *
 * While this value is the lowest permitted, note that the components on the
 * XB-200 are only rated down to 50 MHz. Be aware that performance will likely
 * degrade as you tune to lower frequencies.
 */
#define BLADERF_FREQUENCY_MIN_XB200 0u

/** Minimum tunable frequency (without an XB-200 attached), in Hz */
#define BLADERF_FREQUENCY_MIN       237500000u

/** Maximum tunable frequency, in Hz */
#define BLADERF_FREQUENCY_MAX       3800000000u

/**
 * Specifies that scheduled retune should occur immediately when using
 * bladerf_schedule_retune().
 */
#define BLADERF_RETUNE_NOW  0

/**
 * Frequency tuning modes
 *
 * BLADERF_TUNING_MODE_HOST is the default if either of the following conditions
 * are true:
 *   - libbladeRF < v1.3.0
 *   - FPGA       < v0.2.0
 *
 * BLADERF_TUNING_MODE_FPGA is the default if both of the following conditions
 * are true:
 *  - libbladeRF >= v1.3.0
 *  - FPGA       >= v0.2.0
 *
 * The default mode can be overridden by setting a BLADERF_DEFAULT_TUNING_MODE
 * environment variable to "host" or "fpga". Overriding this value with a mode
 * not supported by the FPGA will result in failures or unexpected behavior.
 */
typedef enum {
    /** Indicates an invalid mode is set */
    BLADERF_TUNING_MODE_INVALID = -1,

    /**
     * Perform tuning algorithm on the host. This is slower, but provides
     * easier accessiblity to diagnostic information.
     */
    BLADERF_TUNING_MODE_HOST,

    /**
     * Perform tuning algorithm on the FPGA for faster tuning.
     *
     */
    BLADERF_TUNING_MODE_FPGA,
} bladerf_tuning_mode;

/**
 * Quick Re-tune parameters. Note that these parameters, which are associated
 * with LMS6002D register values, are sensitive to changes in the operating
 * environment (e.g., temperature).
 *
 * This structure should be filled in via bladerf_get_quick_tune().
 */
struct bladerf_quick_tune {
    uint8_t freqsel;    /**< Choice of VCO and VCO division factor */
    uint8_t vcocap;     /**< VCOCAP value */
    uint16_t nint;      /**< Integer portion of LO frequency value */
    uint32_t nfrac;     /**< Fractional portion of LO frequency value */
    uint8_t  flags;     /**< Flag bits used internally by libbladeRF */
};

/**
 * Select the appropriate band path given a frequency in Hz.
 *
 * Most API users will not need to use this function, as bladerf_set_frequency()
 * calls this internally after tuning the device.
 *
 * The high band (LNA2 and PA2) is used for `frequency` >= 1.5 GHz. Otherwise,
 * The low band (LNA1 and PA1) is used.
 *
 * Frequency values outside the range of
 * [ \ref BLADERF_FREQUENCY_MIN, \ref BLADERF_FREQUENCY_MAX ]
 * will be clamped.
 *
 * @param       dev         Device handle
 * @param       module      Module to configure
 * @param       frequency   Tuned frequency
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_select_band(struct bladerf *dev, bladerf_module module,
                                  unsigned int frequency);

/**
 * Set module's frequency in Hz.
 *
 * Values outside the range of
 * [ \ref BLADERF_FREQUENCY_MIN, \ref BLADERF_FREQUENCY_MAX ]
 * will be clamped.
 *
 * For best results, it is recommended to keep the RX and TX frequencies at
 * least 1 MHz apart, and to digitally mix on the RX side if reception closer
 * to the TX frequency is required.
 *
 * This calls bladerf_select_band() internally.
 *
 * @param       dev         Device handle
 * @param       module      Module to configure
 * @param       frequency   Desired frequency
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_frequency(struct bladerf *dev,
                                    bladerf_module module,
                                    unsigned int frequency);

/**
 * Schedule a frequency retune to occur at specified sample timestamp value.
 *
 * @pre bladerf_sync_config() must have been called with the
 *      BLADERF_FORMAT_SC16_Q11_META format for the associated module in order
 *      to enable timestamps. (The timestamped metadata format must be enabled
 *      in order to use this function.)
 *
 * @param       dev             Device handle
 *
 * @param       module          Module to retune
 *
 * @param       timestamp       Module's sample timestamp to perform the retune
 *                              operation. If this value is in the past, the
 *                              retune will occur immediately. To perform the
 *                              retune immediately, specify BLADERF_RETUNE_NOW.
 *
 * @param       frequency       Desired frequency, in Hz.
 *
 * @param       quick_tune      If NULL, the `frequency` parameter will be used.
 *                              If non-NULL, the provided "quick retune" values
 *                              will be applied to the transceiver to tune it
 *                              according to a previous state retrieved via
 *                              bladerf_get_quick_tune().
 *
 *
 * @return 0 on success, value from \ref RETCODES list on failure. If the
 *         underlying queue of scheduled retune requests becomes full,
 *         BLADERF_ERR_QUEUE_FULL will be returned. In this case, it should be
 *         possible to schedule a retune after the timestamp of one of the
 *         earlier requests occurs.
 */
API_EXPORT
int CALL_CONV bladerf_schedule_retune(struct bladerf *dev,
                                      bladerf_module module,
                                      uint64_t timestamp,
                                      unsigned int frequency,
                                      struct bladerf_quick_tune *quick_tune);

/**
 * Cancel all pending scheduled retune operations for the specified module.
 *
 * This will be done automatically during bladerf_close() to ensure that
 * previously queued retunes do not continue to occur after closing and then
 * later re-opening a device.
 *
 * @param   dev     Device handle
 * @param   module  Module to cancel pending operations on
 *
 * @return 0 on success, value from \ref RETCODES list on failure.
 */
API_EXPORT
int CALL_CONV bladerf_cancel_scheduled_retunes(struct bladerf *dev,
                                               bladerf_module module);

/**
 * Get module's current frequency in Hz
 *
 * @param       dev         Device handle
 * @param       module      Module to configure
 * @param       frequency   Pointer to the returned frequency
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_frequency(struct bladerf *dev,
                                    bladerf_module module,
                                    unsigned int *frequency);

/**
 * Fetch parameters used to tune the transceiver to the current frequency for
 * use with bladerf_schedule_retune() to perform a "quick retune."
 *
 * This allows for a faster retune, with a potential trade off of
 * increased phase noise.  Note that these parameters are sensitive to
 * changes in the operating environment, and should be "refreshed" if planning
 * to use the "quick retune" functionality over a long period of time.
 *
 * @pre bladerf_set_frequency() or bladerf_schedule_retune() have previously
 *      been used to retune to the desired frequency.
 *
 * @param[in]   dev         Device handle
 * @param[in]   module      Module to query
 * @param[out]  quick_tune  Quick retune parameters
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_quick_tune(struct bladerf *dev,
                                     bladerf_module module,
                                     struct bladerf_quick_tune *quick_tune);

/**
 * Set the device's tuning mode
 *
 * @param       dev         Device handle
 * @param       mode        Desired tuning mode. Note that the available modes
 *                          depends on the FPGA version.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_tuning_mode(struct bladerf *dev,
                                      bladerf_tuning_mode mode);


/** @} (End of FN_TUNING) */

/**
 * @defgroup FN_LOOPBACK Internal loopback
 *
 * The bladeRF provides a variety of loopback modes to aid in development
 * and testing.
 *
 * In general, the digital or baseband loopback modes provide the most "ideal"
 * operating conditions, while the internal RF loopback modes introduce more of
 * the typical nonidealities of analog systems.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/**
 * Loopback options
 */
typedef enum {

    /**
     * Firmware loopback inside of the FX3
     */
    BLADERF_LB_FIRMWARE = 1,

    /**
     * Baseband loopback. TXLPF output is connected to the RXVGA2 input.
     */
    BLADERF_LB_BB_TXLPF_RXVGA2,

    /**
     * Baseband loopback. TXVGA1 output is connected to the RXVGA2 input.
     */
    BLADERF_LB_BB_TXVGA1_RXVGA2,

    /**
     * Baseband loopback. TXLPF output is connected to the RXLPF input.
     */
    BLADERF_LB_BB_TXLPF_RXLPF,

    /**
     * Baseband loopback. TXVGA1 output is connected to RXLPF input.
     */
    BLADERF_LB_BB_TXVGA1_RXLPF,

    /**
     * RF loopback. The TXMIX output, through the AUX PA, is connected to the
     * output of LNA1.
     */
    BLADERF_LB_RF_LNA1,


    /**
     * RF loopback. The TXMIX output, through the AUX PA, is connected to the
     * output of LNA2.
     */
    BLADERF_LB_RF_LNA2,

    /**
     * RF loopback. The TXMIX output, through the AUX PA, is connected to the
     * output of LNA3.
     */
    BLADERF_LB_RF_LNA3,

    /**
     * Disables loopback and returns to normal operation.
     */
    BLADERF_LB_NONE

} bladerf_loopback;

/**
 * Apply specified loopback mode
 *
 * @param       dev     Device handle
 * @param       l       Loopback mode. Note that BLADERF_LB_NONE disables the
 *                      use of loopback functionality.
 *
 * @note Loopback modes should only be enabled or disabled while the RX and TX
 *       modules are both disabled (and therefore, when no samples are being
 *       actively streamed). Otherwise, unexpected behavior may occur.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_loopback(struct bladerf *dev, bladerf_loopback l);


/**
 * Get current loopback mode
 *
 * @param[in]   dev     Device handle
 * @param[out]  l       Current loopback mode
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_loopback(struct bladerf *dev, bladerf_loopback *l);

/** @} (End of FN_LOOPBACK) */

/**
 * @defgroup FN_SMB_CLOCK SMB clock port control
 *
 * The SMB clock port (J62) may be used to synchronize sampling on multiple
 * devices, or to generate an arbitrary clock output for a different device.
 *
 * For MIMO configurations, one device is the clock "master" and outputs
 * its 38.4 MHz reference on this port.  The clock "slave" devices configure
 * the SMB port as an input and expect to see this 38.4 MHz reference on this
 * port. This implies that the "master" must be configured first.
 *
 * Alternatively, this port may be used to generate an arbitrary clock signal
 * for use with other devices via the bladerf_set_smb_frequency() and
 * bladerf_set_rational_smb_frequency() functions.
 *
 * @warning <b>Do not</b> use these functions when operating an expansion board.
 *          A different clock configuration is required for the XB devices
 *          which cannot be used simultaneously with the SMB clock port.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/**
 * Maximum output frequency on SMB connector, if no expansion board attached.
 */
#define BLADERF_SMB_FREQUENCY_MAX   200000000u

/**
 * Minimum output frequency on SMB connector, if no expansion board attached.
 */
#define BLADERF_SMB_FREQUENCY_MIN   ((38400000u * 66u) / (32 * 567))


/**
 * SMB clock port mode of operation
 */
typedef enum {
    BLADERF_SMB_MODE_INVALID = -1,  /**< Invalid selection */

    BLADERF_SMB_MODE_DISABLED,      /**< Not in use. Device operates from
                                     *   its onboard clock and does not
                                     *   use J62. */

    BLADERF_SMB_MODE_OUTPUT,        /**< Device outputs a 38.4 MHz reference
                                     *   clock on J62. This may be used to
                                     *   drive another device that is
                                     *   configured with
                                     *   ::BLADERF_SMB_MODE_INPUT.
                                     */

    BLADERF_SMB_MODE_INPUT,         /**< Device configures J62 as an input
                                     *   and expects a 38.4 MHz reference
                                     *   to be available when this setting
                                     *   is applied.
                                     */

    BLADERF_SMB_MODE_UNAVAILBLE,    /**< SMB port is unavailable for use due
                                     *   the underlying clock being used
                                     *   elsewhere (e.g., for and expansion
                                     *   board).
                                     */

} bladerf_smb_mode;

/**
 * Set the current mode of operation of the SMB clock port
 *
 * In a MIMO configuration, one "master" device should first be configured to
 * output its reference clock to the slave devices via
 * `bladerf_set_smb_mode(dev, BLADERF_SMB_MODE_OUTPUT)`.
 *
 * Next, all "slave" devices should be configured to use the reference clock
 * provided on the SMB clock port (instead of using their on-board reference)
 * via `bladerf_set_smb_mode(dev, BLADERF_SMB_MODE_INPUT)`.
 *
 * @param[in]   dev         Device handle
 * @param[in]   mode        Desired mode
 *
 * @return 0 on success, or a value from \ref RETCODES list on failure.
 */
API_EXPORT
int CALL_CONV bladerf_set_smb_mode(struct bladerf *dev, bladerf_smb_mode mode);

/**
 * Get the current mode of operation of the SMB clock port
 *
 * @param[in]   dev         Device handle
 * @param[out]  mode        Desired mode
 *
 * @return 0 on success, or a value from \ref RETCODES list on failure.
 */
API_EXPORT
int CALL_CONV bladerf_get_smb_mode(struct bladerf *dev, bladerf_smb_mode *mode);

/**
 * Set the SMB clock port frequency in rational Hz
 *
 * @param[in]   dev         Device handle
 * @param[in]   rate        Rational frequency
 * @param[out]  actual      If non-NULL, this is written with the actual
 *
 * The frequency must be between \ref BLADERF_SMB_FREQUENCY_MIN and
 * \ref BLADERF_SMB_FREQUENCY_MAX.
 *
 * This function inherently configures the SMB clock port as an output. Do not
 * call bladerf_set_smb_mode() with ::BLADERF_SMB_MODE_OUTPUT, as this will
 * reset the output frequency to the 38.4 MHz reference.
 *
 * @warning This clock should not be set if an expansion board is connected.
 *
 * @return 0 on success,
 *         BLADERF_ERR_INVAL for an invalid frequency,
 *         or a value from \ref RETCODES list on failure.
 */
API_EXPORT
int CALL_CONV bladerf_set_rational_smb_frequency(
                                        struct bladerf *dev,
                                        struct bladerf_rational_rate *rate,
                                        struct bladerf_rational_rate *actual);

/**
 * Set the SMB connector output frequency in Hz.
 * Use bladerf_set_rational_smb_frequency() for more arbitrary values.
 *
 * @param[in]   dev         Device handle
 * @param[in]   rate        Frequency
 * @param[out]  actual      If non-NULL. this is written with the actual
 *                          frequency achieved.
 *
 * This function inherently configures the SMB clock port as an output. Do not
 * call bladerf_set_smb_mode() with ::BLADERF_SMB_MODE_OUTPUT, as this will
 * reset the output frequency to the 38.4 MHz reference.
 *
 * The frequency must be between \ref BLADERF_SMB_FREQUENCY_MIN and
 * \ref BLADERF_SMB_FREQUENCY_MAX.
 *
 * @warning This clock should not be set if an expansion board is connected.
 *
 * @return 0 on success,
 *         BLADERF_ERR_INVAL for an invalid frequency,
 *         or a value from \ref RETCODES list on other failures
 */
API_EXPORT
int CALL_CONV bladerf_set_smb_frequency(struct bladerf *dev,
                                        uint32_t rate, uint32_t *actual);

/**
 * Read the SMB connector output frequency in rational Hz
 *
 * @param[in]   dev         Device handle
 * @param[out]  rate        Pointer to returned rational frequency
 *
 * @return 0 on success, value from \ref RETCODES list upon failure
 */
API_EXPORT
int CALL_CONV bladerf_get_rational_smb_frequency(
                                        struct bladerf *dev,
                                        struct bladerf_rational_rate *rate);

/**
 * Read the SMB connector output frequency in Hz
 *
 * @param[in]   dev         Device handle
 * @param[out]  rate        Pointer to returned frequency
 *
 * @return 0 on success, value from \ref RETCODES list upon failure
 */
API_EXPORT
int CALL_CONV bladerf_get_smb_frequency(struct bladerf *dev,
                                        unsigned int *rate);

/** @} (End of FN_SMB_CLOCK) */

/**
 * @defgroup FN_TRIG   Triggers and synchronization
 *
 * Trigger functionality introduced in bladeRF FPGA v0.6.0 allows TX and/or RX
 * samples to be gated via a trigger signal. This allows multiple devices to
 * synchronize their TX/RX operations upon the reception of a trigger event.
 *
 * The set of functions presented in this section of the API provides control
 * over this triggering functionality. It is intended that these functions be
 * used <b>prior</b> to starting sample streams. Attempting to use these
 * functions while streaming may yield undefined and undesirable behavior.
 * These functions are thread-safe.
 *
 * For devices running at the same sample rate, the trigger event should
 * achieve synchronization within +/- 1 sample on each device in the chain.
 *
 *
 * As of FPGA v0.6.0, J71 pin 4 (mini_exp_1) has been allocated as the
 * trigger signal. However, this API section is designed to allow future
 * signals to be added, including users' software and hardware customizations.
 *
 * @note <b>Important</b>: Ensure that you disarm triggers <b>before</b>
 * stopping sample streams (i.e., calling bladerf_enable_module()
 * with `enable = false`).  Otherwise, the operation of shutting down streams
 * will block for the entire duration of the stream timeout (or infinitely if
 * the timeouts were set to 0).
 *
 *
 * The standard usage of these functions is shown below. This example
 * assumes:
 *
 *  - The two devices are connected such they share a common ground and their
 *      J71-4 pins are connected.
 *
 *  - Both devices are already configured to utilize a common clock signal via
 *      the external SMB connection.  Generally, this will consist of one device
 *      to outputting its reference clock via the SMB clock port, and
 *      configuring the other device(s) to use the SMB clock port as a reference
 *      clock input. This may be achieved using the bladerf_set_smb_mode()
 *      function, found in the \ref FN_SMB_CLOCK section.
 *
 *
 * @code{.c}
 *
 * int status;
 * bladerf_module module = BLADERF_MODULE_RX;
 * bladerf_trigger_signal = BLADERF_TRIGGER_J71_4;
 *
 * // Allocate and initialize a bladerf_trigger structure for each
 * // trigger in the system.
 * struct bladerf_trigger trig_master, trig_slave;
 *
 * status = bladerf_trigger_init(dev_master, module, signal, &trig_master);
 * if (status == 0) {
 *     trig_master.role = BLADERF_TRIGGER_ROLE_MASTER;
 * } else {
 *     goto handle_error;
 * }
 *
 * status = bladerf_trigger_init(dev_slave1, module, signal, &trig_slave);
 * if (status == 0) {
 *     master_rx.role = BLADERF_TRIGGER_ROLE_SLAVE;
 * } else {
 *     goto handle_error;
 * }
 *
 * // Arm the triggering functionality on each device
 * status = bladerf_trigger_arm(dev_master, &trig_master, true, 0, 0);
 * if (status != 0) {
 *     goto handle_error;
 * }
 *
 * status = bladerf_trigger_arm(dev_slave, &trig_slave, true, 0, 0);
 * if (status != 0) {
 *     goto handle_error;
 * }
 *
 * // Call bladerf_sync_config() and bladerf_sync_rx() on each device.
 * // Ensure the timeout parameters used are long enough to accommodate
 * // the expected time until the trigger will be fired.
 * status = start_rx_streams(dev_master, dev_slave);
 * if (status != 0) {
 *     goto handle_error;
 * }
 *
 * // Fire the trigger signal
 * status = bladerf_trigger_fire(dev_master, &trig_master);
 * if (status != 0) {
 *     goto handle_error;
 * }
 *
 * // Handle RX signals and then shut down streams.
 * // Synchronized samples should now be reaching the host following the
 * // reception of the external trigger signal.
 * status = handle_rx_operations(dev_master, dev_slave);
 * if (status != 0) {
 *     goto handle_error;
 * }
 *
 * // Disable triggering on all devices to restore normal RX operation
 * trig_master.role = BLADERF_TRIGGER_ROLE_DISABLED;
 * status = bladerf_trigger_arm(dev_master, &trig_master, false, 0, 0);
 * if (status != 0) {
 *     goto handle_error;
 * }
 *
 * trig_slave.role  = BLADERF_TRIGGER_ROLE_DISABLED;
 * status = bladerf_trigger_arm(dev_master, &trig_slave, false, 0, 0);
 * if (status != 0) {
 *     goto handle_error;
 * }
 *
 * @endcode
 *
 * @{
 */

/**
 * This value denotes the role of a device in a trigger chain.
 */
typedef enum  {
    BLADERF_TRIGGER_ROLE_INVALID = -1,  /**< Invalid role selection */

    BLADERF_TRIGGER_ROLE_DISABLED,      /**< Triggering functionality is
                                         *   disabled on this device. Samples
                                         *   are not gated and the trigger
                                         *   signal is an input.
                                         */

    BLADERF_TRIGGER_ROLE_MASTER,        /**< This device is the trigger master.
                                         *   Its trigger signal will be an
                                         *   output and this device will
                                         *   determine when all devices shall
                                         *   trigger.
                                         */

    BLADERF_TRIGGER_ROLE_SLAVE,         /**< This device is the trigger slave.
                                         *   This device's trigger signal will
                                         *   be an input and this devices will
                                         *   wait for the master's trigger
                                         *   signal assertion.
                                         */
} bladerf_trigger_role;

/**
 * Trigger signal selection
 *
 * This selects pin or signal used for the trigger.
 *
 * ::BLADERF_TRIGGER_J71_4 is the only valid option as of FPGA v0.6.0.
 *
 * The BLADERF_TRIGGER_USER_* values have been added to allow users to modify
 * both hardware and software implementations to add custom triggers, while
 * maintaining libbladeRF API compatibility. Official bladeRF releases will
 * not utilize these user signal IDs.
 */
typedef enum  {
    BLADERF_TRIGGER_INVALID = -1, /**< Invalid selection */
    BLADERF_TRIGGER_J71_4,        /**< J71 pin 4 (mini_exp_1) */

    BLADERF_TRIGGER_USER_0 = 128, /**< Reserved for user SW/HW customizations */
    BLADERF_TRIGGER_USER_1,       /**< Reserved for user SW/HW customizations */
    BLADERF_TRIGGER_USER_2,       /**< Reserved for user SW/HW customizations */
    BLADERF_TRIGGER_USER_3,       /**< Reserved for user SW/HW customizations */
    BLADERF_TRIGGER_USER_4,       /**< Reserved for user SW/HW customizations */
    BLADERF_TRIGGER_USER_5,       /**< Reserved for user SW/HW customizations */
    BLADERF_TRIGGER_USER_6,       /**< Reserved for user SW/HW customizations */
    BLADERF_TRIGGER_USER_7,       /**< Reserved for user SW/HW customizations */
} bladerf_trigger_signal;

/**
 * Trigger configuration
 *
 * It is <b>highly recommended</b> to keep a 1:1 relationship between triggers
 * in the physical setup and instances of this structure. (i.e., do not
 * re-use and change the same bladerf_trigger) for multiple triggers.)
 */
struct bladerf_trigger
{
    bladerf_module module;         /**< RX/TX module associated with trigger */
    bladerf_trigger_role role;     /**< Role of the device in a trigger chain */
    bladerf_trigger_signal signal; /**< Pin or signal being used */
    uint64_t options;              /**< Reserved field for future options. This
                                    *   is unused and should be set to 0.
                                    */
};

/**
 * Initialize a bladerf_trigger structure based upon the current configuration
 * of the specified trigger signal.
 *
 * While it is possible to simply declare and manually fill in a
 * bladerf_trigger structure, it is recommended to use this function to
 * retrieve the current `role` and `options` values.
 *
 * @param[in]   dev         Device to query
 * @param[in]   module      Module to query
 * @param[in]   signal      Trigger signal to query
 * @param[out]  trigger     Updated to describe trigger
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_trigger_init(struct bladerf *dev,
                                   bladerf_module module,
                                   bladerf_trigger_signal signal,
                                   struct bladerf_trigger *trigger);

/**
 * Configure and (dis)arm a trigger on the specified device.
 *
 * @note If trigger->role is set to ::BLADERF_TRIGGER_ROLE_DISABLED,
 *       this will inherently disarm an armed trigger and clear any fire
 *       requests, regardless of the value of `arm`.
 *
 * @param[in]   dev     Device to configure
 * @param[in]   trigger Trigger configure
 * @param[in]   arm     (Re)Arm trigger if true, disarm if false
 * @param[in]   resv1   Reserved for future use. Set to 0.
 * @param[in]   resv2   Reserved for future use. Set to 0.
 *
 * @warning Configuring two devices in the trigger chain (or both RX and
 *          TX on a single device) as masters can damage the associated FPGA
 *          pins, as this would cause contention over the trigger signal.<b>
 *          Ensure only one device in the chain is configured as the master!
 *          </b>
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_trigger_arm(struct bladerf *dev,
                                  const struct bladerf_trigger *trigger,
                                  bool arm, uint64_t resv1, uint64_t resv2);

/**
 * Fire a trigger event.
 *
 * Calling this functiona with a trigger whose role is anything other than
 * ::BLADERF_TRIGGER_REG_MASTER will yield a BLADERF_ERR_INVAL return value.
 *
 * @param[in]   dev         Device handle
 * @param[in]   trigger     Trigger to assert
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_trigger_fire(struct bladerf *dev,
                                   const struct bladerf_trigger *trigger);

/**
 * Query the fire request status of a master trigger
 *
 * @param[in]   dev             Device handle
 *
 * @param[in]   trigger         Trigger to query
 *
 * @param[out]  is_armed        Set to true if the trigger is armed, and false
 *                              otherwise. May be NULL.
 *
 * @param[out]  has_fired       Set to true if the trigger has fired, and false
 *                              otherwise. May be NULL.
 *
 * @param[out]  fire_requested  Only applicable to a trigger master.
 *                              Set to true if a fire request has been
 *                              previously submitted. May be NULL.
 *
 * @param[out]  resv1           Reserved for future use.
 *                              This field is written as 0 if not set to NULL.
 *
 * @param[out]  resv2           Reserved for future use.
 *                              This field is written as 0 if not set to NULL.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_trigger_state(struct bladerf *dev,
                                    const struct bladerf_trigger *trigger,
                                    bool *is_armed,
                                    bool *has_fired,
                                    bool *fire_requested,
                                    uint64_t *resv1,
                                    uint64_t *resv2);

/** @} (End of FN_TRIG) */

/**
 * @defgroup FN_CORR    Corrections and calibration
 *
 * This group provides routines for performing calibration and applying
 * corrections. These functions are thread-safe.
 *
 *
 * The automatic DC correction used by the `bladeRF-cli` is not part of
 * this API, but it is implemented using libbladeRF. This automatic DC
 * calibration code is available
 * <a class="el" href="https://github.com/Nuand/bladeRF/blob/master/host/common/src/dc_calibration.c">here</a>
 * under an "MIT" license.
 * @{
 */

/**
 * DC Calibration Modules
 */
typedef enum {
    BLADERF_DC_CAL_INVALID = -1,
    BLADERF_DC_CAL_LPF_TUNING,
    BLADERF_DC_CAL_TX_LPF,
    BLADERF_DC_CAL_RX_LPF,
    BLADERF_DC_CAL_RXVGA2
} bladerf_cal_module;

/**
 * Correction parameter selection
 *
 * These values specify the correction parameter to modify or query when
 * calling bladerf_set_correction() or bladerf_get_correction(). Note that the
 * meaning of the `value` parameter to these functions depends upon the
 * correction parameter.
 *
 */
typedef enum {
    /**
     * Adjusts the in-phase DC offset via controls provided by the LMS6002D
     * front end. Valid values are [-2048, 2048], which are scaled to the
     * available control bits in the LMS device.
     */
    BLADERF_CORR_LMS_DCOFF_I,

    /**
     * Adjusts the quadrature DC offset via controls provided the LMS6002D
     * front end. Valid values are [-2048, 2048], which are scaled to the
     * available control bits.
     */
    BLADERF_CORR_LMS_DCOFF_Q,

    /**
     * Adjusts FPGA-based phase correction of [-10, 10] degrees, via a provided
     * count value of [-4096, 4096].
     */
    BLADERF_CORR_FPGA_PHASE,

    /**
     * Adjusts FPGA-based gain correction value in [-1.0, 1.0], via provided
     * values in the range of [-4096, 4096].
     */
    BLADERF_CORR_FPGA_GAIN
} bladerf_correction;

/**
 * VCTCXO Tamer mode selection
 *
 * These values control the use of header J71 pin 1 for taming the
 * on-board VCTCXO to improve or sustain frequency accuracy.
 *
 * When supplying input into the VCTCXO tamer, a 1.8V signal must be provided.
 *
 * <b>
 * IMPORTANT: Exceeding 1.8V on J71-1 can damage the associated FPGA I/O bank.
 * Ensure that you provide only a 1.8V signal!
 * </b>
 */
typedef enum {
    /** Denotes an invalid selection or state */
    BLADERF_VCTCXO_TAMER_INVALID = -1,

    /** Do not attempt to tame the VCTCXO with an input source. */
    BLADERF_VCTCXO_TAMER_DISABLED = 0,

    /** Use a 1 pps input source to tame the VCTCXO. */
    BLADERF_VCTCXO_TAMER_1_PPS = 1,

    /** Use a 10 MHz input source to tame the VCTCXO. */
    BLADERF_VCTCXO_TAMER_10_MHZ = 2
} bladerf_vctcxo_tamer_mode;

/**
 * Set the value of the specified configuration parameter
 *
 * See the ::bladerf_correction description for the valid ranges of the
 * `value` parameter.
 *
 * @param   dev         Device handle
 * @param   module      Module to apply correction to
 * @param   corr        Correction type
 * @param   value       Value to apply
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_correction(struct bladerf *dev, bladerf_module module,
                                     bladerf_correction corr, int16_t value);

/**
 * Obtain the current value of the specified configuration parameter
 *
 * @param[in]   dev         Device handle
 * @param[in]   module      Module to retrieve correction information from
 * @param[in]   corr        Correction type
 * @param[out]  value       Current value
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_correction(struct bladerf *dev, bladerf_module module,
                                     bladerf_correction corr, int16_t *value);


/**
 * Set the VCTCXO tamer mode.
 *
 * @param       dev         Device handle
 * @param       mode        VCTCXO taming mode
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_vctcxo_tamer_mode(struct bladerf *dev,
                                             bladerf_vctcxo_tamer_mode mode);

/**
 * Get the current VCTCXO tamer mode
 *
 * @param[in]       dev         Device handle
 * @param[out]      mode        Current VCTCXO taming mode or
 *                              BLADERF_VCTCXO_TAMER_INVALID if a failure
 *                              occurs.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_vctcxo_tamer_mode(struct bladerf *dev,
                                             bladerf_vctcxo_tamer_mode *mode);

/**
 * Write value to VCTCXO trim DAC.
 *
 * This should not be used when the VCTCXO tamer is enabled.
 *
 * @param   dev         Device handle
 * @param   val         Value to write to VCTCXO trim DAC
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_dac_write(struct bladerf *dev, uint16_t val);

/**
 * Read value from VCTCXO trim DAC.
 *
 * This is similar to bladerf_get_vctcxo_trim(), except that it returns the
 * current trim DAC value, as opposed to the calibration value read from
 * flash.
 *
 * Use this if you are trying to query the value after having previously
 * made calls to bladerf_dac_write().
 *
 * @param[in]   dev     Device handle
 * @param[out]  val     Value to read from VCTCXO trim DAC
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_dac_read(struct bladerf *dev, uint16_t *val);

/** @} (End of FN_CORR) */

/**
 * @defgroup    FN_XB   Expansion boards
 *
 * This group of functions provides the ability to control and configure
 * expansion boards such as the XB-100, XB-200, and XB-300.
 *
 * In general, one should call bladerf_expansion_attach() immediately after
 * opening the device.
 *
 * Hotplug and expansion board removal is not supported. It is expected that
 * the expansion boards are attached at power-on and remain attached
 * until power is removed.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/**
 * Expansion boards
 */
typedef enum {
    BLADERF_XB_NONE = 0,    /**< No expansion boards attached */
    BLADERF_XB_100,         /**< XB-100 GPIO expansion board.
                             *   This device is not yet supported in
                             *   libbladeRF, and is here as a placeholder
                             *   for future support. */
    BLADERF_XB_200,         /**< XB-200 Transverter board */
    BLADERF_XB_300          /**< XB-300 Amplifier board */
} bladerf_xb;

/**
 * XB-200 filter selection options
 */
typedef enum {
    /** 50-54 MHz (6 meter band) filterbank */
    BLADERF_XB200_50M = 0,

    /** 144-148 MHz (2 meter band) filterbank */
    BLADERF_XB200_144M,

    /**
     * 222-225 MHz (1.25 meter band) filterbank.
     *
     * Note that this filter option is technically wider, covering 206-235 MHz.
     */
    BLADERF_XB200_222M,

    /**
     * This option enables the RX/TX module's custom filter bank path across the
     * associated FILT and FILT-ANT SMA connectors on the XB-200 board.
     *
     * For reception, it is often possible to simply connect the RXFILT and
     * RXFILT-ANT connectors with an SMA cable (effectively, "no filter"). This
     * allows for reception of signals outside of the frequency range of the
     * on-board filters, with some potential trade-off in signal quality.
     *
     * For transmission, <b>always</b> use an appropriate filter on the custom
     * filter path to avoid spurious emissions.
     *
     */
    BLADERF_XB200_CUSTOM,

    /**
     * When this option is selected, the other filter options are automatically
     * selected depending on the RX or TX module's current frequency, based upon
     * the 1dB points of the on-board filters.  For frequencies outside the
     * range of the on-board filters, the custom path is selected.
     */
    BLADERF_XB200_AUTO_1DB,

    /**
     * When this option is selected, the other filter options are automatically
     * selected depending on the RX or TX module's current frequency, based upon
     * the 3dB points of the on-board filters.  For frequencies outside the
     * range of the on-board filters, the custom path is selected.
     */
    BLADERF_XB200_AUTO_3DB
} bladerf_xb200_filter;

/**
 * XB-200 signal paths
 */
typedef enum {
    BLADERF_XB200_BYPASS = 0,   /**< Bypass the XB-200 mixer */
    BLADERF_XB200_MIX           /**< Pass signals through the XB-200 mixer */
} bladerf_xb200_path;

/**
 * XB-300 TRX setting
 */
typedef enum {
    BLADERF_XB300_TRX_INVAL = -1,   /**< Invalid TRX selection */
    BLADERF_XB300_TRX_TX = 0,       /**< TRX antenna operates as TX */
    BLADERF_XB300_TRX_RX,           /**< TRX antenna operates as RX */
    BLADERF_XB300_TRX_UNSET         /**< TRX antenna unset */
} bladerf_xb300_trx;

/**
 * XB-300 Amplifier selection
 */
typedef enum {
    BLADERF_XB300_AMP_INVAL = -1,   /**< Invalid amplifier selection */
    BLADERF_XB300_AMP_PA = 0,       /**< TX Power amplifier */
    BLADERF_XB300_AMP_LNA,          /**< RX LNA */
    BLADERF_XB300_AMP_PA_AUX        /**< Auxillary Power amplifier */
} bladerf_xb300_amplifier;

/**
 * Attach and enable an expansion board's features
 *
 * @param       dev         Device handle
 * @param       xb          Expansion board
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_expansion_attach(struct bladerf *dev, bladerf_xb xb);

/**
 * Determine which expansion board is attached
 *
 * @param       dev         Device handle
 * @param       xb          Expansion board
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_expansion_get_attached(struct bladerf *dev, bladerf_xb *xb);

/**
 * Set XB-200 filterbank
 *
 * @param       dev         Device handle
 * @param       mod         Module
 * @param       filter      XB200 filterbank
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_xb200_set_filterbank(struct bladerf *dev,
                                           bladerf_module mod,
                                           bladerf_xb200_filter filter);

/**
 * Get current XB-200 filterbank
 *
 * @param[in]    dev        Device handle
 * @param[in]    module     Module to query
 * @param[out]   filter     Pointer to filterbank, only updated if return
 *                          value is 0.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_xb200_get_filterbank(struct bladerf *dev,
                                           bladerf_module module,
                                           bladerf_xb200_filter *filter);

/**
 * Set XB-200 signal path
 *
 * @param       dev         Device handle
 * @param       module      Module to configure
 * @param       path        Desired XB-200 signal path
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_xb200_set_path(struct bladerf *dev,
                                     bladerf_module module,
                                     bladerf_xb200_path path);

/**
 * Get current XB-200 signal path
 *
 * @param       dev         Device handle
 * @param       module      Module to query
 * @param       path        Pointer to XB200 signal path
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_xb200_get_path(struct bladerf *dev,
                                     bladerf_module module,
                                     bladerf_xb200_path *path);

/**
 * Configure the XB-300 TRX path
 *
 * @param       dev         Device handle
 * @param       trx         Desired XB-300 TRX setting
 *
 * @return 0 on success, BLADERF_ERR_* on failure
 */
API_EXPORT
int CALL_CONV bladerf_xb300_set_trx(struct bladerf *dev,
                   bladerf_xb300_trx trx);
/**
 * Get the current XB-300 signal path
 *
 * @param       dev         Device handle
 * @param       trx         XB300 TRX antenna setting
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_xb300_get_trx(struct bladerf *dev,
                   bladerf_xb300_trx *trx);
/**
 * Enable or disable selected XB-300 amplifier
 *
 * @param       dev         Device handle
 * @param       amp         XB-300 amplifier
 * @param       enable      Set true to enable or false to disable
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_xb300_set_amplifier_enable(struct bladerf *dev,
                   bladerf_xb300_amplifier amp,
                   bool enable);
/**
 * Get state of selected XB-300 amplifier
 *
 * @param       dev         Device handle
 * @param       amp         XB-300 amplifier
 * @param       enable      Set true to enable or false to disable
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_xb300_get_amplifier_enable(struct bladerf *dev,
                   bladerf_xb300_amplifier amp,
                   bool *enable);
/**
 * Get current PA PDET output power in dBm
 *
 * @param       dev         Device handle
 * @param       val         Output power in dBm
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_xb300_get_output_power(struct bladerf *dev, float *val);


/** @} (End of FN_XB) */

/**
 * @defgroup FN_EXP_IO Expansion IO control
 *
 * These definitions and functions provide high-level functionality for
 * manipulating pins on the bladeRF U74 Expansion Header, and the associated
 * mappings on expansion boards.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/** Expansion pin GPIO number to bitmask */
#define BLADERF_XB_GPIO(n) (1 << (n-1))

/** Specifies a pin to be an output */
#define BLADERF_XB_DIR_OUTPUT(pin)  (pin)

/** Specifies a pin to be an input */
#define BLADERF_XB_DIR_INPUT(pin)   (0)

/** Pin bitmask for Expansion GPIO 1 (U74 pin 11) */
#define BLADERF_XB_GPIO_01 BLADERF_XB_GPIO(1)

/** Pin bitmask for Expansion GPIO 2 (U74 pin 13) */
#define BLADERF_XB_GPIO_02 BLADERF_XB_GPIO(2)

/** Pin bitmask for Expansion GPIO 3 (U74 pin 17) */
#define BLADERF_XB_GPIO_03 BLADERF_XB_GPIO(3)

/** Pin bitmask for Expansion GPIO 4 (U74 pin 19) */
#define BLADERF_XB_GPIO_04 BLADERF_XB_GPIO(4)

/** Pin bitmask for Expansion GPIO 5 (U74 pin 23) */
#define BLADERF_XB_GPIO_05 BLADERF_XB_GPIO(5)

/** Pin bitmask for Expansion GPIO 6 (U74 pin 25) */
#define BLADERF_XB_GPIO_06 BLADERF_XB_GPIO(6)

/** Pin bitmask for Expansion GPIO 7 (U74 pin 29) */
#define BLADERF_XB_GPIO_07 BLADERF_XB_GPIO(7)

/** Pin bitmask for Expansion GPIO 8 (U74 pin 31) */
#define BLADERF_XB_GPIO_08 BLADERF_XB_GPIO(8)

/** Pin bitmask for Expansion GPIO 9 (U74 pin 35) */
#define BLADERF_XB_GPIO_09 BLADERF_XB_GPIO(9)

/** Pin bitmask for Expansion GPIO 10 (U74 pin 37) */
#define BLADERF_XB_GPIO_10 BLADERF_XB_GPIO(10)

/** Pin bitmask for Expansion GPIO 11 (U74 pin 41) */
#define BLADERF_XB_GPIO_11 BLADERF_XB_GPIO(11)

/** Pin bitmask for Expansion GPIO 12 (U74 pin 43) */
#define BLADERF_XB_GPIO_12 BLADERF_XB_GPIO(12)

/** Pin bitmask for Expansion GPIO 13 (U74 pin 47) */
#define BLADERF_XB_GPIO_13 BLADERF_XB_GPIO(13)

/** Pin bitmask for Expansion GPIO 14 (U74 pin 49) */
#define BLADERF_XB_GPIO_14 BLADERF_XB_GPIO(14)

/** Pin bitmask for Expansion GPIO 15 (U74 pin 53) */
#define BLADERF_XB_GPIO_15 BLADERF_XB_GPIO(15)

/** Pin bitmask for Expansion GPIO 16 (U74 pin 55) */
#define BLADERF_XB_GPIO_16 BLADERF_XB_GPIO(16)

/** Pin bitmask for Expansion GPIO 17 (U74 pin 12) */
#define BLADERF_XB_GPIO_17 BLADERF_XB_GPIO(17)

/** Pin bitmask for Expansion GPIO 18 (U74 pin 14) */
#define BLADERF_XB_GPIO_18 BLADERF_XB_GPIO(18)

/** Pin bitmask for Expansion GPIO 19 (U74 pin 18) */
#define BLADERF_XB_GPIO_19 BLADERF_XB_GPIO(19)

/** Pin bitmask for Expansion GPIO 20 (U74 pin 20) */
#define BLADERF_XB_GPIO_20 BLADERF_XB_GPIO(20)

/** Pin bitmask for Expansion GPIO 21 (U74 pin 24) */
#define BLADERF_XB_GPIO_21 BLADERF_XB_GPIO(21)

/** Pin bitmask for Expansion GPIO 22 (U74 pin 26) */
#define BLADERF_XB_GPIO_22 BLADERF_XB_GPIO(22)

/** Pin bitmask for Expansion GPIO 23 (U74 pin 30) */
#define BLADERF_XB_GPIO_23 BLADERF_XB_GPIO(23)

/** Pin bitmask for Expansion GPIO 24 (U74 pin 32) */
#define BLADERF_XB_GPIO_24 BLADERF_XB_GPIO(24)

/** Pin bitmask for Expansion GPIO 25 (U74 pin 36) */
#define BLADERF_XB_GPIO_25 BLADERF_XB_GPIO(25)

/** Pin bitmask for Expansion GPIO 26 (U74 pin 38) */
#define BLADERF_XB_GPIO_26 BLADERF_XB_GPIO(26)

/** Pin bitmask for Expansion GPIO 27 (U74 pin 42) */
#define BLADERF_XB_GPIO_27 BLADERF_XB_GPIO(27)

/** Pin bitmask for Expansion GPIO 28 (U74 pin 44) */
#define BLADERF_XB_GPIO_28 BLADERF_XB_GPIO(28)

/** Pin bitmask for Expansion GPIO 29 (U74 pin 48) */
#define BLADERF_XB_GPIO_29 BLADERF_XB_GPIO(29)

/** Pin bitmask for Expansion GPIO 30 (U74 pin 50) */
#define BLADERF_XB_GPIO_30 BLADERF_XB_GPIO(30)

/** Pin bitmask for Expansion GPIO 31 (U74 pin 54) */
#define BLADERF_XB_GPIO_31 BLADERF_XB_GPIO(31)

/** Pin bitmask for Expansion GPIO 32 (U74 pin 56) */
#define BLADERF_XB_GPIO_32 BLADERF_XB_GPIO(32)


/** Bitmask for XB-200 header J7, pin 1 */
#define BLADERF_XB200_PIN_J7_1  BLADERF_XB_GPIO_10

/** Bitmask for XB-200 header J7, pin 2 */
#define BLADERF_XB200_PIN_J7_2  BLADERF_XB_GPIO_11

/** Bitmask for XB-200 header J7, pin 5 */
#define BLADERF_XB200_PIN_J7_5  BLADERF_XB_GPIO_08

/** Bitmask for XB-200 header J7, pin 6 */
#define BLADERF_XB200_PIN_J7_6  BLADERF_XB_GPIO_09

/** Bitmask for XB-200 header J13, pin 1 */
#define BLADERF_XB200_PIN_J13_1 BLADERF_XB_GPIO_17

/** Bitmask for XB-200 header J13, pin 2 */
#define BLADERF_XB200_PIN_J13_2 BLADERF_XB_GPIO_18

/* XB-200 J13 Pin 6 is actually reserved for SPI */

/** Bitmask for XB-200 header J16, pin 1 */
#define BLADERF_XB200_PIN_J16_1 BLADERF_XB_GPIO_31

/** Bitmask for XB-200 header J16, pin 2 */
#define BLADERF_XB200_PIN_J16_2 BLADERF_XB_GPIO_32

/** Bitmask for XB-200 header J16, pin 3 */
#define BLADERF_XB200_PIN_J16_3 BLADERF_XB_GPIO_19

/** Bitmask for XB-200 header J16, pin 4 */
#define BLADERF_XB200_PIN_J16_4 BLADERF_XB_GPIO_20

/** Bitmask for XB-200 header J16, pin 5 */
#define BLADERF_XB200_PIN_J16_5 BLADERF_XB_GPIO_21

/** Bitmask for XB-200 header J16, pin 6 */
#define BLADERF_XB200_PIN_J16_6 BLADERF_XB_GPIO_24

/** Bitmask for XB-100 header J2, pin 3 */
#define BLADERF_XB100_PIN_J2_3 BLADERF_XB_GPIO_07

/** Bitmask for XB-100 header J2, pin 4 */
#define BLADERF_XB100_PIN_J2_4  BLADERF_XB_GPIO_08

/** Bitmask for XB-100 header J3, pin 3 */
#define BLADERF_XB100_PIN_J3_3  BLADERF_XB_GPIO_09

/** Bitmask for XB-100 header J3, pin 4 */
#define BLADERF_XB100_PIN_J3_4  BLADERF_XB_GPIO_10

/** Bitmask for XB-100 header J4, pin 3 */
#define BLADERF_XB100_PIN_J4_3  BLADERF_XB_GPIO_11

/** Bitmask for XB-100 header J4, pin 4 */
#define BLADERF_XB100_PIN_J4_4  BLADERF_XB_GPIO_12

/** Bitmask for XB-100 header J5, pin 3 */
#define BLADERF_XB100_PIN_J5_3  BLADERF_XB_GPIO_13

/** Bitmask for XB-100 header J5, pin 4 */
#define BLADERF_XB100_PIN_J5_4  BLADERF_XB_GPIO_14

/** Bitmask for XB-100 header J11, pin 2 */
#define BLADERF_XB100_PIN_J11_2 BLADERF_XB_GPIO_05

/** Bitmask for XB-100 header J11, pin 3 */
#define BLADERF_XB100_PIN_J11_3 BLADERF_XB_GPIO_04

/** Bitmask for XB-100 header J11, pin 4 */
#define BLADERF_XB100_PIN_J11_4 BLADERF_XB_GPIO_03

/** Bitmask for XB-100 header J11, pin 5 */
#define BLADERF_XB100_PIN_J11_5 BLADERF_XB_GPIO_06

/** Bitmask for XB-100 header J12, pin 2 */
#define BLADERF_XB100_PIN_J12_2 BLADERF_XB_GPIO_01

/*  XB-100 header J12, pins 3 and 4 are reserved for SPI */

/** Bitmask for XB-100 header J12, pin 5 */
#define BLADERF_XB100_PIN_J12_5 BLADERF_XB_GPIO_02

/** Bitmask for XB-100 LED_D1 (blue) */
#define BLADERF_XB100_LED_D1    BLADERF_XB_GPIO_24

/** Bitmask for XB-100 LED_D2 (blue) */
#define BLADERF_XB100_LED_D2    BLADERF_XB_GPIO_32

/** Bitmask for XB-100 LED_D3 (blue) */
#define BLADERF_XB100_LED_D3    BLADERF_XB_GPIO_30

/** Bitmask for XB-100 LED_D4 (red) */
#define BLADERF_XB100_LED_D4    BLADERF_XB_GPIO_28

/** Bitmask for XB-100 LED_D5 (red) */
#define BLADERF_XB100_LED_D5    BLADERF_XB_GPIO_23

/** Bitmask for XB-100 LED_D6 (red) */
#define BLADERF_XB100_LED_D6    BLADERF_XB_GPIO_25

/** Bitmask for XB-100 LED_D7 (green) */
#define BLADERF_XB100_LED_D7    BLADERF_XB_GPIO_31

/** Bitmask for XB-100 LED_D8 (green) */
#define BLADERF_XB100_LED_D8    BLADERF_XB_GPIO_29

/** Bitmask for XB-100 tricolor LED, red cathode */
#define BLADERF_XB100_TLED_RED  BLADERF_XB_GPIO_22

/** Bitmask for XB-100 tricolor LED, green cathode */
#define BLADERF_XB100_TLED_GREEN  BLADERF_XB_GPIO_21

/** Bitmask for XB-100 tricolor LED, blue cathode */
#define BLADERF_XB100_TLED_BLUE BLADERF_XB_GPIO_20

/** Bitmask for XB-100 DIP switch 1 */
#define BLADERF_XB100_DIP_SW1   BLADERF_XB_GPIO_27

/** Bitmask for XB-100 DIP switch 2 */
#define BLADERF_XB100_DIP_SW2   BLADERF_XB_GPIO_26

/** Bitmask for XB-100 DIP switch 3 */
#define BLADERF_XB100_DIP_SW3   BLADERF_XB_GPIO_16

/** Bitmask for XB-100 DIP switch 4 */
#define BLADERF_XB100_DIP_SW4   BLADERF_XB_GPIO_15

/** Bitmask for XB-100 button J6 */
#define BLADERF_XB100_BTN_J6   BLADERF_XB_GPIO_19

/** Bitmask for XB-100 button J7 */
#define BLADERF_XB100_BTN_J7   BLADERF_XB_GPIO_18

/** Bitmask for XB-100 button J8 */
#define BLADERF_XB100_BTN_J8   BLADERF_XB_GPIO_17

/* XB-100 buttons J9 and J10 are not mapped to the GPIO register,
 * but instead to reserved SPI pins. FPGA modifications are needed to
 * use these. */

/**
 * Read the state of expansion GPIO values
 *
 * @param[in]   dev         Device handle
 * @param[out]  val         Value of GPIO pins
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_expansion_gpio_read(struct bladerf *dev, uint32_t *val);

/**
 * Write expansion GPIO pins.
 *
 * Callers should be sure to perform a read-modify-write sequence to avoid
 * accidentally clearing other GPIO bits that may be set by the library
 * internally.
 *
 * Consider using bladerf_expansion_gpio_masked_write() instead.
 *
 * @param   dev         Device handle
 * @param   val         Data to write to GPIO pins.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_expansion_gpio_write(struct bladerf *dev, uint32_t val);

/**
 * Write values to the specified GPIO pins
 *
 * This function alleviates the need for the caller to perform a
 * read-modify-write sequence. The supplied mask is used by the FPGA to
 * perform the required RMW operation.
 *
 * @param   dev         Device handle
 * @param   mask        Mask of pins to write
 * @param   value       Value to write.
 *
 * For example, to set XB200 pins J16-1 and J16-2, and clear J16-4 and J16-5:
 * @code{.c}
 *  const uint32_t pins_to_write =
 *      BLADERF_XB200_PIN_J16_1 |
 *      BLADERF_XB200_PIN_J16_2 |
 *      BLADERF_XB200_PIN_J16_3 |
 *      BLADERF_XB200_PIN_J16_4;
 *
 *  const uint32_t values_to_write =
 *      BLADERF_XB200_PIN_J16_1 |
 *      BLADERF_XB200_PIN_J16_2;
 *
 *  int status = bladerf_expansion_gpio_masked_write(dev,
 *                                                   pins_to_write,
 *                                                   values_to_write);
 * @endcode
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_expansion_gpio_masked_write(struct bladerf *dev,
                                                  uint32_t mask,
                                                  uint32_t value);

/**
 * Read the expansion GPIO direction register
 *
 * @param[in]   dev         Device handle
 * @param[out]  outputs     Pins configured as outputs will be set to '1'.
 *                          Pins configured as inputs will be set to '0'.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_expansion_gpio_dir_read(struct bladerf *dev,
                                              uint32_t *outputs);

/**
 * Write to the expansion GPIO direction register.
 *
 * Callers should be sure to perform a read-modify-write sequence to avoid
 * accidentally clearing other GPIO bits that may be set by the library
 * internally.
 *
 * Consider using bladerf_expansion_gpio_dir_masked_write() instead.
 *
 * @param   dev         Device handle
 * @param   outputs     Pins set to '1' will be configured as outputs.
 *                      Pins set to '0' will be configured as inputs.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_expansion_gpio_dir_write(struct bladerf *dev,
                                               uint32_t outputs);

/**
 * Configure the direction of the specified expansion GPIO pins
 *
 * This function alleviates the need for the caller to perform a
 * read-modify-write sequence. The supplied mask is used by the FPGA to
 * perform the required RMW operation.
 *
 * @param   dev         Device handle
 * @param   mask        Bitmask of pins to configure
 * @param   outputs     Pins set to '1' will be configured as outputs.
 *                      Pins set to '0' will be configured as inputs.
 *
 * For example, to configure XB200 pins J16-1 and J16-2 and pins
 * J16-4 and J16-5 as inputs:
 *
 * @code{.c}
 *  const uint32_t pins_to_config =
 *      BLADERF_XB200_PIN_J16_1 |
 *      BLADERF_XB200_PIN_J16_2 |
 *      BLADERF_XB200_PIN_J16_3 |
 *      BLADERF_XB200_PIN_J16_4;
 *
 *  const uint32_t output_pins =
 *      BLADERF_XB200_PIN_J16_1 |
 *      BLADERF_XB200_PIN_J16_2;
 *
 *  int status = bladerf_expansion_gpio_masked_write(dev,
 *                                                   pins_to_config,
 *                                                   output_pins);
 * @endcode
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_expansion_gpio_dir_masked_write(struct bladerf *dev,
                                                      uint32_t mask,
                                                      uint32_t outputs);

/** @} (End of FN_EXP_IO) */

/**
 * @defgroup FN_MISC Miscellaneous
 *
 * This section contains various helper/utility functions that do not
 * fall into one of the other API categories.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/**
 * Severity levels for logging functions
 */
typedef enum {
    BLADERF_LOG_LEVEL_VERBOSE,  /**< Verbose level logging */
    BLADERF_LOG_LEVEL_DEBUG,    /**< Debug level logging */
    BLADERF_LOG_LEVEL_INFO,     /**< Information level logging */
    BLADERF_LOG_LEVEL_WARNING,  /**< Warning level logging */
    BLADERF_LOG_LEVEL_ERROR,    /**< Error level logging */
    BLADERF_LOG_LEVEL_CRITICAL, /**< Fatal error level logging */
    BLADERF_LOG_LEVEL_SILENT    /**< No output */
} bladerf_log_level;

/**
 * Retrieve the backend string associated with the specified
 * backend enumeration value.
 *
 * @warning Do not attempt to modify or free() the returned string.
 *
 * @return A string that can used to specify the `backend` portion of a device
 *         identifier string. (See bladerf_open().)
 */
API_EXPORT
const char * CALL_CONV bladerf_backend_str(bladerf_backend backend);


/**
 * Get libbladeRF version information
 *
 * @param[out]  version     libbladeRF version information
 */
API_EXPORT
void CALL_CONV bladerf_version(struct bladerf_version *version);

/**
 * Sets the filter level for displayed log messages. Messages that are at or
 * above the specified log level will be printed, while messages with a lower
 * log level will be suppressed.
 *
 * @param   level       The new log level filter value
 */
API_EXPORT
void CALL_CONV bladerf_log_set_verbosity(bladerf_log_level level);

/**
 * Read firmware log data and write it to the specified file
 *
 * @param   dev         Device to read firmware log from
 * @param   filename    Filename to write log information to. If set to NULL,
 *                      log data will be printed to stdout.
 *
 * @return 0 upon success, or a value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_fw_log(struct bladerf *dev, const char *filename);

/** @} (End of FN_MISC) */

/**
 * @defgroup FMT_META   Sample formats and metadata
 *
 * This section defines the available sample formats and metadata flags.
 *
 * @{
 */

/**
 * Sample format
 */
typedef enum {
    /**
     * Signed, Complex 16-bit Q11. This is the native format of the DAC data.
     *
     * Values in the range [-2048, 2048) are used to represent [-1.0, 1.0).
     * Note that the lower bound here is inclusive, and the upper bound is
     * exclusive. Ensure that provided samples stay within [-2048, 2047].
     *
     * Samples consist of interleaved IQ value pairs, with I being the first
     * value in the pair. Each value in the pair is a right-aligned,
     * little-endian int16_t. The FPGA ensures that these values are
     * sign-extended.
     *
     * When using this format the minimum required buffer size, in bytes, is:
     * <pre>
     *   buffer_size_min = [ 2 * num_samples * sizeof(int16_t) ]
     * </pre>
     *
     * For example, to hold 2048 samples, a buffer must be at least 8192 bytes
     * large.
     */
    BLADERF_FORMAT_SC16_Q11,

    /**
     * This format is the same as the ::BLADERF_FORMAT_SC16_Q11 format, except
     * the first 4 samples in every <i>block*</i> of samples are replaced with
     * metadata organized as follows. All fields are little-endian byte order.
     *
     * <pre>
     *  .-------------.-----------.----------------------------------.
     *  | Byte offset |   Type    | Description                      |
     *  +-------------+-----------+----------------------------------+
     *  |    0x00     | uint32_t  | Reserved                         |
     *  |    0x04     | uint64_t  | 64-bit Timestamp                 |
     *  |    0x0c     | uint32_t  | BLADERF_META_FLAG_* flags        |
     *  `-------------`-----------`----------------------------------`
     * </pre>
     *
     * <i>*</i>The number of samples in a <i>block</i> is dependent upon
     * the USB speed being used:
     *  - USB 2.0 Hi-Speed: 256 samples
     *  - USB 3.0 SuperSpeed: 512 samples
     *
     * When using the bladerf_sync_rx() and bladerf_sync_tx() functions, the
     * above details are entirely transparent; the caller need not be concerned
     * with these details. These functions take care of packing/unpacking the
     * metadata into/from the underlying stream and convey this information
     * through the ::bladerf_metadata structure.
     *
     * However, when using the \ref FN_DATA_ASYNC interface, the user is
     * responsible for manually packing/unpacking the above metadata into/from
     * their samples.
     *
     * For a more information, see the
     * <a class="el" href="https://github.com/Nuand/bladeRF/blob/master/host/libraries/libbladeRF/src/metadata.h">metadata.h</a>
     * header in the libbladeRF codebase.
     */
    BLADERF_FORMAT_SC16_Q11_META,
} bladerf_format;

/*
 * Metadata status bits
 *
 * These are used in conjunction with the bladerf_metadata structure's
 * `status` field.
 */

/**
 * A sample overrun has occurred. This indicates that either the host
 * (more likely) or the FPGA is not keeping up with the incoming samples
 */
#define BLADERF_META_STATUS_OVERRUN  (1 << 0)

/**
 * A sample underrun has occurred. This generally only occurrs on the TX module
 * when the FPGA is starved of samples.
 *
 * @note libbladeRF does not report this status. It is here for future use.
 */
#define BLADERF_META_STATUS_UNDERRUN (1 << 1)



/*
 * Metadata flags
 *
 * These are used in conjunction with the bladerf_metadata structure's
 * `flags` field.
 */

/**
 * Mark the associated buffer as the start of a burst transmission.
 * This is only used for the bladerf_sync_tx() call.
 *
 * When using this flag, the bladerf_metadata::timestamp field should contain
 * the timestamp at which samples should be sent.
 *
 * Between specifying the ::BLADERF_META_FLAG_TX_BURST_START and
 * ::BLADERF_META_FLAG_TX_BURST_END flags, there is no need for the user to the
 * bladerf_metadata::timestamp field because the library will ensure the
 * correct value is used, based upon the timestamp initially provided and
 * the number of samples that have been sent.
 */
#define BLADERF_META_FLAG_TX_BURST_START   (1 << 0)

/**
 * Mark the associated buffer as the end of a burst transmission. This will
 * flush the remainder of the sync interface's current working buffer and
 * enqueue samples into the hardware's transmit FIFO.
 *
 * As of libbladeRF v1.3.0, it is no longer necessary for the API user to
 * ensure that the final 3 samples of a burst are 0+0j. libbladeRF now ensures
 * this hardware requirement (driven by the LMS6002D's pre-DAC register stages)
 * is upheld.
 *
 * Specifying this flag and flushing the sync interface's working buffer implies
 * that the next timestamp that can be transmitted is the current timestamp plus
 * the duration of the burst that this flag is ending <b>and</b> the remaining
 * length of the remaining buffer that is flushed. (The buffer size, in this
 * case, is the `buffer_size` value passed to the previous bladerf_sync_config()
 * call.)
 *
 * Rather than attempting to keep track of the number of samples sent with
 * respect to buffer sizes, it is easiest to always assume 1 buffer's worth of
 * time is required between bursts. In this case "buffer" refers to the
 * `buffer_size` parameter provided to bladerf_sync_config().) If this is too
 * much time, consider using the ::BLADERF_META_FLAG_TX_UPDATE_TIMESTAMP
 * flag.
 *
 * This is only used for the bladerf_sync_tx() call. It is ignored by the
 * bladerf_sync_rx() call.
 *
 */
#define BLADERF_META_FLAG_TX_BURST_END     (1 << 1)

/**
 * Use this flag in conjunction with ::BLADERF_META_FLAG_TX_BURST_START to
 * indicate that the burst should be transmitted as soon as possible, as opposed
 * to waiting for a specific timestamp.
 *
 * When this flag is used, there is no need to set the
 * bladerf_metadata::timestamp field.
 */
#define BLADERF_META_FLAG_TX_NOW           (1 << 2)

/**
 * Use this flag within a burst (i.e., between the use of
 * ::BLADERF_META_FLAG_TX_BURST_START and ::BLADERF_META_FLAG_TX_BURST_END) to
 * specify that bladerf_sync_tx() should read the bladerf_metadata::timestamp
 * field and zero-pad samples up to the specified timestamp. The provided
 * samples will then be transmitted at that timestamp.
 *
 * Use this flag when potentially flushing an entire buffer via the
 * ::BLADERF_META_FLAG_TX_BURST_END would yield an unacceptably large gap in
 * the transmitted samples.
 *
 * In some applications where a transmitter is constantly transmitting
 * with extremely small gaps (less than a buffer), users may end up using a
 * single ::BLADERF_META_FLAG_TX_BURST_START, and then numerous calls to
 * bladerf_sync_tx() with the ::BLADERF_META_FLAG_TX_UPDATE_TIMESTAMP
 * flag set.  The ::BLADERF_META_FLAG_TX_BURST_END would only be used to end
 * the stream when shutting down.
 */
#define BLADERF_META_FLAG_TX_UPDATE_TIMESTAMP (1 << 3)

/**
 * This flag indicates that calls to bladerf_sync_rx should return any available
 * samples, rather than wait until the timestamp indicated in the
 * bladerf_metadata timestamp field.
 */
#define BLADERF_META_FLAG_RX_NOW           (1 << 31)

/**
 * Sample metadata
 *
 * This structure is used in conjunction with the ::BLADERF_FORMAT_SC16_Q11_META
 * format to TX scheduled bursts or retrieve timestamp information about
 * received samples.
 */
struct bladerf_metadata {

    /**
     * Free-running FPGA counter that monotonically increases at the
     * sample rate of the associated module. */
    uint64_t timestamp;

    /**
     * Input bit field to control the behavior of the call that the metadata
     * structure is passed to. API calls read this field from the provided
     * data structure, and do not modify it.
     *
     * Valid flags include
     *  ::BLADERF_META_FLAG_TX_BURST_START, ::BLADERF_META_FLAG_TX_BURST_END,
     *  ::BLADERF_META_FLAG_TX_NOW, ::BLADERF_META_FLAG_TX_UPDATE_TIMESTAMP,
     *  and ::BLADERF_META_FLAG_RX_NOW
     *
     */
    uint32_t flags;

    /**
     * Output bit field to denoting the status of transmissions/receptions. API
     * calls will write this field.
     *
     * Possible status flags include ::BLADERF_META_STATUS_OVERRUN and
     * ::BLADERF_META_STATUS_UNDERRUN;
     *
     */
    uint32_t status;

    /**
     * This output parameter is updated to reflect the actual number of
     * contiguous samples that have been populated in an RX buffer during
     * a bladerf_sync_rx() call.
     *
     * This will not be equal to the requested count in the event of a
     * discontinuity (i.e., when the status field has the
     * ::BLADERF_META_STATUS_OVERRUN flag set). When an overrun occurs, it is
     * important not to read past the number of samples specified by this
     * value, as the remaining contents of the buffer are undefined.
     *
     * This parameter is not currently used by bladerf_sync_tx().
     */
    unsigned int actual_count;

    /**
     * Reserved for future use. This is not used by any functions.
     * It is recommended that users zero out this field.
     */
    uint8_t reserved[32];
};

/**
 * Retrieve the specified module's current timestamp counter value from the
 * FPGA.
 *
 * This function is only intended to be used to retrieve a coarse estimate of
 * the current timestamp when starting up a stream. It <b>should not</b> be used
 * as a means to accurately retrieve the current timestamp of individual samples
 * within a running stream. The reasons for this are:
 *  - The timestamp counter will have advanced during the time that the captured
 *      value is propagated back from the FPGA to the host
 *  - The value retrieved in this manner is not tightly-coupled with
 *      specific sample positions in the stream.
 *
 * When actively receiving a sample stream, instead use the
 * ::bladerf_metadata::timestamp field (provided when using the
 * ::BLADERF_FORMAT_SC16_Q11_META format) to retrieve the timestamp value
 * associated with a block of samples. See the
 * <a class="el" href="sync_rx_meta.html">RX with metadata</a> page for
 * examples of this.
 *
 * An example use-case of this function is to schedule an initial TX burst
 * in a set of bursts;
 *  - Configure and start a TX stream using the ::BLADERF_FORMAT_SC16_Q11_META
 *      format.
 *  - Retrieve timestamp `T`, a coarse estimate the TX's current timestamp via this
 *      function.
 *  - Schedule the first burst, `F` to occur in the future: `F = T + N`.
 *      Generally, adding `N` in tens to low hundreds of milliseconds is
 *      sufficient to account for timestamp retrieval overhead and stream
 *      startup.
 *  - Schedule additional bursts relative to the first burst `F`.
 *
 * Examples of the above are shown on the <a class="el"
 * href="sync_tx_meta_bursts.html">TX with metadata</a> page.
 *
 * @param[in]   dev         Device handle
 * @param[in]   mod         Module to query
 * @param[out]  value       Coarse timestamp value
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_timestamp(struct bladerf *dev, bladerf_module mod,
                                    uint64_t *value);

/** @} (End of FMT_META) */


/**
 * @defgroup FN_DATA_ASYNC    Asynchronous data transmission and reception
 *
 * This interface gives the API user full control over the stream and buffer
 * management, at the cost of added complexity.
 *
 * New users are recommended to first evaluate the \ref FN_DATA_SYNC interface,
 * and to only use this interface if the former is found to not yield suitable
 * performance.
 *
 * These functions are either thread-safe or may be used in a thread-safe
 * manner (per the details noted in the function description).
 *
 * @{
 */

/**
 * Use this as a return value in callbacks or as the buffer parameter to
 * bladerf_submit_stream_buffer() to shutdown a stream.
 */
#define BLADERF_STREAM_SHUTDOWN (NULL)

/**
 * Use this value in a stream callback to indicate that no buffer is being
 * provided. In this case, buffers are expected to be provided via
 * bladerf_submit_stream_buffer().
 */
#define BLADERF_STREAM_NO_DATA  ((void*)(-1))

/** This opaque structure is used to keep track of stream information */
struct bladerf_stream;

/**
 * This typedef represents a callback function that is executed in response to
 * this interface's asynchronous events.
 *
 * Stream callbacks <b>must not</b> block or perform long-running operations.
 * Otherwise, timeouts may occur. If this cannot be guaranteed, consider
 * returning BLADERF_STREAM_NO_DATA in callbacks and later submit a buffer using
 * bladerf_submit_stream_buffer(). However, callbacks should always take a
 * single approach of returning buffers <b>or</b> returning
 * BLADERF_STREAM_NO_DATA and submitting buffers later -- <b>but not both</b>.
 *
 * When running in a full-duplex mode of operation with simultaneous TX and RX
 * stream threads, be aware that one module's callback may occur in the context
 * of another module's thread. The API user is responsible for ensuring their
 * callbacks are thread safe. For example, when managing access to sample
 * buffers, the caller must ensure that if one thread is processing samples in a
 * buffer, that this buffer is not returned via the callback's return value.
 *
 * As of libbladeRF v0.15.0, is guaranteed that only one callback from a module
 * will occur at a time. (i.e., a second TX callback will not fire while one is
 * currently being handled.)  To achieve this, while a callback is executing, a
 * per-stream lock is held. It is important to consider this when thinking about
 * the order of lock acquisitions both in the callbacks, and the code
 * surrounding bladerf_submit_stream_buffer().
 *
 * <b>Note:</b>Do not call bladerf_submit_stream_buffer() from a callback.
 *
 * For both RX and TX, the stream callback receives:
 *  - dev:          Device structure
 *  - stream:       The associated stream
 *  - metadata:     For future support - do not attempt to read/write this
 *                  in the current library implementation.
 *  - user_data:    User data provided when initializing stream
 *
 * For TX callbacks:
 *  - samples:      Pointer to buffer of samples that was sent
 *  - num_samples:  Number of sent in last transfer and to send in next transfer
 *  - Return value: The user specifies the address of the next buffer to send,
 *                  BLADERF_STREAM_SHUTDOWN, or BLADERF_STREAM_NO_DATA.
 *
 * For RX callbacks:
 *  - samples:          Buffer filled with received data
 *  - num_samples:      Number of samples received and size of next buffers
 *  - Return value:     The user specifies the next buffer to fill with RX data,
 *                      which should be `num_samples` in size,
 *                      BLADERF_STREAM_SHUTDOWN, or BLADERF_STREAM_NO_DATA.
 *
 */
typedef void *(*bladerf_stream_cb)(struct bladerf *dev,
                                   struct bladerf_stream *stream,
                                   struct bladerf_metadata *meta,
                                   void *samples,
                                   size_t num_samples,
                                   void *user_data);

/**
 * Initialize a stream for use with asynchronous routines.
 *
 * This function will internally allocate data buffers, which will be provided
 * to the API user in callback functions.
 *
 * The `buffers` output parameter populates a pointer to the list of allocated
 * buffers. This allows the API user to implement a buffer management scheme to
 * best suit his or her specific use case.
 *
 * Generally, one will want to set the `buffers` parameter to a value larger
 * than the `num_transfers` parameter, and keep track of which buffers are
 * currently "in-flight", versus those available for use.
 *
 * For example, for a transmit stream, modulated data can be actively written
 * into free buffers while transfers of other buffers are occurring. Once a
 * buffer has been filled with data, it can be marked 'in-flight' and be
 * returned in a successive callback to transmit.
 *
 * The choice of values for the `num_transfers` and `buffer_size` should be
 * made based upon the desired samplerate, and the stream timeout value
 * specified via bladerf_set_stream_timeout(), which defaults to 1 second.
 *
 * For a given sample rate, the below relationship must be upheld to transmit or
 * receive data without timeouts or dropped data.
 *
 * @f[
 * Sample\ Rate > \frac{\#\ Transfers}{Timeout} \times Buffer\ Size
 * @f]
 *
 * ...where Sample Rate is in samples per second, and Timeout is in seconds.
 *
 * To account for general system overhead, it is recommended to multiply the
 * righthand side by 1.1 to 1.25.
 *
 * While increasing the number of buffers available provides additional
 * elasticity, be aware that it also increases latency.
 *
 * @param[out]  stream          Upon success, this will be updated to contain
 *                              a stream handle (i.e., address)
 *
 * @param[in]   dev             Device to associate with the stream
 *
 * @param[in]   callback        Callback routine to handle asynchronous events
 *
 * @param[out]  buffers         This will be updated to point to a dynamically
 *                              allocated array of buffer pointers.
 *
 * @param[in]   num_buffers     Number of buffers to allocate and return. This
 *                              value must >= the `num_transfers` parameter.
 *
 * @param[in]   format          Sample data format
 *
 * @param[in]   samples_per_buffer  Size of allocated buffers, in units of
 *                                  samples Note that the physical size of the
 *                                  buffer is a function of this and the format
 *                                  parameter.
 *
 * @param[in]   num_transfers   Maximum number of transfers that may be
 *                              in-flight simultaneously. This must be <= the
 *                              `num_buffers` parameter.
 *
 * @param[in]   user_data       Caller-provided data that will be provided
 *                              in stream callbacks
 *
 *
 * @note  This call should be later followed by a call to
 *        bladerf_deinit_stream() to avoid memory leaks.
 *
 * @return 0 on success,
 *          value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_init_stream(struct bladerf_stream **stream,
                                  struct bladerf *dev,
                                  bladerf_stream_cb callback,
                                  void ***buffers,
                                  size_t num_buffers,
                                  bladerf_format format,
                                  size_t samples_per_buffer,
                                  size_t num_transfers,
                                  void *user_data);

/**
 * Begin running a stream. This call will block until the steam completes.
 *
 * Only 1 RX stream and 1 TX stream may be running at a time. Attempting to
 * call bladerf_stream() with more than one stream per module will yield
 * unexpected (and most likely undesirable) results. See the ::bladerf_stream_cb
 * description for additional thread-safety caveats.
 *
 * @pre This function should be preceded by a call to bladerf_enable_module()
 *      to enable the associated RX or TX module before attempting to use
 *      it to stream data.
 *
 * @param   stream  A stream handle that has been successfully been initialized
 *                  via bladerf_init_stream()
 *
 * @param   module  Module to perform streaming with
 *
 * @return  0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_stream(struct bladerf_stream *stream,
                             bladerf_module module);

/**
 * Submit a buffer to a stream from outside of a stream callback function.
 * Use this only when returning BLADERF_STREAM_NO_DATA from callbacks. <b>Do
 * not</b> use this function if the associated callback functions will be
 * returning buffers for submission.
 *
 * This call may block if the device is not ready to submit a buffer for
 * transfer. Use the `timeout_ms` to place an upper limit on the time this
 * function can block.
 *
 * To safely submit buffers from outside the stream callback flow, this function
 * internally acquires a per-stream lock (the same one that is held during the
 * execution of a stream callback). Therefore, it is important to be aware of
 * locks that may be held while making this call, especially those acquired
 * during execution of the associated stream callback function. (i.e., be wary
 * of the order of lock acquisitions, including the internal per-stream lock.)
 *
 * @param   stream      Stream to submit buffer to
 * @param   buffer      Buffer to fill (RX) or containing data (TX). This buffer
 *                      is assumed to be the size specified in the associated
 *                      bladerf_init_stream() call.
 * @param   timeout_ms  Milliseconds to timeout in, if this call blocks. 0
 *                      implies an "infinite" wait.
 *
 * @return  0 on success, BLADERF_ERR_TIMEOUT upon a timeout, or a value from
 * \ref RETCODES list on other failures
 */
API_EXPORT
int CALL_CONV bladerf_submit_stream_buffer(struct bladerf_stream *stream,
                                           void *buffer,
                                           unsigned int timeout_ms);

/**
 * This is a non-blocking variant of bladerf_submit_stream_buffer(). All of the
 * caveats and important notes from bladerf_submit_stream_buffer() apply.
 *
 * In the event that this call would need to block in order to submit a buffer,
 * it returns BLADERF_ERR_WOULD_BLOCK. In this case, the caller could either
 * wait and try again or defer buffer submission to the asynchronous callback.
 *
 * @param   stream      Stream to submit buffer to
 * @param   buffer      Buffer to fill (RX) or containing data (TX). This buffer
 *                      is assumed to be the size specified in the associated
 *                      bladerf_init_stream() call.
 *
 * @return  0 on success,
 *          BLADERF_ERR_WOULD_BLOCK if the call would have to block to succeed,
 *          or another value from \ref RETCODES upon other failure
 */
API_EXPORT
int CALL_CONV bladerf_submit_stream_buffer_nb(struct bladerf_stream *stream,
                                              void *buffer);


/**
 * Deinitialize and deallocate stream resources.
 *
 * @pre    Stream is no longer being used (via bladerf_submit_stream_buffer() or
 *          bladerf_stream() calls.)
 * @post   Stream is deallocated and may no longer be used.
 *
 * @param   stream      Stream to deinitialize. This function does nothing
 *                      if stream is NULL.
 */
API_EXPORT
void CALL_CONV bladerf_deinit_stream(struct bladerf_stream *stream);

/**
 * Set stream transfer timeout in milliseconds
 *
 * @param   dev         Device handle
 * @param   module      Module to adjust
 * @param   timeout     Timeout in milliseconds
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_set_stream_timeout(struct bladerf *dev,
                                         bladerf_module module,
                                         unsigned int timeout);


/**
 * Get transfer timeout in milliseconds
 *
 * @param[in]   dev         Device handle
 * @param[in]   module      Module to adjust
 * @param[out]  timeout     On success, updated with current transfer
 *                          timeout value. Undefined on failure.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_stream_timeout(struct bladerf *dev,
                                         bladerf_module module,
                                         unsigned int *timeout);

/** @} (End of FN_DATA_ASYNC) */

/**
 * @defgroup FN_DATA_SYNC  Synchronous data transmission and reception
 *
 * This group of functions presents synchronous, blocking calls (with optional
 * timeouts) for transmitting and receiving samples.
 *
 * The synchronous interface is built atop the asynchronous interface, and is
 * generally less complex and easier to work with.  It alleviates the need to
 * explicitly spawn threads (it is done under the hood) and manually manage
 * sample buffers.
 *
 * Under the hood, this interface spawns worker threads to handle an
 * asynchronous stream and perform thread-safe buffer management.
 *
 * These functions are thread-safe.
 *
 * The following pages provide additional information and example usage:
 *  <ul>
 *      <li>
 *          <a class="el" href="sync_no_meta.html">
 *              Synchronous Interface: Basic usage without metadata
 *          </a>
 *      </li>
 *      <li>
 *          <a class="el" href="sync_rx_meta.html">
 *             Synchronous Interface: RX with metadata
 *          </a>
 *      </li>
 *      <li>
            <a class="el" href="sync_tx_meta_bursts.html">
 *             Synchronous Interface: TX with metadata
 *          </a>
 *      </li>
 *  </ul>
 *
 * @{
 */

/**
 * (Re)Configure a device for synchronous transmission or reception
 *
 * This function sets up the device for the specified format and initializes
 * the underlying asynchronous stream parameters
 *
 * This function does not call bladerf_enable_module(). The API user is
 * responsible for enabling/disable modules when desired.
 *
 * Note that (re)configuring ::BLADERF_MODULE_TX does not affect the
 * ::BLADERF_MODULE_RX modules, and vice versa. This call configures each module
 * independently.
 *
 * Memory allocated by this function will be deallocated when bladerf_close()
 * is called.
 *
 * See the bladerf_init_stream() documentation for information on determining
 * appropriate values for `buffers_size`, `num_transfers`, and `stream_timeout`.
 * The `num_buffers` parameter should generally be increased as the amount of
 * work done between bladerf_sync_rx() or bladerf_sync_tx() calls increases.
 *
 * @param   dev             Device to configure
 *
 * @param   module          Module to use with synchronous interface
 *
 * @param   format          Format to use in synchronous data transfers
 *
 * @param   num_buffers     The number of buffers to use in the underlying
 *                          data stream. This must be greater than the
 *                          `num_xfers` parameter.
 *
 * @param   buffer_size     The size of the underlying stream buffers, in
 *                          samples. This value must be a multiple of 1024.
 *                          Note that samples are only transferred when a buffer
 *                          of this size is filled.
 *
 * @param   num_transfers   The number of active USB transfers that may be
 *                          in-flight at any given time. If unsure of what
 *                          to use here, try values of 4, 8, or 16.
 *
 * @param   stream_timeout  Timeout (milliseconds) for transfers in the
 *                          underlying data stream.
 *
 * @return 0 on success,
 *         BLADERF_ERR_UNSUPPORTED if libbladeRF is not built with support
 *         for this functionality,
 *         or a value from \ref RETCODES list on failures.
 */
API_EXPORT
int CALL_CONV bladerf_sync_config(struct bladerf *dev,
                                  bladerf_module module,
                                  bladerf_format format,
                                  unsigned int num_buffers,
                                  unsigned int buffer_size,
                                  unsigned int num_transfers,
                                  unsigned int stream_timeout);

/**
 * Transmit IQ samples.
 *
 * Under the hood, this call starts up an underlying asynchronous stream as
 * needed. This stream can be stopped by disabling the TX module. (See
 * bladerf_enable_module for more details.)
 *
 * Samples will only be sent to the FPGA when a buffer have been filled. The
 * number of samples required to fill a buffer corresponds to the `buffer_size`
 * parameter passed to bladerf_sync_config().
 *
 * @param[in]   dev         Device handle
 *
 * @param[in]   samples     Array of samples
 *
 * @param[in]   num_samples Number of samples to write
 *
 * @param[in]   metadata    Sample metadata. This must be provided when using
 *                          the ::BLADERF_FORMAT_SC16_Q11_META format, but may
 *                          be NULL when the interface is configured for
 *                          the ::BLADERF_FORMAT_SC16_Q11 format.
 *
 * @param[in]   timeout_ms  Timeout (milliseconds) for this call to complete.
 *                          Zero implies "infinite."
 *
 * @pre A bladerf_sync_config() call has been to configure the device for
 *      synchronous data transfer.
 *
 * @pre A call to bladerf_enable_module() should be made before attempting to
 *      transmit samples. Failing to do this may result in timeouts and other
 *      errors.
 *
 * @return 0 on success,
 *         BLADERF_ERR_UNSUPPORTED if libbladeRF is not built with support
 *         for this functionality,
 *         or a value from \ref RETCODES list on failures.
 */
API_EXPORT
int CALL_CONV bladerf_sync_tx(struct bladerf *dev,
                              void *samples, unsigned int num_samples,
                              struct bladerf_metadata *metadata,
                              unsigned int timeout_ms);

/**
 * Receive IQ samples.
 *
 * Under the hood, this call starts up an underlying asynchronous stream as
 * needed. This stream can be stopped by disabling the RX module. (See
 * bladerf_enable_module for more details.)
 *
 * @param[in]   dev         Device handle
 *
 * @param[out]  samples     Buffer to store samples in. The caller is
 *                          responsible for ensuring this buffer is sufficiently
 *                          large for the number of samples requested,
 *                          considering the size of the sample format being
 *                          used.
 *
 * @param[in]   num_samples Number of samples to read
 *
 * @param[out]  metadata    Sample metadata. This must be provided when using
 *                          the ::BLADERF_FORMAT_SC16_Q11_META format, but may
 *                          be NULL when the interface is configured for
 *                          the ::BLADERF_FORMAT_SC16_Q11 format.
 *
 * @param[in]   timeout_ms  Timeout (milliseconds) for this call to complete.
 *                          Zero implies "infinite."
 *
 * @pre A bladerf_sync_config() call has been to configure the device for
 *      synchronous data transfer.
 *
 * @pre A call to bladerf_enable_module() should be made before attempting to
 *      receive samples. Failing to do this may result in timeouts and other
 *      errors.
 *
 *
 * @return 0 on success,
 *         BLADERF_ERR_UNSUPPORTED if libbladeRF is not built with support
 *         for this functionality,
 *         or a value from \ref RETCODES list on failures.
 */
API_EXPORT
int CALL_CONV bladerf_sync_rx(struct bladerf *dev,
                              void *samples, unsigned int num_samples,
                              struct bladerf_metadata *metadata,
                              unsigned int timeout_ms);


/** @} (End of FN_DATA_SYNC) */

/**
 * @defgroup FN_PROG  Device loading and programming
 *
 * These functions provide the ability to load and program devices
 * on the bladeRF board. They are thread-safe.
 *
 * @{
 */

/**
 * Write FX3 firmware to the bladeRF's SPI flash
 *
 * @note This will require a power cycle to take effect
 *
 * @param   dev         Device handle
 * @param   firmware    Full path to firmware file
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_flash_firmware(struct bladerf *dev,
                                     const char *firmware);

/**
 * Load device's FPGA. Note that this FPGA configuration will be reset
 * at the next power cycle.
 *
 * @param   dev         Device handle
 * @param   fpga        Full path to FPGA bitstream
 *
 * @return 0 upon successfully, or a value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_load_fpga(struct bladerf *dev, const char *fpga);

/**
 * Write the provided FPGA image to the bladeRF's SPI flash and enable FPGA
 * loading from SPI flash at power on (also referred to within this project as
 * FPGA "autoloading").
 *
 * @param   dev         Device handle
 * @param   fpga_image  Full path to FPGA file
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_flash_fpga(struct bladerf *dev,
                                 const char *fpga_image);

/**
 * Erase the FPGA region of SPI flash, effectively disabling FPGA autoloading
 *
 * @param   dev         Device handle
 */
API_EXPORT
int CALL_CONV bladerf_erase_stored_fpga(struct bladerf *dev);

/**
 * Reset the device, causing it to reload its firmware from flash
 *
 * @param   dev         Device handle
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_device_reset(struct bladerf *dev);

/**
 * Clear out a firmware signature word in flash and jump to FX3 bootloader.
 *
 * The device will continue to boot into the FX3 bootloader across power cycles
 * until new firmware is written to the device.
 *
 * @param   dev         Device handle
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_jump_to_bootloader(struct bladerf *dev);

/** @} (End of FN_PROG) */

/**
 * @defgroup FN_BOOTLOADER  Bootloader recovery
 *
 * These functions provide the ability to identify devices enumerating as an
 * FX3 bootloader, download firmware to RAM, and then execute the firmware.
 *
 * Care should be taken to ensure that devices operated on are indeed a bladeRF,
 * as opposed to another FX3-based device running in bootloader mode.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/**
 * Get a list of devices that are running the FX3 bootloader.
 *
 * After obtaining this list, identify the device that you would like to load
 * firmware onto. Save the bus and address values so that you can provide them
 * to bladerf_load_fw_from_bootloader(), and then free this list via
 * bladerf_free_device_list().
 *
 * @param[out]   list    Upon finding devices, this will be updated to point
 *                       to a list of bladerf_devinfo structures that
 *                       describe the identified devices.
 *
 * @return Number of items populated in `list`,
 *         or an error value from the \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_get_bootloader_list(struct bladerf_devinfo **list);

/**
 * Download firmware to the specified device that is enumarating an FX3
 * bootloader, and begin executing the firmware from RAM.
 *
 * Note that this function <b>does not</b> write the firmware to SPI flash.
 * If this is desired, open the newly enumerated device with bladerf_open() and
 * use bladerf_flash_firmware().
 *
 * @param device_identifier   Device identifier string describing the
 *                            backend to use via the
 *                              `<backend>:device=<bus>:<addr>` syntax.
 *                            If this is NULL, the backend, bus, and addr
 *                            arguments will be used instead.
 *
 * @param backend             Backend to use. This is only used if
 *                              device_identifier is NULL.
 *
 * @param bus                 Bus number the device is located on. This is only
 *                              used if device_identifier is NULL.
 *
 * @param addr                Bus address the device is located on. This is only
 *                              used if device_identifier is NULL.
 *
 * @param file                Filename of the firmware image to boot
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 *
 *
 */
API_EXPORT
int CALL_CONV bladerf_load_fw_from_bootloader(const char *device_identifier,
                                              bladerf_backend backend,
                                              uint8_t bus, uint8_t addr,
                                              const char *file);

/** @} (End of FN_BOOTLOADER) */


/**
 * @defgroup FN_IMAGE Flash image format
 *
 * This section contains a file format and associated routines for storing
 * and loading flash contents with metadata.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/** Type of data stored in a flash image */
typedef enum {
    BLADERF_IMAGE_TYPE_INVALID = -1,  /**< Used to denote invalid value */
    BLADERF_IMAGE_TYPE_RAW,           /**< Misc. raw data */
    BLADERF_IMAGE_TYPE_FIRMWARE,      /**< Firmware data */
    BLADERF_IMAGE_TYPE_FPGA_40KLE,    /**< FPGA bitstream for 40 KLE device */
    BLADERF_IMAGE_TYPE_FPGA_115KLE,   /**< FPGA bitstream for 115  KLE device */
    BLADERF_IMAGE_TYPE_CALIBRATION,   /**< Board calibration */
    BLADERF_IMAGE_TYPE_RX_DC_CAL,     /**< RX DC offset calibration table */
    BLADERF_IMAGE_TYPE_TX_DC_CAL,     /**< TX DC offset calibration table */
    BLADERF_IMAGE_TYPE_RX_IQ_CAL,     /**< RX IQ balance calibration table */
    BLADERF_IMAGE_TYPE_TX_IQ_CAL,     /**< TX IQ balance calibration table */
} bladerf_image_type;

/**
 * Size of the magic signature at the beginning of bladeRF image files
 */
#define BLADERF_IMAGE_MAGIC_LEN 7

/**
 * Size of bladeRF flash image checksum
 */
#define BLADERF_IMAGE_CHECKSUM_LEN 32

/**
 * Size of reserved region of flash image
 */
#define BLADERF_IMAGE_RESERVED_LEN 128

/**
 * Image format for backing up and restoring bladeRF flash contents
 *
 * The on disk format generated by the bladerf_image_write function is a
 * serialized version of this structure and its contents. When written to disk,
 * values are converted to big-endian byte order, for ease of reading in a hex
 * editor.
 *
 * When creating and using a bladerf_image of type BLADERF_IMAGE_TYPE_RAW,
 * the address and length fields must be erase-block aligned.
 */
struct bladerf_image {

    /**
     * Magic value used to identify image file format.
     *
     * Note that an extra character is added to store a NUL-terminator,
     * to allow this field to be printed. This NUL-terminator is *NOT*
     * written in the serialized image.
     */
    char magic[BLADERF_IMAGE_MAGIC_LEN + 1];

    /**
     * SHA256 checksum of the flash image. This is computed over the entire
     * image, with this field filled with 0's.
     */
    uint8_t checksum[BLADERF_IMAGE_CHECKSUM_LEN];

    /**
     * Image format version. Only the major, minor, and patch fields are
     * written to the disk; the describe field is not used. The version is
     * serialized as: [major | minor | patch]
     */
    struct bladerf_version version;

    /** UTC image timestamp, in seconds since the Unix Epoch */
    uint64_t timestamp;

    /**
     * Serial number of the device that the image was obtained from. This
     * field should be all '\0' if irrelevant.
     *
     * The +1 here is actually extraneous; BLADERF_SERIAL_LENGTH already
     * accounts for a NUL terminator. However, this is left here to avoid
     * breaking backwards compatibility.
     */
    char serial[BLADERF_SERIAL_LENGTH + 1];

    /**
     * Reserved for future metadata. Should be 0's.
     */
    char reserved[BLADERF_IMAGE_RESERVED_LEN];

    /**
     * Type of data contained in the image. Serialized as a uint32_t.
     */
    bladerf_image_type type;

    /**
     * Address of the flash data in this image. A value of 0xffffffff
     * implies that this field is left unspecified (i.e., "don't care").
     */
    uint32_t address;

    /** Length of the data contained in the image */
    uint32_t length;

    /** Image data */
    uint8_t *data;
};

/**
 * Allocate and initialize an image structure.
 *
 * This following bladerf_image fields are populated: `magic`, `version`,
 * `timestamp`, `type`, `address`, and `length`
 *
 * The following bladerf_image fields are zeroed out:  `checksum`, `serial`, and
 * `reserved`,
 *
 * If the `length` parameter is not 0, the bladerf_image `data` field will be
 * dynamically allocated. Otherwise, `data` will be set to NULL.
 *
 * @note A non-zero `lenth` should be use only with bladerf_image_write();
 * bladerf_image_read() allocates and sets `data` based upon size of the image
 * contents, and does not attempt to free() the `data` field before setting it.
 *
 * The `address` and `length` fields should be set 0 when reading an image from
 * a file.
 *
 * @return Pointer to allocated and initialized structure on success,
 *         NULL on memory allocation failure or invalid address/length.
 */
API_EXPORT
struct bladerf_image * CALL_CONV bladerf_alloc_image(bladerf_image_type type,
                                                     uint32_t address,
                                                     uint32_t length);

/**
 * Create a flash image initialized to contain a calibration data region.
 * This is intended to be used in conjunction with bladerf_image_write(),
 * or a write of the image's `data` field to flash.
 *
 * @param   fpga_size    Target FPGA size
 * @param   vctcxo_trim  VCTCXO oscillator trim value.
 *
 * @return Pointer to allocated and initialized structure on success,
 *         NULL on memory allocation failure
 */
API_EXPORT
struct bladerf_image * CALL_CONV bladerf_alloc_cal_image(
                                                bladerf_fpga_size fpga_size,
                                                uint16_t vctcxo_trim);

/**
 * Free a bladerf_image previously obtained via bladerf_alloc_image.
 * If the bladerf_image's `data` field is non-NULL, it will be freed.
 */
API_EXPORT
void CALL_CONV bladerf_free_image(struct bladerf_image *image);


/**
 * Write a flash image to a file.
 *
 * This function will fill in the checksum field before writing the contents to
 * the specified file. The user-supplied contents of this field are ignored.
 *
 * @pre   `image` has been initialized using bladerf_alloc_image()
 * @post `image->checksum` will be populated if this function succeeds
 *
 * @param[in]    image       Flash image
 * @param[in]    file        File to write the flash image to
 *
 * @return 0 upon success, or a value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_image_write(struct bladerf_image *image,
                                  const char *file);

/**
 * Read flash image from a file.
 *
 * @param[out]   image      Flash image structure to populate.
 *
 * @param[in]    file       File to read image from.
 *
 * @pre  The `image` parameter has been obtained via a call to
 *       bladerf_alloc_image(), with a `length` of 0.
 *
 * @post The `image` fields will be populated upon success, overwriting
 *       any previous values.
 *
 * @note The contents of the `image` paramater should not be used if this
 *       function fails.
 *
 *
 * @return 0 upon success,<br>
 *         BLADERF_ERR_CHECKSUM upon detecting a checksum mismatch,<br>
 *         BLADERF_ERR_INVAL if any image fields are invalid,<br>
 *         BLADERF_ERR_IO on a file I/O error,<br>
 *         or a value from \ref RETCODES list on any other failure<br>
 */
API_EXPORT
int CALL_CONV bladerf_image_read(struct bladerf_image *image, const char *file);

/** @} (End of FN_IMAGE) */


/**
 * @defgroup LOW_LEVEL Low-level development and testing routines
 *
 * In a most cases, higher-level routines should be used. These routines are
 * only intended to support development and testing.
 *
 * Use these routines with great care, and be sure to reference the relevant
 * schematics, data sheets, and source code (i.e., firmware and hdl).
 *
 * Be careful when mixing these calls with higher-level routines that manipulate
 * the same registers/settings.
 *
 * These functions are thread-safe.
 *
 * @{
 */

/**
 * Read a Si5338 register
 *
 * @param   dev         Device handle
 * @param   address     Si5338 register offset
 * @param   val         Pointer to variable the data should be read into
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_si5338_read(struct bladerf *dev,
                                  uint8_t address, uint8_t *val);

/**
 * Write a Si5338 register
 *
 * @param   dev         Device handle
 * @param   address     Si5338 register offset
 * @param   val         Data to write to register
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_si5338_write(struct bladerf *dev,
                                   uint8_t address, uint8_t val);

/**
 * This structure is used to directly apply DC calibration register values to
 * the LMS, rather than use the values resulting from an auto-calibration.
 *
 * A value < 0 is used to denote that the specified value should not
 * be written.  If a value is to be written, it will be truncated to 8-bits.
 */
struct bladerf_lms_dc_cals
{
    int16_t lpf_tuning; /**< LPF tuning module */
    int16_t tx_lpf_i;   /**< TX LPF I filter */
    int16_t tx_lpf_q;   /**< TX LPF Q filter */
    int16_t rx_lpf_i;   /**< RX LPF I filter */
    int16_t rx_lpf_q;   /**< RX LPF Q filter */
    int16_t dc_ref;     /**< RX VGA2 DC reference module */
    int16_t rxvga2a_i;  /**< RX VGA2, I channel of first gain stage */
    int16_t rxvga2a_q;  /**< RX VGA2, Q channel of first gain stage */
    int16_t rxvga2b_i;  /**< RX VGA2, I channel of second gain stage */
    int16_t rxvga2b_q;  /**< RX VGA2, Q channel of second gain stage */
};

/**
 * Read a LMS register
 *
 * @param   dev         Device handle
 * @param   address     LMS register offset
 * @param   val         Pointer to variable the data should be read into
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_lms_read(struct bladerf *dev,
                               uint8_t address, uint8_t *val);

/**
 * Write a LMS register
 *
 * @param   dev         Device handle
 * @param   address     LMS register offset
 * @param   val         Data to write to register
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_lms_write(struct bladerf *dev,
                                uint8_t address, uint8_t val);

/**
 * Manually load values into LMS6002 DC calibration registers.
 *
 * This is generally intended for applying a set of known values resulting from
 * a previous run of the LMS autocalibrations.
 *
 * @param   dev        Device handle
 * @param   dc_cals    Calibration values to load. Values set to <0 will
 *                     not be applied.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_lms_set_dc_cals(struct bladerf *dev,
                                     const struct bladerf_lms_dc_cals *dc_cals);

/**
 * Retrieve the current DC calibration values from the LMS6002
 *
 * @param[in]   dev        Device handle
 * @param[out]  dc_cals    Populated with current values
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_lms_get_dc_cals(struct bladerf *dev,
                                      struct bladerf_lms_dc_cals *dc_cals);

/**
 * Enable LMS receive
 *
 * @note This bit is set/cleared by bladerf_enable_module()
 */
#define BLADERF_GPIO_LMS_RX_ENABLE (1 << 1)

/**
 * Enable LMS transmit
 *
 * @note This bit is set/cleared by bladerf_enable_module()
 */
#define BLADERF_GPIO_LMS_TX_ENABLE  (1 << 2)

/**
 * Switch to use TX low band (300MHz - 1.5GHz)
 *
 * @note This is set using bladerf_set_frequency().
 */
#define BLADERF_GPIO_TX_LB_ENABLE   (2 << 3)

/**
 * Switch to use TX high band (1.5GHz - 3.8GHz)
 *
 * @note This is set using bladerf_set_frequency().
 */
#define BLADERF_GPIO_TX_HB_ENABLE   (1 << 3)

/**
 * Counter mode enable
 *
 * Setting this bit to 1 instructs the FPGA to replace the (I, Q) pair in
 * sample data with an incrementing, little-endian, 32-bit counter value. A
 * 0 in bit specifies that sample data should be sent (as normally done).
 *
 * This feature is useful when debugging issues involving dropped samples.
 */
#define BLADERF_GPIO_COUNTER_ENABLE (1 << 9)


/**
 * Bit mask representing the rx mux selection
 *
 * @note These bits are set using bladerf_set_rx_mux()
 */
#define BLADERF_GPIO_RX_MUX_MASK (0x7 << BLADERF_GPIO_RX_MUX_SHIFT)

/**
 * Starting bit index of the RX mux values in FX3 <-> FPGA GPIO bank
 */
#define BLADERF_GPIO_RX_MUX_SHIFT 8

/**
 * Switch to use RX low band (300M - 1.5GHz)
 *
 * @note This is set using bladerf_set_frequency().
 */
#define BLADERF_GPIO_RX_LB_ENABLE   (2 << 5)

/**
 * Switch to use RX high band (1.5GHz - 3.8GHz)
 *
 * @note This is set using bladerf_set_frequency().
 */
#define BLADERF_GPIO_RX_HB_ENABLE   (1 << 5)

/**
 * AGC enable control bit
 *
 * @note This is set using bladerf_set_gain_mode().
 */
#define BLADERF_GPIO_AGC_ENABLE     (1 << 12)

/**
 * This GPIO bit configures the FPGA to use smaller DMA
 * transfers (256 cycles instead of 512). This is required
 * when the device is not connected at Super Speed (i.e., when
 * it is connected at High Speed).
 *
 * However, the caller need not set this in bladerf_config_gpio_write() calls.
 * The library will set this as needed; callers generally
 * do not need to be concerned with setting/clearing this bit.
 */
#define BLADERF_GPIO_FEATURE_SMALL_DMA_XFER (1 << 7)

/**
 * Enable-bit for timestamp counter in the FPGA
 */
#define BLADERF_GPIO_TIMESTAMP      (1 << 16)

/**
 * Timestamp 2x divider control.
 *
 * @note <b>Important</b>: This bit has no effect and is always enabled (1) in
 *                         FPGA versions >= v0.3.0.
 *
 * @note The remainder of the description of this bit is presented here for
 *       historical purposes only. It is relevant to FPGA versions <= v0.1.2.
 *
 *
 * By default (value = 0), the sample counter is incremented with I and Q,
 * yielding two counts per sample.
 *
 * Set this bit to 1 to enable a 2x timestamp divider, effectively
 * achieving 1 timestamp count per sample.
 * */
#define BLADERF_GPIO_TIMESTAMP_DIV2 (1 << 17)

/**
 * Read a configuration GPIO register
 *
 * @param   dev         Device handle
 * @param   val         Pointer to variable the data should be read into
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_config_gpio_read(struct bladerf *dev, uint32_t *val);

/**
 * Write a configuration GPIO register. Callers should be sure to perform a
 * read-modify-write sequence to avoid accidentally clearing other
 * GPIO bits that may be set by the library internally.
 *
 * @param   dev         Device handle
 * @param   val         Data to write to GPIO register
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_config_gpio_write(struct bladerf *dev, uint32_t val);

/**
 * Write value to secondary XB SPI
 *
 * @param   dev         Device handle
 * @param   val         Data to write to XB SPI
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_xb_spi_write(struct bladerf *dev, uint32_t val);


/**
 * Perform DC calibration
 *
 * @param   dev         Device handle
 * @param   module      Module to calibrate
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_calibrate_dc(struct bladerf *dev,
                                   bladerf_cal_module module);

/**
 * Trigger control register "Arm" bit
 *
 * This bit arms (i.e., enables) the trigger controller when set to 1. Samples
 * will be gated until the "Fire" bit has been asserted.
 *
 * A 0 in this bit disables the trigger controller. Samples will continue
 * to flow as they normally do in this state.
 */
#define BLADERF_TRIGGER_REG_ARM     ((uint8_t) (1 << 0))

/**
 * Trigger control register "Fire" bit
 *
 * For a master, this bit causes a trigger to be sent to all slave devices. Once
 * this trigger is received (the master "receives" it immediately as well),
 * devices begin streaming samples.
 *
 * This bit has no effect on slave devices.
 */
#define BLADERF_TRIGGER_REG_FIRE    ((uint8_t) (1 << 1))

/**
 * Trigger control register "Master" bit
 *
 * Selects whether the device is a trigger master (1) or trigger slave (0).
 * The trigger master drives the trigger signal as an output.
 * Slave devices configure the trigger signal as an input.
 */
#define BLADERF_TRIGGER_REG_MASTER  ((uint8_t) (1 << 2))

/**
 * Trigger control registers "line" bit
 *
 * This is a read-only register bit that denotes the current state of the
 * the trigger signal.
 */
#define BLADERF_TRIGGER_REG_LINE    ((uint8_t) (1 << 3))

/**
 * Read trigger control register
 *
 * @param   dev             Device handle
 * @param   module          Module to read from
 * @param   signal          Trigger signal (control register) to read from
 * @param   val             Pointer to variable that register is read into
 *                          See the BLADERF_TRIGGER_REG_* macros for the meaning
 *                          of each bit.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_read_trigger(struct bladerf *dev,
                                   bladerf_module module,
                                   bladerf_trigger_signal signal,
                                   uint8_t *val);

/**
 * Write trigger control register
 *
 * @param   dev             Device handle
 * @param   module          Module to configure
 * @param   signal          Trigger signal to configure
 * @param   val             Data to write into the trigger control register.
 *                          See the BLADERF_TRIGGER_REG_* macros for options.
 *
 * @return 0 on success, value from \ref RETCODES list on failure
 */
API_EXPORT
int CALL_CONV bladerf_write_trigger(struct bladerf *dev,
                                    bladerf_module module,
                                    bladerf_trigger_signal signal,
                                    uint8_t val);

/** @} (End of LOW_LEVEL) */

/**
 * @defgroup FN_FLASH  Low-level flash routines
 *
 * These routines provide the ability to manipulate the device's SPI flash.
 * Most users will find no reason to use these, as higher-level functions
 * perform flash accesses under the hood.
 *
 * These routines are not recommended for use other than testing, development,
 * and significant customization of the bladeRF platform (which would require
 * firmware and libbladeRF changes).
 *
 * Use of these functions requires an understanding of the underlying SPI
 * flash device, and the bladeRF's flash memory map. Be sure to review the
 * following page and the associated flash datasheet before using these
 * functions:
 *   https://github.com/nuand/bladeRF/wiki/FX3-Firmware#spi-flash-layout
 *
 * These functions are thread-safe.
 *
 * @{
 */

/** Total size of bladeRF SPI flash, in bytes */
#define BLADERF_FLASH_TOTAL_SIZE  (4 * 1024 * 1024)

/** SPI flash page size, in bytes */
#define BLADERF_FLASH_PAGE_SIZE   256

/** SPI flash 64KiB erase block size, in bytes */
#define BLADERF_FLASH_EB_SIZE     (64 * 1024)

/** Size of the SPI flash, in pages */
#define BLADERF_FLASH_NUM_PAGES \
    (BLADERF_FLASH_TOTAL_SIZE / BLADERF_FLASH_PAGE_SIZE)

/** Size of the SPI flash, in 64KiB erase blocks */
#define BLADERF_FLASH_NUM_EBS \
    (BLADERF_FLASH_TOTAL_SIZE / BLADERF_FLASH_EB_SIZE)



/** Convert byte addresses to units of flash pages */
#define BLADERF_FLASH_TO_PAGES(bytes) ((bytes) / BLADERF_FLASH_PAGE_SIZE)

/** Convert byte addresses to units of flash erase blocks */
#define BLADERF_FLASH_TO_EB(bytes)    ((bytes) / BLADERF_FLASH_EB_SIZE)



/** Byte address of FX3 firmware */
#define BLADERF_FLASH_ADDR_FIRMWARE     0x00000000

/** Flash page where FX3 firmware starts */
#define BLADERF_FLASH_PAGE_FIRMWARE \
            (BLADERF_FLASH_TO_PAGES(BLADERF_FLASH_ADDR_FIRMWARE))

/** Flash erase block where FX3 firmware starts */
#define BLADERF_FLASH_EB_FIRMWARE \
            (BLADERF_FLASH_TO_EB(BLADERF_FLASH_ADDR_FIRMWARE))

/** Length of firmware region of flash, in bytes */
#define BLADERF_FLASH_BYTE_LEN_FIRMWARE 0x00030000

/** Length of firmware region of flash, in pages */
#define BLADERF_FLASH_PAGE_LEN_FIRMWARE \
            (BLADERF_FLASH_TO_PAGES(BLADERF_FLASH_BYTE_LEN_FIRMWARE))

/** Length of firmware region of flash, in erase blocks */
#define BLADERF_FLASH_EB_LEN_FIRMWARE \
            (BLADERF_FLASH_TO_EB(BLADERF_FLASH_BYTE_LEN_FIRMWARE))


/** Byte address of calibration data region */
#define BLADERF_FLASH_ADDR_CAL  0x00030000

/** Flash page where calibration data starts */
#define BLADERF_FLASH_PAGE_CAL  (BLADERF_FLASH_TO_PAGES(BLADERF_FLASH_ADDR_CAL))

/** Flash erase block where calibration data starts */
#define BLADERF_FLASH_EB_CAL    (BLADERF_FLASH_TO_EB(BLADERF_FLASH_ADDR_CAL))

/** Length of calibration data, in bytes */
#define BLADERF_FLASH_BYTE_LEN_CAL 0x100

/** Length of calibration data, in pages */
#define BLADERF_FLASH_PAGE_LEN_CAL \
            (BLADERF_FLASH_TO_PAGES(FLASH_BYTE_LEN_CAL))

/**
 * Length of calibration data, in erase blocks. This is a special case,
 * as the entire remainder of the erase block is reserved for future calibration
 * data use. When updating calibration data, the whole block will be erased,
 * even though the current firmware only uses one page of it. */
#define BLADERF_FLASH_EB_LEN_CAL 1


/**
 * Byte address of of the autoloaded FPGA and associated metadata.
 * The first page is allocated for metadata, and the FPGA bitstream resides
 * in the following pages.
 */
#define BLADERF_FLASH_ADDR_FPGA 0x00040000

/** Flash page where FPGA metadata and bitstream start */
#define BLADERF_FLASH_PAGE_FPGA \
            (BLADERF_FLASH_TO_PAGES(BLADERF_FLASH_ADDR_FPGA))

/** Flash erase block where FPGA metadata and bitstream start */
#define BLADERF_FLASH_EB_FPGA \
            (BLADERF_FLASH_TO_EB(BLADERF_FLASH_ADDR_FPGA))

/** Length of entire FPGA region, including both metadata and bitstream. */
#define BLADERF_FLASH_BYTE_LEN_FPGA 0x00370000

/** Length of entire FPGA region, in units of erase blocks */
#define BLADERF_FLASH_EB_LEN_FPGA \
            (BLADERF_FLASH_TO_EB(BLADERF_FLASH_BYTE_LEN_FPGA))

/**
 * Erase regions of the bladeRF's SPI flash
 *
 * This function operates in units of 64KiB erase blocks
 *
 * @param   dev             Device handle
 * @param   erase_block     Erase block to start erasing at
 * @param   count           Number of blocks to erase.
 *
 * @return 0 on success, or BLADERF_ERR_INVAL on an invalid `erase_block` or
 *         `count` value, or a value from \ref RETCODES list on other failures
 */
API_EXPORT
int CALL_CONV bladerf_erase_flash(struct bladerf *dev,
                                  uint32_t erase_block, uint32_t count);

/**
 * Read data from the bladeRF's SPI flash
 *
 * This function operates in units of 256-byte pages.
 *
 * @param   dev     Device handle
 * @param   buf     Buffer to read data into. Must be
 *                  `count` * BLADERF_FLASH_PAGE_SIZE bytes or larger.
 *
 * @param   page    Page to begin reading from
 * @param   count   Number of pages to read
 *
 * @return 0 on success, or BLADERF_ERR_INVAL on an invalid `page` or
 *         `count` value, or a value from \ref RETCODES list on other failures.
 */
API_EXPORT
int CALL_CONV bladerf_read_flash(struct bladerf *dev, uint8_t *buf,
                                 uint32_t page, uint32_t count);

/**
 * Write data to the bladeRF's SPI flash device
 *
 * @param   dev   Device handle
 * @param   buf   Data to write to flash
 *
 * @param   page  Page to begin writing at
 * @param   count Number of pages to write
 *
 * @return 0 on success, or BLADERF_ERR_INVAL on an invalid `page` or
 *         `count` value, or a value from \ref RETCODES list on other failures.
 */
API_EXPORT
int CALL_CONV bladerf_write_flash(struct bladerf *dev, const uint8_t *buf,
                                  uint32_t page, uint32_t count);

/** @} (End of FN_FLASH) */

/**
 * @defgroup    RETCODES    Error codes
 *
 * bladeRF library routines return negative values to indicate errors.
 * Values >= 0 are used to indicate success.
 *
 * @code
 *  int status = bladerf_set_txvga1(dev, 2);
 *
 *  if (status < 0)
 *      handle_error();
 * @endcode
 *
 * @{
 */
#define BLADERF_ERR_UNEXPECTED  (-1)  /**< An unexpected failure occurred */
#define BLADERF_ERR_RANGE       (-2)  /**< Provided parameter is out of range */
#define BLADERF_ERR_INVAL       (-3)  /**< Invalid operation/parameter */
#define BLADERF_ERR_MEM         (-4)  /**< Memory allocation error */
#define BLADERF_ERR_IO          (-5)  /**< File/Device I/O error */
#define BLADERF_ERR_TIMEOUT     (-6)  /**< Operation timed out */
#define BLADERF_ERR_NODEV       (-7)  /**< No device(s) available */
#define BLADERF_ERR_UNSUPPORTED (-8)  /**< Operation not supported */
#define BLADERF_ERR_MISALIGNED  (-9)  /**< Misaligned flash access */
#define BLADERF_ERR_CHECKSUM    (-10) /**< Invalid checksum */
#define BLADERF_ERR_NO_FILE     (-11) /**< File not found */
#define BLADERF_ERR_UPDATE_FPGA (-12) /**< An FPGA update is required */
#define BLADERF_ERR_UPDATE_FW   (-13) /**< A firmware update is requied */
#define BLADERF_ERR_TIME_PAST   (-14) /**< Requested timestamp is in the past */
#define BLADERF_ERR_QUEUE_FULL  (-15) /**< Could not enqueue data into
                                       *   full queue */
#define BLADERF_ERR_FPGA_OP     (-16) /**< An FPGA operation reported failure */
#define BLADERF_ERR_PERMISSION  (-17) /**< Insufficient permissions for the
                                       *   requested operation */
#define BLADERF_ERR_WOULD_BLOCK (-18) /**< Operation would block, but has been
                                       *   requested to be non-blocking. This
                                       *   indicates to a caller that it may
                                       *   need to retry the operation later.
                                       */

/**
 * Obtain a textual description of a value from the \ref RETCODES list
 *
 * @warning Do not attempt to modify the returned string.
 *
 * @param   error   Error value to look up
 * @return  Error string
 */
API_EXPORT
const char * CALL_CONV bladerf_strerror(int error);

/** @} (End RETCODES) */


#ifdef __cplusplus
}
#endif

#endif /* BLADERF_H_ */
