#include <xc.h>
#include <stdint.h>

#define _XTAL_FREQ 16000000 // 16 MHz oscillator frequency

#define SINE_TABLE_SIZE 256

// Sine table with values from 0 to 1023 for 10-bit PWM
const uint16_t sine_table[SINE_TABLE_SIZE] = {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,};

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

// Variables for V/F control
volatile uint16_t amplitude_scaling = 784; // Default to maximum amplitude
volatile uint16_t frequency_scaling = 1; // Not used in this version

// Timer0 variables
volatile uint8_t tmr0_reload_value = 0;

void update_pwm(void);
void init_ADC(void);
uint16_t read_ADC(uint8_t channel);
void init_PWM(void);
void init_Timer0(uint16_t freq_adc);
void init_Oscillator(void);
void init_PPS(void);

void update_pwm(void)
{
// Get the raw sine values
uint16_t raw_dutyA = sine_table[phaseA_index];
uint16_t raw_dutyB = sine_table[phaseB_index];
uint16_t raw_dutyC = sine_table[phaseC_index];

// Scale the amplitude based on the amplitude_scaling factor (0 to 1023)
uint16_t dutyA = (raw_dutyA * amplitude_scaling) / 784;
uint16_t dutyB = (raw_dutyB * amplitude_scaling) / 784;
uint16_t dutyC = (raw_dutyC * amplitude_scaling) / 784;

// Set PWM duty cycles (10-bit values)
PWM1DCH = (dutyA >> 2) & 0xFF;
PWM1DCL = (dutyA & 0x0003) << 6;

PWM2DCH = (dutyB >> 2) & 0xFF;
PWM2DCL = (dutyB & 0x0003) << 6;

PWM3DCH = (dutyC >> 2) & 0xFF;
PWM3DCL = (dutyC & 0x0003) << 6;

// Increment phase indexes by 1
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 main(void) {
init_Oscillator();
init_PWM();
init_PPS();
init_ADC();

// Initial frequency setup
uint16_t freq_adc = read_ADC(1);  // Initial frequency ADC value
init_Timer0(freq_adc);            // Initialize Timer0 with initial frequency

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

while (1) {
    // Read ADC values for amplitude and frequency
    amplitude_scaling = read_ADC(0);  // 10-bit result (0 to 1023)
    freq_adc = read_ADC(1);           // 10-bit result (0 to 1023)

    // Update Timer0 settings based on frequency ADC input
    init_Timer0(freq_adc);
}

}

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

    // Reload TMR0
    TMR0 = tmr0_reload_value;

    // Update PWM outputs
    update_pwm();
}

// Add ADC interrupt handling if using interrupt-driven ADC (optional)

}

void init_ADC(void) {
// Configure ADC
ADCON1bits.ADCS = 0b110; // ADC Conversion Clock FOSC/64
ADCON1bits.ADFM = 1; // Right justified result
ADCON1bits.ADPREF = 0b00; // Vref+ is Vdd

// Configure ADC input channels
ANSELAbits.ANSA0 = 1;  // RA0 as analog input (AN0)
ANSELAbits.ANSA1 = 1;  // RA1 as analog input (AN1)

TRISAbits.TRISA0 = 1;  // Set RA0 as input
TRISAbits.TRISA1 = 1;  // Set RA1 as input

ADCON0bits.ADON = 1;   // Turn on ADC

}

uint16_t read_ADC(uint8_t channel) {
// Select ADC channel
ADCON0bits.CHS = channel; // Select ADC channel
__delay_us(5); // Acquisition time

// Start conversion
ADCON0bits.GO_nDONE = 1;
while (ADCON0bits.GO_nDONE);  // Wait for conversion to complete

// Get ADC result
uint16_t result = ((ADRESH << 8) | ADRESL);
return result;  // 10-bit result

}

void init_PWM(void) {
// 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
PWM1CONbits.PWM1POL = 0;  // Active-high
PWM1CONbits.PWM1OE = 1;   // PWM1 Output Enable
PWM1CONbits.PWM1EN = 1;   // Enable PWM1

PWM2CONbits.PWM2POL = 0;
PWM2CONbits.PWM2OE = 1;
PWM2CONbits.PWM2EN = 1;

PWM3CONbits.PWM3POL = 0;
PWM3CONbits.PWM3OE = 1;
PWM3CONbits.PWM3EN = 1;

}

void init_Timer0(uint16_t freq_adc) {
// Configure Timer0 for updates based on frequency ADC value
// Calculate the Timer0 preload value to achieve desired sine wave frequency

// Constants
uint32_t FOSC = 16000000UL;    // 16 MHz
uint32_t F_TIMER0 = FOSC / 4;  // Timer0 clock frequency (Fosc/4) = 4 MHz
uint8_t prescaler = 16;        // Prescaler value (options: 2, 4, 8, 16, 32, 64, 128, 256)

// Map freq_adc (0-1023) to desired frequency range (e.g., 10 Hz to 200 Hz)
// Adjust the frequency range as needed
uint16_t min_freq = 10;    // Minimum frequency in Hz
uint16_t max_freq = 200;   // Maximum frequency in Hz

// Map freq_adc to frequency
uint16_t desired_freq = min_freq + ((uint32_t)(max_freq - min_freq) * freq_adc) / 1023;

if (desired_freq < min_freq) desired_freq = min_freq;
if (desired_freq > max_freq) desired_freq = max_freq;

// Calculate the Timer0 interrupt interval (in seconds)
double interrupt_interval = 1.0 / (desired_freq * SINE_TABLE_SIZE);

// Calculate the required Timer0 counts
uint32_t timer_counts = interrupt_interval * F_TIMER0 / prescaler;

// Ensure timer_counts is less than 256 (8-bit Timer0)
if (timer_counts > 255) {
    timer_counts = 255;
} else if (timer_counts < 2) {
    timer_counts = 2;  // Minimum practical value
}

// Calculate the preload value
tmr0_reload_value = 256 - (uint8_t)timer_counts;

// Configure Timer0
OPTION_REGbits.T0CS = 0;    // Timer0 Clock Source: Internal (FOSC/4)
OPTION_REGbits.PSA = 0;     // Prescaler assigned to Timer0
OPTION_REGbits.PS = 0b100;  // Prescaler = 1:16

// Set TMR0 to reload value
TMR0 = tmr0_reload_value;

}

void init_Oscillator(void) {
// Oscillator configuration
OSCCONbits.IRCF = 0b1111; // 16 MHz internal oscillator
OSCCONbits.SCS = 0b10; // Internal oscillator
}
move Tmr0 calculations into adc module and only need 10hz to 60hz