Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: LCD_DISCO_F429ZI mbed TS_DISCO_F429ZI BSP_DISCO_F429ZI
Revision 2:5828e6917e75, committed 2020-06-09
- Comitter:
- Clancy_SENDSOR
- Date:
- Tue Jun 09 22:57:20 2020 +0000
- Parent:
- 1:35eb0c8fa2c0
- Child:
- 3:b029a3f73a9e
- Commit message:
- added ventilation files
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Monitoring.c Tue Jun 09 22:57:20 2020 +0000
@@ -0,0 +1,1375 @@
+*********************************************************************/
+
+/* Includes ------------------------------------------------------------------*/
+#define EXTERN extern
+#include "SS.h"
+#include "main.h"
+#include "_ss_pwm.h"
+#include "_SS_I2CX_Drivers.h"
+#include "_SS_I2CX_SDP600.h"
+#include "_SS_I2CX_X201641.h"
+#include "Ventilation.h"
+#include "MotorTempTable.h"
+#include "_SS_FlowComputer.h"
+#include "_SS_TSI_4040.h"
+#include "_SS_Data_Logging.h"
+#include "_SS_OnOffActioner.h"
+#undef EXTERN
+
+#define INIT_VARIABLES
+#define EXTERN
+#include "Monitoring.h"
+#undef EXTERN
+#undef INIT_VARIABLES
+
+
+// *********************** Register locations **********************************
+#define DMA_IFCR1 (*(volatile uint32_t *)0x40020004)
+#define DMA_CCR1 (*(volatile uint32_t *)0x40020008)
+#define DMA_CNTDR1 (*(volatile uint32_t *)0x4002000c)
+#define DMA_CPAR1 (*(volatile uint32_t *)0x40020010)
+#define DMA_CMAR1 (*(volatile uint32_t *)0x40020014)
+
+#define ADC1_SR (*(volatile uint32_t *)0x40012400)
+#define ADC1_SQR1 (*(volatile uint32_t *)0x4001242C)
+#define ADC1_SQR2 (*(volatile uint32_t *)0x40012430)
+#define ADC1_SQR3 (*(volatile uint32_t *)0x40012434)
+#define ADC1_LTR (*(volatile uint32_t *)0x40012428)
+#define ADC1_HTR (*(volatile uint32_t *)0x40012424)
+#define ADC1_CR1 (*(volatile uint32_t *)0x40012404)
+#define ADC1_CR2 (*(volatile uint32_t *)0x40012408)
+
+
+// ************************* ADC CONFIGURATION CHANNELS ************************
+#define FREE_MEAS_CHANNEL 0
+#define PPROX_MEAS_CHANNEL 1
+#define CURRENT_MEAS_CHANNEL 2
+#define ALIM_24V_MEAS_CHANNEL 6
+#define TEMP_PHASE_A 5
+#define TEMP_PHASE_B 4
+#define TEMP_PHASE_C 3
+
+// ********************* 24V ALARM MANAGEMENT **********************************
+#ifndef C_M3_DEVICETEST_TARGET
+
+#endif
+
+
+
+// ************************ I2C SENSORS MANAGEMENT *****************************
+#ifndef C_M3_DEVICETEST_TARGET
+ #define READING_NO_SENSOR 0
+ #define READING_FLOW_SENSORS 1
+ //#define READING_PRESSURE_SENSORS 2
+ #define STOP_READING_FLOW_SENSORS 3
+ #define START_READING_FLOW_SENSORS 4
+ #define NUMBER_I2C_REBOOT 3
+
+ #define FLOW_SENSOR_READING 0
+ #define FLOW_SENSOR_OK 1
+ #define FLOW_SENSOR_FAIL 2
+ static u8 ucStatusSDP600=FLOW_SENSOR_READING;
+ static u8 ucStatusX201641=FLOW_SENSOR_READING;
+
+ static volatile u8 ucReadingFlowSensor=START_READING_FLOW_SENSORS; // I2Cx sensor managment
+ static u8 ucCounterFlowErrorMeasurement=0;
+ static u16 uiTotalCounterFlowErrorMeasurement=0;
+
+ #if defined(SDP600_USED_I2C1_BUS) || defined(X201641_USED_I2C1_BUS)
+ #ifdef DISPLAY_AVERAGE_BLOWER_RAW_FLOW
+ #define SMOOTH_BLOWER_RAW_FLOW_COUNTER 50
+ static u16 uiBlowerRAWFlowTemp[SMOOTH_BLOWER_RAW_FLOW_COUNTER];
+ static u8 ucIndexBlowerRAWFlowSmooth=0;
+
+ #define BLOWER_RAW_FLOW_SAMPLES_NUMBER 200
+ static u32 ulSumBlowerFlowRAWMes=0;
+ static u16 uiBlowerRAWFlowSamplesCounter=BLOWER_RAW_FLOW_SAMPLES_NUMBER;
+ #endif
+
+ #define SMOOTH_BLOWER_FLOW_LARGE_COUNTER 75//100 // MUST BE HIGHER THAN SMOOTH_BLOWER_FLOW_SMALL_COUNTER
+ #define SMOOTH_BLOWER_FLOW_SMALL_COUNTER 15 // MUST BE LOWER THAN SMOOTH_BLOWER_FLOW_LARGE_COUNTER
+ static int16_t iTempBlowerFlowForSmallSmooth[SMOOTH_BLOWER_FLOW_SMALL_COUNTER];
+ static int16_t iTempBlowerFlowForLargeSmooth[SMOOTH_BLOWER_FLOW_LARGE_COUNTER];
+ static u8 ucIndexSmallBlowerFlowSmooth=0;
+ static u8 ucIndexLargeBlowerFlowSmooth=0;
+
+ static int16_t idConductancedtSmooth[SMOOTH_BLOWER_FLOW_SMALL_COUNTER];
+ #endif // (SDP600_USED_I2C1_BUS) || (X201641_USED_I2C1_BUS)
+#endif // C_M3_DEVICETEST_TARGET
+
+
+
+// ****************** PROXIMAL PRESSURE SENSOR MANAGEMENT **********************
+#ifndef C_M3_DEVICETEST_TARGET
+ #define SMOOTH_PPROX_PRESSURE_COUNTER 40
+ static u8 ucIndexPproxPressureSmooth=0;
+ static u16 uiProximalPressureTemp[SMOOTH_PPROX_PRESSURE_COUNTER];
+#endif // C_M3_DEVICETEST_TARGET
+
+
+
+// ********************* MEASURES MANAGEMENT **********************************
+#ifndef C_M3_DEVICETEST_TARGET
+ // ---- Current measurement
+ static u32 ulSumCurrentADCMesFiltered=0;
+ static u32 ulCounterADC_FilteredBlowerCurrentMes=0;
+
+ // ---- Temperature measurement
+ static u32 ulADCSumBlowerTemperature=0;
+ static u16 uiTemperatureSamplesCounter=0;
+
+ #ifdef TEMPERATURE_TRENDS
+ #ifdef USE_FLOW_COMPUTER
+ #define FLOW_COMPUTER_CYCLE_DETECTION_TIMER 10 // 100ms
+ static u8 ucFlowComputerCycle=EXPIRATION_CYCLE;
+ static u16 uiFlowComputerCycleModificationTimer=FLOW_COMPUTER_CYCLE_DETECTION_TIMER;
+ #else
+ #define TIME_OUT_TEMPERATURE_MEASUREMENT 6000 // 60s
+ static u16 uiTimeOutTemperatureMeasurement=0;
+ #endif // #ifdef USE_FLOW_COMPUTER
+ static u32 ulADCSumTemperaturePhaseA=0;
+ static u16 uiADCTemperaturePhaseA;
+ static u32 ulADCSumTemperaturePhaseB=0;
+ static u16 uiADCTemperaturePhaseB;
+ static u32 ulADCSumTemperaturePhaseC=0;
+ static u16 uiADCTemperaturePhaseC;
+ #endif
+
+ // ---- Blower Speed measurment
+ static u32 ulSumTachoTicks=0;
+ static u32 ulCounterAverageMotorSpeed=0;
+
+ // --- Blower current Bessel filter
+ /*static u16 uiCurrentADCMesFilteredPrev2;
+ static u16 uiCurrentADCMesFilteredPrev1;
+ static u16 uiCurrentADCMesPrev2;
+ static u16 uiCurrentADCMesPrev1;
+ static u16 uiCurrentADCMesFiltered;*/
+
+ // --- Motor voltage
+ static u32 ulSumADC_MotorVoltage;
+ static u32 ulCounterADC_MotorVoltage;
+
+ // --- Temporary measurements
+ static u16 uiPproxMax;
+ static u16 uiVtiTemp;
+ static u16 uiVteTemp;
+ static u16 uiTiMesTemp;
+ static u16 uiTeMesTemp;
+#endif // #ifndef C_M3_DEVICETEST_TARGET
+
+
+#ifndef C_M3_DEVICETEST_TARGET
+ static u8 ucVentilationCycleCopy=INSPIRATION_CYCLE;
+ static int32_t lSumVti=0;
+ static int32_t lSumVte=0;
+ static u8 ucCounterAlarmVteMin=0;
+ static u8 ucCounterLPAlarm=0;
+#endif // C_M3_DEVICETEST_TARGET
+
+
+#define RCC_APB2RSTR (*(volatile uint32_t *)0x4002100c)
+
+
+// ***************** Functions **********************************************
+int16_t ComputeFlowInLitersPerMin(u16 uFlowRAW, bool bPositiveFlow);
+void ComputeBlowerPower(void);
+u16 ComputeTemperature(u16 uiADCMotorTemp, u16 *puiTempLUT, u16 uiTemperatureGain);
+
+
+/*******************************************************************************
+* Function Name : ADC1_init
+* Description : Init ADC1
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ADC1_init(void)
+{
+ // First perform De_init
+ DMA_CCR1 &= (uint32_t)(~0x1); // channel 1 disable
+ DMA_CCR1 = 0; // Reset Channelx control register
+ DMA_CNTDR1 = 0; // Reset Channelx remaining bytes register
+ DMA_CPAR1 = 0; // Reset Channelx peripheral address register
+ DMA_CMAR1 = 0; // Reset Channelx memory address register
+ DMA_IFCR1 |= DMA_Channel1_IT_Mask; // Reset interrupt pending bits
+ // end de-init
+
+ // Initialise DMA #1
+ DMA_CPAR1 = (uint32_t)(ADC1_BASE + 0x4c); // base adress of ADC1 ADC_DR register
+
+ DMA_CMAR1 = (unsigned long)(&uiADC_Value[0]);
+ DMA_CNTDR1 = NUMBER_ADC_CONVERSION; // numbers of data to be transfered
+
+ DMA_CCR1 = (3<<12) + (1<<10) + (1<<8) + (1<<7) + (1<<5) /*+ (1<<1)*/; // very high priority, mem size 16 bits, periph size 16 bits, mem increase,/* circular enabled*/, /*transfer complete IT*/
+ DMA_CCR1 |= 1; // channel 1 enable
+
+
+
+ // De-init of the ADC 1
+ RCC_APB2RSTR |= RCC_APB2Periph_ADC1; // enable
+ RCC_APB2RSTR &= ~RCC_APB2Periph_ADC1; // disable
+ // end De-init of the ADC 1
+
+ // Select channels of the regular group
+ #ifdef TEMPERATURE_TRENDS
+ ADC1_SQR1 = ((NUMBER_ADC_CONVERSION-1)<<20) + (FREE_MEAS_CHANNEL<<15) + (FREE_MEAS_CHANNEL<<10) + (FREE_MEAS_CHANNEL<<5) + FREE_MEAS_CHANNEL;
+ ADC1_SQR2 = (FREE_MEAS_CHANNEL<<25) + (FREE_MEAS_CHANNEL<<20) + (FREE_MEAS_CHANNEL<<15) + (FREE_MEAS_CHANNEL<<10) + (FREE_MEAS_CHANNEL<<5) + TEMP_PHASE_C;
+ ADC1_SQR3 = (TEMP_PHASE_B<<25) + (TEMP_PHASE_A<<20) + (FREE_MEAS_CHANNEL<<15) + (CURRENT_MEAS_CHANNEL<<10) + (ALIM_24V_MEAS_CHANNEL<<5) + PPROX_MEAS_CHANNEL;
+ #else
+ ADC1_SQR1 = ((NUMBER_ADC_CONVERSION-1)<<20) + (FREE_MEAS_CHANNEL<<15) + (FREE_MEAS_CHANNEL<<10) + (FREE_MEAS_CHANNEL<<5) + FREE_MEAS_CHANNEL;
+ ADC1_SQR2 = (FREE_MEAS_CHANNEL<<25) + (FREE_MEAS_CHANNEL<<20) + (FREE_MEAS_CHANNEL<<15) + (FREE_MEAS_CHANNEL<<10) + (FREE_MEAS_CHANNEL<<5) + FREE_MEAS_CHANNEL;
+ ADC1_SQR3 = (FREE_MEAS_CHANNEL<<25) + (FREE_MEAS_CHANNEL<<20) + (FREE_MEAS_CHANNEL<<15) + (CURRENT_MEAS_CHANNEL<<10) + (ALIM_24V_MEAS_CHANNEL<<5) + PPROX_MEAS_CHANNEL;
+ #endif
+
+ // 21 micros ADC conversion time
+ ADC1->SMPR2= (7<<27) + (7<<24) + (7<<21) + (7<<18) + (7<<15) + (7<<12) + (7<<9) + (7<<6) + (7<<3) + 7;
+ ADC1->SMPR1= (7<<21) + (7<<18) + (7<<15) + (7<<12) + (7<<9) + (7<<6) + (7<<3) + 7;
+
+ ADC1_CR1 = (1<<8); // Scan mode enabled
+ ADC1_CR2 = (1<<8); // DMA mode enabled
+
+ ADC1_CR2 |= 1; // start ADC1 - power-on
+
+ // Delay at least 1uSec for ADC calibration/stabilisation. See ADC documentation
+ // Stabilization time > 1uS for ADC, between power-on and start of conversion
+ // Give it 10uSecs just to be sure.
+ Delay100NS(100);
+
+ // Calibration of ADC1
+ ADC1_CR2 |= (1<<3); // reset calibration registers
+ ADC1_CR2 |= (1<<2); // Enable calibration
+ while ((ADC1_CR2 & (1<<2)) == (1<<2)); // Wait end of calibration
+
+ ADC1_CR2 |= 1; // start ADC1 - start conversions
+}
+
+
+/*******************************************************************************
+* Function Name : CheckAlimMotorVoltage
+* Description : Check the voltage range of the 24V power supply
+* Input : None
+* Output : None
+* Return : OPSTATUS_OK or OPSTATUS_FAIL
+*******************************************************************************/
+opstatus_t CheckAlimMotorVoltage(void)
+{
+ if (uiDCinADCMeas<271 || uiDCinADCMeas>2090)
+ return(OPSTATUS_FAIL); // <12V or >24V
+ return(OPSTATUS_OK);
+}
+
+
+/*******************************************************************************
+* Function Name : Compute24VMeasure
+* Description : Compute the 24V measure
+* Input : None
+* Output : None
+* Return : OPSTATUS_OK or OPSTATUS_FAIL
+*******************************************************************************/
+#ifndef C_M3_DEVICETEST_TARGET
+void Compute24VMeasure(void)
+{
+ u32 ulTemp;
+ u16 uiADC_BlowerVoltage;
+
+ if (bMemoStartVentilation==TRUE)
+ uiADC_BlowerVoltage=uiAverageADC_MotorVoltage;
+ else
+ uiADC_BlowerVoltage=uiDCinADCMeas;
+
+ ulTemp=((u32)uiADC_BlowerVoltage*100)/1452;
+ ulTemp+=100;
+ uiTechnicalDataMes[MOTOR_VOLTAGE_TEC_MES]=(u16)ulTemp;
+ uiMotorVoltageMes=(u16)ulTemp;
+}
+#endif
+
+void GetFirstMotorVoltageReading(void)
+{
+ uiAverageADC_MotorVoltage=uiDCinADCMeas;
+}
+/*******************************************************************************
+* Function Name : ComputeBlowerPower
+* Description : Compute the power of the blower
+* Input : None
+* Output : None
+* Return : OPSTATUS_OK or OPSTATUS_FAIL
+*******************************************************************************/
+void ComputeBlowerPower(void)
+{
+ uiTechnicalDataMes[MOTOR_POWER_TEC_MES]=((u32)uiMotorVoltageMes*uiBlowerCurrentMes)/10;
+}
+
+/*******************************************************************************
+* Function Name : SpeedMeasurement
+* Description : Return blower speed
+* Input : Tacho counter
+* Output : None
+* Return : Blower speed in RPM
+*******************************************************************************/
+u16 SpeedMeasurement(u16 uiTachoCounter)
+{
+ u16 uiSpeedTemp=65500;
+
+ if (uiTachoCounter>915)
+ uiSpeedTemp=(u16)(60000000UL/uiTachoCounter);
+
+ return(uiSpeedTemp);
+}
+
+
+/*******************************************************************************
+* Function Name : ReadADCInputs
+* Description : Read all ADC input (function calls every 1ms)
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ReadADCInputs(void)
+{
+ //u32 ulTerm1, ulTerm2, ulTerm3, ulTerm4, ulTerm5;
+
+ // ADC Pprox measurement
+ uiProximalPressureADCMes=uiADC_Value[ADC_PPROX_MES];
+
+ // ADC DCin measurement
+ uiDCinADCMeas=uiADC_Value[ADC_DCIN_MES];
+
+ // ADC Blower current measurement
+ ComputeADCBlowerCurrent(FALSE);
+
+ // ADC Free measurement
+ uiADCBlowerTemperatureMeas=uiADC_Value[ADC_FREE_MES];
+
+ #ifdef TEMPERATURE_TRENDS
+ uiADCTemperaturePhaseA=uiADC_Value[ADC_TEMP_PHASE_A];
+ uiADCTemperaturePhaseB=uiADC_Value[ADC_TEMP_PHASE_B];
+ uiADCTemperaturePhaseC=uiADC_Value[ADC_TEMP_PHASE_C];
+ #endif
+
+ // 2nd order Bessel Filter (Fcut-out=36Hz, sample rate=1KHz)
+ /*ulTerm1=(919UL*uiADCBlowerCurrent)>>6;
+ ulTerm2=(919UL*uiCurrentADCMesPrev1)>>5;
+ ulTerm3=(919UL*uiCurrentADCMesPrev2)>>6;
+ ulTerm4=(1427UL*uiCurrentADCMesFilteredPrev1)>>1;
+ ulTerm5=259UL*uiCurrentADCMesFilteredPrev2;
+
+ uiCurrentADCMesFiltered=(ulTerm1+ulTerm2+ulTerm3+ulTerm4-ulTerm5)>>9;
+ uiCurrentADCMesFilteredPrev2=uiCurrentADCMesFilteredPrev1;
+ uiCurrentADCMesFilteredPrev1=uiCurrentADCMesFiltered;
+ uiCurrentADCMesPrev2=uiCurrentADCMesPrev1;
+ uiCurrentADCMesPrev1=uiADCBlowerCurrent;*/
+
+
+ // 2nd order Bessel Filter (Fcut-out=150Hz, sample rate=1KHz)
+ /*ulTerm1=(1929UL*uiADCBlowerCurrent)>>1;
+ ulTerm2=(1929UL*uiCurrentADCMesPrev1);
+ ulTerm3=(1929UL*uiCurrentADCMesPrev2)>>1;
+ ulTerm4=(1095UL*uiCurrentADCMesFilteredPrev1)>>1;
+ ulTerm5=(2479UL*uiCurrentADCMesFilteredPrev2)>>3;
+
+ uiCurrentADCMesFiltered=(ulTerm1+ulTerm2+ulTerm3+ulTerm4-ulTerm5)>>12;
+ uiCurrentADCMesFilteredPrev2=uiCurrentADCMesFilteredPrev1;
+ uiCurrentADCMesFilteredPrev1=uiCurrentADCMesFiltered;
+ uiCurrentADCMesPrev2=uiCurrentADCMesPrev1;
+ uiCurrentADCMesPrev1=uiADCBlowerCurrent;*/
+
+ // --- Start new conversions
+ ADC1->CR2 |= 1;
+}
+
+#ifndef C_M3_DEVICETEST_TARGET
+/*******************************************************************************
+* Function Name : ComputeMeasurements
+* Description : Compute different measures
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ComputeMeasurements(void)
+{
+ // ---------------------- Measure Current (A) ----------------------------
+ uiBlowerCurrentMes=ComputeBlowerCurrentInAmper(uiADCBlowerCurrent);
+
+ // -------------------- Compute motor voltage (V) ------------------------
+ Compute24VMeasure();
+ ComputeBlowerPower();
+
+ // ---------------------- Others measurements ----------------------------
+ if (bMemoStartVentilation==TRUE)
+ {
+ // --- Motor speed (RPM) (every 10ms)
+ uiBlowerSpeedMes=SpeedMeasurement(uiTachoTimeTicks);
+ }
+}
+#endif // #ifndef C_M3_DEVICETEST_TARGET
+
+
+#ifndef C_M3_DEVICETEST_TARGET
+#ifdef TEMPERATURE_TRENDS
+/*******************************************************************************
+* Function Name : ComputeAverageOnMeasurements
+* Description : Average differents mesures : MUST BE CALLED EVERY 10ms
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ComputeAverageOnMeasurements(void)
+{
+ #ifdef USE_FLOW_COMPUTER
+ // ----------- USE THE FLOW COMPUTER TO DETECT CYCLE ----------------
+ u16 uiDummy;
+ opstatus_t opstatus;
+
+ // Read new flow from flow computer every 10ms
+ opstatus=SS_Xgetw(flc, &uiDummy);
+ if (opstatus==OPSTATUS_OK)
+ {
+ // Update flow/pressure displayed
+ uiBlowerFlow=iFlowFromFlowComputer*10;
+ uiPoutPressureMes=uiPressureFromFlowComputer;
+
+ // Comm with flow computer OK !!
+ #ifdef DATA_LOGGING
+ if (bRecordTemperatureTrendsAllowed==FALSE)
+ {
+ bRecordTemperatureTrendsAllowed=TRUE;
+ uiTrendsSampleTime=RECORD_TRENDS_SAMPLE_TIME;
+ }
+ #endif // DATA_LOGGING
+
+ // inspiration/expiration cycle detection
+ if (ucFlowComputerCycle==EXPIRATION_CYCLE)
+ {
+ // Inspiration detection
+ if (iFlowFromFlowComputer>50) // 5l/min
+ {
+ uiFlowComputerCycleModificationTimer--;
+ if (uiFlowComputerCycleModificationTimer==0)
+ {
+ ucFlowComputerCycle=INSPIRATION_CYCLE;
+
+ // Compute temperature of the previous inspiratory cycle
+ if (uiTemperatureSamplesCounter!=0)
+ {
+ uiTechnicalDataMes[MOTOR_TEMPERATURE_TEC_MES]=ComputeMotorTemperature(ulADCSumBlowerTemperature/uiTemperatureSamplesCounter);
+ uiADCAverageTemperaturePhaseA=ulADCSumTemperaturePhaseA/uiTemperatureSamplesCounter;
+ uiADCAverageTemperaturePhaseB=ulADCSumTemperaturePhaseB/uiTemperatureSamplesCounter;
+ uiADCAverageTemperaturePhaseC=ulADCSumTemperaturePhaseC/uiTemperatureSamplesCounter;
+ }
+ ulADCSumBlowerTemperature=0;
+ ulADCSumTemperaturePhaseA=0;
+ ulADCSumTemperaturePhaseB=0;
+ ulADCSumTemperaturePhaseC=0;
+ uiTemperatureSamplesCounter=0;
+ }
+ }
+ else
+ uiFlowComputerCycleModificationTimer=FLOW_COMPUTER_CYCLE_DETECTION_TIMER;
+ }
+ else
+ {
+ // Record temperature as long as the flow is positive
+ if (iFlowFromFlowComputer>(-10)) // >-1l/min
+ {
+ ulADCSumBlowerTemperature+=uiADCBlowerTemperatureMeas;
+ ulADCSumTemperaturePhaseA+=uiADCTemperaturePhaseA;
+ ulADCSumTemperaturePhaseB+=uiADCTemperaturePhaseB;
+ ulADCSumTemperaturePhaseC+=uiADCTemperaturePhaseC;
+ uiTemperatureSamplesCounter++;
+ }
+
+ // Expiration detection
+ if (iFlowFromFlowComputer<(-50)) // <-5l/min
+ {
+ uiFlowComputerCycleModificationTimer--;
+ if (uiFlowComputerCycleModificationTimer==0)
+ ucFlowComputerCycle=EXPIRATION_CYCLE;
+ }
+ else
+ uiFlowComputerCycleModificationTimer=FLOW_COMPUTER_CYCLE_DETECTION_TIMER;
+ }
+ }
+ else if (opstatus==OPSTATUS_FAIL)
+ {
+ // Comm Failure with flow computer => no data recorded
+ uiBlowerFlow=0;
+ uiPoutPressureMes=0;
+
+ #ifdef DATA_LOGGING
+ bRecordTemperatureTrendsAllowed=FALSE;
+ #endif
+ uiTechnicalDataMes[MOTOR_TEMPERATURE_TEC_MES]=0;
+ }
+ #else
+ // ----------- USE THE 24V MEASURE TO DETECT CYCLE ----------------
+ if (uiDCinADCMeas>500)
+ {
+ // Inspiration
+ ulADCSumBlowerTemperature+=uiADCBlowerTemperatureMeas;
+ ulADCSumTemperaturePhaseA+=uiADCTemperaturePhaseA;
+ ulADCSumTemperaturePhaseB+=uiADCTemperaturePhaseB;
+ ulADCSumTemperaturePhaseC+=uiADCTemperaturePhaseC;
+ uiTemperatureSamplesCounter++;
+ uiTimeOutTemperatureMeasurement=TIME_OUT_TEMPERATURE_MEASUREMENT;
+ #ifdef DATA_LOGGING
+ bRecordTemperatureTrendsAllowed=TRUE;
+ #endif
+ }
+ else if (uiTimeOutTemperatureMeasurement!=0)
+ {
+ // Expiration
+ uiTimeOutTemperatureMeasurement--;
+ if (uiTemperatureSamplesCounter!=0)
+ {
+ uiTechnicalDataMes[MOTOR_TEMPERATURE_TEC_MES]=ComputeMotorTemperature(ulADCSumBlowerTemperature/uiTemperatureSamplesCounter);
+ uiADCAverageTemperaturePhaseA=ulADCSumTemperaturePhaseA/uiTemperatureSamplesCounter;
+ uiADCAverageTemperaturePhaseB=ulADCSumTemperaturePhaseB/uiTemperatureSamplesCounter;
+ uiADCAverageTemperaturePhaseC=ulADCSumTemperaturePhaseC/uiTemperatureSamplesCounter;
+ }
+ ulADCSumBlowerTemperature=0;
+ ulADCSumTemperaturePhaseA=0;
+ ulADCSumTemperaturePhaseB=0;
+ ulADCSumTemperaturePhaseC=0;
+ uiTemperatureSamplesCounter=0;
+ }
+ else
+ {
+ uiTechnicalDataMes[MOTOR_TEMPERATURE_TEC_MES]=0;
+
+ ulADCSumBlowerTemperature=0;
+ ulADCSumTemperaturePhaseA=0;
+ ulADCSumTemperaturePhaseB=0;
+ ulADCSumTemperaturePhaseC=0;
+ uiTemperatureSamplesCounter=0;
+
+ #ifdef DATA_LOGGING
+ bRecordTemperatureTrendsAllowed=FALSE;
+ #endif
+ }
+ #endif // #ifdef USE_FLOW_COMPUTER
+}
+#endif // #ifdef TEMPERATURE_TRENDS
+#endif // #ifndef C_M3_DEVICETEST_TARGET
+
+
+/*******************************************************************************
+* Function Name : ComputeADCBlowerCurrent
+* Description : Compute the average current during a PWM cycle (20micros)
+* Input : bRecordCurrentOffset
+* Output : None
+* Return : None
+*******************************************************************************/
+void ComputeADCBlowerCurrent(bool bRecordCurrentOffset)
+{
+ if (bRecordCurrentOffset==TRUE)
+ {
+ uiADCOffsetBlowerCurrent=uiADCBlowerCurrent=uiADC_Value[ADC_CURRENT_MES];
+ }
+ else
+ {
+ uiADCBlowerCurrent=uiADC_Value[ADC_CURRENT_MES];
+ }
+}
+
+
+/*******************************************************************************
+* Function Name : ComputeBlowerCurrentInAmper
+* Description : Return blower current value in cAmper (ex: 100=1.00A)
+* Input : ADC value
+* Output : None
+* Return : Blower current in cAmper (ex: 100=1.00A)
+*******************************************************************************/
+int16_t ComputeBlowerCurrentInAmper(u16 uiADCBlowerCurrentLocal)
+{
+ int32_t lTempValue;
+
+ // Computation using MOT_CUR_MEAS2
+ lTempValue=(int32_t)uiADCBlowerCurrentLocal-(int32_t)uiADCOffsetBlowerCurrent;
+ lTempValue*=1000;
+ lTempValue/=uiTechnicalDataSet[GAIN_BLOWER_CURRENT_TEC];
+ return(lTempValue);
+}
+
+
+#ifndef C_M3_DEVICETEST_TARGET
+/*******************************************************************************
+* Function Name : LaunchFlowReadingOnI2CBus
+* Description : Open and Read the flow sensor(s) on the I2C bus
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void LaunchFlowReadingOnI2CBus(void)
+{
+ opstatus_t byOpStatus;
+ u16 uiSensorErr;
+
+ if (fOpenI2C1SDP600Sensors==FALSE || fOpenI2C2SDP600Sensors==FALSE ||
+ fOpenI2C1X201641Sensors==FALSE || fOpenI2C2X201641Sensors==FALSE)
+ {
+ byOpStatus=SS_Xopen(I2C_SDP600);
+ if (byOpStatus==OPSTATUS_FAIL)
+ uiFlagsAlarm[ALARM_FLAGS2]|=FLOW_SENSOR_FAILURE_ALARM_MASK;
+
+ byOpStatus=SS_Xopen(I2C_X201641);
+ if (byOpStatus==OPSTATUS_FAIL)
+ uiFlagsAlarm[ALARM_FLAGS2]|=FLOW_SENSOR_FAILURE_ALARM_MASK;
+
+ ucReadingFlowSensor=STOP_READING_FLOW_SENSORS;
+ }
+ else if (ucReadingFlowSensor==STOP_READING_FLOW_SENSORS)
+ {
+ ucReadingFlowSensor=START_READING_FLOW_SENSORS;
+ }
+ else if (ucReadingFlowSensor==READING_FLOW_SENSORS)
+ {
+ // Reading SDP600 Flow sensors
+ if (ucStatusSDP600==FLOW_SENSOR_READING)
+ {
+ byOpStatus=SS_Xgetw(I2C_SDP600, &uiSensorErr);
+ if (byOpStatus==OPSTATUS_OK)
+ ucStatusSDP600=FLOW_SENSOR_OK;
+ else if (byOpStatus==OPSTATUS_FAIL)
+ ucStatusSDP600=FLOW_SENSOR_FAIL;
+ }
+
+ // Reading X201641 Flow sensors
+ if (ucStatusX201641==FLOW_SENSOR_READING)
+ {
+ byOpStatus=SS_Xgetw(I2C_X201641, &uiSensorErr);
+ if (byOpStatus==OPSTATUS_OK)
+ ucStatusX201641=FLOW_SENSOR_OK;
+ else if (byOpStatus==OPSTATUS_FAIL)
+ ucStatusX201641=FLOW_SENSOR_FAIL;
+ }
+
+ // End of flow measurement?
+ if (ucStatusSDP600!=FLOW_SENSOR_READING && ucStatusX201641!=FLOW_SENSOR_READING)
+ {
+ if (ucStatusSDP600==FLOW_SENSOR_OK && ucStatusX201641==FLOW_SENSOR_OK)
+ {
+ ucCounterFlowErrorMeasurement=0;
+ #ifdef TIME_MEASUREMENT
+ GPIOB->BRR = GPIO_Pin_5;
+ #endif
+ }
+ else
+ {
+ // Error counters
+ uiTotalCounterFlowErrorMeasurement++;
+ ucCounterFlowErrorMeasurement++;
+ if (ucCounterFlowErrorMeasurement>=NUMBER_I2C_REBOOT)
+ {
+ //ulErrorCounter|=uiSensorErr;
+ uiFlagsAlarm[ALARM_FLAGS2]|=FLOW_SENSOR_FAILURE_ALARM_MASK;
+ }
+ }
+
+ // Next Sensors to measure
+ ucReadingFlowSensor=READING_NO_SENSOR;
+ ucStatusSDP600=FLOW_SENSOR_READING;
+ ucStatusX201641=FLOW_SENSOR_READING;
+ }
+ }
+}
+#endif // #ifndef C_M3_DEVICETEST_TARGET
+
+
+
+#ifndef C_M3_DEVICETEST_TARGET
+/*******************************************************************************
+* Function Name : ComputeFlowMeasurement
+* Description : Conpute inspiratory and erxpiratory flow measurements
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ComputeFlowMeasurement(void)
+{
+ #if defined(SDP600_USED_I2C1_BUS) || defined(X201641_USED_I2C1_BUS)
+ int32_t lValue;
+ u16 uiValue;
+ #ifdef DISPLAY_AVERAGE_BLOWER_RAW_FLOW
+ u32 ulValue;
+ #endif
+ #endif
+
+ if (ucReadingFlowSensor==START_READING_FLOW_SENSORS)
+ {
+ ucReadingFlowSensor=READING_FLOW_SENSORS;
+ }
+ else if (ucReadingFlowSensor==READING_NO_SENSOR)
+ {
+ ucReadingFlowSensor=READING_FLOW_SENSORS;
+
+ // **** Reading of the Inspiratory RAW Flow
+ #if defined(SDP600_USED_I2C1_BUS) || defined(X201641_USED_I2C1_BUS)
+ #ifdef SDP600_USED_I2C1_BUS
+ SDP600_ReadADCFlowValue(I2C1, SDP600_BLOWER_FLOW_SENSOR, &uiValue);
+ #endif
+ #ifdef X201641_USED_I2C1_BUS
+ X201641_ReadADCFlowValue(I2C1, X201641_BLOWER_FLOW_SENSOR, &uiValue);
+ #endif
+ if (uiValue==uiTechnicalDataSet[FLOWI_OFFSET_TEC])
+ {
+ uiBlowerFlowRAWMes=0;
+ iBlowerFlowMes=0;
+ }
+ else if (uiValue>uiTechnicalDataSet[FLOWI_OFFSET_TEC])
+ {
+ uiBlowerFlowRAWMes=uiValue-uiTechnicalDataSet[FLOWI_OFFSET_TEC];
+ iBlowerFlowMes=ComputeFlowInLitersPerMin(uiBlowerFlowRAWMes, FALSE);
+ }
+ else
+ {
+ uiBlowerFlowRAWMes=uiTechnicalDataSet[FLOWI_OFFSET_TEC]-uiValue;
+ iBlowerFlowMes=ComputeFlowInLitersPerMin(uiBlowerFlowRAWMes, TRUE);
+ }
+
+ // Smoothing RWA data signals
+ #ifdef DISPLAY_AVERAGE_BLOWER_RAW_FLOW
+ uiBlowerRAWFlowTemp[ucIndexBlowerRAWFlowSmooth]=uiBlowerFlowRAWMes;
+ ulValue=0;
+ for (uiValue=0; uiValue<SMOOTH_BLOWER_RAW_FLOW_COUNTER; uiValue++)
+ ulValue+=uiBlowerRAWFlowTemp[uiValue];
+ uiBlowerFlowRAWSmoothingMes=ulValue/SMOOTH_BLOWER_RAW_FLOW_COUNTER;
+ ucIndexBlowerRAWFlowSmooth++;
+ if (ucIndexBlowerRAWFlowSmooth>=SMOOTH_BLOWER_RAW_FLOW_COUNTER)
+ ucIndexBlowerRAWFlowSmooth=0;
+
+ // Average of the RAW data signal
+ ulSumBlowerFlowRAWMes+=uiBlowerFlowRAWSmoothingMes;
+ uiBlowerRAWFlowSamplesCounter--;
+ if (uiBlowerRAWFlowSamplesCounter==0)
+ {
+ uiAverageBlowerFlowRAWMes=ulSumBlowerFlowRAWMes/BLOWER_RAW_FLOW_SAMPLES_NUMBER;
+ ulSumBlowerFlowRAWMes=0;
+ uiBlowerRAWFlowSamplesCounter=BLOWER_RAW_FLOW_SAMPLES_NUMBER;
+ }
+ #endif // DISPLAY_AVERAGE_BLOWER_RAW_FLOW
+
+
+ // **** Reading of the Inspiratory Flow in l/min
+ /*#ifdef SDP600_USED_I2C1_BUS
+ SDP600_CalculFlowValue(I2C1, SDP600_BLOWER_FLOW_SENSOR, &iBlowerFlowMes);
+ #endif
+ #ifdef X201641_USED_I2C1_BUS
+ X201641_CalculFlowValue(I2C1, X201641_BLOWER_FLOW_SENSOR, &iBlowerFlowMes);
+ #endif*/
+ iTempBlowerFlowForSmallSmooth[ucIndexSmallBlowerFlowSmooth]=iBlowerFlowMes;
+ iTempBlowerFlowForLargeSmooth[ucIndexLargeBlowerFlowSmooth]=iBlowerFlowMes;
+
+ // Small Smoothing of the inspiratory flow signal
+ lValue=0;
+ for (uiValue=0; uiValue<SMOOTH_BLOWER_FLOW_SMALL_COUNTER; uiValue++)
+ lValue+=iTempBlowerFlowForSmallSmooth[uiValue];
+ iBlowerFlowSmoothingMes=lValue/(int16_t)SMOOTH_BLOWER_FLOW_SMALL_COUNTER;
+ ucIndexSmallBlowerFlowSmooth++;
+ if (ucIndexSmallBlowerFlowSmooth>=SMOOTH_BLOWER_FLOW_SMALL_COUNTER)
+ ucIndexSmallBlowerFlowSmooth=0;
+
+ // Large Smoothing of the inspiratory flow signal
+ lValue=0;
+ for (uiValue=0; uiValue<SMOOTH_BLOWER_FLOW_LARGE_COUNTER; uiValue++)
+ lValue+=iTempBlowerFlowForLargeSmooth[uiValue];
+ iBlowerFlowSmoothingMesForTrigger=lValue/(int16_t)SMOOTH_BLOWER_FLOW_LARGE_COUNTER;
+ ucIndexLargeBlowerFlowSmooth++;
+ if (ucIndexLargeBlowerFlowSmooth>=SMOOTH_BLOWER_FLOW_LARGE_COUNTER)
+ ucIndexLargeBlowerFlowSmooth=0;
+
+ // Flow for Optima Comm
+ uiBlowerFlow=iBlowerFlowMes;
+ uiBlowerFlowSmoothingMes=iBlowerFlowSmoothingMes;
+ uiBlowerFlowTriggerMes=iBlowerFlowSmoothingMesForTrigger;
+ #endif // (SDP600_USED_I2C1_BUS) || (X201641_USED_I2C1_BUS)
+ }
+
+}
+#endif // #ifndef C_M3_DEVICETEST_TARGET
+
+
+
+#ifndef C_M3_DEVICETEST_TARGET
+double powApprox(double a, double x)
+{
+ union
+ {
+ double d;
+ int A[2];
+ } Z = { a };
+ Z.A[1] = (int)(x * (Z.A[1] - 1072632447) + 1072632447);
+ Z.A[0] = 0;
+ return Z.d;
+}
+/*******************************************************************************
+* Function Name : ComputeConductance
+* Description : Compute Conductance
+* Input : Pressure, Flow
+* Output : Conductance
+* Return : None
+*******************************************************************************/
+float prevConductance = 0.0f;
+u8 bufferIndex = 0;
+bool filled = FALSE;
+int16_t littleSum = 0;
+
+void ComputeConductance(void)
+{
+ float pressure = iProximalPressureMes/10.0f;
+ float flow = iBlowerFlowSmoothingMes/100.0f/60.0f;
+ float density = 1.225f;
+ float viscosity = 0.00018f;
+ float calcConductance = 0.0f;
+
+ if(pressure != 0)
+ {
+ calcConductance = (100000)*((powApprox((flow*0.001f),1.75)*powApprox(density,0.75)*powApprox(viscosity,0.25)/(pressure / 10.0f)* 98.0638f));
+ calcConductance = calcConductance * 1000.0f;
+ if(calcConductance < 60000 && calcConductance > -60000)
+ {
+ uiConductanceCalc = (int16_t)calcConductance;
+ }
+ }
+// int16_t tempValue = idConductancedtSmooth[bufferIndex];
+// idConductancedtSmooth[bufferIndex]= (int16_t)(calcConductance - prevConductance);//1000;
+// littleSum += idConductancedtSmooth[bufferIndex];
+// bufferIndex++;
+// if(bufferIndex > SMOOTH_BLOWER_FLOW_LARGE_COUNTER)
+// {
+// bufferIndex = 0;
+// if(!filled)
+// {
+// filled = TRUE;
+// }
+// }
+//
+// if(filled)
+// {
+// littleSum -= tempValue;
+// uidConductanceCalcdt = littleSum/SMOOTH_BLOWER_FLOW_LARGE_COUNTER;
+// }
+ uidConductanceCalcdt = (int16_t)(calcConductance - prevConductance);
+ prevConductance = calcConductance;
+}
+/*******************************************************************************
+* Function Name : ComputeProximalPressureMeasurements
+* Description : Compute Proximal pressure measurements
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ComputeProximalPressureMeasurements(void)
+{
+ u32 ulValue;
+ u16 uiValue;
+
+ iProximalPressureMes=((100L*((int16_t)uiProximalPressureADCMes-(int16_t)uiTechnicalDataSet[PPROX_OFFSET_TEC]))/(int16_t)uiTechnicalDataSet[PPROX_GAIN_TEC]);
+ if (iProximalPressureMes>0)
+ uiProximalPressureMes=(u16)iProximalPressureMes;
+ else
+ uiProximalPressureMes=0;
+ uiNegativeProximalPressureMes=iProximalPressureMes;
+
+ // Smoothing proximal pressure
+ uiProximalPressureTemp[ucIndexPproxPressureSmooth]=uiProximalPressureMes;
+ ulValue=0;
+ for (uiValue=0; uiValue<SMOOTH_PPROX_PRESSURE_COUNTER; uiValue++)
+ ulValue+=uiProximalPressureTemp[uiValue];
+ uiProximalPressureSmoothingMes=ulValue/SMOOTH_PPROX_PRESSURE_COUNTER;
+
+ ucIndexPproxPressureSmooth++;
+ if (ucIndexPproxPressureSmooth>=SMOOTH_PPROX_PRESSURE_COUNTER)
+ ucIndexPproxPressureSmooth=0;
+}
+#endif // #ifndef C_M3_DEVICETEST_TARGET
+
+
+#ifndef C_M3_DEVICETEST_TARGET
+/*******************************************************************************
+* Function Name : ComputeOffsetProximalPressureSensor
+* Description : Compute offset of the proximal pressure sensor
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ComputeOffsetProximalPressureSensor(void)
+{
+ u32 ulOffsetSum=0;
+ u16 i;
+
+ for (i=0; i<64; i++)
+ {
+ ulOffsetSum+=uiADC_Value[ADC_PPROX_MES];
+ uiTempoSysTick=5;
+ while (uiTempoSysTick!=0){}
+ }
+ uiTechnicalDataSet[PPROX_OFFSET_TEC]=ulOffsetSum>>6;
+}
+#endif // #ifndef C_M3_DEVICETEST_TARGET
+
+
+
+#ifndef C_M3_DEVICETEST_TARGET
+/*******************************************************************************
+* Function Name : VentilationMonitoringAndAlarms
+* Description : Compute measurements and alarms during ventilation
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void VentilationMonitoringAndAlarms(void)
+{
+ u16 uiTotalTimeMes;
+
+ if (bMemoStartVentilation==TRUE && uiTechnicalDataSet[DEVICE_MODE_TEC]==VENTILATION_MODE)
+ {
+ if (ucVentilationCycle==INSPIRATION_CYCLE)
+ {
+ // ***************** INSPIRATION ******************
+ if (ucVentilationCycleCopy==EXPIRATION_CYCLE)
+ {
+ // --- Beginning of inspiration
+ ucVentilationCycleCopy=INSPIRATION_CYCLE;
+ SS_Xputdw(act, EV_CTL|FLAG_ACTIONER_ON);
+
+ // Update Vte measurement
+ uiVentilationMeasures[VTE_MES]=uiVteTemp;
+
+ // Update Te measurement
+ uiVentilationMeasures[TE_MES]=uiTeMesTemp;
+
+ // Update Average ADC Motor Voltage
+ if (ulCounterADC_MotorVoltage!=0)
+ uiAverageADC_MotorVoltage=ulSumADC_MotorVoltage/ulCounterADC_MotorVoltage;
+
+ // Update Current measurement
+ if (ulCounterADC_FilteredBlowerCurrentMes!=0)
+ uiBreathBlowerCurrentMes=ComputeBlowerCurrentInAmper(ulSumCurrentADCMesFiltered/ulCounterADC_FilteredBlowerCurrentMes);
+ ulSumCurrentADCMesFiltered=0; ulCounterADC_FilteredBlowerCurrentMes=0;
+
+ // Update average blower speed
+ if (ulCounterAverageMotorSpeed!=0)
+ uiAverageBlowerSpeedMes=SpeedMeasurement(ulSumTachoTicks/ulCounterAverageMotorSpeed);
+ ulSumTachoTicks=0;
+ ulCounterAverageMotorSpeed=0;
+
+ // Update average motor temperature during inspiration
+ if (uiTemperatureSamplesCounter!=0)
+ {
+ uiTechnicalDataMes[MOTOR_TEMPERATURE_TEC_MES]=ComputeMotorTemperature(ulADCSumBlowerTemperature/uiTemperatureSamplesCounter);
+ if (uiTechnicalDataMes[MOTOR_TEMPERATURE_TEC_MES]>890)
+ uiFlagsAlarm[ALARM_FLAGS2]|=MOTOR_TEMPERATURE_ALARM_MASK;
+ else if (uiTechnicalDataMes[MOTOR_TEMPERATURE_TEC_MES]<810)
+ uiFlagsAlarm[ALARM_FLAGS2]&=(~MOTOR_TEMPERATURE_ALARM_MASK);
+ }
+ ulADCSumBlowerTemperature=0; uiTemperatureSamplesCounter=0;
+
+ // --- Pmax=0
+ uiPproxMax=0;
+
+ // --- Vti=0
+ lSumVti=0;
+ uiRecordVtiMes=uiVentilationMeasures[VTI_MES];
+
+ // --- Dislay Breath rate
+ uiTotalTimeMes=uiVentilationMeasures[TI_MES]+uiVentilationMeasures[TE_MES];
+ if (uiTotalTimeMes>0)
+ uiVentilationMeasures[BREATH_RATE_MES]=600000/uiTotalTimeMes;
+
+ // --- Ti=0
+ uiTiMesTemp=0;
+
+ // --- Max flow
+ iBlowerFlowSmoothingMaxMes=0;
+
+ // --- Alarm Vte Min
+ if (uiVentilationMeasures[VTE_MES]<uiVentilationSet[VTE_MIN_ALARM_SET] && enVentilationMode!=CPAP_MODE)
+ {
+ ucCounterAlarmVteMin++;
+ if (ucCounterAlarmVteMin>=5)
+ {
+ ucCounterAlarmVteMin=5;
+ uiFlagsAlarm[ALARM_FLAGS1]|=LOW_VTE_ALARM_MASK;
+ }
+ }
+ else
+ {
+ ucCounterAlarmVteMin=0;
+ uiFlagsAlarm[ALARM_FLAGS1]&=(~LOW_VTE_ALARM_MASK);
+ }
+ }
+ else //if (ucVentilationCycle==EXPIRATION_CYCLE)
+ {
+ // --- During inspiration
+
+ // --- Motor Speed
+ ulSumTachoTicks+=uiTachoTimeTicks;
+ ulCounterAverageMotorSpeed++;
+
+ // --- Blower Current
+ ulSumCurrentADCMesFiltered+=uiADCBlowerCurrent;
+ ulCounterADC_FilteredBlowerCurrentMes++;
+
+ // --- Inc Pmax
+ if (uiProximalPressureMes>uiPproxMax)
+ uiPproxMax=uiProximalPressureMes;
+
+ // --- Inc max flow
+ if (iBlowerFlowSmoothingMes>iBlowerFlowSmoothingMaxMes)
+ iBlowerFlowSmoothingMaxMes=iBlowerFlowSmoothingMes;
+
+ // --- Inc Vti
+ if (iBlowerFlowMes>30)
+ lSumVti+=iBlowerFlowMes;
+ uiVtiTemp=(u32)lSumVti/6000;
+
+ // --- Inc Ti
+ uiTiMesTemp++;
+
+ // --- Motor temperature
+ ulADCSumBlowerTemperature+=uiADCBlowerTemperatureMeas;
+ uiTemperatureSamplesCounter++;
+
+ // --- Alarm Pmax
+ if (uiProximalPressureMes>uiVentilationSet[HIGH_PRESSURE_ALARM_SET] && enVentilationMode!=CPAP_MODE)
+ {
+ uiFlagsAlarm[ALARM_FLAGS1]|=HIGH_PRESSURE_ALARM_MASK;
+ fAlarmPmax=TRUE;
+ }
+
+ // --- Alarm Vti Max
+ if ((uiVtiTemp>uiVentilationSet[VTI_MAX_ALARM_SET] && enVentilationMode==PS_MODE) ||
+ (uiVtiTemp>uiVentilationSet[VTI_MAX_ALARM_SET] && enVentilationMode==APCV_MODE))
+ {
+ uiFlagsAlarm[ALARM_FLAGS1]|=HIGH_VTI_ALARM_MASK;
+ fAlarmVtiMax=TRUE;
+ }
+ }
+ }
+ else
+ {
+ // ***************** EXPIRATION ******************
+ if (ucVentilationCycleCopy==INSPIRATION_CYCLE)
+ {
+ // --- Beginning of Expiration
+ ucVentilationCycleCopy=EXPIRATION_CYCLE;
+ SS_Xputdw(act, EV_CTL|FLAG_ACTIONER_OFF);
+
+ // Update Pprox max measurement
+ uiVentilationMeasures[PPROX_MAX_MES]=uiPproxMax;
+
+ // Update Vti measurement
+ uiVentilationMeasures[VTI_MES]=uiVtiTemp;
+
+ // Update Ti measurement
+ uiVentilationMeasures[TI_MES]=uiTiMesTemp;
+
+ // --- Motor Speed
+ ulSumTachoTicks+=uiTachoTimeTicks;
+ ulCounterAverageMotorSpeed++;
+
+ // --- Blower Current
+ ulSumCurrentADCMesFiltered+=uiADCBlowerCurrent;
+ ulCounterADC_FilteredBlowerCurrentMes++;
+
+ // --- Vte=0
+ lSumVte=0;
+
+ // --- Te=0
+ uiTeMesTemp=0;
+
+ // --- Alarm Low Pressure
+ if ((uiVentilationMeasures[PPROX_MAX_MES]<(uiVentilationSet[PS_SET]-5) && enVentilationMode==PS_MODE) ||
+ (uiVentilationMeasures[PPROX_MAX_MES]<(uiVentilationSet[PI_SET]-5) && enVentilationMode==APCV_MODE) ||
+ (uiVentilationMeasures[PPROX_MAX_MES]<uiVentilationSet[LOW_PRESSURE_ALARM_SET] && enVentilationMode==AVC_MODE))
+ {
+ ucCounterLPAlarm++;
+ if (ucCounterLPAlarm>=4)
+ {
+ ucCounterLPAlarm=4;
+ uiFlagsAlarm[ALARM_FLAGS1]|=LOW_PRESSURE_ALARM_MASK;
+ }
+ }
+ else
+ {
+ ucCounterLPAlarm=0;
+ uiFlagsAlarm[ALARM_FLAGS1]&=(~LOW_PRESSURE_ALARM_MASK);
+ }
+
+ // --- Clear Alarm High pressure
+ if (fAlarmPmax==FALSE)
+ uiFlagsAlarm[ALARM_FLAGS1]&=(~HIGH_PRESSURE_ALARM_MASK);
+ fAlarmPmax=FALSE;
+
+ // --- Clear Alarm Vti Max
+ if (fAlarmVtiMax==FALSE)
+ uiFlagsAlarm[ALARM_FLAGS1]&=(~HIGH_VTI_ALARM_MASK);
+ fAlarmVtiMax=FALSE;
+ }
+ else
+ {
+ // --- During Expiration
+
+ // --- Motor Speed
+ ulSumTachoTicks+=uiTachoTimeTicks;
+ ulCounterAverageMotorSpeed++;
+
+ // --- Blower Current
+ ulSumCurrentADCMesFiltered+=uiADCBlowerCurrent;
+ ulCounterADC_FilteredBlowerCurrentMes++;
+
+ // --- Inc Vte
+ if (iBlowerFlowMes<(-30))
+ lSumVte+=iBlowerFlowMes;
+ if (lSumVte<0)
+ uiVteTemp=(u32)(lSumVte/(-6000));
+ else
+ uiVteTemp=0;
+
+ // --- Inc Te
+ uiTeMesTemp++;
+ if (uiTeMesTemp>60000) uiTeMesTemp=60000;
+
+ // --- Average motor voltage
+ if (uiTeMesTemp==100)
+ {
+ ulSumADC_MotorVoltage=0;
+ ulCounterADC_MotorVoltage=0;
+ }
+ else if (uiTeMesTemp>100)
+ {
+ ulSumADC_MotorVoltage+=uiDCinADCMeas;
+ ulCounterADC_MotorVoltage++;
+ }
+ }
+ }
+ }
+ else // if (bMemoStartVentilation==TRUE && uiTechnicalDataSet[DEVICE_MODE_TEC]==VENTILATION_MODE)
+ {
+ #ifndef TEMPERATURE_TRENDS
+ uiTechnicalDataMes[MOTOR_TEMPERATURE_TEC_MES]=ComputeMotorTemperature(uiADCBlowerTemperatureMeas);
+ #endif
+ }
+}
+#endif // #ifndef C_M3_DEVICETEST_TARGET
+
+
+#ifndef C_M3_DEVICETEST_TARGET
+/*******************************************************************************
+* Function Name : ClearVentilationAlarm
+* Description : Clear all ventilation Alarms
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ClearAllVentilationAlarms(void)
+{
+ u8 i;
+ u8 ucAlarmFlag;
+
+ for (i=0; i<SIZE_BLOWER_ALARM; i++)
+ {
+ ucAlarmFlag=stBlowerAlarmStatus[i].ucAlarmFlag;
+ if (stBlowerAlarmStatus[i].bVentilationAlarm==TRUE && (ucAlarmFlag==ALARM_FLAGS1 || ucAlarmFlag==ALARM_FLAGS2))
+ uiFlagsAlarm[ucAlarmFlag]&=(~stBlowerAlarmStatus[i].uiAlarmMask);
+ }
+}
+
+
+/*******************************************************************************
+* Function Name : ClearAlarm
+* Description : Clear a specific alarm
+* Input : Mask of the alarm
+* Output : None
+* Return : None
+*******************************************************************************/
+void ClearAlarm(u8 ucAlarmFlag, u16 uiMask)
+{
+ uiFlagsAlarm[ucAlarmFlag]&=(~uiMask);
+}
+
+
+/*******************************************************************************
+* Function Name : ClearAllMeasures
+* Description : Clear all ventilation measures
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ClearAllMeasures(void)
+{
+ u8 i;
+
+ // Reset measures except alarms
+ for (i=0; i<SIZE_LRM_GROUP; i++)
+ {
+ if (i!=ALARM_ID1_MES && i!=ALARM_ID2_MES)// && i!=ALARM_ID3_MES && i!=ALARM_ID4_MES)
+ uiVentilationMeasures[i]=0;
+ }
+
+ // Reset others measures
+ uiBlowerSpeedMes=0; uiAverageBlowerSpeedMes=0; // Speed=0 RPM
+ ulSumTachoTicks=0; ulCounterAverageMotorSpeed=0;
+ uiBreathBlowerCurrentMes=0; // Blower current=0 A
+ ulSumCurrentADCMesFiltered=0; ulCounterADC_FilteredBlowerCurrentMes=0;
+ bDisplayInspiratoryTrigger=FALSE;
+ #ifdef MOTOR_LIFE_TESTING
+ uiAverateMotorTempMes=0;
+ #endif // #ifdef MOTOR_LIFE_TESTING
+
+ // Init temporary variables
+ ucVentilationCycleCopy=INSPIRATION_CYCLE;
+ uiPproxMax=0;
+ uiVtiTemp=0;
+ uiTiMesTemp=0;
+ ucCounterLPAlarm=0;
+ fAlarmPmax=FALSE;
+ fAlarmVtiMax=FALSE;
+ ucCounterAlarmVteMin=0;
+}
+
+
+/*******************************************************************************
+* Function Name : ReadStopVentilationAlarmNumber
+* Description : Read the alarm number which stops the ventilation
+* Input : None
+* Output : None
+* Return : alarm number
+*******************************************************************************/
+u8 ReadStopVentilationAlarmNumber(void)
+{
+ u16 uiMask;
+ u8 i;
+ u8 ucAlarmNumber=SIZE_BLOWER_ALARM;
+
+ // Check Alarm which stops ventilation
+ if (uiFlagsAlarm[ALARM_FLAGS1]!=0 ||
+ uiFlagsAlarm[ALARM_FLAGS2]!=0)
+ /*uiFlagsAlarm[ALARM_FLAGS3]!=0 ||
+ uiFlagsAlarm[ALARM_FLAGS4]!=0)*/
+ {
+ for (i=0; i<SIZE_BLOWER_ALARM; i++)
+ {
+ if (stBlowerAlarmStatus[i].bForceVentilToStop==TRUE)
+ {
+ uiMask=stBlowerAlarmStatus[i].uiAlarmMask;
+ if ((uiFlagsAlarm[stBlowerAlarmStatus[i].ucAlarmFlag]&uiMask)==uiMask)
+ {
+ ucAlarmNumber=i;
+ break;
+ }
+ }
+ }
+ }
+ return(ucAlarmNumber);
+}
+
+
+/*******************************************************************************
+* Function Name : UpdateAlarmsMeasureID
+* Description : Update the alarms ventilation measure variables
+* Input : None
+* Output : None
+* Return : alarm number
+*******************************************************************************/
+#ifdef USE_OPTIMACOMM
+void UpdateAlarmsMeasureID(void)
+{
+ uiVentilationMeasures[ALARM_ID1_MES]=uiFlagsAlarm[ALARM_FLAGS1];
+ uiVentilationMeasures[ALARM_ID2_MES]=uiFlagsAlarm[ALARM_FLAGS2];
+}
+#endif // #ifdef USE_OPTIMACOMM
+#endif // #ifndef C_M3_DEVICETEST_TARGET
+
+
+/*******************************************************************************
+* Function Name : ComputeMotorTemperature
+* Description : Return temperature (in degres C)
+* Input : uiADCMotorTemp : ADC value
+* Output : None
+* Return : None
+*******************************************************************************/
+u16 ComputeMotorTemperature(u16 uiADCMotorTemp)
+{
+ u16 uiTemp, uiTempDec;
+ u32 ulTemp;
+
+ for (uiTemp=0; uiTemp<121; uiTemp++)
+ {
+ if (uiADCMotorTemp>=uiADCMotorTempTable[uiTemp])
+ break;
+ }
+
+ if (uiADCMotorTemp<uiADCMotorTempTable[120])
+ return(1200);
+ else if (uiADCMotorTemp>=uiADCMotorTempTable[0])
+ return(0);
+ else if (uiADCMotorTemp==uiADCMotorTempTable[uiTemp])
+ ulTemp=uiTemp*10;
+ else
+ {
+ uiTempDec=((uiADCMotorTempTable[uiTemp-1]-uiADCMotorTemp)*10)/(uiADCMotorTempTable[uiTemp-1]-uiADCMotorTempTable[uiTemp]);
+ ulTemp=((uiTemp-1)*10)+uiTempDec;
+ }
+
+ ulTemp*=1000;
+ ulTemp/=uiTechnicalDataSet[GAIN_BLOWER_TEMP_TEC];
+ return((u16)ulTemp);
+}
+
+
+/*******************************************************************************
+* Function Name : ComputeFlowInLitersPerMin
+* Description : Compute the flow in l/min
+* Input : uFlowRAW : flow digital value, bPositiveFlow= TRUE if positive flow
+* Output : None
+* Return : signed Flow in l/min
+*******************************************************************************/
+int16_t ComputeFlowInLitersPerMin(u16 uiFlowRAW, bool bPositiveFlow)
+{
+ u16 uiIndex;
+ int16_t iFlow;
+ u32 a;
+ int32_t b;
+ int32_t y;
+
+ for (uiIndex=0; uiIndex<stLUTFlowSensor.uiLUT_TableSize; uiIndex++)
+ {
+ if (uiFlowRAW==stLUTFlowSensor.uiFlowSensorTicks[uiIndex])
+ {
+ iFlow=(int16_t)stLUTFlowSensor.uiFlowValue[uiIndex];
+ break;
+ }
+ else if (uiFlowRAW<stLUTFlowSensor.uiFlowSensorTicks[uiIndex])
+ {
+ if (uiIndex==0)
+ {
+ iFlow=(int16_t)(((u32)uiFlowRAW*stLUTFlowSensor.uiFlowValue[uiIndex])/stLUTFlowSensor.uiFlowSensorTicks[uiIndex]);
+ }
+ else
+ {
+ a=(100UL*(stLUTFlowSensor.uiFlowValue[uiIndex]-stLUTFlowSensor.uiFlowValue[uiIndex-1]))/(stLUTFlowSensor.uiFlowSensorTicks[uiIndex]-stLUTFlowSensor.uiFlowSensorTicks[uiIndex-1]);
+ b=((int32_t)stLUTFlowSensor.uiFlowValue[uiIndex-1]*100)-((int32_t)stLUTFlowSensor.uiFlowSensorTicks[uiIndex-1]*a);
+ y=((int32_t)a*(int32_t)uiFlowRAW)+b;
+ iFlow=(int16_t)(y/100);
+ }
+ break;
+ }
+ else
+ {
+ iFlow=(int16_t)stLUTFlowSensor.uiFlowValue[uiIndex];
+ }
+ }
+
+ if (bPositiveFlow==FALSE)
+ iFlow*=(-1);
+
+ return(iFlow);
+}
+
+/******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Safety.c Tue Jun 09 22:57:20 2020 +0000
@@ -0,0 +1,75 @@
+
+/* Includes ------------------------------------------------------------------*/
+#define EXTERN extern
+#include "SS.h"
+#include "_SS_OnOffActioner.h"
+#include "main.h"
+#undef EXTERN
+
+#define INIT_VARIABLES
+#define EXTERN
+#include "safety.h"
+#undef EXTERN
+#undef INIT_VARIABLES
+
+
+
+/*******************************************************************************
+* Function Name : ControlHW
+* Description : Control the STOP_BLOWER and WDI_CPLD pins
+* Input : BLOWER_OFF__PAT_CPLD or BLOWER_ON__PAT_CPLD or BLOWER_OFF__STOP_PAT_CPLD
+* Output : None
+* Return : None
+*******************************************************************************/
+void ControlHW(_enHWStatus enHWStatus)
+{
+ // Clock=0
+ SS_Xputdw(act, CLK_ACTUATORS|FLAG_ACTIONER_OFF);
+
+ /*if (enHWStatus==BLOWER_OFF__PAT_CPLD)
+ {
+ SS_Xputdw(act, CTL_ACTUATORS|FLAG_ACTIONER_OFF); // CTL_ACTUATORS=0
+ SS_Xputdw(act, CTL_CPLD|FLAG_ACTIONER_OFF); // CTL_CPLD=0
+ SS_Xputdw(act, CLK_ACTUATORS|FLAG_ACTIONER_ON); // Clock=1 => STOP_BLOWER=0, WDI_CPLD=0
+
+ SS_Xputdw(act, CLK_ACTUATORS|FLAG_ACTIONER_OFF); // Clock=0
+ SS_Xputdw(act, CTL_CPLD|FLAG_ACTIONER_ON); // CTL_CPLD=1
+ SS_Xputdw(act, CLK_ACTUATORS|FLAG_ACTIONER_ON); // Clock=1 => STOP_BLOWER=0, WDI_CPLD=1
+ }*/
+ if (enHWStatus==BLOWER_ON__PAT_CPLD)
+ {
+ SS_Xputdw(act, CTL_ACTUATORS|FLAG_ACTIONER_ON); // CTL_ACTUATORS=1
+ SS_Xputdw(act, CTL_CPLD|FLAG_ACTIONER_OFF); // CTL_CPLD=0
+ SS_Xputdw(act, CLK_ACTUATORS|FLAG_ACTIONER_ON); // Clock=1 => STOP_BLOWER=1, WDI_CPLD=0
+
+ SS_Xputdw(act, CLK_ACTUATORS|FLAG_ACTIONER_OFF); // Clock=0
+ SS_Xputdw(act, CTL_CPLD|FLAG_ACTIONER_ON); // CTL_CPLD=1
+ SS_Xputdw(act, CLK_ACTUATORS|FLAG_ACTIONER_ON); // Clock=1 => STOP_BLOWER=1, WDI_CPLD=1
+ }
+ else //if (enHWStatus==BLOWER_OFF__STOP_PAT_CPLD)
+ {
+ SS_Xputdw(act, CTL_ACTUATORS|FLAG_ACTIONER_OFF); // CTL_ACTUATORS=0
+ SS_Xputdw(act, CTL_CPLD|FLAG_ACTIONER_OFF); // CTL_CPLD=0
+ SS_Xputdw(act, CLK_ACTUATORS|FLAG_ACTIONER_ON); // Clock=1 => STOP_BLOWER=0, WDI_CPLD=0
+ }
+}
+
+
+
+/*******************************************************************************
+* Function Name : TestStopBlowerInputPin
+* Description : Test the state of the STOP_BLOWER input pin
+* Input : None
+* Output : None
+* Return : OPSTATUS_OK if the pin="0"
+*******************************************************************************/
+opstatus_t TestStopBlowerInputPin(void)
+{
+ if (GPIO_ReadInputDataBit(sPortConfig[STOP_BLOWER_PORT].Port, sPortConfig[STOP_BLOWER_PORT].Pin)==Bit_RESET)
+ return(OPSTATUS_OK);
+ return(OPSTATUS_FAIL);
+}
+/******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Ventilation.c Tue Jun 09 22:57:20 2020 +0000
@@ -0,0 +1,3355 @@
+
+/* Includes ------------------------------------------------------------------*/
+#define EXTERN extern
+#include <stdlib.h>
+#include <string.h>
+#include "SS.h"
+#include "main.h"
+#include "_SS_OnOffActioner.h"
+#include "_SS_Pwm.h"
+#include "Monitoring.h"
+#include "Safety.h"
+#include "_SS_Data_Logging.h"
+#include "_SS_Record_Settings.h"
+#include "_SS_I2CX_SDP600.h"
+#include "_SS_I2CX_X201641.h"
+#include "_SS_OptimaComm.h"
+#undef EXTERN
+
+#define INIT_VARIABLES
+#define EXTERN
+#include "Ventilation.h"
+#undef EXTERN
+#undef INIT_VARIABLES
+
+
+/* Internal constants --------------------------------------------------------*/
+// ******************* Min-max PI or PDF ***************************************
+#define MAX_VOLTAGE_REF MAX_PI_OUTPUT // MAX_PI_OUTPUT = 1343 = 18.5micros = 93.3%, want 80%
+#define MIN_VOLTAGE_REF MIN_PI_OUTPUT
+#define INTEGRAL_MAX (2147483647)
+#define INTEGRAL_MIN (-2147483648)
+
+
+#ifndef C_M3_DEVICETEST_TARGET
+ /* Internal variables --------------------------------------------------------*/
+ // ******************* MANAGED CONSTANT SPEED ****************************
+ static u16 uiBlowerSpeedSetting;
+ static int32_t lIntegral_Speed_I;
+ static bool bMaxPIOutputSpeedI;
+ static bool bMinPIOutputSpeedI;
+
+
+ // ************* MANAGED BAROMETRIC VENTILATION *************************
+ static u16 uiIpapSettingTemp;
+ static u16 uiTeBaroSet;
+ static int32_t lIntegral_Pressure_I;
+ static bool bMaxPIOutputPressureI;
+ static bool bMinPIOutputPressureI;
+ static u16 uiTiD;
+ static u8 ucIndexTableSlope;
+ #define TEMPO_TRIGGER_EXPI 30
+ static u8 ucTempoTriggerExpiAuto;
+ #define MIN_THRESHOLD_EXPI_TRIGGER_AUTO 25
+ static u8 ucExpiTriggerTreshold;
+ static u8 fFirstCycleInspi;
+
+ // ----------- Main blower management during expiration -------------------
+ static u16 uiPWMatTheEndOfInspiration;
+ static bool fFirstCycleExpi;
+ static u16 uiEpapSettingTemp;
+ static int32_t lIntegral_Pressure_E;
+ static bool bMaxPIOutputPressureE;
+ static bool bMinPIOutputPressureE;
+ static u16 uiPWMatTheEndOfExpiration;
+ static u16 uiTeD;
+ static bool fBlockCloseLoop;
+
+ static u16 uiTiTyp;
+
+ // ************* MANAGED VOLUMETRIC VENTILATION *************************
+ static u32 ulMaxIFlowSet;
+ static u32 ulMinIFlowSet;
+ static u32 ulDecFlowStep;
+ static u16 uiTeVoluSet;
+ static u16 uiProximalPressureAtTheEndOfInspiration;
+ static int32_t lIntegral_Flow_I;
+ static bool bMaxPIOutputFlowI;
+ static bool bMinPIOutputFlowI;
+ static int16_t iVtAdjust=0;
+ static u8 ucCounterHPAlarm=0;
+
+
+ // ******************* MANAGED_CPAP_VENTILATION ******************************
+ #define EXPIRATORY_DISCONNECTION_TIME_OUT 500 // 500ms
+ #define CPAP_DISCONNECTION_TEST_PERIODICITY 4000 // 4s
+ static u16 uiDisconnectionTime;
+ static u16 uiDisconnectionTimeInCPAP;
+ static u16 uiMemoPWMDuringDisconnection;
+ //static u8 ucStandByMode;
+
+ // ***************** MANAGED INSPIRATORY TRIGGER *****************************
+ #define MAX_DELTA_FLOW 100 // 1 l/min
+ #define SIZE_DELTA_INSPIRATORY_FLOW_BUFFER 40
+ #define NUMBER_TRIGGER_VALID 20
+ #define NUMBER_MIN_FLOW_VALUE 30
+ //static int16_t iBufferIFlowDelta[SIZE_DELTA_INSPIRATORY_FLOW_BUFFER];
+ static u8 ucInspiTriggerScheduler;
+ static u8 ucMinFlowCounter;
+ static int16_t iInspiratoryFlowMin;
+ //static int16_t iOldInspiratoryFlowSmoothingMesForTrigger;
+ #define SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER 250
+ static int16_t iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER];
+ // static int16_t iBufferConductance[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER];
+ static u8 ucCounterTriggerValid;
+ static int16_t iFlowBaseLineReference;
+ static bool bDetectionConstantFlow;
+
+
+ // *********************** MANAGED MONITORING FOR MLT ************************
+ static u16 uiMLT_PressureSetPoint;
+ #ifdef MOTOR_LIFE_TESTING
+ #define MLT_AVERAGE_MONITORING 1000
+ static u16 uiAverageMonitoringMLT;
+ static u32 ulMLT_SumSpeedMes;
+ static u32 ulMLT_SumCurrentMes;
+ static u32 ulMLT_SumTemperatureMes;
+ static u32 ulMLT_SumBlowerVoltage;
+ static u16 uiMLT_EnableAlarm;
+ #endif // #ifdef MOTOR_LIFE_TESTING
+
+
+ // ************************ MANAGED CALIBRATION ******************************
+ typedef enum
+ {
+ INIT_FLOW_CALIB_TEST=0,
+ SET_GAS_TYPE,
+ SET_GAS_STANDARD,
+ START_FLOW_READING,
+ SEND_FLOW_COMMAND,
+ READ_FLOW_VALUE,
+ SEND_HIGH_FLOW_CALIB_REQUEST,
+ WAIT_FOR_HIGH_FLOW_CALIB_ACK,
+ PREPARE_FAILURE_COMMAND,
+ PREPARE_SUCCESS_COMMAND,
+ SEND_COMMAND_TO_PF300,
+ CHECK_COMMAND_FROM_PF300,
+ END_OF_CALIBRATION,
+ } type_enLowFlowCalibrationStep;
+
+ typedef enum
+ {
+ INIT_PRESSURE_CALIB_TEST=0,
+ START_PRESSURE_READING,
+ SEND_PRESSURE_COMMAND,
+ READ_PRESSURE_VALUE,
+ PRESSURE_CALIB_FAILURE_COMMAND,
+ PRESSURE_CALIB_SUCCESS_COMMAND,
+ PRESSURE_CALIB_SEND_COMMAND_TO_PF300,
+ PRESSURE_CALIB_CHECK_COMMAND_FROM_PF300,
+ PRESSURE_CALIB_END_OF_CALIBRATION,
+ } type_enPressureCalibrationStep;
+
+ #define SIZE_BUFFER_FLOW_VALUE 15
+ typedef struct
+ {
+ unsigned char ucIndex;
+ bool bFirstPartOfTheCRReceived;
+ char szValue[SIZE_BUFFER_FLOW_VALUE];
+ } type_stFlow;
+
+ // Flow and pressure calibration
+ #define TIME_OUT_RECEPTION_PACKET_FROM_PF300 2000 // 2s
+ #define SAMPLE_RATE_BETWEEN_TWO_FLOW 5000 // 5s
+ #define SIZE_RX_BUFFER_PF300 20
+ static u16 uiCalibrationTimeOut;
+ static unsigned char ucIndexAnswerFromPF300;
+ static char szAnswerFromPF300[SIZE_RX_BUFFER_PF300];
+ static char szExpectedAnswerFromPF300[SIZE_RX_BUFFER_PF300];
+ static u8 ucNumberOfBytesToCheckFromPF300Answer;
+
+ // Flow calibration
+ static type_enLowFlowCalibrationStep enLowFlowCalibrationStep;
+ static type_enLowFlowCalibrationStep enGoBackToStep;
+ static unsigned long ulSumFlowTicks;
+ static unsigned int uiFlowTicksSamplesCounter;
+ //static type_stLUTFlowSensor stTemporayLUTFlowSensor;
+ static bool bHighFlowCalibrationInProgress;
+ static unsigned int uiMotorDutyCyleForFlowCalib;
+ static unsigned int uiImHereMsgTimer;
+
+ // Pressure calibration
+ #define SAMPLE_RATE_BETWEEN_TWO_PRESSURE 10000 // 30s
+ static type_enPressureCalibrationStep enPressureCalibrationStep;
+ static type_enPressureCalibrationStep enPressureCalibGoBackToStep;
+ static u32 ulSumPressureTicks;
+ static u16 uiPressureTicksSamplesCounter;
+
+ // List of command to PF300
+ static const char szPF300_CmdSwitchOffEcho[]={"%CM#5$0\r"}; // Command Echo from PF300 off
+ static const char szPF300_AnswerSwitchOffEcho[]={"%CM#5"}; // Answer echo off from PF300 (WO \r)
+ static const char szPF300_SetAirGasType[]={"%WS#1$0\r"}; // command Air
+ static const char szPF300_AnswerAirGasType[]={"%WS#1$0"}; // Answer Air
+ static const char szPF300_SetGasStandard[]={"%WS#3$1\r"}; // Command STPD
+ static const char szPF300_AnswerGasStandard[]={"%WS#3$1"}; // Answer STPD
+ static const char szPF300_ReadLowFlowCmd[]={"%RM#1\r"}; // Command read low flow
+ static const char szPF300_ReadLowFlowAnswer[]={"%RM#1$"}; // Answer read low flow
+ static const char szPF300_ReadHighFlowCmd[]={"%RM#0\r"}; // Command read high flow
+ static const char szPF300_ReadHighFlowAnswer[]={"%RM#0$"}; // Answer read high flow
+ static const char szPF300_ReadPdiffCmd[]={"%RM#3\r"}; // Command read pressure diff.
+ static const char szPF300_ReadPdiffAnswer[]={"%RM#3$"}; // Answewr read pressure diff.
+
+ // List of Command to Handset
+ static const char szRequestHighFlowCalib[]={"@N"};
+ static const char szEndOfCalibOK[]={"@S"};
+ static const char szImHere[]={"@*"};
+
+
+ // ---------------- Management FRAM for settings -----------------------------
+ #ifdef RECORD_SETTINGS
+ #endif // RECORD_SETTINGS
+
+ // -------------------- Manage Motor starting --------------------------------
+ #ifndef TEMPERATURE_TRENDS
+ static u8 ucStartVentilationScheduler=0;
+ #endif
+ static enMaroubraModes enPreviousMode;
+ static u16 uiPreviousDeviceMode;
+#endif // C_M3_DEVICETEST_TARGET
+
+
+#ifndef C_M3_DEVICETEST_TARGET
+ #define SIZE_SLOPE2_TABLE 21
+ const unsigned char ucSlope2Table[SIZE_SLOPE2_TABLE]= {
+ 0, 35, 50, 59, 65, 70, 74, 77, 80, 83,
+ 85, 87, 89, 91, 92, 94, 95, 96, 98, 99,
+ 100 };
+
+ // Table pente inspiratoire 2
+ #define SIZE_SLOPE3_TABLE 41
+ const unsigned char ucSlope3Table[SIZE_SLOPE3_TABLE]= {
+ 0, 20, 35, 44, 50, 55, 59, 62, 65, 68, 70,
+ 72, 74, 76, 77, 79, 80, 81, 83, 84, 85, 86,
+ 87, 88, 89, 90, 91, 91, 92, 93, 94, 94, 95,
+ 96, 96, 97, 98, 98, 99, 99, 100 };
+
+ // Table pente inspiratoire 3
+ #define SIZE_SLOPE4_TABLE 61
+ const unsigned char ucSlope4Table[SIZE_SLOPE4_TABLE]= {
+ 0, 11, 26, 35, 41, 46, 50, 53, 56, 59, 61,
+ 63, 65, 67, 68, 70, 71, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 83, 84, 85, 86, 86,
+ 87, 88, 88, 89 ,90, 90, 91, 91, 92, 92, 93,
+ 93, 94, 94, 95, 95, 96, 96, 96, 97, 97, 98,
+ 98, 99, 99, 99, 100, 100 };
+
+
+ // Maximum allowed flow in expiration Flow=f(PEEP set) (example: flow-by max=29L/min @ 5hPa)
+ const u16 uiMaximumFlowInExpiration[41]={
+ 0, 1300, 1830, 2250, 2600, 2900, 3180, 3430, 3670, 3900,
+ 4110, 4310, 4500, 4680, 4860, 5030, 5200, 5360, 5510, 5660,
+ 5810, 5950, 6090, 6230, 6360, 6500, 6620, 6750, 6870, 7000,
+ 7120, 7230, 7350, 7460, 7580, 7690, 7800, 7900, 8010, 8110, 8220
+ };
+#endif // C_M3_DEVICETEST_TARGET
+
+
+/* Internal functions --------------------------------------------------------*/
+#ifndef C_M3_DEVICETEST_TARGET
+ u16 ComputeTe(u16 uiF, u16 uiTi);
+ void ComputeInspiratoryFlowSetPointInAVC(u16 uiTypeOfPatient, u16 uiVtc, u16 uiTi, u16 uiFlowShape, u32 *ulMaxFlow, u32 *ulMinFlow, u32 *ulFlowStep);
+ unsigned char TestTriggerExpiratoire(unsigned char ucValeurSeuil, unsigned int uiPressureSetting);
+ bool TestInspiratoryTrigger(bool bSpont, u16 uiTe, u16 uiFlowThreshold);
+ int16_t UpdateInspiratoryFlowAverage(void);
+ int16_t UpdateInspiratoryConductanceAverage(void);
+ void ResetInspiratoryConductanceAverage(void);
+ bool TestInspiratorySlowTrigger(int16_t iTheFlowBaseLine, u16 uiFlowTreshold);
+ void ApplyDefaultValueToTemporaryVentilationSettings(void);
+ void ApplyDefaultValueToTechnicalSettings(void);
+ void ApplyAllDefaultValues(void);
+ bool ApplyNewVentilationMode(void);
+ void ApplyDefaultFlowLUT(void);
+ void CheckFlowLUTRange(void);
+ void ManageFlowCalibration(void);
+ void ManagePressureCalibration(void);
+ void ManageCstPressure(void);
+#endif // C_M3_DEVICETEST_TARGET
+
+
+
+#ifndef C_M3_DEVICETEST_TARGET
+/*******************************************************************************
+* Function Name : InitSettings
+* Description : Initialize parameters for ventilation
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void InitSettings(void)
+{
+ uiPreviousDeviceMode=0xFF;
+ enPreviousMode=NUMBER_OF_MODE;
+
+ // --- Init Settings
+ uiTechnicalDataMes[SW_VERSION_TEC_MES]=MAROUBRA_BLOWER_SW_VERSION;
+ bComputeOffsetSensors=FALSE;
+
+ #ifdef RECORD_SETTINGS
+ // Read and init FRAM
+ if (InitSettingsZoneAndTechnicalZoneInFRAM()==OPSTATUS_OK)
+ {
+ if (ReadSettingsZoneAndTechnicalZoneInFRAM()==OPSTATUS_FAIL)
+ {
+ uiFlagsAlarm[ALARM_FLAGS2]|=FRAM_FAILURE_ALARM_MASK;
+ ApplyAllDefaultValues();
+ }
+ }
+ else
+ {
+ uiFlagsAlarm[ALARM_FLAGS2]|=FRAM_FAILURE_ALARM_MASK;
+ ApplyAllDefaultValues();
+ }
+ #else
+ ApplyAllDefaultValues();
+ #endif
+
+ // Compute offsets sensors if necessary
+ if (bComputeOffsetSensors==TRUE)
+ {
+ // ------ Update Blower Flow sensor offset before ventilation -------
+ #ifdef SDP600_USED_I2C1_BUS
+ SDP600_ComputeOffsetFlowSensorOnI2C1(SDP600_BLOWER_FLOW_SENSOR);
+ #endif // SDP600_USED_I2C1_BUS
+
+ #ifdef X201641_USED_I2C1_BUS
+ X201641_ComputeOffsetFlowSensorOnI2C1(X201641_BLOWER_FLOW_SENSOR);
+ #endif // X201641_USED_I2C1_BUS
+
+ // ----- Update Proximal Pressure sensor offset before ventilation -------
+ ComputeOffsetProximalPressureSensor();
+ }
+
+ // Check Technical settings range
+ CheckTechnicalSettingsRange();
+
+ // Check Flow LUT
+ CheckFlowLUTRange();
+
+ // Check temporary ventilation setting range
+ if (CheckTemporaryVentilationSettingRange()==OPSTATUS_FAIL)
+ {
+ ApplyDefaultValueToTemporaryVentilationSettings();
+ uiFlagsAlarm[ALARM_FLAGS2]|=VENTILATION_SETTINGS_RANGE_ALARM_MASK;
+ }
+
+ // --- Update computed settings (Te,...)
+ UpdateSettings();
+
+ #ifdef MOTOR_LIFE_TESTING
+ uiTechnicalDataSet[DEVICE_MODE_TEC]=PRESSURE_CST_MODE;
+ uiTechnicalDataSet[START_STOP_VENTILATION]=1;
+ #endif
+}
+
+
+/*******************************************************************************
+* Function Name : InitVentilation
+* Description : Initialize variables for ventilation
+* Function called :
+* - when we start ventilation
+* - when we change of ventilation mode
+* - when we change of device mode
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void InitVentilation(void)
+{
+ ucVentilationCycle=EXPIRATION_CYCLE;
+ uiTiD=0;
+ uiTeD=0;
+ uiTiTyp = 1000;
+ bManualBreath=FALSE;
+
+ if (enPreviousMode==NUMBER_OF_MODE)
+ {
+ // Start ventilation
+ uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT;
+ uiDisconnectionTimeInCPAP=CPAP_DISCONNECTION_TEST_PERIODICITY;
+ uiMemoPWMDuringDisconnection=0;
+ fBlockCloseLoop=FALSE;
+ }
+
+ ClearAllVentilationAlarms();
+ ClearAllMeasures();
+
+ switch(uiTechnicalDataSet[DEVICE_MODE_TEC])
+ {
+ default:
+ case VENTILATION_MODE:
+ {
+ if (enVentilationMode==APCV_MODE || enVentilationMode==PS_MODE)
+ {
+ if (enPreviousMode==APCV_MODE || enPreviousMode==PS_MODE)
+ {
+ // --- We are already in pressure mode
+ }
+ else
+ {
+ // --- Start a pressure mode
+ fFirstCycleInspi=TRUE;
+ uiPWMatTheEndOfInspiration=MIN_VOLTAGE_REF;
+
+ if (enPreviousMode!=AVC_MODE)
+ {
+ uiPWMatTheEndOfExpiration=MIN_VOLTAGE_REF;
+ lIntegral_Pressure_E=0;
+ bMaxPIOutputPressureE=FALSE;
+ bMinPIOutputPressureE=FALSE;
+ fFirstCycleExpi=TRUE;
+ }
+ }
+ }
+ else if (enVentilationMode==AVC_MODE)
+ {
+ iVtAdjust=0;
+ fFirstCycleInspi=TRUE;
+ uiPWMatTheEndOfInspiration=MIN_VOLTAGE_REF;
+
+ if (enPreviousMode!=APCV_MODE && enPreviousMode!=PS_MODE)
+ {
+ uiPWMatTheEndOfExpiration=MIN_VOLTAGE_REF;
+ lIntegral_Pressure_E=0;
+ bMaxPIOutputPressureE=FALSE;
+ bMinPIOutputPressureE=FALSE;
+ fFirstCycleExpi=TRUE;
+ }
+ }
+ else if (enVentilationMode==CPAP_MODE)
+ {
+ Ki_Pressure_I=1000;
+ uiPWMatTheEndOfInspiration=MIN_VOLTAGE_REF;
+ lIntegral_Pressure_I=0;
+ bMaxPIOutputPressureI=FALSE;
+ bMinPIOutputPressureI=FALSE;
+ }
+ break;
+ }
+ case ONE_CST_PWM_MODE:
+ {
+ uiInspirationBlowerPWMTec=250;
+ break;
+ }
+ case TWO_CST_PWM_MODE:
+ {
+ uiInspirationBlowerPWMTec=350;
+ uiExpirationBlowerPWMTec=150;
+ break;
+ }
+ case CST_SPEED_MODE:
+ {
+ uiBlowerSpeedSet=15000;
+ uiBlowerSpeedSetting=5000;
+ break;
+ }
+ case FLOW_CAL_MODE:
+ {
+ enLowFlowCalibrationStep=INIT_FLOW_CALIB_TEST;
+ bHighFlowCalibrationInProgress=FALSE;
+ stTemporayLUTFlowSensor.uiLUT_TableSize=0;
+ uiCalibrationTimeOut=(TIME_OUT_BLOWER_HANDSET_COMM*20); // 2s
+ break;
+ }
+ case PRESSURE_CAL_MODE:
+ {
+ enPressureCalibrationStep=INIT_PRESSURE_CALIB_TEST;
+ uiCalibrationTimeOut=(TIME_OUT_BLOWER_HANDSET_COMM*20); // 2s
+ break;
+ }
+ case PRESSURE_CST_MODE:
+ {
+ uiMLT_PressureSetPoint=10;
+ lIntegral_Pressure_I=0;
+ bMaxPIOutputPressureI=FALSE;
+ bMinPIOutputPressureI=FALSE;
+
+ #ifdef MOTOR_LIFE_TESTING
+ uiMLT_EnableAlarm=5000; // 5s before enabling alarm
+ uiAverageMonitoringMLT=MLT_AVERAGE_MONITORING;
+ ulMLT_SumSpeedMes=0;
+ ulMLT_SumCurrentMes=0;
+ ulMLT_SumTemperatureMes=0;
+ ulMLT_SumBlowerVoltage=0;
+ #endif // #ifdef MOTOR_LIFE_TESTING
+ break;
+ }
+ }
+ enPreviousMode=enVentilationMode;
+}
+
+
+/*******************************************************************************
+* Function Name : StopAllActuators
+* Description : Stop all actuators
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void StopAllActuators(void)
+{
+ // Stop main blower
+ SS_Xclose(mdrv);
+
+ // Valve OFF
+ SS_Xputdw(act, EV_CTL|FLAG_ACTIONER_OFF);
+}
+
+/*******************************************************************************
+* Function Name : CalculateHoseDrop
+* Description : Manage Ti, Te, DAC, Blower, PID
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+u16 CalculateHoseDrop(void)
+{
+ u16 hoseDrop = (u16)(10*(iBlowerFlowSmoothingMes/100.0f/60.0f * 0.5f));
+ return hoseDrop;
+}
+
+/*******************************************************************************
+* Function Name : ManageCPAPVentilation
+* Description : Manage Ti, Te, DAC, Blower, PID
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ManageCPAPVentilation(void)
+{
+
+
+
+ // *************************** UPDATE SETTINGS *******************************
+ if (ApplyNewVentilationMode()==TRUE)
+ return;
+
+ // **************************** Cycle detection ******************************
+ // Test Synchronisation
+ /*if (iBlowerFlowSmoothingMesForTrigger<(-500) && ucVentilationCycle==INSPIRATION_CYCLE)
+ ucVentilationCycle=EXPIRATION_CYCLE; */
+ int32_t peakP = 2;//(int32_t)uiVentilationSet[PS_CPAP_SET];
+ // Cycle detection
+ if (ucVentilationCycle==INSPIRATION_CYCLE)
+ {
+ uiTiD++;
+ if(uiTiD < (0.1f * uiTiTyp))
+ {
+ peakP =(int32_t)( uiVentilationSet[PS_CPAP_SET] * ((uiTiD* 1.0f)/(0.1f * uiTiTyp)));
+ }
+ else if(uiTiD < (1.0f * uiTiTyp))
+ {
+ peakP = ((int32_t)uiVentilationSet[PS_CPAP_SET] - ((int32_t)(uiVentilationSet[PS_CPAP_SET] * (uiTiD * 1.0f)/(1.1f * uiTiTyp)))) + 20;
+ }
+ else
+ {
+ peakP = 2;
+ }
+
+ if (uiTiD>5000 || (uiTiD>TiBaroSet_P_MIN && TestTriggerExpiratoire(20, uiVentilationSet[PS_CPAP_SET])==TRUE))
+ {
+ ucVentilationCycle=EXPIRATION_CYCLE;
+ uiPWMatTheEndOfInspiration = uiInspirationBlowerPWMTec;
+ if(uiTiD < 2000)
+ {
+ uiTiTyp = uiTiD;
+ }
+ else
+ {
+ uiTiTyp = 2000;
+ }
+
+ uiTeD=0;
+ }
+ }
+ else
+ {
+ uiTeD++;
+ if (uiTeD>TE_SET_MAX) uiTeD=TE_SET_MAX;
+
+ if (TestInspiratoryTrigger(TRUE, uiTeD, 15)==TRUE)
+ {
+ ucVentilationCycle=INSPIRATION_CYCLE;
+ uiTiD=0;
+ }
+ }
+
+ // Barometric Mode : error computation
+ ControlPressure((int32_t)(peakP + CalculateHoseDrop()));
+}
+
+/*******************************************************************************
+* Function Name : ControlPressure
+* Description : Manage Ti, Te, DAC, Blower, PID
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+int32_t previousError = 0;
+int32_t lIntegralSum = 0;
+void ControlPressure(int32_t setPressure)//pressure in cmH2O*10
+{
+ int32_t lPropTerm;
+ int32_t lIntegralTerm;
+ int32_t lDerivativeTerm;
+ int32_t lOutputPressure;
+
+
+ int32_t lError = setPressure - uiProximalPressureMes;
+
+ lPropTerm = (int32_t)uiTechnicalDataSet[KP_CPAP_VENTED_PRESSURE_I] * lError;
+ lIntegralTerm += (int32_t)(uiTechnicalDataSet[KI_CPAP_VENTED_PRESSURE_I] * lError);
+ lDerivativeTerm = (int32_t)(uiTechnicalDataSet[KP_FLOW_I]*(lError - previousError/1000));
+ previousError = lError;
+
+ // Close loop in pressure
+ if ((lIntegralTerm + lIntegralSum) > INTEGRAL_MAX)
+ {
+ lIntegralSum = INTEGRAL_MAX;
+ }
+ else if ((lIntegralTerm - lIntegralSum)< INTEGRAL_MIN)
+ {
+ lIntegralSum = INTEGRAL_MIN;
+ }
+ else
+ {
+ lIntegralSum += lIntegralTerm;
+ }
+
+ lOutputPressure = (lDerivativeTerm>>19) + (lIntegralSum>>16) + (lPropTerm>>13) ;
+
+ lOutputPressure+=uiPWMatTheEndOfInspiration;
+
+
+ // Limit and Update blower PWM
+ if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF))
+ {
+ bMaxPIOutputPressureI = TRUE;
+ uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF;
+ }
+ else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF))
+ {
+ bMinPIOutputPressureI = TRUE;
+ uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ }
+ else
+ {
+ bMaxPIOutputPressureI = FALSE;
+ bMinPIOutputPressureI = FALSE;
+ uiInspirationBlowerPWMTec = lOutputPressure;
+ }
+
+ SS_Xputdw(mdrv, uiInspirationBlowerPWMTec);
+
+}
+
+
+/*******************************************************************************
+* Function Name : DavidCControlPressure
+* Description : Manage Ti, Te, DAC, Blower, PID
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void DavidCControlPressure(int32_t setPressure)//pressure in cmH2O*10
+{
+ int32_t lPropTerm;
+ int32_t lIntegralTerm;
+ int32_t lOutputPressure;
+ u16 uiFlowMaxInExpi;
+ int32_t lError = setPressure - uiProximalPressureMes;
+
+ lIntegralTerm = (int32_t)Ki_Pressure_I * lError;
+ if (Ki_Pressure_I<uiTechnicalDataSet[KI_CPAP_VENTED_PRESSURE_I])
+ {
+ Ki_Pressure_I++;
+ }
+
+ // Close loop in pressure
+ if ((lIntegral_Pressure_I>=0) && (lIntegralTerm>=0) && (bMaxPIOutputPressureI==FALSE))
+ {
+ if ((lIntegral_Pressure_I + lIntegralTerm) <0)
+ lIntegral_Pressure_I = INTEGRAL_MAX;
+ else
+ lIntegral_Pressure_I += lIntegralTerm;
+ }
+ else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm<=0) && (bMinPIOutputPressureI==FALSE))
+ {
+ if ((lIntegral_Pressure_I + lIntegralTerm)>0)
+ lIntegral_Pressure_I = INTEGRAL_MIN;
+ else
+ lIntegral_Pressure_I += lIntegralTerm;
+ }
+ else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm>=0))
+ lIntegral_Pressure_I += lIntegralTerm;
+ else if ((lIntegral_Pressure_I>=0) && (lIntegralTerm<=0))
+ lIntegral_Pressure_I += lIntegralTerm;
+
+ lPropTerm = (int32_t)uiTechnicalDataSet[KP_CPAP_VENTED_PRESSURE_I] * lError;
+
+ lOutputPressure = (lIntegral_Pressure_I>>16) + (lPropTerm>>13);
+
+ lOutputPressure+=uiPWMatTheEndOfInspiration;
+
+ // Flow limiting
+ uiFlowMaxInExpi=uiMaximumFlowInExpiration[uiVentilationSet[PS_CPAP_SET]/10];
+ if (lError>5 && iBlowerFlowSmoothingMes>(int16_t)uiFlowMaxInExpi)
+ {
+ // Impossible to maintain the peep (patient disconnection)
+ if (uiDisconnectionTime==0)
+ {
+ if (fBlockCloseLoop==FALSE)
+ uiDisconnectionTimeInCPAP=CPAP_DISCONNECTION_TEST_PERIODICITY;
+ fBlockCloseLoop=TRUE; // Block the close loop
+ if (uiMemoPWMDuringDisconnection!=0) // Apply a fixed PWM value
+ uiInspirationBlowerPWMTec=uiMemoPWMDuringDisconnection;
+ else
+ uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ }
+ else
+ uiDisconnectionTime--;
+ }
+ else if (iBlowerFlowSmoothingMes<(int16_t)uiFlowMaxInExpi && (lError>(-2) && lError<2))
+ {
+ // Good pressure : no disconnection
+ uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT;
+
+ if (fBlockCloseLoop==TRUE)
+ {
+ // The close loop was block before => unblock it
+ fBlockCloseLoop=FALSE;
+ lIntegral_Pressure_I=0;
+ bMaxPIOutputPressureI = FALSE;
+ bMinPIOutputPressureI = FALSE;
+ uiPWMatTheEndOfInspiration=uiInspirationBlowerPWMTec;
+ return;
+ }
+ else if (iBlowerFlowSmoothingMes>=0)
+ {
+ // Record current PWM
+ uiMemoPWMDuringDisconnection=uiInspirationBlowerPWMTec;
+ }
+ }
+
+ // Unblock the close loop every 4s in case of none recorded PWM value
+ if (fBlockCloseLoop==TRUE && uiMemoPWMDuringDisconnection==0 && uiDisconnectionTimeInCPAP==0)
+ {
+ uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT;
+ fBlockCloseLoop=FALSE;
+ lIntegral_Pressure_I=0;
+ bMaxPIOutputPressureI = FALSE;
+ bMinPIOutputPressureI = FALSE;
+ uiPWMatTheEndOfInspiration=uiInspirationBlowerPWMTec;
+ return;
+ }
+
+ // Update Time counters
+ if (uiDisconnectionTimeInCPAP!=0)
+ uiDisconnectionTimeInCPAP--;
+
+ // Update blower PWM
+ if (fBlockCloseLoop==TRUE)
+ {
+ bMaxPIOutputPressureI = TRUE;
+ }
+ else if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF))
+ {
+ bMaxPIOutputPressureI = TRUE;
+ uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF;
+ }
+ else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF))
+ {
+ bMinPIOutputPressureI = TRUE;
+ uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ }
+ else
+ {
+ bMaxPIOutputPressureI = FALSE;
+ bMinPIOutputPressureI = FALSE;
+ uiInspirationBlowerPWMTec = lOutputPressure;
+ }
+
+ SS_Xputdw(mdrv, uiInspirationBlowerPWMTec);
+
+}
+
+/*******************************************************************************
+* Function Name : ManageOneCstPWM
+* Description : Manage Ti, Te, DAC, Blower, PID
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ManageOneCstPWM(void)
+{
+ // *************************** UPDATE SETTINGS *******************************
+ if (ApplyNewVentilationMode()==TRUE)
+ return;
+
+ // Update Blower Speed
+ SS_Xputdw(mdrv, uiInspirationBlowerPWMTec);
+}
+
+
+/*******************************************************************************
+* Function Name : Manage2CstPWM
+* Description : Manage Ti, Te, DAC, Blower, PID
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void Manage2CstPWM(void)
+{
+ if (ucVentilationCycle==INSPIRATION_CYCLE)
+ {
+ // ------------- INSPIRATION ------------
+ SS_Xputdw(mdrv, uiInspirationBlowerPWMTec);
+
+ // Inspiratoy time
+ uiTiD++;
+ if (uiTiD>=uiVentilationSet[TI_BARO_SET])
+ {
+ ucVentilationCycle=EXPIRATION_CYCLE;
+ uiTiD=0;
+ }
+ }
+ else
+ {
+ // ------------- EXPIRATION ------------
+ // *************************** UPDATE SETTINGS *******************************
+ if (ApplyNewVentilationMode()==TRUE)
+ return;
+
+ SS_Xputdw(mdrv, uiExpirationBlowerPWMTec);
+
+ // Expiratoy time
+ uiTeD++;
+ if (uiTeD>=uiTeBaroSet)
+ {
+ ucVentilationCycle=INSPIRATION_CYCLE;
+ uiTeD=0;
+ }
+ }
+}
+
+
+/*******************************************************************************
+* Function Name : ManageCstSpeed
+* Description : Manage constant speed ventilation
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ManageCstSpeed(void)
+{
+ int32_t lError;
+ int32_t lPropTerm;
+ int32_t lIntegralTerm;
+ int32_t lOutputSpeed;
+
+ // *************************** UPDATE SETTINGS *******************************
+ if (ApplyNewVentilationMode()==TRUE)
+ return;
+
+ // Update settings
+ if (uiBlowerSpeedSetting<uiBlowerSpeedSet)
+ uiBlowerSpeedSetting+=10;
+ else if (uiBlowerSpeedSetting>uiBlowerSpeedSet)
+ uiBlowerSpeedSetting-=10;
+
+ uiTiD++;
+ if ((uiTiD%10)==0)
+ {
+ // Barometric Mode : error computation
+ lError=(int32_t)uiBlowerSpeedSetting-(int32_t)uiBlowerSpeedMes;
+ lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_SPEED_I_TEC] * lError;
+
+ // Close loop in pressure
+ if ((lIntegral_Speed_I>=0) && (lIntegralTerm>=0) && (bMaxPIOutputSpeedI==FALSE))
+ {
+ if ((lIntegral_Speed_I + lIntegralTerm) <0)
+ lIntegral_Speed_I = INTEGRAL_MAX;
+ else
+ lIntegral_Speed_I += lIntegralTerm;
+ }
+ else if ((lIntegral_Speed_I<=0) && (lIntegralTerm<=0) && (bMinPIOutputSpeedI==FALSE))
+ {
+ if ((lIntegral_Speed_I + lIntegralTerm)>0)
+ lIntegral_Speed_I = INTEGRAL_MIN;
+ else
+ lIntegral_Speed_I += lIntegralTerm;
+ }
+ else if ((lIntegral_Speed_I<=0) && (lIntegralTerm>=0))
+ lIntegral_Speed_I += lIntegralTerm;
+ else if ((lIntegral_Speed_I>=0) && (lIntegralTerm<=0))
+ lIntegral_Speed_I += lIntegralTerm;
+
+ lPropTerm = (int32_t)uiTechnicalDataSet[KP_SPEED_I_TEC] * lError;
+ lOutputSpeed = (lIntegral_Speed_I>>16) + (lPropTerm>>13);
+
+ if (lOutputSpeed>=((int32_t)MAX_VOLTAGE_REF))
+ {
+ bMaxPIOutputSpeedI = TRUE;
+ uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF;
+ }
+ else if (lOutputSpeed<((int32_t)MIN_VOLTAGE_REF))
+ {
+ bMinPIOutputSpeedI = TRUE;
+ uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ }
+ else
+ {
+ bMaxPIOutputSpeedI = FALSE;
+ bMinPIOutputSpeedI = FALSE;
+ uiInspirationBlowerPWMTec = lOutputSpeed;
+ }
+ SS_Xputdw(mdrv, uiInspirationBlowerPWMTec);
+ }
+}
+
+/*******************************************************************************
+* Function Name : ManageFlowCalibration
+* Description : Manage Low flow calibration
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ManageFlowCalibration(void)
+{
+ char cCharValue;
+ char szTempBuf[SIZE_RX_BUFFER_PF300];
+
+ /*
+ #ifdef USE_TSI_4040
+ switch(enTSICommScheduler)
+ {
+ default:
+ case TSI_SET_TYPE_OF_GAS:
+ {
+ // Send Type of Gas command
+ ucTSICommand=TSI_SEND_GAS_TYPE_AIR_CMD;
+ if (SS_Xputdw(tsi, &ucTSICommand)==TRUE)
+ {
+ enTSICommScheduler=TSI_CHECK_ANSWER;
+ enTSIGoBackToStep=TSI_SET_FLOW_UNIT;
+ }
+ break;
+ }
+ case TSI_SET_FLOW_UNIT:
+ {
+ // Send Type of Gas command
+ ucTSICommand=TSI_SEND_FLOW_UNIT_STANDARD_CMD;
+ if (SS_Xputdw(tsi, &ucTSICommand)==TRUE)
+ {
+ enTSICommScheduler=TSI_CHECK_ANSWER;
+ enTSIGoBackToStep=TSI_SET_SAMPLE_TIME;
+ }
+ break;
+ }
+ case TSI_SET_SAMPLE_TIME:
+ {
+ // Send sample time
+ ucTSICommand=TSI_SEND_SAMPLE_TIME_10MS_CMD;
+ if (SS_Xputdw(tsi, &ucTSICommand)==TRUE)
+ {
+ enTSICommScheduler=TSI_CHECK_ANSWER;
+ enTSIGoBackToStep=TSI_READ_FLOW;
+ }
+ break;
+ }
+ case TSI_READ_FLOW:
+ {
+ // Send sample time
+ ucTSICommand=TSI_SEND_READ_FLOW_CMD;
+ if (SS_Xputdw(tsi, &ucTSICommand)==TRUE)
+ {
+ enTSICommScheduler=TSI_CHECK_ANSWER;
+ enTSIGoBackToStep=TSI_CYCLE_DETECTION;
+ }
+ break;
+ }
+ case TSI_CYCLE_DETECTION:
+ {
+ uiBlowerFlow=iFlowFromTSI;
+ break;
+ }
+ case TSI_CHECK_ANSWER:
+ {
+ opstatus=SS_Xgetw(tsi, &uiDummy);
+ if (opstatus==OPSTATUS_OK)
+ {
+ enTSICommScheduler=enTSIGoBackToStep;
+ }
+ else if (opstatus==OPSTATUS_FAIL)
+ {
+ enTSICommScheduler=TSI_SET_TYPE_OF_GAS;
+ }
+ break;
+ }
+ }
+ #endif // #ifdef USE_TSI_4040
+ */
+
+ switch(enLowFlowCalibrationStep)
+ {
+ case INIT_FLOW_CALIB_TEST:
+ {
+ // Init comm with PF300 => wait 2s before sending first command to PF300
+ // We need to wait for this delay in order to the handset to activate its transparent mode
+ if (uiCalibrationTimeOut==0)
+ {
+ bDisableMaroubraCommCommunication=TRUE;
+
+ // Prepare command to PF300
+ UpdateBufferToSend((char*)szPF300_CmdSwitchOffEcho);
+ enLowFlowCalibrationStep=SEND_COMMAND_TO_PF300;
+ strcpy(szExpectedAnswerFromPF300, szPF300_AnswerSwitchOffEcho);
+ ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_AnswerSwitchOffEcho);
+ enGoBackToStep=SET_GAS_TYPE;
+ }
+ else
+ {
+ uiCalibrationTimeOut--;
+ }
+ break;
+ }
+ case SET_GAS_TYPE:
+ {
+ // Prepare command to PF300
+ UpdateBufferToSend((char*)szPF300_SetAirGasType);
+ enLowFlowCalibrationStep=SEND_COMMAND_TO_PF300;
+ strcpy(szExpectedAnswerFromPF300, szPF300_AnswerAirGasType);
+ ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_AnswerAirGasType);
+ enGoBackToStep=SET_GAS_STANDARD;
+ break;
+ }
+ case SET_GAS_STANDARD:
+ {
+ // Prepare command to PF300
+ UpdateBufferToSend((char*)szPF300_SetGasStandard);
+ enLowFlowCalibrationStep=SEND_COMMAND_TO_PF300;
+ strcpy(szExpectedAnswerFromPF300, szPF300_AnswerGasStandard);
+ ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_AnswerGasStandard);
+ enGoBackToStep=START_FLOW_READING;
+ break;
+ }
+ case START_FLOW_READING:
+ {
+ // Set Min blower speed
+ uiMotorDutyCyleForFlowCalib=MIN_PI_OUTPUT;
+ SS_Xputdw(mdrv, uiMotorDutyCyleForFlowCalib);
+
+ // Init variable for flow sensor
+ uiCalibrationTimeOut=SAMPLE_RATE_BETWEEN_TWO_FLOW;
+ ulSumFlowTicks=0;
+ uiFlowTicksSamplesCounter=0;
+
+ // Next step
+ enLowFlowCalibrationStep=SEND_FLOW_COMMAND;
+ break;
+ }
+ case SEND_FLOW_COMMAND:
+ {
+ if (uiCalibrationTimeOut!=0)
+ {
+ uiCalibrationTimeOut--;
+
+ if (uiCalibrationTimeOut<(SAMPLE_RATE_BETWEEN_TWO_FLOW>>1))
+ {
+ ulSumFlowTicks+=uiBlowerFlowRAWMes;
+ uiFlowTicksSamplesCounter++;
+ }
+ }
+ else
+ {
+ // Prepare next command (Read Low Flow)
+ enLowFlowCalibrationStep=SEND_COMMAND_TO_PF300;
+ if (bHighFlowCalibrationInProgress==FALSE)
+ {
+ UpdateBufferToSend((char*)szPF300_ReadLowFlowCmd); // %RM#1\r
+ strcpy(szExpectedAnswerFromPF300, szPF300_ReadLowFlowAnswer); // %RM#1$
+ ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_ReadLowFlowAnswer);
+ }
+ else
+ {
+ UpdateBufferToSend((char*)szPF300_ReadHighFlowCmd); // %RM#0\r
+ strcpy(szExpectedAnswerFromPF300, szPF300_ReadHighFlowAnswer); // %RM#0$
+ ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_ReadHighFlowAnswer);
+ }
+ enGoBackToStep=READ_FLOW_VALUE;
+ }
+ break;
+ }
+ case READ_FLOW_VALUE:
+ {
+ if (uiFlowTicksSamplesCounter!=0)
+ {
+ // Read PF300 flow (l/min)
+ strcpy(szTempBuf, &szAnswerFromPF300[ucNumberOfBytesToCheckFromPF300Answer]);
+
+ // Store value of flow
+ if (stTemporayLUTFlowSensor.uiLUT_TableSize<LOW_FLOW_CALIB_NUMBER_OF_SAMPLES)
+ stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]=(unsigned int)atoi(szTempBuf);
+ else
+ stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]=(unsigned int)atoi(szTempBuf)*10;
+
+ // Store ticks value
+ stTemporayLUTFlowSensor.uiFlowSensorTicks[stTemporayLUTFlowSensor.uiLUT_TableSize]=ulSumFlowTicks/uiFlowTicksSamplesCounter;
+ uiCalibrationTimeOut=SAMPLE_RATE_BETWEEN_TWO_FLOW;
+ ulSumFlowTicks=0;
+ uiFlowTicksSamplesCounter=0;
+
+ // Check if current flow <0.1l/min
+ if (stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]<10)
+ {
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ break;
+ }
+
+ // Check if the last low flow is higher than 20l/min or lower than 2l/min
+ if (stTemporayLUTFlowSensor.uiLUT_TableSize==(LOW_FLOW_CALIB_NUMBER_OF_SAMPLES-1))
+ {
+ // Check if the last low flow is higher than 20l/min or lower than 2l/min
+ if (stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]>2000 || stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]<200)
+ {
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ break;
+ }
+ }
+
+ // Next flow sample
+ if (stTemporayLUTFlowSensor.uiLUT_TableSize==LOW_FLOW_CALIB_NUMBER_OF_SAMPLES && stTemporayLUTFlowSensor.uiFlowValue[LOW_FLOW_CALIB_NUMBER_OF_SAMPLES]<(stTemporayLUTFlowSensor.uiFlowValue[LOW_FLOW_CALIB_NUMBER_OF_SAMPLES-1]+500))
+ {
+ // No enough flow margin between the last value of the low flow and the first value of the high flow
+ }
+ else if (stTemporayLUTFlowSensor.uiLUT_TableSize!=0 && stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize]<(stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize-1]+50))
+ {
+ // No enough margin between two consecutives flow
+ }
+ else if (stTemporayLUTFlowSensor.uiLUT_TableSize!=0 && stTemporayLUTFlowSensor.uiFlowSensorTicks[stTemporayLUTFlowSensor.uiLUT_TableSize]<=stTemporayLUTFlowSensor.uiFlowSensorTicks[stTemporayLUTFlowSensor.uiLUT_TableSize-1])
+ {
+ // Same or less ticks between two consecutives flow
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ break;
+ }
+ else
+ {
+ stTemporayLUTFlowSensor.uiLUT_TableSize++;
+ if (stTemporayLUTFlowSensor.uiFlowValue[stTemporayLUTFlowSensor.uiLUT_TableSize-1]>=14000)
+ {
+ // End of calib => check the number of samples
+ if (stTemporayLUTFlowSensor.uiLUT_TableSize>(FLOW_CALIB_NUMBER_OF_SAMPLES>>1))
+ {
+ enLowFlowCalibrationStep=PREPARE_SUCCESS_COMMAND;
+
+ // Transfer the temporary LUT in the definitive LUT
+ stLUTFlowSensor=stTemporayLUTFlowSensor;
+ }
+ else
+ {
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ }
+ break;
+ }
+ else if (stTemporayLUTFlowSensor.uiLUT_TableSize>FLOW_CALIB_NUMBER_OF_SAMPLES)
+ {
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ break;
+ }
+ }
+
+ // Prepare next flow reading
+ if (stTemporayLUTFlowSensor.uiLUT_TableSize<LOW_FLOW_CALIB_NUMBER_OF_SAMPLES)
+ {
+ // New motor speed
+ uiMotorDutyCyleForFlowCalib+=20;
+ enLowFlowCalibrationStep=SEND_FLOW_COMMAND;
+ }
+ else if (stTemporayLUTFlowSensor.uiLUT_TableSize==LOW_FLOW_CALIB_NUMBER_OF_SAMPLES && bHighFlowCalibrationInProgress==FALSE)
+ {
+ // Min speed for motor
+ uiMotorDutyCyleForFlowCalib=MIN_PI_OUTPUT;
+ SS_Xputdw(mdrv, uiMotorDutyCyleForFlowCalib);
+ enLowFlowCalibrationStep=SEND_HIGH_FLOW_CALIB_REQUEST;
+ break;
+ }
+ else
+ {
+ // New motor speed
+ uiMotorDutyCyleForFlowCalib+=10;
+ enLowFlowCalibrationStep=SEND_FLOW_COMMAND;
+ }
+
+ // Update motor speed
+ if (uiMotorDutyCyleForFlowCalib<MAX_PI_OUTPUT)
+ {
+ SS_Xputdw(mdrv, uiMotorDutyCyleForFlowCalib);
+ }
+ else
+ {
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ break;
+ }
+ }
+ else // if (uiFlowTicksSamplesCounter!=0)
+ {
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ }
+ break;
+ }
+ case SEND_HIGH_FLOW_CALIB_REQUEST:
+ {
+ if (TransferCommandToHandset((char*)szRequestHighFlowCalib)==TRUE)
+ enLowFlowCalibrationStep=WAIT_FOR_HIGH_FLOW_CALIB_ACK;
+ break;
+ }
+ case WAIT_FOR_HIGH_FLOW_CALIB_ACK:
+ {
+ // Wait for acknownledge from handset
+ if (ReadByteReceive(&cCharValue)==TRUE)
+ {
+ if (cCharValue=='@')
+ {
+ // Continue flow calibration
+ bHighFlowCalibrationInProgress=TRUE;
+ enLowFlowCalibrationStep=SEND_FLOW_COMMAND;
+ }
+ else
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ }
+ break;
+ }
+ case PREPARE_FAILURE_COMMAND:
+ {
+ if (TransferCommandToHandset((char*)szEndOfCalibFailed)==TRUE)
+ enLowFlowCalibrationStep=END_OF_CALIBRATION;
+ break;
+ }
+ case PREPARE_SUCCESS_COMMAND:
+ {
+ if (TransferCommandToHandset((char*)szEndOfCalibOK)==TRUE)
+ enLowFlowCalibrationStep=END_OF_CALIBRATION;
+ break;
+ }
+ case SEND_COMMAND_TO_PF300:
+ {
+ // Send a byte every 1ms
+ if (TransferBufferToPF300()==TRUE)
+ {
+ // Buffer sent !!
+ if (ucNumberOfBytesToCheckFromPF300Answer!=0)
+ {
+ // Check answer from PF300
+ ucIndexAnswerFromPF300=0;
+ uiCalibrationTimeOut=TIME_OUT_RECEPTION_PACKET_FROM_PF300;
+ enLowFlowCalibrationStep=CHECK_COMMAND_FROM_PF300;
+ }
+ else
+ enLowFlowCalibrationStep=enGoBackToStep;
+ }
+ break;
+ }
+ case CHECK_COMMAND_FROM_PF300:
+ {
+ if (uiCalibrationTimeOut==0)
+ {
+ // Time-out in reception !!
+ ucIndexAnswerFromPF300=0;
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ }
+ else if (ReadByteReceive(&cCharValue)==TRUE)
+ {
+ // Check last byte received
+ if (cCharValue=='\r')
+ {
+ // End of answer => check buffer content
+ ucIndexAnswerFromPF300=0;
+ strcpy(szTempBuf, szAnswerFromPF300);
+ szTempBuf[ucNumberOfBytesToCheckFromPF300Answer]=0;
+ if (strcmp(szTempBuf, szExpectedAnswerFromPF300)==0)
+ {
+ // Buffer OK !!
+ enLowFlowCalibrationStep=enGoBackToStep;
+ }
+ else
+ {
+ // Buffer wrong !!
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ }
+ }
+ else if (cCharValue=='?')
+ {
+ // PF300 is lost => end of calibration
+ ucIndexAnswerFromPF300=0;
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ }
+ else
+ {
+ // Store byte from PF300 into buffer
+ szAnswerFromPF300[ucIndexAnswerFromPF300++]=cCharValue;
+ if (ucIndexAnswerFromPF300>=SIZE_RX_BUFFER_PF300)
+ {
+ // Answer too long !!
+ ucIndexAnswerFromPF300=0;
+ enLowFlowCalibrationStep=PREPARE_FAILURE_COMMAND;
+ }
+ else
+ {
+ // Add 0 at the end of the string
+ szAnswerFromPF300[ucIndexAnswerFromPF300]=0;
+ }
+ }
+ }
+ else
+ {
+ // No byte received !!
+ uiCalibrationTimeOut--;
+ }
+ break;
+ }
+ default:
+ case END_OF_CALIBRATION:
+ {
+ uiTechnicalDataSet[START_STOP_VENTILATION]=0;
+ bDisableMaroubraCommCommunication=FALSE;
+ break;
+ }
+ } // switch
+
+ // Every 300ms, send '@*' to inform the handset that the blower works properly
+ if (uiImHereMsgTimer==0)
+ {
+ if (enLowFlowCalibrationStep!=SEND_COMMAND_TO_PF300)
+ {
+ uiImHereMsgTimer=300;
+ TransferCommandToHandset((char*)szImHere);
+ }
+ }
+ else
+ uiImHereMsgTimer--;
+}
+
+/*******************************************************************************
+* Function Name : ManagePressureCalibration
+* Description : Manage pressure calibration
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ManagePressureCalibration(void)
+{
+ char cCharValue;
+ char szTempBuf[SIZE_RX_BUFFER_PF300];
+ u16 uiCalibPressureADCValue;
+ u16 uiCalibPressureValue;
+ u16 uiCalibPressureGain;
+
+ switch(enPressureCalibrationStep)
+ {
+ case INIT_PRESSURE_CALIB_TEST:
+ {
+ // Init comm with PF300 => wait 2s before sending first command to PF300
+ // We need to wait for this delay in order to the handset to activate its transparent mode
+ if (uiCalibrationTimeOut==0)
+ {
+ bDisableMaroubraCommCommunication=TRUE;
+
+ // Prepare command to PF300
+ UpdateBufferToSend((char*)szPF300_CmdSwitchOffEcho);
+ strcpy(szExpectedAnswerFromPF300, szPF300_AnswerSwitchOffEcho);
+ ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_AnswerSwitchOffEcho);
+ enPressureCalibrationStep=PRESSURE_CALIB_SEND_COMMAND_TO_PF300;
+ enPressureCalibGoBackToStep=START_PRESSURE_READING;
+ }
+ else
+ {
+ uiCalibrationTimeOut--;
+ }
+ break;
+ }
+ case START_PRESSURE_READING:
+ {
+ // Set blower speed
+ SS_Xputdw(mdrv, 600);
+
+ // Init variable for flow sensor
+ uiCalibrationTimeOut=SAMPLE_RATE_BETWEEN_TWO_PRESSURE;
+ ulSumPressureTicks=0;
+ uiPressureTicksSamplesCounter=0;
+
+ enPressureCalibrationStep=SEND_PRESSURE_COMMAND;
+ break;
+ }
+ case SEND_PRESSURE_COMMAND:
+ {
+ if (uiCalibrationTimeOut!=0)
+ {
+ uiCalibrationTimeOut--;
+
+ if (uiCalibrationTimeOut<2000)
+ {
+ ulSumPressureTicks+=uiProximalPressureADCMes;
+ uiPressureTicksSamplesCounter++;
+ }
+ }
+ else
+ {
+ // Prepare next command
+ UpdateBufferToSend((char*)szPF300_ReadPdiffCmd);
+ strcpy(szExpectedAnswerFromPF300, szPF300_ReadPdiffAnswer);
+ ucNumberOfBytesToCheckFromPF300Answer=strlen(szPF300_ReadPdiffAnswer);
+ enPressureCalibrationStep=PRESSURE_CALIB_SEND_COMMAND_TO_PF300;
+ enPressureCalibGoBackToStep=READ_PRESSURE_VALUE;
+ }
+ break;
+ }
+ case READ_PRESSURE_VALUE:
+ {
+ if (uiPressureTicksSamplesCounter!=0)
+ {
+ // Read PF300 pressure
+ strcpy(szTempBuf, &szAnswerFromPF300[ucNumberOfBytesToCheckFromPF300Answer]);
+
+ // Store value of Pressure
+ uiCalibPressureValue=(unsigned int)atoi(szTempBuf);
+
+ // Store ticks value
+ uiCalibPressureADCValue=ulSumPressureTicks/uiPressureTicksSamplesCounter;
+ uiCalibrationTimeOut=SAMPLE_RATE_BETWEEN_TWO_PRESSURE;
+ ulSumPressureTicks=0;
+ uiPressureTicksSamplesCounter=0;
+
+ // Check if current pressure<10cmH20
+ if (uiCalibPressureValue<1000)
+ {
+ enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND;
+ break;
+ }
+
+ // Compute pressure gain
+ uiCalibPressureGain=(10000UL*(uiCalibPressureADCValue-uiTechnicalDataSet[PPROX_OFFSET_TEC]))/uiCalibPressureValue;
+ uiCalibPressureGain+=5;
+ uiCalibPressureGain/=10;
+
+ // Check pressure gain range
+ if (uiCalibPressureGain<Tec_GainPprox_MIN || uiCalibPressureGain>Tec_GainPprox_MAX)
+ {
+ enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND;
+ }
+ else
+ {
+ enPressureCalibrationStep=PRESSURE_CALIB_SUCCESS_COMMAND;
+
+ // Transfer the temporary LUT in the definitive LUT
+ uiTechnicalDataSet[PPROX_GAIN_TEC]=uiCalibPressureGain;
+ }
+ }
+ else // if (uiPressureTicksSamplesCounter!=0)
+ {
+ enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND;
+ }
+ break;
+ }
+ case PRESSURE_CALIB_FAILURE_COMMAND:
+ {
+ if (TransferCommandToHandset((char*)szEndOfCalibFailed)==TRUE)
+ enPressureCalibrationStep=PRESSURE_CALIB_END_OF_CALIBRATION;
+ break;
+ }
+ case PRESSURE_CALIB_SUCCESS_COMMAND:
+ {
+ if (TransferCommandToHandset((char*)szEndOfCalibOK)==TRUE)
+ enPressureCalibrationStep=PRESSURE_CALIB_END_OF_CALIBRATION;
+ break;
+ }
+ case PRESSURE_CALIB_SEND_COMMAND_TO_PF300:
+ {
+ // Send a byte every 1ms
+ if (TransferBufferToPF300()==TRUE)
+ {
+ // Buffer sent !!
+ if (ucNumberOfBytesToCheckFromPF300Answer!=0)
+ {
+ // Check answer from PF300
+ ucIndexAnswerFromPF300=0;
+ uiCalibrationTimeOut=TIME_OUT_RECEPTION_PACKET_FROM_PF300;
+ enPressureCalibrationStep=PRESSURE_CALIB_CHECK_COMMAND_FROM_PF300;
+ }
+ else
+ enPressureCalibrationStep=enPressureCalibGoBackToStep;
+ }
+ break;
+ }
+ case PRESSURE_CALIB_CHECK_COMMAND_FROM_PF300:
+ {
+ if (uiCalibrationTimeOut==0)
+ {
+ // Time-out in reception !!
+ ucIndexAnswerFromPF300=0;
+ enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND;
+ }
+ else if (ReadByteReceive(&cCharValue)==TRUE)
+ {
+ // Check last byte received
+ if (cCharValue=='\r')
+ {
+ // End of answer => check buffer content
+ ucIndexAnswerFromPF300=0;
+ strcpy(szTempBuf, szAnswerFromPF300);
+ szTempBuf[ucNumberOfBytesToCheckFromPF300Answer]=0;
+ if (strcmp(szTempBuf, szExpectedAnswerFromPF300)==0)
+ {
+ // Buffer OK !!
+ enPressureCalibrationStep=enPressureCalibGoBackToStep;
+ }
+ else
+ {
+ // Buffer wrong !!
+ enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND;
+ }
+ }
+ else if (cCharValue=='?')
+ {
+ // PF300 is lost => end of calibration
+ ucIndexAnswerFromPF300=0;
+ enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND;
+ }
+ else
+ {
+ // Store byte from PF300 into buffer
+ szAnswerFromPF300[ucIndexAnswerFromPF300++]=cCharValue;
+ if (ucIndexAnswerFromPF300>=SIZE_RX_BUFFER_PF300)
+ {
+ // Answer too long !!
+ ucIndexAnswerFromPF300=0;
+ enPressureCalibrationStep=PRESSURE_CALIB_FAILURE_COMMAND;
+ }
+ else
+ {
+ // Add 0 at the end of the string
+ szAnswerFromPF300[ucIndexAnswerFromPF300]=0;
+ }
+ }
+ }
+ else
+ {
+ // No byte received !!
+ uiCalibrationTimeOut--;
+ }
+ break;
+ }
+ default:
+ case PRESSURE_CALIB_END_OF_CALIBRATION:
+ {
+ uiTechnicalDataSet[START_STOP_VENTILATION]=0;
+ bDisableMaroubraCommCommunication=FALSE;
+ break;
+ }
+ } // switch
+
+ // Every 300ms, send '@*' to inform the handset that the blower works properly
+ if (uiImHereMsgTimer==0)
+ {
+ if (enPressureCalibrationStep!=PRESSURE_CALIB_SEND_COMMAND_TO_PF300)
+ {
+ uiImHereMsgTimer=300;
+ TransferCommandToHandset((char*)szImHere);
+ }
+ }
+ else
+ uiImHereMsgTimer--;
+}
+
+
+/*******************************************************************************
+* Function Name : ManageCstPressure
+* Description : Manage constant pressure
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ManageCstPressure(void)
+{
+ int32_t lError;
+ int32_t lPropTerm;
+ int32_t lIntegralTerm;
+ int32_t lOutputPressure;
+
+
+ // Barometric Mode : error computation
+ lError=(int32_t)uiMLT_PressureSetPoint-(int32_t)uiProximalPressureMes;
+ lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_CPAP_VENTED_PRESSURE_I] * lError;
+ if (uiMLT_PressureSetPoint<uiVentilationSet[PI_SET]) uiMLT_PressureSetPoint++;
+
+ // Close loop in pressure
+ if ((lIntegral_Pressure_I>=0) && (lIntegralTerm>=0) && (bMaxPIOutputPressureI==FALSE))
+ {
+ if ((lIntegral_Pressure_I + lIntegralTerm) <0)
+ lIntegral_Pressure_I = INTEGRAL_MAX;
+ else
+ lIntegral_Pressure_I += lIntegralTerm;
+ }
+ else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm<=0) && (bMinPIOutputPressureI==FALSE))
+ {
+ if ((lIntegral_Pressure_I + lIntegralTerm)>0)
+ lIntegral_Pressure_I = INTEGRAL_MIN;
+ else
+ lIntegral_Pressure_I += lIntegralTerm;
+ }
+ else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm>=0))
+ lIntegral_Pressure_I += lIntegralTerm;
+ else if ((lIntegral_Pressure_I>=0) && (lIntegralTerm<=0))
+ lIntegral_Pressure_I += lIntegralTerm;
+
+ lPropTerm = (int32_t)uiTechnicalDataSet[KP_CPAP_VENTED_PRESSURE_I] * lError;
+ lOutputPressure = (lIntegral_Pressure_I>>16) + (lPropTerm>>13);
+
+ // Add constante value (PWM at the end of the previous inspiration)
+ //lOutputPressure+=300;
+
+ if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF))
+ {
+ bMaxPIOutputPressureI = TRUE;
+ uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF;
+ }
+ else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF))
+ {
+ bMinPIOutputPressureI = TRUE;
+ uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ }
+ else
+ {
+ bMaxPIOutputPressureI = FALSE;
+ bMinPIOutputPressureI = FALSE;
+ uiInspirationBlowerPWMTec = lOutputPressure;
+ }
+
+ // Update Blower Speed
+ SS_Xputdw(mdrv, uiInspirationBlowerPWMTec);
+
+ // Monitoring and Alarm (every 1s)
+ #ifdef MOTOR_LIFE_TESTING
+ if (uiAverageMonitoringMLT==0)
+ {
+ uiAverageBlowerSpeedMes=ulMLT_SumSpeedMes/MLT_AVERAGE_MONITORING;
+ uiBreathBlowerCurrentMes=ulMLT_SumCurrentMes/MLT_AVERAGE_MONITORING;
+ uiAverateMotorTempMes=ulMLT_SumTemperatureMes/MLT_AVERAGE_MONITORING;
+ uiAverageMotorVoltage=ulMLT_SumBlowerVoltage/MLT_AVERAGE_MONITORING;
+
+ ulMLT_SumSpeedMes=0;
+ ulMLT_SumCurrentMes=0;
+ ulMLT_SumTemperatureMes=0;
+ ulMLT_SumBlowerVoltage=0;
+ uiAverageMonitoringMLT=MLT_AVERAGE_MONITORING;
+ }
+ else
+ {
+ ulMLT_SumSpeedMes+=uiBlowerSpeedMes;
+ ulMLT_SumCurrentMes+=uiBlowerCurrentMes;
+ ulMLT_SumTemperatureMes+=uiTechnicalDataMes[MOTOR_TEMPERATURE_TEC_MES];
+ ulMLT_SumBlowerVoltage+=uiTechnicalDataMes[MOTOR_VOLTAGE_TEC_MES];
+ uiAverageMonitoringMLT--;
+ }
+
+ // Alarms management
+ if (uiMLT_EnableAlarm==0)
+ {
+ // High Speed alarm
+ if (uiAverageBlowerSpeedMes>uiTechnicalDataSet[MLT_HIGH_SPEED_TEC])
+ uiFlagsAlarm[ALARM_FLAGS2]|=HIGH_BLOWER_SPEED_ALARM_MASK;
+
+ // Low Speed alarm
+ if (uiAverageBlowerSpeedMes<uiTechnicalDataSet[MLT_LOW_SPEED_TEC])
+ uiFlagsAlarm[ALARM_FLAGS2]|=LOW_BLOWER_SPEED_ALARM_MASK;
+
+ // High blower current alarm
+ if (uiBreathBlowerCurrentMes>uiTechnicalDataSet[MLT_HIGH_CURRENT_TEC])
+ uiFlagsAlarm[ALARM_FLAGS2]|=HIGH_BLOWER_CURRENT_ALARM_MASK;
+
+ // High Blower temperature
+ if (uiAverateMotorTempMes>uiTechnicalDataSet[MLT_HIGH_TEMPERATURE_TEC])
+ uiFlagsAlarm[ALARM_FLAGS2]|=HIGH_BLOWER_TEMP_ALARM_MASK;
+
+ // Low Blower temperature
+ if (uiAverateMotorTempMes<100)
+ uiFlagsAlarm[ALARM_FLAGS2]|=LOW_BLOWER_TEMP_ALARM_MASK;
+
+ // High Blower Flow
+ if (iBlowerFlowSmoothingMesForTrigger>uiTechnicalDataSet[MLT_HIGH_FLOW_TEC] || iBlowerFlowSmoothingMesForTrigger<uiTechnicalDataSet[MLT_LOW_FLOW_TEC])
+ uiFlagsAlarm[ALARM_FLAGS2]|=OOR_BLOWER_FLOW_ALARM_MASK;
+ }
+ else
+ uiMLT_EnableAlarm--;
+ #endif // MOTOR_LIFE_TESTING
+}
+
+
+/*******************************************************************************
+* Function Name : ManagePACVVentilation
+* Description : Manage Bilevel ventilation
+* Input : bPSMode=true in PS mode, false in PI mode
+* Output : None
+* Return : None
+*******************************************************************************/
+void ManagePACVVentilation(bool bPSMode)
+{
+int32_t lError;
+int32_t lPropTerm;
+int32_t lIntegralTerm;
+int32_t lOutputPressure;
+u16 uiPressureSetPoint;
+u16 uiTiMax;
+u16 uiTiMin;
+//u16 uiTeMax;
+u16 uiFlowMaxInExpi;
+
+if (ucVentilationCycle==INSPIRATION_CYCLE)
+ {
+ // ---------------------------------------------------------------------------
+ // - INSPIRATION -
+ // --------------------------------------------------------------------------
+
+ // Ti et pressure set point management
+ if (bPSMode==TRUE)
+ {
+ uiPressureSetPoint=uiVentilationSet[PS_SET];
+ uiTiMax=uiVentilationSet[TI_MAX_SET];
+ }
+ else
+ {
+ uiPressureSetPoint=uiVentilationSet[PI_SET];
+ uiTiMax=uiVentilationSet[TI_BARO_SET];
+ }
+
+ // Compute Timin
+ if (uiPatientType==PATIENT_ADULT)
+ uiTiMin=TiBaroSet_A_MIN;
+ else
+ uiTiMin=TiBaroSet_P_MIN;
+
+ // Limit the pressure setting
+ if (uiVentilationSet[HIGH_PRESSURE_ALARM_SET]<uiPressureSetPoint)
+ uiPressureSetPoint=uiVentilationSet[HIGH_PRESSURE_ALARM_SET];
+
+ if (uiTiD==0)
+ {
+ // Management Expiratory Trigger
+ ucTempoTriggerExpiAuto=TEMPO_TRIGGER_EXPI;
+ ucExpiTriggerTreshold=MIN_THRESHOLD_EXPI_TRIGGER_AUTO;
+
+ // Management Inspiratory slope
+ switch(uiVentilationSet[SLOPE_BARO_SET])
+ {
+ default:
+ case 1:
+ {
+ // Slope of 5ms/hPa => 0.2hPa/ms
+ uiIpapSettingTemp=uiVentilationSet[PEEP_SET]+2;
+ break;
+ }
+ case 2:
+ {
+ ucIndexTableSlope=0;
+ uiIpapSettingTemp=(uiPressureSetPoint*ucSlope2Table[ucIndexTableSlope++])/100;
+ break;
+ }
+ case 3:
+ {
+ ucIndexTableSlope=0;
+ uiIpapSettingTemp=(uiPressureSetPoint*ucSlope3Table[ucIndexTableSlope++])/100;
+ break;
+ }
+ case 4:
+ {
+ ucIndexTableSlope=0;
+ uiIpapSettingTemp=(uiPressureSetPoint*ucSlope4Table[ucIndexTableSlope++])/100;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Management Inspiratory slope
+ switch(uiVentilationSet[SLOPE_BARO_SET])
+ {
+ default:
+ case 1:
+ {
+ // Slope of 5ms/hPa => 0.2hPa/ms
+ uiIpapSettingTemp+=2;
+ if (uiIpapSettingTemp>uiPressureSetPoint)
+ uiIpapSettingTemp=uiPressureSetPoint;
+ break;
+ }
+ case 2:
+ {
+ if (ucIndexTableSlope<SIZE_SLOPE2_TABLE && (uiTiD%10)==0)
+ uiIpapSettingTemp=(uiPressureSetPoint*ucSlope2Table[ucIndexTableSlope++])/100;
+ break;
+ }
+ case 3:
+ {
+ if (ucIndexTableSlope<SIZE_SLOPE3_TABLE && (uiTiD%10)==0)
+ uiIpapSettingTemp=(uiPressureSetPoint*ucSlope3Table[ucIndexTableSlope++])/100;
+ break;
+ }
+ case 4:
+ {
+ if (ucIndexTableSlope<SIZE_SLOPE4_TABLE && (uiTiD%10)==0)
+ uiIpapSettingTemp=(uiPressureSetPoint*ucSlope4Table[ucIndexTableSlope++])/100;
+ break;
+ }
+ }
+ }
+
+ // Barometric Mode : error computation
+ lError=(int32_t)uiIpapSettingTemp-(int32_t)uiProximalPressureMes;
+ if (fFirstCycleInspi==FALSE)
+ lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_VENTED_PRESSURE_I] * lError;
+ else
+ {
+ lIntegralTerm = (int32_t)(uiTechnicalDataSet[KI_VENTED_PRESSURE_I]>>2) * lError;
+ uiPWMatTheEndOfInspiration=uiExpirationBlowerPWMTec;
+ }
+
+ // Close loop in pressure
+ if ((lIntegral_Pressure_I>=0) && (lIntegralTerm>=0) && (bMaxPIOutputPressureI==FALSE))
+ {
+ if ((lIntegral_Pressure_I + lIntegralTerm) <0)
+ lIntegral_Pressure_I = INTEGRAL_MAX;
+ else
+ lIntegral_Pressure_I += lIntegralTerm;
+ }
+ else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm<=0) && (bMinPIOutputPressureI==FALSE))
+ {
+ if ((lIntegral_Pressure_I + lIntegralTerm)>0)
+ lIntegral_Pressure_I = INTEGRAL_MIN;
+ else
+ lIntegral_Pressure_I += lIntegralTerm;
+ }
+ else if ((lIntegral_Pressure_I<=0) && (lIntegralTerm>=0))
+ lIntegral_Pressure_I += lIntegralTerm;
+ else if ((lIntegral_Pressure_I>=0) && (lIntegralTerm<=0))
+ lIntegral_Pressure_I += lIntegralTerm;
+
+ lPropTerm = (int32_t)uiTechnicalDataSet[KP_VENTED_PRESSURE_I] * lError;
+ lOutputPressure = (lIntegral_Pressure_I>>16) + (lPropTerm>>13);
+
+ // Add constante value (PWM at the end of the previous inspiration)
+ lOutputPressure+=uiPWMatTheEndOfInspiration;
+
+ if (fAlarmPmax==TRUE || fAlarmVtiMax==TRUE)
+ {
+ bMaxPIOutputPressureI = TRUE;
+ }
+ else if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF))
+ {
+ bMaxPIOutputPressureI = TRUE;
+ uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF;
+ }
+ else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF))
+ {
+ bMinPIOutputPressureI = TRUE;
+ uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ }
+ else
+ {
+ bMaxPIOutputPressureI = FALSE;
+ bMinPIOutputPressureI = FALSE;
+ uiInspirationBlowerPWMTec = lOutputPressure;
+ }
+
+ // Update Blower Speed
+ SS_Xputdw(mdrv, uiInspirationBlowerPWMTec);
+
+ // ************************ CYCLE MANAGEMENT *********************************
+ uiTiD++;
+ if ((uiTiD>=uiTiMax) ||
+ (TestTriggerExpiratoire(uiVentilationSet[TRIG_E_SET], uiVentilationSet[PS_SET])==TRUE && uiTiD>uiVentilationSet[TI_MIN_SET] && bPSMode==TRUE) ||
+ (fAlarmPmax==TRUE && uiTiD>uiTiMin) ||
+ (fAlarmVtiMax==TRUE && uiTiD>uiTiMin))
+ {
+ // Beginning of the expiration
+ if (fAlarmPmax==FALSE && fAlarmVtiMax==FALSE)
+ {
+ fFirstCycleInspi=FALSE;
+ uiPWMatTheEndOfInspiration=uiInspirationBlowerPWMTec;
+ }
+ else
+ {
+ fFirstCycleInspi=TRUE;
+ uiPWMatTheEndOfInspiration=MIN_VOLTAGE_REF;
+ }
+
+ ucVentilationCycle=EXPIRATION_CYCLE;
+ uiTiD=0;
+
+ // Reset PI variables for next inspiration
+ lIntegral_Pressure_E=0;
+ bMaxPIOutputPressureE=FALSE;
+ bMinPIOutputPressureE=FALSE;
+
+ fFirstCycleExpi=FALSE;
+ }
+ }
+else
+ {
+ // ---------------------------------------------------------------------------
+ // - EXPIRATION -
+ // ---------------------------------------------------------------------------
+
+ // *************************** UPDATE SETTINGS *******************************
+ if (ApplyNewVentilationMode()==TRUE)
+ return;
+
+ // ******************** MAIN BLOWER MANAGEMENT *******************************
+ if (uiVentilationSet[PEEP_SET]==0)
+ {
+ uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ SS_Xputdw(mdrv, uiExpirationBlowerPWMTec);
+ }
+ else
+ {
+ if (uiTeD==0)
+ {
+ // First blower current setting
+ uiEpapSettingTemp=uiVentilationSet[PI_SET]-2; // Slope of 5ms/hPa => 0.2hPa/ms
+ }
+ else
+ {
+ // we increase the speed of the blower every 1ms
+ uiEpapSettingTemp-=2; // Slope of 5ms/hPa => 0.2hPa/ms
+ if (uiEpapSettingTemp<uiVentilationSet[PEEP_SET])
+ uiEpapSettingTemp=uiVentilationSet[PEEP_SET];
+ }
+
+ // Barometric Mode : error computation
+ if (fFirstCycleExpi==FALSE)
+ {
+ lError=(int32_t)uiEpapSettingTemp-(int32_t)uiProximalPressureMes;
+ lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_VENTED_PRESSURE_E] * lError;
+ }
+ else
+ {
+ lError=(int32_t)uiVentilationSet[PEEP_SET]-(int32_t)uiProximalPressureMes;
+ lIntegralTerm = (int32_t)(uiTechnicalDataSet[KI_VENTED_PRESSURE_E]>>2) * lError;
+ }
+
+ // Close loop in pressure
+ if ((lIntegral_Pressure_E>=0) && (lIntegralTerm>=0) && (bMaxPIOutputPressureE==FALSE))
+ {
+ if ((lIntegral_Pressure_E + lIntegralTerm) <0)
+ lIntegral_Pressure_E = INTEGRAL_MAX;
+ else
+ lIntegral_Pressure_E += lIntegralTerm;
+ }
+ else if ((lIntegral_Pressure_E<=0) && (lIntegralTerm<=0) && (bMinPIOutputPressureE==FALSE))
+ {
+ if ((lIntegral_Pressure_E + lIntegralTerm)>0)
+ lIntegral_Pressure_E = INTEGRAL_MIN;
+ else
+ lIntegral_Pressure_E += lIntegralTerm;
+ }
+ else if ((lIntegral_Pressure_E<=0) && (lIntegralTerm>=0))
+ lIntegral_Pressure_E += lIntegralTerm;
+ else if ((lIntegral_Pressure_E>=0) && (lIntegralTerm<=0))
+ lIntegral_Pressure_E += lIntegralTerm;
+
+ lPropTerm = (int32_t)uiTechnicalDataSet[KP_VENTED_PRESSURE_E] * lError;
+ lOutputPressure = (lIntegral_Pressure_E>>16) + (lPropTerm>>13);
+
+ // Add constante value (PWM at the end of the previous expiration)
+ lOutputPressure+=uiPWMatTheEndOfExpiration;
+
+ // Flow limiting
+ uiFlowMaxInExpi=uiMaximumFlowInExpiration[uiVentilationSet[PS_CPAP_SET]/10];
+ if (lError>5 && iBlowerFlowSmoothingMes>(int16_t)uiFlowMaxInExpi)
+ {
+ // Impossible to maintain the peep (patient disconnection)
+ if (uiDisconnectionTime==0)
+ {
+ fBlockCloseLoop=TRUE; // Block the close loop
+ if (uiMemoPWMDuringDisconnection!=0) // Apply a fixed PWM value
+ uiExpirationBlowerPWMTec=uiMemoPWMDuringDisconnection;
+ else
+ uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ }
+ else
+ uiDisconnectionTime--;
+ }
+ else if (iBlowerFlowSmoothingMes<(int16_t)uiFlowMaxInExpi && (lError>(-2) && lError<2))
+ {
+ // Good pressure : no disconnection
+ uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT;
+ if (fBlockCloseLoop==TRUE)
+ {
+ // The close loop was block before => unblock it
+ fBlockCloseLoop=FALSE;
+ lIntegral_Pressure_E=0;
+ bMaxPIOutputPressureE = FALSE;
+ bMinPIOutputPressureE = FALSE;
+ lOutputPressure=uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec;
+ }
+ else if (iBlowerFlowSmoothingMes>=0)
+ {
+ // Record current PWM
+ uiMemoPWMDuringDisconnection=uiExpirationBlowerPWMTec;
+ }
+ }
+
+ // Unblock the close loop every 4s in case of none recorded PWM value
+ if (fBlockCloseLoop==TRUE && uiMemoPWMDuringDisconnection==0 && uiTeD==0)
+ {
+ uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT;
+ fBlockCloseLoop=FALSE;
+ lIntegral_Pressure_E=0;
+ bMaxPIOutputPressureE = FALSE;
+ bMinPIOutputPressureE = FALSE;
+ lOutputPressure=uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec;
+ }
+
+ // Update blower PWM
+ if (fBlockCloseLoop==TRUE)
+ {
+ bMaxPIOutputPressureE = TRUE;
+ }
+ else if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF))
+ {
+ bMaxPIOutputPressureE = TRUE;
+ uiExpirationBlowerPWMTec=MAX_VOLTAGE_REF;
+ }
+ else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF))
+ {
+ bMinPIOutputPressureE = TRUE;
+ uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ }
+ else
+ {
+ bMaxPIOutputPressureE = FALSE;
+ bMinPIOutputPressureE = FALSE;
+ uiExpirationBlowerPWMTec = lOutputPressure;
+ }
+ SS_Xputdw(mdrv, uiExpirationBlowerPWMTec);
+ }
+
+ // Expiratory time
+ uiTeD++;
+ if (uiTeD>TE_SET_MAX) uiTeD=TE_SET_MAX;
+ if ((uiTeD>=uiTeBaroSet && bPSMode==FALSE) || TestInspiratoryTrigger(bPSMode, uiTeD, uiVentilationSet[TRIG_I_FLOW_SET])==TRUE)
+ {
+ ucVentilationCycle=INSPIRATION_CYCLE;
+ uiTeD=0;
+
+ // Record PWM value at the end of the expiration
+ uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec;
+
+ // Reset PI variables for next inspiration
+ lIntegral_Pressure_I=0;
+ bMaxPIOutputPressureI=FALSE;
+ bMinPIOutputPressureI=FALSE;
+ }
+ }
+}
+
+
+
+/*******************************************************************************
+* Function Name : ManageVolumetricVentilation
+* Description : Manage Volumetric Ventilation
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ManageVolumetricVentilation(void)
+{
+int32_t lError;
+int32_t lPropTerm;
+int32_t lIntegralTerm;
+int32_t lOutputPressure;
+int16_t iMaxVtAdjust;
+u16 uiFlowMaxInExpi;
+u16 uiTiMin;
+
+if (ucVentilationCycle==INSPIRATION_CYCLE)
+ {
+ // ---------------------------------------------------------------------------
+ // - INSPIRATION -
+ // ---------------------------------------------------------------------------
+
+ // Compute Timin
+ if (uiPatientType==PATIENT_ADULT)
+ uiTiMin=TiVoluSet_A_MIN;
+ else
+ uiTiMin=TiVoluSet_P_MIN;
+
+ // ************************** Main Blower MANAGEMENT *************************
+ if (uiTiD==0)
+ {
+ // Compute Volume adjustment
+ if (fFirstCycleInspi==FALSE)
+ {
+ if ((uiFlagsAlarm[ALARM_FLAGS1]&HIGH_PRESSURE_ALARM_MASK)==0)
+ {
+ if (ucCounterHPAlarm==0)
+ {
+ iVtAdjust+=(((int16_t)uiVentilationSet[VT_SET]-(int16_t)uiRecordVtiMes>>1));
+ if (iVtAdjust>0)
+ {
+ iMaxVtAdjust=(int16_t)(uiVentilationSet[VT_SET]>>1); // >0
+ if (iVtAdjust>iMaxVtAdjust)
+ iVtAdjust=iMaxVtAdjust;
+ }
+ else if (iVtAdjust<0)
+ {
+ iMaxVtAdjust=(int16_t)(~(uiVentilationSet[VT_SET]>>1)+1); // <0
+ if (iVtAdjust<iMaxVtAdjust)
+ iVtAdjust=iMaxVtAdjust;
+ }
+ }
+ else
+ ucCounterHPAlarm--;
+ }
+ else
+ ucCounterHPAlarm=1;
+ }
+ else
+ iVtAdjust=0;
+
+ ComputeInspiratoryFlowSetPointInAVC(uiPatientType, (u16)((int16_t)uiVentilationSet[VT_SET]+iVtAdjust), uiVentilationSet[TI_VOLU_SET], uiVentilationSet[SHAPE_SET], &ulMaxIFlowSet, &ulMinIFlowSet, &ulDecFlowStep);
+ }
+ else
+ {
+ if (ulMaxIFlowSet>=ulDecFlowStep)
+ ulMaxIFlowSet-=ulDecFlowStep;
+ if (ulMaxIFlowSet<ulMinIFlowSet)
+ ulMaxIFlowSet=ulMinIFlowSet;
+ }
+
+ // Volumetric Mode : error computation
+ //lError=(int32_t)(ulMaxIFlowSet/100)-iBlowerFlowMes;
+ lError=(int32_t)(ulMaxIFlowSet/100)-iBlowerFlowSmoothingMes;
+ if (fFirstCycleInspi==FALSE)
+ {
+ if (ulMaxIFlowSet<150000 && uiTiD>30000)
+ lIntegralTerm = (int32_t)(uiTechnicalDataSet[KI_FLOW_I]>>1) * lError;
+ else
+ lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_FLOW_I] * lError;
+ }
+ else
+ lIntegralTerm = (int32_t)(uiTechnicalDataSet[KI_FLOW_I]>>2) * lError;
+
+ // Close loop in pressure or flow (PI)
+ if ((lIntegral_Flow_I>=0) && (lIntegralTerm>=0) && (bMaxPIOutputFlowI==FALSE))
+ {
+ if ((lIntegral_Flow_I + lIntegralTerm) <0)
+ lIntegral_Flow_I = INTEGRAL_MAX;
+ else
+ lIntegral_Flow_I += lIntegralTerm;
+ }
+ else if ((lIntegral_Flow_I<=0) && (lIntegralTerm<=0) && (bMinPIOutputFlowI==FALSE))
+ {
+ if ((lIntegral_Flow_I + lIntegralTerm)>0)
+ lIntegral_Flow_I = INTEGRAL_MIN;
+ else
+ lIntegral_Flow_I += lIntegralTerm;
+ }
+ else if ((lIntegral_Flow_I<=0) && (lIntegralTerm>=0))
+ lIntegral_Flow_I += lIntegralTerm;
+ else if ((lIntegral_Flow_I>=0) && (lIntegralTerm<=0))
+ lIntegral_Flow_I += lIntegralTerm;
+
+ lPropTerm = (int32_t)uiTechnicalDataSet[KP_FLOW_I] * lError;
+ lOutputPressure = (lIntegral_Flow_I>>16) + (lPropTerm>>13);
+
+ // Add constante value (PWM at the end of the previous inspiration)
+ lOutputPressure+=uiPWMatTheEndOfExpiration;
+
+ if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF))
+ {
+ bMaxPIOutputFlowI = TRUE;
+ uiInspirationBlowerPWMTec=MAX_VOLTAGE_REF;
+ }
+ else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF))
+ {
+ bMinPIOutputFlowI = TRUE;
+ uiInspirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ }
+ else
+ {
+ bMaxPIOutputFlowI = FALSE;
+ bMinPIOutputFlowI = FALSE;
+ uiInspirationBlowerPWMTec = lOutputPressure;
+ }
+
+ // Update Blower Speed
+ SS_Xputdw(mdrv, uiInspirationBlowerPWMTec);
+
+ // ************************ CYCLE MANAGEMENT *********************************
+ uiTiD++;
+ if ((uiTiD>=uiVentilationSet[TI_VOLU_SET]) ||
+ (fAlarmPmax==TRUE && uiTiD>uiTiMin))
+ {
+ // Beginning of the expiration
+ uiPWMatTheEndOfInspiration=uiInspirationBlowerPWMTec;
+ uiProximalPressureAtTheEndOfInspiration=uiProximalPressureMes;
+
+ ucVentilationCycle=EXPIRATION_CYCLE;
+ uiTiD=0;
+
+ // Reset PI variables for next inspiration
+ lIntegral_Pressure_E=0;
+ bMaxPIOutputPressureE=FALSE;
+ bMinPIOutputPressureE=FALSE;
+
+ fFirstCycleExpi=FALSE;
+ fFirstCycleInspi=FALSE;
+ }
+ }
+else
+ {
+ // ---------------------------------------------------------------------------
+ // - EXPIRATION -
+ // ---------------------------------------------------------------------------
+
+ // *************************** UPDATE SETTINGS *******************************
+ if (ApplyNewVentilationMode()==TRUE)
+ return;
+
+ // ******************** MAIN BLOWER MANAGEMENT *******************************
+ if (uiVentilationSet[PEEP_SET]==0)
+ {
+ uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ SS_Xputdw(mdrv, uiExpirationBlowerPWMTec);
+ }
+ else
+ {
+ if (uiTeD==0)
+ {
+ // First blower pressure setting
+ if (uiProximalPressureAtTheEndOfInspiration<uiVentilationSet[PEEP_SET])
+ uiEpapSettingTemp=uiVentilationSet[PEEP_SET];
+ else if (uiProximalPressureAtTheEndOfInspiration>=2)
+ uiEpapSettingTemp=uiProximalPressureAtTheEndOfInspiration-2; // Slope of 5ms/hPa => 0.2hPa/ms
+ else
+ uiEpapSettingTemp=uiVentilationSet[PEEP_SET];
+ }
+ else
+ {
+ // we decrease the speed of the blower every 1ms
+ if (uiEpapSettingTemp>=2)
+ uiEpapSettingTemp-=2; // Slope of 5ms/hPa => 0.2hPa/ms
+ }
+
+ // Pressure set point limitation
+ if (uiEpapSettingTemp<uiVentilationSet[PEEP_SET])
+ uiEpapSettingTemp=uiVentilationSet[PEEP_SET];
+
+ // Barometric Mode : error computation
+ if (fFirstCycleExpi==FALSE)
+ {
+ lError=(int32_t)uiEpapSettingTemp-(int32_t)uiProximalPressureMes;
+ lIntegralTerm = (int32_t)uiTechnicalDataSet[KI_VENTED_PRESSURE_E] * lError;
+ }
+ else
+ {
+ lError=(int32_t)uiVentilationSetTemp[PEEP_SET]-(int32_t)uiProximalPressureMes;
+ lIntegralTerm = (int32_t)(uiTechnicalDataSet[KI_VENTED_PRESSURE_E]>>2) * lError;
+ }
+
+ // Close loop in pressure
+ if ((lIntegral_Pressure_E>=0) && (lIntegralTerm>=0) && (bMaxPIOutputPressureE==FALSE))
+ {
+ if ((lIntegral_Pressure_E + lIntegralTerm) <0)
+ lIntegral_Pressure_E = INTEGRAL_MAX;
+ else
+ lIntegral_Pressure_E += lIntegralTerm;
+ }
+ else if ((lIntegral_Pressure_E<=0) && (lIntegralTerm<=0) && (bMinPIOutputPressureE==FALSE))
+ {
+ if ((lIntegral_Pressure_E + lIntegralTerm)>0)
+ lIntegral_Pressure_E = INTEGRAL_MIN;
+ else
+ lIntegral_Pressure_E += lIntegralTerm;
+ }
+ else if ((lIntegral_Pressure_E<=0) && (lIntegralTerm>=0))
+ lIntegral_Pressure_E += lIntegralTerm;
+ else if ((lIntegral_Pressure_E>=0) && (lIntegralTerm<=0))
+ lIntegral_Pressure_E += lIntegralTerm;
+
+ lPropTerm = (int32_t)uiTechnicalDataSet[KP_VENTED_PRESSURE_E] * lError;
+ lOutputPressure = (lIntegral_Pressure_E>>16) + (lPropTerm>>13);
+
+ // Add constante value (PWM at the end of the previous expiration)
+ lOutputPressure+=uiPWMatTheEndOfExpiration;
+
+ // Flow limiting
+ uiFlowMaxInExpi=uiMaximumFlowInExpiration[uiVentilationSet[PS_CPAP_SET]/10];
+ if (lError>5 && iBlowerFlowSmoothingMes>(int16_t)uiFlowMaxInExpi)
+ {
+ // Impossible to maintain the peep (patient disconnection)
+ if (uiDisconnectionTime==0)
+ {
+ fBlockCloseLoop=TRUE; // Block the close loop
+ if (uiMemoPWMDuringDisconnection!=0) // Apply a fixed PWM value
+ uiExpirationBlowerPWMTec=uiMemoPWMDuringDisconnection;
+ else
+ uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ }
+ else
+ uiDisconnectionTime--;
+ }
+ else if (iBlowerFlowSmoothingMes<(int16_t)uiFlowMaxInExpi && (lError>(-2) && lError<2))
+ {
+ // Good pressure : no disconnection
+ uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT;
+ if (fBlockCloseLoop==TRUE)
+ {
+ // The close loop was block before => unblock it
+ fBlockCloseLoop=FALSE;
+ lIntegral_Pressure_E=0;
+ bMaxPIOutputPressureE = FALSE;
+ bMinPIOutputPressureE = FALSE;
+ lOutputPressure=uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec;
+ }
+ else if (iBlowerFlowSmoothingMes>=0)
+ {
+ // Record current PWM
+ uiMemoPWMDuringDisconnection=uiExpirationBlowerPWMTec;
+ }
+ }
+
+ // Unblock the close loop every 4s in case of none recorded PWM value
+ if (fBlockCloseLoop==TRUE && uiMemoPWMDuringDisconnection==0 && uiTeD==0)
+ {
+ uiDisconnectionTime=EXPIRATORY_DISCONNECTION_TIME_OUT;
+ fBlockCloseLoop=FALSE;
+ lIntegral_Pressure_E=0;
+ bMaxPIOutputPressureE = FALSE;
+ bMinPIOutputPressureE = FALSE;
+ lOutputPressure=uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec;
+ }
+
+ // Update blower PWM
+ if (fBlockCloseLoop==TRUE)
+ {
+ bMaxPIOutputPressureE = TRUE;
+ }
+ else if (lOutputPressure>=((int32_t)MAX_VOLTAGE_REF))
+ {
+ bMaxPIOutputPressureE = TRUE;
+ uiExpirationBlowerPWMTec=MAX_VOLTAGE_REF;
+ }
+ else if (lOutputPressure<((int32_t)MIN_VOLTAGE_REF))
+ {
+ bMinPIOutputPressureE = TRUE;
+ uiExpirationBlowerPWMTec=MIN_VOLTAGE_REF;
+ }
+ else
+ {
+ bMaxPIOutputPressureE = FALSE;
+ bMinPIOutputPressureE = FALSE;
+ uiExpirationBlowerPWMTec = lOutputPressure;
+ }
+ // Update Blower Speed
+ SS_Xputdw(mdrv, uiExpirationBlowerPWMTec);
+ }
+
+ // Expiratory time
+ uiTeD++;
+ if (uiTeD>=uiTeVoluSet || TestInspiratoryTrigger(FALSE, uiTeD, uiVentilationSet[TRIG_I_FLOW_SET])==TRUE)
+ {
+ ucVentilationCycle=INSPIRATION_CYCLE;
+ uiTeD=0;
+
+ // Record PWM value at the end of the expiration
+ if (fBlockCloseLoop==FALSE)
+ uiPWMatTheEndOfExpiration=uiExpirationBlowerPWMTec;
+ else
+ uiPWMatTheEndOfExpiration=0;
+ fBlockCloseLoop=FALSE;
+
+ // Reset PI variables for next inspiration
+ lIntegral_Flow_I=0;
+ bMaxPIOutputFlowI=FALSE;
+ bMinPIOutputFlowI=FALSE;
+ }
+ }
+}
+
+
+
+/*******************************************************************************
+* Function Name : LaunchTherapyEngine
+* Description : Select and launch the therapy engine
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void LaunchTherapyEngine(void)
+{
+ if (bMemoStartVentilation==TRUE)
+ {
+ // ---- Check new configuration
+ if (uiTechnicalDataSet[DEVICE_MODE_TEC]!=uiPreviousDeviceMode)
+ {
+ UpdateSettings();
+ enPreviousMode=NUMBER_OF_MODE; // Force full init of the variables
+ InitVentilation();
+ uiPreviousDeviceMode=uiTechnicalDataSet[DEVICE_MODE_TEC];
+ }
+
+
+ switch(uiTechnicalDataSet[DEVICE_MODE_TEC])
+ {
+ default:
+ case VENTILATION_MODE:
+ {
+ if (enVentilationMode==PS_MODE)
+ ManagePACVVentilation(TRUE);
+ else if (enVentilationMode==APCV_MODE)
+ ManagePACVVentilation(FALSE);
+ else if (enVentilationMode==AVC_MODE)
+ ManageVolumetricVentilation();
+ else if (enVentilationMode==CPAP_MODE)
+ ManageCPAPVentilation();
+ break;
+ }
+ case ONE_CST_PWM_MODE:
+ {
+ ManageOneCstPWM();
+ break;
+ }
+ case TWO_CST_PWM_MODE:
+ {
+ Manage2CstPWM();
+ break;
+ }
+ case CST_SPEED_MODE:
+ {
+ ManageCstSpeed();
+ break;
+ }
+ case FLOW_CAL_MODE:
+ {
+ ManageFlowCalibration();
+ break;
+ }
+ case PRESSURE_CAL_MODE:
+ {
+ ManagePressureCalibration();
+ break;
+ }
+ case PRESSURE_CST_MODE:
+ {
+ ManageCstPressure();
+ break;
+ }
+ }
+ }
+}
+
+
+/*******************************************************************************
+* Function Name : StartStopVentilation
+* Description : Detect a start/stop ventilation request
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void StartStopVentilation(void)
+{
+ #ifndef TEMPERATURE_TRENDS
+ opstatus_t byOpStatus;
+ #endif
+
+ // Check if an alarm must stop the ventilation
+ ucStopVentilationAlarmNumber=ReadStopVentilationAlarmNumber();
+
+ #ifndef TEMPERATURE_TRENDS
+ if (uiTechnicalDataSet[START_STOP_VENTILATION]==1 && ucStopVentilationAlarmNumber==SIZE_BLOWER_ALARM)
+ {
+ // *************** VENTILATION is ON **************
+ if (bMemoStartVentilation==FALSE)
+ {
+ switch(ucStartVentilationScheduler)
+ {
+ default:
+ case 0:
+ {
+ // Active the HW safety system
+ ControlHW(BLOWER_ON__PAT_CPLD);
+ ucStartVentilationScheduler++;
+ break;
+ }
+ case 1:
+ {
+ // Pat CPLD (WDI_CPLD), STOP_BLOWER=1
+ ControlHW(BLOWER_ON__PAT_CPLD);
+
+ // Read Offset of the Blower current
+ ComputeADCBlowerCurrent(TRUE);
+
+ ucStartVentilationScheduler++;
+ break;
+ }
+ case 2:
+ {
+ // Pat CPLD (WDI_CPLD), STOP_BLOWER=1
+ ControlHW(BLOWER_ON__PAT_CPLD);
+
+ // Open motor driver
+ byOpStatus=SS_Xopen(mdrv);
+ if (byOpStatus==OPSTATUS_FAIL)
+ {
+ uiFlagsAlarm[ALARM_FLAGS2]|=MOTOR_FAILURE_ALARM_MASK;
+ ucStartVentilationScheduler=0;
+ }
+ else if (byOpStatus==OPSTATUS_OK)
+ {
+ // Force init settings and variables
+ uiPreviousDeviceMode=0xFF;
+
+ uiTempo1min=TEMPO_1MIN;
+ #ifdef DATA_LOGGING
+ uiTrendsSampleTime=RECORD_TRENDS_SAMPLE_TIME;
+ #endif // DATA_LOGGING
+
+ // Check if ventilation mode is activated
+ if (uiTechnicalDataSet[DEVICE_MODE_TEC]!=VENTILATION_MODE)
+ uiFlagsAlarm[ALARM_FLAGS2]|=DEVICE_MODE_ALARM_MASK;
+
+ bMemoStartVentilation=TRUE;
+ ucStartVentilationScheduler=0;
+ }
+ break;
+ }
+ }
+ }
+ // --- Check Safety system for Motor transistors ----
+ else if (IsMotorOK()==FALSE)
+ {
+ ControlHW(BLOWER_OFF__STOP_PAT_CPLD);
+ uiFlagsAlarm[ALARM_FLAGS2]|=MOTOR_FAILURE_ALARM_MASK;
+ }
+ // --- Test safety system thanks to the "STOP_BLOWER" Input pin
+ else if (TestStopBlowerInputPin()==OPSTATUS_OK)
+ {
+ ControlHW(BLOWER_ON__PAT_CPLD);
+ uiFlagsAlarm[ALARM_FLAGS2]&=(~HW_SAFETY_ALARM_MASK);
+ }
+ else
+ {
+ uiFlagsAlarm[ALARM_FLAGS2]|=HW_SAFETY_ALARM_MASK;
+ }
+ }
+ else
+ #endif // #ifndef TEMPERATURE_TRENDS
+ {
+ // *************** VENTILATION is OFF **************
+ uiFlagsAlarm[ALARM_FLAGS2]&=(~DEVICE_MODE_ALARM_MASK);
+
+ if (ucStopVentilationAlarmNumber!=SIZE_BLOWER_ALARM)
+ {
+ // Stop patting CPLD (WDI_CPLD=0), STOP_BLOWER=0
+ ControlHW(BLOWER_OFF__STOP_PAT_CPLD);
+ }
+ else
+ {
+ // Pat CPLD (WDI_CPLD), STOP_BLOWER=1
+ ControlHW(BLOWER_ON__PAT_CPLD);
+
+ // ---- Test STOP_ACTUATOR Input pin Status
+ if (TestStopBlowerInputPin()==OPSTATUS_FAIL)
+ uiFlagsAlarm[ALARM_FLAGS2]|=HW_SAFETY_ALARM_MASK;
+ else
+ uiFlagsAlarm[ALARM_FLAGS2]&=(~HW_SAFETY_ALARM_MASK);
+ }
+
+ if (bMemoStartVentilation==TRUE)
+ {
+ StopAllActuators();
+ ClearAllVentilationAlarms();
+ ClearAllMeasures();
+ }
+
+ uiTechnicalDataSet[START_STOP_VENTILATION]=0;
+ bMemoStartVentilation=FALSE;
+ #ifndef TEMPERATURE_TRENDS
+ ucStartVentilationScheduler=0;
+ #endif
+ bDisableMaroubraCommCommunication=FALSE;
+ }
+}
+#endif // #ifndef C_M3_DEVICETEST_TARGET
+
+
+/*******************************************************************************
+* Function Name : ComputeTe
+* Description : Compute expiratory time
+* Input : uiF = Breath frequency (bpm)
+ uiTi = Inspiratory time (ms)
+* Output : Expiratory time (ms)
+* Return : None
+*******************************************************************************/
+#ifndef C_M3_DEVICETEST_TARGET
+u16 ComputeTe(u16 uiF, u16 uiTi)
+{
+ u16 uiTtot;
+ u16 uiTeTemp=TE_SET_MIN;
+
+ if (uiF!=0)
+ {
+ // Compute Ttotal
+ uiTtot=60000/uiF;
+ if (uiTtot>uiTi)
+ {
+ uiTeTemp=uiTtot-uiTi;
+ if (uiTeTemp<TE_SET_MIN)
+ uiTeTemp=TE_SET_MIN;
+ }
+ }
+ else
+ {
+ // F=0 => Te=2xTi
+ uiTeTemp=uiTi<<1;
+ }
+ return(uiTeTemp);
+}
+
+
+/*******************************************************************************
+* Function Name : UpdateSettings
+* Description : Update the settings zone with the temporary settings zone
+* Input : None
+* Output : None
+* Return : TRUE if the ventilation mode has changed
+*******************************************************************************/
+bool UpdateSettings(void)
+{
+ u8 ucIndex;
+
+ // Take into account a modification of the PEEP
+ if (uiVentilationSet[PEEP_SET]!=uiVentilationSetTemp[PEEP_SET] || uiVentilationSet[PS_CPAP_SET]!=uiVentilationSetTemp[PS_CPAP_SET])
+ uiMemoPWMDuringDisconnection=0;
+
+ // Transfert data from the setting temporary zone to the settings zone
+ for (ucIndex=0; ucIndex<SIZE_LRS_GROUP; ucIndex++)
+ uiVentilationSet[ucIndex]=uiVentilationSetTemp[ucIndex];
+
+ // Update barometric expiratory time
+ uiTeBaroSet=ComputeTe(uiVentilationSet[BREATH_RATE_BARO_SET], uiVentilationSet[TI_BARO_SET]);
+
+ // Update volumetric expiratory time
+ uiTeVoluSet=ComputeTe(uiVentilationSet[BREATH_RATE_VOLU_SET], uiVentilationSet[TI_VOLU_SET]);
+
+ // Update Tube configuration type
+ enTubeConfigType=enTubeConfigTypeTemp;
+
+ // Update Patient type
+ uiPatientType=uiPatientTypeTemp;
+
+ // Update Ventilation mode
+ if (enVentilationMode!=enVentilationModeTemp)
+ {
+ enVentilationMode=enVentilationModeTemp;
+ InitVentilation();
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+
+/*******************************************************************************
+* Function Name : ApplyNewVentilationMode
+* Description : Update settings and init variables if the ventilation mode has changed
+* Input : None
+* Output : None
+* Return : TRUE if new ventilation mode is applied
+*******************************************************************************/
+bool ApplyNewVentilationMode(void)
+{
+ if (fUpdateTheSettings==TRUE)
+ {
+ fUpdateTheSettings=FALSE;
+ if (UpdateSettings()==TRUE)
+ {
+ InitVentilation();
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+}
+
+
+/*******************************************************************************
+* Function Name : ComputeInspiratoryFlowSetPointInAVC
+* Description : Compute:
+ - the inspiratory flow max set point
+ - the inspiratory flow min set point
+ - the flow step between the flow max and the flow min during Ti
+* Input : uiTypeOfPatient = Adult or Pedia
+ uiVtc = set point in volume (ml)
+ uiTi = Ti set point (ms)
+ uiFlowShape = Flow shape (0 to 4)
+* Output : uiMaxFlow = the inspiratory flow max set point (cl/min => 100=1l/min)
+ uiMinFlow = the inspiratory flow min set point (cl/min => 100=1l/min)
+ uiFlowStep = the flow step between the flow max and the flow min during Ti (cl/min => 100=1l/min)
+* Return : None
+*******************************************************************************/
+void ComputeInspiratoryFlowSetPointInAVC(u16 uiTypeOfPatient, u16 uiVtc, u16 uiTi, u16 uiFlowShape, u32 *ulMaxFlow, u32 *ulMinFlow, u32 *ulFlowStep)
+{
+ u32 ulFlowMax;
+ u32 ulFlowMin;
+ u32 ulMaxMaxFlow;
+ u32 ulMinMinFlow;
+ u16 uiTiMin;
+ u32 ulFlowStepTemp;
+
+ // Define min/max flow
+ if (uiTypeOfPatient==PATIENT_ADULT)
+ {
+ ulMinMinFlow=InspiratoryFlowSet_A_MIN;
+ ulMaxMaxFlow=InspiratoryFlowSet_A_MAX;
+ uiTiMin=TiVoluSet_A_MIN;
+ }
+ else
+ {
+ ulMinMinFlow=InspiratoryFlowSet_P_MIN;
+ ulMaxMaxFlow=InspiratoryFlowSet_P_MAX;
+ uiTiMin=TiVoluSet_P_MIN;
+ }
+
+ // Check Ti
+ if (uiTi==0)
+ uiTi=uiTiMin;
+
+ // Compute flow max
+ switch(uiFlowShape)
+ {
+ default:
+ case 0:
+ {
+ ulFlowMax=((u32)uiVtc*6000)/uiTi;
+ break;
+ }
+ case 1:
+ {
+ ulFlowMax=((u32)uiVtc*7500)/uiTi;
+ break;
+ }
+ case 2:
+ {
+ ulFlowMax=((u32)uiVtc*9000)/uiTi;
+ break;
+ }
+ case 3:
+ {
+ ulFlowMax=((u32)uiVtc*10500)/uiTi;
+ break;
+ }
+ case 4:
+ {
+ ulFlowMax=((u32)uiVtc*12000)/uiTi;
+ break;
+ }
+ }
+
+ // Limitation of the max flow
+ if (ulFlowMax>ulMaxMaxFlow)
+ ulFlowMax=ulMaxMaxFlow;
+
+ // Limitation of the min flow
+ if (ulFlowMax<ulMinMinFlow)
+ ulFlowMax=ulMinMinFlow;
+
+ // Factor 100 on flow max (and flow min and flow step)
+ ulFlowMax*=100;
+
+ // Compute flow min and flow step
+ switch(uiFlowShape)
+ {
+ default:
+ case 0:
+ {
+ ulFlowMin=ulFlowMax;
+ break;
+ }
+ case 1:
+ {
+ ulFlowMin=(ulFlowMax*3)>>2;
+ break;
+ }
+ case 2:
+ {
+ ulFlowMin=ulFlowMax>>1;
+ break;
+ }
+ case 3:
+ {
+ ulFlowMin=ulFlowMax>>2;
+ break;
+ }
+ case 4:
+ {
+ ulFlowMin=0;
+ break;
+ }
+ }
+
+ // Max flow
+ *ulMaxFlow=ulFlowMax;
+
+ // Min flow
+ *ulMinFlow=ulFlowMin;
+
+ // Flow Step
+ ulFlowStepTemp=(ulFlowMax-ulFlowMin)/uiTi;
+ //if (uiFlowStepTemp==0 && uiFlowShape!=0) uiFlowStepTemp=1;
+ *ulFlowStep=ulFlowStepTemp;
+}
+
+
+
+/*******************************************************************************
+* Function Name : TestTriggerExpiratoire
+* Description : Manage the expiratory trigger
+* Input : ucValeurSeuil = threshold (% of the flow max) to reach in order to cycle
+* Output : None
+* Return : TRUE if cycling active
+*******************************************************************************/
+unsigned char TestTriggerExpiratoire(unsigned char ucValeurSeuil, unsigned int uiPressureSetting)
+{
+ unsigned char ucSeuil=ucValeurSeuil;
+ unsigned int uiCalculTemp;
+ int16_t iConductanceBaseLine=UpdateInspiratoryConductanceAverage();
+ // Management automatic expiratory trigger
+ ucTempoTriggerExpiAuto--;
+ if (ucTempoTriggerExpiAuto==0)
+ {
+ ucTempoTriggerExpiAuto=TEMPO_TRIGGER_EXPI;
+ ucExpiTriggerTreshold++;
+ }
+
+ // Test si flow<0??
+ if (iBlowerFlowSmoothingMes<0)
+ {
+ return(TRUE);
+ }
+ // Test if deacring flow??
+ else if (iBlowerFlowSmoothingMes<iBlowerFlowSmoothingMaxMes)
+ {
+ // Test if Trigger Expi=AUTO ??
+ if ((ucValeurSeuil==ExpiTriggerSet_A_MAX && uiPatientType==PATIENT_ADULT) ||
+ (ucValeurSeuil==ExpiTriggerSet_P_MAX && uiPatientType==PATIENT_PEDIA))
+ ucSeuil=ucExpiTriggerTreshold;
+
+ u16 conducThresh = 2000;
+
+ if(enTubeConfigType == 1 )
+ conducThresh = 750;
+ else if(enTubeConfigType == 2)
+ conducThresh = 1500;
+
+ // Test if cycling or not
+ uiCalculTemp=((unsigned long)iBlowerFlowSmoothingMaxMes*ucSeuil)/100;
+ if (uiCalculTemp>iBlowerFlowSmoothingMes)
+ return(TRUE);
+ else if (uiProximalPressureMes>(uiPressureSetting+20))
+ return(TRUE);
+ else if (uiConductanceCalc < (iConductanceBaseLine - conducThresh))
+ {
+ ResetInspiratoryConductanceAverage();
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+}
+
+
+/*******************************************************************************
+* Function Name : TestInspiratoryTrigger
+* Description : Manage the inspiratory trigger
+* Input : bSpont = TRUE if spontaneous mode
+* uiTe = expiration time (ms)
+* uiFlowTreshold = flow threshold (dl/min)
+* Output : None
+* Return : TRUE if cycling active
+*******************************************************************************/
+bool TestInspiratoryTrigger(bool bSpont, u16 uiTe, u16 uiFlowTreshold)
+{
+ //int16_t iInspiratoryFlowDeltaAverage;
+ //int16_t iDeltaOfTheDelta1, iDeltaOfTheDelta2, iDeltaOfTheDelta3, iDeltaOfTheDelta4;
+ bool bTrigger=FALSE;
+ //int16_t iVirtualFlow;
+ int16_t iConductanceBaseLine;
+
+ // Manual breath management
+ if (uiTe>TE_SET_MIN)
+ {
+ if (bManualBreath==TRUE)
+ {
+ bManualBreath=FALSE;
+ bDisplayInspiratoryTrigger=TRUE;
+ return(TRUE);
+ }
+ }
+
+ // Trigger management
+ if ((bSpont==TRUE) ||
+ (bSpont==FALSE && uiFlowTreshold<InspiTriggerFlowSet_A_MAX && uiPatientType==PATIENT_ADULT) ||
+ (bSpont==FALSE && uiFlowTreshold<InspiTriggerFlowSet_P_MAX && uiPatientType==PATIENT_PEDIA))
+ {
+ // Init scheduler
+ if (uiTe==1)
+ {
+ ucInspiTriggerScheduler=0;
+ iInspiratoryFlowMin=0;
+ ucMinFlowCounter=NUMBER_MIN_FLOW_VALUE;
+ ucCounterTriggerValid=NUMBER_TRIGGER_VALID;
+ bDetectionConstantFlow=FALSE;
+ }
+
+ iConductanceBaseLine=UpdateInspiratoryConductanceAverage();
+ // Manage detection phase
+ switch(ucInspiTriggerScheduler)
+ {
+ default:
+ case 0:
+ {
+ // Update the buffer on the Inspiratory flow average
+
+ // Detect min flow
+ if (iBlowerFlowSmoothingMesForTrigger<iInspiratoryFlowMin)
+ {
+ iInspiratoryFlowMin=iBlowerFlowSmoothingMesForTrigger;
+ ucMinFlowCounter=NUMBER_MIN_FLOW_VALUE;
+ }
+ else
+ {
+ ucMinFlowCounter--;
+ if (ucMinFlowCounter==0)
+ ucInspiTriggerScheduler=1;
+ }
+ break;
+ }
+ case 1:
+ {
+ //ucTriggerNumber=0;
+
+ if (uiTe>TE_SET_MIN)
+ {
+// // Fast trigger management
+// if (iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-50]<=iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-25])
+// {
+// iVirtualFlow=(iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-25]<<1)-iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-50];
+// if (iBlowerFlowSmoothingMesForTrigger>=(iVirtualFlow+(int16_t)(uiFlowTreshold*7)))
+// {
+// //ucTriggerNumber=1;
+// //if (fBlockCloseLoop==FALSE)
+// bTrigger=TRUE;
+// }
+// }
+// if (bTrigger==FALSE && iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-100]<=iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-50])
+// {
+// iVirtualFlow=(iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-50]<<1)-iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-100];
+// if (iBlowerFlowSmoothingMesForTrigger>=(iVirtualFlow+(int16_t)(uiFlowTreshold*15)))
+// {
+// //ucTriggerNumber=2;
+// //if (fBlockCloseLoop==FALSE)
+// bTrigger=TRUE;
+// }
+// }
+//
+// // Slow trigger management
+// if (TestInspiratorySlowTrigger(iFlowBaseLine, uiFlowTreshold*10)==TRUE)
+// {
+// //ucTriggerNumber=3;
+// bTrigger=TRUE;
+// }
+ //Conductance Trigger
+ if(uiConductanceCalc >= (iConductanceBaseLine + 2000))
+ {
+ bTrigger = TRUE;
+ }
+
+ // Trigger occurs??
+ if (bTrigger==TRUE)
+ {
+ ucCounterTriggerValid--;
+ if (ucCounterTriggerValid==0)
+ {
+ bDisplayInspiratoryTrigger=TRUE;
+ ResetInspiratoryConductanceAverage();
+ return(TRUE);
+ }
+ }
+ else
+ ucCounterTriggerValid=NUMBER_TRIGGER_VALID;
+ }
+ break;
+ }
+ }
+ }
+ return(FALSE);
+}
+
+/*******************************************************************************
+* Function Name : UpdateInspiratoryConductanceAverage
+* Description : Fill the buffer with the expiratory conductance and compute the average
+* Input : None
+* Output : None
+* Return : Inspiratory flow average
+*******************************************************************************/
+u16 conducIndex = 0;
+int32_t lSumConductance = 0;
+bool bufFilled = FALSE;
+
+int16_t UpdateInspiratoryConductanceAverage(void)
+{
+ int16_t oldValue = iBufferIFlow[conducIndex];
+ iBufferIFlow[conducIndex] = uiConductanceCalc;
+ lSumConductance += uiConductanceCalc;
+ conducIndex++;
+
+ if(conducIndex > SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER)
+ {
+ conducIndex = 0;
+ bufFilled = TRUE;
+ }
+
+ if(bufFilled)
+ {
+ lSumConductance -= oldValue;
+ return (lSumConductance/SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER);
+ }
+ else
+ {
+ return (lSumConductance/conducIndex);
+ }
+}
+
+/*******************************************************************************
+* Function Name : ResetInspiratoryConductanceAverage
+* Description : Fill the buffer with the expiratory conductance and compute the average
+* Input : None
+* Output : None
+* Return : Inspiratory flow average
+*******************************************************************************/
+
+void ResetInspiratoryConductanceAverage(void)
+{
+ conducIndex = 0;
+ lSumConductance = 0;
+ bufFilled = FALSE;
+}
+
+/*******************************************************************************
+* Function Name : UpdateInspiratoryFlowAverage
+* Description : Fill the buffer with the inspiratory flow and compute the average
+* Input : None
+* Output : None
+* Return : Inspiratory flow average
+*******************************************************************************/
+int16_t UpdateInspiratoryFlowAverage(void)
+{
+ u16 uiIndex;
+ int32_t lSumIFlow=0;
+
+ // Roll the buffer
+ for(uiIndex=1; uiIndex<SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER; uiIndex++)
+ {
+ iBufferIFlow[uiIndex-1]=iBufferIFlow[uiIndex]; // Upate the Inspiratory Flow buffer
+ lSumIFlow+=iBufferIFlow[uiIndex-1]; // Sum the Inspiratory Flow
+ }
+
+ // Add new flow value
+ iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-1]=iBlowerFlowSmoothingMesForTrigger; // Upate the Inspiratory Flow buffer
+ lSumIFlow+=iBlowerFlowSmoothingMesForTrigger; // Sum the Inspiratory Flow
+
+ return(lSumIFlow/SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER);
+}
+
+
+/*******************************************************************************
+* Function Name : TestInspiratorySlowTrigger
+* Description : Compute flow base line and test trigger
+* Input : FlowTreshold = flow threshold (cl/min)
+* Output : None
+* Return : TRUE if trigger occurs
+*******************************************************************************/
+bool TestInspiratorySlowTrigger(int16_t iTheFlowBaseLine, u16 uiFlowTreshold)
+{
+ int16_t iFlowDelta1, iFlowDelta2, iFlowDelta3;
+
+ if (bDetectionConstantFlow==FALSE)
+ {
+ // Detection constant flow
+ if (iBufferIFlow[0]<iTheFlowBaseLine)
+ iFlowDelta1=iTheFlowBaseLine-iBufferIFlow[0];
+ else
+ iFlowDelta1=iBufferIFlow[0]-iTheFlowBaseLine;
+
+ if (iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER>>1]<iTheFlowBaseLine)
+ iFlowDelta2=iTheFlowBaseLine-iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER>>1];
+ else
+ iFlowDelta2=iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER>>1]-iTheFlowBaseLine;
+
+ if (iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-1]<iTheFlowBaseLine)
+ iFlowDelta3=iTheFlowBaseLine-iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-1];
+ else
+ iFlowDelta3=iBufferIFlow[SIZE_INSPIRATORY_FLOW_AVERAGE_BUFFER-1]-iTheFlowBaseLine;
+
+ if (iFlowDelta1<60 && iFlowDelta2<60 && iFlowDelta3<60)
+ {
+ iFlowBaseLineReference=iTheFlowBaseLine;
+ bDetectionConstantFlow=TRUE;
+ }
+ }
+ else
+ {
+ // Detect trigger
+ if (iBlowerFlowSmoothingMesForTrigger>=(iFlowBaseLineReference+(int16_t)uiFlowTreshold))
+ {
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+}
+
+
+/*******************************************************************************
+* Function Name : ApplyDefaultValueToTemporaryVentilationSettings
+* Description : Init temporary ventilation settings with default values
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ApplyDefaultValueToTemporaryVentilationSettings(void)
+{
+ u8 ucIndex;
+
+ enVentilationModeTemp=VentilationMode_DEF;
+ uiPatientTypeTemp=PatientType_DEF;
+ enTubeConfigTypeTemp=(enMaroubraTubeConfigurationList)ReturnDefaultTubeConfiguration(VentilationMode_DEF);
+
+ // Init all temporary settings
+ if (uiPatientType==PATIENT_ADULT)
+ {
+ for (ucIndex=0; ucIndex<SIZE_LRS_GROUP; ucIndex++)
+ uiVentilationSetTemp[ucIndex]=sLRSGroup[ucIndex].uiDefault_Adult;
+ }
+ else
+ {
+ for (ucIndex=0; ucIndex<SIZE_LRS_GROUP; ucIndex++)
+ uiVentilationSetTemp[ucIndex]=sLRSGroup[ucIndex].uiDefault_Pedia;
+ }
+}
+
+
+/*******************************************************************************
+* Function Name : CheckTemporaryVentilationSettingRange
+* Description : Check all the temporary settings range
+* Input : None
+* Output : None
+* Return : FALSE if one the settings is out of range
+*******************************************************************************/
+opstatus_t CheckTemporaryVentilationSettingRange(void)
+{
+ u8 ucIndex;
+
+ if ((uiPatientTypeTemp==PATIENT_PEDIA || uiPatientTypeTemp==PATIENT_ADULT) && enVentilationModeTemp<NUMBER_OF_MODE && enTubeConfigTypeTemp<NUMBER_OF_TUBE_CONFIGURATION)
+ {
+ for (ucIndex=0; ucIndex<SIZE_LRS_GROUP; ucIndex++)
+ {
+ // Check data range
+ if (uiPatientTypeTemp==PATIENT_PEDIA)
+ {
+ if (uiVentilationSetTemp[ucIndex]<sLRSGroup[ucIndex].uiMin_Pedia)
+ return(OPSTATUS_FAIL);
+ else if (uiVentilationSetTemp[ucIndex]>sLRSGroup[ucIndex].uiMax_Pedia)
+ return(OPSTATUS_FAIL);
+ }
+ else
+ {
+ if (uiVentilationSetTemp[ucIndex]<sLRSGroup[ucIndex].uiMin_Adult)
+ return(OPSTATUS_FAIL);
+ else if (uiVentilationSetTemp[ucIndex]>sLRSGroup[ucIndex].uiMax_Adult)
+ return(OPSTATUS_FAIL);
+ }
+ }
+ return(OPSTATUS_OK);
+ }
+ return(OPSTATUS_FAIL);
+}
+
+
+
+/*******************************************************************************
+* Function Name : ApplyDefaultValueToTechnicalSettings
+* Description : Init technical settings with default values
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ApplyDefaultValueToTechnicalSettings(void)
+{
+ u8 ucIndex;
+
+ // Init all temporary settings
+ for (ucIndex=0; ucIndex<SIZE_LRTS_GROUP; ucIndex++)
+ uiTechnicalDataSet[ucIndex]=sLRTSGroup[ucIndex].uiDefault;
+}
+
+
+/*******************************************************************************
+* Function Name : CheckTechnicalSettingsRange
+* Description : Check all the technical settings range
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void CheckTechnicalSettingsRange(void)
+{
+ u8 ucIndex;
+ bool fError=FALSE;
+
+ for (ucIndex=0; ucIndex<SIZE_LRTS_GROUP; ucIndex++)
+ {
+ if (uiTechnicalDataSet[ucIndex]<sLRTSGroup[ucIndex].uiMin || uiTechnicalDataSet[ucIndex]>sLRTSGroup[ucIndex].uiMax)
+ {
+ uiTechnicalDataSet[ucIndex]=sLRTSGroup[ucIndex].uiDefault;
+ fError=TRUE;
+ //break;
+ }
+ }
+
+ if (fError==TRUE)
+ uiFlagsAlarm[ALARM_FLAGS2]|=TECHNICAL_SETTINGS_RANGE_ALARM_MASK;
+ else
+ uiFlagsAlarm[ALARM_FLAGS2]&=(~TECHNICAL_SETTINGS_RANGE_ALARM_MASK);
+}
+
+
+/*******************************************************************************
+* Function Name : CheckFlowLUTRange
+* Description : Check the flow LUT
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void CheckFlowLUTRange(void)
+{
+ u16 uiIndex;
+ bool fError=FALSE;
+
+ if (stLUTFlowSensor.uiLUT_TableSize<(FLOW_CALIB_NUMBER_OF_SAMPLES>>1) || stLUTFlowSensor.uiLUT_TableSize>FLOW_CALIB_NUMBER_OF_SAMPLES)
+ {
+ ApplyDefaultFlowLUT();
+ fError=TRUE;
+ }
+ else
+ {
+ for (uiIndex=1; uiIndex<stLUTFlowSensor.uiLUT_TableSize; uiIndex++)
+ {
+ if (stLUTFlowSensor.uiFlowValue[uiIndex]<=stLUTFlowSensor.uiFlowValue[uiIndex-1] ||
+ stLUTFlowSensor.uiFlowSensorTicks[uiIndex]<=stLUTFlowSensor.uiFlowSensorTicks[uiIndex-1])
+ {
+ ApplyDefaultFlowLUT();
+ fError=TRUE;
+ break;
+ }
+ }
+ }
+
+ if (fError==TRUE)
+ uiFlagsAlarm[ALARM_FLAGS2]|=NO_FLOW_LUT_ALARM_MASK;
+ else
+ uiFlagsAlarm[ALARM_FLAGS2]&=(~NO_FLOW_LUT_ALARM_MASK);
+}
+
+
+/*******************************************************************************
+* Function Name : ApplyDefaultFlowLUT
+* Description : Apply default value for the flow LUT
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ApplyDefaultFlowLUT(void)
+{
+ u16 uiIndex;
+
+ stLUTFlowSensor.uiLUT_TableSize=stDefaultLUTFlowSensor.uiLUT_TableSize;
+ for (uiIndex=0; uiIndex<FLOW_CALIB_NUMBER_OF_SAMPLES; uiIndex++)
+ {
+ stLUTFlowSensor.uiFlowValue[uiIndex]=stDefaultLUTFlowSensor.uiFlowValue[uiIndex];
+ stLUTFlowSensor.uiFlowSensorTicks[uiIndex]=stDefaultLUTFlowSensor.uiFlowSensorTicks[uiIndex];
+ }
+}
+
+
+/*******************************************************************************
+* Function Name : ReturnDefaultTubeConfiguration
+* Description : The default tubing configuration according to the current ventilation mode
+* Input : a ventilation mode
+* Output : None
+* Return : The tube configuration
+*******************************************************************************/
+u16 ReturnDefaultTubeConfiguration(u16 uiMode)
+{
+ u8 ucIndex;
+
+ for (ucIndex=0; ucIndex<NUMBER_OF_TUBE_CONFIGURATION; ucIndex++)
+ {
+ if (ucTubeConfigurationTable[ucIndex][uiMode]==TUBE_DEFAULT)
+ {
+ return(ucIndex);
+ }
+ }
+ return(0);
+}
+
+
+/*******************************************************************************
+* Function Name : ApplyAllDefaultValues
+* Description : Apply all default values in the technical and settings zones
+* : BE CARFUL this function call "ControlHW" function
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ApplyAllDefaultValues(void)
+{
+ // Init ventilation settings
+ ApplyDefaultValueToTemporaryVentilationSettings();
+
+ // Init technical settings
+ ApplyDefaultValueToTechnicalSettings();
+
+ // Init flow LUT
+ ApplyDefaultFlowLUT();
+
+ // Default value for the device/patient time counter
+ ulDeviceTimeCounter=0;
+ ulPatientTimeCounter=0;
+
+ // Default value for the blower revolution counter
+ ulBlowerRevolutionCounter=0;
+
+ bComputeOffsetSensors=TRUE;
+}
+#endif // C_M3_DEVICETEST_TARGET
+
+/******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/
+
+
+
--- a/main.cpp Tue Jun 09 22:28:46 2020 +0000
+++ b/main.cpp Tue Jun 09 22:57:20 2020 +0000
@@ -37,9 +37,9 @@
setPressure = (y*20)/y_max;
sprintf((char*)isr_text, "SetP=%2d", setPressure);
lcd.DisplayStringAt(0, LINE(1), (uint8_t *)&isr_text, CENTER_MODE);
- sprintf((char*)isr_text, "PDIFF=%.2f", pdiff.read()*6.0f);
+ sprintf((char*)isr_text, "PDIFF=%.2f", (pdiff.read()*6.0f)-0.8f);
lcd.DisplayStringAt(0, LINE(2), (uint8_t *)&isr_text, CENTER_MODE);
- sprintf((char*)isr_text, "PGUAGE=%.2f", p_guage.read()*38.0f);
+ sprintf((char*)isr_text, "PGUAGE=%.2f", (p_guage.read()*38.0f)-10.0f);
lcd.DisplayStringAt(0, LINE(3), (uint8_t *)&isr_text, CENTER_MODE);
BSP_LCD_SetFont(&Font12);
@@ -50,8 +50,8 @@
lcd.DisplayStringAt(10, 130, (uint8_t *)&isr_text, LEFT_MODE);
sprintf((char*)isr_text, "Settings");
lcd.DisplayStringAt(95, 130, (uint8_t *)&isr_text, LEFT_MODE);
- sprintf((char*)isr_text, " Stop");
- lcd.DisplayStringAt(165, 130, (uint8_t *)&isr_text, LEFT_MODE);
+ sprintf((char*)isr_text, "Stop");
+ lcd.DisplayStringAt(170, 130, (uint8_t *)&isr_text, LEFT_MODE);
lcd.DrawRect(5, 160, 70, 50);
lcd.DrawRect(85, 160, 70, 50);