#include "reflow.h"
#include "process.h"
#include <math.h>

// nastaveni teplot a casu
#define TEPLOTA_PREDEHREVU    120
#define DOBA_PREDEHREVU       60

#define TEPLOTA_VRCHOLU       210
#define DOBA_VRCHOLU          5

// CPU IO rozhrani
#define LCD_RS          PIN_C1      // rizeni registru LCD displeje
#define LCD_E           PIN_C2      // enable LCD displeje
#define LCD_DATA_LSB    PIN_D0      // data LCD
#include "lcd.c"

#define TL1             PIN_B3      // tlacitko S1
#define TL2             PIN_B2      // tlacitko S2
#define TL3             PIN_B1      // tlacitko S3
#define TL4             PIN_B0      // tlacitko S4

#define POWER_T3        PIN_A3      // ovladani optotriaku T3
#define POWER_T4        PIN_A5      // ovladani optotriaku T4
#define POWER_T5        PIN_A4      // ovladani optotriaku T5

#define ADC_PIN         PIN_A0   //info, nelze menit - pin pouzit jako input analog
#define ADC_PIN_NC      PIN_A1   //info, nelze menit - pin pouzit jako input analog
#define REF_PIN         PIN_A3   //info, nelze menit - pin pouzit jako input reference 2.5V

// interni
#define PowerOn()    output_low(POWER_T4);output_low(POWER_T5)
#define PowerOff()   output_high(POWER_T4);output_high(POWER_T5)

// globalni promenne
struct time
{
   volatile unsigned int8  hod;
   volatile unsigned int8  min;
   volatile unsigned int8  sec;
}cas;

unsigned int top_heat_power=0;  // range 0-200% nad 100% je ale teleso jiz pretizene
unsigned int bottom_heat_power=0; // contains heating power range 0-100%
unsigned int period;

float temp_last=0;

void GeneralCpuInit() // inicializace
{
   output_high(POWER_T4);
   output_high(POWER_T5);
   port_b_pullups(true);
    
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_SS_DISABLED);
   
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);  //nepouzit
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);               // rizeni
   setup_timer_2(T2_DIV_BY_16,249,10);       //rtc 40ms
   
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_TIMER2);
   
   setup_adc_ports(AN0_AN1_VSS_VREF);        //A0 vstup cidla, A1 nepozit, A3 - ref. 2.5V
   setup_adc(ADC_CLOCK_DIV_8);                
   SET_ADC_CHANNEL(0);                       //AN0,  PIN_A0  
}

unsigned int16 adc(void)
{
   unsigned int16 analog;
   unsigned int8  a;

   analog = 0;
   for (a=0;a<32;a++)
   {
      analog += read_adc();
      delay_us(50);
   }
   return (analog >> 5  );         // prumer = analog/32
}

float teplota(void)
{
   return (0.674201*adc() - 294.35);
}

void top_heating()
{
  if (period <= top_heat_power){
    output_low(POWER_T4);
    output_low(POWER_T5);
  }
  else{
    output_high(POWER_T4);
    output_high(POWER_T5);
  }
}

void bottom_heating()
{

  if (period <= 2*bottom_heat_power){
    output_low(POWER_T3);
  }
  else{
    output_high(POWER_T3);
  }

}

#int_TIMER1
void heating_control()        //rizeni topnych teles pri preteceni casovace
{

top_heating();
bottom_heating();

if (period <= 200) period++;
else period=0;
}


#int_TIMER2
void Rtc(void)         //40ms
{
   static unsigned int8 ms40=0;
   struct time* time;
   
   time=&cas;
   if ( ++ms40 < 25) return;
   
   ms40=0;                    
    if (++(time->sec) >= 60)
    {
       time->sec=0;            //1min
        if (++(time->min) >= 60) 
      {
         time->min = 0;                    //1hod
        (time->hod)++;
      }
    }
}

void slope_control(float ramp, unsigned int balance) // P proporcionalni rizeni narustu teploty predpoklada periodicke volani 1x/s
{
float slope_deviation;

slope_deviation = (teplota() - temp_last) - ramp;          // vypocet strmosti a odchylky od pozadovane strmosti

if(slope_deviation < 0)
{
  top_heat_power= slope_deviation*(-10) + balance;
  bottom_heat_power= slope_deviation*(-10);
}
else{
  top_heat_power=0;
  bottom_heat_power=0;
}

temp_last = teplota();
}

void level_control(float level) // P proporcionalni rizeni teploty
{

teplota();

}


void nullcas(struct time* time)
{
   disable_interrupts(INT_TIMER2);
   
   time->sec=0;
   time->hod=0;
   time->min=0;
   
   enable_interrupts(INT_TIMER2);
}

void reflow_solder()
{

// preheat
  nullcas(&cas);

  do {
    slope_control(PREHEAT_SLOPE, 0); // hlida strmost predehrevu 

    lcd_gotoxy(1,1);
    printf(lcd_putc,"%3.1f\21C  ",teplota());

    lcd_gotoxy(9,1);
    printf(lcd_putc,"%2u:%02u:%02u",cas.hod,cas.min,cas.sec);

    delay_ms(1000);
  }
  while (teplota() < SOAK_TEMP);

// soak
  nullcas(&cas);
  while (cas.min*60+cas.sec <= SOAK_TIME)
  {
    level_control(SOAK_TEMP);

    lcd_gotoxy(1,1);
    printf(lcd_putc,"%3.1f\21C  ",teplota());

    lcd_gotoxy(9,1);
    printf(lcd_putc,"%2u:%02u:%02u",cas.hod, SOAK_TIME/60 - cas.min, SOAK_TIME - cas.min*60 - cas.sec);
    delay_ms(1000);
  }
  
// solder
  
}


void main() // main loop 
{
   GeneralCpuInit();
   PowerOff();
   
   lcd_init();
   lcd_define_char(1,LCD_CHAR_STUPEN);
      
   nullcas(&cas);
   
   while(true)
   {
      delay_ms(300);
      
      
      reflow_solder();
      
   }
}