// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config STVREN = OFF     // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <math.h>

#define _XTAL_FREQ 16000000  // 16 MHz oscillator frequency

#define SINE_TABLE_SIZE 256

uint8_t phaseA_index = 0;
uint8_t phaseB_index = SINE_TABLE_SIZE / 3;
uint8_t phaseC_index = (2 * SINE_TABLE_SIZE) / 3;

volatile uint8_t tmr0_reload_value = 20;  // Initial TMR0 reload value
volatile uint8_t amplitude_percent;

const uint16_t sine_table[256]=
{384, 393, 403, 412, 422, 431, 440, 450, 459, 468, 477, 486, 495, 504, 513, 522, 531, 540, 548, 557, 565, 573, 581, 589, 597, 605, 613, 620, 628, 635, 642, 649, 656, 662, 669, 675, 681, 687, 692, 698, 703, 708, 713, 718, 723, 727, 731, 735, 739, 742, 746, 749, 751, 754, 756, 759, 761, 762, 764, 765, 766, 767, 768, 768,
768, 768, 768, 767, 766, 765, 764, 762, 761, 759, 756, 754, 751, 749, 746, 742, 739, 735, 731, 727, 723, 718, 713, 708, 703, 698, 692, 687, 681, 675, 669, 662, 656, 649, 642, 635, 628, 620, 613, 605, 597, 589, 581, 573, 565, 557, 548, 540, 531, 522, 513, 504, 495, 486, 477, 468, 459, 450, 440, 431, 422, 412, 403, 393,
384, 375, 365, 356, 346, 337, 328, 318, 309, 300, 291, 282, 273, 264, 255, 246, 237, 228, 220, 211, 203, 195, 187, 179, 171, 163, 155, 148, 140, 133, 126, 119, 112, 106, 99, 93, 87, 81, 76, 70, 65, 60, 55, 50, 45, 41, 37, 33, 29, 26, 22, 19, 17, 14, 12, 9, 7, 6, 4, 3, 2, 1, 0, 0,
0, 0, 0, 1, 2, 3, 4, 6, 7, 9, 12, 14, 17, 19, 22, 26, 29, 33, 37, 41, 45, 50, 55, 60, 65, 70, 76, 81, 87, 93, 99, 106, 112, 119, 126, 133, 140, 148, 155, 163, 171, 179, 187, 195, 203, 211, 220, 228, 237, 246, 255, 264, 273, 282, 291, 300, 309, 318, 328, 337, 346, 356, 365, 375,};

void update_pwm(void) 
{
    uint16_t dutyA = sine_table[phaseA_index];
    uint16_t dutyB = sine_table[phaseB_index];
    uint16_t dutyC = sine_table[phaseC_index];

    // Set PWM duty cycles
    PWM1DCH = ((dutyA & 0x03FCu) >> 2);
    PWM1DCL = ((dutyA & 0x0003u) << 6);     // Assuming 8-bit duty cycle

    PWM2DCH = ((dutyB & 0x03FCu) >> 2);
    PWM2DCL = ((dutyB & 0x0003u) << 6);

    PWM3DCH = ((dutyC & 0x03FCu) >> 2);
    PWM3DCL = ((dutyC & 0x0003u) << 6);
    

    // Increment phase indexes
    phaseA_index = (phaseA_index + 1) % SINE_TABLE_SIZE;
    phaseB_index = (phaseB_index + 1) % SINE_TABLE_SIZE;
    phaseC_index = (phaseC_index + 1) % SINE_TABLE_SIZE;
}

void init_adc(void)
{
    // Configure ADC
    ADCON1bits.ADFM = 1;       // Right justified
    ADCON1bits.ADCS = 0b110;   // FOSC/64
    ADCON1bits.ADPREF = 0;     // VREF+ = VDD
    ADCON0bits.CHS = 0b00000;  // Select AN0
    ADCON0bits.ADON = 1;       // Enable ADC
    __delay_us(10);            // Acquisition time
    
}

void main(void) {
    // Oscillator configuration
    OSCCONbits.IRCF = 0b1111; // 16 MHz internal oscillator
    OSCCONbits.SCS = 0b10;    // Internal oscillator
    
    // Configure Timer2 for PWM
    T2CONbits.T2CKPS = 0b00;  // Prescaler = 1
    PR2 = 199;                 // PR2 value for 20 kHz PWM frequency
    T2CONbits.TMR2ON = 1;     // Enable Timer2

    // Configure PWM Modules
    
    PWM1CON = 0xC0;
    PWM2CON = 0xC0;
    PWM3CON = 0xC0;
    
    // Set PWM pins as outputs
    TRISCbits.TRISC5 = 0;
    TRISCbits.TRISC3 = 0;
    TRISAbits.TRISA2 = 0;

    // Configure Timer0 for updates
    OPTION_REGbits.T0CS = 0;    // Timer0 Clock Source: Internal
    OPTION_REGbits.PSA = 0;     // Prescaler assigned to Timer0
    OPTION_REGbits.PS = 0b100;  // Prescaler = 1:16

    TMR0 = 256 - 20;            // Preload TMR0

    // Enable Timer0 interrupt
    INTCONbits.TMR0IE = 1;      // Enable Timer0 interrupt
    INTCONbits.GIE = 1;         // Enable Global Interrupts

   init_adc();

     while (1) {
        // Read AN0 for Timer0 reload value
        ADCON0bits.CHS = 0b00000;  // Select AN0
        __delay_us(10);            // Acquisition time
        ADCON0bits.GO_nDONE = 1;   
        while (ADCON0bits.GO_nDONE); // Wait for conversion to complete
        uint16_t adc_value_tmr = ((uint16_t)ADRESH << 8) | ADRESL;

        // Map AN0 ADC value to TMR0 reload value
        tmr0_reload_value = 16 + ((uint32_t)adc_value_tmr * 33) / 1023;
        if (tmr0_reload_value < 16) tmr0_reload_value = 16;
        if (tmr0_reload_value > 49) tmr0_reload_value = 49;

        // Read AN1 for Amplitude Control
        ADCON0bits.CHS = 0b00001;  // Select AN1
        __delay_us(10);            // Acquisition time
        ADCON0bits.GO_nDONE = 1;   
        while (ADCON0bits.GO_nDONE); // Wait for conversion to complete
        uint16_t adc_value_amp = ((uint16_t)ADRESH << 8) | ADRESL;

        // Map AN1 ADC value to Amplitude Percent (0-100%)
        amplitude_percent = (adc_value_amp * 100) / 1023;

        // Clamp amplitude_percent to 0-100%
        if (amplitude_percent > 100) amplitude_percent = 100;

        // Optional: Additional logic or delay
        __delay_ms(10);
    }
}

void __interrupt() ISR(void) {
    if (INTCONbits.TMR0IF) {
        INTCONbits.TMR0IF = 0; // Clear Timer0 interrupt flag

        // Reload TMR0
        TMR0 = 256 - tmr0_reload_value;

        // Update PWM outputs
        update_pwm();
    }
}