#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include <util/atomic.h>
#include <stdio.h>

#include "usbdrv/usbdrv.h"

#include "display.h"
#include "spi.h"
#include "usb.h"
#include "softtimer.h"

#include "main.h"

uint8_t newThermoData = 1;
uint16_t thermoData[] = {1024, 814, 2475, 2243};


void hardinit() {
  /* initializes the hardware */
  DDRB = _BV(1) | _BV(2) | _BV(0);
  DDRC = 0x3f;

  // no pullups; all digital outputs can take care of themselves
  PORTB = 0x00;
  PORTC = 0x00;
  PORTD = 0x00;

  // hardware pwm for brightness/contrast:
  TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10);
  TCCR1B = _BV(WGM12) | _BV(CS11); // clk/8 prescaler, 4kHz PWM-freq.

  OCR1A = 15; // contrast
  OCR1B = 50; // brightness

  // enable softtimer isr
  TIMSK1 |= _BV(TOIE1);
	
  // init LCD:
  lcd_init(1);
  lcd_clrscr(1);

  spi_init();

  sei();
}

void softinit() {
  lcd_defchar(1, LCD_CHAR_HALFBAR, lcd_halfbar_char);
  lcd_defchar(1, LCD_CHAR_BAR, lcd_bar_char);
  lcd_defchar(1, LCD_CHAR_DEGREE,  lcd_degree_char);
}


int __attribute__((noreturn)) main(void) {
  hardinit();
  softinit();
  usbInit();

  //hard-reset usb for debugging ease #TODO:remove
  cli();
  usbDeviceDisconnect();
  _delay_us(100);
  usbDeviceConnect();
  sei();

    display_gotoyx(0,0);
    display_puts("\nstart");
    display_update();

  for(;;){
    usbPoll();

    SOFTTIMER(2,500) {     
      thermoData[0]=thermoData[0]+5;
      thermoData[1]=thermoData[1]+15;
      thermoData[2]=thermoData[2]+7;
      thermoData[3]=thermoData[3]+18;
      newThermoData = 1;
    }

    SOFTTIMER(1,250) {
      updateTemperature();    
    }

/*    SOFTTIMER(3,100) {
/*        uint8_t foo[4];
        foo[0]=0x55;
        foo[1]=0x88;
        foo[3]=0x23;
        spi_mst_write_read(2,foo);
        spi_mst_start_packet();
        spi_mst_write_read(2,foo+2);
        spi_mst_end_packet();

        uint16_t foo=0x3456;
        foo=spi_master_communicate(3,5,foo);
        display_gotoyx(0,0);
        display_puthex(foo[0]);
        display_puthex(foo[1]);
        display_puthex(foo[2]);
        display_puthex(foo[3]);
        display_puthex((foo>>8)&0xff);
        display_puthex((foo)&0xff);
        display_puts("\nfoo");
        display_update();

    }*/

  }
}

/*
  ISR(TIMER1_OVF_vect, ISR_NAKED){
  asm volatile ("in %0, %1\n" : "=r" (sreg_store) : "I" (_SFR_IO_ADDR(SREG)));
  timer1_acc++;
  asm volatile ("out %1, %0\n" : "=r" (sreg_store) : "I" (_SFR_IO_ADDR(SREG)));
  reti();
  }*/

ISR(TIMER1_OVF_vect,ISR_NOBLOCK){
    uint16_t tmp;
    tmp=timer1_acc;
    tmp++;

    /* the ATOMIC is acutally only needed if timer1_acc is never read from an ISR, which
     * is probably the case.
     * ATOMIC_FORCEON: the ISR_NOBLOCK sets sei() a few cycles before.
     */
    ATOMIC_BLOCK(ATOMIC_FORCEON){ 
        timer1_acc=tmp;
    }

}
