///////////////////////////////////////////////////////////////////////////////////////////////////
// NXP B.V. 2013. All rights reserved.
// Disclaimer
// 1.         The NXP Software/Source Code is provided to Licensee "AS IS" without any warranties of
// any kind. NXP makes no warranties to Licensee and shall not indemnify Licensee or hold it harmless 
// for any reason related to the NXP Software/Source Code or otherwise be liable to the NXP customer.
// The NXP customer acknowledges and agrees that the NXP Software/Source Code is provided AS-IS and 
// accepts all risks of utilizing the NXP Software under the conditions set forth according to this 
// disclaimer. 
// 
// 2.         NXP EXPRESSLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED 
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND 
// NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS. NXP SHALL HAVE NO LIABILITY TO THE NXP CUSTOMER,
// OR ITS SUBSIDIARIES, AFFILIATES, OR ANY OTHER THIRD PARTY FOR ANY DAMAGES, INCLUDING WITHOUT 
// LIMITATION, DAMAGES RESULTING OR ALLEGDED TO HAVE RESULTED FROM ANY DEFECT, ERROR OR OMMISSION IN 
// THE NXP SOFTWARE/SOURCE CODE, THIRD PARTY APPLICATION SOFTWARE AND/OR DOCUMENTATION, OR AS A 
// RESULT OF ANY INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHT OF ANY THIRD PARTY. IN NO EVENT
// SHALL NXP BE LIABLE FOR ANY INCIDENTAL, INDIRECT, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL 
// DAMAGES (INCLUDING LOST PROFITS) SUFFERED BY NXP CUSTOMER OR ITS SUBSIDIARIES, AFFILIATES, 
// OR ANY OTHER THIRD PARTY ARISING OUT OF OR RELATED TO THE NXP SOFTWARE/SOURCE CODE EVEN IF 
// NXP HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
///////////////////////////////////////////////////////////////////////////////////////////////////

#include <NXP_TJA1145FD_Functions.h>
#include <NXP_UJA11XX_defines.h>
#include <TJA1145FD_Application_Specific_Functions.h>
#include <uC_Specific_Functions.h>
#include "Lpspi_Ip.h"
#include "Siul2_Port_Ip.h"
#include "Siul2_Dio_Ip.h"

//#define Lpspi_Ip_DeviceAttributes_SPI3_TJA1145_1_BOARD_InitPeripherals (Lpspi_Ip_DeviceAttributes_SPI3_TJA1145_1_BOARD_InitPeripherals)
//#define Lpspi_Ip_DeviceAttributes_SPI3_TJA1145_2_BOARD_InitPeripherals (Lpspi_Ip_DeviceAttributes_SPI3_TJA1145_2_BOARD_InitPeripherals)

#define Lpspi_Ip_DeviceAttributes_SPI3_TJA1145_1_BOARD_InitPeripherals (Lpspi_Ip_DeviceAttributes_BOARD_InitPeripherals[8])
#define Lpspi_Ip_DeviceAttributes_SPI3_TJA1145_2_BOARD_InitPeripherals (Lpspi_Ip_DeviceAttributes_BOARD_InitPeripherals[9])


// it indicates what SPI instance is used for TJA1145
uint32_t instSpiTja1145 = TJA1145_LPSPI_INSTANCE;	/*LPSPI3 interface*/

// it indicates what SPI PCS pin  is used for TJA1145
uint32_t pcsSpiTja1145 = TJA1145_LPSPI_PCS1;	/* LPSPI_PCS1 */

// it indicates which TJA1145 is to be accessed by MCU, assuming that there are two TJA1145 on the same SPI interface with two different PCS pin;
uint32_t nTja1145Sel = 0;

extern void InitScheduler(void);

void TJA1145_Select(int nSelect)
{
	nTja1145Sel = nSelect;
	if(nTja1145Sel == 0)
	{
		instSpiTja1145 = TJA1145_LPSPI_INSTANCE;
		pcsSpiTja1145 = TJA1145_LPSPI_PCS1;
	}
	else if(nTja1145Sel == 1)
	{
		instSpiTja1145 = TJA1145_LPSPI_INSTANCE;
		pcsSpiTja1145 = TJA1145_LPSPI_PCS3;
	}
}

/**
* \brief SPI transmission routine
* \todo implement this function with your microcontroller specific code
*	- Disable interrupts
*	- SPI_DATA_REG = tx;
*	- Wait until transition is done
*	- tx = SPI_DATA_REG
*	- Enable interrupts
* Remark: Furthermore, this function should not only send data via SPI, it should also check, if the SPI access was successful. 
* Therefore, after the 1st SPI access, a 2nd SPI read access is performed to ensure that the configurations has been 
* changed or rather the 1st read values have been correct.  
*
* \param data A pointer to the data which shall be transmitted by the SPI interface
* \param length Number of data Bytes which shall be transmitted by the SPI interface
* \param mask Mask of Bits interesting for the consistency check
* \param type Type (write/read/interrupt) of the SPI access 
* \return <b>NXP_UJA11XX_Error_Code_t</b> possible values: NXP_UJA11XX_ERROR_WRITE_FAIL = 0, NXP_UJA11XX_ERROR_READ_FAIL = 1, NXP_UJA11XX_ERROR_SPI_HW_FAIL = 2, NXP_UJA11XX_SUCCESS = 3
*/
/*Std_ReturnType SPI_Send(uint8_t spiDevice, uint8_t numOfBytes, uint8_t* sendDataPtr, uint8_t* rcvDataPtr)
{
  return LPSPI_DRV_MasterTransferBlocking(spiDevice, sendDataPtr, rcvDataPtr, numOfBytes, SPI_TIMEOUT) ? E_NOT_OK : E_OK;
}*/

NXP_UJA11XX_Error_Code_t TJA1145FD_SPI_Send(Byte* data, NXP_UJA11XX_SPI_Msg_Length_t length, Byte mask, NXP_UJA11XX_Access_t type) {

	// Insert your microcontroller specific code here
	// e.g.
	// First SPI access:
	// - Disable interrupts
	// - SPI_DATA_REG = tx;
	// - Wait until transision done
	// - tx = SPI_DATA_REG
	// - Enable interrupts
	// If no MTP register is accessed, read a second time:
	// - Disable interrupts
	// - SPI_DATA_REG = tx;
	// - Wait until transision done
	// - tx = SPI_DATA_REG
	// - Enable interrupts	
	// Check of consistency:
	// - In case of a write access: 
	// -- If address bytes of both SPI accesses and the data byte(s) sent in 1st and read back in 2nd SPI access are similar, SPI access was successful (NXP_UJA11XX_SUCCESS).
	// -- Else if address and data byte(s) read back are '0x00' or '0xFF', NXP_UJA11XX_ERROR_SPI_HW_FAIL is returned.
	// -- Else SPI write access was not succesful and NXP_UJA11XX_ERROR_WRITE_FAIL is returned. 
	// - In case of an read access: 
	// -- If address bytes and the data byte(s) of both SPI read accesses are similar, SPI access was successful (NXP_UJA11XX_SUCCESS).
	// -- Else SPI read access was not succesful and NXP_UJA11XX_ERROR_READ_FAIL is returned.
	// - In case of an access to an interrupt register:
	// -- If address bytes of both SPI accesses are similar and the according interrupt bit(s) are cleared in 2nd SPI access data, SPI access was successful.
	// -- Else SPI write access was not succesful and NXP_UJA11XX_ERROR_WRITE_FAIL is returned.

	uint8_t tmpTxBuf[2];
	uint8_t tmpRxBuf[2];
	NXP_UJA11XX_Error_Code_t ret;
	Std_ReturnType status = E_OK;
	(void)length;
	(void)type;

	tmpTxBuf[0] = data[1] & mask;
	tmpTxBuf[1] = data[0];

	/* tja1145 may share the same SPI with other devices, it's needed to modify the frame size before start SPI transmission */
	Std_ReturnType tmpStatus;
	do {
		tmpStatus = Lpspi_Ip_UpdateFrameSize(&Lpspi_Ip_DeviceAttributes_SPI3_PCS1_TJA1145_1_Instance_3_BOARD_InitPeripherals, 16);
	} while(tmpStatus != E_OK);

	if(TJA1145_LPSPI_PCS1 == pcsSpiTja1145)
	{
		while(Lpspi_Ip_GetStatus(TJA1145_LPSPI_INSTANCE) == LPSPI_IP_BUSY);
		status = Lpspi_Ip_SyncTransmit(&Lpspi_Ip_DeviceAttributes_SPI3_PCS1_TJA1145_1_Instance_3_BOARD_InitPeripherals, tmpTxBuf, tmpRxBuf, 2, 50000u);
	}
	else if(TJA1145_LPSPI_PCS3 == pcsSpiTja1145)
	{
		while(Lpspi_Ip_GetStatus(TJA1145_LPSPI_INSTANCE) == LPSPI_IP_BUSY);
		status = Lpspi_Ip_SyncTransmit(&Lpspi_Ip_DeviceAttributes_SPI3_PCS3_TJA1145_2_Instance_3_BOARD_InitPeripherals, tmpTxBuf, tmpRxBuf, 2, 50000u);
	}
	data[0] = tmpRxBuf[1];
	data[1] = tmpRxBuf[0];
	if(status == E_OK)
	{
		//if( (type == NXP_UJA11XX_WRITE) && (tmpRxBuf[1] == tmpTxBuf[1]) )
		if(tmpRxBuf[1] == 0)
			ret = NXP_UJA11XX_ERROR_READ_FAIL;
		else if(tmpRxBuf[1] == tmpTxBuf[1])
			ret = NXP_UJA11XX_SUCCESS;
		else
			ret = NXP_UJA11XX_ERROR_WRITE_FAIL;
	}
	else
	{
		ret = NXP_UJA11XX_ERROR_SPI_HW_FAIL;
	}
	return ret;
}

/**
* \brief Init routine of the microcontroller
* \todo implement this function with your microcontroller specific code
*	- Configure SPI with MSB first, shifting on rising and sampling on falling edge
*	- Configure timer interrupt
*	- Configure external interrupt, edge sensitive, interrupt on falling edge
*	- Configure internal CAN Protocol Engine (PE)
*	- Configure Serial Communication Interfaces for LIN communication
*	- Configure internal Analog/Digital Converter (ADC)
*/
void InitMicrocontroller(void){
	// Insert your microcontroller specific code here
	// e.g.
	// Configure SPI with 16 Bit, MSB first, shifting on rising and sampling on falling edge
	// Configure timer interrupt
	// Configure external interrupt, edge sensitive, interrupt on falling edge
	// Configure CAN PE
	// Configure ADC

}

/**
* \brief Check if a flash request is pending
* \todo implement this function with your microcontroller specific code
*	- Read dedicated register in Flash Memory Controller
* \return indicates if a flash update request is pending
*	- 1 = A Flash update is required
*	- 0 = No Flash update request pending
*/
Byte FlashProgramming(void){    
	// Insert your microcontroller specific code here
	// e.g.
	// Read dedicated register in Flash Memory Controller etc.

	return 0;
}

/**
* \brief Disable microcontroller oscillator
* \todo implement this function with your microcontroller specific code
*	- stop asm command 
*/
void EnterMcuStopMode(void)
{
	// Insert your microcontroller specific code here
	// e.g. stop asm command
} 


/**
* \brief Stop CAN transmission in application 
* \todo implement this function with your microcontroller specific code
*	- abort all tasks sending data via CAN
* \return indicates if Abort Transmission was successful
*	- 1 = All CAN transmission aborted
*	- 0 = Abort of all CAN transmissions failed
*/
Byte AbortTransmissionCAN(void){
	// Insert your microcontroller specific code here

	return 0;
}

/**
* \brief CAN PE is stopped (wake-up disabled)
* \todo implement this function with your microcontroller specific code
*	- Disable CAN PE completely
* \return indicates if Abort Transmission was successful
*	- 1 = CAN PE entered Stop Mode
*	- 0 = CAN PE has not entered Stop Mode
*/
Byte CANStopMode(void){
	// Insert your microcontroller specific code here
	// e.g. Disable CAN PE  with wake-up disabled

	return 0;
}

/**
* \brief CAN PE enters Sleep Mode (wake-up enabled)
* \todo implement this function with your microcontroller specific code
*	- Disable CAN PE completely or abort transmission
* \return indicates if Abort Transmission was successful
*	- 1 = CAN PE entered Sleep Mode
*	- 0 = CAN PE has not entered Sleep Mode
*/
Byte CANSleepMode(void){
	// Insert your microcontroller specific code here
	// e.g. Disable CAN PE  with wake-up enabled

	return 0;
}

/**
* \brief Enable transmissions of the CAN PE
* \todo implement this function with your microcontroller specific code
*	- Enable CAN PE completely or enable transmission path
* \return indicates if Enable Transmission was successful
*	- 1 = CAN PE is now able to transmit new messages
*	- 0 = Enabling of transmissions failed
*/
Byte EnableTransmissionCAN(void){
	// Insert your microcontroller specific code here
	// e.g. Enable CAN PE

	return 0;
}



/**
* \brief Read GPIO port configured as input port
* \todo implement this function with your microcontroller specific code
*	- Read GPIO port
* \return Port input value
*/
Byte ScanPort(void){
	// Insert your microcontroller specific code here
	// e.g. Read GPIO port and return value
	//if(Siul2_Dio_Ip_ReadChannel(0, TJA1145_1_RXD_PIN_NUM) == 1)			//change to normal mode
	if(Siul2_Dio_Ip_ReadPin(CAN0_RX_PORT, CAN0_RX_PIN) == 1)			//change to normal mode
		return 0x30;
	//else if(Siul2_Dio_Ip_ReadChannel(0, TJA1145_2_RXD_PIN_NUM) == 1)	//change to sleep mode
	else if(Siul2_Dio_Ip_ReadPin(CAN1_RX_PORT, CAN1_RX_PIN) == 1)	//change to sleep mode
		return 0x60;
	else
		return 0x70;	//do nothing
}

/**
* \brief Disable global timebase
* \todo implement this function with your microcontroller specific code
*	- Disable timer
* \return indicates if Scheduler Disable was successful
*	- 1 = Timer disabled
*	- 0 = Timer disable failed
*/
Byte Scheduler_Disable(void){
	// Insert your microcontroller specific code here
	// e.g. disable global timer 

	return 0;
}

/**
* \brief Enable global time base
* \todo implement this function with your microcontroller specific code
*	- Enable timer
* \return indicates if Scheduler Enable was successful
*	- 1 = Timer enabled
*	- 0 = Timer enable failed
*/
Byte Scheduler_Enable(void){
	// Insert your microcontroller specific code here

	return 0;
}

/**
* \brief Get RXD CAN value
* \todo implement this function with your microcontroller specific code
* \return RXD CAN value
*	- 1 = RXD CAN is high
*	- 0 = RXD CAN is low
*/
Byte RXDC_GetValue(){
	// Insert your microcontroller specific code here
	// e.g. return value of port pin connected to UJA1164 RXD pin 
	if(nTja1145Sel == 0)
		return (Siul2_Dio_Ip_ReadPin(CAN0_RX_PORT, CAN0_RX_PIN));	//return (Siul2_Dio_Ip_ReadChannel(0, TJA1145_1_RXD_PIN_NUM));
	else if(nTja1145Sel == 1)
		return (Siul2_Dio_Ip_ReadPin(CAN1_RX_PORT, CAN1_RX_PIN));	//return (Siul2_Dio_Ip_ReadChannel(0, TJA1145_2_RXD_PIN_NUM));
	else
		return 1;
	return 1;
}


/**
* \brief Read Port Pin that gives the start signal for MTP programmg  
* \todo implement this function with your microcontroller specific code
* \return Port pin value
*	- 1 = port pin is high (default): wait for start signal
*	- 0 = port pin is low: start programming MTP
*/
Byte MtpvnProgStart(void){
	// Insert your microcontroller specific code here

	return 1;
}


/**
* \brief Read Port Pin used for control SDMC configuration during MTP programming and watchdog triggering during normal operation  
* \todo implement this function with your microcontroller specific code
* \return Port pin value
*	- 1 = port pin is high (default): During MTP programming, SDMC = 0; During Normal Operation: "Normal" WD triggering requested
*	- 0 = port pin is low: During MTP programming, SDMC = 1; During Normal Operation: "Debug" WD triggering requested (autonomous mode) 
*/
Byte WdEmulation(void){
	// Insert your microcontroller specific code here

	return 1;
}


/**
* \brief Set Port Pin on high level used for control a LED that shows, if SBC is in Normal Mode or not 
* \todo implement this function with your microcontroller specific code
*/
void SetNormalModeLed(void) {
	// Insert your microcontroller specific code here

}


/**
* \brief Set Port Pin on low level used for control a LED that shows, if SBC is in Normal Mode or not 
* \todo implement this function with your microcontroller specific code
*/
void ClearNormalModeLed(void) {
	// Insert your microcontroller specific code here

}


/**
* \brief Toggle Port Pin used for signalling a Watchdog trigger
* \todo implement this function with your microcontroller specific code
*/
void ToggleWdTriggerLed(void) {
	// Insert your microcontroller specific code here

}
