/*******************************************************************************
 * ON Semiconductor                                                            *
 * NCV7383 Evaluation KIT                                                      *
 *                                                                             *
 * FlexRay_CC.c                                                                *
 * FlexRay module handling functions                                           *
 *                                                                             *
 * Created by: Filip Brtan                                                     *
 * Date: 30.07.2012                                                            *
 *******************************************************************************/



/* S12X derivative information */ 
#include "mc9s12xf512.h"
/* Macro definitions for general purpose I/O handling  */
#include "GPIO_macros.h"
/* Standard and driver types */
#include "Fr_UNIFIED_types.h"  
/* UNIFIED driver implementation */         
#include "Fr_UNIFIED.h"               
/* Configuration data for the FlexRay node */
#include "Fr_UNIFIED_cfg.h"
/* FlexRay Communication Controller functions definitions */
#include "FlexRay_CC.h"
/* Bus Driver functions definitions */
#include "FlexRay_BD.h"

#pragma DATA_SEG FlexRay_CC_DATA
#pragma CODE_SEG FlexRay_CC_CODE

/*******************************************************************************/
/* Global variables                                                            */
/*******************************************************************************/
		
/* Return values */
Fr_return_type return_value;           /* General return value */
Fr_tx_MB_status_type tx_return_value;  /* Transmission return values */
Fr_rx_MB_status_type rx_return_value;  /* Reception return values */    

word rx_status_slot = 0;               /* Received frame status */
Fr_POC_state_type protocol_state;      /* Current protocol state */ 
Fr_wakeup_state_type wakeup_status;    /* Current wakeup status */ 
byte current_cycle;                    /* Current cycle value */
word current_macrotick;                /* Current macrotick value */


byte payload_length = 6;   /* Transmitter data length */
byte rx_data_length = 0;   /* Received data length */

/* Transmission and reception data array */
word tx_data[5][16] = {0};
word rx_data[5][16] = {0};  
  
/*  */
byte LEDS;
/*  */
bool FlexRay_CC_initialized;
/*  */
bool FlexRay_Cluster_Stop = FALSE;
/*  */
bool Enter_STOP_MODE = FALSE;

byte last_cycle;
#define CYCLE_COUNT_MAX 64


/*******************************************************************************/
/* Error function for debugging                                                */
/*******************************************************************************/
void Failed(byte dummy)               
{    
    while(dummy);       /* Function only for debugging, CC should be restarted */
}

/*******************************************************************************/
/* Callback function for transmission from MB 1                                */
/*******************************************************************************/
void CC_interrupt_1(byte buffer_idx)
{
    if (Fr_tx_buffer_cfg[buffer_idx].transmit_frame_ID == 1)
    {
      if (tx_data[buffer_idx][FR_SIGNAL_MODES] & FR_SIGNAL_MODES_BD_GO_TO_STANDBY)   
      {
        if (FlexRay_Cluster_Stop == FALSE)
        {  
          last_cycle = current_cycle + 10;
          if (last_cycle >= CYCLE_COUNT_MAX) last_cycle -= CYCLE_COUNT_MAX;
          tx_data[buffer_idx][FR_SIGNAL_MODES] = FR_SIGNAL_MODES_BD_GO_TO_STANDBY | last_cycle;
          FlexRay_Cluster_Stop = TRUE;
        } 
      }
    } 
    
    /* Update transmit MB with */
    tx_return_value = Fr_transmit_data(FR_TX_BUFFER_1, &tx_data[buffer_idx][0], payload_length);
    //if(tx_return_value == FR_TXMB_UPDATED) LEDS |= LED8_MASK; 
        
}

/*******************************************************************************/
/* Callback function for transmission from MB 2                                */
/*******************************************************************************/
void CC_interrupt_2(byte buffer_idx)
{
    /* Update transmit MB with */
    tx_return_value = Fr_transmit_data(FR_TX_BUFFER_2, &tx_data[buffer_idx][0], payload_length);
    //if(tx_return_value == FR_TXMB_UPDATED) LEDS |= LED7_MASK; 
}

/*******************************************************************************/
/* Callback function for transmission from MB 3                                */
/*******************************************************************************/
void CC_interrupt_3(byte buffer_idx)
{
    /* Update transmit MB with */
    tx_return_value = Fr_transmit_data(FR_TX_BUFFER_3, &tx_data[buffer_idx][0], payload_length);
    //if(tx_return_value == FR_TXMB_UPDATED) LEDS |= LED6_MASK;     
}

/*******************************************************************************/
/* Callback function for transmission from MB 4                                */
/*******************************************************************************/
void CC_interrupt_4(byte buffer_idx)
{
    /* Update transmit MB with */
    tx_return_value = Fr_transmit_data(FR_TX_BUFFER_4, &tx_data[buffer_idx][0], payload_length);
    //if(tx_return_value == FR_TXMB_UPDATED) LEDS |= LED5_MASK;    
}

/*******************************************************************************/
/* Callback function for transmission from MB 5                                */
/*******************************************************************************/
void CC_interrupt_5(byte buffer_idx)
{
    /* Update transmit MB with */
    tx_return_value = Fr_transmit_data(FR_TX_BUFFER_5, &tx_data[buffer_idx][0], payload_length);
    //if(tx_return_value == FR_TXMB_UPDATED) LEDS |= LED4_MASK;      
} 

/*******************************************************************************/
/* Callback function for reception from RX MB 1                                */
/*******************************************************************************/
void CC_interrupt_rx_1(byte buffer_idx)
{
    /* Copy received data into given array */
    rx_return_value = Fr_receive_data(buffer_idx, &rx_data[buffer_idx-FR_RX_BUFFER_1][0],
                                      &rx_data_length, &rx_status_slot);
                                      
    if(rx_return_value == FR_RXMB_RECEIVED) 
    {
      LEDS |= LED8_MASK;
      if (rx_data[buffer_idx-FR_RX_BUFFER_1][FR_SIGNAL_MODES] & FR_SIGNAL_MODES_BD_GO_TO_STANDBY) 
      {
        if (FlexRay_Cluster_Stop == FALSE)
        {  
          last_cycle = (byte)(rx_data[buffer_idx-FR_RX_BUFFER_1][FR_SIGNAL_MODES] & 0x00FF);
          FlexRay_Cluster_Stop = TRUE;
        }
      }
    }      
}

/*******************************************************************************/
/* Callback function for reception from RX MB 2                                */
/*******************************************************************************/
void CC_interrupt_rx_2(byte buffer_idx)
{
    /* Copy received data into given array */
    rx_return_value = Fr_receive_data(buffer_idx, &rx_data[buffer_idx-FR_RX_BUFFER_1][0],
                                      &rx_data_length, &rx_status_slot); 
    if(rx_return_value == FR_RXMB_RECEIVED) 
    {
      LEDS |= LED7_MASK;
    }
}

/*******************************************************************************/
/* Callback function for reception from RX MB 3                                */
/*******************************************************************************/
void CC_interrupt_rx_3(byte buffer_idx)
{
    /* Copy received data into given array */
    rx_return_value = Fr_receive_data(buffer_idx, &rx_data[buffer_idx-FR_RX_BUFFER_1][0],
                                      &rx_data_length, &rx_status_slot); 
    if(rx_return_value == FR_RXMB_RECEIVED) 
    {
      LEDS |= LED6_MASK;
    }                                                                                 
}

/*******************************************************************************/
/* Callback function for reception from RX MB 4                                */
/*******************************************************************************/
void CC_interrupt_rx_4(byte buffer_idx)
{
    /* Copy received data into given array */
    rx_return_value = Fr_receive_data(buffer_idx, &rx_data[buffer_idx-FR_RX_BUFFER_1][0],
                                      &rx_data_length, &rx_status_slot);                                            
    if(rx_return_value == FR_RXMB_RECEIVED) 
    {
      LEDS |= LED5_MASK;
    }
}

/*******************************************************************************/
/* Callback function for reception from RX MB 5                                */
/*******************************************************************************/
void CC_interrupt_rx_5(byte buffer_idx)
{
    /* Copy received data into given array */
    rx_return_value = Fr_receive_data(buffer_idx, &rx_data[buffer_idx-FR_RX_BUFFER_1][0],
                                      &rx_data_length, &rx_status_slot);                                            
    if(rx_return_value == FR_RXMB_RECEIVED) 
    {
      LEDS |= LED4_MASK;
    }
}

/*******************************************************************************/
/* FlexRay Timer 1 Callback service routine                                    */
/*******************************************************************************/
void CC_interrupt_timer_1(void)
{
    /* Get the global time */
    Fr_get_global_time(&current_cycle, &current_macrotick);     
}

/*******************************************************************************/
/* FlexRay Timer 2 Callback service routine                                    */
/*******************************************************************************/
void CC_interrupt_timer_2(void)
{
    /* Get the global time */
    Fr_get_global_time(&current_cycle, &current_macrotick);
}

/*******************************************************************************/
/* FlexRay wakeup interrupt Callback service routine                           */
/*******************************************************************************/
void CC_interrupt_wakeup(Fr_channel_type wakeup_channel)
{
  if (wakeup_channel == FR_CHANNEL_B ) NOP();
  wakeup_status = Fr_get_wakeup_state();  /* Retrieve the wakeup state */
    
  /* Check whether a wakeup pattern has been received */
  if(wakeup_status == FR_WAKEUPSTATE_UNDEFINED)
  {   

  }
}
 
/*******************************************************************************/
/* FlexRay protocol interrupt Callback service routine                           */
/*******************************************************************************/
void CC_interrupt_protocol(void)
{

} 
 
/*******************************************************************************/
/* FlexRay protocol state changed interrupt Callback service routine           */
/*******************************************************************************/
void CC_interrupt_protocol_state_changed(void)
{
  
}

/*******************************************************************************/
/* FlexRay cycle start interrupt Callback service routine                      */
/*******************************************************************************/
void CC_interrupt_cycle_start(void)
{
    /* Get the global time */
    Fr_get_global_time(&current_cycle, &current_macrotick); 
    
    tx_data[FR_TX_BUFFER_1][FR_SIGNAL_COUNTERL]++;
    if (current_cycle == 10) 
    {
      tx_data[FR_TX_BUFFER_1][FR_SIGNAL_COUNTERH]++;
    }
    
      
    if (FlexRay_Cluster_Stop == TRUE)
      if (current_cycle == last_cycle)
      {      
        /* Initialization of message buffers, receive shadow buffers and FIFO storages */                
        return_value = Fr_stop_communication(FR_HALT_COMMUNICATION);
        if (return_value == FR_SUCCESS) 
          while(Fr_get_POC_state() != FR_POCSTATE_HALT)
            protocol_state = Fr_get_POC_state(); /* Current POC state */;    
        fr_bd_change_mode(FR_CHANNEL_AB, FR_BD_STANDBY);                      
        Enter_STOP_MODE = TRUE;
      };

}


/*******************************************************************************/
/* FlexRay CC Configuration                                                    */
/*******************************************************************************/
void FlexRay_CC_configuration(void) {
    
    /* Initialization of the FlexRay CC with protocol configuration parameter */
    Fr_set_configuration(&Fr_HW_cfg_01, &Fr_low_level_cfg_set_01);
    
    /* Initialization of message buffers, receive shadow buffers and FIFO storages */
    return_value = Fr_buffers_init(&Fr_buffer_cfg_01[0], &Fr_buffer_cfg_set_01[0]);
    
    /* MB Transmission completed calback functions */
    /* Set callback function in case that an interrupt from MB 1-5 occurs */
    Fr_set_MB_callback(&CC_interrupt_1, FR_TX_BUFFER_1);  
    Fr_set_MB_callback(&CC_interrupt_2, FR_TX_BUFFER_2);  
    Fr_set_MB_callback(&CC_interrupt_3, FR_TX_BUFFER_3);  
    Fr_set_MB_callback(&CC_interrupt_4, FR_TX_BUFFER_4);  
    Fr_set_MB_callback(&CC_interrupt_5, FR_TX_BUFFER_5);  
    
    /* Reception callback functions*/
    /* Set callback function in case that an interrupt from MB 1-5 occurs */
    Fr_set_MB_callback(&CC_interrupt_rx_1, FR_RX_BUFFER_1); 
    Fr_set_MB_callback(&CC_interrupt_rx_2, FR_RX_BUFFER_2); 
    Fr_set_MB_callback(&CC_interrupt_rx_3, FR_RX_BUFFER_3); 
    Fr_set_MB_callback(&CC_interrupt_rx_4, FR_RX_BUFFER_4); 
    Fr_set_MB_callback(&CC_interrupt_rx_5, FR_RX_BUFFER_5); 


    /* Initialization of the timers */
    Fr_timers_init(&Fr_timers_cfg_00_ptr[0]);

    /* Set callback function in case that an interrupt from timer 1 occurs */
    return_value = Fr_set_protocol_0_IRQ_callback(&CC_interrupt_timer_1, FR_TIMER_1_EXPIRED_IRQ);

    /* Set callback function in case that an interrupt from timer 2 occurs */
    return_value = Fr_set_protocol_0_IRQ_callback(&CC_interrupt_timer_2, FR_TIMER_2_EXPIRED_IRQ);

    /* Set callback function in case that cycle start interrupt occurs */
    return_value = Fr_set_protocol_0_IRQ_callback(&CC_interrupt_cycle_start, FR_CYCLE_START_IRQ);

    /* Set callback function in case that wakeup interrupt occurs */
    Fr_set_wakeup_IRQ_callback(&CC_interrupt_wakeup);
    //return_value = Fr_set_global_IRQ_callback(&CC_interrupt_wakeup, FR_WAKEUP_IRQ);

    /* Set callback function in case that protocol interrupt occurs */
    return_value = Fr_set_global_IRQ_callback(&CC_interrupt_protocol, FR_PROTOCOL_IRQ);

    /* Set callback function in case that protocol state changed interrupt occurs */
    return_value = Fr_set_protocol_1_IRQ_callback(&CC_interrupt_protocol_state_changed, FR_PROTOCOL_STATE_CHANGED_IRQ);
    
    /* Leave FR_POCSTATE_CONFIG state */
    return_value = Fr_leave_configuration_mode();
    if(return_value == FR_NOT_SUCCESS)
      Failed(2);   // Call debug function in case of any error  
    
    /* Wait until the FR CC is not in the FR_POCSTATE_READY */ 
    while(Fr_get_POC_state() != FR_POCSTATE_READY);     
    
    /* Wakeup sequence */    
    return_value = Fr_send_wakeup(); 
    if (return_value == FR_NOT_SUCCESS) 
    {
      NOP();
    }
    
    /* Wait until the FR CC complete the WAKEUP  */
    while(Fr_get_POC_state() == FR_POCSTATE_WAKEUP);
    wakeup_status = Fr_get_wakeup_state();  // Read current wakeup status   

    /* Initiate Startup */
    while(Fr_get_POC_state() != FR_POCSTATE_READY);    
    return_value = Fr_start_communication();    // Initialize startup   
    protocol_state = Fr_get_POC_state(); 

    /* Enable appropriate interrupts */
    Fr_enable_interrupts((FR_PROTOCOL_IRQ | FR_RECEIVE_IRQ | FR_TRANSMIT_IRQ | FR_WAKEUP_IRQ), 
                    (FR_TIMER_1_EXPIRED_IRQ | FR_TIMER_2_EXPIRED_IRQ | FR_CYCLE_START_IRQ), (FR_PROTOCOL_STATE_CHANGED_IRQ));
                        
    Fr_start_timer(FR_TIMER_T1);    // Start Timer T1 
    Fr_start_timer(FR_TIMER_T2);    // Start Timer T2  
    
     
}

/*******************************************************************************/
/* FlexRay Message buffers first initialization                                */
/*******************************************************************************/
Fr_return_type Fr_init_message_buffers(void) {
  byte idx = 0;
  byte i = 0;
  word buffer = 0;
  
  return_value = FR_SUCCESS;    
  /* First initialization of the message buffers */  
  while (i<255)
  {      
    idx = Fr_buffer_cfg_set_01[i++];
    if (idx < FR_LAST_MB)
    {
      if (Fr_buffer_cfg_01[idx].buffer_type == FR_TRANSMIT_BUFFER)
      {  
        buffer = Fr_buffer_cfg_01[idx].buffer_index_init;
        tx_return_value = Fr_transmit_data(buffer, &tx_data[buffer][0], payload_length);
        if(tx_return_value == FR_TXMB_NO_ACCESS) 
          return_value = FR_NOT_SUCCESS;  
      } 
      else 
      {
        NOP();
      }
    } 
    else 
    {
      i=255;
    }
  }
  return return_value;
}


/*******************************************************************************/
/* FlexRay module configuration                                                */
/*******************************************************************************/
void FlexRay_Init(void) 
{     
  word i,j; 
  
  /* Clear the transmission data arrays */ 
  for (i=0;i<5;i++)
    for(j=0;j<16;j++) 
      tx_data[i][j] = 0; 

  /* Check whether the CC module was already initialized */  
  if (FlexRay_CC_initialized == FALSE) 
  {    
    /* Change FlexRay Bus Driver (NCV7383) mode to Normal Mode */
    fr_bd_change_mode(FR_CHANNEL_AB, FR_BD_NORMAL);
    
    /* Enable Transmitter Function - BGE = High  */ 
    FR_BGE_A = 1;
    FR_BGE_B = 1;
 
    /* Configure Low Level Config Set - based on Address set by PCB DIP Switch  */
    Fr_low_level_cfg_set_01.P_KEY_SLOT_ID = (word)SW_ADDRESS; 
    Fr_low_level_cfg_set_01.P_KEY_SLOT_USED_FOR_STARTUP= (word)SW_ADDRESS < 6 ? TRUE : FALSE;
    Fr_low_level_cfg_set_01.P_KEY_SLOT_USED_FOR_SYNC= (word)SW_ADDRESS < 6 ? TRUE : FALSE;     
    Fr_low_level_cfg_set_01.P_KEY_SLOT_HEADER_CRC = Calculate_Header_Crc(Fr_low_level_cfg_set_01.P_KEY_SLOT_USED_FOR_SYNC, 
                                                                       Fr_low_level_cfg_set_01.P_KEY_SLOT_USED_FOR_STARTUP, 
                                                                       (word)SW_ADDRESS, 
                                                                       6);
                                                                       
    Fr_tx_buffer_cfg[0].transmit_frame_ID = (word)SW_ADDRESS;                                                                    
    Fr_tx_buffer_cfg[0].header_CRC = Fr_low_level_cfg_set_01.P_KEY_SLOT_HEADER_CRC;  
    
    // Disable Receive message buffer associated to the transmitting slot 
    if ((SW_ADDRESS < 6) & (SW_ADDRESS > 0)) Fr_rx_buffer_cfg[SW_ADDRESS-1].rx_MB_interrupt_enable = FALSE;
 
    // Enable the FlexRay CC and force it into FR_POCSTATE_CONFIG
    return_value = Fr_init(&Fr_HW_cfg_01, &Fr_low_level_cfg_set_01);
    if(return_value == FR_SUCCESS)
    {
      FlexRay_CC_initialized = TRUE;
      FlexRay_CC_configuration(); 
      return_value = Fr_init_message_buffers();                      
    } 
  } else 
  {
    // Reset FlexRay CC
    return_value = Fr_reset_protocol_engine();
    if(return_value != FR_SUCCESS)
    { 
      NOP();
    }
    // Force the CC into FR_POCSTATE_CONFIG 
    return_value = Fr_enter_configuration_mode();
    if(return_value == FR_SUCCESS)
    {       
      protocol_state = Fr_get_POC_state(); // Current POC state
      if(protocol_state != FR_POCSTATE_CONFIG) 
      {
        NOP();
      }
      FlexRay_Cluster_Stop = FALSE;
      Enter_STOP_MODE = FALSE;
      FlexRay_CC_configuration();                     
    }
  }
} 

/*******************************************************************************/
/* Used to calculate Header CRC                                                */
/* Params:                                                                     */
/*   SyncFrame (bool): True if the frame is used as Synchronization frame      */
/*   StartupFrame (bool): True if the frame is used as Startup frame           */
/*   FrameId (word)                                                            */
/*   PayloadLength (byte)                                                      */
/* Returns:                                                                    */
/*   Calculated CRC (word)                                                     */
/*******************************************************************************/
word Calculate_Header_Crc(bool SyncFrame, bool StartupFrame, word FrameId, byte PayloadLength)
{
    byte i;
    word vCrcReg;
    dword CrcInput;
    bool CrcRegMSB;
    bool CrcInputLSB; 

    if (SyncFrame) 
      CrcInput = 0x80000;
    if (StartupFrame) 
      CrcInput += 0x40000;
    CrcInput += (dword)FrameId << 7;
    CrcInput += PayloadLength;

    vCrcReg = vCrcInit;

    for (i = 0; i < 20; i++)
    { 
        CrcInputLSB = (CrcInput & 0x80000) != 0 ? TRUE : FALSE; // MSB bit 20
        CrcInput <<=1;
        CrcRegMSB = (vCrcReg & 0x0400) != 0 ? TRUE : FALSE; // MSB bit 11
        vCrcReg <<= 1;
        vCrcReg &= 0x07FE;
        if ((CrcRegMSB ^ CrcInputLSB) != 0) vCrcReg ^= vCrcPolynomial;
    }

    return vCrcReg;
}



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

 #pragma CODE_SEG DEFAULT
 