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"
11 #include "oXs_sdp3x.h"
12 #include "oXs_ads1115.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"
24 #include "KalmanFilter.h"
25 #include "oXs_hmc5883.h"
28 #if defined (SAVE_TO_EEPROM ) and ( SAVE_TO_EEPROM == YES )
30 #include "EEPROMAnything.h"
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
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
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
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
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
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
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
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
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
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
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
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
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
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,
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,
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
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
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
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
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
116 #if defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES)
118 #error When MEASURE_RF_LINK_QUALITY = YES , PIN_PPM must be defined (in file oXs_config_advanced.h)
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
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
126 #if defined ( SEQUENCE_OUTPUTS )
127 #error When MEASURE_RF_LINK_QUALITY = YES , SEQUENCE_OUTPUTS may not be defined
129 #endif //defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES)
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
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
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)
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
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
196 // ************ declare some functions being used ***************
200 void Reset1SecButtonPress() ;
201 void Reset3SecButtonPress() ;
202 void Reset10SecButtonPress() ;
203 void SaveToEEProm() ;
204 void LoadFromEEProm() ;
205 void ProcessPPMSignal() ;
206 //unsigned int ReadPPM() ;
208 bool checkFreeTime() ;
209 void setNewSequence() ;
210 void checkSequence() ;
211 void blinkLed( uint8_t blinkType ) ;
212 void checkFlowParam() ;
214 // *********** declare some variables *****************************
216 bool newVarioAvailable ;
217 struct ONE_MEASUREMENT mainVspeed ;
220 bool newVarioAvailable2 ;
223 #if defined (VARIO) && defined ( AIRSPEED_IS_USED)
224 struct ONE_MEASUREMENT compensatedClimbRate ;
225 bool switchCompensatedClimbRateAvailable ;
226 float rawCompensatedClimbRate ;
229 #if defined (VARIO) && ( defined (VARIO2) || defined ( AIRSPEED_IS_USED) || defined (USE_6050) )
230 struct ONE_MEASUREMENT switchVSpeed ;
233 #if defined (VARIO) && defined (VARIO2)
234 struct ONE_MEASUREMENT averageVSpeed ;
235 float averageVSpeedFloat ;
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 ;
247 KalmanFilter kalman ;
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 ;
263 extern float magHeading ;
264 extern boolean newMagHeading;
266 #ifdef DEBUG_KALMAN_TIME
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 ;
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
300 #ifdef SEQUENCE_OUTPUTS
302 uint8_t sequence_m100 [] = { SEQUENCE_m100 } ;
304 uint8_t sequence_m100 [2] = { 0 , 0 } ;
307 uint8_t sequence_m75 [] = { SEQUENCE_m75 } ;
309 uint8_t sequence_m75 [2] = { 0 , 0 } ;
312 uint8_t sequence_m50 [] = { SEQUENCE_m50 } ;
314 uint8_t sequence_m50 [2] = { 0 , 0 } ;
317 uint8_t sequence_m25 [] = { SEQUENCE_m25 } ;
319 uint8_t sequence_m25 [2] = { 0 , 0 } ;
322 uint8_t sequence_0 [] = { SEQUENCE_0 } ;
324 uint8_t sequence_0 [2] = { 0 , 0 } ;
327 uint8_t sequence_25 [] = { SEQUENCE_25 } ;
329 uint8_t sequence_25 [2] = { 0 , 0 } ;
332 uint8_t sequence_50 [] = { SEQUENCE_50 } ;
334 uint8_t sequence_50 [2] = { 0 , 0 } ;
337 uint8_t sequence_75 [] = { SEQUENCE_75 } ;
339 uint8_t sequence_75 [2] = { 0 , 0 } ;
342 uint8_t sequence_100 [] = { SEQUENCE_100 } ;
344 uint8_t sequence_100 [2] = { 0 , 0 } ;
347 uint8_t sequence_low [] = { SEQUENCE_LOW } ;
349 uint8_t sequence_low [2] = { 0 , 0 } ;
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.
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
362 uint16_t sequenceUnit = SEQUENCE_UNIT * 10 ;
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 ;
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 ;
396 uint8_t selectedVario = VARIO_PRIMARY ; // identify the vario to be used when switch vario with PPM is active (1 = first MS5611)
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 ******************************************
406 #ifdef SENSOR_IS_BMP180
408 OXS_BMP180 oXs_MS5611 = OXS_BMP180(Serial);
410 OXS_BMP180 oXs_MS5611 = OXS_BMP180();
412 #elif defined(SENSOR_IS_BMP280 )
414 OXS_BMP280 oXs_MS5611 = OXS_BMP280(Serial);
416 OXS_BMP280 oXs_MS5611 = OXS_BMP280();
418 #else // not a BMP180 or BMP280
420 OXS_MS5611 oXs_MS5611(I2C_MS5611_Add,Serial);
422 OXS_MS5611 oXs_MS5611(I2C_MS5611_Add);
424 #endif // BMP180 or MS5611 sensor
430 OXS_MS5611 oXs_MS5611_2(I2C_MS5611_Add - 1,Serial);
432 OXS_MS5611 oXs_MS5611_2(I2C_MS5611_Add - 1);
436 #ifdef AIRSPEED_4525 // differential pressure
438 OXS_4525 oXs_4525(I2C_4525_Add ,Serial);
440 OXS_4525 oXs_4525(I2C_4525_Add);
444 #ifdef AIRSPEED_SDP3X
446 OXS_SDP3X oXs_sdp3x(I2C_SDP3X_Add ,Serial);
448 OXS_SDP3X oXs_sdp3x(I2C_SDP3X_Add);
452 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
454 OXS_VOLTAGE oXs_Voltage(Serial);
456 OXS_VOLTAGE oXs_Voltage(0);
460 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
462 OXS_CURRENT oXs_Current(PIN_CURRENTSENSOR,Serial);
464 OXS_CURRENT oXs_Current(PIN_CURRENTSENSOR);
470 OXS_GPS oXs_Gps(Serial);
476 #if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE)
478 OXS_ADS1115 oXs_ads1115( I2C_ADS_Add , Serial);
480 OXS_ADS1115 oXs_ads1115( I2C_ADS_Add );
485 //Create a class used for telemetry ;content of class depends on the selected protocol (managed via #ifdef in different files)
487 OXS_OUT oXs_Out(PIN_SERIALTX,Serial);
489 OXS_OUT oXs_Out(PIN_SERIALTX);
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 () *******************************************************
500 // set up the UART speed (38400 if GPS installed else 115200)
502 Serial.begin(38400); // when GPS is used, baudrate is reduced because main loop must have the time to read the received char.
505 #ifndef GPS_INSTALLED
506 Serial.begin(115200L); // when GPS is not used, baudrate can be 115200
508 Serial.println(F("openXsensor starting.."));
509 Serial.print(F(" milli="));
510 Serial.println(millis());
511 Serial.print(F("freeRam="));
512 Serial.println(freeRam());
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);
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);
527 pinMode(PIN_LED, OUTPUT); // The signal LED (used for the function debug loop)
530 #ifdef PIN_PUSHBUTTON
531 pinMode(PIN_PUSHBUTTON, INPUT_PULLUP);
534 pinMode(PIN_LED, OUTPUT); // The signal LED (used for the function push button)
536 // sensitivityPpmMapped = 0 ;
537 compensationPpmMapped = 100 ;
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;
555 Serial.println(F("vario setting up.."));
560 Serial.println(F("vario is up.."));
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
572 oXs_MS5611_2.setup();
573 oXs_Out.varioData_2=&oXs_MS5611_2.varioData;
578 oXs_Out.airSpeedData=&oXs_4525.airSpeedData;
579 #endif // end AIRSPEED
581 #ifdef AIRSPEED_SDP3X
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;
591 #if defined (VARIO) && defined ( AIRSPEED_IS_USED)
592 compensatedClimbRate.available = false;
593 // compensatedClimbRate = 0;
606 #if defined( USE_HMC5883 ) && defined (USE_6050)
607 setup_hmc5883() ; // set up magnetometer
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;
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;
620 #if defined (SAVE_TO_EEPROM ) and ( SAVE_TO_EEPROM == YES )
627 ppm.available = false ;
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
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
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] ;
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(" , "));
681 Serial.println(F(" "));
683 seqState = 2 ; // declare that sequence is stopped
684 PORTB &= ~sequenceOutputs ; // set all output to LOW
685 DDRB |= sequenceOutputs ; // set pin to output mode
687 //#ifdef DEBUGSEQUENCE
688 ppm.value = -100 ; // fix the sequence to be used by default (e.g. when no PPM signal is present);
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
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);
703 Serial.println(F("End of general set up"));
706 } // ******************** end of Setup *****************************************************
709 //*******************************************************************************************
711 //*******************************************************************************************
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());
748 #ifdef DEBUG_BLINK_MAINLOOP
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
764 #ifdef DEBUG_CALCULATE_FIELDS
765 Serial.print("call calculateAllFields at") ; Serial.println(millis()) ;
767 // Calculate all fields
768 calculateAllFields();
770 #ifdef DEBUG_CALCULATE_FIELDS
771 Serial.print("end of call calculateAllFields at") ; Serial.println(millis()) ;
774 // prepare the telemetry data to be sent (nb: data are prepared but not sent)
775 if ( millis() > 1500 ) oXs_Out.sendData();
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();
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() ;
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
807 Serial.println(F("Start sequence low voltage"));
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
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
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
819 Serial.println(F("End sequence low voltage"));
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();
835 #if defined( A_LOCATOR_IS_CONNECTED ) and ( A_LOCATOR_IS_CONNECTED == YES)
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 ;
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
859 #ifdef DEBUG_ENTER_READSENSORS
860 Serial.print( "read baro 1 at ") ; Serial.println(millis());
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 ;
874 #ifdef DEBUG_ENTER_READSENSORS
875 Serial.print( "read baro 2 at ") ; Serial.println(millis());
878 newVarioAvailable2 = oXs_MS5611_2.readSensor(); // Read pressure & temperature on MS5611, calculate Altitude and vertical speed
882 oXs_4525.readSensor(); // Read again the sensor in order to reduce response time/noise
885 #ifdef AIRSPEED_SDP3X
886 oXs_sdp3x.readSensor(); //read the SDP3X sensor
890 newImuAvailable = read6050() ;
893 #if defined( USE_HMC5883 ) && defined (USE_6050)
897 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
898 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.
899 #endif // end voltage
901 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
902 oXs_Current.readSensor() ; // Do not perform calculation if there is less than 2000 usec before MS5611 ADC is available = (9000 - 2000)/2
903 #endif // End defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
906 #ifdef DEBUG_ENTER_READSENSORS
907 Serial.print( "read gps at ") ; Serial.println(millis());
910 oXs_Gps.readGps() ; // Do not perform calculation if there is less than 2000 usec before MS5611 ADC is available = (9000 - 2000)/2
911 #endif // End GPS_INSTALLED
913 #if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE)
914 if( oXs_ads1115.readSensor() ) { // return true when a new average is available; it means that the new value has to be stored/processed.
916 #endif // End ADS_MEASURE
920 if (millis() > ( lastRpmMillis + 200) ){ // allow transmission of RPM only once every 200 msec
921 if (RpmSet == true) { // rpm is set
926 sport_rpm.value = RpmValue ;
927 sport_rpm.available = true ;
928 lastRpmMillis = millis() ;
930 Serial.print( "RPM ") ; Serial.println(sport_rpm.value);
935 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)
936 processFlowMeterCnt () ;
940 #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
941 uint8_t oReg = SREG ; // save status register
943 if ( TxDataIdx == 8 ) {
944 TxDataIdx++ ; // Increase the number of data in order to avoid to read twice
945 uint16_t txField = ( TxData[2] << 8 ) + TxData[1] ; // id of the field being received
946 uint32_t txValue = ( ( ( ( (TxData[6] << 8) + TxData[5] ) << 8 ) + TxData[4] ) << 8 ) + TxData[3] ; // value of the field being received
947 SREG = oReg ; // restore the status register
948 #ifdef DEBUG_READ_SPORT
949 Serial.print("At: ") ; Serial.print(millis()) ;
950 Serial.print(" "); Serial.print(TxData[0], HEX);
951 Serial.print(" "); Serial.print(TxData[1], HEX);
952 Serial.print(" "); Serial.print(TxData[2], HEX);
953 Serial.print(" "); Serial.print(TxData[3], HEX);
954 Serial.print(" "); Serial.print(TxData[4], HEX);
955 Serial.print(" "); Serial.print(TxData[5], HEX);
956 Serial.print(" "); Serial.print(TxData[6], HEX);
957 Serial.print(" "); Serial.print(TxData[7], HEX);
960 #if ( defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES) )
961 if ( txField <= TX_FIELD_FLOW_CORR_4) { // save values for flow meter parameter in memory
962 flowParam[txField] = txValue ;
963 } else if ( txField == TX_FIELD_TANK_CAPACITY) { // save values for capacity in memory
964 tankCapacity = txValue ; // note: values will be saved in eeprom in EEPROM function
965 } else if ( txField == TX_FIELD_RESET_FUEL ) {
966 consumedML = 0 ; // reset consumption
969 #if defined ( PPM_VIA_SPORT ) && ( ( PROTOCOL == FRSKY_SPORT ) || ( PROTOCOL == FRSKY_SPORT_HUB ) )
970 if ( txField == TX_FIELD_PPM ) { // save the value for ppm
971 newPpm.value = ((int32_t) txValue) * 100 / 1024 ;
972 newPpm.available = true ;
976 SREG = oReg ; // restore the status register
980 } // ************** end of readSensors ********************************************
983 //#define ALTITUDE_AVAILABLE_BIT 1
984 //#define VSPEED_AVAILABLE_BIT 2
985 // ********************************* Calculate all fields that could be sent
986 void calculateAllFields () {
988 // compensated Vpeed based on MS4525
989 #if defined(VARIO) && defined ( AIRSPEED_IS_USED)
990 if ( newVarioAvailable ) calculateDte() ;
994 #if defined (VARIO) && defined (VARIO2)
995 if( (newVarioAvailable ) || ( newVarioAvailable2 ) ) {
996 averageVSpeedFloat = ( oXs_MS5611.varioData.climbRateFloat + oXs_MS5611_2.varioData.climbRateFloat ) / 2 ;
997 if ( abs((int32_t) averageVSpeedFloat - averageVSpeed.value) > VARIOHYSTERESIS ) {
998 averageVSpeed.value = (int32_t) averageVSpeedFloat ; // update only when difference is greater than hysteresis
1000 averageVSpeed.available = true ;
1004 // calculate vSpeedImu & vSpeedImuAvailable
1005 #if defined (VARIO) && defined (USE_6050)
1006 if (newImuAvailable) { // newImuAvailable says that a new world_linear_acceleration is available (flag has been returned by read6050()
1007 newImuAvailable = false ; // reset the flag saying a new world_linear_acceleration is available
1009 unsigned long beginKalman = micros();
1011 if ( countAltitudeToKalman != 0) { // this calculate the initial altitude
1012 if( oXs_MS5611.varioData.rawAltitude != 0) {
1013 countAltitudeToKalman-- ;
1014 altitudeOffsetToKalman = oXs_MS5611.varioData.rawAltitude ;
1017 altitudeToKalman = (oXs_MS5611.varioData.rawAltitude - altitudeOffsetToKalman ) / 100 ; // convert from * 100cm to cm
1018 kalman.Update((float) altitudeToKalman , world_linear_acceleration_z , &zTrack, &vTrack); // Altitude and acceleration are in cm
1019 vSpeedImu.value = vTrack ;
1020 vSpeedImu.available = true ;
1021 switchVTrackAvailable = true ;
1023 //#define FILL_TEST_3_WITH_EXPECTED_ALT // force a calculation of an expected altitude x seconds in the future
1024 #ifdef FILL_TEST_3_WITH_EXPECTED_ALT
1025 #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
1026 test3.value = ( zTrack - oXs_MS5611.varioData.altOffset ) + ( vTrack * EXPECTED_AT_SEC ) + ( 0.5 * world_linear_acceleration_z * EXPECTED_AT_SEC * EXPECTED_AT_SEC ) ;
1027 test3.available = true ;
1030 //#define FILL_TEST_1_2_3_WITH_LINEAR_ACC
1031 #ifdef FILL_TEST_1_2_3_WITH_LINEAR_ACC
1032 test1.value = linear_acceleration_x * 981 ;
1033 test1.available = true ;
1034 test2.value = linear_acceleration_y * 981;
1035 test2.available = true ;
1036 test3.value = linear_acceleration_z * 981;
1037 test3.available = true ;
1040 #ifdef DEBUG_KALMAN_TIME
1041 /// Serial.print(F("delay Kal ")) ; Serial.print( millis() - beginKalman ) ;Serial.print(F(", "));
1042 // 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) ;
1043 /// 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) ;
1044 Serial.print("delayK ") ; Serial.print( delayKalman[0] ) ; Serial.print(" ") ; Serial.print( delayKalman[1] ) ;
1045 Serial.print(" ") ; Serial.print( delayKalman[2] ) ; Serial.print(" ") ; Serial.print( delayKalman[3] ) ;Serial.print(" ") ; Serial.println( delayKalman[4] ) ;
1047 } // end of newimuAvailable
1051 // calculate selected Vspeed based on ppm
1052 #if defined (VARIO) && ( defined (VARIO2) || defined (AIRSPEED_IS_USED) || defined (USE_6050 ) ) && defined (VARIO_SECONDARY ) && defined( VARIO_PRIMARY ) && defined (PPM_IS_USED)
1053 if (( selectedVario == FIRST_BARO ) && ( newVarioAvailable ) ) {
1054 switchVSpeed.value = oXs_MS5611.varioData.climbRate.value ;
1055 switchVSpeed.available = true ;
1057 #if defined (VARIO2)
1058 else if ( ( selectedVario == SECOND_BARO ) && ( newVarioAvailable2 )) {
1059 switchVSpeed.value = oXs_MS5611_2.varioData.climbRate.value ;
1060 switchVSpeed.available = true ;
1062 else if ( ( selectedVario == AVERAGE_FIRST_SECOND ) && ( averageVSpeed.available == true )) {
1063 switchVSpeed.value = averageVSpeed.value ;
1064 switchVSpeed.available = true ;
1066 #endif // end of VARIO2
1067 #ifdef AIRSPEED_IS_USED
1068 else if ( ( selectedVario == AIRSPEED_COMPENSATED ) && ( newVarioAvailable )) {
1069 switchVSpeed.value = compensatedClimbRate.value ;
1070 switchVSpeed.available = true ;
1071 #if defined (SWITCH_VARIO_GET_PRIO)
1072 switchCompensatedClimbRateAvailable = true ; // avoid to reset the value on false in order to continue to send the same value as often as possible
1074 switchCompensatedClimbRateAvailable = false ; // this is the normal process in order to avoid sending twice the same data.
1075 #endif // end defined (SWITCH_VARIO_GET_PRIO)
1077 #endif // end defined (AIRSPEED) || (defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined (ADS_MEASURE) && defined (ADS_AIRSPEED_BASED_ON) )
1078 #if defined (USE_6050)
1079 else if ( ( selectedVario == BARO_AND_IMU ) && ( switchVTrackAvailable )) {
1080 switchVSpeed.value = vSpeedImu.value ;
1081 switchVSpeed.available = true ;
1083 #endif // end USE_6050
1084 #endif // end #if defined (VARIO) && ( defined (VARIO2) || defined (AIRSPEED_IS_USED) || defined (USE_6050 ) ) && defined (VARIO_SECONDARY ) && defined( VARIO_PRIMARY ) && defined (PPM_IS_USED)
1086 // mainVSpeed (calculated based on the setup in config)
1087 #if defined(VARIO) && ( (!defined(VSPEED_SOURCE)) || (defined(VSPEED_SOURCE) && (VSPEED_SOURCE == FIRST_BARO) ) )
1088 mainVspeed.value = oXs_MS5611.varioData.climbRate.value ;
1089 mainVspeed.available = oXs_MS5611.varioData.climbRate.available ;
1090 #elif defined(VARIO) && defined(VARIO2) && (VSPEED_SOURCE == SECOND_BARO)
1091 mainVspeed.value = oXs_MS5611_2.varioData.climbRate.value ;
1092 mainVspeed.available = oXs_MS5611_2.varioData.climbRate.available ;
1093 #elif defined(VARIO) && defined(VARIO2) && (VSPEED_SOURCE == AVERAGE_FIRST_SECOND)
1094 mainVspeed.value = averageVSpeed.value ;
1095 mainVspeed.available = averageVSpeed.available ;
1096 #elif defined(VARIO) && defined(AIRSPEED_IS_USED) && (VSPEED_SOURCE == AIRSPEED_COMPENSATED)
1097 mainVspeed.value = compensatedClimbRate.value ;
1098 mainVspeed.available = compensatedClimbRate.available ;
1099 #elif defined(VARIO) && defined(USE_6050) && (VSPEED_SOURCE == BARO_AND_IMU)
1100 mainVspeed.value = vSpeedImu.value ;
1101 mainVspeed.available = vSpeedImu.available ;
1102 #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)
1103 mainVspeed.value = switchVSpeed.value ;
1104 mainVspeed.available = switchVSpeed.available ;
1105 #if defined (DEBUG_SELECTED_VARIO)
1106 static uint32_t next_debug_vspeeds_millis ;
1107 static boolean next_debug_vspeeds_flag = true ;
1108 if (millis() > next_debug_vspeeds_millis) {
1109 if (next_debug_vspeeds_flag) {
1110 Serial.println("vspeeds= first, compensated, switched , main");
1111 next_debug_vspeeds_flag = false ;
1113 Serial.print("vspeeds= ");Serial.print(oXs_MS5611.varioData.climbRate.value); Serial.print(",");Serial.print(compensatedClimbRate.value);
1114 Serial.print(",");Serial.print(switchVSpeed.value); Serial.print(",");Serial.print(mainVspeed.value); Serial.println(" ");
1115 next_debug_vspeeds_millis = millis() + 500 ;
1118 #endif // end DEBUG_SELECTED_VARIO
1120 #endif // end mainVSpeed (calculated based on the setup in config)
1123 // calculate glider ratio and average vertical speed (based on first vario)
1124 #if defined (VARIO) && defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC) && GLIDER_RATIO_CALCULATED_AFTER_X_SEC >= 1
1125 calculateAverages();
1128 // fill test1 and test2 with Vspeed and relative Alt
1129 //#define FILL_TEST_1_2_WITH_VSPEED_AND_ALT_FROM_SECOND_VARIO
1130 #if defined (VARIO) && ( defined (VARIO2) ) && defined(FILL_TEST_1_2_WITH_VSPEED_AND_ALT_FROM_SECOND_VARIO)
1131 test1.value = oXs_MS5611_2.varioData.climbRate.value ;
1132 test1.available = oXs_MS5611_2.varioData.climbRate.available ;
1133 test2.value = oXs_MS5611_2.varioData.relativeAlt.value ;
1134 test2.available = oXs_MS5611_2.varioData.relativeAlt.available ;
1137 // fill test1 and test2 with DTE and PPM_COMPENSATION
1138 //#define FILL_TEST_1_WITH_DTE
1139 //#define FILL_TEST_2_WITH_PPM_AIRSPEED_COMPENSATION
1140 #if defined(VARIO) && defined(AIRSPEED_IS_USED)
1141 #ifdef FILL_TEST_1_WITH_DTE
1142 test1.value = compensatedClimbRate.value ;
1143 test1.available = compensatedClimbRate.available ;
1145 #if defined(FILL_TEST_2_WITH_PPM_AIRSPEED_COMPENSATION) && defined(PPM_IS_USED)
1146 static uint32_t lastPpmCompensationMillis ;
1147 uint32_t PpmCompensationMillis = millis() ;
1148 if ( ( PpmCompensationMillis - lastPpmCompensationMillis ) > 200 ) {
1149 test2.value = compensationPpmMapped ;
1150 test2.available = true ;
1151 lastPpmCompensationMillis = PpmCompensationMillis ;
1156 #if defined (VARIO) && defined (USE_6050)
1157 //#define FILL_TEST_1_WITH_YAWRATE
1158 #ifdef FILL_TEST_1_WITH_YAWRATE
1159 static int32_t previousYaw ;
1160 static uint32_t previousYawRateMillis ;
1161 uint32_t currentMillis ;
1162 currentMillis = millis() ;
1163 if (currentMillis >= previousYawRateMillis + 200 ) {
1164 test1.value = (yaw.value - previousYaw) * 1000 / (int32_t) (currentMillis - previousYawRateMillis ) ; // calculate yaw rate in degree / sec
1165 test1.available = true ;
1166 //#define DEBUGYAWRATE
1168 //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) ;
1169 Serial.print( currentMillis ) ;Serial.print(" ") ; Serial.print( yaw.value ) ; Serial.print(" ") ; Serial.print( test1.value ) ; Serial.print(" ") ; Serial.println(oXs_MS5611.varioData.absoluteAlt.value) ;
1172 previousYaw = yaw.value ;
1173 previousYawRateMillis = currentMillis ;
1176 // test1.value = oXs_MS5611.varioData.climbRate.value ;
1177 // test1.available = oXs_MS5611.varioData.climbRate.available ;
1178 // test2.value = vSpeedImu.value ;
1179 // test2.available = vSpeedImu.available ;
1183 //#define DEBUG_CHANGE_IN_TEST12
1184 #if defined( DEBUG_CHANGE_IN_TEST12 )
1185 static uint32_t millisLastChangeTest ;
1186 if (millis() > millisLastChangeTest ) {
1187 millisLastChangeTest += 100 ;
1189 test1.available = true ;
1191 test2.available = true ;
1195 //#define FILL_TEST1_WITH_HEADING_FROM_MAGNETOMETER
1196 #if defined ( USE_HMC5883 ) && defined (USE_6050) && defined (FILL_TEST1_WITH_HEADING_FROM_MAGNETOMETER)
1197 if ( newMagHeading ) {
1198 newMagHeading = false ;
1199 test1.value = magHeading ;
1200 test1.available = true ;
1206 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)&& defined (FILL_TEST_1_2_3_WITH_FLOW_SENSOR_CONSUMPTION)
1207 if( newFlowAvailable ) {
1208 test1.value = actualFlow.value ;
1209 test2.value = remainingFuelML.value ;
1210 test3.value = fuelPercent.value ;
1211 test1.available = test2.available = test3.available = true ;
1212 newFlowAvailable = false ;
1217 #if defined ( A_GPS_IS_CONNECTED ) && ( A_GPS_IS_CONNECTED == YES )
1218 #if defined ( FILL_TEST1_WITH_GPS_NUMBER_OF_SAT )
1219 test1.value = GPS_numSat ;
1221 test1.value += 100 ;
1223 test1.available = true ;
1225 #if defined ( FILL_TEST2_WITH_GPS_HDOP )
1226 test2.value = GPS_hdop ;
1227 test2.available = true ;
1231 // test1.value = oXs_MS5611.varioData.absoluteAlt.value/10 ;
1232 // test1.available = true ;
1234 //#if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1235 //if ( currentData.consumedMilliAmps.available) {
1236 // test1.value = currentData.consumedMilliAmps.value ;
1237 // test1.available = true ;
1238 // currentData.consumedMilliAmps.available = false ;
1242 //#if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(ADS_CURRENT_BASED_ON)
1243 //if ( oXs_ads1115.adsCurrentData.MilliAmps.available) {
1244 // test2.value = oXs_ads1115.adsCurrentData.MilliAmps.value ;
1245 // test2.available = true ;
1246 // oXs_ads1115.adsCurrentData.MilliAmps.available = false ;
1248 //if ( oXs_ads1115.adsCurrentData.consumedMilliAmps.available) {
1249 // test3.value = oXs_ads1115.adsCurrentData.consumedMilliAmps.value ;
1250 // test3.available = true ;
1251 // oXs_ads1115.adsCurrentData.consumedMilliAmps.available = false ;
1255 //#if ( defined(AIRSPEED) && (defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined (ADS_MEASURE) && defined (ADS_AIRSPEED_BASED_ON) )
1256 // if ( oXs_ads1115.adsAirSpeedData.airSpeed.available == true ) {
1257 // test1.value = oXs_ads1115.adsAirSpeedData.airSpeed.value ;
1258 // test1.available = true ;
1259 // oXs_ads1115.adsAirSpeedData.airSpeed.available = false ;
1263 // if ( oXs_MS5611.varioData.climbRate.available ) {
1264 // test1.value = oXs_MS5611.varioData.temperature ;
1265 // test1.available = true ;
1267 } // end of calculate all fields
1271 //***************** checkFreeTime ********* if there is at least 2000 usec before the next MS5611 read (in order to avoid delaying it
1272 bool checkFreeTime() { // return true if there is no vario or if the vario sensor must not be read within a short time.
1273 // return false if a vario must be read within a short time
1274 #if defined (VARIO) || defined (VARIO2)
1275 // extendedMicros = micros() ;
1277 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)
1278 #else // only VARIO2
1279 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)
1280 #endif // enf of at least one vario
1281 #else // No vario at all
1284 } // ******************************* end of checkFreeTime *****************************
1286 // ********************************** Calculate dTE based on rawAltitude and differential pressure
1287 #if defined (VARIO) && defined ( AIRSPEED_IS_USED)
1288 #define SMOOTHING_DTE_MIN SENSITIVITY_MIN
1289 #define SMOOTHING_DTE_MAX SENSITIVITY_MAX
1290 #define SMOOTHING_DTE_MIN_AT SENSITIVITY_MIN_AT
1291 #define SMOOTHING_DTE_MAX_AT SENSITIVITY_MAX_AT
1293 void calculateDte () { // is calculated about every 2O ms each time that an altitude is available
1294 static float rawTotalEnergy ;
1295 static float abs_deltaCompensatedClimbRate ;
1296 static float smoothingDteMin = SMOOTHING_DTE_MIN ;
1297 static float expoSmoothDte_auto ;
1298 static float smoothCompensatedClimbRate ;
1299 static float rawCompensation ;
1300 static float totalEnergyLowPass ;
1301 static float totalEnergyHighPass ;
1304 // difPressure (in PSI) = difPressureAdc * 0.0001525972 because 1 PSI = (8192 - 1638) = 6554 steps
1305 // difPressure (Pa) = difPressure (in PSI) * 6894.757f = difPressureAdc * 6894.757 * 0.0001525972 = difPressureAdc * 1.0520
1306 // airspeed = sqr(2 * differential_pressure / air_density) ; air density = pressure pa / (287.05 * (Temp celcius + 273.15))
1307 // so airspeed m/sec =sqr( 2 * 287.05 * differential_pressure pa * (temperature Celsius + 273.15) / pressure pa )
1308 // total energy = (m * g * altitude) + (m * airspeed * airspeed / 2) => m * 9.81 * (altitude + airspeed * airspeed / 2 /9.81)
1309 // compensation (m/sec) = airspeed * airspeed / 2 / 9.81 =
1310 // = 2 * 287.05 * difPressureAdc * 1.0520 * (temperature Celsius + 273.15) / pressure pa /2 /9.81 (m/sec) = 30.78252803 * difPressureAdc * Temp(kelv) / Press (Pa)
1311 // compensation (cm/sec) = 3078.252803 * difPressureAdc * Temp(kelv) / Press (Pa)
1313 // difPressure (Pa) = difPressureAdc * 0.061035156 because 2 kpa = 32768 steps ; so 1 step = 2000 / 32768 = 0.061035156
1314 // compensation (m/sec) = airspeed * airspeed / 2 / 9.81 =
1315 // = 2 * 287.05 * difPressureAdc * 0.061035156 * (temperature Celsius + 273.15) / pressure pa /2 /9.81 (m/sec) = 1.785947149 * difPressureAdc * Temp(kelv) / Press (Pa)
1316 // compensation (cm/sec) = 178.5947149 * difPressureAdc * Temp(kelv) / Press (Pa)
1318 // difPressure is already in Pa
1319 // airspeed (m/sec) = sqr( 2 * 287.05 * differential_pressure pa * (temperature Celsius + 273.15) / pressure pa )
1320 // compensation (m/sec) = airspeed * airspeed / 2 / 9.81 =
1321 // = 2 * 287.05 * difPressureAdc * (temperature Celsius + 273.15) / pressure pa /2 /9.81 (m/sec) =
1322 // = 29,26095821* difPressureAdc * Temp(kelv) / Press (Pa)
1323 // compensation (cm/sec) = 2926,09 * difPressureAdc * Temp(kelv) / Press (Pa)
1326 #if defined( DEBUG_DTE ) && defined(AIRSPEED_7002) // when 7002 is used
1327 static bool firstDteData = true ;
1328 if ( firstDteData ) {
1329 Serial.println(F("at , difPressADC_0 , cnt , rawAlt , rawComp , rawEnerg ")) ;
1330 firstDteData = false ;
1332 Serial.print( millis() ); Serial.print(F(" , "));
1333 Serial.print( ads_sumDifPressureAdc_0 ); Serial.print(F(" , "));
1334 Serial.print( ads_cntDifPressureAdc_0); Serial.print(F(" , "));
1337 #if defined ( AIRSPEED_4525) // when 4525 is used
1338 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
1339 #elif defined ( AIRSPEED_7002) // when 7002 is used
1340 if ( ads_cntDifPressureAdc_0 > 0 ) {
1341 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
1342 ads_cntDifPressureAdc_0 = 1 ; // so cnt is reset to 1 and not to 0
1343 rawCompensation = 178.5947149 * ads_sumDifPressureAdc_0 * ( 293 ) / actualPressure ; // 293 could be replaced by the temperature from mS5611
1345 #elif defined( AIRSPEED_SDP3X) // when SDP3X is used
1346 rawCompensation = 2926.09 * oXs_sdp3x.airSpeedData.difPressureAdc_zero * oXs_sdp3x.airSpeedData.temperature4525 / actualPressure ;
1348 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.
1349 if (totalEnergyLowPass == 0) {
1350 totalEnergyLowPass = totalEnergyHighPass = rawTotalEnergy ;
1352 #if defined ( DEBUG_DTE ) && defined(AIRSPEED_7002)
1353 Serial.print( oXs_MS5611.varioData.rawAltitude * 0.01 ); Serial.print(F(" , "));
1354 Serial.print( rawCompensation ); Serial.print(F(" , "));
1355 Serial.print( rawTotalEnergy ); Serial.print(F(" , "));
1356 Serial.println(" ") ;
1359 // test1.value = rawCompensation;
1360 // test1.available = true ;
1362 //test2.value = rawTotalEnergy;
1363 //test2.available = true ;
1365 totalEnergyLowPass += 0.085 * ( rawTotalEnergy - totalEnergyLowPass) ;
1366 totalEnergyHighPass += 0.1 * ( rawTotalEnergy - totalEnergyHighPass) ;
1367 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
1369 // test3.value = rawCompensatedClimbRate ;
1370 // test3.available = true ;
1371 abs_deltaCompensatedClimbRate = abs(rawCompensatedClimbRate - smoothCompensatedClimbRate) ;
1372 if ( sensitivityPpmMapped > 0) smoothingDteMin = sensitivityPpmMapped ; // a value of sensitivityPpmMapped = 50 becomes a smoothing factor 0.1
1373 if ( (abs_deltaCompensatedClimbRate <= SMOOTHING_DTE_MIN_AT) || (smoothingDteMin >= SMOOTHING_DTE_MAX ) ){
1374 expoSmoothDte_auto = smoothingDteMin ;
1375 } else if (abs_deltaCompensatedClimbRate >= SMOOTHING_DTE_MAX_AT) {
1376 expoSmoothDte_auto = SMOOTHING_DTE_MAX ;
1378 expoSmoothDte_auto = smoothingDteMin + ( SMOOTHING_DTE_MAX - smoothingDteMin ) * (abs_deltaCompensatedClimbRate - SMOOTHING_DTE_MIN_AT) / (SMOOTHING_DTE_MAX_AT - SMOOTHING_DTE_MIN_AT) ;
1380 smoothCompensatedClimbRate += expoSmoothDte_auto * ( rawCompensatedClimbRate - smoothCompensatedClimbRate ) * 0.001;
1381 if ( abs( ((int32_t) smoothCompensatedClimbRate) - compensatedClimbRate.value) > VARIOHYSTERESIS ) {
1382 compensatedClimbRate.value = smoothCompensatedClimbRate ;
1384 compensatedClimbRate.available = true ; // allows SPORT protocol to transmit the value every 20 ms
1385 switchCompensatedClimbRateAvailable = true ; ; // inform readsensors() that a switchable vspeed is available
1386 // oXs_MS5611.varioData.altitudeAt20MsecAvailable = false ; // avoid to handel it each time.
1388 #ifdef DEBUGCOMPENSATEDCLIMBRATE
1389 static bool firstCompensatedClimbRate = true ;
1390 if ( firstCompensatedClimbRate ) {
1391 Serial.println(F("at, altitude, difPressureADC_zero, rawCompensation , rawTotalEnergy , delaySmooth , rawCompensatedClimbRate , compensatedClimbRate ")) ;
1392 firstCompensatedClimbRate = false ;
1394 Serial.print( micros() ) ;Serial.print(F(" , ")) ;
1395 Serial.print( oXs_MS5611.varioData.rawAltitude ) ;Serial.print(F(" , ")) ;
1396 Serial.print( oXs_4525.airSpeedData.difPressureAdc_zero ) ;Serial.print(F(" , ")) ;
1397 Serial.print( rawCompensation ) ;Serial.print(F(" , ")) ;
1398 Serial.print( rawTotalEnergy ) ;Serial.print(F(" , ")) ;
1399 Serial.print( oXs_MS5611.varioData.delaySmooth ) ;Serial.print(F(" , ")) ;
1400 Serial.print( rawCompensatedClimbRate ) ;Serial.print(F(" , ")) ;
1401 Serial.print( compensatedClimbRate.value) ;
1402 Serial.println(F(" ")) ;
1406 } // end calculateDte
1407 #endif //#if defined (VARIO) && defined ( AIRSPEED_IS_USED)
1408 // ***************************** end calculate Dte ***********************************************
1411 //****************************** Calculate averages and glider ratio ********************************************
1412 #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 )
1413 void calculateAverages( ){
1414 static int32_t altitudeAtT0 ; // in cm
1415 static int32_t distanceSinceT0 ; // in cm
1416 // static int32_t averageVspeedSinceT0 ; //in cm/sec
1417 static int16_t aSpeedAtT0 ;
1418 // static uint16_t secFromT0 ; // in 1/10 sec
1419 static uint32_t millisAtT0 ;
1420 static unsigned long prevAverageAltMillis ; // wait 5 sec before calculating those data ; // save when AverageAltitude has to be calculated
1421 int32_t altitudeDifference ;
1422 unsigned long currentGliderMillis ;
1423 bool aSpeedWithinTolerance = true ;
1424 static boolean previousGliderRatioPpmOn = false ;
1425 currentGliderMillis = millis() ;
1426 if ( prevAverageAltMillis == 0 ) {
1427 prevAverageAltMillis = currentGliderMillis + 5000 ;
1428 millisAtT0 = currentGliderMillis ;
1430 if ( (uint16_t) (currentGliderMillis - prevAverageAltMillis) > 500 ) { // check on tolerance has to be done
1431 if ( ( gliderRatioPpmOn) && (previousGliderRatioPpmOn) ) {
1432 altitudeDifference = oXs_MS5611.varioData.absoluteAlt.value -altitudeAtT0 ; // in cm
1433 secFromT0.value = ( currentGliderMillis - millisAtT0 ) / 100 ; // in 1/10 of sec
1434 averageVspeedSinceT0.value = altitudeDifference * 10 / secFromT0.value ; // * 10 because secFromT0 is in 1/10 of sec
1435 #ifdef AIRSPEED_4525
1436 distanceSinceT0 += oXs_4525.airSpeedData.smoothAirSpeed / (1000 / 500) ; // to adapt if delay is different.
1438 if ( secFromT0.value >= GLIDER_RATIO_CALCULATED_AFTER_X_SEC * 10 ) { // *10 because secFromT0 is in 1/10 of sec
1439 #ifdef AIRSPEED_4525
1440 gliderRatio.value = distanceSinceT0 * -10 / altitudeDifference ; // when gliderRatio is > (50.0 *10) it it not realistic (*10 is done in order to add a decimal)
1441 if ( gliderRatio.value > 500) gliderRatio.value = 0 ; //
1443 averageVspeedSinceT0.value = altitudeDifference * 10 / secFromT0.value ; // * 10 because secFromT0 is in 1/10 of sec
1447 altitudeAtT0 = oXs_MS5611.varioData.absoluteAlt.value ;
1448 millisAtT0 = currentGliderMillis ;
1449 secFromT0.value = 0 ;
1450 averageVspeedSinceT0.value = 0 ;
1451 #ifdef AIRSPEED_4525
1452 distanceSinceT0 = 0 ;
1453 gliderRatio.value = 0 ;
1457 prevAverageAltMillis = currentGliderMillis ;
1458 gliderRatio.available = true;
1459 secFromT0.available = true ;
1460 averageVspeedSinceT0.available = true ;
1461 previousGliderRatioPpmOn = gliderRatioPpmOn ;
1462 } // end check on 500 ms
1463 } // end Calculate averages
1470 #if defined (VARIO) && defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC) && GLIDER_RATIO_CALCULATED_AFTER_X_SEC >= 1
1471 #if defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC) && GLIDER_RATIO_CALCULATED_AFTER_X_SEC < 1
1472 #error when defined, GLIDER_RATIO_CALCULATED_AFTER_X_SEC must be greater or equal to 1 (sec)
1474 void calculateAverages( ){
1475 static int32_t altitudeAtT0 ; // in cm
1476 static int32_t distanceSinceT0 ; // in cm
1477 // static int32_t averageVspeedSinceT0 ; //in cm/sec
1478 static int16_t aSpeedAtT0 ;
1479 // static uint16_t secFromT0 ; // in 1/10 sec
1480 static uint32_t millisAtT0 ;
1481 static unsigned long prevAverageAltMillis = millis() + 5000 ; // wait 5 sec before calculating those data ; // save when AverageAltitude has to be calculated
1482 int32_t altitudeDifference ;
1483 unsigned long currentGliderMillis = millis() ;
1484 bool aSpeedWithinTolerance = true ;
1486 if ( (uint16_t) (currentGliderMillis - prevAverageAltMillis) > 500 ) { // check on tolerance has to be done
1487 altitudeDifference = oXs_MS5611.varioData.absoluteAlt.value -altitudeAtT0 ; // in cm
1488 secFromT0.value = ( currentGliderMillis - millisAtT0 ) / 100 ; // in 1/10 of sec
1489 #ifdef DEBUG_GLIDER8RATIO
1490 serial.print((F("secFromT0: ")); serial.println( secFromT0.value ) ;
1492 #ifdef AIRSPEED_4525
1493 if ( (aSpeedAtT0 > 300) && ( oXs_4525.airSpeedData.smoothAirSpeed > 300 ) ) {
1494 aSpeedWithinTolerance = ( (abs( oXs_4525.airSpeedData.smoothAirSpeed - aSpeedAtT0) * 100L ) / aSpeedAtT0 ) <= SPEED_TOLERANCE ;
1496 aSpeedWithinTolerance = false ;
1499 if ( ( oXs_MS5611.varioData.climbRate.value < VSPEED_MIN_TOLERANCE ) || ( oXs_MS5611.varioData.climbRate.value > VSPEED_MAX_TOLERANCE ) \
1500 || ( altitudeDifference > -10 ) || ( aSpeedWithinTolerance == false ) ) { // reset all when out of tolerance
1501 altitudeAtT0 = oXs_MS5611.varioData.absoluteAlt.value ;
1502 #ifdef AIRSPEED_4525
1503 aSpeedAtT0 = oXs_4525.airSpeedData.smoothAirSpeed ;
1504 distanceSinceT0 = 0 ;
1506 secFromT0.value = 0 ;
1507 millisAtT0 = currentGliderMillis ;
1508 averageVspeedSinceT0.value = 0 ;
1509 gliderRatio.value = 0 ;
1510 #ifdef DEBUG_GLIDER8RATIO
1511 serial.println((F("Reset"));
1514 } else { // within tolerance, calculate glider ratio and average sinking
1515 #ifdef AIRSPEED_4525
1516 distanceSinceT0 += oXs_4525.airSpeedData.smoothAirSpeed / (1000 / 500) ; // to adapt if delay is different.
1518 if ( secFromT0.value >= GLIDER_RATIO_CALCULATED_AFTER_X_SEC * 10 ) { // *10 because secFromT0 is in 1/10 of sec
1519 #ifdef AIRSPEED_4525
1520 gliderRatio.value = distanceSinceT0 * -10 / altitudeDifference ; // when gliderRatio is > (50.0 *10) it it not realistic (*10 is done in order to add a decimal)
1521 if ( gliderRatio.value > 500) gliderRatio.value = 0 ; //
1523 averageVspeedSinceT0.value = altitudeDifference * 10 / secFromT0.value ; // * 10 because secFromT0 is in 1/10 of sec
1526 prevAverageAltMillis += 500 ;
1527 gliderRatio.available = true;
1528 secFromT0.available = true ;
1529 averageVspeedSinceT0.available = true ;
1533 #endif // End of #if defined (VARIO) && defined (GLIDER_RATIO_BASED_ON_PPM )
1534 //********end calculate glider ratio************************************************************************************************
1540 #ifdef PIN_PUSHBUTTON // // ****************** check button
1541 void checkButton() {
1542 static int lastSensorVal=HIGH;
1543 static unsigned int buttonDownMs;
1544 //read the pushbutton value into a variable
1545 int sensorVal = digitalRead(PIN_PUSHBUTTON);
1546 if (sensorVal == HIGH) {
1547 // button not pressed released
1548 digitalWrite(PIN_LED, LOW);
1551 //button is currently being pressed down
1552 unsigned int buttonPressDuration=millis()-buttonDownMs;
1554 if( (buttonPressDuration>1000) and (buttonPressDuration<1200) )
1555 digitalWrite(PIN_LED, LOW); // Blink after 1 second
1557 else if( (buttonPressDuration>3000) and (buttonPressDuration<3200) )
1558 digitalWrite(PIN_LED, LOW); // Blink 1 after 3 second
1559 else if( (buttonPressDuration>3300) and (buttonPressDuration<3400) )
1560 digitalWrite(PIN_LED, LOW); // Blink 2 after 3 second
1562 else if( (buttonPressDuration>10000) and (buttonPressDuration<10200) )
1563 digitalWrite(PIN_LED, LOW); // Blink after 10 second
1564 else if( (buttonPressDuration>10300) and (buttonPressDuration<10400) )
1565 digitalWrite(PIN_LED, LOW); // Blink after 10 second
1566 else if( (buttonPressDuration>10500) and (buttonPressDuration<10600) )
1567 digitalWrite(PIN_LED, LOW); // Blink after 10 second
1568 else digitalWrite(PIN_LED, HIGH);
1570 if( (lastSensorVal==HIGH) && (sensorVal==LOW))
1571 { // Button has been pressed down
1572 buttonDownMs=millis();
1574 if( (lastSensorVal==LOW) && (sensorVal==HIGH))
1575 { // Button has been released
1576 unsigned int buttonPressDuration=millis()-buttonDownMs;
1577 //Serial.print(F("Button Released after ms:"));
1578 //Serial.println(buttonPressDuration);
1579 // Do Something after certain times the button has been pressed for....
1580 if( (buttonPressDuration>=100) and (buttonPressDuration<3000) )
1581 Reset1SecButtonPress();
1582 else if( (buttonPressDuration>=3000) and (buttonPressDuration<8000) )
1583 Reset3SecButtonPress();
1584 //else if( (buttonPressDuration>=5000) and (buttonPressDuration<10000) )
1585 else if( (buttonPressDuration>=10000) and (buttonPressDuration<15000) )
1586 Reset10SecButtonPress();
1589 lastSensorVal=sensorVal;
1590 } // End checkButton
1592 //ToDo: implement different reset actions on button press
1593 void Reset1SecButtonPress()
1596 Serial.println(F(" Reset 0.1-3 sec"));
1599 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1600 struct CURRENTDATA *cd = &oXs_Current.currentData ;
1601 // FORCE_INDIRECT(cd) ;
1602 // cd->maxMilliAmps=cd->milliAmps;
1603 // cd->minMilliAmps=cd->milliAmps;
1607 // oXs_MS5611.resetValues() ;
1611 // oXs_MS5611_2.resetValues() ;
1616 void Reset3SecButtonPress()
1619 Serial.println(F(" Reset 3-5 sec"));
1621 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1622 oXs_Current.resetValues();
1623 #elif defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined (ADS_MEASURE) && defined (ADS_CURRENT_BASED_ON)
1624 oXs_ads1115.floatConsumedMilliAmps = 0 ;
1625 oXs_ads1115.adsCurrentData.consumedMilliAmps.value = 0 ;
1627 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)
1632 void Reset10SecButtonPress()
1635 Serial.println(F("Reset 5-10")) ;
1643 #if defined (SAVE_TO_EEPROM ) and ( SAVE_TO_EEPROM == YES )
1644 /****************************************/
1645 /* SaveToEEProm => save persistant Data */
1646 /****************************************/
1647 void SaveToEEProm(){
1648 static uint8_t caseWriteEeprom = 0;
1649 #define CASE_MAX_EEPROM 2 // to adapt if thee are more data to save.
1651 Serial.print(F("Saving to EEProm:"));
1652 Serial.println(caseWriteEeprom);
1654 switch (caseWriteEeprom ) {
1655 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1657 EEPROM_writeAnything( 0 , oXs_Current.currentData.consumedMilliAmps);
1660 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)
1662 if ( ((uint16_t) consumedML) != consumedMLEeprom ) { // write in EEPROM only if there is a change
1663 consumedMLEeprom = consumedML ;
1664 EEPROM_writeAnything( 4 , consumedMLEeprom );
1668 if ( tankCapacity != tankCapacityEeprom ) { // write in EEPROM only if there is a change
1669 tankCapacityEeprom = tankCapacity ;
1670 EEPROM_writeAnything( 8 , tankCapacityEeprom );
1672 for (uint8_t idxWrite = 0 ; idxWrite < 8 ; idxWrite++ ) {
1673 if ( flowParam[idxWrite] != flowParamEeprom[idxWrite] ) {
1674 flowParamEeprom[idxWrite] = flowParam[idxWrite] ;
1675 EEPROM_writeAnything( 12 + (idxWrite * 4 ) , flowParamEeprom[idxWrite] );
1679 #endif // end A_FLOW_SENSOR_IS_CONNECTED
1682 if(caseWriteEeprom > CASE_MAX_EEPROM) caseWriteEeprom = 0;
1684 // to do : add values from ads1115 about current consumption; to do also in LoadFromEEprom()
1686 } // end SaveToEEPom
1688 /******************************************/
1689 /* LoadFromEEProm => load persistant Data */
1690 /******************************************/
1691 void LoadFromEEProm(){
1692 // Load the last saved value
1693 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1694 EEPROM_readAnything( 0 , oXs_Current.currentData.consumedMilliAmps);
1696 Serial.println(F("Restored consumed mA"));
1699 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES )
1700 EEPROM_readAnything(4, consumedMLEeprom ) + 4 ;
1701 consumedML = consumedMLEeprom ;
1702 EEPROM_readAnything( 8, tankCapacityEeprom );
1703 tankCapacity = tankCapacityEeprom ;
1704 for (uint8_t idxRead = 0 ; idxRead < 8 ; idxRead++ ) {
1705 EEPROM_readAnything( 12 + ( idxRead * 4) , flowParamEeprom[idxRead] );
1706 flowParam[idxRead] = flowParamEeprom[idxRead] ;
1710 Serial.print(F("Restored consumed= ")); Serial.print(consumedMLEeprom) ; Serial.print(F(" Tank=")) ; Serial.print(tankCapacityEeprom) ; Serial.print(F(" Param=")) ;
1711 for (uint8_t idxRead = 0 ; idxRead < 8 ; idxRead++ ) {
1712 Serial.print(flowParamEeprom[idxRead]) ; Serial.print(" ") ;
1714 Serial.println(" ");
1716 Serial.print(F(" consumed= ")); Serial.print(consumedML) ; Serial.print(F(" Tank=")) ; Serial.print(tankCapacity) ; Serial.print(F(" Param=")) ;
1717 for (uint8_t idxRead = 0 ; idxRead < 8 ; idxRead++ ) {
1718 Serial.print(flowParam[idxRead]) ; Serial.print(" ") ;
1720 Serial.println(" ");
1724 #endif //SAVE_TO_EEPROM
1727 /***************************************************************/
1728 /* ProcessPPMSignal => read PPM signal from receiver and */
1729 /* use its value to adjust sensitivity and other parameters */
1730 /***************************************************************/
1731 #if defined ( PPM_IS_USED )
1733 void ProcessPPMSignal(){
1734 boolean getNewPpm = false ; // become true if a new ppm value has been acquired
1735 #if defined( PIN_PPM ) // when ppm is read from a rx channel
1736 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
1737 #ifdef DEBUGFORCEPPM
1738 //for debuging ppm without having a connection to ppm; force ppm to a value
1739 ppmus = ( PPM_MIN_100 + PPM_PLUS_100) / 2 ; // force a ppm equal to 0 (neutral)
1740 #endif // end of DEBUGFORCEPPM
1741 if (ppmus>0){ // if a value has been defined for ppm (in microseconds)
1742 ppm.value = map( ppmus , PPM_MIN_100, PPM_PLUS_100, -100 , 100 ) ; // map ppm in order to calibrate between -100 and 100
1743 ppm.available = true ;
1746 #else // so when done via SPORT (defined ( PPM_VIA_SPORT ) && ( PROTOCOL == FRSKY_SPORT ) || (PROTOCOL == FRSKY_SPORT_HUB) ) )
1747 // newPpm.value and .available are already filled in readSensor() when new values are received
1748 if (newPpm.available ){
1749 ppm.value = newPpm.value ;
1750 ppm.available = true ;
1751 newPpm.available = false ;
1756 getNewPpm = false ; // reset the indicator saying there is a new ppm to handle.
1757 #ifdef DEBUGPPMVALUE
1758 Serial.print(micros()); Serial.print(F(" ppm=")); Serial.println(ppm.value);
1760 #ifdef SEQUENCE_OUTPUTS
1761 if ( ( ( ppm.value - prevPpm) > 3 ) || (( prevPpm - ppm.value) > 3 ) ) { // handel ppm only if it changes by more than 3
1762 prevPpm = ppm.value ;
1765 #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
1766 if ( ( ( ppm.value - prevPpm) < 4 ) && ( ( prevPpm - ppm.value) < 4 ) ) { // test if new value is quite close to previous in order to avoid unstabel handling
1768 #if defined ( VARIO_PRIMARY) && defined ( VARIO_SECONDARY) && defined (VARIO ) && ( defined (VARIO2) || defined ( AIRSPEED_IS_USED) || defined (USE_6050) ) && defined (PPM_IS_USED)
1769 if ( (ppm.value >= (SWITCH_VARIO_MIN_AT_PPM - 4)) && (ppm.value <= (SWITCH_VARIO_MAX_AT_PPM + 4)) ) {
1770 selectedVario = VARIO_PRIMARY ;
1771 } else if ( ( ppm.value <= (4 - SWITCH_VARIO_MIN_AT_PPM)) && (ppm.value >= (- 4 - SWITCH_VARIO_MAX_AT_PPM)) ) {
1772 selectedVario = VARIO_SECONDARY ;
1774 #ifdef DEBUG_SELECTED_VARIO
1775 Serial.print(F("selected vario=")); Serial.println(selectedVario);
1777 #endif // endif defined ( VARIO_PRIMARY) && defined ( VARIO_SECONDARY) && ...
1779 #if defined (VARIO) || defined (VARIO2)
1780 if ( (abs(ppm.value) >= (SENSITIVITY_MIN_AT_PPM - 4)) && ( abs(ppm.value) <= (SENSITIVITY_MAX_AT_PPM + 4)) ) {
1781 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
1783 oXs_MS5611.varioData.sensitivityPpm = sensitivityPpmMapped ; // adjust sensitivity when abs PPM is within range
1785 #if defined( VARIO2)
1786 oXs_MS5611_2.varioData.sensitivityPpm = sensitivityPpmMapped ;
1789 #endif // end else defined (VARIO) || defined (VARIO2)
1792 #if defined ( AIRSPEED_IS_USED) // adjust compensation
1793 if ( (abs(ppm.value) >= (COMPENSATION_MIN_AT_PPM - 4)) && ( abs(ppm.value) <= (COMPENSATION_MAX_AT_PPM + 4)) ) {
1794 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
1795 if (compensationPpmMapped == COMPENSATION_PPM_MIN ) compensationPpmMapped = 0 ; // force compensation to 0 when compensation = min
1797 if ( ( ppm.value >= (AIRSPEED_RESET_AT_PPM - 4)) && ( ppm.value <= (AIRSPEED_RESET_AT_PPM + 4)) ) {
1798 #if defined (AIRSPEED_4525) // if 4525 is used
1799 oXs_4525.airSpeedData.airspeedReset = true ; // allow a recalculation of offset 4525
1800 #elif defined (AIRSPEED_7002) // when 7002 is used
1801 oXs_ads1115.adsAirSpeedData.airspeedReset = true ; // allow a recalculation of offset mvxp7002 connected to ads1115
1802 #endif // for SDP3X sensor , there is no need for a reset
1804 #endif // end AIRSPEED_IS_USED
1806 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)
1807 if ( ( ppm.value >= (FLOW_SENSOR_RESET_AT_PPM - 4)) && ( ppm.value <= (FLOW_SENSOR_RESET_AT_PPM + 4)) ) {
1808 consumedML = 0 ; // reset the flow counter
1813 #if defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC ) && defined ( GLIDER_RATIO_ON_AT_PPM )
1814 if ( (ppm.value >= (GLIDER_RATIO_ON_AT_PPM - 4)) && (ppm.value <= (GLIDER_RATIO_ON_AT_PPM + 4)) ) {
1815 gliderRatioPpmOn = true ;
1817 gliderRatioPpmOn = false ;
1821 } // end ppm == prePpm
1822 prevPpm = ppm.value ;
1823 #endif // end of #ifdef SEQUENCE_OUTPUTS & #else
1824 } // end if (ppm.available )
1826 } // end processPPMSignal
1829 /**********************************************************/
1830 /* ReadPPM => read PPM signal from receiver */
1831 /* pre-evaluate its value for validity */
1832 /**********************************************************/
1834 #ifdef PPM_INTERRUPT
1835 uint16_t StartTime ;
1836 volatile uint16_t time1 ; // pulsewidth (in millisec)
1837 //volatile uint8_t PulseTime ; // A byte to avoid
1838 volatile uint32_t ppmPulseMicros ; // timestamp when falling edges occurs in micros sec
1839 volatile boolean PulseTimeAvailable = false ;
1841 #if defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES)
1842 uint32_t ppmTimestampPrev ; //Timestamp (micros) of the previous PPM signal (used to check that the delay between 2 pulses is about 18ms)
1843 uint16_t widthPrev ; // width of the previous PWM pulse ( micros)
1844 uint8_t lqError ; // count the number of errors (new PWM pulses having the same value as the previous one)
1845 uint8_t lqCount ; // count total number of PWM pulses (to calculate a %); use to reset the counters after XXX (e.g.50) PWM
1846 uint8_t prevFrameInError ; // boolean ; true when the previous PWM was wrong (used to calculate consecutive errors)
1847 uint8_t lqConsecutiveError ; // count number of consecutive PWM errors
1848 uint8_t lqConsecutiveErrorMax ; // keep the max of consecutive errors within a sequence
1850 extern uint16_t lastTimerValue ;
1851 extern uint32_t TotalMicros ;
1854 #if PIN_PPM == 2 // When pin 2 is used, arduino handle INT0 (see datasheet)
1855 ISR(INT0_vect, ISR_NOBLOCK) // NOBLOCK allows other interrupts to be served when this one is activated
1856 #else //// When pin 3 is used, arduino handle INT1
1857 ISR(INT1_vect, ISR_NOBLOCK)
1860 uint8_t oReg = SREG; // store SREG value
1862 uint16_t time = TCNT1 ; // Read timer 1
1863 uint16_t lastTimerValueTemp = lastTimerValue ; // save the value to avoid any change in interrupt (not sure it is required
1864 uint32_t TotalMicrosTemp = TotalMicros ; // save the value to avoid any change in interrupt (not sure it is required
1865 SREG = oReg ; // restore SREG value
1866 if ( EICRA & PPM_INT_EDGE ) // a rising edge occurs
1868 StartTime = time ; // save the value of the timer
1869 EICRA &= ~PPM_INT_EDGE ; // allow a falling edge to generate next interrupt
1871 else // a falling edge occurs
1873 uint16_t elapsed = time - lastTimerValueTemp ;
1874 #if F_CPU == 20000000L // 20MHz clock
1875 #error Unsupported clock speed
1876 #elif F_CPU == 16000000L // 16MHz clock
1877 ppmPulseMicros = TotalMicrosTemp + ( elapsed >> 4 ) ;
1878 #elif F_CPU == 8000000L // 8MHz clock
1879 ppmPulseMicros = TotalMicrosTemp + ( elapsed >> 3 ) ;
1881 #error Unsupported clock speed
1885 #if F_CPU == 20000000L // 20MHz clock
1886 #error Unsupported clock speed
1887 #elif F_CPU == 16000000L // 16MHz clock
1888 time>>= 4 ; // delay in usec
1889 #elif F_CPU == 8000000L // 8MHz clock
1890 time >>= 3 ; // delay in usec
1892 #error Unsupported clock speed
1895 PulseTimeAvailable = true ;
1896 EICRA |= PPM_INT_EDGE ; // allow a Rising edge to generate next interrupt
1900 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
1901 static uint8_t ppmIdx ;
1902 static uint16_t ppmTemp ;
1903 static uint16_t ppmMax ; // highest value of ppmTemp received ; Some ppm measurement are wrong (to low) because there are some interrupt some
1904 ppmus = 0 ; // reset the pulse width
1906 if ( PulseTimeAvailable ) { // if new pulse is available
1907 #define PPM_COUNT_MAX 5 // select the max of 5 ppm (so once every 100 msec
1908 uint8_t oReg = SREG ; // save Status register
1910 ppmTemp = time1 ; // use values from interrupt
1911 uint32_t ppmTimestamp = ppmPulseMicros ;
1912 PulseTimeAvailable = false ;
1913 SREG = oReg ; // restore Status register
1914 #if defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES)
1915 uint32_t pulseInterval = (ppmTimestamp - ppmTimestampPrev) ;
1916 if ( (pulseInterval > PULSE_INTERVAL_MIN) && (pulseInterval < PULSE_INTERVAL_MAX ) ) {
1917 if ( abs (( int16_t) (ppmTemp - widthPrev)) <= WIDTH_ERROR_MAX ) {
1919 if ( prevFrameInError == true) {
1920 lqConsecutiveError++ ; // count consecutive errors
1921 if (lqConsecutiveError > lqConsecutiveErrorMax) {
1922 lqConsecutiveErrorMax = lqConsecutiveError ;
1926 prevFrameInError = true ;
1928 lqConsecutiveError = 0 ; // reset the counter when a valid PWM is received
1929 prevFrameInError = false ; // reset the flag when we get a valid PWM signal
1932 #if defined ( DEBUG_RF_LINK_QUALITY )
1933 Serial.print("Read ppm at ") ; Serial.print(ppmTimestamp) ;
1934 Serial.print(" Delay= ") ; Serial.print(pulseInterval) ;
1935 Serial.print(" Process at ") ; Serial.print(millis()) ;
1936 Serial.print(" Width= ") ; Serial.print(ppmTemp) ;
1937 Serial.print(" delta=") ; Serial.print( abs (( int16_t) (ppmTemp - widthPrev)) ) ;
1938 Serial.print(" lqC=") ; Serial.print( lqCount ) ;
1939 Serial.print(" lqE=") ; Serial.print( lqError ) ;
1940 Serial.print(" cons=") ; Serial.print( lqConsecutiveError) ;
1941 Serial.print(" Max=") ; Serial.print( lqConsecutiveErrorMax) ;
1942 Serial.print(" %=") ; Serial.println( ( ( (LQ_COUNT_MAX - (uint16_t) lqError)) * 100 ) / LQ_COUNT_MAX ) ;
1944 if ( lqCount >= LQ_COUNT_MAX ) {
1945 #if defined ( FILL_TEST_1_2_WITH_LQ )
1946 test1.value = ( ( (LQ_COUNT_MAX - (uint16_t) lqError)) * 100 ) / LQ_COUNT_MAX ;
1947 test1.available = true ;
1948 test2.value = lqConsecutiveErrorMax ;
1949 test2.available = true ;
1950 #endif // FILL_TEST_1_2_WITH_LQ
1953 lqConsecutiveError = 0 ;
1954 lqConsecutiveErrorMax = 0 ;
1955 // to do : save the values in data that can be transmitted
1958 ppmTimestampPrev = ppmTimestamp ;
1959 widthPrev = ppmTemp ;
1960 #endif // defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES)
1962 if ( ppmIdx >= PPM_COUNT_MAX ) {
1963 ppmus = ppmMax ; // we keep the highest value
1968 if( ppmTemp > ppmMax ) ppmMax = ppmTemp ; // save the highest value
1969 } // end test on ppmIdx
1970 } // end test on PulseTimeAvailable
1972 #endif // end #ifdef PPM_INTERRUPT
1977 #if defined ( A_FLOW_SENSOR_IS_CONNECTED )
1978 #if ( A_FLOW_SENSOR_IS_CONNECTED == YES) // flowMeterCnt is updated by interrupt PCINT0
1982 float mapFlowCorr( uint8_t idx) { // calculate correction factor depending on current flow
1983 uint8_t flowCorrIdx = idx + TX_FIELD_FLOW_CORR_1 ;
1984 return ( flowParam[flowCorrIdx ] + ( currentFlow - flowParam[idx]) / (flowParam[idx + 1] - flowParam[idx]) * (flowParam[flowCorrIdx + 1] - flowParam[flowCorrIdx ] ) ) ;
1987 void checkFlowParam() {
1988 if ( (tankCapacity % 50) != 0) tankCapacity = ( tankCapacity / 50 ) * 50 ; // set tank capacity in steps of 50 ml
1989 tankCapacity = constrain( tankCapacity , 100 , 3000 ) ;
1990 for (uint8_t i = 0; i < 4 ; i++) {
1991 if ( ( flowParam[i] % 5) != 0 ) flowParam[i] = ( flowParam[i] / 5 ) * 5 ;
1992 flowParam[i] = constrain( flowParam[i] , 30 , 800 + (5 * i)) ;
1993 flowParam[ i+ 4] = constrain( flowParam[i+4] , -100 , +100 ) ;
1995 for (uint8_t i= 1 ; i < 4 ; i++) {
1996 if ( flowParam[i] <= flowParam[i - 1] ) flowParam[i] = flowParam[i - 1] + 5 ;
2000 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
2001 // save the result in eeprom is done in main loop for all data to be saved in EEPROM
2002 #define FLOW_DELAY 2000 // calculates once per 2 sec
2004 uint16_t flowMeterCntCopy ;
2005 static uint32_t prevFlowMillis ;
2006 uint32_t currentFlowMillis = millis() ;
2007 if ( ( currentFlowMillis - prevFlowMillis ) > FLOW_DELAY ) {
2008 prevFlowMillis = currentFlowMillis ;
2009 uint8_t oReg = SREG ; // save status register
2010 cli() ; // avoid interrupt to ensure that counter is consistent
2011 flowMeterCntCopy = flowMeterCnt ;
2013 SREG = oReg ; // restore status register
2014 sei() ; // allow interrupt again
2015 #ifdef DEBUG_SIMULATE_FLOW_SENSOR
2016 flowMeterCntCopy = 100 ; // force a fix value in order to test without a flow sensor
2018 #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)
2019 currentFlow = ((float) flowMeterCntCopy) * CONVERT_TO_ML_PER_MIN ; // expected value should be between 15 and 800 ml/min for the conrad flow meter
2020 if (currentFlow < flowParam[TX_FIELD_FLOW_1] ) {
2021 flowCorr = flowParam[TX_FIELD_FLOW_CORR_1] ; // flow crrection is supposed to be in %
2022 } else if (currentFlow < flowParam[TX_FIELD_FLOW_2] ) {
2023 flowCorr = mapFlowCorr( TX_FIELD_FLOW_1 ) ;
2024 } else if (currentFlow < flowParam[TX_FIELD_FLOW_3] ) {
2025 flowCorr = mapFlowCorr( TX_FIELD_FLOW_2 ) ;
2026 } else if (currentFlow < flowParam[TX_FIELD_FLOW_4] ) {
2027 flowCorr = mapFlowCorr( TX_FIELD_FLOW_3 ) ;
2029 flowCorr = flowParam[TX_FIELD_FLOW_CORR_4] ;
2031 currentFlow = ((float) currentFlow ) * ( 100.0 + flowCorr) * 0.01 ; // 0.01 because flowCorr is in %)
2032 actualFlow.value = currentFlow ;
2033 actualFlow.available= true ;
2034 consumedML += currentFlow * FLOW_DELAY / 60000.0 ;
2035 if ( consumedML > tankCapacity ) consumedML = tankCapacity ;
2036 remainingFuelML.value = tankCapacity - consumedML ;
2037 remainingFuelML.available= true ;
2038 fuelPercent.value = remainingFuelML.value * 100 / tankCapacity ; // in percent
2039 fuelPercent.available= true ;
2040 newFlowAvailable = true ; // this is use to fill TEST_1, 2, 3 to avoid conflict with JETI protocol which uses 3 individual flags
2041 #if defined ( DEBUG) && defined (DEBUG_FLOW_SENSOR)
2042 Serial.print(" At " ); Serial.print( prevFlowMillis ) ;
2043 Serial.print(" flcnt " ); Serial.print( flowMeterCntCopy ) ;
2044 Serial.print(" remain " ); Serial.print( remainingFuelML.value ) ;
2045 Serial.print(" ml/min " ); Serial.print( currentFlow ) ;
2046 Serial.print(" cons " ); Serial.println( consumedML ) ;
2050 } // end processFlowMeterCnt
2053 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
2054 flowMeterCnt++ ; // we increase the counter of pin change.
2059 #endif // end A_FLOW_SENSOR_IS_CONNECTED
2063 #ifdef SEQUENCE_OUTPUTS
2064 void setNewSequence() { // ********** setNewSequence( ) ************** handle a new ppm value
2065 // int8_t prevPpmMain = -100 ; // this value is unusual; so it will forced a change at first call
2066 int16_t ppmAbs = ppm.value + 114 ;
2067 int8_t ppmMain = ppmAbs / 25 ;
2068 int8_t ppmRest = ppmAbs % 25 ;
2069 if ( (ppmRest > 4) && (ppmMain >= 0) && (ppmMain <= 9) && (ppmMain != prevPpmMain) ) { // process only if valid and different from previous
2070 #ifdef DEBUGSEQUENCE
2071 Serial.println(F(" "));
2072 Serial.print(F("ppmMain=")); Serial.println(ppmMain );
2073 //Serial.println(F(" "));
2075 prevPpmMain = ppmMain ;
2076 seqRef = sequencePointer[ppmMain] ; // seqTab contains pointers to the sequence array
2077 seqMax = sequenceMaxNumber[ppmMain] ;
2080 #ifdef DEBUGSEQUENCE
2081 test1.value = ppmMain;
2082 test1.available = true ;
2088 void checkSequence() {
2090 uint8_t portbTempValue ;
2091 static uint16_t seqDelay ;
2092 static unsigned long currentMillis ;
2093 static unsigned long nextSequenceMillis ;
2094 #ifdef DEBUGSEQUENCE
2095 // Serial.print(F("seqState=")); Serial.println(seqState );
2098 if ( seqState == 0 ) {
2099 portbTempValue = *(seqRef + 1);
2100 seqDelay = *(seqRef ) * sequenceUnit; //
2101 portbTemp = (~sequenceOutputs) & PORTB; // reset the bit that are controlled
2102 PORTB = portbTemp | ( portbTempValue & sequenceOutputs ); // set the bit as defined in the sequence if they have to be controlled
2103 #ifdef DEBUGSEQUENCE
2104 Serial.print(F("seqStep=")); Serial.println( seqStep );
2105 Serial.print(F("portbTempValue=")); Serial.println( portbTempValue );
2106 Serial.print(F("seqDelay=")); Serial.println( seqDelay );
2107 Serial.print(F("portbTemp=")); Serial.println( portbTemp );
2108 Serial.print(F("PORTB=")); Serial.println( portbTempValue & sequenceOutputs );
2111 if (seqDelay == 0 ) {
2112 seqState = 2 ; // set state to sequence stopped if delay is 0
2114 seqState = 1 ; //says that sequence is running
2115 nextSequenceMillis = millis() + seqDelay ;
2117 } else if ( seqState == 1 ) { // when sequence is running, check the timestamp to activate next sequence step
2118 currentMillis = millis() ;
2119 if ( currentMillis > nextSequenceMillis ) {
2120 seqStep += 2 ; // increase by 2 because there are 2 parameters per step
2121 if ( (seqStep + 1) >= seqMax ) seqStep = 0 ; // return to 0 if end is reached
2122 portbTempValue = *(seqRef + 1 + seqStep );
2123 seqDelay = *(seqRef + seqStep) * sequenceUnit ;
2124 portbTemp = (~sequenceOutputs) & PORTB; // reset the bit that are controlled
2125 PORTB = portbTemp | ( portbTempValue & sequenceOutputs ); // set the bit as defined in the sequence if they have to be controlled
2126 if (seqDelay == 0 ) {
2127 seqState = 2 ; // set state to sequence stopped if delay is 0
2129 seqState = 1 ; //says that sequence is running
2130 nextSequenceMillis = currentMillis + seqDelay ;
2132 #ifdef DEBUGSEQUENCE
2133 Serial.print(F("At")); Serial.print( currentMillis );
2134 Serial.print(F(" seqStep=")); Serial.println( seqStep );
2135 Serial.print(F("portbTempValue=")); Serial.println( portbTempValue );
2136 Serial.print(F("seqDelay=")); Serial.println( seqDelay );
2137 Serial.print(F("portbTemp=")); Serial.println( portbTemp );
2138 Serial.print(F("PORTB=")); Serial.println( portbTempValue & sequenceOutputs );
2141 } // end ( currentMillis > nextSequenceMillis )
2142 } // end ( seqState == 0 ) or ( seqState == 1 )
2143 } // end checkSequence()
2144 #endif // end SEQUENCE_OUTPUTS
2149 //************************************************************ OutputToSerial
2150 void OutputToSerial(){
2151 //#define DEBUGMINMAX 0
2152 //#define DEBUGVREF 0
2153 //#define DEBUGDIVIDER 0
2154 //#define DEBUGTEMP 0
2159 Serial.print(F(" Sensitivity PPM="));
2160 Serial.print( oXs_MS5611.varioData.sensitivityPpm);
2161 Serial.print(F(" ;absAlt="));
2162 Serial.print( ( (float)oXs_MS5611.varioData.absoluteAlt.value)/100);
2163 Serial.print(F(" ;Vspd="));
2164 Serial.print( ( (float)oXs_MS5611.varioData.climbRate.value)/100);
2165 Serial.print(F(" ;Temp="));
2166 Serial.print((float)oXs_MS5611.varioData.temperature/10);
2169 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
2170 Serial.print(F(" ;mA="));
2171 Serial.print( ( ((float)(int32_t)(oXs_Current.currentData.milliAmps.value))) );
2173 Serial.print(F(" ;mAh="));
2174 Serial.print( oXs_Current.currentData.consumedMilliAmps.value);
2175 #endif // defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
2177 Serial.println("H.");
2183 /***********************************************/
2184 /* freeRam => Cook coffee and vaccuum the flat */
2185 /***********************************************/
2187 extern int __heap_start, *__brkval;
2189 return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);