/*
  This sketch uses Wire.h library to communicate with DS3231 module without using a dedicated DS3231 library

  See YouTube channel Rudolf - 'Learn everything about the DS3231-SN Real Time Clock | Use without Arduino Library'
  See https://lastminuteengineers.com/ds3231-rtc-arduino-tutorial/ for DS3231 specs and instruction
  DS3231 I2C address is fixed at 0x68
  24C32 EEPROM I2C address is adjustable, default is 0x57

  To enable communication, both the SDA and SCL lines should have 4.7K pull-up resistors.
    - These are built into the DS3231 RTC module
  Battery - CR2032 (3V coin) or ML2032, LIR2032 (rechargeable)
  !! NOTE !! If board uses recharging circuit. Remove resistor if you're using a CR2032 battery.
  To use 24C32 EEPROM, install uEEPROMLib library.

  Set date and time to 11:23:47 PM, Saturday, October 28, 2024, Alarm-1: 11:50:00 PM 28th of each month

  The simulated DS1307 is automatically initialized to the current system time when starting the simulation.
  It then keeps counting the time. You can override the initial time by setting the initTime attribute
  to a different value. The value can be either a valid ISO 8601 date string (e.g. "2019-11-19T11:41:56Z"), 
  or one of the following special values:

  "0" - Set the initial time to "2000-01-01T00:00:00Z"
  "now" - Set the initial time to the current system time
  Note that "Z" at the end of the date string indicates that the time is in UTC, and not in the local time zone. If you omit the "Z", the time will be interpreted as local time.
 */

#include <Wire.h>

#define DS1307_ADDR 0x68

// dayofWeek 1,Monday 2,Tuesday 3,Wednesday 4,Thursday 5,Friday 6,Saturday 7,Sunday
uint8_t seconds = 47, minutes = 23, hours = 11, dayofWeek = 6, dayofMonth = 28, month = 10, year = 24;
uint8_t hoursAMPM;

bool isPM = true; // 0x02 Hour regester, Bit 5 is set low(0) for AM and set high(1) for PM


void setup() {
  Serial.begin(9600);
  Wire.begin(); // initialize I2C communication

  hoursAMPM = dectoBcd(hours); // 1st: set the hour, in this example 11 or 00001011 in BCD

  // 2nd: Set the DS3231 12-hour format bit settings
  // 0x02 Hour address, Bit 6 is set high(1) for 12 hour format or set low(0) for 24 hour format
  hoursAMPM = hoursAMPM | 0b01000000; // or write 64, or 0x40, OR's 01000000 | 00010001 (11)

  // 3rd: Is PM set to 'true'?
  if (isPM) {
    hoursAMPM = hoursAMPM | 0b00100000; // or write 32, or 0x20, OR's 010010001 | 00100000
  }

  // Set-Time by writing to DS3231
  Wire.beginTransmission(DS1307_ADDR); // start communication using DS3231 hex address
  Wire.write(0x00); // write to register address 0x00 the seconds register
  Wire.write(dectoBcd(seconds)); // write seconds in BCD format, 0100(MSB) and 0111(LSB)
  Wire.write(0x01); // write to 0x01 minutes register, not required - DS1307 moves to next register by itself
  Wire.write(dectoBcd(minutes));
  Wire.write(hoursAMPM);
  Wire.write(dayofWeek);
  Wire.write(dectoBcd(dayofMonth));
  Wire.write(dectoBcd(month));
  Wire.write(dectoBcd(year));
  Wire.endTransmission();
}

void loop() {

  Serial.print(dectoBcd(seconds), BIN);
  Serial.println(" Writing " + String(seconds) + " to seconds register");
  Serial.print(dectoBcd(minutes), BIN);
  Serial.println(" Writing " + String(minutes) + " to minutes register");
  Serial.print(hoursAMPM, BIN);
  Serial.println(" bit 6, 12 hr: bit 5, PM: Writing " + String(hours) + " to hours register");
  Serial.print(dayofWeek, BIN);
  Serial.println(" Writing " + String(dayofWeek) + " to dayofWeek register");
  Serial.print(dectoBcd(dayofMonth), BIN);
  Serial.println(" Writing " + String(dayofMonth) + " to date register");
  Serial.print(dectoBcd(month), BIN);
  Serial.println(" Writing " + String(month) + " to month register");
  Serial.print(dectoBcd(year), BIN);
  Serial.println(" Writing " + String(year) + " to year register");




  while(true) {
    delay(1000);
  }

}

// BCD (Binary Coded Decimal) Example: 47 / 10 = 4 or 00000100, shift left 4 places = 01000000
// 47 % 10 returns remainder which is 7, or 00000111
// Combined this will be 0100 + 0111 (see DS1307 datasheet)
byte dectoBcd(byte val) {
  return ((val / 10 * 16) + (val % 10)); // This works the same as below
  //return ((val / 10 << 4) + (val % 10)); // This works the same as above
}

// Need a fuction to turn BCD to DEC
byte bcdtoDec(byte value) {
  return ((value / 16 * 10) + (value % 16));
}
GND5VSDASCLSQWRTCDS1307+