/************************************************************************************
* This file contains PHY HW specific initializations.
*
* Author(s): Thomas O. Jensen, Allan Poulsen, Michael V. Christensen
*
* (c) Copyright 2004, Freescale, Inc.  All rights reserved.
*
* Freescale Confidential Proprietary
* Digianswer Confidential
*
* No part of this document must be reproduced in any form - including copied,
* transcribed, printed or by any electronic means - without specific written
* permission from Freescale.
*
* Last Inspected:
* Last Tested:
************************************************************************************/
typedef enum ePhyEnums_t phyTxRxState_t;

/************************************************************************************
* Includes
************************************************************************************/
#include "DigiType.h"
#include "phy_spi.h"
#include "AbelReg.h"
#include "gb60_io.h"
#include "MacPhy.h"
#include "NV_Data.h"
#include "PhyMacMsg.h"
#include "Debug.h"
#include "Target.h"

// Prototypes to be used by phy
extern void DoFastRxEof(void);
extern void DoFastTxEof(void);
extern void RxTimeout(void);
extern uint16_t gIsrMask;
extern bool_t gStopAsyncRx;
extern bool_t gSeqInErrorState;
extern void SeqIsrCompletedInErrorState(void);
extern void ReStartRx(void);
extern void SeqGenerateWakeInd(void);
extern uint8_t gIsrEntryCounter;

#pragma PLACE_DATA_SEG(SLEEP_VARIABLE)
extern uint8_t gSeqPowerSaveMode;
extern uint8_t gSeqClkoState;
#pragma RESTORE_DATA_SEG

extern phyTxRxState_t mPhyTxRxState;

extern void ICG_Setup(void);
#define ICG_FLL_LOCKED	0x08
#define aAckSize_s 22

// Needed to initialize Timer1 vector
void DummyISR(void)
{
  ;
}
void (*pTimer1Isr)(void) = DummyISR; // Makes it possible to dynamically change interrupt vector for testing!
extern void (*gpTimer2Isr)(void);
extern void (*mpfPendingSetup)(void);
extern void RestartRxOrTimeout(void);

/************************************************************************************
*************************************************************************************
* Private memory declarations
*************************************************************************************
************************************************************************************/
uint8_t StreamingRxError; //Counts up when a StreamingRx interrupt is received, but not
                          //serviced by gIsrFastAction as expected
uint8_t StreamingTxError; //Counts up when a StreamingTx interrupt is received, but not
                          //serviced by gIsrFastAction as expected


// The following table contains addresses of Abel register to be initialized
// Each address has a corresponding value in the setupValueTable table. Do NOT
// change the order of occurence. It might be worth considering entering
// the initialization tables into the NV section for costumer control
static const uint8_t setupAddrTable[] = {
  ABEL_reg8,
  ABEL_LO1DIV_REG,
  ABEL_LO1NUM_REG,
  ABEL_reg11,
  ABEL_reg12,
  ABEL_reg13,
  ABEL_reg31,
  ABEL_reg38,
#ifndef TARGET_TOROWEAP
  // Abel 2.2 only. May be removed for Abel 2.3. Fix for excess power consumption during hibernate and doze. 
  // Must activate thermometer and deactivate later for power to be low enough in these modes 
  ABEL_CONTROL2_REG,// Abel 2.2 only
  ABEL_reg9,        // Abel 2.2 only  
#endif
  //
  ABEL_CONTROL2_REG,
  ABEL_MASK_REG,
  ABEL_reg9,
  ABEL_TMR1_HI_REG, // Stop all wrap around interrupts
  ABEL_TMR2_HI_REG,
  ABEL_TMR3_HI_REG,
  ABEL_TMR4_HI_REG,
  ABEL_regB         // Configured to all outputs (inputs on all but GPIO1 and GPIO2 : 0x01FC)
};



// The following table contains values of Abel registers to be initialized
// Each value has a address value in the setupAddrTable table. Do NOT
// change the order of occurence
static const uint16_t setupValueTable[] = {
  0xFFF7,           // R0x08: 0xFFF7
  0x0F95,           // 0x0F8F for 2305Mhz, 0x0F95 for 2405Mhz
  0x5000,           // 0x1000 for 2305MHz, 0x5000 for 2405MHz
  0xA0FF,           // 0xA0FF: Recommended setting from Phoenix team
  0x00BC,           // V1.2:0x80CC, default V2.0:0x000C : PA level
  0x1843,           // V1.2:0x1803, default V2.0:0x1863 : Sigma-delta fade detector differs
  0xA000,
  0x0008,           // Correlator VT, 0x0000=Abel 1.2
#ifndef TARGET_TOROWEAP
  // The next two are for Abel 2.2 only. May be removed for Abel 2.3. Fix for excess power consumption
  // during hibernate and doze. Must activate thermometer and deactivate later for power to be low enough
  // in these modes 
  0x7D3C,           // For Abel 2.2 only
  0xF3FD,           // For Abel 2.2 only
#endif
  // The next three values may not be evaluated in a pretty way, but it is very effective - let the preprocessor do the work

#ifdef TARGET_TOROWEAP
  // Default is single-ended antenna
#define tmp1 (0x5c00 | cUSE_STRM_MODE | (0<<8)) /* bit 8=0 is SFD throw away length 0,1,2, and restart Rx */
#else
#define tmp1 (0x7c00 | cABEL2SPI_MASK | cUSE_STRM_MODE)
#endif
#ifdef USE_INTERRUPT_TXEOF 
#define tmp2 (tmp1 | (uint16_t) cTX_DONE_MASK)  // Yes, we want Tx done interrupts
#else
#define tmp2 (tmp1)
#endif
#ifdef USE_INTERRUPT_RXEOF
#define tmp3 (tmp2 | (uint16_t) cRX_DONE_MASK)  // Yes, we want Rx done interrupts
#else
#define tmp3 (tmp2)
#endif
  tmp3,             // Setup interrupt mask

#define tmp4 (cTMR4_MASK | cTMR2_MASK | cLO1_LOCK_MASK)
#if gAspPowerSaveCapability_d
#define tmp5 (tmp4 | cDOZE_MASK | cTMR1_MASK)
#else 
#define tmp5 (tmp4)
#endif
  tmp5,             // Write Abel Mask registers ("Control2" and "Mask")  

#define tmp6 (0xF3FD & ~cTMR_PRESCALEmask)
#define tmp7 (tmp6 | (5 << cTMR_PRESCALEshift)) // 5=62.5kHz, 3=250kHz(default)
#define tmp8 (tmp7 | 0x80)  // Alternate GPIO enable
  tmp8,

  0x8000,           // Stop all wrap around interrupts
  0x8000,
  0x8000,
  0x8000,
  0x3F80            // Configured to all outputs (inputs on all but GPIO1 and GPIO2 : 0x01FC)
};

                          
/*************************************************************************************
*************************************************************************************
* Private functions
*************************************************************************************
************************************************************************************/


/************************************************************************************
*  SPI configured as ABEL interface                                                  *
************************************************************************************/
void InitAbelSPI(void)
{
  // SPI Bit Clock Rate = BUSCLK / 2
  PTED = 0x04;	//PTED.2=SS = LOW  : 0x00 for autoselect
  PTEPE = 0x00;
  PTEDD |= 0x34;

  SPIC1 = 0x50; //SPIC1.1 = SSOE   : 0x52 for autoselect
  SPIC2 = 0x00; //SPIC2.4 = MODEEN : 0x10 for autoselect
  SPIBR = 0x00;
  SPIS;
}

/************************************************************************************
* All the complete systems I/O port definitions are described here                  *
************************************************************************************/
void InitPHYIO(void)
{
  // Setup port A
  mSETUP_PORT_A

  // Setup Port B
  mSETUP_PORT_B

  // Setup port C
  mSETUP_PORT_C

  // Setup port D
  mSETUP_PORT_D

  CODE_PROFILING_ENABLE_PINS
  ENABLE_TIMING_PINS
  ENABLE_ISR_TIMING_PINS
  
  RX_ANTENNE_ENABLED

  RxTxEnable           // RxTxEnable static = 1;
  HWAssertAbelReset    // keep Abel in reset for now

}


/*******************************************************************
* Make a pulse on hardware reset PIN at ABEL                       *
*******************************************************************/
void HWResetAbel(void)
{
  HWAssertAbelReset     //To ensure time goes....
  HWAssertAbelReset
  HWAssertAbelReset
  HWAssertAbelReset

  HWDeAssertAbelReset
}

/*******************************************************************
* Now use SPI to initialize ABEL                                   *
*******************************************************************/
void AbelRegisterSetup(void)
{
  uint8_t   idx, addr;
  uint16_t  retReg;

  // MSB = CCA Energy detect threshold: abs(power in dBm)*2, 0x96=-75dBm
  // LSB = Power compensation Offset added to RSSI. Typically 0x74 FFJ/JK 13/01/04 (Abel 013)
  ABEL_WRITE(ABEL_reg4, NV_RAM_ptr->HF_Calibration);  

   // Now set up various register from the tables (see tables above)

  for (idx = 0; idx < sizeof(setupAddrTable)/sizeof(setupAddrTable[0]); idx++) {
    addr = setupAddrTable[idx]; // It saves a few code bytes to use a stack variable
    ABEL_WRITE(addr, setupValueTable[idx]);
  }

#ifdef TARGET_TOROWEAP
    // Setup default antenna switch mode
  if (NV_RAM_ptr->AntennaSelect == 1){
    ABEL_READ(ABEL_CONTROL2_REG, retReg);
    retReg &= 0x8FFF;
    retReg |= 0x4000; // Dual antenna setup at boot, CT_Bias_en = 1, RF_switch_mode = 0, CT_Bias_inv = 0
    ABEL_WRITE(ABEL_CONTROL2_REG, retReg);
  }
#endif

  ABEL_READ(ABEL_STATUS_REG, retReg);   // Clear interrupts by reading interrupt status
  ABEL_WRITE(ABEL_TMR2_HI_REG, 0x0000); // Enable TMR2 interrupts

  IRQSC = 0x17;                         // Enable external interrupt from Abel, low level and edge-triggered
}

/*************************************************************************************
* Used by JT to make PHY speed test (Header calculation)                             *
*************************************************************************************/

#if gAspPowerSaveCapability_d

void WakeUpIsr(void)
{
    // Dont do anything if we are already awake (ATTN IRQ will always cause
    // this ISR to be called even though the ABEL is out of pover save mode).
  if(gSeqPowerSaveMode != 0) {
    uint16_t ctrl2val, maskval;

    SeqGenerateWakeInd();

    gSeqPowerSaveMode = 0; // Set to gSeqPowerModeAwake_c;

      // Disable ATTN Irq when not in low power mode
    ABEL_READ_INT(ABEL_MASK_REG, maskval);
    maskval=maskval & (~cATTN_MASK);
    ABEL_WRITE_INT(ABEL_MASK_REG, maskval);

    ABEL_READ(ABEL_CONTROL2_REG, ctrl2val);

    ctrl2val = ctrl2val & ~(cDOZE_EN | cCLKO_DOZE_EN | cHIB_EN);

#ifdef USE_INTERRUPT_TXEOF
    ctrl2val = ctrl2val | (uint16_t) cTX_DONE_MASK;
#endif  
#ifdef USE_INTERRUPT_RXEOF
    ctrl2val = ctrl2val | (uint16_t) cRX_DONE_MASK;
#endif  

    ABEL_WRITE(ABEL_CONTROL2_REG, ctrl2val);

    // Don't attempt to setup clock if clko is already running..
    // Attempting to do so will cause an undeterministic wakeup time!!
    if (gSeqClkoState == 0) // Check if equal to gSeqClkoStateDisabled_c
    {
      gSeqClkoState = 1; // Set to gSeqClkoStateEnabled_c (clko running)

      // Setup clock again
 #if defined BOOTLOADER_ENABLED && !defined FOR_BOOTLOADER_ONLY
     // Call version in bootloader
	    FL_ICG_Setup();
#else
	    ICG_Setup(); // Reuse code in function to reduce code size
#endif defined BOOTLOADER_ENABLED && !defined FOR_BOOTLOADER_ONLY
    } // if - clko restore..
  } // if - power save mode..
}
#endif // gAspPowerSaveCapability_d

/*************************************************************************************
* Must signal to gIsrAsyncTailFunction/Header calculation, that the calculation must *
* stop now, or receiver to be restarted.                                             *
*************************************************************************************/
void LO_LOCK_IRQ(void)
{
    // Handle Lo1 unlock
    // If current action is Rx (typical), merely restart Rx, ensuring that TO did not just occur. 
    // If current action is Tx, act as if everything went ok here by calling fast action TxEof code.
    // If either Ed of Cca should get Lo1 unlock, fast action is already set up for Eof 
    // and will have been called on irq H-L, so ignore here!
  if (mPhyTxRxState==cBusy_Rx) RestartRxOrTimeout();
  if (mPhyTxRxState==cBusy_Tx) {
    ABEL_READ_INT(ABEL_CURR_TIME_LSB_REG, gRxTimeStamp);
    gRxTimeStamp = gRxTimeStamp - aAckSize_s;
    DoFastTxEof();
  }
}


/*************************************************************************************
* This is where everything happens...  Abel driver runs through here                 *
*************************************************************************************/
__interrupt void AbelInterrupt(void)
{
  uint16_t retReg;
  uint8_t *pTmp;
  register uint8_t tmpStatus;

#ifdef TIME_INTERRUPT
  uint8_t tmpRunning;
  tmpRunning = CHECK_ABEL_ISR_RUNNING_1;
  ABEL_ISR_RUNNING_1;
#endif
  ISR_DISABLED_0;

  if (gIsrSuperFastAction){
    gIsrSuperFastAction();
    gIsrSuperFastAction=NULL;
    mpfPendingSetup = NULL;
  }

  tmpStatus = IRQSC;
  tmpStatus |=  0x04;   // IACK, MUST be done before RxStreaming...
  tmpStatus &=  ~0x02;  // 0x02 = DISABLE ABEL ISR
  IRQSC = tmpStatus;

  SETTIMINGPIN_0
  gIsrEntryCounter++;
  gIsrMask = 0xFFFF;
  ENABLE_ALL_INTERRUPTS;    // Interrupts are always enabled in this system. Disable ABEL only when needed

  (gIsrFastAction)();

  if(IRQSC & 0x08)  //IRQF test
  {
    IRQSC |=  0x04;   //IACK, Could be initiated by new/next edge.

    ABEL_READ_INT(ABEL_reg24, retReg);

      // If interrupt other than streaming Rx occured kill filter.

    retReg = retReg & gIsrMask;
    if (retReg & 0xFF00)
    {
      gStopAsyncRx = TRUE;
      if (retReg & cLO_LOCK_IRQ){  LO_LOCK_IRQ(); {if (retReg & cTMR4_IRQ) RxTimeout();} goto IsrExit;}
#ifdef USE_INTERRUPT_RXEOF
      if (retReg & cRX_DONE){      PhyPlmeSyncLossIndication(); goto IsrExit;}
#else
      if (retReg & cRX_DONE)       DummyISR();
#endif
#ifdef USE_INTERRUPT_TXEOF
      if (retReg & cTX_DONE){      DoFastTxEof();  goto IsrExit;} ///*PhyPlmeSyncLossIndication();*/} //HACK for Timeout in TxAck 
#else
      if (retReg & cTX_DONE)       DummyISR();
#endif

      if (retReg & cTMR1_IRQ)      pTimer1Isr();
#if gAspPowerSaveCapability_d
      if (retReg & cResetATTN_IRQ) WakeUpIsr();
      if (retReg & cDOZE_IRQ)      WakeUpIsr();
#endif // gAspPowerSaveCapability_d

      if (retReg & (cSTRM_DATA_ERR | cHG_IRQ)) {
        gStopAsyncRx = FALSE;
        DummyISR();
      }
    }

    if (retReg & (0x00FC & ~cRX_RCVD_IRQ)) //@RNI: ignore cRX_RCVD_IRQ
    {
      gStopAsyncRx = TRUE;
      if (retReg & cCCA_IRQ)       DummyISR(); // Ignore CCA irq here. Fast action catches it. (Otherwise ignore the failure)
      if (retReg & cTMR2_IRQ)      gpTimer2Isr();
      if (retReg & cTMR4_IRQ){     RxTimeout();  goto IsrExit;}  
      if (retReg & cTMR3_IRQ)      DummyISR();
      //if (retReg & cRX_RCVD_IRQ)   StreamingRxError++;
      if (retReg & cTX_SENT_IRQ)   StreamingTxError++;
    }
  }

  gIsrAsyncTailFunction();
IsrExit:
    // Assume that interrupts are DISABLED at this point!
  pTmp = &gIsrEntryCounter;
  if (!(--*pTmp)){
    if (gSeqInErrorState){ 
      SeqIsrCompletedInErrorState();
    }
  }

  DISABLE_ALL_INTERRUPTS;
  ENABLE_ABEL_INTERRUPTS_FAST;
  CLRTIMINGPIN_0
#ifdef TIME_INTERRUPT
  if (tmpRunning == 0) ABEL_ISR_DONE_1; // Ensure measuring entire time of nested interrupts!
#endif
  ISR_ENABLED_0;
}

/************************************************************************************
*************************************************************************************
* Public function(s)
*************************************************************************************
************************************************************************************/

/*******************************************************************
* Setup everything                                                 *
*******************************************************************/
void PHY_HW_Setup(void)
{
  InitPHYIO();
  InitAbelSPI();
  HWResetAbel();
}

/*******************************************************************************
* Pulse ATTN pin of the ABEL radio in order to bring it out of power save mode *
*******************************************************************************/
void AbelWakeUp(void)
{
#if defined(AttEnable) && defined(AttDisable)

  uint8_t i=10; // ~10us ATTN pulse @ 62.5KHz

  AttEnable;

  while(i) { i--; }

  AttDisable;

    // Wait for ICG to lock onto operational clock frequency.
  if(((ICGS1 & ICG_FLL_LOCKED) != ICG_FLL_LOCKED)) {
    while((ICGS1 & ICG_FLL_LOCKED) != ICG_FLL_LOCKED) {}
  }

#endif
}

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

