Update oXs_out_frsky.cpp
[openXsensor.git] / openXsensor / openXsensor.ino
blob6c2ba243f95b23d0a44d7d3352a040f2942afc6c
3 #include "oXs_config_basic.h"
4 #include "oXs_config_advanced.h"
5 #include "oXs_config_macros.h"
6 #include "oXs_voltage.h"
7 #include "oXs_ms5611.h"
8 #include "oXs_bmp180.h"
9 #include "oXs_bmp280.h"
10 #include "oXs_4525.h"
11 #include "oXs_sdp3x.h"
12 #include "oXs_ads1115.h"
13 #include "oXs_curr.h"
14 #include "oXs_out_frsky.h"
15 #include "oXs_out_multiplex.h"
16 #include "oXs_out_hott.h"
17 #include "oXs_out_jeti.h"
18 #include "oXs_general.h"
19 #include "oXs_gps.h"
20 #include "oXs_lora.h"
22 #ifdef USE_6050
23   #include "oXs_imu.h"
24   #include "KalmanFilter.h"
25   #include "oXs_hmc5883.h"
26 #endif
27   
28 #if defined (SAVE_TO_EEPROM ) and ( SAVE_TO_EEPROM == YES ) 
29   #include <EEPROM.h>
30   #include "EEPROMAnything.h"
31 #endif
33 #if  ! defined(PROTOCOL)
34     #error The parameter PROTOCOL in config_basic.h is not defined
35 #elif ! ( (PROTOCOL == FRSKY_SPORT) or (PROTOCOL == FRSKY_HUB) or (PROTOCOL == FRSKY_SPORT_HUB) or (PROTOCOL == HOTT) or (PROTOCOL == MULTIPLEX)  or (PROTOCOL == JETI))    
36     #error The parameter PROTOCOL in config_basic.h is NOT valid
37 #endif
38 #if ( ( (PROTOCOL == HOTT) or (PROTOCOL == MULTIPLEX)  or (PROTOCOL == JETI) ) and ( PIN_SERIALTX == 7 ) ) 
39     #error PIN_SERIALTX may be 7 only for Frsky protocols
40 #endif
41 #if  defined(VARIO) and (! defined(VSPEED_SOURCE))
42     #error The parameter VSPEED_SOURCE in config_basic.h is not defined while a type of baro sensor is defined
43 #elif  defined(VARIO) and  defined(VSPEED_SOURCE) and ( ! ( (VSPEED_SOURCE == FIRST_BARO) or (VSPEED_SOURCE == SECOND_BARO) or (VSPEED_SOURCE == AVERAGE_FIRST_SECOND) \
44                                                             or (VSPEED_SOURCE == AIRSPEED_COMPENSATED) or (VSPEED_SOURCE == BARO_AND_IMU) or (VSPEED_SOURCE == PPM_SELECTION) ) )
45     #error The parameter VSPEED_SOURCE in config_basic.h is NOT valid
46 #endif    
48 #if defined( ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES) and defined (AN_ADS1115_IS_CONNECTED) and (AN_ADS1115_IS_CONNECTED == YES) and defined(ADS_MEASURE) and defined(ADS_CURRENT_BASED_ON)
49   #error It is not allowed to ask for current calculation based both on arduino Adc and on ads1115; define only or ARDUINO_MEASURES_A_CURRENT or ADS_CURRENT_BASED_ON
50 #endif            
52 #if defined (PIN_PPM ) && defined ( USE_6050 ) &&  ( PIN_INT_6050 == PIN_PPM )
53   #error Error in oXs_config_advanced.h : PIN_PPM may not be equal to PIN_INT_6050
54 #endif    
56 #if  defined ( PPM_VIA_SPORT ) && ( (PROTOCOL  != FRSKY_SPORT) && (PROTOCOL  != FRSKY_SPORT_HUB) ) 
57   #error Error in oXs_config_advanced.h : PPM_VIA_SPORT is allowed only when protocol is FRSKY_SPORT or FRSKY_SPORT_HUB
58 #endif
60 #if defined( VFAS_SOURCE ) && ( !  ( ( VFAS_SOURCE == VOLT_1) || ( VFAS_SOURCE == VOLT_2) || ( VFAS_SOURCE == VOLT_3) || ( VFAS_SOURCE == VOLT_4) || ( VFAS_SOURCE == VOLT_5) || ( VFAS_SOURCE == VOLT_6) || ( VFAS_SOURCE == ADS_VOLT_1) || ( VFAS_SOURCE == ADS_VOLT_2) || ( VFAS_SOURCE == ADS_VOLT_3) || ( VFAS_SOURCE == ADS_VOLT_4)) ) 
61  #error When defined, VFAS_SOURCE must be one of following values VOLT_1, VOLT_2, VOLT_3, VOLT_4, VOLT_5, VOLT_6, ADS_VOLT_1, ADS_VOLT_2, ADS_VOLT_3, ADS_VOLT_4 
62 #endif
63 #if defined( FUEL_SOURCE ) && ( !  ( ( FUEL_SOURCE == VOLT_1) || ( FUEL_SOURCE == VOLT_2) || ( FUEL_SOURCE == VOLT_3) || ( FUEL_SOURCE == VOLT_4) || ( FUEL_SOURCE == VOLT_5) || ( FUEL_SOURCE == VOLT_6) || ( VFAS_SOURCE == ADS_VOLT_1) || ( VFAS_SOURCE == ADS_VOLT_2) || ( VFAS_SOURCE == ADS_VOLT_3) || ( VFAS_SOURCE == ADS_VOLT_4)) ) 
64  #error When defined, FUEL_SOURCE must be one of following values VOLT_1, VOLT_2, VOLT_3, VOLT_4, VOLT_5, VOLT_6, ADS_VOLT_1, ADS_VOLT_2, ADS_VOLT_3, ADS_VOLT_4
65 #endif
66 #if defined( A3_SOURCE ) && ( !  ( ( A3_SOURCE == VOLT_1) || ( A3_SOURCE == VOLT_2) || ( A3_SOURCE == VOLT_3) || ( A3_SOURCE == VOLT_4) || ( A3_SOURCE == VOLT_5) || ( A3_SOURCE == VOLT_6) || ( A3_SOURCE == ADS_VOLT_1) || ( A3_SOURCE == ADS_VOLT_2) || ( A3_SOURCE == ADS_VOLT_3) || ( A3_SOURCE == ADS_VOLT_4) ) ) 
67  #error When defined, A3_SOURCE must be one of following values VOLT_1, VOLT_2, VOLT_3, VOLT_4, VOLT_5, VOLT_6, ADS_VOLT_1, ADS_VOLT_2, ADS_VOLT_3, ADS_VOLT_4
68 #endif
69 #if defined( A4_SOURCE ) && ( !  ( ( A4_SOURCE == VOLT_1) || ( A4_SOURCE == VOLT_2) || ( A4_SOURCE == VOLT_3) || ( A4_SOURCE == VOLT_4) || ( A4_SOURCE == VOLT_5) || ( A4_SOURCE == VOLT_6) || ( A3_SOURCE == ADS_VOLT_1) || ( A3_SOURCE == ADS_VOLT_2) || ( A3_SOURCE == ADS_VOLT_3) || ( A3_SOURCE == ADS_VOLT_4) ) ) 
70  #error When defined, A4_SOURCE must be one of following values VOLT_1, VOLT_2, VOLT_3, VOLT_4, VOLT_5, VOLT_6, ADS_VOLT_1, ADS_VOLT_2, ADS_VOLT_3, ADS_VOLT_4
71 #endif
72 #if defined( ACCX_SOURCE ) && ( !  ( ( ACCX_SOURCE == VOLT_1) || ( ACCX_SOURCE == VOLT_2) || ( ACCX_SOURCE == VOLT_3) || ( ACCX_SOURCE == VOLT_4) || ( ACCX_SOURCE == VOLT_5) || ( ACCX_SOURCE == VOLT_6) \
73     || ( ACCX_SOURCE == ADS_VOLT_1) || ( ACCX_SOURCE == ADS_VOLT_2) || ( ACCX_SOURCE == ADS_VOLT_3) || ( ACCX_SOURCE == ADS_VOLT_4) \
74     || ( ACCX_SOURCE == TEST_1) || ( ACCX_SOURCE == TEST_2) || ( ACCX_SOURCE == TEST_3) || ( ACCX_SOURCE == GLIDER_RATIO) || ( ACCX_SOURCE == SECONDS_SINCE_T0) || ( ACCX_SOURCE == AVERAGE_VSPEED_SINCE_TO) || ( ACCX_SOURCE == PITCH) || ( ACCX_SOURCE == ROLL) || ( ACCX_SOURCE == YAW) ) )
75  #error When defined, ACCX_SOURCE must be one of following values TEST_1, TEST_2, TEST_3, GLIDER_RATIO , SECONDS_SINCE_T0 ,AVERAGE_VSPEED_SINCE_TO , VOLT_1, VOLT_2, VOLT_3, VOLT_4, VOLT_5, VOLT_6, ADS_VOLT_1, ADS_VOLT_2, ADS_VOLT_3, ADS_VOLT_4, PITCH, ROLL, YAW
76 #endif
77 #if defined( ACCY_SOURCE ) && ( !  ( ( ACCY_SOURCE == VOLT_1) || ( ACCY_SOURCE == VOLT_2) || ( ACCY_SOURCE == VOLT_3) || ( ACCY_SOURCE == VOLT_4) || ( ACCY_SOURCE == VOLT_5) || ( ACCY_SOURCE == VOLT_6) \
78     || ( ACCY_SOURCE == ADS_VOLT_1) || ( ACCY_SOURCE == ADS_VOLT_2) || ( ACCY_SOURCE == ADS_VOLT_3) || ( ACCY_SOURCE == ADS_VOLT_4) \
79     || ( ACCY_SOURCE == TEST_1) || ( ACCY_SOURCE == TEST_2) || ( ACCY_SOURCE == TEST_3) || ( ACCY_SOURCE == GLIDER_RATIO) || ( ACCY_SOURCE == SECONDS_SINCE_T0) || ( ACCY_SOURCE == AVERAGE_VSPEED_SINCE_TO) || ( ACCY_SOURCE == PITCH) || ( ACCY_SOURCE == ROLL) || ( ACCY_SOURCE == YAW) ) )
80  #error When defined, ACCY_SOURCE must be one of following values TEST_1, TEST_2, TEST_3, GLIDER_RATIO , SECONDS_SINCE_T0 ,AVERAGE_VSPEED_SINCE_TO , VOLT_1, VOLT_2, VOLT_3, VOLT_4, VOLT_5, VOLT_6, ADS_VOLT_1, ADS_VOLT_2, ADS_VOLT_3, ADS_VOLT_4, PITCH, ROLL, YAW
81 #endif
82 #if defined( ACCZ_SOURCE ) && ( !  ( ( ACCZ_SOURCE == VOLT_1) || ( ACCZ_SOURCE == VOLT_2) || ( ACCZ_SOURCE == VOLT_3) || ( ACCZ_SOURCE == VOLT_4) || ( ACCZ_SOURCE == VOLT_5) || ( ACCZ_SOURCE == VOLT_6) \
83     || ( ACCZ_SOURCE == ADS_VOLT_1) || ( ACCZ_SOURCE == ADS_VOLT_2) || ( ACCZ_SOURCE == ADS_VOLT_3) || ( ACCZ_SOURCE == ADS_VOLT_4) \
84     || ( ACCZ_SOURCE == TEST_1) || ( ACCZ_SOURCE == TEST_2) || ( ACCZ_SOURCE == TEST_3) || ( ACCZ_SOURCE == GLIDER_RATIO) || ( ACCZ_SOURCE == SECONDS_SINCE_T0) || ( ACCZ_SOURCE == AVERAGE_VSPEED_SINCE_TO) || ( ACCZ_SOURCE == PITCH) || ( ACCZ_SOURCE == ROLL) || ( ACCZ_SOURCE == YAW) ) )
85  #error When defined, ACCZ_SOURCE must be one of following values TEST_1, TEST_2, TEST_3, GLIDER_RATIO , SECONDS_SINCE_T0 ,AVERAGE_VSPEED_SINCE_TO , VOLT_1, VOLT_2, VOLT_3, VOLT_4, VOLT_5, VOLT_6, ADS_VOLT_1, ADS_VOLT_2, ADS_VOLT_3, ADS_VOLT_4, PITCH, ROLL, YAW
86 #endif
87 #if defined( T1_SOURCE ) && ( !  ( ( T1_SOURCE == PPM) || ( T1_SOURCE == GLIDER_RATIO) || ( T1_SOURCE == SECONDS_SINCE_T0) || ( T1_SOURCE == AVERAGE_VSPEED_SINCE_TO) || ( T1_SOURCE == SENSITIVITY) \
88     || ( T1_SOURCE == VOLT_1) || ( T1_SOURCE == VOLT_2) || ( T1_SOURCE == VOLT_3) || ( T1_SOURCE == VOLT_4) || ( T1_SOURCE == VOLT_5) || ( T1_SOURCE == VOLT_6) \
89     || ( T1_SOURCE == ADS_VOLT_1) || ( T1_SOURCE == ADS_VOLT_2) || ( T1_SOURCE == ADS_VOLT_3) || ( T1_SOURCE == ADS_VOLT_4) \
90     || ( T1_SOURCE == TEST_1) || ( T1_SOURCE == TEST_2) || ( T1_SOURCE == TEST_3) ) )
91  #error When defined, T1_SOURCE must be one of following values TEST_1, TEST_2, TEST_3, GLIDER_RATIO , SECONDS_SINCE_T0 ,AVERAGE_VSPEED_SINCE_TO , SENSITIVITY , PPM , VOLT_1, VOLT_2, VOLT_3, VOLT_4, VOLT_5, VOLT_6, ADS_VOLT_1, ADS_VOLT_2, ADS_VOLT_3, ADS_VOLT_4, 
92 #endif
93 #if defined( T2_SOURCE ) && ( !  ( ( T2_SOURCE == PPM) || ( T2_SOURCE == GLIDER_RATIO) || ( T2_SOURCE == SECONDS_SINCE_T0) || ( T2_SOURCE == AVERAGE_VSPEED_SINCE_TO) || ( T2_SOURCE == SENSITIVITY) \
94     || ( T2_SOURCE == VOLT_1) || ( T2_SOURCE == VOLT_2) || ( T2_SOURCE == VOLT_3) || ( T2_SOURCE == VOLT_4) || ( T2_SOURCE == VOLT_5) || ( T2_SOURCE == VOLT_6)\
95     || ( T2_SOURCE == ADS_VOLT_1) || ( T2_SOURCE == ADS_VOLT_2) || ( T2_SOURCE == ADS_VOLT_3) || ( T2_SOURCE == ADS_VOLT_4) \
96     || ( T2_SOURCE == TEST_1) || ( T2_SOURCE == TEST_2) || ( T2_SOURCE == TEST_3) ) )
97  #error When defined, T2_SOURCE must be one of following values TEST_1, TEST_2, TEST_3, GLIDER_RATIO , SECONDS_SINCE_T0 ,AVERAGE_VSPEED_SINCE_TO , SENSITIVITY , PPM , VOLT_1, VOLT_2, VOLT_3, VOLT_4, VOLT_5, VOLT_6, ADS_VOLT_1, ADS_VOLT_2, ADS_VOLT_3, ADS_VOLT_4, 
98 #endif
99 #if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES) && (!defined(ADS_MEASURE))
100   #error When AN_ADS1115_IS_CONNECTED is set on YES, ADS_MEASURE (in oXs_config_advanced.h) must be uncommented and contains 4 values
101 #endif
102 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && (!defined(PIN_VOLTAGE))
103   #error When ARDUINO_MEASURES_VOLTAGES is set on YES, PIN_VOLTAGE must be uncommented and contains 6 values
104 #endif
105 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES) && (!defined(PIN_CURRENTSENSOR))
106   #error When ARDUINO_MEASURES_A_CURRENT is set on YES, PIN_CURRENTSENSOR must be uncommented and must specify the analog pin that is connected to the current sensor
107 #endif
109 #if defined ( ADS_AIRSPEED_BASED_ON ) && ( ! ( ( ADS_AIRSPEED_BASED_ON == ADS_VOLT_1) || ( ADS_AIRSPEED_BASED_ON == ADS_VOLT_2) || ( ADS_AIRSPEED_BASED_ON == ADS_VOLT_3) || ( ADS_AIRSPEED_BASED_ON == ADS_VOLT_4) ) )
110  #error When defined, ADS_AIRSPEED_BASED_ON must be one of following values ADS_VOLT_1, ADS_VOLT_2, ADS_VOLT_3, ADS_VOLT_4
111 #endif
112 #if defined(GPS_REFRESH_RATE) && ( ! ( (GPS_REFRESH_RATE == 1) || (GPS_REFRESH_RATE == 5) || (GPS_REFRESH_RATE == 10) ))      
113   #error When defined GPS_REFRESH_RATE must be 1, 5 or 10
114 #endif
116 #if defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES) 
117   #ifndef PIN_PPM
118     #error When MEASURE_RF_LINK_QUALITY = YES , PIN_PPM must be defined (in file oXs_config_advanced.h)
119   #endif
120   #if defined ( VSPEED_SOURCE ) &&  ( VSPEED_SOURCE == PPM_SELECTION)
121     #error When MEASURE_RF_LINK_QUALITY = YES , VSPEED_SOURCE may not be set to PPM_SELECTION
122   #endif
123   #if defined (AIRSPEED_SENSOR_USE) && (not(AIRSPEED_SENSOR_USE == NO_AIRSPEED))
124     #error When MEASURE_RF_LINK_QUALITY = YES , SEQUENCE_OUTPUTS may not be defined
125   #endif
126   #if defined ( SEQUENCE_OUTPUTS )
127     #error When MEASURE_RF_LINK_QUALITY = YES , SEQUENCE_OUTPUTS may not be defined
128   #endif
129 #endif //defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES)
131   
132 #ifdef PIN_PPM
133  #if PIN_PPM == 2
134         #define PPM_INTERRUPT                   ON // define to use interrupt code in Aserial.cpp
135         #define PPM_INT_MASK                    0x03
136         #define PPM_INT_EDGE                    0x01
137         #define PPM_PIN_HEX                       0x02
138         #define PPM_INT_BIT                     0x01
139  #endif
141  #if PIN_PPM == 3
142         #define PPM_INTERRUPT                   ON // define to use interrupt code in Aserial.cpp
143         #define PPM_INT_MASK                    0x0C
144         #define PPM_INT_EDGE                    0x04
145         #define PPM_PIN_HEX                     0x04
146         #define PPM_INT_BIT                     0x02
147  #endif
148 #endif
151 //*************** There is normally no reason changing the 2 next parameters
152 #define I2C_MS5611_Add           0x77 // 0x77 The I2C Address of the MS5611 breakout board 
153                                // (normally 0x76 or 0x77 configured on the MS5611 module 
154                                // via a solder pin or fixed)
155                                
156 #define I2C_4525_Add        0x28 // 0x28 is the default I2C adress of a 4525DO sensor
157 #define I2C_SDP3X_Add       0x21 // 0x21 is the default I2C adress of a SDP3X sensor
158 //#define I2C_SDP3X_Add       0x25 // 0x25 is the I2C adress of a SDP810 sensor
161 #define I2C_ADS_Add 0x48 // default I2C address of ads1115 when addr pin is connected to ground
163 #define PIN_LED            13  // The Signal LED (default=13=onboard LED)
166 extern unsigned long micros( void ) ;
167 extern unsigned long millis( void ) ;
168 //static unsigned long extendedMicros ;
170 #ifdef DEBUG_BLINK  // this does not require that DEBUG is active.; Use only one of the blink 
171    //DEBUG_BLINK_MAINLOOP
172    //DEBUG_BLINK_CLIMBRATE
173 #endif
175 #ifdef DEBUG
176 //#define DEBUGCOMPENSATEDCLIMBRATE
177 //#define DEBUGOUTDATATOSERIAL
178 //#define DEBUGENTERLOOP
179 //#define DEBUG_ENTER_READSENSORS
180 //#define DEBUG_CALCULATE_FIELDS
181 //#define DEBUGSEQUENCE
182 //#define DEBUG_PPM_AVAILABLE_FROM_INTERRUPT
183 #define DEBUG_RF_LINK_QUALITY
184 //#define DEBUGPPMVALUE
185 //#define DEBUGFORCEPPM
186 //#define DEBUG_SELECTED_VARIO
187 //#define DEBUG_VARIO_TIME
188 //#define DEBUG_VOLTAGE_TIME
189 //#define DEBUG_READ_SPORT
190 //#define DEBUG_SIMULATE_FLOW_SENSOR
191 //#define DEBUG_FLOW_SENSOR
192 //#define DEBUG_RPM
193 #endif
196 // ************ declare some functions being used ***************
197 int freeRam () ;
198 void checkButton() ;
199 void readSensors() ;
200 void Reset1SecButtonPress() ;
201 void Reset3SecButtonPress() ; 
202 void Reset10SecButtonPress() ;
203 void SaveToEEProm() ;
204 void LoadFromEEProm() ; 
205 void ProcessPPMSignal() ;
206 //unsigned int ReadPPM() ;
207 void ReadPPM() ;
208 bool checkFreeTime() ;
209 void setNewSequence() ;
210 void checkSequence() ;
211 void blinkLed( uint8_t blinkType ) ;
212 void checkFlowParam() ;
214 // *********** declare some variables *****************************
215 #ifdef VARIO
216 bool newVarioAvailable ;
217 struct ONE_MEASUREMENT mainVspeed ;
218 #endif
219 #ifdef VARIO2
220 bool newVarioAvailable2 ;
221 #endif
223 #if defined (VARIO) && defined ( AIRSPEED_IS_USED)  
224 struct ONE_MEASUREMENT compensatedClimbRate ;
225 bool switchCompensatedClimbRateAvailable ;
226 float rawCompensatedClimbRate ; 
227 #endif
229 #if defined (VARIO) && ( defined (VARIO2) || defined ( AIRSPEED_IS_USED) || defined (USE_6050) )
230 struct ONE_MEASUREMENT switchVSpeed ;
231 #endif
233 #if defined (VARIO) && defined (VARIO2)
234 struct ONE_MEASUREMENT averageVSpeed ;
235 float averageVSpeedFloat ;
236 #endif
238 #if defined  (VARIO) && defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC) && GLIDER_RATIO_CALCULATED_AFTER_X_SEC >= 1 
239 struct ONE_MEASUREMENT gliderRatio ;
240 struct ONE_MEASUREMENT secFromT0 ; // in 1/10 sec
241 struct ONE_MEASUREMENT averageVspeedSinceT0 ; //in cm/sec
242 void calculateAverages();
243 boolean gliderRatioPpmOn = false ;
244 #endif
246 #ifdef USE_6050
247   KalmanFilter kalman ;
248   float zTrack ;
249   float vTrack ;
250   struct ONE_MEASUREMENT vSpeedImu ;
251   bool vTrackAvailable ;
252   bool switchVTrackAvailable ;
253   extern float linear_acceleration_x ;
254   extern float linear_acceleration_y ;
255   extern float linear_acceleration_z ;
256   extern float world_linear_acceleration_z ;
257   extern bool newImuAvailable;
258   float altitudeToKalman ;
259   int countAltitudeToKalman = 100 ;
260   int32_t altitudeOffsetToKalman ;
261   extern volatile uint32_t lastImuInterruptMillis ;
262 #ifdef USE_HMC5883 
263   extern float magHeading ;
264   extern boolean newMagHeading; 
265 #endif
266   #ifdef DEBUG_KALMAN_TIME  
267     int delayKalman[5] ;
268   #endif
269 #endif // end of USE_6050
273 #if defined(ADS_AIRSPEED_BASED_ON) and (ADS_AIRSPEED_BASED_ON >= ADS_VOLT1) and (ADS_AIRSPEED_BASED_ON <= ADS_VOLT_4)
274   extern float ads_sumDifPressureAdc_0 ;
275   extern uint8_t ads_cntDifPressureAdc_0 ;
276 #endif
278 uint16_t ppmus ; // duration of ppm in usec
279 int prevPpm ; //^previous ppm
280 struct ONE_MEASUREMENT ppm ; // duration of pulse in range -100 / + 100 ; can exceed those limits
281 struct ONE_MEASUREMENT newPpm ; // keep the ppm value received via sport before it is processed in other part of the code
283 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)  // we will use interrupt PCINT0 
284   volatile uint16_t flowMeterCnt ;            // counter of pin change connected to the flow sensor (increased in the interrupt. reset every X sec when flow is processed)
285   float currentFlow  ;                     // count the consumed ml/min during the last x sec
286   float consumedML   ;                     // total of consumed ml since the last reset (or restart if reset is not activated); can be saved in EEPROM
287   struct ONE_MEASUREMENT actualFlow ;             // in ml/min
288   struct ONE_MEASUREMENT remainingFuelML ;         // in ml
289   struct ONE_MEASUREMENT fuelPercent ;             // in % of tank capacity
290   boolean newFlowAvailable = false ;
291   int16_t flowParam[8] =  { INIT_FLOW_PARAM } ;                      // table that contains the parameters to correct the ml/pulse depending on the flow ; can be loaded by SPORT in EEPROM; can also be defined in a parameter 
292   uint16_t tankCapacity =  TANK_CAPACITY ;     // capacity of fuel tank
293   uint16_t consumedMLEeprom   ;                 //Last value saved in eeprom
294   uint16_t tankCapacityEeprom ;                 //Last value saved in eeprom
295   int16_t flowParamEeprom[8]  ;                 //Last value saved in eeprom
296 #endif
300 #ifdef SEQUENCE_OUTPUTS
301 #ifdef SEQUENCE_m100
302   uint8_t sequence_m100 [] = { SEQUENCE_m100 } ;
303 #else
304   uint8_t sequence_m100 [2] = { 0 , 0 } ;
305 #endif
306 #ifdef SEQUENCE_m75
307   uint8_t sequence_m75 [] = { SEQUENCE_m75 } ;
308 #else
309   uint8_t sequence_m75 [2] = { 0 , 0 } ;
310 #endif
311 #ifdef SEQUENCE_m50
312   uint8_t sequence_m50 [] = { SEQUENCE_m50 } ;
313 #else
314   uint8_t sequence_m50 [2] = { 0 , 0 } ;
315 #endif
316 #ifdef SEQUENCE_m25
317   uint8_t sequence_m25 [] = { SEQUENCE_m25 } ;
318 #else
319   uint8_t sequence_m25 [2] = { 0 , 0 } ;
320 #endif
321 #ifdef SEQUENCE_0
322   uint8_t sequence_0 [] = { SEQUENCE_0 } ;
323 #else
324   uint8_t sequence_0 [2] = { 0 , 0 } ;
325 #endif
326 #ifdef SEQUENCE_25
327   uint8_t sequence_25 [] = { SEQUENCE_25 } ;
328 #else
329   uint8_t sequence_25 [2] = { 0 , 0 } ;
330 #endif
331 #ifdef SEQUENCE_50
332   uint8_t sequence_50 [] = { SEQUENCE_50 } ;
333 #else
334   uint8_t sequence_50 [2] = { 0 , 0 } ;
335 #endif
336 #ifdef SEQUENCE_75
337   uint8_t sequence_75 [] = { SEQUENCE_75 } ;
338 #else
339   uint8_t sequence_75 [2] = { 0 , 0 } ;
340 #endif
341 #ifdef SEQUENCE_100
342   uint8_t sequence_100 [] = { SEQUENCE_100 } ;
343 #else
344   uint8_t sequence_100 [2] = { 0 , 0 } ;
345 #endif
346 #ifdef SEQUENCE_LOW
347   uint8_t sequence_low [] = { SEQUENCE_LOW } ;
348 #else
349   uint8_t sequence_low [2] = { 0 , 0 } ;
350 #endif
353     uint16_t sequenceMaxNumber[10] ;  // this array contains the number of events of each sequence
354     uint8_t * sequencePointer[10] ; // this is an array of pointers; each pointer refers to the first element of a 2 dim array.
355     
356     uint8_t *seqRef  ;  // seqRef contains a pointer to the first item of the selected sequence array
357     uint16_t seqMax ; // number of sequences in the selected array
358     uint8_t seqState ; // say if the sequence is starting (0), running (1) or stopped (2)
359     uint16_t seqStep ;  // says the current step in the sequence , first step = 0 ;
360     uint8_t sequenceOutputs = SEQUENCE_OUTPUTS & 0b00111111 ; // Mask to define which pin of portB are outputs
361 #ifdef SEQUENCE_UNIT
362     uint16_t sequenceUnit = SEQUENCE_UNIT * 10 ; 
363 #else
364     uint16_t sequenceUnit = 10 ; 
365 #endif // SEQUENCE_UNIT
366 #endif // end of SEQUENCE_OUTPUTS
368 int8_t prevPpmMain = -100 ; // this value is unusual; so it will forced a change at first call
369 bool lowVoltage = false ;
370 bool prevLowVoltage = false ;
371 //uint32_t currentLoopMillis ;
373 volatile bool RpmSet  ;
374 volatile uint16_t RpmValue ;
375 unsigned long lastRpmMillis ;
376 #if defined (MEASURE_RPM)
377   struct ONE_MEASUREMENT sport_rpm ;
378 #endif
380 int PWRValue; // calculation field for Vertical speed on PWR
381 unsigned long lastMillisPWR ;
383 float actualPressure  ; // default pressure in pascal; to actualise if vario exist; is used in airspeed calculation.
384 int sensitivityPpmMapped ;
385 int compensationPpmMapped ;
386 struct ONE_MEASUREMENT test1 ; // used in order to test the transmission of any value
387 struct ONE_MEASUREMENT test2 ; // used in order to test the transmission of any value
388 struct ONE_MEASUREMENT test3 ; // used in order to test the transmission of any value
389 //int32_t test1Value ;// used in order to test the transmission of any value
390 //bool test1ValueAvailable ;
391 //int32_t test2Value ;// used in order to test the transmission of any value
392 //bool test2ValueAvailable ;
393 //int32_t test3Value ;// used in order to test the transmission of any value
394 //bool test3ValueAvailable ;
395 #ifdef VARIO_PRIMARY
396 uint8_t selectedVario = VARIO_PRIMARY ; // identify the vario to be used when switch vario with PPM is active (1 = first MS5611) 
397 #endif
399 // to read SPORT (for Frsky protocol
400 extern uint8_t  volatile TxData[8] ;
401 extern uint8_t  volatile TxDataIdx ;
404 //******************* Create instances of the used classes ******************************************
405 #ifdef VARIO
406   #ifdef SENSOR_IS_BMP180
407       #ifdef DEBUG  
408         OXS_BMP180 oXs_MS5611 = OXS_BMP180(Serial);
409       #else
410         OXS_BMP180 oXs_MS5611 = OXS_BMP180();
411       #endif  //DEBUG
412   #elif defined(SENSOR_IS_BMP280 )
413       #ifdef DEBUG  
414         OXS_BMP280 oXs_MS5611 = OXS_BMP280(Serial);
415       #else
416         OXS_BMP280 oXs_MS5611 = OXS_BMP280();
417       #endif  //DEBUG
418   #else // not a BMP180 or BMP280
419       #ifdef DEBUG  
420         OXS_MS5611 oXs_MS5611(I2C_MS5611_Add,Serial);
421       #else
422         OXS_MS5611 oXs_MS5611(I2C_MS5611_Add);
423       #endif  //DEBUG
424   #endif // BMP180 or MS5611 sensor
425 #endif // VARIO
428 #ifdef VARIO2
429   #ifdef DEBUG  
430     OXS_MS5611 oXs_MS5611_2(I2C_MS5611_Add - 1,Serial);
431   #else
432     OXS_MS5611 oXs_MS5611_2(I2C_MS5611_Add - 1);
433   #endif  //DEBUG
434 #endif
436 #ifdef AIRSPEED_4525 // differential pressure
437   #ifdef DEBUG  
438     OXS_4525 oXs_4525(I2C_4525_Add ,Serial);
439   #else
440     OXS_4525 oXs_4525(I2C_4525_Add);
441   #endif  //DEBUG
442 #endif
444 #ifdef AIRSPEED_SDP3X 
445   #ifdef DEBUG  
446     OXS_SDP3X oXs_sdp3x(I2C_SDP3X_Add ,Serial);
447   #else
448     OXS_SDP3X oXs_sdp3x(I2C_SDP3X_Add);
449   #endif  //DEBUG
450 #endif
452 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
453   #ifdef DEBUG  
454     OXS_VOLTAGE oXs_Voltage(Serial);
455   #else
456     OXS_VOLTAGE oXs_Voltage(0);
457   #endif  //DEBUG
458 #endif
460 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
461   #ifdef DEBUG  
462     OXS_CURRENT oXs_Current(PIN_CURRENTSENSOR,Serial);
463   #else
464     OXS_CURRENT oXs_Current(PIN_CURRENTSENSOR);
465   #endif //DEBUG
466 #endif
468 #ifdef GPS_INSTALLED
469   #ifdef DEBUG
470     OXS_GPS oXs_Gps(Serial);
471   #else
472     OXS_GPS oXs_Gps(0);
473   #endif //DEBUG
474 #endif
476 #if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE)
477   #ifdef DEBUG
478     OXS_ADS1115 oXs_ads1115(  I2C_ADS_Add , Serial);
479   #else
480     OXS_ADS1115 oXs_ads1115( I2C_ADS_Add );
481   #endif //DEBUG
482 #endif
485 //Create a class used for telemetry ;content of class depends on the selected protocol (managed via #ifdef in different files)
486 #ifdef DEBUG  
487   OXS_OUT oXs_Out(PIN_SERIALTX,Serial);
488 #else
489   OXS_OUT oXs_Out(PIN_SERIALTX);
490 #endif
491 // *********************************** End of create objects *************************************************
493                             // Mike I do not understand this instruction; could you explain
494 #define FORCE_INDIRECT(ptr) __asm__ __volatile__ ("" : "=e" (ptr) : "0" (ptr))
497 //******************************************* Setup () *******************************************************
499 void setup(){
500 // set up the UART speed (38400 if GPS installed else 115200)
501 #ifdef GPS_INSTALLED
502   Serial.begin(38400); // when GPS is used, baudrate is reduced because main loop must have the time to read the received char.
503 #endif
504 #ifdef DEBUG 
505 #ifndef GPS_INSTALLED
506   Serial.begin(115200L); // when GPS is not used, baudrate can be 115200
507 #endif
508   Serial.println(F("openXsensor starting.."));
509   Serial.print(F(" milli="));  
510   Serial.println(millis());
511   Serial.print(F("freeRam="));  
512   Serial.println(freeRam());
513 #endif 
515 // set up pins
516 #ifdef DEBUG_SETUP_PIN 
517     pinMode(DEBUG_SETUP_PIN, OUTPUT); // Set the start signal to high to say that set up start
518     digitalWrite(DEBUG_SETUP_PIN, HIGH);
519 #endif  
521   #ifdef DEBUG_SPORT_PIN 
522     pinMode(DEBUG_SPORT_PIN, OUTPUT); // Set the pulse used during SPORT detection to LOW because detection is not yet started
523     digitalWrite(DEBUG_SPORT_PIN, LOW);
524 #endif  
526 #ifdef DEBUG_BLINK
527   pinMode(PIN_LED, OUTPUT); // The signal LED (used for the function debug loop)
528 #endif
530 #ifdef PIN_PUSHBUTTON  
531   pinMode(PIN_PUSHBUTTON, INPUT_PULLUP);
532 #endif
534   pinMode(PIN_LED, OUTPUT); // The signal LED (used for the function push button)
536 //  sensitivityPpmMapped = 0 ;
537   compensationPpmMapped = 100 ;
538 //  test1.value = 0 ;
539 //  test2.value = 0 ;
540 //  test3.value = 0 ;
541 //  test1.available = false ;
542 //  test2.available = false ;
543 //  test3.available = false ;
544   actualPressure = 101325 ; // default pressure in pascal; to actualise if vario exist; is used in airspeed calcualtion.
547   // ******** Invoke all setup methods and set reference
548 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
549   oXs_Voltage.setupVoltage(); 
550   oXs_Out.voltageData=&oXs_Voltage.voltageData; 
551 #endif
553 #ifdef VARIO
554 #ifdef DEBUG 
555   Serial.println(F("vario setting up.."));
556   delay(1000);
557 #endif 
558   oXs_MS5611.setup();
559 #ifdef DEBUG 
560   Serial.println(F("vario is up.."));
561   delay(1000);
562 #endif 
564   oXs_Out.varioData=&oXs_MS5611.varioData; 
565   #ifdef PIN_ANALOG_VSPEED
566     lastMillisPWR = 3500 ; // So we will wait for 3.5 sec before generating a Vertical speed on PWM
567     analogWrite(PIN_ANALOG_VSPEED,255/5*1.6); // initialize the output pin 
568   #endif
569 #endif // vario
571 #ifdef VARIO2
572   oXs_MS5611_2.setup();
573   oXs_Out.varioData_2=&oXs_MS5611_2.varioData; 
574 #endif // vario
576 #ifdef AIRSPEED_4525
577   oXs_4525.setup();
578   oXs_Out.airSpeedData=&oXs_4525.airSpeedData; 
579 #endif // end AIRSPEED
581 #ifdef AIRSPEED_SDP3X 
582   oXs_sdp3x.setup();
583   oXs_Out.airSpeedData=&oXs_sdp3x.airSpeedData; 
584 #endif // end AIRSPEED SDP3X
586 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
587   oXs_Current.setupCurrent( );
588   oXs_Out.currentData=&oXs_Current.currentData;
589 #endif
591 #if defined (VARIO) &&  defined ( AIRSPEED_IS_USED) 
592   compensatedClimbRate.available = false;
593 //  compensatedClimbRate = 0;
594 #endif
596 #ifdef GPS_INSTALLED
597   oXs_Gps.setupGps();
598 #endif
600   oXs_Out.setup();
602 #ifdef USE_6050
603     setupImu() ;
604 #endif
606 #if defined( USE_HMC5883 ) && defined (USE_6050)
607   setup_hmc5883() ;  // set up magnetometer
608 #endif
610 #if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE)
611   oXs_ads1115.setup() ;
612 #if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(ADS_CURRENT_BASED_ON)
613   oXs_Out.currentData=&oXs_ads1115.adsCurrentData;
614 #endif            
615 #if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(ADS_AIRSPEED_BASED_ON)
616   oXs_Out.airSpeedData=&oXs_ads1115.adsAirSpeedData;
617 #endif            
618 #endif
620 #if defined (SAVE_TO_EEPROM ) and ( SAVE_TO_EEPROM == YES )
621   LoadFromEEProm();
622 #endif
624 #ifdef PIN_PPM
625 //    ppmus = 0 ;
626 //    prevPpm = 0 ;
627     ppm.available = false ;
628 #endif
630 #ifdef PPM_INTERRUPT      // PPM use INT0 (pin 2) or INT1 (pin 3) that are on port D
631         PORTD |= PPM_PIN_HEX ;  // Pullup resistor
632         DDRD &= ~PPM_PIN_HEX ;  // Input
633         EICRA |= PPM_INT_MASK ;         // Interrupt on rising edge
634         EIFR = PPM_INT_BIT ;                    // Clear interrupt flag
635         EIMSK |= PPM_INT_BIT ;          // Enable interrupt
636 #endif
638 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)  // we will use interrupt PCINT0 
639   PORTB |= 0X2 ;  // set pullup resistor on pin 9 (= PB1)
640   DDRB &= ~ 0X2 ; // set pin as input on pin 9 (= PB1)
641   PCMSK0 = 0X2 ; // prepare to allow pin change interrupt on only pin 9 ( = PB1)
642   PCICR |= (1<<PCIE0)   ;     // enable pin change interrupt 0 so on pin from PB0 to PB7 = e.g. pins 8 to 13 to collect pin changes for flow sensor 
643 #endif
645   RpmSet = false ;
646 //  RpmValue = 0 ;
647 //  RpmAvailable = false ;
649 //************************* set up of sequence outputs
650 #ifdef SEQUENCE_OUTPUTS
651     sequenceMaxNumber[0] = sizeof(sequence_m100) ; // sizeof(sequence_m100[0]) ;
652     sequenceMaxNumber[1] = sizeof(sequence_m75) ;// sizeof(sequence_m75[0]) ;
653     sequenceMaxNumber[2] = sizeof(sequence_m50) ;// sizeof(sequence_m50[0]) ;
654     sequenceMaxNumber[3] = sizeof(sequence_m25) ;// sizeof(sequence_m25[0]) ;
655     sequenceMaxNumber[4] = sizeof(sequence_0) ;// sizeof(sequence_0[0]) ;
656     sequenceMaxNumber[5] = sizeof(sequence_25) ;// sizeof(sequence_25[0]) ;
657     sequenceMaxNumber[6] = sizeof(sequence_50) ;// sizeof(sequence_50[0]) ;
658     sequenceMaxNumber[7] = sizeof(sequence_75) ;// sizeof(sequence_75[0]) ;
659     sequenceMaxNumber[8] = sizeof(sequence_100) ;// sizeof(sequence_100[0]) ;
660     sequenceMaxNumber[9] = sizeof(sequence_low) ;// sizeof(sequence_100[0]) ;
661     sequencePointer[0] = &sequence_m100[0] ;
662     sequencePointer[1] = &sequence_m75[0] ;
663     sequencePointer[2] = &sequence_m50[0] ;
664     sequencePointer[3] = &sequence_m25[0] ;
665     sequencePointer[4] = &sequence_0[0] ;
666     sequencePointer[5] = &sequence_25[0] ;
667     sequencePointer[6] = &sequence_50[0] ;
668     sequencePointer[7] = &sequence_75[0] ;
669     sequencePointer[8] = &sequence_100[0] ;
670     sequencePointer[9] = &sequence_low[0] ;     
671 #ifdef DEBUG
672     seqRef = sequencePointer[0] ;  // seqTab contains pointers to the sequence array
673     seqMax = sequenceMaxNumber[0] ;
674     Serial.print(F("SeqRef="));  Serial.println( (uint16_t) seqRef) ;
675     Serial.print(F("SeqMax="));  Serial.println( (uint16_t) seqMax) ;
676     Serial.print(F("Sequence_m100="));    
677     for (uint8_t idxDebugSeq = 0 ; idxDebugSeq < (seqMax) ; idxDebugSeq++ ) {
678       Serial.print( *(seqRef + idxDebugSeq ) );
679       Serial.print(F(" , "));
680     }
681     Serial.println(F(" "));
682 #endif    
683     seqState = 2 ; // declare that sequence is stopped
684     PORTB &= ~sequenceOutputs ; // set all output to LOW
685     DDRB |= sequenceOutputs ; // set pin to output mode
686     
687 //#ifdef DEBUGSEQUENCE
688     ppm.value = -100 ; // fix the sequence to be used by default (e.g. when no PPM signal is present);  
689     setNewSequence( ) ; 
690 //#endif
691 #endif //****************************** end of SEQUENCE_OUTPUTS
693 #ifdef DEBUG_SPORT_PIN 
694     digitalWrite(DEBUG_SPORT_PIN, LOW);
695 //    pinMode(DEBUG_SPORT_PIN, INPUT); // Set the pin in input mode because it is not used anymore
696 #endif  
697 #ifdef DEBUG_SETUP_PIN 
698     digitalWrite(DEBUG_SETUP_PIN, LOW); // Set the setup signal to low to say that set up is done
699 //    pinMode(DEBUG_SETUP_PIN, OUTPUT); 
700 #endif  
702 #ifdef DEBUG
703   Serial.println(F("End of general set up"));
704 #endif
706 } // ******************** end of Setup *****************************************************
709 //*******************************************************************************************
710 //                                Main loop                                               ***
711 //*******************************************************************************************
712 void loop(){ 
714 uint8_t flagMillis ;
715 static uint32_t lastLoop20Millis ;
716 static uint32_t lastLoop50Millis ;
717 static uint32_t lastLoop200Millis ;
718 static uint32_t lastLoop500Millis ;
720 #define BIT20MILLIS 1 ;
721 #define BIT50MILLIS 2 ;
722 #define BIT200MILLIS 4 ;
723 #define BIT500MILLIS 8 ;
725 //currentLoopMillis = millis() ;
727 if ( currentLoopMillis - lastLoop20Millis > 20 ) {
728   lastLoop20Millis = currentLoopMillis ;
729   flagMillis = BIT20MILLIS ;
731 if ( currentLoopMillis - lastLoop50Millis > 50 ) {
732   lastLoop50Millis = currentLoopMillis ;
733   flagMillis |= BIT50MILLIS ;
735 if ( currentLoopMillis - lastLoop200Millis > 200 ) {
736   lastLoop200Millis = currentLoopMillis ;
737   flagMillis |= BIT200MILLIS ;
739 if ( currentLoopMillis - lastLoop500Millis > 500 ) {
740   lastLoop500Millis = currentLoopMillis ;
741   flagMillis |= BIT500MILLIS ;
744 #ifdef DEBUGENTERLOOP
745   Serial.print(F("in loop="));  
746   Serial.println(millis());
747 #endif 
748 #ifdef DEBUG_BLINK_MAINLOOP
749     blinkLed(1) ;
750 #endif
751   //extern volatile uint8_t state ; 
752   //Serial.println(state) ;
753     // Check if a button has been pressed
754 #ifdef PIN_PUSHBUTTON
755 #if defined (VARIO) || defined (VARIO2)
756     if (checkFreeTime()) checkButton(); // Do not perform calculation if there is less than 2000 usec before MS5611 ADC is available =  (9000 - 2000)/2
757 #else
758     checkButton();
759 #endif    
760 #endif 
762     // read all sensors
763     readSensors(); 
764 #ifdef DEBUG_CALCULATE_FIELDS
765   Serial.print("call calculateAllFields at") ; Serial.println(millis()) ;
766 #endif
767     // Calculate all fields
768     calculateAllFields(); 
770 #ifdef DEBUG_CALCULATE_FIELDS
771   Serial.print("end of call calculateAllFields at") ; Serial.println(millis()) ;
772 #endif
774     // prepare the telemetry data to be sent (nb: data are prepared but not sent)
775     if ( millis() > 1500 ) oXs_Out.sendData(); 
776    
777 // PPM Processing = Read the ppm Signal from receiver  or use the SPORT ppm value from readSensors and process it 
778 #if defined ( PPM_IS_USED ) 
779 #if defined (VARIO) || defined (VARIO2)
780     if (checkFreeTime()) ProcessPPMSignal();
781 #else
782     ProcessPPMSignal();
783 #endif      
784 #endif //PIN_PPM
786 // if analog vario, generate the PWR value
787 #if defined (VARIO) && defined(PIN_ANALOG_VSPEED)
788     if (millis() > lastMillisPWR + 100) {
789         if (checkFreeTime()) { // Do not change PWM if there is less than 2000 usec before MS5611 ADC is available =  (9000 - 2000)/2
790             PWRValue=map( (long) oXs_MS5611.varioData.climbRate.value ,ANALOG_VSPEED_MIN*100,ANALOG_VSPEED_MAX * 100,0,255/5*3.2);
791             PWRValue=constrain(PWRValue, 0, 255/5*3.2 ) ;
792             analogWrite(PIN_ANALOG_VSPEED,(int)PWRValue);
793             lastMillisPWR = millis() ; 
794         }
795     }  
796 #endif // analog vario 
798 // if a sequence is set up
799 #ifdef SEQUENCE_OUTPUTS
800 #if defined( SEQUENCE_MIN_VOLT_6) || defined ( SEQUENCE_MIN_CELL ) 
801   if ( (lowVoltage == true) && (prevLowVoltage == false) ) {
802     prevLowVoltage = true ;
803     ppm.value = 125 ; // fix the sequence to be used when voltage is low  ; it is sequence +125
804     prevPpmMain = -10 ; // will force a new sequence because ppmMain will be different from prevPpmMain
805     setNewSequence() ;
806     #ifdef DEBUG
807         Serial.println(F("Start sequence low voltage"));
808     #endif
809   }  else if ( (lowVoltage == false) && (prevLowVoltage == true) ) {
810     prevLowVoltage = false ;
811     prevPpmMain = -10 ; //will force a new sequence because ppmMain will be different from prevPpmMain
812 #ifdef PIN_PPM
813     if ( ppmus == 0) ppm.value = -100 ; // force ppm to -100 (default) when no ppm signal is received ,  else it will use the current ppm value
814 #else 
815     ppm.value = -100 ; // if ppm is not configure force to go back to sequence -100 (= default);
816 #endif  // end PIN_PPM def or not
817     setNewSequence() ; 
818     #ifdef DEBUG
819         Serial.println(F("End sequence low voltage"));
820     #endif
821   }  
822 #endif // end (defined( SEQUENCE_MIN_VOLT_6) || defined ( SEQUENCE_MIN_CELL ) 
823   checkSequence() ; // check if outputs have to be modified because time expired
824 #endif  // SEQUENCE_OUTPUTS
826 // Save Persistant Data To EEProm every 10 seconds
827 #if defined (SAVE_TO_EEPROM ) and ( SAVE_TO_EEPROM == YES )
828   static unsigned long LastEEPromMs=millis();
829   if (millis() > LastEEPromMs+10000){ 
830     LastEEPromMs=millis();
831     SaveToEEProm();
832   }
833 #endif
835 #if defined( A_LOCATOR_IS_CONNECTED )  and ( A_LOCATOR_IS_CONNECTED == YES) 
836   loraHandle() ;
837 #endif  
838 }          // ****************   end of main loop *************************************
845 //**********************************************************************************************************
846 //***                                            Read all the sensors / Inputs                          ****
847 //**********************************************************************************************************
848 extern uint16_t i2cPressureError ;
849 extern uint16_t i2cTemperatureError ;
850 extern uint16_t i2cReadCount ;
852 void readSensors() {  
853    
854 #ifdef AIRSPEED_4525
855   oXs_4525.readSensor(); // Read a first time the differential pressure on 4525DO, calculate airspeed; note airspeed is read a second time in the loop in order to reduce response time
856 #endif
858 #ifdef VARIO
859 #ifdef DEBUG_ENTER_READSENSORS
860   Serial.print( "read baro 1 at ") ; Serial.println(millis()); 
861 #endif
863   newVarioAvailable = oXs_MS5611.readSensor(); // Read pressure & temperature on MS5611, calculate Altitude and vertical speed; 
864   if ( oXs_MS5611.varioData.absoluteAlt.available == true and oXs_MS5611.varioData.rawPressure > 100000.0f ) {
865       actualPressure = oXs_MS5611.varioData.rawPressure / 10000.0 ; // this value can be used when calculating the Airspeed
866     #ifdef FILL_TEST_1_WITH_VARIO_TEMP
867       test1.value = oXs_MS5611.varioData.temperature/100.0 ;
868       test1.available = true ;
869     #endif
870     #ifdef FILL_TEST_2_WITH_VARIO_TEMP
871       test2.value = oXs_MS5611.varioData.temperature/100.0 ;
872       test2.available = true ;
873     #endif
874     #ifdef FILL_TEST_3_WITH_VARIO_TEMP
875       test3.value = oXs_MS5611.varioData.temperature/100.0 ;
876       test3.available = true ;
877     #endif
878   }
879 #endif
881 #ifdef VARIO2
882 #ifdef DEBUG_ENTER_READSENSORS
883   Serial.print( "read baro 2 at ") ; Serial.println(millis()); 
884 #endif
886   newVarioAvailable2 = oXs_MS5611_2.readSensor(); // Read pressure & temperature on MS5611, calculate Altitude and vertical speed
887 #endif
889 #ifdef AIRSPEED_4525
890   oXs_4525.readSensor(); // Read again the sensor in order to reduce response time/noise
891 #endif 
893 #ifdef AIRSPEED_SDP3X 
894   oXs_sdp3x.readSensor(); //read the SDP3X sensor
895 #endif
897 #ifdef USE_6050
898     newImuAvailable = read6050() ;
899 #endif // USE_6050
901 #if defined( USE_HMC5883 ) && defined (USE_6050)
902     read_hmc5883() ;
903 #endif
905 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
906     oXs_Voltage.readSensor();    // read voltage only if there enough time to avoid delaying vario reading; It takes about 750 usec to go through the read sensor.
907 #endif   // end voltage
909 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
910     oXs_Current.readSensor() ; // Do not perform calculation if there is less than 2000 usec before MS5611 ADC is available =  (9000 - 2000)/2
911 #endif             // End defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
913 #ifdef GPS_INSTALLED
914 #ifdef DEBUG_ENTER_READSENSORS
915   Serial.print( "read gps at ") ; Serial.println(millis()); 
916 #endif
918     oXs_Gps.readGps() ; // Do not perform calculation if there is less than 2000 usec before MS5611 ADC is available =  (9000 - 2000)/2
919 #endif             // End GPS_INSTALLED
921 #if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE)
922     if( oXs_ads1115.readSensor() ) { // return true when a new average is available; it means that the new value has to be stored/processed.
923     }
924 #endif             // End ADS_MEASURE
927 #ifdef MEASURE_RPM
928   if (millis() > ( lastRpmMillis + 200) ){  // allow transmission of RPM only once every 200 msec
929         if (RpmSet == true) {               // rpm is set 
930             RpmSet = false ;
931         } else {
932             RpmValue = 0 ;
933         }
934         sport_rpm.value = RpmValue ;
935         sport_rpm.available = true ;    
936         lastRpmMillis = millis() ;
937 #ifdef DEBUG_RPM
938        Serial.print( "RPM ") ; Serial.println(sport_rpm.value); 
939 #endif       
940   }      
941 #endif
943 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)  
944     processFlowMeterCnt () ;
945 #endif 
948 #if ( defined ( PPM_VIA_SPORT ) || ( defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES) ) ) && defined (PROTOCOL ) && ( ( PROTOCOL == FRSKY_SPORT ) || ( PROTOCOL == FRSKY_SPORT_HUB ) ) // if it is allowed to read SPORT
949     uint8_t oReg = SREG ; // save status register
950     cli() ;
951     if ( TxDataIdx == 8 ) {
952       TxDataIdx++ ; // Increase the number of data in order to avoid to read twice
953       uint16_t txField = ( TxData[2] << 8 ) + TxData[1] ;                                                      // id of the field being received
954       uint32_t txValue = ( ( ( ( (TxData[6] << 8) + TxData[5] ) << 8 ) + TxData[4] ) << 8 ) + TxData[3] ;      // value of the field being received
955       SREG = oReg ;  // restore the status register
956 #ifdef DEBUG_READ_SPORT
957       Serial.print("At: ") ; Serial.print(millis()) ;
958       Serial.print(" "); Serial.print(TxData[0], HEX);  
959       Serial.print(" "); Serial.print(TxData[1], HEX);  
960       Serial.print(" "); Serial.print(TxData[2], HEX);  
961       Serial.print(" "); Serial.print(TxData[3], HEX);  
962       Serial.print(" "); Serial.print(TxData[4], HEX);  
963       Serial.print(" "); Serial.print(TxData[5], HEX);  
964       Serial.print(" "); Serial.print(TxData[6], HEX);
965       Serial.print(" "); Serial.print(TxData[7], HEX);
966       Serial.println(" ");    
967 #endif      
968 #if  ( defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES) )
969       if (  txField <= TX_FIELD_FLOW_CORR_4)  {  // save values for flow meter parameter in memory
970         flowParam[txField] = txValue ;
971       } else if (  txField ==  TX_FIELD_TANK_CAPACITY) {  // save values for capacity in memory
972         tankCapacity = txValue ;                          // note: values will be saved in eeprom in EEPROM function
973       } else if (  txField ==  TX_FIELD_RESET_FUEL ) {
974         consumedML = 0 ;                                  // reset consumption                                               
975       }
976 #endif
977 #if  defined ( PPM_VIA_SPORT ) &&   ( ( PROTOCOL  == FRSKY_SPORT ) || ( PROTOCOL == FRSKY_SPORT_HUB ) )   
978       if ( txField == TX_FIELD_PPM )  {                   // save the value for ppm 
979           newPpm.value =  ((int32_t) txValue) * 100 / 1024 ;
980           newPpm.available = true ;
981       }   
982 #endif
983     } else {
984       SREG = oReg ;  // restore the status register      
985     }
986 #endif
988 }                  // ************** end of readSensors ********************************************
991 //#define ALTITUDE_AVAILABLE_BIT 1
992 //#define VSPEED_AVAILABLE_BIT 2 
993 // ********************************* Calculate all fields that could be sent
994 void calculateAllFields () {
996 // compensated Vpeed based on MS4525
997 #if defined(VARIO) &&  defined ( AIRSPEED_IS_USED) 
998     if ( newVarioAvailable ) calculateDte() ; 
999 #endif 
1001 // average Vpeed
1002 #if defined (VARIO) &&  defined (VARIO2)
1003   if( (newVarioAvailable ) || ( newVarioAvailable2 ) ) {
1004     averageVSpeedFloat = ( oXs_MS5611.varioData.climbRateFloat + oXs_MS5611_2.varioData.climbRateFloat ) / 2 ;
1005     if ( abs((int32_t)  averageVSpeedFloat - averageVSpeed.value) > VARIOHYSTERESIS ) {
1006           averageVSpeed.value = (int32_t)  averageVSpeedFloat ;    // update only when difference is greater than hysteresis
1007     }    
1008     averageVSpeed.available = true ;
1009   }  
1010 #endif  
1012 // calculate vSpeedImu & vSpeedImuAvailable 
1013 #if defined (VARIO) && defined (USE_6050)
1014         if (newImuAvailable) { // newImuAvailable says that a new world_linear_acceleration is available (flag has been returned by read6050()
1015           newImuAvailable = false ;   // reset the flag saying a new world_linear_acceleration is available
1016   #ifdef DEBUG_KALMAN
1017             unsigned long beginKalman = micros();
1018   #endif  
1019             if ( countAltitudeToKalman != 0) {                                   // this calculate the initial altitude
1020                 if( oXs_MS5611.varioData.rawAltitude != 0) {
1021                   countAltitudeToKalman-- ;
1022                   altitudeOffsetToKalman = oXs_MS5611.varioData.rawAltitude ;
1023                 }        
1024             }
1025             altitudeToKalman = (oXs_MS5611.varioData.rawAltitude - altitudeOffsetToKalman ) / 100 ; // convert from * 100cm to cm
1026             kalman.Update((float) altitudeToKalman  , world_linear_acceleration_z ,  &zTrack, &vTrack);  // Altitude and acceleration are in cm
1027             vSpeedImu.value = vTrack ;
1028             vSpeedImu.available = true ;
1029             switchVTrackAvailable = true ;
1031   //#define FILL_TEST_3_WITH_EXPECTED_ALT    // force a calculation of an expected altitude x seconds in the future
1032   #ifdef FILL_TEST_3_WITH_EXPECTED_ALT
1033             #define EXPECTED_AT_SEC 0.2        // number of sec used for the projection; can have decimals; NB: expected alt = Alt at time 0 + Vspeed at time 0 * seconds  + 0.5 * Accz at time 0 * seconds * seconds
1034             test3.value = ( zTrack - oXs_MS5611.varioData.altOffset ) + ( vTrack *  EXPECTED_AT_SEC ) + ( 0.5 *  world_linear_acceleration_z * EXPECTED_AT_SEC * EXPECTED_AT_SEC ) ;
1035             test3.available = true ; 
1036   #endif
1038   //#define FILL_TEST_1_2_3_WITH_LINEAR_ACC
1039   #ifdef FILL_TEST_1_2_3_WITH_LINEAR_ACC                                                  
1040             test1.value = linear_acceleration_x * 981 ; 
1041             test1.available = true ; 
1042             test2.value =  linear_acceleration_y * 981; 
1043             test2.available = true ; 
1044             test3.value = linear_acceleration_z * 981; 
1045             test3.available = true ; 
1046   #endif
1048   #ifdef DEBUG_KALMAN_TIME
1049 ///           Serial.print(F("delay Kal ")) ; Serial.print( millis() - beginKalman ) ;Serial.print(F(", "));
1050 //            Serial.print( (int) world_linear_acceleration_z ) ; Serial.print(F(", "));Serial.print( (int) altitudeToKalman) ; Serial.print(F(", ")); Serial.print(oXs_MS5611.varioData.climbRate) ; Serial.print(F(", "));Serial.println(( int )vSpeedImu.value) ;
1051 ///           Serial.print( millis() ) ; Serial.print(F(", ")); Serial.print( (int)  ) ; Serial.print(F(", "));Serial.print( (int) world_linear_acceleration_z ) ; Serial.print(F(", "));Serial.print( (int) altitudeToKalman) ; Serial.print(F(", ")); Serial.print(oXs_MS5611.varioData.climbRate) ; Serial.print(F(", "));Serial.println(( int )vSpeedImu.value) ;
1052               Serial.print("delayK ") ; Serial.print( delayKalman[0] ) ; Serial.print(" ") ; Serial.print( delayKalman[1] ) ;
1053               Serial.print(" ") ; Serial.print( delayKalman[2] ) ; Serial.print(" ") ; Serial.print( delayKalman[3] ) ;Serial.print(" ") ; Serial.println( delayKalman[4] ) ;
1054 #endif  
1055         } // end of newimuAvailable 
1056 #endif
1059 // calculate selected Vspeed based on ppm
1060 #if defined (VARIO) && ( defined (VARIO2) || defined (AIRSPEED_IS_USED) || defined (USE_6050 ) ) && defined (VARIO_SECONDARY ) && defined( VARIO_PRIMARY )  && defined (PPM_IS_USED)
1061   if (( selectedVario == FIRST_BARO ) && ( newVarioAvailable ) )  {
1062       switchVSpeed.value = oXs_MS5611.varioData.climbRate.value ;
1063       switchVSpeed.available = true ;
1064   } 
1065   #if  defined (VARIO2)
1066   else if ( ( selectedVario == SECOND_BARO ) && ( newVarioAvailable2 )) {
1067       switchVSpeed.value = oXs_MS5611_2.varioData.climbRate.value ;
1068       switchVSpeed.available = true ;
1069   }
1070   else if ( ( selectedVario == AVERAGE_FIRST_SECOND ) && ( averageVSpeed.available == true )) {
1071       switchVSpeed.value = averageVSpeed.value ;
1072       switchVSpeed.available = true ;
1073   }
1074   #endif // end of VARIO2
1075   #ifdef AIRSPEED_IS_USED
1076   else if ( ( selectedVario == AIRSPEED_COMPENSATED ) && ( newVarioAvailable )) {
1077     switchVSpeed.value = compensatedClimbRate.value ;
1078     switchVSpeed.available = true ;  
1079   #if defined (SWITCH_VARIO_GET_PRIO)
1080     switchCompensatedClimbRateAvailable = true ; // avoid to reset the value on false in order to continue to send the same value as often as possible
1081   #else
1082     switchCompensatedClimbRateAvailable = false ; // this is the normal process in order to avoid sending twice the same data.
1083   #endif  // end  defined (SWITCH_VARIO_GET_PRIO)   
1084   } 
1085   #endif // end  defined (AIRSPEED) || (defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined (ADS_MEASURE) && defined (ADS_AIRSPEED_BASED_ON) )
1086   #if  defined (USE_6050)
1087   else if ( ( selectedVario == BARO_AND_IMU ) && ( switchVTrackAvailable )) {
1088       switchVSpeed.value = vSpeedImu.value ;
1089       switchVSpeed.available = true ;
1090   }
1091   #endif  // end USE_6050
1092 #endif // end #if defined (VARIO) && ( defined (VARIO2) || defined (AIRSPEED_IS_USED) || defined (USE_6050 ) ) && defined (VARIO_SECONDARY ) && defined( VARIO_PRIMARY )  && defined (PPM_IS_USED)  
1094 // mainVSpeed (calculated based on the setup in config)
1095 #if defined(VARIO) &&  ( (!defined(VSPEED_SOURCE)) || (defined(VSPEED_SOURCE) && (VSPEED_SOURCE == FIRST_BARO) ) )
1096     mainVspeed.value = oXs_MS5611.varioData.climbRate.value ;
1097     mainVspeed.available = oXs_MS5611.varioData.climbRate.available ;
1098 #elif defined(VARIO) && defined(VARIO2) && (VSPEED_SOURCE == SECOND_BARO)
1099     mainVspeed.value = oXs_MS5611_2.varioData.climbRate.value ;
1100     mainVspeed.available = oXs_MS5611_2.varioData.climbRate.available ;
1101 #elif defined(VARIO) && defined(VARIO2) && (VSPEED_SOURCE == AVERAGE_FIRST_SECOND)
1102     mainVspeed.value = averageVSpeed.value ;
1103         mainVspeed.available = averageVSpeed.available ;
1104 #elif defined(VARIO) && defined(AIRSPEED_IS_USED) && (VSPEED_SOURCE == AIRSPEED_COMPENSATED)
1105     mainVspeed.value = compensatedClimbRate.value ;
1106     mainVspeed.available = compensatedClimbRate.available ;
1107 #elif defined(VARIO) && defined(USE_6050) && (VSPEED_SOURCE == BARO_AND_IMU)
1108     mainVspeed.value = vSpeedImu.value ;
1109     mainVspeed.available = vSpeedImu.available ;
1110 #elif defined(VARIO) && ( defined (VARIO2) || defined (AIRSPEED_IS_USED) || defined (USE_6050) ) && defined (VARIO_SECONDARY ) && defined( VARIO_PRIMARY )  && defined (PPM_IS_USED)  && (VSPEED_SOURCE == PPM_SELECTION)
1111     mainVspeed.value = switchVSpeed.value   ;
1112     mainVspeed.available = switchVSpeed.available   ;
1113 #if defined (DEBUG_SELECTED_VARIO)
1114 static uint32_t next_debug_vspeeds_millis ;
1115 static boolean next_debug_vspeeds_flag = true ;
1116   if (millis() > next_debug_vspeeds_millis) {
1117     if (next_debug_vspeeds_flag) {
1118       Serial.println("vspeeds= first, compensated, switched , main");
1119       next_debug_vspeeds_flag = false ;
1120     } else {
1121       Serial.print("vspeeds= ");Serial.print(oXs_MS5611.varioData.climbRate.value); Serial.print(",");Serial.print(compensatedClimbRate.value); 
1122       Serial.print(",");Serial.print(switchVSpeed.value); Serial.print(",");Serial.print(mainVspeed.value); Serial.println(" ");
1123       next_debug_vspeeds_millis = millis() + 500 ;
1124     }
1125   }
1126 #endif //  end DEBUG_SELECTED_VARIO
1127     
1128 #endif // end mainVSpeed (calculated based on the setup in config)
1131 // calculate glider ratio and average vertical speed (based on first vario)
1132 #if defined  (VARIO) && defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC) && GLIDER_RATIO_CALCULATED_AFTER_X_SEC >= 1
1133         calculateAverages();
1134 #endif        
1136 // fill test1 and test2 with Vspeed and relative Alt
1137 //#define FILL_TEST_1_2_WITH_VSPEED_AND_ALT_FROM_SECOND_VARIO
1138 #if defined (VARIO) && ( defined (VARIO2) ) && defined(FILL_TEST_1_2_WITH_VSPEED_AND_ALT_FROM_SECOND_VARIO)
1139     test1.value = oXs_MS5611_2.varioData.climbRate.value ;
1140     test1.available = oXs_MS5611_2.varioData.climbRate.available ;
1141     test2.value = oXs_MS5611_2.varioData.relativeAlt.value ;
1142     test2.available = oXs_MS5611_2.varioData.relativeAlt.available ;
1143 #endif
1145 //  fill test1 and test2 with DTE and PPM_COMPENSATION
1146 //#define FILL_TEST_1_WITH_DTE
1147 //#define FILL_TEST_2_WITH_PPM_AIRSPEED_COMPENSATION
1148 #if defined(VARIO) && defined(AIRSPEED_IS_USED) 
1149 #ifdef FILL_TEST_1_WITH_DTE
1150   test1.value = compensatedClimbRate.value ;
1151   test1.available = compensatedClimbRate.available ; 
1152 #endif
1153 #if  defined(FILL_TEST_2_WITH_PPM_AIRSPEED_COMPENSATION) && defined(PPM_IS_USED)
1154   static uint32_t lastPpmCompensationMillis ;
1155   uint32_t PpmCompensationMillis = millis() ;
1156   if ( ( PpmCompensationMillis - lastPpmCompensationMillis ) > 200 ) {
1157     test2.value =  compensationPpmMapped ; 
1158     test2.available = true ;
1159     lastPpmCompensationMillis = PpmCompensationMillis ;
1160   }
1161 #endif
1162 #endif 
1164 #if defined (VARIO) &&  defined (USE_6050)
1165 //#define FILL_TEST_1_WITH_YAWRATE
1166 #ifdef FILL_TEST_1_WITH_YAWRATE
1167 static int32_t  previousYaw ;
1168 static uint32_t previousYawRateMillis ;
1169  uint32_t currentMillis ;
1170         currentMillis = millis() ;
1171       if (currentMillis >= previousYawRateMillis + 200 ) {
1172         test1.value = (yaw.value - previousYaw) * 1000 / (int32_t) (currentMillis - previousYawRateMillis )  ; // calculate yaw rate in degree / sec
1173         test1.available = true ;
1174 //#define DEBUGYAWRATE
1175 #ifdef DEBUGYAWRATE
1176         //Serial.print(lastImuInterruptMillis) ;  Serial.print(" ") ; Serial.print( previousYawRateMillis ) ;Serial.print(" ") ; Serial.print( yaw.value ) ; Serial.print(" ") ; Serial.print( test1.value ) ; Serial.print(" ") ; Serial.println(oXs_MS5611.varioData.absoluteAlt.value) ;
1177          Serial.print( currentMillis ) ;Serial.print(" ") ; Serial.print( yaw.value ) ; Serial.print(" ") ; Serial.print( test1.value ) ; Serial.print(" ") ; Serial.println(oXs_MS5611.varioData.absoluteAlt.value) ;
1178 #endif
1180         previousYaw = yaw.value ;
1181         previousYawRateMillis = currentMillis ;
1182      
1183       }      
1184 //    test1.value = oXs_MS5611.varioData.climbRate.value ;
1185 //    test1.available = oXs_MS5611.varioData.climbRate.available ;
1186 //    test2.value = vSpeedImu.value ;
1187 //    test2.available = vSpeedImu.available ;
1188 #endif
1189 #endif
1191 //#define DEBUG_CHANGE_IN_TEST12
1192 #if defined( DEBUG_CHANGE_IN_TEST12 )
1193       static uint32_t millisLastChangeTest ;
1194       if (millis() > millisLastChangeTest ) {
1195         millisLastChangeTest += 100 ;
1196         test1.value += 1 ;
1197         test1.available = true ;
1198         test2.value += 1 ;
1199         test2.available = true ;
1200       }  
1201 #endif
1203 //#define FILL_TEST1_WITH_HEADING_FROM_MAGNETOMETER
1204 #if defined ( USE_HMC5883 )  && defined (USE_6050) && defined (FILL_TEST1_WITH_HEADING_FROM_MAGNETOMETER)
1205       if ( newMagHeading ) {
1206         newMagHeading = false ;
1207         test1.value = magHeading ;
1208         test1.available = true ; 
1209       }
1210 #endif
1214 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)&& defined (FILL_TEST_1_2_3_WITH_FLOW_SENSOR_CONSUMPTION)
1215   if( newFlowAvailable ) {
1216     test1.value = actualFlow.value ; 
1217     test2.value = remainingFuelML.value ; 
1218     test3.value = fuelPercent.value ; 
1219     test1.available = test2.available = test3.available = true ;
1220     newFlowAvailable = false ;
1221   }  
1222 #endif
1225 #if defined ( A_GPS_IS_CONNECTED ) && ( A_GPS_IS_CONNECTED == YES ) 
1226   #if defined ( FILL_TEST1_WITH_GPS_NUMBER_OF_SAT )
1227   test1.value = GPS_numSat ;
1228   if ( GPS_fix ) {
1229     test1.value += 100 ;
1230   }
1231   test1.available = true ;
1232   #endif
1233   #if defined ( FILL_TEST2_WITH_GPS_HDOP )
1234   test2.value = GPS_hdop ; 
1235   test2.available = true ;
1236   #endif
1237 #endif
1239 //  test1.value = oXs_MS5611.varioData.absoluteAlt.value/10 ;
1240 //  test1.available = true ;
1242 //#if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1243 //if ( currentData.consumedMilliAmps.available) {
1244 // test1.value = currentData.consumedMilliAmps.value ;
1245 // test1.available =  true ;
1246 // currentData.consumedMilliAmps.available = false ;
1247 //} 
1248 //#endif
1250 //#if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(ADS_CURRENT_BASED_ON)
1251 //if ( oXs_ads1115.adsCurrentData.MilliAmps.available) {
1252 // test2.value = oXs_ads1115.adsCurrentData.MilliAmps.value ;
1253 // test2.available =  true ;
1254 // oXs_ads1115.adsCurrentData.MilliAmps.available = false ;
1255 //} 
1256 //if ( oXs_ads1115.adsCurrentData.consumedMilliAmps.available) {
1257 // test3.value = oXs_ads1115.adsCurrentData.consumedMilliAmps.value ;
1258 // test3.available =  true ;
1259 // oXs_ads1115.adsCurrentData.consumedMilliAmps.available = false ;
1260 //} 
1261 //#endif
1263 //#if ( defined(AIRSPEED) && (defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined (ADS_MEASURE) && defined (ADS_AIRSPEED_BASED_ON) )
1264 //      if ( oXs_ads1115.adsAirSpeedData.airSpeed.available == true ) {
1265 //     test1.value = oXs_ads1115.adsAirSpeedData.airSpeed.value ;
1266 //       test1.available = true ;
1267 //       oXs_ads1115.adsAirSpeedData.airSpeed.available = false ;
1268 //      }
1269 //#endif
1271 //  if ( oXs_MS5611.varioData.climbRate.available ) {
1272 //    test1.value = oXs_MS5611.varioData.temperature ;
1273 //    test1.available = true ;
1274 //  }  
1275 } // end of calculate all fields
1279 //***************** checkFreeTime ********* if there is at least 2000 usec before the next MS5611 read (in order to avoid delaying it 
1280 bool checkFreeTime() { // return true if there is no vario or if the vario sensor must not be read within a short time.
1281                        // return false if a vario must be read within a short time   
1282 #if defined (VARIO) || defined (VARIO2)
1283 //        extendedMicros = micros() ;
1284   #ifdef VARIO
1285         return ( micros() - oXs_MS5611.varioData.lastCommandMicros < 7000 ) ;   // Do not change PWM if there is less than 2000 usec before MS5611 ADC is available =  (9000 - 2000)
1286   #else // only VARIO2
1287         return ( micros() - oXs_MS5611_2.varioData.lastCommandMicros < 7000 ) ;   // Do not change PWM if there is less than 2000 usec before MS5611 ADC is available =  (9000 - 2000)
1288   #endif // enf of at least one vario
1289 #else // No vario at all
1290   return true ;
1291 #endif  
1292 }  // ******************************* end of checkFreeTime *****************************
1294 // ********************************** Calculate dTE based on rawAltitude and differential pressure
1295 #if defined (VARIO) && defined ( AIRSPEED_IS_USED) 
1296 #define SMOOTHING_DTE_MIN SENSITIVITY_MIN
1297 #define SMOOTHING_DTE_MAX SENSITIVITY_MAX
1298 #define SMOOTHING_DTE_MIN_AT SENSITIVITY_MIN_AT
1299 #define SMOOTHING_DTE_MAX_AT SENSITIVITY_MAX_AT
1301 void calculateDte () {  // is calculated about every 2O ms each time that an altitude is available
1302   static float rawTotalEnergy ;
1303   static float abs_deltaCompensatedClimbRate ;
1304   static float smoothingDteMin =  SMOOTHING_DTE_MIN ;
1305   static float expoSmoothDte_auto ;
1306   static float smoothCompensatedClimbRate ;
1307   static float rawCompensation ;
1308   static float totalEnergyLowPass ;
1309   static float totalEnergyHighPass ;
1311           // for 4525:
1312                //  difPressure (in PSI) = difPressureAdc * 0.0001525972 because 1 PSI = (8192 - 1638) = 6554 steps
1313                //  difPressure (Pa) =  difPressure (in PSI) * 6894.757f  = difPressureAdc * 6894.757 *  0.0001525972 = difPressureAdc * 1.0520
1314                // airspeed = sqr(2 * differential_pressure / air_density) ; air density = pressure  pa / (287.05 * (Temp celcius + 273.15))
1315                // so airspeed m/sec =sqr( 2 * 287.05 * differential_pressure pa * (temperature Celsius + 273.15) / pressure pa )
1316                // total energy = (m * g * altitude) + (m * airspeed * airspeed / 2) => m * 9.81 * (altitude + airspeed * airspeed / 2 /9.81)
1317                // compensation (m/sec) = airspeed * airspeed / 2 / 9.81 =
1318                //                      = 2 * 287.05 * difPressureAdc * 1.0520  * (temperature Celsius + 273.15) / pressure pa /2 /9.81 (m/sec) = 30.78252803 * difPressureAdc * Temp(kelv) / Press (Pa)
1319                // compensation (cm/sec) =  3078.252803 * difPressureAdc * Temp(kelv) / Press (Pa)
1320           // for 7002
1321               // difPressure (Pa) = difPressureAdc * 0.061035156 because 2 kpa = 32768 steps ; so 1 step = 2000 / 32768 = 0.061035156
1322               // compensation (m/sec) = airspeed * airspeed / 2 / 9.81 =
1323               //                      = 2 * 287.05 * difPressureAdc * 0.061035156  * (temperature Celsius + 273.15) / pressure pa /2 /9.81 (m/sec) = 1.785947149 * difPressureAdc * Temp(kelv) / Press (Pa)
1324               // compensation (cm/sec) = 178.5947149 * difPressureAdc * Temp(kelv) / Press (Pa) 
1325           // for SDP3X
1326               // difPressure is already in Pa
1327               // airspeed (m/sec) = sqr( 2 * 287.05 * differential_pressure pa * (temperature Celsius + 273.15) / pressure pa )
1328               // compensation (m/sec) = airspeed * airspeed / 2 / 9.81 =
1329               //                      = 2 * 287.05 * difPressureAdc * (temperature Celsius + 273.15) / pressure pa /2 /9.81 (m/sec) = 
1330               //                      = 29,26095821* difPressureAdc * Temp(kelv) / Press (Pa)
1331               // compensation (cm/sec) = 2926,09 * difPressureAdc * Temp(kelv) / Press (Pa) 
1332           
1333 //#define DEBUG_DTE
1334 #if defined( DEBUG_DTE ) && defined(AIRSPEED_7002) // when 7002 is used
1335     static bool firstDteData = true ;
1336     if ( firstDteData ) {
1337             Serial.println(F("at , difPressADC_0 , cnt , rawAlt , rawComp , rawEnerg ")) ;
1338           firstDteData = false ;
1339     } 
1340     Serial.print( millis() ); Serial.print(F(" , "));
1341     Serial.print( ads_sumDifPressureAdc_0 ); Serial.print(F(" , "));
1342     Serial.print( ads_cntDifPressureAdc_0); Serial.print(F(" , "));
1343 #endif
1345 #if defined ( AIRSPEED_4525) // when 4525 is used
1346   rawCompensation = 3078.25 * oXs_4525.airSpeedData.difPressureAdc_zero * oXs_4525.airSpeedData.temperature4525  /  actualPressure    ; // 3078.25 = comp = 2 * 287.05 / 2 / 9.81 * 1.0520 * 100 * Temp / Pressure  
1347 #elif defined ( AIRSPEED_7002) // when 7002 is used
1348   if ( ads_cntDifPressureAdc_0 > 0 ) {
1349       ads_sumDifPressureAdc_0 = ads_sumDifPressureAdc_0 / ads_cntDifPressureAdc_0 ; // we use the average of airspeed pressure when possible and we keep the average as first value for next loop
1350       ads_cntDifPressureAdc_0 = 1 ;  // so cnt is reset to 1 and not to 0
1351       rawCompensation = 178.5947149 * ads_sumDifPressureAdc_0 * ( 293 )   /  actualPressure    ; //  293 could be replaced by the temperature from mS5611  
1352   }
1353 #elif defined( AIRSPEED_SDP3X) // when SDP3X is used
1354   rawCompensation = 2926.09 * oXs_sdp3x.airSpeedData.difPressureAdc_zero * oXs_sdp3x.airSpeedData.temperature4525  /  actualPressure ;
1355 #endif   
1356   rawTotalEnergy = (oXs_MS5611.varioData.rawAltitude * 0.01) + rawCompensation * compensationPpmMapped * 0.0115; // 0.01 means 100% compensation but we add 15% because it seems that it is 15% undercompensated. 
1357   if (totalEnergyLowPass == 0) { 
1358     totalEnergyLowPass = totalEnergyHighPass = rawTotalEnergy ; 
1359   }
1360 #if defined  ( DEBUG_DTE ) && defined(AIRSPEED_7002) 
1361     Serial.print( oXs_MS5611.varioData.rawAltitude * 0.01 ); Serial.print(F(" , ")); 
1362     Serial.print( rawCompensation ); Serial.print(F(" , ")); 
1363     Serial.print( rawTotalEnergy ); Serial.print(F(" , "));
1364     Serial.println(" ") ;                      
1365 #endif
1367 //  test1.value = rawCompensation; 
1368 //  test1.available = true ; 
1369   
1370   //test2.value = rawTotalEnergy; 
1371   //test2.available = true ; 
1372   
1373   totalEnergyLowPass += 0.085 * ( rawTotalEnergy - totalEnergyLowPass) ;
1374   totalEnergyHighPass += 0.1 * ( rawTotalEnergy - totalEnergyHighPass) ;
1375   rawCompensatedClimbRate = ((totalEnergyHighPass - totalEnergyLowPass )  * 566667.0 ) /     oXs_MS5611.varioData.delaySmooth; // 0.566667 is the parameter to be used for 0.085 and 0.1 filtering if delay is in sec
1377 //  test3.value = rawCompensatedClimbRate ; 
1378 //  test3.available = true ; 
1379   abs_deltaCompensatedClimbRate =  abs(rawCompensatedClimbRate - smoothCompensatedClimbRate) ;
1380   if ( sensitivityPpmMapped  > 0) smoothingDteMin =   sensitivityPpmMapped  ; // a value of sensitivityPpmMapped = 50 becomes a smoothing factor 0.1
1381     if ( (abs_deltaCompensatedClimbRate <= SMOOTHING_DTE_MIN_AT) || (smoothingDteMin >= SMOOTHING_DTE_MAX ) ){
1382      expoSmoothDte_auto = smoothingDteMin ;  
1383   } else if (abs_deltaCompensatedClimbRate >= SMOOTHING_DTE_MAX_AT)  {
1384      expoSmoothDte_auto = SMOOTHING_DTE_MAX ; 
1385   } else {
1386      expoSmoothDte_auto = smoothingDteMin + ( SMOOTHING_DTE_MAX - smoothingDteMin ) * (abs_deltaCompensatedClimbRate - SMOOTHING_DTE_MIN_AT) / (SMOOTHING_DTE_MAX_AT - SMOOTHING_DTE_MIN_AT) ;
1387   }
1388   smoothCompensatedClimbRate += expoSmoothDte_auto * (  rawCompensatedClimbRate -  smoothCompensatedClimbRate ) * 0.001; 
1389   if ( abs( ((int32_t)  smoothCompensatedClimbRate) - compensatedClimbRate.value) > VARIOHYSTERESIS ) {
1390       compensatedClimbRate.value = smoothCompensatedClimbRate  ;
1391   } 
1392   compensatedClimbRate.available = true ; // allows SPORT protocol to transmit the value every 20 ms
1393   switchCompensatedClimbRateAvailable = true ; ; // inform readsensors() that a switchable vspeed is available
1394 //  oXs_MS5611.varioData.altitudeAt20MsecAvailable = false ; // avoid to handel it each time.
1396 #ifdef DEBUGCOMPENSATEDCLIMBRATE
1397   static bool firstCompensatedClimbRate = true ;
1398   if ( firstCompensatedClimbRate ) {
1399         Serial.println(F("at, altitude, difPressureADC_zero, rawCompensation , rawTotalEnergy , delaySmooth , rawCompensatedClimbRate , compensatedClimbRate ")) ;
1400         firstCompensatedClimbRate = false ;
1401   } else {
1402   Serial.print( micros() ) ;Serial.print(F(" , ")) ;
1403   Serial.print( oXs_MS5611.varioData.rawAltitude ) ;Serial.print(F(" , ")) ;
1404   Serial.print( oXs_4525.airSpeedData.difPressureAdc_zero ) ;Serial.print(F(" , ")) ;
1405   Serial.print( rawCompensation ) ;Serial.print(F(" , ")) ;
1406   Serial.print( rawTotalEnergy ) ;Serial.print(F(" , ")) ;
1407   Serial.print( oXs_MS5611.varioData.delaySmooth ) ;Serial.print(F(" , ")) ;
1408   Serial.print( rawCompensatedClimbRate ) ;Serial.print(F(" , ")) ;
1409   Serial.print( compensatedClimbRate.value) ;
1410   Serial.println(F(" ")) ; 
1411   } 
1412 #endif    
1413    
1414 } // end calculateDte  
1415 #endif //#if defined (VARIO) &&  defined ( AIRSPEED_IS_USED)     
1416 // ***************************** end calculate Dte ***********************************************
1419 //****************************** Calculate averages and glider ratio ********************************************
1420 #if defined (VARIO) && defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC ) && (GLIDER_RATIO_CALCULATED_AFTER_X_SEC >= 1 )  && defined ( PPM_IS_USED ) && defined (GLIDER_RATIO_ON_AT_PPM )
1421 void calculateAverages( ){
1422         static int32_t altitudeAtT0 ; // in cm
1423         static int32_t distanceSinceT0 ; // in cm
1424 //        static int32_t averageVspeedSinceT0 ; //in cm/sec
1425         static int16_t aSpeedAtT0 ;
1426 //        static uint16_t secFromT0 ;  // in 1/10 sec
1427         static uint32_t millisAtT0 ;
1428         static unsigned long prevAverageAltMillis  ; // wait 5 sec before calculating those data ; // save when AverageAltitude has to be calculated
1429         int32_t altitudeDifference ;
1430         unsigned long currentGliderMillis ;
1431         bool aSpeedWithinTolerance = true ;
1432         static boolean previousGliderRatioPpmOn = false ;   
1433         currentGliderMillis = millis() ;
1434         if (  prevAverageAltMillis == 0 ) { 
1435           prevAverageAltMillis =  currentGliderMillis + 5000  ; 
1436           millisAtT0 = currentGliderMillis ;
1437         }
1438         if ( (uint16_t) (currentGliderMillis - prevAverageAltMillis) >   500 ) { // check on tolerance has to be done
1439              if ( ( gliderRatioPpmOn) && (previousGliderRatioPpmOn) ) {
1440               altitudeDifference = oXs_MS5611.varioData.absoluteAlt.value -altitudeAtT0  ; // in cm
1441               secFromT0.value =  ( currentGliderMillis - millisAtT0 ) / 100 ;            // in 1/10 of sec
1442               averageVspeedSinceT0.value = altitudeDifference * 10 / secFromT0.value  ;      // * 10 because secFromT0 is in 1/10 of sec
1443 #ifdef AIRSPEED_4525
1444                 distanceSinceT0 += oXs_4525.airSpeedData.smoothAirSpeed / (1000 /  500) ;  // to adapt if delay is different.
1445 #endif                
1446                 if (  secFromT0.value >=  GLIDER_RATIO_CALCULATED_AFTER_X_SEC * 10 ) {         // *10 because secFromT0 is in 1/10 of sec 
1447 #ifdef AIRSPEED_4525
1448                     gliderRatio.value = distanceSinceT0  * -10 / altitudeDifference  ;        // when gliderRatio is > (50.0 *10) it it not realistic (*10 is done in order to add a decimal)
1449                     if ( gliderRatio.value > 500) gliderRatio.value = 0 ;                                                   // 
1450 #endif                    
1451                     averageVspeedSinceT0.value = altitudeDifference * 10 / secFromT0.value  ;      // * 10 because secFromT0 is in 1/10 of sec
1452                 }
1453               
1454             } else {
1455               altitudeAtT0 = oXs_MS5611.varioData.absoluteAlt.value   ;
1456               millisAtT0 = currentGliderMillis ;
1457               secFromT0.value = 0 ;
1458               averageVspeedSinceT0.value = 0 ; 
1459 #ifdef AIRSPEED_4525
1460                 distanceSinceT0 = 0 ;
1461                 gliderRatio.value = 0 ;
1462 #endif                
1463             }  
1465             prevAverageAltMillis = currentGliderMillis  ; 
1466             gliderRatio.available = true;
1467             secFromT0.available = true ; 
1468             averageVspeedSinceT0.available = true ;
1469             previousGliderRatioPpmOn = gliderRatioPpmOn ; 
1470         }  // end check on 500 ms
1471 }        // end Calculate averages
1477 #else
1478 #if defined  (VARIO) && defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC) && GLIDER_RATIO_CALCULATED_AFTER_X_SEC >= 1 
1479 #if defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC) && GLIDER_RATIO_CALCULATED_AFTER_X_SEC < 1
1480 #error  when defined, GLIDER_RATIO_CALCULATED_AFTER_X_SEC must be greater or equal to 1 (sec)
1481 #endif
1482 void calculateAverages( ){
1483         static int32_t altitudeAtT0 ; // in cm
1484         static int32_t distanceSinceT0 ; // in cm
1485 //        static int32_t averageVspeedSinceT0 ; //in cm/sec
1486         static int16_t aSpeedAtT0 ;
1487 //        static uint16_t secFromT0 ;  // in 1/10 sec
1488         static uint32_t millisAtT0 ;
1489         static unsigned long prevAverageAltMillis =  millis() + 5000 ; // wait 5 sec before calculating those data ; // save when AverageAltitude has to be calculated
1490         int32_t altitudeDifference ;
1491         unsigned long currentGliderMillis = millis() ;
1492         bool aSpeedWithinTolerance = true ;  
1494         if ( (uint16_t) (currentGliderMillis - prevAverageAltMillis) >   500 ) { // check on tolerance has to be done
1495             altitudeDifference = oXs_MS5611.varioData.absoluteAlt.value -altitudeAtT0  ; // in cm
1496             secFromT0.value =  ( currentGliderMillis - millisAtT0 ) / 100 ;            // in 1/10 of sec
1497 #ifdef DEBUG_GLIDER8RATIO
1498             serial.print((F("secFromT0: ")); serial.println( secFromT0.value ) ;
1499 #endif
1500 #ifdef AIRSPEED_4525
1501             if ( (aSpeedAtT0 > 300) && ( oXs_4525.airSpeedData.smoothAirSpeed > 300 ) ) {
1502                 aSpeedWithinTolerance = ( (abs( oXs_4525.airSpeedData.smoothAirSpeed - aSpeedAtT0) * 100L ) / aSpeedAtT0 ) <= SPEED_TOLERANCE ;
1503             } else {
1504                 aSpeedWithinTolerance = false ;
1505             }
1506 #endif            
1507             if (  ( oXs_MS5611.varioData.climbRate.value <  VSPEED_MIN_TOLERANCE ) || ( oXs_MS5611.varioData.climbRate.value >  VSPEED_MAX_TOLERANCE ) \
1508                 || ( altitudeDifference > -10 ) || ( aSpeedWithinTolerance == false ) ) {    // reset all when out of tolerance
1509                 altitudeAtT0 = oXs_MS5611.varioData.absoluteAlt.value ;
1510 #ifdef AIRSPEED_4525                
1511                 aSpeedAtT0 = oXs_4525.airSpeedData.smoothAirSpeed ;
1512                 distanceSinceT0 = 0 ;
1513 #endif                
1514                 secFromT0.value = 0 ;
1515                 millisAtT0 = currentGliderMillis ;
1516                 averageVspeedSinceT0.value = 0 ;
1517                 gliderRatio.value = 0 ;
1518 #ifdef DEBUG_GLIDER8RATIO
1519             serial.println((F("Reset")); 
1520 #endif
1522             } else {                                                      // within tolerance, calculate glider ratio and average sinking  
1523 #ifdef AIRSPEED_4525
1524                 distanceSinceT0 += oXs_4525.airSpeedData.smoothAirSpeed / (1000 /  500) ;  // to adapt if delay is different.
1525 #endif                
1526                 if (  secFromT0.value >=  GLIDER_RATIO_CALCULATED_AFTER_X_SEC * 10 ) {         // *10 because secFromT0 is in 1/10 of sec 
1527 #ifdef AIRSPEED_4525
1528                     gliderRatio.value = distanceSinceT0  * -10 / altitudeDifference  ;        // when gliderRatio is > (50.0 *10) it it not realistic (*10 is done in order to add a decimal)
1529                     if ( gliderRatio.value > 500) gliderRatio.value = 0 ;                                                   // 
1530 #endif                    
1531                     averageVspeedSinceT0.value = altitudeDifference * 10 / secFromT0.value  ;      // * 10 because secFromT0 is in 1/10 of sec
1532                 }
1533              }
1534             prevAverageAltMillis += 500  ; 
1535             gliderRatio.available = true;
1536             secFromT0.available = true ; 
1537             averageVspeedSinceT0.available = true ; 
1538         }
1539 }        
1540 #endif
1541 #endif // End of #if defined (VARIO) && defined (GLIDER_RATIO_BASED_ON_PPM )
1542 //********end calculate glider ratio************************************************************************************************
1548 #ifdef PIN_PUSHBUTTON   // // ****************** check button
1549 void checkButton() {
1550   static int lastSensorVal=HIGH;
1551   static unsigned int buttonDownMs;
1552   //read the pushbutton value into a variable
1553   int sensorVal = digitalRead(PIN_PUSHBUTTON);
1554   if (sensorVal == HIGH) {
1555     // button not pressed released
1556     digitalWrite(PIN_LED, LOW);
1557   }
1558   else {
1559     //button is currently being pressed down
1560     unsigned int buttonPressDuration=millis()-buttonDownMs;
1562     if( (buttonPressDuration>1000) and (buttonPressDuration<1200) )
1563       digitalWrite(PIN_LED, LOW); // Blink after 1 second
1565     else if( (buttonPressDuration>3000) and (buttonPressDuration<3200) )
1566       digitalWrite(PIN_LED, LOW); // Blink 1 after 3 second
1567     else if( (buttonPressDuration>3300) and (buttonPressDuration<3400) )
1568       digitalWrite(PIN_LED, LOW); // Blink 2 after 3 second
1570     else if( (buttonPressDuration>10000) and (buttonPressDuration<10200) )
1571       digitalWrite(PIN_LED, LOW); // Blink after 10 second
1572     else if( (buttonPressDuration>10300) and (buttonPressDuration<10400) )
1573       digitalWrite(PIN_LED, LOW); // Blink after 10 second
1574     else if( (buttonPressDuration>10500) and (buttonPressDuration<10600) )
1575       digitalWrite(PIN_LED, LOW); // Blink after 10 second
1576     else digitalWrite(PIN_LED, HIGH);
1577   }
1578   if( (lastSensorVal==HIGH) && (sensorVal==LOW))
1579   { // Button has been pressed down
1580     buttonDownMs=millis();
1581   }
1582   if( (lastSensorVal==LOW) && (sensorVal==HIGH))
1583   { // Button has been released
1584     unsigned int buttonPressDuration=millis()-buttonDownMs;
1585     //Serial.print(F("Button Released after ms:"));
1586     //Serial.println(buttonPressDuration);
1587     // Do Something after certain times the button has been pressed for....
1588     if( (buttonPressDuration>=100) and (buttonPressDuration<3000) )
1589       Reset1SecButtonPress();
1590     else if( (buttonPressDuration>=3000) and (buttonPressDuration<8000) )
1591       Reset3SecButtonPress();
1592     //else if( (buttonPressDuration>=5000) and (buttonPressDuration<10000) )
1593     else if( (buttonPressDuration>=10000) and (buttonPressDuration<15000) )
1594       Reset10SecButtonPress();
1595   }
1597   lastSensorVal=sensorVal;
1598 }  // End checkButton 
1600 //ToDo: implement different reset actions on button press
1601 void Reset1SecButtonPress()
1603 #ifdef DEBUG
1604   Serial.println(F(" Reset 0.1-3 sec"));
1605 #endif
1607 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1608   struct CURRENTDATA *cd = &oXs_Current.currentData ;
1609 //  FORCE_INDIRECT(cd) ;
1610 //  cd->maxMilliAmps=cd->milliAmps;
1611 //  cd->minMilliAmps=cd->milliAmps;
1612 #endif
1614 //#ifdef VARIO
1615 //  oXs_MS5611.resetValues() ;
1616 //#endif
1618 //#ifdef VARIO2
1619 //  oXs_MS5611_2.resetValues() ;
1620 //#endif
1624 void Reset3SecButtonPress()
1626 #ifdef DEBUG
1627   Serial.println(F(" Reset 3-5 sec"));
1628 #endif
1629 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1630   oXs_Current.resetValues();
1631 #elif defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined (ADS_MEASURE)  && defined (ADS_CURRENT_BASED_ON)
1632   oXs_ads1115.floatConsumedMilliAmps = 0 ;
1633   oXs_ads1115.adsCurrentData.consumedMilliAmps.value = 0 ;
1634 #endif
1635 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)
1636   consumedML = 0 ;
1637 #endif
1640 void Reset10SecButtonPress()
1642 #ifdef DEBUG
1643   Serial.println(F("Reset 5-10")) ;
1644 #endif
1647 #endif
1651 #if defined (SAVE_TO_EEPROM ) and ( SAVE_TO_EEPROM == YES )
1652 /****************************************/
1653 /* SaveToEEProm => save persistant Data */
1654 /****************************************/
1655 void SaveToEEProm(){
1656   static uint8_t caseWriteEeprom = 0;
1657 #define CASE_MAX_EEPROM 2  // to adapt if thee are more data to save.   
1658 #ifdef DEBUG
1659   Serial.print(F("Saving to EEProm:"));    
1660   Serial.println(caseWriteEeprom);    
1661 #endif
1662   switch (caseWriteEeprom ) {
1663 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1664   case 0 :
1665     EEPROM_writeAnything( 0 , oXs_Current.currentData.consumedMilliAmps);
1666     break ;
1667 #endif
1668 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES) 
1669   case ( 1 ) : 
1670     if ( ((uint16_t) consumedML) != consumedMLEeprom ) {                            // write in EEPROM only if there is a change
1671       consumedMLEeprom = consumedML ;  
1672       EEPROM_writeAnything( 4 , consumedMLEeprom );
1673     }   
1674     break;  
1675   case ( 2 ) : 
1676     if ( tankCapacity != tankCapacityEeprom ) {                            // write in EEPROM only if there is a change
1677       tankCapacityEeprom = tankCapacity ; 
1678       EEPROM_writeAnything( 8 , tankCapacityEeprom ); 
1679     }
1680     for (uint8_t idxWrite = 0 ; idxWrite < 8 ; idxWrite++ ) { 
1681       if ( flowParam[idxWrite] != flowParamEeprom[idxWrite] ) {
1682         flowParamEeprom[idxWrite] = flowParam[idxWrite] ;
1683         EEPROM_writeAnything( 12 + (idxWrite * 4 ) , flowParamEeprom[idxWrite] ); 
1684       }
1685     }
1686     break;  
1687 #endif  // end A_FLOW_SENSOR_IS_CONNECTED
1688   }     // end of switch
1689   caseWriteEeprom++;
1690   if(caseWriteEeprom > CASE_MAX_EEPROM) caseWriteEeprom = 0;
1692 // to do : add values from ads1115 about current consumption; to do also in LoadFromEEprom()
1693   
1694 } // end SaveToEEPom
1696 /******************************************/
1697 /* LoadFromEEProm => load persistant Data */
1698 /******************************************/
1699 void LoadFromEEProm(){
1700   // Load the last saved value
1701 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1702   EEPROM_readAnything( 0 , oXs_Current.currentData.consumedMilliAmps);
1703   #ifdef DEBUG
1704     Serial.println(F("Restored consumed mA"));
1705   #endif  
1706 #endif
1707 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES ) 
1708     EEPROM_readAnything(4, consumedMLEeprom  ) + 4 ;
1709     consumedML = consumedMLEeprom  ; 
1710     EEPROM_readAnything( 8, tankCapacityEeprom  );
1711     tankCapacity = tankCapacityEeprom ;
1712     for (uint8_t idxRead = 0 ; idxRead < 8 ; idxRead++ ) {
1713         EEPROM_readAnything( 12 + ( idxRead * 4) , flowParamEeprom[idxRead] );
1714         flowParam[idxRead] = flowParamEeprom[idxRead] ;
1715     }
1716     checkFlowParam() ;
1717   #ifdef DEBUG  
1718     Serial.print(F("Restored consumed= ")); Serial.print(consumedMLEeprom) ; Serial.print(F("  Tank=")) ; Serial.print(tankCapacityEeprom) ; Serial.print(F(" Param=")) ;
1719     for (uint8_t idxRead = 0 ; idxRead < 8 ; idxRead++ ) {
1720       Serial.print(flowParamEeprom[idxRead]) ; Serial.print(" ") ;  
1721     }
1722    Serial.println(" ");
1723    
1724    Serial.print(F("          consumed= ")); Serial.print(consumedML) ; Serial.print(F("  Tank=")) ; Serial.print(tankCapacity) ; Serial.print(F(" Param=")) ;
1725     for (uint8_t idxRead = 0 ; idxRead < 8 ; idxRead++ ) {
1726       Serial.print(flowParam[idxRead]) ; Serial.print(" ") ;  
1727     }
1728    Serial.println(" ");
1729   #endif  
1730 #endif
1732 #endif //SAVE_TO_EEPROM
1735 /***************************************************************/
1736 /* ProcessPPMSignal => read PPM signal from receiver and       */
1737 /*   use its value to adjust sensitivity and other parameters  */
1738 /***************************************************************/
1739 #if defined ( PPM_IS_USED ) 
1741 void ProcessPPMSignal(){
1742   boolean getNewPpm = false ; // become true if a new ppm value has been acquired  
1743 #if defined( PIN_PPM )  // when ppm is read from a rx channel
1744   ReadPPM(); // set ppmus to 0 if ppm is not available or has not been collected X time, other fill ppmus with the (max) pulse duration in usec 
1745 #ifdef DEBUGFORCEPPM
1746 //for debuging ppm without having a connection to ppm; force ppm to a value
1747   ppmus = ( PPM_MIN_100 + PPM_PLUS_100) / 2 ; // force a ppm equal to 0 (neutral)
1748 #endif // end of DEBUGFORCEPPM 
1749   if (ppmus>0){  // if a value has been defined for ppm (in microseconds)
1750     ppm.value = map( ppmus , PPM_MIN_100, PPM_PLUS_100, -100 , 100 ) ; // map ppm in order to calibrate between -100 and 100
1751     ppm.available = true ;
1752     getNewPpm = true ;
1753   } 
1754 #else   // so when done via SPORT (defined ( PPM_VIA_SPORT ) && ( PROTOCOL  == FRSKY_SPORT ) || (PROTOCOL  == FRSKY_SPORT_HUB) ) )
1755         // newPpm.value and .available are already filled in readSensor() when new values are received
1756       if (newPpm.available ){
1757           ppm.value = newPpm.value ;
1758           ppm.available = true ;
1759           newPpm.available = false ;
1760           getNewPpm = true ;
1761       }
1762 #endif  
1763   if  (getNewPpm ) { 
1764     getNewPpm = false ; // reset the indicator saying there is a new ppm to handle. 
1765 #ifdef DEBUGPPMVALUE
1766        Serial.print(micros()); Serial.print(F(" ppm="));  Serial.println(ppm.value);
1767 #endif
1768 #ifdef SEQUENCE_OUTPUTS
1769     if ( ( ( ppm.value - prevPpm) > 3 ) || (( prevPpm - ppm.value) > 3 )  )  { // handel ppm only if it changes by more than 3 
1770         prevPpm = ppm.value ;
1771         setNewSequence( ) ;
1772     }  
1773 #else // so if Sequence is not used and so PPM is used for Vario sensitivity , vario compensation , airspeed reset , glider ratio and/or vario source selection 
1774     if ( ( ( ppm.value - prevPpm) < 4 ) && ( ( prevPpm - ppm.value) < 4 ) ) {  // test if new value is quite close to previous in order to avoid unstabel handling 
1775     
1776 #if defined ( VARIO_PRIMARY) && defined ( VARIO_SECONDARY)  && defined (VARIO ) && ( defined (VARIO2) ||  defined ( AIRSPEED_IS_USED)  || defined (USE_6050) )  && defined (PPM_IS_USED)
1777         if ( (ppm.value >= (SWITCH_VARIO_MIN_AT_PPM - 4)) && (ppm.value <= (SWITCH_VARIO_MAX_AT_PPM + 4)) ) {
1778           selectedVario = VARIO_PRIMARY ;
1779         } else if ( ( ppm.value <= (4 - SWITCH_VARIO_MIN_AT_PPM)) && (ppm.value >= (- 4 - SWITCH_VARIO_MAX_AT_PPM)) ) {
1780             selectedVario = VARIO_SECONDARY ; 
1781         }  
1782 #ifdef DEBUG_SELECTED_VARIO
1783     Serial.print(F("selected vario="));  Serial.println(selectedVario);
1784 #endif
1785 #endif // endif defined ( VARIO_PRIMARY) && defined ( VARIO_SECONDARY)  && ...
1787 #if defined (VARIO) || defined (VARIO2) 
1788         if ( (abs(ppm.value) >= (SENSITIVITY_MIN_AT_PPM - 4)) && ( abs(ppm.value) <= (SENSITIVITY_MAX_AT_PPM + 4)) ) {
1789             sensitivityPpmMapped =  map( constrain(abs(ppm.value), SENSITIVITY_MIN_AT_PPM , SENSITIVITY_MAX_AT_PPM ), SENSITIVITY_MIN_AT_PPM , SENSITIVITY_MAX_AT_PPM , SENSITIVITY_PPM_MIN , SENSITIVITY_PPM_MAX); // map value and change stepping to 10
1790 #if defined( VARIO) 
1791             oXs_MS5611.varioData.sensitivityPpm = sensitivityPpmMapped ; // adjust sensitivity when abs PPM is within range
1792 #endif
1793 #if defined( VARIO2) 
1794             oXs_MS5611_2.varioData.sensitivityPpm = sensitivityPpmMapped ;
1795 #endif
1796         }
1797 #endif  // end else defined (VARIO) || defined (VARIO2) 
1798         
1800 #if defined ( AIRSPEED_IS_USED)  // adjust compensation
1801         if ( (abs(ppm.value) >= (COMPENSATION_MIN_AT_PPM - 4)) && ( abs(ppm.value) <= (COMPENSATION_MAX_AT_PPM + 4)) ) {
1802             compensationPpmMapped =  map( constrain(abs(ppm.value), COMPENSATION_MIN_AT_PPM , COMPENSATION_MAX_AT_PPM ), COMPENSATION_MIN_AT_PPM , COMPENSATION_MAX_AT_PPM , COMPENSATION_PPM_MIN , COMPENSATION_PPM_MAX); // map value and change stepping to 10
1803             if (compensationPpmMapped == COMPENSATION_PPM_MIN ) compensationPpmMapped = 0 ; // force compensation to 0 when compensation = min
1804         }
1805         if ( ( ppm.value >= (AIRSPEED_RESET_AT_PPM - 4)) && ( ppm.value <= (AIRSPEED_RESET_AT_PPM + 4)) ) {
1806 #if defined (AIRSPEED_4525) // if 4525 is used
1807             oXs_4525.airSpeedData.airspeedReset = true ; // allow a recalculation of offset 4525
1808 #elif defined (AIRSPEED_7002) // when 7002 is used
1809             oXs_ads1115.adsAirSpeedData.airspeedReset = true ; // allow a recalculation of offset mvxp7002 connected to ads1115
1810 #endif   // for SDP3X sensor , there is no need for a reset
1811         }    
1812 #endif  // end AIRSPEED_IS_USED
1814 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)  
1815         if ( ( ppm.value >= (FLOW_SENSOR_RESET_AT_PPM - 4)) && ( ppm.value <= (FLOW_SENSOR_RESET_AT_PPM + 4)) ) {
1816             consumedML = 0 ;     // reset the flow counter
1817         }
1818 #endif
1821 #if defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC ) && defined ( GLIDER_RATIO_ON_AT_PPM )
1822          if ( (ppm.value >= (GLIDER_RATIO_ON_AT_PPM - 4)) && (ppm.value <= (GLIDER_RATIO_ON_AT_PPM + 4)) ) {
1823           gliderRatioPpmOn = true ;
1824         } else {
1825             gliderRatioPpmOn = false ; 
1826         } 
1827 #endif    
1828     
1829     } // end ppm == prePpm
1830     prevPpm = ppm.value ;  
1831 #endif  // end of #ifdef SEQUENCE_OUTPUTS & #else
1832   }  // end if  (ppm.available ) 
1833   
1834 }  // end processPPMSignal
1837 /**********************************************************/
1838 /* ReadPPM => read PPM signal from receiver               */
1839 /*   pre-evaluate its value for validity                  */
1840 /**********************************************************/
1842 #ifdef PPM_INTERRUPT
1843 uint16_t StartTime ;
1844 volatile uint16_t time1 ; // pulsewidth (in millisec)
1845 //volatile uint8_t PulseTime ;          // A byte to avoid 
1846 volatile uint32_t ppmPulseMicros ; // timestamp when falling edges occurs in micros sec
1847 volatile boolean  PulseTimeAvailable = false ;
1849 #if defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES)
1850             uint32_t ppmTimestampPrev ; //Timestamp (micros) of the previous PPM signal (used to check that the delay between 2 pulses is about 18ms)
1851             uint16_t widthPrev ;  // width of the previous PWM pulse ( micros)
1852             uint8_t lqError ;     // count the number of errors (new PWM pulses having the same value as the previous one)
1853             uint8_t lqCount ;     // count total number of PWM pulses (to calculate a %); use to reset the counters after XXX (e.g.50) PWM
1854             uint8_t prevFrameInError ; // boolean ; true when the previous PWM was wrong (used to calculate consecutive errors)
1855             uint8_t lqConsecutiveError ;  // count number of consecutive PWM errors
1856             uint8_t lqConsecutiveErrorMax ; // keep the max of consecutive errors within a sequence
1857 #endif
1858 extern uint16_t lastTimerValue ;
1859 extern uint32_t TotalMicros ;
1862 #if PIN_PPM == 2 // When pin 2 is used, arduino handle INT0 (see datasheet)
1863 ISR(INT0_vect, ISR_NOBLOCK)  // NOBLOCK allows other interrupts to be served when this one is activated 
1864 #else            //// When pin 3 is used, arduino handle INT1
1865 ISR(INT1_vect, ISR_NOBLOCK)
1866 #endif
1868         uint8_t oReg = SREG; // store SREG value 
1869         cli() ;
1870         uint16_t time = TCNT1 ; // Read timer 1
1871   uint16_t lastTimerValueTemp  = lastTimerValue ; // save the value to avoid any change in interrupt (not sure it is required
1872   uint32_t TotalMicrosTemp = TotalMicros ; // save the value to avoid any change in interrupt (not sure it is required
1873         SREG = oReg ; // restore SREG value
1874         if ( EICRA & PPM_INT_EDGE ) // a rising edge occurs
1875         {
1876                 StartTime = time ;              // save the value of the timer
1877                 EICRA &= ~PPM_INT_EDGE ;                                // allow a falling edge to generate next interrupt
1878         }
1879         else                       // a falling edge occurs   
1880         {
1881     uint16_t elapsed = time - lastTimerValueTemp ;
1882 #if F_CPU == 20000000L   // 20MHz clock 
1883    #error Unsupported clock speed
1884 #elif F_CPU == 16000000L  // 16MHz clock                                                  
1885       ppmPulseMicros = TotalMicrosTemp + ( elapsed >> 4 ) ;
1886 #elif F_CPU == 8000000L   // 8MHz clock
1887       ppmPulseMicros = TotalMicrosTemp + ( elapsed >> 3 ) ;
1888 #else
1889     #error Unsupported clock speed
1890 #endif  
1892                 time -= StartTime ;
1893 #if F_CPU == 20000000L   // 20MHz clock 
1894    #error Unsupported clock speed
1895 #elif F_CPU == 16000000L  // 16MHz clock                                                  
1896                 time>>= 4 ;             // delay in usec
1897 #elif F_CPU == 8000000L   // 8MHz clock
1898                 time >>= 3 ;            // delay in usec
1899 #else
1900     #error Unsupported clock speed
1901 #endif
1902                 time1 = time ; 
1903     PulseTimeAvailable = true ;
1904                 EICRA |= PPM_INT_EDGE ;                         //  allow a Rising edge to generate next interrupt
1905         }
1908 void ReadPPM() {    // set ppmus to 0 if ppm is not available or has not been collected X time, other fill ppmus with the (max) pulse duration in usec 
1909          static uint8_t ppmIdx ;
1910          static uint16_t ppmTemp ;
1911          static uint16_t ppmMax ; // highest value of ppmTemp received ; Some ppm measurement are wrong (to low) because there are some interrupt some 
1912          ppmus = 0 ; // reset the pulse width
1914          if ( PulseTimeAvailable ) { // if new pulse is available
1915 #define PPM_COUNT_MAX 5 // select the max of 5 ppm (so once every 100 msec
1916            uint8_t oReg = SREG ; // save Status register
1917            cli() ; 
1918             ppmTemp = time1 ;    // use values from interrupt
1919             uint32_t ppmTimestamp = ppmPulseMicros ; 
1920             PulseTimeAvailable = false ;
1921             SREG = oReg ;  // restore Status register 
1922 #if defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES) 
1923             uint32_t pulseInterval = (ppmTimestamp - ppmTimestampPrev)  ;
1924             if ( (pulseInterval > PULSE_INTERVAL_MIN) && (pulseInterval < PULSE_INTERVAL_MAX ) ) {
1925               if ( abs (( int16_t) (ppmTemp - widthPrev)) <= WIDTH_ERROR_MAX )  {
1926                     lqError++ ;
1927                     if ( prevFrameInError == true) {
1928                       lqConsecutiveError++ ;      // count consecutive errors
1929                       if (lqConsecutiveError > lqConsecutiveErrorMax) {
1930                         lqConsecutiveErrorMax = lqConsecutiveError ;
1931                       }
1932                     }
1933                     
1934                     prevFrameInError = true ;
1935               } else {
1936                 lqConsecutiveError = 0 ; // reset the counter when a valid PWM is received
1937                 prevFrameInError = false ; // reset the flag when we get a valid PWM signal 
1938               }
1939               lqCount++ ;
1940 #if defined ( DEBUG_RF_LINK_QUALITY )
1941               Serial.print("Read ppm at ") ; Serial.print(ppmTimestamp) ;
1942               Serial.print(" Delay= ") ; Serial.print(pulseInterval) ;
1943               Serial.print(" Process at ") ; Serial.print(millis()) ;
1944               Serial.print(" Width= ") ; Serial.print(ppmTemp) ;
1945               Serial.print(" delta=") ; Serial.print( abs (( int16_t) (ppmTemp - widthPrev)) ) ;
1946               Serial.print(" lqC=") ; Serial.print( lqCount ) ;
1947               Serial.print(" lqE=") ; Serial.print( lqError ) ;
1948               Serial.print(" cons=") ; Serial.print( lqConsecutiveError) ;
1949               Serial.print(" Max=") ; Serial.print( lqConsecutiveErrorMax) ;
1950               Serial.print(" %=") ; Serial.println(  (  ( (LQ_COUNT_MAX - (uint16_t) lqError)) *  100 ) / LQ_COUNT_MAX  ) ;
1951 #endif
1952               if ( lqCount >= LQ_COUNT_MAX ) {
1953 #if defined ( FILL_TEST_1_2_WITH_LQ )
1954               test1.value =   (  ( (LQ_COUNT_MAX - (uint16_t) lqError)) *  100 ) / LQ_COUNT_MAX ; 
1955               test1.available = true ; 
1956               test2.value =  lqConsecutiveErrorMax ; 
1957               test2.available = true ;          
1958 #endif // FILL_TEST_1_2_WITH_LQ
1959                 lqCount = 0 ;
1960                 lqError = 0 ;
1961                 lqConsecutiveError = 0 ; 
1962                 lqConsecutiveErrorMax = 0 ;
1963                 // to do : save the values in data that can be transmitted
1964               }
1965             }
1966             ppmTimestampPrev = ppmTimestamp ;
1967             widthPrev = ppmTemp ;
1968 #endif  // defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES)
1970             if ( ppmIdx >= PPM_COUNT_MAX ) {
1971                 ppmus = ppmMax ; // we keep the highest value
1972                 ppmIdx = 0 ;
1973                 ppmMax = ppmTemp ; 
1974             } else {
1975                 ppmIdx++ ;
1976                 if( ppmTemp > ppmMax ) ppmMax = ppmTemp ;  // save the highest value
1977             }  // end test on ppmIdx   
1978         } // end test on PulseTimeAvailable
1979 } //end ReadPPM()
1980 #endif // end #ifdef PPM_INTERRUPT
1982 #endif //PIN_PPM
1985 #if defined ( A_FLOW_SENSOR_IS_CONNECTED )
1986   #if ( A_FLOW_SENSOR_IS_CONNECTED == YES)  // flowMeterCnt is updated by interrupt PCINT0 
1990 float mapFlowCorr( uint8_t idx) {                             // calculate correction factor depending on current flow
1991   uint8_t flowCorrIdx = idx + TX_FIELD_FLOW_CORR_1 ;
1992   return ( flowParam[flowCorrIdx ] + ( currentFlow - flowParam[idx]) / (flowParam[idx + 1] - flowParam[idx]) * (flowParam[flowCorrIdx + 1] - flowParam[flowCorrIdx ] ) ) ;
1994   
1995 void checkFlowParam() {
1996   if ( (tankCapacity % 50) != 0) tankCapacity = ( tankCapacity / 50 ) * 50 ; // set tank capacity in steps of 50 ml
1997   tankCapacity = constrain( tankCapacity , 100 , 3000 ) ;
1998   for (uint8_t i = 0; i < 4 ; i++) {
1999       if ( ( flowParam[i] % 5) != 0 ) flowParam[i] = ( flowParam[i] / 5 ) * 5 ;
2000       flowParam[i] = constrain( flowParam[i] , 30 , 800 + (5 * i)) ;
2001       flowParam[ i+ 4] = constrain( flowParam[i+4] , -100 , +100 ) ;
2002   }
2003   for (uint8_t i= 1 ; i < 4 ; i++) {
2004       if ( flowParam[i] <= flowParam[i - 1] )  flowParam[i] = flowParam[i - 1] + 5 ;
2005   }
2008 void processFlowMeterCnt () {    // get the flowmeter counter once per X seconds, convert it in mili liter and activate the flag saying a new value is available
2009                                  // save the result in eeprom is done in main loop for all data to be saved in EEPROM
2010 #define FLOW_DELAY 2000                                   // calculates once per 2 sec
2011   float flowCorr ;
2012   uint16_t flowMeterCntCopy ;
2013   static uint32_t prevFlowMillis ;
2014   uint32_t currentFlowMillis = millis() ;
2015   if ( ( currentFlowMillis - prevFlowMillis ) > FLOW_DELAY ) {   
2016     prevFlowMillis = currentFlowMillis ;
2017     uint8_t oReg = SREG ; // save status register
2018     cli() ;  // avoid interrupt to ensure that counter is consistent
2019     flowMeterCntCopy = flowMeterCnt ; 
2020     flowMeterCnt = 0 ;
2021     SREG = oReg ; // restore status register
2022     sei() ;  // allow interrupt again
2023 #ifdef DEBUG_SIMULATE_FLOW_SENSOR
2024     flowMeterCntCopy = 100 ;        // force a fix value in order to test without a flow sensor
2025 #endif    
2026 #define CONVERT_TO_ML_PER_MIN  30.0 / ( PULSES_PER_ML * FLOW_DELAY / 1000.0 ) //  30 = 60 /2 : 60 = 60 sec/min, 1000 = msec instead of sec , 2 because counter is increased by all changes (rise and fall)
2027     currentFlow  =  ((float) flowMeterCntCopy) * CONVERT_TO_ML_PER_MIN ;                                          // expected value should be between 15 and 800 ml/min for the conrad flow meter   
2028     if (currentFlow < flowParam[TX_FIELD_FLOW_1] ) {
2029       flowCorr = flowParam[TX_FIELD_FLOW_CORR_1] ;               // flow crrection is supposed to be in %
2030     } else if (currentFlow < flowParam[TX_FIELD_FLOW_2] ) { 
2031       flowCorr = mapFlowCorr(  TX_FIELD_FLOW_1 ) ;
2032     } else if (currentFlow < flowParam[TX_FIELD_FLOW_3] ) { 
2033       flowCorr = mapFlowCorr(  TX_FIELD_FLOW_2 ) ;
2034     } else if (currentFlow < flowParam[TX_FIELD_FLOW_4] ) { 
2035       flowCorr = mapFlowCorr(  TX_FIELD_FLOW_3 ) ;
2036     }  else {
2037       flowCorr = flowParam[TX_FIELD_FLOW_CORR_4] ;
2038     }  
2039     currentFlow = ((float) currentFlow ) * ( 100.0 + flowCorr) * 0.01   ; // 0.01 because flowCorr is in %)  
2040     actualFlow.value = currentFlow ;
2041     actualFlow.available= true ;
2042     consumedML += currentFlow  * FLOW_DELAY / 60000.0 ; 
2043     if ( consumedML > tankCapacity ) consumedML = tankCapacity ;
2044     remainingFuelML.value = tankCapacity - consumedML ;
2045     remainingFuelML.available= true ;
2046     fuelPercent.value =  remainingFuelML.value * 100 / tankCapacity ; // in percent
2047     fuelPercent.available= true ;
2048     newFlowAvailable = true ;   // this is use to fill TEST_1, 2, 3 to avoid conflict with JETI protocol which uses 3 individual flags 
2049 #if defined ( DEBUG) && defined (DEBUG_FLOW_SENSOR)
2050     Serial.print(" At " ); Serial.print( prevFlowMillis ) ;
2051     Serial.print(" flcnt " ); Serial.print( flowMeterCntCopy ) ;
2052     Serial.print(" remain " ); Serial.print( remainingFuelML.value ) ;
2053     Serial.print(" ml/min " ); Serial.print( currentFlow ) ;
2054     Serial.print(" cons " ); Serial.println( consumedML ) ;
2055 #endif
2056   
2057   } 
2058 }      // end processFlowMeterCnt
2061 ISR(PCINT0_vect, )  {       // a pin change interrupt occurs on the pin being connected to the flow sensor; we do not use ISR_NOBLOCK because the interrupt is very short
2062   flowMeterCnt++ ;            // we increase the counter of pin change.
2066   #endif
2067 #endif // end A_FLOW_SENSOR_IS_CONNECTED 
2071 #ifdef SEQUENCE_OUTPUTS
2072 void setNewSequence() {                   // **********  setNewSequence( ) **************  handle a new ppm value
2073 //    int8_t prevPpmMain = -100 ; // this value is unusual; so it will forced a change at first call
2074     int16_t ppmAbs = ppm.value + 114 ;
2075     int8_t ppmMain = ppmAbs / 25 ;
2076     int8_t ppmRest = ppmAbs % 25 ;
2077     if ( (ppmRest > 4) && (ppmMain >= 0) && (ppmMain <= 9) && (ppmMain != prevPpmMain) ) { // process only if valid and different from previous
2078 #ifdef DEBUGSEQUENCE
2079     Serial.println(F(" "));
2080     Serial.print(F("ppmMain="));  Serial.println(ppmMain );  
2081     //Serial.println(F(" "));
2082 #endif
2083        prevPpmMain = ppmMain ;
2084        seqRef = sequencePointer[ppmMain] ;  // seqTab contains pointers to the sequence array
2085        seqMax = sequenceMaxNumber[ppmMain] ; 
2086        seqState = 0 ;
2087        seqStep = 0 ;
2088 #ifdef DEBUGSEQUENCE
2089        test1.value = ppmMain; 
2090        test1.available = true ; 
2091 #endif
2092        checkSequence() ;
2093     }    
2096 void checkSequence() {
2097   uint8_t portbTemp ;
2098   uint8_t portbTempValue ;
2099   static uint16_t seqDelay ;
2100   static unsigned long  currentMillis ;
2101   static unsigned long  nextSequenceMillis ;
2102 #ifdef DEBUGSEQUENCE
2103 //    Serial.print(F("seqState="));  Serial.println(seqState );  
2104 #endif
2106   if ( seqState == 0 ) {
2107     portbTempValue = *(seqRef + 1); 
2108     seqDelay = *(seqRef ) * sequenceUnit; //
2109     portbTemp =  (~sequenceOutputs) & PORTB; // reset the bit that are controlled
2110     PORTB = portbTemp | ( portbTempValue & sequenceOutputs ); // set the bit as defined in the sequence if they have to be controlled
2111 #ifdef DEBUGSEQUENCE
2112     Serial.print(F("seqStep="));  Serial.println( seqStep );
2113     Serial.print(F("portbTempValue="));  Serial.println( portbTempValue );
2114     Serial.print(F("seqDelay="));  Serial.println( seqDelay );
2115     Serial.print(F("portbTemp="));  Serial.println( portbTemp );
2116     Serial.print(F("PORTB="));  Serial.println(  portbTempValue & sequenceOutputs );  
2117 #endif
2118     
2119     if (seqDelay == 0 ) {
2120       seqState = 2 ; // set state to sequence stopped if delay is 0
2121     } else {   
2122       seqState = 1 ; //says that sequence is running
2123       nextSequenceMillis = millis() +  seqDelay ;
2124     }  
2125   } else if ( seqState == 1 ) { // when sequence is running, check the timestamp to activate next sequence step
2126     currentMillis = millis() ;
2127     if ( currentMillis >  nextSequenceMillis  ) {
2128        seqStep += 2 ; // increase by 2 because there are 2 parameters per step
2129       if ( (seqStep + 1)  >=  seqMax  ) seqStep = 0 ; // return to 0 if end is reached
2130       portbTempValue = *(seqRef + 1 + seqStep ); 
2131       seqDelay = *(seqRef + seqStep) * sequenceUnit ;
2132       portbTemp =  (~sequenceOutputs) & PORTB; // reset the bit that are controlled
2133       PORTB = portbTemp | ( portbTempValue & sequenceOutputs ); // set the bit as defined in the sequence if they have to be controlled
2134       if (seqDelay == 0 ) {
2135           seqState = 2 ; // set state to sequence stopped if delay is 0
2136       } else {   
2137           seqState = 1 ; //says that sequence is running
2138           nextSequenceMillis = currentMillis  +  seqDelay ;
2139       }
2140 #ifdef DEBUGSEQUENCE
2141       Serial.print(F("At"));  Serial.print( currentMillis );
2142       Serial.print(F(" seqStep="));  Serial.println( seqStep );
2143       Serial.print(F("portbTempValue="));  Serial.println( portbTempValue );
2144       Serial.print(F("seqDelay="));  Serial.println( seqDelay );
2145       Serial.print(F("portbTemp="));  Serial.println( portbTemp );
2146       Serial.print(F("PORTB="));  Serial.println( portbTempValue & sequenceOutputs );  
2147 #endif
2148      
2149     } // end  ( currentMillis >  nextSequenceMillis  )
2150   }   // end  ( seqState == 0 ) or ( seqState == 1 ) 
2151 }     // end checkSequence() 
2152 #endif // end SEQUENCE_OUTPUTS
2156 #ifdef DEBUG
2157 //************************************************************   OutputToSerial
2158 void OutputToSerial(){
2159 //#define DEBUGMINMAX 0
2160 //#define DEBUGVREF 0
2161 //#define DEBUGDIVIDER 0
2162 //#define DEBUGTEMP 0
2166 #ifdef VARIO
2167   Serial.print(F(" Sensitivity PPM="));    
2168   Serial.print( oXs_MS5611.varioData.sensitivityPpm);
2169   Serial.print(F(" ;absAlt="));  
2170   Serial.print( ( (float)oXs_MS5611.varioData.absoluteAlt.value)/100);
2171   Serial.print(F(" ;Vspd="));    
2172   Serial.print( ( (float)oXs_MS5611.varioData.climbRate.value)/100);
2173   Serial.print(F(" ;Temp="));    
2174   Serial.print((float)oXs_MS5611.varioData.temperature/10);
2175 #endif // VARIO
2177 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
2178   Serial.print(F(" ;mA="));    
2179   Serial.print( ( ((float)(int32_t)(oXs_Current.currentData.milliAmps.value))) );
2180   Serial.print("(");    
2181   Serial.print(F(" ;mAh="));  
2182   Serial.print( oXs_Current.currentData.consumedMilliAmps.value);
2183 #endif // defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
2184 #ifdef HOTT
2185   Serial.println("H.");
2186 #endif  
2187   Serial.println();
2188   
2191 /***********************************************/
2192 /* freeRam => Cook coffee and vaccuum the flat */
2193 /***********************************************/
2194 int freeRam () {
2195   extern int __heap_start, *__brkval; 
2196   int v; 
2197   return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
2199 #endif // End DEBUG