1 // file for FRSKY telemetry (SPORT and HUB)
3 #include "oXs_out_frsky.h"
4 #if defined(PROTOCOL) && ( (PROTOCOL == FRSKY_SPORT) || ( PROTOCOL == FRSKY_HUB ) || (PROTOCOL == FRSKY_SPORT_HUB ) ) //if Frsky protocol is used
7 // ************************* Several parameters to help debugging
8 //#define DEBUG_LOAD_SPORT
10 //#define DEBUG_SPORT_RECEIVED
11 //#define DEBUGSENDDATA
12 //#define DEBUGSENDSENSITIVITY
13 //#define DEBUGNEXTVALUETYPE
14 //#define DEBUGSENDDATADELAY
15 //#define DEBUGTRANSMITDELAY
16 //#define DEBUGLOADVALUETOSEND
17 //#define DEBUGLOADVALUETOSENDALTIMETER
18 //#define DEBUGLOADVALUETOSENDVERTICALSPEED
19 //#define DEBUGLOADVALUETOSENDALTIMETER_2
20 //#define DEBUGLOADVALUETOSENDVERTICALSPEED_2
22 //#define DEBUGLOADVALUETOSENDVOLT1
23 //#define DEBUGLOADVALUETOSENDVOLT2
24 //#define DEBUGLOADVALUETOSENDSENSITIVITY
25 //#define DEBUGLOADVALUETOSENDALT_OVER_10_SEC
26 //#define DEBUGLOADVALUETOSENDSENSITIVITY_2
27 //#define DEBUGLOADVALUETOSENDALT_OVER_10_SEC_2
29 //#define DEBUGLOADVALUETOSENDCELL_1_2
30 //#define DEBUGLOADVALUETOSENDCELL_3_4
31 //#define DEBUGLOADVALUETOSENDCELL_5_6
32 //#define DEBUGLOADVALUETOSENDCURRENTMA
33 //#define DEBUGLOADVALUETOSENDMILLIAH
34 //#define DEBUGHUBPROTOCOL
35 //#define DEBUGWITHFIXVALUE // for SPORT protocol only; send a value varying continuously (cycling) between min and max value (see code below)
38 extern OXS_MS5611 oXs_MS5611
;
39 extern OXS_VOLTAGE oXs_Voltage
;
40 extern OXS_CURRENT oXs_Current
;
41 extern OXS_4525 oXs_4525
;
42 extern OXS_SDP3X oXs_sdp3x
;
43 #if defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(ADS_CURRENT_BASED_ON)
44 extern CURRENTDATA adsCurrentData
;
47 extern unsigned long micros( void ) ;
48 extern unsigned long millis( void ) ;
49 extern void delay(unsigned long ms
) ;
51 //used only by Sport protocol
52 extern uint8_t volatile sportData
[7] ;
53 uint8_t volatile TxData
[8] ;
54 uint8_t volatile TxDataIdx
;
56 extern uint8_t LastRx
;
57 static volatile uint8_t prevLastRx
; // just for testing
59 uint8_t volatile sportDataLock
;
60 extern uint8_t volatile sendStatus
;
61 #if defined(VFAS_SOURCE)
62 struct ONE_MEASUREMENT vfas
;
65 #if ( defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES) ) || ( defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(ADS_CURRENT_BASED_ON))
66 struct ONE_MEASUREMENT sport_currentData
;
69 #if defined(GPS_INSTALLED)
70 struct ONE_MEASUREMENT sport_gps_lon
;
71 struct ONE_MEASUREMENT sport_gps_lat
;
72 struct ONE_MEASUREMENT sport_gps_alt
;
73 struct ONE_MEASUREMENT sport_gps_speed
;
74 struct ONE_MEASUREMENT sport_gps_course
;
75 #if defined GPS_TRANSMIT_TIME
76 struct ONE_MEASUREMENT sport_gps_date
;
77 struct ONE_MEASUREMENT sport_gps_time
;
82 extern struct ONE_MEASUREMENT sport_rpm
;
84 //used only by Hub protocol
85 //static int fieldToSend ;
86 //static bool fieldOk ;
87 extern uint8_t volatile hubData
[MAXSIZEBUFFER
] ;
88 //extern uint8_t volatile hubCurrentData ; //index of current data
89 extern uint8_t volatile hubMaxData
; // max number of data prepared to be send
92 //Used by both protocols
93 volatile bool sportAvailable
= false ;
94 //int fieldContainsData[][5] = { SETUP_FRSKY_DATA_TO_SEND } ; // contains the set up of field to be transmitted
95 //int numberOfFields = sizeof(fieldContainsData) / sizeof(fieldContainsData[0]) ;
96 //static uint16_t convertToSportId[15] = { FRSKY_SPORT_ID } ; // this array is used to convert an index inside fieldContainsData[][0] into the SPORT field Id (or defaultfield)
97 //static uint8_t convertToHubId[15] = { FRSKY_HUB_ID } ; //// this array is used to convert an index inside fieldContainsData[][0] into the Hub field Id (or defaultfield)
98 //static uint8_t currentFieldToSend = 0 ;
99 extern volatile uint8_t state
; //!< Holds the state of the UART.
102 #ifdef DEBUG_SPORT_RECEIVED
103 volatile uint16_t sportRcvCount
;
108 OXS_OUT::OXS_OUT(uint8_t pinTx
,HardwareSerial
&print
)
110 OXS_OUT::OXS_OUT(uint8_t pinTx
)
115 printer
= &print
; //operate on the address of print
120 // **************** Setup the FRSky OutputLib *********************
121 void OXS_OUT::setup() {
122 // here we look if sport is available or not; when available, sport protocol must be activated otherwise hub protocol
124 TRXDDR
&= ~( 1 << PIN_SERIALTX
) ; // PIN is input, tri-stated.
125 TRXPORT
&= ~( 1 << PIN_SERIALTX
) ; // PIN is input, tri-stated.
126 #if PIN_SERIALTX == 7
127 ADCSRB
&= ~(1<<ACME
) ;
128 ACSR
= (1<<ACBG
) | (1 << ACIS1
) ;
129 DIDR1
|= (1<<AIN1D
) ;
132 #if defined( PROTOCOL ) && ( PROTOCOL == FRSKY_SPORT )
135 sportAvailable
= true ; // force the SPORT protocol
136 #elif defined(PROTOCOL) && ( PROTOCOL == FRSKY_HUB )
138 sportAvailable
= false ; // force the HUB protocol
139 #else // we will detect automatically if SPORT is available
140 // Activate pin change interupt 2 on Tx pin
141 #if PIN_SERIALTX == 4
142 PCMSK2
|= 0x10 ; // IO4 (PD4) on Arduini mini
143 #elif PIN_SERIALTX == 2
144 PCMSK2
|= 0x04 ; // IO2 (PD2) on Arduini mini
146 #if PIN_SERIALTX != 7
147 #error "This PIN is not supported"
149 #endif // test on PIN_SERIALTX
150 delay(1500) ; // this delay has been added because some users reported that SPORT is not recognised with a X6R ; perhaps is it related to the EU firmware (2015)
151 #ifdef DEBUG_SPORT_PIN
152 digitalWrite(DEBUG_SPORT_PIN
, HIGH
); // Set the pulse used during SPORT detection to HIGH because detecttion is starting
155 #if PIN_SERIALTX == 7
156 ACSR
|= ( 1<<ACI
) ; // clear pending interrupt
158 PCIFR
= (1<<PCIF2
) ; // clear pending interrupt
160 delay(20) ; // to see if SPORT is active, we have to wait at least 12 msec and check bit PCIF2 from PCIFR; if bit is set, it is SPORT
161 #ifdef DEBUG_SPORT_PIN
162 digitalWrite(DEBUG_SPORT_PIN
, LOW
); // Set the pulse used during SPORT detection to LOW because detection is done
164 #if PIN_SERIALTX == 7
165 if ( ( ACSR
& (1<<ACI
)) == 0 ) {
167 if ( ( PCIFR
& (1<<PCIF2
)) == 0 ) {
169 sportAvailable
= false ;
173 sportAvailable
= true ;
177 #endif // end test on FRSKY
179 printer
->print(F("FRSky Output Module: TX Pin="));
180 printer
->println(_pinTx
);
181 printer
->print(F("Sport protocol= "));
182 printer
->println(sportAvailable
);
187 void OXS_OUT::sendData() {
188 #if defined( PROTOCOL ) && ( PROTOCOL == FRSKY_SPORT )
190 #elif defined(PROTOCOL) && ( PROTOCOL == FRSKY_HUB )
192 #else // we will detect automatically if SPORT is available
193 if (sportAvailable
) {
202 //****************************************************** Look which value can be transmitted and load it in a set of fields used by interrupt routine
203 // oXs reacts on 6 sensorId being send by the Rx
204 // In the main loop, we look periodically (calling function sendData ) if a new data has to be preloaded for each of the 6 sensors
205 // It is the ISR that send the data and set a flag (to 1) in a bit of "frskyStatus" to say that a new data has to be loaded (bit 0...5 are used).
206 // The main loop set the bit to 0 when a data has been loaded.
208 #if defined( PROTOCOL ) && ( ( PROTOCOL == FRSKY_SPORT ) || ( PROTOCOL == FRSKY_SPORT_HUB ) )
210 volatile uint8_t idToReply
; // each bit (0..5) reports (set to 1) if oXs has to reply to a pooling on a specific Id (this has been added because oXs has to reply with all 0x00 when he has not yet data available
211 volatile uint8_t frskyStatus
= 0x3F ; //Status of SPORT protocol saying if data is to load in work field (bit 0...5 are used for the 6 sensorId), initially all data are to be loaded
212 uint8_t currFieldIdx
[6] = { 0 , 2, 5 , 10 , 17 , 21 } ; // per sensor, say which field has been loaded the last time (so next time, we have to search from the next one)
213 const uint8_t fieldMinIdx
[7] = { 0 , 2, 5 , 10 , 17 , 21 , 24 } ; // per sensor, say the first field index ; there is one entry more in the array to know the last index
214 const uint8_t fieldId
[24] = { 0x10 , 0x11 , 0x30 , 0x30 , 0x30 , 0x21 , 0x20 , 0x60 ,0x90, 0x91 , 0x80, 0x80 , 0x82 , 0x83 , 0x84 , 0x85, 0x85, 0x50 , 0x40 , 0x41 , 0xA0 , 0x70 , 0x71 , 0x72 } ; //fieldID to send to Tx (to shift 4 bits to left
215 struct ONE_MEASUREMENT
* p_measurements
[24] ; // array of 22 pointers (each pointer point to a structure containing a byte saying if a value is available and to the value.
216 // There are 20 possible fields to transmit in SPORT
217 // They are grouped per sensor ID
218 // Sensor 0 start from index = 0 and contains Alt + Vspeed
219 // Sensor 1 start from index = 2 and contains Cell_1_2 , Cell_3_4 and Cell_5_6
220 // Sensor 2 start from index = 5 and contains vfas , current and fuel
221 // Sensor 3 start from index = 10 and contains gps_lon , gps_lat, gps_alt , gps_speed and gps_course
222 // Sensor 4 start from index = 15 and contains rpm, T1, T2, airspeed
223 // Sensor 5 start from index = 19 and contains accX , accY, accZ
225 int32_t dataValue
[6] ; // keep for each sensor id the next value to be sent
226 uint8_t dataId
[6] ; // keep for each sensor id the Id of next field to be sent
230 struct ONE_MEASUREMENT no_data
= { 0, 0 } ;
232 void initMeasurement() {
233 // pointer to Altitude
235 p_measurements
[0] = &oXs_MS5611
.varioData
.relativeAlt
; // we use always relative altitude in Frsky protocol
238 p_measurements
[0] = &no_data
;
243 p_measurements
[1] = &mainVspeed
;
245 p_measurements
[1] = &no_data
;
248 // pointer to Cell_1_2
249 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && defined(NUMBEROFCELLS) && (NUMBEROFCELLS > 0)
250 p_measurements
[2] = &oXs_Voltage
.voltageData
.mVoltCell_1_2
;
253 p_measurements
[2] = &no_data
;
256 // pointer to Cell_3_4
257 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && defined(NUMBEROFCELLS) && (NUMBEROFCELLS > 2)
258 p_measurements
[3] = &oXs_Voltage
.voltageData
.mVoltCell_3_4
;
260 p_measurements
[3] = &no_data
;
263 // pointer to Cell_5_6
264 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && defined(NUMBEROFCELLS) && (NUMBEROFCELLS > 4)
265 p_measurements
[4] = &oXs_Voltage
.voltageData
.mVoltCell_5_6
;
267 p_measurements
[4] = &no_data
;
270 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && 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 )
271 p_measurements
[5] = &vfas
;
273 #elif defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(VFAS_SOURCE) && ( VFAS_SOURCE == ADS_VOLT_1 || VFAS_SOURCE == ADS_VOLT_2 || VFAS_SOURCE == ADS_VOLT_3 || VFAS_SOURCE == ADS_VOLT_4 )
274 p_measurements
[5] = &vfas
;
277 p_measurements
[5] = &no_data
;
280 // pointer to current
281 #if ( defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES) ) || ( defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(ADS_CURRENT_BASED_ON))
282 p_measurements
[6] = &sport_currentData
;
285 p_measurements
[6] = &no_data
;
289 #if defined(FUEL_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)&& ( FUEL_SOURCE == VOLT_1 || FUEL_SOURCE == VOLT_2 || FUEL_SOURCE == VOLT_3 || FUEL_SOURCE == VOLT_4 || FUEL_SOURCE == VOLT_5 || FUEL_SOURCE == VOLT_6 )
290 p_measurements
[7] = &oXs_Voltage
.voltageData
.mVolt
[FUEL_SOURCE
- VOLT_1
];
292 #elif defined(FUEL_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( FUEL_SOURCE == ADS_VOLT_1 || FUEL_SOURCE == ADS_VOLT_2 || FUEL_SOURCE == ADS_VOLT_3 || FUEL_SOURCE == ADS_VOLT_4 )
293 p_measurements
[7] = &ads_Conv
[FUEL_SOURCE
- ADS_VOLT_1
];
296 p_measurements
[7] = &no_data
;
300 #if defined(A3_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( A3_SOURCE == VOLT_1 || A3_SOURCE == VOLT_2 || A3_SOURCE == VOLT_3 || A3_SOURCE == VOLT_4 || A3_SOURCE == VOLT_5 || A3_SOURCE == VOLT_6 )
301 p_measurements
[8] = &oXs_Voltage
.voltageData
.mVolt
[A3_SOURCE
- VOLT_1
];
303 #elif defined(A3_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( A3_SOURCE == ADS_VOLT_1 || A3_SOURCE == ADS_VOLT_2 || A3_SOURCE == ADS_VOLT_3 || A3_SOURCE == ADS_VOLT_4 )
304 p_measurements
[8] = &ads_Conv
[A3_SOURCE
- ADS_VOLT_1
];
307 p_measurements
[8] = &no_data
;
311 #if defined(A4_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( A4_SOURCE == VOLT_1 || A4_SOURCE == VOLT_2 || A4_SOURCE == VOLT_3 || A4_SOURCE == VOLT_4 || A4_SOURCE == VOLT_5 || A4_SOURCE == VOLT_6 )
312 p_measurements
[9] = &oXs_Voltage
.voltageData
.mVolt
[A4_SOURCE
- VOLT_1
];
314 #elif defined(A4_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( A4_SOURCE == ADS_VOLT_1 || A4_SOURCE == ADS_VOLT_2 || A4_SOURCE == ADS_VOLT_3 || A4_SOURCE == ADS_VOLT_4 )
315 p_measurements
[9] = &ads_Conv
[A4_SOURCE
- ADS_VOLT_1
];
318 p_measurements
[9] = &no_data
;
322 // pointer to GPS lon
323 #if defined(GPS_INSTALLED)
324 p_measurements
[10] = &sport_gps_lon
;
327 p_measurements
[10] = &no_data
;
330 // pointer to GPS lat
331 #if defined(GPS_INSTALLED)
332 p_measurements
[11] = &sport_gps_lat
;
334 p_measurements
[11] = &no_data
;
337 // pointer to GPS alt
338 #if defined(GPS_INSTALLED)
339 p_measurements
[12] = &sport_gps_alt
;
341 p_measurements
[12] = &no_data
;
344 // pointer to GPS speed
345 #if defined(GPS_INSTALLED)
346 p_measurements
[13] = &sport_gps_speed
;
348 p_measurements
[13] = &no_data
;
351 // pointer to GPS course
352 #if defined(GPS_INSTALLED)
353 p_measurements
[14] = &sport_gps_course
;
355 p_measurements
[14] = &no_data
;
358 #if defined(GPS_TRANSMIT_TIME)
359 // pointer to GPS date
360 #if defined(GPS_INSTALLED)
361 p_measurements
[15] = &sport_gps_date
;
362 p_measurements
[16] = &sport_gps_time
;
364 p_measurements
[15] = &no_data
;
365 p_measurements
[16] = &no_data
;
368 p_measurements
[15] = &no_data
;
369 p_measurements
[16] = &no_data
;
373 #if defined(MEASURE_RPM)
374 p_measurements
[17] = &sport_rpm
;
377 p_measurements
[17] = &no_data
;
381 #if defined(T1_SOURCE) && ( T1_SOURCE == TEST_1)
382 p_measurements
[18] = &test1
;
384 #elif defined(T1_SOURCE) && ( T1_SOURCE == TEST_2)
385 p_measurements
[18] = &test2
;
387 #elif defined(T1_SOURCE) && ( T1_SOURCE == TEST_3)
388 p_measurements
[18] = &test3
;
390 #elif defined(T1_SOURCE) && ( T1_SOURCE == GLIDER_RATIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
391 p_measurements
[18] = &gliderRatio
;
393 #elif defined(T1_SOURCE) && ( T1_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
394 p_measurements
[18] = &secFromT0
;
396 #elif defined(T1_SOURCE) && ( T1_SOURCE == AVERAGE_VSPEED_SINCE_TO ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
397 p_measurements
[18] = &averageVspeedSinceT0
;
399 #elif defined(T1_SOURCE) && ( T1_SOURCE == SENSITIVITY) && defined(VARIO)
400 p_measurements
[18] = &oXs_MS5611
.varioData
.sensitivity
;
402 #elif defined(T1_SOURCE) && ( T1_SOURCE == PPM) && ( defined(PIN_PPM) || ( defined(PPM_VIA_SPORT) && ( (PROTOCOL == FRSKY_SPORT) || (PROTOCOL == FRSKY_SPORT_HUB) ) ) )
403 p_measurements
[18] = &ppm
;
405 #elif defined(T1_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( T1_SOURCE == VOLT_1 || T1_SOURCE == VOLT_2 || T1_SOURCE == VOLT_3 || T1_SOURCE == VOLT_4 || T1_SOURCE == VOLT_5 || T1_SOURCE == VOLT_6 )
406 p_measurements
[18] = &oXs_Voltage
.voltageData
.mVolt
[T1_SOURCE
- VOLT_1
] ;
408 #elif defined(T1_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( T1_SOURCE == ADS_VOLT_1 || T1_SOURCE == ADS_VOLT_2 || T1_SOURCE == ADS_VOLT_3 || T1_SOURCE == ADS_VOLT_4 )
409 p_measurements
[18] = &ads_Conv
[T1_SOURCE
- ADS_VOLT_1
];
412 p_measurements
[18] = &no_data
; // T1
416 #if defined(T2_SOURCE) && ( T2_SOURCE == TEST_1)
417 p_measurements
[19] = &test1
;
419 #elif defined(T2_SOURCE) && ( T2_SOURCE == TEST_2)
420 p_measurements
[19] = &test2
;
422 #elif defined(T2_SOURCE) && ( T2_SOURCE == TEST_3)
423 p_measurements
[19] = &test3
;
425 #elif defined(T2_SOURCE) && ( T2_SOURCE == GLIDER_RATIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
426 p_measurements
[19] = &gliderRatio
;
428 #elif defined(T2_SOURCE) && ( T2_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
429 p_measurements
[19] = &secFromT0
;
431 #elif defined(T2_SOURCE) && ( T2_SOURCE == AVERAGE_VSPEED_SINCE_TO ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
432 p_measurements
[19] = &averageVspeedSinceT0
;
434 #elif defined(T2_SOURCE) && ( T2_SOURCE == SENSITIVITY) && defined(VARIO)
435 p_measurements
[19] = &oXs_MS5611
.varioData
.sensitivity
;
437 #elif defined(T2_SOURCE) && ( T2_SOURCE == PPM) && ( defined(PIN_PPM) || ( defined(PPM_VIA_SPORT) && ( (PROTOCOL == FRSKY_SPORT) || (PROTOCOL == FRSKY_SPORT_HUB) ) ) )
438 p_measurements
[19] = &ppm
;
440 #elif defined(T2_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( T2_SOURCE == VOLT_1 || T2_SOURCE == VOLT_2 || T2_SOURCE == VOLT_3 || T2_SOURCE == VOLT_4 || T2_SOURCE == VOLT_5 || T2_SOURCE == VOLT_6 )
441 p_measurements
[19] = &oXs_Voltage
.voltageData
.mVolt
[T2_SOURCE
- VOLT_1
] ;
443 #elif defined(T2_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( T2_SOURCE == ADS_VOLT_1 || T2_SOURCE == ADS_VOLT_2 || T2_SOURCE == ADS_VOLT_3 || T2_SOURCE == ADS_VOLT_4 )
444 p_measurements
[19] = &ads_Conv
[T2_SOURCE
- ADS_VOLT_1
];
447 p_measurements
[19] = &no_data
; // T2
452 // pointer to airspeed
453 #if defined(AIRSPEED)
454 p_measurements
[20] = &oXs_4525
.airSpeedData
.airSpeed
;
456 #elif defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(ADS_AIRSPEED_BASED_ON)
457 p_measurements
[20] = &oXs_ads1115
.adsAirSpeedData
.airSpeed
;
459 #elif defined(AIRSPEED_SDP3X)
460 p_measurements
[20] = &oXs_sdp3x
.airSpeedData
.airSpeed
;
463 p_measurements
[20] = &no_data
;
467 #if defined(ACCX_SOURCE) && ( ACCX_SOURCE == TEST_1)
468 p_measurements
[21] = &test1
; // accX
470 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == TEST_2)
471 p_measurements
[21] = &test2
; // accX
473 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == TEST_3)
474 p_measurements
[21] = &test3
; // accX
476 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == GLIDER_RATIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
477 p_measurements
[21] = &gliderRatio
;
479 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
480 p_measurements
[21] = &secFromT0
;
482 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == AVERAGE_VSPEED_SINCE_TO ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
483 p_measurements
[21] = &averageVspeedSinceT0
;
485 #elif defined(ACCX_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( ACCX_SOURCE == VOLT_1 || ACCX_SOURCE == VOLT_2 || ACCX_SOURCE == VOLT_3 || ACCX_SOURCE == VOLT_4 || ACCX_SOURCE == VOLT_5 || ACCX_SOURCE == VOLT_6 )
486 p_measurements
[21] = &oXs_Voltage
.voltageData
.mVolt
[ACCX_SOURCE
- VOLT_1
] ;
488 #elif defined(ACCX_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( ACCX_SOURCE == ADS_VOLT_1 || ACCX_SOURCE == ADS_VOLT_2 || ACCX_SOURCE == ADS_VOLT_3 || ACCX_SOURCE == ADS_VOLT_4 )
489 p_measurements
[21] = &ads_Conv
[ACCX_SOURCE
- ADS_VOLT_1
];
491 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == PITCH) && defined(USE_6050)
492 p_measurements
[21] = &pitch
; // accX
494 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == ROLL) && defined(USE_6050)
495 p_measurements
[21] = &roll
; // accX
497 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == YAW) && defined(USE_6050)
498 p_measurements
[21] = &yaw
; // accX
501 p_measurements
[21] = &no_data
; // accX
505 #if defined(ACCY_SOURCE) && ( ACCY_SOURCE == TEST_1)
506 p_measurements
[22] = &test1
; // accY
508 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == TEST_2)
509 p_measurements
[22] = &test2
; // accY
511 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == TEST_3)
512 p_measurements
[22] = &test3
; // accY
514 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == GLIDER_RATIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
515 p_measurements
[22] = &gliderRatio
;
517 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
518 p_measurements
[22] = &secFromT0
;
520 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == AVERAGE_VSPEED_SINCE_TO ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
521 p_measurements
[22] = &averageVspeedSinceT0
;
523 #elif defined(ACCY_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( ACCY_SOURCE == VOLT_1 || ACCY_SOURCE == VOLT_2 || ACCY_SOURCE == VOLT_3 || ACCY_SOURCE == VOLT_4 || ACCY_SOURCE == VOLT_5 || ACCY_SOURCE == VOLT_6 )
524 p_measurements
[22] = &oXs_Voltage
.voltageData
.mVolt
[ACCY_SOURCE
- VOLT_1
] ;
526 #elif defined(ACCY_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( ACCY_SOURCE == ADS_VOLT_1 || ACCY_SOURCE == ADS_VOLT_2 || ACCY_SOURCE == ADS_VOLT_3 || ACCY_SOURCE == ADS_VOLT_4 )
527 p_measurements
[22] = &ads_Conv
[ACCY_SOURCE
- ADS_VOLT_1
];
529 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == PITCH) && defined(USE_6050)
530 p_measurements
[22] = &pitch
;
532 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == ROLL) && defined(USE_6050)
533 p_measurements
[22] = &roll
;
535 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == YAW) && defined(USE_6050)
536 p_measurements
[22] = &yaw
;
539 p_measurements
[22] = &no_data
; // accY
543 #if defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == TEST_1)
544 p_measurements
[23] = &test1
; // accZ
546 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == TEST_2)
547 p_measurements
[23] = &test2
; // accZ
549 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == TEST_3)
550 p_measurements
[23] = &test3
; // accZ
552 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == GLIDER_RATIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
553 p_measurements
[23] = &gliderRatio
;
555 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
556 p_measurements
[23] = &secFromT0
;
558 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == AVERAGE_VSPEED_SINCE_TO ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
559 p_measurements
[23] = &averageVspeedSinceT0
;
561 #elif defined(ACCZ_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( ACCZ_SOURCE == VOLT_1 || ACCZ_SOURCE == VOLT_2 || ACCZ_SOURCE == VOLT_3 || ACCZ_SOURCE == VOLT_4 || ACCZ_SOURCE == VOLT_5 || ACCZ_SOURCE == VOLT_6 )
562 p_measurements
[23] = &oXs_Voltage
.voltageData
.mVolt
[ACCZ_SOURCE
- VOLT_1
] ;
564 #elif defined(ACCZ_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( ACCZ_SOURCE == ADS_VOLT_1 || ACCZ_SOURCE == ADS_VOLT_2 || ACCZ_SOURCE == ADS_VOLT_3 || ACCZ_SOURCE == ADS_VOLT_4 )
565 p_measurements
[23] = &ads_Conv
[ACCZ_SOURCE
- ADS_VOLT_1
];
567 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == PITCH) && defined(USE_6050)
568 p_measurements
[23] = &pitch
; // accX
570 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == ROLL) && defined(USE_6050)
571 p_measurements
[23] = &roll
; // accX
573 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == YAW) && defined(USE_6050)
574 p_measurements
[23] = &yaw
; // accX
577 p_measurements
[23] = &no_data
; // accZ
583 void OXS_OUT::sendSportData()
585 #if defined(GPS_TRANSMIT_TIME)
586 static uint32_t ptxtime
=0;
590 Serial
.print("State "); Serial
.print(state
,HEX
) ; Serial
.print(" LastRx "); Serial
.print(LastRx
,HEX
) ; Serial
.print(" prevLastRx "); Serial
.print(prevLastRx
,HEX
) ;
591 Serial
.print(" sensorIsr "); Serial
.println(sensorIsr
,HEX
) ;
594 // first we calculate fields that are used only by SPORT
595 #if defined(VFAS_SOURCE)
596 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( (VFAS_SOURCE == VOLT_1) || (VFAS_SOURCE == VOLT_2) || (VFAS_SOURCE == VOLT_3) || (VFAS_SOURCE == VOLT_4) || (VFAS_SOURCE == VOLT_5) || (VFAS_SOURCE == VOLT_6) )
597 if ( (!vfas
.available
) && ( oXs_Voltage
.voltageData
.mVolt
[VFAS_SOURCE
- VOLT_1
].available
) ){
598 vfas
.value
= oXs_Voltage
.voltageData
.mVolt
[VFAS_SOURCE
- VOLT_1
].value
/ 10 ; // voltage in mv is divided by 10 because SPORT expect it (volt * 100)
599 vfas
.available
= true ;
600 oXs_Voltage
.voltageData
.mVolt
[VFAS_SOURCE
- VOLT_1
].available
= false ;
602 #elif defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( (VFAS_SOURCE == ADS_VOLT_1) || (VFAS_SOURCE == ADS_VOLT_2) || (VFAS_SOURCE == ADS_VOLT_3) || (VFAS_SOURCE == ADS_VOLT_4) )
603 if ( (!vfas
.available
) && ( ads_Conv
[VFAS_SOURCE
- ADS_VOLT_1
].available
) ){
604 vfas
.value
= ads_Conv
[VFAS_SOURCE
- ADS_VOLT_1
].value
/ 10 ; // voltage in mv is divided by 10 because SPORT expect it (volt * 100)
605 vfas
.available
= true ;
606 ads_Conv
[VFAS_SOURCE
- ADS_VOLT_1
].available
= false;
609 #if ( (VFAS_SOURCE == ADS_VOLT_1) || (VFAS_SOURCE == ADS_VOLT_2) || (VFAS_SOURCE == ADS_VOLT_3) || (VFAS_SOURCE == ADS_VOLT_4) )
610 #error When VFAS_SOURCE is ADS_VOLT_1, ADS_VOLT_2,... ADS_VOLT_4 then ADS_MEASURE must be defined too.
611 #elif ( (VFAS_SOURCE == VOLT_1) || (VFAS_SOURCE == VOLT_2) || (VFAS_SOURCE == VOLT_3) || (VFAS_SOURCE == VOLT_4) || (VFAS_SOURCE == VOLT_5) || (VFAS_SOURCE == VOLT_6) )
612 #error When VFAS_SOURCE is VOLT_1, VOLT_2,... VOLT_6 then PIN_VOLTAGE must be defined too.
614 #error When defined, VFAS_SOURCE must be VOLT_1, VOLT_2,... VOLT_6 or ADS_VOLT_1, ADS_VOLT_2,... ADS_VOLT_4
619 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
620 if ( oXs_Current
.currentData
.milliAmps
.available
) {
621 oXs_Current
.currentData
.milliAmps
.available
= false ;
622 sport_currentData
.value
= oXs_Current
.currentData
.milliAmps
.value
/ 100 ;
623 if (sport_currentData
.value
<0) {
624 sport_currentData
.value
=0;
626 sport_currentData
.available
= true ;
628 #elif defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(ADS_CURRENT_BASED_ON)
629 if ( oXs_ads1115
.adsCurrentData
.milliAmps
.available
) {
630 oXs_ads1115
.adsCurrentData
.milliAmps
.available
= false ;
631 sport_currentData
.value
= oXs_ads1115
.adsCurrentData
.milliAmps
.value
/ 100 ;
632 if (sport_currentData
.value
<0) {
633 sport_currentData
.value
=0;
635 sport_currentData
.available
= true ;
639 #if defined(GPS_INSTALLED)
640 if (GPS_lonAvailable
) {
641 sport_gps_lon
.available
= GPS_lonAvailable
;
642 GPS_lonAvailable
= false ;
643 sport_gps_lon
.value
= (( ((((uint32_t)( GPS_lon
< 0 ? -GPS_lon
: GPS_lon
)) /10 ) * 6 ) / 10 ) & 0x3FFFFFFF) | 0x80000000;
644 if(GPS_lon
< 0) sport_gps_lon
.value
|= 0x40000000;
646 if (GPS_latAvailable
) {
647 sport_gps_lat
.available
= GPS_latAvailable
;
648 GPS_latAvailable
= false ;
649 sport_gps_lat
.value
= (( ((((uint32_t)( GPS_lat
< 0 ? -GPS_lat
: GPS_lat
)) / 10 ) * 6 )/ 10 ) & 0x3FFFFFFF ) ;
650 if(GPS_lat
< 0) sport_gps_lat
.value
|= 0x40000000;
652 if (GPS_altitudeAvailable
) {
653 sport_gps_alt
.available
= GPS_altitudeAvailable
;
654 GPS_altitudeAvailable
= false ;
655 sport_gps_alt
.value
= GPS_altitude
/ 10; // convert mm in cm
658 if (GPS_speed_3dAvailable
) {
659 sport_gps_speed
.available
= GPS_speed_3dAvailable
;
660 GPS_speed_3dAvailable
= false ;
661 #ifdef GPS_SPEED_IN_KMH
662 sport_gps_speed
.value
= ( ((uint32_t) GPS_speed_3d
) * 36 ) ; // convert cm/s in 1/100 of km/h (factor = 3.6)
664 sport_gps_speed
.value
= ( ((uint32_t) GPS_speed_3d
) * 700 ) / 36 ; // convert cm/s in 1/100 of knots (factor = 19.44)
665 #endif // end of GPS_SPEED_IN_KMH
667 #else // use gps_Speed_2d
668 if (GPS_speed_2dAvailable
) {
669 sport_gps_speed
.available
= GPS_speed_2dAvailable
;
670 GPS_speed_2dAvailable
= false ;
671 #ifdef GPS_SPEED_IN_KMH
672 sport_gps_speed
.value
= ( ((uint32_t) GPS_speed_2d
) * 36 ) ; // convert cm/s in 1/100 of km/h (factor = 3.6)
674 sport_gps_speed
.value
= ( ((uint32_t) GPS_speed_2d
) * 700 ) / 36 ; // convert cm/s in 1/1000 of knots (factor = 19.44)
675 #endif // end of GPS_SPEED_IN_KMH
677 #endif // enf of GPS_SPEED_3D or 2D
678 if (GPS_ground_courseAvailable
) {
679 sport_gps_course
.available
= GPS_ground_courseAvailable
;
680 GPS_ground_courseAvailable
= false ;
681 sport_gps_course
.value
= GPS_ground_course
/ 1000; // convert from degree * 100000 to degree * 100
684 #if defined(GPS_TRANSMIT_TIME)
685 if (GPS_timeAvailable
) {
686 sport_gps_date
.value
=(GPS_year
% 100);
687 sport_gps_date
.value
<<=8;
688 sport_gps_date
.value
+=GPS_month
;
689 sport_gps_date
.value
<<=8;
690 sport_gps_date
.value
+=GPS_day
;
691 sport_gps_date
.value
<<=8;
692 sport_gps_date
.value
+=0xFF;
693 sport_gps_time
.value
=GPS_hour
;
694 sport_gps_time
.value
<<=8;
695 sport_gps_time
.value
+=GPS_min
;
696 sport_gps_time
.value
<<=8;
697 sport_gps_time
.value
+=GPS_sec
;
698 sport_gps_time
.value
<<=8;
699 if (ptxtime
!=sport_gps_time
.value
) {
700 ptxtime
=sport_gps_time
.value
;
701 sport_gps_date
.available
=GPS_timeAvailable
;
702 sport_gps_time
.available
=GPS_timeAvailable
;
706 #endif // end of GPS_INSTALLED
708 // Serial.print("frskyStatus "); Serial.println(frskyStatus,HEX) ;
709 if ( frskyStatus
) { // if at least one data has to be loaded
710 for (uint8_t sensorSeq
= 0 ; sensorSeq
< 6 ; sensorSeq
++ ) { // for each sensor (currently 6)
711 if ( frskyStatus
& (1 << sensorSeq
) ) { //if frskyStatus says that a data must be loaded for this sensor
712 uint8_t currFieldIdx_
= currFieldIdx
[sensorSeq
] ; // retrieve the last field being loaded for this sensor
713 for (uint8_t iCount
= fieldMinIdx
[sensorSeq
] ; iCount
< fieldMinIdx
[sensorSeq
+1] ; iCount
++ ) { // we will not seach more than the number of fields for the selected sensor
714 currFieldIdx_
++ ; // search with next field
715 if ( currFieldIdx_
>= fieldMinIdx
[sensorSeq
+1] ) currFieldIdx_
= fieldMinIdx
[sensorSeq
] ; // if overlap within sensor range, set idx to first idx for this sensorSeq
716 // Serial.print("currFieldIdx_ "); Serial.print(currFieldIdx_) ;
717 // Serial.print(" p_m.av "); Serial.print( p_measurements[currFieldIdx_]->available) ;
718 // Serial.print(" p_m.va "); Serial.println( p_measurements[currFieldIdx_]->value) ;
719 if ( p_measurements
[currFieldIdx_
]->available
){ // if data of current index of sensor is available
720 p_measurements
[currFieldIdx_
]->available
= 0 ; // mark the data as not available
721 dataValue
[sensorSeq
] = p_measurements
[currFieldIdx_
]->value
; // store the value in a buffer
722 dataId
[sensorSeq
] = fieldId
[currFieldIdx_
] ; // mark the data from this sensor as available
723 uint8_t oReg
= SREG
; // save status register
725 frskyStatus
&= ~(1<< sensorSeq
) ; // says that data is loaded by resetting one bit
726 SREG
= oReg
; // restore the status register
727 #ifdef DEBUG_LOAD_SPORT
728 Serial
.print("Load "); Serial
.print(dataId
[sensorSeq
],HEX
) ; Serial
.print(" ") ; Serial
.println(dataValue
[sensorSeq
]);
730 break ; // exit inner for
733 currFieldIdx
[sensorSeq
] = currFieldIdx_
; // save currentFieldIdx for this
735 } // End for one sensorSeq
736 } // End of if (frskystatus)
737 #ifdef DEBUG_SPORT_RECEIVED
738 Serial
.print("RcvCnt "); Serial
.println( sportRcvCount
) ;
745 // -------------------------End of SPORT protocol--------------------------------------------------------------------------------------
747 //========================= Hub protocol ==========================================
748 #if defined( PROTOCOL ) && ( ( PROTOCOL == FRSKY_HUB ) || ( PROTOCOL == FRSKY_SPORT_HUB ) )
749 void OXS_OUT::sendHubData() // for Hub protocol
751 #define FRAME2_EVERY_N_FRAME1 1 // n means that there is n frame1 after one frame2(gps)
752 #define FRAME3_EVERY_N_FRAME2 5 // n means that there is n frame3 after n frame3 (gps) accordingly to hub protocol time get transmitter every 5 sec
753 #define MSEC_PER_BYTE 7 // number of msec per byte to transmit; I expect that a value of 7 ms should work; probably it can even be reduced up to 6.
754 static uint32_t lastMsFrame1
=0;
755 static uint16_t lastFrameLength
;
756 static uint32_t temp
;
757 static uint8_t countFrame1
= FRAME2_EVERY_N_FRAME1
;
758 static uint8_t countFrame2
= FRAME3_EVERY_N_FRAME2
;
760 //static uint32_t lastMsFrame2=0;
765 if ( (state
== IDLE
) && (temp
> (lastMsFrame1
+ ( lastFrameLength
* MSEC_PER_BYTE
) ) ) ) {
767 #if defined(GPS_TRANSMIT_TIME)
768 if ( (countFrame2
== 0 ) && GPS_fix
) {
770 lastFrameLength
= hubMaxData
;
771 countFrame2
= FRAME3_EVERY_N_FRAME2
;
775 if ( (countFrame1
== 0 ) && GPS_fix
) {
777 lastFrameLength
= hubMaxData
;
778 if ( countFrame2
) countFrame2
-- ;
779 countFrame1
= FRAME2_EVERY_N_FRAME1
;
785 lastFrameLength
= hubMaxData
;
786 if ( countFrame1
) countFrame1
-- ;
791 // second frame used for GPS
793 if ( (state == IDLE ) && (temp > lastMsFrame2 + INTERVAL_FRAME2 ) && (temp >= lastMsFrame1 + INTERVAL_FRAME1 ) && GPS_fix ) {
794 #ifdef DEBUGHUBPROTOCOL
795 printer->print("F2 at ");
796 printer->println( millis() );
802 if ( (state == IDLE) && (temp >= lastMsFrame1 + INTERVAL_FRAME1 ) && (temp >= lastMsFrame2 + INTERVAL_FRAME1 ) ) {
803 #ifdef DEBUGHUBPROTOCOL
804 printer->print("F1 at ");
805 printer->println( millis() );
811 } // end sendData Hub protocol
813 //======================================================================================================Send Frame 1A via serial
814 void OXS_OUT::SendFrame1(){
815 hubMaxData
= 0 ; // reset of number of data to send
817 // pointer to Altitude
819 uint16_t Centimeter
= uint16_t(abs(oXs_MS5611
.varioData
.absoluteAlt
.value
)%100);
821 if (oXs_MS5611
.varioData
.absoluteAlt
.value
>0){
822 Meter
= (oXs_MS5611
.varioData
.absoluteAlt
.value
- Centimeter
);
824 Meter
= -1*(abs(oXs_MS5611
.varioData
.absoluteAlt
.value
) + Centimeter
);
827 SendValue(FRSKY_USERDATA_BARO_ALT_B
, (int16_t)Meter
);
828 SendValue(FRSKY_USERDATA_BARO_ALT_A
, Centimeter
);
833 SendValue( FRSKY_USERDATA_VERT_SPEED
, (int16_t) mainVspeed
.value
);
837 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && defined(NUMBEROFCELLS) && (NUMBEROFCELLS > 0)
838 SendCellVoltage( oXs_Voltage
.voltageData
.mVoltCell_1_2
.value
);
842 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && defined(NUMBEROFCELLS) && (NUMBEROFCELLS > 2)
843 SendCellVoltage( oXs_Voltage
.voltageData
.mVoltCell_3_4
.value
) ;
847 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && defined(NUMBEROFCELLS) && (NUMBEROFCELLS > 4)
848 SendCellVoltage( oXs_Voltage
.voltageData
.mVoltCell_5_6
.value
) ;
852 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && 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) )
853 SendValue( FRSKY_USERDATA_VFAS_NEW
, (int16_t) (voltageData
->mVolt
[VFAS_SOURCE
- VOLT_1
].value
/ 100) ) ; // convert mvolt in 1/10 of volt; in openTx 2.1.x, it is possible to get 1 more decimal using [VFAS_SOURCE - VOLT_1 ].value/10.)+2000);
854 #elif defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(VFAS_SOURCE) && ( (VFAS_SOURCE == ADS_VOLT_1) || (VFAS_SOURCE == ADS_VOLT_2) || (VFAS_SOURCE == ADS_VOLT_3) || (VFAS_SOURCE == ADS_VOLT_4) )
855 SendValue( FRSKY_USERDATA_VFAS_NEW
, (int16_t) (ads_Conv
[VFAS_SOURCE
- ADS_VOLT_1
].value
/ 100) ) ; // convert mvolt in 1/10 of volt; in openTx 2.1.x, it is possible to get 1 more decimal using [VFAS_SOURCE - VOLT_1 ].value/10.)+2000);
859 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
860 SendValue( FRSKY_USERDATA_CURRENT
, (int16_t) ( oXs_Current
.currentData
.milliAmps
.value
/ 100 ) ) ;
861 #elif defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && defined(ADS_CURRENT_BASED_ON)
862 SendValue( FRSKY_USERDATA_CURRENT
, (int16_t) ( oXs_ads1115
.adsCurrentData
.milliAmps
.value
/ 100 ) ) ;
866 #if defined(FUEL_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( FUEL_SOURCE == VOLT_1 || FUEL_SOURCE == VOLT_2 || FUEL_SOURCE == VOLT_3 || FUEL_SOURCE == VOLT_4 || FUEL_SOURCE == VOLT_5 || FUEL_SOURCE == VOLT_6 )
867 SendValue(FRSKY_USERDATA_FUEL
, (int16_t) voltageData
->mVolt
[FUEL_SOURCE
- VOLT_1
].value
) ;
868 #elif defined(VFAS_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( (FUEL_SOURCE == ADS_VOLT_1) || (FUEL_SOURCE == ADS_VOLT_2) || (FUEL_SOURCE == ADS_VOLT_3) || (FUEL_SOURCE == ADS_VOLT_4) )
869 SendValue( FRSKY_USERDATA_FUEL
, (int16_t) (ads_Conv
[FUEL_SOURCE
- ADS_VOLT_1
].value
) ) ;
873 #if defined(MEASURE_RPM)
874 SendValue( FRSKY_USERDATA_RPM
, (int16_t) sport_rpm
.value
) ;
878 #if defined(T1_SOURCE) && ( T1_SOURCE == TEST_1)
879 SendValue( FRSKY_USERDATA_TEMP1
, (int16_t) test1
.value
) ;
880 #elif defined(T1_SOURCE) && ( T1_SOURCE == TEST_2)
881 SendValue( FRSKY_USERDATA_TEMP1
, (int16_t) test2
.value
) ;
882 #elif defined(T1_SOURCE) && ( T1_SOURCE == TEST_3)
883 SendValue( FRSKY_USERDATA_TEMP1
, (int16_t) test3
.value
) ;
884 #elif defined(T1_SOURCE) && ( T1_SOURCE == GLIDER_RATIO) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
885 SendValue( FRSKY_USERDATA_TEMP1
, (int16_t) gliderRatio
.value
) ;
886 #elif defined(T1_SOURCE) && ( T1_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
887 SendValue( FRSKY_USERDATA_TEMP1
, (int16_t) secFromT0
.value
) ;
888 #elif defined(T1_SOURCE) && ( T1_SOURCE == AVERAGE_VSPEED_SINCE_TO ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
889 SendValue( FRSKY_USERDATA_TEMP1
, (int16_t) averageVspeedSinceT0
.value
) ;
890 #elif defined(T1_SOURCE) && ( T1_SOURCE == SENSITIVITY) && defined(VARIO)
891 SendValue( FRSKY_USERDATA_TEMP1
, (int16_t) oXs_MS5611
.varioData
.sensitivity
.value
) ;
892 #elif defined(T1_SOURCE) && ( T1_SOURCE == PPM) && ( defined(PIN_PPM) || ( defined(PPM_VIA_SPORT) && ( (PROTOCOL == FRSKY_SPORT) || (PROTOCOL == FRSKY_SPORT_HUB) ) ) )
893 SendValue( FRSKY_USERDATA_TEMP1
, (int16_t) ppm
.value
) ;
894 #elif defined(T1_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( (T1_SOURCE == VOLT_1) || (T1_SOURCE == VOLT_2) || (T1_SOURCE == VOLT_3) || (T1_SOURCE == VOLT_4) || (T1_SOURCE == VOLT_5) || (T1_SOURCE == VOLT_6) )
895 SendValue( FRSKY_USERDATA_TEMP1
, (int16_t) (voltageData
->mVolt
[T1_SOURCE
- VOLT_1
].value
) ) ;
896 #elif defined(T1_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( (T1_SOURCE == ADS_VOLT_1) || (T1_SOURCE == ADS_VOLT_2) || (T1_SOURCE == ADS_VOLT_3) || (T1_SOURCE == ADS_VOLT_4) )
897 SendValue( FRSKY_USERDATA_TEMP1
, (int16_t) (ads_Conv
[T1_SOURCE
- ADS_VOLT_1
].value
) ) ;
902 #if defined(T2_SOURCE) && ( T2_SOURCE == TEST_1)
903 SendValue( FRSKY_USERDATA_TEMP2
, (int16_t) test1
.value
) ;
904 #elif defined(T2_SOURCE) && ( T2_SOURCE == TEST_2)
905 SendValue( FRSKY_USERDATA_TEMP2
, (int16_t) test2
.value
) ;
906 #elif defined(T2_SOURCE) && ( T2_SOURCE == TEST_3)
907 SendValue( FRSKY_USERDATA_TEMP2
, (int16_t) test3
.value
) ;
908 #elif defined(T2_SOURCE) && ( T2_SOURCE == GLIDER_RATIO) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
909 SendValue( FRSKY_USERDATA_TEMP2
, (int16_t) gliderRatio
.value
) ;
910 #elif defined(T2_SOURCE) && ( T2_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
911 SendValue( FRSKY_USERDATA_TEMP2
, (int16_t) secFromT0
.value
) ;
912 #elif defined(T2_SOURCE) && ( T2_SOURCE == AVERAGE_VSPEED_SINCE_TO ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
913 SendValue( FRSKY_USERDATA_TEMP2
, (int16_t) averageVspeedSinceT0
.value
) ;
914 #elif defined(T2_SOURCE) && ( T2_SOURCE == SENSITIVITY) && defined(VARIO)
915 SendValue( FRSKY_USERDATA_TEMP2
, (int16_t) oXs_MS5611
.varioData
.sensitivity
.value
) ;
916 #elif defined(T2_SOURCE) && ( T2_SOURCE == PPM) && ( defined(PIN_PPM) || ( defined(PPM_VIA_SPORT) && ( (PROTOCOL == FRSKY_SPORT) || (PROTOCOL == FRSKY_SPORT_HUB) ) ) )
917 SendValue( FRSKY_USERDATA_TEMP2
, (int16_t) ppm
.value
) ;
918 #elif defined(T2_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( (T2_SOURCE == VOLT_1) || (T2_SOURCE == VOLT_2) || (T2_SOURCE == VOLT_3) || (T2_SOURCE == VOLT_4) || (T2_SOURCE == VOLT_5) || (T2_SOURCE == VOLT_6) )
919 SendValue( FRSKY_USERDATA_TEMP2
, (int16_t) (voltageData
->mVolt
[T2_SOURCE
- VOLT_1
].value
) ) ;
920 #elif defined(T2_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( (T2_SOURCE == ADS_VOLT_1) || (T2_SOURCE == ADS_VOLT_2) || (T2_SOURCE == ADS_VOLT_3) || (T2_SOURCE == ADS_VOLT_4) )
921 SendValue( FRSKY_USERDATA_TEMP2
, (int16_t) (ads_Conv
[T2_SOURCE
- ADS_VOLT_1
].value
) ) ;
924 // airspeed // not implemented in Hub protocol; to add in T1 or T2
925 #if defined(AIRSPEED)
926 //oXs_4525.airSpeedData.airSpeed ;
930 #if defined(ACCX_SOURCE) && ( ACCX_SOURCE == TEST_1)
931 SendValue( FRSKY_USERDATA_ACC_X
, (int16_t) test1
.value
) ;
932 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == TEST_2)
933 SendValue( FRSKY_USERDATA_ACC_X
, (int16_t) test2
.value
) ;
934 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == TEST_3)
935 SendValue( FRSKY_USERDATA_ACC_X
, (int16_t) test3
.value
) ;
936 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == GLIDER_RATIO) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
937 SendValue( FRSKY_USERDATA_ACC_X
, (int16_t) gliderRatio
.value
) ;
938 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
939 SendValue( FRSKY_USERDATA_ACC_X
, (int16_t) secFromT0
.value
) ;
940 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == AVERAGE_VSPEED_SINCE_TO ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
941 SendValue( FRSKY_USERDATA_ACC_X
, (int16_t) averageVspeedSinceT0
.value
) ;
942 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == PITCH) && defined(USE_6050)
943 SendValue( FRSKY_USERDATA_ACC_X
, (int16_t) pitch
.value
) ;
944 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == ROLL) && defined(USE_6050)
945 SendValue( FRSKY_USERDATA_ACC_X
, (int16_t) roll
.value
) ;
946 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == YAW) && defined(USE_6050)
947 SendValue( FRSKY_USERDATA_ACC_X
, (int16_t) yaw
.value
) ;
948 #elif defined(ACCX_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( (ACCX_SOURCE == VOLT_1) || (ACCX_SOURCE == VOLT_2) || (ACCX_SOURCE == VOLT_3) || (ACCX_SOURCE == VOLT_4) || (ACCX_SOURCE == VOLT_5) || (ACCX_SOURCE == VOLT_6) )
949 SendValue( FRSKY_USERDATA_ACC_X
, (int16_t) (voltageData
->mVolt
[ACCX_SOURCE
- VOLT_1
].value
) ) ;
950 #elif defined(ACCX_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( (ACCX_SOURCE == ADS_VOLT_1) || (ACCX_SOURCE == ADS_VOLT_2) || (ACCX_SOURCE == ADS_VOLT_3) || (ACCX_SOURCE == ADS_VOLT_4) )
951 SendValue( FRSKY_USERDATA_ACC_X
, (int16_t) (ads_Conv
[ACCX_SOURCE
- ADS_VOLT_1
].value
) ) ;
955 #if defined(ACCY_SOURCE) && ( ACCY_SOURCE == TEST_1)
956 SendValue( FRSKY_USERDATA_ACC_Y
, (int16_t) test1
.value
) ;
957 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == TEST_2)
958 SendValue( FRSKY_USERDATA_ACC_Y
, (int16_t) test2
.value
) ;
959 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == TEST_3)
960 SendValue( FRSKY_USERDATA_ACC_Y
, (int16_t) test3
.value
) ;
961 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == GLIDER_RATIO) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
962 SendValue( FRSKY_USERDATA_ACC_Y
, (int16_t) gliderRatio
.value
) ;
963 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
964 SendValue( FRSKY_USERDATA_ACC_Y
, (int16_t) secFromT0
.value
) ;
965 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == AVERAGE_VSPEED_SINCE_TO ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
966 SendValue( FRSKY_USERDATA_ACC_Y
, (int16_t) averageVspeedSinceT0
.value
) ;
967 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == PITCH) && defined(USE_6050)
968 SendValue( FRSKY_USERDATA_ACC_Y
, (int16_t) pitch
.value
) ;
969 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == ROLL) && defined(USE_6050)
970 SendValue( FRSKY_USERDATA_ACC_Y
, (int16_t) roll
.value
) ;
971 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == YAW) && defined(USE_6050)
972 SendValue( FRSKY_USERDATA_ACC_Y
, (int16_t) yaw
.value
) ;
973 #elif defined(ACCY_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( (ACCY_SOURCE == VOLT_1) || (ACCY_SOURCE == VOLT_2) || (ACCY_SOURCE == VOLT_3) || (ACCY_SOURCE == VOLT_4) || (ACCY_SOURCE == VOLT_5) || (ACCY_SOURCE == VOLT_6) )
974 SendValue( FRSKY_USERDATA_ACC_Y
, (int16_t) (voltageData
->mVolt
[ACCY_SOURCE
- VOLT_1
].value
) ) ;
975 #elif defined(ACCY_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( (ACCY_SOURCE == ADS_VOLT_1) || (ACCY_SOURCE == ADS_VOLT_2) || (ACCY_SOURCE == ADS_VOLT_3) || (ACCY_SOURCE == ADS_VOLT_4) )
976 SendValue( FRSKY_USERDATA_ACC_Y
, (int16_t) (ads_Conv
[ACCY_SOURCE
- ADS_VOLT_1
].value
) ) ;
980 #if defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == TEST_1)
981 SendValue( FRSKY_USERDATA_ACC_Z
, (int16_t) test1
.value
) ;
982 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == TEST_2)
983 SendValue( FRSKY_USERDATA_ACC_Z
, (int16_t) test2
.value
) ;
984 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == TEST_3)
985 SendValue( FRSKY_USERDATA_ACC_Z
, (int16_t) test3
.value
) ;
986 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == GLIDER_RATIO) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
987 SendValue( FRSKY_USERDATA_ACC_Z
, (int16_t) gliderRatio
.value
) ;
988 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
989 SendValue( FRSKY_USERDATA_ACC_Z
, (int16_t) secFromT0
.value
) ;
990 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == AVERAGE_VSPEED_SINCE_TO ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
991 SendValue( FRSKY_USERDATA_ACC_Z
, (int16_t) averageVspeedSinceT0
.value
) ;
992 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == PITCH) && defined(USE_6050)
993 SendValue( FRSKY_USERDATA_ACC_Z
, (int16_t) pitch
.value
) ;
994 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == ROLL) && defined(USE_6050)
995 SendValue( FRSKY_USERDATA_ACC_Z
, (int16_t) roll
.value
) ;
996 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == YAW) && defined(USE_6050)
997 SendValue( FRSKY_USERDATA_ACC_Z
, (int16_t) yaw
.value
) ;
998 #elif defined(ACCZ_SOURCE) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && ( (ACCZ_SOURCE == VOLT_1) || (ACCZ_SOURCE == VOLT_2) || (ACCZ_SOURCE == VOLT_3) || (ACCZ_SOURCE == VOLT_4) || (ACCZ_SOURCE == VOLT_5) || (ACCZ_SOURCE == VOLT_6) )
999 SendValue( FRSKY_USERDATA_ACC_Z
, (int16_t) (voltageData
->mVolt
[ACCZ_SOURCE
- VOLT_1
].value
) ) ;
1000 #elif defined(ACCZ_SOURCE) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE) && ( (ACCZ_SOURCE == ADS_VOLT_1) || (ACCZ_SOURCE == ADS_VOLT_2) || (ACCZ_SOURCE == ADS_VOLT_3) || (ACCZ_SOURCE == ADS_VOLT_4) )
1001 SendValue( FRSKY_USERDATA_ACC_Z
, (int16_t) (ads_Conv
[ACCZ_SOURCE
- ADS_VOLT_1
].value
) ) ;
1004 if( hubMaxData
> 0 ) {
1005 sendHubByte(0x5E) ; // End of Frame 1!
1008 #ifdef DEBUGHUBPROTOCOL
1009 printer
->print(F("Frame 1 to send: "));
1010 for (int cntPrint
= 0 ; cntPrint
< hubData
.maxData
; cntPrint
++) {
1011 printer
->print(" ");
1012 printer
->print(hubData
.data
[cntPrint
] , HEX
);
1014 printer
->println(" ");
1016 } // end send frame 1
1019 #define FRSKY_USERDATA_GPS_ALT_B 0x01 // Altitude m
1020 #define FRSKY_USERDATA_GPS_ALT_A 0x09 // Altitude in centimeter
1021 #define FRSKY_USERDATA_GPS_SPEED_B 0x11 // Speed knots
1022 #define FRSKY_USERDATA_GPS_LONG_B 0x12 // Longitude (DDMM)
1023 #define FRSKY_USERDATA_GPS_LAT_B 0x13 // Latitude (DDMM)
1024 #define FRSKY_USERDATA_GPS_CURSE_B 0x14 // Course degrees
1025 #define FRSKY_USERDATA_GPS_DATE 0x15 // Course degrees
1026 #define FRSKY_USERDATA_GPS_YEAR 0x16 // Course degrees
1027 #define FRSKY_USERDATA_GPS_HOURMIN 0x17 // Course degrees
1028 #define FRSKY_USERDATA_GPS_SECONDS 0x18 // Course degrees
1029 #define FRSKY_USERDATA_GPS_SPEED_A 0x19 // Speed 2 decimals of knots
1030 #define FRSKY_USERDATA_GPS_LONG_A 0x1A // Longitude (.MMMM)
1031 #define FRSKY_USERDATA_GPS_LAT_A 0x1B // Latitude (.MMMM)
1032 #define FRSKY_USERDATA_GPS_CURSE_A 0x1C // // Course 2 decimals of degrees
1033 #define FRSKY_USERDATA_GPS_LONG_EW 0x22 //(uint16_t)(flon < 0 ? 'W' : 'E')
1034 #define FRSKY_USERDATA_GPS_LAT_EW 0x23 //(uint16_t)(lat < 0 ? 'S' : 'N')
1035 #define FRSKY_USERDATA_GPS_DIST 0x3C
1038 #ifdef GPS_INSTALLED
1039 //======================================================================================================Send Frame 2 via serial used for GPS
1040 void OXS_OUT::SendFrame2(){
1041 static uint8_t hubGpsCount
;
1042 uint32_t absLongLat
;
1043 uint32_t decimalPartOfDegree
;
1044 uint32_t minWith7Decimals
;
1045 hubMaxData
= 0 ; // reset of number of data to send
1046 // here we fill the buffer with all GPS data
1047 // GPS_lon // longitude in degree with 7 decimals, (neg for S)
1048 // GPS_lat // latitude in degree with 7 decimals, (neg for ?)
1049 // GPS_altitude; // altitude in mm
1050 // GPS_speed_3d; // speed in cm/s
1051 // GPS_speed; // speed in cm/s
1052 // GPS_ground_course ; // degrees with 5 decimals
1053 if ( hubGpsCount
== 0 ) {
1054 absLongLat
= abs(GPS_lat
) ;
1055 decimalPartOfDegree
= (absLongLat
% 10000000 );
1056 minWith7Decimals
= decimalPartOfDegree
* 60 ;
1057 SendValue(FRSKY_USERDATA_GPS_LAT_B
, (uint16_t) (((absLongLat
/ 10000000L) * 100 ) + (minWith7Decimals
/ 10000000L )) ) ; // Latitude (DDMM)
1058 SendValue(FRSKY_USERDATA_GPS_LAT_A
, (uint16_t) (( minWith7Decimals
% 10000000L) / 1000 ) ) ; // Latitude (.MMMM)
1059 SendValue(FRSKY_USERDATA_GPS_LAT_EW
, (uint16_t)(GPS_lat
< 0 ? 'S' : 'N')) ;
1060 } else if ( hubGpsCount
== 1 ) {
1061 absLongLat
= abs(GPS_lon
) ;
1062 decimalPartOfDegree
= (absLongLat
% 10000000 );
1063 minWith7Decimals
= decimalPartOfDegree
* 60 ;
1064 SendValue(FRSKY_USERDATA_GPS_LONG_B
, (uint16_t) (((absLongLat
/ 10000000L) * 100 ) + (minWith7Decimals
/ 10000000L )) ) ; // Longitude (DDMM)
1065 SendValue(FRSKY_USERDATA_GPS_LONG_A
, (uint16_t) (( minWith7Decimals
% 10000000L) / 1000 ) ) ; // Longitude (.MMMM)
1066 SendValue(FRSKY_USERDATA_GPS_LONG_EW
, (uint16_t)(GPS_lon
< 0 ? 'W' : 'E')) ;
1067 } else if ( hubGpsCount
== 2 ) {
1068 SendValue(FRSKY_USERDATA_GPS_ALT_B
, (int16_t) (GPS_altitude
/ 1000) ); // Altitude m
1069 SendValue(FRSKY_USERDATA_GPS_ALT_A
, (uint16_t) ( ( (abs(GPS_altitude
) % 1000 ) / 10 ) ) ) ; // Altitude centimeter
1070 } else if ( hubGpsCount
== 3 ) {
1072 uint32_t GPSSpeedKnot
= GPS_speed_3d
* 1944L ; // speed in knots with 5 décimals (1 cm/sec = 0,0194384 knot)
1074 uint32_t GPSSpeedKnot
= GPS_speed_2d
* 1944L ;
1076 SendValue(FRSKY_USERDATA_GPS_SPEED_B
, (uint16_t) ( GPSSpeedKnot
/ 100000) ) ; // Speed knots
1077 SendValue(FRSKY_USERDATA_GPS_SPEED_A
, (uint16_t) ( (GPSSpeedKnot
% 100000 ) /1000) ) ; // Speed 2 decimals of knots
1078 } else if ( hubGpsCount
== 4 ) {
1079 SendValue(FRSKY_USERDATA_GPS_CURSE_B
, (uint16_t) ( GPS_ground_course
/ 100000 ) ) ; // Course degrees
1080 SendValue(FRSKY_USERDATA_GPS_CURSE_A
, (uint16_t) ( (GPS_ground_course
% 100000) / 1000 ) ) ; // Course 2 decimals of degrees
1083 if ( hubGpsCount
>= 5 ) hubGpsCount
= 0 ;
1084 if( hubMaxData
> 0 ) {
1085 sendHubByte(0x5E) ; // End of Frame 2!
1088 #ifdef DEBUGHUBPROTOCOL
1089 printer
->print("Frame2 to send = ");
1090 for (int cntPrint
= 0 ; cntPrint
< hubData
.maxData
; cntPrint
++) {
1091 printer
->print(" ");
1092 printer
->print(hubData
.data
[cntPrint
] , HEX
);
1094 printer
->println(" ");
1098 #if defined(GPS_TRANSMIT_TIME)
1099 void OXS_OUT::SendFrame3(){
1100 static uint16_t value
;
1101 hubMaxData
= 0 ; // reset of number of data to send
1105 SendValue(FRSKY_USERDATA_GPS_DATE
, value
) ; // DATE (DDMM)
1106 value
=(GPS_year
% 100);
1108 SendValue(FRSKY_USERDATA_GPS_YEAR
, value
) ; // YEAR (CC00)
1112 SendValue(FRSKY_USERDATA_GPS_HOURMIN
, value
) ; // HOURMIN (hhmm)
1115 SendValue(FRSKY_USERDATA_GPS_SECONDS
, value
) ; // seconds (ss00)
1116 if( hubMaxData
> 0 ) {
1117 sendHubByte(0x5E) ; // End of Frame 2!
1122 #endif // end of GPS_INSTALLED
1125 // ******************************************************** //
1126 // SendValue => send a value as frsky sensor hub data //
1127 // ******************************************************** //
1128 void OXS_OUT::SendValue(uint8_t ID
, uint16_t Value
) {
1129 uint8_t tmp1
= Value
& 0x00ff;
1130 uint8_t tmp2
= (Value
& 0xff00)>>8;
1134 if ( (tmp1
== 0x5E) || (tmp1
== 0x5D) ){
1139 if ( (tmp2
== 0x5E) || (tmp2
== 0x5D) ){
1146 //***************************************************
1147 // Put a byte in the buffer
1148 //***************************************************
1149 void OXS_OUT::sendHubByte( uint8_t byte
)
1151 hubData
[hubMaxData
] = byte
;
1156 // ***************************************************
1157 // Search the value, format it and put it in a buffer
1158 // ***************************************************
1159 void OXS_OUT::loadHubValueToSend( uint8_t currentFieldToSend ) {
1160 fieldToSend = (int) convertToHubId[ fieldContainsData[currentFieldToSend][0] ] ;
1161 if ( (fieldToSend >= FRSKY_USERDATA_GPS_ALT_B ) && (fieldToSend <= FRSKY_USERDATA_FUELPERCENT ) ) fieldOk = true ;
1162 else fieldOk = false ;
1163 switch ( fieldContainsData[currentFieldToSend][1] ) {
1167 // if ( (SwitchFrameVariant == 0) && (varioData->absoluteAltAvailable) ) { //========================================================================== Vario Data
1168 if (fieldToSend == DEFAULTFIELD) {
1169 SendAlt( ( (varioData->relativeAlt.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1170 // varioData->absoluteAlt.available = false ;
1172 else if( fieldOk == true ) {
1173 SendValue((int8_t) fieldToSend ,(int16_t) ( (varioData->relativeAlt.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1174 // varioData->absoluteAlt.available = false ;
1178 case VERTICAL_SPEED :
1179 // if ( (SwitchFrameVariant == 0) && (varioData->climbRateAvailable) ){
1180 if (fieldToSend == DEFAULTFIELD) {
1181 // Attempt to work around the annoying 10cm double beep
1182 //SendValue(FRSKY_USERDATA_VERT_SPEED,(int16_t)varioData->climbRate); // ClimbRate in open9x Vario mode
1183 if (varioData->climbRate.value==10) SendValue(FRSKY_USERDATA_VERT_SPEED,(int16_t)9); // ClimbRate in open9x Vario mode
1184 else if (varioData->climbRate.value==-10) SendValue(FRSKY_USERDATA_VERT_SPEED,(int16_t)-9);
1185 else SendValue(FRSKY_USERDATA_VERT_SPEED,( ( (int16_t) varioData->climbRate.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]))+ fieldContainsData[currentFieldToSend][4] ); // ClimbRate in open9x Vario mode
1186 // varioData->climbRateAvailable = false ;
1188 else if( fieldOk == true ) {
1189 SendValue((int8_t) fieldToSend , ( ((int16_t)varioData->climbRate.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]))+ fieldContainsData[currentFieldToSend][4] );
1190 varioData->climbRate.available = false ;
1195 // if ( (SwitchFrameVariant == 0) && (varioData->sensitivity.available ) ){
1196 if ( fieldOk == true ) {
1197 SendValue((int8_t) fieldToSend , ( ((int16_t) varioData->sensitivity.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]))+ fieldContainsData[currentFieldToSend][4] );
1198 // varioData->sensitivityAvailable = false ;
1202 case ALT_OVER_10_SEC :
1203 // if ( (SwitchFrameVariant == 0) && (varioData->vSpeed10SecAvailable ) ){
1204 if ( fieldOk == true ) {
1205 SendValue((int8_t) fieldToSend , ( ( (int16_t) varioData->vSpeed10SecAvailable * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]) ) + fieldContainsData[currentFieldToSend][4] );
1206 // varioData->vSpeed10SecAvailable = false ;
1217 // if ( (SwitchFrameVariant == 0) && (varioData_2->absoluteAltAvailable) ) { //========================================================================== Vario Data
1218 if (fieldToSend == DEFAULTFIELD) {
1219 SendAlt( ( (varioData_2->absoluteAlt.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4]);
1220 // varioData_2->absoluteAltAvailable = false ;
1222 else if( fieldOk == true ) {
1223 SendValue((int8_t) fieldToSend ,(int16_t) ( (varioData_2->absoluteAlt.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1224 // varioData_2->absoluteAltAvailable = false ;
1228 case VERTICAL_SPEED_2 :
1229 // if ( (SwitchFrameVariant == 0) && (varioData_2->climbRateAvailable) ){
1230 if (fieldToSend == DEFAULTFIELD) {
1231 // Attempt to work around the annoying 10cm double beep
1232 //SendValue(FRSKY_USERDATA_VERT_SPEED,(int16_t)varioData->climbRate); // ClimbRate in open9x Vario mode
1233 if (varioData_2->climbRate.value == 10) SendValue(FRSKY_USERDATA_VERT_SPEED,(int16_t)9); // ClimbRate in open9x Vario mode
1234 else if (varioData_2->climbRate.value == -10) SendValue(FRSKY_USERDATA_VERT_SPEED,(int16_t)-9);
1235 else SendValue(FRSKY_USERDATA_VERT_SPEED, ( ( (int16_t) varioData_2->climbRate.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]))+ fieldContainsData[currentFieldToSend][4] ); // ClimbRate in open9x Vario mode
1236 // varioData_2->climbRateAvailable = false ;
1238 else if( fieldOk == true ) {
1239 SendValue((int8_t) fieldToSend , ( ( (int16_t) varioData_2->climbRate.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]))+ fieldContainsData[currentFieldToSend][4] );
1240 // varioData_2->climbRateAvailable = false ;
1244 case SENSITIVITY_2 :
1245 // if ( (SwitchFrameVariant == 0) && (varioData_2->sensitivityAvailable ) ){
1246 if ( fieldOk == true ) {
1247 SendValue((int8_t) fieldToSend , ( ( (int16_t) varioData_2->sensitivity.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]))+ fieldContainsData[currentFieldToSend][4] );
1248 // varioData_2->sensitivityAvailable = false ;
1252 case ALT_OVER_10_SEC_2 :
1253 // if ( (SwitchFrameVariant == 0) && (varioData_2->vSpeed10SecAvailable ) ){
1254 if ( fieldOk == true ) {
1255 SendValue((int8_t) fieldToSend ,(int16_t) ( (varioData_2->vSpeed10SecAvailable * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]) ) + fieldContainsData[currentFieldToSend][4] );
1256 // varioData_2->vSpeed10SecAvailable = false ;
1262 #endif // end vario2
1264 #if defined (VARIO ) && defined (VARIO2)
1265 case VERTICAL_SPEED_A :
1266 if( fieldOk == true ) {
1267 SendValue((int8_t) fieldToSend , ( ( (int16_t) averageVSpeed.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1272 #if defined (VARIO ) && ( defined (VARIO2) || defined( AIRSPEED) || defined(USE_6050) ) && defined (VARIO_PRIMARY ) && defined (VARIO_SECONDARY ) && defined (PIN_PPM)
1274 if( fieldOk == true ) {
1275 SendValue((int8_t) fieldToSend , ( ( (int16_t) switchVSpeed.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1282 if (fieldToSend == DEFAULTFIELD) {
1283 SendGPSSpeed( (( (int16_t) airSpeedData->airSpeed.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4]) ;
1285 else if( fieldOk == true ) {
1286 SendValue((int8_t) fieldToSend , ( ( (int16_t) airSpeedData->airSpeed.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1289 case PRANDTL_COMPENSATION :
1290 // if ( (SwitchFrameVariant == 0) && (airSpeedData->airSpeedAvailable) ) { //========================================================================== Vario Data
1291 if( fieldOk == true ) {
1292 SendValue((int8_t) fieldToSend , ( ( (int16_t) airSpeedData->compensation * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1293 // airSpeedData->airSpeedAvailable = false ;
1298 #endif // end airspeed
1300 #if defined (VARIO) && defined ( AIRSPEED)
1302 if( fieldOk == true ) {
1303 SendValue((int8_t) fieldToSend , ( ((int16_t) compensatedClimbRate.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1306 #endif // End defined (VARIO) && defined ( AIRSPEED)
1311 SendVoltX( 0 , currentFieldToSend) ;
1314 SendVoltX( 1 , currentFieldToSend) ;
1317 SendVoltX( 2 , currentFieldToSend) ;
1320 SendVoltX( 3 , currentFieldToSend) ;
1323 SendVoltX( 4 , currentFieldToSend) ;
1326 SendVoltX( 5 , currentFieldToSend) ;
1330 #if defined (PIN_CURRENTSENSOR)
1332 // if ( (SwitchFrameVariant == 0) && (currentData->milliAmpsAvailable ) ) {
1333 if ( fieldToSend == DEFAULTFIELD ) {
1334 SendCurrentMilliAmps(( ( (int16_t) currentData->milliAmps.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]) ) + fieldContainsData[currentFieldToSend][4]);
1335 // currentData->milliAmpsAvailable = false ;
1337 else if( fieldOk == true ) {
1338 SendValue((int8_t) fieldToSend , ( ( (int16_t) currentData->milliAmps.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]) ) + fieldContainsData[currentFieldToSend][4] );
1339 // currentData->milliAmpsAvailable = false ;
1344 // if ( (SwitchFrameVariant == 0) && (currentData->consumedMilliAmpsAvailable) ){
1345 if( fieldOk == true ) {
1346 SendValue((int8_t) fieldToSend ,(int16_t) ( (currentData->consumedMilliAmps * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1347 // currentData->consumedMilliAmpsAvailable = false ;
1351 // case FRSKY_USERDATA_CURRENT_MAX :
1352 //// if ( (SwitchFrameVariant == 0) ) {
1353 // if ( fieldToSend == DEFAULTFIELD ) {
1354 // SendValue(0x38,int16_t(currentData->maxMilliAmps)); //Cur+ OK!
1356 // else if( fieldOk == true ) {
1357 // SendValue((int8_t) fieldToSend ,(int16_t) ( (currentData->maxMilliAmps * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]) ) + fieldContainsData[currentFieldToSend][4] );
1361 #endif // End PIN_CURRENTSENSOR
1363 #if defined (NUMBEROFCELLS) && (NUMBEROFCELLS > 0) && defined (PIN_VOLTAGE)
1365 // if ( (SwitchFrameVariant == 0) && ( voltageData->mVoltCell_1_2_Available ) ) {
1366 if ( fieldToSend == DEFAULTFIELD ) {
1367 SendCellVoltage( voltageData->mVoltCell_1_2.value ) ;
1368 // voltageData->mVoltCell_1_2_Available = false ;
1374 // if ( (SwitchFrameVariant == 0) && ( voltageData->mVoltCell_3_4_Available ) ) {
1375 if ( fieldToSend == DEFAULTFIELD ) {
1376 SendCellVoltage( voltageData->mVoltCell_3_4.value ) ;
1377 // voltageData->mVoltCell_3_4_Available = false ;
1383 // if ( (SwitchFrameVariant == 0) && ( voltageData->mVoltCell_5_6_Available ) ) {
1384 if ( fieldToSend == DEFAULTFIELD ) {
1385 SendCellVoltage( voltageData->mVoltCell_5_6.value ) ;
1386 // voltageData->mVoltCell_5_6_Available = false ;
1391 #endif // NUMBEROFCELLS > 0
1395 if( fieldOk == true ) {
1396 SendValue((int8_t) fieldToSend , ( ( (int16_t) ppm * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1404 // if ( (SwitchFrameVariant == 0) && ( RpmAvailable ) ) {
1405 if ( fieldToSend == DEFAULTFIELD || fieldToSend == FRSKY_USERDATA_RPM ) {
1406 SendValue(FRSKY_USERDATA_RPM, (( RpmValue * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4]);
1410 #endif // MEASURE_RPM
1412 if( fieldOk == true ) {
1413 SendValue((int8_t) fieldToSend ,(int16_t) ( (test1.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1417 if( fieldOk == true ) {
1418 SendValue((int8_t) fieldToSend ,(int16_t) ( (test2.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1422 if( fieldOk == true ) {
1423 SendValue((int8_t) fieldToSend ,(int16_t) ( (test3.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1429 } // End function loadValueToSend (Frame 1)
1433 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && defined (NUMBEROFCELLS) && (NUMBEROFCELLS > 0)
1434 // ********************************************************** //
1435 // SendCellVoltage => send a cell voltage //
1436 // ********************************************************** //
1437 void OXS_OUT::SendCellVoltage( uint32_t voltage
) {
1438 // For SPORT, cell voltage is formatted as (hex) 12 34 56 78 where 123 = volt of cell n+1 (divided by 2), 456 idem for cell n, 7 = max number of cell and 8 = n (number of cell)
1439 // target format for Hub (hex) is having 2 data sent in format : 84 56 and 91 23 (where 9 = content of 8 incresed by 1)
1440 byte cellID
= (voltage
& 0x0000000f);
1441 uint16_t cellVolt
= ((voltage
>> 8) & 0x0fff) ;
1442 uint8_t v1
= ( (cellID
)<<4 & 0xf0) | ((cellVolt
& 0x0f00)>>8) ;
1443 uint8_t v2
= (cellVolt
& 0x00ff);
1444 uint16_t Value
= (v2
<<8) | (v1
& 0x00ff) ;
1445 SendValue(FRSKY_USERDATA_CELL_VOLT
, Value
);
1447 if (cellID
< NUMBEROFCELLS
) {
1448 cellVolt
= (voltage
& 0xfff00000) >> 20 ;
1449 uint8_t v1
= ( (cellID
)<<4 & 0xf0) | ((cellVolt
& 0x0f00)>>8) ;
1450 uint8_t v2
= (cellVolt
& 0x00ff);
1451 uint16_t Value
= (v2
<<8) | (v1
& 0x00ff) ;
1452 SendValue(FRSKY_USERDATA_CELL_VOLT
, Value
);
1455 #endif // enf of 6 voltage
1457 // ********************************** //
1458 // SendGPSDist => send 0..32768 //
1459 // ********************************** //
1460 //void OXS_OUT::SendGPSDist(uint16_t dist) {// ==> Field "Dist" in open9x
1461 // SendValue(0x3C,uint16_t(dist)); //>> DIST
1464 // ************************************************************ //
1465 // SendTemperature1/2 => tempc in 1/100th of degree celsius //
1466 // Display Range in openTX: -3276,8..32768=-3276,8C..+3276,C //
1467 // ************************************************************ //
1468 void OXS_OUT::SendTemperature1(int16_t tempc) {
1469 SendValue(FRSKY_USERDATA_TEMP1, tempc);
1471 void OXS_OUT::SendTemperature2(int16_t tempc) {
1472 SendValue(FRSKY_USERDATA_TEMP2, tempc);
1475 // ************************************* //
1476 // SendRPM => Send Rounds Per Minute //
1477 // ************************************* //
1478 //void OXS_OUT::SendRPM(uint16_t rpm) {
1480 // rpm = uint16_t((float)rpm/(60/blades));
1481 // SendValue(FRSKY_USERDATA_RPM, rpmValue);
1485 // ************************************* //
1486 // SendFuel => SendFuel Level //
1487 // ************************************* //
1488 void OXS_OUT::SendFuel(uint16_t fuel) {
1489 SendValue(FRSKY_USERDATA_FUEL, fuel);
1492 // ********************************** //
1493 // SendAlt => Send ALtitude in cm //
1494 // ********************************* //
1495 void OXS_OUT::SendAlt(long altcm)
1497 uint16_t Centimeter = uint16_t(abs(altcm)%100);
1501 Meter = (altcm-(long)Centimeter);
1504 Meter = -1*(abs(altcm)+(long)Centimeter);
1507 SendValue(FRSKY_USERDATA_BARO_ALT_B, (int16_t)Meter);
1508 SendValue(FRSKY_USERDATA_BARO_ALT_A, Centimeter);
1511 // **************************************************************** //
1512 // SendGPSAlt - send the a value to the GPS altitude field //
1513 // parameter: altitude in cm between -3276800 and 3276799 //
1514 // cm will not be displayed //
1515 // **************************************************************** //
1516 void OXS_OUT::SendGPSAlt(long altcm)
1518 uint16_t Centimeter = uint16_t(abs(altcm)%100);
1521 Meter = (altcm-(long)Centimeter);
1524 Meter = -1*(abs(altcm)+(long)Centimeter);
1528 // need to send a gps fix before openTX displays this field....
1529 SendValue(FRSKY_USERDATA_GPS_LONG_A, 1);
1530 SendValue(FRSKY_USERDATA_GPS_LONG_B, 1);
1531 SendValue(FRSKY_USERDATA_GPS_LAT_A, 1);
1532 SendValue(FRSKY_USERDATA_GPS_LAT_B, 1);
1533 // now send the data
1534 SendValue(FRSKY_USERDATA_GPS_ALT_B, Meter);
1535 SendValue(FRSKY_USERDATA_GPS_ALT_A, Centimeter);
1539 // **************************************************************** //
1540 // SendGPSSpeed - send the a value to the GPS speed //
1541 // value is split in 2 fields //
1542 // knots and 1/10 of knots //
1543 // **************************************************************** //
1544 void OXS_OUT::SendGPSSpeed(long speedknots)
1546 uint16_t knotDecimal = uint16_t(abs(speedknots)%10);
1549 knots = (speedknots-(long) knotDecimal);
1552 knots = -1*(abs(speedknots)+(long)knotDecimal);
1556 // need to send a gps fix before openTX displays this field....
1557 SendValue(FRSKY_USERDATA_GPS_LONG_A, 1);
1558 SendValue(FRSKY_USERDATA_GPS_LONG_B, 1);
1559 SendValue(FRSKY_USERDATA_GPS_LAT_A, 1);
1560 SendValue(FRSKY_USERDATA_GPS_LAT_B, 1);
1561 // now send the data
1562 SendValue(FRSKY_USERDATA_GPS_SPEED_B, knots);
1563 SendValue(FRSKY_USERDATA_GPS_SPEED_A, knotDecimal);
1566 // *********************************************** //
1567 // SendCurrentMilliAmps => Send Current //
1568 // current will be transmitted as 1/10th of A //
1569 // Range: -32768..32767 => disp -3276..3276 //
1570 // *********************************************** //
1571 void OXS_OUT::SendCurrentMilliAmps(int32_t milliamps)
1573 #ifdef ForceAbsolutCurrent
1574 milliamps=abs(milliamps);
1576 SendValue(FRSKY_USERDATA_CURRENT, (uint16_t)(milliamps/100));
1579 //#endif // End of FRSKY_SPORT
1581 #endif // end HUB protocol --------------------------------------------------------------------------
1583 // ********************************** Here the code to handle the UART communication with the receiver
1585 //#define DEBUGSETNEWDATA
1588 //#define DEBUGASERIAL // Generate signal on A0 A1 in order to debug UART timing
1590 #define FORCE_INDIRECT(ptr) __asm__ __volatile__ ("" : "=e" (ptr) : "0" (ptr))
1592 volatile uint8_t state
; //!< Holds the state of the UART.
1593 static volatile unsigned char SwUartTXData
; //!< Data to be transmitted.
1594 static volatile unsigned char SwUartTXBitCount
; //!< TX bit counter.
1595 static volatile uint8_t SwUartRXData
; //!< Storage for received bits.
1596 static volatile uint8_t SwUartRXBitCount
; //!< RX bit counter.
1597 static volatile uint8_t TxCount
;
1599 volatile uint8_t debugUartRx
;
1601 volatile uint8_t ppmInterrupted
; // This flag is activated at the end of handling interrupt on Timer 1 Compare A if during this interrupt handling an interrupt on pin change (INT0 or INT1) occurs
1602 // in this case, ppm will be wrong and has to be discarded
1606 // Here the code for both Frsky protocols +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1607 //! \brief Timer1 interrupt service routine. *************** interrupt between 2 bits (handled by timer1)
1609 // Timer1 will ensure that bits are written and read at the correct instants in time.
1610 // The state variable will ensure context switching between transmit and receive.
1611 // If state should be something else, the variable is set to IDLE. IDLE is regarded as a safe state/mode.
1614 uint8_t ByteStuffByte
= 0 ;
1617 uint8_t volatile hubData
[MAXSIZEBUFFER
] ;
1618 uint8_t volatile hubMaxData
; // max number of data prepared to be send
1622 uint8_t TxSportData
[7] ;
1624 uint8_t volatile sportData
[7] ;
1625 uint8_t volatile sendStatus
;
1626 //uint8_t volatile gpsSendStatus ;
1627 //uint8_t volatile gpsSportDataLock ;
1628 //uint8_t volatile gpsSportData[7] ;
1629 uint8_t currentSensorId
; // save the sensor id being received and on which oXs will reply (can be the main sensor id or GPS sensor id)
1632 ISR(TIMER1_COMPA_vect
)
1634 #if defined( PROTOCOL ) && ( ( PROTOCOL == FRSKY_SPORT ) || ( PROTOCOL == FRSKY_SPORT_HUB ) )
1635 if ( sportAvailable
) { // ++++++++ here only for SPORT protocol ++++++++++++++++++++++++++++++++++
1639 case TRANSMIT
: // Output the TX buffer in SPORT ************ we are sending each bit of data
1643 if( SwUartTXBitCount
< 8 )
1645 if( SwUartTXData
& 0x01 ) // If the LSB of the TX buffer is 1:
1647 CLEAR_TX_PIN() ; // Send a logic 1 on the TX_PIN.
1651 SET_TX_PIN() ; // Send a logic 0 on the TX_PIN.
1653 SwUartTXData
= SwUartTXData
>> 1 ; // Bitshift the TX buffer and
1654 SwUartTXBitCount
+= 1 ; // increment TX bit counter.
1656 else //Send stop bit.
1658 CLEAR_TX_PIN(); // Output a logic 1.
1659 state
= TRANSMIT_STOP_BIT
;
1660 //ENABLE_TIMER0_INT() ; // Allow this in now.
1662 OCR1A
+= TICKS2WAITONESPORT
; // Count one period into the future.
1668 // Go to idle after stop bit was sent.
1669 case TRANSMIT_STOP_BIT
: // SPORT ************************************* We have sent a stop bit, we look now if there is other byte to send
1670 if ( ByteStuffByte
|| (++TxCount
< 8 ) ) // Have we sent 8 bytes?
1672 if ( ByteStuffByte
)
1674 SwUartTXData
= ByteStuffByte
;
1679 if ( TxCount
< 7 ) // Data (or crc)?
1681 SwUartTXData
= TxSportData
[TxCount
] ;
1682 Crc
+= SwUartTXData
; //0-1FF
1683 Crc
+= Crc
>> 8 ; //0-100
1688 SwUartTXData
= 0xFF-Crc
; // prepare sending check digit
1690 if ( ( SwUartTXData
== 0x7E ) || ( SwUartTXData
== 0x7D ) )
1692 ByteStuffByte
= SwUartTXData
^ 0x20 ;
1693 SwUartTXData
= 0x7D ;
1696 SET_TX_PIN() ; // Send a logic 0 on the TX_PIN. (= start bit)
1697 OCR1A
= TCNT1
+ TICKS2WAITONESPORT
- INTERRUPT_BETWEEN_TRANSMIT
; // Count one period into the future. Compensate the time for ISR
1698 SwUartTXBitCount
= 0 ;
1700 //DISABLE_TIMER0_INT() ; // For the byte duration
1702 else // 8 bytes have been send
1704 frskyStatus
|= 1 << sensorIsr
; // set the bit relative to sensorIsr to say that a new data has to be loaded for sensorIsr.
1706 OCR1A
+= DELAY_3500
; // 3.5mS gap before listening
1707 TRXDDR
&= ~( 1 << PIN_SERIALTX
) ; // PIN is input
1708 TRXPORT
&= ~( 1 << PIN_SERIALTX
) ; // PIN is tri-stated.
1712 case RECEIVE
: // SPORT **** Start bit has been received and we will read bits of data receiving, LSB first.
1713 OCR1A
+= TICKS2WAITONESPORT
; // Count one period after the falling edge is trigged.
1715 uint8_t data
; // Use a temporary local storage
1716 data
= SwUartRXBitCount
;
1717 if( data
< 8 ) { // If 8 bits are not yet read
1718 SwUartRXBitCount
= data
+ 1 ;
1719 data
= SwUartRXData
;
1720 data
>>= 1 ; // Shift due to receiving LSB first.
1724 #if PIN_SERIALTX == 7
1725 if( GET_RX_PIN( )) {
1727 if( GET_RX_PIN( ) == 0 ) {
1729 data
|= 0x80 ; // If a logical 1 is read, let the data mirror this.
1734 SwUartRXData
= data
;
1736 else { //Done receiving = 8 bits are in SwUartRXData
1740 #ifdef DEBUG_SPORT_RECEIVED
1744 if ( LastRx
== 0x7E ) {
1745 switch (SwUartRXData
) {
1747 #define VARIO_ID DATA_ID_VARIO // replace those values by the right on
1748 #define CELL_ID DATA_ID_FLVSS
1749 #define CURRENT_ID DATA_ID_FAS
1750 #define GPS_ID DATA_ID_GPS
1751 #define RPM_ID DATA_ID_RPM
1752 #define ACC_ID DATA_ID_ACC
1753 #define TX_ID DATA_ID_TX // this ID is used when TX sent data to RX with a LUA script ; it requires that LUA script uses the same parameters
1754 #define SENSOR_ISR_FOR_TX_ID 0XF0 // this value says that we already received a byte == TX_ID
1757 sensorIsr
= 0 ; break ;
1759 sensorIsr
= 1 ; break ;
1761 sensorIsr
= 2 ; break ;
1763 sensorIsr
= 3 ; break ;
1765 sensorIsr
= 4 ; break ;
1767 sensorIsr
= 5 ; break ;
1769 TxDataIdx
= 0 ; // reset the counter used to register all bytes received from Tx
1770 sensorIsr
= SENSOR_ISR_FOR_TX_ID
; break ; // this value says that an ID related to a frame sent by Tx has been received; take care that it is perhaps just a pulling from RX without Tx frame.
1774 if ( ( sensorIsr
< 6 ) && ( idToReply
& (1 << sensorIsr
) ) ) { // If this sensor ID is supported by oXs and it has been configured in order to send some data
1775 if ( ( frskyStatus
& ( 1 << sensorIsr
) ) == 0 ) { // If this sensor ID is supported by oXs and oXs has prepared data to reply data in dataValue[] for this sensorSeq
1776 // if ( sportDataLock == 0 ) {
1777 TxSportData
[0] = 0x10 ;
1778 TxSportData
[1] = dataId
[sensorIsr
] << 4 ;
1779 TxSportData
[2] = dataId
[sensorIsr
] >> 4 ;
1780 TxSportData
[3] = dataValue
[sensorIsr
] ;
1781 TxSportData
[4] = dataValue
[sensorIsr
] >> 8 ;
1782 TxSportData
[5] = dataValue
[sensorIsr
] >> 16 ;
1783 TxSportData
[6] = dataValue
[sensorIsr
] >> 24 ;
1785 TxSportData
[0] = 0x10 ;
1786 TxSportData
[1] = 0 ;
1787 TxSportData
[2] = 0 ;
1788 TxSportData
[3] = 0 ;
1789 TxSportData
[4] = 0 ;
1790 TxSportData
[5] = 0 ;
1791 TxSportData
[6] = 0 ;
1794 OCR1A
+= ( DELAY_400
- TICKS2WAITONESPORT
) ; // 400 uS gap before sending (remove 1 tick time because it was already added before
1796 } else if ( sensorIsr
== SENSOR_ISR_FOR_TX_ID
) { // we received an ID that could be used by TX to send data to the sensor; so we have to continue reading bytes
1797 state
= IDLE
; // Go back to idle
1798 } else { // No data are loaded (so there is no data yet available or oXs does not have to reply to this ID)
1799 state
= WAITING
; // Wait for idle time
1800 OCR1A
+= DELAY_3500
; // 3.5mS gap before listening
1802 } // end receive 1 byte and previous was equal to 0x7E
1803 else if ( SwUartRXData
== 0x7E) { // reset sensorIsr when 0X7E is received (stop receiving data from Tx) and listen to next byte
1804 sensorIsr
= 128 ; // reset sensorIsr when 0X7E is received (stop receiving data from Tx)
1805 rxStuff
= 0; // and reset the stuff flag
1806 state
= IDLE
; // Go back to idle.
1807 } else if ((sensorIsr
== SENSOR_ISR_FOR_TX_ID
) && (TxDataIdx
< 8) ){ // we receive one byte that is not 0x7E. We check if it follow a sequence 0X7E and the Tx_ID which means it is sent by Tx to oXs
1808 // Note: if all bytes have been received, then TxDataIdx = 8 and we do not store the data anymore; test on TxDataIdx = 8 is done in .ino file
1809 if (SwUartRXData
== 0x7D) // byte stuffing indicator
1810 rxStuff
= 1; // set the flag and discard byte
1811 else if (rxStuff
== 0)
1812 TxData
[TxDataIdx
++] = SwUartRXData
; // we save the received byte in a buffer
1814 TxData
[TxDataIdx
++] = SwUartRXData
| 0x20 ; // we save the received byte in a buffer taking into account the stuff bit
1815 rxStuff
= 0; // and reset the flag
1817 state
= IDLE
; // Go back to idle.
1819 state
= IDLE
; // Go back to idle.
1820 } // end of test on receiving one byte
1821 LastRx
= SwUartRXData
; // save the current byte
1822 if (state
== IDLE
) { // when Go back to idle.
1823 DISABLE_TIMER_INTERRUPT() ; // Stop the timer interrupts.
1824 #if PIN_SERIALTX == 7
1825 ACSR
|= ( 1<<ACI
) ; // clear pending interrupt
1826 ACSR
|= ( 1<<ACIE
) ; // interrupt enabled (so we can receive another byte)
1828 PCIFR
= ( 1<<PCIF2
) ; // clear pending interrupt
1829 PCICR
|= ( 1<<PCIE2
) ; // pin change interrupt enabled
1833 } // End receiving 1 bit or 1 byte (8 bits)
1837 case TxPENDING
: // SPORT ****** we will here send a start bit before sending a byte
1841 TRXDDR
|= ( 1 << PIN_SERIALTX
) ; // PIN is output
1842 SET_TX_PIN() ; // Send a logic 0 on the TX_PIN. = start bit
1843 OCR1A
= TCNT1
+ ( TICKS2WAITONESPORT
- INTERRUPT_ENTRY_TRANSMIT
); // Count one period into the future (less the time to execute ISR) .
1844 SwUartTXBitCount
= 0 ;
1845 Crc
= SwUartTXData
= TxSportData
[0] ;
1852 //#endif // end of Frsky_Port
1854 case WAITING
: // SPORT ******** we where waiting for some time before listening for an start bit; we can now expect a start bit again
1855 DISABLE_TIMER_INTERRUPT() ; // Stop the timer interrupts.
1856 state
= IDLE
; // Go back to idle.
1857 #if PIN_SERIALTX == 7
1858 ACSR
|= ( 1<<ACI
) ; // clear pending interrupt
1859 ACSR
|= ( 1<<ACIE
) ; // interrupt enabled (so we can receive another byte)
1861 PCIFR
= ( 1<<PCIF2
) ; // clear pending interrupt
1862 PCICR
|= ( 1<<PCIE2
) ; // pin change interrupt enabled
1868 state
= IDLE
; // Error, should not occur. Going to a safe state.
1870 } // end sportAvailable == true
1872 #endif // end of #if defined( PROTOCOL ) && ( ( PROTOCOL == FRSKY_SPORT ) || ( PROTOCOL == FRSKY_SPORT_HUB ) )
1873 #if defined( PROTOCOL ) && ( ( PROTOCOL == FRSKY_HUB ) || ( PROTOCOL == FRSKY_SPORT_HUB ) ) // ++++++++ here for Hub protocol ++++++++++++++++++++++++++++++++++
1875 if (!sportAvailable
) { // we are handling the Hub protocol
1878 case TRANSMIT
: // Hub **** Output the TX buffer. Start bit has already been sent ************
1882 if( SwUartTXBitCount
< 8 ) { // if all bits have not been sent
1883 if( SwUartTXData
& 0x01 ) { // If the LSB of the TX buffer is 1:
1884 CLEAR_TX_PIN() ; // Send a logic 1 on the TX_PIN.
1885 } else { // Otherwise:
1886 SET_TX_PIN() ; // Send a logic 0 on the TX_PIN.
1888 SwUartTXData
= SwUartTXData
>> 1 ; // Bitshift the TX buffer and
1889 SwUartTXBitCount
+= 1 ; // increment TX bit counter.
1890 } else { //all 8 bits have been sent so now Send stop bit.
1891 CLEAR_TX_PIN(); // Output a logic 1.
1892 state
= TRANSMIT_STOP_BIT
;
1894 OCR1A
+= TICKS2WAITONEHUB
; // Count one period into the future.
1900 // Go to idle after stop bit was sent.
1901 case TRANSMIT_STOP_BIT
: // HUB ********************* We have sent a stop bit, now sent eventually next byte from buffer
1902 if ( ++TxCount
< hubMaxData
) { // Have we sent all bytes? if not,
1903 SwUartTXData
= hubData
[TxCount
] ; // load next byte
1904 SET_TX_PIN() ; // Send a logic 0 on the TX_PIN. (= start bit)
1905 OCR1A
= TCNT1
+ TICKS2WAITONEHUB
- INTERRUPT_BETWEEN_TRANSMIT
; // Count one period into the future.
1906 SwUartTXBitCount
= 0 ;
1908 } else { // if all bytes have been send, wait 100usec
1911 OCR1A
+= DELAY_3500
; // 3500 usec gap (instead of 100uS gap)
1916 DISABLE_TIMER_INTERRUPT() ; // Stop the timer interrupts.
1917 state
= IDLE
; // Go back to idle.
1922 state
= IDLE
; // Error, should not occur. Going to a safe state.
1925 } // end Hub protocol
1926 #endif // end of code for HUB protocol
1929 // End of the code for both Frsky protocols +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1932 //____________________Here the code for SPORT interface only ++++++++++++++++++++++++++++++++++++++++++
1933 #if defined( PROTOCOL ) && ( ( PROTOCOL == FRSKY_SPORT ) || ( PROTOCOL == FRSKY_SPORT_HUB ) )
1934 //brief Function to initialize the UART for Sport protocol
1935 // This function will set up pins to transmit and receive on. Control of Timer0 and External interrupt 0.
1936 void initSportUart( ) //*************** initialise UART pour SPORT
1939 #if defined ( SPORT_SENSOR_ID ) && SPORT_SENSOR_ID >= 1 && SPORT_SENSOR_ID <= 28
1940 #define ID_MIN_1 (SPORT_SENSOR_ID - 1)
1941 #define BIT0 ( ID_MIN_1 & 0x01 )
1942 #define BIT1 (( ID_MIN_1 >> 1) & 0x01 )
1943 #define BIT2 (( ID_MIN_1 >> 2) & 0x01 )
1944 #define BIT3 (( ID_MIN_1 >> 3) & 0x01 )
1945 #define BIT4 (( ID_MIN_1 >> 4) & 0x01 )
1946 #define BIT5 (BIT0 xor BIT1 xor BIT2)
1947 #define BIT6 (BIT2 xor BIT3 xor BIT4)
1948 #define BIT7 (BIT0 xor BIT2 xor BIT4)
1949 sensorId = ID_MIN_1 | (BIT5 << 5) | (BIT6 << 6) | (BIT7 << 7) ;
1951 #error "SPORT_SENSOR_ID must be between 1 and 28 (included)"
1955 TRXDDR
&= ~( 1 << PIN_SERIALTX
) ; // PIN is input.
1956 TRXPORT
&= ~( 1 << PIN_SERIALTX
) ; // PIN is tri-stated.
1958 // External interrupt
1960 #if PIN_SERIALTX == 4
1961 PCMSK2
|= 0x10 ; // IO4 (PD4) on Arduini mini
1962 #elif PIN_SERIALTX == 2
1963 PCMSK2
|= 0x04 ; // IO2 (PD2) on Arduini mini
1965 #if PIN_SERIALTX != 7
1966 #error "This PIN is not supported"
1970 #if PIN_SERIALTX == 7
1971 ACSR
|= ( 1<<ACI
) ; // clear pending interrupt
1972 ACSR
|= ( 1<<ACIE
) ; // interrupt enabled (so we can receive another byte)
1974 PCIFR
= ( 1<<PCIF2
) ; // clear pending interrupt
1975 PCICR
|= ( 1<<PCIE2
) ; // pin change interrupt enabled
1978 // Internal State Variable
1982 DDRC
= 0x03 ; // PC0,1 as o/p debug
1987 // ! \brief External interrupt service routine. ********************
1988 // Interrupt on Pin Change to detect change on level on SPORT signal (= could be a start bit)
1990 // The falling edge in the beginning of the start
1991 // bit will trig this interrupt. The state will
1992 // be changed to RECEIVE, and the timer interrupt
1993 // will be set to trig one and a half bit period
1994 // from the falling edge. At that instant the
1995 // code should sample the first data bit.
1997 // note initSoftwareUart( void ) must be called in advance.
1999 // This is the pin change interrupt for port D
2000 // This assumes it is the only pin change interrupt on port D
2001 //#ifdef FRSKY_SPORT
2002 #if PIN_SERIALTX == 7
2003 ISR(ANALOG_COMP_vect
)
2005 ACSR
&= ~(1 << ACIE
) ; // interrupt disabled
2007 state
= RECEIVE
; // Change state
2008 DISABLE_TIMER_INTERRUPT() ; // Disable timer to change its registers.
2009 OCR1A
= TCNT1
+ TICKS2WAITONE_HALFSPORT
- INTERRUPT_EXEC_CYCL
- INTERRUPT_EARLY_BIAS
; // Count one and a half period into the future.
2011 DDRC
= 0x03 ; // PC0,1 as o/p debug
2014 SwUartRXBitCount
= 0 ; // Clear received bit counter.
2015 CLEAR_TIMER_INTERRUPT() ; // Clear interrupt bits
2016 ENABLE_TIMER_INTERRUPT() ; // Enable timer1 interrupt on again
2021 if ( TRXPIN
& ( 1 << PIN_SERIALTX
) ) { // if Pin is high = start bit (inverted)
2022 DISABLE_PIN_CHANGE_INTERRUPT() ; // pin change interrupt disabled
2024 state
= RECEIVE
; // Change state
2025 DISABLE_TIMER_INTERRUPT() ; // Disable timer to change its registers.
2026 OCR1A
= TCNT1
+ TICKS2WAITONE_HALFSPORT
- INTERRUPT_EXEC_CYCL
- INTERRUPT_EARLY_BIAS
; // Count one and a half period into the future.
2030 SwUartRXBitCount
= 0 ; // Clear received bit counter.
2031 CLEAR_TIMER_INTERRUPT() ; // Clear interrupt bits
2032 ENABLE_TIMER_INTERRUPT() ; // Enable timer1 interrupt on again
2034 //#ifdef PPM_INTERRUPT
2035 // if ( EIFR & PPM_INT_BIT) ppmInterrupted = 1 ;
2040 #endif // #end of code for SPORT protocol
2045 //____________________Here the code for HUB interface only ++++++++++++++++++++++++++++++++++++++++++
2046 #if defined( PROTOCOL ) && ( ( PROTOCOL == FRSKY_HUB ) || ( PROTOCOL == FRSKY_SPORT_HUB ) )
2047 //brief Function to initialize the UART for Sport protocol
2048 // This function will set up pins to transmit and receive on. Control of Timer0 and External interrupt 0.
2051 // ThisHubData = pdata ;
2052 TRXPORT
&= ~( 1 << PIN_SERIALTX
) ; // PIN is low
2053 TRXDDR
|= ( 1 << PIN_SERIALTX
) ; // PIN is output.
2055 //Internal State Variable
2061 DDRC
= 0x03 ; // PC0,1 as o/p debug
2066 void setHubNewData( )
2068 if ( (TxCount
== 0) && (hubMaxData
> 0) ) {
2069 // for (int cntNewData = 0 ; cntNewData < hubMaxData ; cntNewData++) {
2070 // TxHubData[cntNewData] = hubData[cntNewData] ;
2072 // TxMax = hubMaxData ;
2073 #ifdef DEBUGSETNEWDATA
2074 Serial
.print("set new data at ");
2075 Serial
.print( millis() );
2077 for (int cntNewData
= 0 ; hubMaxData
; cntNewData
++) {
2078 Serial
.print( hubData
[cntNewData
] , HEX
);
2081 Serial
.println(" ");
2083 startHubTransmit() ;
2087 void startHubTransmit()
2089 if ( state
!= IDLE
)
2093 SET_TX_PIN() ; // Send a logic 0 on the TX_PIN (=start bit).
2094 uint8_t oReg
= SREG
; // save status register
2096 OCR1A
= TCNT1
+ TICKS2WAITONEHUB
- INTERRUPT_ENTRY_TRANSMIT
; // Count one period into the future.
2097 CLEAR_TIMER_INTERRUPT() ; // Clear interrupt bits
2098 SREG
= oReg
; // restore the status register
2099 SwUartTXBitCount
= 0 ;
2100 SwUartTXData
= hubData
[0] ;
2103 ENABLE_TIMER_INTERRUPT() ; // Enable timer1 interrupt on again
2109 // end of function that are hub specific
2110 #endif // end of code for Hub protocol
2113 //********************************** End of code to handle the UART communication with the receiver
2114 #endif //End of FRSKY protocols