Started a gui menuflow

Dependencies:   LCD_DISCO_F429ZI mbed TS_DISCO_F429ZI BSP_DISCO_F429ZI

Revision:
3:b029a3f73a9e
Parent:
2:5828e6917e75
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Ventilation.txt	Thu Jun 11 22:55:06 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****/
+
+
+