/**
*   @file    IoDal_Bridge.c
*   @version 1.0.0
*
*   @brief   Integration Framework - IO Driver Abstraction Layer component for analog
*                                      input channels
*   @details This file implements the IODAL interface to application layer to lower bridge layers
*            
*   (c) Copyright 2006-2016 Freescale Semiconductor, Inc. 
*       Copyright 2017-2018 NXP
*   All Rights Reserved.
*   This file contains sample code only. It is not part of the production code deliverables.
*
*   @addtogroup IODAL
*   @{
*/
/*=========================================================================================================================
*   Platform             : PA
*
*   Autosar Version      : 4.3.1
*   Autosar Revision     : ASR_REL_4_3_REV_0001
*   
*   SW Version           : 1.0.0
*   Build Version        : MPC5777CXG_MCAL_1_0_0_RTM_ASR_REL_4_3_REV_0001_20190318
*
============================================================================================================================*/
/*============================================================================================================================
==============================================================================================================================*/


#ifdef __cplusplus
extern "C"{
#endif

/*===================================================================================================================
                                         INCLUDE FILES
 1) system and project includes
 2) needed interfaces from external units
 3) internal and external interfaces from this unit
====================================================================================================================*/
#include "Std_Types.h"
#include "Mcal.h"
#include "IoDal_Drv_Cfg.h"
#include "IoDal_Types.h"
#include "IoDal_Cfg.h"
#include "IoDal_Motor_Bridge.h"
#include "Pwm.h"

/*===================================================================================================================
*                              SOURCE FILE VERSION INFORMATION
====================================================================================================================*/
#define IODAL_MOTOR_BRIDGE_VENDOR_ID_C                        43
                                                       
#define IODAL_MOTOR_BRIDGE_AR_RELEASE_MAJOR_VERSION_C       4
#define IODAL_MOTOR_BRIDGE_AR_RELEASE_MINOR_VERSION_C        3
#define IODAL_MOTOR_BRIDGE_AR_RELEASE_REVISION_VERSION_C     1
                                                       
#define IODAL_MOTOR_BRIDGE_SW_MAJOR_VERSION_C                1
#define IODAL_MOTOR_BRIDGE_SW_MINOR_VERSION_C                0
#define IODAL_MOTOR_BRIDGE_SW_PATCH_VERSION_C                0
                                                       
                                                       
                                                       
/*===================================================================================================================
*                                     FILE VERSION CHECKS
====================================================================================================================*/
/* Check if source file and IODAL header file are of the same vendor */
#if (IODAL_MOTOR_BRIDGE_VENDOR_ID_C != IODAL_CFG_VENDOR_ID)
    #error "IoDal_Bridge.c and IoDal_Cfg.h have different vendor ids"
#endif

/* Check if source file and IODAL header file are of the same Autosar version */
#if ((IODAL_MOTOR_BRIDGE_AR_RELEASE_MAJOR_VERSION_C != IODAL_CFG_AR_RELEASE_MAJOR_VERSION) || \
     (IODAL_MOTOR_BRIDGE_AR_RELEASE_MINOR_VERSION_C != IODAL_CFG_AR_RELEASE_MINOR_VERSION) || \
     (IODAL_MOTOR_BRIDGE_AR_RELEASE_REVISION_VERSION_C != IODAL_CFG_AR_RELEASE_REVISION_VERSION) \
    )
    #error "AutoSar Version Numbers of IoDal_Bridge.c and IoDal_Cfg.h are different"
#endif

/* Check if source file and IODAL header file are of the same Software version */
#if ((IODAL_MOTOR_BRIDGE_SW_MAJOR_VERSION_C != IODAL_CFG_SW_MAJOR_VERSION) || \
     (IODAL_MOTOR_BRIDGE_SW_MINOR_VERSION_C != IODAL_CFG_SW_MINOR_VERSION) || \
     (IODAL_MOTOR_BRIDGE_SW_PATCH_VERSION_C != IODAL_CFG_SW_PATCH_VERSION) \
    )
    #error "Software Version Numbers of IoDal_Bridge.c and IoDal_Cfg.h are different"
#endif

/* Check if source file and IODAL IPW header file are from the same vendor */
#if (IODAL_MOTOR_BRIDGE_VENDOR_ID_C != IODAL_MOTOR_BRIDGE_VENDOR_ID)
    #error "IoDal_Bridge.c and IoDal_Dio.h have different vendor ids"
#endif

/* Check if source file and IODAL types header file are of the same Autosar version */
#if ((IODAL_MOTOR_BRIDGE_AR_RELEASE_MAJOR_VERSION_C != IODAL_MOTOR_BRIDGE_AR_RELEASE_MAJOR_VERSION) || \
     (IODAL_MOTOR_BRIDGE_AR_RELEASE_MINOR_VERSION_C != IODAL_MOTOR_BRIDGE_AR_RELEASE_MINOR_VERSION) || \
     (IODAL_MOTOR_BRIDGE_AR_RELEASE_REVISION_VERSION_C != IODAL_MOTOR_BRIDGE_AR_RELEASE_REVISION_VERSION) \
    )
    #error "AutoSar Version Numbers of IoDal_Bridge.c and IoDal_Dio.h are different"
#endif

/* Check if source file and IODAL types header file are of the same Software version */
#if ((IODAL_MOTOR_BRIDGE_SW_MAJOR_VERSION_C != IODAL_MOTOR_BRIDGE_SW_MAJOR_VERSION) || \
     (IODAL_MOTOR_BRIDGE_SW_MINOR_VERSION_C != IODAL_MOTOR_BRIDGE_SW_MINOR_VERSION) || \
     (IODAL_MOTOR_BRIDGE_SW_PATCH_VERSION_C != IODAL_MOTOR_BRIDGE_SW_PATCH_VERSION) \
    )
  #error "Software Version Numbers of IoDal_Bridge.c and IoDal_Dio.h are different"
#endif


#ifndef DISABLE_MCAL_INTERMODULE_ASR_CHECK
 /* Check if source file and Std_Types header file are of the same AutoSar version */
 #if ((IODAL_MOTOR_BRIDGE_AR_RELEASE_MAJOR_VERSION_C != STD_AR_RELEASE_MAJOR_VERSION) || \
      (IODAL_MOTOR_BRIDGE_AR_RELEASE_MINOR_VERSION_C != STD_AR_RELEASE_MINOR_VERSION) \
     )
 #error "AutoSar Version Numbers of IoDal_Bridge.c and Std_Types.h are different"
 #endif
 /* Check if source file and Mcal header file are of the same AutoSar version */
 #if ((IODAL_MOTOR_BRIDGE_AR_RELEASE_MAJOR_VERSION_C != MCAL_AR_RELEASE_MAJOR_VERSION) || \
      (IODAL_MOTOR_BRIDGE_AR_RELEASE_MINOR_VERSION_C != MCAL_AR_RELEASE_MINOR_VERSION) \
     )
 #error "AutoSar Version Numbers of IoDal_Bridge.c and Mcal.h are different"
 #endif 
#endif

#if IODAL_MAX_MOTOR_BRIDGE_OUTPUT_DESCRIPTORS > 0U
/*===================================================================================================================
                                        LOCAL MACROS
====================================================================================================================*/
/* Mask needed in order to filter direction information */
#define IODAL_MOTOR_DIRECTION_MASK             0xFF00FFFF

/* Shift needed in order to filter direction information */
#define IODAL_MOTOR_DIRECTION_SHIFT            16U

/* Mask needed in order to filter motor bridge type information */
#define IODAL_MOTOR_TYPE_MASK                  0x00FFFFFF

/* Shift needed in order to filter motor bridge type information */
#define IODAL_MOTOR_TYPE_SHIFT                 24U

/* Mask needed in order to filter motor speed information */
#define IODAL_MOTOR_SPEED_MASK                 0x0000FFFF

/* Maximum possible output channels for any bridge */
#define IODAL_MOTOR_BRIDGE_MAX_OUTPUT_CHANNELS     3U

/* Pwm half duty needed for active braking */
#define IODAL_MOTOR_BRIDGE_HALF_DUTY           0x4000

/* Motor clockwise direction pwm channel index*/
#define IODAL_MOTOR_BRIDGE_CLOCKWISE_INDEX           0U

/* Motor counterclockwise direction pwm channel index*/
#define IODAL_MOTOR_BRIDGE_COUNTERCLOCKWISE_INDEX    1U

/* Motor not used direction pwm channel index, needed for future compatibility */
#define IODAL_MOTOR_BRIDGE_TERNARY_OUTPUT_INDEX            2U

/*===================================================================================================================
                          LOCAL TYPEDEFS (STRUCTURES, UNIONS, ENUMS)
====================================================================================================================*/
typedef enum
{
    IODAL_MOTOR_BRIDGE_BRDC = 0U,         /* type brushed DC */
    IODAL_MOTOR_BRIDGE_BRDL = 1U,         /* type brush less DC */
    IODAL_MOTOR_BRIDGE_STEPPER = 2U,      /* stepper */
    IODAL_MOTOR_BRIDGE_SERVO = 3U         /* servo motor*/
}Iodal_MotorBridgeType;
/*===================================================================================================================
                                       LOCAL CONSTANTS
====================================================================================================================*/
/**
* @brief          Global Configuration Pointer for Digital inputs components.
* @details        Data structure containing the set of configuration parameters required for
*                 initializing the IODAL - Bridge components.
*
*/
static P2CONST(IoDal_BswIoConfigType, IODAL_VAR,  IODAL_APPL_CONST) IoDal_pMotorBridgeGlobalCfgPtr=NULL_PTR;

/*===================================================================================================================
                                       LOCAL VARIABLES
====================================================================================================================*/
static VAR(Pwm_ChannelType, IODAL_APP_CONST) Iodal_OutputChannels[IODAL_MAX_MOTOR_BRIDGE_OUTPUT_DESCRIPTORS][IODAL_MOTOR_BRIDGE_MAX_OUTPUT_CHANNELS];

/*===================================================================================================================
                                       GLOBAL CONSTANTS
====================================================================================================================*/


/*===================================================================================================================
                                       GLOBAL VARIABLES
====================================================================================================================*/


/*===================================================================================================================
                                   LOCAL FUNCTION PROTOTYPES
====================================================================================================================*/


/*===================================================================================================================
                                       LOCAL FUNCTIONS
====================================================================================================================*/


/*===================================================================================================================
                                       GLOBAL FUNCTIONS
====================================================================================================================*/
/*==================================================================================================================*/

/*==================================================================================================================*/
/**
@brief      IoDal_Motor_Bridge_Init - Initialize the IODAL Bridge components

@param[in]  ConfigPtr    Pointer to configuration data (this data is shared between all IODAL components)

@return     None

@pre None
@post None
*/
/*===================================================================================================================*/
FUNC(void, IODAL_APP_CODE) IoDal_Motor_Bridge_Init(P2CONST(IoDal_BswIoConfigType, AUTOMATIC, IODAL_APP_CONST) ConfigPtr)
{        
    VAR(IoDal_BswChannelType, AUTOMATIC) ChannelType;
    VAR(IoDal_BswDescriptorIdType, AUTOMATIC) Iodal_MotorBridgeMapIndex;

    VAR(uint8, AUTOMATIC) MaxIoChannels = 0U;
    VAR(uint8, AUTOMATIC) Iodal_ChannelIndex = 0U;
    
    IoDal_pMotorBridgeGlobalCfgPtr = ConfigPtr;
    
    MaxIoChannels =  IoDal_pMotorBridgeGlobalCfgPtr->AdcDescriptorsCount + IoDal_pMotorBridgeGlobalCfgPtr->PwmChannelCount + \
                     IoDal_pMotorBridgeGlobalCfgPtr->DioChannelCount  + IoDal_pMotorBridgeGlobalCfgPtr->OcuChannelCount + \
                     IoDal_pMotorBridgeGlobalCfgPtr->IcuChannelCount + + IoDal_pMotorBridgeGlobalCfgPtr->BridgeChannelCount;
  
  
    for(Iodal_ChannelIndex = 0U; Iodal_ChannelIndex < MaxIoChannels; Iodal_ChannelIndex++)
    {
        ChannelType = IoDal_pMotorBridgeGlobalCfgPtr->pBswChannelMap[Iodal_ChannelIndex].BswChannelType;
        if(IODAL_EXT_DEV_OUTPUT == ChannelType)
        {
            Iodal_MotorBridgeMapIndex = IoDal_pMotorBridgeGlobalCfgPtr->pBswChannelMap[Iodal_ChannelIndex].BswDescriptorIndex;
            Iodal_OutputChannels[Iodal_MotorBridgeMapIndex][IODAL_MOTOR_BRIDGE_CLOCKWISE_INDEX] = (((IoDal_pMotorBridgeGlobalCfgPtr->pBridgeChanDescriptor))[Iodal_MotorBridgeMapIndex]).PwmPrimaryDriveChannel;
            Iodal_OutputChannels[Iodal_MotorBridgeMapIndex][IODAL_MOTOR_BRIDGE_COUNTERCLOCKWISE_INDEX] = (((IoDal_pMotorBridgeGlobalCfgPtr->pBridgeChanDescriptor))[Iodal_MotorBridgeMapIndex]).PwmSecondaryDriveChannel;
            Iodal_OutputChannels[Iodal_MotorBridgeMapIndex][IODAL_MOTOR_BRIDGE_TERNARY_OUTPUT_INDEX] = (((IoDal_pMotorBridgeGlobalCfgPtr->pBridgeChanDescriptor))[Iodal_MotorBridgeMapIndex]).PwmTernaryDriveChannel;                                                                                                           
        }
    }
}

/*===================================================================================================================*/
/**
@brief      IoDal_Bridge_WriteOutputs - Write the output requests.
@details    For channels connected to bridge this function shall call the driver directly and write based on bridge 
            type and bridge direction output values in duty cycle. 

@param[in]  BswIoChannel    Logical BSW output channel id.
@param[out] OutputValue     Value to be written to a digital output channel.

@return     void
@retval     

@pre None
@post None
*/
/*===================================================================================================================*/
FUNC(void, IODAL_APP_CODE) IoDal_Motor_Bridge_WriteOutputs(IoDal_BswChannelIdType BswIoChannel, IoDal_BswValueType OutputValue)
{
    VAR(IoDal_MotorOperationType,   AUTOMATIC) Iodal_MotorBridge_MotorOperation;
    VAR(uint32,                     AUTOMATIC) Iodal_MotorBridge_OutputDuty;
    VAR(IoDal_BswDescriptorIdType,  AUTOMATIC) Iodal_MotorBridge_DescriptorIndex;
    VAR(Iodal_MotorBridgeType,      AUTOMATIC) Iodal_MotorBridge;
    
    /* Get Bridge type */
    Iodal_MotorBridge = (Iodal_MotorBridgeType) ((OutputValue & IODAL_MOTOR_DIRECTION_MASK) >> IODAL_MOTOR_TYPE_SHIFT);
    
    /* Get Motor direction */
    Iodal_MotorBridge_MotorOperation = (IoDal_MotorOperationType) ((OutputValue & IODAL_MOTOR_TYPE_MASK) >> IODAL_MOTOR_DIRECTION_SHIFT);
    
    /* Get output value */
    Iodal_MotorBridge_OutputDuty = OutputValue & IODAL_MOTOR_SPEED_MASK;
   
    /*Index of current channel in own data type channel descriptor*/
    Iodal_MotorBridge_DescriptorIndex = IoDal_pMotorBridgeGlobalCfgPtr->pBswChannelMap[BswIoChannel].BswDescriptorIndex;
    
    
    if(IODAL_MOTOR_BRIDGE_BRDC == Iodal_MotorBridge)
    {
        switch(Iodal_MotorBridge_MotorOperation)
        {
            case IODAL_MOTOR_BRIDGE_CW:
            {
                /* Set only first pwm for clockwise direction */
                Pwm_SetDutyCycle(Iodal_OutputChannels[Iodal_MotorBridge_DescriptorIndex][IODAL_MOTOR_BRIDGE_CLOCKWISE_INDEX], Iodal_MotorBridge_OutputDuty);
                Pwm_SetDutyCycle(Iodal_OutputChannels[Iodal_MotorBridge_DescriptorIndex][IODAL_MOTOR_BRIDGE_COUNTERCLOCKWISE_INDEX], 0);
            } break;        
            
            case IODAL_MOTOR_BRIDGE_CCW:
            {
                /* Set only second pwm for counterclockwise direction */
                Pwm_SetDutyCycle(Iodal_OutputChannels[Iodal_MotorBridge_DescriptorIndex][IODAL_MOTOR_BRIDGE_CLOCKWISE_INDEX], 0);
                Pwm_SetDutyCycle(Iodal_OutputChannels[Iodal_MotorBridge_DescriptorIndex][IODAL_MOTOR_BRIDGE_COUNTERCLOCKWISE_INDEX], Iodal_MotorBridge_OutputDuty);
                
            } break;        
            
            case IODAL_MOTOR_BRIDGE_STOP:
            {
                /* Set both pwms to 0 for stop */
                Pwm_SetDutyCycle(Iodal_OutputChannels[Iodal_MotorBridge_DescriptorIndex][IODAL_MOTOR_BRIDGE_CLOCKWISE_INDEX], 0);
                Pwm_SetDutyCycle(Iodal_OutputChannels[Iodal_MotorBridge_DescriptorIndex][IODAL_MOTOR_BRIDGE_COUNTERCLOCKWISE_INDEX], 0);
                
            } break;        
            
            case IODAL_MOTOR_BRIDGE_BREAK:
            {
                /* Set both pwms to half value for active brake */
                Pwm_SetDutyCycle(Iodal_OutputChannels[Iodal_MotorBridge_DescriptorIndex][IODAL_MOTOR_BRIDGE_CLOCKWISE_INDEX], IODAL_MOTOR_BRIDGE_HALF_DUTY);
                Pwm_SetDutyCycle(Iodal_OutputChannels[Iodal_MotorBridge_DescriptorIndex][IODAL_MOTOR_BRIDGE_COUNTERCLOCKWISE_INDEX], IODAL_MOTOR_BRIDGE_HALF_DUTY);
                
            } break;
            
            case IODAL_MOTOR_BRIDGE_ERROR:
            default:
            {
                /* Set both pwms 0 if any error occurs */
                Pwm_SetDutyCycle(Iodal_OutputChannels[Iodal_MotorBridge_DescriptorIndex][IODAL_MOTOR_BRIDGE_CLOCKWISE_INDEX], 0);
                Pwm_SetDutyCycle(Iodal_OutputChannels[Iodal_MotorBridge_DescriptorIndex][IODAL_MOTOR_BRIDGE_COUNTERCLOCKWISE_INDEX], 0);
            } break; 
        }    
    }
}

/*===================================================================================================================*/
/**
@brief      Iodal_MotorBridge_MainFunction 
@retval     None

@pre None
@post None
*/
/*===================================================================================================================*/
FUNC(void, IODAL_APP_CODE) Iodal_Motor_Bridge_MainFunction(IoDal_BswChannelIdType BswIoChannel)
{        
    /* TO DO: Add error handling whenever new feedback is available via sw triggering */  
}


#endif /* IODAL_MAX_MOTOR_BRIDGE_OUTPUT_DESCRIPTORS > 0U*/
/*===================================================================================================================*/

#ifdef __cplusplus
}
#endif 
/** @} */
