#include "si5351.h"

uint32_t si5351_freq_a;
uint32_t si5351_freq_b;

void si5351_init(uint32_t freq_xtal, uint32_t freq_a, uint32_t freq_b) {
    si5351_write8(CLK_ENABLE_CONTROL, 0x00); // Enable all outputs
    si5351_write8(XTAL_LOAD_CAP, 0xD2);     //crystal load capacitor = 10pF

    si5351_write8(CLK0_CONTROL, 0x0F);      // PLLA to CLK0, 8 mA output
    si5351_write8(PLL_RESET, 0xA0);         // Reset both PLLs

    si5351_freq_a = freq_a;
    si5351_freq_b = freq_b;

    double fdiv = (double) si5351_freq_a / (double) freq_xtal;

    //TODO: Find better way to determine c and b
    uint32_t c = 0x0FFFFF;
    uint32_t a = (uint32_t) fdiv;
    double rm = fdiv - a;
    uint32_t b = rm * c;
    uint32_t p1  = 128 * a + (128 * b / c) - 512;
    uint32_t p2 = 128 * b - c * (128 * b / c);
    uint32_t p3 = c;
    si5351_write_params(PLL_A, p1, p2, p3);


    fdiv = (double) freq_xtal / (double) si5351_freq_a;

    //TODO: Find better way to determine c and b
    c = 0x0FFFFF;
    a = (uint32_t) fdiv;
    rm = fdiv - a;
    b = rm * c;
    p1  = 128 * a + (128 * b / c) - 512;
    p2 = 128 * b - c * (128 * b / c);
    p3 = c;
    si5351_write_params(PLL_B, p1, p2, p3);
}

void si5351_set_freq(enum si5351_param_base base, uint32_t freq) {
    //TODO: Pick freq by clock source
    double fdiv = (double) si5351_freq_a / (double) freq;

    //TODO: Find better way to determine c and b
    uint32_t c = 0x0FFFFF;
    uint32_t a = (uint32_t) fdiv;
    double rm = fdiv - a;
    uint32_t b = rm * c;
    uint32_t p1  = 128 * a + (128 * b / c) - 512;
    uint32_t p2 = 128 * b - c * (128 * b / c);
    uint32_t p3 = c;
    si5351_write_params(base, p1, p2, p3);
}



uint8_t si5351_write_params(enum si5351_param_base base, uint32_t p1, uint32_t p2, uint32_t p3) {
    uint8_t data[9] = {
                    base,
                    (p3 & 0x00FF00) >> 8,
                    p3 & 0x0000FF,
                    (p1 & 0x030000) >> 16,
                    (p1 & 0x00FF00) >> 8,
                    p1 & 0x0000FF,
                    ((p3 & 0x0F0000) >> 12) | ((p2 & 0x0F0000) >> 16),
                    (p2 & 0x00FF00) >> 8,
                    p2 & 0x0000FF
                };
    return twi_write(SI5351_ADDRESS, data, 9);
}
