#include "adc.h"
#include "common.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

#ifdef PRINTF_STDLIB
#include <stdio.h>
#endif
#ifdef PRINTF_CUSTOM
#include "tinystdio.h"
#endif



SemaphoreHandle_t adc_raw_data_semphr;

// here raw values will be put by DMA
static volatile uint16_t adc_raw[ADC_TOTAL_COUNT] = {0};



// Сырые данные АЦП канала
uint16_t adc_mv_raw(adc_chan_t chan)
{
	return adc_raw[chan];
}


// Данные АЦП канала в мВ
uint16_t adc_mv(adc_chan_t chan) 
{
	return (((uint32_t)adc_raw[chan]) * VREF) >> 12;
}


//
void adc_init(void)
{
    adc_raw_data_semphr = xSemaphoreCreateBinary();
    
    adc_gpio_init();
    adc_dma_init();
    adc_init_base();    
    adc_timer_init();
    
    adc_tim_set(TRUE);
}


//
void adc_init_base(void)
{
    adc_base_config_type adc_base_struct;
    
    crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
    crm_adc_clock_div_set(CRM_ADC_DIV_2);
    
    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
    nvic_irq_enable(ADC1_2_IRQn, 5, 0);
    
    //NVIC_SetPriority(ADC1_2_IRQn, 5);
        
    // 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 = FALSE;
    adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
    adc_base_struct.ordinary_channel_length = 3;
    adc_base_config(ADC1, &adc_base_struct);
    
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_9,  1, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_10, 2, ADC_SAMPLETIME_239_5);
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_16, 3, ADC_SAMPLETIME_239_5);
    
    adc_ordinary_conversion_trigger_set(ADC1, ADC12_ORDINARY_TRIG_SOFTWARE, TRUE);
    
    adc_dma_mode_enable(ADC1, TRUE);
    adc_tempersensor_vintrv_enable(TRUE);
    
    adc_flag_clear(ADC1, ADC_CCE_FLAG);
    
    adc_interrupt_enable(ADC1, ADC_CCE_INT, TRUE);
    
    adc_enable(ADC1, TRUE);
    adc_calibration_init(ADC1);
    
    while(adc_calibration_init_status_get(ADC1));
    adc_calibration_start(ADC1);
    while(adc_calibration_status_get(ADC1));
}


//
void adc_gpio_init(void)
{
    gpio_init_type gpio_initstructure;
        
    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);
 
    gpio_default_para_init(&gpio_initstructure);
    
    // Vbat
    gpio_initstructure.gpio_mode           = GPIO_MODE_ANALOG;  
    gpio_initstructure.gpio_pins           = GPIO_PINS_1;
    gpio_init(GPIOB, &gpio_initstructure);
    
    // check 220
    gpio_initstructure.gpio_pins           = GPIO_PINS_0;
    gpio_init(GPIOC, &gpio_initstructure);
    
    gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;  
    gpio_initstructure.gpio_pull           = GPIO_PULL_NONE;  
    gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;  
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_initstructure.gpio_pins           = GPIO_PINS_11;
    gpio_init(GPIOD, &gpio_initstructure);
        
    // Установка пина подключает измерительную цепь. Цепь подключена всегда.
    gpio_bits_set(GPIOD, GPIO_PINS_11);
}


//
void adc_timer_init(void)
{
    crm_clocks_freq_type crm_clocks_freq_struct = {0};
    
    crm_periph_clock_enable(CRM_TMR7_PERIPH_CLOCK, TRUE);

    crm_clocks_freq_get(&crm_clocks_freq_struct);
    tmr_base_init(TMR7, 999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
    tmr_cnt_dir_set(TMR7, TMR_COUNT_UP);
        
    tmr_flag_clear(TMR7, TMR_OVF_FLAG);

    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
    nvic_irq_enable(TMR7_GLOBAL_IRQn, 5, 0);
       
    tmr_counter_enable(TMR7, FALSE);
    
    tmr_interrupt_enable(TMR7, TMR_OVF_INT, TRUE);
}


//
void adc_tim_set(confirm_state state)
{
    //tmr_counter_enable(TMR7, state);
    //tmr_interrupt_enable(TMR7, TMR_OVF_INT, state);
    tmr_counter_enable(TMR7, state);
}


//
void adc_dma_init(void)
{  
    dma_init_type dma_init_struct;
    
    crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
    
    dma_reset(DMA1_CHANNEL1);
    
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = 3;
    dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_base_addr = (uint32_t)adc_raw;
    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)&(ADC1->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(DMA1_CHANNEL1, &dma_init_struct);
    
    dma_flexible_config(DMA1, FLEX_CHANNEL1, DMA_FLEXIBLE_ADC1);
    dma_channel_enable(DMA1_CHANNEL1, TRUE);
}


//
void ADC1_2_IRQHandler(void)
{
    static uint8_t empty = 0;
    static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    adc_flag_clear(ADC1, ADC_CCE_FLAG);

    if (empty > 3) {
        xSemaphoreGiveFromISR(adc_raw_data_semphr, &xHigherPriorityTaskWoken);
    }
    else 
        empty++;

#if 0   
    Ubat = ADC_UBAT_FACTOR*(float)adc1_ordinary_valuetab[0]*ADC_VREF/4096.0;
    check_220 = ((float)adc1_ordinary_valuetab[1]*ADC_VREF/4096.0)/CONST_RESISTOR_DEVIDER;
    temperature = (ADC_TEMP_BASE - (float)adc1_ordinary_valuetab[2]*ADC_VREF/4096.0)/ADC_TEMP_SLOPE + 25.0;
    
    printf("Ubat: %f ", Ubat);
    printf("check 220V: %f ", check_220);
    printf("temper: %.2f ", temperature);
#endif
    
#if 0
    printf("Ubat: %u \r\n", adc_raw[0]);
    printf("check 220V: %u \r\n", adc_raw[1]);
    printf("temper: %.2u \r\n\n", adc_raw[2]);
#endif    
}


//
void TMR7_GLOBAL_IRQHandler(void)
{
    if(tmr_flag_get(TMR7, TMR_OVF_FLAG) != RESET)
    {
        tmr_flag_clear(TMR7, TMR_OVF_FLAG);
        adc_ordinary_software_trigger_enable(ADC1, TRUE);
    }
}

