/*
 * MKW01_Communication.c
 *
 *  Created on: Sep 25, 2015
 *      Author: B50961
 */

#include <hidef.h>                   /* for EnableInterrupts macro       */
#include "derivative.h"              /* include peripheral declarations  */
#include "Common.h"
#include <MKW01_Communication.h>
#include "user_configuration.h"
#include "szk_lf_data_detect.h"
#include "dal.h"                     /* reference to all Suzuka calls    */
#include "szk_ff_tpm.h"
#include "main.h"
#include "LED.h"


/********************************
 * gau8DataBuffer[CLEAR] : command
 * gau8DataBuffer[1] : parameter (if applicable). Here : period between two transmissions
 * 
 *  
 * Case 1 (gau8DataBuffer[CLEAR] = 0x01) : 
 * 	FXTH87 goes back to STOP1 with LF block enabled to be able to receive data
 * 
 * Case 2 (gau8DataBuffer[CLEAR] = 0x02) : 
 * 	Each time an LF frame is received, the FXTH87 sends a complete RF frame (with full measurements and compensation)
 * 	
 * Case 3 (gau8DataBuffer[CLEAR] = 0x03) :  
 * 	A complete RF frame is sent periodically. The value of gau8DataBuffer[1] gives the period in seconds
 * 	
 * Case 4 (gau8DataBuffer[CLEAR] = 0x04) :
 *	A complete RF frame is sent periodically every 550ms (shortest period possible using PWU)
 *	
 * Case 5 (gau8DataBuffer[CLEAR] = 0x05) :
 * 	Complete RF frames are sent as fast as possible (period is around 40ms) during a number of
 * 	seconds specified in gau8DataBuffer[1].
 * 	
 * Case 6 (gau8DataBuffer[CLEAR] = 0x06) :
 * 	Complete RF frames are sent as fast as possible (period is around 40ms) forever (LF control is lost)
 * 	
 * Case 7 (gau8DataBuffer[CLEAR] = 0x0F) :
 *  LED1 is turned on during 100ms. Then module goes back to STOP1 with LF enabled.
 *  
 */

#define PWU_MASK	BIT6

UINT8 buffer_setting;

#pragma DATA_SEG BATTERY_BACKED_RAM
t_Current_State current_state;


/*
 * Private functions
 */
void vfnConfigureStartPeriodicTx(void);
void vfnConfigureStartPeriodicTx_550ms(void);
void vfnConfigureStartFastestPeriodicTx(void);
void vfnSendCompleteRFFrame(void);
void vfnSendCompleteRFFrame_FastestTx(void);
void Do_Nothing (void);
void Disable_Rf (void);
void vfnConfigureStartFastestPeriodicTxNeverEnding(void);
void vfnNeverEndingRFinterrupt (void);
void ReStartTx (void);
void StopRF_EnLF (void);
void vfnNoLfConfigureStartPeriodicTx (void);


/* LIST OF POSSIBLE STATES */
/*
Current_State :
{
	void (*vfnExecuteAtLfWakeUp)(void) => executed when the LF command is decoded
	void (*vfnExecuteAtRfWakeUp)(void) => executed when we wake up with RF interrupt (end of TX)
	void (*vfnExecuteAtPwuWakeUp)(void) => executed when we wake up with PWU periodic interrupt
	void (*vfnExecuteBeforeSTOP)(void) => executed just before going to sleep with the instruction __asm STOP;
}
*/

#pragma CONST_SEG ROM_SECTION

/*
 * The two states below do not use LF at all
 * Refer to user_configuration.h
 */

/* NO_LF_FASTEST_TX_ONLY mode */
const t_Current_State NoLF_FastestTxOnly = {
		NULL, // LF is disabled
		vfnNeverEndingRFinterrupt,
		ReStartTx,
		Do_Nothing
};

/* NO_LF_PWU_TX mode */
const t_Current_State NoLF_PWUtransmission = {
		NULL, // LF is disabled
		Disable_Rf,
		vfnSendCompleteRFFrame,
		Do_Nothing
};

/*
 * The states below are for LF_COMMUNICATION mode
 * Refer to user_configuration.h
 */
const t_Current_State Init_State = {
		DisRF_EnLF,
		NULL, // RF is disabled
		DisRF_EnLF,
		Do_Nothing
};

const t_Current_State GoStop1 = {
		DisRF_EnLF,
		NULL, // No RF frame sent
		DisRF_EnLF,
		Do_Nothing
};

const t_Current_State Tx_OneFrame = {
		vfnSendCompleteRFFrame,
		DisRF_EnLF,
		DisRF_EnLF,
		Do_Nothing
};

const t_Current_State Periodic_Tx_550ms = {
		vfnConfigureStartPeriodicTx_550ms,
		DisRF_EnLF,
		vfnSendCompleteRFFrame,
		Do_Nothing
};

const t_Current_State Periodic_Tx_Xseconds = {
		vfnConfigureStartPeriodicTx,
		DisRF_EnLF,
		vfnSendCompleteRFFrame,
		Do_Nothing
};

const t_Current_State Fastest_Tx_state = {
		vfnConfigureStartFastestPeriodicTx,
		vfnSendCompleteRFFrame_FastestTx,
		StopRF_EnLF,
		Do_Nothing
};

const t_Current_State Fastest_Tx_never_ending = {
		vfnConfigureStartFastestPeriodicTxNeverEnding,
		vfnNeverEndingRFinterrupt,
		ReStartTx,
		Do_Nothing
};

/**************************************************************************
 **************************************************************************/
/* Public */
void vfnUpdateStateMachine(void)
{	
	switch (gau8DataBuffer[CLEAR])
		{
			
		case 0x01: // Go back to STOP1 with LF
			current_state = GoStop1;
			break;
		
		case 0x02: // Transmit one RF frame
			current_state = Tx_OneFrame;
			break;
			
		case 0x03: // RF periodic (period configurable) transmission
			current_state = Periodic_Tx_Xseconds;
			break;
			
		case 0x04: // RF periodic (550ms) transmission
			current_state = Periodic_Tx_550ms;
			break;
			
		case 0x05: // RF fastest transmission
			current_state = Fastest_Tx_state;
			break;
			
		case 0x06: // RF fastest transmission never ending (LF control is lost)
			current_state = Fastest_Tx_never_ending;
			break;	
				
		case 0x0F: // Turn on LED
			current_state = Init_State;
			FLASH_LED1;
			break;
			
		default: // Default : go back to STOP1			
			 current_state = Init_State;
			 FLASH_LED2;
			break;			
		}	
	
	return;
}

/* Public */
void vfnInitStateMachine(void)
{

#if (MODE == LF_COMMUNICATION)
	
	current_state = Init_State;
	
#elif (MODE == NO_LF_FASTEST_TX_ONLY)
	
	current_state = NoLF_FastestTxOnly;	
	vfnConfigureStartFastestPeriodicTxNeverEnding();
	
#elif (MODE == NO_LF_PWU_TX)
	
	current_state = NoLF_PWUtransmission;	
	vfnNoLfConfigureStartPeriodicTx();

#endif	

	return;
}
void Do_Nothing (void)
{
	return;
}

/* Public */
void DisRF_EnLF (void)
{
	TPMS_RF_ENABLE(CLEAR);
	// Configure LFR for data mode
    vfnDataModeInit();
    vfnClearReceivedBuffer();
    TPMS_LF_ENABLE(SET);
    vfnWaitMSec(3);
	return;
}


/*
 * Below are private functions
 */


void Disable_Rf (void)
{
	TPMS_RF_ENABLE(CLEAR);
}

void vfnSendCompleteRFFrame(void)
{
	TPMS_LF_ENABLE(CLEAR);
	/* Configure device for STOP4 - needed for measurement routines */
	vfnSetSTOPMode(STOP4);
	Measure_P_T_V_AccZ();
	TPMS_RF_ENABLE(SET);
	vfnWaitMSec(3u);
  
  	Init_RF(); 
  
  	vfnUpdateTireID();          

  	RFCR7_RFIACK = SET;  // Clear all Flags
  	  
  	Fill_RFBUFFER();
  	TPMS_RF_SET_TX(255); 
}


void vfnSendCompleteRFFrame_FastestTx(void)
{
	/* Configure device for STOP4 - needed for measurement routines */
	vfnSetSTOPMode(STOP4);
	Measure_P_T_V_AccZ();
	TPMS_RF_ENABLE(SET);
	vfnWaitMSec(3u);
  
  	Init_RF(); 
  
  	vfnUpdateTireID();          

  	RFCR7_RFIACK = SET;  // Clear all Flags
  
  	Fill_RFBUFFER();

  	// If PWU overflow: we must stop the transmissions
  	if ((TPMS_INTERRUPT_FLAG & PWU_MASK) == PWU_MASK)
  	{
   	  DisRF_EnLF();
  	}
  	else 
  	{
  	  TPMS_RF_SET_TX(255); 
  	}  	
}


void vfnConfigureStartPeriodicTx_550ms(void)
{
	/* Configure PWU for a periodic wake-up every 550ms */
	  PWUCS0 = 0x01;
	  PWUCS1 = CLEAR;
	  PWUDIV = 0x03;
	  
	  vfnSendCompleteRFFrame();
	  
	  return;
}

void vfnConfigureStartPeriodicTx(void)
{
	UINT8 temp;
	temp = 0x00;
	
	PWUCS0 = 0x02;
	PWUCS0 = 0x03; // Write any value to PWUSC0 in order to re-start the timer.
	
	/* Configure PWU for a periodic wake-up */
	if ((gau8DataBuffer[1] > 95) || (gau8DataBuffer[1] == 0))
	{
	  // Period incorrect => go back to 1s period
	  PWUCS0 = 0x01;
	  PWUCS1 = CLEAR;
	  PWUDIV = PWUDIV_1sec_calibrated;
	}
	else if (gau8DataBuffer[1] == 95)
	{
	  // Maximum period : this is a common case so we check if we are here so that we save time not doing the calculation
	  PWUCS0 = 0x3F; // 63 => Period = 63*1.512s = 95s
	  PWUCS1 = CLEAR;
	  PWUDIV = 0x3F; // 1.512s base time
	}
	else if (gau8DataBuffer[1] <= 63)
	{
	  // If period is under 63 seconds no need to do calculation because we can use the 1 second base time
	  PWUCS0 = gau8DataBuffer[1]; // Number of seconds
	  PWUCS1 = CLEAR;
	  PWUDIV = PWUDIV_1sec_calibrated; // 1 second base time
	}
	else
	{
	// We will use PWUDIV = 0x3F => 1.512s base time => calculation needed because value of PWUCS0 is not immediate
	// So PWUCS0 = gau8DataBuffer[1] / 3/2 = gau8DataBuffer[1] * 2 / 3
	// For the division by 3 we use the fact that x/3 = x/2 - x/4 + x/8 - x/16 ...
	  temp = gau8DataBuffer[1];
	  temp -= (temp << 1);
	  temp += (temp << 1);
	  temp -= (temp << 1);
	  temp += 0x02; // We are always under the expected result by 2 counts (due to the approximation)
	  if (temp == 0x00)
	  {
		  temp = 0x01;
	  }
	  else if (temp >= 0x3F)
	  {
		  temp = 0x3F;
	  }
	  PWUCS0 = temp;
	  PWUCS1 = CLEAR;
      PWUDIV = 0x3F; // 1.512 second base time
	}	  
	
	vfnSendCompleteRFFrame();
	
	return;
}

void vfnConfigureStartFastestPeriodicTx(void)
{
	// The PWU wake up will allow us to leave the fastest mode and go back to STOP1 w LF
	PWUCS0 = 0x3D; 
	PWUCS0 = 0x3E; // Write any value to PWUCS0 in order to re-start the timer.
	vfnConfigureStartPeriodicTx(); // Configure the PWU and start the first RF transmission
	
	return;
}

/*
 * Used by : NoLF_FastestTxOnly
 */
void vfnConfigureStartFastestPeriodicTxNeverEnding(void)
{
	vfnSetPWU();
	vfnSendCompleteRFFrame();

	return;
}

void vfnNeverEndingRFinterrupt (void)
{
	vfnSendCompleteRFFrame();
	
	return;
}

void ReStartTx (void)
{
	UINT8 timeout = 0;
	// We end up here if PWU interrupt occurred during RF transmission in STOP1
	// Wait for current transmission to end
	while ((RF_Interrupt == CLEAR) && (timeout < 10))
	{
		timeout ++;
		vfnWaitMSec(10u);
	}

	vfnSendCompleteRFFrame();
	
	return;
}

void StopRF_EnLF (void)
{
	UINT8 timeout = 0;
	// We end up here if PWU interrupt occurred during RF transmission in STOP1
	// Wait for current transmission to end
	while ((RF_Interrupt == CLEAR) && (timeout < 10))
	{
		timeout ++;
		vfnWaitMSec(10u);
	}
	
	DisRF_EnLF();
}

/* Used by No LF PWU mode */
void vfnNoLfConfigureStartPeriodicTx (void)
{
	// Configure PWU wake up period
	PWUCS0 = PWU_PERIOD; // Number of seconds
	PWUCS1 = CLEAR;
	PWUDIV = PWUDIV_1sec_calibrated; // 1 second base time
	
	vfnSendCompleteRFFrame();
}

