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

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

// PROJECT INCLUDES

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

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


//#ifndef NULL
//#define NULL                    ((void *)0)
//#endif

//*****************************************************************************
//
//! \addtogroup example_list
//! <h1>Radio modul AT86RF231 (at86rf231)</h1>
//!
//! Proste nejaky kecy...
//
//*****************************************************************************


//*****************************************************************************
//
//! \page at86rf231_intro Radio modul
//!
//! Hooooodne moc omacky....
//!
//! The code for this module is contained in the <tt>at86rf231.c</tt> file,
//! with the <tt>at86rf231.h</tt> file containing definitions and functions
//! exported to the rest of the application.
//
//*****************************************************************************


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

unsigned long *ptr231_TimeCounter;
tSnifferSettings *ptr231_SnifferSettings;


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


unsigned char trx231_get_irq(void);
void trx231_bit_write(unsigned char addr, unsigned char mask, unsigned char pos, unsigned char val);
unsigned char trx231_bit_read(unsigned char addr,unsigned char mask, unsigned char pos);
void trx231_reg_write(unsigned char addr,unsigned char val);
void trx231_print_ident(void);
tBoolean trx231_setstate_RX_ON(void);
unsigned char trx231_reg_read(unsigned char addr);


//*****************************************************************************
unsigned char trx231_get_irq(void)
{
  unsigned char trxirq;
  trxirq = trx231_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 trx231_get_state(void)
{
  unsigned char trxstat;
  
  trxstat = trx231_bit_read(SR_TRX_STATUS);

#ifdef DEBUG  
  DebugMsg("TRX231 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;
}
//*****************************************************************************
//rf231 datasheet p.19
unsigned char trx231_reg_read(unsigned char addr)
{
    unsigned char rData;   
	
    spi_rx_clean();
    trx231_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
    trx231_pinset_select(1);    
    return rData;   
}
//*****************************************************************************

//rf231 datasheet p.19
void trx231_reg_write(unsigned char addr,unsigned char val)
{    		
    trx231_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);	
    trx231_pinset_select(1);  
}

//*****************************************************************************
void trx231_bit_write(unsigned char addr, unsigned char mask, unsigned char pos, unsigned char val)
{
    volatile unsigned char tmp;
    
    tmp = trx231_reg_read(addr);
    tmp &= ~mask;
    val <<= pos;
    val &=mask;
    val |= tmp;
    trx231_reg_write(addr, val);
}
 //*****************************************************************************
unsigned char trx231_bit_read(unsigned char addr,unsigned char mask, unsigned char pos)
{
    volatile unsigned char data;
    data = trx231_reg_read(addr);
    data &= mask;
    data >>= pos;
    return data;
}
//*****************************************************************************
tBoolean trx231_init(tSnifferSettings *SnifferSettings, unsigned long *ptrTimestamp)
{
  
  
    ptr231_TimeCounter=ptrTimestamp;
    ptr231_SnifferSettings=SnifferSettings;
    
	// TODO: ADD DISABLE CLKM
    trx231_pinset_select(0);
    
    delay(tTR1);
    trx231_pinset_reset(0);
    trx231_pinset_slptr(0);
    delay(t10);
    trx231_pinset_reset(1);
    
    trx231_pinset_select(1);
    
    trx231_reg_write(RG_IRQ_MASK, 0); 
    trx231_get_irq();  
    trx231_bit_write(SR_TRX_CMD, CMD_TRX_OFF);
    delay(tTR2);
    trx231_reg_write(RG_IRQ_MASK, TRX_IRQ_TRX_END);  
      
    if((trx231_get_state() == TRX_OFF) && (trx231_get_irq() & TRX_IRQ_TRX_END)) 
      return true;  
    else	
      return false;
}

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

//*****************************************************************************
void trx231_set_filter_short_address(unsigned char addr[])
{
	// set short address filter
    trx231_reg_write(RG_SHORT_ADDR_0, addr[0]);
    trx231_reg_write(RG_SHORT_ADDR_1, addr[1]);	
}
//*****************************************************************************
void trx231_set_filter_panid(unsigned char panid[])
{
	// set PAN ID filter 
	trx231_reg_write(RG_PAN_ID_0, panid[0]);
    trx231_reg_write(RG_PAN_ID_1, panid[1]);	
}
//*****************************************************************************
void trx231_set_filter_mac_addr(unsigned char mac[])
{
    // set MAC address
    trx231_reg_write(RG_IEEE_ADDR_0, mac[0]);
    trx231_reg_write(RG_IEEE_ADDR_1, mac[1]);
    trx231_reg_write(RG_IEEE_ADDR_2, mac[2]);
    trx231_reg_write(RG_IEEE_ADDR_3, mac[3]);
    trx231_reg_write(RG_IEEE_ADDR_4, mac[4]);
    trx231_reg_write(RG_IEEE_ADDR_5, mac[5]);
    trx231_reg_write(RG_IEEE_ADDR_6, mac[6]);
    trx231_reg_write(RG_IEEE_ADDR_7, mac[7]);  	
}
//*****************************************************************************
// at86rf231 p.56 Promiscuos mode
void trx231_set_promiscuos_mode(void)
{
	// safe mode off
   	trx231_bit_write(SR_RX_SAFE_MODE, 0x00);	
    // set controls the ACK behavior, depending on FCF frame version number
    trx231_bit_write(SR_AACK_FVN_MODE, 0x11);
    // set promiscuous mode
    trx231_bit_write(SR_AACK_PROM_MODE, 1);
    // set non PANID coordinator
    trx231_bit_write(SR_AACK_I_AM_COORD, 0);
    // deny non IEEE 802.15.4 frame reception
    trx231_bit_write(SR_AACK_UPLD_RES_FT, 0);
    // disable filter over non IEEE 802.15.4 packets
    trx231_bit_write(SR_AACK_FLTR_RES_FT, 0);
    // disable auto ACK
    trx231_bit_write(SR_AACK_DIS_ACK, 1);
}
//*****************************************************************************
tBoolean trx231_set_channel(unsigned char chn)
{
  
    if((chn < 11) && (chn > 26))
      return false;
      
    trx231_bit_write(SR_CHANNEL,chn);
    delay(tTR20);
    
    return true;
}
//*****************************************************************************
unsigned char trx231_get_channel(void)
{
 	unsigned char chn;
 	chn = trx231_bit_read(SR_CHANNEL);
 	DebugMsg("Channel=%d\n",chn);
 	return chn;
}
//*****************************************************************************
tBoolean trx231_setstate_TRX_OFF(void)
{
	unsigned char trxstat;
        
        
        trx231_bit_write(SR_TRX_CMD, CMD_TRX_OFF);
        delay(tTR7);
        /* AT86RF231::TRX_OFF */
        trxstat = trx231_bit_read(SR_TRX_STATUS);
        if (trxstat==TRX_OFF)
    	  return true;
        else 
    	  return false;
        
}
//*****************************************************************************
tBoolean trx231_setstate_RX_ON(void)
{
	unsigned char trxstat;
        trx231_bit_write(SR_TRX_CMD, CMD_RX_ON);
        delay(tTR6);
        trxstat = trx231_bit_read(SR_TRX_STATUS);
        if (trxstat==RX_ON)
    	  return true;
        else 
    	  return false;
}
//*****************************************************************************
void trx231_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();
    trx231_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;
    }
	trx231_pinset_select(1);
}

//*****************************************************************************
void trx231_irq(void)
{	
    TtrxPacket *packetPtr;
	
    if(trx231_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=*ptr231_TimeCounter;
      	trx231_frame_read(&packetPtr->length, &packetPtr->data[0] , &packetPtr->lqi, &packetPtr->crcOk, IEEE_802154_MAX_PAYLOAD); 
          if( (ptr231_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 trx231_ED_Scan(unsigned char *data,unsigned char chn, tSnifferState state)
{
    int i;
    
    if(trx231_setstate_TRX_OFF()==false)
      return false;
    
     // Disable promiscuous mode
    trx231_bit_write(SR_AACK_PROM_MODE, 0);
                        
    for(i=11;i<27;i++)
    {
          
        trx231_bit_write(SR_CHANNEL, i);
        delay(tTR20);
            
        if(trx231_setstate_RX_ON()==false) 
          return false;
        
        trx231_reg_write(RG_PHY_ED_LEVEL, 0);
        delay(tTR26);
        data[i] = trx231_reg_read(RG_PHY_ED_LEVEL);
             
        if(trx231_setstate_TRX_OFF()==false)   
          return false;
    }
   
    
    // Enable promiscuous mode
    trx231_bit_write(SR_AACK_PROM_MODE, 1);
      
    trx231_bit_write(SR_CHANNEL, chn);
    delay(tTR20);    
    
    if(state==RUNNING) 
      return (trx231_setstate_RX_ON());

    return true;
}
//*****************************************************************************
//
// Set channel, Rx sensitivity, PAN filter.
// Return: true is OK, false is error
//
//*****************************************************************************
tBoolean trx231_set_config(unsigned char chan,
                           tSnifferSensitivity sens,
                           unsigned char *panfilter,
                           tSnifferState state)
{
  
  unsigned char trxstat,rxpdtlvl;
  
  DebugMsg("TRX231 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;
  
  trx231_bit_write(SR_TRX_CMD, CMD_TRX_OFF);
  delay(tTR7);
    /* AT86RF231::TRX_OFF */
  trxstat = trx231_bit_read(SR_TRX_STATUS);
  if(trxstat!=TRX_OFF)
    return false;
  
  
  trx231_bit_write(SR_CHANNEL,chan);
  
  if(trx231_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;
  
  }
  trx231_bit_write(SR_RX_PDT_LEVEL, rxpdtlvl);
  
  if(trx231_bit_read(SR_RX_PDT_LEVEL)!=rxpdtlvl)
    return false;
    
  trx231_reg_write(RG_PAN_ID_0, panfilter[0]);
  if(trx231_reg_read(RG_PAN_ID_0)!=panfilter[0])
    return false;
  
  trx231_reg_write(RG_PAN_ID_1, panfilter[1]);
  if(trx231_reg_read(RG_PAN_ID_1)!=panfilter[1])
    return false;
  
  
  if(state==RUNNING)            
  {
    trx231_bit_write(SR_TRX_CMD, CMD_RX_ON);
    delay(tTR6);
    /* AT86RF231::RX_ON */
    trxstat = trx231_bit_read(SR_TRX_STATUS);
    if(trxstat!=RX_ON)
      return false;  
  }

  
  return true;

}

