#include "GenericTypeDefs.h"
#include "HardwareProfile.h"

#include "delays.h"
#include "i2c.h"


#include "Si4703.h"



/** VARIABLES ******************************************************/
#pragma udata

unsigned char SI4703_ADDRESS = 0x10;

// Registers
UINT16 si4703_registers[16];




/** PRIVATE PROTOTYPES *********************************************/
BYTE readRegisters(void);
void updateRegisters(void);



/** DECLARATIONS ***************************************************/
#pragma code


unsigned char WriteI2C( unsigned char data_out )
{
  SSPBUF = data_out;           // write single byte to SSPBUF
  if ( SSPCON1bits.WCOL )      // test if write collision occurred
   return ( -1 );              // if WCOL bit is set return negative #
  else
  {
	if( ((SSPCON1&0x0F)!=0x08) && ((SSPCON1&0x0F)!=0x0B) )	//Slave mode only
	{
	      SSPCON1bits.CKP = 1;        // release clock line
	      while ( !PIR1bits.SSPIF );  // wait until ninth clock pulse received

	      if ( ( !SSPSTATbits.R_W ) && ( !SSPSTATbits.BF ) )// if R/W=0 and BF=0, NOT ACK was received
	      {
	        return ( -2 );           //return NACK
	      }
		  else
		  {
			return ( 0 );				//return ACK
		  }
	}
	else if( ((SSPCON1&0x0F)==0x08) || ((SSPCON1&0x0F)==0x0B) )	//master mode only
	{
	    while( SSPSTATbits.BF );   // wait until write cycle is complete
	    IdleI2C();  // ensure module is idle

	    if ( SSPCON2bits.ACKSTAT ) // test for ACK condition received
	    	 return ( -2 );			// return NACK
		else return ( 0 );              //return ACK
	}

  }
}



/**
 * Initializes Si4703 chip and I2C communication accordingly
 */
void initSi4703(void) {

    int i = 0;
    for(; i < 16; i++)
        si4703_registers[i] = 0x0000;

    
    mInitAllLEDs();

    // Make all three pins RC5, RB4 and RB6 output pins
    TRISCbits.TRISC0 = OUTPUT_PIN;     // RST -> RC0
    TRISBbits.TRISB4 = OUTPUT_PIN;     // Low SDIO
    
    // Set both pins to low
    LATBbits.LATB4 = 0;             // A low SDIO indicates a 2-wire interface
    LATCbits.LATC0 = 0;             // Put Si4703 into reset

    // Some delays while we allow pins to settle (1ms)
    Delay10KTCYx(12);

    // Bring Si4703 out of reset with SDIO set to low and SEN pulled high with on-board resistor
    LATCbits.LATC0 = 1;

    // Allow Si4703 to come out of reset
    Delay10KTCYx(12);
    
    // ----------------------------------------------------------
    // I2C register for PIC18F14K50 are -> RB4 (SDA) & RB6 (SCK)
    // ----------------------------------------------------------

    TRISBbits.TRISB4 = INPUT_PIN;     // SDIO -> RB4
    TRISBbits.TRISB6 = INPUT_PIN;     // SCLK -> RB6


    // Initialize the I2C module for master mode with 100KHz
    OpenI2C(MASTER, SLEW_OFF);

    // 100kHz Baud clock @48MHz PIC and @12MHz crystal (p. 167 of PIC18F Data Sheet)
    SSPADD = 0x77;

    // Start I2C and wait for device to get ready
    IdleI2C();
    StartI2C();
    IdleI2C();


    while(!PIR1bits.SSPIF);
    PIR1bits.SSPIF = 0;
    

    //readRegisters();


    si4703_registers[0x07] = 0x8100;	// Enable the oscillator, from AN230 page 9, rev 0.61 (works)
    si4703_registers[0x0F] = 0x0000;	// Fix for bug in Si4703 - C19, from Si4703-03-C19

    updateRegisters();


    mLED_3_On();


    // Wait for clock to settle - from AN230 page 9

    
    
    si4703_registers[POWERCFG] = 0x4001; // Enable the IC, disables Mute and disables Softmute
    //si4703_registers[POWERCFG] |= (1 << SMUTE) | (1 << DMUTE); // Disable Mute, disable softmute
    si4703_registers[SYSCONFIG1] |= (1 << RDS); // Enable RDS

    si4703_registers[SYSCONFIG1] |= (1 << DE); // 50kHz Europe setup
    si4703_registers[SYSCONFIG2] |= (1 << SPACE0); // 100kHz channel spacing for Europe

    si4703_registers[SYSCONFIG2] &= 0xFFF0; // Clear volume bits
    si4703_registers[SYSCONFIG2] |= 0x0001; // Set volume to lowest


    updateRegisters();

    mLED_4_On();
}



BYTE readRegisters(void) {

    unsigned char data, status, rec;
    int x = 0;

    data = SSPBUF;      // Read any previous stored content in buffer to clear buffer full status

    do {
        // Write the address of slave R/W bit is '1' for read from slave
        status = WriteI2C(SI4703_ADDRESS | 0x01);
        if(status == -1)    // Check if bus collision happened
	{
            data = SSPBUF;  // Upon bus collision detection clear the buffer,
            SSPCON1bits.WCOL = 0;   // Clear the bus collision status bit
        }
    }
    while(status != 0);		// Write until successful communication
    
    IdleI2C();


    // Read in these 32 bytes
    for(x = 0x0A; ; x++) {
        if(x == 0x10) x = 0; // Loop back to zero

        si4703_registers[x] = ((int) ReadI2C()) << 8;
        
        mLED_3_On();

        AckI2C();
        IdleI2C();

        return 0;

        si4703_registers[x] |= (int) ReadI2C();
        
        if(x == 0x09) {
            // Send the end of transmission signal through nack
            NotAckI2C();
            // Wait till ack sequence is complete
            while(SSPCON2bits.ACKEN != 0);
            IdleI2C();
            break; // We're done!
        }

        AckI2C();
        IdleI2C();
    }

    StopI2C();
}


void updateRegisters(void) {
    unsigned char data, status, rec;
    int x = 0;

    data = SSPBUF;      // Read any previous stored content in buffer to clear buffer full status

    do {
        // Write the address of slave R/W bit is '0' for write to slave
        status = WriteI2C(SI4703_ADDRESS | 0x00);
        if(status == -1)    // Check if bus collision happened
	{
            data = SSPBUF;  // Upon bus collision detection clear the buffer,
            SSPCON1bits.WCOL = 0;   // Clear the bus collision status bit
        }
    }
    while(status != 0);		// Write until successful communication

    IdleI2C();

    
    for(x = 0x02 ; x < 0x08 ; x++) {
        BYTE high_byte = si4703_registers[x] >> 8;
        BYTE low_byte = si4703_registers[x] & 0x00FF;

        status = WriteI2C(high_byte);
        IdleI2C();
        status = WriteI2C(low_byte);
        IdleI2C();
    }
}
