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 ;
870 #ifdef FILL_TEST_2_WITH_VARIO_TEMP
871 test2.value = oXs_MS5611.varioData.temperature/100.0 ;
872 test2.available = true ;
874 #ifdef FILL_TEST_3_WITH_VARIO_TEMP
875 test3.value = oXs_MS5611.varioData.temperature/100.0 ;
876 test3.available = true ;
882 #ifdef DEBUG_ENTER_READSENSORS
883 Serial.print( "read baro 2 at ") ; Serial.println(millis());
886 newVarioAvailable2 = oXs_MS5611_2.readSensor(); // Read pressure & temperature on MS5611, calculate Altitude and vertical speed
890 oXs_4525.readSensor(); // Read again the sensor in order to reduce response time/noise
893 #ifdef AIRSPEED_SDP3X
894 oXs_sdp3x.readSensor(); //read the SDP3X sensor
898 newImuAvailable = read6050() ;
901 #if defined( USE_HMC5883 ) && defined (USE_6050)
905 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
906 oXs_Voltage.readSensor(); // read voltage only if there enough time to avoid delaying vario reading; It takes about 750 usec to go through the read sensor.
907 #endif // end voltage
909 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
910 oXs_Current.readSensor() ; // Do not perform calculation if there is less than 2000 usec before MS5611 ADC is available = (9000 - 2000)/2
911 #endif // End defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
914 #ifdef DEBUG_ENTER_READSENSORS
915 Serial.print( "read gps at ") ; Serial.println(millis());
918 oXs_Gps.readGps() ; // Do not perform calculation if there is less than 2000 usec before MS5611 ADC is available = (9000 - 2000)/2
919 #endif // End GPS_INSTALLED
921 #if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE)
922 if( oXs_ads1115.readSensor() ) { // return true when a new average is available; it means that the new value has to be stored/processed.
924 #endif // End ADS_MEASURE
928 if (millis() > ( lastRpmMillis + 200) ){ // allow transmission of RPM only once every 200 msec
929 if (RpmSet == true) { // rpm is set
934 sport_rpm.value = RpmValue ;
935 sport_rpm.available = true ;
936 lastRpmMillis = millis() ;
938 Serial.print( "RPM ") ; Serial.println(sport_rpm.value);
943 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)
944 processFlowMeterCnt () ;
948 #if ( defined ( PPM_VIA_SPORT ) || ( defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES) ) ) && defined (PROTOCOL ) && ( ( PROTOCOL == FRSKY_SPORT ) || ( PROTOCOL == FRSKY_SPORT_HUB ) ) // if it is allowed to read SPORT
949 uint8_t oReg = SREG ; // save status register
951 if ( TxDataIdx == 8 ) {
952 TxDataIdx++ ; // Increase the number of data in order to avoid to read twice
953 uint16_t txField = ( TxData[2] << 8 ) + TxData[1] ; // id of the field being received
954 uint32_t txValue = ( ( ( ( (TxData[6] << 8) + TxData[5] ) << 8 ) + TxData[4] ) << 8 ) + TxData[3] ; // value of the field being received
955 SREG = oReg ; // restore the status register
956 #ifdef DEBUG_READ_SPORT
957 Serial.print("At: ") ; Serial.print(millis()) ;
958 Serial.print(" "); Serial.print(TxData[0], HEX);
959 Serial.print(" "); Serial.print(TxData[1], HEX);
960 Serial.print(" "); Serial.print(TxData[2], HEX);
961 Serial.print(" "); Serial.print(TxData[3], HEX);
962 Serial.print(" "); Serial.print(TxData[4], HEX);
963 Serial.print(" "); Serial.print(TxData[5], HEX);
964 Serial.print(" "); Serial.print(TxData[6], HEX);
965 Serial.print(" "); Serial.print(TxData[7], HEX);
968 #if ( defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES) )
969 if ( txField <= TX_FIELD_FLOW_CORR_4) { // save values for flow meter parameter in memory
970 flowParam[txField] = txValue ;
971 } else if ( txField == TX_FIELD_TANK_CAPACITY) { // save values for capacity in memory
972 tankCapacity = txValue ; // note: values will be saved in eeprom in EEPROM function
973 } else if ( txField == TX_FIELD_RESET_FUEL ) {
974 consumedML = 0 ; // reset consumption
977 #if defined ( PPM_VIA_SPORT ) && ( ( PROTOCOL == FRSKY_SPORT ) || ( PROTOCOL == FRSKY_SPORT_HUB ) )
978 if ( txField == TX_FIELD_PPM ) { // save the value for ppm
979 newPpm.value = ((int32_t) txValue) * 100 / 1024 ;
980 newPpm.available = true ;
984 SREG = oReg ; // restore the status register
988 } // ************** end of readSensors ********************************************
991 //#define ALTITUDE_AVAILABLE_BIT 1
992 //#define VSPEED_AVAILABLE_BIT 2
993 // ********************************* Calculate all fields that could be sent
994 void calculateAllFields () {
996 // compensated Vpeed based on MS4525
997 #if defined(VARIO) && defined ( AIRSPEED_IS_USED)
998 if ( newVarioAvailable ) calculateDte() ;
1002 #if defined (VARIO) && defined (VARIO2)
1003 if( (newVarioAvailable ) || ( newVarioAvailable2 ) ) {
1004 averageVSpeedFloat = ( oXs_MS5611.varioData.climbRateFloat + oXs_MS5611_2.varioData.climbRateFloat ) / 2 ;
1005 if ( abs((int32_t) averageVSpeedFloat - averageVSpeed.value) > VARIOHYSTERESIS ) {
1006 averageVSpeed.value = (int32_t) averageVSpeedFloat ; // update only when difference is greater than hysteresis
1008 averageVSpeed.available = true ;
1012 // calculate vSpeedImu & vSpeedImuAvailable
1013 #if defined (VARIO) && defined (USE_6050)
1014 if (newImuAvailable) { // newImuAvailable says that a new world_linear_acceleration is available (flag has been returned by read6050()
1015 newImuAvailable = false ; // reset the flag saying a new world_linear_acceleration is available
1017 unsigned long beginKalman = micros();
1019 if ( countAltitudeToKalman != 0) { // this calculate the initial altitude
1020 if( oXs_MS5611.varioData.rawAltitude != 0) {
1021 countAltitudeToKalman-- ;
1022 altitudeOffsetToKalman = oXs_MS5611.varioData.rawAltitude ;
1025 altitudeToKalman = (oXs_MS5611.varioData.rawAltitude - altitudeOffsetToKalman ) / 100 ; // convert from * 100cm to cm
1026 kalman.Update((float) altitudeToKalman , world_linear_acceleration_z , &zTrack, &vTrack); // Altitude and acceleration are in cm
1027 vSpeedImu.value = vTrack ;
1028 vSpeedImu.available = true ;
1029 switchVTrackAvailable = true ;
1031 //#define FILL_TEST_3_WITH_EXPECTED_ALT // force a calculation of an expected altitude x seconds in the future
1032 #ifdef FILL_TEST_3_WITH_EXPECTED_ALT
1033 #define EXPECTED_AT_SEC 0.2 // number of sec used for the projection; can have decimals; NB: expected alt = Alt at time 0 + Vspeed at time 0 * seconds + 0.5 * Accz at time 0 * seconds * seconds
1034 test3.value = ( zTrack - oXs_MS5611.varioData.altOffset ) + ( vTrack * EXPECTED_AT_SEC ) + ( 0.5 * world_linear_acceleration_z * EXPECTED_AT_SEC * EXPECTED_AT_SEC ) ;
1035 test3.available = true ;
1038 //#define FILL_TEST_1_2_3_WITH_LINEAR_ACC
1039 #ifdef FILL_TEST_1_2_3_WITH_LINEAR_ACC
1040 test1.value = linear_acceleration_x * 981 ;
1041 test1.available = true ;
1042 test2.value = linear_acceleration_y * 981;
1043 test2.available = true ;
1044 test3.value = linear_acceleration_z * 981;
1045 test3.available = true ;
1048 #ifdef DEBUG_KALMAN_TIME
1049 /// Serial.print(F("delay Kal ")) ; Serial.print( millis() - beginKalman ) ;Serial.print(F(", "));
1050 // Serial.print( (int) world_linear_acceleration_z ) ; Serial.print(F(", "));Serial.print( (int) altitudeToKalman) ; Serial.print(F(", ")); Serial.print(oXs_MS5611.varioData.climbRate) ; Serial.print(F(", "));Serial.println(( int )vSpeedImu.value) ;
1051 /// Serial.print( millis() ) ; Serial.print(F(", ")); Serial.print( (int) ) ; Serial.print(F(", "));Serial.print( (int) world_linear_acceleration_z ) ; Serial.print(F(", "));Serial.print( (int) altitudeToKalman) ; Serial.print(F(", ")); Serial.print(oXs_MS5611.varioData.climbRate) ; Serial.print(F(", "));Serial.println(( int )vSpeedImu.value) ;
1052 Serial.print("delayK ") ; Serial.print( delayKalman[0] ) ; Serial.print(" ") ; Serial.print( delayKalman[1] ) ;
1053 Serial.print(" ") ; Serial.print( delayKalman[2] ) ; Serial.print(" ") ; Serial.print( delayKalman[3] ) ;Serial.print(" ") ; Serial.println( delayKalman[4] ) ;
1055 } // end of newimuAvailable
1059 // calculate selected Vspeed based on ppm
1060 #if defined (VARIO) && ( defined (VARIO2) || defined (AIRSPEED_IS_USED) || defined (USE_6050 ) ) && defined (VARIO_SECONDARY ) && defined( VARIO_PRIMARY ) && defined (PPM_IS_USED)
1061 if (( selectedVario == FIRST_BARO ) && ( newVarioAvailable ) ) {
1062 switchVSpeed.value = oXs_MS5611.varioData.climbRate.value ;
1063 switchVSpeed.available = true ;
1065 #if defined (VARIO2)
1066 else if ( ( selectedVario == SECOND_BARO ) && ( newVarioAvailable2 )) {
1067 switchVSpeed.value = oXs_MS5611_2.varioData.climbRate.value ;
1068 switchVSpeed.available = true ;
1070 else if ( ( selectedVario == AVERAGE_FIRST_SECOND ) && ( averageVSpeed.available == true )) {
1071 switchVSpeed.value = averageVSpeed.value ;
1072 switchVSpeed.available = true ;
1074 #endif // end of VARIO2
1075 #ifdef AIRSPEED_IS_USED
1076 else if ( ( selectedVario == AIRSPEED_COMPENSATED ) && ( newVarioAvailable )) {
1077 switchVSpeed.value = compensatedClimbRate.value ;
1078 switchVSpeed.available = true ;
1079 #if defined (SWITCH_VARIO_GET_PRIO)
1080 switchCompensatedClimbRateAvailable = true ; // avoid to reset the value on false in order to continue to send the same value as often as possible
1082 switchCompensatedClimbRateAvailable = false ; // this is the normal process in order to avoid sending twice the same data.
1083 #endif // end defined (SWITCH_VARIO_GET_PRIO)
1085 #endif // end defined (AIRSPEED) || (defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined (ADS_MEASURE) && defined (ADS_AIRSPEED_BASED_ON) )
1086 #if defined (USE_6050)
1087 else if ( ( selectedVario == BARO_AND_IMU ) && ( switchVTrackAvailable )) {
1088 switchVSpeed.value = vSpeedImu.value ;
1089 switchVSpeed.available = true ;
1091 #endif // end USE_6050
1092 #endif // end #if defined (VARIO) && ( defined (VARIO2) || defined (AIRSPEED_IS_USED) || defined (USE_6050 ) ) && defined (VARIO_SECONDARY ) && defined( VARIO_PRIMARY ) && defined (PPM_IS_USED)
1094 // mainVSpeed (calculated based on the setup in config)
1095 #if defined(VARIO) && ( (!defined(VSPEED_SOURCE)) || (defined(VSPEED_SOURCE) && (VSPEED_SOURCE == FIRST_BARO) ) )
1096 mainVspeed.value = oXs_MS5611.varioData.climbRate.value ;
1097 mainVspeed.available = oXs_MS5611.varioData.climbRate.available ;
1098 #elif defined(VARIO) && defined(VARIO2) && (VSPEED_SOURCE == SECOND_BARO)
1099 mainVspeed.value = oXs_MS5611_2.varioData.climbRate.value ;
1100 mainVspeed.available = oXs_MS5611_2.varioData.climbRate.available ;
1101 #elif defined(VARIO) && defined(VARIO2) && (VSPEED_SOURCE == AVERAGE_FIRST_SECOND)
1102 mainVspeed.value = averageVSpeed.value ;
1103 mainVspeed.available = averageVSpeed.available ;
1104 #elif defined(VARIO) && defined(AIRSPEED_IS_USED) && (VSPEED_SOURCE == AIRSPEED_COMPENSATED)
1105 mainVspeed.value = compensatedClimbRate.value ;
1106 mainVspeed.available = compensatedClimbRate.available ;
1107 #elif defined(VARIO) && defined(USE_6050) && (VSPEED_SOURCE == BARO_AND_IMU)
1108 mainVspeed.value = vSpeedImu.value ;
1109 mainVspeed.available = vSpeedImu.available ;
1110 #elif defined(VARIO) && ( defined (VARIO2) || defined (AIRSPEED_IS_USED) || defined (USE_6050) ) && defined (VARIO_SECONDARY ) && defined( VARIO_PRIMARY ) && defined (PPM_IS_USED) && (VSPEED_SOURCE == PPM_SELECTION)
1111 mainVspeed.value = switchVSpeed.value ;
1112 mainVspeed.available = switchVSpeed.available ;
1113 #if defined (DEBUG_SELECTED_VARIO)
1114 static uint32_t next_debug_vspeeds_millis ;
1115 static boolean next_debug_vspeeds_flag = true ;
1116 if (millis() > next_debug_vspeeds_millis) {
1117 if (next_debug_vspeeds_flag) {
1118 Serial.println("vspeeds= first, compensated, switched , main");
1119 next_debug_vspeeds_flag = false ;
1121 Serial.print("vspeeds= ");Serial.print(oXs_MS5611.varioData.climbRate.value); Serial.print(",");Serial.print(compensatedClimbRate.value);
1122 Serial.print(",");Serial.print(switchVSpeed.value); Serial.print(",");Serial.print(mainVspeed.value); Serial.println(" ");
1123 next_debug_vspeeds_millis = millis() + 500 ;
1126 #endif // end DEBUG_SELECTED_VARIO
1128 #endif // end mainVSpeed (calculated based on the setup in config)
1131 // calculate glider ratio and average vertical speed (based on first vario)
1132 #if defined (VARIO) && defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC) && GLIDER_RATIO_CALCULATED_AFTER_X_SEC >= 1
1133 calculateAverages();
1136 // fill test1 and test2 with Vspeed and relative Alt
1137 //#define FILL_TEST_1_2_WITH_VSPEED_AND_ALT_FROM_SECOND_VARIO
1138 #if defined (VARIO) && ( defined (VARIO2) ) && defined(FILL_TEST_1_2_WITH_VSPEED_AND_ALT_FROM_SECOND_VARIO)
1139 test1.value = oXs_MS5611_2.varioData.climbRate.value ;
1140 test1.available = oXs_MS5611_2.varioData.climbRate.available ;
1141 test2.value = oXs_MS5611_2.varioData.relativeAlt.value ;
1142 test2.available = oXs_MS5611_2.varioData.relativeAlt.available ;
1145 // fill test1 and test2 with DTE and PPM_COMPENSATION
1146 //#define FILL_TEST_1_WITH_DTE
1147 //#define FILL_TEST_2_WITH_PPM_AIRSPEED_COMPENSATION
1148 #if defined(VARIO) && defined(AIRSPEED_IS_USED)
1149 #ifdef FILL_TEST_1_WITH_DTE
1150 test1.value = compensatedClimbRate.value ;
1151 test1.available = compensatedClimbRate.available ;
1153 #if defined(FILL_TEST_2_WITH_PPM_AIRSPEED_COMPENSATION) && defined(PPM_IS_USED)
1154 static uint32_t lastPpmCompensationMillis ;
1155 uint32_t PpmCompensationMillis = millis() ;
1156 if ( ( PpmCompensationMillis - lastPpmCompensationMillis ) > 200 ) {
1157 test2.value = compensationPpmMapped ;
1158 test2.available = true ;
1159 lastPpmCompensationMillis = PpmCompensationMillis ;
1164 #if defined (VARIO) && defined (USE_6050)
1165 //#define FILL_TEST_1_WITH_YAWRATE
1166 #ifdef FILL_TEST_1_WITH_YAWRATE
1167 static int32_t previousYaw ;
1168 static uint32_t previousYawRateMillis ;
1169 uint32_t currentMillis ;
1170 currentMillis = millis() ;
1171 if (currentMillis >= previousYawRateMillis + 200 ) {
1172 test1.value = (yaw.value - previousYaw) * 1000 / (int32_t) (currentMillis - previousYawRateMillis ) ; // calculate yaw rate in degree / sec
1173 test1.available = true ;
1174 //#define DEBUGYAWRATE
1176 //Serial.print(lastImuInterruptMillis) ; Serial.print(" ") ; Serial.print( previousYawRateMillis ) ;Serial.print(" ") ; Serial.print( yaw.value ) ; Serial.print(" ") ; Serial.print( test1.value ) ; Serial.print(" ") ; Serial.println(oXs_MS5611.varioData.absoluteAlt.value) ;
1177 Serial.print( currentMillis ) ;Serial.print(" ") ; Serial.print( yaw.value ) ; Serial.print(" ") ; Serial.print( test1.value ) ; Serial.print(" ") ; Serial.println(oXs_MS5611.varioData.absoluteAlt.value) ;
1180 previousYaw = yaw.value ;
1181 previousYawRateMillis = currentMillis ;
1184 // test1.value = oXs_MS5611.varioData.climbRate.value ;
1185 // test1.available = oXs_MS5611.varioData.climbRate.available ;
1186 // test2.value = vSpeedImu.value ;
1187 // test2.available = vSpeedImu.available ;
1191 //#define DEBUG_CHANGE_IN_TEST12
1192 #if defined( DEBUG_CHANGE_IN_TEST12 )
1193 static uint32_t millisLastChangeTest ;
1194 if (millis() > millisLastChangeTest ) {
1195 millisLastChangeTest += 100 ;
1197 test1.available = true ;
1199 test2.available = true ;
1203 //#define FILL_TEST1_WITH_HEADING_FROM_MAGNETOMETER
1204 #if defined ( USE_HMC5883 ) && defined (USE_6050) && defined (FILL_TEST1_WITH_HEADING_FROM_MAGNETOMETER)
1205 if ( newMagHeading ) {
1206 newMagHeading = false ;
1207 test1.value = magHeading ;
1208 test1.available = true ;
1214 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)&& defined (FILL_TEST_1_2_3_WITH_FLOW_SENSOR_CONSUMPTION)
1215 if( newFlowAvailable ) {
1216 test1.value = actualFlow.value ;
1217 test2.value = remainingFuelML.value ;
1218 test3.value = fuelPercent.value ;
1219 test1.available = test2.available = test3.available = true ;
1220 newFlowAvailable = false ;
1225 #if defined ( A_GPS_IS_CONNECTED ) && ( A_GPS_IS_CONNECTED == YES )
1226 #if defined ( FILL_TEST1_WITH_GPS_NUMBER_OF_SAT )
1227 test1.value = GPS_numSat ;
1229 test1.value += 100 ;
1231 test1.available = true ;
1233 #if defined ( FILL_TEST2_WITH_GPS_HDOP )
1234 test2.value = GPS_hdop ;
1235 test2.available = true ;
1239 // test1.value = oXs_MS5611.varioData.absoluteAlt.value/10 ;
1240 // test1.available = true ;
1242 //#if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1243 //if ( currentData.consumedMilliAmps.available) {
1244 // test1.value = currentData.consumedMilliAmps.value ;
1245 // test1.available = true ;
1246 // currentData.consumedMilliAmps.available = false ;
1250 //#if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(ADS_CURRENT_BASED_ON)
1251 //if ( oXs_ads1115.adsCurrentData.MilliAmps.available) {
1252 // test2.value = oXs_ads1115.adsCurrentData.MilliAmps.value ;
1253 // test2.available = true ;
1254 // oXs_ads1115.adsCurrentData.MilliAmps.available = false ;
1256 //if ( oXs_ads1115.adsCurrentData.consumedMilliAmps.available) {
1257 // test3.value = oXs_ads1115.adsCurrentData.consumedMilliAmps.value ;
1258 // test3.available = true ;
1259 // oXs_ads1115.adsCurrentData.consumedMilliAmps.available = false ;
1263 //#if ( defined(AIRSPEED) && (defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined (ADS_MEASURE) && defined (ADS_AIRSPEED_BASED_ON) )
1264 // if ( oXs_ads1115.adsAirSpeedData.airSpeed.available == true ) {
1265 // test1.value = oXs_ads1115.adsAirSpeedData.airSpeed.value ;
1266 // test1.available = true ;
1267 // oXs_ads1115.adsAirSpeedData.airSpeed.available = false ;
1271 // if ( oXs_MS5611.varioData.climbRate.available ) {
1272 // test1.value = oXs_MS5611.varioData.temperature ;
1273 // test1.available = true ;
1275 } // end of calculate all fields
1279 //***************** checkFreeTime ********* if there is at least 2000 usec before the next MS5611 read (in order to avoid delaying it
1280 bool checkFreeTime() { // return true if there is no vario or if the vario sensor must not be read within a short time.
1281 // return false if a vario must be read within a short time
1282 #if defined (VARIO) || defined (VARIO2)
1283 // extendedMicros = micros() ;
1285 return ( micros() - oXs_MS5611.varioData.lastCommandMicros < 7000 ) ; // Do not change PWM if there is less than 2000 usec before MS5611 ADC is available = (9000 - 2000)
1286 #else // only VARIO2
1287 return ( micros() - oXs_MS5611_2.varioData.lastCommandMicros < 7000 ) ; // Do not change PWM if there is less than 2000 usec before MS5611 ADC is available = (9000 - 2000)
1288 #endif // enf of at least one vario
1289 #else // No vario at all
1292 } // ******************************* end of checkFreeTime *****************************
1294 // ********************************** Calculate dTE based on rawAltitude and differential pressure
1295 #if defined (VARIO) && defined ( AIRSPEED_IS_USED)
1296 #define SMOOTHING_DTE_MIN SENSITIVITY_MIN
1297 #define SMOOTHING_DTE_MAX SENSITIVITY_MAX
1298 #define SMOOTHING_DTE_MIN_AT SENSITIVITY_MIN_AT
1299 #define SMOOTHING_DTE_MAX_AT SENSITIVITY_MAX_AT
1301 void calculateDte () { // is calculated about every 2O ms each time that an altitude is available
1302 static float rawTotalEnergy ;
1303 static float abs_deltaCompensatedClimbRate ;
1304 static float smoothingDteMin = SMOOTHING_DTE_MIN ;
1305 static float expoSmoothDte_auto ;
1306 static float smoothCompensatedClimbRate ;
1307 static float rawCompensation ;
1308 static float totalEnergyLowPass ;
1309 static float totalEnergyHighPass ;
1312 // difPressure (in PSI) = difPressureAdc * 0.0001525972 because 1 PSI = (8192 - 1638) = 6554 steps
1313 // difPressure (Pa) = difPressure (in PSI) * 6894.757f = difPressureAdc * 6894.757 * 0.0001525972 = difPressureAdc * 1.0520
1314 // airspeed = sqr(2 * differential_pressure / air_density) ; air density = pressure pa / (287.05 * (Temp celcius + 273.15))
1315 // so airspeed m/sec =sqr( 2 * 287.05 * differential_pressure pa * (temperature Celsius + 273.15) / pressure pa )
1316 // total energy = (m * g * altitude) + (m * airspeed * airspeed / 2) => m * 9.81 * (altitude + airspeed * airspeed / 2 /9.81)
1317 // compensation (m/sec) = airspeed * airspeed / 2 / 9.81 =
1318 // = 2 * 287.05 * difPressureAdc * 1.0520 * (temperature Celsius + 273.15) / pressure pa /2 /9.81 (m/sec) = 30.78252803 * difPressureAdc * Temp(kelv) / Press (Pa)
1319 // compensation (cm/sec) = 3078.252803 * difPressureAdc * Temp(kelv) / Press (Pa)
1321 // difPressure (Pa) = difPressureAdc * 0.061035156 because 2 kpa = 32768 steps ; so 1 step = 2000 / 32768 = 0.061035156
1322 // compensation (m/sec) = airspeed * airspeed / 2 / 9.81 =
1323 // = 2 * 287.05 * difPressureAdc * 0.061035156 * (temperature Celsius + 273.15) / pressure pa /2 /9.81 (m/sec) = 1.785947149 * difPressureAdc * Temp(kelv) / Press (Pa)
1324 // compensation (cm/sec) = 178.5947149 * difPressureAdc * Temp(kelv) / Press (Pa)
1326 // difPressure is already in Pa
1327 // airspeed (m/sec) = sqr( 2 * 287.05 * differential_pressure pa * (temperature Celsius + 273.15) / pressure pa )
1328 // compensation (m/sec) = airspeed * airspeed / 2 / 9.81 =
1329 // = 2 * 287.05 * difPressureAdc * (temperature Celsius + 273.15) / pressure pa /2 /9.81 (m/sec) =
1330 // = 29,26095821* difPressureAdc * Temp(kelv) / Press (Pa)
1331 // compensation (cm/sec) = 2926,09 * difPressureAdc * Temp(kelv) / Press (Pa)
1334 #if defined( DEBUG_DTE ) && defined(AIRSPEED_7002) // when 7002 is used
1335 static bool firstDteData = true ;
1336 if ( firstDteData ) {
1337 Serial.println(F("at , difPressADC_0 , cnt , rawAlt , rawComp , rawEnerg ")) ;
1338 firstDteData = false ;
1340 Serial.print( millis() ); Serial.print(F(" , "));
1341 Serial.print( ads_sumDifPressureAdc_0 ); Serial.print(F(" , "));
1342 Serial.print( ads_cntDifPressureAdc_0); Serial.print(F(" , "));
1345 #if defined ( AIRSPEED_4525) // when 4525 is used
1346 rawCompensation = 3078.25 * oXs_4525.airSpeedData.difPressureAdc_zero * oXs_4525.airSpeedData.temperature4525 / actualPressure ; // 3078.25 = comp = 2 * 287.05 / 2 / 9.81 * 1.0520 * 100 * Temp / Pressure
1347 #elif defined ( AIRSPEED_7002) // when 7002 is used
1348 if ( ads_cntDifPressureAdc_0 > 0 ) {
1349 ads_sumDifPressureAdc_0 = ads_sumDifPressureAdc_0 / ads_cntDifPressureAdc_0 ; // we use the average of airspeed pressure when possible and we keep the average as first value for next loop
1350 ads_cntDifPressureAdc_0 = 1 ; // so cnt is reset to 1 and not to 0
1351 rawCompensation = 178.5947149 * ads_sumDifPressureAdc_0 * ( 293 ) / actualPressure ; // 293 could be replaced by the temperature from mS5611
1353 #elif defined( AIRSPEED_SDP3X) // when SDP3X is used
1354 rawCompensation = 2926.09 * oXs_sdp3x.airSpeedData.difPressureAdc_zero * oXs_sdp3x.airSpeedData.temperature4525 / actualPressure ;
1356 rawTotalEnergy = (oXs_MS5611.varioData.rawAltitude * 0.01) + rawCompensation * compensationPpmMapped * 0.0115; // 0.01 means 100% compensation but we add 15% because it seems that it is 15% undercompensated.
1357 if (totalEnergyLowPass == 0) {
1358 totalEnergyLowPass = totalEnergyHighPass = rawTotalEnergy ;
1360 #if defined ( DEBUG_DTE ) && defined(AIRSPEED_7002)
1361 Serial.print( oXs_MS5611.varioData.rawAltitude * 0.01 ); Serial.print(F(" , "));
1362 Serial.print( rawCompensation ); Serial.print(F(" , "));
1363 Serial.print( rawTotalEnergy ); Serial.print(F(" , "));
1364 Serial.println(" ") ;
1367 // test1.value = rawCompensation;
1368 // test1.available = true ;
1370 //test2.value = rawTotalEnergy;
1371 //test2.available = true ;
1373 totalEnergyLowPass += 0.085 * ( rawTotalEnergy - totalEnergyLowPass) ;
1374 totalEnergyHighPass += 0.1 * ( rawTotalEnergy - totalEnergyHighPass) ;
1375 rawCompensatedClimbRate = ((totalEnergyHighPass - totalEnergyLowPass ) * 566667.0 ) / oXs_MS5611.varioData.delaySmooth; // 0.566667 is the parameter to be used for 0.085 and 0.1 filtering if delay is in sec
1377 // test3.value = rawCompensatedClimbRate ;
1378 // test3.available = true ;
1379 abs_deltaCompensatedClimbRate = abs(rawCompensatedClimbRate - smoothCompensatedClimbRate) ;
1380 if ( sensitivityPpmMapped > 0) smoothingDteMin = sensitivityPpmMapped ; // a value of sensitivityPpmMapped = 50 becomes a smoothing factor 0.1
1381 if ( (abs_deltaCompensatedClimbRate <= SMOOTHING_DTE_MIN_AT) || (smoothingDteMin >= SMOOTHING_DTE_MAX ) ){
1382 expoSmoothDte_auto = smoothingDteMin ;
1383 } else if (abs_deltaCompensatedClimbRate >= SMOOTHING_DTE_MAX_AT) {
1384 expoSmoothDte_auto = SMOOTHING_DTE_MAX ;
1386 expoSmoothDte_auto = smoothingDteMin + ( SMOOTHING_DTE_MAX - smoothingDteMin ) * (abs_deltaCompensatedClimbRate - SMOOTHING_DTE_MIN_AT) / (SMOOTHING_DTE_MAX_AT - SMOOTHING_DTE_MIN_AT) ;
1388 smoothCompensatedClimbRate += expoSmoothDte_auto * ( rawCompensatedClimbRate - smoothCompensatedClimbRate ) * 0.001;
1389 if ( abs( ((int32_t) smoothCompensatedClimbRate) - compensatedClimbRate.value) > VARIOHYSTERESIS ) {
1390 compensatedClimbRate.value = smoothCompensatedClimbRate ;
1392 compensatedClimbRate.available = true ; // allows SPORT protocol to transmit the value every 20 ms
1393 switchCompensatedClimbRateAvailable = true ; ; // inform readsensors() that a switchable vspeed is available
1394 // oXs_MS5611.varioData.altitudeAt20MsecAvailable = false ; // avoid to handel it each time.
1396 #ifdef DEBUGCOMPENSATEDCLIMBRATE
1397 static bool firstCompensatedClimbRate = true ;
1398 if ( firstCompensatedClimbRate ) {
1399 Serial.println(F("at, altitude, difPressureADC_zero, rawCompensation , rawTotalEnergy , delaySmooth , rawCompensatedClimbRate , compensatedClimbRate ")) ;
1400 firstCompensatedClimbRate = false ;
1402 Serial.print( micros() ) ;Serial.print(F(" , ")) ;
1403 Serial.print( oXs_MS5611.varioData.rawAltitude ) ;Serial.print(F(" , ")) ;
1404 Serial.print( oXs_4525.airSpeedData.difPressureAdc_zero ) ;Serial.print(F(" , ")) ;
1405 Serial.print( rawCompensation ) ;Serial.print(F(" , ")) ;
1406 Serial.print( rawTotalEnergy ) ;Serial.print(F(" , ")) ;
1407 Serial.print( oXs_MS5611.varioData.delaySmooth ) ;Serial.print(F(" , ")) ;
1408 Serial.print( rawCompensatedClimbRate ) ;Serial.print(F(" , ")) ;
1409 Serial.print( compensatedClimbRate.value) ;
1410 Serial.println(F(" ")) ;
1414 } // end calculateDte
1415 #endif //#if defined (VARIO) && defined ( AIRSPEED_IS_USED)
1416 // ***************************** end calculate Dte ***********************************************
1419 //****************************** Calculate averages and glider ratio ********************************************
1420 #if defined (VARIO) && defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC ) && (GLIDER_RATIO_CALCULATED_AFTER_X_SEC >= 1 ) && defined ( PPM_IS_USED ) && defined (GLIDER_RATIO_ON_AT_PPM )
1421 void calculateAverages( ){
1422 static int32_t altitudeAtT0 ; // in cm
1423 static int32_t distanceSinceT0 ; // in cm
1424 // static int32_t averageVspeedSinceT0 ; //in cm/sec
1425 static int16_t aSpeedAtT0 ;
1426 // static uint16_t secFromT0 ; // in 1/10 sec
1427 static uint32_t millisAtT0 ;
1428 static unsigned long prevAverageAltMillis ; // wait 5 sec before calculating those data ; // save when AverageAltitude has to be calculated
1429 int32_t altitudeDifference ;
1430 unsigned long currentGliderMillis ;
1431 bool aSpeedWithinTolerance = true ;
1432 static boolean previousGliderRatioPpmOn = false ;
1433 currentGliderMillis = millis() ;
1434 if ( prevAverageAltMillis == 0 ) {
1435 prevAverageAltMillis = currentGliderMillis + 5000 ;
1436 millisAtT0 = currentGliderMillis ;
1438 if ( (uint16_t) (currentGliderMillis - prevAverageAltMillis) > 500 ) { // check on tolerance has to be done
1439 if ( ( gliderRatioPpmOn) && (previousGliderRatioPpmOn) ) {
1440 altitudeDifference = oXs_MS5611.varioData.absoluteAlt.value -altitudeAtT0 ; // in cm
1441 secFromT0.value = ( currentGliderMillis - millisAtT0 ) / 100 ; // in 1/10 of sec
1442 averageVspeedSinceT0.value = altitudeDifference * 10 / secFromT0.value ; // * 10 because secFromT0 is in 1/10 of sec
1443 #ifdef AIRSPEED_4525
1444 distanceSinceT0 += oXs_4525.airSpeedData.smoothAirSpeed / (1000 / 500) ; // to adapt if delay is different.
1446 if ( secFromT0.value >= GLIDER_RATIO_CALCULATED_AFTER_X_SEC * 10 ) { // *10 because secFromT0 is in 1/10 of sec
1447 #ifdef AIRSPEED_4525
1448 gliderRatio.value = distanceSinceT0 * -10 / altitudeDifference ; // when gliderRatio is > (50.0 *10) it it not realistic (*10 is done in order to add a decimal)
1449 if ( gliderRatio.value > 500) gliderRatio.value = 0 ; //
1451 averageVspeedSinceT0.value = altitudeDifference * 10 / secFromT0.value ; // * 10 because secFromT0 is in 1/10 of sec
1455 altitudeAtT0 = oXs_MS5611.varioData.absoluteAlt.value ;
1456 millisAtT0 = currentGliderMillis ;
1457 secFromT0.value = 0 ;
1458 averageVspeedSinceT0.value = 0 ;
1459 #ifdef AIRSPEED_4525
1460 distanceSinceT0 = 0 ;
1461 gliderRatio.value = 0 ;
1465 prevAverageAltMillis = currentGliderMillis ;
1466 gliderRatio.available = true;
1467 secFromT0.available = true ;
1468 averageVspeedSinceT0.available = true ;
1469 previousGliderRatioPpmOn = gliderRatioPpmOn ;
1470 } // end check on 500 ms
1471 } // end Calculate averages
1478 #if defined (VARIO) && defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC) && GLIDER_RATIO_CALCULATED_AFTER_X_SEC >= 1
1479 #if defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC) && GLIDER_RATIO_CALCULATED_AFTER_X_SEC < 1
1480 #error when defined, GLIDER_RATIO_CALCULATED_AFTER_X_SEC must be greater or equal to 1 (sec)
1482 void calculateAverages( ){
1483 static int32_t altitudeAtT0 ; // in cm
1484 static int32_t distanceSinceT0 ; // in cm
1485 // static int32_t averageVspeedSinceT0 ; //in cm/sec
1486 static int16_t aSpeedAtT0 ;
1487 // static uint16_t secFromT0 ; // in 1/10 sec
1488 static uint32_t millisAtT0 ;
1489 static unsigned long prevAverageAltMillis = millis() + 5000 ; // wait 5 sec before calculating those data ; // save when AverageAltitude has to be calculated
1490 int32_t altitudeDifference ;
1491 unsigned long currentGliderMillis = millis() ;
1492 bool aSpeedWithinTolerance = true ;
1494 if ( (uint16_t) (currentGliderMillis - prevAverageAltMillis) > 500 ) { // check on tolerance has to be done
1495 altitudeDifference = oXs_MS5611.varioData.absoluteAlt.value -altitudeAtT0 ; // in cm
1496 secFromT0.value = ( currentGliderMillis - millisAtT0 ) / 100 ; // in 1/10 of sec
1497 #ifdef DEBUG_GLIDER8RATIO
1498 serial.print((F("secFromT0: ")); serial.println( secFromT0.value ) ;
1500 #ifdef AIRSPEED_4525
1501 if ( (aSpeedAtT0 > 300) && ( oXs_4525.airSpeedData.smoothAirSpeed > 300 ) ) {
1502 aSpeedWithinTolerance = ( (abs( oXs_4525.airSpeedData.smoothAirSpeed - aSpeedAtT0) * 100L ) / aSpeedAtT0 ) <= SPEED_TOLERANCE ;
1504 aSpeedWithinTolerance = false ;
1507 if ( ( oXs_MS5611.varioData.climbRate.value < VSPEED_MIN_TOLERANCE ) || ( oXs_MS5611.varioData.climbRate.value > VSPEED_MAX_TOLERANCE ) \
1508 || ( altitudeDifference > -10 ) || ( aSpeedWithinTolerance == false ) ) { // reset all when out of tolerance
1509 altitudeAtT0 = oXs_MS5611.varioData.absoluteAlt.value ;
1510 #ifdef AIRSPEED_4525
1511 aSpeedAtT0 = oXs_4525.airSpeedData.smoothAirSpeed ;
1512 distanceSinceT0 = 0 ;
1514 secFromT0.value = 0 ;
1515 millisAtT0 = currentGliderMillis ;
1516 averageVspeedSinceT0.value = 0 ;
1517 gliderRatio.value = 0 ;
1518 #ifdef DEBUG_GLIDER8RATIO
1519 serial.println((F("Reset"));
1522 } else { // within tolerance, calculate glider ratio and average sinking
1523 #ifdef AIRSPEED_4525
1524 distanceSinceT0 += oXs_4525.airSpeedData.smoothAirSpeed / (1000 / 500) ; // to adapt if delay is different.
1526 if ( secFromT0.value >= GLIDER_RATIO_CALCULATED_AFTER_X_SEC * 10 ) { // *10 because secFromT0 is in 1/10 of sec
1527 #ifdef AIRSPEED_4525
1528 gliderRatio.value = distanceSinceT0 * -10 / altitudeDifference ; // when gliderRatio is > (50.0 *10) it it not realistic (*10 is done in order to add a decimal)
1529 if ( gliderRatio.value > 500) gliderRatio.value = 0 ; //
1531 averageVspeedSinceT0.value = altitudeDifference * 10 / secFromT0.value ; // * 10 because secFromT0 is in 1/10 of sec
1534 prevAverageAltMillis += 500 ;
1535 gliderRatio.available = true;
1536 secFromT0.available = true ;
1537 averageVspeedSinceT0.available = true ;
1541 #endif // End of #if defined (VARIO) && defined (GLIDER_RATIO_BASED_ON_PPM )
1542 //********end calculate glider ratio************************************************************************************************
1548 #ifdef PIN_PUSHBUTTON // // ****************** check button
1549 void checkButton() {
1550 static int lastSensorVal=HIGH;
1551 static unsigned int buttonDownMs;
1552 //read the pushbutton value into a variable
1553 int sensorVal = digitalRead(PIN_PUSHBUTTON);
1554 if (sensorVal == HIGH) {
1555 // button not pressed released
1556 digitalWrite(PIN_LED, LOW);
1559 //button is currently being pressed down
1560 unsigned int buttonPressDuration=millis()-buttonDownMs;
1562 if( (buttonPressDuration>1000) and (buttonPressDuration<1200) )
1563 digitalWrite(PIN_LED, LOW); // Blink after 1 second
1565 else if( (buttonPressDuration>3000) and (buttonPressDuration<3200) )
1566 digitalWrite(PIN_LED, LOW); // Blink 1 after 3 second
1567 else if( (buttonPressDuration>3300) and (buttonPressDuration<3400) )
1568 digitalWrite(PIN_LED, LOW); // Blink 2 after 3 second
1570 else if( (buttonPressDuration>10000) and (buttonPressDuration<10200) )
1571 digitalWrite(PIN_LED, LOW); // Blink after 10 second
1572 else if( (buttonPressDuration>10300) and (buttonPressDuration<10400) )
1573 digitalWrite(PIN_LED, LOW); // Blink after 10 second
1574 else if( (buttonPressDuration>10500) and (buttonPressDuration<10600) )
1575 digitalWrite(PIN_LED, LOW); // Blink after 10 second
1576 else digitalWrite(PIN_LED, HIGH);
1578 if( (lastSensorVal==HIGH) && (sensorVal==LOW))
1579 { // Button has been pressed down
1580 buttonDownMs=millis();
1582 if( (lastSensorVal==LOW) && (sensorVal==HIGH))
1583 { // Button has been released
1584 unsigned int buttonPressDuration=millis()-buttonDownMs;
1585 //Serial.print(F("Button Released after ms:"));
1586 //Serial.println(buttonPressDuration);
1587 // Do Something after certain times the button has been pressed for....
1588 if( (buttonPressDuration>=100) and (buttonPressDuration<3000) )
1589 Reset1SecButtonPress();
1590 else if( (buttonPressDuration>=3000) and (buttonPressDuration<8000) )
1591 Reset3SecButtonPress();
1592 //else if( (buttonPressDuration>=5000) and (buttonPressDuration<10000) )
1593 else if( (buttonPressDuration>=10000) and (buttonPressDuration<15000) )
1594 Reset10SecButtonPress();
1597 lastSensorVal=sensorVal;
1598 } // End checkButton
1600 //ToDo: implement different reset actions on button press
1601 void Reset1SecButtonPress()
1604 Serial.println(F(" Reset 0.1-3 sec"));
1607 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1608 struct CURRENTDATA *cd = &oXs_Current.currentData ;
1609 // FORCE_INDIRECT(cd) ;
1610 // cd->maxMilliAmps=cd->milliAmps;
1611 // cd->minMilliAmps=cd->milliAmps;
1615 // oXs_MS5611.resetValues() ;
1619 // oXs_MS5611_2.resetValues() ;
1624 void Reset3SecButtonPress()
1627 Serial.println(F(" Reset 3-5 sec"));
1629 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1630 oXs_Current.resetValues();
1631 #elif defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined (ADS_MEASURE) && defined (ADS_CURRENT_BASED_ON)
1632 oXs_ads1115.floatConsumedMilliAmps = 0 ;
1633 oXs_ads1115.adsCurrentData.consumedMilliAmps.value = 0 ;
1635 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)
1640 void Reset10SecButtonPress()
1643 Serial.println(F("Reset 5-10")) ;
1651 #if defined (SAVE_TO_EEPROM ) and ( SAVE_TO_EEPROM == YES )
1652 /****************************************/
1653 /* SaveToEEProm => save persistant Data */
1654 /****************************************/
1655 void SaveToEEProm(){
1656 static uint8_t caseWriteEeprom = 0;
1657 #define CASE_MAX_EEPROM 2 // to adapt if thee are more data to save.
1659 Serial.print(F("Saving to EEProm:"));
1660 Serial.println(caseWriteEeprom);
1662 switch (caseWriteEeprom ) {
1663 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1665 EEPROM_writeAnything( 0 , oXs_Current.currentData.consumedMilliAmps);
1668 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)
1670 if ( ((uint16_t) consumedML) != consumedMLEeprom ) { // write in EEPROM only if there is a change
1671 consumedMLEeprom = consumedML ;
1672 EEPROM_writeAnything( 4 , consumedMLEeprom );
1676 if ( tankCapacity != tankCapacityEeprom ) { // write in EEPROM only if there is a change
1677 tankCapacityEeprom = tankCapacity ;
1678 EEPROM_writeAnything( 8 , tankCapacityEeprom );
1680 for (uint8_t idxWrite = 0 ; idxWrite < 8 ; idxWrite++ ) {
1681 if ( flowParam[idxWrite] != flowParamEeprom[idxWrite] ) {
1682 flowParamEeprom[idxWrite] = flowParam[idxWrite] ;
1683 EEPROM_writeAnything( 12 + (idxWrite * 4 ) , flowParamEeprom[idxWrite] );
1687 #endif // end A_FLOW_SENSOR_IS_CONNECTED
1690 if(caseWriteEeprom > CASE_MAX_EEPROM) caseWriteEeprom = 0;
1692 // to do : add values from ads1115 about current consumption; to do also in LoadFromEEprom()
1694 } // end SaveToEEPom
1696 /******************************************/
1697 /* LoadFromEEProm => load persistant Data */
1698 /******************************************/
1699 void LoadFromEEProm(){
1700 // Load the last saved value
1701 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
1702 EEPROM_readAnything( 0 , oXs_Current.currentData.consumedMilliAmps);
1704 Serial.println(F("Restored consumed mA"));
1707 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES )
1708 EEPROM_readAnything(4, consumedMLEeprom ) + 4 ;
1709 consumedML = consumedMLEeprom ;
1710 EEPROM_readAnything( 8, tankCapacityEeprom );
1711 tankCapacity = tankCapacityEeprom ;
1712 for (uint8_t idxRead = 0 ; idxRead < 8 ; idxRead++ ) {
1713 EEPROM_readAnything( 12 + ( idxRead * 4) , flowParamEeprom[idxRead] );
1714 flowParam[idxRead] = flowParamEeprom[idxRead] ;
1718 Serial.print(F("Restored consumed= ")); Serial.print(consumedMLEeprom) ; Serial.print(F(" Tank=")) ; Serial.print(tankCapacityEeprom) ; Serial.print(F(" Param=")) ;
1719 for (uint8_t idxRead = 0 ; idxRead < 8 ; idxRead++ ) {
1720 Serial.print(flowParamEeprom[idxRead]) ; Serial.print(" ") ;
1722 Serial.println(" ");
1724 Serial.print(F(" consumed= ")); Serial.print(consumedML) ; Serial.print(F(" Tank=")) ; Serial.print(tankCapacity) ; Serial.print(F(" Param=")) ;
1725 for (uint8_t idxRead = 0 ; idxRead < 8 ; idxRead++ ) {
1726 Serial.print(flowParam[idxRead]) ; Serial.print(" ") ;
1728 Serial.println(" ");
1732 #endif //SAVE_TO_EEPROM
1735 /***************************************************************/
1736 /* ProcessPPMSignal => read PPM signal from receiver and */
1737 /* use its value to adjust sensitivity and other parameters */
1738 /***************************************************************/
1739 #if defined ( PPM_IS_USED )
1741 void ProcessPPMSignal(){
1742 boolean getNewPpm = false ; // become true if a new ppm value has been acquired
1743 #if defined( PIN_PPM ) // when ppm is read from a rx channel
1744 ReadPPM(); // set ppmus to 0 if ppm is not available or has not been collected X time, other fill ppmus with the (max) pulse duration in usec
1745 #ifdef DEBUGFORCEPPM
1746 //for debuging ppm without having a connection to ppm; force ppm to a value
1747 ppmus = ( PPM_MIN_100 + PPM_PLUS_100) / 2 ; // force a ppm equal to 0 (neutral)
1748 #endif // end of DEBUGFORCEPPM
1749 if (ppmus>0){ // if a value has been defined for ppm (in microseconds)
1750 ppm.value = map( ppmus , PPM_MIN_100, PPM_PLUS_100, -100 , 100 ) ; // map ppm in order to calibrate between -100 and 100
1751 ppm.available = true ;
1754 #else // so when done via SPORT (defined ( PPM_VIA_SPORT ) && ( PROTOCOL == FRSKY_SPORT ) || (PROTOCOL == FRSKY_SPORT_HUB) ) )
1755 // newPpm.value and .available are already filled in readSensor() when new values are received
1756 if (newPpm.available ){
1757 ppm.value = newPpm.value ;
1758 ppm.available = true ;
1759 newPpm.available = false ;
1764 getNewPpm = false ; // reset the indicator saying there is a new ppm to handle.
1765 #ifdef DEBUGPPMVALUE
1766 Serial.print(micros()); Serial.print(F(" ppm=")); Serial.println(ppm.value);
1768 #ifdef SEQUENCE_OUTPUTS
1769 if ( ( ( ppm.value - prevPpm) > 3 ) || (( prevPpm - ppm.value) > 3 ) ) { // handel ppm only if it changes by more than 3
1770 prevPpm = ppm.value ;
1773 #else // so if Sequence is not used and so PPM is used for Vario sensitivity , vario compensation , airspeed reset , glider ratio and/or vario source selection
1774 if ( ( ( ppm.value - prevPpm) < 4 ) && ( ( prevPpm - ppm.value) < 4 ) ) { // test if new value is quite close to previous in order to avoid unstabel handling
1776 #if defined ( VARIO_PRIMARY) && defined ( VARIO_SECONDARY) && defined (VARIO ) && ( defined (VARIO2) || defined ( AIRSPEED_IS_USED) || defined (USE_6050) ) && defined (PPM_IS_USED)
1777 if ( (ppm.value >= (SWITCH_VARIO_MIN_AT_PPM - 4)) && (ppm.value <= (SWITCH_VARIO_MAX_AT_PPM + 4)) ) {
1778 selectedVario = VARIO_PRIMARY ;
1779 } else if ( ( ppm.value <= (4 - SWITCH_VARIO_MIN_AT_PPM)) && (ppm.value >= (- 4 - SWITCH_VARIO_MAX_AT_PPM)) ) {
1780 selectedVario = VARIO_SECONDARY ;
1782 #ifdef DEBUG_SELECTED_VARIO
1783 Serial.print(F("selected vario=")); Serial.println(selectedVario);
1785 #endif // endif defined ( VARIO_PRIMARY) && defined ( VARIO_SECONDARY) && ...
1787 #if defined (VARIO) || defined (VARIO2)
1788 if ( (abs(ppm.value) >= (SENSITIVITY_MIN_AT_PPM - 4)) && ( abs(ppm.value) <= (SENSITIVITY_MAX_AT_PPM + 4)) ) {
1789 sensitivityPpmMapped = map( constrain(abs(ppm.value), SENSITIVITY_MIN_AT_PPM , SENSITIVITY_MAX_AT_PPM ), SENSITIVITY_MIN_AT_PPM , SENSITIVITY_MAX_AT_PPM , SENSITIVITY_PPM_MIN , SENSITIVITY_PPM_MAX); // map value and change stepping to 10
1791 oXs_MS5611.varioData.sensitivityPpm = sensitivityPpmMapped ; // adjust sensitivity when abs PPM is within range
1793 #if defined( VARIO2)
1794 oXs_MS5611_2.varioData.sensitivityPpm = sensitivityPpmMapped ;
1797 #endif // end else defined (VARIO) || defined (VARIO2)
1800 #if defined ( AIRSPEED_IS_USED) // adjust compensation
1801 if ( (abs(ppm.value) >= (COMPENSATION_MIN_AT_PPM - 4)) && ( abs(ppm.value) <= (COMPENSATION_MAX_AT_PPM + 4)) ) {
1802 compensationPpmMapped = map( constrain(abs(ppm.value), COMPENSATION_MIN_AT_PPM , COMPENSATION_MAX_AT_PPM ), COMPENSATION_MIN_AT_PPM , COMPENSATION_MAX_AT_PPM , COMPENSATION_PPM_MIN , COMPENSATION_PPM_MAX); // map value and change stepping to 10
1803 if (compensationPpmMapped == COMPENSATION_PPM_MIN ) compensationPpmMapped = 0 ; // force compensation to 0 when compensation = min
1805 if ( ( ppm.value >= (AIRSPEED_RESET_AT_PPM - 4)) && ( ppm.value <= (AIRSPEED_RESET_AT_PPM + 4)) ) {
1806 #if defined (AIRSPEED_4525) // if 4525 is used
1807 oXs_4525.airSpeedData.airspeedReset = true ; // allow a recalculation of offset 4525
1808 #elif defined (AIRSPEED_7002) // when 7002 is used
1809 oXs_ads1115.adsAirSpeedData.airspeedReset = true ; // allow a recalculation of offset mvxp7002 connected to ads1115
1810 #endif // for SDP3X sensor , there is no need for a reset
1812 #endif // end AIRSPEED_IS_USED
1814 #if defined ( A_FLOW_SENSOR_IS_CONNECTED ) && ( A_FLOW_SENSOR_IS_CONNECTED == YES)
1815 if ( ( ppm.value >= (FLOW_SENSOR_RESET_AT_PPM - 4)) && ( ppm.value <= (FLOW_SENSOR_RESET_AT_PPM + 4)) ) {
1816 consumedML = 0 ; // reset the flow counter
1821 #if defined (GLIDER_RATIO_CALCULATED_AFTER_X_SEC ) && defined ( GLIDER_RATIO_ON_AT_PPM )
1822 if ( (ppm.value >= (GLIDER_RATIO_ON_AT_PPM - 4)) && (ppm.value <= (GLIDER_RATIO_ON_AT_PPM + 4)) ) {
1823 gliderRatioPpmOn = true ;
1825 gliderRatioPpmOn = false ;
1829 } // end ppm == prePpm
1830 prevPpm = ppm.value ;
1831 #endif // end of #ifdef SEQUENCE_OUTPUTS & #else
1832 } // end if (ppm.available )
1834 } // end processPPMSignal
1837 /**********************************************************/
1838 /* ReadPPM => read PPM signal from receiver */
1839 /* pre-evaluate its value for validity */
1840 /**********************************************************/
1842 #ifdef PPM_INTERRUPT
1843 uint16_t StartTime ;
1844 volatile uint16_t time1 ; // pulsewidth (in millisec)
1845 //volatile uint8_t PulseTime ; // A byte to avoid
1846 volatile uint32_t ppmPulseMicros ; // timestamp when falling edges occurs in micros sec
1847 volatile boolean PulseTimeAvailable = false ;
1849 #if defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES)
1850 uint32_t ppmTimestampPrev ; //Timestamp (micros) of the previous PPM signal (used to check that the delay between 2 pulses is about 18ms)
1851 uint16_t widthPrev ; // width of the previous PWM pulse ( micros)
1852 uint8_t lqError ; // count the number of errors (new PWM pulses having the same value as the previous one)
1853 uint8_t lqCount ; // count total number of PWM pulses (to calculate a %); use to reset the counters after XXX (e.g.50) PWM
1854 uint8_t prevFrameInError ; // boolean ; true when the previous PWM was wrong (used to calculate consecutive errors)
1855 uint8_t lqConsecutiveError ; // count number of consecutive PWM errors
1856 uint8_t lqConsecutiveErrorMax ; // keep the max of consecutive errors within a sequence
1858 extern uint16_t lastTimerValue ;
1859 extern uint32_t TotalMicros ;
1862 #if PIN_PPM == 2 // When pin 2 is used, arduino handle INT0 (see datasheet)
1863 ISR(INT0_vect, ISR_NOBLOCK) // NOBLOCK allows other interrupts to be served when this one is activated
1864 #else //// When pin 3 is used, arduino handle INT1
1865 ISR(INT1_vect, ISR_NOBLOCK)
1868 uint8_t oReg = SREG; // store SREG value
1870 uint16_t time = TCNT1 ; // Read timer 1
1871 uint16_t lastTimerValueTemp = lastTimerValue ; // save the value to avoid any change in interrupt (not sure it is required
1872 uint32_t TotalMicrosTemp = TotalMicros ; // save the value to avoid any change in interrupt (not sure it is required
1873 SREG = oReg ; // restore SREG value
1874 if ( EICRA & PPM_INT_EDGE ) // a rising edge occurs
1876 StartTime = time ; // save the value of the timer
1877 EICRA &= ~PPM_INT_EDGE ; // allow a falling edge to generate next interrupt
1879 else // a falling edge occurs
1881 uint16_t elapsed = time - lastTimerValueTemp ;
1882 #if F_CPU == 20000000L // 20MHz clock
1883 #error Unsupported clock speed
1884 #elif F_CPU == 16000000L // 16MHz clock
1885 ppmPulseMicros = TotalMicrosTemp + ( elapsed >> 4 ) ;
1886 #elif F_CPU == 8000000L // 8MHz clock
1887 ppmPulseMicros = TotalMicrosTemp + ( elapsed >> 3 ) ;
1889 #error Unsupported clock speed
1893 #if F_CPU == 20000000L // 20MHz clock
1894 #error Unsupported clock speed
1895 #elif F_CPU == 16000000L // 16MHz clock
1896 time>>= 4 ; // delay in usec
1897 #elif F_CPU == 8000000L // 8MHz clock
1898 time >>= 3 ; // delay in usec
1900 #error Unsupported clock speed
1903 PulseTimeAvailable = true ;
1904 EICRA |= PPM_INT_EDGE ; // allow a Rising edge to generate next interrupt
1908 void ReadPPM() { // set ppmus to 0 if ppm is not available or has not been collected X time, other fill ppmus with the (max) pulse duration in usec
1909 static uint8_t ppmIdx ;
1910 static uint16_t ppmTemp ;
1911 static uint16_t ppmMax ; // highest value of ppmTemp received ; Some ppm measurement are wrong (to low) because there are some interrupt some
1912 ppmus = 0 ; // reset the pulse width
1914 if ( PulseTimeAvailable ) { // if new pulse is available
1915 #define PPM_COUNT_MAX 5 // select the max of 5 ppm (so once every 100 msec
1916 uint8_t oReg = SREG ; // save Status register
1918 ppmTemp = time1 ; // use values from interrupt
1919 uint32_t ppmTimestamp = ppmPulseMicros ;
1920 PulseTimeAvailable = false ;
1921 SREG = oReg ; // restore Status register
1922 #if defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES)
1923 uint32_t pulseInterval = (ppmTimestamp - ppmTimestampPrev) ;
1924 if ( (pulseInterval > PULSE_INTERVAL_MIN) && (pulseInterval < PULSE_INTERVAL_MAX ) ) {
1925 if ( abs (( int16_t) (ppmTemp - widthPrev)) <= WIDTH_ERROR_MAX ) {
1927 if ( prevFrameInError == true) {
1928 lqConsecutiveError++ ; // count consecutive errors
1929 if (lqConsecutiveError > lqConsecutiveErrorMax) {
1930 lqConsecutiveErrorMax = lqConsecutiveError ;
1934 prevFrameInError = true ;
1936 lqConsecutiveError = 0 ; // reset the counter when a valid PWM is received
1937 prevFrameInError = false ; // reset the flag when we get a valid PWM signal
1940 #if defined ( DEBUG_RF_LINK_QUALITY )
1941 Serial.print("Read ppm at ") ; Serial.print(ppmTimestamp) ;
1942 Serial.print(" Delay= ") ; Serial.print(pulseInterval) ;
1943 Serial.print(" Process at ") ; Serial.print(millis()) ;
1944 Serial.print(" Width= ") ; Serial.print(ppmTemp) ;
1945 Serial.print(" delta=") ; Serial.print( abs (( int16_t) (ppmTemp - widthPrev)) ) ;
1946 Serial.print(" lqC=") ; Serial.print( lqCount ) ;
1947 Serial.print(" lqE=") ; Serial.print( lqError ) ;
1948 Serial.print(" cons=") ; Serial.print( lqConsecutiveError) ;
1949 Serial.print(" Max=") ; Serial.print( lqConsecutiveErrorMax) ;
1950 Serial.print(" %=") ; Serial.println( ( ( (LQ_COUNT_MAX - (uint16_t) lqError)) * 100 ) / LQ_COUNT_MAX ) ;
1952 if ( lqCount >= LQ_COUNT_MAX ) {
1953 #if defined ( FILL_TEST_1_2_WITH_LQ )
1954 test1.value = ( ( (LQ_COUNT_MAX - (uint16_t) lqError)) * 100 ) / LQ_COUNT_MAX ;
1955 test1.available = true ;
1956 test2.value = lqConsecutiveErrorMax ;
1957 test2.available = true ;
1958 #endif // FILL_TEST_1_2_WITH_LQ
1961 lqConsecutiveError = 0 ;
1962 lqConsecutiveErrorMax = 0 ;
1963 // to do : save the values in data that can be transmitted
1966 ppmTimestampPrev = ppmTimestamp ;
1967 widthPrev = ppmTemp ;
1968 #endif // defined ( MEASURE_RF_LINK_QUALITY ) && ( MEASURE_RF_LINK_QUALITY == YES)
1970 if ( ppmIdx >= PPM_COUNT_MAX ) {
1971 ppmus = ppmMax ; // we keep the highest value
1976 if( ppmTemp > ppmMax ) ppmMax = ppmTemp ; // save the highest value
1977 } // end test on ppmIdx
1978 } // end test on PulseTimeAvailable
1980 #endif // end #ifdef PPM_INTERRUPT
1985 #if defined ( A_FLOW_SENSOR_IS_CONNECTED )
1986 #if ( A_FLOW_SENSOR_IS_CONNECTED == YES) // flowMeterCnt is updated by interrupt PCINT0
1990 float mapFlowCorr( uint8_t idx) { // calculate correction factor depending on current flow
1991 uint8_t flowCorrIdx = idx + TX_FIELD_FLOW_CORR_1 ;
1992 return ( flowParam[flowCorrIdx ] + ( currentFlow - flowParam[idx]) / (flowParam[idx + 1] - flowParam[idx]) * (flowParam[flowCorrIdx + 1] - flowParam[flowCorrIdx ] ) ) ;
1995 void checkFlowParam() {
1996 if ( (tankCapacity % 50) != 0) tankCapacity = ( tankCapacity / 50 ) * 50 ; // set tank capacity in steps of 50 ml
1997 tankCapacity = constrain( tankCapacity , 100 , 3000 ) ;
1998 for (uint8_t i = 0; i < 4 ; i++) {
1999 if ( ( flowParam[i] % 5) != 0 ) flowParam[i] = ( flowParam[i] / 5 ) * 5 ;
2000 flowParam[i] = constrain( flowParam[i] , 30 , 800 + (5 * i)) ;
2001 flowParam[ i+ 4] = constrain( flowParam[i+4] , -100 , +100 ) ;
2003 for (uint8_t i= 1 ; i < 4 ; i++) {
2004 if ( flowParam[i] <= flowParam[i - 1] ) flowParam[i] = flowParam[i - 1] + 5 ;
2008 void processFlowMeterCnt () { // get the flowmeter counter once per X seconds, convert it in mili liter and activate the flag saying a new value is available
2009 // save the result in eeprom is done in main loop for all data to be saved in EEPROM
2010 #define FLOW_DELAY 2000 // calculates once per 2 sec
2012 uint16_t flowMeterCntCopy ;
2013 static uint32_t prevFlowMillis ;
2014 uint32_t currentFlowMillis = millis() ;
2015 if ( ( currentFlowMillis - prevFlowMillis ) > FLOW_DELAY ) {
2016 prevFlowMillis = currentFlowMillis ;
2017 uint8_t oReg = SREG ; // save status register
2018 cli() ; // avoid interrupt to ensure that counter is consistent
2019 flowMeterCntCopy = flowMeterCnt ;
2021 SREG = oReg ; // restore status register
2022 sei() ; // allow interrupt again
2023 #ifdef DEBUG_SIMULATE_FLOW_SENSOR
2024 flowMeterCntCopy = 100 ; // force a fix value in order to test without a flow sensor
2026 #define CONVERT_TO_ML_PER_MIN 30.0 / ( PULSES_PER_ML * FLOW_DELAY / 1000.0 ) // 30 = 60 /2 : 60 = 60 sec/min, 1000 = msec instead of sec , 2 because counter is increased by all changes (rise and fall)
2027 currentFlow = ((float) flowMeterCntCopy) * CONVERT_TO_ML_PER_MIN ; // expected value should be between 15 and 800 ml/min for the conrad flow meter
2028 if (currentFlow < flowParam[TX_FIELD_FLOW_1] ) {
2029 flowCorr = flowParam[TX_FIELD_FLOW_CORR_1] ; // flow crrection is supposed to be in %
2030 } else if (currentFlow < flowParam[TX_FIELD_FLOW_2] ) {
2031 flowCorr = mapFlowCorr( TX_FIELD_FLOW_1 ) ;
2032 } else if (currentFlow < flowParam[TX_FIELD_FLOW_3] ) {
2033 flowCorr = mapFlowCorr( TX_FIELD_FLOW_2 ) ;
2034 } else if (currentFlow < flowParam[TX_FIELD_FLOW_4] ) {
2035 flowCorr = mapFlowCorr( TX_FIELD_FLOW_3 ) ;
2037 flowCorr = flowParam[TX_FIELD_FLOW_CORR_4] ;
2039 currentFlow = ((float) currentFlow ) * ( 100.0 + flowCorr) * 0.01 ; // 0.01 because flowCorr is in %)
2040 actualFlow.value = currentFlow ;
2041 actualFlow.available= true ;
2042 consumedML += currentFlow * FLOW_DELAY / 60000.0 ;
2043 if ( consumedML > tankCapacity ) consumedML = tankCapacity ;
2044 remainingFuelML.value = tankCapacity - consumedML ;
2045 remainingFuelML.available= true ;
2046 fuelPercent.value = remainingFuelML.value * 100 / tankCapacity ; // in percent
2047 fuelPercent.available= true ;
2048 newFlowAvailable = true ; // this is use to fill TEST_1, 2, 3 to avoid conflict with JETI protocol which uses 3 individual flags
2049 #if defined ( DEBUG) && defined (DEBUG_FLOW_SENSOR)
2050 Serial.print(" At " ); Serial.print( prevFlowMillis ) ;
2051 Serial.print(" flcnt " ); Serial.print( flowMeterCntCopy ) ;
2052 Serial.print(" remain " ); Serial.print( remainingFuelML.value ) ;
2053 Serial.print(" ml/min " ); Serial.print( currentFlow ) ;
2054 Serial.print(" cons " ); Serial.println( consumedML ) ;
2058 } // end processFlowMeterCnt
2061 ISR(PCINT0_vect, ) { // a pin change interrupt occurs on the pin being connected to the flow sensor; we do not use ISR_NOBLOCK because the interrupt is very short
2062 flowMeterCnt++ ; // we increase the counter of pin change.
2067 #endif // end A_FLOW_SENSOR_IS_CONNECTED
2071 #ifdef SEQUENCE_OUTPUTS
2072 void setNewSequence() { // ********** setNewSequence( ) ************** handle a new ppm value
2073 // int8_t prevPpmMain = -100 ; // this value is unusual; so it will forced a change at first call
2074 int16_t ppmAbs = ppm.value + 114 ;
2075 int8_t ppmMain = ppmAbs / 25 ;
2076 int8_t ppmRest = ppmAbs % 25 ;
2077 if ( (ppmRest > 4) && (ppmMain >= 0) && (ppmMain <= 9) && (ppmMain != prevPpmMain) ) { // process only if valid and different from previous
2078 #ifdef DEBUGSEQUENCE
2079 Serial.println(F(" "));
2080 Serial.print(F("ppmMain=")); Serial.println(ppmMain );
2081 //Serial.println(F(" "));
2083 prevPpmMain = ppmMain ;
2084 seqRef = sequencePointer[ppmMain] ; // seqTab contains pointers to the sequence array
2085 seqMax = sequenceMaxNumber[ppmMain] ;
2088 #ifdef DEBUGSEQUENCE
2089 test1.value = ppmMain;
2090 test1.available = true ;
2096 void checkSequence() {
2098 uint8_t portbTempValue ;
2099 static uint16_t seqDelay ;
2100 static unsigned long currentMillis ;
2101 static unsigned long nextSequenceMillis ;
2102 #ifdef DEBUGSEQUENCE
2103 // Serial.print(F("seqState=")); Serial.println(seqState );
2106 if ( seqState == 0 ) {
2107 portbTempValue = *(seqRef + 1);
2108 seqDelay = *(seqRef ) * sequenceUnit; //
2109 portbTemp = (~sequenceOutputs) & PORTB; // reset the bit that are controlled
2110 PORTB = portbTemp | ( portbTempValue & sequenceOutputs ); // set the bit as defined in the sequence if they have to be controlled
2111 #ifdef DEBUGSEQUENCE
2112 Serial.print(F("seqStep=")); Serial.println( seqStep );
2113 Serial.print(F("portbTempValue=")); Serial.println( portbTempValue );
2114 Serial.print(F("seqDelay=")); Serial.println( seqDelay );
2115 Serial.print(F("portbTemp=")); Serial.println( portbTemp );
2116 Serial.print(F("PORTB=")); Serial.println( portbTempValue & sequenceOutputs );
2119 if (seqDelay == 0 ) {
2120 seqState = 2 ; // set state to sequence stopped if delay is 0
2122 seqState = 1 ; //says that sequence is running
2123 nextSequenceMillis = millis() + seqDelay ;
2125 } else if ( seqState == 1 ) { // when sequence is running, check the timestamp to activate next sequence step
2126 currentMillis = millis() ;
2127 if ( currentMillis > nextSequenceMillis ) {
2128 seqStep += 2 ; // increase by 2 because there are 2 parameters per step
2129 if ( (seqStep + 1) >= seqMax ) seqStep = 0 ; // return to 0 if end is reached
2130 portbTempValue = *(seqRef + 1 + seqStep );
2131 seqDelay = *(seqRef + seqStep) * sequenceUnit ;
2132 portbTemp = (~sequenceOutputs) & PORTB; // reset the bit that are controlled
2133 PORTB = portbTemp | ( portbTempValue & sequenceOutputs ); // set the bit as defined in the sequence if they have to be controlled
2134 if (seqDelay == 0 ) {
2135 seqState = 2 ; // set state to sequence stopped if delay is 0
2137 seqState = 1 ; //says that sequence is running
2138 nextSequenceMillis = currentMillis + seqDelay ;
2140 #ifdef DEBUGSEQUENCE
2141 Serial.print(F("At")); Serial.print( currentMillis );
2142 Serial.print(F(" seqStep=")); Serial.println( seqStep );
2143 Serial.print(F("portbTempValue=")); Serial.println( portbTempValue );
2144 Serial.print(F("seqDelay=")); Serial.println( seqDelay );
2145 Serial.print(F("portbTemp=")); Serial.println( portbTemp );
2146 Serial.print(F("PORTB=")); Serial.println( portbTempValue & sequenceOutputs );
2149 } // end ( currentMillis > nextSequenceMillis )
2150 } // end ( seqState == 0 ) or ( seqState == 1 )
2151 } // end checkSequence()
2152 #endif // end SEQUENCE_OUTPUTS
2157 //************************************************************ OutputToSerial
2158 void OutputToSerial(){
2159 //#define DEBUGMINMAX 0
2160 //#define DEBUGVREF 0
2161 //#define DEBUGDIVIDER 0
2162 //#define DEBUGTEMP 0
2167 Serial.print(F(" Sensitivity PPM="));
2168 Serial.print( oXs_MS5611.varioData.sensitivityPpm);
2169 Serial.print(F(" ;absAlt="));
2170 Serial.print( ( (float)oXs_MS5611.varioData.absoluteAlt.value)/100);
2171 Serial.print(F(" ;Vspd="));
2172 Serial.print( ( (float)oXs_MS5611.varioData.climbRate.value)/100);
2173 Serial.print(F(" ;Temp="));
2174 Serial.print((float)oXs_MS5611.varioData.temperature/10);
2177 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
2178 Serial.print(F(" ;mA="));
2179 Serial.print( ( ((float)(int32_t)(oXs_Current.currentData.milliAmps.value))) );
2181 Serial.print(F(" ;mAh="));
2182 Serial.print( oXs_Current.currentData.consumedMilliAmps.value);
2183 #endif // defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
2185 Serial.println("H.");
2191 /***********************************************/
2192 /* freeRam => Cook coffee and vaccuum the flat */
2193 /***********************************************/
2195 extern int __heap_start, *__brkval;
2197 return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);