#include "main.h"

__C_task void main(void)
{
  uint8_t i;
  //uint8_t tmp8;

  /* Disable comaparator */
  ACSR = 1<<ACD;

  /* Init LED */
  LED_DDR = LED_1 | LED_2;
  LED_OFF(LED_1);
  LED_OFF(LED_2);

  /* Init 7 segment LED indicators */
  INDCTR_SEGMENT_DDR = 0xFF; // segment pins to output
  INDCTR_SEGMENT_PORT = 0x00; // off all segment

  INDCTR_COMMON_DDR = INDCTR_COMMON_ALL; // common pins to output
  INDCTR_COMMON_PORT = ~INDCTR_COMMON_ALL; // off all indikators

  for(i=0; i<INDCTR_NUMS; i++) {
    Display[i] = Sym_minus;
  }

  Flag.needDot = 0;

  /* Timer0 every 4 ms switch showing LED */
  TCCR0 = TIM0_PRESCALER;
  TCNT0 = TIM0_CNT; // load timer
  TIMSK |= 1<<TOIE0; // enable TIM0_OVF interrupt

  /* Timer1 ticks with 1 MHz frequency for DS18B20 delays */
  TCCR1B = TIM1_PRESCALER;
//  TCNT1 = 64536;
//  TIMSK |= 1<<TOIE1; // enable TIM1_OVF interrupt

  /* ADC init */
  resultADC = 0;
  ADMUX = (1<<REFS0) | (1<<ADLAR); // Vref = AVcc, channel ADC0, Left adjusted result
  ADCSR = 1<<ADEN | 1<<ADPS2 | 1<<ADPS1; // enable ADC, prescaler = 64

  /* I2C init */
  TWI_MasterInit(100);

  __enable_interrupt();

  /* Init Scheduler and TDelay */
  RTOS_Init();

  // Tasks for sheduler
  RTOS_SetTask(startADC,0,50);
  RTOS_SetTask(getTime,4,500);
  RTOS_SetTask(ds18b20_StartMeasure,8,10000);
  
  /* Get time */

  while(1) {
    /*
    if (1 == Flag.newTime) {
      Flag.newTime = 0;

      Display[0] = IndctrNums[(0x0F & (Clock.hours>>4))];
      Display[1] = IndctrNums[(0x0F & Clock.hours)];
      Display[2] = IndctrNums[(0x0F & (Clock.minutes>>4))];
      Display[3] = IndctrNums[(0x0F & Clock.minutes)];
    }
    */

    if (1 == Flag.newTemp) {
      Flag.newTemp = 0;

      Display[0] = Sym_blank;
      Display[1] = IndctrNums[(0x0F & (Temperature>>4))];
      Display[2] = IndctrNums[(0x0F & Temperature)];
      Display[3] = Sym_gradus;
    }

    if (1 == Flag.newBTN) {
      Flag.newBTN = 0;
      
      btn_t btn = getBTN();
      if (btn == btn_1) {
        LED_ON(LED_1);
      } else if (btn == btn_2) {
        LED_ON(LED_2);
      } else if (btn == btn_3) {
        LED_OFF(LED_1);
      } else if (btn == btn_4) {
        LED_OFF(LED_2);
      } else if (btn == btn_5) {
        LED_ON(LED_1);
        LED_ON(LED_2);
      } else if (btn == btn_6) {
        LED_OFF(LED_1);
        LED_OFF(LED_2);
      }
    }

    tdelay_ms(10); // sleep and rotate dispatcher
  } // end of while(1)
} // end of main()

/**
 *  S u b r o u t i n e s
 */

static void startADC(void) {
  // enable interrupt and start conversion
  ADCSR |= ((1<<ADSC) | (1<<ADIE));
}

static btn_t getBTN(void) {
  uint8_t btn_code = resultADC;
  if (btn_code > 0xED) {
    return btn_no;
  } else if (btn_code > 0xD8) {
    return btn_1;
  } else if (btn_code > 0xD0) {
    return btn_2;
  } else if (btn_code > 0xC5) {
    return btn_3;
  } else if (btn_code > 0xB4) {
    return btn_4;
  } else if (btn_code > 0x94) {
    return btn_5;
  } else if (btn_code > 0x3F) {
    return btn_6;
  } else {
    return btn_7;
  }
}

static void getTime(void) {
  static uint8_t old_sec;

  /*устанавливаем указатель DS1307 на нулевой адрес*/
  twi_buf[0] = (DS1307_ADR<<1)|0; //адресный пакет
  twi_buf[1] = 0;                 //адрес регистра   
  TWI_SendData(twi_buf, 2);

  /*считываем время с DS1307*/
  twi_buf[0] = (DS1307_ADR<<1)|1;
  TWI_SendData(twi_buf, 5);

  /*переписываем данные буфера драйвера в свой буфер*/
  TWI_GetData(twi_buf, 5);

  Clock.seconds = twi_buf[1];
  Clock.minutes = twi_buf[2];
  Clock.hours = twi_buf[3];

  if (old_sec != Clock.seconds) {
    Flag.needDot = 1;
    old_sec = Clock.seconds;
  } else {
    Flag.needDot = 0;
  }
  Flag.newTime = 1;
}

static void setTime(void) {
   /*подготавливаем сообщение*/
  twi_buf[0] = (DS1307_ADR<<1)|0; //адресный пакет
  twi_buf[1] = 0;                 //адрес регистра
  twi_buf[2] = Clock.seconds;     //значение секунд 
  twi_buf[3] = Clock.minutes;     //значение минут 
  twi_buf[4] = Clock.hours;       //значение часов

  /*отправляем его*/
  TWI_SendData(twi_buf, 5);
}

/* DS18B20 functions */
static uint8_t ds18b20_Reset(void) {
  uint8_t i;

  /* Pull line low and wait for 480uS */
  DS18B20_LOW;
  DS18B20_OUTPUT_MODE;

  //ds18b20_delay(us(480));
  TCNT1 = 0;
  while (TCNT1 <= 500) {
  }

  /* Release line and wait for 60uS */
  DS18B20_INPUT_MODE;
  //ds18b20_delay(us(60));
  TCNT1 = 0;
  while (TCNT1 <= 70) {
  }

  /* Store line value and wait until the completion of 480uS period */
  i = DS18B20_VALUE;
  //ds18b20_delay(us(420));
  //OCR1B = 420;
  TCNT1 = 0;
  while (TCNT1 <= 430) {
  }

  /* Return the value read from the presence pulse (0=OK, else=WRONG) */
  return i;
}

static void ds18b20_WriteBit(uint8_t bit) {
  /* Pull line low for 1uS */
  DS18B20_LOW;
  DS18B20_OUTPUT_MODE;
  //ds18b20_delay(us(1));
  TCNT1 = 0;
  while (TCNT1 <= 1);

  /* If we want to write 1, release the line (if not will keep low) */
  if(1 == bit) {
    DS18B20_INPUT_MODE;
  }

  /* Wait for 60uS and release the line */
  //ds18b20_delay(us(60));
  TCNT1 = 0;
  while (TCNT1 <= 60) {
  }

  DS18B20_INPUT_MODE;
}

static uint8_t ds18b20_ReadBit(void) {
  uint8_t bit=0;

  /* Pull line low for 1uS */
  DS18B20_LOW;
  DS18B20_OUTPUT_MODE;
  //ds18b20_delay(us(1));
  TCNT1 = 0;
  while (TCNT1 <= 1);

  /* Release line and wait for 14uS */
  DS18B20_INPUT_MODE;
  //ds18b20_delay(us(14));
  TCNT1 = 0;
  while (TCNT1 <= 14) {
  }

  /* Read line value */
  if (DS18B20_VALUE != 0) {
    bit = 0x80;
  }

  /* Wait for 45uS to end and return read value */
  //ds18b20_delay(us(45));
  TCNT1 = 0;
  while (TCNT1 <= 45) {
  }

  return bit;
}

static uint8_t ds18b20_ReadByte(void) {
  uint8_t i=8, n=0;

  while (i--) {
    /* Shift one position right and store read value */
    n >>= 1;
    n |= ds18b20_ReadBit();
  }
  return n;
}

static void ds18b20_WriteByte(uint8_t byte) {
  uint8_t i=8;

  while (i--) {
    /* Write actual bit and shift one position right to make the next bit ready */
    ds18b20_WriteBit(byte & 0x01);
    byte >>= 1;
  }
}

static void ds18b20_StartMeasure(void) {
  /* Reset, skip ROM and start temperature conversion */
  if (ds18b20_Reset() != 0) {
    Temperature = -99;
    Flag.newTemp = 1;
  } else {
    ds18b20_WriteByte(DS18B20_CMD_SKIPROM);
    ds18b20_WriteByte(DS18B20_CMD_CONVERTTEMP);
    RTOS_SetTask(ds18b20_ReadTemperature, 800, 0);
  }
}

static void ds18b20_ReadTemperature(void) {
  uint8_t temperature[2];

  /* Reset, skip ROM and send command to read Scratchpad */
  if (ds18b20_Reset() != 0) {
    Temperature = -98;
  } else {
    ds18b20_WriteByte(DS18B20_CMD_SKIPROM);
    ds18b20_WriteByte(DS18B20_CMD_RSCRATCHPAD);

    /* Read Scratchpad (only 2 first bytes) */
    temperature[0]=ds18b20_ReadByte();
    temperature[1]=ds18b20_ReadByte();

    //ds18b20_reset();

    /* Store temperature integer digits */
    Temperature = ((temperature[1]&0x7)<<4) | (temperature[0]>>4);

    /* Get only integer part of temperature */
//    Temperature = (int8_t)digit;

    //выделяем с помощью битовой маски дробную часть
    tempDecimals = (temperature[0] & 15);
    
    //преобразуем в целое число
    tempDecimals *= 10; //(tempDecimals << 1) + (tempDecimals << 3);// Умножаем на 10
    tempDecimals >>= 4; //(tempDecimals >> 4);//делим на 16 или умножаем на 0.0625
    
    if (tempDecimals > 4) {
      Temperature ++;
    }
  }
  Flag.newTemp = 1;
}


/**
 *  I n t e r r u p t   h a n d l e r s
 */

#pragma vector=TIMER0_OVF_vect
__interrupt void TIMER0_OVF_ISR(void) {
  static uint8_t indicator = 0;

  TCNT0 = TIM0_CNT; // reload timer

  INDCTR_COMMON_PORT &= ~INDCTR_COMMON_ALL; // off all indikators

  switch (indicator) {
  case 0:
    INDCTR_SEGMENT_PORT = Display[0];
    INDCTR_COMMON_PORT |= 0x01;
    indicator = 1;
    break;

  case 1:
    if (1 == Flag.needDot) {
      INDCTR_SEGMENT_PORT = Display[1] | Sym_dot;
    } else {
      INDCTR_SEGMENT_PORT = Display[1];
    }
    INDCTR_COMMON_PORT |= 0x02;
    indicator = 2;
    break;

  case 2:
    INDCTR_SEGMENT_PORT = Display[2];
    INDCTR_COMMON_PORT |= 0x04;
    indicator = 3;
    break;

  case 3:
    INDCTR_SEGMENT_PORT = Display[3];
    INDCTR_COMMON_PORT |= 0x08;

  default:
    indicator = 0;
    break;
  }
}

#pragma vector=TIMER1_COMPA_vect
__interrupt void TIMER1_COMPA_ISR(void) {
}

#pragma vector=TIMER1_COMPB_vect
__interrupt void TIMER1_COMPB_ISR(void) {
}

#pragma vector=TIMER1_OVF_vect
__interrupt void TIMER1_OVF_ISR(void) {
  Flag.T1OC = 1;
}

#pragma vector=ADC_vect
__interrupt void ADC_ISR(void) {
  resultADC = ADCH;
  ADCSR &= ~(1<<ADIE); // disable interrupt
  Flag.newBTN = 1;
}
