

// ------- Preamble -------- //
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/power.h>

#include "pinDefines.h"
#include "USART.h"

#include "i2c.h"                                  /* for i2c functions */
#include "25LC256.h"                            /* for EEPROM specific */

// -------- Defines --------- //

#define LM75_ADDRESS_W 0b10010000
#define LM75_ADDRESS_R 0b10010001
#define LM75_TEMP_REGISTER           0b00000000
#define LM75_CONFIG_REGISTER         0b00000001
#define LM75_THYST_REGISTER          0b00000010
#define LM75_TOS_REGISTER            0b00000011

#define CURRENT_LOCATION_POINTER  0
          /* where to store a pointer to the current reading in EEPROM */
#define SECONDS_POINTER           2
                                     /* store seconds-delay value here */
#define MEMORY_START              4
                          /* where to start logging temperature values */
#define MENU_DELAY                5
                         /* seconds to wait before bypassing main menu */

// -------- Functions --------- //

static inline void printTemperature(uint8_t tempReading) {
                                   /* temperature stored as 2x Celcius */
  printByte((tempReading >> 1));
  if (tempReading & 1) {
    printString(".5\r\n");
  }
  else {
    printString(".0\r\n");
  }
}

int main(void) {
  uint16_t secondsDelay;          /* how long to wait between readings */
  uint16_t currentMemoryLocation;           /* where are we in EEPROM? */
  uint16_t i;                        /* used to count memory locations */
  uint8_t tempHighByte, tempLowByte, temperatureByte;     /* from LM75 */
  uint8_t enterMenu;                                   /* logical flag */

  // -------- Inits --------- //
  clock_prescale_set(clock_div_1);                            /* 8 MHz */
  initSPI();
  initI2C();
  initUSART();
  LED_DDR |= (1 << LED0);

                                    /* Load up last values from EEPROM */
  secondsDelay = EEPROM_readWord(SECONDS_POINTER);

                            /* Delay to allow input to enter main menu */
  printString("*** Press [m] within ");
  printByte(MENU_DELAY);
  printString(" seconds to enter menu. ***\r\n ");

  for (i = 0; i < MENU_DELAY; i++) {
    _delay_ms(1000);
  }

  if (bit_is_set(UCSR0A, RXC0) && (UDR0 == 'm')) {
    enterMenu = 1;
  }
  else {
    enterMenu = 0;
  }

  while (enterMenu) {
    printString("\r\n====[  Logging Thermometer ]====\r\n  ");
    currentMemoryLocation = EEPROM_readWord(CURRENT_LOCATION_POINTER);
    printWord(currentMemoryLocation - MEMORY_START);
    printString(" readings in log.\r\n  ");
    printWord(secondsDelay);
    printString(" seconds between readings.\r\n");
    printString(" [<] to shorten sample delay time\r\n");
    printString(" [>] to increase sample delay time\r\n");
    printString(" [?] to reset delay time to 60 sec\r\n");
    printString(" [d] to print out log over serial\r\n");
    printString(" [e] to erase memory\r\n");
    printString(" [s] to start logging\r\n\r\n");

    switch (receiveByte()) {
    case 'd':
      SLAVE_SELECT;
      SPI_tradeByte(EEPROM_READ);
      EEPROM_send16BitAddress(MEMORY_START);
      for (i = MEMORY_START; i < currentMemoryLocation; i++) {
        SPI_tradeByte(0);
        printTemperature(SPDR);
      }
      SLAVE_DESELECT;
      break;
    case '<':
      if (secondsDelay >= 10) {
        secondsDelay -= 5;
        EEPROM_writeWord(SECONDS_POINTER, secondsDelay);
      }
      break;
    case '>':
      if (secondsDelay < 65000) {
        secondsDelay += 5;
        EEPROM_writeWord(SECONDS_POINTER, secondsDelay);
      }
      break;
    case '?':
      secondsDelay = 60;
      EEPROM_writeWord(SECONDS_POINTER, secondsDelay);
      break;
    case 'e':
      printString("Clearing EEPROM, this could take a few seconds.\r\n");
      EEPROM_clearAll();
      EEPROM_writeWord(CURRENT_LOCATION_POINTER, MEMORY_START);
      EEPROM_writeWord(SECONDS_POINTER, secondsDelay);
      break;
    case 's':
      printString("OK, logging...\r\n");
      enterMenu = 0;
      break;
    default:
      printString("Sorry, didn't understand that.\r\n");
    }
  }

  // ------ Event loop ------ //
  while (1) {

    currentMemoryLocation = EEPROM_readWord(CURRENT_LOCATION_POINTER);

                                      /* Make sure in temperature mode */
    i2cStart();
    i2cSend(LM75_ADDRESS_W);
    i2cSend(LM75_TEMP_REGISTER);
                                          /* Get Temp from thermometer */
    i2cStart();               /* Setup and send address, with read bit */
    i2cSend(LM75_ADDRESS_R);
    tempHighByte = i2cReadAck();           /* two bytes of temperature */
    tempLowByte = i2cReadNoAck();
    i2cStop();
    temperatureByte = (tempHighByte << 1) | (tempLowByte >> 7);
         /* temperatureByte now contains 2x the temperature in Celcius */
    printTemperature(temperatureByte);                /* serial output */

                                     /* Save the new temperature value */
    EEPROM_writeByte(currentMemoryLocation, temperatureByte);

    /* move on to next location and record new position
       if not already at the end of memory */
    if (currentMemoryLocation < EEPROM_BYTES_MAX) {
      currentMemoryLocation++;
      EEPROM_writeWord(CURRENT_LOCATION_POINTER, currentMemoryLocation);
    }

                                                              /* delay */
    for (i = 0; i < secondsDelay; i++) {
      _delay_ms(1000);
      LED_PORT ^= (1 << LED0);             /* blink to show working */
    }

  }                                                  /* End event loop */
  return 0;                            /* This line is never reached */
}
