/**
 * @file		hal_adc.c
 * @copyright  	Nehemis SARL reserves all rights even in the event of industrial
 *             	property rights. We reserve all rights of disposal such as
 *             	copying and passing on to third parties.
 *
 * @brief      	STM HAL layer wrapper class for ADC.
 *
 */

/******************************************************************************
 * Include Header Files
 ******************************************************************************/
#include "hal_adc.h"

/* CubeMX */
#include "adc.h"
/******************************************************************************
 * Macro Constant Declarations
 ******************************************************************************/
#define HAL_ADC_TIMEOUT		10u /* in milliseconds */
/******************************************************************************
 * Module Global Variable Declarations
 ******************************************************************************/
static uint32 (*halAdcCallbacks[MAP_HAL_ADC_NUMBER])(void);
/******************************************************************************
 * Extern Function Definitions
 ******************************************************************************/
void HalAdcCalibrate(MapHalAdcModule_en module_en)
{
	uint32 error_u32 = NMS_ERR_DEFAULT;
	ADC_HandleTypeDef *targetModule_pst;

	error_u32 = MapHalAdcModule(module_en, &targetModule_pst);
    if (error_u32 == NMS_ERR_NONE)
    {
    	HAL_ADCEx_Calibration_Start(targetModule_pst, ADC_SINGLE_ENDED);
    }
    else
    {
    	/* Handle error */
    }
}


uint32 HalAdcStart(MapHalAdcModule_en module_en)
{
	uint32 error_u32 = NMS_ERR_NONE;
    HAL_StatusTypeDef halAdcStatus_en = HAL_OK;
    ADC_HandleTypeDef *targetModule_pst;

    error_u32 = MapHalAdcModule(module_en, &targetModule_pst);

    if (error_u32 == NMS_ERR_NONE)
    {
        /* Start the ADC conversion */
        halAdcStatus_en = HAL_ADC_Start(targetModule_pst);

        switch (halAdcStatus_en)
        {
            case HAL_BUSY:      error_u32 = NMS_ERR_BUSY;       break;
            case HAL_TIMEOUT:   error_u32 = NMS_ERR_TIMEOUT;    break;
            case HAL_ERROR:     error_u32 = NMS_ERR_INTERNAL;   break;
            case HAL_OK:        error_u32 = NMS_ERR_NONE;       break;
            default:            error_u32 = NMS_ERR_UNKNOWN; 	break;
        }
    }
    return error_u32;
}


uint32 HalAdcRead(MapHalAdcModule_en module_en, uint32 *adcValue_pu32)
{
	uint32 error_u32 = NMS_ERR_NONE;
    HAL_StatusTypeDef halAdcStatus_en = HAL_OK;
    ADC_HandleTypeDef *targetModule_pst;

    error_u32 = MapHalAdcModule(module_en, &targetModule_pst);

    if (error_u32 == NMS_ERR_NONE)
    {
        halAdcStatus_en = HAL_ADC_PollForConversion(targetModule_pst, HAL_ADC_TIMEOUT);
        if (halAdcStatus_en == HAL_OK)
        {
            *adcValue_pu32 = HAL_ADC_GetValue(targetModule_pst);
            return NMS_ERR_NONE;
        }
        else
        {
            return NMS_ERR_UNKNOWN;
        }
    }
    return error_u32;
}


uint32 HalAdcStop(MapHalAdcModule_en module_en)
{
	uint32 error_u32 = NMS_ERR_NONE;
    HAL_StatusTypeDef halAdcStatus_en = HAL_OK;
    ADC_HandleTypeDef * targetModule_pst;

    error_u32 = MapHalAdcModule(module_en, &targetModule_pst);

    if(error_u32 == NMS_ERR_NONE)
    {
    	halAdcStatus_en = HAL_ADC_Stop(targetModule_pst);

        switch(halAdcStatus_en)
        {
			case HAL_BUSY:      error_u32 = NMS_ERR_BUSY;       break;
			case HAL_TIMEOUT:   error_u32 = NMS_ERR_TIMEOUT;    break;
			case HAL_ERROR:     error_u32 = NMS_ERR_INTERNAL;   break;
			case HAL_OK:        error_u32 = NMS_ERR_NONE;       break;
			default:            error_u32 = NMS_ERR_UNKNOWN; 	break;
        }
    }
    return error_u32;
}


uint32 HalAdcStartDMA(MapHalAdcModule_en module_en, uint32 * pData_u32, uint32 length_u32)
{
	uint32 error_u32 = NMS_ERR_NONE;
    HAL_StatusTypeDef halAdcStatus_en = HAL_OK;
    ADC_HandleTypeDef * targetModule_pst;

    error_u32 = MapHalAdcModule(module_en, &targetModule_pst);

    if(error_u32 == NMS_ERR_NONE)
    {
    	halAdcStatus_en = HAL_ADC_Start_DMA(targetModule_pst, pData_u32, length_u32);

        switch(halAdcStatus_en)
        {
			case HAL_BUSY:      error_u32 = NMS_ERR_BUSY;       break;
			case HAL_TIMEOUT:   error_u32 = NMS_ERR_TIMEOUT;    break;
			case HAL_ERROR:     error_u32 = NMS_ERR_INTERNAL;   break;
			case HAL_OK:        error_u32 = NMS_ERR_NONE;       break;
			default:            error_u32 = NMS_ERR_UNKNOWN; 	break;
        }
    }
    return error_u32;
}


uint32 HalAdcConfigureCallback(MapHalAdcModule_en adcModule_en, uint32 (*callback_pfn)(void))
{
    uint32 error_u32 = NMS_ERR_DEFAULT;

    if (adcModule_en < MAP_HAL_ADC_NUMBER )
    {
    	halAdcCallbacks[adcModule_en] = callback_pfn;
        error_u32 = NMS_ERR_NONE;
    }
    else
    {
        error_u32 = NMS_ERR_UNKNOWN;
    }

    return error_u32;
}


void HalAdcDeinit(MapHalAdcModule_en adcModule_en)
{
    uint32 error_u32 = NMS_ERR_DEFAULT;
    ADC_HandleTypeDef * targetModule_pst;
    uint8 index_u8;
    uint8 startIndex_u8;
    uint8 iteration_u8 = 1u;		 /* Default to 1 loop iteration (deinit one module) */

    if(adcModule_en == MAP_HAL_ADC_NUMBER)
    {
        iteration_u8  = adcModule_en;
        startIndex_u8 = 0u;
    }
    else
    {
        iteration_u8 += adcModule_en;
        startIndex_u8 = adcModule_en;
    }

    for(index_u8 = startIndex_u8; index_u8 < iteration_u8; index_u8++)
    {
        error_u32 = MapHalAdcModule((MapHalAdcModule_en)index_u8, &targetModule_pst);
        if(error_u32 == NMS_ERR_NONE)
        {
            HAL_ADC_DeInit(targetModule_pst);
        }
    }
}
/******************************************************************************
 * Callback Function Definitions
 ******************************************************************************/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    uint32 error_u32 = NMS_ERR_DEFAULT;
    MapHalAdcModule_en adcModule_en;

    error_u32 = MapHalAdcCallback(MAP_HAL_ADC_1, &adcModule_en);

    if (error_u32 == NMS_ERR_NONE)
    {
        if (adcModule_en < MAP_HAL_ADC_NUMBER)
        {
            if (halAdcCallbacks[adcModule_en] != NULL)
            {
                halAdcCallbacks[adcModule_en]();
            }
            else
            {
                error_u32 = NMS_ERR_UNKNOWN;
            }
        }
        else
        {
            error_u32 = NMS_ERR_INVALID_MODULE;
        }
    }
    else
    {
        error_u32 = NMS_ERR_UNKNOWN;
    }
}

void HAL_ADC_ErrorCallback(ADC_HandleTypeDef* hadc)
{
    uint32 error_u32 = NMS_ERR_DEFAULT;
    ADC_HandleTypeDef *targetModule_pst = NULL;

    error_u32 = MapHalAdcModule(MAP_HAL_ADC_1, &targetModule_pst);

    if(error_u32 == NMS_ERR_NONE)
    {
        switch(hadc->State)
        {
        case HAL_ADC_STATE_RESET:
        	error_u32 = NMS_ERR_UNKNOWN;
        	break;

        case HAL_ADC_STATE_BUSY:
        	error_u32 = NMS_ERR_BUSY;
            break;

        case HAL_ADC_STATE_TIMEOUT:
        	error_u32 = NMS_ERR_TIMEOUT;
            break;

        case HAL_ADC_STATE_ERROR:
        	error_u32 = NMS_ERR_BUSY;
        	break;

        case HAL_ADC_STATE_READY:
        	error_u32 = NMS_ERR_NOT_RUNNING;
        	break;

        default:
        	error_u32 = NMS_ERR_UNKNOWN;
        	break;
        }
    }
    else
    {
    	error_u32 = NMS_ERR_UNKNOWN;
    }
}
