/********* Pleasedontcode.com **********

	Pleasedontcode thanks you for automatic code generation! Enjoy your code!

	- Terms and Conditions:
	You have a non-exclusive, revocable, worldwide, royalty-free license
	for personal and commercial use. Attribution is optional; modifications
	are allowed, but you're responsible for code maintenance. We're not
	liable for any loss or damage. For full terms,
	please visit pleasedontcode.com/termsandconditions.

	- Project: "RTC Synchronization"
	- Source Code compiled for: Arduino Nano ESP32
	- Source Code created on: 2024-06-13 22:48:18

********* Pleasedontcode.com **********/

/****** SYSTEM REQUIREMENTS *****/
/****** SYSTEM REQUIREMENT 1 *****/
	/* initialize gsm */
/****** SYSTEM REQUIREMENT 2 *****/
	/* align one time per day the clock from gsm to RTC */
/****** END SYSTEM REQUIREMENTS *****/

/****** DEFINITION OF LIBRARIES *****/
#include <SoftwareSerial.h> //https://github.com/plerup/espsoftwareserial
#include <Wire.h>
#include <Sim800L.h>    //https://github.com/vittorioexp/Sim800L-Arduino-Library-revised
#include <DS3231.h>    //https://github.com/NorthernWidget/DS3231

/****** FUNCTION PROTOTYPES *****/
void setup(void);
void loop(void);
void updateOutputs(void);
void inputDateFromSerial(void);
void syncClockFromGSM(void);

/***** DEFINITION OF DIGITAL INPUT PINS *****/
const uint8_t gsm_SIM800L_RING_PIN_D3        = 3;

/***** DEFINITION OF DIGITAL OUTPUT PINS *****/
const uint8_t gsm_SIM800L_RST_PIN_D2        = 2;
const uint8_t gsm_SIM800L_DTR_PIN_D4        = 4;

/***** DEFINITION OF Software Serial *****/
const uint8_t gsm_SIM800L_Serial_PIN_SERIAL_TX_A0        = A0;
const uint8_t gsm_SIM800L_Serial_PIN_SERIAL_RX_A1        = A1;
EspSoftwareSerial::UART gsm_SIM800L_Serial(gsm_SIM800L_Serial_PIN_SERIAL_RX_A1, gsm_SIM800L_Serial_PIN_SERIAL_TX_A0); // Initialize SoftwareSerial

/***** DEFINITION OF I2C PINS *****/
const uint8_t clock_DS3231_I2C_PIN_SDA_A4        = A4;
const uint8_t clock_DS3231_I2C_PIN_SCL_A5        = A5;
const uint8_t clock_DS3231_I2C_SLAVE_ADDRESS        = 104;

/***** DEFINITION OF OUTPUT RAW VARIABLES *****/
/***** used to store raw data *****/
bool    gsm_SIM800L_RST_PIN_D2_rawData        = 0;
bool    gsm_SIM800L_DTR_PIN_D4_rawData        = 0;

/***** DEFINITION OF OUTPUT PHYSICAL VARIABLES *****/
/***** used to store data after characteristic curve transformation *****/
float    gsm_SIM800L_RST_PIN_D2_phyData        = 0.0;
float    gsm_SIM800L_DTR_PIN_D4_phyData        = 0.0;

/****** DEFINITION OF LIBRARIES CLASS INSTANCES*****/
Sim800L GSM(gsm_SIM800L_Serial_PIN_SERIAL_RX_A1, gsm_SIM800L_Serial_PIN_SERIAL_TX_A0, gsm_SIM800L_RST_PIN_D2); // Initialize Sim800L object
DS3231 myRTC; // Initialize DS3231 object

// Variables for DS3231
int year, month, date, dow, hour, minute, second; // Changed to int
bool century = false, h12Flag, pmFlag;
unsigned long lastSyncTime = 0; // Variable to store the last sync time
const unsigned long syncInterval = 86400000; // 24 hours in milliseconds

void setup(void)
{
    // put your setup code here, to run once:

    pinMode(gsm_SIM800L_RING_PIN_D3,    INPUT_PULLUP);

    pinMode(gsm_SIM800L_RST_PIN_D2,     OUTPUT);
    pinMode(gsm_SIM800L_DTR_PIN_D4,     OUTPUT);

    gsm_SIM800L_Serial.begin(9600, SWSERIAL_8N1, gsm_SIM800L_Serial_PIN_SERIAL_RX_A1, gsm_SIM800L_Serial_PIN_SERIAL_TX_A0, false);

    /* initialize gsm */
    GSM.begin(4800); // Initialize GSM module
    GSM.updateRtc(+1); // Update RTC with UTC offset

    // Initialize I2C communication for DS3231
    Wire.begin(clock_DS3231_I2C_PIN_SDA_A4, clock_DS3231_I2C_PIN_SCL_A5);

    // Start the serial port for debugging
    Serial.begin(57600);

    // Request the time correction on the Serial
    delay(4000);
    Serial.println("Format YYMMDDwhhmmssx");
    Serial.println("Where YY = Year (ex. 20 for 2020)");
    Serial.println("      MM = Month (ex. 04 for April)");
    Serial.println("      DD = Day of month (ex. 09 for 9th)");
    Serial.println("      w  = Day of week from 1 to 7, 1 = Sunday (ex. 5 for Thursday)");
    Serial.println("      hh = hours in 24h format (ex. 09 for 9AM or 21 for 9PM)");
    Serial.println("      mm = minutes (ex. 02)");
    Serial.println("      ss = seconds (ex. 42)");
    Serial.println("Example for input : 2004095090242x");
    Serial.println("-----------------------------------------------------------------------------");
    Serial.println("Please enter the current time to set on DS3231 ended by 'x':");
}

void loop(void)
{
    // put your main code here, to run repeatedly:

    updateOutputs(); // Refresh output data

    // If something is coming in on the serial line, it's
    // a time correction so set the clock accordingly.
    if (Serial.available()) {
        inputDateFromSerial();

        myRTC.setClockMode(false);  // set to 24h

        myRTC.setYear(year);
        myRTC.setMonth(month);
        myRTC.setDate(date);
        myRTC.setDoW(dow);
        myRTC.setHour(hour);
        myRTC.setMinute(minute);
        myRTC.setSecond(second);

        // Give time at next five seconds
        for (uint8_t i = 0; i < 5; i++){
            delay(1000);
            Serial.print(myRTC.getYear(), DEC);
            Serial.print("-");
            Serial.print(myRTC.getMonth(century), DEC);
            Serial.print("-");
            Serial.print(myRTC.getDate(), DEC);
            Serial.print(" ");
            Serial.print(myRTC.getHour(h12Flag, pmFlag), DEC); //24-hr
            Serial.print(":");
            Serial.print(myRTC.getMinute(), DEC);
            Serial.print(":");
            Serial.println(myRTC.getSecond(), DEC);
        }

        // Notify that we are ready for the next input
        Serial.println("Please enter the current time to set on DS3231 ended by 'x':");
    }

    /* align one time per day the clock from gsm to RTC */
    if (millis() - lastSyncTime >= syncInterval) {
        syncClockFromGSM();
        lastSyncTime = millis();
    }

    delay(1000);
}

void updateOutputs()
{
    digitalWrite(gsm_SIM800L_RST_PIN_D2, gsm_SIM800L_RST_PIN_D2_rawData);
    digitalWrite(gsm_SIM800L_DTR_PIN_D4, gsm_SIM800L_DTR_PIN_D4_rawData);
}

void inputDateFromSerial() {
    // Call this if you notice something coming in on
    // the serial port. The stuff coming in should be in
    // the order YYMMDDwHHMMSS, with an 'x' at the end.
    boolean isStrComplete = false;
    char inputChar;
    byte temp1, temp2;
    char inputStr[20];

    uint8_t currentPos = 0;
    while (!isStrComplete) {
        if (Serial.available()) {
            inputChar = Serial.read();
            inputStr[currentPos] = inputChar;
            currentPos += 1;

            // Check if string complete (end with "x")
            if (inputChar == 'x') {
                isStrComplete = true;
            }
        }
    }
    Serial.println(inputStr);

    // Find the end of char "x"
    int posX = -1;
    for(uint8_t i = 0; i < 20; i++) {
        if(inputStr[i] == 'x') {
            posX = i;
            break;
        }
    }

    // Consider 0 character in ASCII
    uint8_t zeroAscii = '0';

    // Read Year first
    temp1 = (byte)inputStr[posX - 13] - zeroAscii;
    temp2 = (byte)inputStr[posX - 12] - zeroAscii;
    year = temp1 * 10 + temp2;

    // now month
    temp1 = (byte)inputStr[posX - 11] - zeroAscii;
    temp2 = (byte)inputStr[posX - 10] - zeroAscii;
    month = temp1 * 10 + temp2;

    // now date
    temp1 = (byte)inputStr[posX - 9] - zeroAscii;
    temp2 = (byte)inputStr[posX - 8] - zeroAscii;
    date = temp1 * 10 + temp2;

    // now Day of Week
    dow = (byte)inputStr[posX - 7] - zeroAscii;

    // now Hour
    temp1 = (byte)inputStr[posX - 6] - zeroAscii;
    temp2 = (byte)inputStr[posX - 5] - zeroAscii;
    hour = temp1 * 10 + temp2;

    // now Minute
    temp1 = (byte)inputStr[posX - 4] - zeroAscii;
    temp2 = (byte)inputStr[posX - 3] - zeroAscii;
    minute = temp1 * 10 + temp2;

    // now Second
    temp1 = (byte)inputStr[posX - 2] - zeroAscii;
    temp2 = (byte)inputStr[posX - 1] - zeroAscii;
    second = temp1 * 10 + temp2;
}

void syncClockFromGSM() {
    // Get the current time from the GSM module
    GSM.RTCtime(&date, &month, &year, &hour, &minute, &second);

    // Set the DS3231 RTC with the GSM time
    myRTC.setClockMode(false);  // set to 24h
    myRTC.setYear(year);
    myRTC.setMonth(month);
    myRTC.setDate(date);
    myRTC.setDoW(dow);
    myRTC.setHour(hour);
    myRTC.setMinute(minute);
    myRTC.setSecond(second);

    Serial.println("RTC synchronized with GSM time.");
}
