
#include "io430.h"
#include "stdint.h"
#include "stdbool.h"

#define OUT_TEMP BIT5
#define INPUT_TEMP BIT4

#define SHIFT_REG_LATCH     BIT0
#define SHIFT_REG_SDA       BIT1
#define SHIFT_REG_CLK       BIT2
#define SHIFT_REG_OE        BIT3

#define LIGHT_IN            BIT3
#define TEMP_INPUT          BIT0

#define LATCH_E    P2OUT |= SHIFT_REG_LATCH; __delay_cycles(1000); P2OUT &= ~SHIFT_REG_LATCH

const char numbers_1[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; // szegmensek
const char numbers[] = {0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x10}; // szegmensek
const char digits[] = {0x06, 0x05, 0x03}; // digitek

unsigned int adc_temp[64];          // ADC tároló
long homero_atlag = 0, volt=0;
int k_fok;
bool f_sign=false;
char digits_count=0, display_data;
bool contrast=false;
int contrast_count=1000;
int display_count;
bool temp_input=false;
bool inout_temp = false;

void shift_reg_write(uint8_t byte){
     
     char bit_count=8;                 // kiírandó bit számláló
     
     while(bit_count--){               // kiíró ciklus
          P2OUT &= ~SHIFT_REG_SDA;     // shift regiszter SDA láb alacsony
          if(byte &(1<<bit_count))     // ha a bit 1 azaz magas
               P2OUT |= SHIFT_REG_SDA; // akkor SDA magas
          P2OUT |= SHIFT_REG_CLK;      // shift regiszter órajel magas
          P2OUT &= ~SHIFT_REG_CLK;     // shift regiszter órajel alacsony
     } // while
} // void

void analog_setup(uint16_t csat, uint8_t port){
    ADC10CTL0 &= ~ENC;
    ADC10CTL1 = CONSEQ_2 + csat;                     // többszöri konverzió, a "csat" bemenetről
    ADC10CTL0 = SREF_1 + ADC10SHT_2 + MSC + REFON + REF2_5V + ADC10ON + ADC10IE; 
    // ADC10ON, megszakítás eng, referencia be, ref 2.5volt
    ADC10DTC1 = 0x40;                                // 64 konverzió
    ADC10AE0 = port;                                 // ADC bemenet kiválasztása
}  // -- analog_setup void
void AD_CONV(){
    ADC10CTL0 &= ~ENC;                         // analóg kikapcsolása
    while (ADC10CTL1 & BUSY);                  // várunk, ha ADC10 foglalt
    ADC10SA = (uint16_t) adc_temp;             // adatok mentése "adc_temp"-be
    ADC10CTL0 |= ENC + ADC10SC;                // mintavétel és konverzió indítása
    __low_power_mode_0();                      // LPM0 mód bekapcsolás 
}  // -- AD_CONV void

void display_write(int data, bool out_temp){
     
     shift_reg_write(digits[digits_count]);  // digit shift regiszter
     
     switch(digits_count++){     // szegmens shift regiszter
        case 0:                  // első szegmens
          if(f_sign){            // ha minusz az adat
               if(data< 10){     // ha 10-nél kisebb
                    shift_reg_write(digits[1]); // a második digitre kerül az előjel
                    digits_count++; // digit számláló nöcelése, hogy kihadjuk a második digitet
               } // if
               display_data = 0xbf;   // '-' előjel
               f_sign = false;        // előjel változó nullázása
          }else                       // ha nincs előjel
               display_data = 0xff;   // üres az első digit
          break;
        case 1:                       // második digit
          if(data<10){                // ha 10-nél kisebb
               display_data = 0xff;   // üres digit
          }else{
               display_data = numbers_1[data /10]; // kiírandó érték számolása
          } // else
          break;
        case 2:                                  // harmadik digit
          if(out_temp)                           // ha belső hőmérő
              display_data = numbers[data%10];   // akkor van pont (DP) 
          else                                   // ha külső hőmérő
              display_data = numbers_1[data%10]; // akkor nincs pont kiírás
          digits_count = 0;                      // digit számláló nullázása
          break;
    } // switch
    if(contrast){                      // kijelző kontrast állító rutin
         while(contrast_count--){      // számláló ciklus
              P2OUT |= SHIFT_REG_OE;   // 74hc595 OE láb engedélyezése
         } // while
         contrast_count=300;          // számláló változó értékadás
         P2OUT &= ~SHIFT_REG_OE;       // OE láb alacson
    } // if
    
    shift_reg_write(display_data);     // szegmens kiíró rutin hívás
    LATCH_E;                           // 74hc595 kimenetek engedélyezése
} // void
//-----------------------------------------------------------------------
void main( void ){
    
    // Stop watchdog timer to prevent time out reset
    WDTCTL = WDTPW + WDTHOLD;
    
    BCSCTL1 = CALBC1_1MHZ;      // Kalibrált 1MHz
    DCOCTL = CALDCO_1MHZ;
    
    P2DIR |= (SHIFT_REG_CLK + SHIFT_REG_SDA + SHIFT_REG_LATCH + SHIFT_REG_OE);
    P2OUT |= SHIFT_REG_LATCH;
    P2OUT &= ~SHIFT_REG_OE;
    
//    P1DIR |= BIT0;
//    P1OUT &= ~BIT0;
    
    P1DIR &= ~(LIGHT_IN + TEMP_INPUT);
    P1IES |= (LIGHT_IN + TEMP_INPUT);
    P1REN |= TEMP_INPUT;
    P1OUT &= ~TEMP_INPUT;
    P1IE |= (LIGHT_IN + TEMP_INPUT);
    P1IFG &= ~(LIGHT_IN + TEMP_INPUT);
    
    __enable_interrupt();

    while(1){
        switch(temp_input){
          case true:                            // belső hőmérő
            analog_setup(INCH_4, INPUT_TEMP);   // analóg beállítás A4 input
            AD_CONV();                          // hőmérő érték beolvasása
            inout_temp = true;                  // értékadás
            break;
          case false:                         // külső hőmérő
            analog_setup(INCH_5, OUT_TEMP);   // analóg beállítás A5 input
            AD_CONV();                        // hőmérő érték beolvasása
            inout_temp = false;               // értékadás
            break;
        } // switch
        
        homero_atlag = 0;                 // töröljük a vátozót
        for(char i=0; i<63; i++)          // beolvasott értékek
            homero_atlag += adc_temp[i];  // összeadása
        homero_atlag = homero_atlag >> 6; // átlag számolás
        volt = homero_atlag * 2500;       // mV kiszámítás
        volt /= 1024;                     // volt / ADC 10bit
        k_fok = (volt - 500);             // C° kiszámolás
        k_fok /=10;                       // fok osztás 10-el, nem kell tized pontosság
        if(k_fok<0){            // ha mínusz
            f_sign = true;      // előjek jelző
            k_fok *= -1;        // érték legyen plusz
        } //if
        
        display_count = 1000;                 // kiírás számláló értékadás
        while(display_count--){               // megjelenítés ciklus
            display_write(k_fok, inout_temp); // megjelenítés
        } // while
    } // while
} // main
// ---------------- Megszakítások ---------------------
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void){
  __low_power_mode_off_on_exit();        // Ébresztő
}  // ADC10
// --- Port 1 interrupt ---
#pragma vector=PORT1_VECTOR
__interrupt void Port1_int(void){
    
    if(P1IFG & TEMP_INPUT){      // hőszenzor választó
        if(temp_input)           // ha külső hőmérő
            temp_input = false;  // akkor 0
        else                     // ha belső
            temp_input = true;   // akkor 1
    }else {
        if(P1IN & LIGHT_IN){     // világítás figyelés
            P1IES &= ~LIGHT_IN;  // megszakítás bemenet élváltás
            contrast = true;
        }else {
            P1IES |= LIGHT_IN;   // megszakítás bemenet élváltás
            contrast = false;
        } // else
    } //if
    P1IFG &= ~(LIGHT_IN + TEMP_INPUT);  // P1 flag törlés
     __low_power_mode_off_on_exit();
} // port 1