UBlox M10 Support
[openXsensor.git] / openXsensor / oXs_out_frsky.cpp
blobbd6d9fc3a763638a8f3a7d0c570e2bedeb5d8e25
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
6 #ifdef DEBUG
7 // ************************* Several parameters to help debugging
8 //#define DEBUG_LOAD_SPORT
9 //#define DEBUG_STATE
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)
36 #endif
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 ;
45 #endif
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 ;
55 uint8_t rxStuff ;
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 ;
63 #endif
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 ;
67 #endif
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;
78 #endif
79 extern bool GPS_fix ;
80 #endif
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 ;
104 #endif
107 #ifdef DEBUG
108 OXS_OUT::OXS_OUT(uint8_t pinTx,HardwareSerial &print)
109 #else
110 OXS_OUT::OXS_OUT(uint8_t pinTx)
111 #endif
113 _pinTx = pinTx ;
114 #ifdef DEBUG
115 printer = &print; //operate on the address of print
116 #endif
117 } // end constructor
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
123 //initilalise PORT
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) ;
130 #endif
132 #if defined( PROTOCOL ) && ( PROTOCOL == FRSKY_SPORT )
133 initMeasurement() ;
134 initSportUart( ) ;
135 sportAvailable = true ; // force the SPORT protocol
136 #elif defined(PROTOCOL) && ( PROTOCOL == FRSKY_HUB )
137 initHubUart( ) ;
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
145 #else
146 #if PIN_SERIALTX != 7
147 #error "This PIN is not supported"
148 #endif
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
153 #endif
155 #if PIN_SERIALTX == 7
156 ACSR |= ( 1<<ACI ) ; // clear pending interrupt
157 #else
158 PCIFR = (1<<PCIF2) ; // clear pending interrupt
159 #endif
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
163 #endif
164 #if PIN_SERIALTX == 7
165 if ( ( ACSR & (1<<ACI)) == 0 ) {
166 #else
167 if ( ( PCIFR & (1<<PCIF2)) == 0 ) {
168 #endif
169 sportAvailable = false ;
170 initHubUart() ;
172 else {
173 sportAvailable = true ;
174 initMeasurement() ;
175 initSportUart() ;
177 #endif // end test on FRSKY
178 #ifdef DEBUG
179 printer->print(F("FRSky Output Module: TX Pin="));
180 printer->println(_pinTx);
181 printer->print(F("Sport protocol= "));
182 printer->println(sportAvailable);
183 #endif // end DEBUG
184 } // end of setup
187 void OXS_OUT::sendData() {
188 #if defined( PROTOCOL ) && ( PROTOCOL == FRSKY_SPORT )
189 sendSportData() ;
190 #elif defined(PROTOCOL) && ( PROTOCOL == FRSKY_HUB )
191 sendHubData() ;
192 #else // we will detect automatically if SPORT is available
193 if (sportAvailable) {
194 sendSportData() ;
195 } else {
196 sendHubData() ;
198 #endif
201 //For SPORT protocol
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
227 uint8_t sensorSeq ;
228 uint8_t sensorIsr ;
230 struct ONE_MEASUREMENT no_data = { 0, 0 } ;
232 void initMeasurement() {
233 // pointer to Altitude
234 #if defined(VARIO)
235 p_measurements[0] = &oXs_MS5611.varioData.relativeAlt ; // we use always relative altitude in Frsky protocol
236 idToReply |= 0x01 ;
237 #else
238 p_measurements[0] = &no_data ;
239 #endif
241 // pointer to VSpeed
242 #if defined(VARIO)
243 p_measurements[1] = &mainVspeed ;
244 #else
245 p_measurements[1] = &no_data ;
246 #endif
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 ;
251 idToReply |= 0x02 ;
252 #else
253 p_measurements[2] = &no_data ;
254 #endif
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 ;
259 #else
260 p_measurements[3] = &no_data ;
261 #endif
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 ;
266 #else
267 p_measurements[4] = &no_data ;
268 #endif
269 // pointer to vfas
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 ;
272 idToReply |= 0x04 ;
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 ;
275 idToReply |= 0x04 ;
276 #else
277 p_measurements[5] = &no_data ;
278 #endif
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 ;
283 idToReply |= 0x04 ;
284 #else
285 p_measurements[6] = &no_data ;
286 #endif
288 // pointer to fuel
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];
291 idToReply |= 0x04 ;
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];
294 idToReply |= 0x04 ;
295 #else
296 p_measurements[7] = &no_data ;
297 #endif
299 // pointer to A3
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];
302 idToReply |= 0x04 ;
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];
305 idToReply |= 0x04 ;
306 #else
307 p_measurements[8] = &no_data ;
308 #endif
310 // pointer to A4
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];
313 idToReply |= 0x04 ;
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];
316 idToReply |= 0x04 ;
317 #else
318 p_measurements[9] = &no_data ;
319 #endif
322 // pointer to GPS lon
323 #if defined(GPS_INSTALLED)
324 p_measurements[10] = &sport_gps_lon ;
325 idToReply |= 0x08 ;
326 #else
327 p_measurements[10] = &no_data ;
328 #endif
330 // pointer to GPS lat
331 #if defined(GPS_INSTALLED)
332 p_measurements[11] = &sport_gps_lat ;
333 #else
334 p_measurements[11] = &no_data ;
335 #endif
337 // pointer to GPS alt
338 #if defined(GPS_INSTALLED)
339 p_measurements[12] = &sport_gps_alt ;
340 #else
341 p_measurements[12] = &no_data ;
342 #endif
344 // pointer to GPS speed
345 #if defined(GPS_INSTALLED)
346 p_measurements[13] = &sport_gps_speed ;
347 #else
348 p_measurements[13] = &no_data ;
349 #endif
351 // pointer to GPS course
352 #if defined(GPS_INSTALLED)
353 p_measurements[14] = &sport_gps_course ;
354 #else
355 p_measurements[14] = &no_data ;
356 #endif
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 ;
363 #else
364 p_measurements[15] = &no_data ;
365 p_measurements[16] = &no_data ;
366 #endif
367 #else
368 p_measurements[15] = &no_data ;
369 p_measurements[16] = &no_data ;
370 #endif
372 // pointer to RPM
373 #if defined(MEASURE_RPM)
374 p_measurements[17] = &sport_rpm ;
375 idToReply |= 0x10 ;
376 #else
377 p_measurements[17] = &no_data ;
378 #endif
380 // pointer to T1
381 #if defined(T1_SOURCE) && ( T1_SOURCE == TEST_1)
382 p_measurements[18] = &test1 ;
383 idToReply |= 0x10 ;
384 #elif defined(T1_SOURCE) && ( T1_SOURCE == TEST_2)
385 p_measurements[18] = &test2 ;
386 idToReply |= 0x10 ;
387 #elif defined(T1_SOURCE) && ( T1_SOURCE == TEST_3)
388 p_measurements[18] = &test3 ;
389 idToReply |= 0x10 ;
390 #elif defined(T1_SOURCE) && ( T1_SOURCE == GLIDER_RATIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
391 p_measurements[18] = &gliderRatio ;
392 idToReply |= 0x10 ;
393 #elif defined(T1_SOURCE) && ( T1_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
394 p_measurements[18] = &secFromT0 ;
395 idToReply |= 0x10 ;
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 ;
398 idToReply |= 0x10 ;
399 #elif defined(T1_SOURCE) && ( T1_SOURCE == SENSITIVITY) && defined(VARIO)
400 p_measurements[18] = &oXs_MS5611.varioData.sensitivity ;
401 idToReply |= 0x10 ;
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 ;
404 idToReply |= 0x10 ;
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] ;
407 idToReply |= 0x10 ;
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];
410 idToReply |= 0x10 ;
411 #else
412 p_measurements[18] = &no_data ; // T1
413 #endif
415 // pointer to T2
416 #if defined(T2_SOURCE) && ( T2_SOURCE == TEST_1)
417 p_measurements[19] = &test1 ;
418 idToReply |= 0x10 ;
419 #elif defined(T2_SOURCE) && ( T2_SOURCE == TEST_2)
420 p_measurements[19] = &test2 ;
421 idToReply |= 0x10 ;
422 #elif defined(T2_SOURCE) && ( T2_SOURCE == TEST_3)
423 p_measurements[19] = &test3 ;
424 idToReply |= 0x10 ;
425 #elif defined(T2_SOURCE) && ( T2_SOURCE == GLIDER_RATIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
426 p_measurements[19] = &gliderRatio ;
427 idToReply |= 0x10 ;
428 #elif defined(T2_SOURCE) && ( T2_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
429 p_measurements[19] = &secFromT0 ;
430 idToReply |= 0x10 ;
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 ;
433 idToReply |= 0x10 ;
434 #elif defined(T2_SOURCE) && ( T2_SOURCE == SENSITIVITY) && defined(VARIO)
435 p_measurements[19] = &oXs_MS5611.varioData.sensitivity ;
436 idToReply |= 0x10 ;
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 ;
439 idToReply |= 0x10 ;
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] ;
442 idToReply |= 0x10 ;
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];
445 idToReply |= 0x10 ;
446 #else
447 p_measurements[19] = &no_data ; // T2
448 #endif
452 // pointer to airspeed
453 #if defined(AIRSPEED)
454 p_measurements[20] = &oXs_4525.airSpeedData.airSpeed ;
455 idToReply |= 0x10 ;
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 ;
458 idToReply |= 0x10 ;
459 #elif defined(AIRSPEED_SDP3X)
460 p_measurements[20] = &oXs_sdp3x.airSpeedData.airSpeed ;
461 idToReply |= 0x10 ;
462 #else
463 p_measurements[20] = &no_data ;
464 #endif
466 // pointer to accX
467 #if defined(ACCX_SOURCE) && ( ACCX_SOURCE == TEST_1)
468 p_measurements[21] = &test1 ; // accX
469 idToReply |= 0x20 ;
470 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == TEST_2)
471 p_measurements[21] = &test2 ; // accX
472 idToReply |= 0x20 ;
473 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == TEST_3)
474 p_measurements[21] = &test3 ; // accX
475 idToReply |= 0x20 ;
476 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == GLIDER_RATIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
477 p_measurements[21] = &gliderRatio ;
478 idToReply |= 0x20 ;
479 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
480 p_measurements[21] = &secFromT0 ;
481 idToReply |= 0x20 ;
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 ;
484 idToReply |= 0x20 ;
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] ;
487 idToReply |= 0x20 ;
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];
490 idToReply |= 0x20 ;
491 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == PITCH) && defined(USE_6050)
492 p_measurements[21] = &pitch ; // accX
493 idToReply |= 0x20 ;
494 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == ROLL) && defined(USE_6050)
495 p_measurements[21] = &roll ; // accX
496 idToReply |= 0x20 ;
497 #elif defined(ACCX_SOURCE) && ( ACCX_SOURCE == YAW) && defined(USE_6050)
498 p_measurements[21] = &yaw ; // accX
499 idToReply |= 0x20 ;
500 #else
501 p_measurements[21] = &no_data ; // accX
502 #endif
504 // pointer to accY
505 #if defined(ACCY_SOURCE) && ( ACCY_SOURCE == TEST_1)
506 p_measurements[22] = &test1 ; // accY
507 idToReply |= 0x20 ;
508 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == TEST_2)
509 p_measurements[22] = &test2 ; // accY
510 idToReply |= 0x20 ;
511 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == TEST_3)
512 p_measurements[22] = &test3 ; // accY
513 idToReply |= 0x20 ;
514 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == GLIDER_RATIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
515 p_measurements[22] = &gliderRatio ;
516 idToReply |= 0x20 ;
517 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
518 p_measurements[22] = &secFromT0 ;
519 idToReply |= 0x20 ;
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 ;
522 idToReply |= 0x20 ;
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] ;
525 idToReply |= 0x20 ;
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];
528 idToReply |= 0x20 ;
529 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == PITCH) && defined(USE_6050)
530 p_measurements[22] = &pitch ;
531 idToReply |= 0x20 ;
532 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == ROLL) && defined(USE_6050)
533 p_measurements[22] = &roll ;
534 idToReply |= 0x20 ;
535 #elif defined(ACCY_SOURCE) && ( ACCY_SOURCE == YAW) && defined(USE_6050)
536 p_measurements[22] = &yaw ;
537 idToReply |= 0x20 ;
538 #else
539 p_measurements[22] = &no_data ; // accY
540 #endif
542 // pointer to accZ
543 #if defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == TEST_1)
544 p_measurements[23] = &test1 ; // accZ
545 idToReply |= 0x20 ;
546 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == TEST_2)
547 p_measurements[23] = &test2 ; // accZ
548 idToReply |= 0x20 ;
549 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == TEST_3)
550 p_measurements[23] = &test3 ; // accZ
551 idToReply |= 0x20 ;
552 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == GLIDER_RATIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
553 p_measurements[23] = &gliderRatio ;
554 idToReply |= 0x20 ;
555 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == SECONDS_SINCE_T0 ) && defined(VARIO) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
556 p_measurements[23] = &secFromT0 ;
557 idToReply |= 0x20 ;
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 ;
560 idToReply |= 0x20 ;
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] ;
563 idToReply |= 0x20 ;
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];
566 idToReply |= 0x20 ;
567 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == PITCH) && defined(USE_6050)
568 p_measurements[23] = &pitch ; // accX
569 idToReply |= 0x20 ;
570 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == ROLL) && defined(USE_6050)
571 p_measurements[23] = &roll ; // accX
572 idToReply |= 0x20 ;
573 #elif defined(ACCZ_SOURCE) && ( ACCZ_SOURCE == YAW) && defined(USE_6050)
574 p_measurements[23] = &yaw ; // accX
575 idToReply |= 0x20 ;
576 #else
577 p_measurements[23] = &no_data ; // accZ
578 #endif
583 void OXS_OUT::sendSportData()
585 #if defined(GPS_TRANSMIT_TIME)
586 static uint32_t ptxtime=0;
587 #endif
589 #ifdef DEBUG_STATE
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) ;
592 #endif
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;
608 #else
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.
613 #else
614 #error When defined, VFAS_SOURCE must be VOLT_1, VOLT_2,... VOLT_6 or ADS_VOLT_1, ADS_VOLT_2,... ADS_VOLT_4
615 #endif
616 #endif
617 #endif
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 ;
637 #endif
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
657 #ifdef GPS_SPEED_3D
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)
663 #else
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)
673 #else
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;
705 #endif
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
724 cli() ;
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]);
729 #endif
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) ;
739 #endif
744 #endif
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 ;
759 #ifdef GPS_INSTALLED
760 //static uint32_t lastMsFrame2=0;
762 #endif
764 temp = millis() ;
765 if ( (state == IDLE ) && (temp > (lastMsFrame1 + ( lastFrameLength * MSEC_PER_BYTE) ) ) ) {
766 #ifdef GPS_INSTALLED
767 #if defined(GPS_TRANSMIT_TIME)
768 if ( (countFrame2 == 0 ) && GPS_fix ) {
769 SendFrame3();
770 lastFrameLength = hubMaxData ;
771 countFrame2 = FRAME3_EVERY_N_FRAME2 ;
772 lastMsFrame1=temp;
773 } else
774 #endif
775 if ( (countFrame1 == 0 ) && GPS_fix ) {
776 SendFrame2();
777 lastFrameLength = hubMaxData ;
778 if ( countFrame2 ) countFrame2-- ;
779 countFrame1 = FRAME2_EVERY_N_FRAME1 ;
780 lastMsFrame1=temp;
781 } else
782 #endif
784 SendFrame1();
785 lastFrameLength = hubMaxData ;
786 if ( countFrame1 ) countFrame1-- ;
787 lastMsFrame1=temp;
791 // second frame used for GPS
792 #ifdef GPS_INSTALLED
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() );
797 #endif
798 lastMsFrame2=temp;
799 SendFrame2();
801 #endif
802 if ( (state == IDLE) && (temp >= lastMsFrame1 + INTERVAL_FRAME1 ) && (temp >= lastMsFrame2 + INTERVAL_FRAME1 ) ) {
803 #ifdef DEBUGHUBPROTOCOL
804 printer->print("F1 at ");
805 printer->println( millis() );
806 #endif
807 lastMsFrame1=temp;
808 SendFrame1();
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
818 #if defined(VARIO)
819 uint16_t Centimeter = uint16_t(abs(oXs_MS5611.varioData.absoluteAlt.value)%100);
820 int32_t Meter;
821 if (oXs_MS5611.varioData.absoluteAlt.value >0){
822 Meter = (oXs_MS5611.varioData.absoluteAlt.value - Centimeter);
823 } else{
824 Meter = -1*(abs(oXs_MS5611.varioData.absoluteAlt.value) + Centimeter);
826 Meter=Meter/100;
827 SendValue(FRSKY_USERDATA_BARO_ALT_B, (int16_t)Meter);
828 SendValue(FRSKY_USERDATA_BARO_ALT_A, Centimeter);
829 #endif
831 // VSpeed
832 #if defined(VARIO)
833 SendValue( FRSKY_USERDATA_VERT_SPEED , (int16_t) mainVspeed.value);
834 #endif
836 // Cell_1_2
837 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && defined(NUMBEROFCELLS) && (NUMBEROFCELLS > 0)
838 SendCellVoltage( oXs_Voltage.voltageData.mVoltCell_1_2.value );
839 #endif
841 // Cell_3_4
842 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && defined(NUMBEROFCELLS) && (NUMBEROFCELLS > 2)
843 SendCellVoltage( oXs_Voltage.voltageData.mVoltCell_3_4.value) ;
844 #endif
846 // Cell_5_6
847 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && defined(NUMBEROFCELLS) && (NUMBEROFCELLS > 4)
848 SendCellVoltage( oXs_Voltage.voltageData.mVoltCell_5_6.value) ;
849 #endif
851 // vfas
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);
856 #endif
858 // current
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 ) ) ;
863 #endif
865 // fuel
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 ) ) ;
870 #endif
872 // RPM
873 #if defined(MEASURE_RPM)
874 SendValue( FRSKY_USERDATA_RPM , (int16_t) sport_rpm.value ) ;
875 #endif
877 // T1
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 ) ) ;
898 #endif
901 // T2
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 ) ) ;
922 #endif
924 // airspeed // not implemented in Hub protocol; to add in T1 or T2
925 #if defined(AIRSPEED)
926 //oXs_4525.airSpeedData.airSpeed ;
927 #endif
929 // accX
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 ) ) ;
952 #endif
954 // accY
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 ) ) ;
977 #endif
979 // accZ
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 ) ) ;
1002 #endif
1004 if( hubMaxData > 0 ) {
1005 sendHubByte(0x5E) ; // End of Frame 1!
1006 setHubNewData( ) ;
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(" ");
1015 #endif
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 ) {
1071 #ifdef GPS_SPEED_3D
1072 uint32_t GPSSpeedKnot = GPS_speed_3d * 1944L ; // speed in knots with 5 décimals (1 cm/sec = 0,0194384 knot)
1073 #else
1074 uint32_t GPSSpeedKnot = GPS_speed_2d * 1944L ;
1075 #endif
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
1082 hubGpsCount++ ;
1083 if ( hubGpsCount >= 5 ) hubGpsCount = 0 ;
1084 if( hubMaxData > 0 ) {
1085 sendHubByte(0x5E) ; // End of Frame 2!
1086 setHubNewData( ) ;
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(" ");
1095 #endif
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
1102 value=GPS_day;
1103 value<<8;
1104 value+=GPS_month;
1105 SendValue(FRSKY_USERDATA_GPS_DATE , value) ; // DATE (DDMM)
1106 value=(GPS_year % 100);
1107 value<<8;
1108 SendValue(FRSKY_USERDATA_GPS_YEAR , value) ; // YEAR (CC00)
1109 value=GPS_hour;
1110 value<<8;
1111 value+=GPS_min;
1112 SendValue(FRSKY_USERDATA_GPS_HOURMIN , value) ; // HOURMIN (hhmm)
1113 value=GPS_sec;
1114 value<<8;
1115 SendValue(FRSKY_USERDATA_GPS_SECONDS , value) ; // seconds (ss00)
1116 if( hubMaxData > 0 ) {
1117 sendHubByte(0x5E) ; // End of Frame 2!
1118 setHubNewData( ) ;
1121 #endif
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;
1131 sendHubByte(0x5E) ;
1132 sendHubByte(ID);
1134 if ( (tmp1 == 0x5E) || (tmp1 == 0x5D) ){
1135 tmp1 ^= 0x60 ;
1136 sendHubByte(0x5D);
1138 sendHubByte(tmp1);
1139 if ( (tmp2 == 0x5E) || (tmp2 == 0x5D) ){
1140 tmp2 ^= 0x60 ;
1141 sendHubByte(0x5D);
1143 sendHubByte(tmp2);
1146 //***************************************************
1147 // Put a byte in the buffer
1148 //***************************************************
1149 void OXS_OUT::sendHubByte( uint8_t byte )
1151 hubData[hubMaxData] = byte ;
1152 hubMaxData ++ ;
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] ) {
1165 #ifdef VARIO
1166 case ALTIMETER :
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 ;
1176 // }
1177 break ;
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 ;
1192 // }
1193 break ;
1194 case SENSITIVITY :
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 ;
1200 // }
1201 break ;
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 ;
1208 // }
1209 break ;
1212 #endif // end vario
1215 #ifdef VARIO2
1216 case ALTIMETER_2 :
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 ;
1226 // }
1227 break ;
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 ;
1242 // }
1243 break ;
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 ;
1250 // }
1251 break ;
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 ;
1258 // }
1259 break ;
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] );
1269 break ;
1270 #endif
1272 #if defined (VARIO ) && ( defined (VARIO2) || defined( AIRSPEED) || defined(USE_6050) ) && defined (VARIO_PRIMARY ) && defined (VARIO_SECONDARY ) && defined (PIN_PPM)
1273 case PPM_VSPEED :
1274 if( fieldOk == true ) {
1275 SendValue((int8_t) fieldToSend , ( ( (int16_t) switchVSpeed.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1277 break ;
1278 #endif
1280 #ifdef AIRSPEED
1281 case AIR_SPEED :
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] );
1288 break ;
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 ;
1295 // }
1296 break ;
1298 #endif // end airspeed
1300 #if defined (VARIO) && defined ( AIRSPEED)
1301 case PRANDTL_DTE :
1302 if( fieldOk == true ) {
1303 SendValue((int8_t) fieldToSend , ( ((int16_t) compensatedClimbRate.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1305 break ;
1306 #endif // End defined (VARIO) && defined ( AIRSPEED)
1309 #ifdef PIN_VOLTAGE
1310 case VOLT1 :
1311 SendVoltX( 0 , currentFieldToSend) ;
1312 break ;
1313 case VOLT2 :
1314 SendVoltX( 1 , currentFieldToSend) ;
1315 break ;
1316 case VOLT3 :
1317 SendVoltX( 2 , currentFieldToSend) ;
1318 break ;
1319 case VOLT4 :
1320 SendVoltX( 3 , currentFieldToSend) ;
1321 break ;
1322 case VOLT5 :
1323 SendVoltX( 4 , currentFieldToSend) ;
1324 break ;
1325 case VOLT6 :
1326 SendVoltX( 5 , currentFieldToSend) ;
1327 break ;
1328 #endif
1330 #if defined (PIN_CURRENTSENSOR)
1331 case CURRENTMA :
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 ;
1341 // }
1342 break ;
1343 case MILLIAH :
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 ;
1349 // }
1350 break ;
1351 // case FRSKY_USERDATA_CURRENT_MAX :
1352 //// if ( (SwitchFrameVariant == 0) ) {
1353 // if ( fieldToSend == DEFAULTFIELD ) {
1354 // SendValue(0x38,int16_t(currentData->maxMilliAmps)); //Cur+ OK!
1355 // }
1356 // else if( fieldOk == true ) {
1357 // SendValue((int8_t) fieldToSend ,(int16_t) ( (currentData->maxMilliAmps * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]) ) + fieldContainsData[currentFieldToSend][4] );
1358 // }
1359 // }
1360 // break ;
1361 #endif // End PIN_CURRENTSENSOR
1363 #if defined (NUMBEROFCELLS) && (NUMBEROFCELLS > 0) && defined (PIN_VOLTAGE)
1364 case CELLS_1_2 :
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 ;
1370 // }
1371 break ;
1373 case CELLS_3_4 :
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 ;
1379 // }
1380 break ;
1382 case CELLS_5_6 :
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 ;
1387 // }
1389 break ;
1391 #endif // NUMBEROFCELLS > 0
1393 #ifdef PIN_PPM
1394 case PPM :
1395 if( fieldOk == true ) {
1396 SendValue((int8_t) fieldToSend , ( ( (int16_t) ppm * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1398 break ;
1399 #endif
1402 #ifdef MEASURE_RPM
1403 case RPM :
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]);
1408 // }
1409 break ;
1410 #endif // MEASURE_RPM
1411 case TEST1 :
1412 if( fieldOk == true ) {
1413 SendValue((int8_t) fieldToSend ,(int16_t) ( (test1.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1415 break ;
1416 case TEST2 :
1417 if( fieldOk == true ) {
1418 SendValue((int8_t) fieldToSend ,(int16_t) ( (test2.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1420 break ;
1421 case TEST3 :
1422 if( fieldOk == true ) {
1423 SendValue((int8_t) fieldToSend ,(int16_t) ( (test3.value * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3])) + fieldContainsData[currentFieldToSend][4] );
1425 break ;
1428 } // end Switch
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);
1446 cellID++;
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) {
1479 // byte blades=2;
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);
1498 long Meter;
1500 if (altcm >0){
1501 Meter = (altcm-(long)Centimeter);
1503 else{
1504 Meter = -1*(abs(altcm)+(long)Centimeter);
1506 Meter=Meter/100;
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);
1519 long Meter;
1520 if (altcm >0){
1521 Meter = (altcm-(long)Centimeter);
1523 else{
1524 Meter = -1*(abs(altcm)+(long)Centimeter);
1526 Meter=Meter/100;
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);
1547 long knots;
1548 if (speedknots >0){
1549 knots = (speedknots-(long) knotDecimal);
1551 else{
1552 knots = -1*(abs(speedknots)+(long)knotDecimal);
1554 knots=knots/10;
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);
1575 #endif
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
1584 #ifdef DEBUG
1585 //#define DEBUGSETNEWDATA
1586 #endif
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
1603 uint8_t sensorId ;
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.
1613 //For Frsky only
1614 uint8_t ByteStuffByte = 0 ;
1616 // only for Hub
1617 uint8_t volatile hubData[MAXSIZEBUFFER] ;
1618 uint8_t volatile hubMaxData ; // max number of data prepared to be send
1620 // only for Sport
1621 uint8_t LastRx ;
1622 uint8_t TxSportData[7] ;
1623 uint16_t Crc ;
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 ++++++++++++++++++++++++++++++++++
1636 switch (state)
1638 // Transmit Byte.
1639 case TRANSMIT : // Output the TX buffer in SPORT ************ we are sending each bit of data
1640 #ifdef DEBUGASERIAL
1641 PORTC |= 1 ;
1642 #endif
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.
1649 else
1650 { // Otherwise:
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.
1663 #ifdef DEBUGASERIAL
1664 PORTC &= ~1 ;
1665 #endif
1666 break ;
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 ;
1675 ByteStuffByte = 0 ;
1677 else
1679 if ( TxCount < 7 ) // Data (or crc)?
1681 SwUartTXData = TxSportData[TxCount] ;
1682 Crc += SwUartTXData ; //0-1FF
1683 Crc += Crc >> 8 ; //0-100
1684 Crc &= 0x00ff ;
1686 else
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 ;
1699 state = TRANSMIT ;
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.
1705 state = WAITING ;
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.
1710 break ;
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.
1721 #ifdef DEBUGASERIAL
1722 PORTC &= ~1 ;
1723 #endif
1724 #if PIN_SERIALTX == 7
1725 if( GET_RX_PIN( )) {
1726 #else
1727 if( GET_RX_PIN( ) == 0 ) {
1728 #endif
1729 data |= 0x80 ; // If a logical 1 is read, let the data mirror this.
1731 #ifdef DEBUGASERIAL
1732 PORTC |= 1 ;
1733 #endif
1734 SwUartRXData = data ;
1736 else { //Done receiving = 8 bits are in SwUartRXData
1737 #ifdef DEBUGASERIAL
1738 PORTC &= ~1 ;
1739 #endif
1740 #ifdef DEBUG_SPORT_RECEIVED
1741 sportRcvCount ++ ;
1742 #endif
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
1756 case VARIO_ID :
1757 sensorIsr = 0 ; break ;
1758 case CELL_ID :
1759 sensorIsr = 1 ; break ;
1760 case CURRENT_ID :
1761 sensorIsr = 2 ; break ;
1762 case GPS_ID :
1763 sensorIsr = 3 ; break ;
1764 case RPM_ID :
1765 sensorIsr = 4 ; break ;
1766 case ACC_ID :
1767 sensorIsr = 5 ; break ;
1768 case TX_ID :
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.
1771 default :
1772 sensorIsr = 128 ;
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 ;
1784 } else {
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 ;
1793 state = TxPENDING ;
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
1813 else {
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.
1818 } else {
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)
1827 #else
1828 PCIFR = ( 1<<PCIF2 ) ; // clear pending interrupt
1829 PCICR |= ( 1<<PCIE2 ) ; // pin change interrupt enabled
1830 #endif
1833 } // End receiving 1 bit or 1 byte (8 bits)
1835 break ;
1837 case TxPENDING : // SPORT ****** we will here send a start bit before sending a byte
1838 #ifdef DEBUGASERIAL
1839 PORTC |= 1 ;
1840 #endif
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] ;
1846 TxCount = 0 ;
1847 state = TRANSMIT ;
1848 #ifdef DEBUGASERIAL
1849 PORTC &= ~1 ;
1850 #endif
1851 break ;
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)
1860 #else
1861 PCIFR = ( 1<<PCIF2 ) ; // clear pending interrupt
1862 PCICR |= ( 1<<PCIE2 ) ; // pin change interrupt enabled
1863 #endif
1864 break ;
1866 // Unknown state.
1867 default:
1868 state = IDLE; // Error, should not occur. Going to a safe state.
1869 } // End CASE
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
1876 switch (state) {
1877 // Transmit Byte.
1878 case TRANSMIT : // Hub **** Output the TX buffer. Start bit has already been sent ************
1879 #ifdef DEBUGASERIAL
1880 PORTC |= 1 ;
1881 #endif
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.
1895 #ifdef DEBUGASERIAL
1896 PORTC &= ~1 ;
1897 #endif
1898 break ;
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 ;
1907 state = TRANSMIT ;
1908 } else { // if all bytes have been send, wait 100usec
1909 TxCount = 0 ;
1910 state = WAITING ;
1911 OCR1A += DELAY_3500 ; // 3500 usec gap (instead of 100uS gap)
1913 break ;
1915 case WAITING :
1916 DISABLE_TIMER_INTERRUPT() ; // Stop the timer interrupts.
1917 state = IDLE ; // Go back to idle.
1918 break ;
1920 // Unknown state.
1921 default:
1922 state = IDLE; // Error, should not occur. Going to a safe state.
1923 } // End CASE
1925 } // end Hub protocol
1926 #endif // end of code for HUB protocol
1927 } // End of ISR
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) ;
1950 #else
1951 #error "SPORT_SENSOR_ID must be between 1 and 28 (included)"
1952 #endif
1954 //PORT
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
1964 #else
1965 #if PIN_SERIALTX != 7
1966 #error "This PIN is not supported"
1967 #endif
1968 #endif
1970 #if PIN_SERIALTX == 7
1971 ACSR |= ( 1<<ACI ) ; // clear pending interrupt
1972 ACSR |= ( 1<<ACIE ) ; // interrupt enabled (so we can receive another byte)
1973 #else
1974 PCIFR = ( 1<<PCIF2 ) ; // clear pending interrupt
1975 PCICR |= ( 1<<PCIE2 ) ; // pin change interrupt enabled
1976 #endif
1978 // Internal State Variable
1979 state = IDLE ;
1981 #ifdef DEBUGASERIAL
1982 DDRC = 0x03 ; // PC0,1 as o/p debug
1983 PORTC = 0 ;
1984 #endif
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
2006 // PORTC &= ~2 ;
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.
2010 #ifdef DEBUGASERIAL
2011 DDRC = 0x03 ; // PC0,1 as o/p debug
2012 PORTC |= 1 ;
2013 #endif
2014 SwUartRXBitCount = 0 ; // Clear received bit counter.
2015 CLEAR_TIMER_INTERRUPT() ; // Clear interrupt bits
2016 ENABLE_TIMER_INTERRUPT() ; // Enable timer1 interrupt on again
2018 #else
2019 ISR(PCINT2_vect)
2021 if ( TRXPIN & ( 1 << PIN_SERIALTX ) ) { // if Pin is high = start bit (inverted)
2022 DISABLE_PIN_CHANGE_INTERRUPT() ; // pin change interrupt disabled
2023 //PORTC &= ~2 ;
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.
2027 #ifdef DEBUGASERIAL
2028 PORTC |= 1 ;
2029 #endif
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 ;
2036 //#endif
2039 #endif
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.
2049 void initHubUart( )
2051 // ThisHubData = pdata ;
2052 TRXPORT &= ~( 1 << PIN_SERIALTX ) ; // PIN is low
2053 TRXDDR |= ( 1 << PIN_SERIALTX ) ; // PIN is output.
2055 //Internal State Variable
2056 state = IDLE ;
2057 // TxMax = 0 ;
2058 TxCount = 0 ;
2060 #ifdef DEBUGASERIAL
2061 DDRC = 0x03 ; // PC0,1 as o/p debug
2062 PORTC = 0 ;
2063 #endif
2066 void setHubNewData( )
2068 if ( (TxCount == 0) && (hubMaxData > 0) ) {
2069 // for (int cntNewData = 0 ; cntNewData < hubMaxData ; cntNewData++) {
2070 // TxHubData[cntNewData] = hubData[cntNewData] ;
2071 // }
2072 // TxMax = hubMaxData ;
2073 #ifdef DEBUGSETNEWDATA
2074 Serial.print("set new data at ");
2075 Serial.print( millis() );
2076 Serial.print(" ");
2077 for (int cntNewData = 0 ; hubMaxData ; cntNewData++) {
2078 Serial.print( hubData[cntNewData] , HEX );
2079 Serial.print(" ");
2081 Serial.println(" ");
2082 #endif
2083 startHubTransmit() ;
2087 void startHubTransmit()
2089 if ( state != IDLE )
2091 return ;
2093 SET_TX_PIN() ; // Send a logic 0 on the TX_PIN (=start bit).
2094 uint8_t oReg = SREG ; // save status register
2095 cli() ;
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] ;
2101 //TxNotEmpty = 0 ;
2102 state = TRANSMIT ;
2103 ENABLE_TIMER_INTERRUPT() ; // Enable timer1 interrupt on again
2104 #ifdef DEBUGASERIAL
2105 PORTC &= ~1 ;
2106 #endif
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