Skip to content

Ignition key example

28 July, 2013

In response to Justin on the X-Plane.org forums, who’s using a rotary switch to control the ignition key and asked for help with the code.

I’ll share the code then comment on it.

#include "Bounce.h"

// per X-Plane DataRef docs
enum IGN_KEY_POSITION {
  IGN_OFF = 0,
  IGN_LEFT = 1,
  IGN_RIGHT = 2,
  IGN_BOTH = 3,
  IGN_START = 4
};

// button input pins
const int Pin_IgnOff = 1;
const int Pin_IgnRight = 2;
const int Pin_IgnLeft = 5;
const int Pin_IgnBoth = 9;
const int Pin_IgnStart = 12;

Bounce ignOff = Bounce (Pin_IgnOff, 5);
Bounce ignRight = Bounce (Pin_IgnRight, 5);
Bounce ignLeft = Bounce (Pin_IgnLeft, 5);
Bounce ignBoth = Bounce (Pin_IgnBoth, 5);
Bounce ignStart = Bounce (Pin_IgnStart, 5);

// output dataref/commands
// the ignition key dataref does not engage the starter for some reason
// so we'll also use the normal engage_starter_1 command
FlightSimInteger ignPosition;
FlightSimCommand engineStart1;

void setup() {
  pinMode (Pin_IgnOff, INPUT_PULLUP);
  pinMode (Pin_IgnRight, INPUT_PULLUP);
  pinMode (Pin_IgnLeft, INPUT_PULLUP);
  pinMode (Pin_IgnBoth, INPUT_PULLUP);
  pinMode (Pin_IgnStart, INPUT_PULLUP);

  ignPosition = XPlaneRef("sim/cockpit2/engine/actuators/ignition_on[0]");
  engineStart1 = XPlaneRef("sim/starters/engage_starter_1");

  pinMode (LED_BUILTIN, OUTPUT);
}

void loop() {
  FlightSim.update();

  ignOff.update();
  ignRight.update();
  ignLeft.update();
  ignBoth.update();
  ignStart.update();

  // non-blocking input to update ignition key position
  if (ignOff.fallingEdge()) ignPosition = IGN_OFF;
  if (ignLeft.fallingEdge()) ignPosition = IGN_LEFT;
  if (ignRight.fallingEdge()) ignPosition = IGN_RIGHT;
  if (ignBoth.fallingEdge()) ignPosition = IGN_BOTH;
  // engage starter using command as well as by moving key
  if (ignStart.fallingEdge()) {
    ignPosition = IGN_START;
    engineStart1.begin();
    digitalWrite (LED_BUILTIN, HIGH);
  }
  if (ignStart.risingEdge()) {
    engineStart1.end();
    digitalWrite (LED_BUILTIN, LOW);
  }

// debug code for hardware test
//  if ( ignOff.read() == LOW ||
//       ignRight.read() == LOW ||
//       ignLeft.read() == LOW ||
//       ignBoth.read() == LOW ||
//       ignStart.read() == LOW
//       ) {
//    digitalWrite(LED_BUILTIN, HIGH);
//  } else {
//    digitalWrite(LED_BUILTIN, LOW);
//  }

}

First thing I did was look through the list of datarefs for anything that looked relevant to the ignition key.

http://www.xsquawkbox.net/xpsdk/docs/DataRefs.html
I found two candidates: sim/cockpit2/engine/actuators/ignition_key and sim/cockpit2/engine/actuators/ignition_on. They’re integer datarefs and the SDK website lists the meaning of their values: 0=off, 1=left etc.

Then, loading X-Plane and the default Cessna (which has a nice prominent ignition key to experiment on!), I opened DataRefEditor and typed ‘ignition’ into its filter box. A little bit of experimenting shows how they work: they’re almost identical. Write them a number between 0-4 and the key moves to that position. The difference is, if you move the key to ‘start’ using ignition_key it will go back to ‘both’ on the next frame, while if you use ignition_on it stays there. That’s the behaviour we want – we don’t want the key automatically moving anywhere, we want it to only move to where our hardware key tells it to go.

Next, I slapped some pushbuttons and a Teensy 3 onto a breadboard. (I don’t have any rotary switches at the moment!). It’s always useful to begin by writing code which simply tests your hardware, and you can see the remnant of that commented out at the bottom of the update function there – it made the onboard LED turn on when any of the buttons were pressed. You’d probably need to devise something different to test a rotary switch. I assume most rotary switches have a bunch of output pins which connect to a common pin as the switch is turned – this makes a rotary switch identical to a bunch of pushbuttons from an electrical perspective.

With the hardware tested, I added the FlightSimInteger (and FlightSim.update() – I’ve had enough of forgetting that line and spending ages wondering why the code doesn’t work :D ) The code will move the sim ignition switch when the hardware switch is moved. It won’t hold the sim switch to the hardware switch position (it’s not a ‘blocking’ input – remind me to write about that) so if you use some other way to turn the key (by clicking on it in the cockpit for example) the hardware won’t fight you and override the other input.

I found this would move the key nicely, but moving it to the ‘start’ position wasn’t engaging the starter motor. I have no idea why, and didn’t fancy spending all evening figuring it out – a nice quick solution was to add a FlightSimCommand object for the Engine 1 Starter Engage command, and have it active when the rotary switch is in the ‘Start’ position (or, in my case, when you’re pressing the pushbutton corresponding to the ‘Start’ position).

Just for fun, I made the onboard LED light as well when the starter’s engaged. Ideally you’d have a rotary switch like a car ignition where you have to hold the thing in the ‘Start’ position against a spring, but that kind of switch is likely hard to come by, so perhaps a warning LED can do instead. The LED can remind you if you’ve left the switch in the ‘Start’ position and forgotten about it.

And with that, the code appears complete – it appears to work on my desktop anyway :)

Avoiding magic numbers

Magic Numbers are literal numbers in your program, instead of a named variable. I often see them used for Teensy pin numbers. In principle they’re bad because they’re less descriptive than a named variable and harder to change. There’s at least three ways I’ve avoided using them in this short program:

  • using const int Pin_IgnOff = 0 etc for the pin numbers
  • using an to store the values we can feed to the ignition key dataref
  • using someCommand.begin() and someCommand.end() instead of someCommand = 1 and someCommand = 0

    Arguably these are all unnecessary refinements in a program this short – but it’s a good habit to get into, and pays dividends when you come back six months later to make a change, or (more usually) when this all becomes part of a much bigger project. For instance, if you’ve used named constants for your pin numbers, you only need to make a change in one place in the code when you connect your hardware to some different pins.

  • From → Examples

    Leave a Comment

    Leave a comment