line source
/**
******************************************************************************
* @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>© 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 "tm_stm32f4_otp.h"
#include "externalInterface.h"
/* uncomment to enable restoting of last known date in case of a power loss (RTC looses timing data) */
/* #define RESTORE_LAST_KNOWN_DATE */
#define INVALID_PREASURE_VALUE (0.0f)
#define START_DIVE_MOUNTAIN_MODE_BAR (0.88f)
#define START_DIVE_IMMEDIATLY_BAR (1.16f)
/* Private types -------------------------------------------------------------*/
const SGas Air = {79,0,0,0,0};
/* Exported variables --------------------------------------------------------*/
SGlobal global;
SDevice DeviceDataFlash;
uint8_t deviceDataFlashValid = 0;
uint8_t deviceDataSubSeconds = 0;
/* Private variables ---------------------------------------------------------*/
static uint16_t ManualExitDiveCounter = 0; /* The computer will exit dive mode in shallow area immediately. Increase depth to restart dive while counter is active */
/* can be lost while in sleep */
uint8_t clearDecoNow = 0;
uint8_t setButtonsNow = 0;
/* has to be in SRAM2 */
uint8_t secondsCount = 0;
static uint8_t dospisync = SPI_SYNC_METHOD_NONE;
SScheduleCtrl Scheduler;
/* Private function prototypes -----------------------------------------------*/
_Bool vpm_crush2(void);
void scheduleUpdateDeviceData(void);
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 copyAmbientLightData(void);
void copyTissueData(void);
void copyVpmCrushingData(void);
void copyDeviceData(void);
void copyPICdata(void);
void copyExtADCdata();
static void schedule_update_timer_helper(int8_t thisSeconds);
uint32_t time_elapsed_ms(uint32_t ticksstart,uint32_t ticksnow);
void scheduleSetDate(SDeviceLine *line);
/* Exported functions --------------------------------------------------------*/
void initGlobals(void)
{
bzero(&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 = 51; /* 51 equals a percentage of 85% which was the default value before */
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 = HAL_ERROR; // 0x00 would be everything working
global.lifeData.pressure_ambient_bar = INVALID_PREASURE_VALUE;
global.lifeData.pressure_surface_bar = INVALID_PREASURE_VALUE;
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 = 0;
global.dataSendToMaster.header.checkCode[0] = 0xA1;
global.dataSendToMaster.header.checkCode[1] = SPI_RX_STATE_OFFLINE;
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 = 0;
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;
Scheduler.communicationTimeout = SPI_COM_TIMEOUT_START;
Scheduler_Request_sync_with_SPI(SPI_SYNC_METHOD_HARD);
}
void reinitGlobals(void)
{
global.dataSendToSlavePending = 0;
global.dataSendToSlaveIsValid = 0;
global.dataSendToSlaveIsNotValidCount = 0;
global.sync_error_count = 0;
global.check_sync_not_running = 0;
Scheduler.communicationTimeout = SPI_COM_TIMEOUT_START;
}
void scheduleSpecial_Evaluate_DataSendToSlave(void)
{
//TEMPORARY fix for compass calibration.
//TODO: Fix I2C timeout for complete solving problem.
if(global.mode==MODE_CALIB){
return;
}
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)
{
if(global.mode!=MODE_CALIB){
global.dataSendToMaster.confirmRequest.ub.batterygauge = 1;
battery_gas_gauge_set(global.dataSendToSlave.data.newBatteryGaugePercentageFloat);
}
}
if(global.dataSendToSlave.setEndDive)
{
ManualExitDiveCounter = 30 * 60; /* This will cause the computer to leave dive mode if in shallow area and increase the depth to enter dive mode for the next 30 minutes */
}
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;
/* Set pressure and temperature offsets */
pressure_set_offset (global.dataSendToSlave.data.offsetPressureSensor_mbar, global.dataSendToSlave.data.offsetTemperatureSensor_centiDegree);
/* for device data updates */
deviceDataFlashValid = 0;
memcpy(&DeviceDataFlash, &global.dataSendToSlave.data.DeviceData, sizeof(SDevice));
deviceDataFlashValid = 1;
#if 0
//TODO: Temporary placed here. Duration ~210 ms.
if (global.I2C_SystemStatus != HAL_OK) {
MX_I2C1_TestAndClear();
MX_I2C1_Init();
// init_pressure();
// compass_init(0, 7);
// accelerator_init();
}
#endif /* already called once a second */
}
/**
******************************************************************************
* @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 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;
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);
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;
static void schedule_update_timer_helper(int8_t thisSeconds)
{
static RTC_TimeTypeDef sTimeLast;
static RTC_DateTypeDef sDateLast;
RTC_TimeTypeDef sTimeNow;
RTC_DateTypeDef sDateNow;
uint32_t secondsPast;
HAL_RTC_GetTime(&RTCHandle, &sTimeNow, RTC_FORMAT_BCD);
HAL_RTC_GetDate(&RTCHandle, &sDateNow, RTC_FORMAT_BCD);
if(thisSeconds != 0) // otherwise just store sTimeLast, sDateLast
{
if(thisSeconds > 0) // use this value instead, good for pre-loading sTimeLast and sDateLast
{
secondsPast = thisSeconds;
} else {
// thisSeconds < 0 and not <= !
secondsPast = schedule_time_compare_helper(sTimeNow, sDateNow, sTimeLast, sDateLast);
}
if(global.seconds_since_last_dive)
{
if(secondsPast >= 777900)
{
global.seconds_since_last_dive = 0;
}
else
{
uint32_t 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;
}
/**
******************************************************************************
* @brief schedule_check_resync.
* @author heinrichs weikamp gmbh
* @version V0.0.2
* @date 18-June-2015
******************************************************************************
*/
void schedule_check_resync(void)
{
/* counter is incremented in cyclic 100ms loop and reset to 0 if the transmission complete callback is called */
if((global.check_sync_not_running >= Scheduler.communicationTimeout))
{
// global.dataSendToSlaveIsNotValidCount = 0;
global.check_sync_not_running = 0;
global.sync_error_count++;
/* Try to start communication again. If exchange is stuck during execution for some reason the TX will be aborted by the
* function error handler
*/
HAL_SPI_TransmitReceive_DMA(&hspi1,(uint8_t*) &(global.dataSendToMaster),(uint8_t*) &(global.dataSendToSlave), EXCHANGE_BUFFERSIZE);
Scheduler.communicationTimeout = SPI_COM_TIMEOUT_COMMON; /* Reduce error detection time */
Scheduler_Request_sync_with_SPI(SPI_SYNC_METHOD_HARD);
}
}
/**
******************************************************************************
* @brief scheduleDiveMode. / Dive Mode: Main Loop
* @author Peter Ryser
* @version V0.0.1
* @date 22-April-2014
******************************************************************************
*/
void scheduleDiveMode(void)
{
uint32_t ticksdiff = 0;
uint32_t lasttick = 0;
uint8_t extAdcChannel = 0;
uint8_t counterAscentRate = 0;
float lastPressure_bar = 0.0f;
global.dataSendToMaster.mode = MODE_DIVE;
global.deviceDataSendToMaster.mode = MODE_DIVE;
uint8_t counter_exit = 0;
Scheduler.counterSPIdata100msec = 0;
Scheduler.counterCompass100msec = 0;
Scheduler.counterPressure100msec = 0;
Scheduler.counterAmbientLight100msec = 0;
Scheduler.tick_execute1second = SCHEDULER_TICK_EXE1SEC;
global.deviceData.diveCycles.value_int32++;
scheduleSetDate(&global.deviceData.diveCycles);
global.lifeData.counterSecondsShallowDepth = 0;
/* Get the last stable value in case of an unstable surface history condition */
if(!is_surface_pressure_stable())
{
set_last_surface_pressure_stable();
}
global.lifeData.pressure_surface_bar = get_surface_mbar() / 1000.0f;
ManualExitDiveCounter = 0; /* reset early exit request */
Scheduler.tickstart = HAL_GetTick();
while(global.mode == MODE_DIVE)
{
lasttick = HAL_GetTick();
ticksdiff = time_elapsed_ms(Scheduler.tickstart,lasttick);
if(ticksdiff >= Scheduler.counterSPIdata100msec * 100 + 10)
{
if(SPI_Evaluate_RX_Data()!=0) /* did we receive something ? */
{
Scheduler.counterSPIdata100msec++;
}
schedule_check_resync();
extAdcChannel = externalInterface_ReadAndSwitch();
if(extAdcChannel != EXTERNAL_ADC_NO_DATA)
{
externalInterface_CalculateADCValue(extAdcChannel);
copyExtADCdata();
}
}
//Evaluate pressure at 20 ms, 120 ms, 220 ms,....
if(ticksdiff >= Scheduler.counterPressure100msec * 100 + 20)
{
global.check_sync_not_running++;
pressure_update_alternating();
scheduleUpdateDeviceData();
#ifdef DEMOMODE
if(global.demo_mode)
{
int turbo_seconds = demo_modify_temperature_and_pressure(global.lifeData.dive_time_seconds, Scheduler.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);
}
#endif
//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;
}
copyPressureData();
Scheduler.counterPressure100msec++;
}
//evaluate compass data at 50 ms, 150 ms, 250 ms,....
if(ticksdiff >= Scheduler.counterCompass100msec * 100 + 50)
{
compass_read();
acceleration_read();
compass_calc();
copyCompassData();
Scheduler.counterCompass100msec++;
}
if(ticksdiff >= Scheduler.counterAmbientLight100msec * 100 + 70)
{
adc_ambient_light_sensor_get_data();
copyAmbientLightData();
Scheduler.counterAmbientLight100msec++;
}
//Evaluate tissues, toxic data, vpm, etc. once a second
if(ticksdiff >= Scheduler.tick_execute1second)
{
Scheduler.tick_execute1second = 0xFFFFFFFF; /* execute once only in the second cycle */
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))
|| (ManualExitDiveCounter))
{
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) || (ManualExitDiveCounter))
{
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();
HAL_Delay(100);
I2C_DeInit();
HAL_Delay(100);
MX_I2C1_Init();
HAL_Delay(100);
init_pressure();
}
}
if(ticksdiff >= 1000)
{
/* reset counter */
Scheduler.tickstart = HAL_GetTick();
Scheduler.counterSPIdata100msec = 0;
Scheduler.counterCompass100msec = 0;
Scheduler.counterPressure100msec = 0;
Scheduler.counterAmbientLight100msec = 0;
Scheduler.tick_execute1second = SCHEDULER_TICK_EXE1SEC;
}
}
}
/**
******************************************************************************
* @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 ticksdiff = 0;
uint32_t lasttick = 0;
Scheduler.tickstart = HAL_GetTick();
Scheduler.counterPressure100msec = 0;
float temperature_carousel = 0.0f;
float temperature_changer = 0.1f;
while(global.mode == MODE_TEST)
{
lasttick = HAL_GetTick();
ticksdiff = time_elapsed_ms(Scheduler.tickstart,lasttick);
//Evaluate received data at 10 ms, 110 ms, 210 ms,...
if(ticksdiff >= Scheduler.counterSPIdata100msec * 100 + 10)
{
if(SPI_Evaluate_RX_Data()!=0) /* did we receive something ? */
{
Scheduler.counterSPIdata100msec++;
}
schedule_check_resync();
}
//Evaluate pressure at 20 ms, 120 ms, 220 ms,...
if(ticksdiff >= Scheduler.counterPressure100msec * 100 + 20)
{
global.check_sync_not_running++;
pressure_update_alternating();
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;
Scheduler.counterPressure100msec++;
}
if(ticksdiff >= 1000)
{
//Set back tick counter
Scheduler.tickstart = HAL_GetTick();
Scheduler.counterPressure100msec = 0;
Scheduler.counterSPIdata100msec = 0;
}
};
}
void scheduleSurfaceMode(void)
{
uint32_t ticksdiff = 0;
uint32_t lasttick = 0;
uint8_t extAdcChannel = 0;
Scheduler.tickstart = HAL_GetTick();
Scheduler.counterSPIdata100msec = 0;
Scheduler.counterCompass100msec = 0;
Scheduler.counterPressure100msec = 0;
Scheduler.counterAmbientLight100msec = 0;
Scheduler.tick_execute1second = SCHEDULER_TICK_EXE1SEC;
global.dataSendToMaster.mode = MODE_SURFACE;
global.deviceDataSendToMaster.mode = MODE_SURFACE;
while(global.mode == MODE_SURFACE)
{
lasttick = HAL_GetTick();
ticksdiff = time_elapsed_ms(Scheduler.tickstart,lasttick);
if(setButtonsNow == 1)
{
if(scheduleSetButtonResponsiveness())
setButtonsNow = 0;
}
/* Evaluate received data at 10 ms, 110 ms, 210 ms,... duration ~<1ms */
if(ticksdiff >= Scheduler.counterSPIdata100msec * 100 + 10)
{
if(SPI_Evaluate_RX_Data()!=0) /* did we receive something ? */
{
Scheduler.counterSPIdata100msec++;
}
schedule_check_resync();
extAdcChannel = externalInterface_ReadAndSwitch();
if(extAdcChannel != EXTERNAL_ADC_NO_DATA)
{
externalInterface_CalculateADCValue(extAdcChannel);
copyExtADCdata();
}
}
/* Evaluate pressure at 20 ms, 120 ms, 220 ms,... duration ~22ms] */
if(ticksdiff >= Scheduler.counterPressure100msec * 100 + 20)
{
global.check_sync_not_running++;
pressure_update_alternating();
scheduleUpdateDeviceData();
global.lifeData.ascent_rate_meter_per_min = 0;
copyPressureData();
Scheduler.counterPressure100msec++;
if (!is_ambient_pressure_close_to_surface(&global.lifeData))
global.mode = MODE_DIVE;
}
/* Evaluate compass data at 50 ms, 150 ms, 250 ms,... duration ~5ms */
if(ticksdiff >= Scheduler.counterCompass100msec * 100 + 50)
{
compass_read();
acceleration_read();
compass_calc();
copyCompassData();
Scheduler.counterCompass100msec++;
}
/* evaluate compass data at 70 ms, 170 ms, 270 ms,... duration <1ms */
if(ticksdiff >= Scheduler.counterAmbientLight100msec * 100 + 70)
{
adc_ambient_light_sensor_get_data();
copyAmbientLightData();
Scheduler.counterAmbientLight100msec++;
}
/* Evaluate tissues, toxic data, etc. once a second... duration ~1ms */
if(ticksdiff >= Scheduler.tick_execute1second)
{
Scheduler.tick_execute1second = 0xFFFFFFFF;
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;
}
if(ManualExitDiveCounter)
{
ManualExitDiveCounter--;
}
if(global.seconds_since_last_dive)
{
schedule_update_timer_helper(-1);
}
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);
/* start desaturation calculation after first valid measurement has been done */
if(global.lifeData.pressure_surface_bar != INVALID_PREASURE_VALUE)
{
global.lifeData.desaturation_time_minutes = decom_calc_desaturation_time(global.lifeData.tissue_nitrogen_bar,global.lifeData.tissue_helium_bar,global.lifeData.pressure_surface_bar);
}
else
{
global.lifeData.desaturation_time_minutes = 0;
}
battery_charger_get_status_and_contral_battery_gas_gauge(0);
battery_gas_gauge_get_data();
copyCnsAndOtuData();
copyTimeData();
copyBatteryData();
copyDeviceData();
/* check if I2C is not up an running and try to reactivate if necessary. Also do initialization if problem occured during startup */
if(global.I2C_SystemStatus != HAL_OK)
{
MX_I2C1_TestAndClear();
HAL_Delay(100);
I2C_DeInit();
HAL_Delay(100);
MX_I2C1_Init();
HAL_Delay(100);
if(global.I2C_SystemStatus == HAL_OK)
{
init_pressure();
if(is_init_pressure_done()) /* Init surface data with initial measurement */
{
init_surface_ring(0);
}
if(!battery_gas_gauge_CheckConfigOK())
{
init_battery_gas_gauge();
}
}
}
}
if(ticksdiff >= 1000)
{
//Set back tick counter
Scheduler.tickstart = HAL_GetTick();
Scheduler.counterSPIdata100msec = 0;
Scheduler.counterCompass100msec = 0;
Scheduler.counterPressure100msec = 0;
Scheduler.counterAmbientLight100msec = 0;
Scheduler.tick_execute1second = SCHEDULER_TICK_EXE1SEC;
}
}
}
inline void Scheduler_Request_sync_with_SPI(uint8_t SyncMethod)
{
if( SyncMethod < SPI_SYNC_METHOD_INVALID)
{
dospisync = SyncMethod;
}
}
void Scheduler_SyncToSPI(uint8_t TXtick)
{
uint32_t deltatick = 0;
int8_t TXcompensation;
switch(dospisync)
{
case SPI_SYNC_METHOD_HARD:
//Set back tick counter
Scheduler.tickstart = HAL_GetTick() - 4; /* consider 4ms offset for transfer */
Scheduler.counterSPIdata100msec = 0;
Scheduler.counterCompass100msec = 0;
Scheduler.counterPressure100msec = 0;
Scheduler.counterAmbientLight100msec = 0;
dospisync = SPI_SYNC_METHOD_NONE;
break;
case SPI_SYNC_METHOD_SOFT:
deltatick = time_elapsed_ms(Scheduler.tickstart,HAL_GetTick());
deltatick %= 100; /* clip to 100ms window */
if(Scheduler.tickstart - deltatick >= 0) /* adjust start time to the next 100ms window */
{
Scheduler.tickstart -= deltatick;
}
else
{
Scheduler.tickstart = 0xFFFFFFFF- (deltatick - Scheduler.tickstart);
}
dospisync = SPI_SYNC_METHOD_NONE;
break;
default: /* continous sync activity */
if(TXtick < 100) /* do not handle unexpected jump length > 100ms */
{
TXtick += 4; /* add 4ms TX time to offset of 100ms time stamp */
deltatick = time_elapsed_ms(Scheduler.tickstart,HAL_GetTick());
deltatick %= 100;
if(deltatick > 50)
{
TXcompensation = deltatick - 100; /* neg drift */
}
else
{
TXcompensation = deltatick; /* pos drift */
}
TXcompensation = TXtick - TXcompensation;
Scheduler.tickstart -= TXcompensation;
}
else
{
Scheduler_Request_sync_with_SPI(SPI_SYNC_METHOD_SOFT); /* A large shift in 100ms cycle occured => clip to 100ms in next sync call */
}
break;
}
}
/**
******************************************************************************
* @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);
}
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();
/* check if I2C is not up and running and try to reactivate if necessary. Also do initialization if problem occurred during startup */
if(global.I2C_SystemStatus != HAL_OK)
{
MX_I2C1_TestAndClear();
HAL_Delay(100);
I2C_DeInit();
HAL_Delay(100);
MX_I2C1_Init();
HAL_Delay(100);
if((global.I2C_SystemStatus == HAL_OK) && (!is_init_pressure_done()))
{
init_pressure();
}
}
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);
}
if(global.accidentRemainingSeconds)
{
if(global.accidentRemainingSeconds > 2)
global.accidentRemainingSeconds -= 2;
else
{
global.accidentRemainingSeconds = 0;
global.accidentFlag = 0;
}
}
if (((!is_ambient_pressure_close_to_surface(&global.lifeData)) && (global.lifeData.pressure_surface_bar > START_DIVE_MOUNTAIN_MODE_BAR ))
|| (global.lifeData.pressure_ambient_bar > START_DIVE_IMMEDIATLY_BAR))
{
global.mode = MODE_BOOT;
}
scheduleUpdateLifeData(2000);
}
while(global.mode == MODE_SLEEP);
/* new section for system after Standby */
scheduleUpdateLifeData(-1);
clearDecoNow = 0;
setButtonsNow = 0;
reinitGlobals();
}
/* Private functions ---------------------------------------------------------*/
/**
******************************************************************************
* @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;
uint8_t updateTissueData = 0;
if(global.lifeData.pressure_surface_bar == INVALID_PREASURE_VALUE)
{
updateTissueData = 1;
}
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(updateTissueData)
{
decom_reset_with_ambientmbar(global.lifeData.pressure_surface_bar,&global.lifeData);
}
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 scheduletranslateDate(uint32_t datetmpreg, RTC_DateTypeDef *sDate)
{
datetmpreg = (uint32_t)(datetmpreg & RTC_DR_RESERVED_MASK);
/* Fill the structure fields with the read parameters */
sDate->Year = (uint8_t)((datetmpreg & (RTC_DR_YT | RTC_DR_YU)) >> 16);
sDate->Month = (uint8_t)((datetmpreg & (RTC_DR_MT | RTC_DR_MU)) >> 8);
sDate->Date = (uint8_t)(datetmpreg & (RTC_DR_DT | RTC_DR_DU));
sDate->WeekDay = (uint8_t)((datetmpreg & (RTC_DR_WDU)) >> 13);
/* Convert the date structure parameters to Binary format */
sDate->Year = (uint8_t)RTC_Bcd2ToByte(sDate->Year);
sDate->Month = (uint8_t)RTC_Bcd2ToByte(sDate->Month);
sDate->Date = (uint8_t)RTC_Bcd2ToByte(sDate->Date);
}
void scheduleCheckDate(void)
{
uint32_t localdate;
RTC_DateTypeDef sDate;
localdate = (uint32_t)(RTCHandle.Instance->DR & RTC_DR_RESERVED_MASK);
scheduletranslateDate(localdate, &sDate);
/* RTC start in year 2000 in case of a power loss. Use the operation counter time stamp to bring at last date to a more realistic value */
if(sDate.Year < 15)
{
scheduletranslateDate(DeviceDataFlash.hoursOfOperation.date_rtc_dr, &sDate);
if(sDate.Year > 16)
{
RTC_SetDate(sDate);
}
}
}
void scheduleUpdateDeviceData(void)
{
/* first step, main CPU */
if(deviceDataFlashValid)
{
/* max values */
if(global.deviceData.hoursOfOperation.value_int32 < DeviceDataFlash.hoursOfOperation.value_int32)
{
scheduleCopyDeviceData(&global.deviceData.hoursOfOperation, &DeviceDataFlash.hoursOfOperation);
#ifdef RESTORE_LAST_KNOWN_DATE
scheduleCheckDate();
#endif
}
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);
}
/* 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++;
scheduleSetDate(&global.deviceData.hoursOfOperation);
}
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;
}
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 = global.I2C_SystemStatus;
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;
global.dataSendToMaster.data[boolPressureData].SPARE1 = is_surface_pressure_stable();
}
//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;
}
/* 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;
}
void copyExtADCdata()
{
float value;
uint8_t channel = 0;
for(channel = 0; channel < MAX_ADC_CHANNEL; channel++)
{
value = getExternalInterfaceChannel(channel);
global.dataSendToMaster.data[0].extADC_voltage[channel] = value;
}
}
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 difference
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 *lifeData)
{
_Bool retval = true;
if(lifeData->pressure_ambient_bar != INVALID_PREASURE_VALUE) /* as long as no valid data is available expect we are close to surface */
{
/* this will e.g. apply in case of a significant pressure change during last 30 minutes => use increased offset for surface detection */
if (lifeData->pressure_ambient_bar > START_DIVE_IMMEDIATLY_BAR)
{
retval = false;
}
else if(is_surface_pressure_stable()) /* this is the expected start condition */
{
if((lifeData->pressure_ambient_bar >= (lifeData->pressure_surface_bar + 0.1f))
&& (ManualExitDiveCounter == 0)) /* only if diver did not request to exit dive mode */
{
retval = false;
}
}
}
return retval;
}
/************************ (C) COPYRIGHT heinrichs weikamp *****END OF FILE****/