//
// Created by villuton on 25.08.2025.
//
#include <string.h>
#include "Adcs.h"
#include "at32f403a_407_gpio.h"


///Таблица значений ADC DMA
__IO uint16_t adc_ordinary_valuetab[ADCS_ADC_BUFF_SIZE] = {0};
__IO uint16_t dma_trans_complete_flag = 0;

/**
  * @brief  gpio configuration.
  * @param  none
  * @retval none
  */
static void adc_gpio_config(void) {
    gpio_init_type gpio_initstructure;
    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

    gpio_default_para_init(&gpio_initstructure);
    gpio_initstructure.gpio_mode = GPIO_MODE_ANALOG;

    /// Инициализация пинов ADC GPIOA
    gpio_initstructure.gpio_pins =
            GPIO_PINS_0 | GPIO_PINS_1 | GPIO_PINS_2 | GPIO_PINS_3 |
            GPIO_PINS_4 | GPIO_PINS_5 | GPIO_PINS_6 | GPIO_PINS_7;
    gpio_init(GPIOA, &gpio_initstructure);

    /// Инициализация пинов ADC GPIOB
    gpio_initstructure.gpio_pins = GPIO_PINS_0 | GPIO_PINS_1;
    gpio_init(GPIOB, &gpio_initstructure);
}

/**
  * @brief  dma configuration.
  * @param  none
  * @retval none
  */
static void adc_dma_config(void) {
    dma_init_type dma_init_struct;
    crm_periph_clock_enable(ADCS_ADC_CRM_DMAx_PERIPH_CLOCK, TRUE);
    nvic_irq_enable(ADCS_ADC_DMAx_Channelx_IRQn, 0, 0);
    dma_reset(ADCS_ADC_DMAx_CHANNELx);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = ADCS_ADC_BUFF_SIZE;
    dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_base_addr = (uint32_t) adc_ordinary_valuetab;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t) &(ADCS_ADCx->odt);
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    dma_init_struct.loop_mode_enable = TRUE;
    dma_init(ADCS_ADC_DMAx_CHANNELx, &dma_init_struct);

    dma_interrupt_enable(ADCS_ADC_DMAx_CHANNELx, DMA_FDT_INT, TRUE);
    dma_channel_enable(ADCS_ADC_DMAx_CHANNELx, TRUE);
}


/**
  * @brief  adc channel configuration.
  * @param  none
  * @retval none
  */
static void adc_channel_config(void) {
    for (int i = ADC_CHANNEL_0; i <= ADC_CHANNEL_9; i++) {
        adc_ordinary_channel_set(ADCS_ADCx, i, i + 1, ADC_SAMPLETIME_239_5);
    }
    /**
    adc_ordinary_channel_set(ADCS_ADCx, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADCS_ADCx, ADC_CHANNEL_1, 2, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADCS_ADCx, ADC_CHANNEL_2, 3, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADCS_ADCx, ADC_CHANNEL_3, 4, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADCS_ADCx, ADC_CHANNEL_4, 5, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADCS_ADCx, ADC_CHANNEL_5, 6, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADCS_ADCx, ADC_CHANNEL_6, 7, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADCS_ADCx, ADC_CHANNEL_7, 8, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADCS_ADCx, ADC_CHANNEL_8, 9, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADCS_ADCx, ADC_CHANNEL_9, 10, ADC_SAMPLETIME_239_5);
     */
}

/**
  * @brief  adc configuration.
  * @param  none
  * @retval none
  */
static void adc_config(void) {
    adc_base_config_type adc_base_struct;
    crm_periph_clock_enable(ADCS_CRM_ADCx_PERIPH_CLOCK, TRUE);
    crm_adc_clock_div_set(CRM_ADC_DIV_6);

    /* select combine mode */
    adc_combine_mode_select(ADC_INDEPENDENT_MODE);
    adc_base_default_para_init(&adc_base_struct);
    adc_base_struct.sequence_mode = TRUE;
    adc_base_struct.repeat_mode = TRUE;
    adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
    adc_base_struct.ordinary_channel_length = ADCS_ADC_BUFF_SIZE;
    adc_base_config(ADCS_ADCx, &adc_base_struct);

    adc_channel_config();

    adc_ordinary_conversion_trigger_set(
            ADCS_ADCx,
            ADCS_ADCx_ORDINARY_TRIG_SOFTWARE,
            TRUE);

    adc_dma_mode_enable(ADCS_ADCx, TRUE);

    adc_enable(ADCS_ADCx, TRUE);
    adc_calibration_init(ADCS_ADCx);
    while (adc_calibration_init_status_get(ADCS_ADCx));
    adc_calibration_start(ADCS_ADCx);
    while (adc_calibration_status_get(ADCS_ADCx));
}

/**
 * Инициализация ADC
 * @param *env tAdcs
 */
void Adcs_Init(tAdcs *env) {
    adc_gpio_config();
    adc_dma_config();
    adc_config();
    memset(env->tab, 0, ADCS_ADC_BUFF_SIZE);
}


/**
 * Обновление таблицы значений каналов ADC
 * @param env
 */
void Adcs_UpdateTab(tAdcs *env) {
    memcpy(env->tab, (void *) adc_ordinary_valuetab, ADCS_ADC_BUFF_SIZE);
}