diff --git a/Binaries/OpenLog_Artemis-V10-v22.bin b/Binaries/OpenLog_Artemis-V10-v22.bin new file mode 100644 index 0000000..38e82f2 Binary files /dev/null and b/Binaries/OpenLog_Artemis-V10-v22.bin differ diff --git a/Binaries/OpenLog_Artemis-X04-v22.bin b/Binaries/OpenLog_Artemis-X04-v22.bin new file mode 100644 index 0000000..40b8c77 Binary files /dev/null and b/Binaries/OpenLog_Artemis-X04-v22.bin differ diff --git a/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino b/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino index 58c22b7..50473b8 100644 --- a/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino +++ b/Firmware/OpenLog_Artemis/OpenLog_Artemis.ino @@ -13,10 +13,6 @@ The Board should be set to SparkFun Apollo3 \ RedBoard Artemis ATP. - Please note: this version of the firmware compiles on v2.1.0 of the Apollo3 boards. - - (At the time of writing, data logging with the the u-blox ZED-F9P is problematic when using v2.1.1 of the core.) - v1.0 Power Consumption: Sleep between reads, RTC fully charged, no Qwiic, SD, no USB, no Power LED: 260uA 10Hz logging IMU, no Qwiic, SD, no USB, no Power LED: 9-27mA @@ -112,10 +108,27 @@ (done) Add a fix for issue #109 - check if a BME280 is connected before calling multiplexerBegin: https://github.com/sparkfun/OpenLog_Artemis/issues/109 (done) Correct issue #104. enableSD was redundant. The microSD power always needs to be on if there is a card inserted, otherwise the card pulls the SPI lines low, preventing communication with the IMU: https://github.com/sparkfun/OpenLog_Artemis/issues/104 + + v2.2: + Use Apollo3 v2.2.1 with changes by paulvha to fix Issue 117 (Thank you Paul!) + https://github.com/sparkfun/OpenLog_Artemis/issues/117#issuecomment-1085881142 + Also includes Paul's SPI.end fix + https://github.com/sparkfun/Arduino_Apollo3/issues/442 + In libraries/SPI/src/SPI.cpp change end() to: + void arduino::MbedSPI::end() { + if (dev) { + delete dev; + dev = NULL; + } + } + Use SdFat v2.1.2 + Compensate for missing / not-populated IMU + Add support for yyyy/mm/dd and ISO 8601 date style (Issue 118) + Add support for fractional time zone offsets */ const int FIRMWARE_VERSION_MAJOR = 2; -const int FIRMWARE_VERSION_MINOR = 1; +const int FIRMWARE_VERSION_MINOR = 2; //Define the OLA board identifier: // This is an int which is unique to this variant of the OLA and which allows us @@ -125,7 +138,7 @@ const int FIRMWARE_VERSION_MINOR = 1; // the variant * 0x100 (OLA = 1; GNSS_LOGGER = 2; GEOPHONE_LOGGER = 3) // the major firmware version * 0x10 // the minor firmware version -#define OLA_IDENTIFIER 0x121 // Stored as 289 decimal in OLA_settings.txt +#define OLA_IDENTIFIER 0x122 // Stored as 290 decimal in OLA_settings.txt #include "settings.h" @@ -192,7 +205,7 @@ TwoWire qwiic(PIN_QWIIC_SDA,PIN_QWIIC_SCL); //Will use pads 8/9 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #include -#include //SdFat v2.0.7 by Bill Greiman: http://librarymanager/All#SdFat_exFAT +#include //SdFat by Bill Greiman: http://librarymanager/All#SdFat_exFAT #define SD_FAT_TYPE 3 // SD_FAT_TYPE = 0 for SdFat/File, 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT. #define SD_CONFIG SdSpiConfig(PIN_MICROSD_CHIP_SELECT, SHARED_SPI, SD_SCK_MHZ(24)) // 24MHz @@ -448,7 +461,7 @@ void setup() { else SerialPrintln(F("Serial logging offline")); if (online.IMU == true) SerialPrintln(F("IMU online")); - else SerialPrintln(F("IMU offline")); + else SerialPrintln(F("IMU offline - or not present")); if (settings.logMaxRate == true) SerialPrintln(F("Logging analog pins at max data rate")); @@ -480,7 +493,7 @@ void setup() { //If we are sleeping between readings then we cannot rely on millis() as it is powered down //Use RTC instead - measurementStartTime = bestMillis(); + measurementStartTime = rtcMillis(); digitalWrite(PIN_STAT_LED, LOW); // Turn the STAT LED off now that everything is configured @@ -547,12 +560,12 @@ void loop() { //If we are sleeping between readings then we cannot rely on millis() as it is powered down //Use RTC instead - lastSeriaLogSyncTime = bestMillis(); //Reset the last sync time to now + lastSeriaLogSyncTime = rtcMillis(); //Reset the last sync time to now newSerialData = true; } else if (newSerialData == true) { - if ((bestMillis() - lastSeriaLogSyncTime) > MAX_IDLE_TIME_MSEC) //If we haven't received any characters recently then sync log file + if ((rtcMillis() - lastSeriaLogSyncTime) > MAX_IDLE_TIME_MSEC) //If we haven't received any characters recently then sync log file { if (incomingBufferSpot > 0) { @@ -568,7 +581,7 @@ void loop() { } newSerialData = false; - lastSeriaLogSyncTime = bestMillis(); //Reset the last sync time to now + lastSeriaLogSyncTime = rtcMillis(); //Reset the last sync time to now printDebug("Total chars received: " + (String)charsReceived + "\r\n"); } } @@ -660,9 +673,9 @@ void loop() { } //Force sync every 500ms - if (bestMillis() - lastDataLogSyncTime > 500) + if (rtcMillis() - lastDataLogSyncTime > 500) { - lastDataLogSyncTime = bestMillis(); + lastDataLogSyncTime = rtcMillis(); sensorDataFile.sync(); if (settings.frequentFileAccessTimestamps == true) updateDataFileAccess(&sensorDataFile); // Update the file access time & date @@ -719,7 +732,7 @@ void loop() { { // Check if we have been awake long enough (millis is reset to zero when waking from sleep) // goToSleep will automatically compensate for how long we have been awake - if ((bestMillis() - lastAwakeTimeMillis) < settings.minimumAwakeTimeMillis) + if ((rtcMillis() - lastAwakeTimeMillis) < settings.minimumAwakeTimeMillis) return; // Too early to sleep - leave sleepAfterRead set true } @@ -1233,6 +1246,7 @@ void beginDataLogging() } updateDataFileCreate(&sensorDataFile); // Update the file create time & date + sensorDataFile.sync(); online.dataLogging = true; } @@ -1257,6 +1271,7 @@ void beginSerialLogging() } updateDataFileCreate(&serialDataFile); // Update the file create time & date + serialDataFile.sync(); //We need to manually restore the Serial1 TX and RX pins configureSerial1TxRx(); diff --git a/Firmware/OpenLog_Artemis/Sensors.ino b/Firmware/OpenLog_Artemis/Sensors.ino index 20f8831..ae5c1d9 100644 --- a/Firmware/OpenLog_Artemis/Sensors.ino +++ b/Firmware/OpenLog_Artemis/Sensors.ino @@ -188,7 +188,7 @@ void getData() //If we are sleeping between readings then we cannot rely on millis() as it is powered down //Use RTC instead - currentMillis = bestMillis(); + currentMillis = rtcMillis(); float actualRate; if ((currentMillis - measurementStartTime) < 1) // Avoid divide by zero actualRate = 0.0; @@ -278,7 +278,7 @@ void gatherDeviceValues() setQwiicPullups(0); //Disable pullups to minimize CRC issues SFE_UBLOX_GNSS *nodeDevice = (SFE_UBLOX_GNSS *)temp->classPtr; - struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; + struct_ublox *nodeSetting = (struct_ublox *)temp->configPtr; if (nodeSetting->log == true) { @@ -299,12 +299,18 @@ void gatherDeviceValues() else sprintf(gnssMonthStr, "%d", gnssMonth); sprintf(gnssYearStr, "%d", gnssYear); - if (settings.americanDateStyle == true) + if (settings.dateStyle == 0) { sprintf(tempData, "%s/%s/%s,", gnssMonthStr, gnssDayStr, gnssYearStr); } - else + else if (settings.dateStyle == 1) + { sprintf(tempData, "%s/%s/%s,", gnssDayStr, gnssMonthStr, gnssYearStr); + } + else // if (settings.dateStyle == 2) + { + sprintf(tempData, "%s/%s/%s,", gnssYearStr, gnssMonthStr, gnssDayStr); + } strcat(outputData, tempData); } if (nodeSetting->logTime) @@ -1182,7 +1188,7 @@ void printHelperText(bool terminalOnly) break; case DEVICE_GPS_UBLOX: { - struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; + struct_ublox *nodeSetting = (struct_ublox *)temp->configPtr; if (nodeSetting->log) { if (nodeSetting->logDate) @@ -1566,7 +1572,7 @@ void setMaxI2CSpeed() if (temp->deviceType == DEVICE_GPS_UBLOX) { //Check if i2cSpeed is lowered - struct_uBlox *sensor = (struct_uBlox*)temp->configPtr; + struct_ublox *sensor = (struct_ublox*)temp->configPtr; if (sensor->i2cSpeed == 100000) { //printDebug("setMaxI2CSpeed: sensor->i2cSpeed is 100000. Reducing maxSpeed to 100kHz\r\n"); diff --git a/Firmware/OpenLog_Artemis/autoDetect.ino b/Firmware/OpenLog_Artemis/autoDetect.ino index 88fe21a..ee42b32 100644 --- a/Firmware/OpenLog_Artemis/autoDetect.ino +++ b/Firmware/OpenLog_Artemis/autoDetect.ino @@ -138,7 +138,7 @@ bool addDevice(deviceType_e deviceType, uint8_t address, uint8_t muxAddress, uin case DEVICE_GPS_UBLOX: { temp->classPtr = new SFE_UBLOX_GNSS; - temp->configPtr = new struct_uBlox; + temp->configPtr = new struct_ublox; } break; case DEVICE_PROXIMITY_VCNL4040: @@ -351,7 +351,7 @@ bool beginQwiicDevices() { setQwiicPullups(0); //Disable pullups for u-blox comms. SFE_UBLOX_GNSS *tempDevice = (SFE_UBLOX_GNSS *)temp->classPtr; - struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; //Create a local pointer that points to same spot as node does + struct_ublox *nodeSetting = (struct_ublox *)temp->configPtr; //Create a local pointer that points to same spot as node does if (nodeSetting->powerOnDelayMillis > qwiicPowerOnDelayMillis) qwiicPowerOnDelayMillis = nodeSetting->powerOnDelayMillis; // Increase qwiicPowerOnDelayMillis if required if(settings.printGNSSDebugMessages == true) tempDevice->enableDebugging(); // Enable debug messages if required temp->online = tempDevice->begin(qwiic, temp->address); //Wire port, Address @@ -661,7 +661,7 @@ void configureDevice(node * temp) setQwiicPullups(0); //Disable pullups for u-blox comms. SFE_UBLOX_GNSS *sensor = (SFE_UBLOX_GNSS *)temp->classPtr; - struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; + struct_ublox *nodeSetting = (struct_ublox *)temp->configPtr; sensor->setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise) @@ -882,7 +882,7 @@ FunctionPointer getConfigFunctionPtr(uint8_t nodeNumber) ptr = (FunctionPointer)menuConfigure_VL53L1X; break; case DEVICE_GPS_UBLOX: - ptr = (FunctionPointer)menuConfigure_uBlox; + ptr = (FunctionPointer)menuConfigure_ublox; break; case DEVICE_PROXIMITY_VCNL4040: ptr = (FunctionPointer)menuConfigure_VCNL4040; diff --git a/Firmware/OpenLog_Artemis/lowerPower.ino b/Firmware/OpenLog_Artemis/lowerPower.ino index 199ec6d..e5c94c2 100644 --- a/Firmware/OpenLog_Artemis/lowerPower.ino +++ b/Firmware/OpenLog_Artemis/lowerPower.ino @@ -322,6 +322,11 @@ void goToSleep(uint32_t sysTicksToSleep) { am_hal_gpio_pinconfig(48 , g_AM_HAL_GPIO_DISABLE); //TX0 am_hal_gpio_pinconfig(49 , g_AM_HAL_GPIO_DISABLE); //RX0 + if (settings.useTxRxPinsForTerminal == true) + { + am_hal_gpio_pinconfig(12 , g_AM_HAL_GPIO_DISABLE); //TX1 + am_hal_gpio_pinconfig(13 , g_AM_HAL_GPIO_DISABLE); //RX1 + } } //Make sure PIN_POWER_LOSS is configured as an input for the WDT @@ -438,13 +443,11 @@ void wakeFromSleep() am_hal_gpio_pincfg_t intPinConfig = g_AM_HAL_GPIO_INPUT_PULLUP; if (settings.fallingEdgeTrigger == true) { - SerialPrintln(F("Falling-edge triggering is enabled. Sensor data will be logged on a falling edge on GPIO pin 11.")); attachInterrupt(PIN_TRIGGER, triggerPinISR, FALLING); // Enable the interrupt intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; } else { - SerialPrintln(F("Rising-edge triggering is enabled. Sensor data will be logged on a rising edge on GPIO pin 11.")); attachInterrupt(PIN_TRIGGER, triggerPinISR, RISING); // Enable the interrupt intPinConfig.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI; } @@ -469,6 +472,10 @@ void wakeFromSleep() { pin_config(PinName(48), g_AM_BSP_GPIO_COM_UART_TX); pin_config(PinName(49), g_AM_BSP_GPIO_COM_UART_RX); + if (settings.useTxRxPinsForTerminal == true) + { + configureSerial1TxRx(); + } } //Re-enable CIPO, COPI, SCK and the chip selects but may as well leave ICM_INT disabled @@ -486,9 +493,6 @@ void wakeFromSleep() if (settings.useTxRxPinsForTerminal == true) { - //We may need to manually restore the Serial1 TX and RX pins? - configureSerial1TxRx(); - Serial1.begin(settings.serialTerminalBaudRate); // Start the serial port } @@ -557,11 +561,13 @@ void waitForQwiicBusPowerDelay() // Wait while the qwiic devices power up //Depending on what hardware is configured, the Qwiic bus may have only been turned on a few ms ago //Give sensors, specifically those with a low I2C address, time to turn on // If we're not using the SD card, everything will have happened much quicker than usual. - uint64_t qwiicPowerHasBeenOnFor = bestMillis() - qwiicPowerOnTime; - if (qwiicPowerHasBeenOnFor < qwiicPowerOnDelayMillis) + uint64_t qwiicPowerHasBeenOnFor = rtcMillis() - qwiicPowerOnTime; + printDebug("waitForQwiicBusPowerDelay: qwiicPowerHasBeenOnFor " + (String)((unsigned long)qwiicPowerHasBeenOnFor) + "ms\r\n"); + if (qwiicPowerHasBeenOnFor < (uint64_t)qwiicPowerOnDelayMillis) { - unsigned long delayFor = qwiicPowerOnDelayMillis - qwiicPowerHasBeenOnFor; - for (unsigned long i = 0; i < delayFor; i++) + uint64_t delayFor = (uint64_t)qwiicPowerOnDelayMillis - qwiicPowerHasBeenOnFor; + printDebug("waitForQwiicBusPowerDelay: delaying for " + (String)((unsigned long)delayFor) + "\r\n"); + for (uint64_t i = 0; i < delayFor; i++) { checkBattery(); delay(1); @@ -579,7 +585,7 @@ void qwiicPowerOn() digitalWrite(PIN_QWIIC_POWER, HIGH); #endif - qwiicPowerOnTime = bestMillis(); //Record this time so we wait enough time before detecting certain sensors + qwiicPowerOnTime = rtcMillis(); //Record this time so we wait enough time before detecting certain sensors } void qwiicPowerOff() { diff --git a/Firmware/OpenLog_Artemis/menuAttachedDevices.ino b/Firmware/OpenLog_Artemis/menuAttachedDevices.ino index 7380535..5281574 100644 --- a/Firmware/OpenLog_Artemis/menuAttachedDevices.ino +++ b/Firmware/OpenLog_Artemis/menuAttachedDevices.ino @@ -961,14 +961,14 @@ void menuConfigure_NAU7802(void *configPtr) } } -void menuConfigure_uBlox(void *configPtr) +void menuConfigure_ublox(void *configPtr) { - struct_uBlox *sensorSetting = (struct_uBlox*)configPtr; + struct_ublox *sensorSetting = (struct_ublox*)configPtr; while (1) { SerialPrintln(F("")); - SerialPrintln(F("Menu: Configure uBlox GPS Receiver")); + SerialPrintln(F("Menu: Configure u-blox GPS Receiver")); SerialPrint(F("1) Sensor Logging: ")); if (sensorSetting->log == true) SerialPrintln(F("Enabled")); @@ -1137,7 +1137,7 @@ void getUbloxDateTime(int &year, int &month, int &day, int &hour, int &minute, i setQwiicPullups(0); //Disable pullups to minimize CRC issues SFE_UBLOX_GNSS *nodeDevice = (SFE_UBLOX_GNSS *)temp->classPtr; - struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; + struct_ublox *nodeSetting = (struct_ublox *)temp->configPtr; //If autoPVT is enabled, flush the data to make sure we get fresh date and time if (nodeSetting->useAutoPVT) nodeDevice->flushPVT(); @@ -1175,7 +1175,7 @@ void gnssFactoryDefault(void) setQwiicPullups(0); //Disable pullups to minimize CRC issues SFE_UBLOX_GNSS *nodeDevice = (SFE_UBLOX_GNSS *)temp->classPtr; - struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; + struct_ublox *nodeSetting = (struct_ublox *)temp->configPtr; //Reset the module to the factory defaults nodeDevice->factoryDefault(); diff --git a/Firmware/OpenLog_Artemis/menuMain.ino b/Firmware/OpenLog_Artemis/menuMain.ino index 8542898..fe45b32 100644 --- a/Firmware/OpenLog_Artemis/menuMain.ino +++ b/Firmware/OpenLog_Artemis/menuMain.ino @@ -12,7 +12,8 @@ void menuMain() SerialPrintln(F("2) Configure Time Stamp")); - SerialPrintln(F("3) Configure IMU Logging")); + if (online.IMU) + SerialPrintln(F("3) Configure IMU Logging")); if (settings.useTxRxPinsForTerminal == false) SerialPrintln(F("4) Configure Serial Logging")); @@ -42,7 +43,7 @@ void menuMain() menuLogRate(); else if (incoming == '2') menuTimeStamp(); - else if (incoming == '3') + else if ((incoming == '3') && (online.IMU)) restartIMU = menuIMU(); else if ((incoming == '4') && (settings.useTxRxPinsForTerminal == false)) menuSerialLogging(); @@ -175,7 +176,7 @@ void menuMain() totalCharactersPrinted = 0; //If we are sleeping between readings then we cannot rely on millis() as it is powered down //Use RTC instead - measurementStartTime = bestMillis(); + measurementStartTime = rtcMillis(); //Edge case: after 10Hz reading, user sets the log rate above 2s mark. We never go to sleep because //takeReading is not true. And since we don't wake up, takeReading never gets set to true. diff --git a/Firmware/OpenLog_Artemis/menuTimeStamp.ino b/Firmware/OpenLog_Artemis/menuTimeStamp.ino index 1b10775..6d1b88d 100644 --- a/Firmware/OpenLog_Artemis/menuTimeStamp.ino +++ b/Firmware/OpenLog_Artemis/menuTimeStamp.ino @@ -23,10 +23,12 @@ void menuTimeStamp() sprintf(rtcYear, "200%d", myRTC.year); else sprintf(rtcYear, "20%d", myRTC.year); - if (settings.americanDateStyle == true) + if (settings.dateStyle == 0) sprintf(rtcDate, "%s/%s/%s,", rtcMonth, rtcDay, rtcYear); - else + else if (settings.dateStyle == 1) sprintf(rtcDate, "%s/%s/%s,", rtcDay, rtcMonth, rtcYear); + else + sprintf(rtcDate, "%s/%s/%s,", rtcYear, rtcMonth, rtcDay); SerialPrint(rtcDate); SerialPrint(F(" ")); @@ -79,8 +81,10 @@ void menuTimeStamp() SerialPrintln(F("4) Manually set RTC date")); SerialPrint(F("5) Toggle date style: ")); - if (settings.americanDateStyle == true) SerialPrintln(F("mm/dd/yyyy")); - else SerialPrintln(F("dd/mm/yyyy")); + if (settings.dateStyle == 0) SerialPrintln(F("mm/dd/yyyy")); + else if (settings.dateStyle == 1) SerialPrintln(F("dd/mm/yyyy")); + else if (settings.dateStyle == 2) SerialPrintln(F("yyyy/mm/dd")); + else SerialPrintln(F("ISO 8601")); } if (settings.logTime == true) @@ -148,7 +152,7 @@ void menuTimeStamp() else if (incoming == 9) { SerialPrint(F("Enter the local hour offset from UTC (-12 to 14): ")); - int offset = getNumber(menuTimeout); //Timeout after x seconds + float offset = (float)getDouble(menuTimeout); //Timeout after x seconds if (offset < -12 || offset > 14) SerialPrintln(F("Error: Offset is out of range")); else @@ -181,7 +185,9 @@ void menuTimeStamp() } else if (incoming == 5) { - settings.americanDateStyle ^= 1; + settings.dateStyle += 1; + if (settings.dateStyle == 4) + settings.dateStyle = 0; } } diff --git a/Firmware/OpenLog_Artemis/nvm.ino b/Firmware/OpenLog_Artemis/nvm.ino index 1a58034..e819dfd 100644 --- a/Firmware/OpenLog_Artemis/nvm.ino +++ b/Firmware/OpenLog_Artemis/nvm.ino @@ -125,7 +125,7 @@ void recordSystemSettingsToFile() settingsFile.println("logRTC=" + (String)settings.logRTC); settingsFile.println("logHertz=" + (String)settings.logHertz); settingsFile.println("correctForDST=" + (String)settings.correctForDST); - settingsFile.println("americanDateStyle=" + (String)settings.americanDateStyle); + settingsFile.println("dateStyle=" + (String)settings.dateStyle); settingsFile.println("hour24Style=" + (String)settings.hour24Style); settingsFile.println("serialTerminalBaudRate=" + (String)settings.serialTerminalBaudRate); settingsFile.println("serialLogBaudRate=" + (String)settings.serialLogBaudRate); @@ -135,7 +135,7 @@ void recordSystemSettingsToFile() settingsFile.println("logA13=" + (String)settings.logA13); settingsFile.println("logA32=" + (String)settings.logA32); settingsFile.println("logAnalogVoltages=" + (String)settings.logAnalogVoltages); - 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); @@ -217,6 +217,7 @@ bool loadSystemSettingsFromFile() { //If we can't read the first line of the settings file, give up SerialPrintln(F("Giving up on settings file")); + settingsFile.close(); return (false); } } @@ -226,6 +227,7 @@ bool loadSystemSettingsFromFile() { //If we can't read the first line of the settings file, give up SerialPrintln(F("Giving up on settings file")); + settingsFile.close(); return (false); } } @@ -348,8 +350,10 @@ bool parseLine(char* str) { settings.logHertz = d; else if (strcmp(settingName, "correctForDST") == 0) settings.correctForDST = d; - else if (strcmp(settingName, "americanDateStyle") == 0) - settings.americanDateStyle = d; + else if (strcmp(settingName, "dateStyle") == 0) + settings.dateStyle = d; + else if (strcmp(settingName, "americanDateStyle") == 0) // Included for backward-compatibility + settings.dateStyle = d; else if (strcmp(settingName, "hour24Style") == 0) settings.hour24Style = d; else if (strcmp(settingName, "serialTerminalBaudRate") == 0) @@ -533,7 +537,7 @@ void recordDeviceSettingsToFile() break; case DEVICE_GPS_UBLOX: { - struct_uBlox *nodeSetting = (struct_uBlox *)temp->configPtr; + struct_ublox *nodeSetting = (struct_ublox *)temp->configPtr; settingsFile.println((String)base + "log=" + nodeSetting->log); settingsFile.println((String)base + "logDate=" + nodeSetting->logDate); settingsFile.println((String)base + "logTime=" + nodeSetting->logTime); @@ -834,7 +838,7 @@ bool loadDeviceSettingsFromFile() } //SerialPrintln(F("Device config file read complete")); - updateDataFileAccess(&settingsFile); // Update the file access time & date + //updateDataFileAccess(&settingsFile); // Update the file access time & date settingsFile.close(); return (true); } @@ -976,7 +980,7 @@ bool parseDeviceLine(char* str) { break; case DEVICE_GPS_UBLOX: { - struct_uBlox *nodeSetting = (struct_uBlox *)deviceConfigPtr; + struct_ublox *nodeSetting = (struct_ublox *)deviceConfigPtr; //Apply the appropriate settings if (strcmp(deviceSettingName, "log") == 0) diff --git a/Firmware/OpenLog_Artemis/productionTest.ino b/Firmware/OpenLog_Artemis/productionTest.ino index 6beea0d..94b7cc3 100644 --- a/Firmware/OpenLog_Artemis/productionTest.ino +++ b/Firmware/OpenLog_Artemis/productionTest.ino @@ -171,6 +171,8 @@ void productionTest() if (myICM.dataReady()) { myICM.getAGMT(); //Update values + delay(10); + myICM.getAGMT(); //Update values #ifdef verboseProdTest olaftoa(myICM.temp(), tempData1, 2, sizeof(tempData1) / sizeof(char)); Serial.printf("IMU Temp is: %sC\r\n", tempData1); @@ -212,6 +214,8 @@ void productionTest() if (myICM.dataReady()) { myICM.getAGMT(); //Update values + delay(10); + myICM.getAGMT(); //Update values #ifdef verboseProdTest olaftoa(myICM.accX(), tempData1, 2, sizeof(tempData1) / sizeof(char)); olaftoa(myICM.accY(), tempData2, 2, sizeof(tempData2) / sizeof(char)); @@ -257,6 +261,8 @@ void productionTest() if (myICM.dataReady()) { myICM.getAGMT(); //Update values + delay(10); + myICM.getAGMT(); //Update values #ifdef verboseProdTest olaftoa(myICM.magX(), tempData1, 2, sizeof(tempData1) / sizeof(char)); olaftoa(myICM.magY(), tempData2, 2, sizeof(tempData2) / sizeof(char)); diff --git a/Firmware/OpenLog_Artemis/settings.h b/Firmware/OpenLog_Artemis/settings.h index a24b77b..f7d8662 100644 --- a/Firmware/OpenLog_Artemis/settings.h +++ b/Firmware/OpenLog_Artemis/settings.h @@ -55,7 +55,7 @@ typedef void (*FunctionPointer)(void*); //Used for pointing to device config men //Begin specific sensor config structs //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -const unsigned long worstCaseQwiicPowerOnDelay = 1000; // Remember to update this if required when adding a new sensor (currently defined by the uBlox). (This is OK for the SCD30. beginQwiicDevices will extend the delay.) +const unsigned long worstCaseQwiicPowerOnDelay = 1000; // Remember to update this if required when adding a new sensor (currently defined by the u-blox). (This is OK for the SCD30. beginQwiicDevices will extend the delay.) const unsigned long minimumQwiicPowerOnDelay = 10; //The minimum number of milliseconds between turning on the Qwiic power and attempting to communicate with Qwiic devices // Power On Delay Testing: @@ -117,7 +117,7 @@ struct struct_VCNL4040 { unsigned long powerOnDelayMillis = minimumQwiicPowerOnDelay; // Wait for at least this many millis before communicating with this device. Increase if required! }; -struct struct_uBlox { +struct struct_ublox { bool log = true; bool logDate = true; bool logTime = true; @@ -364,7 +364,7 @@ struct struct_settings { bool logRTC = true; bool logHertz = true; bool correctForDST = false; - bool americanDateStyle = true; + int dateStyle = 0; // 0 : mm/dd/yyyy, 1 : dd/mm/yyyy, 2 : yyyy/mm/dd, 3 : ISO8601 (date and time) bool hour24Style = true; int serialTerminalBaudRate = 115200; int serialLogBaudRate = 9600; @@ -374,7 +374,7 @@ struct struct_settings { bool logA13 = false; bool logA32 = false; bool logAnalogVoltages = true; - int localUTCOffset = 0; //Default to UTC because we should + float localUTCOffset = 0; // Default to UTC because we should. Support offsets in 15 minute increments. bool printDebugMessages = false; #if(HARDWARE_VERSION_MAJOR == 0) bool powerDownQwiicBusBetweenReads = false; // For the SparkX (black) board: default to leaving the Qwiic power enabled during sleep and powerDown to prevent a brown-out. diff --git a/Firmware/OpenLog_Artemis/support.ino b/Firmware/OpenLog_Artemis/support.ino index 1acb047..429d8cb 100644 --- a/Firmware/OpenLog_Artemis/support.ino +++ b/Firmware/OpenLog_Artemis/support.ino @@ -90,7 +90,7 @@ uint8_t getByteChoice(int numberOfSeconds, bool updateDZSERIAL) if (settings.useTxRxPinsForTerminal == true) while (Serial1.available() > 0) Serial1.read(); //Clear buffer - long startTime = millis(); + unsigned long startTime = millis(); byte incoming; while (1) { @@ -160,7 +160,7 @@ int64_t getNumber(int numberOfSeconds) //Get input from user char cleansed[20]; //Good for very large numbers: 123,456,789,012,345,678\0 - long startTime = millis(); + unsigned long startTime = millis(); int spot = 0; while (spot < 20 - 1) //Leave room for terminating \0 { @@ -265,7 +265,7 @@ double getDouble(int numberOfSeconds) //Get input from user char cleansed[20]; //Good for very large numbers: 123,456,789,012,345,678\0 - long startTime = millis(); + unsigned long startTime = millis(); int spot = 0; bool dpSeen = false; while (spot < 20 - 1) //Leave room for terminating \0 diff --git a/Firmware/OpenLog_Artemis/timeStamp.ino b/Firmware/OpenLog_Artemis/timeStamp.ino index ada44eb..88ae45f 100644 --- a/Firmware/OpenLog_Artemis/timeStamp.ino +++ b/Firmware/OpenLog_Artemis/timeStamp.ino @@ -26,16 +26,20 @@ void getTimeString(char timeStringBuffer[]) sprintf(rtcYear, "200%d", myRTC.year); else sprintf(rtcYear, "20%d", myRTC.year); - if (settings.americanDateStyle == true) + if (settings.dateStyle == 0) sprintf(rtcDate, "%s/%s/%s,", rtcMonth, rtcDay, rtcYear); - else + else if (settings.dateStyle == 1) sprintf(rtcDate, "%s/%s/%s,", rtcDay, rtcMonth, rtcYear); + else if (settings.dateStyle == 2) + sprintf(rtcDate, "%s/%s/%s,", rtcYear, rtcMonth, rtcDay); + else // if (settings.dateStyle == 3) + sprintf(rtcDate, "%s-%s-%sT", rtcYear, rtcMonth, rtcDay); strcat(timeStringBuffer, rtcDate); } - if (settings.logTime) + if ((settings.logTime) || ((settings.logDate) && (settings.dateStyle == 3))) { - char rtcTime[13]; //09:14:37.41, + char rtcTime[16]; //09:14:37.41, or 09:14:37+00:00, int adjustedHour = myRTC.hour; if (settings.hour24Style == false) { @@ -45,6 +49,8 @@ void getTimeString(char timeStringBuffer[]) char rtcMin[3]; char rtcSec[3]; char rtcHundredths[3]; + char timeZoneH[4]; + char timeZoneM[4]; if (adjustedHour < 10) sprintf(rtcHour, "0%d", adjustedHour); else @@ -61,8 +67,37 @@ void getTimeString(char timeStringBuffer[]) sprintf(rtcHundredths, "0%d", myRTC.hundredths); else sprintf(rtcHundredths, "%d", myRTC.hundredths); - sprintf(rtcTime, "%s:%s:%s.%s,", rtcHour, rtcMin, rtcSec, rtcHundredths); - strcat(timeStringBuffer, rtcTime); + if (settings.localUTCOffset >= 0) + { + if (settings.localUTCOffset < 10) + sprintf(timeZoneH, "+0%d", (int)settings.localUTCOffset); + else + sprintf(timeZoneH, "+%d", (int)settings.localUTCOffset); + } + else + { + if (settings.localUTCOffset <= -10) + sprintf(timeZoneH, "-%d", 0 - (int)settings.localUTCOffset); + else + sprintf(timeZoneH, "-0%d", 0 - (int)settings.localUTCOffset); + } + int tzMins = (int)((settings.localUTCOffset - (float)((int)settings.localUTCOffset)) * 60.0); + if (tzMins < 0) + tzMins = 0 - tzMins; + if (tzMins < 10) + sprintf(timeZoneM, ":0%d", tzMins); + else + sprintf(timeZoneM, ":%d", tzMins); + if ((settings.logDate) && (settings.dateStyle == 3)) + { + sprintf(rtcTime, "%s:%s:%s%s%s,", rtcHour, rtcMin, rtcSec, timeZoneH, timeZoneM); + strcat(timeStringBuffer, rtcTime); + } + if (settings.logTime) + { + sprintf(rtcTime, "%s:%s:%s.%s,", rtcHour, rtcMin, rtcSec, rtcHundredths); + strcat(timeStringBuffer, rtcTime); + } } if (settings.logMicroseconds) @@ -115,7 +150,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 @@ -123,10 +158,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); @@ -155,7 +204,7 @@ void correctDate(int &year, int &month, int &day, int &hour) adjustMonth = true; else if (month == 2) { - if (year % 4 == 0 && day == 30) + if (year % 4 == 0 && day == 30) // Note: this will fail in 2100. 2100 is not a leap year. adjustMonth = true; else if (day == 29) adjustMonth = true; @@ -213,7 +262,7 @@ void correctDate(int &year, int &month, int &day, int &hour) day = 31; break; case 2: //February - if (year % 4 == 0) day = 29; + if (year % 4 == 0) day = 29; // Note: this will fail in 2100. 2100 is not a leap year. else day = 28; break; case 3: //March diff --git a/README.md b/README.md index e7e983e..f57dcb8 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ OpenLog Artemis is highly configurable over an easy to use serial interface. Sim The OpenLog Artemis automatically scans, detects, configures, and logs various Qwiic sensors plugged into the board (no soldering required!). Currently, auto-detection is supported on the following Qwiic products: -* uBlox GPS Modules (Lat/Long, Altitude, Velocity, SIV, Time, Date): +* u-blox GPS Modules (Lat/Long, Altitude, Velocity, SIV, Time, Date): * [ZED-F9P](https://www.sparkfun.com/products/15136) 1cm High Precision GPS * [NEO-M8P-2](https://www.sparkfun.com/products/15005) 2.5cm High Precision GPS * [SAM-M8Q](https://www.sparkfun.com/products/15210) 1.5m 72 Channel GPS @@ -59,7 +59,7 @@ The OLA can be tailored to many different applications and we will be releasing * [Latest OLA firmware](https://github.com/sparkfun/OpenLog_Artemis/tree/main/Binaries) * [Geophone Logger firmware](https://github.com/sparkfun/OpenLog_Artemis_Geophone_Logger) for logging seismic activity -* [GNSS Logger](https://github.com/sparkfun/OpenLog_Artemis_GNSS_Logger) for advanced data logging with the uBlox F9 and M9 GNSS modules including support for RAWX and RELPOSNED +* [GNSS Logger](https://github.com/sparkfun/OpenLog_Artemis_GNSS_Logger) for advanced data logging with the u-blox F9 and M9 GNSS modules including support for RAWX and RELPOSNED Repository Contents -------------------