#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
#include "IFsh1.h"


#define IIC_ERROR_STATUS 0
#define IIC_READY_STATUS 1
#define IIC_HEADER_SENT_STATUS 2
#define IIC_DATA_TRANSMISION_STATUS 3
#define IIC_DATA_SENT_STATUS 4

void configureI2C(unsigned char);
unsigned char WriteBytesI2C (unsigned char,unsigned char);
unsigned char ReadBytesI2C (unsigned char,unsigned char);

//----I2C Variables -------------------------------------------------------
unsigned char I2C_STEP = IIC_READY_STATUS;
unsigned char I2C_DATA_DIRECTION = 0;      /* 1 Transmit, 0 Read */
unsigned char I2C_LENGTH = 1;
unsigned char I2C_COUNTER = 0;

unsigned char I2C_DATA[8];			/* IIC Buffer */

//-------------------------------------------------------------------------



byte pm_reg_address_ram_table[19];
byte pm_reg_value_ram_table[19];

byte pm_order_table[8];
byte pm_delay_table[8];

byte rx_buffer[16];
byte rx_buffer_index;

byte SCIdata_RX_flag;

byte RX_receive_counter;
byte RX_array_address;
byte RX_i2c_index_address;
byte RX_i2c_data;


const byte FLASH_REG_VALUE[18]  @ 0xFC00;
const byte FLASH_ORDER_VALUE[8] @ 0xFC20;
const byte FLASH_DELAY_VALUE[8] @ 0xFC30;


#define PM_POWER_ON   PTBD_PTBD2
#define PM_SYS_ON     PTBD_PTBD3
#define PM_nRST       PTBD_PTBD4
#define PM_UP_LED     PTBD_PTBD5


void MCU_init(void) /* Device initialization function declaration */
   {
    
       SOPT1 = 0x22;     // STOP enabled, Background enabled and no RESET pin
       SOPT2 = 0x02;    // Set I2C pins to PTB6 and PTB7

			 /* SYS IO init code */
			 
			 /* Port A:
              Bit 0    : Input, SYS POWER ON PUSH BUTTON
              Bit 1    : Input, detects power in
              Bit 2    : Unused, set to output low
              Bit 3    : Input, PM EXT WAKEUP
              Bit 4    : Use only as the BKGD pin
              Bit 5    : Use only as the nRESET pin  */
       PTAD  = 0x00;       
       PTADD = 0x04;

  
       /* Port B:
              Bit 0    : Micro Rx, set to input
              Bit 1    : Micro Tx, set to output
              Bit 2    : Output, PM POWER ON
              Bit 3    : Output, PM SYS ON
              Bit 4    : Output, PM nRST 
              BIt 5    : Output, PM UP LED
              Bit 6    : SDA
              Bit 7    : SCL  */
      
      PTBD  = 0x00;         
      PTBDD = 0x3E;
   }
    
    
void MCU_delay(word count) 
   {
      word i; 
   
      for(i=0;i<count;i++);
   }
  
  
void send_val(byte n) 
   {
      byte h;
      
      h = (n/16);
      while(!SCIS1_TDRE);
      if (h > 9)
         SCID = (0x37 + h);
       else
         SCID = (0x30 + h);
      h = (n%16);
      while(!SCIS1_TDRE);
      if (h > 9)
         SCID = (0x37 + h);
       else
         SCID = (0x30 + h);  
   }
       
byte cal_val(byte h, byte l) 
   {
      byte n;
      byte m;
      byte u;
      
      if (h < 0x3A)
         m = (h - 0x30);
       else
          m = (h - 0x37);
       
      if (l < 0x3A)
         u = (l - 0x30);
       else
          u = (l - 0x37);
       
       n = m*16 + u;
       
       return n;
   }
          
      
  

/* Function to configure the IIC module. */
void configureI2C(unsigned char selfAddress){
   IICC_IICEN = 1;           /* Enable IIC            */
    IICA = selfAddress;      /* IIC Address           */
      IICF = 0x4B;           /* Set IIC frequency     */    
    I2C_STEP = IIC_READY_STATUS;
    IICC_IICIE = 1;      /* Enable IIC interrupts */
    
}                                                                                                                                


unsigned char WriteBytesI2C (unsigned char slaveAddress,unsigned char numberOfBytes){
	unsigned char Temp;
  
  I2C_LENGTH = numberOfBytes;
  I2C_COUNTER =0;
  I2C_STEP = IIC_HEADER_SENT_STATUS;
  I2C_DATA_DIRECTION = 1;
  
  /* Format the Address to fit in the IICA register and place a 0 on the R/W bit.*/
  slaveAddress &= 0xFE;

  IICC_IICEN = 0;
  IICC_IICEN = 1;
  IICS;					  				   /* Clear any pending interrupt */
  IICS_IICIF = 1;

  IICC_MST = 0;
  
  IICS_SRW = 0;
  IICC_TX = 1;				          /* Select Transmit Mode */
	IICC_MST = 1;				        /* Select Master Mode (Send Start Bit) */
    
  for(Temp=0;Temp<3;Temp++);    /* Small delay */
  
  IICD = slaveAddress;						/* Send selected slave address */
     
  return(1);
}


unsigned char ReadBytesI2C (unsigned char slaveAddress,unsigned char numberOfBytes){
  
  I2C_LENGTH = numberOfBytes;

  I2C_COUNTER =0;
  I2C_STEP = IIC_HEADER_SENT_STATUS;
  I2C_DATA_DIRECTION = 0;
                                                                                                                     
  /* Format the Address to fit in the IICA register and place a 1 on the R/W bit. */
 
  slaveAddress &= 0xFE;
  slaveAddress |= 0x01;         /* Set the Read from slave bit. */

  IICS;					  				    /* Clear any pending interrupt  */
  IICS_IICIF = 1;
  
  IICC_TX = 1;				          /* Select Transmit Mode          */
	IICC_MST = 1;				        /* Select Master Mode (Send Start Bit)*/
  
  IICD = slaveAddress;						/* Send selected slave address   */
  
  return(1);
}   
   

void Init_Serial_Port(void) 
   {
      SCIdata_RX_flag = 0;
      RX_receive_counter = 0;
   
      SCIBDH          =    0x00;    // Baud rate = BUSCLK/(16xSBR12:SBR0)
      SCIBDL          =    0x0D;    // 19200 =~ 4000000/(16*13)
      SCIC1           =    0x44;    // LOOPS=0, SCISWAI=1,RSRC=0, M=0, WAKE=0, ILT=1, PE=0, PT=0
     // SCIC2           =    0x4C;    // transmit and receive are enabled, RX INT enabled
      SCIC2           =    0x0C;    // transmit and receive are enabled, RX INT disable
   }
   
void write_to_FLASH(void) 
   {
      word flash_base;
      byte index;
      
      flash_base = 0xFC00;
      for(index=0;index<19;index++)
         IFsh1_SetByteFlash((flash_base + index), pm_reg_value_ram_table[index]);
         
      flash_base = 0xFC20;
      for(index=0;index<8;index++)
         IFsh1_SetByteFlash((flash_base + index), pm_order_table[index]);
         
      flash_base = 0xFC30;
      for(index=0;index<8;index++)
         IFsh1_SetByteFlash((flash_base + index), pm_delay_table[index]);            
   
   }
   
   
  
void PM_tables_init(void) 
   {
            
      byte index; 
      
      for(n=0;n<19;n++)
         pm_reg_value_ram_table[index] = FLASH_REG_VALUE[index];
         
            
      pm_reg_address_ram_table[0]  = 0x07; // PM SCR1 reg
      pm_reg_value_ram_table[0]    = 0x00;
           
      pm_reg_address_ram_table[1]  = 0x0B; // PM BBCC reg
      pm_reg_value_ram_table[1]    = 0x01;
           
      pm_reg_address_ram_table[2]  = 0x0E; // PM SCR2 reg
      pm_reg_value_ram_table[2]    = 0x20; // GPIO1 is not enable line for charger, RTC-LDO1 tracking disable
           
           
      pm_reg_address_ram_table[3]  = 0x23; // PM B1TV1 reg
      pm_reg_value_ram_table[3]    = 0x19; // 3.3V
           
      pm_reg_address_ram_table[4]  = 0x24; // PM B1TV2 reg
      pm_reg_value_ram_table[4]    = 0x16; // 2.5V  
           
      pm_reg_address_ram_table[5]  = 0x25; // PM B1RS reg
      pm_reg_value_ram_table[5]    = 0x10; // 10mV/uS ramp rate 
           
      pm_reg_address_ram_table[6]  = 0x29; // PM B2TV1 reg
      pm_reg_value_ram_table[6]    = 0x14; // 1.8V
           
      pm_reg_address_ram_table[7]  = 0x2A; // PM B1TV2 reg
      pm_reg_value_ram_table[7]    = 0x12; // 1.65V  
           
      pm_reg_address_ram_table[8]  = 0x2B; // PM B2RS reg
      pm_reg_value_ram_table[8]    = 0x10; // 10mV/uS ramp rate
           
      pm_reg_address_ram_table[9]  = 0x32; // PM B3TV1 reg
      pm_reg_value_ram_table[9]    = 0x0D; // 1.4V
           
      pm_reg_address_ram_table[10] = 0x33; // PM B3TV2 reg
      pm_reg_value_ram_table[10]   = 0x0F; // 1.5V  
           
      pm_reg_address_ram_table[11] = 0x34; // PM B3RS reg
      pm_reg_value_ram_table[11]   = 0x10; // 10mV/uS ramp rate  
           
      pm_reg_address_ram_table[12] = 0x38; // PM BFR reg
      pm_reg_value_ram_table[12]   = 0x00; // 10mV/uS ramp rate          
           
      pm_reg_address_ram_table[13] = 0x39; // PM L21VCR reg
      pm_reg_value_ram_table[13]   = 0x4F; // 2.2V for LDO2, 3.3V for LDO1
        
      pm_reg_address_ram_table[14] = 0x3A; // PM L43VCR reg
      pm_reg_value_ram_table[14]   = 0x8B; // 1.4V for LDO4, 2.9V for LDO3  
           
      pm_reg_address_ram_table[15] = 0x3B; // PM L5VCR reg
      pm_reg_value_ram_table[15]   = 0x0C; // 2.5V for LDO5
           
      pm_reg_address_ram_table[16] = 0x10; // PM BOVEN reg
      pm_reg_value_ram_table[16]   = 0x00; // All bucks are disabled   
           
      pm_reg_address_ram_table[17] = 0x12; // PM LDOEN reg
      pm_reg_value_ram_table[17]   = 0x00; // All LDOs are disabled
           
      pm_reg_address_ram_table[18] = 0x20; // PM Vcc1 reg
      pm_reg_value_ram_table[18]   = 0x51; // Use TV1 for all bucks, ramp voltage as selected by B1VS when EN
      
      /*pm_order_table[0]            = 0x99;
      pm_order_table[1]            = 0x0A;
      pm_order_table[2]            = 0x0B;
      pm_order_table[3]            = 0x0C;
      pm_order_table[4]            = 0x0D;
      pm_order_table[5]            = 0x0E;
      pm_order_table[6]            = 0x0F;
      pm_order_table[7]            = 0x99;
      
      pm_delay_table[0]            = 0x88;
      pm_delay_table[1]            = 0xA0;
      pm_delay_table[2]            = 0xB0;
      pm_delay_table[3]            = 0xC0;
      pm_delay_table[4]            = 0xD0;
      pm_delay_table[5]            = 0xE0;
      pm_delay_table[6]            = 0xF0;
      pm_delay_table[7]            = 0x88; */
      
      for(index=0;index<8;index++)
         pm_order_table[index] = FLASH_REG_VALUE[index];
         
      for(index=0;index<8;index++)
         pm_delay_table[index] = FLASH_DELAY_VALUE[index];   
      
   }  
   
    
void main(void) 
   {
        word i;
        byte n;
        byte h;
        byte l;
        byte index;
        
        
        MCU_init();
        
       // SCIInit(); //See here and SCI.h for setting baud rates 
        
        
        // Turn PM on
        PM_POWER_ON = 1;
        

        // Reset the PM chip
        PM_nRST = 0; 
        MCU_delay(10000);
        PM_nRST = 1;
        MCU_delay(5000);
        
        // Set all PM registers to required values        

        PM_tables_init();
        
        
        configureI2C(0x50);
          
        EnableInterrupts; /* enable interrupts */
          
       
        // Set initial PM values
        
        for(n=0;n<19;n++)
           {
              I2C_DATA[0] = pm_reg_address_ram_table[n];
              I2C_DATA[1] = pm_reg_value_ram_table[n];
              WriteBytesI2C(0x68,2);
              while(IICC_MST == 1);
              MCU_delay(5);
           };
       
       
        // Enable hardware control
        PM_SYS_ON = 1;
        
        MCU_delay(50);

        //Enable DCDC3       1.4V
        I2C_DATA[0] = 0x10;     // PM BOVEN reg
        I2C_DATA[1] = 0x10;     // DCDC3 is enabled
        WriteBytesI2C(0x68,2);
        while(IICC_MST == 1);
        
        //I2C_DATA[0] = 0x20;     // PM Vcc1 reg
        //I2C_DATA[1] = 0x40;     // Start DCDC3 value change
        //WriteBytesI2C(0x68,2);
       // while(IICC_MST == 1);  
           
           
        MCU_delay(50);   
        //Enable DCDC2       1.8V
        I2C_DATA[0] = 0x10;     // PM BOVEN reg
        I2C_DATA[1] = 0x14;     // DCDC2 is enabled
        WriteBytesI2C(0x68,2);
        while(IICC_MST == 1);
        
        //I2C_DATA[0] = 0x20;     // PM Vcc1 reg
        //I2C_DATA[1] = 0x50;     // Start DCDC2 value change
        //WriteBytesI2C(0x68,2);
        //while(IICC_MST == 1);  
        
        MCU_delay(50); 
          
        //Enable DCDC1        3.3V
        I2C_DATA[0] = 0x10;     // PM BOVEN reg
        I2C_DATA[1] = 0x15;     // DCDC31 is enabled
        WriteBytesI2C(0x68,2);
        while(IICC_MST == 1);
        
        //I2C_DATA[0] = 0x20;     // PM Vcc1 reg
        //I2C_DATA[1] = 0x51;     // Start DCDC3 value change
        //WriteBytesI2C(0x68,2);
        //while(IICC_MST == 1);              
           
           
        MCU_delay(50); 
        
         
         
        //Enable LDO1
        I2C_DATA[0] = 0x12;     // PM LDONE reg
        I2C_DATA[1] = 0x02;     // LDO1 is enabled
        WriteBytesI2C(0x68,2);
        while(IICC_MST == 1); 
        
        MCU_delay(50);   
        //Enable LDO2
        I2C_DATA[0] = 0x12;     // PM LDONE reg
        I2C_DATA[1] = 0x06;     // LDO2 is enabled
        WriteBytesI2C(0x68,2);
        while(IICC_MST == 1);
        
        MCU_delay(50);   
        //Enable LDO3
        I2C_DATA[0] = 0x12;     // PM LDONE reg
        I2C_DATA[1] = 0x0E;     // LDO3 is enabled
        WriteBytesI2C(0x68,2);
        while(IICC_MST == 1);
        
        MCU_delay(50);   
        //Enable LDO4
        I2C_DATA[0] = 0x12;     // PM LDONE reg
        I2C_DATA[1] = 0x1E;     // LDO4 is enabled
        WriteBytesI2C(0x68,2);
        while(IICC_MST == 1); 
        
        MCU_delay(50);   
        //Enable LDO5
        I2C_DATA[0] = 0x12;     // PM LDONE reg
        I2C_DATA[1] = 0x3E;     // LDO5 is enabled
        WriteBytesI2C(0x68,2);
        while(IICC_MST == 1); 
           
        
        PM_UP_LED = 1; 
        
        
        Init_Serial_Port(); 
        
        rx_buffer_index = 0;  
           
        while(1) 
           {
              if (SCIS1_RDRF)
                 {
                    rx_buffer[rx_buffer_index] = SCID;
            
                    if(rx_buffer[rx_buffer_index] == 0x0D)
                       {
                         switch(rx_buffer[0])
                            {
                              case 'R':  // Reading all values tables  Message is: 'R' /CR
                                         for(n=0;n<19;n++) 
                                            {
                                              send_val(pm_reg_value_ram_table[n]);
                                            }  
                                            
                                          for(n=0;n<8;n++) 
                                            {
                                              send_val(pm_order_table[n]);
                                            } 
                                            
                                          for(n=0;n<8;n++) 
                                            {
                                              send_val(pm_delay_table[n]);
                                            } 
                                            
                                          break;                                                 
                              
                              case 'W':  // setting an LP3971 register and updating the RAM table  Message is 'W' xx yy /CR 
                                         
                                         RX_array_address     = cal_val(rx_buffer[1],rx_buffer[2]);
                                         RX_i2c_data          = cal_val(rx_buffer[3], rx_buffer[4]);
                                         
                                         while(!SCIS1_TDRE);
                                         SCID = 0x59;
                                         
                                         pm_reg_value_ram_table[RX_array_address] = RX_i2c_data;
                                             
                                         I2C_DATA[0] = pm_reg_address_ram_table[RX_array_address]; // PM I2C index reg
                                         I2C_DATA[1] = pm_reg_value_ram_table[RX_array_address];   // PM I2C data value
                                         WriteBytesI2C(0x68,2);
                                         while(IICC_MST == 1); 
           
                                         while(!SCIS1_TDRE);
                                         SCID = 0x0D;
 
                                         break;
                                         
                               case 'O':  // setting the order RAM table  Message is 'O' xx yy zz aa bb cc dd ee /CR 
                                         
                                         for(index=0;index<8;index++)
                                            pm_order_table[index] = cal_val(rx_buffer[index*2],rx_buffer[index*2+1]);
                                         
                                         while(!SCIS1_TDRE);
                                         SCID = 0x0D;
                                         
                                         break;             
                                         
                              case 'D':  // setting the delay RAM table  Message is 'D' xx yy zz aa bb cc dd ee /CR 
                                         
                                         for(index=0;index<8;index++)
                                            pm_delay_table[index] = cal_val(rx_buffer[index*2],rx_buffer[index*2+1]);
                                         
                                         while(!SCIS1_TDRE);
                                         SCID = 0x0D;
                                         
                                         break; 
                                         
                              case 'F': // Writing all tables to FLASH  Message is: 'F' /CR 
                                        
                                        write_to_FLASH();
                                         
                                        while(!SCIS1_TDRE);
                                        SCID = 0x0D; 
                                           
                                         
                              default:
                                         break;            
                              }
                           
                           rx_buffer_index = 0;    
                        }
                     else
                         { 
                            rx_buffer_index++;    
 
                         };

                 };
           };
   };





//-------------------------------------------------------------





/* Interrupt handler routine to manage all the events related
 * to the IIC module.    */

interrupt 17 void Viic_isr(void){

	IICS;					  				 /* ACK the interrupt */
  IICS_IICIF = 1;
 
  if(IICS_ARBL==1){	       /* Verify the Arbitration lost status */	     
	     IICS_ARBL= 1;
	     IICC_MST = 0;	
	     I2C_STEP = IIC_ERROR_STATUS;
	        

	          
	     return;     
	}										       /* If Arbitration is OK continue */  
		

	
	if(IICC_MST==1){          /* If we are the IIC Master */
	 
	 				 	 
	 	 if(IICS_RXAK==1){      /* Verify if byte sent was ACK */
	 	    IICC_MST = 0;
	      I2C_STEP = IIC_ERROR_STATUS;
	   
	      return;
	 	 }
	 			             
     if(I2C_STEP == IIC_HEADER_SENT_STATUS){ /* Header Sent */
          IICC_TX = I2C_DATA_DIRECTION;
          
          I2C_STEP = IIC_DATA_TRANSMISION_STATUS; 
          
          if(IICC_TX==0){  /* If we are reading data clock in first slave byte */
              IICD;
              return;
          }
     }
              
     if(I2C_STEP == IIC_DATA_TRANSMISION_STATUS){	 /* If byte transmision is in progress.*/
           
        	  if(IICC_TX==1){				               /* If Master is sending data to slave */     	 
        	            	    
        	    IICD = I2C_DATA[I2C_COUNTER];	     /* Send the next byte */
        	         	 
        	    I2C_COUNTER++;
        	    if(I2C_LENGTH <= I2C_COUNTER){        	     
        	      I2C_STEP=IIC_DATA_SENT_STATUS;     /* Mark we are done sending Bytes */   	  
        	    }
        	    return;        	 								     /* wait until last byte sent      */
        	  } 
        	  else{										               /* If master is reading data from slave */
        	      
        	      if((I2C_COUNTER+1) == I2C_LENGTH)  /* Master should not ACK the last byte */
        	          IICC_TXAK = 1;							   /* to indicate end of transfer         */
        	      
        	      I2C_DATA[I2C_COUNTER] = IICD;	   /* Read the next byte */       	         	 
        	      I2C_COUNTER++;
        	      																 
        	      if(I2C_LENGTH <= I2C_COUNTER){        	     
        	        I2C_STEP=IIC_DATA_SENT_STATUS;   /* Mark we are done sending Bytes */   	  
        	      }   
        	      
        	      return;           	    					 /* Return until next byte is read */
        	 }	  
       }
                   
       if(I2C_STEP==IIC_DATA_SENT_STATUS){	       /* We are done with the transmition.*/ 
        	 
        	 I2C_STEP=IIC_READY_STATUS;	             /* Reset our status flag            */
        	 IICS;					  				               /* ACK the interrupt                */
           IICS_IICIF=1;
        	 
        	 IICC_TX=0;
        	 IICS_SRW=0;
        	 IICC_MST=0;
        	 			                                   /* Generate a stop condition        */        	  
        	 return;
       }        
	}
  else{			 /*  SLAVE OPERATION  */  
                   																						 

       if(I2C_STEP <= IIC_READY_STATUS){	 				 /* If it is the first byte tranmited */
           I2C_STEP = IIC_DATA_TRANSMISION_STATUS;
           IICC_TX = IICS_SRW;				           /* Set the transmision reception status */
           I2C_COUNTER = 1;
           
           /* If we are receiving data read IIC1D to get free bus and get the next byte */
           if(IICC_TX==0){
              IICD;
              return;
           }
       }
       	
       
			 if(IICS_TCF==1){
          if(IICC_TX == 0){	        /* If data is received store it on the buffer */              
              I2C_DATA[I2C_COUNTER]=IICD;
              I2C_COUNTER++;
              return;          
          } 
          else{	                      /* Data sent by the slave */              
              
              if(IICS_RXAK==1){      /* If byte is not ACK end transmision. */
	                IICC_TX = 0;
	                IICD;
	                I2C_STEP = IIC_READY_STATUS;
	                return;
	 	          }
              
              IICD = I2C_DATA[I2C_COUNTER];
              I2C_COUNTER++;
              return;          
          }
		  }
   }
}


/* Interrupt handler routine to manage all the UART receive events */


//interrupt 15 void Vsci_rx_isr(void)
//   {
//      byte status, dummy;
//  
    	// ensure Rx data buffer is full
//	    do {
//		        status = SCIS1;
//	       }
//	    while ((status & 0x20) == 0);

		  //Good Data.
    	//SCIdata[0] = SCID; // load SCI register to data
    	//SCIdata[1] = 0;
//    	dummy = SCID;
//	    SCIdata_RX_flag = 1;

//   }







