#include "MCP7940_ADI.h"

#include <Wire.h>

// Serial Monitor Cheat Cheat for setting time and alarms
//  SETTING TIME
// format set a to 1 if 12hr mode, then b to 1 if PM, otherwise set to 00 for 24hr mode
// Thh:mm:22 ab mm/dd/yr w

// Example for setting time to 3:41:00PM 2/4/17 SAT
////T03:41:00 11 02/04/17 7

// SETTING ALARM
//  abc = alarm mask, like 001=Minutes alarm
//  d = AM/PM, 1=PM w=weekday
// A0hh:mm:ss abc d mm/dd w
// Example for setting alarm for 12:13PM on Sunday 2/4
// A012:13:00 111 1 02/04 1

// defines
#define RTCADDR B1101111 // page11 datasheet
#define RTCSEC 0x00
#define RTCMIN 0x01
#define RTCHOUR 0x02
#define RTCWKDAY 0x03
#define RTCDATE 0x04
#define RTCMTH 0x05
#define RTCYEAR 0x06
#define CONTROL 0x07
#define OSCTRIM 0x08
#define ALM0SEC 0x0A
#define ALM0MIN 0x0B
#define ALM0HOUR 0x0C
#define ALM0WKDAY 0x0D
#define ALM0DATE 0x0E
#define ALM0MTH 0x0F
#define ALM1SEC 0x11
#define ALM1MIN 0x12
#define ALM1HOUR 0x13
#define ALM1WKDAY 0x14
#define ALM1DATE 0x15
#define ALM1MTH 0x16
#define PWRDNMIN 0x18
#define PWRDNHOUR 0x19
#define PWRDNDATE 0x1A
#define PWRDNMTH 0x1B
#define PWRUPMIN 0x1C
#define PWRUPHOUR 0x1D
#define PWRUPDATE 0x1E
#define PWRUPMTH 0x1F

// variables used here
byte rtcSeconds, rtcMinutes, rtcHours;
byte rtcWeekDay, rtcDay, rtcMonth, rtcYear;
boolean rtc12hrMode, rtcPM, rtcOscRunning, rtcPowerFail, rtcVbatEn;
String weekDay[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
boolean mfpPinTriggered = false;

void rtcInit()
{ // RTC Initialize
  int i;
  // sets up I2C at 100kHz
  Wire.setClock(100000);
  Wire.begin();

  Wire.beginTransmission(RTCADDR);
  Wire.write(CONTROL);
  Wire.write(0x00); // clear out the entire control register // was 0x41
  Wire.endTransmission();

  Wire.beginTransmission(RTCADDR);
  Wire.write(RTCWKDAY);
  Wire.endTransmission();
  Wire.requestFrom(RTCADDR, 1);
  delay(1);
  byte rtcWeekdayRegister = Wire.read();
  rtcWeekdayRegister |= 0x08; // enable Battery backup
  Wire.beginTransmission(RTCADDR);
  Wire.write(RTCWKDAY);
  Wire.write(rtcWeekdayRegister);
  Wire.endTransmission();

  Wire.beginTransmission(RTCADDR);
  Wire.write(RTCSEC);
  Wire.endTransmission();
  Wire.requestFrom(RTCADDR, 1);
  delay(1);
  byte rtcSecondRegister = Wire.read(); // read out seconds
  rtcSecondRegister |= 0x80;            // flip the start bit to ON
  Wire.beginTransmission(RTCADDR);
  Wire.write(RTCSEC);
  Wire.write(rtcSecondRegister); // write it back in... now the RTC is running
  Wire.endTransmission();

  // read time out of rtc
  Wire.beginTransmission(RTCADDR);
  Wire.write(RTCSEC);
  Wire.endTransmission();
  Wire.requestFrom(RTCADDR, 7); // pull out all timekeeping registers
  delay(1);                     // little delay
}

uint32_t getEpochRtc(void)
{

  uint32_t ep;

  Wire.beginTransmission(RTCADDR);
  Wire.write(RTCSEC);
  Wire.endTransmission();
  Wire.requestFrom(RTCADDR, 7); // pull out all timekeeping registers
  delay(1);                     // little delay

  // now read each byte in and clear off bits we don't need, hence the AND operations
  rtcSeconds = Wire.read() & 0x7F;
  rtcMinutes = Wire.read() & 0x7F;
  rtcHours = Wire.read() & 0x7F;
  rtcWeekDay = Wire.read() & 0x3F;
  rtcDay = Wire.read() & 0x3F;
  rtcMonth = Wire.read() & 0x3F;
  rtcYear = Wire.read();

  // now format the data, combine lower and upper parts of byte to give decimal number
  rtcSeconds = (rtcSeconds >> 4) * 10 + (rtcSeconds & 0x0F);
  rtcMinutes = (rtcMinutes >> 4) * 10 + (rtcMinutes & 0x0F);

  if ((rtcHours >> 6) == 1) // check for 12hr mode
    rtc12hrMode = true;
  else
    rtc12hrMode = false;

  // 12hr check and formatting of Hours
  if (rtc12hrMode)
  { // 12 hr mode so get PM/AM
    if ((rtcHours >> 5) & 0x01 == 1)
      rtcPM = true;
    else
      rtcPM = false;
    rtcHours = ((rtcHours >> 4) & 0x01) * 10 + (rtcHours & 0x0F); // only up to 12
  }
  else
  { // 24hr mode
    rtcPM = false;
    rtcHours = ((rtcHours >> 4) & 0x03) * 10 + (rtcHours & 0x0F); // uses both Tens digits, '23'
  }

  // weekday register has some other bits in it, that are pulled out here
  if ((rtcWeekDay >> 5) & 0x01 == 1)
    rtcOscRunning = true; // good thing to check to make sure the RTC is running
  else
    rtcOscRunning = false;
  if ((rtcWeekDay >> 4) & 0x01 == 1)
    rtcPowerFail = true; // if the power fail bit is set, we can then go pull the timestamp for when it happened
  else
    rtcPowerFail = false;
  if ((rtcWeekDay >> 3) & 0x01 == 1) // check to make sure the battery backup is enabled
    rtcVbatEn = true;
  else
    rtcVbatEn = false;

  rtcWeekDay = rtcWeekDay & 0x07; // only the bottom 3 bits for the actual weekday value

  // more formatting bytes into decimal numbers
  rtcDay = (rtcDay >> 4) * 10 + (rtcDay & 0x0F);
  rtcMonth = ((rtcMonth >> 4) & 0x01) * 10 + (rtcMonth & 0x0F);
  rtcYear = (rtcYear >> 4) * 10 + (rtcYear & 0x0F);

  dt.Second = rtcSeconds;
  dt.Minute = rtcMinutes;
  dt.Hour = rtcHours;
  dt.Wday = rtcWeekDay;
  dt.Day = rtcDay;
  dt.Month = rtcMonth;
  dt.Year = rtcYear;

  // dt.Year += 30; //from 1970. not  2000
  dt.Year += 30;
  ep = makeTime(dt);
  // dt.Year -= 30;

  if (VB)
  {
    Serial.print("Epoch Created: ");
    Serial.println(ep);
    // print everything out
    Serial.print(rtcHours);
    Serial.print(":");
    Serial.print(rtcMinutes);
    Serial.print(":");
    Serial.print(rtcSeconds);

    if (rtc12hrMode == true && rtcPM == true)
      Serial.print(" PM ");
    else if (rtc12hrMode == true && rtcPM == false)
      Serial.print(" AM ");

    if (rtc12hrMode == false)
      Serial.print(" 24hr ");

    if (rtcWeekDay > 0)
      if (rtcWeekDay < 8)
      {
        // Serial.print("WeekDay=");
        // Serial.print(rtcWeekDay);
        Serial.print(weekDay[rtcWeekDay - 1]);
        Serial.print(" ");
        Serial.print(rtcMonth);
        Serial.print("/");
        Serial.print(rtcDay);
        Serial.print("/");
        Serial.print(rtcYear);
        Serial.println("");
      }
  }

  return (ep);
}

/*
  void checkAlarm() {
  if (mfpPinTriggered == true) {
    Serial.println("MFP Triggered");
    mfpPinTriggered = false;
    Wire.beginTransmission(RTCADDR);//Enable Alarm0
    Wire.write(ALM0WKDAY);
    Wire.endTransmission();
    Wire.requestFrom(RTCADDR, 1);
    delay(1);
    byte alarm0Check = Wire.read();
    Serial.println(alarm0Check, BIN);
    if (((alarm0Check >> 3) & 0x01) == 1)
      Serial.println("Alarm0 Triggered");
    else Serial.println("Alarm0 False Alarm");
  }

  }
*/

void setEpochRtc(uint32_t ep)
{
  tmElements_t et;

  parms.write(69, ep); // just to monitor last rtc set

  Serial.print("Setting RTC with Epoch: ");
  Serial.println(ep);

  // breakTime off by 30 years
  breakTime(ep, et);
  et.Year -= 30;

  // let's go change the time:
  // first stop the clock:
  Wire.beginTransmission(RTCADDR);
  Wire.write(RTCSEC);
  Wire.write(0x00);
  Wire.endTransmission();

  getEpochRtc();
  // rtcGetTime();//go grab the time again just to make sure the osc stopped

  if (rtcOscRunning == false)
  { // oscillator stopped, we're good
    Serial.println("RTC has stopped - Changing Time");
    Wire.beginTransmission(RTCADDR); // set the time/date
    Wire.write(RTCSEC);
    Wire.write(((et.Second / 10) << 4) + (et.Second % 10));
    Wire.write(((et.Minute / 10) << 4) + (et.Minute % 10));
    Wire.write(((et.Hour / 10) << 4) + (et.Hour % 10));
    Wire.write(et.Wday + 8);
    Wire.write(((et.Day / 10) << 4) + (et.Day % 10));
    Wire.write(((et.Month / 10) << 4) + (et.Month % 10));
    Wire.write(((et.Year / 10) << 4) + (et.Year % 10)); // two digit year
    Wire.endTransmission();

    Wire.beginTransmission(RTCADDR); // start back up
    Wire.write(RTCSEC);
    Wire.endTransmission();
    Wire.requestFrom(RTCADDR, 1);
    delay(1);
    byte rtcSecondRegister = Wire.read();
    rtcSecondRegister |= 0x80; // start bit!
    Wire.beginTransmission(RTCADDR);
    Wire.write(RTCSEC);
    Wire.write(rtcSecondRegister);
    Wire.endTransmission();

    Wire.beginTransmission(RTCADDR); // Enable Alarm0
    Wire.write(CONTROL);
    Wire.endTransmission();
    Wire.requestFrom(RTCADDR, 1);
    delay(1);
    byte rtcControlRegister = Wire.read();
    rtcControlRegister |= 0x10; // enable alm0
    Wire.beginTransmission(RTCADDR);
    Wire.write(CONTROL);
    Wire.write(rtcControlRegister);
    Wire.endTransmission();
  }
  Serial.println("  --RTC set finished");
}

String makeTimeStr(void)
{
  getEpochRtc();
  return (String(dt.Year - 30) + "-" + String(dt.Month) + "-" + String(dt.Day) + "-" + String(dt.Hour) + "-" + String(dt.Minute) + "-" + String(dt.Second));
}

void toggleMFP(void)
{
  Wire.beginTransmission(RTCADDR);
  Wire.write(CONTROL);
  Wire.write(0x80);
  Wire.endTransmission();
  delay(250);
  Wire.beginTransmission(RTCADDR);
  Wire.write(CONTROL);
  Wire.write(0x00);
  Wire.endTransmission();
}
