/*
This program is RTC_1kHz_study.ino

Set the RTC to generate square wave pulses.
*/
#define GGcode true

// CPU is M0 or M4.
#define M0CPU false

#if GGcode
// library for Arduino I2C activities
#include <Wire.h>

// Real time clock libraries, and related stuff
#include "RTClib.h"
RTC_DS3231 rtc;

// declare which pin we'll inspect with a scope probe so that we can
// keep an eye on a manually-generated square wave to see ot the processor
// is frozen at the time it is reset.
int pin_of_interest = 10;

// pin value
int pin_value = HIGH;

// I will load date/time from the RTC into this:
DateTime nowis;

const char daysOfTheWeek[7][12] = 
  {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

// the default I2C address, of course.
#define DS3231_I2C_ADDR 0x68

// see Maxim data sheet, p. 11 for the timekeeping register map. The 8-bit quantities
// are two's complement: for a negative integer, flip the bits on the positive version, 
// then add 1.

// array of register bytes:
#define number_time_bytes 19
uint8_t time_register[number_time_bytes];

// addresses for the control and control/status registers inside the DS3231
const uint8_t control_byte_address = 0x0E;
const uint8_t control_status_byte_address = 0x0F;

// individual values and fields, using the Maxim namings, for the device's
// registers. names are self-explanatory. Note that "day" refers to day of the 
// week, and runs from 1 to 7. "date" is day of the month, from 1 to 31.

////////////////////// time of day

// 0x00
uint8_t t_seconds_units;
uint8_t t_seconds_tens;

// 0x01
uint8_t t_minutes_units;
uint8_t t_minutes_tens;

// 0x02
uint8_t t_hours_units;
uint8_t t_hours_ten;
uint8_t t_hours_twenty;
bool t_12_24bar;

////////////////////// day/date

// 0x03
uint8_t t_day;

// 0x04
uint8_t t_date_units;
uint8_t t_date_tens;

// 0x05
uint8_t t_month_units;
uint8_t t_month_tens;
uint8_t t_century;

// 0x06
uint8_t t_year_units;
uint8_t t_year_tens;

////////////////////// alarm1 settings

// A1M1, A1M2, A1M3, and A1M4 determine the mode of operation of the alarm.
//    case 0xf: Alarm once per second
//    case 0xe: Alarm when seconds match
//    case 0xc: Alarm when minutes and seconds match
//    case 0x8: Alarm when hours, minutes, and seconds match
//    case 0x0 and !alarm1_DY_DT: Alarm when date, hours, minutes, and seconds match
//    case 0x0 and alarm1_DY_DT: Alarm when day of the week, hours, minutes, and seconds match

// 0x07
uint8_t alarm1_seconds_units;
uint8_t alarm1_seconds_tens;
bool    A1M1;

// 0x08
uint8_t alarm1_minutes_units;
uint8_t alarm1_minutes_tens;
bool    A1M2;

// 0x09
uint8_t alarm1_hours_units;
uint8_t alarm1_hours_ten;
uint8_t alarm1_hours_twenty;
bool    alarm1_12_24bar;
bool    A1M3;

// 0x0a
uint8_t alarm1_day_date;
uint8_t alarm1_date_tens;
bool    alarm1_DY_DT;
bool    A1M4;

////////////////////// alarm2 settings

// A2M2, A2M3, and A2M4 determine the mode of operation of the alarm.
//    case 0x7: Alarm once per minute (00 seconds of ebvery minute)
//    case 0x6: Alarm when minutes match
//    case 0x4: Alarm when hours and minutes match
//    case 0x0 and !alarm2_DY_DT: Alarm when date, hours, and minutes match
//    case 0x0 and alarm2_DY_DT: Alarm when day of the week, hours, and minutes match

// 0x0b
uint8_t alarm2_minutes_units;
uint8_t alarm2_minutes_tens;
bool    A2M2;

// 0x0c
uint8_t alarm2_hours_units;
uint8_t alarm2_hours_ten;
uint8_t alarm2_hours_twenty;
bool    alarm2_12_24bar;
bool    A2M3;

// 0x0d
uint8_t alarm2_day_date_units;
uint8_t alarm2_date_tens;
bool    alarm2_DY_DT;
bool    A2M4;

// 0x0e
uint8_t control_byte;
// alarm1 interrupt enable
bool    control_A1IE;
// alarm2 interrupt enable
bool    control_A2IE;
// "interrupt control": 1 for alarm pulses, 0 for square wave
bool    control_INTCN;
// look at the Maxim documentation for the rest of these.
// RS1 and RS2 set the square wave frequency. For 1 Hz make RS1 and RS2 be zero.
// RS1 = 1 and RS2 = 0 for 1.024 kHz
// RS1 = 0 and RS2 = 1 for 4.096 kHz
// RS1 = 1 and RS2 = 1 for 8.192 kHz

bool    control_RS1;
bool    control_RS2;
bool    control_CONV;
bool    control_BBSQW;
bool    control_EOSCbar;

//0x0f
uint8_t control_status_byte;
// alarm1 is firing
bool    controlstatus_A1F;
// alarm2 is firing
bool    controlstatus_A2F;
// device is busy
bool    controlstatus_BSY;
// enable 32kHz square wave output on dedicated pin
bool    controlstatus_EN32kHz;
bool    controlstatus_OSF;

//0x10
uint8_t aging_offset;

//0x11
uint8_t temp_MSB;

//0x12
uint8_t temp_LSB;

// temperature inside the chip
float temperatureC;
float temperatureF;

// I derive these from the control and control/status bits.
bool alarm1_enabled;
bool alarm1_is_triggered;

bool alarm2_enabled;
bool alarm2_is_triggered;

uint8_t toggle = 1;
uint32_t loop_entries = 0;
uint32_t exploration_1_entries = 0;
uint32_t exploration_2_entries = 0;
uint32_t exploration_3_entries = 0;
uint32_t exploration_4_entries = 0;



#if M0CPU
// adafruit M0 I2C pins
int SDA_pin_number = 20;
int SCL_pin_number = 21;
#else
// adafruit M$ I2C pins
int SDA_pin_number = 22;
int SCL_pin_number = 21;
#endif

int SDA_pin_status;

int old_secs = 99;

int tick_tock = 5;
int first_LED_pin = 11;
int second_LED_pin = 12;
uint32_t t1, tmax;
const uint32_t serial_timeout = 5000;

// switch to keep track of whether or not we are still in the setup-induced
// LED state.
bool flash_fast;
const int pushbutton_pin = 6;
// fast blink rate
const int fast_blink_rate = 10;

// different parameters for LED blinking:
int LED_fast_on_ms = 50;
int LED_slow_on_ms = 1000;
uint32_t blink_time;
uint32_t old_blink_time;
uint32_t reset_bump_time;
uint32_t old_reset_bump_time;

 bool LED_on_status = false;

int t_bump = 30;

uint32_t duration;

void setup()
{
  // light up the serial monitor and wait for it to be ready, but with a 
  // timeout in case the serial monitor isn't open.

  t1 = millis();
  tmax = t1 + 5000;
  Serial.begin(115200);
  while(!Serial && millis() < tmax);

  Serial.println("\n\n======================== DS3231 RTC setup ========================");

  bool I2C_restarted_OK = reset_restart_I2C();

  print_the_time();

  // initialize some of the RTC mode parameters: alarms, 12 vs 24 hour, etc.
  initialize_RTC_parameters();

  // for use when we set some RTC parameters.
  uint8_t bit_value, which_register, which_bit;

  // now read all the DS3231 timekeeping registers 
  fetch_RTC_registers();

  // now print what we found fetching the register contents.
  report_RTC();
  
  // INTCN: set to zero for square wave from SQW pin.
  bit_value = 0;
  which_register = control_byte_address;
  which_bit = 2;
  put_register(bit_value, which_register, which_bit);

  // RS1 and RS2 set the square wave frequency. For 1 Hz make RS1 and RS2 be zero.
  // RS1 = 1 and RS2 = 0 for 1.024 kHz
  // RS1 = 0 and RS2 = 1 for 4.096 kHz
  // RS1 = 1 and RS2 = 1 for 8.192 kHz

  which_register = control_byte_address;
  // RS1
  which_bit = 3;
  bit_value = 1;
  put_register(bit_value, which_register, which_bit);

  which_register = control_byte_address;
  // RS2
  which_bit = 4;
  bit_value = 0;
  put_register(bit_value, which_register, which_bit);

  // BBSQW
  which_register = control_byte_address;
  which_bit = 6;
  bit_value = 0;
  put_register(bit_value, which_register, which_bit);

  Serial.println("just set SQW to run now...");

  // now read all the DS3231 timekeeping registers 
  fetch_RTC_registers();

  // now print what we found fetching the register contents.
  report_RTC();
  

}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

void loop()
{
  // play with the LEDs, perhaps do something cute, so I don't
  // need to use the serial monitor to keep track.

  bool debug = false;

  if(debug)
  {
    Serial.print("Just before bumping alarm1 time...");
    print_the_time();
    fetch_RTC_registers();

    Serial.print(" * control_A1IE = ");boolprint(control_A1IE);
    Serial.print(" * control_A2IE = ");boolprint(control_A2IE);
    Serial.print(" * control_INTCN = ");boolprint(control_INTCN);
    Serial.print(" * control_RS1 = ");boolprintln(control_RS1);
    Serial.print(" * control_RS2 = ");boolprint(control_RS2);
    Serial.print(" * control_CONV = ");boolprint(control_CONV);
    Serial.print(" * control_BBSQW = ");boolprint(control_BBSQW);
    Serial.print(" * control_EOSCbar = ");boolprintln(control_EOSCbar);

    Serial.print(" * controlstatus_A1F = ");boolprint(controlstatus_A1F);
    Serial.print(" * controlstatus_A2F = ");boolprint(controlstatus_A2F);
    Serial.print(" * controlstatus_BSY = ");boolprintln(controlstatus_BSY);
    Serial.print(" * controlstatus_EN32kHz = ");boolprint(controlstatus_EN32kHz);
    Serial.print(" * controlstatus_OSF = ");boolprintln(controlstatus_OSF);

    int alarm1_mode = A1M1 + 2 * A1M2 + 4 * A1M3 + 8 * A1M4;
    Serial.print("Alarm1 mode: ");

    switch(alarm1_mode)
    {
      case 0xf:
        Serial.println("Alarm once per second");
        break;
      case 0xe:
        Serial.println("Alarm when seconds match");
        break;
      case 0xc:
        Serial.println("Alarm when minutes and seconds match");
        break;
      case 0x8:
        Serial.println("Alarm when hours, minutes, and seconds match");
        break;
      case 0x0:
        if(!alarm1_DY_DT)
        {
        Serial.println("Alarm when date, hours, minutes, and seconds match");
        } else {
        Serial.println("Alarm when day of the week, hours, minutes, and seconds match");
        }
        break;
    }

    if(control_A1IE && control_INTCN)
    {
      Serial.println("Alarm 1 is ** ENABLED **");
    } else {
      Serial.println("Alarm 1 is ** DISABLED ** so INTbar/SQW line stays HIGH");
    }

    if(alarm1_is_triggered)
    {
      Serial.println("Alarm 1 is ACTIVE and TRIGGERED");
    } else {
      Serial.println("Alarm 1 is NOT TRIGGERED");
    }

  }

}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

void print_the_time(void)
{
  // read and report the RTC reading
  nowis = rtc.now();

  Serial.print(F("current DS3231 RTC reading: "));
  Serial.print(nowis.year(), DEC);
  Serial.print('/');
  if(nowis.month() < 10) {Serial.print(F("0"));}
  Serial.print(nowis.month(), DEC);
  Serial.print('/');
  if(nowis.day() < 10) {Serial.print(F("0"));}
  Serial.print(nowis.day(), DEC);
  Serial.print(F(" ("));
  Serial.print(daysOfTheWeek[nowis.dayOfTheWeek()]);
  Serial.print(F(") "));
  Serial.print(nowis.hour(), DEC);
  Serial.print(':');
  if(nowis.minute() < 10) {Serial.print(F("0"));}
  Serial.print(nowis.minute(), DEC);
  Serial.print(':');
  if(nowis.second() < 10) {Serial.print(F("0"));}
  Serial.print(nowis.second(), DEC);
  Serial.println();
  
}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

uint8_t get_register(int which_register)
{
  // fetch the value of a single DS3231 8-bit timekeeping register (0 - 18)
  // and return its contents.

  uint8_t register_value;

  // do the I2C transaction.
  Wire.beginTransmission(DS3231_I2C_ADDR);

  // tell the device which byte we'd like
  Wire.write(which_register);

  // we are done sending...
  Wire.endTransmission();

  // now ask for the byte.
  Wire.requestFrom(DS3231_I2C_ADDR, 1);
  register_value = Wire.read();

  // all done!
  return register_value;
}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

void put_register(uint8_t bit_value, int which_register, int which_bit)
{
  // put bit_value into one bit of a register, leaving the others unchanged.
  // see https://www.techissocool.com/how-to-ds3231-real-time-clock-arduino/ 

  bool debug = false;

  // first see what's already in that register byte.
  uint8_t old_register_value = get_register(which_register);

  // now construct the replacement byte.
  uint8_t new_register_value = old_register_value;

  // we need to psh a 1 into the right bit. do this with a bitwise or.
  if(bit_value == 1)
  {
    // left-shift a single bit
    uint8_t mask = 0x01 << which_bit;

    // now OR with the existing value
    new_register_value = new_register_value | mask;

    if(debug) {Serial.print("Inside function put_register. OR mask "); Serial.print(mask, BIN);}

  } else {

    // left-shift a single bit
    uint8_t mask = 0x01 << which_bit;

    // get the bitwise complement
    mask = ~mask;

    // do a bitwise AND to zero out the desired bit
    new_register_value = new_register_value & mask;

    if(debug) {Serial.print("Inside function put_register. AND mask "); Serial.print(mask, BIN);}
  }

  if(debug)
  {
    Serial.print("  bit_value ");
    Serial.print(bit_value);
    Serial.print("  which_register (hex) 0x0");
    Serial.print(which_register, HEX);
    Serial.print("  which_bit ");
    Serial.print(which_bit);

    Serial.print("\nold, (hoped for) new register values (binary) ");
    Serial.print(old_register_value, BIN); Serial.print("  ");
    Serial.println(new_register_value, BIN);
  } 

  // now that we have what the new byte should be, use I2C to push it into the right
  //place inside the DS3231.

  // do the I2C transaction.
  Wire.beginTransmission(DS3231_I2C_ADDR);

  // tell the device which byte we'd like to receive our transmission
  Wire.write(which_register);

  // now write the new byte
  Wire.write(new_register_value);

  // we are done sending...
  Wire.endTransmission();

  // all done!

}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

bool reset_restart_I2C()
{
  // Sometimes resetting the processor causes the I2C data line SDA to hang.
  // It is possible that the reset happened during the transmission of data
  // from a slave, before the end of the transmission. In this case the slave 
  // is waiting for more SCL clock pulses to finish the transmission, but the
  // master has forgotten that it was in the middle of an I2C interaction.
  // Fix this by sending a string of nine I2C clock pulses. See 
  // https://espace.cern.ch/CMS-MPA/SiteAssets/SitePages/Documents/I2C_bus_specifications_V2_0.pdf
  // and "Implementing an I2C Reset," Analog Devices AN-686.
  // We need to follow this pulse train with a start/stop: make SDA an output,
  // hold SCL high, and pull SDA LOW, then HIGH.

  // Look at the status of the SDA line. (It's pin 20 in an Adafruit M0.) It
  // can be stuck in either state: LOW or HIGH.

  const bool debug = true;
  bool everything_is_fine = true;

  // set some initial RTC parameters.
  uint8_t bit_value, which_register, which_bit;

  pinMode(SDA_pin_number, INPUT);
  SDA_pin_status = digitalRead(SDA_pin_number);

  if(debug)
  {
    Serial.print("Now in reset_restart_I2C... SDA pin 20 value = ");
    Serial.println(SDA_pin_status);
  }

  // now pulse the clock line nine times.
  pinMode(SCL_pin_number, OUTPUT);
  digitalWrite(SCL_pin_number, HIGH);

  // consider pulsing it a LOT instead of just 9 times. Nope, doesn't help
  int how_many_SCL_pulses = 9;
  // int how_many_SCL_pulses = 50;
  for(int ijk = 0; ijk < how_many_SCL_pulses; ijk++)
    {
      delay(5);
      digitalWrite(SCL_pin_number, LOW);
      delay(5);
      digitalWrite(SCL_pin_number, HIGH);
    }
  delay(5);

  // now read the data line. It should be HIGH.
  SDA_pin_status = digitalRead(SDA_pin_number);
  if(SDA_pin_status == 0) {everything_is_fine = false;}

  // now send start/stop
  pinMode(SDA_pin_number, OUTPUT);

  // hold SCL high
  digitalWrite(SCL_pin_number, HIGH);
  delay(5);
  
  // pull SDA low (start signal)
  digitalWrite(SDA_pin_number, LOW);
  delay(5);

  // push SDA high (stop signal)
  digitalWrite(SDA_pin_number, HIGH);
  delay(5);

  // we have both SCL and SDA HIGH now: that's IDLE.
  
  if(debug)
  {
    Serial.print("SDA status after sending lots of clock pulses and stop/start is ");
    Serial.println(SDA_pin_status);
    if(!everything_is_fine) {Serial.println(">>>>>>> Uh oh, SDA is stuck LOW!! <<<<<<<");}
    Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
  }

  // now (re)start the I2C interface so I can access some of its functions.
  Wire.begin();
  delay(100);
  
  // now make sure the RTC's alarm flags A1F and A2F are off.

  // A1F off
  bit_value = 0;
  which_register = control_status_byte_address;
  which_bit = 0;
  put_register(bit_value, which_register, which_bit);

  // A2F off
  bit_value = 0;
  which_register = control_status_byte_address;
  which_bit = 1;
  put_register(bit_value, which_register, which_bit);

  // OSF (oscillator stop flag) off
  bit_value = 0;
  which_register = control_status_byte_address;
  which_bit = 7;
  put_register(bit_value, which_register, which_bit);


  // INTCN: set to zero for square wave from SQW pin.
  bit_value = 0;
  which_register = control_byte_address;
  which_bit = 2;
  put_register(bit_value, which_register, which_bit);

  // RS1, RS2 for square wave rates
  bit_value = 1;
  which_register = control_byte_address;
  which_bit = 3;
  put_register(bit_value, which_register, which_bit);
  bit_value = 0;
  which_register = control_byte_address;
  which_bit = 4;
  put_register(bit_value, which_register, which_bit);

  // now read/print the registers again.
  uint8_t creg = get_register(0x0e);
  uint8_t csreg = get_register(0x0f);
  Serial.print("0x0e and 0x0f registers (binary) "); 
  Serial.print(creg, BIN);
  Serial.print("   "); 
  Serial.println(csreg, BIN);

  return everything_is_fine;

}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

void fetch_RTC_registers(void)
{
  // load RTC time register values and unpack them

/*
  // this version of fetching takes 7.9 milliseconds
  for (int ijk = 0; ijk < number_time_bytes; ijk++)
  {
    Wire.beginTransmission(DS3231_I2C_ADDR);
    Wire.write(ijk);
    Wire.endTransmission();
    Wire.requestFrom(DS3231_I2C_ADDR, 1);
    time_register[ijk] = Wire.read();
  }
*/

  // this version of fetching takes 2.1 milliseconds
    Wire.beginTransmission(DS3231_I2C_ADDR);
    Wire.write(0);
    Wire.endTransmission();
    Wire.requestFrom(DS3231_I2C_ADDR, 18);
    int ijk = 0; 
    while(Wire.available())
    {
      time_register[ijk] = Wire.read();
      ijk++;
    }

  int index;

  // see the Maxim data sheet for the register memory map information.
  index = 0x00;
  t_seconds_units = time_register[index] & 0x0f;
  t_seconds_tens = time_register[index] >> 4;

  index = 0x01;
  t_minutes_units = time_register[index] & 0x0f;
  t_minutes_tens = time_register[index] >> 4;

  index = 0x02;
  t_hours_units = time_register[index] & 0x0f;
  t_hours_ten = (time_register[index] >> 4) & 0x01;
  t_hours_twenty = (time_register[index] >> 5) & 0x01;
  t_12_24bar = (((time_register[index] >> 6) & 0x01) != 0);

  index = 0x03;
  t_day = time_register[index] & 0x07;

  index = 0x04;
  t_date_units = time_register[index] & 0x0f;
  t_date_tens = time_register[index]  >> 4;

  index = 0x05;
  t_month_units = time_register[index] & 0x0f;
  t_month_tens = (time_register[index] >> 4) & 0x01;
  t_century = time_register[index] >> 7;

  index = 0x06;
  t_year_units = time_register[index] & 0x0f;
  t_year_tens = time_register[index] >> 4;

  index = 0x07;
  alarm1_seconds_units = time_register[index] & 0x0f;
  alarm1_seconds_tens = (time_register[index] >> 4) & 0x07;
  A1M1 = (time_register[index] & 0x80) > 0;

  index = 0x08;
  alarm1_minutes_units = time_register[index] & 0x0f;
  alarm1_minutes_tens = (time_register[index] >> 4) & 0x07;
  A1M2 = (time_register[index] & 0x80) > 0;

  index = 0x09;
  alarm1_hours_units = time_register[index] & 0x0f;
  alarm1_hours_ten = (time_register[index]  >> 4) & 0x01;
  alarm1_hours_twenty = (time_register[index] >> 5) & 0x01;
  alarm1_12_24bar = (time_register[index] & 0x40) > 0;
  A1M3 = (time_register[index] & 0x80) > 0;

  index = 0x0a;
  alarm1_day_date = time_register[index] & 0x0f;
  alarm1_date_tens = (time_register[index] >> 4) & 0x03;
  alarm1_DY_DT = time_register[index] & 0x40 > 0;
  A1M4 = (time_register[index] & 0x80) > 0;

  index = 0x0b;
  alarm2_minutes_units = time_register[index] & 0x0f;
  alarm2_minutes_tens = (time_register[index] >> 4) & 0x07;
  A2M2 = (time_register[index] & 0x80) > 0;

  index = 0x0c;
  alarm2_hours_units = time_register[index] & 0x0f;
  alarm2_hours_ten = (time_register[index] >> 4) & 0x01;
  alarm2_hours_twenty = (time_register[index] >> 5) & 0x01;
  alarm2_12_24bar = (time_register[index] & 0x40) > 0;
  A2M3 = (time_register[index] & 0x80) > 0;

  index = 0x0d;
  alarm2_day_date_units = time_register[index] & 0x0f;
  alarm2_date_tens = (time_register[index]>> 4) & 0x03;
  alarm2_DY_DT = (time_register[index] & 0x40) > 0;
  A2M4 = (time_register[index] & 0x80) > 0;

  index = 0x0e;
  control_byte = time_register[index];
  control_A1IE = (time_register[index] & 0x01) > 0;
  control_A2IE = (time_register[index] & 0x02) > 0;
  control_INTCN = (time_register[index] & 0x04) > 0;
  control_RS1 = (time_register[index] & 0x08) > 0;
  control_RS2 = (time_register[index] & 0x10) > 0;
  control_CONV = (time_register[index] & 0x20) > 0;
  control_BBSQW = (time_register[index] & 0x40) > 0;
  control_EOSCbar = (time_register[index] & 0x80) > 0;

  index = 0x0f;
  control_status_byte = time_register[index];
  controlstatus_A1F = (time_register[index] & 0x01) > 0;
  controlstatus_A2F = (time_register[index] & 0x02) > 0;
  controlstatus_BSY = (time_register[index] & 0x04) > 0;
  controlstatus_EN32kHz = (time_register[index] & 0x08) > 0;
  controlstatus_OSF = (time_register[index] & 0x80) > 0;

  index = 0x10;
  aging_offset = time_register[index];

  index = 0x11;
  temp_MSB = time_register[index];

  index = 0x12;
  temp_LSB = time_register[index];
  temperatureC = temp_MSB + float(temp_LSB) / 100.;
  temperatureF = 1.8 * temperatureC + 32.0;

  // now set flags about alarm status.
  alarm1_enabled = control_A1IE && control_INTCN;
  alarm1_is_triggered = controlstatus_A1F && alarm1_enabled;
  
  alarm2_enabled = control_A2IE && control_INTCN;
  alarm2_is_triggered = controlstatus_A2F && alarm2_enabled;
  
}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

void report_RTC(void)
{
  // print RTC time register values to the serial monitor

  Serial.println("\n*******************************************************");
  Serial.println(  "************ DS3231 RTC time register dump ************");
  print_the_time();

  Serial.println("\ntime_registers 0x00 - 0x12 ");
  for (int ijk = 0; ijk < number_time_bytes; ijk++)
  {
    if(ijk == 10) {Serial.print("\n");}
    Serial.print(ijk, HEX);
    Serial.print(" = ");
    Serial.print(time_register[ijk], HEX);
    Serial.print("; ");
  }

  int ijk = 0;

  Serial.print("\nregister 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   t_seconds_units = ");Serial.print(t_seconds_units);
  Serial.print("   t_seconds_tens = ");Serial.println(t_seconds_tens);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   t_minutes_units = ");Serial.print(t_minutes_units);
  Serial.print("   t_minutes_tens = ");Serial.println(t_minutes_tens);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   t_hours_units = ");Serial.print(t_hours_units);
  Serial.print("   t_hours_ten = ");Serial.print(t_hours_ten);
  Serial.print("   t_hours_twenty = ");Serial.print(t_hours_twenty);
  // 0 for 24-hour mode.
  Serial.print("   t_12_24bar = "); boolprintln(t_12_24bar);

  Serial.print(">>> parsing current time: "); 
  if(t_12_24bar != 0)
  {
    // 12 hour mode
    Serial.print(t_hours_ten);
  } else {
    // 24 hour mode
    if(t_hours_twenty == 0)
    {
      Serial.print(t_hours_ten);
    } else {
      Serial.print(2);
    }
  }
  Serial.print(t_hours_units); 
  Serial.print(":");
  Serial.print(t_minutes_tens);
  Serial.print(t_minutes_units);
  Serial.print(":");
  Serial.print(t_seconds_tens);
  Serial.println(t_seconds_units);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   t_day = ");Serial.println(t_day);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   t_date_units = ");Serial.print(t_date_units);
  Serial.print("   t_date_tens = ");Serial.println(t_date_tens);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   t_month_units = ");Serial.print(t_month_units);
  Serial.print("   t_month_tens = ");Serial.print(t_month_tens);
  Serial.print("   t_century = ");Serial.println(t_century);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   t_year_units = ");Serial.print(t_year_units);
  Serial.print("   t_year_tens = ");Serial.println(t_year_tens);

  Serial.print(">>> parsing current date (yyyy/mm/dd): "); 
  Serial.print("20");
  Serial.print(t_year_tens);
  Serial.print(t_year_units);
  Serial.print("/");
  Serial.print(t_month_tens);
  Serial.print(t_month_units);
  Serial.print("/");
  Serial.print(t_date_tens);
  Serial.println(t_date_units);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   alarm1_seconds_units = ");Serial.print(alarm1_seconds_units);
  Serial.print("   alarm1_seconds_tens = ");Serial.println(alarm1_seconds_tens);
  Serial.print("   A1M1 = ");boolprintln(A1M1);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   alarm1_minutes_units = ");Serial.print(alarm1_minutes_units);
  Serial.print("   alarm1_minutes_tens = ");Serial.println(alarm1_minutes_tens);
  Serial.print("   A1M2 = ");boolprintln(A1M2);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   alarm1_hours_units = ");Serial.print(alarm1_hours_units);
  Serial.print("   alarm1_hours_ten = ");Serial.print(alarm1_hours_ten);
  Serial.print("   alarm1_hours_twenty = ");Serial.println(alarm1_hours_twenty);
  Serial.print("   alarm1_12_24bar = ");Serial.print(alarm1_12_24bar);
  Serial.print("   A1M3 = ");boolprintln(A1M3);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   alarm1_day_date = ");Serial.print(alarm1_day_date);
  Serial.print("   alarm1_date_tens = ");Serial.print(alarm1_date_tens);
  Serial.print("   alarm1_DY_DT = ");Serial.print(alarm1_DY_DT);
  Serial.print("   A1M4 = ");boolprintln(A1M4);

  Serial.print(">>> parsing alarm1 time (hh:mm:ss) and day/date: "); 
  if(alarm1_12_24bar != 0)
  {
    // 12 hour mode
    Serial.print(alarm1_hours_ten);
  } else {
    // 24 hour mode
    if(alarm1_hours_twenty == 0)
    {
      Serial.print(alarm1_hours_ten);
    } else {
      Serial.print(2);
    }
  }
  Serial.print(alarm1_hours_units); 
  Serial.print(":");
  Serial.print(alarm1_minutes_tens);
  Serial.print(alarm1_minutes_units);
  Serial.print(":");
  Serial.print(alarm1_seconds_tens);
  Serial.print(alarm1_seconds_units);

  if(alarm1_DY_DT == 1)
  {
    Serial.print("   alarm1 day of the week (1 - 7) = ");
    Serial.println(alarm1_day_date);
  } else {
    Serial.print("   alarm1 day of the month (1 - 31) = ");
    Serial.print(alarm1_date_tens);
    Serial.println(alarm1_day_date);
  }

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   alarm2_minutes_units = ");Serial.print(alarm2_minutes_units);
  Serial.print("   alarm2_minutes_tens = ");Serial.print(alarm2_minutes_tens);
  Serial.print("   A2M2 = ");boolprintln(A2M2);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   alarm2_hours_units = ");Serial.print(alarm2_hours_units);
  Serial.print("   alarm2_hours_ten = ");Serial.print(alarm2_hours_ten);
  Serial.print("   alarm2_hours_twenty = ");Serial.println(alarm2_hours_twenty);
  Serial.print("   alarm2_12_24bar = ");Serial.print(alarm2_12_24bar);
  Serial.print("   A2M3 = ");boolprintln(A2M3);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   alarm2_day_date_units = ");Serial.print(alarm2_day_date_units);
  Serial.print("   alarm2_date_tens = ");Serial.print(alarm2_date_tens);
  Serial.print("   alarm2_DY_DT = ");Serial.print(alarm2_DY_DT);
  Serial.print("   A2M4 = ");boolprintln(A2M4);

  Serial.print(">>> parsing alarm2 time (hh:mm) and day/date: "); 
  if(alarm2_12_24bar != 0)
  {
    // 12 hour mode
    Serial.print(alarm2_hours_ten);
  } else {
    // 24 hour mode
    if(alarm2_hours_twenty == 0)
    {
      Serial.print(alarm2_hours_ten);
    } else {
      Serial.print(2);
    }
  }
  Serial.print(alarm2_hours_units); 
  Serial.print(":");
  Serial.print(alarm2_minutes_tens);
  Serial.print(alarm2_minutes_units);

  if(alarm2_DY_DT == 1)
  {
    Serial.print("   alarm2 day of the week (1 - 7) = ");
    Serial.println(alarm2_day_date_units);
  } else {
    Serial.print("   alarm2 day of the month (1 - 31) = ");
    Serial.print(alarm2_date_tens);
    Serial.println(alarm2_day_date_units);
  }

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   control_A1IE = ");boolprint(control_A1IE);
  Serial.print("   control_A2IE = ");boolprint(control_A2IE);
  Serial.print("   control_INTCN = ");boolprint(control_INTCN);
  Serial.print("   control_RS1 = ");boolprintln(control_RS1);
  Serial.print("   control_RS2 = ");boolprint(control_RS2);
  Serial.print("   control_CONV = ");boolprint(control_CONV);
  Serial.print("   control_BBSQW = ");boolprint(control_BBSQW);
  Serial.print("   control_EOSCbar = ");boolprintln(control_EOSCbar);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   controlstatus_A1F = ");boolprint(controlstatus_A1F);
  Serial.print("   controlstatus_A2F = ");boolprint(controlstatus_A2F);
  Serial.print("   controlstatus_BSY = ");boolprintln(controlstatus_BSY);
  Serial.print("   controlstatus_EN32kHz = ");boolprint(controlstatus_EN32kHz);
  Serial.print("   controlstatus_OSF = ");boolprintln(controlstatus_OSF);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   aging_offset = ");Serial.println(aging_offset);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   temp_MSB = ");Serial.println(temp_MSB);

  Serial.print("register 0x0");
  Serial.print(ijk, HEX);
  Serial.print(" (hex) = ");
  Serial.println(time_register[ijk], HEX);
  ijk++;

  Serial.print("   temp_LSB = ");Serial.println(temp_LSB);
  Serial.print("\ntemperatureC = ");Serial.println(temperatureC);
  Serial.print("temperatureF = ");Serial.println(temperatureF);

  int alarm1_mode = A1M1 + 2 * A1M2 + 4 * A1M3 + 8 * A1M4;
  Serial.println("\n>>> Alarm1 mode: ");

  switch(alarm1_mode)
  {
    case 0xf:
      Serial.println("Alarm once per second");
      break;
    case 0xe:
      Serial.println("Alarm when seconds match");
      break;
    case 0xc:
      Serial.println("Alarm when minutes and seconds match");
      break;
    case 0x8:
      Serial.println("Alarm when hours, minutes, and seconds match");
      break;
    case 0x0:
      if(!alarm1_DY_DT)
      {
      Serial.println("Alarm when date, hours, minutes, and seconds match");
      } else {
      Serial.println("Alarm when day of the week, hours, minutes, and seconds match");
      }
      break;
  }

  if(control_A1IE && control_INTCN)
  {
    Serial.println("Alarm 1 is ** ENABLED ** to drop INTbar/SQW line LOW");
  } else {
    Serial.println("Alarm 1 is ** DISABLED ** so INTbar/SQW line stays HIGH");
  }

  if(alarm1_is_triggered)
  {
    Serial.println("Alarm 1 is ACTIVE and TRIGGERED");
  } else {
    Serial.println("Alarm 1 is NOT TRIGGERED");
  }

  int alarm2_mode = A1M2 + 2 * A1M3 + 4 * A1M4;
  Serial.println("\n>>> Alarm2 mode: ");

  switch(alarm2_mode)
  {
    case 7:
      Serial.println("Alarm once per minute (00 seconds of every minute)");
      break;
    case 6:
      Serial.println("Alarm when minutes match");
      break;
    case 4:
      Serial.println("Alarm when hours and minutes match");
      break;
    case 0:
      if(!alarm2_DY_DT)
      {
      Serial.println("Alarm when date, hours, and minutes match");
      } else {
      Serial.println("Alarm when day of the week, hours, and minutes match");
      }
      break;
  }

  if(control_A2IE && control_INTCN)
  {
    Serial.println("Alarm 2 is ** ENABLED ** to drop INTbar/SQW line LOW");
  } else {
    Serial.println("Alarm 2 is ** DISABLED ** so INTbar/SQW line stays HIGH");
  }

  if(alarm2_is_triggered)
  {
    Serial.println("Alarm 2 is ACTIVE and TRIGGERED");
  } else {
    Serial.println("Alarm 2 is NOT TRIGGERED\n");
  }

}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

void boolprint(bool value)
{
  // when I know a byte holds a bool, print it as true or false instead of 1 or 0.
  if(value)
  {
    Serial.print("true");
  } else {
    Serial.print("false");
  }
}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

void boolprintln(bool value)
{
  // when I know a byte holds a bool, print it as true or false instead of 1 or 0.
  // include a new line at the end.
  if(value)
  {
    Serial.println("true");
  } else {
    Serial.println("false");
  }
}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

void initialize_RTC_parameters()
{
  // initialize some of the RTC and RTC alarm parameters. Note that.I am NOT
  // setting the RTC time, only some of its mode parameters,

  // we want eventually to enable alarm1 to fire when time and date match the alarm 
  // setting. but for now disable the alarms.

  /*
  Here are the RTC timekeeping registers. See 
  https://datasheets.maximintegrated.com/en/ds/DS3231.pdf

  // addresses for the control and control/status registers inside the DS3231
  const uint8_t control_byte_address = 0x0E;
  const uint8_t control_status_byte_address = 0x0F;

  // individual values and fields, using the Maxim namings, for the device's
  // registers. names are self-explanatory. Note that "day" refers to day of the 
  // week, and runs from 1 to 7. "date" is day of the month, from 1 to 31.

  ////////////////////// time of day

  // 0x00
  uint8_t t_seconds_units;
  uint8_t t_seconds_tens;

  // 0x01
  uint8_t t_minutes_units;
  uint8_t t_minutes_tens;

  // 0x02
  uint8_t t_hours_units;
  uint8_t t_hours_ten;
  uint8_t t_hours_twenty;
  bool t_12_24bar;

  ////////////////////// day/date

  // 0x03
  uint8_t t_day;

  // 0x04
  uint8_t t_date_units;
  uint8_t t_date_tens;

  // 0x05
  uint8_t t_month_units;
  uint8_t t_month_tens;
  uint8_t t_century;

  // 0x06
  uint8_t t_year_units;
  uint8_t t_year_tens;

  ////////////////////// alarm1 settings

  // A1M1, A1M2, A1M3, and A1M4 determine the mode of operation of the alarm.
  //    case 0xf: Alarm once per second
  //    case 0xe: Alarm when seconds match
  //    case 0xc: Alarm when minutes and seconds match
  //    case 0x8: Alarm when hours, minutes, and seconds match
  //    case 0x0 and !alarm1_DY_DT: Alarm when date, hours, minutes, and seconds match
  //    case 0x0 and alarm1_DY_DT: Alarm when day of the week, hours, minutes, and seconds match

  // 0x07
  uint8_t alarm1_seconds_units;
  uint8_t alarm1_seconds_tens;
  bool    A1M1;

  // 0x08
  uint8_t alarm1_minutes_units;
  uint8_t alarm1_minutes_tens;
  bool    A1M2;

  // 0x09
  uint8_t alarm1_hours_units;
  uint8_t alarm1_hours_ten;
  uint8_t alarm1_hours_twenty;
  bool    alarm1_12_24bar;
  bool    A1M3;

  // 0x0a
  uint8_t alarm1_day_date;
  uint8_t alarm1_date_tens;
  bool    alarm1_DY_DT;
  bool    A1M4;

  ////////////////////// alarm2 settings

  // A2M2, A2M3, and A2M4 determine the mode of operation of the alarm.
  //    case 0x7: Alarm once per minute (00 seconds of ebvery minute)
  //    case 0x6: Alarm when minutes match
  //    case 0x4: Alarm when hours and minutes match
  //    case 0x0 and !alarm2_DY_DT: Alarm when date, hours, and minutes match
  //    case 0x0 and alarm2_DY_DT: Alarm when day of the week, hours, and minutes match

  // 0x0b
  uint8_t alarm2_minutes_units;
  uint8_t alarm2_minutes_tens;
  bool    A2M2;

  // 0x0c
  uint8_t alarm2_hours_units;
  uint8_t alarm2_hours_ten;
  uint8_t alarm2_hours_twenty;
  bool    alarm2_12_24bar;
  bool    A2M3;

  // 0x0d
  uint8_t alarm2_day_date_units;
  uint8_t alarm2_date_tens;
  bool    alarm2_DY_DT;
  bool    A2M4;

  // 0x0e
  uint8_t control_byte;
  // alarm1 interrupt enable
  bool    control_A1IE;
  // alarm2 interrupt enable
  bool    control_A2IE;
  // "interrupt control": 1 for alarm pulses, 0 for square wave
  bool    control_INTCN;
  // look at the Maxim documentation for the rest of these.
  // RS1 and RS2 set the square wave frequency. For 1 Hz make RS1 and RS2 be zero.
  bool    control_RS1;
  bool    control_RS2;
  bool    control_CONV;
  bool    control_BBSQW;
  bool    control_EOSCbar;

  //0x0f
  uint8_t control_status_byte;
  // alarm1 is firing
  bool    controlstatus_A1F;
  // alarm2 is firing
  bool    controlstatus_A2F;
  // device is busy
  bool    controlstatus_BSY;
  // enable 32kHz square wave output on dedicated pin
  bool    controlstatus_EN32kHz;
  bool    controlstatus_OSF;

  //0x10
  uint8_t aging_offset;

  //0x11
  uint8_t temp_MSB;

  //0x12
  uint8_t temp_LSB;
  */

  // for use when we set some RTC parameters.
  uint8_t bit_value, which_register, which_bit;

  // first set the RTC time mode to be 24 hours, not 12 hours with AM/PM.
  bit_value = 0;
  which_register = 0x02;
  which_bit = 6;
  put_register(bit_value, which_register, which_bit);

  // now disable alarm1 and alarm2 so that the alarms don't fire until we are ready.
  // First alarm1...
  bit_value = 0;
  which_register = 0x0e;
  which_bit = 0;
  put_register(bit_value, which_register, which_bit);
  // ...then alarm2.
  which_bit = 1;
  put_register(bit_value, which_register, which_bit);

  // now clear the alarm1 and alarm2 flags A1F and A2F.
  which_register = 0x0f;
  which_bit = 0;
  put_register(bit_value, which_register, which_bit);
  // now alarm2.
  which_bit = 1;
  put_register(bit_value, which_register, which_bit);

  // now set the alarm1 mode for time/date match. (A1M1 - 4 all zero and alarm1_DY_DT
  // also zero.)
  // A1M1:
  bit_value = 0;
  which_register = 0x07;
  which_bit = 7;
  put_register(bit_value, which_register, which_bit);
  // A1M2:
  which_register = 0x08;
  put_register(bit_value, which_register, which_bit);
  // A1M3:
  which_register = 0x09;
  put_register(bit_value, which_register, which_bit);
  // A1M4:
  which_register = 0x0a;
  put_register(bit_value, which_register, which_bit);
  // dy_dt:
  bit_value = 0;
  which_register = 0x0a;
  which_bit = 6;
  put_register(bit_value, which_register, which_bit);

  // also zero the 12/24bar bit to set alarm1 to 24 hour time:
  bit_value = 0;
  which_register = 0x09;
  which_bit = 6;
  put_register(bit_value, which_register, which_bit);

  // all done!
  return;

}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

void set_alarm1(int seconds_into_the_future)
{
  // set alarm1 to go off in the future.

  // debug switch
  bool debug = false;

  // set some initial RTC parameters.
  uint8_t bit_value, which_register, which_bit;

  // get the current time
  nowis = rtc.now();

  // calculate a date/time which is some seconds into the future
  DateTime future(nowis + seconds_into_the_future);

  if(debug)
  {
    Serial.print("We will set alarm1 to fire this many seconds into the future: ");
    Serial.println(seconds_into_the_future);

    Serial.print("alarm time: ");
    Serial.print(future.year(), DEC);
    Serial.print('/');
    if(future.month() < 10) {Serial.print("0");}
    Serial.print(future.month(), DEC);
    Serial.print('/');
    if(future.day() < 10) {Serial.print("0");}
    Serial.print(future.day(), DEC);
    Serial.print(' ');
    Serial.print(future.hour(), DEC);
    Serial.print(':');
    if(future.minute() < 10) {Serial.print("0");}
    Serial.print(future.minute(), DEC);
    Serial.print(':');
    if(future.second() < 10) {Serial.print("0");}
    Serial.print(future.second(), DEC);
    Serial.println();
    Serial.println();
  }
  
  // now disable alarm1 and alarm2 so that the alarms don't fire until we are ready.
  // First alarm1...
  bit_value = 0;
  which_register = 0x0e;
  which_bit = 0;
  put_register(bit_value, which_register, which_bit);
  // ...then alarm2.
  which_bit = 1;
  put_register(bit_value, which_register, which_bit);

  // now set the alarm1 time. values are stored as BCD (binary codwed decimal), which is 
  // a minor nuisance.
  alarm1_seconds_units = future.second() % 10;
  alarm1_seconds_tens = floor(future.second() / 10.0);
  alarm1_minutes_units = future.minute() % 10;
  alarm1_minutes_tens = floor(future.minute() / 10.0);
  alarm1_hours_units = future.hour() % 10;
  uint8_t aht = floor(future.hour() / 10.0);
  if(aht == 0)
  {
    alarm1_hours_ten = 0;
    alarm1_hours_twenty = 0;
  } 
  else if(aht == 1)
  {
    alarm1_hours_ten = 1;
    alarm1_hours_twenty = 0;
  }
  else
  {
    alarm1_hours_ten = 0;
    alarm1_hours_twenty = 1;
  }
  alarm1_day_date = future.day() % 10;  
  alarm1_date_tens = floor(future.day() / 10.0);  

  // now load these into the alarm1 time  registers.

  // alarm1_seconds_units:
  uint8_t mask = 1;
  which_register = 0x07;
  for(which_bit = 0; which_bit < 4; which_bit++)
  {
    if((mask & alarm1_seconds_units) == 0)
    {
      put_register(0, which_register, which_bit);
    } else {
      put_register(1, which_register, which_bit);
    }
    // left-shift the mask bit now:
    mask = mask << 1;
  }

  // alarm1_seconds_tens:
 mask = 1;
  which_register = 0x07;
  for(which_bit = 4; which_bit < 7; which_bit++)
  {
    if((mask & alarm1_seconds_tens) == 0)
    {
      put_register(0, which_register, which_bit);
    } else {
      put_register(1, which_register, which_bit);
    }
    // left-shift the mask bit now:
    mask = mask << 1;
  }

  // alarm1_minutes_units:
 mask = 1;
  which_register = 0x08;
  for(which_bit = 0; which_bit < 4; which_bit++)
  {
    if((mask & alarm1_minutes_units) == 0)
    {
      put_register(0, which_register, which_bit);
    } else {
      put_register(1, which_register, which_bit);
    }
    // left-shift the mask bit now:
    mask = mask << 1;
  }

  // alarm1_minutes_tens:
 mask = 1;
  which_register = 0x08;
  for(which_bit = 4; which_bit < 7; which_bit++)
  {
    if((mask & alarm1_minutes_tens) == 0)
    {
      put_register(0, which_register, which_bit);
    } else {
      put_register(1, which_register, which_bit);
    }
    // left-shift the mask bit now:
    mask = mask << 1;
  }

  // alarm1_hours_units:
 mask = 1;
  which_register = 0x09;
  for(which_bit = 0; which_bit < 4; which_bit++)
  {
    if((mask & alarm1_hours_units) == 0)
    {
      put_register(0, which_register, which_bit);
    } else {
      put_register(1, which_register, which_bit);
    }
    // left-shift the mask bit now:
    mask = mask << 1;
  }

  // alarm1_hours_ten:
  which_register = 0x09;
  which_bit = 4;
  if((alarm1_hours_ten) == 0)
  {
    put_register(0, which_register, which_bit);
  } else {
    put_register(1, which_register, which_bit);
  }

  // alarm1_hours_twenty:
  which_register = 0x09;
  which_bit = 5;
  if((alarm1_hours_twenty) == 0)
  {
    put_register(0, which_register, which_bit);
  } else {
    put_register(1, which_register, which_bit);
  }

  // alarm1_day_date:
 mask = 1;
  which_register = 0x0a;
  for(which_bit = 0; which_bit < 4; which_bit++)
  {
    if((mask & alarm1_day_date) == 0)
    {
      put_register(0, which_register, which_bit);
    } else {
      put_register(1, which_register, which_bit);
    }
    // left-shift the mask bit now:
    mask = mask << 1;
  }

  // alarm1_date_tens:
 mask = 1;
  which_register = 0x0a;
  for(which_bit = 4; which_bit < 6; which_bit++)
  {
    if((mask & alarm1_date_tens) == 0)
    {
      put_register(0, which_register, which_bit);
    } else {
      put_register(1, which_register, which_bit);
    }
    // left-shift the mask bit now:
    mask = mask << 1;
  }

  // now enable alarm1 
  bit_value = 1;
  which_register = 0x0e;
  which_bit = 0;
  put_register(bit_value, which_register, which_bit);

  if(debug)
  {
    // now read all the DS3231 timekeeping registers 
    fetch_RTC_registers();
    // now print what we found fetching the register contents.
    report_RTC();
  }

  return;
}

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

#else

/*
  DS3231: Real-Time Clock. SQW & 32kHz Example
  Read more: www.jarzebski.pl/arduino/komponenty/zegar-czasu-rzeczywistego-rtc-ds3231.html
  GIT: https://github.com/jarzebski/Arduino-DS3231
  Web: http://www.jarzebski.pl
  (c) 2014 by Korneliusz Jarzebski
*/

#include <Wire.h>
#include <DS3231.h>

DS3231 clock;

boolean state;

void setup()
{
  Serial.begin(115200);

  while(!Serial);

  // Initialize DS3231
  Serial.println("Initialize DS3231");;
  clock.begin();

  // disable 32kHz 
  clock.enable32kHz(false);

  // Select output as rate to 1Hz
  // clock.setOutput(DS3231_1HZ);
  clock.setOutput(DS3231_8192HZ);

  // Enable output
  clock.enableOutput(true);

  // Check config

  if (clock.isOutput())
  {
    Serial.println("Oscilator is enabled");
  } else
  {
    Serial.println("Oscilator is disabled");
  }

  switch (clock.getOutput())
  {
    case DS3231_1HZ:     Serial.println("SQW = 1Hz"); break;
    case DS3231_4096HZ:  Serial.println("SQW = 4096Hz"); break;
    case DS3231_8192HZ:  Serial.println("SQW = 8192Hz"); break;
    case DS3231_32768HZ: Serial.println("SQW = 32768Hz"); break;
    default: Serial.println("SQW = Unknown"); break; }
}

void loop()
{
   // Togle 32kHz output
   clock.enable32kHz(state);
   state = !state;
   delay(2000);
}




#endif