#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "yaMBSiavr.h"
#include "pt100.h"

void init_clk(void)
{
    // ========= System Clock configuration =========
    // Set to external 16Mhz crystal, using the PLL at *2
    // set it to be a 12-16Mhz crystal with a slow start-up time.
    OSC.XOSCCTRL = OSC_FRQRANGE_2TO9_gc | OSC_XOSCSEL_XTAL_16KCLK_gc ;
    OSC.CTRL |= OSC_XOSCEN_bm ; // enable it
    while( (OSC.STATUS & OSC_XOSCRDY_bm) == 0 ){} // wait until it's stable

    // The external crystal is now running and stable.
    // (Note that it's not yet selected as the clock source)
    // Now configure the PLL to be eXternal oscillator * 2
    OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2;

    // now enable the PLL...
    OSC.CTRL |= OSC_PLLEN_bm ; // enable the PLL...
    while( (OSC.STATUS & OSC_PLLRDY_bm) == 0 ){} // wait until it's stable

    // And now, *finally*, we can switch from the internal 2Mhz clock to the PLL
    CCP = CCP_IOREG_gc;	// protected write follows   
    CLK.CTRL = CLK_SCLKSEL_PLL_gc;	// The System clock is now  PLL (16Mhz * 2)
    // ==============================================
}

void init_timer_100us(){
    TCC0.CTRLA |= TC_CLKSEL_DIV256_gc;
    TCC0.PER = 13; // ==> 9615Hz
    TCC0.INTCTRLA |= TC_OVFINTLVL_HI_gc;
}

void io_setup(void){
    // LED
    PORTD.DIRSET = 1 << 5;

    // pullups for address switch
    PORTCFG.MPCMASK = 0xFF;
    PORTC.PIN1CTRL = PORT_OPC_PULLUP_gc;
}

void modbusGet(void) {
	if (modbusGetBusState() & (1<<ReceiveCompleted))
    {
        PORTD.OUTSET = 1 << 5;
        switch(rxbuffer[1]) {
            case fcReadHoldingRegisters: ;
                modbusExchangeRegisters((uint16_t*)ch_values, 0, 20);
                break;
            default:
                modbusSendException(ecIllegalFunction);
                break;
        }
        PORTD.OUTCLR = 1 << 5;
    }
}

int main(void){
    init_clk();
    io_setup();

    // blink LED on startup
    PORTD.OUTTGL = 1 << 5;
    _delay_ms(500);
    PORTD.OUTTGL = 1 << 5;

    // init pt100 stuff
    adc_init();
    dma_init();

    // setup modbus tick timer
    init_timer_100us();

    PMIC.CTRL |= PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm; 
    sei();

    modbusSetAddress(1);
    modbusInit();

    for(;;){
        modbusGet();
    }
}

ISR(TCC0_OVF_vect){
    modbusTickTimer();
}
