
/******************************************************************************
 * 
 * TPMS FXTH87 LF RF Communication
 * Data received by LF is processed
 * The RF frame format and RF settings are compatible with the MKW01 receiver. 
 * 
 * user_configuration.h : contains the demo parameters configurable by the user
 * 
 * MKW01_Communication.c : contains functions to process LF frame received and
 * execute commands accordingly
 *   
 ******************************************************************************/

/*
 ******************************************************************************
 *
 *  Main.c - Code will reside in here.
 *
 ******************************************************************************
 */
#include <hidef.h>                   /* for EnableInterrupts macro       */
#include "derivative.h"              /* include peripheral declarations  */
#include "main.h"                   
#include "user_configuration.h"
#include "dal.h"                     
#include "szk_lf_data_detect.h"
#include "szk_ff_tpm.h"
#include "MKW01_Communication.h"
#include "LED.h"



#pragma DATA_SEG BATTERY_BACKED_RAM
UINT16 gu16UUMA[5u];
UINT16 FrameID;
UINT32 Tire_ID;
UINT8 Firmware_Version;
UINT8 Derivative_Descriptor;
UINT8 PWUDIV_1sec_calibrated;
volatile UINT8 RF_Interrupt; // Used in Fastest_Tx_never_ending


//#pragma DATA_SEG DEFAULT
#pragma DATA_SEG MY_ZEROPAGE // Not very useful for these variables
UINT8 gu8CompPressure; /* 8-bit representation for comp pressure */
UINT8 gu8CompVolt; /* Comp V */
UINT8 gu8CompTemp; /* Comp T */
UINT8 gu8CompX; /* 8-bit representation for comp X */
UINT8 gu8CompZ; /* 8-bit representation for comp Z */
UINT16 u16CompPressure; /* 16-bit representation for comp P */
UINT16 u16CompAccelX; /* 16-bit representation for comp X */
UINT16 u16CompAccelZ; /* 16-bit representation for comp Z */
UINT8 u8StatusAcqRead; /* Status byte for all measurements */
UINT8 u8StatusAcqComp; /* Status byte for all compensations */
UINT8 TPMS_ID[6];

#pragma DATA_SEG DEFAULT

/*
 ******************************************************************************
 *
 *                       		 M A I N
 *                        
 *            Choose demo parameters in user_configuration.h      
 *
 ******************************************************************************
 */
#pragma CODE_SEG DEFAULT

/* Be careful: LED5 and LED6 are driven by PTB0 and PTB1 which are also used in priority by the LF block 
 * So when the LF block is ON, LED5 and LED6 cannot be used.
 * Choose in user_configuration.h to use LEDs or not.
 */

void main(void) {
	UINT8 u8LFCount;
	UINT8 u8LFFirst;

	u8LFFirst = LFDATA;

	/* Config GPIO for setup */
	vfnSetupGPIO();

	for (;;) {

		if (CLEAR == SPMSC2_PDF)  //we did not wake up from STOP1
		{
			/* Set PWU, enable STOP, disable RF */
			vfnSetupMCU();

			vfnSetPWU();

			/* Determine derivative once */
			(void) u8fnDALDetectDerivative();

			/* Clear the interrupts flag */
			TPMS_INTERRUPT_FLAG = CLEAR;

			// Enable block to write in register and perform LFO calibration
			TPMS_RF_ENABLE (SET); // 400µs	
			
			// Disable RF interrupt
			RFCR7_RFIEN = CLEAR;
			
			PWUDIV_1sec_calibrated = 0;
			PWUDIV_1sec_calibrated = TPMS_LFOCAL (); 
			if (PWUDIV_1sec_calibrated == 0x80) {
				// The calibration could not be done because of a XTAL problem => go back to non-calibrated value
				PWUDIV_1sec_calibrated = 0x1F;
			}
			
			// Disable RF block
			TPMS_RF_ENABLE (CLEAR); // 24µs

			FrameID = CLEAR;

#if (TIRE_ID_VALUE == UNIQUE_ID)
			TPMS_READ_ID (TPMS_ID); // 512µs
			Firmware_Version = TPMS_ID[0];
			Derivative_Descriptor = TPMS_ID[1];
			Tire_ID = 0;
			Tire_ID |= TPMS_ID[2];
			Tire_ID <<= 8;
			Tire_ID |= TPMS_ID[3];
			Tire_ID <<= 8;
			Tire_ID |= TPMS_ID[4];
			Tire_ID <<= 8;
			Tire_ID |= TPMS_ID[5];
#endif

			vfnInitStateMachine();

#if (MODE == LF_COMMUNICATION)
			/* Configure LFR for data mode */
			vfnDataModeInit();
			vfnClearReceivedBuffer();
			TPMS_LF_ENABLE (SET);
#endif	  

		} else {
			EnableInterrupts;

			if (SET == SIMSES_LFF)	// LF Interrupt
			{

				SIMOPT1 = SIMOPT1_STOPE_MASK | BIT0;

				vfnSetSTOPMode(STOP4 ); //Receive LF Data Frame
				u8LFCount = TPMS_LF_READ_DATA (gau8DataBuffer,
						sizeof(gau8DataBuffer));

				TPMS_LF_ENABLE (CLEAR);
				TPMS_INTERRUPT_FLAG = CLEAR;
				gau8DataBuffer[CLEAR] = u8LFFirst;
				
				vfnUpdateStateMachine();
				
				/* LED3 will be turned off just before going to STOP1 */
				INIT_LED3;
				LED3_ON;

				current_state.vfnExecuteAtLfWakeUp();

			} // end LF interrupt

			else if (SET == SIMSES_RFF) // RF Interrupt
			{
				vfnSetupMCU();
				TPMS_RF_ENABLE (CLEAR);
				FLASH_LED5_30ms; // LED5 cannot be used when LF is ON
				
				current_state.vfnExecuteAtRfWakeUp();
				
			} else if (SET == SIMSES_PWUF) // If PWU periodic interrupt
			{
				vfnSetupMCU();
				TPMS_LF_ENABLE (CLEAR);
				
				current_state.vfnExecuteAtPwuWakeUp();

			} // End PWU interrupt
			
			else //Exception to be safe if wake up
			{
				vfnSetupMCU();
				DisRF_EnLF();
			}

			// Need to enable Power Down Control in order to clear the flag below
			SPMSC2 |= SPMSC2_PDC_MASK;
			/* Clear STOP1 entry flag */
			// Partial Power Down Acknowledge
			SPMSC2_PPDACK = SET;

		} // End PDF is set

		current_state.vfnExecuteBeforeSTOP();

		// This flag is used in NoLF_FastestTxOnly state and LF_FastestTxNeverEnding (we cannot use RF block flags as they are cleared in the interrupt handler)
		// We need to clear it before going to STOP1
		RF_Interrupt = CLEAR;
		// We use this flag in LF fastest Tx state 
		// We need to clear it before going to STOP1
		TPMS_INTERRUPT_FLAG = CLEAR;
		
		LED3_OFF;
		
		vfnSetSTOPMode(STOP1);

		EnableInterrupts;
		
		__asm STOP;

	}
}

/******************************************************************************

 function    :UpdateTireID(void)

 parameters  :void

 returns     :void

 description: In case of define CYCLING_ID: tire ID changes each time an RF frame is sent
 in order to simulate four wheels.
 In case of FIXED_ID: the same ID will be sent at each transmission,
 choose the ID number below (uncomment one of the lines)

 *******************************************************************************/
void vfnUpdateTireID(void) {

#if (METHOD == FIXED_ID)
	/* Uncomment one of the four IDs */
	Tire_ID = ID1;
	//Tire_ID = ID2;
	//Tire_ID = ID3;
	//Tire_ID = ID4;
#elif (METHOD == CYCLING_ID)

	if (Tire_ID == ID1)
	{
		Tire_ID = ID2;
	} else if (Tire_ID == ID2)
	{
		Tire_ID = ID3;
	} else if (Tire_ID == ID3)
	{
		Tire_ID = ID4;
	} else
	{
		Tire_ID = ID1;
	}

#endif
		
#if (TIRE_ID_VALUE == UNIQUE_ID)
	/* Read again to check if everything is still ok (to check if flash has not been corrupted for example) */
	/* This can be removed to save time if needed as we stored the info in BATTERY_BACKED RAM at the beginning */
			TPMS_READ_ID (TPMS_ID); // execution time = 512µs
			Firmware_Version = TPMS_ID[0];
			Derivative_Descriptor = TPMS_ID[1];
			Tire_ID = 0;
			Tire_ID |= TPMS_ID[2];
			Tire_ID <<= 8;
			Tire_ID |= TPMS_ID[3];
			Tire_ID <<= 8;
			Tire_ID |= TPMS_ID[4];
			Tire_ID <<= 8;
			Tire_ID |= TPMS_ID[5];
#endif
}

/******************************************************************************

 function    :Init_RF(void)

 parameters  :void

 returns     :void

 type        :low level c

 description: RF Setup 

 *******************************************************************************/
void Init_RF(void) {
	/* Turn module on in case it wasn't */
	TPMS_RF_ENABLE (SET);

	/* In this example registers are configured by hand. Could also be */
	/* done through TPMS_RF_CONFIG().                                  */
	RFCR0 = 0x19;

	RFCR1 = 0x78;    // set to 78 for 120 bits - largest frame

	RFCR2 = 0x0E;    // RF Transmission OFF - No EOM - Pout=5dBm    - RPAGE=0
					 // 00001110   

	RFCR3 = 0x00;    // RF Output Low - RF Power UP - One Frame Transmitted
					 // 00000000

	RFCR4 = 0x01;     //Interframe timing set to 1

	RFCR5 = 0x00;     //No Pseudo-random number used

	RFCR6 = 0x01;     //VCO highest Power - interframe timing
					  // was 00
	RFCR7 = 0x08;     // RF Interrupt Enabled - LVD Disable - RFM Not reset

#if(FREQ==315)

	// fDATA0=fXTAL x ((12 + 4 x CF) + AFREQ/8192)
	//       = 26MHz x((12 + 4 x 0) + 922 (1110011010) /8192)
	//       = 314.9263

	// fDATA1=fXTAL x ((12 + 4 x CF) + BFREQ/8192)
	//       = 26MHz x((12 + 4 x 0) + 950 (1110110110) /8192)
	//       = 315.0151

	// 315.0151 - 314.9263 = 44.4kHz

	/* 315MHz */
	PLLCR0 = 0x1C;   //  0001 1100
					 //  AFREQ[12:5]

	PLLCR1 = 0xD2;   //  1101 0     0   10   
					 //  AFREQ[4:0] POL CODE[1:0]

	PLLCR2 = 0x1D;   //  00011101

	PLLCR3 = 0xB2; //  10110 010 CF=0 315MHz   MOD=1 FSK   CKREF=0 DX signal not generated
	//PLLCR3=0xB0;   //  10110 000 CF=0 315MHz   MOD=0 OOK   CKREF=0 DX signal not generated

#elif(FREQ==434) 

	// fDATA0=fXTAL x ((12 + 4 x CF) + AFREQ/8192)
	//       = 26MHz x((12 + 4 x 1) + 5644 (10110000 01100) /8192)
	//       = 433.9131

	// fDATA1=fXTAL x ((12 + 4 x CF) + BFREQ/8192)
	//       = 26MHz x((12 + 4 x 1) + 5674 (1011000101010) /8192)
	//       = 434.0083 

	// 434.0083 - 433.9131 = 47.6kHz

	/* 434MHz */
	PLLCR0=0xB0;// 1011 0000
				//  AFREQ[12:5]

	PLLCR1=0x62;//  01100      0   10
				//  AFREQ[4:0] POL CODE[1:0]                 

	PLLCR2=0xB1;// 10110001

	PLLCR3=0x56;// 01010 110  CF=1 434MHz   MOD=1 FSK   CKREF=0 DX signal not generated
	//PLLCR3=0x54;   // 01010 100  CF=1 434MHz   MOD=0 OOK   CKREF=0 DX signal not generated	

#endif  
	
	/* Configuration for various frequencies (FSK)
	315MHz
	PLLCR0_3 = {0x1D, 0x4A, 0x1D, 0xCA};
	
	313.5MHz
	PLLCR0_3 = {0x0E, 0x82, 0x0F, 0x02};
	
	314MHz
	PLLCR0_3 = {0x13, 0x72, 0x13, 0xF2};
	
	314.5MHz
	PLLCR0_3 = {0x18, 0x5A, 0x18, 0xDA};
	
	315.5MHz
	PLLCR0_3 = {0x22, 0x32, 0x22, 0xB2};
	
	316MHz
	PLLCR0_3 = {0x27, 0x22, 0x27, 0xA2};
	
	316.5MHz
	PLLCR0_3 = {0x2C, 0x0A, 0x2C, 0x8A};


	434MHz
	PLLCR0_3 = {0xB0, 0x62, 0xB1, 0x56};

	432.5MHz
	PLLCR0_3 = {0xA2, 0x32, 0xA2, 0xB6};

	433MHz // To be adjusted (RF loss around 6%)
	PLLCR0_3 = {0xA7, 0x22, 0xA7, 0xA6};

	433.5MHz
	PLLCR0_3 = {0xAC, 0x0A, 0xAC, 0x8E};

	434.5MHz // To be adjusted (RF loss around 25%)
	PLLCR0_3 = {0xB5, 0xEA, 0xB6, 0x66};

	435MHz // To be adjusted (RF loss around 6%)
	PLLCR0_3 = {0xBA, 0xD2, 0xBB, 0x56};

	435.5MHz // To be adjusted (RF loss around 6%)
	PLLCR0_3 = {0xBF, 0xC2, 0xC0, 0x3E};
	*/

	return;
}


/****************************************************************************
 Function	: Measure_P_T_V
 NOTES		:   This function measures Pressure, Temperature, Voltage and store them in RFRD_data

 *****************************************************************************/
void Measure_P_T_V_AccZ(void) {

	UINT8 u8StatusAcqCompT; /* Status acq for temperature compensation */
	UINT8 u8StatusAcqCompV; /* Status acq for voltage compensation */
	UINT8 u8StatusAcqCompX; /* Status acq for accelX compensation */
	UINT8 u8StatusAcqCompZ; /* Status acq for accelZ compensation */
	UINT8 u8StatusAcqCompP; /* Status acq for pressure compensation */

	/* Enable Bandgap - required for V and T measurements 
	 * It takes 25µs to stabilize. So it will be completely stabilized after the pressure reading and
	 * ready to be used in the voltage and temperature readings. 
	 */
	SPMSC1_BGBE = SET;

	u8StatusAcqRead = 0;

	/****Pressure data acquisition ***/
	u8StatusAcqRead |= TPMS_READ_PRESSURE (gu16UUMA, 4u);

	/****Initial measurements for compensation ***/
	u8StatusAcqRead |= TPMS_READ_VOLTAGE (gu16UUMA);
	u8StatusAcqRead |= TPMS_READ_TEMPERATURE (gu16UUMA);

	/**** Pressure compensation ****/
	u8StatusAcqCompP = TPMS_COMP_PRESSURE (&u16CompPressure, gu16UUMA);
	gu8CompPressure = (UINT8) (u16CompPressure >> 1);
	/****Temperature data acquisition ***/
	u8StatusAcqCompT = TPMS_COMP_TEMPERATURE (&gu8CompTemp, gu16UUMA);
	/****Voltage data acquisition ***/
	u8StatusAcqCompV = TPMS_COMP_VOLTAGE (&gu8CompVolt, gu16UUMA);

	/* gu8Derivative is owned by DAL. It allows us to differentiate between */
	/* a one-axis and a two-axis product. Here, we use that info to make    */
	/* a smart decision of whether to read the X-axis or not.               */
	if (TWO_AXIS_DERIVATIVE_INDEX == gu8Derivative) {
   
		u8StatusAcqRead |= TPMS_READ_ACCEL_X (gu16UUMA, 1u, CLEAR, 7u); // Offset 7

		u8StatusAcqCompX = TPMS_COMP_ACCEL_X ((UINT16*) &u16CompAccelX, gu16UUMA);
		gu8CompX = (UINT8) (u16CompAccelX >> 1);
							
	} 

	/* No matter the derivative, always take Z-axis readings */
	u8StatusAcqRead |= TPMS_READ_ACCEL_Z (gu16UUMA, 1u, CLEAR, 6); // Offset 6

	u8StatusAcqCompZ = TPMS_COMP_ACCEL_Z ((UINT16*) &u16CompAccelZ, gu16UUMA);
	gu8CompZ = (UINT8) (u16CompAccelZ >> 1);

	/* Disable bandgap - allows us to save some power */
	SPMSC1_BGBE = CLEAR;

/*
 	 STATUS ACQUISITION
 
 	 u8StatusAcqRead   RTVZ XP00
 	 BIT0 : 0
 	 BIT1 : 0 	 
 	 BIT2 : PRESSURE UNDER/OVERFLOW
 	 BIT3 : ACCELX OVER/UNDERFLOW
 	 BIT4 : ACCELZ OVER/UNDERFLOW 
 	 BIT5 : VOLTAGE UNDER/OVERFLOW
 	 BIT6 : TEMPERATURE UNDER/OVERFLOW	 
 	 BIT7 : Reading not acquired 	 
 	 
 	 u8StatusAcqComp   0TVZ XP00
 	 BIT0 : 0
 	 BIT1 : 0 
 	 BIT2 : PRESSURE UNDER/OVERFLOW
 	 BIT3 : ACCELX OVER/UNDERFLOW
 	 BIT4 : ACCELZ OVER/UNDERFLOW 
 	 BIT5 : VOLTAGE UNDER/OVERFLOW
 	 BIT6 : TEMPERATURE UNDER/OVERFLOW	
 	 BIT7 : 0 
 
 */
	
	u8StatusAcqComp = 0;
	u8StatusAcqComp |= (u8StatusAcqCompT&0x01); // we discard low voltage bit in all comp status as we already took it into account in u8StatusAcqRead
	u8StatusAcqComp = u8StatusAcqComp << 1;
	u8StatusAcqComp |= (u8StatusAcqCompV&0x01);
	u8StatusAcqComp = u8StatusAcqComp << 1;
	u8StatusAcqComp |= (u8StatusAcqCompZ&0x01);
	u8StatusAcqComp = u8StatusAcqComp << 1;
	u8StatusAcqComp |= (u8StatusAcqCompX&0x01);
	u8StatusAcqComp = u8StatusAcqComp << 1;
	u8StatusAcqComp |= (u8StatusAcqCompP&0x01);
	u8StatusAcqComp = u8StatusAcqComp << 2;
	
	return;
}


/******************************************************************************

 function    :Fill_RFBUFFER(void)

 parameters  :void

 returns     :void

 type        :low level c

 description: RF Buffer filling 

 *******************************************************************************/
void Fill_RFBUFFER(void) {

	UINT8 au8RFDataForCS[32]; // Maximum length is 32 bytes; size of the RF buffer (in bytes)
	UINT8 Payload_Length;
	UINT16 Verification_Value;
	Payload_Length = 22; // CRC is not part of the payload

	/* Gather data into a local array that is to be loaded into the RF */

	au8RFDataForCS[0u] = (UINT8) (0x55); 					// Preamble
	au8RFDataForCS[1u] = (UINT8) (0x55); 					// Preamble
	au8RFDataForCS[2u] = (UINT8) (0x55); 					// Preamble
	au8RFDataForCS[3u] = (UINT8) (0x01); 					// Sync word 
	au8RFDataForCS[4u] = (UINT8) (0x01); 					// Sync word 
	au8RFDataForCS[5u] = (UINT8) (0x01);				    // Sync word
	au8RFDataForCS[6u] = (UINT8) (0x01);				    // Sync word
	au8RFDataForCS[7u] = (UINT8) (Payload_Length); 			// Payload length, does not include CRC
	au8RFDataForCS[8u] = (UINT8) (0xF0); 					// MKW01 receiver address (NODE_ADDRESS 0xF0 or BROADCAST_ADDRESS 0xFF). Address check disabled on KW01 side.
	au8RFDataForCS[9u] = (UINT8) (Tire_ID >> 24u); 			// Tire ID
	au8RFDataForCS[10u] = (UINT8) (Tire_ID >> 16u); 		// Tire ID
	au8RFDataForCS[11u] = (UINT8) (Tire_ID >> 8u); 		   	// Tire ID
	au8RFDataForCS[12u] = (UINT8) (Tire_ID);       			// Tire ID
	au8RFDataForCS[13u] = (UINT8) (Firmware_Version);		// Firmware Version
	au8RFDataForCS[14u] = (UINT8) (Derivative_Descriptor);	// Derivative Descriptor
	au8RFDataForCS[15u] = (UINT8) (u16CompPressure >> 8u); 	// Pressure
	au8RFDataForCS[16u] = (UINT8) (u16CompPressure);
	au8RFDataForCS[17u] = (UINT8) (u16CompAccelZ >> 8u); 	// Z-axis acceleration
	au8RFDataForCS[18u] = (UINT8) (u16CompAccelZ);
	au8RFDataForCS[19u] = (UINT8) (u16CompAccelX >> 8u); 	// X-axis acceleration
	au8RFDataForCS[20u] = (UINT8) (u16CompAccelX);
	au8RFDataForCS[21u] = (UINT8) (gu8CompVolt); 			// Voltage
	au8RFDataForCS[22u] = (UINT8) (gu8CompTemp); 			// Temperature
	au8RFDataForCS[23u] = (UINT8) (u8StatusAcqRead); 		// Status Acquisition for READ functions
	au8RFDataForCS[24u] = (UINT8) (u8StatusAcqComp); 		// Status Acquisition for COMP functions	 
	au8RFDataForCS[25u] = (UINT8) (FrameID >> 8);			// Frame ID: keep alive counter
	au8RFDataForCS[26u] = (UINT8) (FrameID); 					
	au8RFDataForCS[27u] = (UINT8) (0xC0); 					// Fixed data => can be modified by the user			
	au8RFDataForCS[28u] = (UINT8) (0xC1); 					// Fixed data => can be modified by the user
	au8RFDataForCS[29u] = (UINT8) (0xC2); 					// Fixed data => can be modified by the user
	

	/* Calculate CRC and add it at the end of the frame */
	Verification_Value = Calculate_CRC_MKW01( &au8RFDataForCS[7], (UINT8)(Payload_Length + 1));
	au8RFDataForCS[30u] = (UINT8) (Verification_Value >> 8); // CRC
	au8RFDataForCS[31u] = (UINT8) (Verification_Value);

	TPMS_RF_WRITE_DATA_REVERSE (sizeof(au8RFDataForCS), &(au8RFDataForCS[0]), 0u);
}



/*
 ******************************************************************************
 * u16fnAccessUUMA
 ******************************************************************************
 */
UINT16 u16fnAccessUUMA(UINT8 u8Index) {
	UINT16 u16Result;

	u16Result = CLEAR;
	switch (u8Index) {
	case (0u): {
		u16Result = gu16UUMA[UUMA_VOLT];
		break;
	}
	case(1u):
	{
		u16Result = gu16UUMA[UUMA_TEMP];
		break;
	}
	case(2u):
	{
		u16Result = gu16UUMA[UUMA_PRESSURE];
		break;
	}
	case(3u):
	{
		u16Result = gu16UUMA[UUMA_X];
		break;
	}
	case(4u):
	{
		u16Result = gu16UUMA[UUMA_Z];
		break;
	}
	default:
	{
		u16Result = CLEAR;
	}
}	;

	return (u16Result);
}
/*
 ******************************************************************************
 *
 *                        vfnSetupMCU
 *
 ******************************************************************************
 */
void vfnSetupMCU(void) {
	/* enable stop4 mode */
	SPMSC1 = SPMSC1_LVDE_MASK | SPMSC1_LVDSE_MASK;

	/* enable STOP mode, disable COP - A real app will need COP */
	SIMOPT1 = (SIMOPT1 | SIMOPT1_STOPE_MASK) & (UINT8) (~((UINT8) SIMOPT1_COPE_MASK));

	return;
}
/*
 ******************************************************************************
 *
 *                        vfnSetSTOPMode
 *
 ******************************************************************************
 */
void vfnSetSTOPMode(UINT8 u8Mode) {
	/*
	 Table 3-1. Stop Mode Selection
	 SIMPOT1  SPMSC2   SPMSC1        BDCSCR
	 STOPE    PDC      LVDE & LVDSE  ENBDM   Stop Mode
	 0       x        x             x      Stop modes disabled; illegal opcode reset if STOP instruction executed
	 1       1        0             0      Stop1
	 1       x        1             x      Stop4
	 1       x        x             1      Stop4 with BDM
	 */
	if (u8Mode == STOP1 ) {
		SPMSC2 |= SPMSC2_PDC_MASK;
		SPMSC1 = (SPMSC1 | SPMSC1_LVDE_MASK)
				& (UINT8) (~((UINT8) (SPMSC1_LVDSE_MASK | SPMSC1_BGBE_MASK)));
	} else if (u8Mode == STOP4 ) {
		SPMSC2 |= SPMSC2_PDC_MASK;
		/* Use BGBE for accurate ADC measurements */
		SPMSC1 |= (SPMSC1_LVDSE_MASK | SPMSC1_LVDE_MASK | SPMSC1_BGBE_MASK);
	} else {
		/* Do nothing */
	}
}
/*
 ******************************************************************************
 *
 *                        vfnSetPWU
 *
 ******************************************************************************
 */
void vfnSetPWU(void) {
	/* Configure PWU for a periodic wake-up */
	PWUCS0 = 0x1Fu;
	PWUCS1 = CLEAR;
	PWUDIV = 0x1Fu;

	return;
}

/*
 ******************************************************************************
 *  vfnSetupGPIO
 ******************************************************************************
 */
void vfnSetupGPIO(void) {

	// All GPIOs are inputs
	PTADD = 0x00;
	PTBDD = 0x00;

	return;
}

/*************************************
 * Added for MKW01 CRC 
 *************************************/
UINT16 Calculate_CRC_MKW01(UINT8 *buffer, UINT8 length) {
	UINT8 i = 0;
	UINT16 crc = 0;
	UINT16 polynomial = 0;
	polynomial = 0x1021;
	crc = 0x1D0F;
	for (i = 0; i < length; i++) {
		crc = ComputeCrc_MKW01(crc, buffer[i], polynomial);
	}
	return ((UINT16) (~crc));
}

UINT16 ComputeCrc_MKW01(UINT16 crc, UINT8 dataByte, UINT16 polynomial) {
	UINT8 i;
	for (i = 0; i < 8; i++) {
		if ((((crc & 0x8000) >> 8) ^ (dataByte & 0x80)) != 0) {
			crc <<= 1; // shift left once
			crc ^= polynomial; // XOR with polynomial
		} else {
			crc <<= 1; // shift left once
		}
		dataByte <<= 1; // Next data bit
	}
	return crc;
}


/****************************************************************************/
/* Function	: CheckSum_FSL_Full(byte *array)                               */
/* NOTES		:	     Compute checkusum - has to be complient to ESTAR receiver */
/*****************************************************************************/

UINT8 CheckSum_FSL_Full(UINT8 *array, UINT8 u8Size) {
	UINT8 j;
	UINT8 u8CS;

	u8CS = CLEAR;

	for (j = 0; j < u8Size; j++) {
		u8CS += *(array++);
	}
	u8CS = ((UINT8) 0xFFu) - u8CS;
	return (u8CS);
}


/*
 ******************************************************************************
 *
 *  End of file.
 *
 ******************************************************************************
 */
