XPData Library for X-Plane data Input/Output ( 2013 to 2014)


CLOSED (in 2015) project, not updated, next ARDref and ArdSim projects was developed as replacement of XPData. Successor of XPData/ARDref Libraries and ArdSim is ArdSimX Interface

The XPlaneData a Library (later XPData) project was started (in 2014) to unificate of all our previous X-plane interface code samples.

The XPlaneData library provides network interaction between Arduino and X-Plane and includes functions for easy assignment different types of input, including common buttons, switches, encoders to each Arduino pins and functions for transmission of control data to X-Plane.

You can use library functions to assign specific commands or datarefs for chosen pins as arguments of the control functions in your Arduino code. This makes the Arduino programming for users quite simple - you need to write down specific function (button, switch, encoder, axes, LED output, etc.) and add pin number and dataref/command as arguments.

No other software and plugin is needed! All data is transmitted directly to X-Plane using its built-in UDP protocol.

You can use as many Arduino boards with XPData input library as you need to. All boards should have an Ethernet shield (or module) connected to your LAN.


About X-Plane



All parameters that X-Plane can send using inbuilt UDP protocol you can find in the X-Plane menu "Settings->Data Input & Output. Currently there are 133 groups, each of them may contain up to 8 parameters, in form of 4-byte float numbers.

To find out what parameters each group includes, you can select some groups for output to the Cockpit View when flying. For this check the right box in this group. Using the Datarefs Editor plugin, you can correlate parameters that you want to check with corresponding datarefs.

For example, you need to receive gear positions for your indicators. These parameters are located in data group #67 named "landing gear deployment".
To start sending this group's data over network you need to check the left box in this group. Check the right box to output these parameters to the Cockpit View and watch how they are changing during operations.

sv sv



Network settings

To receive the values of controlled parameters from X-Plane, you need to tell X-Plane where to send the data.
You can do this in the "Net Connections -- >> Data" preferences screen:

sv

X-Plane Data format

The size of the UDP packet that X-Plane will send is determined by the number of selected data groups. Each UDP packet transmitted by X-Plane begins with a 5-byte header (DATA<), in decimal code. The next four bytes contain the number of the group from 0 to 133 (actually only the first byte does, as the other 3 are "0"). For example, group #67 - Landing gear deployment ratio.

And the next 32 bytes represent the data of 8 parameters (4 bytes x8 ). Each 4-byte block is a floating point value of one parameter.

HeaderIndex32 bytes of Data - 8 sim parameters in the format of 4-byte floating point numbersIndexNext data
68-65-84-65-6067-0-0-0252-163-78-63154-242-71-63167-252-81-630-0-128-630-0-128-630-0-128-630-0-128-630-0-128-6368-0-0-0245-230-128-63

As we can see, often we have to receive many excessive data from X-Plane, when we need only one parameter in given group, but X-Plane can send the whole data group only. XPData library function process incoming UDP packet, find the group number and position index of the chosen parameter.

To read the value of incoming data, for example the "Flaps actual position" (fifth byte in the group #13) using XPData Library call the "ReadData(n, m)" function, where the "n" argument is the group number, and the "m" is the number of the parameter inside the group:

       Flaps = ReadData ( 13, 5 );

Some functions can use data to directly send values on the output devices :
			LEDout (13, 127, 6);   // Control the LED on the pin #13 by data from group #127/6 ("Gear Warning")




XPData library functions



Digital Inputs / Actuator types

Button ( Pin, Cmd ) ;

Button function (for commands). It activates one command when pressed. Use for toggle buttons to change the parameter's state or for one-command button to set parameter once pressed (or one position for the multi-position switch is chosen).
Arguments used: 1) the pin number for the button, 2) Command string (or defined name (#define operatior) of the command)
Button ( 2, "radios/com1_standy_flip" );
Button ( 25, "flight_controls/landing_gear_up" );
Button ( 5, "v" );
example 1 - toggle button connected to Pin# 2, Com1 frequency flip
example 2 - "Set" button for Gear lever (pin #25)
example 4 - Emulates the "v" char of the keyboard (default turns parking brake on/off)
The "Button()" function can be used as "Continuous command button" or "Click and hold to repeat" button together with the Repeat() function

Button ( Pin, Dref, Val )

Button function for datarefs. The same function, but used with datarefs (set dataref value when clicked)
Arguments used: 1)- the pin number for this button, 2)- Dataref string (or defined name for this dataref), 3)- Value dataref is taken when button is clicked
Button_D ( 7, "cockpit2/controls/flap_ratio", "0", 0,5 ); example - "Set" button for multi-position flaps lever, (position on the Pin# 7)

Repeat ( Pin, Mode )

Repeat function for the button. Placed directly after the "Button()" function with the same pin#. Has two mode - "Continuous command button" and "Click and repeat after hold delay"
Button ( 8, "annunciator/test_all_annunciators"); Repeat ( 8, 2 );Mode 2 - "Continuous command button". It continuously activates the command while pressed. Use for the command to be sent continuously to work, such as "Test annunciators"
Button ( 12, "radios/obs_HSI_up"); Repeat ( 12, 1 );Mode 1 - Work as simple button when clicked once and start repeating after 0.8 sec when hold. Use it for increment value button (can be used instead of encoder):

MPrepeat ( Pin, Mode )

The same as above Repeat function, but for the Multi-position analog input! Argument "Pin" - is the position number, not the pin #.

Toggle ( Pin, Cmd1, Cmd2 )

Toggle switch (for commands). With this function you can assign the switch as input actuator for the chosen pin. For the switch shoud be used a couple of commands.
Toggle ( 9, "systems/avionics_on","systems/avionics_off" );
Toggle ( 11, "lights/nav_lights_on", "lights/nav_lights_off" );
Toggle (on/off) Switch - activates one command when it is in one position and sends the other command when toggled into the second position.

Toggle ( Pin, Dref, N, Val1, Val2 )

Toggle switch (for Datarefs). With this function you can assign the switch as input actuator for the chosen pin. For the switch shoud be used one dataref with two values
Toggle (42, "cockpit2/Togglees/landing_lights_Toggle", 2, 1,0 );
Toggle (7, "cockpit2/radios/actuators/RMI_left_use_adf_pilot", 0, 1,0 );
Toggle (on/off) Switch when DataRefs used - toggles between two values for one dataref. For simple toggle use 1 and 0 value, but you can assign any other needed values (such as 0.5 / 1, etc.))

Encoder ( Pin, Cmd1, Cmd2, Type )

Encoder (for commands). Assign encoder for two commands. As arguments, define first Pin number, two commands and encoder type (0,1,2). .
Encoder (42, "radios/obs_HSI_down", "radios/obs_HSI_up", 0 );
Encoder (30, "radios/stby_com1_fine_up", "radios/stby_com1_fine_down", 2 );
- Encoder Type 0 connecte to the pins 42-43 - HSI Heading knob
- Encoder Type 2 on the bus pins #30-31 - Radio Com1 frequency

Encoder_D ( Pin, Dref, Val, Inc, Type )

Encoder (for datarefs). Assign encoder for one dataref. As arguments, define 1) first Pin number, 2) Dataref, 3) Current value of dataref, 4) Increment/Decrement value for one step 5) Encoder type (0,1,2). .
First, you should assign the variable for the parameter to be controlled when used dataref for encoder: float HSI;
HSI = Encoder_D (42, "cockpit2/radios/actuators/hsi_obs_deg_mag_pilot[0]", HSI, 1, 0 );

Mode ( Pin )

Mode for input pins. Simple function to read current state of any inputs (pin #0-49 or pins #100-227 for Bus extension). Returns "0" or "1". Can be used for built-in encoder button, for creating your custom code behaviour.
enc = Mode ( 5 ); - Check the pin #5 state. Variable "enc" set to 0 or 1
btn = Mode(148); if (btn) adf++; if (adf == 3) adf = 0; - When button on the pin #148 is clicked, the "btn" will change its value from 0, 1, 2, 0... in cycle (for ADF frequency input encoder mode )
if  (enc==1)   Encoder ( 38, "radios/stby_com1_fine_up","radios/stby_com1_fine_down", 0 );             // Com1 frequency fine if button "enc" is pressed
            else  Encoder ( 38, "radios/stby_com1_coarse_up", "radios/stby_com1_coarse_down", 0 );    // Com1 frequency coarse if button "enc" is released


Analog Inputs

MultiPosition ( APin, Pos )

Function for creating multi-position Rotary Switch or Button Array connected to one analog pin. Define: 1) pin number, 2) Number of positions for rotary switch or number of buttons for button array.
When command are needed for contol, use the associated function "MPcom()" for each position:
MultiPosition(1, 5);
  MPcom (1, "magnetos/magnetos_off_1");
  MPcom (2, "magnetos/magnetos_right_1");
  MPcom (3, "magnetos/magnetos_left_1");
  MPcom (4, "magnetos/magnetos_both_1");
  MPcom (5, "starters/engage_starter_1"); MPrepeat(5,1);
- Define the 5-position Rotatry Switch on the analog input #1 and check its state
  - position #1 - Magneto off
  - position #2 - Magneto right
  - position #3 - Magneto left
  - position #4 - Magneto both
  - position #5 - Starter On and repeat when hold position
When dataref are needed for contol, use the associated function "MPdref()" for each position:
MultiPosition(1, 3);
 MPdref (1, "cockpit2/radios/actuators/HSI_source_select_pilot[0]", 0);
 MPdref (2, "cockpit2/radios/actuators/HSI_source_select_pilot[0]", 1);
 MPdref (3, "cockpit2/radios/actuators/HSI_source_select_pilot[0]", 2);
- Define the 3-position Rotatry Switch on the analog input #1 and check its state
  - position #1 - HSI source NAV1
  - position #2 - HSI source NAV2
  - position #3 - HSI source GPS

AnalogIn ( Pin, Dref, min, max, Prec )

Used for reading the changing values of potentiometer or some other analog device, connected to analog pin. Define: 1) pin number, 2) Dataref string, 3) The minimum and 4) maximum values for chosen dataref, 5) - precision.
The last number (Prec) is the number of steps or positions for desired precision , from 2 to 1000 (when using 2 - it can be the simple toggle switch)
AnalogIn ( 0, "cockpit2/controls/yoke_pitch_ratio[0]", -1, 1, 500 );
AnalogIn ( 1, "cockpit2/controls/flap_ratio[0]", 0, 1, 5);
// Yoke Pitch axis, precision 500 steps
// Flaps, 5 positions precision


Outputs / Configure and read incoming data for output

Output control - LEDs

LEDout ( NAME )

LEDout ( P, D, V, M, I )

Control the LED output with specific dataref. You can use this function with one argument that is previously defined constant "NAME" ( it is preferable), or use all 2-5 arguments directly without defining the named constant LEDout ( Pitot );
LEDout ( Flaps)
LEDout (8, 5, 0.5)
LEDout (10, 6, 0.4, 0,8, 1)
When defining the constant "NAME" in the beginning of the code you should assign at least two elements - the pin number for this LED output (P) and the dataref number (D). Next optional elements is the value of dataref on wich the LED should light up (V), another value of dataref for the value range (M). Last optional element "I" used to set inversion. Default V = 1, it means the LED is on when value =1.

#define NAME P, D, V, M, I


#define Pitot 10, 5
#define PitotHeat 10, 5, 0
#define Flaps1 11, 6, 0.5
#define Flaps2 12, 6, 0.4, 0.7
#define Flaps3 13, 6, 0.4, 0.7, 1


- Define Pitot LED connected to pin #10 and controlled by dataref #5
- The same as above but inverted output - the LED is on when value of dataref is 0
- Flaps LED on the pin #11, dataref #6, controlling dataref value = 0.5
- Flaps LED on the pin #12, dataref #6, controlling dataref range is 0.4-0.7
- Flaps LED on the pin #13, dataref #6, controlling dataref range is 0.4-0.7, inverted

LEDout ( Pitot )
LEDout ( Flaps1 )
LEDout ( Flaps2 )
LEDout ( Flaps3 )
// - Pitot LED on the pin #10, dataref #5. LED is on when value of dataref is 1
// - LED is ON only when flaps position = 0.5 ( useful for mutiple LEDs for one data range )
// - LED is ON when dataref value is in 0.4-0,7 range
// - LED is ON when dataref value is outside of 0.4-0,7 range

LEDout ( Pin, State )

Direct control of the LED. You can use this function if you need control the LED from your codeLEDout ( 13, ON );
LEDout ( 12, OFF)

if (your_condition==1) LEDout (13, ON);
if (your_condition==0) LEDout (13, OFF);


// -- Turn the LED on the pin #13 ON if your condition is 1
// -- Turn the LED on the pin #13 OFF if your condition is 0


Output control - Servo

servoGauge ( Dref, ServoName )

Assign which dataref (number "Dref") will be "linked" with a specific predefined servo ("ServoName"). servoGauge ( 6, Flaps );
The first argument (Dref) is the dataref number which is assigned for this dataref in the "out_1.cfg" file:

The second argument in this function ("ServoName") is the name of the preliminary defined construction in the beginning of your Arduino code. For example define the "Flaps" servo with control pulse range of 600-2200 mcsec connected to the pin #40, and dataref value range to control this servo 0.00 to 1.00 :

#define    Flaps        40, 0, 1, 600, 2200

.. where after the defined name ( Flaps ) you have to write five numbers:

1) Number of the Arduino Pin to which this servo is connected (pin #40 here)
2) Minimum value for the given dataref (0.00)
3) Maximum value for the given dataref (1.00)
4) The microseconds number which corresponds to the minimum value of dataref (560 here)
4) The microseconds number which corresponds to the maximum value of dataref (2100 here)

How to define the range of your particular servo: Servo control

Then place the servoGauge function for this example in the main code loop:

servoGauge ( 6, Flaps )


Output control - Coil ammeters

Gauge ( Dref, GaugeName )

Assign which dataref (number "Dref") will be "linked" with a specific predefined servo ("GaugeName"). Gauge ( 6, Flaps );
The first argument (Dref) is the dataref number which is assigned for this dataref in the "out_1.cfg" file:

The second argument in this function ("ServoName") is the name of the preliminary defined construction in the beginning of your Arduino code. For example define the "Flaps" servo with dataref value range to control this servo 0.00 to 1.00 :

#define    Flaps        5, 0, 1

.. where after the defined name ( Flaps ) you have to write 3 numbers:

1) Number of the Arduino Pin to which this servo is connected (pin #5 here)
2) Minimum value for the given dataref (0.00)
3) Maximum value for the given dataref (1.00)


Then place the Gauge function for this example in the main code loop:

Gauge ( 6, Flaps )



Please pay attention: pass the dataref and command strings to the functions without the "sim/" prefix. It's done to reduce the global variables memory usage, that can be critical when too many datarefs are used.




All examples are included in the package with this XPlaneData Library. Examples of X-Plane I/O interaction can be found in the Arduino IDE menu - "File" --> "Examples"---> XPData. Download newer Arduino IDE version from Arduino site if you have version less than 1.0.6 before using the library!

XPData library Sample -Single-Prop Inputs



/*
base code template for one-engine piston airplane.
(as Cessna-172, Cessna-182. etc) using XPData library
for X-Plane Simulator.
Inputs only

XPlaneData Library 

  by Vlad Sychev 2014-15
http://simvim.com
 */

//---------------------------
#include <SPI.h>         
#include <Ethernet.h> 
#include <XPData.h>          // -- include XPlaneData library
//-----------------------------
byte MAC[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // MAC-Address of Arduino Ethernet shield
unsigned int XPR = 49001;  // or 5080, if plugin       // port to to receive data from X-Plane
unsigned int XPW = 49000;                              // port to send data to X-Plane
byte IP[] = {192, 168, 1, 10};                 // This Arduino IP address (0,0,0,0 - for auto)
//------------------------------------


int enc;  // Encoders built-in button
int adf; // ADF encoder built-in button status (cyclic  3-digits positions ) 

void setup()
      {
    XPDStart (XPR, XPW, MAC, IP);         //==! init XPlaneData  
   
  }

//---------------------------------------------------
void loop() 
{
XPDScan();  
 // ------ 3-Axis -------------
  
AnalogIn (0, "cockpit2/controls/yoke_pitch_ratio[0]", -1, 1, 500);  // Pitch yoke, precision 500
AnalogIn (1, "cockpit2/controls/yoke_roll_ratio[0]", -1, 1, 500);    // Roll  yoke, precision 500
AnalogIn (2, "cockpit2/controls/yoke_heading_ratio[0]", -1, 1, 500);  // Rudder, precision 1000
 
//=== Throttle  --------- 

AnalogIn (3, "cockpit2/engine/actuators/throttle_ratio[0]", 0, 1, 300);  // Throttle, precision 300

//=========================  Prop Pitch Angle for Cessna 182 etc. (2 variants) ---------

AnalogIn(4, "cockpit2/engine/actuators/prop_pitch_deg[0]", 0, 60, 300);  // 
//AnalogIn(4, "cockpit2/engine/actuators/prop_rotation_speed_rad_sec[0]", 0, 300, 300);  // 

 //=======================================-  Mixture  ---------

AnalogIn(5, "cockpit2/engine/actuators/mixture_ratio[0]", 0, 1, 300);  // 

//==================================  Flaps ( DREF packet ) ================================

//-------Connect to analog input potentiometer 10 kOm - and make lever with several fixed positions (if needed)
//-------( must  be the full stroke of potentiometer, use the gears ) 

AnalogIn(6, "cockpit2/controls/flap_ratio[0]", 0, 1, 4);     // Flaps, 5 positions precision
        
//=======================================-  Starter/Magnetos =======================================

MultiPosition(7, 5);         
  MPcom(1, "magnetos/magnetos_off_1"); 
  MPcom(2, "magnetos/magnetos_right_1");  
  MPcom(3, "magnetos/magnetos_left_1");  
  MPcom(4, "magnetos/magnetos_both_1"); 
  MPcom(5, "starters/engage_starter_1"); MPrepeat(5,1);

//=======================================-  Transponder Mode Switch ===================================

//------------------------ 6 positions  Transponder Mode ------------------------------

MultiPosition(8, 5);  
      MPcom(1, "transponder/transponder_off");      // - OFF               
      MPcom(2, "transponder/transponder_standby");  // - STBY 
      MPcom(3, "transponder/transponder_alt");      // - ALT mode
      MPcom(4, "transponder/transponder_test");     // - TEST mode
      MPcom(5, "transponder/transponder_on");       // - ON mode
      MPcom(6, "transponder/transponder_ground");   // - GND mode      
      
//=======================  Panel/Radio Lighting Brightness ( DREF packet ) =============================

AnalogIn(9, "cockpit2/switches/instrument_brightness_ratio[0]", 0, 1, 100);  
AnalogIn(10, "cockpit2/switches/instrument_brightness_ratio[1]", 0, 1, 100);

//============================ Digital inputs section ===================================================


 // ---- Toogles and Buttons

Toggle (13, "systems/avionics_on", "systems/avionics_off");   /* Master Avionics switch  (active "1") Pin#13 must be connected 
                                                                                  to the GND through resistor 5-10k ("pulldown" resistor)
                                                                                  active toggle must connect Pin #13 to the +5v 
                                                                                   */                    
            // all other buttons/toggles connects pins to the GND (active state - "0"), no resistors are used:
                                
Toggle (12, "electrical/generator_1_off", "electrical/generator_1_on");      // Alternator  switch  
Toggle (11, "electrical/battery_1_on", "electrical/battery_1_off");         // BATTERY switch 
Toggle (9, "lights/beacon_lights_on", "lights/beacon_lights_off");         // Beacon Light switch 
Toggle (8, "lights/strobe_lights_on", "lights/strobe_lights_off");        // Strobe Light switch    
Toggle (7, "lights/nav_lights_on", "lights/nav_lights_off");             // NAV light  switch       
Toggle (6, "lights/taxi_lights_on", "lights/taxi_lights_off");          // Taxi  light switch        
Toggle_D (5, "cockpit2/switches/landing_lights_on[0]", 0, 1);               //-- Landing Lights  ---
Toggle (3, "fuel/fuel_pump_1_on", "fuel/fuel_pump_1_off");            // FUEL Pump
Toggle (2, "ice/pitot_heat0_on", "ice/pitot_heat0_off");             // Pitot Heat switch 

Button (1, "flight_controls/landing_gear_up");                        //---- GEAR UP  
Button (0, "flight_controls/landing_gear_down");                     //---- GEAR DN         

//============ Audio selector Panel (7 buttons on the  pins #14-20 ) - for X-Plane 10 only

Button (14, "audio_panel/monitor_audio_com1");        //  A_Com1
Button (15, "audio_panel/monitor_audio_com2");        //  A_Com2    
Button (16, "audio_panel/monitor_audio_nav1");        //  A_Nav1
Button (17, "audio_panel/monitor_audio_nav2");        //  A_Nav2     
Button (18, "audio_panel/monitor_audio_adf1");        //  A_Adf 1
Button (19, "audio_panel/monitor_audio_dme");         //  A_DME  
Button (20, "audio_panel/monitor_audio_mkr");         //  A_Mkr 
 
Button (21, "transponder/transponder_ident");         //------Transponder IDENT button ----  
      
Button(22, "radios/com1_standy_flip");                  //--  Com1/Com1-stby flip
Button(23, "radios/nav1_standy_flip");                  //--- NAV1/NAV1-stby flip
Button(24, "radios/com2_standy_flip");                  //--- Com2/Com2-stby flip
Button(25, "radios/nav2_standy_flip");                  //--- NAV2/NAV2-stby flip
Button(26, "radios/adf1_standy_flip");                  //--- Change ADF stdby Freq 

enc = Mode(27); 
 if (enc) { adf++; if (adf == 3) adf = 0; delay(15); }   
 
  //--- Encoders button PUSH/OFF
  //for  ADF: push one = "1"; push two = "10", push three = "100"
                                                                                      

//=================================== Encoders Section ==================

//------! encoders use paired inputs - 28-29,  30-31,  32-33,  34-35... ... 48-49, common pin is connected to "GND"

// -----!- Encoders for Com/Nav have the built-in  Push Button (If Pressed - fine up/dn) - Pin #27

                 
if(enc) Encoder(28, "radios/stby_com1_fine_up", "radios/stby_com1_fine_down", 0);             // Com1 Freq
        else  Encoder(28, "radios/stby_com1_coarse_up", "radios/stby_com1_coarse_down", 0);           
             
if(enc) Encoder(30, "radios/stby_com2_fine_up", "radios/stby_com2_fine_down", 0);           // Com2 Freq
       else   Encoder(30, "radios/stby_com2_coarse_up", "radios/stby_com2_coarse_down", 0);          
            
if(enc) Encoder(32, "radios/stby_nav1_fine_up", "radios/stby_nav1_fine_down", 0);           // Nav1 Freq
         else Encoder(32, "radios/stby_nav1_coarse_up", "radios/stby_nav1_coarse_down", 0);           
           
if(enc) Encoder(34, "radios/stby_nav2_fine_up", "radios/stby_nav2_fine_down", 0);              // Nav2 Freq
        else  Encoder(34, "radios/stby_nav2_coarse_up", "radios/stby_nav2_coarse_down", 0);   


if(adf==0) Encoder(36, "radios/stby_adf1_ones_up", "radios/stby_adf1_ones_down", 0);          // ADF Freq 1
if(adf==1) Encoder(36, "radios/stby_adf1_tens_up", "radios/stby_adf1_tens_down", 0);          // ADF Freq 10
if(adf==2) Encoder(36, "radios/stby_adf1_hundreds_up", "radios/stby_adf1_hundreds_down", 0);  // ADF Freq 100

Encoder(38, "radios/obs2_up", "radios/obs2_down", 0);                        // Nav2 OBS 
Encoder(40, "instruments/barometer_up", "instruments/barometer_down", 0); // Barometer, alt  

//---------------- Transponder code (4 encoders on the pins #42-43, 44-45, 46-47, 48-49

Encoder(42, "transponder/transponder_ones_up", "transponder/transponder_ones_down", 0);           // Transponder 1
Encoder(44, "transponder/transponder_tens_up", "transponder/transponder_tens_down", 0);           // Transponder 10   
Encoder(46, "transponder/transponder_hundreds_up", "transponder/transponder_hundreds_down", 0);   // Transponder 100
Encoder(48, "transponder/transponder_thousands_up", "transponder/transponder_thousands_down", 0); // Transponder 1000
//---------------------------------------

 }  //=========--- end 

/* 
Don't leave in the final code any lines with Serial.print(), that you could used for testing! 
That will take a lot of processing time, and lead to encoders timing inconsistency. 
Comment  or delete the lines with Serial.print() ! 

If you're not using some analog input, which has active code - connect it to GND, or "comment' this part of code! 
(Or it will constantly send interference data and take time too)

  by Vlad Sychev .2014-2015
 */






© Copyright 2012-2016 - SimVim