/************************************************************************************
 * KD8CEC 
 * kd8cec@gmail.com   http://www.hamskey.com
 * 
 * Merge two SI5351 Librarys
 * KE7ER's fixed vco and variable Clocks Configure values
 * G3ZIL's fixed Clock Configure Value and variable VCO
 *  * I have combined the two libraries above. All licenses follow the above library.
 * 
 * PLL-A is generated by fixing 850Mhz clock. All output clocks use PLL-A to 
 * generate the frequency. This is the method used in QRP radios such as uBITX.
 * When switching to WSPR transmission mode, PLL-B operates for the base frequency to transmit WSPR. 
 * The output clock channel that controls the frequency is connected to the PLL-B. 
 * The WSPR protocol is generated by changing the clock of the PLL-B.
 ************************************************************************************/
#include "ubitx.h"

// *************  SI5315 routines - tks Jerry Gaffke, KE7ER   ***********************
// An minimalist standalone set of Si5351 routines.
// VCOA is fixed at 875mhz, VCOB not used.
// The output msynth dividers are used to generate 3 independent clocks
// with 1hz resolution to any frequency between 4khz and 109mhz.

// Usage:
// Call si5351bx_init() once at startup with no args;
// Call si5351bx_setfreq(clknum, freq) each time one of the
// three output CLK pins is to be updated to a new frequency.
// A freq of 0 serves to shut down that output clock.

// The global variable si5351bx_vcoa starts out equal to the nominal VCOA
// frequency of 25mhz*35 = 875000000 Hz.  To correct for 25mhz crystal errors,
// the user can adjust this value.  The vco frequency will not change but
// the number used for the (a+b/c) output msynth calculations is affected.
// Example:  We call for a 5mhz signal, but it measures to be 5.001mhz.
// So the actual vcoa frequency is 875mhz*5.001/5.000 = 875175000 Hz,
// To correct for this error:     si5351bx_vcoa=875175000;

// Most users will never need to generate clocks below 500khz.
// But it is possible to do so by loading a value between 0 and 7 into
// the global variable si5351bx_rdiv, be sure to return it to a value of 0
// before setting some other CLK output pin.  The affected clock will be
// divided down by a power of two defined by  2**si5351_rdiv
// A value of zero gives a divide factor of 1, a value of 7 divides by 128.
// This lightweight method is a reasonable compromise for a seldom used feature.


#define BB0(x) ((uint8_t)x)             // Bust int32 into Bytes
#define BB1(x) ((uint8_t)(x>>8))
#define BB2(x) ((uint8_t)(x>>16))

//#define SI5351BX_ADDR 0x60              // I2C address of Si5351   (typical)
uint8_t SI5351BX_ADDR;                    // I2C address of Si5351   (variable from Version 1.097)
#define SI5351BX_XTALPF 2               // 1:6pf  2:8pf  3:10pf

// If using 27mhz crystal, set XTAL=27000000, MSA=33.  Then vco=891mhz
#define SI5351BX_XTAL 25000000          // Crystal freq in Hz
#define SI5351BX_MSA  35                // VCOA is at 25mhz*35 = 875mhz

// User program may have reason to poke new values into these 3 RAM variables
uint32_t si5351bx_vcoa = (SI5351BX_XTAL*SI5351BX_MSA);  // 25mhzXtal calibrate
uint8_t  si5351bx_rdiv = 0;             // 0-7, CLK pin sees fout/(2**rdiv)

#if UBITX_BOARD_VERSION == 5
uint8_t  si5351bx_drive[3] = {3, 3, 3}; // 0=2ma 1=4ma 2=6ma 3=8ma for CLK 0,1,2
#else
uint8_t  si5351bx_drive[3] = {1, 1, 1}; // 0=2ma 1=4ma 2=6ma 3=8ma for CLK 0,1,2
#endif

uint8_t  si5351bx_clken = 0xFF;         // Private, all CLK output drivers off
int32_t calibration = 0;

void i2cWrite(uint8_t reg, uint8_t val) {   // write reg via i2c
  Wire.beginTransmission(SI5351BX_ADDR);
  Wire.write(reg);
  Wire.write(val);
  Wire.endTransmission();
}

void i2cWriten(uint8_t reg, uint8_t *vals, uint8_t vcnt) {  // write array
  Wire.beginTransmission(SI5351BX_ADDR);
  Wire.write(reg);
  while (vcnt--) Wire.write(*vals++);
  Wire.endTransmission();
}

uint8_t  si5351Val[8] = {0, 1, 0, 0, 0, 0, 0, 0}; //for reduce program memory size

void si5351bx_init() {                  // Call once at power-up, start PLLA
  uint32_t msxp1;
  Wire.begin();
  i2cWrite(149, 0);                     // SpreadSpectrum off
  i2cWrite(3, si5351bx_clken);          // Disable all CLK output drivers
  i2cWrite(183, SI5351BX_XTALPF << 6);  // Set 25mhz crystal load capacitance
  msxp1 = 128 * SI5351BX_MSA - 512;     // and msxp2=0, msxp3=1, not fractional
  //uint8_t  vals[8] = {0, 1, BB2(msxp1), BB1(msxp1), BB0(msxp1), 0, 0, 0};
  si5351Val[2] = BB2(msxp1);
  si5351Val[3] = BB1(msxp1);
  si5351Val[4] = BB0(msxp1);
  
  i2cWriten(26, si5351Val, 8);               // Write to 8 PLLA msynth regs
  i2cWrite(177, 0x20);                  // Reset PLLA  (0x80 resets PLLB)


#if UBITX_BOARD_VERSION == 5
  //why? TODO : CHECK by KD8CEC
  //initializing the ppl2 as well
  i2cWriten(34, si5351Val, 8);          // Write to 8 PLLA msynth regs
  i2cWrite(177, 0xa0);                  // Reset PLLA  & PPLB (0x80 resets PLLB)
#else
  //
#endif

    
}

void si5351bx_setfreq(uint8_t clknum, uint32_t fout) {  // Set a CLK to fout Hz
  uint32_t  msa, msb, msc, msxp1, msxp2, msxp3p2top;
  if ((fout < 500000) || (fout > 109000000)) // If clock freq out of range
    si5351bx_clken |= 1 << clknum;      //  shut down the clock
  else {
    msa = si5351bx_vcoa / fout;     // Integer part of vco/fout
    msb = si5351bx_vcoa % fout;     // Fractional part of vco/fout
    msc = fout;             // Divide by 2 till fits in reg
    while (msc & 0xfff00000) {
      msb = msb >> 1;
      msc = msc >> 1;
    }
    msxp1 = (128 * msa + 128 * msb / msc - 512) | (((uint32_t)si5351bx_rdiv) << 20);
    msxp2 = 128 * msb - 128 * msb / msc * msc; // msxp3 == msc;
    msxp3p2top = (((msc & 0x0F0000) << 4) | msxp2);     // 2 top nibbles
    uint8_t vals[8] = { BB1(msc), BB0(msc), BB2(msxp1), BB1(msxp1),
                        BB0(msxp1), BB2(msxp3p2top), BB1(msxp2), BB0(msxp2)
                      };
    i2cWriten(42 + (clknum * 8), vals, 8); // Write to 8 msynth regs
    i2cWrite(16 + clknum, 0x0C | si5351bx_drive[clknum]); // use local msynth
    si5351bx_clken &= ~(1 << clknum);   // Clear bit to enable clock
  }
  i2cWrite(3, si5351bx_clken);        // Enable/disable clock
}

void si5351_set_calibration(int32_t cal){
    si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + cal; // apply the calibration correction factor
    si5351bx_setfreq(0, usbCarrier);
}

void SetCarrierFreq()
{
  unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (inTx == 0) ? ifShiftValue : 0));
  //si5351bx_setfreq(0, (sdrModeOn ? 0 : appliedCarrier));
  si5351bx_setfreq(0, ((sdrModeOn && (inTx == 0)) ? 0 : appliedCarrier)); //found bug by KG4GEK
  

    /*
  if (cwMode == 0)
    si5351bx_setfreq(0, usbCarrier + (isIFShift ? ifShiftValue : 0));
  else
    si5351bx_setfreq(0, cwmCarrier + (isIFShift ? ifShiftValue : 0));
    */
}

void initOscillators(){
  //initialize the SI5351
  si5351bx_init();
  si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + calibration; // apply the calibration correction factor
  SetCarrierFreq();
}

//============================================================
// ADD FUNCTIONS by KD8CEC
//============================================================
uint8_t Wspr_Reg1[8] = {0xFF,0xFE, 0x00, 0, 0, 0, 0, 0};  //3, 4, 5, 6, 7
uint8_t Wspr_Reg2[8] = {0, 1, 0, 0, 0, 0, 0, 0};          //2, 3, 4

void Set_WSPR_Param(void) 
{ 
  i2cWrite(18, 128);
  i2cWriten(34, Wspr_Reg1, 8);
  i2cWriten(58, Wspr_Reg2, 8);
  i2cWrite(177, 128);
  i2cWrite(18, 111);

  si5351bx_clken &= ~(1 << 2);
  i2cWrite(3, si5351bx_clken);
}

void TXSubFreq(unsigned long P2)
{                   
  i2cWrite(40, (P2 & 65280) >> 8);
  i2cWrite(41, P2 & 255);
}
