//*****************************************************************************
//
//! @file
//! @brief AT86RF212
//
//*****************************************************************************

// STELARISWARE
#include "inc/hw_types.h"
#include "driverlib/timer.h"

// PROJECT INCLUDES

#include "at86rf212.h"
#include "packet.h"
#include "spi.h"

#include "sniffer.h"
#include "myutils/packetfifo.h"
#include "myutils/crc.h"

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

unsigned long *ptr212_TimeCounter;
tSnifferSettings *ptr212_SnifferSettings;


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


unsigned char trx212_get_irq(void);
void trx212_bit_write(unsigned char addr, unsigned char mask, unsigned char pos, unsigned char val);
unsigned char trx212_bit_read(unsigned char addr,unsigned char mask, unsigned char pos);
void trx212_reg_write(unsigned char addr,unsigned char val);
void trx212_print_ident(void);
tBoolean trx212_setstate_RX_ON(void);
unsigned char trx212_reg_read(unsigned char addr);


//*****************************************************************************
unsigned char trx212_get_irq(void)
{
  unsigned char trxirq;
  trxirq = trx212_reg_read(RG_IRQ_MASK);	

  
  
#ifdef DEBUG  	
  DebugMsg("IRQ=(%x): ",trxirq);
  if(trxirq & TRX_IRQ_PLL_LOCK)DebugMsg("TRX_IRQ_PLL_LOCK, ");
  if(trxirq & TRX_IRQ_PLL_UNLOCK)DebugMsg("TRX_IRQ_PLL_UNLOCK, ");  
  if(trxirq & TRX_IRQ_RX_START)DebugMsg("TRX_IRQ_RX_START, ");
  if(trxirq & TRX_IRQ_TRX_END)DebugMsg("TRX_IRQ_TRX_END, ");	
  if(trxirq & TRX_IRQ_CCA_ED_DONE)DebugMsg("TRX_IRQ_CCA_ED_DONE, ");	
  if(trxirq & TRX_IRQ_AMI)DebugMsg("TRX_IRQ_AMI, ");	  
  if(trxirq & TRX_IRQ_UR)DebugMsg("TRX_IRQ_UR, ");	 
  if(trxirq & TRX_IRQ_BAT_LOW)DebugMsg("TRX_IRQ_BAT_LOW, ");
  DebugMsg("\n");
#endif

  return trxirq;
}
//*****************************************************************************
unsigned char trx212_get_state(void)
{
  unsigned char trxstat;
  
  trxstat = trx212_bit_read(SR_TRX_STATUS);

#ifdef DEBUG  
  DebugMsg("TRX212 Status=(%x):",trxstat);
  switch(trxstat) 
  {    
    case P_ON: 
    {
      DebugMsg("P_ON\n");        
      break;      
    }
    case BUSY_RX: 
    {
      DebugMsg("BUSY_RX\n");        
      break;      
    }
    case BUSY_TX: 
    {
      DebugMsg("BUSY_TX\n");        
      break;      
    }
    case RX_ON: 
    {
      DebugMsg("RX_ON\n");        
      break;      
    }
    case TRX_OFF: 
    {
      DebugMsg("TRX_OFF\n");        
      break;      
    }
    case PLL_ON: 
    {
      DebugMsg("PLL_ON\n");        
      break;      
    }
    case SLEEP: 
    {
      DebugMsg("SLEEP\n");        
      break;      
    }
    case BUSY_RX_AACK: 
    {
      DebugMsg("BUSY_RX_AACK\n");        
      break;      
    }
    case BUSY_TX_ARET: 
    {
      DebugMsg("BUSY_TX_ARET\n");        
      break;      
    }
    case RX_AACK_ON: 
    {
      DebugMsg("RX_AACK_ON\n");        
      break;      
    }
    case TX_ARET_ON: 
    {
      DebugMsg("TX_ARET_ON\n");        
      break;      
    }
    case RX_ON_NOCLK: 
    {
      DebugMsg("RX_ON_NOCLK\n");        
      break;      
    }
    case RX_AACK_ON_NOCLK: 
    {
      DebugMsg("RX_AACK_ON_NOCLK\n");        
      break;      
    }
    case BUSY_RX_AACK_NOCLK: 
    {
      DebugMsg("BUSY_RX_AACK_NOCLK\n");        
      break;      
    }
    default:
      DebugMsg("UNKNOWN_STATUS\n"); 
      break;  
  } 
#endif
  
  return trxstat;
}
//*****************************************************************************
//rf212 datasheet p.19
unsigned char trx212_reg_read(unsigned char addr)
{
    unsigned char rData;   
	
    spi_rx_clean();
    trx212_pinset_select(0);
    spi_send(TRX_CMD_RR | (TRX_CMD_RADDR_MASK & addr)); //send address
    //delay(t5);
    spi_busy_wait(); 
    spi_send(TRX_CMD_RR | (TRX_CMD_RADDR_MASK & addr)); //send dummy byte
	
    spi_busy_wait();	
    //delay(t5);   
    spi_getdata(&rData); // get PHY status
    spi_getdata(&rData); // get data
    trx212_pinset_select(1);    
    return rData;   
}
//*****************************************************************************

//rf212 datasheet p.19
void trx212_reg_write(unsigned char addr,unsigned char val)
{    		
    trx212_pinset_select(0);
    spi_send(TRX_CMD_RW | (TRX_CMD_RADDR_MASK & addr));
    spi_busy_wait();
    //delay(t5);	
    spi_send(val); 
    spi_busy_wait();
    //delay(t5);	
    trx212_pinset_select(1);  
}

//*****************************************************************************
void trx212_bit_write(unsigned char addr, unsigned char mask, unsigned char pos, unsigned char val)
{
    volatile unsigned char tmp;
    
    tmp = trx212_reg_read(addr);
    tmp &= ~mask;
    val <<= pos;
    val &=mask;
    val |= tmp;
    trx212_reg_write(addr, val);
}
 //*****************************************************************************
unsigned char trx212_bit_read(unsigned char addr,unsigned char mask, unsigned char pos)
{
    volatile unsigned char data;
    data = trx212_reg_read(addr);
    data &= mask;
    data >>= pos;
    return data;
}
//*****************************************************************************
tBoolean trx212_init(tSnifferSettings *SnifferSettings, unsigned long *ptrTimestamp)
{
  
  
    ptr212_TimeCounter=ptrTimestamp;
    ptr212_SnifferSettings=SnifferSettings;
    
	// TODO: ADD DISABLE CLKM
    
    trx212_pinset_select(0);
    
    delay(tTR1);
    trx212_pinset_reset(0);
    trx212_pinset_slptr(0);
    delay(t10);
    trx212_pinset_reset(1);
    
    trx212_pinset_select(1);
    
    trx212_reg_write(RG_IRQ_MASK, 0); 
    trx212_get_irq();  
    trx212_bit_write(SR_TRX_CMD, CMD_TRX_OFF);
    delay(tTR2);
    trx212_reg_write(RG_IRQ_MASK, TRX_IRQ_TRX_END);  
      
    if((trx212_get_state() == TRX_OFF) && (trx212_get_irq() & TRX_IRQ_TRX_END)) 
      return true;
    else  
      return false;
}

//*****************************************************************************
void trx212_print_ident(void)
{
  unsigned char pn, vn, mid0, mid1;
  
  pn = trx212_reg_read(RG_PART_NUM);
  vn = trx212_reg_read(RG_VERSION_NUM);
  mid0 = trx212_reg_read(RG_MAN_ID_0);
  mid1 = trx212_reg_read(RG_MAN_ID_1);
  DebugMsg("Part Num=%d, Version=%d, MAN_ID=%02x %02x\n",pn,vn,mid0,mid1);   
}

//*****************************************************************************
void trx212_set_filter_short_address(unsigned char addr[])
{
	// set short address filter
    trx212_reg_write(RG_SHORT_ADDR_0, addr[0]);
    trx212_reg_write(RG_SHORT_ADDR_1, addr[1]);	
}
//*****************************************************************************
void trx212_set_filter_panid(unsigned char panid[])
{
	// set PAN ID filter 
	trx212_reg_write(RG_PAN_ID_0, panid[0]);
        trx212_reg_write(RG_PAN_ID_1, panid[1]);	
}
//*****************************************************************************
void trx212_set_filter_mac_addr(unsigned char mac[])
{
    // set MAC address
    trx212_reg_write(RG_IEEE_ADDR_0, mac[0]);
    trx212_reg_write(RG_IEEE_ADDR_1, mac[1]);
    trx212_reg_write(RG_IEEE_ADDR_2, mac[2]);
    trx212_reg_write(RG_IEEE_ADDR_3, mac[3]);
    trx212_reg_write(RG_IEEE_ADDR_4, mac[4]);
    trx212_reg_write(RG_IEEE_ADDR_5, mac[5]);
    trx212_reg_write(RG_IEEE_ADDR_6, mac[6]);
    trx212_reg_write(RG_IEEE_ADDR_7, mac[7]);  	
}
//*****************************************************************************
// at86rf212 p.56 Promiscuos mode
void trx212_set_promiscuos_mode(void)
{
    // safe mode off
    trx212_bit_write(SR_RX_SAFE_MODE, 0x00);	
    // set controls the ACK behavior, depending on FCF frame version number
    trx212_bit_write(SR_AACK_FVN_MODE, 0x11);
    // set promiscuous mode
    trx212_bit_write(SR_AACK_PROM_MODE, 1);
    // set non PANID coordinator
    trx212_bit_write(SR_AACK_I_AM_COORD, 0);
    // deny non IEEE 802.15.4 frame reception
    trx212_bit_write(SR_AACK_UPLD_RES_FT, 0);
    // disable filter over non IEEE 802.15.4 packets
    trx212_bit_write(SR_AACK_FLTR_RES_FT, 0);
    // disable auto ACK
    trx212_bit_write(SR_AACK_DIS_ACK, 1);
}
//*****************************************************************************
tBoolean trx212_set_channel(unsigned char chn)
{
    //check if channel is 0..10
    if(chn > 10)
      return false;
    
    trx212_bit_write(SR_CHANNEL,chn);
    delay(tTR20);
    
    return true;
}
//*****************************************************************************
unsigned char trx212_get_channel(void)
{
 	unsigned char chn;
 	chn = trx212_bit_read(SR_CHANNEL);
 	DebugMsg("Channel=%d\n",chn);
 	return chn;
}
//*****************************************************************************
tBoolean trx212_setstate_TRX_OFF(void)
{
	unsigned char trxstat;
        
        
        trx212_bit_write(SR_TRX_CMD, CMD_TRX_OFF);
        delay(tTR7);
        /* AT86RF212::TRX_OFF */
        trxstat = trx212_bit_read(SR_TRX_STATUS);
        if (trxstat==TRX_OFF)
    	  return true;
        else 
    	  return false;
        
}
//*****************************************************************************
tBoolean trx212_setstate_RX_ON(void)
{
	unsigned char trxstat;
        trx212_bit_write(SR_TRX_CMD, CMD_RX_ON);
        delay(tTR6);
        trxstat = trx212_bit_read(SR_TRX_STATUS);
        if (trxstat==RX_ON)
    	  return true;
        else 
    	  return false;
}
//*****************************************************************************
void trx212_frame_read(unsigned char *length, unsigned char *data, unsigned char *lqi, tBoolean *crc_ok, unsigned char datasz)
{
    unsigned char i;
    unsigned short crc=0x0000;
    unsigned short p_crc;

    spi_rx_clean();
    trx212_pinset_select(0);

    /* start frame read */
    spi_send(TRX_CMD_FR);
    spi_busy_wait();

    /* read length */
    spi_send(0);
    spi_busy_wait();
    spi_getdata(length);
    spi_getdata(length);

    if (*length <= datasz)
    {
        i = *length;
        do
        {
            spi_send(0);   /* dummy out */
            spi_busy_wait();
            spi_getdata(data);
            if(i>2) // last 2B cointains CRC
 	    crc = update_crc(crc, *data);
            data++;
        }
        while(--i);
        
        p_crc=((unsigned short)*(--data)) << 8;
        p_crc|=((unsigned short)*(--data)) & 0x00FF;
        
        if(crc == p_crc) 
          *crc_ok = true; 
        else      
          *crc_ok = false;
		
        if (lqi!= NULL)
        {   		
            spi_send(0);   /* dummy out */
            spi_busy_wait();
            spi_getdata(lqi);
        }
    }
    else
    {
    	// drop frame 
        *length = 0x80 | *length;
    }
	
    
    trx212_pinset_select(1);
}

//*****************************************************************************
void trx212_irq(void)
{	
    TtrxPacket *packetPtr;
	
    if(trx212_reg_read(RG_IRQ_STATUS) & TRX_IRQ_TRX_END)
    {
      packetPtr = packetFifoAdd();
      if(packetPtr != NULL)
      {
        packetPtr->tmst_timer=(0xffffffff - TimerValueGet(TIMER1_BASE, TIMER_A));
        packetPtr->tmst_tcount=*ptr212_TimeCounter;
      	trx212_frame_read(&packetPtr->length, &packetPtr->data[0] , &packetPtr->lqi, &packetPtr->crcOk, IEEE_802154_MAX_PAYLOAD); 
	          
          if( (ptr212_SnifferSettings->filterCrc==true) && (packetPtr->crcOk==false))
          {               
                g_PacketDrop+=1;
                packetFifoAddFailed(packetPtr);
          }
          else
          { 		
                packetFifoAddDone(packetPtr); 
          }
      }
      else
      {
      	// full buffer
      	ledgreen_pinset(1);
      	packetFifoAddFailed(packetPtr);
      }
    }
}
//*****************************************************************************
//
// Function of ED measurement.
// 
//
//*****************************************************************************
tBoolean trx212_ED_Scan(unsigned char *data,unsigned char chn, tSnifferState state)
{
    int i;
    
    if(trx212_setstate_TRX_OFF()==false)
      return false;
    
    // Disable promiscuous mode
    trx212_bit_write(SR_AACK_PROM_MODE, 0);
    
   
    // Dummy read ED value on channel 0
    trx212_bit_write(SR_CHANNEL, 0); 
    delay(tTR20);   
    if(trx212_setstate_RX_ON()==false) 
      return false;    
        
    trx212_reg_write(RG_PHY_ED_LEVEL, 0); 
    delay(tTR26);      
    trx212_reg_read(RG_PHY_ED_LEVEL);
    if(trx212_setstate_TRX_OFF()==false)   
      return false;
    
    for(i=0;i<11;i++)
    {
          
        trx212_bit_write(SR_CHANNEL, i);
        delay(tTR20);        
        
        if(trx212_setstate_RX_ON()==false)
          return false;
  
        trx212_reg_write(RG_PHY_ED_LEVEL, 0);
        delay(tTR26);
        data[i] = trx212_reg_read(RG_PHY_ED_LEVEL); 
    
        if(trx212_setstate_TRX_OFF()==false) 
          return false;
    
    }
    
        
    // Enable promiscuous mode
    trx212_bit_write(SR_AACK_PROM_MODE, 1);
    
    trx212_bit_write(SR_CHANNEL, chn);
    delay(tTR20);
    
    
    if(state==RUNNING) 
      return (trx212_setstate_RX_ON());

    return true;
}


//*****************************************************************************
//
// Set channel, Rx sensitivity, PAN filter.
// Return: true is OK, false is error
//
//*****************************************************************************
tBoolean trx212_set_config(unsigned char chan,
                           tSnifferSensitivity sens,
                           unsigned char *panfilter,
                           tSnifferState state)
{
  
  unsigned char trxstat,rxpdtlvl;
  
  DebugMsg("TRX212 set_config: chan=%d, sens=%d, sens=0x%02x%02x, state=%d\n",
           chan, sens, panfilter[0], panfilter[1],state);
  
  if(state==ERROR)   //when is state=ERROR, than do nothing
    return false;
  
  trx212_bit_write(SR_TRX_CMD, CMD_TRX_OFF);
  delay(tTR7);
    /* AT86RF212::TRX_OFF */
  trxstat = trx212_bit_read(SR_TRX_STATUS);
  if(trxstat!=TRX_OFF)
    return false;
  
  
  trx212_bit_write(SR_CHANNEL,chan);
  
  if(trx212_bit_read(SR_CHANNEL)!=chan)
    return false;
  
  switch(sens)
  {
  case HIGH:
    rxpdtlvl=0x00;     //RSSI value not considered (RSSI_BASE_VAL= -91dBm)
    break;
    
  case MEDIUM:
    rxpdtlvl=0x05;    //   >RSSI_BASE_VAL + 4 * 3 , Value= >-79dBm
    break;
    
  case LOW:
    rxpdtlvl=0x0A;    //   >RSSI_BASE_VAL + 9 * 3 , Value= >-64dBm
    break;     
    
  case LOWEST:
    rxpdtlvl=0x0F;    //   >RSSI_BASE_VAL + 14 * 3 , Value= >-48dBm
    break;
  
  }
  trx212_bit_write(SR_RX_PDT_LEVEL, rxpdtlvl);
  
  if(trx212_bit_read(SR_RX_PDT_LEVEL)!=rxpdtlvl)
    return false;
  
  trx212_reg_write(RG_PAN_ID_0, panfilter[0]);
  if(trx212_reg_read(RG_PAN_ID_0)!=panfilter[0])
    return false;
  
  trx212_reg_write(RG_PAN_ID_1, panfilter[1]);
  if(trx212_reg_read(RG_PAN_ID_1)!=panfilter[1])
    return false;
  
  
  if(state==RUNNING)            
  {
    trx212_bit_write(SR_TRX_CMD, CMD_RX_ON);
    delay(tTR6);
    /* AT86RF212::RX_ON */
    trxstat = trx212_bit_read(SR_TRX_STATUS);
    if(trxstat!=RX_ON)
      return false;  
  }

  
  return true;

}

