#include "WM8960.h"
#include "i2c.h"
#include "sai.h"

#define WM8960_ADDRESS  0x1a

#define USE_BOARD_MIC 1
#define USE_EARPHONE_MIC 0

#if USE_BOARD_MIC
  #if USE_EARPHONE_MIC
    #error "The value of USE_BOARD_MIC and USE_EARPHONE_MIC are error !!"
  #endif
#else
  #if !USE_EARPHONE_MIC
    #error "The value of USE_BOARD_MIC and USE_EARPHONE_MIC are error !!"
  #endif
#endif
  

uint32_t AudioTotalSize;  /* This variable holds the total size of the audio file */
uint32_t AudioRemSize;    /* This variable holds the remaining data in audio file */
uint16_t *CurrentPos;     /* This variable holds the current position of audio pointer */


//This array is used to store the value of WM8960 registers.
static uint16_t WM8960_REG_VAL[56] =
{  
  0x0097, 0x0097, 0x0000, 0x0000, 0x0000, 0x0008, 0x0000, 0x000A,
  0x01C0, 0x0000, 0x00FF, 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000,
  0x0000, 0x007B, 0x0100, 0x0032, 0x0000, 0x00C3, 0x00C3, 0x01C0,
  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
  0x0100, 0x0100, 0x0050, 0x0050, 0x0050, 0x0050, 0x0000, 0x0000,
  0x0000, 0x0000, 0x0040, 0x0000, 0x0000, 0x0050, 0x0050, 0x0000,
  0x0000, 0x0037, 0x004D, 0x0080, 0x0008, 0x0031, 0x0026, 0x00ED
};


/**
  * @brief  Writes a 16-bit value to a specified register.
  * @param  reg: The number of the register.
  * @param  dat: The value to write.
  * @retval The return value of the I2C transmit function.
  */
uint8_t WM8960_Write_Reg(uint8_t reg, uint16_t dat)  {
  
  uint8_t res,I2C_Data[2];
  
  I2C_Data[0] = (reg<<1)|((uint8_t)((dat>>8)&0x0001));  //RegAddr
  I2C_Data[1] = (uint8_t)(dat&0x00FF);                  //RegValue
  
  res = HAL_I2C_Master_Transmit(&hi2c1,(WM8960_ADDRESS<<1),I2C_Data,2,10);
  if(res == HAL_OK)
    WM8960_REG_VAL[reg] = dat;
  
  return res;
}

/**
  * @brief  Read a 16-bit value from a specified register.
  * @param  reg: The number of the register.
  * @retval The value read from register.
  */
uint16_t WM8960_Read_Reg(uint8_t reg) {
  
  return WM8960_REG_VAL[reg];
}

/**
  * @brief  Initialize WM8960
  * @param  None
  * @retval The return value of the I2C transmit function.
  */
uint8_t WM8960_Init(void) {
  
  uint8_t res;
  
  //Reset Device
  res = WM8960_Write_Reg(0x0F, 0xFFFF);
  if(res != 0)
    return res;
  else
    printf("WM8960 reset completed !!\r\n");

  //Set Power Source
  #if USE_BOARD_MIC
  res =  WM8960_Write_Reg(0x19, 0x00E8);
  #elif USE_EARPHONE_MIC
  res =  WM8960_Write_Reg(0x19, 0x00D4);
  #endif
  res += WM8960_Write_Reg(0x1A, 0x01F8);
  res += WM8960_Write_Reg(0x2F, 0x003C);
  
  if(res != 0)  {
    printf("Source set fail !!\r\n");
    printf("Error code: %d\r\n",res);
    return res;
  }
  
  //Configure clock
  //MCLK->div1->SYSCLK->DAC/ADC sample Freq = 25MHz(MCLK)/2*256 = 48.8kHz
  WM8960_Write_Reg(0x04, 0x0000);
  
  /*********Audio Interface*********/
  
  //I2S format 16 bits word length
  WM8960_Write_Reg(0x07, 0x0002);
  
  /*********PGA*********/
  
  //Input PGA
  WM8960_Write_Reg(0x00, 0x003F | 0x0100);//0x003F
  WM8960_Write_Reg(0x01, 0x003F | 0x0100);//0x003F
  
  //Input Signal Path
  #if USE_BOARD_MIC
  WM8960_Write_Reg(0x20, 0x0008 | 0x0100);
  WM8960_Write_Reg(0x21, 0x0000);
  #elif USE_EARPHONE_MIC
  WM8960_Write_Reg(0x20, 0x0000);
  WM8960_Write_Reg(0x21, 0x0008 | 0x0100);
  #endif
  
  //Input Boost Mixer
  WM8960_Write_Reg(0x2B, 0x0000);
  WM8960_Write_Reg(0x2C, 0x0000);
  
  /*********ADC*********/
  
  //ADC Control //ADC High Pass Filter
  WM8960_Write_Reg(0x05, 0x000C);
  
  //ADC Digital Volume Control
  WM8960_Write_Reg(0x15, 0x00C3 | 0x0100);
  WM8960_Write_Reg(0x16, 0x00C3 | 0x0100);
  
  #if USE_BOARD_MIC
  WM8960_Write_Reg(0x17, 0x01C4);
  #elif USE_EARPHONE_MIC
  WM8960_Write_Reg(0x17, 0x01C8);
  #endif
  
  /*********ALC Control*********/
  //Noise Gate Control
  WM8960_Write_Reg(0x14, 0x00F9);
  
  /*********OUTPUT SIGNAL PATH*********/
  
  //Digital Volume Control
  WM8960_Write_Reg(0x0A, 0x00FF | 0x0100);
  WM8960_Write_Reg(0x0B, 0x00FF | 0x0100);
  
  //DAC Soft-Mute Control
  WM8960_Write_Reg(0x05, 0x0000);
  WM8960_Write_Reg(0x06, 0x0000);
  
  //3D Stereo Enhancement Function
  WM8960_Write_Reg(0x10, 0x0000); //No 3D effect
  
  //Left and Right Output Mixer Mute and Volume Control
//  WM8960_Write_Reg(0x22, 0x0180); //Left DAC and LINPUT3 to Left Output Mixer
//  WM8960_Write_Reg(0x25, 0x0180); //Right DAC and RINPUT3 to Right Output Mixer
//  WM8960_Write_Reg(0x2D, 0x0080); //Left Input Boost Mixer to Left Output Mixer
//  WM8960_Write_Reg(0x2E, 0x0080); //Right Input Boost Mixer to Right Output Mixer
  
  /*********ANALOGUE OUTPUTS*********/
  
  //LOUT1/ROUT1 Volume Control
//  WM8960_Write_Reg(0x02, 0x007F | 0x0100);  //Left Volume
//  WM8960_Write_Reg(0x03, 0x007F | 0x0100);  //Right Volume
  
  /*********ENABLING THE OUTPUTS*********/
  
  //Analogue Output Control
  WM8960_Write_Reg(0x31, 0x00F7); //Enable Left and right speakers

  return 0;
  
}

