Started a gui menuflow
Dependencies: LCD_DISCO_F429ZI mbed TS_DISCO_F429ZI BSP_DISCO_F429ZI
Diff: Ventilation.c
- Revision:
- 2:5828e6917e75
diff -r 35eb0c8fa2c0 -r 5828e6917e75 Ventilation.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Ventilation.c Tue Jun 09 22:57:20 2020 +0000 @@ -0,0 +1,3355 @@ + +/* Includes ------------------------------------------------------------------*/ +#define EXTERN extern +#include <stdlib.h> +#include <string.h> +#include "SS.h" +#include "main.h" +#include "_SS_OnOffActioner.h" +#include "_SS_Pwm.h" +#include "Monitoring.h" +#include "Safety.h" +#include "_SS_Data_Logging.h" +#include "_SS_Record_Settings.h" +#include "_SS_I2CX_SDP600.h" +#include "_SS_I2CX_X201641.h" +#include "_SS_OptimaComm.h" +#undef EXTERN + +#define INIT_VARIABLES +#define EXTERN +#include "Ventilation.h" +#undef EXTERN +#undef INIT_VARIABLES + + +/* Internal constants --------------------------------------------------------*/ +// ******************* Min-max PI or PDF *************************************** +#define MAX_VOLTAGE_REF MAX_PI_OUTPUT // MAX_PI_OUTPUT = 1343 = 18.5micros = 93.3%, want 80% +#define MIN_VOLTAGE_REF MIN_PI_OUTPUT +#define INTEGRAL_MAX (2147483647) +#define INTEGRAL_MIN (-2147483648) + + +#ifndef C_M3_DEVICETEST_TARGET + /* Internal variables --------------------------------------------------------*/ + // ******************* MANAGED CONSTANT SPEED **************************** + static u16 uiBlowerSpeedSetting; + static int32_t lIntegral_Speed_I; + static bool bMaxPIOutputSpeedI; + static bool bMinPIOutputSpeedI; + + + // ************* MANAGED BAROMETRIC VENTILATION ************************* + static u16 uiIpapSettingTemp; + static u16 uiTeBaroSet; + static int32_t lIntegral_Pressure_I; + static bool bMaxPIOutputPressureI; + static bool bMinPIOutputPressureI; + static u16 uiTiD; + static u8 ucIndexTableSlope; + #define TEMPO_TRIGGER_EXPI 30 + static u8 ucTempoTriggerExpiAuto; + #define MIN_THRESHOLD_EXPI_TRIGGER_AUTO 25 + static u8 ucExpiTriggerTreshold; + static u8 fFirstCycleInspi; + + // ----------- Main blower management during expiration ------------------- + static u16 uiPWMatTheEndOfInspiration; + static bool fFirstCycleExpi; + static u16 uiEpapSettingTemp; + static int32_t lIntegral_Pressure_E; + static bool bMaxPIOutputPressureE; + static bool bMinPIOutputPressureE; + static u16 uiPWMatTheEndOfExpiration; + static u16 uiTeD; + static bool fBlockCloseLoop; + + static u16 uiTiTyp; + + // ************* MANAGED VOLUMETRIC VENTILATION ************************* + static u32 ulMaxIFlowSet; + static u32 ulMinIFlowSet; + static u32 ulDecFlowStep; + static u16 uiTeVoluSet; + static u16 uiProximalPressureAtTheEndOfInspiration; + static int32_t lIntegral_Flow_I; + static bool bMaxPIOutputFlowI; + static bool bMinPIOutputFlowI; + static int16_t iVtAdjust=0; + static u8 ucCounterHPAlarm=0; + + + // ******************* MANAGED_CPAP_VENTILATION ****************************** + #define EXPIRATORY_DISCONNECTION_TIME_OUT 500 // 500ms + #define CPAP_DISCONNECTION_TEST_PERIODICITY 4000 // 4s + static u16 uiDisconnectionTime; + static u16 uiDisconnectionTimeInCPAP; + static u16 uiMemoPWMDuringDisconnection; + //static u8 ucStandByMode; + + // ***************** MANAGED INSPIRATORY TRIGGER ***************************** + #define MAX_DELTA_FLOW 100 // 1 l/min + #define SIZE_DELTA_INSPIRATORY_FLOW_BUFFER 40 + #define NUMBER_TRIGGER_VALID 20 + #define NUMBER_MIN_FLOW_VALUE 30 + //static int16_t iBufferIFlowDelta[SIZE_DELTA_INSPIRATORY_FLOW_BUFFER]; + static u8 ucInspiTriggerScheduler; + static u8 ucMinFlowCounter; + static int16_t iInspiratoryFlowMin; + //static int16_t iOldInspiratoryFlowSmoothingMesForTrigger; + #define SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER 250 + static int16_t iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER]; + // static int16_t iBufferConductance[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER]; + static u8 ucCounterTriggerValid; + static int16_t iFlowBaseLineReference; + static bool bDetectionConstantFlow; + + + // *********************** MANAGED MONITORING FOR MLT ************************ + static u16 uiMLT_PressureSetPoint; + #ifdef MOTOR_LIFE_TESTING + #define MLT_AVERAGE_MONITORING 1000 + static u16 uiAverageMonitoringMLT; + static u32 ulMLT_SumSpeedMes; + static u32 ulMLT_SumCurrentMes; + static u32 ulMLT_SumTemperatureMes; + static u32 ulMLT_SumBlowerVoltage; + static u16 uiMLT_EnableAlarm; + #endif // #ifdef MOTOR_LIFE_TESTING + + + // ************************ MANAGED CALIBRATION ****************************** + typedef enum + { + INIT_FLOW_CALIB_TEST=0, + SET_GAS_TYPE, + SET_GAS_STANDARD, + START_FLOW_READING, + SEND_FLOW_COMMAND, + READ_FLOW_VALUE, + SEND_HIGH_FLOW_CALIB_REQUEST, + WAIT_FOR_HIGH_FLOW_CALIB_ACK, + PREPARE_FAILURE_COMMAND, + PREPARE_SUCCESS_COMMAND, + SEND_COMMAND_TO_PF300, + CHECK_COMMAND_FROM_PF300, + END_OF_CALIBRATION, + } type_enLowFlowCalibrationStep; + + typedef enum + { + INIT_PRESSURE_CALIB_TEST=0, + START_PRESSURE_READING, + SEND_PRESSURE_COMMAND, + READ_PRESSURE_VALUE, + PRESSURE_CALIB_FAILURE_COMMAND, + PRESSURE_CALIB_SUCCESS_COMMAND, + PRESSURE_CALIB_SEND_COMMAND_TO_PF300, + PRESSURE_CALIB_CHECK_COMMAND_FROM_PF300, + PRESSURE_CALIB_END_OF_CALIBRATION, + } type_enPressureCalibrationStep; + + #define SIZE_BUFFER_FLOW_VALUE 15 + typedef struct + { + unsigned char ucIndex; + bool bFirstPartOfTheCRReceived; + char szValue[SIZE_BUFFER_FLOW_VALUE]; + } type_stFlow; + + // Flow and pressure calibration + #define TIME_OUT_RECEPTION_PACKET_FROM_PF300 2000 // 2s + #define SAMPLE_RATE_BETWEEN_TWO_FLOW 5000 // 5s + #define SIZE_RX_BUFFER_PF300 20 + static u16 uiCalibrationTimeOut; + static unsigned char ucIndexAnswerFromPF300; + static char szAnswerFromPF300[SIZE_RX_BUFFER_PF300]; + static char szExpectedAnswerFromPF300[SIZE_RX_BUFFER_PF300]; + static u8 ucNumberOfBytesToCheckFromPF300Answer; + + // Flow calibration + static type_enLowFlowCalibrationStep enLowFlowCalibrationStep; + static type_enLowFlowCalibrationStep enGoBackToStep; + static unsigned long ulSumFlowTicks; + static unsigned int uiFlowTicksSamplesCounter; + //static type_stLUTFlowSensor stTemporayLUTFlowSensor; + static bool bHighFlowCalibrationInProgress; + static unsigned int uiMotorDutyCyleForFlowCalib; + static unsigned int uiImHereMsgTimer; + + // Pressure calibration + #define SAMPLE_RATE_BETWEEN_TWO_PRESSURE 10000 // 30s + static type_enPressureCalibrationStep enPressureCalibrationStep; + static type_enPressureCalibrationStep enPressureCalibGoBackToStep; + static u32 ulSumPressureTicks; + static u16 uiPressureTicksSamplesCounter; + + // List of command to PF300 + static const char szPF300_CmdSwitchOffEcho[]={"%CM#5$0\r"}; // Command Echo from PF300 off + static const char szPF300_AnswerSwitchOffEcho[]={"%CM#5"}; // Answer echo off from PF300 (WO \r) + static const char szPF300_SetAirGasType[]={"%WS#1$0\r"}; // command Air + static const char szPF300_AnswerAirGasType[]={"%WS#1$0"}; // Answer Air + static const char szPF300_SetGasStandard[]={"%WS#3$1\r"}; // Command STPD + static const char szPF300_AnswerGasStandard[]={"%WS#3$1"}; // Answer STPD + static const char szPF300_ReadLowFlowCmd[]={"%RM#1\r"}; // Command read low flow + static const char szPF300_ReadLowFlowAnswer[]={"%RM#1$"}; // Answer read low flow + static const char szPF300_ReadHighFlowCmd[]={"%RM#0\r"}; // Command read high flow + static const char szPF300_ReadHighFlowAnswer[]={"%RM#0$"}; // Answer read high flow + static const char szPF300_ReadPdiffCmd[]={"%RM#3\r"}; // Command read pressure diff. + static const char szPF300_ReadPdiffAnswer[]={"%RM#3$"}; // Answewr read pressure diff. + + // List of Command to Handset + static const char szRequestHighFlowCalib[]={"@N"}; + static const char szEndOfCalibOK[]={"@S"}; + static const char szImHere[]={"@*"}; + + + // ---------------- Management FRAM for settings ----------------------------- + #ifdef RECORD_SETTINGS + #endif // RECORD_SETTINGS + + // -------------------- Manage Motor starting -------------------------------- + #ifndef TEMPERATURE_TRENDS + static u8 ucStartVentilationScheduler=0; + #endif + static enMaroubraModes enPreviousMode; + static u16 uiPreviousDeviceMode; +#endif // C_M3_DEVICETEST_TARGET + + +#ifndef C_M3_DEVICETEST_TARGET + #define SIZE_SLOPE2_TABLE 21 + const unsigned char ucSlope2Table[SIZE_SLOPE2_TABLE]= { + 0, 35, 50, 59, 65, 70, 74, 77, 80, 83, + 85, 87, 89, 91, 92, 94, 95, 96, 98, 99, + 100 }; + + // Table pente inspiratoire 2 + #define SIZE_SLOPE3_TABLE 41 + const unsigned char ucSlope3Table[SIZE_SLOPE3_TABLE]= { + 0, 20, 35, 44, 50, 55, 59, 62, 65, 68, 70, + 72, 74, 76, 77, 79, 80, 81, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 91, 92, 93, 94, 94, 95, + 96, 96, 97, 98, 98, 99, 99, 100 }; + + // Table pente inspiratoire 3 + #define SIZE_SLOPE4_TABLE 61 + const unsigned char ucSlope4Table[SIZE_SLOPE4_TABLE]= { + 0, 11, 26, 35, 41, 46, 50, 53, 56, 59, 61, + 63, 65, 67, 68, 70, 71, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 83, 84, 85, 86, 86, + 87, 88, 88, 89 ,90, 90, 91, 91, 92, 92, 93, + 93, 94, 94, 95, 95, 96, 96, 96, 97, 97, 98, + 98, 99, 99, 99, 100, 100 }; + + + // Maximum allowed flow in expiration Flow=f(PEEP set) (example: flow-by max=29L/min @ 5hPa) + const u16 uiMaximumFlowInExpiration[41]={ + 0, 1300, 1830, 2250, 2600, 2900, 3180, 3430, 3670, 3900, + 4110, 4310, 4500, 4680, 4860, 5030, 5200, 5360, 5510, 5660, + 5810, 5950, 6090, 6230, 6360, 6500, 6620, 6750, 6870, 7000, + 7120, 7230, 7350, 7460, 7580, 7690, 7800, 7900, 8010, 8110, 8220 + }; +#endif // C_M3_DEVICETEST_TARGET + + +/* Internal functions --------------------------------------------------------*/ +#ifndef C_M3_DEVICETEST_TARGET + u16 ComputeTe(u16 uiF, u16 uiTi); + void ComputeInspiratoryFlowSetPointInAVC(u16 uiTypeOfPatient, u16 uiVtc, u16 uiTi, u16 uiFlowShape, u32 *ulMaxFlow, u32 *ulMinFlow, u32 *ulFlowStep); + unsigned char TestTriggerExpiratoire(unsigned char ucValeurSeuil, unsigned int uiPressureSetting); + bool TestInspiratoryTrigger(bool bSpont, u16 uiTe, u16 uiFlowThreshold); + int16_t UpdateInspiratoryFlowAverage(void); + int16_t UpdateInspiratoryConductanceAverage(void); + void ResetInspiratoryConductanceAverage(void); + bool TestInspiratorySlowTrigger(int16_t iTheFlowBaseLine, u16 uiFlowTreshold); + void ApplyDefaultValueToTemporaryVentilationSettings(void); + void ApplyDefaultValueToTechnicalSettings(void); + void ApplyAllDefaultValues(void); + bool ApplyNewVentilationMode(void); + void ApplyDefaultFlowLUT(void); + void CheckFlowLUTRange(void); + void ManageFlowCalibration(void); + void ManagePressureCalibration(void); + void ManageCstPressure(void); +#endif // C_M3_DEVICETEST_TARGET + + + +#ifndef C_M3_DEVICETEST_TARGET +/******************************************************************************* +* Function Name : InitSettings +* Description : Initialize parameters for ventilation +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void InitSettings(void) +{ + uiPreviousDeviceMode=0xFF; + enPreviousMode=NUMBER_OF_MODE; + + // --- Init Settings + uiTechnicalDataMes[SW_VERSION_TEC_MES]=MAROUBRA_BLOWER_SW_VERSION; + bComputeOffsetSensors=FALSE; + + #ifdef RECORD_SETTINGS + // Read and init FRAM + if (InitSettingsZoneAndTechnicalZoneInFRAM()==OPSTATUS_OK) + { + if (ReadSettingsZoneAndTechnicalZoneInFRAM()==OPSTATUS_FAIL) + { + uiFlagsAlarm[ALARM_FLAGS2]|=FRAM_FAILURE_ALARM_MASK; + ApplyAllDefaultValues(); + } + } + else + { + uiFlagsAlarm[ALARM_FLAGS2]|=FRAM_FAILURE_ALARM_MASK; + ApplyAllDefaultValues(); + } + #else + ApplyAllDefaultValues(); + #endif + + // Compute offsets sensors if necessary + if (bComputeOffsetSensors==TRUE) + { + // ------ Update Blower Flow sensor offset before ventilation ------- + #ifdef SDP600_USED_I2C1_BUS + SDP600_ComputeOffsetFlowSensorOnI2C1(SDP600_BLOWER_FLOW_SENSOR); + #endif // SDP600_USED_I2C1_BUS + + #ifdef X201641_USED_I2C1_BUS + X201641_ComputeOffsetFlowSensorOnI2C1(X201641_BLOWER_FLOW_SENSOR); + #endif // X201641_USED_I2C1_BUS + + // ----- Update Proximal Pressure sensor offset before ventilation ------- + ComputeOffsetProximalPressureSensor(); + } + + // Check Technical settings range + CheckTechnicalSettingsRange(); + + // Check Flow LUT + CheckFlowLUTRange(); + + // Check temporary ventilation setting range + if (CheckTemporaryVentilationSettingRange()==OPSTATUS_FAIL) + { + ApplyDefaultValueToTemporaryVentilationSettings(); + uiFlagsAlarm[ALARM_FLAGS2]|=VENTILATION_SETTINGS_RANGE_ALARM_MASK; + } + + // --- Update computed settings (Te,...) + UpdateSettings(); + + #ifdef MOTOR_LIFE_TESTING + uiTechnicalDataSet[DEVICE_MODE_TEC]=PRESSURE_CST_MODE; + uiTechnicalDataSet[START_STOP_VENTILATION]=1; + #endif +} + + +/******************************************************************************* +* Function Name : InitVentilation +* Description : Initialize variables for ventilation +* Function called : +* - when we start ventilation +* - when we change of ventilation mode +* - when we change of device mode +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void InitVentilation(void) +{ + ucVentilationCycle=EXPIRATION_CYCLE; + uiTiD=0; + uiTeD=0; + uiTiTyp = 1000; + bManualBreath=FALSE; + + if (enPreviousMode==NUMBER_OF_MODE) + { + // Start ventilation + uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT; + uiDisconnectionTimeInCPAP=CPAP_DISCONNECTION_TEST_PERIODICITY; + uiMemoPWMDuringDisconnection=0; + fBlockCloseLoop=FALSE; + } + + ClearAllVentilationAlarms(); + ClearAllMeasures(); + + switch(uiTechnicalDataSet[DEVICE_MODE_TEC]) + { + default: + case VENTILATION_MODE: + { + if (enVentilationMode==APCV_MODE || enVentilationMode==PS_MODE) + { + if (enPreviousMode==APCV_MODE || enPreviousMode==PS_MODE) + { + // --- We are already in pressure mode + } + else + { + // --- Start a pressure mode + fFirstCycleInspi=TRUE; + uiPWMatTheEndOfInspiration=MIN_VOLTAGE_REF; + + if (enPreviousMode!=AVC_MODE) + { + uiPWMatTheEndOfExpiration=MIN_VOLTAGE_REF; + lIntegral_Pressure_E=0; + bMaxPIOutputPressureE=FALSE; + bMinPIOutputPressureE=FALSE; + fFirstCycleExpi=TRUE; + } + } + } + else if (enVentilationMode==AVC_MODE) + { + iVtAdjust=0; + fFirstCycleInspi=TRUE; + uiPWMatTheEndOfInspiration=MIN_VOLTAGE_REF; + + if (enPreviousMode!=APCV_MODE && enPreviousMode!=PS_MODE) + { + uiPWMatTheEndOfExpiration=MIN_VOLTAGE_REF; + lIntegral_Pressure_E=0; + bMaxPIOutputPressureE=FALSE; + bMinPIOutputPressureE=FALSE; + fFirstCycleExpi=TRUE; + } + } + else if (enVentilationMode==CPAP_MODE) + { + Ki_Pressure_I=1000; + uiPWMatTheEndOfInspiration=MIN_VOLTAGE_REF; + lIntegral_Pressure_I=0; + bMaxPIOutputPressureI=FALSE; + bMinPIOutputPressureI=FALSE; + } + break; + } + case ONE_CST_PWM_MODE: + { + uiInspirationBlowerPWMTec=250; + break; + } + case TWO_CST_PWM_MODE: + { + uiInspirationBlowerPWMTec=350; + uiExpirationBlowerPWMTec=150; + break; + } + case CST_SPEED_MODE: + { + uiBlowerSpeedSet=15000; + uiBlowerSpeedSetting=5000; + break; + } + case FLOW_CAL_MODE: + { + enLowFlowCalibrationStep=INIT_FLOW_CALIB_TEST; + bHighFlowCalibrationInProgress=FALSE; + stTemporayLUTFlowSensor.uiLUT_TableSize=0; + uiCalibrationTimeOut=(TIME_OUT_BLOWER_HANDSET_COMM*20); // 2s + break; + } + case PRESSURE_CAL_MODE: + { + enPressureCalibrationStep=INIT_PRESSURE_CALIB_TEST; + uiCalibrationTimeOut=(TIME_OUT_BLOWER_HANDSET_COMM*20); // 2s + break; + } + case PRESSURE_CST_MODE: + { + uiMLT_PressureSetPoint=10; + lIntegral_Pressure_I=0; + bMaxPIOutputPressureI=FALSE; + bMinPIOutputPressureI=FALSE; + + #ifdef MOTOR_LIFE_TESTING + uiMLT_EnableAlarm=5000; // 5s before enabling alarm + uiAverageMonitoringMLT=MLT_AVERAGE_MONITORING; + ulMLT_SumSpeedMes=0; + ulMLT_SumCurrentMes=0; + ulMLT_SumTemperatureMes=0; + ulMLT_SumBlowerVoltage=0; + #endif // #ifdef MOTOR_LIFE_TESTING + break; + } + } + enPreviousMode=enVentilationMode; +} + + +/******************************************************************************* +* Function Name : StopAllActuators +* Description : Stop all actuators +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void StopAllActuators(void) +{ + // Stop main blower + SS_Xclose(mdrv); + + // Valve OFF + SS_Xputdw(act, EV_CTL|FLAG_ACTIONER_OFF); +} + +/******************************************************************************* +* Function Name : CalculateHoseDrop +* Description : Manage Ti, Te, DAC, Blower, PID +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +u16 CalculateHoseDrop(void) +{ + u16 hoseDrop = (u16)(10*(iBlowerFlowSmoothingMes/100.0f/60.0f * 0.5f)); + return hoseDrop; +} + +/******************************************************************************* +* Function Name : ManageCPAPVentilation +* Description : Manage Ti, Te, DAC, Blower, PID +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void ManageCPAPVentilation(void) +{ + + + + // *************************** UPDATE SETTINGS ******************************* + if (ApplyNewVentilationMode()==TRUE) + return; + + // **************************** Cycle detection ****************************** + // Test Synchronisation + /*if (iBlowerFlowSmoothingMesForTrigger<(-500) && ucVentilationCycle==INSPIRATION_CYCLE) + ucVentilationCycle=EXPIRATION_CYCLE; */ + int32_t peakP = 2;//(int32_t)uiVentilationSet[PS_CPAP_SET]; + // Cycle detection + if (ucVentilationCycle==INSPIRATION_CYCLE) + { + uiTiD++; + if(uiTiD < (0.1f * uiTiTyp)) + { + peakP =(int32_t)( uiVentilationSet[PS_CPAP_SET] * ((uiTiD* 1.0f)/(0.1f * uiTiTyp))); + } + else if(uiTiD < (1.0f * uiTiTyp)) + { + peakP = ((int32_t)uiVentilationSet[PS_CPAP_SET] - ((int32_t)(uiVentilationSet[PS_CPAP_SET] * (uiTiD * 1.0f)/(1.1f * uiTiTyp)))) + 20; + } + else + { + peakP = 2; + } + + if (uiTiD>5000 || (uiTiD>TiBaroSet_P_MIN && TestTriggerExpiratoire(20, uiVentilationSet[PS_CPAP_SET])==TRUE)) + { + ucVentilationCycle=EXPIRATION_CYCLE; + uiPWMatTheEndOfInspiration = uiInspirationBlowerPWMTec; + if(uiTiD < 2000) + { + uiTiTyp = uiTiD; + } + else + { + uiTiTyp = 2000; + } + + uiTeD=0; + } + } + else + { + uiTeD++; + if (uiTeD>TE_SET_MAX) uiTeD=TE_SET_MAX; + + if (TestInspiratoryTrigger(TRUE, uiTeD, 15)==TRUE) + { + ucVentilationCycle=INSPIRATION_CYCLE; + uiTiD=0; + } + } + + // Barometric Mode : error computation + ControlPressure((int32_t)(peakP + CalculateHoseDrop())); +} + +/******************************************************************************* +* Function Name : ControlPressure +* Description : Manage Ti, Te, DAC, Blower, PID +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +int32_t previousError = 0; +int32_t lIntegralSum = 0; +void ControlPressure(int32_t setPressure)//pressure in cmH2O*10 +{ + int32_t lPropTerm; + int32_t lIntegralTerm; + int32_t lDerivativeTerm; + int32_t lOutputPressure; + + + int32_t lError = setPressure - uiProximalPressureMes; + + lPropTerm = (int32_t)uiTechnicalDataSet[KP_CPAP_VENTED_PRESSURE_I] * lError; + lIntegralTerm += (int32_t)(uiTechnicalDataSet[KI_CPAP_VENTED_PRESSURE_I] * lError); + lDerivativeTerm = (int32_t)(uiTechnicalDataSet[KP_FLOW_I]*(lError - previousError/1000)); + previousError = lError; + + // Close loop in pressure + if ((lIntegralTerm + lIntegralSum) > INTEGRAL_MAX) + { + lIntegralSum = INTEGRAL_MAX; + } + else if ((lIntegralTerm - lIntegralSum)< INTEGRAL_MIN) + { + lIntegralSum = INTEGRAL_MIN; + } + else + { + lIntegralSum += lIntegralTerm; + } + + lOutputPressure = (lDerivativeTerm>>19) + (lIntegralSum>>16) + (lPropTerm>>13) ; + + lOutputPressure+=uiPWMatTheEndOfInspiration; + + + // Limit and Update blower PWM + if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF)) + { + bMaxPIOutputPressureI = TRUE; + uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF; + } + else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF)) + { + bMinPIOutputPressureI = TRUE; + uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF; + } + else + { + bMaxPIOutputPressureI = FALSE; + bMinPIOutputPressureI = FALSE; + uiInspirationBlowerPWMTec = lOutputPressure; + } + + SS_Xputdw(mdrv, uiInspirationBlowerPWMTec); + +} + + +/******************************************************************************* +* Function Name : DavidCControlPressure +* Description : Manage Ti, Te, DAC, Blower, PID +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void DavidCControlPressure(int32_t setPressure)//pressure in cmH2O*10 +{ + int32_t lPropTerm; + int32_t lIntegralTerm; + int32_t lOutputPressure; + u16 uiFlowMaxInExpi; + int32_t lError = setPressure - uiProximalPressureMes; + + lIntegralTerm = (int32_t)Ki_Pressure_I * lError; + if (Ki_Pressure_I<uiTechnicalDataSet[KI_CPAP_VENTED_PRESSURE_I]) + { + Ki_Pressure_I++; + } + + // Close loop in pressure + if ((lIntegral_Pressure_I>=0) && (lIntegralTerm>=0) && (bMaxPIOutputPressureI==FALSE)) + { + if ((lIntegral_Pressure_I + lIntegralTerm) <0) + lIntegral_Pressure_I = INTEGRAL_MAX; + else + lIntegral_Pressure_I += lIntegralTerm; + } + else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm<=0) && (bMinPIOutputPressureI==FALSE)) + { + if ((lIntegral_Pressure_I + lIntegralTerm)>0) + lIntegral_Pressure_I = INTEGRAL_MIN; + else + lIntegral_Pressure_I += lIntegralTerm; + } + else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm>=0)) + lIntegral_Pressure_I += lIntegralTerm; + else if ((lIntegral_Pressure_I>=0) && (lIntegralTerm<=0)) + lIntegral_Pressure_I += lIntegralTerm; + + lPropTerm = (int32_t)uiTechnicalDataSet[KP_CPAP_VENTED_PRESSURE_I] * lError; + + lOutputPressure = (lIntegral_Pressure_I>>16) + (lPropTerm>>13); + + lOutputPressure+=uiPWMatTheEndOfInspiration; + + // Flow limiting + uiFlowMaxInExpi=uiMaximumFlowInExpiration[uiVentilationSet[PS_CPAP_SET]/10]; + if (lError>5 && iBlowerFlowSmoothingMes>(int16_t)uiFlowMaxInExpi) + { + // Impossible to maintain the peep (patient disconnection) + if (uiDisconnectionTime==0) + { + if (fBlockCloseLoop==FALSE) + uiDisconnectionTimeInCPAP=CPAP_DISCONNECTION_TEST_PERIODICITY; + fBlockCloseLoop=TRUE; // Block the close loop + if (uiMemoPWMDuringDisconnection!=0) // Apply a fixed PWM value + uiInspirationBlowerPWMTec=uiMemoPWMDuringDisconnection; + else + uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF; + } + else + uiDisconnectionTime--; + } + else if (iBlowerFlowSmoothingMes<(int16_t)uiFlowMaxInExpi && (lError>(-2) && lError<2)) + { + // Good pressure : no disconnection + uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT; + + if (fBlockCloseLoop==TRUE) + { + // The close loop was block before => unblock it + fBlockCloseLoop=FALSE; + lIntegral_Pressure_I=0; + bMaxPIOutputPressureI = FALSE; + bMinPIOutputPressureI = FALSE; + uiPWMatTheEndOfInspiration=uiInspirationBlowerPWMTec; + return; + } + else if (iBlowerFlowSmoothingMes>=0) + { + // Record current PWM + uiMemoPWMDuringDisconnection=uiInspirationBlowerPWMTec; + } + } + + // Unblock the close loop every 4s in case of none recorded PWM value + if (fBlockCloseLoop==TRUE && uiMemoPWMDuringDisconnection==0 && uiDisconnectionTimeInCPAP==0) + { + uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT; + fBlockCloseLoop=FALSE; + lIntegral_Pressure_I=0; + bMaxPIOutputPressureI = FALSE; + bMinPIOutputPressureI = FALSE; + uiPWMatTheEndOfInspiration=uiInspirationBlowerPWMTec; + return; + } + + // Update Time counters + if (uiDisconnectionTimeInCPAP!=0) + uiDisconnectionTimeInCPAP--; + + // Update blower PWM + if (fBlockCloseLoop==TRUE) + { + bMaxPIOutputPressureI = TRUE; + } + else if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF)) + { + bMaxPIOutputPressureI = TRUE; + uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF; + } + else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF)) + { + bMinPIOutputPressureI = TRUE; + uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF; + } + else + { + bMaxPIOutputPressureI = FALSE; + bMinPIOutputPressureI = FALSE; + uiInspirationBlowerPWMTec = lOutputPressure; + } + + SS_Xputdw(mdrv, uiInspirationBlowerPWMTec); + +} + +/******************************************************************************* +* Function Name : ManageOneCstPWM +* Description : Manage Ti, Te, DAC, Blower, PID +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void ManageOneCstPWM(void) +{ + // *************************** UPDATE SETTINGS ******************************* + if (ApplyNewVentilationMode()==TRUE) + return; + + // Update Blower Speed + SS_Xputdw(mdrv, uiInspirationBlowerPWMTec); +} + + +/******************************************************************************* +* Function Name : Manage2CstPWM +* Description : Manage Ti, Te, DAC, Blower, PID +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void Manage2CstPWM(void) +{ + if (ucVentilationCycle==INSPIRATION_CYCLE) + { + // ------------- INSPIRATION ------------ + SS_Xputdw(mdrv, uiInspirationBlowerPWMTec); + + // Inspiratoy time + uiTiD++; + if (uiTiD>=uiVentilationSet[TI_BARO_SET]) + { + ucVentilationCycle=EXPIRATION_CYCLE; + uiTiD=0; + } + } + else + { + // ------------- EXPIRATION ------------ + // *************************** UPDATE SETTINGS ******************************* + if (ApplyNewVentilationMode()==TRUE) + return; + + SS_Xputdw(mdrv, uiExpirationBlowerPWMTec); + + // Expiratoy time + uiTeD++; + if (uiTeD>=uiTeBaroSet) + { + ucVentilationCycle=INSPIRATION_CYCLE; + uiTeD=0; + } + } +} + + +/******************************************************************************* +* Function Name : ManageCstSpeed +* Description : Manage constant speed ventilation +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void ManageCstSpeed(void) +{ + int32_t lError; + int32_t lPropTerm; + int32_t lIntegralTerm; + int32_t lOutputSpeed; + + // *************************** UPDATE SETTINGS ******************************* + if (ApplyNewVentilationMode()==TRUE) + return; + + // Update settings + if (uiBlowerSpeedSetting<uiBlowerSpeedSet) + uiBlowerSpeedSetting+=10; + else if (uiBlowerSpeedSetting>uiBlowerSpeedSet) + uiBlowerSpeedSetting-=10; + + uiTiD++; + if ((uiTiD%10)==0) + { + // Barometric Mode : error computation + lError=(int32_t)uiBlowerSpeedSetting-(int32_t)uiBlowerSpeedMes; + lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_SPEED_I_TEC] * lError; + + // Close loop in pressure + if ((lIntegral_Speed_I>=0) && (lIntegralTerm>=0) && (bMaxPIOutputSpeedI==FALSE)) + { + if ((lIntegral_Speed_I + lIntegralTerm) <0) + lIntegral_Speed_I = INTEGRAL_MAX; + else + lIntegral_Speed_I += lIntegralTerm; + } + else if ((lIntegral_Speed_I<=0) && (lIntegralTerm<=0) && (bMinPIOutputSpeedI==FALSE)) + { + if ((lIntegral_Speed_I + lIntegralTerm)>0) + lIntegral_Speed_I = INTEGRAL_MIN; + else + lIntegral_Speed_I += lIntegralTerm; + } + else if ((lIntegral_Speed_I<=0) && (lIntegralTerm>=0)) + lIntegral_Speed_I += lIntegralTerm; + else if ((lIntegral_Speed_I>=0) && (lIntegralTerm<=0)) + lIntegral_Speed_I += lIntegralTerm; + + lPropTerm = (int32_t)uiTechnicalDataSet[KP_SPEED_I_TEC] * lError; + lOutputSpeed = (lIntegral_Speed_I>>16) + (lPropTerm>>13); + + if (lOutputSpeed>=((int32_t)MAX_VOLTAGE_REF)) + { + bMaxPIOutputSpeedI = TRUE; + uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF; + } + else if (lOutputSpeed<((int32_t)MIN_VOLTAGE_REF)) + { + bMinPIOutputSpeedI = TRUE; + uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF; + } + else + { + bMaxPIOutputSpeedI = FALSE; + bMinPIOutputSpeedI = FALSE; + uiInspirationBlowerPWMTec = lOutputSpeed; + } + SS_Xputdw(mdrv, uiInspirationBlowerPWMTec); + } +} + +/******************************************************************************* +* Function Name : ManageFlowCalibration +* Description : Manage Low flow calibration +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void ManageFlowCalibration(void) +{ + char cCharValue; + char szTempBuf[SIZE_RX_BUFFER_PF300]; + + /* + #ifdef USE_TSI_4040 + switch(enTSICommScheduler) + { + default: + case TSI_SET_TYPE_OF_GAS: + { + // Send Type of Gas command + ucTSICommand=TSI_SEND_GAS_TYPE_AIR_CMD; + if (SS_Xputdw(tsi, &ucTSICommand)==TRUE) + { + enTSICommScheduler=TSI_CHECK_ANSWER; + enTSIGoBackToStep=TSI_SET_FLOW_UNIT; + } + break; + } + case TSI_SET_FLOW_UNIT: + { + // Send Type of Gas command + ucTSICommand=TSI_SEND_FLOW_UNIT_STANDARD_CMD; + if (SS_Xputdw(tsi, &ucTSICommand)==TRUE) + { + enTSICommScheduler=TSI_CHECK_ANSWER; + enTSIGoBackToStep=TSI_SET_SAMPLE_TIME; + } + break; + } + case TSI_SET_SAMPLE_TIME: + { + // Send sample time + ucTSICommand=TSI_SEND_SAMPLE_TIME_10MS_CMD; + if (SS_Xputdw(tsi, &ucTSICommand)==TRUE) + { + enTSICommScheduler=TSI_CHECK_ANSWER; + enTSIGoBackToStep=TSI_READ_FLOW; + } + break; + } + case TSI_READ_FLOW: + { + // Send sample time + ucTSICommand=TSI_SEND_READ_FLOW_CMD; + if (SS_Xputdw(tsi, &ucTSICommand)==TRUE) + { + enTSICommScheduler=TSI_CHECK_ANSWER; + enTSIGoBackToStep=TSI_CYCLE_DETECTION; + } + break; + } + case TSI_CYCLE_DETECTION: + { + uiBlowerFlow=iFlowFromTSI; + break; + } + case TSI_CHECK_ANSWER: + { + opstatus=SS_Xgetw(tsi, &uiDummy); + if (opstatus==OPSTATUS_OK) + { + enTSICommScheduler=enTSIGoBackToStep; + } + else if (opstatus==OPSTATUS_FAIL) + { + enTSICommScheduler=TSI_SET_TYPE_OF_GAS; + } + break; + } + } + #endif // #ifdef USE_TSI_4040 + */ + + switch(enLowFlowCalibrationStep) + { + case INIT_FLOW_CALIB_TEST: + { + // Init comm with PF300 => wait 2s before sending first command to PF300 + // We need to wait for this delay in order to the handset to activate its transparent mode + if (uiCalibrationTimeOut==0) + { + bDisableMaroubraCommCommunication=TRUE; + + // Prepare command to PF300 + UpdateBufferToSend((char*)szPF300_CmdSwitchOffEcho); + enLowFlowCalibrationStep=SEND_COMMAND_TO_PF300; + strcpy(szExpectedAnswerFromPF300, szPF300_AnswerSwitchOffEcho); + ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_AnswerSwitchOffEcho); + enGoBackToStep=SET_GAS_TYPE; + } + else + { + uiCalibrationTimeOut--; + } + break; + } + case SET_GAS_TYPE: + { + // Prepare command to PF300 + UpdateBufferToSend((char*)szPF300_SetAirGasType); + enLowFlowCalibrationStep=SEND_COMMAND_TO_PF300; + strcpy(szExpectedAnswerFromPF300, szPF300_AnswerAirGasType); + ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_AnswerAirGasType); + enGoBackToStep=SET_GAS_STANDARD; + break; + } + case SET_GAS_STANDARD: + { + // Prepare command to PF300 + UpdateBufferToSend((char*)szPF300_SetGasStandard); + enLowFlowCalibrationStep=SEND_COMMAND_TO_PF300; + strcpy(szExpectedAnswerFromPF300, szPF300_AnswerGasStandard); + ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_AnswerGasStandard); + enGoBackToStep=START_FLOW_READING; + break; + } + case START_FLOW_READING: + { + // Set Min blower speed + uiMotorDutyCyleForFlowCalib=MIN_PI_OUTPUT; + SS_Xputdw(mdrv, uiMotorDutyCyleForFlowCalib); + + // Init variable for flow sensor + uiCalibrationTimeOut=SAMPLE_RATE_BETWEEN_TWO_FLOW; + ulSumFlowTicks=0; + uiFlowTicksSamplesCounter=0; + + // Next step + enLowFlowCalibrationStep=SEND_FLOW_COMMAND; + break; + } + case SEND_FLOW_COMMAND: + { + if (uiCalibrationTimeOut!=0) + { + uiCalibrationTimeOut--; + + if (uiCalibrationTimeOut<(SAMPLE_RATE_BETWEEN_TWO_FLOW>>1)) + { + ulSumFlowTicks+=uiBlowerFlowRAWMes; + uiFlowTicksSamplesCounter++; + } + } + else + { + // Prepare next command (Read Low Flow) + enLowFlowCalibrationStep=SEND_COMMAND_TO_PF300; + if (bHighFlowCalibrationInProgress==FALSE) + { + UpdateBufferToSend((char*)szPF300_ReadLowFlowCmd); // %RM#1\r + strcpy(szExpectedAnswerFromPF300, szPF300_ReadLowFlowAnswer); // %RM#1$ + ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_ReadLowFlowAnswer); + } + else + { + UpdateBufferToSend((char*)szPF300_ReadHighFlowCmd); // %RM#0\r + strcpy(szExpectedAnswerFromPF300, szPF300_ReadHighFlowAnswer); // %RM#0$ + ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_ReadHighFlowAnswer); + } + enGoBackToStep=READ_FLOW_VALUE; + } + break; + } + case READ_FLOW_VALUE: + { + if (uiFlowTicksSamplesCounter!=0) + { + // Read PF300 flow (l/min) + strcpy(szTempBuf, &szAnswerFromPF300[ucNumberOfBytesToCheckFromPF300Answer]); + + // Store value of flow + if (stTemporayLUTFlowSensor.uiLUT_TableSize<LOW_FLOW_CALIB_NUMBER_OF_SAMPLES) + stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]=(unsigned int)atoi(szTempBuf); + else + stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]=(unsigned int)atoi(szTempBuf)*10; + + // Store ticks value + stTemporayLUTFlowSensor.uiFlowSensorTicks[stTemporayLUTFlowSensor.uiLUT_TableSize]=ulSumFlowTicks/uiFlowTicksSamplesCounter; + uiCalibrationTimeOut=SAMPLE_RATE_BETWEEN_TWO_FLOW; + ulSumFlowTicks=0; + uiFlowTicksSamplesCounter=0; + + // Check if current flow <0.1l/min + if (stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]<10) + { + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + break; + } + + // Check if the last low flow is higher than 20l/min or lower than 2l/min + if (stTemporayLUTFlowSensor.uiLUT_TableSize==(LOW_FLOW_CALIB_NUMBER_OF_SAMPLES-1)) + { + // Check if the last low flow is higher than 20l/min or lower than 2l/min + if (stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]>2000 || stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]<200) + { + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + break; + } + } + + // Next flow sample + if (stTemporayLUTFlowSensor.uiLUT_TableSize==LOW_FLOW_CALIB_NUMBER_OF_SAMPLES && stTemporayLUTFlowSensor.uiFlowValue[LOW_FLOW_CALIB_NUMBER_OF_SAMPLES]<(stTemporayLUTFlowSensor.uiFlowValue[LOW_FLOW_CALIB_NUMBER_OF_SAMPLES-1]+500)) + { + // No enough flow margin between the last value of the low flow and the first value of the high flow + } + else if (stTemporayLUTFlowSensor.uiLUT_TableSize!=0 && stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]<(stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize-1]+50)) + { + // No enough margin between two consecutives flow + } + else if (stTemporayLUTFlowSensor.uiLUT_TableSize!=0 && stTemporayLUTFlowSensor.uiFlowSensorTicks[stTemporayLUTFlowSensor.uiLUT_TableSize]<=stTemporayLUTFlowSensor.uiFlowSensorTicks[stTemporayLUTFlowSensor.uiLUT_TableSize-1]) + { + // Same or less ticks between two consecutives flow + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + break; + } + else + { + stTemporayLUTFlowSensor.uiLUT_TableSize++; + if (stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize-1]>=14000) + { + // End of calib => check the number of samples + if (stTemporayLUTFlowSensor.uiLUT_TableSize>(FLOW_CALIB_NUMBER_OF_SAMPLES>>1)) + { + enLowFlowCalibrationStep=PREPARE_SUCCESS_COMMAND; + + // Transfer the temporary LUT in the definitive LUT + stLUTFlowSensor=stTemporayLUTFlowSensor; + } + else + { + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + } + break; + } + else if (stTemporayLUTFlowSensor.uiLUT_TableSize>FLOW_CALIB_NUMBER_OF_SAMPLES) + { + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + break; + } + } + + // Prepare next flow reading + if (stTemporayLUTFlowSensor.uiLUT_TableSize<LOW_FLOW_CALIB_NUMBER_OF_SAMPLES) + { + // New motor speed + uiMotorDutyCyleForFlowCalib+=20; + enLowFlowCalibrationStep=SEND_FLOW_COMMAND; + } + else if (stTemporayLUTFlowSensor.uiLUT_TableSize==LOW_FLOW_CALIB_NUMBER_OF_SAMPLES && bHighFlowCalibrationInProgress==FALSE) + { + // Min speed for motor + uiMotorDutyCyleForFlowCalib=MIN_PI_OUTPUT; + SS_Xputdw(mdrv, uiMotorDutyCyleForFlowCalib); + enLowFlowCalibrationStep=SEND_HIGH_FLOW_CALIB_REQUEST; + break; + } + else + { + // New motor speed + uiMotorDutyCyleForFlowCalib+=10; + enLowFlowCalibrationStep=SEND_FLOW_COMMAND; + } + + // Update motor speed + if (uiMotorDutyCyleForFlowCalib<MAX_PI_OUTPUT) + { + SS_Xputdw(mdrv, uiMotorDutyCyleForFlowCalib); + } + else + { + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + break; + } + } + else // if (uiFlowTicksSamplesCounter!=0) + { + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + } + break; + } + case SEND_HIGH_FLOW_CALIB_REQUEST: + { + if (TransferCommandToHandset((char*)szRequestHighFlowCalib)==TRUE) + enLowFlowCalibrationStep=WAIT_FOR_HIGH_FLOW_CALIB_ACK; + break; + } + case WAIT_FOR_HIGH_FLOW_CALIB_ACK: + { + // Wait for acknownledge from handset + if (ReadByteReceive(&cCharValue)==TRUE) + { + if (cCharValue=='@') + { + // Continue flow calibration + bHighFlowCalibrationInProgress=TRUE; + enLowFlowCalibrationStep=SEND_FLOW_COMMAND; + } + else + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + } + break; + } + case PREPARE_FAILURE_COMMAND: + { + if (TransferCommandToHandset((char*)szEndOfCalibFailed)==TRUE) + enLowFlowCalibrationStep=END_OF_CALIBRATION; + break; + } + case PREPARE_SUCCESS_COMMAND: + { + if (TransferCommandToHandset((char*)szEndOfCalibOK)==TRUE) + enLowFlowCalibrationStep=END_OF_CALIBRATION; + break; + } + case SEND_COMMAND_TO_PF300: + { + // Send a byte every 1ms + if (TransferBufferToPF300()==TRUE) + { + // Buffer sent !! + if (ucNumberOfBytesToCheckFromPF300Answer!=0) + { + // Check answer from PF300 + ucIndexAnswerFromPF300=0; + uiCalibrationTimeOut=TIME_OUT_RECEPTION_PACKET_FROM_PF300; + enLowFlowCalibrationStep=CHECK_COMMAND_FROM_PF300; + } + else + enLowFlowCalibrationStep=enGoBackToStep; + } + break; + } + case CHECK_COMMAND_FROM_PF300: + { + if (uiCalibrationTimeOut==0) + { + // Time-out in reception !! + ucIndexAnswerFromPF300=0; + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + } + else if (ReadByteReceive(&cCharValue)==TRUE) + { + // Check last byte received + if (cCharValue=='\r') + { + // End of answer => check buffer content + ucIndexAnswerFromPF300=0; + strcpy(szTempBuf, szAnswerFromPF300); + szTempBuf[ucNumberOfBytesToCheckFromPF300Answer]=0; + if (strcmp(szTempBuf, szExpectedAnswerFromPF300)==0) + { + // Buffer OK !! + enLowFlowCalibrationStep=enGoBackToStep; + } + else + { + // Buffer wrong !! + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + } + } + else if (cCharValue=='?') + { + // PF300 is lost => end of calibration + ucIndexAnswerFromPF300=0; + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + } + else + { + // Store byte from PF300 into buffer + szAnswerFromPF300[ucIndexAnswerFromPF300++]=cCharValue; + if (ucIndexAnswerFromPF300>=SIZE_RX_BUFFER_PF300) + { + // Answer too long !! + ucIndexAnswerFromPF300=0; + enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND; + } + else + { + // Add 0 at the end of the string + szAnswerFromPF300[ucIndexAnswerFromPF300]=0; + } + } + } + else + { + // No byte received !! + uiCalibrationTimeOut--; + } + break; + } + default: + case END_OF_CALIBRATION: + { + uiTechnicalDataSet[START_STOP_VENTILATION]=0; + bDisableMaroubraCommCommunication=FALSE; + break; + } + } // switch + + // Every 300ms, send '@*' to inform the handset that the blower works properly + if (uiImHereMsgTimer==0) + { + if (enLowFlowCalibrationStep!=SEND_COMMAND_TO_PF300) + { + uiImHereMsgTimer=300; + TransferCommandToHandset((char*)szImHere); + } + } + else + uiImHereMsgTimer--; +} + +/******************************************************************************* +* Function Name : ManagePressureCalibration +* Description : Manage pressure calibration +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void ManagePressureCalibration(void) +{ + char cCharValue; + char szTempBuf[SIZE_RX_BUFFER_PF300]; + u16 uiCalibPressureADCValue; + u16 uiCalibPressureValue; + u16 uiCalibPressureGain; + + switch(enPressureCalibrationStep) + { + case INIT_PRESSURE_CALIB_TEST: + { + // Init comm with PF300 => wait 2s before sending first command to PF300 + // We need to wait for this delay in order to the handset to activate its transparent mode + if (uiCalibrationTimeOut==0) + { + bDisableMaroubraCommCommunication=TRUE; + + // Prepare command to PF300 + UpdateBufferToSend((char*)szPF300_CmdSwitchOffEcho); + strcpy(szExpectedAnswerFromPF300, szPF300_AnswerSwitchOffEcho); + ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_AnswerSwitchOffEcho); + enPressureCalibrationStep=PRESSURE_CALIB_SEND_COMMAND_TO_PF300; + enPressureCalibGoBackToStep=START_PRESSURE_READING; + } + else + { + uiCalibrationTimeOut--; + } + break; + } + case START_PRESSURE_READING: + { + // Set blower speed + SS_Xputdw(mdrv, 600); + + // Init variable for flow sensor + uiCalibrationTimeOut=SAMPLE_RATE_BETWEEN_TWO_PRESSURE; + ulSumPressureTicks=0; + uiPressureTicksSamplesCounter=0; + + enPressureCalibrationStep=SEND_PRESSURE_COMMAND; + break; + } + case SEND_PRESSURE_COMMAND: + { + if (uiCalibrationTimeOut!=0) + { + uiCalibrationTimeOut--; + + if (uiCalibrationTimeOut<2000) + { + ulSumPressureTicks+=uiProximalPressureADCMes; + uiPressureTicksSamplesCounter++; + } + } + else + { + // Prepare next command + UpdateBufferToSend((char*)szPF300_ReadPdiffCmd); + strcpy(szExpectedAnswerFromPF300, szPF300_ReadPdiffAnswer); + ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_ReadPdiffAnswer); + enPressureCalibrationStep=PRESSURE_CALIB_SEND_COMMAND_TO_PF300; + enPressureCalibGoBackToStep=READ_PRESSURE_VALUE; + } + break; + } + case READ_PRESSURE_VALUE: + { + if (uiPressureTicksSamplesCounter!=0) + { + // Read PF300 pressure + strcpy(szTempBuf, &szAnswerFromPF300[ucNumberOfBytesToCheckFromPF300Answer]); + + // Store value of Pressure + uiCalibPressureValue=(unsigned int)atoi(szTempBuf); + + // Store ticks value + uiCalibPressureADCValue=ulSumPressureTicks/uiPressureTicksSamplesCounter; + uiCalibrationTimeOut=SAMPLE_RATE_BETWEEN_TWO_PRESSURE; + ulSumPressureTicks=0; + uiPressureTicksSamplesCounter=0; + + // Check if current pressure<10cmH20 + if (uiCalibPressureValue<1000) + { + enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND; + break; + } + + // Compute pressure gain + uiCalibPressureGain=(10000UL*(uiCalibPressureADCValue-uiTechnicalDataSet[PPROX_OFFSET_TEC]))/uiCalibPressureValue; + uiCalibPressureGain+=5; + uiCalibPressureGain/=10; + + // Check pressure gain range + if (uiCalibPressureGain<Tec_GainPprox_MIN || uiCalibPressureGain>Tec_GainPprox_MAX) + { + enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND; + } + else + { + enPressureCalibrationStep=PRESSURE_CALIB_SUCCESS_COMMAND; + + // Transfer the temporary LUT in the definitive LUT + uiTechnicalDataSet[PPROX_GAIN_TEC]=uiCalibPressureGain; + } + } + else // if (uiPressureTicksSamplesCounter!=0) + { + enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND; + } + break; + } + case PRESSURE_CALIB_FAILURE_COMMAND: + { + if (TransferCommandToHandset((char*)szEndOfCalibFailed)==TRUE) + enPressureCalibrationStep=PRESSURE_CALIB_END_OF_CALIBRATION; + break; + } + case PRESSURE_CALIB_SUCCESS_COMMAND: + { + if (TransferCommandToHandset((char*)szEndOfCalibOK)==TRUE) + enPressureCalibrationStep=PRESSURE_CALIB_END_OF_CALIBRATION; + break; + } + case PRESSURE_CALIB_SEND_COMMAND_TO_PF300: + { + // Send a byte every 1ms + if (TransferBufferToPF300()==TRUE) + { + // Buffer sent !! + if (ucNumberOfBytesToCheckFromPF300Answer!=0) + { + // Check answer from PF300 + ucIndexAnswerFromPF300=0; + uiCalibrationTimeOut=TIME_OUT_RECEPTION_PACKET_FROM_PF300; + enPressureCalibrationStep=PRESSURE_CALIB_CHECK_COMMAND_FROM_PF300; + } + else + enPressureCalibrationStep=enPressureCalibGoBackToStep; + } + break; + } + case PRESSURE_CALIB_CHECK_COMMAND_FROM_PF300: + { + if (uiCalibrationTimeOut==0) + { + // Time-out in reception !! + ucIndexAnswerFromPF300=0; + enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND; + } + else if (ReadByteReceive(&cCharValue)==TRUE) + { + // Check last byte received + if (cCharValue=='\r') + { + // End of answer => check buffer content + ucIndexAnswerFromPF300=0; + strcpy(szTempBuf, szAnswerFromPF300); + szTempBuf[ucNumberOfBytesToCheckFromPF300Answer]=0; + if (strcmp(szTempBuf, szExpectedAnswerFromPF300)==0) + { + // Buffer OK !! + enPressureCalibrationStep=enPressureCalibGoBackToStep; + } + else + { + // Buffer wrong !! + enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND; + } + } + else if (cCharValue=='?') + { + // PF300 is lost => end of calibration + ucIndexAnswerFromPF300=0; + enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND; + } + else + { + // Store byte from PF300 into buffer + szAnswerFromPF300[ucIndexAnswerFromPF300++]=cCharValue; + if (ucIndexAnswerFromPF300>=SIZE_RX_BUFFER_PF300) + { + // Answer too long !! + ucIndexAnswerFromPF300=0; + enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND; + } + else + { + // Add 0 at the end of the string + szAnswerFromPF300[ucIndexAnswerFromPF300]=0; + } + } + } + else + { + // No byte received !! + uiCalibrationTimeOut--; + } + break; + } + default: + case PRESSURE_CALIB_END_OF_CALIBRATION: + { + uiTechnicalDataSet[START_STOP_VENTILATION]=0; + bDisableMaroubraCommCommunication=FALSE; + break; + } + } // switch + + // Every 300ms, send '@*' to inform the handset that the blower works properly + if (uiImHereMsgTimer==0) + { + if (enPressureCalibrationStep!=PRESSURE_CALIB_SEND_COMMAND_TO_PF300) + { + uiImHereMsgTimer=300; + TransferCommandToHandset((char*)szImHere); + } + } + else + uiImHereMsgTimer--; +} + + +/******************************************************************************* +* Function Name : ManageCstPressure +* Description : Manage constant pressure +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void ManageCstPressure(void) +{ + int32_t lError; + int32_t lPropTerm; + int32_t lIntegralTerm; + int32_t lOutputPressure; + + + // Barometric Mode : error computation + lError=(int32_t)uiMLT_PressureSetPoint-(int32_t)uiProximalPressureMes; + lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_CPAP_VENTED_PRESSURE_I] * lError; + if (uiMLT_PressureSetPoint<uiVentilationSet[PI_SET]) uiMLT_PressureSetPoint++; + + // Close loop in pressure + if ((lIntegral_Pressure_I>=0) && (lIntegralTerm>=0) && (bMaxPIOutputPressureI==FALSE)) + { + if ((lIntegral_Pressure_I + lIntegralTerm) <0) + lIntegral_Pressure_I = INTEGRAL_MAX; + else + lIntegral_Pressure_I += lIntegralTerm; + } + else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm<=0) && (bMinPIOutputPressureI==FALSE)) + { + if ((lIntegral_Pressure_I + lIntegralTerm)>0) + lIntegral_Pressure_I = INTEGRAL_MIN; + else + lIntegral_Pressure_I += lIntegralTerm; + } + else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm>=0)) + lIntegral_Pressure_I += lIntegralTerm; + else if ((lIntegral_Pressure_I>=0) && (lIntegralTerm<=0)) + lIntegral_Pressure_I += lIntegralTerm; + + lPropTerm = (int32_t)uiTechnicalDataSet[KP_CPAP_VENTED_PRESSURE_I] * lError; + lOutputPressure = (lIntegral_Pressure_I>>16) + (lPropTerm>>13); + + // Add constante value (PWM at the end of the previous inspiration) + //lOutputPressure+=300; + + if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF)) + { + bMaxPIOutputPressureI = TRUE; + uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF; + } + else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF)) + { + bMinPIOutputPressureI = TRUE; + uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF; + } + else + { + bMaxPIOutputPressureI = FALSE; + bMinPIOutputPressureI = FALSE; + uiInspirationBlowerPWMTec = lOutputPressure; + } + + // Update Blower Speed + SS_Xputdw(mdrv, uiInspirationBlowerPWMTec); + + // Monitoring and Alarm (every 1s) + #ifdef MOTOR_LIFE_TESTING + if (uiAverageMonitoringMLT==0) + { + uiAverageBlowerSpeedMes=ulMLT_SumSpeedMes/MLT_AVERAGE_MONITORING; + uiBreathBlowerCurrentMes=ulMLT_SumCurrentMes/MLT_AVERAGE_MONITORING; + uiAverateMotorTempMes=ulMLT_SumTemperatureMes/MLT_AVERAGE_MONITORING; + uiAverageMotorVoltage=ulMLT_SumBlowerVoltage/MLT_AVERAGE_MONITORING; + + ulMLT_SumSpeedMes=0; + ulMLT_SumCurrentMes=0; + ulMLT_SumTemperatureMes=0; + ulMLT_SumBlowerVoltage=0; + uiAverageMonitoringMLT=MLT_AVERAGE_MONITORING; + } + else + { + ulMLT_SumSpeedMes+=uiBlowerSpeedMes; + ulMLT_SumCurrentMes+=uiBlowerCurrentMes; + ulMLT_SumTemperatureMes+=uiTechnicalDataMes[MOTOR_TEMPERATURE_TEC_MES]; + ulMLT_SumBlowerVoltage+=uiTechnicalDataMes[MOTOR_VOLTAGE_TEC_MES]; + uiAverageMonitoringMLT--; + } + + // Alarms management + if (uiMLT_EnableAlarm==0) + { + // High Speed alarm + if (uiAverageBlowerSpeedMes>uiTechnicalDataSet[MLT_HIGH_SPEED_TEC]) + uiFlagsAlarm[ALARM_FLAGS2]|=HIGH_BLOWER_SPEED_ALARM_MASK; + + // Low Speed alarm + if (uiAverageBlowerSpeedMes<uiTechnicalDataSet[MLT_LOW_SPEED_TEC]) + uiFlagsAlarm[ALARM_FLAGS2]|=LOW_BLOWER_SPEED_ALARM_MASK; + + // High blower current alarm + if (uiBreathBlowerCurrentMes>uiTechnicalDataSet[MLT_HIGH_CURRENT_TEC]) + uiFlagsAlarm[ALARM_FLAGS2]|=HIGH_BLOWER_CURRENT_ALARM_MASK; + + // High Blower temperature + if (uiAverateMotorTempMes>uiTechnicalDataSet[MLT_HIGH_TEMPERATURE_TEC]) + uiFlagsAlarm[ALARM_FLAGS2]|=HIGH_BLOWER_TEMP_ALARM_MASK; + + // Low Blower temperature + if (uiAverateMotorTempMes<100) + uiFlagsAlarm[ALARM_FLAGS2]|=LOW_BLOWER_TEMP_ALARM_MASK; + + // High Blower Flow + if (iBlowerFlowSmoothingMesForTrigger>uiTechnicalDataSet[MLT_HIGH_FLOW_TEC] || iBlowerFlowSmoothingMesForTrigger<uiTechnicalDataSet[MLT_LOW_FLOW_TEC]) + uiFlagsAlarm[ALARM_FLAGS2]|=OOR_BLOWER_FLOW_ALARM_MASK; + } + else + uiMLT_EnableAlarm--; + #endif // MOTOR_LIFE_TESTING +} + + +/******************************************************************************* +* Function Name : ManagePACVVentilation +* Description : Manage Bilevel ventilation +* Input : bPSMode=true in PS mode, false in PI mode +* Output : None +* Return : None +*******************************************************************************/ +void ManagePACVVentilation(bool bPSMode) +{ +int32_t lError; +int32_t lPropTerm; +int32_t lIntegralTerm; +int32_t lOutputPressure; +u16 uiPressureSetPoint; +u16 uiTiMax; +u16 uiTiMin; +//u16 uiTeMax; +u16 uiFlowMaxInExpi; + +if (ucVentilationCycle==INSPIRATION_CYCLE) + { + // --------------------------------------------------------------------------- + // - INSPIRATION - + // -------------------------------------------------------------------------- + + // Ti et pressure set point management + if (bPSMode==TRUE) + { + uiPressureSetPoint=uiVentilationSet[PS_SET]; + uiTiMax=uiVentilationSet[TI_MAX_SET]; + } + else + { + uiPressureSetPoint=uiVentilationSet[PI_SET]; + uiTiMax=uiVentilationSet[TI_BARO_SET]; + } + + // Compute Timin + if (uiPatientType==PATIENT_ADULT) + uiTiMin=TiBaroSet_A_MIN; + else + uiTiMin=TiBaroSet_P_MIN; + + // Limit the pressure setting + if (uiVentilationSet[HIGH_PRESSURE_ALARM_SET]<uiPressureSetPoint) + uiPressureSetPoint=uiVentilationSet[HIGH_PRESSURE_ALARM_SET]; + + if (uiTiD==0) + { + // Management Expiratory Trigger + ucTempoTriggerExpiAuto=TEMPO_TRIGGER_EXPI; + ucExpiTriggerTreshold=MIN_THRESHOLD_EXPI_TRIGGER_AUTO; + + // Management Inspiratory slope + switch(uiVentilationSet[SLOPE_BARO_SET]) + { + default: + case 1: + { + // Slope of 5ms/hPa => 0.2hPa/ms + uiIpapSettingTemp=uiVentilationSet[PEEP_SET]+2; + break; + } + case 2: + { + ucIndexTableSlope=0; + uiIpapSettingTemp=(uiPressureSetPoint*ucSlope2Table[ucIndexTableSlope++])/100; + break; + } + case 3: + { + ucIndexTableSlope=0; + uiIpapSettingTemp=(uiPressureSetPoint*ucSlope3Table[ucIndexTableSlope++])/100; + break; + } + case 4: + { + ucIndexTableSlope=0; + uiIpapSettingTemp=(uiPressureSetPoint*ucSlope4Table[ucIndexTableSlope++])/100; + break; + } + } + } + else + { + // Management Inspiratory slope + switch(uiVentilationSet[SLOPE_BARO_SET]) + { + default: + case 1: + { + // Slope of 5ms/hPa => 0.2hPa/ms + uiIpapSettingTemp+=2; + if (uiIpapSettingTemp>uiPressureSetPoint) + uiIpapSettingTemp=uiPressureSetPoint; + break; + } + case 2: + { + if (ucIndexTableSlope<SIZE_SLOPE2_TABLE && (uiTiD%10)==0) + uiIpapSettingTemp=(uiPressureSetPoint*ucSlope2Table[ucIndexTableSlope++])/100; + break; + } + case 3: + { + if (ucIndexTableSlope<SIZE_SLOPE3_TABLE && (uiTiD%10)==0) + uiIpapSettingTemp=(uiPressureSetPoint*ucSlope3Table[ucIndexTableSlope++])/100; + break; + } + case 4: + { + if (ucIndexTableSlope<SIZE_SLOPE4_TABLE && (uiTiD%10)==0) + uiIpapSettingTemp=(uiPressureSetPoint*ucSlope4Table[ucIndexTableSlope++])/100; + break; + } + } + } + + // Barometric Mode : error computation + lError=(int32_t)uiIpapSettingTemp-(int32_t)uiProximalPressureMes; + if (fFirstCycleInspi==FALSE) + lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_VENTED_PRESSURE_I] * lError; + else + { + lIntegralTerm = (int32_t)(uiTechnicalDataSet[KI_VENTED_PRESSURE_I]>>2) * lError; + uiPWMatTheEndOfInspiration=uiExpirationBlowerPWMTec; + } + + // Close loop in pressure + if ((lIntegral_Pressure_I>=0) && (lIntegralTerm>=0) && (bMaxPIOutputPressureI==FALSE)) + { + if ((lIntegral_Pressure_I + lIntegralTerm) <0) + lIntegral_Pressure_I = INTEGRAL_MAX; + else + lIntegral_Pressure_I += lIntegralTerm; + } + else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm<=0) && (bMinPIOutputPressureI==FALSE)) + { + if ((lIntegral_Pressure_I + lIntegralTerm)>0) + lIntegral_Pressure_I = INTEGRAL_MIN; + else + lIntegral_Pressure_I += lIntegralTerm; + } + else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm>=0)) + lIntegral_Pressure_I += lIntegralTerm; + else if ((lIntegral_Pressure_I>=0) && (lIntegralTerm<=0)) + lIntegral_Pressure_I += lIntegralTerm; + + lPropTerm = (int32_t)uiTechnicalDataSet[KP_VENTED_PRESSURE_I] * lError; + lOutputPressure = (lIntegral_Pressure_I>>16) + (lPropTerm>>13); + + // Add constante value (PWM at the end of the previous inspiration) + lOutputPressure+=uiPWMatTheEndOfInspiration; + + if (fAlarmPmax==TRUE || fAlarmVtiMax==TRUE) + { + bMaxPIOutputPressureI = TRUE; + } + else if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF)) + { + bMaxPIOutputPressureI = TRUE; + uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF; + } + else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF)) + { + bMinPIOutputPressureI = TRUE; + uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF; + } + else + { + bMaxPIOutputPressureI = FALSE; + bMinPIOutputPressureI = FALSE; + uiInspirationBlowerPWMTec = lOutputPressure; + } + + // Update Blower Speed + SS_Xputdw(mdrv, uiInspirationBlowerPWMTec); + + // ************************ CYCLE MANAGEMENT ********************************* + uiTiD++; + if ((uiTiD>=uiTiMax) || + (TestTriggerExpiratoire(uiVentilationSet[TRIG_E_SET], uiVentilationSet[PS_SET])==TRUE && uiTiD>uiVentilationSet[TI_MIN_SET] && bPSMode==TRUE) || + (fAlarmPmax==TRUE && uiTiD>uiTiMin) || + (fAlarmVtiMax==TRUE && uiTiD>uiTiMin)) + { + // Beginning of the expiration + if (fAlarmPmax==FALSE && fAlarmVtiMax==FALSE) + { + fFirstCycleInspi=FALSE; + uiPWMatTheEndOfInspiration=uiInspirationBlowerPWMTec; + } + else + { + fFirstCycleInspi=TRUE; + uiPWMatTheEndOfInspiration=MIN_VOLTAGE_REF; + } + + ucVentilationCycle=EXPIRATION_CYCLE; + uiTiD=0; + + // Reset PI variables for next inspiration + lIntegral_Pressure_E=0; + bMaxPIOutputPressureE=FALSE; + bMinPIOutputPressureE=FALSE; + + fFirstCycleExpi=FALSE; + } + } +else + { + // --------------------------------------------------------------------------- + // - EXPIRATION - + // --------------------------------------------------------------------------- + + // *************************** UPDATE SETTINGS ******************************* + if (ApplyNewVentilationMode()==TRUE) + return; + + // ******************** MAIN BLOWER MANAGEMENT ******************************* + if (uiVentilationSet[PEEP_SET]==0) + { + uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF; + SS_Xputdw(mdrv, uiExpirationBlowerPWMTec); + } + else + { + if (uiTeD==0) + { + // First blower current setting + uiEpapSettingTemp=uiVentilationSet[PI_SET]-2; // Slope of 5ms/hPa => 0.2hPa/ms + } + else + { + // we increase the speed of the blower every 1ms + uiEpapSettingTemp-=2; // Slope of 5ms/hPa => 0.2hPa/ms + if (uiEpapSettingTemp<uiVentilationSet[PEEP_SET]) + uiEpapSettingTemp=uiVentilationSet[PEEP_SET]; + } + + // Barometric Mode : error computation + if (fFirstCycleExpi==FALSE) + { + lError=(int32_t)uiEpapSettingTemp-(int32_t)uiProximalPressureMes; + lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_VENTED_PRESSURE_E] * lError; + } + else + { + lError=(int32_t)uiVentilationSet[PEEP_SET]-(int32_t)uiProximalPressureMes; + lIntegralTerm = (int32_t)(uiTechnicalDataSet[KI_VENTED_PRESSURE_E]>>2) * lError; + } + + // Close loop in pressure + if ((lIntegral_Pressure_E>=0) && (lIntegralTerm>=0) && (bMaxPIOutputPressureE==FALSE)) + { + if ((lIntegral_Pressure_E + lIntegralTerm) <0) + lIntegral_Pressure_E = INTEGRAL_MAX; + else + lIntegral_Pressure_E += lIntegralTerm; + } + else if ((lIntegral_Pressure_E<=0) && (lIntegralTerm<=0) && (bMinPIOutputPressureE==FALSE)) + { + if ((lIntegral_Pressure_E + lIntegralTerm)>0) + lIntegral_Pressure_E = INTEGRAL_MIN; + else + lIntegral_Pressure_E += lIntegralTerm; + } + else if ((lIntegral_Pressure_E<=0) && (lIntegralTerm>=0)) + lIntegral_Pressure_E += lIntegralTerm; + else if ((lIntegral_Pressure_E>=0) && (lIntegralTerm<=0)) + lIntegral_Pressure_E += lIntegralTerm; + + lPropTerm = (int32_t)uiTechnicalDataSet[KP_VENTED_PRESSURE_E] * lError; + lOutputPressure = (lIntegral_Pressure_E>>16) + (lPropTerm>>13); + + // Add constante value (PWM at the end of the previous expiration) + lOutputPressure+=uiPWMatTheEndOfExpiration; + + // Flow limiting + uiFlowMaxInExpi=uiMaximumFlowInExpiration[uiVentilationSet[PS_CPAP_SET]/10]; + if (lError>5 && iBlowerFlowSmoothingMes>(int16_t)uiFlowMaxInExpi) + { + // Impossible to maintain the peep (patient disconnection) + if (uiDisconnectionTime==0) + { + fBlockCloseLoop=TRUE; // Block the close loop + if (uiMemoPWMDuringDisconnection!=0) // Apply a fixed PWM value + uiExpirationBlowerPWMTec=uiMemoPWMDuringDisconnection; + else + uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF; + } + else + uiDisconnectionTime--; + } + else if (iBlowerFlowSmoothingMes<(int16_t)uiFlowMaxInExpi && (lError>(-2) && lError<2)) + { + // Good pressure : no disconnection + uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT; + if (fBlockCloseLoop==TRUE) + { + // The close loop was block before => unblock it + fBlockCloseLoop=FALSE; + lIntegral_Pressure_E=0; + bMaxPIOutputPressureE = FALSE; + bMinPIOutputPressureE = FALSE; + lOutputPressure=uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec; + } + else if (iBlowerFlowSmoothingMes>=0) + { + // Record current PWM + uiMemoPWMDuringDisconnection=uiExpirationBlowerPWMTec; + } + } + + // Unblock the close loop every 4s in case of none recorded PWM value + if (fBlockCloseLoop==TRUE && uiMemoPWMDuringDisconnection==0 && uiTeD==0) + { + uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT; + fBlockCloseLoop=FALSE; + lIntegral_Pressure_E=0; + bMaxPIOutputPressureE = FALSE; + bMinPIOutputPressureE = FALSE; + lOutputPressure=uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec; + } + + // Update blower PWM + if (fBlockCloseLoop==TRUE) + { + bMaxPIOutputPressureE = TRUE; + } + else if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF)) + { + bMaxPIOutputPressureE = TRUE; + uiExpirationBlowerPWMTec=MAX_VOLTAGE_REF; + } + else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF)) + { + bMinPIOutputPressureE = TRUE; + uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF; + } + else + { + bMaxPIOutputPressureE = FALSE; + bMinPIOutputPressureE = FALSE; + uiExpirationBlowerPWMTec = lOutputPressure; + } + SS_Xputdw(mdrv, uiExpirationBlowerPWMTec); + } + + // Expiratory time + uiTeD++; + if (uiTeD>TE_SET_MAX) uiTeD=TE_SET_MAX; + if ((uiTeD>=uiTeBaroSet && bPSMode==FALSE) || TestInspiratoryTrigger(bPSMode, uiTeD, uiVentilationSet[TRIG_I_FLOW_SET])==TRUE) + { + ucVentilationCycle=INSPIRATION_CYCLE; + uiTeD=0; + + // Record PWM value at the end of the expiration + uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec; + + // Reset PI variables for next inspiration + lIntegral_Pressure_I=0; + bMaxPIOutputPressureI=FALSE; + bMinPIOutputPressureI=FALSE; + } + } +} + + + +/******************************************************************************* +* Function Name : ManageVolumetricVentilation +* Description : Manage Volumetric Ventilation +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void ManageVolumetricVentilation(void) +{ +int32_t lError; +int32_t lPropTerm; +int32_t lIntegralTerm; +int32_t lOutputPressure; +int16_t iMaxVtAdjust; +u16 uiFlowMaxInExpi; +u16 uiTiMin; + +if (ucVentilationCycle==INSPIRATION_CYCLE) + { + // --------------------------------------------------------------------------- + // - INSPIRATION - + // --------------------------------------------------------------------------- + + // Compute Timin + if (uiPatientType==PATIENT_ADULT) + uiTiMin=TiVoluSet_A_MIN; + else + uiTiMin=TiVoluSet_P_MIN; + + // ************************** Main Blower MANAGEMENT ************************* + if (uiTiD==0) + { + // Compute Volume adjustment + if (fFirstCycleInspi==FALSE) + { + if ((uiFlagsAlarm[ALARM_FLAGS1]&HIGH_PRESSURE_ALARM_MASK)==0) + { + if (ucCounterHPAlarm==0) + { + iVtAdjust+=(((int16_t)uiVentilationSet[VT_SET]-(int16_t)uiRecordVtiMes>>1)); + if (iVtAdjust>0) + { + iMaxVtAdjust=(int16_t)(uiVentilationSet[VT_SET]>>1); // >0 + if (iVtAdjust>iMaxVtAdjust) + iVtAdjust=iMaxVtAdjust; + } + else if (iVtAdjust<0) + { + iMaxVtAdjust=(int16_t)(~(uiVentilationSet[VT_SET]>>1)+1); // <0 + if (iVtAdjust<iMaxVtAdjust) + iVtAdjust=iMaxVtAdjust; + } + } + else + ucCounterHPAlarm--; + } + else + ucCounterHPAlarm=1; + } + else + iVtAdjust=0; + + ComputeInspiratoryFlowSetPointInAVC(uiPatientType, (u16)((int16_t)uiVentilationSet[VT_SET]+iVtAdjust), uiVentilationSet[TI_VOLU_SET], uiVentilationSet[SHAPE_SET], &ulMaxIFlowSet, &ulMinIFlowSet, &ulDecFlowStep); + } + else + { + if (ulMaxIFlowSet>=ulDecFlowStep) + ulMaxIFlowSet-=ulDecFlowStep; + if (ulMaxIFlowSet<ulMinIFlowSet) + ulMaxIFlowSet=ulMinIFlowSet; + } + + // Volumetric Mode : error computation + //lError=(int32_t)(ulMaxIFlowSet/100)-iBlowerFlowMes; + lError=(int32_t)(ulMaxIFlowSet/100)-iBlowerFlowSmoothingMes; + if (fFirstCycleInspi==FALSE) + { + if (ulMaxIFlowSet<150000 && uiTiD>30000) + lIntegralTerm = (int32_t)(uiTechnicalDataSet[KI_FLOW_I]>>1) * lError; + else + lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_FLOW_I] * lError; + } + else + lIntegralTerm = (int32_t)(uiTechnicalDataSet[KI_FLOW_I]>>2) * lError; + + // Close loop in pressure or flow (PI) + if ((lIntegral_Flow_I>=0) && (lIntegralTerm>=0) && (bMaxPIOutputFlowI==FALSE)) + { + if ((lIntegral_Flow_I + lIntegralTerm) <0) + lIntegral_Flow_I = INTEGRAL_MAX; + else + lIntegral_Flow_I += lIntegralTerm; + } + else if ((lIntegral_Flow_I<=0) && (lIntegralTerm<=0) && (bMinPIOutputFlowI==FALSE)) + { + if ((lIntegral_Flow_I + lIntegralTerm)>0) + lIntegral_Flow_I = INTEGRAL_MIN; + else + lIntegral_Flow_I += lIntegralTerm; + } + else if ((lIntegral_Flow_I<=0) && (lIntegralTerm>=0)) + lIntegral_Flow_I += lIntegralTerm; + else if ((lIntegral_Flow_I>=0) && (lIntegralTerm<=0)) + lIntegral_Flow_I += lIntegralTerm; + + lPropTerm = (int32_t)uiTechnicalDataSet[KP_FLOW_I] * lError; + lOutputPressure = (lIntegral_Flow_I>>16) + (lPropTerm>>13); + + // Add constante value (PWM at the end of the previous inspiration) + lOutputPressure+=uiPWMatTheEndOfExpiration; + + if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF)) + { + bMaxPIOutputFlowI = TRUE; + uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF; + } + else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF)) + { + bMinPIOutputFlowI = TRUE; + uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF; + } + else + { + bMaxPIOutputFlowI = FALSE; + bMinPIOutputFlowI = FALSE; + uiInspirationBlowerPWMTec = lOutputPressure; + } + + // Update Blower Speed + SS_Xputdw(mdrv, uiInspirationBlowerPWMTec); + + // ************************ CYCLE MANAGEMENT ********************************* + uiTiD++; + if ((uiTiD>=uiVentilationSet[TI_VOLU_SET]) || + (fAlarmPmax==TRUE && uiTiD>uiTiMin)) + { + // Beginning of the expiration + uiPWMatTheEndOfInspiration=uiInspirationBlowerPWMTec; + uiProximalPressureAtTheEndOfInspiration=uiProximalPressureMes; + + ucVentilationCycle=EXPIRATION_CYCLE; + uiTiD=0; + + // Reset PI variables for next inspiration + lIntegral_Pressure_E=0; + bMaxPIOutputPressureE=FALSE; + bMinPIOutputPressureE=FALSE; + + fFirstCycleExpi=FALSE; + fFirstCycleInspi=FALSE; + } + } +else + { + // --------------------------------------------------------------------------- + // - EXPIRATION - + // --------------------------------------------------------------------------- + + // *************************** UPDATE SETTINGS ******************************* + if (ApplyNewVentilationMode()==TRUE) + return; + + // ******************** MAIN BLOWER MANAGEMENT ******************************* + if (uiVentilationSet[PEEP_SET]==0) + { + uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF; + SS_Xputdw(mdrv, uiExpirationBlowerPWMTec); + } + else + { + if (uiTeD==0) + { + // First blower pressure setting + if (uiProximalPressureAtTheEndOfInspiration<uiVentilationSet[PEEP_SET]) + uiEpapSettingTemp=uiVentilationSet[PEEP_SET]; + else if (uiProximalPressureAtTheEndOfInspiration>=2) + uiEpapSettingTemp=uiProximalPressureAtTheEndOfInspiration-2; // Slope of 5ms/hPa => 0.2hPa/ms + else + uiEpapSettingTemp=uiVentilationSet[PEEP_SET]; + } + else + { + // we decrease the speed of the blower every 1ms + if (uiEpapSettingTemp>=2) + uiEpapSettingTemp-=2; // Slope of 5ms/hPa => 0.2hPa/ms + } + + // Pressure set point limitation + if (uiEpapSettingTemp<uiVentilationSet[PEEP_SET]) + uiEpapSettingTemp=uiVentilationSet[PEEP_SET]; + + // Barometric Mode : error computation + if (fFirstCycleExpi==FALSE) + { + lError=(int32_t)uiEpapSettingTemp-(int32_t)uiProximalPressureMes; + lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_VENTED_PRESSURE_E] * lError; + } + else + { + lError=(int32_t)uiVentilationSetTemp[PEEP_SET]-(int32_t)uiProximalPressureMes; + lIntegralTerm = (int32_t)(uiTechnicalDataSet[KI_VENTED_PRESSURE_E]>>2) * lError; + } + + // Close loop in pressure + if ((lIntegral_Pressure_E>=0) && (lIntegralTerm>=0) && (bMaxPIOutputPressureE==FALSE)) + { + if ((lIntegral_Pressure_E + lIntegralTerm) <0) + lIntegral_Pressure_E = INTEGRAL_MAX; + else + lIntegral_Pressure_E += lIntegralTerm; + } + else if ((lIntegral_Pressure_E<=0) && (lIntegralTerm<=0) && (bMinPIOutputPressureE==FALSE)) + { + if ((lIntegral_Pressure_E + lIntegralTerm)>0) + lIntegral_Pressure_E = INTEGRAL_MIN; + else + lIntegral_Pressure_E += lIntegralTerm; + } + else if ((lIntegral_Pressure_E<=0) && (lIntegralTerm>=0)) + lIntegral_Pressure_E += lIntegralTerm; + else if ((lIntegral_Pressure_E>=0) && (lIntegralTerm<=0)) + lIntegral_Pressure_E += lIntegralTerm; + + lPropTerm = (int32_t)uiTechnicalDataSet[KP_VENTED_PRESSURE_E] * lError; + lOutputPressure = (lIntegral_Pressure_E>>16) + (lPropTerm>>13); + + // Add constante value (PWM at the end of the previous expiration) + lOutputPressure+=uiPWMatTheEndOfExpiration; + + // Flow limiting + uiFlowMaxInExpi=uiMaximumFlowInExpiration[uiVentilationSet[PS_CPAP_SET]/10]; + if (lError>5 && iBlowerFlowSmoothingMes>(int16_t)uiFlowMaxInExpi) + { + // Impossible to maintain the peep (patient disconnection) + if (uiDisconnectionTime==0) + { + fBlockCloseLoop=TRUE; // Block the close loop + if (uiMemoPWMDuringDisconnection!=0) // Apply a fixed PWM value + uiExpirationBlowerPWMTec=uiMemoPWMDuringDisconnection; + else + uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF; + } + else + uiDisconnectionTime--; + } + else if (iBlowerFlowSmoothingMes<(int16_t)uiFlowMaxInExpi && (lError>(-2) && lError<2)) + { + // Good pressure : no disconnection + uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT; + if (fBlockCloseLoop==TRUE) + { + // The close loop was block before => unblock it + fBlockCloseLoop=FALSE; + lIntegral_Pressure_E=0; + bMaxPIOutputPressureE = FALSE; + bMinPIOutputPressureE = FALSE; + lOutputPressure=uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec; + } + else if (iBlowerFlowSmoothingMes>=0) + { + // Record current PWM + uiMemoPWMDuringDisconnection=uiExpirationBlowerPWMTec; + } + } + + // Unblock the close loop every 4s in case of none recorded PWM value + if (fBlockCloseLoop==TRUE && uiMemoPWMDuringDisconnection==0 && uiTeD==0) + { + uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT; + fBlockCloseLoop=FALSE; + lIntegral_Pressure_E=0; + bMaxPIOutputPressureE = FALSE; + bMinPIOutputPressureE = FALSE; + lOutputPressure=uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec; + } + + // Update blower PWM + if (fBlockCloseLoop==TRUE) + { + bMaxPIOutputPressureE = TRUE; + } + else if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF)) + { + bMaxPIOutputPressureE = TRUE; + uiExpirationBlowerPWMTec=MAX_VOLTAGE_REF; + } + else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF)) + { + bMinPIOutputPressureE = TRUE; + uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF; + } + else + { + bMaxPIOutputPressureE = FALSE; + bMinPIOutputPressureE = FALSE; + uiExpirationBlowerPWMTec = lOutputPressure; + } + // Update Blower Speed + SS_Xputdw(mdrv, uiExpirationBlowerPWMTec); + } + + // Expiratory time + uiTeD++; + if (uiTeD>=uiTeVoluSet || TestInspiratoryTrigger(FALSE, uiTeD, uiVentilationSet[TRIG_I_FLOW_SET])==TRUE) + { + ucVentilationCycle=INSPIRATION_CYCLE; + uiTeD=0; + + // Record PWM value at the end of the expiration + if (fBlockCloseLoop==FALSE) + uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec; + else + uiPWMatTheEndOfExpiration=0; + fBlockCloseLoop=FALSE; + + // Reset PI variables for next inspiration + lIntegral_Flow_I=0; + bMaxPIOutputFlowI=FALSE; + bMinPIOutputFlowI=FALSE; + } + } +} + + + +/******************************************************************************* +* Function Name : LaunchTherapyEngine +* Description : Select and launch the therapy engine +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void LaunchTherapyEngine(void) +{ + if (bMemoStartVentilation==TRUE) + { + // ---- Check new configuration + if (uiTechnicalDataSet[DEVICE_MODE_TEC]!=uiPreviousDeviceMode) + { + UpdateSettings(); + enPreviousMode=NUMBER_OF_MODE; // Force full init of the variables + InitVentilation(); + uiPreviousDeviceMode=uiTechnicalDataSet[DEVICE_MODE_TEC]; + } + + + switch(uiTechnicalDataSet[DEVICE_MODE_TEC]) + { + default: + case VENTILATION_MODE: + { + if (enVentilationMode==PS_MODE) + ManagePACVVentilation(TRUE); + else if (enVentilationMode==APCV_MODE) + ManagePACVVentilation(FALSE); + else if (enVentilationMode==AVC_MODE) + ManageVolumetricVentilation(); + else if (enVentilationMode==CPAP_MODE) + ManageCPAPVentilation(); + break; + } + case ONE_CST_PWM_MODE: + { + ManageOneCstPWM(); + break; + } + case TWO_CST_PWM_MODE: + { + Manage2CstPWM(); + break; + } + case CST_SPEED_MODE: + { + ManageCstSpeed(); + break; + } + case FLOW_CAL_MODE: + { + ManageFlowCalibration(); + break; + } + case PRESSURE_CAL_MODE: + { + ManagePressureCalibration(); + break; + } + case PRESSURE_CST_MODE: + { + ManageCstPressure(); + break; + } + } + } +} + + +/******************************************************************************* +* Function Name : StartStopVentilation +* Description : Detect a start/stop ventilation request +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void StartStopVentilation(void) +{ + #ifndef TEMPERATURE_TRENDS + opstatus_t byOpStatus; + #endif + + // Check if an alarm must stop the ventilation + ucStopVentilationAlarmNumber=ReadStopVentilationAlarmNumber(); + + #ifndef TEMPERATURE_TRENDS + if (uiTechnicalDataSet[START_STOP_VENTILATION]==1 && ucStopVentilationAlarmNumber==SIZE_BLOWER_ALARM) + { + // *************** VENTILATION is ON ************** + if (bMemoStartVentilation==FALSE) + { + switch(ucStartVentilationScheduler) + { + default: + case 0: + { + // Active the HW safety system + ControlHW(BLOWER_ON__PAT_CPLD); + ucStartVentilationScheduler++; + break; + } + case 1: + { + // Pat CPLD (WDI_CPLD), STOP_BLOWER=1 + ControlHW(BLOWER_ON__PAT_CPLD); + + // Read Offset of the Blower current + ComputeADCBlowerCurrent(TRUE); + + ucStartVentilationScheduler++; + break; + } + case 2: + { + // Pat CPLD (WDI_CPLD), STOP_BLOWER=1 + ControlHW(BLOWER_ON__PAT_CPLD); + + // Open motor driver + byOpStatus=SS_Xopen(mdrv); + if (byOpStatus==OPSTATUS_FAIL) + { + uiFlagsAlarm[ALARM_FLAGS2]|=MOTOR_FAILURE_ALARM_MASK; + ucStartVentilationScheduler=0; + } + else if (byOpStatus==OPSTATUS_OK) + { + // Force init settings and variables + uiPreviousDeviceMode=0xFF; + + uiTempo1min=TEMPO_1MIN; + #ifdef DATA_LOGGING + uiTrendsSampleTime=RECORD_TRENDS_SAMPLE_TIME; + #endif // DATA_LOGGING + + // Check if ventilation mode is activated + if (uiTechnicalDataSet[DEVICE_MODE_TEC]!=VENTILATION_MODE) + uiFlagsAlarm[ALARM_FLAGS2]|=DEVICE_MODE_ALARM_MASK; + + bMemoStartVentilation=TRUE; + ucStartVentilationScheduler=0; + } + break; + } + } + } + // --- Check Safety system for Motor transistors ---- + else if (IsMotorOK()==FALSE) + { + ControlHW(BLOWER_OFF__STOP_PAT_CPLD); + uiFlagsAlarm[ALARM_FLAGS2]|=MOTOR_FAILURE_ALARM_MASK; + } + // --- Test safety system thanks to the "STOP_BLOWER" Input pin + else if (TestStopBlowerInputPin()==OPSTATUS_OK) + { + ControlHW(BLOWER_ON__PAT_CPLD); + uiFlagsAlarm[ALARM_FLAGS2]&=(~HW_SAFETY_ALARM_MASK); + } + else + { + uiFlagsAlarm[ALARM_FLAGS2]|=HW_SAFETY_ALARM_MASK; + } + } + else + #endif // #ifndef TEMPERATURE_TRENDS + { + // *************** VENTILATION is OFF ************** + uiFlagsAlarm[ALARM_FLAGS2]&=(~DEVICE_MODE_ALARM_MASK); + + if (ucStopVentilationAlarmNumber!=SIZE_BLOWER_ALARM) + { + // Stop patting CPLD (WDI_CPLD=0), STOP_BLOWER=0 + ControlHW(BLOWER_OFF__STOP_PAT_CPLD); + } + else + { + // Pat CPLD (WDI_CPLD), STOP_BLOWER=1 + ControlHW(BLOWER_ON__PAT_CPLD); + + // ---- Test STOP_ACTUATOR Input pin Status + if (TestStopBlowerInputPin()==OPSTATUS_FAIL) + uiFlagsAlarm[ALARM_FLAGS2]|=HW_SAFETY_ALARM_MASK; + else + uiFlagsAlarm[ALARM_FLAGS2]&=(~HW_SAFETY_ALARM_MASK); + } + + if (bMemoStartVentilation==TRUE) + { + StopAllActuators(); + ClearAllVentilationAlarms(); + ClearAllMeasures(); + } + + uiTechnicalDataSet[START_STOP_VENTILATION]=0; + bMemoStartVentilation=FALSE; + #ifndef TEMPERATURE_TRENDS + ucStartVentilationScheduler=0; + #endif + bDisableMaroubraCommCommunication=FALSE; + } +} +#endif // #ifndef C_M3_DEVICETEST_TARGET + + +/******************************************************************************* +* Function Name : ComputeTe +* Description : Compute expiratory time +* Input : uiF = Breath frequency (bpm) + uiTi = Inspiratory time (ms) +* Output : Expiratory time (ms) +* Return : None +*******************************************************************************/ +#ifndef C_M3_DEVICETEST_TARGET +u16 ComputeTe(u16 uiF, u16 uiTi) +{ + u16 uiTtot; + u16 uiTeTemp=TE_SET_MIN; + + if (uiF!=0) + { + // Compute Ttotal + uiTtot=60000/uiF; + if (uiTtot>uiTi) + { + uiTeTemp=uiTtot-uiTi; + if (uiTeTemp<TE_SET_MIN) + uiTeTemp=TE_SET_MIN; + } + } + else + { + // F=0 => Te=2xTi + uiTeTemp=uiTi<<1; + } + return(uiTeTemp); +} + + +/******************************************************************************* +* Function Name : UpdateSettings +* Description : Update the settings zone with the temporary settings zone +* Input : None +* Output : None +* Return : TRUE if the ventilation mode has changed +*******************************************************************************/ +bool UpdateSettings(void) +{ + u8 ucIndex; + + // Take into account a modification of the PEEP + if (uiVentilationSet[PEEP_SET]!=uiVentilationSetTemp[PEEP_SET] || uiVentilationSet[PS_CPAP_SET]!=uiVentilationSetTemp[PS_CPAP_SET]) + uiMemoPWMDuringDisconnection=0; + + // Transfert data from the setting temporary zone to the settings zone + for (ucIndex=0; ucIndex<SIZE_LRS_GROUP; ucIndex++) + uiVentilationSet[ucIndex]=uiVentilationSetTemp[ucIndex]; + + // Update barometric expiratory time + uiTeBaroSet=ComputeTe(uiVentilationSet[BREATH_RATE_BARO_SET], uiVentilationSet[TI_BARO_SET]); + + // Update volumetric expiratory time + uiTeVoluSet=ComputeTe(uiVentilationSet[BREATH_RATE_VOLU_SET], uiVentilationSet[TI_VOLU_SET]); + + // Update Tube configuration type + enTubeConfigType=enTubeConfigTypeTemp; + + // Update Patient type + uiPatientType=uiPatientTypeTemp; + + // Update Ventilation mode + if (enVentilationMode!=enVentilationModeTemp) + { + enVentilationMode=enVentilationModeTemp; + InitVentilation(); + return(TRUE); + } + return(FALSE); +} + + +/******************************************************************************* +* Function Name : ApplyNewVentilationMode +* Description : Update settings and init variables if the ventilation mode has changed +* Input : None +* Output : None +* Return : TRUE if new ventilation mode is applied +*******************************************************************************/ +bool ApplyNewVentilationMode(void) +{ + if (fUpdateTheSettings==TRUE) + { + fUpdateTheSettings=FALSE; + if (UpdateSettings()==TRUE) + { + InitVentilation(); + return(TRUE); + } + } + return(FALSE); +} + + +/******************************************************************************* +* Function Name : ComputeInspiratoryFlowSetPointInAVC +* Description : Compute: + - the inspiratory flow max set point + - the inspiratory flow min set point + - the flow step between the flow max and the flow min during Ti +* Input : uiTypeOfPatient = Adult or Pedia + uiVtc = set point in volume (ml) + uiTi = Ti set point (ms) + uiFlowShape = Flow shape (0 to 4) +* Output : uiMaxFlow = the inspiratory flow max set point (cl/min => 100=1l/min) + uiMinFlow = the inspiratory flow min set point (cl/min => 100=1l/min) + uiFlowStep = the flow step between the flow max and the flow min during Ti (cl/min => 100=1l/min) +* Return : None +*******************************************************************************/ +void ComputeInspiratoryFlowSetPointInAVC(u16 uiTypeOfPatient, u16 uiVtc, u16 uiTi, u16 uiFlowShape, u32 *ulMaxFlow, u32 *ulMinFlow, u32 *ulFlowStep) +{ + u32 ulFlowMax; + u32 ulFlowMin; + u32 ulMaxMaxFlow; + u32 ulMinMinFlow; + u16 uiTiMin; + u32 ulFlowStepTemp; + + // Define min/max flow + if (uiTypeOfPatient==PATIENT_ADULT) + { + ulMinMinFlow=InspiratoryFlowSet_A_MIN; + ulMaxMaxFlow=InspiratoryFlowSet_A_MAX; + uiTiMin=TiVoluSet_A_MIN; + } + else + { + ulMinMinFlow=InspiratoryFlowSet_P_MIN; + ulMaxMaxFlow=InspiratoryFlowSet_P_MAX; + uiTiMin=TiVoluSet_P_MIN; + } + + // Check Ti + if (uiTi==0) + uiTi=uiTiMin; + + // Compute flow max + switch(uiFlowShape) + { + default: + case 0: + { + ulFlowMax=((u32)uiVtc*6000)/uiTi; + break; + } + case 1: + { + ulFlowMax=((u32)uiVtc*7500)/uiTi; + break; + } + case 2: + { + ulFlowMax=((u32)uiVtc*9000)/uiTi; + break; + } + case 3: + { + ulFlowMax=((u32)uiVtc*10500)/uiTi; + break; + } + case 4: + { + ulFlowMax=((u32)uiVtc*12000)/uiTi; + break; + } + } + + // Limitation of the max flow + if (ulFlowMax>ulMaxMaxFlow) + ulFlowMax=ulMaxMaxFlow; + + // Limitation of the min flow + if (ulFlowMax<ulMinMinFlow) + ulFlowMax=ulMinMinFlow; + + // Factor 100 on flow max (and flow min and flow step) + ulFlowMax*=100; + + // Compute flow min and flow step + switch(uiFlowShape) + { + default: + case 0: + { + ulFlowMin=ulFlowMax; + break; + } + case 1: + { + ulFlowMin=(ulFlowMax*3)>>2; + break; + } + case 2: + { + ulFlowMin=ulFlowMax>>1; + break; + } + case 3: + { + ulFlowMin=ulFlowMax>>2; + break; + } + case 4: + { + ulFlowMin=0; + break; + } + } + + // Max flow + *ulMaxFlow=ulFlowMax; + + // Min flow + *ulMinFlow=ulFlowMin; + + // Flow Step + ulFlowStepTemp=(ulFlowMax-ulFlowMin)/uiTi; + //if (uiFlowStepTemp==0 && uiFlowShape!=0) uiFlowStepTemp=1; + *ulFlowStep=ulFlowStepTemp; +} + + + +/******************************************************************************* +* Function Name : TestTriggerExpiratoire +* Description : Manage the expiratory trigger +* Input : ucValeurSeuil = threshold (% of the flow max) to reach in order to cycle +* Output : None +* Return : TRUE if cycling active +*******************************************************************************/ +unsigned char TestTriggerExpiratoire(unsigned char ucValeurSeuil, unsigned int uiPressureSetting) +{ + unsigned char ucSeuil=ucValeurSeuil; + unsigned int uiCalculTemp; + int16_t iConductanceBaseLine=UpdateInspiratoryConductanceAverage(); + // Management automatic expiratory trigger + ucTempoTriggerExpiAuto--; + if (ucTempoTriggerExpiAuto==0) + { + ucTempoTriggerExpiAuto=TEMPO_TRIGGER_EXPI; + ucExpiTriggerTreshold++; + } + + // Test si flow<0?? + if (iBlowerFlowSmoothingMes<0) + { + return(TRUE); + } + // Test if deacring flow?? + else if (iBlowerFlowSmoothingMes<iBlowerFlowSmoothingMaxMes) + { + // Test if Trigger Expi=AUTO ?? + if ((ucValeurSeuil==ExpiTriggerSet_A_MAX && uiPatientType==PATIENT_ADULT) || + (ucValeurSeuil==ExpiTriggerSet_P_MAX && uiPatientType==PATIENT_PEDIA)) + ucSeuil=ucExpiTriggerTreshold; + + u16 conducThresh = 2000; + + if(enTubeConfigType == 1 ) + conducThresh = 750; + else if(enTubeConfigType == 2) + conducThresh = 1500; + + // Test if cycling or not + uiCalculTemp=((unsigned long)iBlowerFlowSmoothingMaxMes*ucSeuil)/100; + if (uiCalculTemp>iBlowerFlowSmoothingMes) + return(TRUE); + else if (uiProximalPressureMes>(uiPressureSetting+20)) + return(TRUE); + else if (uiConductanceCalc < (iConductanceBaseLine - conducThresh)) + { + ResetInspiratoryConductanceAverage(); + return(TRUE); + } + } + return(FALSE); +} + + +/******************************************************************************* +* Function Name : TestInspiratoryTrigger +* Description : Manage the inspiratory trigger +* Input : bSpont = TRUE if spontaneous mode +* uiTe = expiration time (ms) +* uiFlowTreshold = flow threshold (dl/min) +* Output : None +* Return : TRUE if cycling active +*******************************************************************************/ +bool TestInspiratoryTrigger(bool bSpont, u16 uiTe, u16 uiFlowTreshold) +{ + //int16_t iInspiratoryFlowDeltaAverage; + //int16_t iDeltaOfTheDelta1, iDeltaOfTheDelta2, iDeltaOfTheDelta3, iDeltaOfTheDelta4; + bool bTrigger=FALSE; + //int16_t iVirtualFlow; + int16_t iConductanceBaseLine; + + // Manual breath management + if (uiTe>TE_SET_MIN) + { + if (bManualBreath==TRUE) + { + bManualBreath=FALSE; + bDisplayInspiratoryTrigger=TRUE; + return(TRUE); + } + } + + // Trigger management + if ((bSpont==TRUE) || + (bSpont==FALSE && uiFlowTreshold<InspiTriggerFlowSet_A_MAX && uiPatientType==PATIENT_ADULT) || + (bSpont==FALSE && uiFlowTreshold<InspiTriggerFlowSet_P_MAX && uiPatientType==PATIENT_PEDIA)) + { + // Init scheduler + if (uiTe==1) + { + ucInspiTriggerScheduler=0; + iInspiratoryFlowMin=0; + ucMinFlowCounter=NUMBER_MIN_FLOW_VALUE; + ucCounterTriggerValid=NUMBER_TRIGGER_VALID; + bDetectionConstantFlow=FALSE; + } + + iConductanceBaseLine=UpdateInspiratoryConductanceAverage(); + // Manage detection phase + switch(ucInspiTriggerScheduler) + { + default: + case 0: + { + // Update the buffer on the Inspiratory flow average + + // Detect min flow + if (iBlowerFlowSmoothingMesForTrigger<iInspiratoryFlowMin) + { + iInspiratoryFlowMin=iBlowerFlowSmoothingMesForTrigger; + ucMinFlowCounter=NUMBER_MIN_FLOW_VALUE; + } + else + { + ucMinFlowCounter--; + if (ucMinFlowCounter==0) + ucInspiTriggerScheduler=1; + } + break; + } + case 1: + { + //ucTriggerNumber=0; + + if (uiTe>TE_SET_MIN) + { +// // Fast trigger management +// if (iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-50]<=iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-25]) +// { +// iVirtualFlow=(iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-25]<<1)-iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-50]; +// if (iBlowerFlowSmoothingMesForTrigger>=(iVirtualFlow+(int16_t)(uiFlowTreshold*7))) +// { +// //ucTriggerNumber=1; +// //if (fBlockCloseLoop==FALSE) +// bTrigger=TRUE; +// } +// } +// if (bTrigger==FALSE && iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-100]<=iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-50]) +// { +// iVirtualFlow=(iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-50]<<1)-iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-100]; +// if (iBlowerFlowSmoothingMesForTrigger>=(iVirtualFlow+(int16_t)(uiFlowTreshold*15))) +// { +// //ucTriggerNumber=2; +// //if (fBlockCloseLoop==FALSE) +// bTrigger=TRUE; +// } +// } +// +// // Slow trigger management +// if (TestInspiratorySlowTrigger(iFlowBaseLine, uiFlowTreshold*10)==TRUE) +// { +// //ucTriggerNumber=3; +// bTrigger=TRUE; +// } + //Conductance Trigger + if(uiConductanceCalc >= (iConductanceBaseLine + 2000)) + { + bTrigger = TRUE; + } + + // Trigger occurs?? + if (bTrigger==TRUE) + { + ucCounterTriggerValid--; + if (ucCounterTriggerValid==0) + { + bDisplayInspiratoryTrigger=TRUE; + ResetInspiratoryConductanceAverage(); + return(TRUE); + } + } + else + ucCounterTriggerValid=NUMBER_TRIGGER_VALID; + } + break; + } + } + } + return(FALSE); +} + +/******************************************************************************* +* Function Name : UpdateInspiratoryConductanceAverage +* Description : Fill the buffer with the expiratory conductance and compute the average +* Input : None +* Output : None +* Return : Inspiratory flow average +*******************************************************************************/ +u16 conducIndex = 0; +int32_t lSumConductance = 0; +bool bufFilled = FALSE; + +int16_t UpdateInspiratoryConductanceAverage(void) +{ + int16_t oldValue = iBufferIFlow[conducIndex]; + iBufferIFlow[conducIndex] = uiConductanceCalc; + lSumConductance += uiConductanceCalc; + conducIndex++; + + if(conducIndex > SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER) + { + conducIndex = 0; + bufFilled = TRUE; + } + + if(bufFilled) + { + lSumConductance -= oldValue; + return (lSumConductance/SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER); + } + else + { + return (lSumConductance/conducIndex); + } +} + +/******************************************************************************* +* Function Name : ResetInspiratoryConductanceAverage +* Description : Fill the buffer with the expiratory conductance and compute the average +* Input : None +* Output : None +* Return : Inspiratory flow average +*******************************************************************************/ + +void ResetInspiratoryConductanceAverage(void) +{ + conducIndex = 0; + lSumConductance = 0; + bufFilled = FALSE; +} + +/******************************************************************************* +* Function Name : UpdateInspiratoryFlowAverage +* Description : Fill the buffer with the inspiratory flow and compute the average +* Input : None +* Output : None +* Return : Inspiratory flow average +*******************************************************************************/ +int16_t UpdateInspiratoryFlowAverage(void) +{ + u16 uiIndex; + int32_t lSumIFlow=0; + + // Roll the buffer + for(uiIndex=1; uiIndex<SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER; uiIndex++) + { + iBufferIFlow[uiIndex-1]=iBufferIFlow[uiIndex]; // Upate the Inspiratory Flow buffer + lSumIFlow+=iBufferIFlow[uiIndex-1]; // Sum the Inspiratory Flow + } + + // Add new flow value + iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-1]=iBlowerFlowSmoothingMesForTrigger; // Upate the Inspiratory Flow buffer + lSumIFlow+=iBlowerFlowSmoothingMesForTrigger; // Sum the Inspiratory Flow + + return(lSumIFlow/SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER); +} + + +/******************************************************************************* +* Function Name : TestInspiratorySlowTrigger +* Description : Compute flow base line and test trigger +* Input : FlowTreshold = flow threshold (cl/min) +* Output : None +* Return : TRUE if trigger occurs +*******************************************************************************/ +bool TestInspiratorySlowTrigger(int16_t iTheFlowBaseLine, u16 uiFlowTreshold) +{ + int16_t iFlowDelta1, iFlowDelta2, iFlowDelta3; + + if (bDetectionConstantFlow==FALSE) + { + // Detection constant flow + if (iBufferIFlow[0]<iTheFlowBaseLine) + iFlowDelta1=iTheFlowBaseLine-iBufferIFlow[0]; + else + iFlowDelta1=iBufferIFlow[0]-iTheFlowBaseLine; + + if (iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER>>1]<iTheFlowBaseLine) + iFlowDelta2=iTheFlowBaseLine-iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER>>1]; + else + iFlowDelta2=iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER>>1]-iTheFlowBaseLine; + + if (iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-1]<iTheFlowBaseLine) + iFlowDelta3=iTheFlowBaseLine-iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-1]; + else + iFlowDelta3=iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-1]-iTheFlowBaseLine; + + if (iFlowDelta1<60 && iFlowDelta2<60 && iFlowDelta3<60) + { + iFlowBaseLineReference=iTheFlowBaseLine; + bDetectionConstantFlow=TRUE; + } + } + else + { + // Detect trigger + if (iBlowerFlowSmoothingMesForTrigger>=(iFlowBaseLineReference+(int16_t)uiFlowTreshold)) + { + return(TRUE); + } + } + return(FALSE); +} + + +/******************************************************************************* +* Function Name : ApplyDefaultValueToTemporaryVentilationSettings +* Description : Init temporary ventilation settings with default values +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void ApplyDefaultValueToTemporaryVentilationSettings(void) +{ + u8 ucIndex; + + enVentilationModeTemp=VentilationMode_DEF; + uiPatientTypeTemp=PatientType_DEF; + enTubeConfigTypeTemp=(enMaroubraTubeConfigurationList)ReturnDefaultTubeConfiguration(VentilationMode_DEF); + + // Init all temporary settings + if (uiPatientType==PATIENT_ADULT) + { + for (ucIndex=0; ucIndex<SIZE_LRS_GROUP; ucIndex++) + uiVentilationSetTemp[ucIndex]=sLRSGroup[ucIndex].uiDefault_Adult; + } + else + { + for (ucIndex=0; ucIndex<SIZE_LRS_GROUP; ucIndex++) + uiVentilationSetTemp[ucIndex]=sLRSGroup[ucIndex].uiDefault_Pedia; + } +} + + +/******************************************************************************* +* Function Name : CheckTemporaryVentilationSettingRange +* Description : Check all the temporary settings range +* Input : None +* Output : None +* Return : FALSE if one the settings is out of range +*******************************************************************************/ +opstatus_t CheckTemporaryVentilationSettingRange(void) +{ + u8 ucIndex; + + if ((uiPatientTypeTemp==PATIENT_PEDIA || uiPatientTypeTemp==PATIENT_ADULT) && enVentilationModeTemp<NUMBER_OF_MODE && enTubeConfigTypeTemp<NUMBER_OF_TUBE_CONFIGURATION) + { + for (ucIndex=0; ucIndex<SIZE_LRS_GROUP; ucIndex++) + { + // Check data range + if (uiPatientTypeTemp==PATIENT_PEDIA) + { + if (uiVentilationSetTemp[ucIndex]<sLRSGroup[ucIndex].uiMin_Pedia) + return(OPSTATUS_FAIL); + else if (uiVentilationSetTemp[ucIndex]>sLRSGroup[ucIndex].uiMax_Pedia) + return(OPSTATUS_FAIL); + } + else + { + if (uiVentilationSetTemp[ucIndex]<sLRSGroup[ucIndex].uiMin_Adult) + return(OPSTATUS_FAIL); + else if (uiVentilationSetTemp[ucIndex]>sLRSGroup[ucIndex].uiMax_Adult) + return(OPSTATUS_FAIL); + } + } + return(OPSTATUS_OK); + } + return(OPSTATUS_FAIL); +} + + + +/******************************************************************************* +* Function Name : ApplyDefaultValueToTechnicalSettings +* Description : Init technical settings with default values +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void ApplyDefaultValueToTechnicalSettings(void) +{ + u8 ucIndex; + + // Init all temporary settings + for (ucIndex=0; ucIndex<SIZE_LRTS_GROUP; ucIndex++) + uiTechnicalDataSet[ucIndex]=sLRTSGroup[ucIndex].uiDefault; +} + + +/******************************************************************************* +* Function Name : CheckTechnicalSettingsRange +* Description : Check all the technical settings range +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void CheckTechnicalSettingsRange(void) +{ + u8 ucIndex; + bool fError=FALSE; + + for (ucIndex=0; ucIndex<SIZE_LRTS_GROUP; ucIndex++) + { + if (uiTechnicalDataSet[ucIndex]<sLRTSGroup[ucIndex].uiMin || uiTechnicalDataSet[ucIndex]>sLRTSGroup[ucIndex].uiMax) + { + uiTechnicalDataSet[ucIndex]=sLRTSGroup[ucIndex].uiDefault; + fError=TRUE; + //break; + } + } + + if (fError==TRUE) + uiFlagsAlarm[ALARM_FLAGS2]|=TECHNICAL_SETTINGS_RANGE_ALARM_MASK; + else + uiFlagsAlarm[ALARM_FLAGS2]&=(~TECHNICAL_SETTINGS_RANGE_ALARM_MASK); +} + + +/******************************************************************************* +* Function Name : CheckFlowLUTRange +* Description : Check the flow LUT +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void CheckFlowLUTRange(void) +{ + u16 uiIndex; + bool fError=FALSE; + + if (stLUTFlowSensor.uiLUT_TableSize<(FLOW_CALIB_NUMBER_OF_SAMPLES>>1) || stLUTFlowSensor.uiLUT_TableSize>FLOW_CALIB_NUMBER_OF_SAMPLES) + { + ApplyDefaultFlowLUT(); + fError=TRUE; + } + else + { + for (uiIndex=1; uiIndex<stLUTFlowSensor.uiLUT_TableSize; uiIndex++) + { + if (stLUTFlowSensor.uiFlowValue[uiIndex]<=stLUTFlowSensor.uiFlowValue[uiIndex-1] || + stLUTFlowSensor.uiFlowSensorTicks[uiIndex]<=stLUTFlowSensor.uiFlowSensorTicks[uiIndex-1]) + { + ApplyDefaultFlowLUT(); + fError=TRUE; + break; + } + } + } + + if (fError==TRUE) + uiFlagsAlarm[ALARM_FLAGS2]|=NO_FLOW_LUT_ALARM_MASK; + else + uiFlagsAlarm[ALARM_FLAGS2]&=(~NO_FLOW_LUT_ALARM_MASK); +} + + +/******************************************************************************* +* Function Name : ApplyDefaultFlowLUT +* Description : Apply default value for the flow LUT +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void ApplyDefaultFlowLUT(void) +{ + u16 uiIndex; + + stLUTFlowSensor.uiLUT_TableSize=stDefaultLUTFlowSensor.uiLUT_TableSize; + for (uiIndex=0; uiIndex<FLOW_CALIB_NUMBER_OF_SAMPLES; uiIndex++) + { + stLUTFlowSensor.uiFlowValue[uiIndex]=stDefaultLUTFlowSensor.uiFlowValue[uiIndex]; + stLUTFlowSensor.uiFlowSensorTicks[uiIndex]=stDefaultLUTFlowSensor.uiFlowSensorTicks[uiIndex]; + } +} + + +/******************************************************************************* +* Function Name : ReturnDefaultTubeConfiguration +* Description : The default tubing configuration according to the current ventilation mode +* Input : a ventilation mode +* Output : None +* Return : The tube configuration +*******************************************************************************/ +u16 ReturnDefaultTubeConfiguration(u16 uiMode) +{ + u8 ucIndex; + + for (ucIndex=0; ucIndex<NUMBER_OF_TUBE_CONFIGURATION; ucIndex++) + { + if (ucTubeConfigurationTable[ucIndex][uiMode]==TUBE_DEFAULT) + { + return(ucIndex); + } + } + return(0); +} + + +/******************************************************************************* +* Function Name : ApplyAllDefaultValues +* Description : Apply all default values in the technical and settings zones +* : BE CARFUL this function call "ControlHW" function +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void ApplyAllDefaultValues(void) +{ + // Init ventilation settings + ApplyDefaultValueToTemporaryVentilationSettings(); + + // Init technical settings + ApplyDefaultValueToTechnicalSettings(); + + // Init flow LUT + ApplyDefaultFlowLUT(); + + // Default value for the device/patient time counter + ulDeviceTimeCounter=0; + ulPatientTimeCounter=0; + + // Default value for the blower revolution counter + ulBlowerRevolutionCounter=0; + + bComputeOffsetSensors=TRUE; +} +#endif // C_M3_DEVICETEST_TARGET + +/******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/ + + +