diff Small_CPU/Src/scheduler.c @ 38:5f11787b4f42

include in ostc4 repository
author heinrichsweikamp
date Sat, 28 Apr 2018 11:52:34 +0200
parents
children a6f0881074a4
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Small_CPU/Src/scheduler.c	Sat Apr 28 11:52:34 2018 +0200
@@ -0,0 +1,1562 @@
+/**
+  ******************************************************************************
+  * @file    scheduler.c 
+  * @author  heinrichs weikamp gmbh
+  * @date    27-March-2014
+  * @version V0.0.6
+  * @since   18-June-2015
+  * @brief   the main part except for base.c
+  *           
+  @verbatim                 
+  ============================================================================== 
+                        ##### How to use #####
+  ============================================================================== 
+  @endverbatim
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT(c) 2015 heinrichs weikamp</center></h2>
+  *
+  ******************************************************************************
+  */ 
+	
+	
+//#define DEBUGMODE
+
+/* Includes ------------------------------------------------------------------*/
+#include <string.h>
+#include "baseCPU2.h"
+#include "stm32f4xx_hal.h"
+#include "i2c.h"
+#include "scheduler.h"
+#include "pressure.h"
+#include "compass.h"
+#include "batteryGasGauge.h"
+#include "batteryCharger.h"
+#include "spi.h"
+#include "rtc.h"
+#include "dma.h"
+#include "adc.h"
+#include "calc_crush.h"
+#include "stm32f4xx_hal_rtc_ex.h"
+#include "decom.h"
+#include "wireless.h"
+#include "tm_stm32f4_otp.h"
+
+
+/* Private types -------------------------------------------------------------*/
+const SGas Air = {79,0,0,0,0};
+
+uint8_t testarrayindex = 0; 
+uint32_t testarray[256];
+uint32_t testarrayMain[256];
+
+/* Exported variables --------------------------------------------------------*/
+SGlobal global;
+SDevice DeviceDataFlash;
+uint8_t deviceDataFlashValid = 0;
+uint8_t deviceDataSubSeconds = 0;
+
+/* Private variables ---------------------------------------------------------*/
+/* can be lost while in sleep */
+uint8_t clearDecoNow = 0;
+uint8_t setButtonsNow = 0;
+
+/* has to be in SRAM2 */
+uint8_t secondsCount = 0;
+ 
+/* Private function prototypes -----------------------------------------------*/
+
+_Bool vpm_crush2(void);
+void scheduleUpdateDeviceData(void);
+void initStructWithZeero(uint8_t* data, uint16_t length);
+long get_nofly_time_minutes(void);
+void copyActualGas(SGas gas);
+void copyPressureData(void);
+void copyCnsAndOtuData(void);
+void copyTimeData(void);
+void copyCompassData(void);
+void copyCompassDataDuringCalibration(int16_t dx, int16_t dy, int16_t dz);
+//void copyBatteryData(void); now in header
+void copyAmbientLightData(void);
+void copyTissueData(void);
+void copyVpmCrushingData(void);
+void copyDeviceData(void);
+void changeAgeWirelessData(void);
+void copyWirelessData(void);
+void copyPICdata(void);
+uint16_t schedule_update_timer_helper(int8_t thisSeconds);
+
+
+uint32_t time_elapsed_ms(uint32_t ticksstart,uint32_t ticksnow);
+
+_Bool scheduleCheck_pressure_reached_dive_mode_level(void);
+void scheduleSetDate(SDeviceLine *line);
+
+/* Exported functions --------------------------------------------------------*/
+
+void initGlobals(void)
+{
+	initStructWithZeero((uint8_t*) &global, sizeof(SGlobal));
+	
+	global.dataSendToSlavePending = 0;
+	global.dataSendToSlaveIsValid = 1;
+	global.dataSendToSlaveIsNotValidCount = 0;
+
+	global.mode = MODE_POWERUP;
+	global.repetitive_dive = 0;
+	global.conservatism = 0;
+	global.whichGas = 0;
+	global.aktualGas[0] = Air;
+	global.lifeData.actualGas = global.aktualGas[0];
+
+	const uint8_t button_standard_sensitivity = ((2400-(  90  *24))/10)+15;
+	global.ButtonResponsiveness[0] = button_standard_sensitivity;
+	global.ButtonResponsiveness[1] = button_standard_sensitivity;
+	global.ButtonResponsiveness[2] = button_standard_sensitivity;
+	global.ButtonResponsiveness[3] = button_standard_sensitivity;
+	
+	global.ButtonPICdata[0] = 0xFF;
+	global.ButtonPICdata[1] = 0xFF;
+	global.ButtonPICdata[2] = 0xFF;
+	global.ButtonPICdata[3] = 0xFF;
+
+	global.I2C_SystemStatus = 0xFF; // 0x00 would be everything working
+	
+	global.lifeData.pressure_ambient_bar = 1.0f;
+	global.lifeData.pressure_surface_bar = 1.0f;
+	decom_reset_with_1000mbar(&global.lifeData);
+	
+	global.demo_mode = 0;
+
+	for(int i = 0; i < MAX_SENSORS; i++)
+	{
+		global.sensorError[i] = HAL_OK; // HAL_OK = 0;
+	}
+
+	global.dataSendToMaster.RTE_VERSION_high = firmwareVersionHigh();//RTE_VERSION_HIGH;;
+	global.dataSendToMaster.RTE_VERSION_low = firmwareVersionLow();//RTE_VERSION_LOW;;
+	global.dataSendToMaster.chargeStatus = 0;
+	
+	global.dataSendToMaster.power_on_reset = 1;
+	global.dataSendToMaster.header.checkCode[0] = 0xA1;
+	global.dataSendToMaster.header.checkCode[1] = 0xA2;
+	global.dataSendToMaster.header.checkCode[2] = 0xA3;
+	global.dataSendToMaster.header.checkCode[3] = 0xA4;
+	global.dataSendToMaster.footer.checkCode[3] = 0xE4;
+	global.dataSendToMaster.footer.checkCode[2] = 0xE3;
+	global.dataSendToMaster.footer.checkCode[1] = 0xE2;
+	global.dataSendToMaster.footer.checkCode[0] = 0xE1;
+	global.dataSendToMaster.sensorErrors = 0;
+
+	global.sync_error_count = 0;
+	global.check_sync_not_running = 0;
+
+	global.deviceDataSendToMaster.RTE_VERSION_high = firmwareVersionHigh();//RTE_VERSION_HIGH;
+	global.deviceDataSendToMaster.RTE_VERSION_low = firmwareVersionLow();//RTE_VERSION_LOW;
+	global.deviceDataSendToMaster.chargeStatus = 0;
+
+	global.deviceDataSendToMaster.power_on_reset = 1;
+	global.deviceDataSendToMaster.header.checkCode[0] = 0xDF;
+	global.deviceDataSendToMaster.header.checkCode[1] = 0xDE;
+	global.deviceDataSendToMaster.header.checkCode[2] = 0xDD;
+	global.deviceDataSendToMaster.header.checkCode[3] = 0xDC;
+	global.deviceDataSendToMaster.footer.checkCode[3] = 0xE4;
+	global.deviceDataSendToMaster.footer.checkCode[2] = 0xE3;
+	global.deviceDataSendToMaster.footer.checkCode[1] = 0xE2;
+	global.deviceDataSendToMaster.footer.checkCode[0] = 0xE1;
+	
+	global.dataSendToSlave.getDeviceDataNow = 0;
+	
+	global.deviceData.batteryChargeCompleteCycles.value_int32 = 0;
+	global.deviceData.batteryChargeCycles.value_int32 = 0;
+	global.deviceData.depthMaximum.value_int32 = 0;
+	global.deviceData.diveCycles.value_int32 = 0;
+	global.deviceData.hoursOfOperation.value_int32 = 0;
+	global.deviceData.temperatureMaximum.value_int32 = INT32_MIN;
+	global.deviceData.temperatureMinimum.value_int32 = INT32_MAX;
+	global.deviceData.voltageMinimum.value_int32 = INT32_MAX;
+}
+
+
+void scheduleSpecial_Evaluate_DataSendToSlave(void)
+{
+	global.dataSendToSlavePending = 0;
+	if(!global.dataSendToSlaveIsValid)
+		return;
+	
+	global.dataSendToMaster.confirmRequest.uw = 0;
+	
+	if(TM_OTP_Read(0,0) == 0xFF)
+	{
+		if(global.dataSendToSlave.revisionHardware == (global.dataSendToSlave.revisionCRCx0x7A ^ 0x7A))
+			TM_OTP_Write(0,0,global.dataSendToSlave.revisionHardware);
+	}
+	
+	if(global.dataSendToSlave.setAccidentFlag)
+	{
+		global.dataSendToMaster.confirmRequest.ub.accident = 1;
+		global.deviceData.diveAccident.value_int32 = global.dataSendToSlave.setAccidentFlag;
+		scheduleSetDate(&global.deviceData.diveAccident);
+		global.accidentFlag |= global.dataSendToSlave.setAccidentFlag;
+		if(global.accidentFlag == ACCIDENT_CNS) // LVL1
+			global.accidentRemainingSeconds = 2*60*60;
+		else
+			global.accidentRemainingSeconds = 24*60*60;
+	}
+	
+	if(global.dataSendToSlave.setTimeNow)
+	{
+		global.dataSendToMaster.confirmRequest.ub.time = 1;
+		RTC_SetTime(global.dataSendToSlave.data.newTime);
+		schedule_update_timer_helper(0);
+	}
+	
+	if(global.dataSendToSlave.setDateNow)
+	{
+		global.dataSendToMaster.confirmRequest.ub.date = 1;
+		RTC_SetDate(global.dataSendToSlave.data.newDate);
+		schedule_update_timer_helper(0);
+	}		
+
+	if(global.dataSendToSlave.calibrateCompassNow)
+	{
+		global.dataSendToMaster.confirmRequest.ub.compass = 1;
+		global.mode = MODE_CALIB;
+	}		
+
+	if(global.dataSendToSlave.clearDecoNow)
+	{
+		global.dataSendToMaster.confirmRequest.ub.clearDeco = 1;
+		clearDecoNow = 1;
+	}		
+
+	if(global.dataSendToSlave.setButtonSensitivityNow)
+	{
+		global.dataSendToMaster.confirmRequest.ub.button = 1;
+		global.ButtonResponsiveness[0] = global.dataSendToSlave.data.buttonResponsiveness[0];
+		global.ButtonResponsiveness[1] = global.dataSendToSlave.data.buttonResponsiveness[1];
+		global.ButtonResponsiveness[2] = global.dataSendToSlave.data.buttonResponsiveness[2];
+		global.ButtonResponsiveness[3] = global.dataSendToSlave.data.buttonResponsiveness[3];
+		setButtonsNow = 1;
+	}		
+
+	if(global.dataSendToSlave.setBatteryGaugeNow)
+	{
+		global.dataSendToMaster.confirmRequest.ub.batterygauge = 1;
+		battery_gas_gauge_set(global.dataSendToSlave.data.newBatteryGaugePercentageFloat);
+	}		
+
+	if((global.mode == MODE_SURFACE) && (global.dataSendToSlave.mode == MODE_SHUTDOWN))
+	{
+		global.mode = MODE_SHUTDOWN;
+	}
+
+	if(global.mode == MODE_DIVE)
+	{
+		copyActualGas(global.dataSendToSlave.data.actualGas);
+	}
+	else
+	{
+		copyActualGas(Air);
+		global.settings.divetimeToCreateLogbook = global.dataSendToSlave.data.divetimeToCreateLogbook;
+		global.settings.timeoutDiveReachedZeroDepth = global.dataSendToSlave.data.timeoutDiveReachedZeroDepth;
+	}
+	
+	/* for simulation / testing */
+	global.ceiling_from_main_CPU_mbar	= global.dataSendToSlave.data.ambient_pressure_mbar_ceiling;
+	
+	/* for device data updates */
+	deviceDataFlashValid = 0;
+	memcpy(&DeviceDataFlash, &global.dataSendToSlave.data.DeviceData, sizeof(SDevice));
+	deviceDataFlashValid = 1;
+}
+
+
+/**
+  ******************************************************************************
+* @brief   schedule_time_compare_helper. 
+  * @author  heinrichs weikamp gmbh
+  * @version V0.0.1
+  * @date    20-Oct-2016
+  ******************************************************************************
+  */
+
+uint8_t RtcBugFixChsw(uint8_t inStupidTime)
+{
+		uint8_t multiplesOf16 = 0;
+	
+	multiplesOf16 = inStupidTime / 16;
+
+	inStupidTime -= multiplesOf16 * 16;
+	
+	return (10 * multiplesOf16) + inStupidTime;
+}
+
+
+uint32_t minCounterDebug = 0;
+
+uint32_t schedule_time_compare_helper(RTC_TimeTypeDef timeNow, RTC_DateTypeDef dateNow, RTC_TimeTypeDef timeLast, RTC_DateTypeDef dateLast)
+{
+	uint32_t nowInSeconds;
+	uint32_t lastInSeconds;
+	uint32_t resultDiff;
+	
+	if(timeNow.Minutes != timeLast.Minutes)
+		minCounterDebug++;
+
+	nowInSeconds  = (uint32_t)RtcBugFixChsw(timeNow.Hours) * 3600;
+	nowInSeconds += (uint32_t)RtcBugFixChsw(timeNow.Minutes) * 60;
+	nowInSeconds += (uint32_t)RtcBugFixChsw(timeNow.Seconds);
+
+	lastInSeconds  = (uint32_t)RtcBugFixChsw(timeLast.Hours) * 3600;
+	lastInSeconds += (uint32_t)RtcBugFixChsw(timeLast.Minutes) * 60;
+	lastInSeconds += (uint32_t)RtcBugFixChsw(timeLast.Seconds);
+
+/*
+		nowInSeconds  = (uint32_t)timeNow.Hours * 3600;
+	nowInSeconds += (uint32_t)timeNow.Minutes * 60;
+	nowInSeconds += (uint32_t)timeNow.Seconds;
+
+	lastInSeconds  = (uint32_t)timeLast.Hours * 3600;
+	lastInSeconds += (uint32_t)timeLast.Minutes * 60;
+	lastInSeconds += (uint32_t)timeLast.Seconds;
+*/
+	
+	if(dateNow.Date != dateLast.Date)
+	{
+		resultDiff = 86400 + nowInSeconds - lastInSeconds;
+	}
+	else
+	{
+		resultDiff = nowInSeconds - lastInSeconds;
+	}
+	return resultDiff;
+}
+
+
+
+/**
+  ******************************************************************************
+* @brief   schedule_update_timer_helper. 
+  * @author  heinrichs weikamp gmbh
+  * @version V0.0.1
+  * @date    20-Oct-2016
+	* @brief	use 0 for init
+						use -1 for RTC controlled
+						use >= 1 for manual control
+  ******************************************************************************
+  */
+extern RTC_HandleTypeDef RTCHandle;
+
+uint16_t schedule_update_timer_helper(int8_t thisSeconds)
+{
+	static RTC_TimeTypeDef sTimeLast;
+	static RTC_DateTypeDef sDateLast;
+	RTC_TimeTypeDef sTimeNow;
+	RTC_DateTypeDef sDateNow;
+	uint32_t secondsPast;
+	uint32_t tempNewValue = 0;
+
+	HAL_RTC_GetTime(&RTCHandle, &sTimeNow, RTC_FORMAT_BCD);
+	HAL_RTC_GetDate(&RTCHandle, &sDateNow, RTC_FORMAT_BCD);
+
+	if(thisSeconds != 0) // otherwise just store sTimeLast, sDateLast and return 0
+	{
+		secondsPast = schedule_time_compare_helper(sTimeNow, sDateNow, sTimeLast, sDateLast);
+
+		if(thisSeconds > 0) // use this value instead, good for pre-loading sTimeLast and sDateLast
+		{
+			secondsPast	= thisSeconds;
+		}
+
+		if(global.seconds_since_last_dive)
+		{
+			if(secondsPast >= 777900)
+			{
+				global.seconds_since_last_dive = 0;
+			}
+			else
+			{
+				tempNewValue = ((uint32_t)global.seconds_since_last_dive) + secondsPast;
+				if(tempNewValue > 777900) // a bit more than nine days [seconds]
+					global.seconds_since_last_dive = 0;
+				else
+					global.seconds_since_last_dive = (long)tempNewValue;
+			}
+		}
+	}
+		
+	sTimeLast = sTimeNow;
+	sDateLast = sDateNow;
+	
+	return tempNewValue;
+}
+
+
+
+
+/**
+  ******************************************************************************
+* @brief   schedule_check_resync. 
+  * @author  heinrichs weikamp gmbh
+  * @version V0.0.2
+  * @date    18-June-2015
+  ******************************************************************************
+  */
+void schedule_check_resync(void)
+{
+	if((global.check_sync_not_running >= 10) || (global.dataSendToSlaveIsNotValidCount >= 2))
+	{
+		global.dataSendToSlaveIsNotValidCount = 0;
+		global.check_sync_not_running = 0;
+		global.sync_error_count++;
+		MX_SPI_DeInit();
+		HAL_Delay(30); /* could be closer to length of data transmission 23.Feb.2015 hw */
+		MX_DMA_Init();
+		MX_SPI1_Init();
+		SPI_Start_single_TxRx_with_Master();
+	}
+}
+
+
+/**
+  ******************************************************************************
+* @brief   scheduleDiveMode. /  Dive Mode: Main Loop
+  * @author  Peter Ryser
+  * @version V0.0.1
+  * @date    22-April-2014
+  ******************************************************************************
+  */
+void scheduleDiveMode(void)
+{
+	uint32_t tickstart = 0;
+	uint32_t ticksdiff = 0; 
+	uint32_t lasttick = 0;
+	tickstart = HAL_GetTick();
+	uint8_t counterPressure100msec = 0;
+	uint8_t counterCompass100msec = 0;
+	uint8_t counterAmbientLight100msec = 0;
+	uint16_t counterWireless1msec = 0;
+//	uint8_t counterDemo250msec = 0;
+	uint32_t turbo_seconds = 0;
+	uint8_t counterAscentRate = 0;
+	float lastPressure_bar = 0.0f;
+	global.dataSendToMaster.mode = MODE_DIVE;
+	global.deviceDataSendToMaster.mode = MODE_DIVE;
+	//uint16_t counterSecondsShallowDepth = 0;
+	uint8_t counter_exit = 0;
+	
+	tickstart = HAL_GetTick() - 1000;
+	
+	global.deviceData.diveCycles.value_int32++;
+	scheduleSetDate(&global.deviceData.diveCycles);
+	global.lifeData.counterSecondsShallowDepth = 0;
+
+	while(global.mode == MODE_DIVE)
+	{
+		schedule_check_resync();
+		lasttick = HAL_GetTick();
+		ticksdiff = time_elapsed_ms(tickstart,lasttick);
+
+
+		//Evaluate wireless data every ms, if present
+		if(ticksdiff > counterWireless1msec)
+		{
+			counterWireless1msec++;
+			changeAgeWirelessData();
+			global.wirelessReceived = wireless_evaluate(global.wirelessdata,MAX_WIRELESS_BYTES, &global.wirelessConfidenceStatus);
+			if((global.wirelessReceived  > 0) && !wireless_evaluate_crc_error(global.wirelessdata,global.wirelessReceived))
+			{
+				copyWirelessData();
+			}
+		}
+
+		//Evaluate pressure at 20 ms, 120 ms, 220 ms,....
+		if(ticksdiff >= counterPressure100msec * 100 + 20)
+		{
+				global.check_sync_not_running++;
+				pressure_update();
+				scheduleUpdateDeviceData();
+				if(global.demo_mode)
+				{
+					turbo_seconds = demo_modify_temperature_and_pressure(global.lifeData.dive_time_seconds, counterPressure100msec, global.ceiling_from_main_CPU_mbar);
+					if(turbo_seconds)
+					{
+						global.lifeData.dive_time_seconds += turbo_seconds;
+						decom_tissues_exposure((int)(turbo_seconds), &global.lifeData);
+						copyTissueData();
+					}
+					if((global.lifeData.counterSecondsShallowDepth > 1) && (global.lifeData.counterSecondsShallowDepth < (global.settings.timeoutDiveReachedZeroDepth - 10)))
+						global.lifeData.counterSecondsShallowDepth = (global.settings.timeoutDiveReachedZeroDepth - 10);
+				}
+				
+				
+				//Calc ascentrate every two second (20 * 100 ms)
+				counterAscentRate++;
+				if(counterAscentRate == 20)
+				{
+					global.lifeData.pressure_ambient_bar = get_pressure_mbar() / 1000.0f;
+					if(lastPressure_bar >= 0)
+					{
+							//2 seconds * 30 == 1 minute, bar * 10 = meter
+							global.lifeData.ascent_rate_meter_per_min = (lastPressure_bar - global.lifeData.pressure_ambient_bar)  * 30 * 10;
+					}
+					lastPressure_bar = global.lifeData.pressure_ambient_bar;
+					counterAscentRate = 0;
+					
+//					if(global.demo_mode)
+//						global.lifeData.ascent_rate_meter_per_min /= 4;
+				}
+				copyPressureData();
+				counterPressure100msec++;
+		}
+			//evaluate compass data at 50 ms, 150 ms, 250 ms,....
+		if(ticksdiff >= counterCompass100msec * 100 + 50)
+		{
+			compass_read();
+			acceleration_read();
+			compass_calc();
+			copyCompassData();
+			counterCompass100msec++;
+		}
+		
+		if(ticksdiff >= counterAmbientLight100msec * 100 + 70)
+		{
+			adc_ambient_light_sensor_get_data();
+			copyAmbientLightData();
+			counterAmbientLight100msec++;
+		}
+
+/*		if(global.demo_mode && (ticksdiff >= counterDemo250msec * 250 + 10))
+		{
+			global.lifeData.dive_time_seconds++;
+			copyTimeData();
+			counterDemo250msec++;
+		}
+*/
+		//Evaluate tissues, toxic data, vpm, etc. once a second 
+		if(ticksdiff >= 1000)
+		{
+			if(global.dataSendToSlave.diveModeInfo != DIVEMODE_Apnea)
+			{
+				scheduleUpdateLifeData(0); // includes tissues
+				global.lifeData.dive_time_seconds++; // there is dive_time_seconds_without_surface_time too
+				global.lifeData.ppO2 = decom_calc_ppO2(global.lifeData.pressure_ambient_bar, &global.lifeData.actualGas);
+				decom_oxygen_calculate_cns(&global.lifeData.cns,global.lifeData.ppO2);
+				decom_oxygen_calculate_otu(&global.lifeData.otu,global.lifeData.ppO2);
+				battery_gas_gauge_get_data();
+
+
+				/** counter_exit allows safe exit via button for testing
+					* and demo_mode is exited too if aplicable.
+					*/
+				if(global.dataSendToMaster.mode == MODE_ENDDIVE)
+				{
+					counter_exit++;
+					if(counter_exit >= 2)
+					{
+						global.mode = MODE_SURFACE;
+						global.demo_mode = 0;
+					}
+				}
+				
+				if(is_ambient_pressure_close_to_surface(&global.lifeData))
+				{
+					global.lifeData.counterSecondsShallowDepth++;
+					if((global.lifeData.counterSecondsShallowDepth >= global.settings.timeoutDiveReachedZeroDepth) || ((global.lifeData.dive_time_seconds < 60) && (global.demo_mode == 0)) || (global.dataSendToSlave.setEndDive))
+					{
+						global.seconds_since_last_dive = 1; // start counter
+						schedule_update_timer_helper(0); // zum starten :-)
+						global.dataSendToMaster.mode = MODE_ENDDIVE;
+						global.deviceDataSendToMaster.mode = MODE_ENDDIVE;
+					}
+				}
+				else
+				{
+					global.lifeData.counterSecondsShallowDepth = 0;
+					global.lifeData.dive_time_seconds_without_surface_time++;
+				}
+				vpm_crush2();
+			}
+			else // DIVEMODE_Apnea
+			{
+				global.lifeData.dive_time_seconds++;
+
+				// exit dive mode
+				if(global.dataSendToMaster.mode == MODE_ENDDIVE)
+				{
+					counter_exit++;
+					if(counter_exit >= 2)
+					{
+						scheduleUpdateLifeData(-1); // 'restart' tissue calculations without calculating time during apnea mode
+						global.lifeData.dive_time_seconds = 0; // use backup noflytime and desaturation time
+						global.mode = MODE_SURFACE;
+						global.demo_mode = 0;
+					}
+				}
+
+				// surface break
+				if(is_ambient_pressure_close_to_surface(&global.lifeData))
+				{
+					global.lifeData.counterSecondsShallowDepth++;
+					if(global.lifeData.counterSecondsShallowDepth > 3) // time for main cpu to copy to apnea_last_dive_time_seconds
+					{
+						global.lifeData.dive_time_seconds = 0; // this apnea dive ends here
+					}
+					if((global.lifeData.counterSecondsShallowDepth >= global.settings.timeoutDiveReachedZeroDepth) || (global.dataSendToSlave.setEndDive))
+					{
+						global.dataSendToMaster.mode = MODE_ENDDIVE;
+						global.deviceDataSendToMaster.mode = MODE_ENDDIVE;
+					}
+				}
+				else
+				{
+					global.lifeData.counterSecondsShallowDepth = 0;
+					global.lifeData.dive_time_seconds_without_surface_time++; 
+				}
+			} // standard dive or DIVEMODE_Apnea
+		
+			copyVpmCrushingData();
+			copyTimeData();
+			copyCnsAndOtuData();
+			copyBatteryData();
+
+			// new hw 170523
+			if(global.I2C_SystemStatus != HAL_OK)
+			{
+				MX_I2C1_TestAndClear();
+				MX_I2C1_Init();
+				if(!is_init_pressure_done())
+				{
+					init_pressure();
+				}
+			}
+			
+			counterCompass100msec = 0;
+			counterPressure100msec = 0;
+			counterAmbientLight100msec = 0;
+			counterWireless1msec = 0;
+//			counterDemo250msec = 0;
+
+			/** keep it in rhythm, do not drop the execution time
+			  * therefore do not use tickstart = HAL_GetTick();
+				* here
+				*/
+			tickstart += 1000; 
+		}
+	}
+}
+
+
+/**
+  ******************************************************************************
+* @brief   scheduleSurfaceMode / surface mode: Main Loop
+  * @author  Peter Ryser
+  * @version V0.0.1
+  * @date    22-April-2014
+  ******************************************************************************
+  */
+
+
+//  ===============================================================================
+//	scheduleTestMode
+/// @brief	included for sealed hardware with permanent RTE update message
+//  ===============================================================================
+void scheduleTestMode(void)
+{
+	uint32_t tickstart = 0;
+	uint32_t ticksdiff = 0; 
+	uint32_t lasttick = 0;
+	tickstart = HAL_GetTick();
+
+	uint8_t counterPressure100msec = 0;
+	
+	float temperature_carousel = 0.0f;
+	float temperature_changer = 0.1f;
+	
+	while(global.mode == MODE_TEST)
+	{
+		schedule_check_resync();
+		lasttick = HAL_GetTick();
+		ticksdiff = time_elapsed_ms(tickstart,lasttick);
+		
+		//Evaluate pressure at 20 ms, 120 ms, 220 ms,...
+		if(ticksdiff >= counterPressure100msec * 100 + 20)
+		{
+				global.check_sync_not_running++;
+
+pressure_update();
+scheduleUpdateDeviceData();
+global.lifeData.ascent_rate_meter_per_min = 0;
+copyPressureData();
+
+				if(temperature_carousel > 20.0f)
+				{
+					temperature_carousel = 20.0f;
+					temperature_changer = -0.1f;
+				}
+				else
+				if(temperature_carousel < 0)
+				{
+					temperature_carousel = 0;
+					temperature_changer = +0.1f;
+				}
+					
+				temperature_carousel += temperature_changer;
+				
+				uint8_t boolPressureData = !global.dataSendToMaster.boolPressureData;
+
+global.dataSendToMaster.data[boolPressureData].pressure_mbar = get_pressure_mbar();
+
+				global.dataSendToMaster.data[boolPressureData].temperature = temperature_carousel;
+				global.dataSendToMaster.data[boolPressureData].pressure_uTick = HAL_GetTick();
+				global.dataSendToMaster.boolPressureData = boolPressureData;
+
+
+				counterPressure100msec++;
+		}
+		
+		if(ticksdiff >= 1000)
+		{
+			//Set back tick counter
+			tickstart = HAL_GetTick();
+			counterPressure100msec = 0;
+		}
+	};	
+}
+
+
+void scheduleSurfaceMode(void)
+{
+	uint32_t tickstart = 0;
+	uint32_t ticksdiff = 0; 
+	uint32_t lasttick = 0;
+	tickstart = HAL_GetTick();
+	uint8_t counterPressure100msec = 0;
+	uint8_t counterCompass100msec = 0;
+	uint8_t counterAmbientLight100msec = 0;
+	uint16_t counterWireless1msec = 0;
+	global.dataSendToMaster.mode = MODE_SURFACE;
+	global.deviceDataSendToMaster.mode = MODE_SURFACE;
+
+	while(global.mode == MODE_SURFACE)
+	{
+	    printf("surface...\n");
+
+		schedule_check_resync();
+		lasttick = HAL_GetTick();
+		ticksdiff = time_elapsed_ms(tickstart,lasttick);
+
+		if(ticksdiff > counterWireless1msec)
+		{
+			counterWireless1msec++;
+			changeAgeWirelessData();
+			global.wirelessReceived = wireless_evaluate(global.wirelessdata,MAX_WIRELESS_BYTES, &global.wirelessConfidenceStatus);
+			if((global.wirelessReceived  > 0) && !wireless_evaluate_crc_error(global.wirelessdata,global.wirelessReceived))
+			{
+				copyWirelessData();
+			}
+		}
+		if(setButtonsNow == 1)
+		{
+			if(scheduleSetButtonResponsiveness())
+				setButtonsNow = 0;
+		}
+		
+		//Evaluate pressure at 20 ms, 120 ms, 220 ms,...
+		if(ticksdiff >= counterPressure100msec * 100 + 20)
+		{
+				global.check_sync_not_running++;
+				pressure_update();
+				scheduleUpdateDeviceData();
+				global.lifeData.ascent_rate_meter_per_min = 0;
+				copyPressureData();
+				counterPressure100msec++;
+				
+				if(scheduleCheck_pressure_reached_dive_mode_level())
+					global.mode = MODE_DIVE;
+		}
+		
+		//evaluate compass data at 50 ms, 150 ms, 250 ms,...
+
+		if(ticksdiff >= counterCompass100msec * 100 + 50)
+		{
+			compass_read();
+			acceleration_read();
+			compass_calc();
+			copyCompassData();
+			counterCompass100msec++;
+		}
+
+		//evaluate compass data at 70 ms, 170 ms, 270 ms,...
+		if(ticksdiff >= counterAmbientLight100msec * 100 + 70)
+		{
+			adc_ambient_light_sensor_get_data();
+			copyAmbientLightData();
+			counterAmbientLight100msec++;
+		}
+		//Evaluate tissues, toxic data, etc. once a second 
+		if(ticksdiff >= 1000)
+		{
+			if(clearDecoNow)
+			{
+				decom_reset_with_1000mbar(&global.lifeData); ///< this should almost reset desaturation time
+				// new 160215 hw
+				global.repetitive_dive = 0;
+				global.seconds_since_last_dive = 0; ///< this will reset OTU and CNS as well
+				global.no_fly_time_minutes = 0;
+				global.accidentFlag = 0;
+				global.accidentRemainingSeconds = 0;
+				vpm_init(&global.vpm, global.conservatism, global.repetitive_dive, global.seconds_since_last_dive);
+				clearDecoNow = 0;
+			}
+	
+			//Set back tick counter
+			tickstart = HAL_GetTick();
+			
+			
+			if(global.seconds_since_last_dive)
+			{
+				schedule_update_timer_helper(-1);
+//				global.seconds_since_last_dive++;
+//				if(global.seconds_since_last_dive > 777900) // a bit more than nine days [seconds]
+//					global.seconds_since_last_dive = 0;
+			}
+			
+			if(global.accidentRemainingSeconds)
+			{
+				global.accidentRemainingSeconds--;
+				if(!global.accidentRemainingSeconds)
+					global.accidentFlag = 0;
+			}
+			global.dataSendToMaster.accidentFlags = global.accidentFlag;
+			
+			update_surface_pressure(1);
+			scheduleUpdateLifeData(0);
+			decom_oxygen_calculate_otu_degrade(&global.lifeData.otu, global.seconds_since_last_dive);
+			decom_oxygen_calculate_cns_degrade(&global.lifeData.cns, global.seconds_since_last_dive);
+			global.lifeData.desaturation_time_minutes = decom_calc_desaturation_time(global.lifeData.tissue_nitrogen_bar,global.lifeData.tissue_helium_bar,global.lifeData.pressure_surface_bar);
+			battery_charger_get_status_and_contral_battery_gas_gauge(0);
+			battery_gas_gauge_get_data();
+			
+			copyCnsAndOtuData();
+			copyTimeData();
+			copyBatteryData();
+			copyDeviceData();
+
+			// new hw 170523
+			if(global.I2C_SystemStatus != HAL_OK)
+			{
+				MX_I2C1_TestAndClear();
+				MX_I2C1_Init();
+				if(!is_init_pressure_done())
+				{
+					init_pressure();
+				}
+			}
+			
+			counterCompass100msec = 0;
+			counterPressure100msec = 0;
+			counterAmbientLight100msec = 0;
+			counterWireless1msec = 0;
+		}
+	}
+}
+
+
+/**
+  ******************************************************************************
+	* @brief   scheduleCompassCalibrationMode
+  * @author  heinrichs weikamp gmbh
+  * @version V0.0.1
+  * @since   31-March-2015
+  * @date    31-March-2015
+  ******************************************************************************
+  */
+void scheduleCompassCalibrationMode(void)
+{
+	compass_init(1,7); // fast mode, max gain
+	compass_calib(); // duration : 1 minute!
+	compass_init(0,7); // back to normal mode
+
+	if(global.seconds_since_last_dive)
+	{
+				schedule_update_timer_helper(-1);
+//		global.seconds_since_last_dive += 60;
+//				if(global.seconds_since_last_dive > 777900) // a bit more than nine days [seconds]
+//					global.seconds_since_last_dive = 0;
+	}
+
+	scheduleUpdateLifeData(0);
+	global.mode = MODE_SURFACE;
+}
+
+
+/**
+  ******************************************************************************
+	* @brief   scheduleSleepMode / sleep mode: Main Loop
+  * @author  heinrichs weikamp gmbh
+  * @version V0.0.2
+  * @since   31-March-2015
+  * @date    22-April-2014
+  ******************************************************************************
+  */
+
+void scheduleSleepMode(void)
+{
+	global.dataSendToMaster.mode = 0;
+	global.deviceDataSendToMaster.mode = 0;
+	
+	/* prevent button wake up problem while in sleep_prepare
+	 * sleep prepare does I2C_DeInit()
+	 */
+	if(global.mode != MODE_SLEEP)
+		MX_I2C1_Init();
+	else
+	do
+	{
+		I2C_DeInit();
+
+#ifdef DEBUGMODE
+		HAL_Delay(2000);
+#else
+		RTC_StopMode_2seconds();
+#endif
+		
+
+		
+		if(global.mode == MODE_SLEEP)
+			secondsCount += 2;
+
+		MX_I2C1_Init();
+		pressure_sensor_get_pressure_raw();
+
+		if(secondsCount >= 30)
+		{
+			pressure_sensor_get_temperature_raw();
+			battery_gas_gauge_get_data();
+//			ReInit_battery_charger_status_pins();
+			battery_charger_get_status_and_contral_battery_gas_gauge(1);
+//			DeInit_battery_charger_status_pins();
+			secondsCount = 0;
+		}
+		
+		pressure_calculation();
+
+		scheduleUpdateDeviceData();
+		update_surface_pressure(2);
+
+		if(global.seconds_since_last_dive)
+		{
+			schedule_update_timer_helper(-1);
+//			global.seconds_since_last_dive += 2;
+//				if(global.seconds_since_last_dive > 777900) // a bit more than nine days [seconds]
+//					global.seconds_since_last_dive = 0;
+		}
+
+		if(global.accidentRemainingSeconds)
+		{
+			if(global.accidentRemainingSeconds > 2)			
+				global.accidentRemainingSeconds -= 2;
+			else
+			{
+				global.accidentRemainingSeconds = 0;
+				global.accidentFlag = 0;
+			}
+		}
+
+		if(scheduleCheck_pressure_reached_dive_mode_level())
+			global.mode = MODE_BOOT;
+
+		scheduleUpdateLifeData(2000);
+	}
+	while(global.mode == MODE_SLEEP);
+	/* new section for system after Standby */
+	scheduleUpdateLifeData(-1);
+	clearDecoNow = 0;
+	setButtonsNow = 0;
+}
+
+
+
+/* Private functions ---------------------------------------------------------*/
+
+
+/**
+  ******************************************************************************
+	* @brief   scheduleCheck_pressure_reached_dive_mode_level
+  * @author  heinrichs weikamp gmbh
+  * @version V0.0.1 from inline code
+  * @date    09-Sept-2015
+  ******************************************************************************
+  */
+_Bool scheduleCheck_pressure_reached_dive_mode_level(void)
+{
+		if(get_pressure_mbar() > 1160)
+			return 1;
+		else
+		if((global.mode == MODE_SURFACE) && (get_pressure_mbar() > (get_surface_mbar() + 100)) && (get_surface_mbar() > 880))
+			return 1;
+		else
+			return 0;
+}
+		
+
+/**
+  ******************************************************************************
+	* @brief   scheduleUpdateLifeData / calculates tissues
+  * @author  Peter Ryser
+  * @version V0.0.1
+  * @date    22-April-2014
+  ******************************************************************************
+  */
+	
+	
+void scheduleUpdateLifeData(int32_t asynchron_milliseconds_since_last)
+{
+	static _Bool first = 1;
+	static uint32_t tickstart = 0;
+	static uint32_t ticksrest = 0;
+
+	uint32_t ticksdiff = 0; 
+	uint32_t ticksnow = 0;
+	uint32_t time_seconds = 0;
+	uint8_t whichGasTmp = 0;
+	
+	if(asynchron_milliseconds_since_last < 0)
+	{
+		first = 1;
+		tickstart = 0;
+		ticksrest = 0;
+		return;
+	}
+
+	if(!asynchron_milliseconds_since_last && first)
+	{
+		tickstart = HAL_GetTick();
+		first = 0;
+		return;
+	}
+
+	whichGasTmp = global.whichGas;
+	global.lifeData.actualGas = global.aktualGas[whichGasTmp];
+	global.lifeData.pressure_ambient_bar = get_pressure_mbar() / 1000.0f;
+	global.lifeData.pressure_surface_bar = get_surface_mbar() / 1000.0f;
+
+	if(!asynchron_milliseconds_since_last)
+	{
+		ticksnow = HAL_GetTick();
+		ticksdiff = time_elapsed_ms(tickstart,ticksnow);
+	}
+	else
+	{
+		first = 1;
+		ticksdiff = asynchron_milliseconds_since_last;
+	}
+
+	if(ticksrest > 1000) 	// whatever happens after standby with STM32L476
+		ticksrest = 0;			// maybe move static to SRAM2 
+
+	ticksdiff += ticksrest;
+	time_seconds = ticksdiff/ 1000;
+	ticksrest = ticksdiff - time_seconds * 1000; 
+	tickstart = ticksnow;
+
+	decom_tissues_exposure((int)time_seconds, &global.lifeData);
+	if(global.demo_mode)
+		decom_tissues_exposure((int)(3*time_seconds), &global.lifeData);
+  copyTissueData();
+}
+
+
+/**
+  ******************************************************************************
+* @brief   scheduleUpdateDeviceData
+  * @author  heinrichs weikamp gmbh
+  * @version V0.0.1
+  * @date    16-March-2015
+	*
+	* two step process
+	* first compare with data from main CPU == externalLogbookFlash
+	* second update with new sensor data
+  ******************************************************************************
+  */
+void scheduleSetDate(SDeviceLine *line)
+{
+	extern RTC_HandleTypeDef RTCHandle;
+
+	line->date_rtc_dr = (uint32_t)(RTCHandle.Instance->DR & RTC_DR_RESERVED_MASK); 
+	line->time_rtc_tr = (uint32_t)(RTCHandle.Instance->TR & RTC_TR_RESERVED_MASK); 
+}
+
+
+void scheduleCopyDeviceData(SDeviceLine *lineWrite, const SDeviceLine *lineRead)
+{	
+	lineWrite->date_rtc_dr = lineRead->date_rtc_dr; 
+	lineWrite->time_rtc_tr = lineRead->time_rtc_tr;
+	lineWrite->value_int32 = lineRead->value_int32;
+}
+
+
+void scheduleUpdateDeviceData(void)
+{
+	/* first step, main CPU */
+
+	if(deviceDataFlashValid)
+	{
+		/* max values */
+		if(global.deviceData.batteryChargeCompleteCycles.value_int32 < DeviceDataFlash.batteryChargeCompleteCycles.value_int32)
+		{
+			scheduleCopyDeviceData(&global.deviceData.batteryChargeCompleteCycles, &DeviceDataFlash.batteryChargeCompleteCycles);
+		}
+		if(global.deviceData.batteryChargeCycles.value_int32 < DeviceDataFlash.batteryChargeCycles.value_int32)
+		{
+			scheduleCopyDeviceData(&global.deviceData.batteryChargeCycles, &DeviceDataFlash.batteryChargeCycles);
+		}
+		if(global.deviceData.temperatureMaximum.value_int32 < DeviceDataFlash.temperatureMaximum.value_int32)
+		{
+			scheduleCopyDeviceData(&global.deviceData.temperatureMaximum, &DeviceDataFlash.temperatureMaximum);
+		}
+		if(global.deviceData.depthMaximum.value_int32 < DeviceDataFlash.depthMaximum.value_int32)
+		{
+			scheduleCopyDeviceData(&global.deviceData.depthMaximum, &DeviceDataFlash.depthMaximum);
+		}
+		if(global.deviceData.diveCycles.value_int32 < DeviceDataFlash.diveCycles.value_int32)
+		{
+			scheduleCopyDeviceData(&global.deviceData.diveCycles, &DeviceDataFlash.diveCycles);
+		}
+		if(global.deviceData.hoursOfOperation.value_int32 < DeviceDataFlash.hoursOfOperation.value_int32)
+		{
+			scheduleCopyDeviceData(&global.deviceData.hoursOfOperation, &DeviceDataFlash.hoursOfOperation);
+		}
+		
+		/* min values */
+		if(global.deviceData.temperatureMinimum.value_int32 > DeviceDataFlash.temperatureMinimum.value_int32)
+		{
+			scheduleCopyDeviceData(&global.deviceData.temperatureMinimum, &DeviceDataFlash.temperatureMinimum);
+		}
+		if(global.deviceData.voltageMinimum.value_int32 > DeviceDataFlash.voltageMinimum.value_int32)
+		{
+			scheduleCopyDeviceData(&global.deviceData.voltageMinimum, &DeviceDataFlash.voltageMinimum);
+		}
+	}		
+		
+	/* second step, sensor data */
+	int32_t temperature_centigrad_int32;
+	int32_t pressure_mbar_int32;
+	int32_t voltage_mvolt_int32;
+	
+	temperature_centigrad_int32 = (int32_t)(get_temperature() * 100);
+	if(temperature_centigrad_int32 < global.deviceData.temperatureMinimum.value_int32)
+	{
+		global.deviceData.temperatureMinimum.value_int32 = temperature_centigrad_int32;
+		scheduleSetDate(&global.deviceData.temperatureMinimum);
+	}
+
+	if(temperature_centigrad_int32 > global.deviceData.temperatureMaximum.value_int32)
+	{
+		global.deviceData.temperatureMaximum.value_int32 = temperature_centigrad_int32;
+		scheduleSetDate(&global.deviceData.temperatureMaximum);
+	}
+
+	pressure_mbar_int32 = (int32_t)get_pressure_mbar();
+	if(pressure_mbar_int32 > global.deviceData.depthMaximum.value_int32)
+	{
+		global.deviceData.depthMaximum.value_int32 = pressure_mbar_int32;
+		scheduleSetDate(&global.deviceData.depthMaximum);
+	}
+	
+	voltage_mvolt_int32 = (int32_t)(get_voltage() * 1000);
+	if(voltage_mvolt_int32 < global.deviceData.voltageMinimum.value_int32)
+	{
+		global.deviceData.voltageMinimum.value_int32 = voltage_mvolt_int32;
+		scheduleSetDate(&global.deviceData.voltageMinimum);
+	}
+
+	/* third step, counter */
+	switch (global.mode)
+	{
+		case MODE_SURFACE:
+		case MODE_DIVE:
+		default:
+			deviceDataSubSeconds++;
+			if(deviceDataSubSeconds > 10)
+			{
+				deviceDataSubSeconds = 0;
+				global.deviceData.hoursOfOperation.value_int32++;
+			}
+			break;
+
+		case	MODE_SLEEP:
+		case MODE_SHUTDOWN:
+			break;
+	}
+}
+
+
+void scheduleUpdateDeviceDataChargerFull(void)
+{
+	global.deviceData.batteryChargeCompleteCycles.value_int32++;
+	scheduleSetDate(&global.deviceData.batteryChargeCompleteCycles);
+}
+
+
+void scheduleUpdateDeviceDataChargerCharging(void)
+{
+	global.deviceData.batteryChargeCycles.value_int32++;
+	scheduleSetDate(&global.deviceData.batteryChargeCycles);
+}
+
+
+/**
+  ******************************************************************************
+* @brief   vpm_crush / calls vpm calc_crushing_pressure every four seconds during descend
+  * @author  Peter Ryser
+  * @version V0.0.1
+  * @date    22-April-2014
+  ******************************************************************************
+  */
+_Bool vpm_crush2(void)
+{
+    int i = 0;
+    static float starting_ambient_pressure = 0;
+    static float ending_ambient_pressure = 0;
+    static float time_calc_begin = -1;
+		static float initial_helium_pressure[16];
+		static float initial_nitrogen_pressure[16];
+		ending_ambient_pressure = global.lifeData.pressure_ambient_bar * 10;
+
+	if((global.lifeData.dive_time_seconds <= 4) || (starting_ambient_pressure >= ending_ambient_pressure))
+	{
+		time_calc_begin = global.lifeData.dive_time_seconds;
+		starting_ambient_pressure = global.lifeData.pressure_ambient_bar * 10;
+		for( i = 0; i < 16; i++)
+		{
+			initial_helium_pressure[i] = global.lifeData.tissue_helium_bar[i] * 10;
+			initial_nitrogen_pressure[i] = global.lifeData.tissue_nitrogen_bar[i] * 10;
+		}
+		return 0;
+	}
+	if(global.lifeData.dive_time_seconds - time_calc_begin >= 4)
+	{
+		if(ending_ambient_pressure > starting_ambient_pressure + 0.5f)
+		{
+			float rate = (ending_ambient_pressure - starting_ambient_pressure) * 60 / 4;
+			calc_crushing_pressure(&global.lifeData, &global.vpm, initial_helium_pressure, initial_nitrogen_pressure, starting_ambient_pressure, rate);
+
+			time_calc_begin = global.lifeData.dive_time_seconds;
+			starting_ambient_pressure = global.lifeData.pressure_ambient_bar * 10;
+			for( i = 0; i < 16; i++)
+			{
+				initial_helium_pressure[i] = global.lifeData.tissue_helium_bar[i] * 10;
+				initial_nitrogen_pressure[i] =  global.lifeData.tissue_nitrogen_bar[i] * 10;
+			}
+
+			return 1;
+		}
+
+	}
+	return 0;
+};
+
+
+void initStructWithZeero(uint8_t* data, uint16_t length)
+{
+	for(uint16_t i = 0; i < length; i++)
+		data[i] = 0;
+}
+
+
+long get_nofly_time_minutes(void)
+{
+	
+	if(global.no_fly_time_minutes <= 0)
+		return 0;
+	
+	long minutes_since_last_dive = global.seconds_since_last_dive/60;
+
+	if((global.seconds_since_last_dive > 0) && (global.no_fly_time_minutes > minutes_since_last_dive))
+	{
+			return (global.no_fly_time_minutes - minutes_since_last_dive);
+	}
+	else
+	{
+		global.no_fly_time_minutes = 0;
+		return 0;
+	}
+}
+
+
+//Supports threadsave copying!!!
+void copyActualGas(SGas gas)
+{
+	uint8_t whichGas = !global.whichGas;
+	global.aktualGas[whichGas] = gas;
+	global.whichGas = whichGas;
+}
+
+
+//Supports threadsave copying!!!
+void copyPressureData(void)
+{
+	global.dataSendToMaster.sensorErrors = I2C1_Status();
+	//uint8_t dataSendToMaster.
+	uint8_t boolPressureData = !global.dataSendToMaster.boolPressureData;
+	global.dataSendToMaster.data[boolPressureData].temperature = get_temperature();
+	global.dataSendToMaster.data[boolPressureData].pressure_mbar = get_pressure_mbar();
+	global.dataSendToMaster.data[boolPressureData].surface_mbar = get_surface_mbar();
+	global.dataSendToMaster.data[boolPressureData].ascent_rate_meter_per_min = global.lifeData.ascent_rate_meter_per_min;
+	global.dataSendToMaster.data[boolPressureData].pressure_uTick = HAL_GetTick();
+	global.dataSendToMaster.boolPressureData = boolPressureData;
+}
+
+
+//Supports threadsave copying!!!
+void copyCnsAndOtuData(void)
+{
+	//uint8_t dataSendToMaster.
+	uint8_t boolToxicData = !global.dataSendToMaster.boolToxicData;
+	global.dataSendToMaster.data[boolToxicData].cns = global.lifeData.cns;
+	global.dataSendToMaster.data[boolToxicData].otu = global.lifeData.otu;
+	global.dataSendToMaster.data[boolToxicData].desaturation_time_minutes = global.lifeData.desaturation_time_minutes;
+	global.dataSendToMaster.data[boolToxicData].no_fly_time_minutes = get_nofly_time_minutes();
+	global.dataSendToMaster.boolToxicData = boolToxicData;
+}
+
+
+//Supports threadsave copying!!!
+void copyTimeData(void)
+{
+	extern RTC_HandleTypeDef RTCHandle;
+	
+	uint8_t boolTimeData = !global.dataSendToMaster.boolTimeData;
+	global.dataSendToMaster.data[boolTimeData].localtime_rtc_tr =  (uint32_t)(RTCHandle.Instance->TR & RTC_TR_RESERVED_MASK); 
+	global.dataSendToMaster.data[boolTimeData].localtime_rtc_dr =  (uint32_t)(RTCHandle.Instance->DR & RTC_DR_RESERVED_MASK); 
+	global.dataSendToMaster.data[boolTimeData].divetime_seconds = (uint32_t)global.lifeData.dive_time_seconds;
+	global.dataSendToMaster.data[boolTimeData].dive_time_seconds_without_surface_time = (uint32_t)global.lifeData.dive_time_seconds_without_surface_time;
+	global.dataSendToMaster.data[boolTimeData].surfacetime_seconds = (uint32_t)global.seconds_since_last_dive;
+	global.dataSendToMaster.data[boolTimeData].counterSecondsShallowDepth = (uint32_t)global.lifeData.counterSecondsShallowDepth;
+	global.dataSendToMaster.boolTimeData = boolTimeData;
+}
+
+
+//Supports threadsave copying!!!
+void copyCompassData(void)
+{
+	extern float compass_heading;
+	extern float compass_roll;
+	extern float compass_pitch;
+	//uint8_t dataSendToMaster.
+	uint8_t boolCompassData = !global.dataSendToMaster.boolCompassData;
+	global.dataSendToMaster.data[boolCompassData].compass_heading = compass_heading;
+	global.dataSendToMaster.data[boolCompassData].compass_roll = compass_roll;
+	global.dataSendToMaster.data[boolCompassData].compass_pitch = compass_pitch;
+	global.dataSendToMaster.data[boolCompassData].compass_DX_f = 0;
+	global.dataSendToMaster.data[boolCompassData].compass_DY_f = 0;
+	global.dataSendToMaster.data[boolCompassData].compass_DZ_f = 0;
+	global.dataSendToMaster.data[boolCompassData].compass_uTick = HAL_GetTick();
+	global.dataSendToMaster.boolCompassData = boolCompassData;
+}
+
+
+void copyCompassDataDuringCalibration(int16_t dx, int16_t dy, int16_t dz)
+{
+	extern float compass_heading;
+	extern float compass_roll;
+	extern float compass_pitch;
+	//uint8_t dataSendToMaster.
+	uint8_t boolCompassData = !global.dataSendToMaster.boolCompassData;
+	global.dataSendToMaster.data[boolCompassData].compass_heading = compass_heading;
+	global.dataSendToMaster.data[boolCompassData].compass_roll = compass_roll;
+	global.dataSendToMaster.data[boolCompassData].compass_pitch = compass_pitch;
+	global.dataSendToMaster.data[boolCompassData].compass_DX_f = dx;
+	global.dataSendToMaster.data[boolCompassData].compass_DY_f = dy;
+	global.dataSendToMaster.data[boolCompassData].compass_DZ_f = dz;
+	global.dataSendToMaster.boolCompassData = boolCompassData;
+}
+
+
+//Supports threadsave copying!!!
+void copyBatteryData(void)
+{
+	uint8_t boolBatteryData = !global.dataSendToMaster.boolBatteryData;
+	global.dataSendToMaster.data[boolBatteryData].battery_voltage = get_voltage();
+	global.dataSendToMaster.data[boolBatteryData].battery_charge= get_charge();
+	global.dataSendToMaster.boolBatteryData = boolBatteryData;
+}
+
+
+//Supports threadsave copying!!!
+void copyAmbientLightData(void)
+{
+	uint8_t boolAmbientLightData = !global.dataSendToMaster.boolAmbientLightData;
+	global.dataSendToMaster.data[boolAmbientLightData].ambient_light_level = get_ambient_light_level();
+	global.dataSendToMaster.boolAmbientLightData = boolAmbientLightData;
+}
+
+
+//Supports threadsave copying!!!
+void copyTissueData(void)
+{
+	//uint8_t dataSendToMaster.
+	uint8_t boolTisssueData = !global.dataSendToMaster.boolTisssueData;
+	for(int i = 0; i < 16; i++)
+	{
+		global.dataSendToMaster.data[boolTisssueData].tissue_nitrogen_bar[i] = global.lifeData.tissue_nitrogen_bar[i];
+		global.dataSendToMaster.data[boolTisssueData].tissue_helium_bar[i] = global.lifeData.tissue_helium_bar[i];
+	}
+	global.dataSendToMaster.boolTisssueData = boolTisssueData;
+}
+
+
+//Supports threadsave copying!!!
+void copyVpmCrushingData(void)
+{
+	//uint8_t dataSendToMaster.
+	uint8_t boolCrushingData = !global.dataSendToMaster.boolCrushingData;
+	for(int i = 0; i < 16; i++)
+	{
+		global.dataSendToMaster.data[boolCrushingData].max_crushing_pressure_n2[i] = global.vpm.max_crushing_pressure_n2[i];
+		global.dataSendToMaster.data[boolCrushingData].max_crushing_pressure_he[i] = global.vpm.max_crushing_pressure_he[i];
+		global.dataSendToMaster.data[boolCrushingData].adjusted_critical_radius_he[i] = global.vpm.adjusted_critical_radius_he[i];
+		global.dataSendToMaster.data[boolCrushingData].adjusted_critical_radius_n2[i] = global.vpm.adjusted_critical_radius_n2[i];
+	}
+	global.dataSendToMaster.boolCrushingData = boolCrushingData;
+}
+
+
+void copyDeviceData(void)
+{
+	uint8_t boolDeviceData = !global.deviceDataSendToMaster.boolDeviceData;
+	memcpy(&global.deviceDataSendToMaster.DeviceData[boolDeviceData], &global.deviceData,sizeof(SDevice));
+	global.deviceDataSendToMaster.boolDeviceData = boolDeviceData; 
+
+	global.deviceDataSendToMaster.boolVpmRepetitiveDataValid = 0;
+	memcpy(&global.deviceDataSendToMaster.VpmRepetitiveData.adjusted_critical_radius_he, 		&global.vpm.adjusted_critical_radius_he,		sizeof(16*4));
+	memcpy(&global.deviceDataSendToMaster.VpmRepetitiveData.adjusted_critical_radius_n2, 		&global.vpm.adjusted_critical_radius_n2,		sizeof(16*4));
+	memcpy(&global.deviceDataSendToMaster.VpmRepetitiveData.adjusted_crushing_pressure_he,	&global.vpm.adjusted_crushing_pressure_he,	sizeof(16*4));
+	memcpy(&global.deviceDataSendToMaster.VpmRepetitiveData.adjusted_crushing_pressure_n2,	&global.vpm.adjusted_crushing_pressure_n2,	sizeof(16*4));
+	memcpy(&global.deviceDataSendToMaster.VpmRepetitiveData.initial_allowable_gradient_he,	&global.vpm.initial_allowable_gradient_he,	sizeof(16*4));
+	memcpy(&global.deviceDataSendToMaster.VpmRepetitiveData.initial_allowable_gradient_n2,	&global.vpm.initial_allowable_gradient_n2,	sizeof(16*4));
+	memcpy(&global.deviceDataSendToMaster.VpmRepetitiveData.max_actual_gradient, 					 	&global.vpm.max_actual_gradient,						sizeof(16*4));
+	global.deviceDataSendToMaster.VpmRepetitiveData.repetitive_variables_not_valid = global.vpm.repetitive_variables_not_valid;
+	global.deviceDataSendToMaster.boolVpmRepetitiveDataValid = 1;
+}
+
+void changeAgeWirelessData(void)
+{
+	for(int i=0;i<4;i++)
+	{
+		if(global.dataSendToMaster.data[global.dataSendToMaster.boolWirelessData].wireless_data[i].ageInMilliSeconds)
+			global.dataSendToMaster.data[global.dataSendToMaster.boolWirelessData].wireless_data[i].ageInMilliSeconds++;
+	}
+}
+
+void copyWirelessData(void)
+{
+	uint8_t boolWirelessData = !global.dataSendToMaster.boolWirelessData;
+	SDataWireless *dataOld, *dataNew;
+	for(int i=0;i<3;i++)
+	{
+		dataNew = &global.dataSendToMaster.data[boolWirelessData].wireless_data[i+1];
+		dataOld = &global.dataSendToMaster.data[!boolWirelessData].wireless_data[i];
+		dataNew->ageInMilliSeconds = dataOld->ageInMilliSeconds;
+		dataNew->numberOfBytes = dataOld->numberOfBytes;
+		dataNew->status = dataOld->status;
+		memcpy(dataNew->data, dataOld->data,8);
+	}
+	
+	global.dataSendToMaster.data[boolWirelessData].wireless_data[0].ageInMilliSeconds = 1;
+	global.dataSendToMaster.data[boolWirelessData].wireless_data[0].numberOfBytes = global.wirelessReceived;
+	global.dataSendToMaster.data[boolWirelessData].wireless_data[0].status = global.wirelessConfidenceStatus;
+	for(int i=0;i<MAX_WIRELESS_BYTES;i++)
+		global.dataSendToMaster.data[boolWirelessData].wireless_data[0].data[i] = global.wirelessdata[i];
+	for(int i=MAX_WIRELESS_BYTES;i<12;i++)
+		global.dataSendToMaster.data[boolWirelessData].wireless_data[0].data[i] = 0xFF;
+	
+	global.dataSendToMaster.boolWirelessData = boolWirelessData;
+}
+
+/* 			copyPICdata(); is used in spi.c */
+void copyPICdata(void)
+{
+	uint8_t boolPICdata = !global.dataSendToMaster.boolPICdata;
+	for(int i = 0; i < 3; i++)
+	{
+		global.dataSendToMaster.data[boolPICdata].button_setting[i] = global.ButtonPICdata[i];
+	}
+	global.dataSendToMaster.boolPICdata = boolPICdata;
+}
+
+
+
+
+typedef enum 
+{
+  SPI3_OK      = 0x00,
+  SPI3_DEINIT  = 0x01,
+} SPI3_StatusTypeDef;
+/* if spi3 is running and the SPI3_ButtonAdjust call returns OK, all is fine
+	 if the SPI3_ButtonAdjust call returns error, the spi3 is DeInit
+	 and will be init the next call of scheduleSetButtonResponsiveness()
+	 and data will be send again on the third call
+	 therefore on return 0 of scheduleSetButtonResponsiveness() the caller flag should kept active
+*/
+uint8_t scheduleSetButtonResponsiveness(void)
+{
+	static uint8_t SPI3status = SPI3_OK;
+	
+	if((SPI3status == SPI3_OK) && (SPI3_ButtonAdjust(global.ButtonResponsiveness, global.ButtonPICdata)))
+	{
+		copyPICdata();
+		return 1;
+	}
+	else
+	{
+		for(int i=0;i<3;i++)
+		{
+			global.ButtonPICdata[i] = 0xFF;
+		}
+		copyPICdata();
+		
+		if(SPI3status == SPI3_OK)
+		{
+			MX_SPI3_DeInit();
+			SPI3status = SPI3_DEINIT;
+		}
+		else
+		{
+			MX_SPI3_Init();
+			SPI3status = SPI3_OK;
+		}
+		return 0;
+	}
+}
+
+
+//save time diffenrence
+uint32_t time_elapsed_ms(uint32_t ticksstart,uint32_t ticksnow)
+{
+	if(ticksstart <= ticksnow)
+	{
+			return ticksnow - ticksstart;
+	}
+	else
+	{
+		return 0xFFFFFFFF - ticksstart + ticksnow;
+	}
+}
+
+/* same as in data_central.c */
+_Bool is_ambient_pressure_close_to_surface(SLifeData *lifeDataCall)
+{
+	if(lifeDataCall->pressure_ambient_bar < (lifeDataCall->pressure_surface_bar + 0.1f)) // hw 161121 now 1 mter, before 0.04f
+		return true;
+	else
+		return false;
+}
+
+
+/************************ (C) COPYRIGHT heinrichs weikamp *****END OF FILE****/
+