/*******************************************************************************
 * @file    dr_adc121s051.h
 * @brief   ADC121S051 12-bit ADC Driver for nRF52840
 *          For 1.2MHz Piezo Echo Envelope Detection
 * @author  Charles KWON
 * @date    2025-12-15
 * 
 * @details This driver reads the envelope-detected DC level from piezo echo.
 *          
 *          Signal Flow:
 *          
 *          [Piezo TX]    [Echo RX]    [Envelope]    [ADC]      [MCU]
 *          1.2MHz   -->  Reflect  -->  Detector -->  DC Level --> Digital
 *          burst         signal        (hardware)    reading     value
 *          
 *          The envelope detector circuit converts the 1.2MHz echo burst
 *          into a DC voltage proportional to the echo amplitude.
 *          ADC samples this DC level for amplitude measurement.
 * 
 * @note    Hardware: Texas Instruments ADC121S051
 *          - 12-bit resolution (0-4095)
 *          - Sample rate: 200-500 ksps
 *          - Input range: 0V to VA
 *          - SPI interface (software bit-bang)
 ******************************************************************************/

#ifndef DR_ADC121S051_H
#define DR_ADC121S051_H

#include <stdint.h>
#include <stdbool.h>
#include "nrf_gpio.h"

/*==============================================================================
 * PIN CONFIGURATION
 * 
 * WARNING: Never hardcode pin numbers!
 * Hardcoding may save a developer's time momentarily,
 * but it will also shorten their lifespan.
 *============================================================================*/
#define DR_ADC_PIN_SCLK         NRF_GPIO_PIN_MAP(0, 14)  /**< Serial Clock */
#define DR_ADC_PIN_SDATA        NRF_GPIO_PIN_MAP(0, 15)  /**< Serial Data (MISO) */
#define DR_ADC_PIN_CS           NRF_GPIO_PIN_MAP(0, 19)  /**< Chip Select P0.13 -> P0.19 */

/*==============================================================================
 * ADC SPECIFICATIONS
 *============================================================================*/
#define DR_ADC_RESOLUTION       12          /**< Bits */
#define DR_ADC_MAX_VALUE        4095        /**< 2^12 - 1 */
#define DR_ADC_VREF_MV          3300        /**< Reference voltage (mV) */

/*==============================================================================
 * ECHO DETECTION CONFIGURATION
 *
 * Bladder Measurement Requirements:
 *   - Target measurement range: 20cm (200mm)
 *   - SCLK frequency: 8.6MHz (bit-bang SPI)
 *   - ADC121S051 requires 16 SCLK cycles per sample
 *   - Actual sample rate: 8.6MHz / 16 = 0.5375MHz = 537.5kHz
 *   - Actual sample interval: 16 / 8.6MHz = 1.86us
 *   - Sound speed in tissue: 1540m/s = 1.54mm/us
 *
 *   Formula: samples = distance(mm) * 2 / (1.86us * 1.54mm/us)
 *                    = distance(mm) * 2 / 2.86
 *                    = distance(mm) * 0.7
 *
 *   10cm = 100mm -> 100 * 0.7 =  70 samples (round-trip 130us)
 *   17cm = 170mm -> 170 * 0.7 = 119 samples (round-trip 221us)
 *   20cm = 200mm -> 200 * 0.7 = 140 samples (round-trip 260us)
 *
 *   Buffer size: 200 samples * 2 bytes = 400 bytes (RAM 256KB, OK)
 *   BLE transmission: 140 samples * 2 bytes = 280 bytes (16-bit raw, no packing)
 *============================================================================*/
#define DR_ADC_SCLK_MHZ             8.6f    /**< SPI bit-bang SCLK frequency */
#define DR_ADC_CLOCKS_PER_SAMPLE    16      /**< ADC121S051: 16 SCLK per sample */
#define DR_ADC_ECHO_SAMPLES_MAX     100     /**< Maximum samples */
#define DR_ADC_ECHO_SAMPLES_DEFAULT 100     /**< Default samples */
#define DR_ADC_SAMPLE_INTERVAL_US   1.86f   /**< 16 / 8.6MHz = 1.86us per sample */
#define DR_ADC_SOUND_SPEED_MM_US    1.54f   /**< Sound speed in tissue (mm/us) */

/*==============================================================================
 * ERROR CODES
 *============================================================================*/
typedef enum {
    DR_ADC_OK = 0,
    DR_ADC_ERR_NOT_INIT,
    DR_ADC_ERR_INVALID_PARAM,
    DR_ADC_ERR_NO_ECHO
} dr_adc_err_t;

/*==============================================================================
 * DATA STRUCTURES
 *============================================================================*/

/**
 * @brief Single ADC reading result
 */
typedef struct {
    uint16_t raw;               /**< Raw 12-bit value (0-4095) */
    uint32_t voltage_mv;        /**< Voltage in millivolts */
} dr_adc_result_t;

/**
 * @brief Echo measurement result
 */
typedef struct {
    uint16_t peak_raw;          /**< Peak amplitude (raw) */
    uint32_t peak_mv;           /**< Peak amplitude (mV) */
    uint16_t peak_index;        /**< Sample index of peak */
    uint32_t peak_time_us;      /**< Time to peak (us) */
    uint16_t baseline_raw;      /**< Baseline level before echo */
    uint16_t num_samples;       /**< Number of samples captured */
} dr_adc_echo_t;

/**
 * @brief Echo capture configuration
 */
typedef struct {
    uint16_t num_samples;       /**< Samples to capture (1-200) */
    uint16_t threshold_raw;     /**< Minimum peak threshold */
    uint16_t delay_us;          /**< Delay before capture starts */
} dr_adc_echo_config_t;

/*==============================================================================
 * INITIALIZATION
 *============================================================================*/

/**
 * @brief Initialize ADC driver
 * @return dr_adc_err_t Error code
 */
dr_adc_err_t dr_adc_init(void);

/**
 * @brief Uninitialize ADC driver
 */
void dr_adc_uninit(void);

/**
 * @brief Check if initialized
 */
bool dr_adc_is_initialized(void);

/*==============================================================================
 * BASIC READ FUNCTIONS
 *============================================================================*/

/**
 * @brief Read single ADC value
 * @param result Pointer to result structure
 * @return dr_adc_err_t Error code
 */
dr_adc_err_t dr_adc_read(dr_adc_result_t *result);

/**
 * @brief Read raw 12-bit value only
 * @param raw_value Pointer to store value
 * @return dr_adc_err_t Error code
 */
dr_adc_err_t dr_adc_read_raw(uint16_t *raw_value);

/**
 * @brief Read averaged value
 * @param result Pointer to result structure
 * @param num_samples Number of samples to average (1-256)
 * @return dr_adc_err_t Error code
 */
dr_adc_err_t dr_adc_read_averaged(dr_adc_result_t *result, uint16_t num_samples);

/*==============================================================================
 * ECHO DETECTION FUNCTIONS
 *============================================================================*/

/**
 * @brief Capture echo envelope after piezo burst
 * @param buffer Array to store samples (must be pre-allocated)
 * @param num_samples Number of samples to capture
 * @return dr_adc_err_t Error code
 * 
 * @note Call this immediately after dr_piezo_burst_sw()
 */
dr_adc_err_t dr_adc_capture_echo(uint16_t *buffer, uint16_t num_samples);

/**
 * @brief Capture and analyze echo in one call
 * @param echo Pointer to echo result structure
 * @param config Pointer to capture configuration (NULL for defaults)
 * @return dr_adc_err_t Error code
 */
dr_adc_err_t dr_adc_measure_echo(dr_adc_echo_t *echo, const dr_adc_echo_config_t *config);

/**
 * @brief Piezo burst + Echo capture in one call
 * @param cycles Number of burst cycles (3~7)
 * @param delay_us Delay before capture (us)
 * @param num_samples Number of samples to capture
 * @param echo Pointer to echo result structure
 * @return dr_adc_err_t Error code
 */
dr_adc_err_t dr_adc_burst_and_capture(uint8_t cycles, uint16_t delay_us,
                                       uint16_t num_samples, dr_adc_echo_t *echo);

/**
 * @brief Get pointer to last captured echo buffer
 * @return Pointer to internal buffer (valid until next capture)
 * @note Buffer contains num_samples values from last burst_and_capture call
 */
const uint16_t* dr_adc_get_echo_buffer(void);

/**
 * @brief Analyze captured echo buffer
 * @param buffer Sample buffer
 * @param num_samples Number of samples in buffer
 * @param echo Pointer to echo result structure
 * @param threshold Minimum threshold for valid peak
 * @return dr_adc_err_t Error code
 */
dr_adc_err_t dr_adc_analyze_echo(const uint16_t *buffer, uint16_t num_samples,
                                  dr_adc_echo_t *echo, uint16_t threshold);

/**
 * @brief Find peak in buffer
 * @param buffer Sample buffer
 * @param num_samples Number of samples
 * @param peak_value Pointer to store peak value
 * @param peak_index Pointer to store peak index (can be NULL)
 */
void dr_adc_find_peak(const uint16_t *buffer, uint16_t num_samples,
                      uint16_t *peak_value, uint16_t *peak_index);

/**
 * @brief Calculate baseline (average of first N samples)
 * @param buffer Sample buffer
 * @param num_samples Number of samples to average for baseline
 * @return Baseline value
 */
uint16_t dr_adc_calc_baseline(const uint16_t *buffer, uint16_t num_samples);

/*==============================================================================
 * UTILITY FUNCTIONS
 *============================================================================*/

/**
 * @brief Convert raw value to millivolts
 * @param raw_value Raw 12-bit value
 * @return Voltage in millivolts
 */
uint32_t dr_adc_raw_to_mv(uint16_t raw_value);

/**
 * @brief Set reference voltage
 * @param vref_mv Reference voltage in millivolts
 */
void dr_adc_set_vref(uint32_t vref_mv);

/**
 * @brief Get reference voltage
 * @return Reference voltage in millivolts
 */
uint32_t dr_adc_get_vref(void);

/*==============================================================================
 * DEBUG FUNCTIONS
 *============================================================================*/

/**
 * @brief Test ADC communication
 * @return true if OK
 */
bool dr_adc_test(void);

/**
 * @brief Print echo buffer to debug output
 * @param buffer Sample buffer
 * @param num_samples Number of samples
 */
void dr_adc_print_buffer(const uint16_t *buffer, uint16_t num_samples);

/*==============================================================================
 * POWER CONTROL
 *============================================================================*/


/*==============================================================================
 * BLE TRANSMISSION CALLBACK
 *============================================================================*/

/*==============================================================================
 * INTEGRATED BURST + CAPTURE + TRANSMIT
 *============================================================================*/

/**
 * @brief Piezo burst + ADC capture + BLE transmission (all-in-one)
 *
 * This function performs the complete measurement cycle internally:
 * 1. Power on ADC
 * 2. Select piezo channel (0~7)
 * 3. Execute piezo burst (frequency based on freq_option)
 * 4. Capture echo samples (after delay_us) - repeated 'averaging' times
 * 5. Average the captured samples (firmware-level noise reduction)
 * 6. Analyze peak/baseline
 * 7. Transmit data via BLE with proper packet timing
 *
 * @param freq_option Frequency option: 0=1.8MHz (default), 1=2.1MHz, 2=2.0MHz, 3=1.7MHz
 * @param delay_us Delay before capture (us), default 20
 * @param num_samples Number of samples to capture (1~200)
 * @param cycles Number of burst cycles (3~7), default 5
 * @param averaging Number of measurements to average (1~1000), default 1
 * @param piezo_ch Piezo channel to use (0~7), default 0
 * @param ble_buffer Working buffer for BLE packets (must be >= 240 bytes)
 * @return dr_adc_err_t Error code
 *
 * @note Must call dr_adc_register_ble_tx() before using this function
 * @note BLE packets: reb: (header+data merged), red: (continuation, >119 samples only)
 * @note Higher averaging reduces noise but increases measurement time (~0.3ms per avg)
 */
dr_adc_err_t dr_adc_burst_capture_transmit(uint8_t freq_option, uint16_t delay_us,
                                            uint16_t num_samples, uint8_t cycles,
                                            uint16_t averaging, uint8_t piezo_ch,
                                            uint8_t *ble_buffer, uint8_t skip_raa);

/**
 * @brief Select piezo channel (0~7)
 * @param channel Piezo channel number (0~7)
 *
 * @note Hardware-dependent: requires MUX or individual GPIO control
 *       Currently uses placeholder - implement based on actual hardware
 */
void dr_piezo_select_channel(uint8_t channel);

/*==============================================================================
 * 4-CHANNEL CAPTURE (maa? command support)
 *============================================================================*/

/**
 * @brief 8-channel echo buffer for maa? command
 * Memory: 140 samples × 2 bytes × 8 channels = 2,240 bytes
 */
#define MAA_NUM_CHANNELS    6       /* 4 -> 8 -> 6  jhChun 26.03.17*/
#define MAA_SAMPLES_MAX     200

/**
 * @brief Echo data for one channel
 */
typedef struct {
    uint16_t samples[MAA_SAMPLES_MAX];  /**< Raw sample data */
    uint16_t num_samples;               /**< Actual sample count */
} dr_maa_channel_t;

/**
 * @brief Capture echo from one channel (no BLE transmission)
 *
 * Captures averaged echo data for a single channel and stores
 * in the provided channel buffer. Does NOT transmit via BLE.
 *
 * @param freq_option Frequency: 0=1.8MHz, 1=2.1MHz, 2=2.0MHz, 3=1.7MHz
 * @param delay_us Delay before capture (us)
 * @param num_samples Number of samples (1~200)
 * @param cycles Burst cycles (3~7)
 * @param averaging Number of averages (1~1000)
 * @param piezo_ch Piezo channel (0~7)
 * @param out_channel Output channel data structure
 * @return dr_adc_err_t Error code
 */
dr_adc_err_t dr_adc_capture_channel_only(uint8_t freq_option, uint16_t delay_us,
                                          uint16_t num_samples, uint8_t cycles,
                                          uint16_t averaging, uint8_t piezo_ch,
                                          dr_maa_channel_t *out_channel);

/**
 * @brief Transmit captured channel data via BLE
 *
 * Sends previously captured channel data using reb+red merged protocol.
 * reb: tag(4) + num_samples(2) + data(up to 238B). red: only if > 119 samples.
 *
 * @param ch_data Pointer to captured channel data
 * @param ble_buffer Working buffer for BLE packets (>= 244 bytes)
 * @return dr_adc_err_t Error code
 */
dr_adc_err_t dr_adc_transmit_channel(const dr_maa_channel_t *ch_data,
                                      uint8_t *ble_buffer);

/*==============================================================================
 * DELTA COMPRESSION (maa? mode=1)
 *
 * Format:
 *   Byte 0-1: First sample (16-bit, little endian)
 *   Byte 2+:  Delta values (8-bit signed)
 *             If delta > 127 or < -127: escape (0x80) + 16-bit value
 *
 * Expected compression: ~50% (280 bytes -> ~140 bytes)
 *============================================================================*/

#define DELTA_ESCAPE_BYTE   0x80    /**< Escape marker for out-of-range delta */

/**
 * @brief Compress sample data using delta encoding
 *
 * @param samples Input sample array (16-bit values)
 * @param num_samples Number of samples
 * @param out_buffer Output buffer for compressed data
 * @param out_size Output: number of bytes written
 * @return dr_adc_err_t Error code
 */
dr_adc_err_t dr_adc_delta_compress(const uint16_t *samples, uint16_t num_samples,
                                    uint8_t *out_buffer, uint16_t *out_size);

/**
 * @brief Transmit captured channel data via BLE with delta compression
 *
 * Uses rdb+rdd merged protocol (delta variant of reb+red merged)
 *
 * @param ch_data Pointer to captured channel data
 * @param ble_buffer Working buffer for BLE packets (>= 240 bytes)
 * @return dr_adc_err_t Error code
 */
dr_adc_err_t dr_adc_transmit_channel_delta(const dr_maa_channel_t *ch_data,
                                            uint8_t *ble_buffer);

/*==============================================================================
 * ASYNC MAA - Non-blocking 8-channel capture
 *
 * Design: State machine driven by BLE TX complete events
 * Flow:
 *   maa? cmd -> maa_async_start() -> capture all CH -> TX reb:(header+data) -> TX red: (if needed)
 *   BLE_NUS_EVT_TX_RDY -> maa_async_on_tx_ready() -> TX next packet or next channel
 *   All done -> TX raa: -> state=IDLE
 *============================================================================*/

/** @brief MAA async state machine states */
typedef enum {
    MAA_ASYNC_IDLE = 0,       /**< Not active */
    MAA_ASYNC_CAPTURING,      /**< ADC capture in progress */
    MAA_ASYNC_TX_HEADER,      /**< Sending reb: header+data merged */
    MAA_ASYNC_TX_DATA,        /**< Sending red: data packets */
    MAA_ASYNC_NEXT_CHANNEL,   /**< Preparing next channel */
    MAA_ASYNC_COMPLETE        /**< Sending raa: and finishing */
} maa_async_state_t;

/** @brief MAA async context */
typedef struct {
    maa_async_state_t state;      /**< Current state */
    uint8_t     current_ch;       /**< Current channel (0~7) */
    uint8_t     current_pkt;      /**< Current packet index */
    uint16_t    data_offset;      /**< Bytes sent so far for current channel */
    uint8_t     freq_option;      /**< Frequency option */
    uint16_t    delay_us;         /**< Capture delay */
    uint16_t    num_samples;      /**< Samples per channel */
    uint8_t     cycles;           /**< Burst cycles */
    uint16_t    averaging;        /**< Averaging count */
    uint8_t    *ble_buffer;       /**< Working buffer for BLE packets */
    dr_maa_channel_t channels[MAA_NUM_CHANNELS]; /**< Captured data for each channel */
    bool        pre_capture_all;  /**< true: 전채널 캡처 완료 후 일괄 전송 (mbb용) */
    void      (*on_complete_cb)(void); /**< 비동기 캡처 완료 후 호출될 콜백 (NULL이면 미사용) */
} maa_async_ctx_t;

/**
 * @brief Start async MAA 8-channel capture
 *
 * Initiates the async state machine. Captures CH0 and begins transmission.
 * Subsequent packets are sent when maa_async_on_tx_ready() is called.
 *
 * @param freq_option Frequency: 0=1.8MHz, 1=2.1MHz, 2=2.0MHz, 3=1.7MHz
 * @param delay_us Capture delay (us)
 * @param num_samples Samples per channel (1~200)
 * @param cycles Burst cycles (3~7)
 * @param averaging Averaging count (1~1000)
 * @param ble_buffer Working buffer (>= 244 bytes)
 * @return dr_adc_err_t DR_ADC_OK if started successfully
 */
dr_adc_err_t maa_async_start(uint8_t freq_option, uint16_t delay_us,
                              uint16_t num_samples, uint8_t cycles,
                              uint16_t averaging, uint8_t *ble_buffer);

/**
 * @brief Handle BLE TX ready event
 *
 * Called from BLE_NUS_EVT_TX_RDY handler. Sends next packet or
 * transitions to next state.
 *
 * @return true if more work pending, false if complete or idle
 */
bool maa_async_on_tx_ready(void);

/**
 * @brief Check if async MAA is active
 * @return true if state != IDLE
 */
bool maa_async_is_busy(void);

/**
 * @brief Get current async state (for debugging)
 * @return Current state
 */
maa_async_state_t maa_async_get_state(void);

/**
 * @brief Abort async MAA operation
 */
void maa_async_abort(void);

/**
 * @brief 자동 전원 플래그 설정 (완료 후 자동 power off)
 */
void maa_async_set_auto_power(bool on);
void maa_async_set_pre_capture_all(bool on);


/**
 * @brief 비동기 캡처 완료 콜백 설정
 * raa: 전송 + 전원 OFF 이후 호출된다. NULL이면 콜백 없음.
 */
void maa_async_set_on_complete(void (*cb)(void));

#endif /* DR_ADC121S051_H */

