//=================================================================================================
//
// Company:       Paul Scherrer Institut
//                5232 Villigen PSI
//                Switzerland
//
//-------------------------------------------------------------------------------------------------
//
// Project:       Peltier Controller V2
// Author:        Noah Piqué (noah.pique@psi.ch)
//
//-------------------------------------------------------------------------------------------------
//
// Module:        Main Application
// Filename:      MAIN_MainApplication.c
// Date:          Handled by Subversion (version control system)
// Revision:      Handled by Subversion (version control system)
// History:       Handled by Subversion (version control system)
//
//-------------------------------------------------------------------------------------------------
//
// Description:   TEC - Peltier Controller Communication handler
//
//=================================================================================================



//=================================================================================================
// Section:       INCLUDES
// Description:   List of required include files.
//=================================================================================================

#include "../PDEF_ProjectDefinitions.h"
#include "MAIN_MainApplication.h"

// Application
#include "VARH_VariableHandler.h"
//#include "ELOG_ErrorLogger.h"

// Drivers
#include "../Drivers/TEMP_Temperature.h"
#include "../Drivers/DIPO_DigitalPorts.h"
#include "../Drivers/CAND_CanDriver.h"
#include "PECO_PeltierController.h"
#include "../Drivers/ANPI_AnalogPortsIn.h"

// Toolbox
#include "../Toolbox/UTIL_Utility.h"

// include STM32 drivers
#include "stm32l4xx_hal.h"

#include "cmsis_os2.h" 

//=================================================================================================
// Section:       DEFINITIONS
// Description:   Definition of local constants (visible by this module only).
//=================================================================================================

#define MSG_QUEUE_SIZE							8

#define EVENT_NEW_MESSAGE 					((U32)(1<<0))
#define EVENT_TIMER_UPDATE					((U32)(1<<1))

#define EVENT_FLAGS_ALL             ( EVENT_NEW_MESSAGE | EVENT_TIMER_UPDATE )

#define COMMAND_NONE                0
#define COMMAND_ON                  1
#define COMMAND_OFF                 2

//=================================================================================================
// Section:       MACROS
// Description:   Definition of local macros (visible by this module only).
//=================================================================================================



//=================================================================================================
// Section:       ENUMERATIONS
// Description:   Definition of local enumerations (visible by this module only).
//=================================================================================================



//=================================================================================================
// Section:       STRUCTURES
// Description:   Definition of local Structures (visible by this module only).
//=================================================================================================



//=================================================================================================
// Section:       LOCAL FUNCTIONS (PROTOTYPES)
// Description:   Definition of local functions (visible by this module only).
//=================================================================================================

PRIVATE VOID vTask( PVOID arg );
PRIVATE VOID vEventCallback( PVOID pvData );
PRIVATE VOID vMsgRxCallback( CAND_Message stMessage );

//=================================================================================================
// Section:       LOCAL VARIABLES
// Description:   Definition of local variables (visible by this module only).
//=================================================================================================

LOCAL osThreadId_t        m_pstThreadID       		= NULL;
LOCAL osMessageQueueId_t  m_pstCANRxMsgQueueID    = NULL;
LOCAL osEventFlagsId_t    m_pstEventID        		= NULL;

LOCAL osTimerId_t         m_pstUpdateTimer    = NULL;

//=================================================================================================
// Section:       LOCAL CONSTANTS
// Description:   Definition of local constants (visible by this module only).
//=================================================================================================

LOCAL CONST osThreadAttr_t stTaskAttribute =
{
  "MAIN_Thread",                    // name of the thread
  osThreadDetached,                 // attribute bits
  NULL,                             // memory for control block
  0,                                // size of provided memory for control block
  NULL,                             // memory for stack
  1024,                             // size of stack
  osPriorityNormal,                 // initial thread priority (default: osPriorityNormal)
  0,                                // TrustZone module identifier
  0,                                // reserved (must be 0)
};


LOCAL CONST osMessageQueueAttr_t stCANRxMsgQueueAttribute =
{
  "MAIN_CAN_Rx_Queue",             // name of the message queue
  0,                                // attribute bits
  NULL,                             // memory for control block
  0,                                // size of provided memory for control block
  NULL,                             // memory for data storage
  0,                                // size of provided memory for data storage 
};



LOCAL CONST osEventFlagsAttr_t stEventAttribute =
{ 
  "MAIN_Event_Flags",               // name of the event flags 
  0,                                // attribute bits 
  NULL,                             // memory for control block
  0,                                // size of provided memory for control block
};

LOCAL CONST osTimerAttr_t stTimerAttribute =
{ 
  "MAIN_UpdateTimer",               // name of the timer
  0,                                // attribute bits
  NULL,                             // memory for control block
  0,                                // size of provided memory for control block
};

//=================================================================================================
// Section:       EXTERNAL FUNCTIONS
// Description:   Definition of external (global) functions.
//=================================================================================================



//=================================================================================================
// Section:       EXTERNAL VARIABLES
// Description:   Definition of external (global) variables.
//=================================================================================================

//=================================================================================================
// Section:       GLOBAL FUNCTIONS
// Description:   Definition (implementation) of global functions.
//=================================================================================================


//-------------------------------------------------------------------------------------------------
// Function:      MAIN_boInitializeModule
// Description:   Initializes the module. Function must be called once immediately after power-up.
// Parameters:    None
// Returns:       Boolean TRUE if successful
//-------------------------------------------------------------------------------------------------

BOOL MAIN_boInitializeModule( VOID )  
{
  BOOL boOK = TRUE;
   
  boOK &= ( ( m_pstEventID = osEventFlagsNew( &stEventAttribute ) ) == NULL ) ? FALSE : TRUE; 
  boOK &= ( ( m_pstThreadID = osThreadNew( vTask, NULL, &stTaskAttribute ) ) == NULL ) ? FALSE : TRUE;
	boOK &= ( ( m_pstCANRxMsgQueueID = osMessageQueueNew( MSG_QUEUE_SIZE, sizeof( CAND_Message ), &stCANRxMsgQueueAttribute ) ) == NULL ) ? FALSE : TRUE;
  boOK &= ( m_pstUpdateTimer = osTimerNew( vEventCallback, osTimerPeriodic, (PVOID)EVENT_TIMER_UPDATE, &stTimerAttribute ) ) == NULL ? FALSE : TRUE;
  
  boOK &= (osTimerStart( m_pstUpdateTimer, 1000 ) == osOK ) ? TRUE : FALSE;
	
	CAND_vSetRxCallback( vMsgRxCallback );
  
  return( boOK );
}

//=================================================================================================
// Section:       LOCAL FUNCTIONS
// Descriptionn:  Definition (implementation) of local functions.
//=================================================================================================

//-------------------------------------------------------------------------------------------------
// Function:      vMainTask
// Description:   Main Application Task
// Parameters:    None
// Returns:       None
//-------------------------------------------------------------------------------------------------
PRIVATE VOID vTask( PVOID arg )
{
  UNUSED( arg );
  U32 u32Flags;

  U8 au8Buffer[8];
	
  while( TRUE )
  {
		
		u32Flags = osEventFlagsWait( m_pstEventID, EVENT_FLAGS_ALL, osFlagsWaitAny, osWaitForever );
		
		if( u32Flags & EVENT_NEW_MESSAGE ) {

			CAND_Message stMessage;
      osMessageQueueGet( m_pstCANRxMsgQueueID, &stMessage, NULL, 0 );

      U8 u8Register = stMessage.au8Data[0];
      U8 u8Type = stMessage.u8Type;

      if( u8Type == MESSAGE_TYPE_READ ){
        if( u8Register >= VARH_eNumberOfVariables ){
          au8Buffer[0] = 0xFF;
          CAND_boSendMessage( au8Buffer, 1 );
        } else {
          VARH_UVariable uVariable = VARH_uGetVariableData(u8Register);
          au8Buffer[0] = u8Register;
          UTIL_vMemCopy(&uVariable, &au8Buffer[1], 4);

          CAND_boSendMessage( au8Buffer, 5 );
        }
        
      } else if( u8Type == MESSAGE_TYPE_WRITE ){
        VARH_UVariable uData;
        UTIL_vMemCopy(&stMessage.au8Data[1], &uData, 4);

        VARH_vSetVariableData(u8Register, uData);
      } else if( u8Type == MESSAGE_TYPE_COMMAND ){

        switch (u8Register)
        {
        case COMMAND_ON:
          PECO_Enable( TRUE );
          break;

        case COMMAND_OFF:
          PECO_Enable( FALSE );
          break;
          // TODO: Implement watchdog
        default:
          break;
        }
      }
    }

		if( u32Flags & EVENT_TIMER_UPDATE )
    {
			DIPO_vToggleOutput( DIPO_eLED );
		}
        
  }
}

//-------------------------------------------------------------------------------------------------
// Function:      vEventCallback
// Description:   Callback for events
// Parameters:    None
// Returns:       None
//-------------------------------------------------------------------------------------------------
PRIVATE VOID vEventCallback( PVOID pvData )
{
  osEventFlagsSet( m_pstEventID, (U32)pvData );
}

//-------------------------------------------------------------------------------------------------
// Function:      vEventCallback
// Description:   Callback for events
// Parameters:    None
// Returns:       None
//-------------------------------------------------------------------------------------------------
PRIVATE VOID vMsgRxCallback( CAND_Message stMessage )
{
  osMessageQueuePut( m_pstCANRxMsgQueueID, &stMessage, 0, 0 );
	osEventFlagsSet( m_pstEventID, EVENT_NEW_MESSAGE );
}


