/**********************************************************************
*
* Freescale Semiconductor Inc.
* (c) Copyright 2004-2015 Freescale Semiconductor, Inc.
* ALL RIGHTS RESERVED.
*
* =================================================================== *
* 																	  *
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY              *
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE *
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR  *
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL FREESCALE OR             *
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT        *
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;        *
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)            *
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, *
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)       *
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED *
* OF THE POSSIBILITY OF SUCH DAMAGE.                                  *
* 																	  *
* =================================================================== */


#define VERSION ((UINT8)0x01u)

/******************************************************************************
 * 
 * TPMS FXTH87 MKW01 Rev4
 * The frame format and RF settings are compatible with the MKW01 receiver,
 * refer to MKW01_IAR7v4_Project_TPMS projects in particular. 
 * 
 ******************************************************************************/

/*
 ******************************************************************************
 *
 *  Main.c - Code will reside in here.
 *
 ******************************************************************************
 */
#include <hidef.h>                   /* for EnableInterrupts macro       */
#include "derivative.h"              /* include peripheral declarations  */
#include "main.h"                    /* reference to all Suzuka calls    */
#include "dal.h"                     /* reference to all Suzuka calls    */

/* Globals going into PARAM registers */
#pragma CONST_SEG VERSIONING_ROM
const UINT16 cu16Freq = FREQ;
const UINT8  cu8Version = VERSION;
#pragma CONST_SEG DEFAULT

#pragma DATA_SEG BATTERY_BACKED_RAM
UINT16 gu16UUMA[5u];
UINT8  u8MainExeCnt;
UINT16 FrameID;
UINT32 Tire_ID;


#pragma DATA_SEG DEFAULT
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  u8StatusAcq;     /* Status byte for all measurements */
UINT16 gau16VReg[2];

/****************************************************************
 * 
 * Transmission speed selection 
 * 
 ****************************************************************/

#define Tx_SPEED_FAST	1			// Tx every 40ms~
#define Tx_SPEED_SLOW	0 			// Tx uses PWU interrupt (set to 1s)

/****************************************************************
 * 
 * Frame display selection
 * Choose here the way frames will be displayed on the MKW01 receiver side:
 * using the hyperterminal or the Freescale Sensor GUI.
 * Or the selection can be done in the MKW01 project.
 * 
 ****************************************************************/
/* Uncomment one of the defines */
//#define Frame_Display		0x11	/* Frame will be displayed using the HYPERTERMINAL */
//#define Frame_Display		0x22	/* Frame will be displayed using the SENSOR GUI */
#define Frame_Display		0x00   /* The choice of the display is done in the MKW01 project */

/****************************************************************
 * 
 * Data verification selection 
 * 
 ****************************************************************/

#define VERIFICATION_CRC_MKW01			1
#define VERIFICATION_CRC_FXTH			0
#define VERIFICATION_CHECKSUM			0
#define VERIFICATION_NO_VERIFICATION	0

/****************************************************************
 * 
 * Tire ID Selection
 * 
 ***************************************************************/
 
#define ID1 0xAA01AA01
#define ID2 0xBB02BB02
#define ID3 0xCC03CC03
#define ID4 0xDD04DD04

#define METHOD_FIXED_ID		0
#define METHOD_CYCLING_ID 	1		// ID changes each time a new frame is sent

/*
 ******************************************************************************
 *
 *                        M A I N
 *
 ******************************************************************************
 */
#pragma CODE_SEG DEFAULT
void main(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)
	switch (Tire_ID){
	case (ID1): Tire_ID = ID2;
	break;
	
	case (ID2): Tire_ID = ID3;
	break;
	
	case (ID3): Tire_ID = ID4;
	break;
	
	case (ID4): Tire_ID = ID1;
	break;
	
	default: Tire_ID = ID1;	
	}
#endif
	
	
  /* Config GPIO for setup */
	vfnSetupGPIO();
  
  /* For demo purposes, remove watch-dog and init MCU core registers */
	vfnSetupMCU();
  
  /* Configure device for STOP4 - needed for measurement routines */
	vfnSetSTOPMode(STOP4);
  
  
  
  /* Configure periodic interrupt for 1 second */
	vfnSetPWU();
  
  /* DAL is a software layer that allows switching between MPXY8500 and MPXY8600 */
  /* transparently. Cost is in execution cycles. Init this layer.                */
    (void)u8fnDALDetectDerivative();
  
  /* Perform all measurements */
	Measure_P_T_V_AccZ();
  
  /* Configure RF HW for transmission */
	Init_RF(); 
  
	RFCR7_RFIACK = SET;  // Clear all Flags
  
  /* Load data into the RF buffer */
	Fill_RFBUFFER();
  
  /* Transmit data */
	TPMS_RF_SET_TX(255); // Number of bits to be transmitted - 1 ; here 32 bytes (maximum); 32*8-1 = 255
  
  /* Ensure STOP1 mode entry */
	vfnSetSTOPMode(STOP1);
   
	EnableInterrupts;
  
  /* Go into STOP */
	__asm STOP;
	__asm STOP;
 
}

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

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=0x34;    // 9600 bauds - Reset value
  RFCR0=0x19; // 19230.8 bauds
    
  RFCR1=0x78;    // set to 78 for 120 bits - largest frame
  
#if (Tx_SPEED_FAST)

  RFCR2=0x0E;    // RF Transmission OFF - No EOM - Pout=5dBm    - RPAGE=0
                   // 00001110  
  RFCR7=0x08;     // RF Interrupt Disable - LVD Disable - RFM Not reset
#elif (Tx_SPEED_SLOW)
   RFCR2=0x8E; 
   RFCR7= 0x00;
#endif


  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
                    
#if(FREQ==315)
  PLLCR0=0x1C;   //  00011100
                     
  PLLCR1=0xD2;

                     
 
   //  315M+50K --> d950 --->0001110110110
   
  PLLCR2=0x1D;   //  00011101
                    
  PLLCR3=0xB2;   //  10110  010 

#elif(FREQ==434)     
   
  PLLCR0=0xB0;   // 10110000
                      
  PLLCR1 = 0x62;
                     
 
   //  434M+35K --> d5682 --->1011000110010
   
  PLLCR2=0xB1;   // 10110001
                      
  PLLCR3=0x56;   // 01010   110 CF=1  (bit2) //FSK
#endif    

  return;
}

/****************************************************************************
Function	:	delay
NOTES		:	realise un delay
*****************************************************************************/

void delay(UINT8 r_max)
{
  UINT8 r,q;
  for(r=0; r<r_max; r++)
  {
  	for(q=0; q<16; q++)
  	{
  	  /* Stay here for a bit */
  	}
  }
  
  return;
} 
/****************************************************************************
Function	: Measure_P_T_V
NOTES		:   This function measures Pressure, Temperature, Voltage and store them in RFRD_data

*****************************************************************************/
/****************************************************************************
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 u8ZIndex;
   
   /* Enable Bandgap - required for V and T measurements */
   SPMSC1_BGBE = SET;
   
   delay(200);
   
   u8StatusAcq=0;
    
   /****Initial measurements for compensation ***/  
   u8StatusAcq |= TPMS_READ_VOLTAGE(gu16UUMA);
   u8StatusAcq |= TPMS_READ_TEMPERATURE(gu16UUMA);
   /****Pressure data acquisition ***/  
   u8StatusAcq |= TPMS_READ_PRESSURE(gu16UUMA, 4u);   
   u8StatusAcq |= TPMS_COMP_PRESSURE(&u16CompPressure, gu16UUMA);     
   gu8CompPressure = (UINT8)(u16CompPressure>>1);
   /****Temperature data acquisition ***/  
   u8StatusAcq |= TPMS_COMP_TEMPERATURE(&gu8CompTemp, gu16UUMA);        
   /****Voltage data acquisition ***/  
   u8StatusAcq |= 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) 
   {
     u8StatusAcq|=TPMS_READ_ACCEL_X(gu16UUMA, 1u, CLEAR, 7u);
     u8StatusAcq|=TPMS_COMP_ACCEL_X((UINT16*)&u16CompAccelX, gu16UUMA);
     gu8CompX = (UINT8)(u16CompAccelX>>1);
     
     u8ZIndex = ((UINT8)6u); 
 
   } 
   else 
   {
    u8ZIndex = ((UINT8)6);
   }
   
   /* No matter the derivative, always take Z-axis readings */
   u8StatusAcq |= TPMS_READ_ACCEL_Z(gu16UUMA, 1u, CLEAR, u8ZIndex);
   u8StatusAcq |= TPMS_COMP_ACCEL_Z((UINT16*)&u16CompAccelZ, gu16UUMA);
   gu8CompZ = (UINT8)(u16CompAccelZ>>1);
   
   /* Disable bandgap - allows us to save some power */
   SPMSC1_BGBE = CLEAR;
         
   return;       
}

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

function    :Fill_RFBUFFER(void)

parameters  :void

returns     :void

type        :low level c

description: RF Buffer filling 

*******************************************************************************/
const UINT8 cau8Preamble[] = 
{
  0xFF, 0xAA, 0x9B
}; // Not used with MKW01 receiver

void Fill_RFBUFFER(void)
{
	
	UINT8  au8RFDataForCS[32]; // Maximum length is 32 bytes; size of the RF buffer (in bytes)
	UINT8 Payload_Length;
	UINT8 Receiver_Address;
	UINT8 Verification_Type; 
	UINT16 Verification_Value;
	Payload_Length = 0x18; // Value updated below in case of MKW01 CRC
	Receiver_Address = 0xFF; // Must match the MKW01 address
	
	/* Verification type => to be chosen at the beginning of the main; do not modify the value here */
	Verification_Type = 0x00; // Value updated below; 0x03 => MKW01 CRC, 0x02 => TPMS CRC, 0x01 => Checksum, 0x00 => no verification

	
	/* 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, 0x18=24 bytes 
	au8RFDataForCS[8u] =  (UINT8)(0xF0); 					// MKW01 receiver address (NODE_ADDRESS 0xF0 or BROADCAST_ADDRESS 0xFF)
	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)(u16CompPressure >> 8u); 	// Pressure
	au8RFDataForCS[14u] = (UINT8)(u16CompPressure);
	au8RFDataForCS[15u] = (UINT8)(u16CompAccelZ >> 8u); 	// Z-axis acceleration
	au8RFDataForCS[16u] = (UINT8)(u16CompAccelZ);	  
	au8RFDataForCS[17u] = (UINT8)(u16CompAccelX >> 8u); 	// X-axis acceleration
	au8RFDataForCS[18u] = (UINT8)(u16CompAccelX);
	au8RFDataForCS[19u] = (UINT8)(gu8CompVolt); 			// Voltage
	au8RFDataForCS[20u] = (UINT8)(gu8CompTemp); 			// Temperature
	au8RFDataForCS[21u] = (UINT8)(u8StatusAcq); 			// Status Acquisition
	au8RFDataForCS[22u] = (UINT8)(FrameID >> 8); 			// Frame ID: keep alive counter 
	au8RFDataForCS[23u] = (UINT8)(FrameID);
	au8RFDataForCS[24u] = (UINT8)(Verification_Type); 		// Verification Type: MKW01 CRC, FXTH CRC, checksum or no verification
	au8RFDataForCS[25u] = (UINT8)(Frame_Display); 			// Frame display: hyperterminal, Sensor GUI or selection to be done on the MKW01 side
	au8RFDataForCS[26u] = (UINT8)(0xC1); 					// Fixed data => can be modified by the user
	au8RFDataForCS[27u] = (UINT8)(0xC2); 					// Fixed data => can be modified by the user
	au8RFDataForCS[28u] = (UINT8)(0xC3); 					// Fixed data => can be modified by the user
	au8RFDataForCS[29u] = (UINT8)(0xC4); 					// Fixed data => can be modified by the user
	
#if (VERIFICATION_CRC_MKW01)
		Payload_Length -= 2; // MKW01 CRC is not part of the payload (refer to MKW01 RM)
		au8RFDataForCS[7u] =  (UINT8)(Payload_Length);	
		
		Verification_Type = 0x03;
		au8RFDataForCS[24u] = (UINT8)(Verification_Type);
	
		Verification_Value = Calculate_CRC_MKW01( &au8RFDataForCS[7], (UINT8)(Payload_Length + 1));		
		
#elif (VERIFICATION_CRC_FXTH)
		Verification_Type = 0x02;
		au8RFDataForCS[24u] = (UINT8)(Verification_Type);
		
		Verification_Value = TPMS_CRC16(&au8RFDataForCS[7],(Payload_Length - 1), 0);
		
#elif (VERIFICATION_CHECKSUM)
		Verification_Type = 0x01;
		au8RFDataForCS[24u] = (UINT8)(Verification_Type);
		
		Verification_Value = 0xC5 << 8;
		Verification_Value &= 0xFF00;
		Verification_Value |= CheckSum_FSL_Full(&au8RFDataForCS[7], (Payload_Length - 1));
		
#else
		Verification_Value = 0xC5C6; /* Fixed data; no verification will be done on the MKW01 side */
#endif
 	

		au8RFDataForCS[30u] = (UINT8)(Verification_Value>>8);  // CRC, checksum or fixed data
		au8RFDataForCS[31u] = (UINT8)(Verification_Value);
		
	 TPMS_RF_WRITE_DATA_REVERSE(sizeof(au8RFDataForCS), &(au8RFDataForCS[0]),0u);
}
 
 /****************************************************************************/
 /* 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);
}


/*
 ******************************************************************************
 * 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 bandgap for V, T measurements, enable stop4 mode */   
  SPMSC1  = SPMSC1_BGBE_MASK | SPMSC1_LVDE_MASK | SPMSC1_LVDSE_MASK;
  
  /* enable STOP mode, Enable RFM, disable COP */
  SIMOPT1 = (SIMOPT1 | SIMOPT1_STOPE_MASK | SIMOPT1_RFEN_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 (~1 sec) */
  PWUCS0 = 0x2u;
  PWUCS1 = CLEAR;
  PWUDIV = 0x1Fu;
  
  return;
}
/*
 ******************************************************************************
 *  vfnSetupGPIO
 ******************************************************************************
 */
void vfnSetupGPIO(void)
{
  /* On 28-May-2014, this function has been modified to match Pascal       */
  /* Bernard's request through e-mail, which follows. This is for v.13     */
  /* 1/ GPIO                                                               */
  /* PTA0 Output low                                                       */
  /* PTA1 Input                                                            */
  /* PTA2 Output High                                                      */
  /* PTA3 Output low                                                       */
  /* PTB0 Output low                                                       */
  /* PTB1 Toggle LF                                                        */

  PTAD  = PTA2_IS_HIGH;
  PTADD = (PTADD_PTADD0_MASK | PTADD_PTADD2_MASK | PTADD_PTADD3_MASK);
  
  PTBD  = CLEAR;
  PTBDD = ALL_PTBS_ARE_OUTPUT;
  
  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;
}


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