/* 
Modified 2/21/12 by H.-J. Berndt for ATmega168 5V Arduino in Europe
experimental only <hjberndt.de>

Source from 
Arduino Si4735 Library
Written by Ryan Owens for SparkFun Electronics - 5/17/11
Altered by Wagner Sartori Junior <wsartori@gmail.com> on 09/13/11
Altered by Jon Carrier <jjcarrier@gmail.com>


This library is for use with the SparkFun Si4735 Shield
Released under the 'Buy Me a Beer' license
(If we ever meet, you buy me a beer)

See the example sketches to learn how to use the library in your code.

For the reading commands work, you'll need to add a diode between GPO1 and pin 12. It's an easy task there're some pictures on my wiki page.
*/
#include "Si4735.h"
#include "WProgram.h"
#include "string.h"

Si4735::Si4735()
{//Do Nothing
}

void Si4735::begin(char mode)
{_mode = mode;
 _currentVolume = 27;
//resetting the Si4735 and configuring the comm. protocol to SPI
 pinMode(POWER_PIN, OUTPUT);
 pinMode(RADIO_RESET_PIN, OUTPUT);
 pinMode(DATAIN, OUTPUT); 
 pinMode(INT_PIN, OUTPUT); 
//Sequence the power to the Si4735
 digitalWrite(RADIO_RESET_PIN, LOW);  
 digitalWrite(POWER_PIN, LOW);
//Configure the device for SPI communication
 digitalWrite(DATAIN, HIGH);
 digitalWrite(INT_PIN, HIGH);
 delay(1);
 digitalWrite(POWER_PIN, HIGH);
 delay(100);
 digitalWrite(RADIO_RESET_PIN, HIGH);
 delay(100);
 //Now configure the I/O pins properly
 pinMode(DATAOUT, OUTPUT);
 pinMode(DATAIN, INPUT);
 pinMode(SPICLOCK,OUTPUT);
 pinMode(SS,OUTPUT); 
 pinMode(INT_PIN, INPUT); 
 digitalWrite(SS, HIGH);	
 //Configure the SPI hardware
 SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);// !!
 // SPCR = (1<<SPE)|(1<<MSTR);	//Enable SPI HW, Master Mode	
 //Send the POWER_UP command
 sprintf(command, "%c%c%c", 0x01, _mode == FM ? 0x50 : 0x51, 0x05);
 sendCommand(command, 3); delay(200);
 //Set the volume to the current value.
 SetProp(RX_VOLUME,_currentVolume); delay(1);
 //Disable Mute
 SetProp(RX_HARD_MUTE,0x0000); delay(1);
 //Enable RDS
 SetProp(RDS_CONFIG,0xAA01);delay(1);
 //Set the seek band limits for the desired mode in kHz
 switch(_mode)
 {case SW:SetProp(AM_SEEK_BAND_BOTTOM,5800); //delay(1);
		  SetProp(AM_SEEK_BAND_TOP,23000); //delay(1);
		  break;
  case LW:SetProp(AM_SEEK_BAND_BOTTOM,153); //delay(1);
  		  SetProp(AM_SEEK_BAND_TOP,513); //delay(1);
   		  break;
  case AM:SetProp(AM_SEEK_BAND_BOTTOM,522); //delay(1);
  		  SetProp(AM_SEEK_BAND_TOP,1620); //delay(1);
   		  break;
  default:break;
 }
}

bool Si4735::tuneFrequency(int f)
{sprintf(command,"%c%c%c%c",_mode == FM ? 0x20 : 0x40, 0x00, f >> 8, f & 0x00FF);
 sendCommand(command, 4); delay(10);
 return true;
}

word Si4735::getFrequency(bool &valid)
{byte response [16];
 sprintf(command, "%c%c", _mode == FM ? 0x22 : 0x42, 0x00);	
 sendCommand(command, 2);
 getResponse(response);	
 valid=(response[0]&1)==1;
 return 256*response[2]+response[3];
}

bool Si4735::seek(bool up)
{switch(_mode)
 {case FM:	sprintf(command, "%c%c", 0x21, up?0x0C:0x04);
		sendCommand(command, 2);
		break;
  case AM:	case SW:
  case LW: sprintf(command, "%c%c%c%c%c%c", 0x41, up?0x0C:0x04, 0x00, 0x00, 0x00, 0x00);
		sendCommand(command, 6);
		break;
  default:	return false;
 }
 delay(1);
 return true;
}

void Si4735::volume(bool up)
{if(up && _currentVolume>=63)return;
 else if(_currentVolume<1)return;
 if(up)_currentVolume++;else _currentVolume--;
 SetProp(RX_VOLUME,_currentVolume);
}

void Si4735::mute(bool m)
{SetProp(RX_HARD_MUTE,m ? 3:0);
}

byte Si4735::getStatus(void)
{byte response;
 digitalWrite(SS, LOW);
 delay(1);
 spiTransfer(0xA0);  //Set up to read a single byte
 delay(1);
 response = spiTransfer(0x00);  //Get the commands response
 digitalWrite(SS, HIGH);
 return response;
}

void Si4735::getResponse(byte *response)
{digitalWrite(SS, LOW);
 delay(1);
 spiTransfer(0xE0);  //Set up to read the long response
 delay(1);
 for(int i=0; i<16; i++)*response++ = spiTransfer(0x00);  //Assign the response to the string.
 digitalWrite(SS, HIGH);
}

void Si4735::end(void)
{sprintf(command, "%c", 0x11);
 sendCommand(command, 1); delay(100);
}

//This function gets the Received Signal Quality Information
void Si4735::getRSQ(byte *RSSI, byte *SNR)
{byte response [16];
 sprintf(command, "%c%c", _mode == FM ? 0x23 : 0x43, 0x00);
 sendCommand(command, 2);
 getResponse(response);	
 *RSSI=response[4];
 *SNR=response[5];
}
//Command 0x13. GET_PROPERTY
#define GET_PROPERTY 0x13
unsigned char Si4735::getVolume(void)
{byte response [16];
 sprintf(command,"%c%c%c%c",GET_PROPERTY,0x00,0x40,0x00);
 sendCommand(command, 4); delay(1);
 getResponse(response);
 return response[3];
 }
#define SET_PROPERTY 0x12 //RES H/L H/L
void Si4735::setDeemphasis(bool eu)
{SetProp(0x1100, eu ? 0x01:0x02);
}
void Si4735::setMono(bool mono)
{SetProp(0x1105, mono ? 0x7F:0x31);
}
void Si4735::setAM9(bool AM9)
{SetProp(0x3402, AM9 ? 0x09:0x05);
}
//Property 0x3403. AM_SEEK_TUNE_SNR_THRESHOLD
void Si4735::setAMtreshold(byte t)
{ SetProp(0x3403,t);
}

//Work in progress ...
WORD Si4735::readRDS(char *sender,char *text) //Page 77
{static char Station[9]="Radiuino";
 static char RadioText[65]="RadioTXT";
 static word PID; char time_str[20]="fail";
 byte i,R[16];// Response is 12 bytes
 WORD A,B,C,D; //RDS Blocks
 WORD PTY,TP,GT,AB,TA,MS,C12,T16;
 sprintf(command, "%c%c", 0x24, 0x00);//FM_RDS_STATUS
 sendCommand(command, 2);
 getResponse(R);
  A = MAKEINT(R[ 4],R[ 5]); //build BLOCKS
  B = MAKEINT(R[ 6],R[ 7]);
  C = MAKEINT(R[ 8],R[ 9]);
  D = MAKEINT(R[10],R[11]);
  // return A //Program Identification PI
  //Senderwechsel?
  if(PID!=A) //Löschen der Zeichenpuffer
  {for(i=0;i<64;i++)RadioText[i]=0;
   for(i=0;i< 8;i++)Station[i]=0;
  }
  PID  = A; //Merken
  PTY = (B>>5)   &0x1F; //0 - 31 -> 10 Pop
  TP  = (R[6]>>2)&0x01; // Traffic Program
  GT  = (R[6]>>4)&0x0F; // Group Type 0 - 15
  AB  = (R[6]>>3)&0x01; // Group A/B -> 0/1
  TA = 0;
  MS = 0;
  C12= 0;
  T16= 0;
  Station[8]='\0';
  RadioText[64]='\0';
  switch(AB)
  {case 0:// Type A 
		switch(GT)// GroupType
        {case 0: TA = bitRead(B,4);//(R[7]>>4)&0x01; // Block B Bit 4
				 MS = (R[7]>>3)&0x01;//MS = bitRead(B,3);
				 C12= R[7]&3;
				 switch(C12)
				 {case 0:Station[0]=R[10]; Station[1]=R[11]; break;
				  case 1:Station[2]=R[10]; Station[3]=R[11]; break;
				  case 2:Station[4]=R[10]; Station[5]=R[11]; break;
				  case 3:Station[6]=R[10]; Station[7]=R[11]; break;
				 }
				 break;
		 case 2: T16 = R[7]&0x0F;//RadioText	
				 RadioText[T16*4+00]=R[ 8];
				 RadioText[T16*4+01]=R[ 9];
				 RadioText[T16*4+02]=R[10];
				 RadioText[T16*4+03]=R[11];
				 break;
		default: break;
		}//switch GT
		break;
   case 1: //Type B
        switch(GT)// GroupType
		{case 2: //T16 = R[7]&0x0F;//RadioText	
				 //RadioText[T16*2+00]=R[10];
				 //RadioText[T16*2+01]=R[11];
				 break;
		 default:break;		 
		}
        break;   
   default:break;
  }// switch AB
  strcpy(sender,Station);
  strcpy(text,RadioText);
  return TA;
}
   
/*******************************************
* Private Functions
*******************************************/
void Si4735::SetProp(int Adr, int Data)
{sprintf(command, "%c%c%c%c%c%c", 0x12, 0x00, highByte(Adr), lowByte(Adr), highByte(Data), lowByte(Data));
 sendCommand(command, 6);
}

char Si4735::spiTransfer(char value)
{SPDR = value;                    // Start the transmission
 while (!(SPSR & (1<<SPIF))){};   // Wait for the end of the transmission
 return SPDR;                     // return the received byte
}

void Si4735::sendCommand(char *command, int length)
{digitalWrite(SS, LOW); delay(1);
 spiTransfer(0x48); delay(1); //Contrl byte to write an SPI command (now send 8 bytes)
 for(int i=0; i<length; i++)spiTransfer(command[i]);
 for(int i=length; i<8; i++)spiTransfer(0x00);  //Fill the rest of the command arguments with 0
 digitalWrite(SS, HIGH);  //End the sequence
}


