<commit_before>#include "MS5803_I2C.h"
#include "SPI.h"
#include "Wire.h"
#include "UTFT.h"
#include "IRremote.h"
#include "SD.h"
#include "SimpleTimer.h"
#include "MAX17043.h"
#include "DS3232RTC.h"
#include "Time.h"

#include "Buhlmann.h"
#include "View.h"
#include "Settings.h"
#include "Logbook.h"
#include "LastDive.h"

//Infrared Receiver initialization
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;

//Pressure Sensor initialization
MS5803 sensor(ADDRESS_HIGH);

// Pin number of the piezo buzzer
int speakerPin = 8;

// TFT setup - 480x320 pixel
UTFT tft(ILI9481,38,39,40,41);
View view(&tft);

// Currently elected menu item
byte selectedMenuItemIndex;

Settings settings = Settings();
float seaLevelPressureSetting = 1013.25;
float oxygenRateSetting = 0.21;
bool testModeSetting = false;
bool soundSetting = true;
bool imperialUnitsSetting = false;

DateTimeSettings* currentDateTimeSettings;

byte selectedSettingIndex = 0;
byte selectedDateTimeSettingIndex = 0;
bool isSdCardPresent = false;

#define SURFACE_MODE 		0  // Menu, Logbook, Surface Time, Settings and About are available
#define DIVE_START_MODE 	1  // When the driver pressed the dive button but not below 2 meters
#define DIVE_PROGRESS_MODE 	2  // During the dive
#define DIVE_STOP_MODE 		3  // Once the diver ascended to the surface - for X minutes - the diver can go under water
#define GAUGE_MODE          4

byte currentMode = SURFACE_MODE;
byte currentScreen = MENU_SCREEN;

Buhlmann buhlmann = Buhlmann(400, 56.7);

//Utility variables
float maxDepthInMeter;
float maxTemperatureInCelsius;
float minTemperatureInCelsius;

#define SAFETY_STOP_NOT_STARTED 0
#define SAFETY_STOP_IN_PROGRESS 1
#define SAFETY_STOP_DONE 		2
#define SAFETY_STOP_VIOLATED	3

byte safetyStopState = SAFETY_STOP_NOT_STARTED;

unsigned long diveDurationInSeconds;
unsigned long safetyStopDurationInSeconds;
unsigned long testPreviousDiveDurationInSeconds;

SimpleTimer diveDurationTimer;

MAX17043 batteryMonitor;
float batterySoc = 255;
float batteryVoltage = 5;

Logbook logbook = Logbook();
int currentProfileNumber = 0; //There is no stored profile - default state
int maximumProfileNumber = 0;
File profileFile;

LastDive lastDive = LastDive();

void setup() {

	// SD Card initialization
	pinMode(53, OUTPUT);
	if (SD.begin(53)) {
		isSdCardPresent = true;

		DiveInoSettings* diveInoSettings = settings.loadDiveInoSettings();
		seaLevelPressureSetting = diveInoSettings->seaLevelPressureSetting;
		oxygenRateSetting = diveInoSettings->oxygenRateSetting;
		testModeSetting = diveInoSettings->testModeSetting;
		soundSetting = diveInoSettings->soundSetting;
		imperialUnitsSetting = diveInoSettings->imperialUnitsSetting;
	}

	Serial.begin(115200);
	Serial.println("");
	Serial.println("DiveIno - START");
	Serial.println("");

	Serial.print("SD Card present: ");
	if (isSdCardPresent) {
		Serial.println("YES");
	} else {
		Serial.println("NO");
	}
	Serial.println("");

	Serial.println("Settings: ");
	Serial.print("seaLevelPressure: ");
	Serial.println(seaLevelPressureSetting, 2);
	Serial.print("oxygenRate: ");
	Serial.println(oxygenRateSetting, 2);
	Serial.print("testMode: ");
	if (testModeSetting) {
		Serial.println("On");
	} else {
		Serial.println("Off");
	}
	Serial.print("sound: ");
	if (soundSetting) {
		Serial.println("On");
	} else {
		Serial.println("Off");
	}
	Serial.print("units: ");
	if (imperialUnitsSetting) {
		Serial.println("Imperial");
	} else {
		Serial.println("Metric");
	}
	Serial.println("");

	Wire.begin();         //Start the I2C interface
	irrecv.enableIRIn();  //Start the Infrared Receiver

    batteryMonitor.reset();
    batteryMonitor.quickStart();

	sensor.reset();
	sensor.begin();

	setSyncProvider((unsigned long int (*)())RTC.get);
    if(timeStatus() != timeSet){
        Serial.println("RTC - time was not set!");
    } else {
        Serial.println("RTC - time was set");
    }

	tft.InitLCD();

    // Set the function, which will be called in every second, if the timer is enabled
	diveDurationTimer.setTimer(1000, diveUnderWater, diveDurationTimer.RUN_FOREVER);
	diveDurationTimer.disable(diveDurationTimer.RUN_FOREVER);

	displayScreen(MENU_SCREEN);
}

void loop() {

	/////////////////////
	// Button Handling //
	/////////////////////

	if (irrecv.decode(&results)) {
		processRemoteButtonPress(&results);
		irrecv.resume(); // Receive the next value
	}

	/////////////
	// Battery //
	/////////////

	batterySoc = batteryMonitor.getSoC();
	batteryVoltage = batteryMonitor.getVCell();

	if (currentScreen == MENU_SCREEN) {
		view.drawBatteryStateOfCharge(batterySoc);
	}

	///////////////
	// Go Diving //
	///////////////

	if (currentScreen == GAUGE_SCREEN || currentScreen == DIVE_SCREEN) {
		if (testModeSetting) {
			diveSurface();
		} else {
			diveDurationTimer.run();
		}
	}
}

//////////
// Dive //
//////////

void calculateSafetyStop(float maxDepthInMeter, float depthInMeter, unsigned int intervalDuration)
{
	//Safety stop calculation - only if the dive was deeper than 10 m
	if (maxDepthInMeter > 10) {

		//Between 3 and 6 meters the diver can do the safety stop
		if (3 < depthInMeter && depthInMeter < 6) {

			if (safetyStopState == SAFETY_STOP_NOT_STARTED) {
				safetyStopState = SAFETY_STOP_IN_PROGRESS;

				if (testModeSetting) {
					Serial.print(" Safety stop STARTED at ");
					Serial.println(depthInMeter);
				}
			} else if (safetyStopState == SAFETY_STOP_VIOLATED) {
				safetyStopState = SAFETY_STOP_IN_PROGRESS;
			}
			if (safetyStopState == SAFETY_STOP_IN_PROGRESS) {
				safetyStopDurationInSeconds += intervalDuration;
				view.drawSafetyStop(safetyStopDurationInSeconds);

				if (testModeSetting) {
					Serial.print(" Safety stop IN PROGRESS at ");
					Serial.println(depthInMeter);
					Serial.print(" Safety stop duration: ");
					Serial.println(safetyStopDurationInSeconds);
				}

				if (180 <= safetyStopDurationInSeconds) {
					safetyStopState = SAFETY_STOP_DONE;

					if (testModeSetting) {
						Serial.print(" Safety stop DONE at ");
						Serial.println(depthInMeter);
					}
				}
			}
		} else if (10 < depthInMeter) {
			//Reset the safety stop mode, if the diver descends back down to 10 m
			if (safetyStopState != SAFETY_STOP_NOT_STARTED) {
				safetyStopState = SAFETY_STOP_NOT_STARTED;

				if (testModeSetting) {
					Serial.print(" Safety stop RESET after DONE at ");
					Serial.println(depthInMeter);
				}
			}
		} else {
			//Between 10-6 meters and above 3 meters the safety stop is violated - the counter will stop
			if (safetyStopState == SAFETY_STOP_IN_PROGRESS) {
				safetyStopState = SAFETY_STOP_VIOLATED;

				if (testModeSetting) {
					Serial.print(" Safety stop VIOLATED at ");
					Serial.println(depthInMeter);
				}
			}
		}
	}
}

void calculateMinMaxValues(float depthInMeter, float temperatureInCelsius)
{
	//Calculate minimum and maximum values during the dive
	if (maxDepthInMeter < depthInMeter) {
		maxDepthInMeter = depthInMeter;
		view.drawMaximumDepth(maxDepthInMeter);
	}
	if (maxTemperatureInCelsius < temperatureInCelsius) {
		maxTemperatureInCelsius = temperatureInCelsius;
	}
	if (minTemperatureInCelsius > temperatureInCelsius) {
		minTemperatureInCelsius = temperatureInCelsius;
	}
}

void diveSurface()
{
	// Check if test data is available, which comes through the serial interface
	if (Serial.available() > 0) {
		float pressureInMillibar = Serial.parseFloat();
		float depthInMeter = Serial.parseFloat();
		diveDurationInSeconds = Serial.parseInt();
		float temperatureInCelsius = Serial.parseFloat();

		view.drawCurrentPressure(pressureInMillibar);
		view.drawDepth(depthInMeter);
		view.drawCurrentTemperature(temperatureInCelsius);
		view.drawDiveDuration(diveDurationInSeconds);

		view.drawBatteryStateOfCharge(batterySoc);

		calculateMinMaxValues(depthInMeter, temperatureInCelsius);

		switch (currentScreen) {
			case GAUGE_SCREEN: {
				//Instead of dive information we will display the current time
				view.drawCurrentTime(settings.getCurrentTimeText());
			}
			break;
			case DIVE_SCREEN: {

				//Calculate the delta between the current and the previous duration information
				if (diveDurationInSeconds > testPreviousDiveDurationInSeconds) {
					unsigned long intervalDuration = diveDurationInSeconds - testPreviousDiveDurationInSeconds;

					testPreviousDiveDurationInSeconds = diveDurationInSeconds;

					//The timer fires in every second
					calculateSafetyStop(maxDepthInMeter, depthInMeter, intervalDuration);

					//Progress with the algorithm in every second
					diveProgress(temperatureInCelsius, pressureInMillibar, depthInMeter, diveDurationInSeconds);
				}
			}
			break;
		}
	}
}

void diveUnderWater() // Called in every second on the GAUGE and DIVE screens
{
	view.drawBatteryStateOfCharge(batterySoc);

	float pressureInMillibar = sensor.getPressure(ADC_4096);
	float temperatureInCelsius = sensor.getTemperature(CELSIUS, ADC_512);

	float depthInMeter = 0;
	if (pressureInMillibar > seaLevelPressureSetting) {
		depthInMeter = buhlmann.calculateDepthFromPressure(pressureInMillibar);
	}

	//Draw the data to the screen
	view.drawCurrentTemperature(temperatureInCelsius);
	view.drawCurrentPressure(pressureInMillibar);
	view.drawDepth(depthInMeter);

	calculateMinMaxValues(depthInMeter, temperatureInCelsius);

	switch (currentScreen) {
		case GAUGE_SCREEN: {
			//Instead of dive information we will display the current time
			view.drawCurrentTime(settings.getCurrentTimeText());

			diveDurationInSeconds++;
			view.drawDiveDuration(diveDurationInSeconds);
		}
		break;
		case DIVE_SCREEN: {
			//Progress with the dive, if we are deeper than 1.2 meter
			if (pressureInMillibar > (seaLevelPressureSetting + 120) || diveDurationInSeconds > 60) {
				diveDurationInSeconds++;
				view.drawDiveDuration(diveDurationInSeconds);

				//The timer fires in every second
				calculateSafetyStop(maxDepthInMeter, depthInMeter, 1);

				//Progress with the algorithm in every second
				diveProgress(temperatureInCelsius, pressureInMillibar, depthInMeter, diveDurationInSeconds);
			}
		}
		break;
	}
}

void startDive()
{
	diveDurationTimer.enable(diveDurationTimer.RUN_FOREVER);

	//Set default values before the dive
	maxDepthInMeter = 0;
	minTemperatureInCelsius = 60;
	maxTemperatureInCelsius = 0;

	safetyStopState = SAFETY_STOP_NOT_STARTED;
	safetyStopDurationInSeconds = 0;
	diveDurationInSeconds = 0;
	testPreviousDiveDurationInSeconds = 0;

	if (currentScreen == DIVE_SCREEN) {

		Serial.println("DIVE - Started");

		//Start dive profile logging - create a new file
		if (maximumProfileNumber <= 0) {
			maximumProfileNumber = logbook.loadLogbookData()->numberOfStoredProfiles;
		}
		profileFile = logbook.createNewProfileFile(maximumProfileNumber+1);

		// Initialize the DiveDeco library based on the settings
		buhlmann.setSeaLevelAtmosphericPressure(seaLevelPressureSetting);
		buhlmann.setNitrogenRateInGas(1 - oxygenRateSetting);

		DiveResult* diveResult = new DiveResult;
		diveResult = buhlmann.initializeCompartments();

		//Retrieve last dive data<commit_msg>Bug fixes after the test week in Croatia<commit_after>#include "MS5803_I2C.h"
#include "SPI.h"
#include "Wire.h"
#include "UTFT.h"
#include "IRremote.h"
#include "SD.h"
#include "SimpleTimer.h"
#include "MAX17043.h"
#include "DS3232RTC.h"
#include "Time.h"

#include "Buhlmann.h"
#include "View.h"
#include "Settings.h"
#include "Logbook.h"
#include "LastDive.h"

//Infrared Receiver initialization
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;

//Pressure Sensor initialization
MS5803 sensor(ADDRESS_HIGH);

// Pin number of the piezo buzzer
int speakerPin = 8;

// TFT setup - 480x320 pixel
UTFT tft(ILI9481,38,39,40,41);
View view(&tft);

// Currently elected menu item
byte selectedMenuItemIndex;

Settings settings = Settings();
float seaLevelPressureSetting = 1013.25;
float oxygenRateSetting = 0.21;
bool testModeSetting = false;
bool soundSetting = true;
bool imperialUnitsSetting = false;

DateTimeSettings* currentDateTimeSettings;

byte selectedSettingIndex = 0;
byte selectedDateTimeSettingIndex = 0;
bool isSdCardPresent = false;

#define SURFACE_MODE 		0  // Menu, Logbook, Surface Time, Settings and About are available
#define DIVE_START_MODE 	1  // When the driver pressed the dive button but not below 2 meters
#define DIVE_PROGRESS_MODE 	2  // During the dive
#define DIVE_STOP_MODE 		3  // Once the diver ascended to the surface - for X minutes - the diver can go under water
#define GAUGE_MODE          4

byte currentMode = SURFACE_MODE;
byte currentScreen = MENU_SCREEN;

Buhlmann buhlmann = Buhlmann(400, 56.7);

//Utility variables
float maxDepthInMeter;
float maxTemperatureInCelsius;
float minTemperatureInCelsius;

#define SAFETY_STOP_NOT_STARTED 0
#define SAFETY_STOP_IN_PROGRESS 1
#define SAFETY_STOP_DONE 		2
#define SAFETY_STOP_VIOLATED	3

byte safetyStopState = SAFETY_STOP_NOT_STARTED;

unsigned long diveStartTimestamp;
unsigned long diveDurationInSeconds;
unsigned long safetyStopDurationInSeconds;
unsigned long testPreviousDiveDurationInSeconds;

SimpleTimer diveDurationTimer;
float previousDepthInMeter;

MAX17043 batteryMonitor;
float batterySoc = 255;
float batteryVoltage = 5;

Logbook logbook = Logbook();
int currentProfileNumber = 0; //There is no stored profile - default state
int maximumProfileNumber = 0;
File profileFile;

LastDive lastDive = LastDive();

void setup() {

	// SD Card initialization
	pinMode(53, OUTPUT);
	if (SD.begin(53)) {
		isSdCardPresent = true;

		DiveInoSettings* diveInoSettings = settings.loadDiveInoSettings();
		seaLevelPressureSetting = diveInoSettings->seaLevelPressureSetting;
		oxygenRateSetting = diveInoSettings->oxygenRateSetting;
		testModeSetting = diveInoSettings->testModeSetting;
		soundSetting = diveInoSettings->soundSetting;
		imperialUnitsSetting = diveInoSettings->imperialUnitsSetting;
	}

	Serial.begin(115200);
	Serial.println("");
	Serial.println("DiveIno - START");
	Serial.println("");

	Serial.print("SD Card present: ");
	if (isSdCardPresent) {
		Serial.println("YES");
	} else {
		Serial.println("NO");
	}
	Serial.println("");

	Serial.println("Settings: ");
	Serial.print("seaLevelPressure: ");
	Serial.println(seaLevelPressureSetting, 2);
	Serial.print("oxygenRate: ");
	Serial.println(oxygenRateSetting, 2);
	Serial.print("testMode: ");
	if (testModeSetting) {
		Serial.println("On");
	} else {
		Serial.println("Off");
	}
	Serial.print("sound: ");
	if (soundSetting) {
		Serial.println("On");
	} else {
		Serial.println("Off");
	}
	Serial.print("units: ");
	if (imperialUnitsSetting) {
		Serial.println("Imperial");
	} else {
		Serial.println("Metric");
	}
	Serial.println("");

	Wire.begin();         //Start the I2C interface
	irrecv.enableIRIn();  //Start the Infrared Receiver

    batteryMonitor.reset();
    batteryMonitor.quickStart();

	sensor.reset();
	sensor.begin();

	setSyncProvider((unsigned long int (*)())RTC.get);
    if(timeStatus() != timeSet){
        Serial.println("RTC - time was not set!");
    } else {
        Serial.println("RTC - time was set");
    }

	tft.InitLCD();

    // Set the function, which will be called in every 5th second, if the timer is enabled
	diveDurationTimer.setTimer(5000, diveUnderWater, diveDurationTimer.RUN_FOREVER);
	diveDurationTimer.disable(diveDurationTimer.RUN_FOREVER);

	displayScreen(MENU_SCREEN);
}

void loop() {

	/////////////////////
	// Button Handling //
	/////////////////////

	if (irrecv.decode(&results)) {
		processRemoteButtonPress(&results);
		irrecv.resume(); // Receive the next value
	}

	/////////////
	// Battery //
	/////////////

	batterySoc = batteryMonitor.getSoC();
	batteryVoltage = batteryMonitor.getVCell();

	if (currentScreen == MENU_SCREEN) {
		view.drawBatteryStateOfCharge(batterySoc);
	}

	///////////////
	// Go Diving //
	///////////////

	if (currentScreen == GAUGE_SCREEN || currentScreen == DIVE_SCREEN) {
		if (testModeSetting) {
			diveSurface();
		} else {
			diveDurationTimer.run();
		}
	}
}

//////////
// Dive //
//////////

void calculateSafetyStop(float maxDepthInMeter, float depthInMeter, unsigned int intervalDuration)
{
	//Safety stop calculation - only if the dive was deeper than 10 m
	if (maxDepthInMeter > 10) {

		//Between 3 and 6 meters the diver can do the safety stop
		if (3 < depthInMeter && depthInMeter < 6) {

			if (safetyStopState == SAFETY_STOP_NOT_STARTED) {
				safetyStopState = SAFETY_STOP_IN_PROGRESS;

				if (testModeSetting) {
					Serial.print(" Safety stop STARTED at ");
					Serial.println(depthInMeter);
				}
			} else if (safetyStopState == SAFETY_STOP_VIOLATED) {
				safetyStopState = SAFETY_STOP_IN_PROGRESS;
			}
			if (safetyStopState == SAFETY_STOP_IN_PROGRESS) {
				safetyStopDurationInSeconds += intervalDuration;
				view.drawSafetyStop(safetyStopDurationInSeconds);

				if (testModeSetting) {
					Serial.print(" Safety stop IN PROGRESS at ");
					Serial.println(depthInMeter);
					Serial.print(" Safety stop duration: ");
					Serial.println(safetyStopDurationInSeconds);
				}

				if (180 <= safetyStopDurationInSeconds) {
					safetyStopState = SAFETY_STOP_DONE;

					if (testModeSetting) {
						Serial.print(" Safety stop DONE at ");
						Serial.println(depthInMeter);
					}
				}
			}
		} else if (10 < depthInMeter) {
			//Reset the safety stop mode, if the diver descends back down to 10 m
			if (safetyStopState != SAFETY_STOP_NOT_STARTED) {
				safetyStopState = SAFETY_STOP_NOT_STARTED;

				if (testModeSetting) {
					Serial.print(" Safety stop RESET after DONE at ");
					Serial.println(depthInMeter);
				}
			}
		} else {
			//Between 10-6 meters and above 3 meters the safety stop is violated - the counter will stop
			if (safetyStopState == SAFETY_STOP_IN_PROGRESS) {
				safetyStopState = SAFETY_STOP_VIOLATED;

				if (testModeSetting) {
					Serial.print(" Safety stop VIOLATED at ");
					Serial.println(depthInMeter);
				}
			}
		}
	}
}

void calculateMinMaxValues(float depthInMeter, float temperatureInCelsius)
{
	//Calculate minimum and maximum values during the dive
	if (maxDepthInMeter < depthInMeter) {
		maxDepthInMeter = depthInMeter;
		view.drawMaximumDepth(maxDepthInMeter);
	}
	if (maxTemperatureInCelsius < temperatureInCelsius) {
		maxTemperatureInCelsius = temperatureInCelsius;
	}
	if (minTemperatureInCelsius > temperatureInCelsius) {
		minTemperatureInCelsius = temperatureInCelsius;
	}
}

void diveSurface()
{
	// Check if test data is available, which comes through the serial interface
	if (Serial.available() > 0) {
		float pressureInMillibar = Serial.parseFloat();
		float depthInMeter = Serial.parseFloat();
		diveDurationInSeconds = Serial.parseInt();
		float temperatureInCelsius = Serial.parseFloat();

		view.drawCurrentPressure(pressureInMillibar);
		view.drawDepth(depthInMeter);
		view.drawCurrentTemperature(temperatureInCelsius);
		view.drawDiveDuration(diveDurationInSeconds);

		view.drawBatteryStateOfCharge(batterySoc);

		calculateMinMaxValues(depthInMeter, temperatureInCelsius);

		switch (currentScreen) {
			case GAUGE_SCREEN: {
				//Instead of dive information we will display the current time
				view.drawCurrentTime(settings.getCurrentTimeText());
			}
			break;
			case DIVE_SCREEN: {

				//Calculate the delta between the current and the previous duration information
				if (diveDurationInSeconds > testPreviousDiveDurationInSeconds) {
					unsigned long intervalDuration = diveDurationInSeconds - testPreviousDiveDurationInSeconds;

					testPreviousDiveDurationInSeconds = diveDurationInSeconds;

					//The timer fires in every second
					calculateSafetyStop(maxDepthInMeter, depthInMeter, intervalDuration);

					//Progress with the algorithm in every second
					diveProgress(temperatureInCelsius, pressureInMillibar, depthInMeter, diveDurationInSeconds);
				}
			}
			break;
		}
	}
}

void diveUnderWater() // Called in every second on the GAUGE and DIVE screens
{
	view.drawBatteryStateOfCharge(batterySoc);

	float pressureInMillibar = sensor.getPressure(ADC_4096);
	float temperatureInCelsius = sensor.getTemperature(CELSIUS, ADC_512);

	float depthInMeter = 0;
	if (pressureInMillibar > seaLevelPressureSetting) {
		depthInMeter = buhlmann.calculateDepthFromPressure(pressureInMillibar);
	}

	//Check for sensor error
	if (abs(depthInMeter-previousDepthInMeter) > 20) {
		//This is a sensor error - skip it!!!
		return;
	} else {
		previousDepthInMeter = depthInMeter;
	}

	//Draw the data to the screen
	view.drawCurrentTemperature(temperatureInCelsius);
	view.drawCurrentPressure(pressureInMillibar);
	view.drawDepth(depthInMeter);

	calculateMinMaxValues(depthInMeter, temperatureInCelsius);

	switch (currentScreen) {
		case GAUGE_SCREEN: {

			view.drawDiveDuration(now()-diveStartTimestamp);

			//Instead of dive information we will display the current time
			view.drawCurrentTime(settings.getCurrentTimeText());
		}
		break;
		case DIVE_SCREEN: {
			if (pressureInMillibar > (seaLevelPressureSetting + 120) || diveDurationInSeconds > 60) {

				//Progress with the dive, if we are deeper than 1.2 meter
				unsigned int intervalDuration = now()-diveStartTimestamp-diveDurationInSeconds;
				calculateSafetyStop(maxDepthInMeter, depthInMeter, intervalDuration);

				diveDurationInSeconds = diveDurationInSeconds + intervalDuration;
				view.drawDiveDuration(diveDurationInSeconds);

				//Progress with the algorithm
				diveProgress(temperatureInCelsius, pressureInMillibar, depthInMeter, diveDurationInSeconds);
			} else {
				//No dive progress - reset the dive timestamp
				diveStartTimestamp = now();
			}
		}
		break;
	}
}

void startDive()
{
	//Store the the current time as seconds since Jan 1 1970 at the start of the dive
	diveStartTimestamp = now();
	previousDepthInMeter = 0;

	diveDurationTimer.enable(diveDurationTimer.RUN_FOREVER);

	//Set default values before the dive
	maxDepthInMeter = 0;
	minTemperatureInCelsius = 60;
	maxTemperatureInCelsius = 0;

	safetyStopState = SAFETY_STOP_NOT_STARTED;
	safetyStopDurationInSeconds = 0;
	diveDurationInSeconds = 0;
	testPreviousDiveDurationInSeconds = 0;

	if (currentScreen == DIVE_SCREEN) {

		Serial.println("DIVE - Started");

		//Start dive profile logging - create a new file
		if (maximumProfileNumber <= 0) {
			maximumProfileNumber = logbook.loadLogbookData()->numberOfStoredProfiles;
		}
		profileFile = logbook.createNewProfileFile(maximumProfileNumber+1);

		// Initialize the DiveDeco library based on the settings
		buhlmann.setSeaLevelAtmosphericPressure(seaLevelPressureSetting);
		buhlmann.setNitrogenRateInGas(1 - oxygenRateSetting);

		DiveResult* diveResult = new DiveResult;
		diveResult = buhlmann.initializeCompartments();

		//Retrieve last dive data
{'fraction_non_alphanumeric': 0.10666431593794076, 'fraction_numerical': 0.012693935119887164, 'mean_word_length': 4.3752665245202556, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2672294', 'n_tokens_mistral': 8230, 'n_tokens_neox': 7263, 'n_words': 1689}