Started a gui menuflow

Dependencies:   LCD_DISCO_F429ZI mbed TS_DISCO_F429ZI BSP_DISCO_F429ZI

Ventilation.c

Committer:
Clancy_SENDSOR
Date:
2020-06-09
Revision:
2:5828e6917e75

File content as of revision 2:5828e6917e75:


/* 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****/