/*
 * sensors.c
 *
 *  Created on: 28.4.2014
 *      Author: Stefan
 */


/* Includes ------------------------------------------------------------------*/
#include "sensors.h"
#include <stdlib.h>

#include "stm32f4xx_gpio.h"
#include "misc.h"
#include "leds.h"

/* Private typedef -----------------------------------------------------------*/
typedef enum sensors_event_en
{
    SENSORS_EV_ERROR = 0,
    SENSORS_EV_OK
} sensors_event_t;

typedef enum sensors_i2c_dir_en
{
    SENSORS_I2C_DIR_SEND = 0,
    SENSORS_I2C_DIR_RECEIVE = 1
} sensors_i2c_dir_t;

typedef enum sensors_adc_resolution_en
{
    SENSORS_ADC_12BIT = 0,
    SENSORS_ADC_10BIT = 1,
    SENSORS_ADC_8BIT = 2,
    SENSORS_ADC_6BIT = 3
} sensors_adc_resolution_t;

typedef struct sensors_i2c_state_struct_
{
    enum sensors_i2c_state_id_en_
    {
        SENSORS_I2C_IDLE,
        SENSORS_I2C_START,
        SENSORS_I2C_ADDRESS,
        SENSORS_I2C_RECEIVE,
        SENSORS_I2C_SEND
    } state_id;
    uint8_t address;
    uint8_t *buffer[2];
    uint32_t bytes_left[2];
}sensors_i2c_state_t;

typedef struct sensors_timer_data_struct
{
    uint32_t last_event;
    uint32_t events_cnt;
    uint32_t last_processed_event;
} sensors_timer_data_t;

/* Private define ------------------------------------------------------------*/
/**
 * \brief Name of Sensors process
 */
#define SENSORS_PNAME     "sensors"

/**
 * \brief Stack size of SENSORS Process
 */
#define SENSORS_PSTACK    (configMINIMAL_STACK_SIZE * 2)

/**
 * \brief Priority of SENSORS process
 */
#define SENSORS_PPRIORITY (tskIDLE_PRIORITY + 4)

/**
 * \brief Measurement interval
 */
#define SENSORS_MEAS_INTERVAL   5000

/**
 * \brief Time to wait for events
 */
#define SENSORS_TIMEOUT 500


/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
static SemaphoreHandle_t sensors_mutex;

static QueueHandle_t sensors_i2c_event;
static TaskHandle_t sensors_task_handle = NULL;
static sensors_i2c_state_t sensors_i2c_state;

static uint8_t sensors_i2c_buffer[16];

static sensors_measurement_t sensors_measurement;

static sensors_timer_data_t sensors_wind_spd_data;
static sensors_timer_data_t sensors_rain_data;

static QueueHandle_t sensors_adc_event;
static uint32_t sensors_adc_result;


/* Public variables ----------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
static void sensors_init_i2c(
    void
)
{
    GPIO_InitTypeDef gpio;
    NVIC_InitTypeDef nvic;

    /* Enable I2C2 */
    RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;
    __DSB();

    /* Reset bus */
    I2C2->CR1 |= I2C_CR1_SWRST;
    __DSB();
    I2C2->CR1 &= ~I2C_CR1_SWRST;
    __DSB();

    /* Stop I2C */
    I2C2->CR1 &= ~I2C_CR1_PE;
    __DSB();

    /* No Packet Error checking */
    I2C2->CR1 &= ~I2C_CR1_PEC;
    /* Configure as I2C bus */
    I2C2->CR1 &= ~I2C_CR1_SMBUS;
    __DSB();

    /* Disable DMA */
    I2C2->CR2 &= ~I2C_CR2_DMAEN;
    /* Enable Buffer interrupt */
    I2C2->CR2 |= I2C_CR2_ITBUFEN;
    /* Enable event interrupt */
    I2C2->CR2 |= I2C_CR2_ITEVTEN;
    /* Enable error interrupt */
    I2C2->CR2 |= I2C_CR2_ITERREN;

    /* Peripherial clock freq. */
    #define I2C_CR2_FREQ_OFFSET     0
    I2C2->CR2 &= ~I2C_CR2_FREQ;
    I2C2->CR2 |= (((42) << I2C_CR2_FREQ_OFFSET) & I2C_CR2_FREQ);

    /* I2C clock */
    /* Standard mode I2C (not fast) */
    I2C2->CCR &= ~I2C_CCR_FS;
    /* 50% Duty */
    I2C2->CCR &= ~I2C_CCR_DUTY;
    /* I2C clock = 100 kHz */
    #define I2C_CCR_CCR_OFFSET      0
    I2C2->CCR &= ~I2C_CCR_CCR;
    I2C2->CCR |= (((210) << I2C_CCR_CCR_OFFSET) & I2C_CCR_CCR);

    /* Rise time */
    /* (1000 ns / 24 ns) + 1 = 43 */
    I2C2->TRISE = 54;

    /* Disable filters */
    I2C2->FLTR = 0;

    /* Sart I2C */
    I2C2->CR1 |= I2C_CR1_PE;
    __DSB();


    /* GPIO */
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOHEN;
    __DSB();

    GPIO_StructInit(&gpio);
    gpio.GPIO_Mode = GPIO_Mode_AF;      /* < Alternate function */
    gpio.GPIO_OType = GPIO_OType_OD;    /* < Open Drain */
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;  /* < No pull Up/Down */
    gpio.GPIO_Speed = GPIO_Speed_2MHz;  /* < Speed 2MHz */

    /* GPIOH */
    /* SCL */
    GPIO_PinAFConfig(GPIOH, GPIO_PinSource4, GPIO_AF_I2C2);
    /* SDA */
    GPIO_PinAFConfig(GPIOH, GPIO_PinSource5, GPIO_AF_I2C2);
    __DSB();
    gpio.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_Init(GPIOH, &gpio);

    /* NVIC */
    nvic.NVIC_IRQChannelCmd = ENABLE;
    nvic.NVIC_IRQChannelPreemptionPriority = 8;
    nvic.NVIC_IRQChannelSubPriority = 0;

    /* I2C Event interrupt */
    nvic.NVIC_IRQChannel = I2C2_EV_IRQn;
    NVIC_Init(&nvic);
    /* I2C Error interrupt */
    nvic.NVIC_IRQChannel = I2C2_ER_IRQn;
    NVIC_Init(&nvic);

}

void sensors_init_timer(
    void
)
{
    GPIO_InitTypeDef gpio;
    NVIC_InitTypeDef nvic;

    /* Temp register */
    register uint16_t tmp16;


    /* Enable clock in TIM5 */
    RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
    __DSB();

    /* Reset TIM5 */
    RCC->APB1RSTR |= RCC_APB1RSTR_TIM5RST;
    __DSB();
    RCC->APB1RSTR &= ~RCC_APB1RSTR_TIM5RST;
    __DSB();


    /* Disable timer */
    TIM5->CR1 &= ~TIM_CR1_CEN;
    __DSB();

    #define TIM_CR1_CKD_OFFSET  8
    /* Load current value of CR1 */
    tmp16 = TIM5->CR1;
    /* Filters clock division */
    tmp16 &= ~TIM_CR1_CKD;
    tmp16 |= ((0 << TIM_CR1_CKD_OFFSET) & TIM_CR1_CKD);
    /* Disable auto-reload */
    tmp16 &= ~TIM_CR1_ARPE;
    /* Set Upcounting mode */
    tmp16 &= ~TIM_CR1_DIR;
    /* Update event can be generated by all supported sources */
    tmp16 &= ~TIM_CR1_URS;
    /* Do not stop the Timer at update event */
    tmp16 &= ~TIM_CR1_OPM;
    /* Store new value to CR1 */
    TIM5->CR1 = tmp16;

    /* Turn channels off */
    TIM5->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E |
            TIM_CCER_CC4E | TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC3NE);
    __DSB();


    #define TIM_CCMR1_CC2S_OFFSET   8
    #define TIM_CCMR1_IC2PSC_OFFSET 10
    #define TIM_CCMR1_IC2F_OFFSET   12
    /* Load CCMR1 */
    tmp16 = TIM5->CCMR1;
    /* Configure capture/compare mode channel 2 */
    /* Channel is input  at TI2 */
    tmp16 &= ~TIM_CCMR1_CC2S;
    tmp16 |= ((1 << TIM_CCMR1_CC2S_OFFSET) & TIM_CCMR1_CC2S);
    /* Configure channel prescaler */
    tmp16 &= ~TIM_CCMR1_IC2PSC;
    tmp16 |= ((0 << TIM_CCMR1_IC2PSC_OFFSET) & TIM_CCMR1_IC2PSC);
    /* configure channel filter */
    tmp16 &= ~TIM_CCMR1_IC2F;
    tmp16 |= ((0 << TIM_CCMR1_IC2F_OFFSET) & TIM_CCMR1_IC2F);
    /* Store CCMR1 */
    TIM5->CCMR1 = tmp16;

    #define TIM_CCMR2_CC3S_OFFSET   0
    #define TIM_CCMR2_IC3PSC_OFFSET 2
    #define TIM_CCMR2_IC3F_OFFSET   4
    /* Load CCMR2 */
    tmp16 = TIM5->CCMR2;
    /* Configure capture/compare mode channel 3 */
    /* Channel is input at TI3 */
    tmp16 &= ~TIM_CCMR2_CC3S;
    tmp16 |= ((1 << TIM_CCMR2_CC3S_OFFSET) & TIM_CCMR2_CC3S);
    /* Configure channel prescaler */
    tmp16 &= ~TIM_CCMR2_IC3PSC;
    tmp16 |= ((1 << TIM_CCMR2_IC3PSC_OFFSET) & TIM_CCMR2_IC3PSC);
    /* configure channel filter */
    tmp16 &= ~TIM_CCMR2_IC3F;
    tmp16 |= ((0 << TIM_CCMR2_IC3F_OFFSET) & TIM_CCMR2_IC3F);
    /* Store CCMR2 */
    TIM5->CCMR2 = tmp16;

    /* Zero counter */
    TIM5->CNT = 0;
    /* Set prescaler value,  */
    TIM5->PSC = 16799;

    /* Disable all interrupts and DMA requests for this timer */
    TIM5->DIER &= ~(TIM_DIER_TDE | TIM_DIER_CC4DE |  TIM_DIER_CC3DE |
            TIM_DIER_CC2DE | TIM_DIER_CC1DE | TIM_DIER_UDE |
            TIM_DIER_TIE | TIM_DIER_CC4IE | TIM_DIER_CC3IE | TIM_DIER_CC2IE |
            TIM_DIER_CC1IE | TIM_DIER_UIE);

    /* Enabel channel 2, 3 and update interrupts */
    TIM5->DIER |= (TIM_DIER_CC3IE | TIM_DIER_CC2IE | TIM_DIER_UIE);

    __DSB();

    /* Load CCER */
    tmp16 = TIM5->CCER;
    /* Enable channels 2 and 3 */
    tmp16 |= (TIM_CCER_CC2E | TIM_CCER_CC3E);
    /* Set trigger as falling Edge */
    tmp16 &= ~(TIM_CCER_CC2NP | TIM_CCER_CC3NP);
    tmp16 |= (TIM_CCER_CC2P | TIM_CCER_CC3P);
    /* Store CCER */
    TIM5->CCER = tmp16;

    /* Enable Update event */
    TIM5->CR1 &= ~TIM_CR1_UDIS;
    __DSB();
    /* Before starting timer, generate an Update event, so new configuration
     * gets copied into shadow registers */
    TIM5->EGR |= TIM_EGR_UG;
    __DSB();
    /* Enable Timer */
    TIM5->CR1 |= TIM_CR1_CEN;
    __DSB();
    /* Do not stop this timer during debug */
    #define DBGMCU_APB1_FZ_DBG_TIM5_STOP ((uint32_t)0x00000008)
    DBGMCU->APB1FZ &= ~DBGMCU_APB1_FZ_DBG_TIM5_STOP;


    GPIO_StructInit(&gpio);
    gpio.GPIO_Mode = GPIO_Mode_AF;      /* < Alternate function */
    gpio.GPIO_OType = GPIO_OType_PP;    /* < Push-Pull */
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;  /* < No pull-up, pull-down */
    gpio.GPIO_Speed = GPIO_Speed_2MHz;  /* < Output speed */

    /* GPIOH */
    /* Enable clock to GPIOH */
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOHEN;
    __DSB();
    /* Configure pins 11 and 12 as TIM5 capture channels */
    gpio.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
    GPIO_Init(GPIOH, &gpio);
    GPIO_PinAFConfig(GPIOH, GPIO_PinSource11, GPIO_AF_TIM5);
    GPIO_PinAFConfig(GPIOH, GPIO_PinSource12, GPIO_AF_TIM5);

    /* NVIC */
    nvic.NVIC_IRQChannelCmd = ENABLE;
    nvic.NVIC_IRQChannelPreemptionPriority = 8;
    nvic.NVIC_IRQChannelSubPriority = 0;

    /* TIM5 Interrupt */
    nvic.NVIC_IRQChannel = TIM5_IRQn;
    NVIC_Init(&nvic);
}

void sensors_init_adc(
    void
)
{
    register uint32_t tmp;
    GPIO_InitTypeDef gpio;
    NVIC_InitTypeDef nvic;

    /* Enable ADC1 clock */
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
    __DSB();

    /* Reset ADC */
    RCC->APB2RSTR |= RCC_APB2RSTR_ADCRST;
    __DSB();
    RCC->APB2RSTR &= ~RCC_APB2RSTR_ADCRST;

    #define ADC_CR1_RES_OFFSET  24
    #define ADC_CR1_DISCNUM_OFFSET  13
    /* Load CR1 */
    tmp = ADC1->CR1;
    /* Disable overrun interupt */
    tmp &= ~ADC_CR1_OVRIE;
    /* Set Resolution 8-bit */
    tmp &= ~ADC_CR1_RES;
    tmp |= ((2 << ADC_CR1_RES_OFFSET) & ADC_CR1_RES);
    /* Disable Analog Watchdog */
    tmp &= ~ADC_CR1_AWDEN;
    tmp &= ~ADC_CR1_JAWDEN;
    /* Number of channels converted in discontinous mode*/
    tmp &= ~ADC_CR1_DISCNUM;
    tmp |= ((0 << ADC_CR1_DISCNUM_OFFSET) & ADC_CR1_DISCNUM);
    /* Discontinous mode on injected channels */
    tmp &= ~ADC_CR1_JDISCEN;
    /* Discontinous mode on regular channels */
    tmp |= ADC_CR1_DISCEN;
    /* Automatic injected group conversion */
    tmp &= ~ADC_CR1_JAUTO;
    /* Watchdog on single channel in scan mode */
    tmp &= ~ADC_CR1_AWDSGL;
    /* Scan mode */
    tmp &= ~ADC_CR1_SCAN;
    /* Interrupt for injected channels */
    tmp &= ~ADC_CR1_JEOCIE;
    /* Analog watcdog interrupt */
    tmp &= ~ADC_CR1_AWDIE;
    /* EOC Interrupt */
    tmp |= ADC_CR1_EOCIE;
    /* Store new CR1 */
    ADC1->CR1 = tmp;

    #define ADC_CR2_EXTEN_OFFSET 28
    #define ADC_CR2_JEXTEN_OFFSET 20
    /* Load CR2 */
    tmp = ADC1->CR2;
    /* Regular conversion start */
    tmp &= ~ADC_CR2_SWSTART;
    /* External trigger for regular group selection */
    tmp &= ~ADC_CR2_EXTEN;
    tmp |= ((0 << ADC_CR2_EXTEN_OFFSET) & ADC_CR2_EXTEN);
    /* Injected conversion start */
    tmp &= ~ADC_CR2_JSWSTART;
    /* External trigger for injected group */
    tmp &= ~ADC_CR2_JEXTEN;
    tmp |= ((0 << ADC_CR2_JEXTEN_OFFSET) & ADC_CR2_JEXTEN);
    /* Data alignment */
    tmp &= ~ADC_CR2_ALIGN;
    /* End of conversion selection */
    tmp &= ~ADC_CR2_EOCS;
    /* DMA disable */
    tmp &= ~ADC_CR2_DMA;
    /* Continuous conversion */
    tmp &= ~ADC_CR2_CONT;
    /* ADC on */
    tmp |= ADC_CR2_ADON;
    /* Store new CR2 */
    ADC1->CR2 = tmp;

    /* Configure sampling time for channels 8 and 9 */
    #define ADC_SMPR2_SMP8_OFFSET   24
    #define ADC_SMPR2_SMP9_OFFSET   27
    /* Load SMPR2 */
    tmp = ADC1->SMPR2;
    /* Zero bits */
    tmp &= ~(ADC_SMPR2_SMP8 | ADC_SMPR2_SMP9);
    /* Configure channel 8 */
    tmp |= ((4 << ADC_SMPR2_SMP8_OFFSET) & ADC_SMPR2_SMP8);
    /* Configure channel 9 */
    tmp |= ((4 << ADC_SMPR2_SMP9_OFFSET) & ADC_SMPR2_SMP9);
    /* Store SMPR2 */
    ADC1->SMPR2 = tmp;



    /* Configure common control register */
    #define ADC_CCR_ADCPRE_OFFSET   16
    #define ADC_CCR_DMA_OFFSET      14
    #define ADC_CCR_DELAY_OFFSET    8
    #define ADC_CCR_MULTI_OFFSET    0
    /* Load CCR */
    tmp = ADC->CCR;
    /* Temperature sensor and Vrefint */
    tmp &= ~ADC_CCR_TSVREFE;
    /* VBAT enable */
    tmp &= ~ADC_CCR_VBATE;
    /* ADC prescaler */
    tmp &= ~ADC_CCR_ADCPRE;
    tmp |= ((1 << ADC_CCR_ADCPRE_OFFSET) & ADC_CCR_ADCPRE);
    /* DMA */
    tmp &= ~ADC_CCR_DMA;
    tmp |= ((0 << ADC_CCR_DMA_OFFSET) & ADC_CCR_DMA);
    /* Multi ADC */
    tmp &= ~ADC_CCR_MULTI;
    tmp |= ((0 << ADC_CCR_MULTI_OFFSET) & ADC_CCR_MULTI);
    /* Store CCR */
    ADC->CCR = tmp;

    GPIO_StructInit(&gpio);
    gpio.GPIO_Mode = GPIO_Mode_AN;      /* < Analog Mode */
    gpio.GPIO_OType = GPIO_OType_PP;    /* < Push-Pull */
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;  /* < No pull-up, pull-down */
    gpio.GPIO_Speed = GPIO_Speed_2MHz;  /* < Output speed */

    /* GPIOB */
    /* Enable clock to GPIOB */
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
    __DSB();
    /* Configure pins 0 and 1 as ADC1 channels */
    gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_Init(GPIOB, &gpio);

    /* NVIC */
    nvic.NVIC_IRQChannelCmd = ENABLE;
    nvic.NVIC_IRQChannelPreemptionPriority = 8;
    nvic.NVIC_IRQChannelSubPriority = 0;

    /* ADC1 Interrupt */
    nvic.NVIC_IRQChannel = ADC_IRQn;
    NVIC_Init(&nvic);
}

/* I2C functions */
static bool_t sensors_i2c_transfer(
    uint8_t address,
    void* send_buffer,
    uint32_t send_length,
    void* receive_buffer,
    uint32_t receive_length
)
{
    bool_t response = FALSE;
    sensors_event_t event;

    sensors_i2c_state.state_id = SENSORS_I2C_START;
    sensors_i2c_state.address = (address << 1);
    if(0 == send_length)
    {
        sensors_i2c_state.address |= 0x01;
    }
    sensors_i2c_state.buffer[0] = send_buffer;
    sensors_i2c_state.bytes_left[0] = send_length;
    sensors_i2c_state.buffer[1] = receive_buffer;
    sensors_i2c_state.bytes_left[1] = receive_length;

    I2C2->CR1 |= I2C_CR1_START;

    /* Enable interrupt */
    I2C2->CR2 |= I2C_CR2_ITEVTEN;



    if( pdTRUE == xQueueReceive(sensors_i2c_event, &event, portMAX_DELAY))
    {
        if(SENSORS_EV_OK == event)
        {
            response = TRUE;
        }
    }

    return response;
}

static bool_t sensors_adc_convert(
    uint8_t channel,
    uint32_t* result,
    sensors_adc_resolution_t resolution
)
{
    register uint32_t tmp;
    bool_t response = FALSE;
    sensors_event_t event;

    /* Configure Regular sequence */
    #define ADC_SQR1_L_OFFSET   20
    /* Load SQR1 */
    tmp = ADC1->SQR1;
    /* Length of sequence */
    tmp &= ~ADC_SQR1_L;
    tmp |= ((0 << ADC_SQR1_L_OFFSET) & ADC_SQR1_L);
    /* Store SQR1 */
    ADC1->SQR1 = tmp;
    #define ADC_SQR3_SQ1_OFFSET 0
        /* Load SQR3 */
    tmp = ADC1->SQR3;
    /* Zero bits */
    tmp &= ~(ADC_SQR3_SQ1);
    /* Set first sequence */
    tmp |= ((channel << ADC_SQR3_SQ1_OFFSET) & ADC_SQR3_SQ1);
    /* Store SQR3 */
    ADC1->SQR3 = tmp;

    /* Load CR1 */
    tmp = ADC1->CR1;
    /* Set Resolution 8-bit */
    tmp &= ~ADC_CR1_RES;
    tmp |= ((resolution << ADC_CR1_RES_OFFSET) & ADC_CR1_RES);
    /* Store CR1 */
    ADC1->CR1 = tmp;
    __DSB();

    /* Start conversion */
    ADC1->CR2 |= ADC_CR2_SWSTART;

    if( pdTRUE == xQueueReceive(sensors_i2c_event, &event, SENSORS_TIMEOUT))
    {
        if(SENSORS_EV_OK == event)
        {
            *result = sensors_adc_result;
            response = TRUE;
        }
    }

    return response;
}

static sensors_direction_t sensors_get_dir(
    int32_t measurement
    )
{
    static const int32_t directions[] = {
        208, 133, 30, 58, 87, 174, 240, 229, 255};
    uint32_t nearest_diff = 0xffffffff;
    uint32_t nearest;
    uint32_t dir;
    uint32_t current_diff;

    for(dir = 0; dir < (sizeof(directions)/sizeof(int32_t)); dir ++)
    {
        current_diff = abs(directions[dir] - measurement);
        if(current_diff <= nearest_diff)
        {
            nearest_diff = current_diff;
            nearest = dir;
        }
    }

    return (sensors_direction_t)nearest;
}

/* Supply update info */
void supply_update_info(
    float voltage,
    float temp
);

/* Task */
static void sensors_main(
    void* arg)
{
    TickType_t last_wake_time;
    sensors_measurement_t tmp_meas;
    sensors_timer_data_t timer_tmp;
    uint32_t tmp;
    uint32_t round;
    (void)arg;



    /* Get currnt tick time */
    last_wake_time = xTaskGetTickCount();

    while(1)
    {
        tmp_meas = sensors_measurement;
        leds_set(LEDS_4, 65535);
        round ++;

        if(TRUE == sensors_adc_convert(9, &tmp, SENSORS_ADC_8BIT))
        {
            tmp_meas.wind_dir = sensors_get_dir((int32_t)tmp);
        }


        if(TRUE == sensors_adc_convert(8, &tmp, SENSORS_ADC_8BIT))
        {
            supply_update_info((float)tmp / 55.4778555f,
               sensors_measurement.temp);
        }


        /* SHT25 - temp */
        sensors_i2c_buffer[0] = 0xe3;
        if(TRUE == sensors_i2c_transfer(
                0x40,
                sensors_i2c_buffer,
                1,
                sensors_i2c_buffer,
                3
            )
        )
        {
            uint16_t tmp;
            tmp = sensors_i2c_buffer[0];
            tmp = tmp << 8;
            tmp |= sensors_i2c_buffer[1];

            tmp_meas.temp = -46.85f + 175.72f * (((float)tmp) / 65536.0f);
        }

        /* SHT25 - RH */
        sensors_i2c_buffer[0] = 0xe5;
        if(TRUE == sensors_i2c_transfer(
                0x40,
                sensors_i2c_buffer,
                1,
                sensors_i2c_buffer,
                3
            )
        )
        {
            uint16_t tmp;
            tmp = sensors_i2c_buffer[0];
            tmp = tmp << 8;
            tmp |= sensors_i2c_buffer[1];

            tmp_meas.humidity = -6.0f + 125.0f * (((float)tmp) / 65536.0f);
        }

        /* BMP085 - Pressure */
        sensors_i2c_buffer[0] = 0xf4;
        sensors_i2c_buffer[1] = 0xb4;
        if(TRUE == sensors_i2c_transfer(
                0x77,
                sensors_i2c_buffer,
                2,
                NULL, 0
            )
        )
        {
            vTaskDelay(15);
            sensors_i2c_buffer[0] = 0xf6;
            if(TRUE == sensors_i2c_transfer(
                    0x77,
                    sensors_i2c_buffer,
                    1,
                    sensors_i2c_buffer, 3
                )
            )
            {


                uint16_t tmp;
                tmp = sensors_i2c_buffer[0];
                tmp = tmp << 8;
                tmp |= sensors_i2c_buffer[1];

                tmp_meas.press = (((float)tmp) / 40.4779f);
            }
        }


        /* Wind speed */
        NVIC_DisableIRQ(TIM5_IRQn);
        __DSB();
        {
            timer_tmp = sensors_wind_spd_data;
            sensors_wind_spd_data.events_cnt = 0;
        }
        NVIC_EnableIRQ(TIM5_IRQn);
        __DSB();

        if(timer_tmp.events_cnt > 1)
        {
            tmp_meas.wind_spd = (2.0f*3.14f*1000.0f) / (float)((
                ((float)(timer_tmp.last_event - timer_tmp.last_processed_event))
                / ((float)(timer_tmp.events_cnt - 1))));
        }
        else
        {
            tmp_meas.wind_spd = 0;
        }

        if(round > (600000/SENSORS_MEAS_INTERVAL))
        {
            round = 0;

            /* Rain */
            NVIC_DisableIRQ(TIM5_IRQn);
            __DSB();
            {
                timer_tmp = sensors_rain_data;
                sensors_rain_data.events_cnt = 0;
            }
            NVIC_EnableIRQ(TIM5_IRQn);
            __DSB();

            if(timer_tmp.events_cnt > 1)
            {
                tmp_meas.rain = 36000000.0f/(float)((
                    ((float)(timer_tmp.last_event - timer_tmp.last_processed_event))
                    / ((float)(timer_tmp.events_cnt - 1))));
            }
            else
            {
                tmp_meas.wind_spd = 0;
            }

        }



        /* Store new values */
        /* try to obtain Mutex */
        if(pdTRUE == xSemaphoreTake(sensors_mutex, SENSORS_TIMEOUT))
        {
            sensors_measurement = tmp_meas;

            /* release mutex */
            xSemaphoreGive(sensors_mutex);

        }
        leds_set(LEDS_4, 0);
        /* Wait for next cycle */
        vTaskDelayUntil(&last_wake_time, SENSORS_MEAS_INTERVAL);
    }

}


/* Public functions ----------------------------------------------------------*/
bool_t sensors_get_current_measurement(
    sensors_measurement_t* buffer
)
{
    bool_t result = FALSE;

    /* try to obtain Mutex */
    if(pdTRUE == xSemaphoreTake(sensors_mutex, SENSORS_TIMEOUT))
    {
        *buffer = sensors_measurement;
        result = TRUE;


        /* release mutex */
        xSemaphoreGive(sensors_mutex);

    }

    return result;
}

bool_t sensors_start(
    void
)
{
    bool_t result = FALSE;

    /* Analog sensors */
    sensors_init_adc();

    /* Timer senseors */
    sensors_init_timer();

    /* I2C Sensors */
    sensors_init_i2c();


    /* System objects */
    sensors_mutex = xSemaphoreCreateMutex();
    sensors_i2c_event = xQueueCreate(1, sizeof(sensors_event_t));
    sensors_adc_event = xQueueCreate(1, sizeof(sensors_event_t));
    if(NULL != sensors_i2c_event && NULL != sensors_adc_event &&
        NULL != sensors_mutex
    )
    {
        if(pdPASS == xTaskCreate(
            sensors_main,
            (const char * const)SENSORS_PNAME,
            SENSORS_PSTACK,
            NULL,
            SENSORS_PPRIORITY,
            &sensors_task_handle
            )
        )
        {
            result = TRUE;
        }

    }

    return result;
}



/* Interrupts ----------------------------------------------------------------*/
void ADC_IRQHandler(
    void
)
{
    sensors_event_t event;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    if(ADC_SR_EOC & (ADC1->SR))
    {
        sensors_adc_result = ADC1->DR;
        event = SENSORS_EV_OK;
    }
    else
    {
        event = SENSORS_EV_OK;
    }

    xQueueSendFromISR(
       sensors_i2c_event,
       &event,
       &xHigherPriorityTaskWoken);

    if(pdTRUE == xHigherPriorityTaskWoken)
    {
        portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
    }
}

void TIM5_IRQHandler(
    void
)
{
    register uint16_t sr = TIM5->SR;

    if(sr & TIM_SR_CC3IF)
    {
        sensors_wind_spd_data.last_event = TIM5->CCR3;
        if(0 == sensors_wind_spd_data.events_cnt)
        {
            sensors_wind_spd_data.last_processed_event =
                sensors_wind_spd_data.last_event;
        }
        sensors_wind_spd_data.events_cnt ++;
    }

    if(sr & TIM_SR_CC2IF)
    {
        sensors_rain_data.last_event = TIM5->CCR2;
        if(0 == sensors_rain_data.events_cnt)
        {
            sensors_rain_data.last_processed_event =
                sensors_rain_data.last_event;
        }
        sensors_rain_data.events_cnt ++;

    }

    if(sr & TIM_SR_UIF)
    {
        TIM5->SR &= ~TIM_SR_UIF;

    }

}


void I2C2_EV_IRQHandler(
    void
)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    sensors_event_t event;
    uint32_t sr1, sr2;

    sr1 = I2C2->SR1;


    switch(sensors_i2c_state.state_id)
    {
    case SENSORS_I2C_START:
        event = (0 != (sr1 & I2C_SR1_SB)) ?
            SENSORS_EV_OK : SENSORS_EV_ERROR;
        if(SENSORS_EV_OK == event)
        {
            /* Enable Buffer interrupt */
            I2C2->CR2 |= I2C_CR2_ITBUFEN;
            sensors_i2c_state.state_id = SENSORS_I2C_ADDRESS;
            I2C2->DR = sensors_i2c_state.address;
        }

        break;

    case SENSORS_I2C_ADDRESS:
        event = (0 != (sr1 & I2C_SR1_ADDR)) ?
            SENSORS_EV_OK : SENSORS_EV_ERROR;
        if(SENSORS_EV_OK == event)
        {
            sensors_i2c_state.state_id =
                (1 == ((sensors_i2c_state.address) & 0x01)) ?
                    SENSORS_I2C_RECEIVE : SENSORS_I2C_SEND;

            if(SENSORS_I2C_RECEIVE == sensors_i2c_state.state_id)
            {
                if(sensors_i2c_state.bytes_left[1] <= 1)
                {
                    I2C2->CR1 &= ~I2C_CR1_ACK;
                }
                else
                {
                    I2C2->CR1 |= I2C_CR1_ACK;
                }
            }
            /* Clear ADDR flag */
            sr1 = I2C2->SR1;
            sr2 = I2C2->SR2;
        }
        else
        {
            xQueueSendFromISR(
                sensors_i2c_event,
                &event,
                &xHigherPriorityTaskWoken);
        }
        break;
    default:
        break;
    }


    if((SENSORS_I2C_SEND == sensors_i2c_state.state_id) &&
        (0 != (sr1 & I2C_SR1_TXE)))
    {

        if(sensors_i2c_state.bytes_left[0] > 0)
        {
            sensors_i2c_state.bytes_left[0] --;

            I2C2->DR = *((sensors_i2c_state.buffer[0]) ++);
        }

        if(0 == sensors_i2c_state.bytes_left[0])
        {
            if(0 != sensors_i2c_state.bytes_left[1])
            {
                sensors_i2c_state.address |= 0x01;

                sensors_i2c_state.state_id = SENSORS_I2C_START;

                /* Disable Buffer interrupt */
                I2C2->CR2 &= ~I2C_CR2_ITBUFEN;

                I2C2->CR1 |= I2C_CR1_START;
            }
            else
            {
                sensors_i2c_state.state_id = SENSORS_I2C_IDLE;
                I2C2->CR1 |= I2C_CR1_STOP;

                event = SENSORS_EV_OK;
                xQueueSendFromISR(
                    sensors_i2c_event,
                    &event,
                    &xHigherPriorityTaskWoken);
            }
        }
    }

    if((SENSORS_I2C_RECEIVE == sensors_i2c_state.state_id) &&
        (0 != (sr1 & I2C_SR1_RXNE)))
    {
        sensors_i2c_state.bytes_left[1] --;
        if(sensors_i2c_state.bytes_left[1] == 1)
        {
            I2C2->CR1 &= ~I2C_CR1_ACK;
            I2C2->CR1 |= I2C_CR1_STOP;
        }
        /*else
        {
            I2C2->CR1 |= I2C_CR1_ACK;
        }*/

        *((sensors_i2c_state.buffer[1]) ++) = I2C2->DR;

        if(sensors_i2c_state.bytes_left[1] == 0)
        {
            sensors_i2c_state.state_id = SENSORS_I2C_IDLE;


            event = SENSORS_EV_OK;
            xQueueSendFromISR(
                sensors_i2c_event,
                &event,
                &xHigherPriorityTaskWoken);
        }

    }

    if(pdTRUE == xHigherPriorityTaskWoken)
    {
        portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
    }

    (void)sr2;
}


void I2C2_ER_IRQHandler(
    void
)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    sensors_event_t event;
    uint32_t sr1, sr2;


    sr1 = I2C2->SR1;
    sr2 = I2C2->SR2;

    if((SENSORS_I2C_ADDRESS == sensors_i2c_state.state_id) &&
        (0 != (sr1 & I2C_SR1_AF))
    )
    {
        I2C2->SR1 &= ~I2C_SR1_AF;
        event = SENSORS_EV_ERROR;

        if((sr2 & (I2C_SR2_BUSY | I2C_SR2_MSL)) == (I2C_SR2_BUSY | I2C_SR2_MSL))
        {
            I2C2->CR1 |= I2C_CR1_STOP;
        }


        xQueueSendFromISR(
            sensors_i2c_event,
            &event,
            &xHigherPriorityTaskWoken);

    }

    if(pdTRUE == xHigherPriorityTaskWoken)
    {
        portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
    }

    (void)sr2;
}

