/* hr.c	- hello radio for MRF49XA	 -*- Mode: C -*-
 *
 * Rehmi Post 
 * CBA MIT 11/28/10
 *
 * (c) Massachusetts Institute of Technology 2010
 * Permission granted for experimental and personal use;
 * license for commercial sale available from MIT.
 *
 * History:
 * 20101128	Created this file; initial target is ATmega328P.
 *
 */

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

//#define DEBUG

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

#include 
#include 
#include 
#include 

#define TRUE (0==0)
#define FALSE (0!=0)

typedef unsigned char		BOOL;			// 8-bit unsigned
typedef unsigned char		BYTE;			// 8-bit unsigned
typedef unsigned short int	WORD;			// 16-bit unsigned
typedef unsigned long		DWORD;			// 32-bit unsigned
typedef signed char		CHAR;			// 8-bit signed
typedef signed short int	SHORT;			// 16-bit signed
typedef signed long		LONG;			// 32-bit signed

typedef unsigned char		u08;			// 8-bit unsigned
typedef unsigned short int	u16;			// 16-bit unsigned
typedef unsigned long		u32;			// 32-bit unsigned
typedef signed char		s08;			// 8-bit signed
typedef signed short int	s16;			// 16-bit signed
typedef signed long		s32;			// 32-bit signed


/****************************************************************/
/* hal_spi.h */

#define DDR_SPI		DDRB
#define DD_SCK		RF_SCK
#define DD_MOSI		RF_MOSI
#define DD_MISO		RF_MISO

typedef enum {
  SPI_MSB_FIRST = 0, SPI_LSB_FIRST = 1
} SPI_data_order;

inline void SPI_Init (void);
inline unsigned char  SPI_Transfer_Byte (unsigned char d);

/****************************************************************/
/* hal_usart.h */

extern void USART_Init(void);
extern void USART_SetBaudRate(unsigned long baud);
extern void USART_Transmit(unsigned char data);
extern int USART_Receive_Ready (void);
extern int USART_Receive (unsigned char *data);

#define uartSendByte 	USART_Transmit
#define uartReceiveByte USART_Receive
#define uartInit	USART_Init
#define uartSetBaudRate USART_SetBaudRate

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

#ifdef HELLO_RADIO_BREADBOARD
#include "hal_breadboard.h"
#endif
#ifdef HELL_O_RADIO_13
#include "hal_hell-o-radio-13.h"
#endif
#if defined(HELLO_RADIO_016) | defined(FABRADIO0_16)
#include "hal_hello_radio-016.h"
#endif

#define TXLED_ON	LED1_HI
#define TXLED_OFF	LED1_LO
#define RXLED_ON	LED0_HI
#define RXLED_OFF	LED0_LO

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

//#define BAND_915
//#define BAND_868 
#define BAND_434
    
#define XTAL_LD_CAP 0x0003		// crystal load 10pF

#define PAYLOAD_LEN 126		    	// maximum payload size
#define PACKET_LEN  PAYLOAD_LEN + 2	// maximum packet length with 2 byte CRC
#define PAYLOAD_MAX PACKET_LEN
    
#if 1
#if  defined(BAND_434)
#define FREQ_Band        0x0010		// 434MHz
#define _CFSREG           0xA640		// Center Frequency: 434MHz
#elif  defined(BAND_868)
#define FREQ_Band        0x0020		// 868MHz
#define _CFSREG           0xA640		// Center Frequency: 868MHz
#elif  defined(BAND_915)
#define FREQ_Band        0x0030	       	// 915MHz
#define _CFSREG           0xA7D0	       	// Center Frequency: 915.000MHz
#else
#error  "At least one frequency band must be defined"
#endif
#endif

#define _GENCREG                 (0x8000 | XTAL_LD_CAP |FREQ_Band)

#define AFCCREG                 0xC4F7
#define TXCREG                  0x9850	// deviation 90kHz, output power 7dBm-0dB
#define TXBREG                  0xB800
#define _RXCREG                  0x9481	// BW 200KHz, LNA gain 0dB, RSSI -97dBm
#define FIFORSTREG              0xCA81
#define _DRVSREG                 0xC623	// bit rate = 9579 / sec
#define PMCREG                  0x8201

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

// transmit and receive packet buffers
//volatile BOOL       	hasPacket = FALSE;
//volatile BYTE       	RxPacket[PACKET_LEN];
//volatile BYTE       	RxPacketLen;
#if 0
BYTE 	       	TxPacket[PACKET_LEN] = {
  0xAA, 0xAA,
  0x55, 0x55,
  0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
  0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
  0x55, 0x55,
  0xAA, 0xAA
};
#endif

/****************************************************************/
/* app_sniffer.h */

#define NUM_RX_BUFS       4

BYTE FreqBand;
BYTE DataRate;
BYTE Deviation;
BYTE Channel;

WORD GENCREG = _GENCREG;
WORD DRVSREG = _DRVSREG;
WORD RXCREG  = _RXCREG;
WORD CFSREG  = _CFSREG;

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

/****************************************************************/
/* hal_usart.c */

void USART_Init(void)
{ 
  /* Enable receiver and transmitter */ 
  UCSR0B = (1<>8);
  UBRR0L = (unsigned char)ubrr;
}

void USART_Transmit(unsigned char data) 
{ 
  /* Wait for empty transmit buffer */ 
  while ( !( UCSR0A & (1<> i)) != 0) {
      RF_MOSI_HI ();
    } else {
      RF_MOSI_LO ();
    }
    data = (data << 1) | (RF_MISO_IN() ? 1 : 0);
#ifdef USE_HARDWARE_SPI
    RF_SCKm_ZZ();
#endif
    RF_SCK_HI ();
    RF_SCK_LO ();
  }  
  RF_MOSI_LO ();
  return data;
#endif 
}

inline unsigned char SPI_Transfer_Word (unsigned short w)
{
  unsigned short v;

#ifdef USE_HARDWARE_SPI
  SPDR = w >> 8;			  /* start transfer of high byte to SPI */
  while(!(SPSR & (1<> 8) >> 8;
  v |= SPI_Transfer_Byte (w & 255) & 255;
#endif

  return v;				  /* return stored word */
}

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

void RF_Interface_Init(void)
{
  // set I/O ports
  RF_nCS_HI ();
  RF_MOSI_HI ();
  RF_MISO_ZZ ();
#ifdef RF_SCKm_ZZ
  RF_SCKm_ZZ ();
#endif
  RF_SCK_HI ();

#ifdef RF_FINT_ZZ
  RF_FINT_ZZ ();
#endif
  RF_nFSEL_ZZ ();
#ifdef RF_INT_ZZ
  RF_INT_ZZ ();
#endif
  RF_nIRQ_ZZ ();

  RF_nRST_LO();
  _delay_us(500);
  RF_nRST_HI ();
  _delay_us(500);
  RF_nRST_PU();

  BUT0_PU();

  LED0_HI ();
  _delay_ms (100);
  LED0_LO ();
  LED1_HI ();
  _delay_ms (100);
  LED1_LO ();
 
  // XXX - TODO: enable RF interrupts
}


void RF_Set_Register(WORD setting)
{
  RF_nCS_LO();				/* select MRF49XA SPI */
  SPI_Transfer_Word (setting);
  RF_nCS_HI();				/* deselect MRF49XA SPI */
}

void RF_Int_Disable (void)
{
  // XXX
}

void RF_Int_Enable (void)
{
  // XXX
}

//#define DEBUG
void MRF49XA_Init (void)
{
#ifdef DEBUG
  printf ("entering MRF49XA_Init ()\n");
#endif

  // configuring the MRF49XA radio
  RF_Int_Disable ();

  RF_Set_Register(FIFORSTREG);
#ifdef DEBUG
  printf ("FIFORSTREG\n");
#endif

  RF_Set_Register(FIFORSTREG | 0x0002);       // enable synchron latch
#ifdef DEBUG
  printf ("FIFORSTREG | 0x0002\n");
#endif

  RF_Set_Register(GENCREG);
#ifdef DEBUG
  printf ("GENCREG\n");
#endif

  RF_Set_Register(AFCCREG);
#ifdef DEBUG
  printf ("AFCCREG\n");
#endif

  RF_Set_Register(CFSREG);
#ifdef DEBUG
  printf ("CFSREG\n");
#endif

  RF_Set_Register(DRVSREG);
#ifdef DEBUG
  printf ("DRVSREG\n");
#endif

  RF_Set_Register(PMCREG);
#ifdef DEBUG
  printf ("PMCREG\n");
#endif

  RF_Set_Register(RXCREG);
#ifdef DEBUG
  printf ("RXCREG\n");
#endif

  RF_Set_Register(TXCREG);
#ifdef DEBUG
  printf ("TXCREG\n");
#endif

  // antenna tuning on startup
#ifdef DEBUG
  printf ("turning on transmitter ()\n");
#endif
  RF_Set_Register(PMCREG | 0x0020);	    // turn on the transmitter
  _delay_ms(5);			    // wait for oscillator to stablize
  // end of antenna tuning
  RF_Set_Register(PMCREG | 0x0080); 	    // turn off transmitter, turn on receiver
#ifdef DEBUG
  printf ("turned off transmitter, turned on receiver\n");
#endif

  RF_Set_Register(GENCREG | 0x0040);	// enable the FIFO
  RF_Set_Register(FIFORSTREG);
  RF_Set_Register(FIFORSTREG | 0x0002); 	// enable synchron latch
  RF_Set_Register(0x0000);		// read status byte (read ITs)
    
  RF_Int_Enable ();
}
#undef DEBUG

void Cmd_RF_buzz (void)
{
  int i;

  RF_Set_Register(FIFORSTREG);
  RF_Set_Register(FIFORSTREG | 0x0002);       // enable synchron latch
  RF_Set_Register(GENCREG);
  RF_Set_Register(AFCCREG);
  RF_Set_Register(CFSREG);
  RF_Set_Register(DRVSREG);
  RF_Set_Register(PMCREG);
  RF_Set_Register(RXCREG);
  RF_Set_Register(TXCREG);
  for (i = 0; i < 20; i++) {
    RF_Set_Register(PMCREG | 0x0020);	    // turn on the transmitter
    _delay_ms(1);
    RF_Set_Register(PMCREG | 0x0080); 	    // turn off transmitter
    _delay_ms(1);
  }
}


/****************************************************************/
/* RF_packet.c */

#include 

WORD CRC16(BYTE *ptr, BYTE count)
{
  WORD crc;
    
  crc = 0;

  while(count-- > 0 ) {
    crc = _crc_xmodem_update (crc, *ptr++);
  }
  
  return crc;
}

void MRF_Send_Packet(BYTE *packet, BYTE len)
{
    BYTE ptr; // send data packet?
    BYTE synCount;
    WORD crc = 0;
    
#define SPI_Transfer_Byte_CRC(b) {	\
      BYTE d=(b);			\
      crc =_crc_xmodem_update (crc, d);	\
      SPI_Transfer_Byte(d);		\
}

    TXLED_ON();
    
    if (len > PACKET_LEN) {
        len = PACKET_LEN;
    }

    //Start_Transmitting:
    RF_Int_Disable ();

    // Turn off receiver, enable the TX register
    RF_Set_Register(PMCREG);
    RF_Set_Register(GENCREG | 0x0080);
    
    // enable transmitter
    RF_Set_Register(PMCREG | 0x0020);


    RF_nCS_LO ();			// select MRF49XA SPI */

    SPI_Transfer_Byte(0xB8);                 // FIFO write
    SPI_Transfer_Byte(0xAA);                 // 3rd preamble
    
    for (ptr = 0, synCount = 0; ptr < len+2; ) {    // 2 CRC bytes follow packet
      if( RF_MISO_IN() ) {
	if( ptr == 0 && synCount < 3 ) {
	  switch(synCount) {
	  case 0:
	    SPI_Transfer_Byte(0x2D);
	    break;
	  case 1:
	    SPI_Transfer_Byte(0xD4);
	    break;
	  case 2:
	    crc = 0;
	    SPI_Transfer_Byte_CRC(len+2);
	    break;
	  default:
	    break;
	  }
	  synCount++;
	} else {
	  if (ptr < len) {
	    SPI_Transfer_Byte_CRC(packet[ptr]);
	  } else if (ptr == len) {
	    SPI_Transfer_Byte(crc >> 8);
	  } else if (ptr == len+1) {
	    SPI_Transfer_Byte(crc &  0xff);
	  }
	  ptr++;
	}
      }
    }

    RF_nCS_HI ();
    
    // Turn off the transmitter, disable the Tx register
    RF_Set_Register(PMCREG | 0x0080);
    RF_Set_Register(GENCREG | 0x0040 );
    RF_Set_Register(FIFORSTREG | 0x0002);
    RF_Int_Enable ();
         
    TXLED_OFF ();
}

/****************************************************************/
/* RF_interrupts.c */

BOOL RF_Int_Enabled (void)
{
  return TRUE;
}


BOOL RF_Int_Flag (void)
{
  return TRUE;
}

void RF_Int_Clear (void)
{
}

#if 0
volatile BOOL RxPacketValid[NUM_RX_BUFS];
BYTE RxPacket[NUM_RX_BUFS][PACKET_LEN]; 
volatile BYTE RxPacketLen[NUM_RX_BUFS]; 
WORD totalReceived = 0;

int ISR(INT0_vect)
{
  if (RF_Int_Enabled() && RF_Int_Flag()) {
    RF_nCS_LO ();
    if (RF_MISO_IN ()) {
      BYTE RxPacketPtr;
      BYTE tmpPacketLen;
      WORD counter;

      // There is data in RX FIFO
      RF_nCS_HI ();
      RF_nFSEL_LO ();                   // FIFO selected
      
      tmpPacketLen = SPI_Transfer_Byte(0);
                     
      if (tmpPacketLen >= PAYLOAD_LEN || tmpPacketLen == 0 || hasPacket) {
      IGNORE_HERE:            
	RF_nFSEL_HI();                          // bad packet len received
	RF_Set_Register(PMCREG);                // turn off the transmitter and receiver
	RF_Set_Register(FIFORSTREG);            // reset FIFO
	RF_Set_Register(GENCREG);               // disable FIFO, TX_latch
	RF_Set_Register(GENCREG | 0x0040);      // enable FIFO
	RF_Set_Register(PMCREG | 0x0080);       // turn on receiver
	RF_Set_Register(FIFORSTREG | 0x0002);   // FIFO synchron latch re-enabled
	goto RETURN_HERE;
      }
            
      RxPacketLen = tmpPacketLen;
      RXLED_ON();
      RF_nFSEL_HI();
            
      RxPacketPtr = 0;
      counter = 0;
            
      while(1) {
	  if (counter++ == 0xFFFF) {
	      goto IGNORE_HERE;
	  } else if (RF_FINT_IN()) {
	      RF_nFSEL_LO ();
	      counter = 0;
	      RxPacket[RxPacketPtr++] = SPI_Transfer_Byte(0);
	      
	      if (RxPacketPtr >= RxPacketLen) {
		  WORD received_crc;
		  WORD calculated_crc;
		  BYTE i;
                        
		  RF_nFSEL_HI();
		  RF_Set_Register(FIFORSTREG);
		  RXLED_OFF();
                        
		  RxPacketLen -= 2;       // do not count CRC
		  received_crc = ((WORD)RxPacket[RxPacketLen+1]) 
		    + (((WORD)RxPacket[RxPacketLen]) << 8);
		  calculated_crc = CRC16((BYTE *)RxPacket, RxPacketLen);

		  if (received_crc != calculated_crc) {
		      RxPacketPtr = 0;
		      RxPacketLen = 0;
		      // FIFO synchron latch re-enable 
		      RF_Set_Register(FIFORSTREG | 0x0002);
		      goto IGNORE_HERE;
		  }

		  RF_Set_Register(FIFORSTREG | 0x0002);
		  hasPacket = TRUE;

		  goto RETURN_HERE;
	      }
	      RF_nFSEL_HI();
	  }
      }
    } else {            // read the rest of the interrupts
	SPI_Transfer_Byte(0);
  	RF_nCS_HI ();
    }
          
  RETURN_HERE:        
    RF_Int_Clear ();
  }
}
#endif

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

#define NODATA		0
#define DATA_RECEIVED	-1
#define PACKET_RECEIVED 1

int MRF_Receive_Packet (BYTE *data, BYTE *length)
{
  static unsigned char len = 0;
  static unsigned char nrbytes = 0;
  unsigned char bl;

  RF_nCS_LO();		// chip select low

  if (RF_MISO_IN()) {		// in case of FINT then read out
    RF_nCS_HI();
    RF_nFSEL_LO();
    if(len) {	       // is this the first byte? go on if not
      // number of bytes in payload is the first byte
      data[(nrbytes++)] = SPI_Transfer_Byte(0);

      if (nrbytes >= len) {    // end of packet
	RF_Set_Register(FIFORSTREG); // reset FIFO	
	RF_nFSEL_HI();		     // whole packet received
	*length = nrbytes;
	nrbytes=0;
	len =0;
	return PACKET_RECEIVED;
      }
    } else {			// the first byte received
      bl=SPI_Transfer_Byte(0);
      // check if correct number of bytes in payload
      if((bl>0) && (bl>4)]);
  putchar (hex[0xf & (b)   ]);
}

#define BUTTON0_PRESSED() (!BUT0_IN())

//#define DEBUG

void Cmd_TXRX_button_loop (void)
{
  BYTE c;
  BYTE rx_len, tx_len = 0, i;
  BOOL receiving = FALSE;
  BOOL building_packet = FALSE;
  BYTE button_down = 10;
  WORD crc = 0, pcrc;

  while (1) {
    if (!receiving) {
      if (BUTTON0_PRESSED()) {
	button_down = 10;
	MRF_Send_Packet ((BYTE *)"R^*|B1", 6);
      } else if (button_down > 0) {
	button_down--;
	MRF_Send_Packet ((BYTE *)"R^*|B0", 6);
      }
    }

    switch (MRF_Receive_Packet (rx_packet, &rx_len)) {
    case NODATA:
      break;

    case DATA_RECEIVED:
      RXLED_ON();
      receiving = TRUE;
      break;

    case PACKET_RECEIVED:
      RXLED_OFF();
      receiving = FALSE;

      for (i = 0; i < rx_len - 2; i++) {
	crc =0;
	crc = _crc_xmodem_update (crc, rx_packet[i]);
      }

      pcrc = rx_packet[rx_len]<<8 | rx_packet[rx_len+1];

      if (TRUE || crc == pcrc) {
#ifdef DEBUG
	printf ("[%02x]", rx_len);
#endif
//	putchar ('{');                                          // delete this charactor
#ifdef DEBUG
	for (i = 0; i < rx_len; i++) {
	  puthex (rx_packet[i]);
	}
#else
	for (i = 0; i < rx_len - 2; i++) {
	  putchar (rx_packet[i]);
	}
#endif
//	putchar ('}');                                          // delete this charactor                                      
      }
      RF_Set_Register(FIFORSTREG | 0x0002); // FIFO sync latch re-enable
#ifdef DEBUG
      printf ("<%04x,%04x>", pcrc, crc);
#endif
//      putchar ('\n');                                     // delete this charactor
      break;

    default:
      break;
    }

    if (USART_Receive_Ready()) {
      USART_Receive (&c);
      switch (c) {
      case '{':
	tx_len = 0;
	building_packet = TRUE;
	break;

      case '}':
	MRF_Send_Packet (tx_packet, tx_len);
	break;

      case '\033':
      case 'x':
      case 'q':
	if (!building_packet)
	  return;
      default:
	if (tx_len < PACKET_LEN) {
	  tx_packet[tx_len++] = c;
	}
	break;
      }
    }
  }
}

void Cmd_TX_loop (void)
{
  BYTE dummy;

  while (!USART_Receive_Ready()) {
    MRF_Send_Packet ((BYTE *)"Hello, radio!", 13);
    _delay_ms (100);
  }
  USART_Receive (&dummy);
  return;
}

BOOL running = TRUE;
void Cmd_Interpreter (void)
{
  BYTE c;

  while (running) {
    printf ("> ");
    while (!USART_Receive_Ready());
    if (USART_Receive (&c)) {
      printf ("%c\n", c);
      switch (c) {
      case '?':
	printf ("?\tprint this help message\n");
	printf ("b\tbuzz on RF (500 Hz OOK for 20 cycles\n");
	printf ("r\treceive and print packets until keypress\n");
	printf ("t\ttransmit packets until keypress\n");
	printf ("k\tremote keyfob demo loop until keypress\n");
	break;
      case 't':
	Cmd_TX_loop ();
	break;
      case 'r':
	Cmd_RX_loop ();
	break;
      case 'b':
	Cmd_RF_buzz ();
	break;
      case 'k':
	Cmd_TXRX_button_loop ();
	break;
      default:
	printf ("unknown command\n");
	break;
      }
    }
  }
}

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

char version[] = "hello_radio.c - Hello Radio v0.2 " __DATE__ " " __TIME__;

int main(void)
{
  BYTE c;

  cli();

  BUT0_PU ();
  LED1_HI ();
  //  while (BUT0_IN());
  LED1_LO ();

  USART_Init ();
  USART_SetBaudRate (9600L);
  stdout = stdout_usart;
  //printf ("\n*** %s ***\n", version); // Not show, because I only communicate one microcomtroller.

  // printf ("initializing SPI...");
  SPI_Init ();
  // printf ("\n");

  // printf ("initializing RF interface...");
  RF_Interface_Init ();
  // printf ("\n");

  // printf ("MRF49XA_init()...");
  MRF49XA_Init ();
  // printf ("\n");

  //while (USART_Receive (&c));
  
  // printf ("Cmd_TXRX_button_loop()...");
  //MRF_Send_Packet ((BYTE *)"", 0);
  // printf ("\n");
    
  //Cmd_RX_loop ();
    
  Cmd_TXRX_button_loop ();

  printf ("*** entering command interpreter; type '?' for help\n");
  Cmd_Interpreter ();

  return 0;
}