From c1ea73c3d1e836bd781c829e18e9fddcffc67e10 Mon Sep 17 00:00:00 2001 From: PaulZC Date: Mon, 13 May 2024 18:22:01 +0100 Subject: [PATCH] Add loop and sample Threads. Fix printf gremlins. --- .../Geophone.ino | 16 ++-- .../OpenLog_Artemis_Geophone_Logger.ino | 57 +++++++++++---- .../Sensors.ino | 45 +++++++++++- .../autoDetect.ino | 2 +- .../logging.ino | 13 +++- .../lowerPower.ino | 8 +- .../menuAttachedDevices.ino | 8 +- .../menuMain.ino | 1 - .../menuThreshold.ino | 4 +- .../menuTimeStamp.ino | 46 ++++++++++-- .../OpenLog_Artemis_Geophone_Logger/nvm.ino | 2 +- .../timeStamp.ino | 73 +++++-------------- 12 files changed, 172 insertions(+), 103 deletions(-) diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/Geophone.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/Geophone.ino index ee9dd9b..46155bc 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/Geophone.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/Geophone.ino @@ -53,12 +53,6 @@ void geophone_setup() g_ui32GeophoneDataBufferPointer = 0; // Reset the pointer //stimer_init(); // Now start the timer - - cancel_handle_sample = the_event_queue.call_every(SAMPLE_INTERVAL, &sampling_interrupt); // Call sampling_interrupt every 2ms (500Hz) - - cancel_handle_loop = the_event_queue.call_every(LOOP_INTERVAL, &mainLoop); // Call mainLoop every 250ms - - the_event_queue.dispatch(); } /* @@ -169,9 +163,11 @@ bool geophone_loop() { for (uint32_t i = 1; i < FREQ_LIMIT; i++) { - sprintf(tempData, "%.2f,", g_fGeophoneMagnitudes[i]); + char tempStr[16]; + olaftoa(g_fGeophoneMagnitudes[i], tempStr, 2, sizeof(tempStr) / sizeof(char)); + sprintf(tempData, "%s,", tempStr); strcat(geophoneData, tempData); - sprintf(tempData, "%.2f\n", g_fGeophoneMagnitudes[i]); + sprintf(tempData, "%s\n", tempStr); strcat(geophoneDataSerial, tempData); } @@ -179,7 +175,9 @@ bool geophone_loop() strcat(geophoneData, tempData); strcat(peakFreq, tempData); - sprintf(tempData, ",%.2f", fMaxValue); + char tempStr[16]; + olaftoa(fMaxValue, tempStr, 2, sizeof(tempStr) / sizeof(char)); + sprintf(tempData, ",%s", tempStr); strcat(peakFreq, tempData); if (settings.printMeasurementCount) diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/OpenLog_Artemis_Geophone_Logger.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/OpenLog_Artemis_Geophone_Logger.ino index ffd36eb..2db3d57 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/OpenLog_Artemis_Geophone_Logger.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/OpenLog_Artemis_Geophone_Logger.ino @@ -22,7 +22,7 @@ The RTC can be set by a u-blox GNSS module. - Based on v14 of: + Based on v2.8 of: OpenLog Artemis By: Nathan Seidle SparkFun Electronics @@ -170,14 +170,12 @@ uint64_t qwiicPowerOnTime = 0; //Used to delay after Qwiic power on to allow sen //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //Geophone settings -#define TEST_PERIOD_1 20000 // Uncomment to enable sinusoidal test signal (period in micros) (20000 = 50Hz) -#define TEST_AMPLITUDE_1 100 // Amplitude of the sinusoidal test signal -#define TEST_PERIOD_2 30303 // Uncomment to enable second (mixed) cosinusoidal test signal (period in micros) (30303 = 33Hz) -#define TEST_AMPLITUDE_2 50 // Amplitude of the sinusoidal test signal +//#define TEST_PERIOD_1 20000 // Uncomment to enable sinusoidal test signal (period in micros) (20000 = 50Hz) +//#define TEST_AMPLITUDE_1 100 // Amplitude of the sinusoidal test signal +//#define TEST_PERIOD_2 30303 // Uncomment to enable second (mixed) cosinusoidal test signal (period in micros) (30303 = 33Hz) +//#define TEST_AMPLITUDE_2 50 // Amplitude of the sinusoidal test signal //#define SAMPLE_INTERVAL 6000 // Interval for 500Hz with a 3MHz clock -#define DUMP(varname) {if (settings.serialPlotterMode == false) Serial.printf("%s: %llu\n", #varname, varname)} - //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #include "WDT.h" // WDT support @@ -212,16 +210,20 @@ void stopWatchdog() //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -// Use an EventQueue to control the ADC samples -#include "mbed_events.h" +// Use Thread and EventQueue to control the ADC samples +#include "mbed.h" #include -events::EventQueue the_event_queue; +rtos::Thread sample_thread; +events::EventQueue sample_event_queue; int cancel_handle_sample = 0; //static const std::chrono::milliseconds SAMPLE_INTERVAL = 2ms; static const uint32_t SAMPLE_INTERVAL = 2; +rtos::Thread loop_thread; +events::EventQueue loop_event_queue; + int cancel_handle_loop = 0; //static const std::chrono::milliseconds LOOP_INTERVAL = 250ms; static const uint32_t LOOP_INTERVAL = 250; @@ -318,8 +320,6 @@ void setup() { else if (settings.serialPlotterMode == false) Serial.println("No Qwiic devices detected"); - //Serial.printf("Setup time: %.02f ms\n", (micros() - startTime) / 1000.0); - //Print the helper text if ((settings.enableTerminalOutput == true) && (settings.serialPlotterMode == false)) { @@ -332,15 +332,46 @@ void setup() { digitalWrite(PIN_STAT_LED, LOW); // Turn the STAT LED off now that everything is configured - geophone_setup(); // Set up the ADC and get ready to start the events + geophone_setup(); // Set up the ADC + + loop_thread.start(&startMainLoop); + + loop_thread.set_priority(osPriorityNormal1); // Increase loop_thread priority above the actual loop() + + sample_thread.start(&startSamples); + + sample_thread.set_priority(osPriorityNormal2); // Increase sample_thread priority so it can interrupt loop_thread } void loop() { + yield(); // Nothing to do here... +} + +void startSamples() +{ + cancel_handle_sample = sample_event_queue.call_every(SAMPLE_INTERVAL, &sampling_interrupt); // Call sampling_interrupt every 2ms (500Hz) + + sample_event_queue.dispatch(); + + while (1) + yield(); +} + +void startMainLoop() +{ + cancel_handle_loop = loop_event_queue.call_every(LOOP_INTERVAL, &mainLoop); // Call mainLoop every 250ms + + loop_event_queue.dispatch(); + + while (1) + yield(); } void mainLoop() { + digitalWrite(PIN_LOGIC_DEBUG, !digitalRead(PIN_LOGIC_DEBUG)); + if (Serial.available()) // Check if the user pressed a key { samplingEnabled = false; // Disable sampling while menu is open diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/Sensors.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/Sensors.ino index 6ceda33..138fc0c 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/Sensors.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/Sensors.ino @@ -11,11 +11,27 @@ void getDateTime() if (settings.logDate) { - char rtcDate[12]; //10/12/2019, + char rtcDate[11]; // 10/12/2019 + char rtcDay[3]; + char rtcMonth[3]; + char rtcYear[5]; + if (myRTC.dayOfMonth < 10) + sprintf(rtcDay, "0%d", myRTC.dayOfMonth); + else + sprintf(rtcDay, "%d", myRTC.dayOfMonth); + if (myRTC.month < 10) + sprintf(rtcMonth, "0%d", myRTC.month); + else + sprintf(rtcMonth, "%d", myRTC.month); + if (myRTC.year < 10) + sprintf(rtcYear, "200%d", myRTC.year); + else + sprintf(rtcYear, "20%d", myRTC.year); if (settings.americanDateStyle == true) - sprintf(rtcDate, "%02d/%02d/20%02d,", myRTC.month, myRTC.dayOfMonth, myRTC.year); + sprintf(rtcDate, "%s/%s/%s,", rtcMonth, rtcDay, rtcYear); else - sprintf(rtcDate, "%02d/%02d/20%02d,", myRTC.dayOfMonth, myRTC.month, myRTC.year); + sprintf(rtcDate, "%s/%s/%s,", rtcDay, rtcMonth, rtcYear); + strcat(dateTime, rtcDate); } @@ -27,7 +43,28 @@ void getDateTime() { if (adjustedHour > 12) adjustedHour -= 12; } - sprintf(rtcTime, "%02d:%02d:%02d.%02d,", adjustedHour, myRTC.minute, myRTC.seconds, myRTC.hundredths); + char rtcHour[3]; + char rtcMin[3]; + char rtcSec[3]; + char rtcHundredths[3]; + if (adjustedHour < 10) + sprintf(rtcHour, "0%d", adjustedHour); + else + sprintf(rtcHour, "%d", adjustedHour); + if (myRTC.minute < 10) + sprintf(rtcMin, "0%d", myRTC.minute); + else + sprintf(rtcMin, "%d", myRTC.minute); + if (myRTC.seconds < 10) + sprintf(rtcSec, "0%d", myRTC.seconds); + else + sprintf(rtcSec, "%d", myRTC.seconds); + if (myRTC.hundredths < 10) + sprintf(rtcHundredths, "0%d", myRTC.hundredths); + else + sprintf(rtcHundredths, "%d", myRTC.hundredths); + sprintf(rtcTime, "%s:%s:%s.%s,", rtcHour, rtcMin, rtcSec, rtcHundredths); + strcat(dateTime, rtcTime); } } //end if use RTC for timestamp diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/autoDetect.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/autoDetect.ino index 3556b7d..d2e6186 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/autoDetect.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/autoDetect.ino @@ -403,7 +403,7 @@ deviceType_e testDevice(uint8_t i2cAddress) //Confidence: Medium - reads Configuration Register SfeADS1219ArdI2C sensor; if (sensor.begin(qwiic, i2cAddress) == true) //Wire port, Address - return (DEVICE_ADC_ADS122C04); + return (DEVICE_ADC_ADS1219); } break; case 0x42: diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/logging.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/logging.ino index 2139bd7..1ae47e1 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/logging.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/logging.ino @@ -35,7 +35,18 @@ char* findNextAvailableLog(int &newFileNumber, const char *fileLeader) static char newFileName[40]; while (1) { - sprintf(newFileName, "%s%05u.TXT", fileLeader, newFileNumber); //Splice the new file number into this file name. Max no. is 99999. + char newFileNumberStr[6]; + if (newFileNumber < 10) + sprintf(newFileNumberStr, "0000%d", newFileNumber); + else if (newFileNumber < 100) + sprintf(newFileNumberStr, "000%d", newFileNumber); + else if (newFileNumber < 1000) + sprintf(newFileNumberStr, "00%d", newFileNumber); + else if (newFileNumber < 10000) + sprintf(newFileNumberStr, "0%d", newFileNumber); + else + sprintf(newFileNumberStr, "%d", newFileNumber); + sprintf(newFileName, "%s%s.TXT", fileLeader, newFileNumberStr); //Splice the new file number into this file name. Max no. is 99999. if (sd.exists(newFileName) == false) break; //File name not found so we will use it. diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/lowerPower.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/lowerPower.ino index 4dcf19a..3800386 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/lowerPower.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/lowerPower.ino @@ -65,8 +65,8 @@ void powerDownOLA(void) detachInterrupt(PIN_POWER_LOSS); #endif - the_event_queue.cancel(cancel_handle_sample); // Stop the ADC task - the_event_queue.cancel(cancel_handle_loop); // Stop the loop task + sample_event_queue.cancel(cancel_handle_sample); // Stop the ADC task + loop_event_queue.cancel(cancel_handle_loop); // Stop the loop task //Prevent stop logging button from waking us from sleep if (settings.useGPIO32ForStopLogging == true) @@ -167,8 +167,8 @@ void resetArtemis(void) delay(sdPowerDownDelay); // Give the SD card time to finish writing ***** THIS IS CRITICAL ***** - the_event_queue.cancel(cancel_handle_sample); // Stop the ADC task - the_event_queue.cancel(cancel_handle_loop); // Stop the loop task + sample_event_queue.cancel(cancel_handle_sample); // Stop the ADC task + loop_event_queue.cancel(cancel_handle_loop); // Stop the loop task Serial.flush(); //Finish any prints diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/menuAttachedDevices.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/menuAttachedDevices.ino index 05b0715..56761ae 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/menuAttachedDevices.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/menuAttachedDevices.ino @@ -111,14 +111,12 @@ void menuAttachedDevices() temp = temp->next; } - availableDevices++; - Serial.printf("%d) Configure Qwiic Settings\r\n", availableDevices); availableDevices++; Serial.println(F("x) Exit")); int nodeNumber = getNumber(menuTimeout); //Timeout after x seconds - if (nodeNumber > 0 && nodeNumber < availableDevices - 1) + if (nodeNumber > 0 && nodeNumber < availableDevices) { //Lookup the function we need to call based the node number FunctionPointer functionPointer = getConfigFunctionPtr(nodeNumber - 1); @@ -129,10 +127,6 @@ void menuAttachedDevices() configureDevice(nodeNumber - 1); //Reconfigure this device with the new settings } - else if (nodeNumber == availableDevices - 1) - { - menuConfigure_QwiicBus(); - } else if (nodeNumber == STATUS_PRESSED_X) break; else if (nodeNumber == STATUS_GETNUMBER_TIMEOUT) diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/menuMain.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/menuMain.ino index 89e25bf..328d0cb 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/menuMain.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/menuMain.ino @@ -12,7 +12,6 @@ void menuMain() Serial.println("2) Configure Time Stamp"); - //Serial.println("3) Detect / Configure Attached Devices"); Serial.println("3) Configure Qwiic Settings"); Serial.println("4) Configure Geophone Threshold"); diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/menuThreshold.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/menuThreshold.ino index 58962b1..aba54f3 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/menuThreshold.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/menuThreshold.ino @@ -6,7 +6,9 @@ void menuThreshold() Serial.println("Menu: Configure Geophone Threshold"); Serial.print("1) Threshold: "); - Serial.printf("%f\n", settings.threshold); + char tempStr[16]; + olaftoa(settings.threshold, tempStr, 3, sizeof(tempStr) / sizeof(char)); + Serial.printf("%s\n", tempStr); Serial.println("x) Exit"); diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/menuTimeStamp.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/menuTimeStamp.ino index fe73149..59c9cb3 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/menuTimeStamp.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/menuTimeStamp.ino @@ -7,22 +7,58 @@ void menuTimeStamp() Serial.print("Current date/time: "); myRTC.getTime(); - char rtcDate[11]; //10/12/2019 + char rtcDate[11]; // 10/12/2019 + char rtcDay[3]; + char rtcMonth[3]; + char rtcYear[5]; + if (myRTC.dayOfMonth < 10) + sprintf(rtcDay, "0%d", myRTC.dayOfMonth); + else + sprintf(rtcDay, "%d", myRTC.dayOfMonth); + if (myRTC.month < 10) + sprintf(rtcMonth, "0%d", myRTC.month); + else + sprintf(rtcMonth, "%d", myRTC.month); + if (myRTC.year < 10) + sprintf(rtcYear, "200%d", myRTC.year); + else + sprintf(rtcYear, "20%d", myRTC.year); if (settings.americanDateStyle == true) - sprintf(rtcDate, "%02d/%02d/20%02d", myRTC.month, myRTC.dayOfMonth, myRTC.year); + sprintf(rtcDate, "%s/%s/%s,", rtcMonth, rtcDay, rtcYear); else - sprintf(rtcDate, "%02d/%02d/20%02d", myRTC.dayOfMonth, myRTC.month, myRTC.year); + sprintf(rtcDate, "%s/%s/%s,", rtcDay, rtcMonth, rtcYear); Serial.print(rtcDate); Serial.print(" "); - char rtcTime[12]; //09:14:37.41 + char rtcTime[13]; //09:14:37.41, int adjustedHour = myRTC.hour; if (settings.hour24Style == false) { if (adjustedHour > 12) adjustedHour -= 12; } - sprintf(rtcTime, "%02d:%02d:%02d.%02d", adjustedHour, myRTC.minute, myRTC.seconds, myRTC.hundredths); + char rtcHour[3]; + char rtcMin[3]; + char rtcSec[3]; + char rtcHundredths[3]; + if (adjustedHour < 10) + sprintf(rtcHour, "0%d", adjustedHour); + else + sprintf(rtcHour, "%d", adjustedHour); + if (myRTC.minute < 10) + sprintf(rtcMin, "0%d", myRTC.minute); + else + sprintf(rtcMin, "%d", myRTC.minute); + if (myRTC.seconds < 10) + sprintf(rtcSec, "0%d", myRTC.seconds); + else + sprintf(rtcSec, "%d", myRTC.seconds); + if (myRTC.hundredths < 10) + sprintf(rtcHundredths, "0%d", myRTC.hundredths); + else + sprintf(rtcHundredths, "%d", myRTC.hundredths); + sprintf(rtcTime, "%s:%s:%s.%s", rtcHour, rtcMin, rtcSec, rtcHundredths); + Serial.println(rtcTime); Serial.print("1) Log Date: "); diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/nvm.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/nvm.ino index 2107436..af5c36e 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/nvm.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/nvm.ino @@ -87,7 +87,7 @@ void recordSystemSettingsToFile() settingsFile.println("americanDateStyle=" + (String)settings.americanDateStyle); settingsFile.println("hour24Style=" + (String)settings.hour24Style); settingsFile.println("serialTerminalBaudRate=" + (String)settings.serialTerminalBaudRate); - settingsFile.println("localUTCOffset=" + (String)settings.localUTCOffset); + settingsFile.print("localUTCOffset="); settingsFile.println(settings.localUTCOffset); settingsFile.println("printDebugMessages=" + (String)settings.printDebugMessages); settingsFile.println("powerDownQwiicBusBetweenReads=" + (String)settings.powerDownQwiicBusBetweenReads); settingsFile.println("qwiicBusMaxSpeed=" + (String)settings.qwiicBusMaxSpeed); diff --git a/Firmware/OpenLog_Artemis_Geophone_Logger/timeStamp.ino b/Firmware/OpenLog_Artemis_Geophone_Logger/timeStamp.ino index 7786248..c082e6e 100644 --- a/Firmware/OpenLog_Artemis_Geophone_Logger/timeStamp.ino +++ b/Firmware/OpenLog_Artemis_Geophone_Logger/timeStamp.ino @@ -1,56 +1,3 @@ -//Gets the current time from GPS -//Adjust the hour by local hour offset -//Adjust the hour by DST as necessary -//Adjust the date as necessary -//Returns a string according to user's settings -//Leap year is taken into account but does not interact with DST (DST happens later in March) -// -//Note: this function should only be called if we know that a u-blox GNSS is actually connected -// -String getGPSDateTimeAsStr() { - //Get latested date/time from GPS -// int year = gpsSensor_ublox.getYear(); -// int month = gpsSensor_ublox.getMonth(); -// int day = gpsSensor_ublox.getDay(); -// int hour = gpsSensor_ublox.getHour(); -// int minute = gpsSensor_ublox.getMinute(); -// int second = gpsSensor_ublox.getSecond(); - - int year = 19; - int month = 1; - int day = 1; - int hour = 6; - int minute = 14; - int second = 37; - - adjustToLocalDateTime(year, month, day, hour, settings.localUTCOffset); - - if (settings.hour24Style == false) - { - if (hour > 12) hour -= 12; - } - - String myTime = ""; - - if (settings.logDate == true) - { - char gpsDate[11]; //10/12/2019 - if (settings.americanDateStyle == true) - sprintf(gpsDate, "%02d/%02d/20%02d", month, day, year); - else - sprintf(gpsDate, "%02d/%02d/20%02d", day, month, year); - myTime += String(gpsDate); - myTime += ","; - } - - char gpsTime[13]; //09:14:37.412 - sprintf(gpsTime, "%02d:%02d:%02d.%03d", hour, minute, second, millis() % 1000); //TODO get GPS hundredths() - myTime += String(gpsTime); - myTime += ","; - - return (myTime); -} - //Gets the current time from GPS //Adjust the hour by local hour offset //Adjust the date as necessary @@ -64,7 +11,7 @@ void getGPSDateTime(int &year, int &month, int &day, int &hour, int &minute, int //Do it twice - to make sure the data is fresh getUbloxDateTime(year, month, day, hour, minute, second, millisecond, dateValid, timeValid); - adjustToLocalDateTime(year, month, day, hour, settings.localUTCOffset); + adjustToLocalDateTime(year, month, day, hour, minute, settings.localUTCOffset); } //Given the date and hour, calculate local date/time @@ -72,10 +19,24 @@ void getGPSDateTime(int &year, int &month, int &day, int &hour, int &minute, int //Adjust the hour by DST as necessary //Adjust the date as necessary //Leap year is taken into account but does not interact with DST (DST happens later in March) -void adjustToLocalDateTime(int &year, int &month, int &day, int &hour, int localUTCOffset) { +void adjustToLocalDateTime(int &year, int &month, int &day, int &hour, int &minute, float localUTCOffset) { //Apply any offset to UTC - hour += localUTCOffset; + hour += (int)localUTCOffset; + + //Apply minutes offset + int tzMins = (int)((localUTCOffset - (float)((int)localUTCOffset)) * 60.0); + minute += tzMins; + if (minute >= 60) + { + hour += 1; + minute -= 60; + } + else if (minute < 0) + { + hour -= 1; + minute += 60; + } //If the adjusted hour is outside 0 to 23, then adjust date as necessary correctDate(year, month, day, hour);