/* Copyright 2017 Jetperch LLC.  All rights reserved. */

/**
 * @file
 *
 * @brief JouleScope settings.
 */

#ifndef JS110_HOST_API_H__
#define JS110_HOST_API_H__

#include "jsdrv/cmacro_inc.h"
#include <stdint.h>
#include <stdbool.h>

JSDRV_CPP_GUARD_START

/**
 * @ingroup joulescope
 * @defgroup js110_host_api Host API
 *
 * @brief The Host API for the messages over USB between the PC and control
 *      microcontroller.
 *
 * @{
 */

#define JS110_HOST_API_VERSION (1)

/**
 * @brief The Joulescope streaming data source.
 *
 * The Joulescope host-side uses bits [3:0].  Bits [7:4] map directly to the
 * sensor FPGA's source register.
 */
enum js110_host_source_e {
    JS110_SOURCE_OFF = 0,                ///< No streaming data (default)
    JS110_SOURCE_PATTERN_BIT = 0x08,     ///< Reserved (test pattern flag)
    JS110_SOURCE_PATTERN_USB = 0x09,     ///< Test pattern data generated by control uC
    JS110_SOURCE_PATTERN_CONTROL = 0x0A, ///< Test pattern data generated by control FPGA
    JS110_SOURCE_PATTERN_SENSOR = 0xAF,  ///< Test pattern data generated by sensor FPGA
    JS110_SOURCE_RAW = 0xC0,             ///< Raw ADC data
};

/**
 * @brief The USB stream data packet type identifier.
 */
enum js110_host_packet_type_e {
    JS110_PACKET_TYPE_UNKNOWN = 0,
    JS110_PACKET_TYPE_RAW = 1,
    JS110_PACKET_TYPE_TEST_PATTERN = 0x80,
};


/**
 * @brief The vendor-specific USB device control requests.
 */
enum js110_host_usb_requests_e {
    /// USB testing for 16-bit value, use wValue
    JS110_HOST_USB_REQUEST_LOOPBACK_WVALUE = 1,

    /// USB testing for messages up to USBD_APP_LOOPBACK_BUFFER_SIZE bytes
    JS110_HOST_USB_REQUEST_LOOPBACK_BUFFER = 2,

    /// Configure operation, including starting streaming
    JS110_HOST_USB_REQUEST_SETTINGS = 3,

    /// Get current status
    JS110_HOST_USB_REQUEST_STATUS = 4,

    /**
     * @brief Sensor bootloader operation.
     *
     * Command in wValue.  See js110_host_sensor_bootloader_e.
     * While sensor bootloader is enable, all normal operation is halted.
     */
    JS110_HOST_USB_REQUEST_SENSOR_BOOTLOADER = 5,

    /**
     * @brief Controller bootloader operation.
     *
     * Request to enter the controller bootloader.  The device will disconnect
     * and then reconnect as the USB bootloader.
     */
    JS110_HOST_USB_REQUEST_ENTER_BOOTLOADER = 6,

    /**
     * @brief Get the 16-byte serial number
     */
    JS110_HOST_USB_REQUEST_SERIAL_NUMBER = 7,

    /**
     * @brief Get the calibration record.
     */
    JS110_HOST_USB_REQUEST_CALIBRATION = 8,
    
    /**
     * @brief Get/set the external GPI/O settings.
     *
     * The payload is struct js110_host_extio_s.
     */
    JS110_HOST_USB_REQUEST_EXTIO = 9,
    
    /**
     * @brief Get the JSON-formatted information metadata.
     *
     * The device returns information including firmware & fpga versions.
     */
    JS110_HOST_USB_REQUEST_INFO = 10,

    /**
     * @brief Enter a test mode.
     */
    JS110_HOST_USB_TEST_MODE = 11,
};

/**
 * @brief The sensor bootloader subcommands for JS110_HOST_USB_REQUEST_SENSOR_BOOTLOADER.
 */
enum js110_host_sensor_bootloader_e {
    /// Enable the sensor bootloader [wIndex=0, wLength=0]
    JS110_HOST_SENSOR_BOOTLOADER_START = 1,
    /// Resume normal operation [wIndex=0, wLength=0]
    JS110_HOST_SENSOR_BOOTLOADER_RESUME = 2,
    /// Erase all flash on the sensor microcontroller [wIndex=0, wLength=0]
    JS110_HOST_SENSOR_BOOTLOADER_ERASE = 3,

    /// Write a flash block [wIndex=block_index, wLength=256*N] where offset_bytes = block_index * 256
    JS110_HOST_SENSOR_BOOTLOADER_WRITE = 4,
};


/**
 * @brief The data test mode bitmap.
 */
enum js110_host_streaming_e {
    JS110_HOST_STREAMING_USB = 0x01,       ///< Enable USB communications
    JS110_HOST_STREAMING_FPGA = 0x02,      ///< Enable FPGA communications
    JS110_HOST_STREAMING_LOOPBACK = 0x80,  ///< Enable loopback test mode
};

enum js110_host_packet_type_s {
    JS110_HOST_PACKET_TYPE_SETTINGS = 1,
    JS110_HOST_PACKET_TYPE_STATUS = 2,
    JS110_HOST_PACKET_TYPE_EXTIO = 3,
    JS110_HOST_PACKET_TYPE_INFO = 4,
};

struct js110_host_header_s {
    uint8_t version;    ///< The JS110_HOST_API_VERSION version
    uint8_t length;     ///< The total length of the packet, including header.
    uint8_t type;       ///< The js110_host_packet_type_s.
    uint8_t rsv1;       ///< Reserved: Force to 4-byte boundary
    uint32_t rsv4;      ///< Reserved: Force to 8-byte boundary
};

/**
 * @brief The Joulescope settings packet payload.
 */
struct js110_host_settings_s {
    uint8_t sensor_power;   // 0=off, 1=on (default=0 with USB 500 mA power)
    uint8_t select;         // bitmap for sensor FPGA select register
    uint8_t source;         // js110_host_source_e (default=0) (upper nibble for sensor FPGA source register)
    uint8_t options;        // bitmap for sensor FPGA options register
    uint8_t streaming;      // bitmap: see js110_host_streaming_e (default=0x00)
    uint8_t rsv1_u8;
    uint8_t rsv2_u8;
    uint8_t rsv3_u8;
};

enum js110_host_extio_trigger_source_e {
    JS110_HOST_EXTIO_TRIGGER_SOURCE_AUTO = 0,
    JS110_HOST_EXTIO_TRIGGER_SOURCE_GPI0 = 2,
    JS110_HOST_EXTIO_TRIGGER_SOURCE_GPI1 = 3,
};

enum js110_host_extio_gpi_e {
    JS110_HOST_EXTIO_NORMAL = 0,
    JS110_HOST_EXTIO_GPI0_LSB = 2,
    JS110_HOST_EXTIO_GPI1_LSB = 3
};

enum js110_host_extio_gpo0_e {
    JS110_HOST_EXTIO_GPO0_0 = 0,
    JS110_HOST_EXTIO_GPO0_1 = 1,
    JS110_HOST_EXTIO_GPO0_START_PULSE = 2,
    JS110_HOST_EXTIO_GPO0_SAMPLE_TOGGLE = 3,
};

enum js110_host_extio_gpo1_e {
    JS110_HOST_EXTIO_GPO1_0 = 0,
    JS110_HOST_EXTIO_GPO1_1 = 1,
};

enum js110_host_extio_uartrx_e {
    JS110_HOST_EXTIO_UARTRX_0 = 0,
    JS110_HOST_EXTIO_UARTRX_1 = 1,
    JS110_HOST_EXTIO_UARTRX_GPI0 = 2,
    JS110_HOST_EXTIO_UARTRX_GPI1 = 3,
};

struct js110_host_extio_s {
    uint8_t flags;
    uint8_t trigger_source;
    uint8_t current_gpi;
    uint8_t voltage_gpi;
    uint8_t gpo0;
    uint8_t gpo1;
    uint8_t rsv0_u8;  // reserved for uart_rx mapping
    uint8_t gpi_value;  // IN (read) only, write (OUT) is ignored.
    uint32_t rsv3_u32;  // reserved for for baudrate
    uint32_t io_voltage_mv;
};

/**
 * @brief The Joulescope status packet payload.
 */
struct js110_host_status_s {
    /**
     * @brief The status of the last JS110_HOST_PACKET_TYPE_SETTINGS.
     *
     * The possible values are:
     * - 0: success
     * - -1: Not yet issued
     * - EMBC_ERROR_BUSY: in progress
     * - All other: error code.
     */
    int32_t settings_result;

    /// The FPGA status;
    uint32_t fpga_frame_counter;
    /// The total number of discarded FPGA data frames.
    uint32_t fpga_discard_counter;

    /// The sensor FPGA flags register.
    uint8_t sensor_flags;

    /// The sensor FPGA select register.
    uint8_t sensor_select;

    /// The sensor FPGA source register.
    uint8_t sensor_source;

    /// The sensor FPGA options register.
    uint8_t sensor_options;

    /// The total number of samples used to compute charge and energy
    int64_t samples_total;
    int64_t power_mean;         // Q34
    int64_t charge;             // Q27 - rollover in 34 years, 7.5 nC
    int64_t energy;             // Q27 - rollover in 2 years,  7.5 nJ

    /// The number of samples in this window.  0 for no update.
    int32_t samples_this;
    /// The number of samples in each update.
    int32_t samples_per_update;
    /// The number of samples per second.
    int32_t samples_per_second;
    int32_t current_mean;       // Q27, 7.5 nA
    int32_t current_min;        // Q27
    int32_t current_max;        // Q27
    int32_t voltage_mean;       // Q17, 7.6 uV
    int32_t voltage_min;        // Q17
    int32_t voltage_max;        // Q17
    int32_t power_min;          // Q21
    int32_t power_max;          // Q21
    int32_t i32_rsv;
};

/**
 * @brief The Joulescope packet.
 */
struct js110_host_packet_s {
    /// The common header
    struct js110_host_header_s header;

    /// The payload differentiated by header.type
    union {
        struct js110_host_settings_s settings;
        struct js110_host_status_s status;
        struct js110_host_extio_s extio;
    } payload;
};

/**
 * @brief Validate a host buffer header.
 *
 * @param buffer The buffer containing js110_host_packet_s.
 * @param length The length of buffer which can be longer than required.
 * @return 0 if the buffer contains valid js110_host_packet_s data,
 *      error code otherwise.
 */
int32_t js110_host_header_validate(uint8_t const * buffer, uint16_t length);

/**
 * @brief Validate a buffer containing js110_host_settings_s.
 *
 * @param buffer The buffer containing js110_host_settings_s.
 * @param length The length of buffer which can be longer than required.
 * @return 0 if the buffer contains valid js110_host_settings_s data,
 *      error code otherwise.
 */
int32_t js110_host_settings_validate(uint8_t const * buffer, uint16_t length);


/** @} */

JSDRV_CPP_GUARD_END

#endif /* JS110_HOST_API_H__ */
