#include "sonar.h"

namespace Sonar
{    
    void Init()
    {
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //Periph clocking
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
        
        GPIO_InitTypeDef param; //TRIG pin configuration
        param.GPIO_Mode = GPIO_Mode_OUT;
        param.GPIO_Pin = GPIO_Pin_9;
        param.GPIO_PuPd = GPIO_PuPd_NOPULL;
        param.GPIO_OType = GPIO_OType_PP;
        param.GPIO_Speed = GPIO_Speed_100MHz;
        GPIO_Init(GPIOC, &param);
        
        param.GPIO_Mode = GPIO_Mode_AF; //ECHO pin configuration
        param.GPIO_Pin = GPIO_Pin_8;
        param.GPIO_PuPd = GPIO_PuPd_NOPULL;
        param.GPIO_OType = GPIO_OType_PP;
        param.GPIO_Speed = GPIO_Speed_100MHz;
        GPIO_Init(GPIOC, &param);
        
        TIM_TimeBaseInitTypeDef timer_param; //timer 8 configuration
        timer_param.TIM_Period = 32767;
        timer_param.TIM_Prescaler = 168;
        timer_param.TIM_ClockDivision = TIM_CKD_DIV1;
        timer_param.TIM_CounterMode = TIM_CounterMode_Up;
        timer_param.TIM_RepetitionCounter = 0;
        TIM_TimeBaseInit(TIM8, &timer_param);
        
        TIM_ICInitTypeDef input_chann; //timer 8 input channel configuration
        input_chann.TIM_Channel = TIM_Channel_3;
        input_chann.TIM_ICPolarity = TIM_ICPolarity_Falling; //waiting falling edge
        input_chann.TIM_ICSelection = TIM_ICSelection_DirectTI;
        input_chann.TIM_ICFilter = 0;
        input_chann.TIM_ICPrescaler = TIM_ICPSC_DIV1;
        TIM_ICInit(TIM8, &input_chann);

        TIM_Cmd(TIM8, ENABLE); //timer 8 enable
        
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_TIM8);
        
        __disable_irq(); //disable interrupts
        
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
        SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource8); //external interrupt selection
        
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //set interrupt priority
        
        EXTI_InitTypeDef EXTI_InitStruct; //exti 8 configuration
        EXTI_InitStruct.EXTI_Line = EXTI_Line8;
        EXTI_InitStruct.EXTI_LineCmd = ENABLE;
        EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; //waiting rising edge
        EXTI_Init(&EXTI_InitStruct);
        
        NVIC_InitTypeDef NVIC_InitStructure; //interrupt configuration
        NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; 
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 9;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
        
        NVIC_EnableIRQ(EXTI9_5_IRQn);
        
        __enable_irq(); //enable interrupts
    }
    
    void sendPulse()
    {
        GPIO_SetBits(GPIOC, GPIO_Pin_9); //send pulse on TRIG pin
        time_service::delayus(40);
        GPIO_ResetBits(GPIOC, GPIO_Pin_9);
    }
    
    uint16_t getValue()
    {
        return TIM8->CCR3 / 59; //reading impulse time in microseconds 
    }
};
