Welcome to Cockpitbuilders.com. Please login or sign up.

July 02, 2022, 02:56:10 AM

Login with username, password and session length

PROUDLY ENDORSING


Fly Elise-ng
8 Guests, 0 Users
Members
Stats
  • Total Posts: 58944
  • Total Topics: 7795
  • Online Today: 112
  • Online Ever: 582
  • (January 22, 2020, 08:44:01 AM)
Users Online
Users: 0
Guests: 8
Total: 8

COUNTDOWN TO WF2022


WORLDFLIGHT TEAM USA

Will Depart in...

Recent

Welcome

X-Plane and toggles switches

Started by Joe Lavery, April 08, 2022, 04:56:38 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Joe Lavery

April 08, 2022, 04:56:38 AM Last Edit: April 08, 2022, 04:57:19 AM by Joe Lavery
Hi everyone (and particularly those using X-Plane).

I have been trying to get a panel working with X-Plane using an Ardunio ProMicro in a joystick configuration.
Specifically to make it a stand alone unit.

It works fine with FSUIPC in conjunction with any of the usual sims, including FS2020. Yet it will not fullly function with XPUIPC in X-Plane.
I have managed to get the normal toggle switches and rotary key working using the offsets provided in the XPUIPC documentation. But the rocker switches for Master  ALT/BAT and the Avionics Master pair refuse to work, even using the specified offsets (281C for the ALT-BATT and 2E80 for the Avionics).
In fact when using these offsets the on screen graphic gets distorted but the switch functions are not changed.

Any help or suggestions would be greatly appreciated.

Regards
Joe.
Life isn't about waiting for the storm to pass, it's about learning to dance in the rain

Journalist - writer for  PC Pilot Magazine

XOrionFE

April 08, 2022, 06:04:04 AM #1 Last Edit: April 08, 2022, 06:26:15 AM by XOrionFE
Unless you are using some 3rd party software (such as Project Magenta or Sim-Avionics) that was specifically written to communicate with FSUIPC offsets) I would suggest not bothering with XPUIPC.  Get XPL Direct plugin for arduino (or similiar) or switch to Teensy Arduino interfaces and use their flight sim plugin.  Then directly communicate with X-plane datarefs and commands.   You can use a plugin called dataref editor to find datarefs and many study level planes in x-plane use and supply documentation of their specific datarefs.   Planes such as Zibo 737,IXEG 737 Classic, FlyJsim 727 and 732, Torquesim SR22 Series as well as BN2 Islander, Hotstart planes including TBM 900, etc all have datarefs and commands that can be directly communicated with using Arduino.  In addition, X-plane has hundreds of generic datarefs and commands.   No need for xpuipc.

Here are some links to help get started

https://www.pjrc.com/teensy/td_flightsim.html

https://github.com/jbliesener/FlightSimSwitches

http://www.flightsimparts.eu/sim_xplane_direct.htm

https://github.com/leecbaker/datareftool

https://developer.x-plane.com/tools/datarefeditor/

Hope this helps,
Scott


Joe Lavery

Thanks very much Scott, I guessed you might have the answer. I'll get started on the links you provided and see if my old brain can figure it out.
I assumed that XPUIPC was the only way to access the datarefs and offsets.

Some reading is in order, I'll let you know how I get on.  8)

Kind Regards
Joe.
Life isn't about waiting for the storm to pass, it's about learning to dance in the rain

Journalist - writer for  PC Pilot Magazine

XOrionFE

I am on vacation in Florida right now so only have my Ipad but when back home this weekend I can offer more help once in front of a PC again.   If you let me know what plane(s) you are planning to fly I can potentially help you with some code.   Looks like a basic GA panel you have so many of the datarefs or commands are probably just x-plane vanilla ones.   I used a Teensy LC board for my SR22 GA cockpit setup where I made a platform with a real mag switch from aircraft spruce along with some basic rotary switches and such to make a panel for my SR22 setup alongside some realsimgear stuff.   i could share my code once home as well.


Joe Lavery

Thank you Scott, you're a star.
I'm also away this weekend, so I'll get back to you when I've had a chance to look at the information you sent.

All the best,
Joe
Life isn't about waiting for the storm to pass, it's about learning to dance in the rain

Journalist - writer for  PC Pilot Magazine

blueskydriver

So glad Scott is here helping everyone again! His brain is full of aviation knowledge....

John
| FSX | FDS-MIP OVRHD SYS CARDS FC1| PM | PMDG 737-700 | UTX | GEX | UT7 | ASE | REX2 | AES | TSR | IS | TOPCAT | AvilaSoft EFB | OC CARDS & OVRHD GAUGES| SIMKITS | SW 3D Lights | FS2CREW2010 | FSXPassengers | Flight1 AE | MATROX TH2GO-D | NTHUSIM | 3-Mits EW230Ust Proj |

AAnnillo

To add my 2 cents here....

I am using XP11 and the FlyJSim 727 for my cockpit project and STRONGLY recommend the DaraRefTool and the Teensys.

Right now (and after a bit of a steep learning curve, of course), I have successfully interfaced 3 EPR gauges, 2 altimeters, 2 DME units and 2 RMIs and they are working flawlessly.  It took a lot of experimenting (naturally) and many, many adjustments but overall, I am more than pleased with the results.  I'm still tweaking code using NEMA17 steppers, spur gears, synchro transmitters and DRV8825 drivers.

I, too, had initially thought I had to use XPUIPC after being used to seeing FSUIPC mentioned and used all over the place and was very relieved at the simplicity of capturing data refs and interfacing. 

I'm continuing my study and experimenting and will follow this thread for updates.

Antny

XOrionFE

Joe, I probably still have your address somewhere from back when I got a set of your clocks (long long time ago in a galaxy far far away...) but if you have a chance, pm your current address.  I will send you. Teensy LC on one of Rob Archer and Jorg Bliesener's custom breakout boards and I will build a sketch and load it for your panel.  i'll post the code here as well.  Just let me know if there is a specific plane you are flying or else I will just use the vanilla x-plane commands/datarefs.

Might take me a week or two in between stuff.

Scott

Joe Lavery

Good morning Scott,
That's extremely generous of you, if you let me know the cost of the components and the postage I will send it over to you by PayPal.
I will PM you my new address shortly.
Many thanks
Joe
Life isn't about waiting for the storm to pass, it's about learning to dance in the rain

Journalist - writer for  PC Pilot Magazine

XOrionFE

April 15, 2022, 04:59:09 PM #9 Last Edit: April 15, 2022, 05:01:10 PM by XOrionFE
So just had a chance to work on this today.  I built you the breakout board pictured below Joe.  This is using a Teensy LC and the board is a custom board Rob Archer and Jorg Bliesener designed for use in our 737-300 builds.  It has allowances to use uln2803 chips (which I did not put on for this one) which can drive incandescent bulbs at 28 vdc.  But for the needs of this GA panel we done need those chips so I put on solder bridges to bypass and treat each pin normally.

So far I built the following code which I still have to test.  Since the default 172 uses Commands instead of Datarefs I located those and should work.  I am using a library called flightsimswitches made by Jorg Bliesener that simplifies and standardizes the code greatly.  This library can be found here:

https://www.arduino.cc/reference/en/libraries/flightsimswitches/

Below is the code I have written so far using Jorg's base code then adding the additional functions.

---------------------------------------------------------
// This example shows how to use the FlightSimSwitchNo message is associated with this attachment.No message is associated with this attachment. library with
// the stock X-Plane Cessna 172 to lights panel, fuel pump, master and avionics, pitot
// and the Magnetos rotary switch.
//
// Make sure to set the Arduino configuration to "USB Type: Flight Sim Controls",
// otherwise the sketch won't compile.
//
// The following Teensy pins are used. You can connect real hardware
// switches or use a protoboard and a jumper to connect these pins to
// GND
//
// Teensy pin 0: Master ALT. Pin open: OFF, Pin connected to GND: ON
// Teensy pin 1: Master BAT. Pin open: OFF, Pin connected to GND: ON
// Teensy pin 2: Fuel Pump. Pin open: OFF, Pin connected to GND: ON
// Teensy pin 3: Beacon lights. Pin open: OFF, Pin connected to GND: ON
// Teensy pin 4: Landing lights. Pin open: OFF, Pin connected to GND: ON
// Teensy pin 5: Taxi lights. Pin open: OFF, Pin connected to GND: ON
// Teensy pin 6: Navigation lights. Pin open: OFF, Pin connected to GND: ON
// Teensy pin 7: Strobe lights. Pin open: OFF, Pin connected to GND: ON
// Teensy pin 8: Pitot Heat. Pin open: OFF, Pin connected to GND: ON
// Teensy pin 9: Avionics BUS 1. Pin open: OFF, Pin connected to GND: ON
// Teensy pin 10: Avionics BUS 2. Pin open: OFF, Pin connected to GND: ON
// Teensy pins 11-14 Magneto switch. At most one of these pins should be
//                connected to GND. This will control the magneto switch
//                in the Cessna as follows:
//                  - All pins open: Off
//                  - Pin 11 to GND: Magnetos R
//                  - Pin 12 to GND: Magnetos L
//                  - Pin 13 to GND: Magnetos BOTH
//                  - Pin 14 to GND: Magnetos START 

// You can follow the actions of this Sketch on the serial console

#include <FlightSimSwitches.h>

// Declaring the FlightSimSwitches object. This object must always be
// declared BEFORE any specific switch. We can either specify all
// parameters here or configure them later in setup().
// In this case, we use the object in its standard configuration,
// without any parameters.
FlightSimSwitches switches;

// Now we configure our individual switches
// The first switch is the Master ALT switch on pin 0. X-Plane
// uses two commands to handle this switch: One when the switch
// turns on, another one when it turns off. We therefore use a
// FlightSimOnOffCommandSwitch object.
FlightSimOnOffCommandSwitch alternatorSwitch(0);

//Configure the rest of the OnOff switches the same way
FlightSimOnOffCommandSwitch batterySwitch(1);
FlightSimOnOffCommandSwitch fuelPumpSwitch(2);
FlightSimOnOffCommandSwitch beaconLightSwitch(3);
FlightSimOnOffCommandSwitch landingLightSwitch(4);
FlightSimOnOffCommandSwitch taxiLightSwitch(5);
FlightSimOnOffCommandSwitch navLightSwitch(6);
FlightSimOnOffCommandSwitch strobeLightSwitch(7);
FlightSimOnOffCommandSwitch pitotHeatSwitch(8);
FlightSimOnOffCommandSwitch avionicsBus1Switch(9);
FlightSimOnOffCommandSwitch avionicsBus2Switch(10);

// The Magnetos switch is more complex. We have a switch with four
// positions and X-Plane wants "up" and "down" commands in order to
// control the setting. The current position is read from a dataref
// and the value is changed with commands. The switch actually has
// five positions, but only four (R, L, BOTH and START) are connected
// to the Teensy. Those four positions correspond with dataref values
// 1 (R), 2 (L), 3 (BOTH) and 4 (START). The fifth position corresponds
// to dataref value 0 and therefore does not need to be specified
// explicitly.
//                                            +--- pin numbers            +-- value for each pin
//                                            |                            |  number
//                                            v                            v
FlightSimUpDownCommandSwitch magnetosSwitch(4,SWITCH_POSITIONS(11,12,13,14),SWITCH_VALUES(1,2,3,4));

void setup() {
  // Serial output stuff, see Wiki (https://www.github.com/jbliesener/FlightSimSwitches/wiki/Serial)
  delay(1000);        // Teensy startup delay
  Serial.begin(9600);
  FlightSim.update();  // Call FlightSim.update to make serial output work. Must not take longer
                      // than 2 seconds for the next call to FlightSim.update()
  Serial.println(__FILE__ ", compiled on " __DATE__ " at "  __TIME__);

  // Set the X-Plane commands to turn the switches on or off
  alternatorSwitch.setOnOffCommands(
    XPlaneRef("sim/electrical/generator_1__on"),
    XPlaneRef("sim/electrical/generator_1_off"));
 
  batterySwitch.setOnOffCommands(
    XPlaneRef("sim/electrical/battery_1_on"),
    XPlaneRef("sim/electrical/battery_1_off"));
 
  fuelPumpSwitch.setOnOffCommands(
    XPlaneRef("sim/fuel/fuel_pumps__on"),
    XPlaneRef("sim/fuel/fuel_pumps_off"));

  beaconLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/beacon_lights_on"),
    XPlaneRef("sim/lights/beacon_lights_off"));

  landingLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/landing_lights_on"),
    XPlaneRef("sim/lights/landing_lights_off"));
 
  taxiLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/taxi_lights_on"),
    XPlaneRef("sim/lights/taxi_lights_off"));

  navLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/nav_lights_on"),
    XPlaneRef("sim/lights/nav_lights_off"));

  strobeLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/strobe_lights_on"),
    XPlaneRef("sim/lights/strobe_lights_off"));

  pitotHeatSwitch.setOnOffCommands(
    XPlaneRef("sim/ice/pitot_heat_on"),
    XPlaneRef("sim/ice/pitot_heat_off"));

  avionicsBus1Switch.setOnOffCommands(
    XPlaneRef("sim/systems/avionics_on"),
    XPlaneRef("sim/sytems/avionics_off"));

  avionicsBus2Switch.setOnOffCommands(
    XPlaneRef("sim/electrical/cross_tie_on"),
    XPlaneRef("sim/electrical/cross_tie_off"));


  // Set X-Plane datarefs and command for the Magnetos switch
  magnetosSwitch.setDatarefAndCommands(
    XPlaneRef("sim/cockpit2/engine/actuators/ignition_key
  • "),
    XPlaneRef("laminar/c172/ignition_up"),
    XPlaneRef("laminar/c172/ignition_down"));

  // The Magnetos switch on the C172 has a very particular issue:
  // The START position does not lock and immediately jumps back
  // to "BOTH" when triggered through command.once(). It therefore
  // acts like a pushbutton on one position only and must be set
  // with command.begin() and command.end(). The
  // MatrixUpDownCommandSwitch allows to set some positions as
  // pushbuttons that will be handled accordingly.
  // The START position is position index 3 (the fourth position)
  // in the switches position list.
  magnetosSwitch.setPushbuttonPosition(3);

  // provide a little feedback on the serial console
  switches.setDebug(DEBUG_SWITCHES);

  // Do not forget to call FlightSimSwitches.begin()!!
  switches.begin();
}

void loop() {
  FlightSim.update();
  switches.loop();
}

Joe Lavery

Hi Scott,
That looks brilliant, and the code looks a bit daunting but I'll have a better look at it in the morning. It's 3.45am here and I need to go to bed.  ???

Thank you so much, I am very gratefull.

Best regards
Joe.

By the way did you get my PM? 
Life isn't about waiting for the storm to pass, it's about learning to dance in the rain

Journalist - writer for  PC Pilot Magazine

XOrionFE

Quote from: Joe Lavery on April 15, 2022, 06:47:29 PMHi Scott,
That looks brilliant, and the code looks a bit daunting but I'll have a better look at it in the morning. It's 3.45am here and I need to go to bed.  ???

Thank you so much, I am very gratefull.

Best regards
Joe.

By the way did you get my PM? 

Yep, got it

XOrionFE

Ok, so my code had a number of typos that Jorg thankfully took a look at and pointed out so below is the working code and I am also linking a little video of testing.  Will get this in the post this afternoon to you Joe.

Scott



---------------------------CODE--------------------------
// The Magnetos switch is more complex. We have a switch with four
// positions and X-Plane wants "up" and "down" commands in order to
// control the setting. The current position is read from a dataref
// and the value is changed with commands. The switch actually has
// five positions, but only four (R, L, BOTH and START) are connected
// to the Teensy. Those four positions correspond with dataref values
// 1 (R), 2 (L), 3 (BOTH) and 4 (START). The fifth position corresponds
// to dataref value 0 and therefore does not need to be specified
// explicitly.
// PLEASE AVOID USING PIN 13 AS AN INPUT, THIS IS WHERE THE LED IS CONNECTED TO.
//                                             +--- pin numbers             +-- value for each pin
//                                             |                            |   number
//                                             v                            v
FlightSimUpDownCommandSwitch magnetosSwitch(4,SWITCH_POSITIONS(11,12,14,15),SWITCH_VALUES(1,2,3,4));

void setup() {
  // Serial output stuff, see Wiki (https://www.github.com/jbliesener/FlightSimSwitches/wiki/Serial)
  delay(1000);         // Teensy startup delay
  Serial.begin(9600);
  FlightSim.update();  // Call FlightSim.update to make serial output work. Must not take longer
                       // than 2 seconds for the next call to FlightSim.update()
  Serial.println(__FILE__ ", compiled on " __DATE__ " at "  __TIME__);

  // Set the X-Plane commands to turn the switches on or off
  alternatorSwitch.setOnOffCommands(
    XPlaneRef("sim/electrical/generator_1_on"), 
    XPlaneRef("sim/electrical/generator_1_off"));
 
  batterySwitch.setOnOffCommands(
    XPlaneRef("sim/electrical/battery_1_on"),
    XPlaneRef("sim/electrical/battery_1_off"));
 
  fuelPumpSwitch.setOnOffCommands(
    XPlaneRef("sim/fuel/fuel_pumps_on"),     
    XPlaneRef("sim/fuel/fuel_pumps_off"));

  beaconLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/beacon_lights_on"),
    XPlaneRef("sim/lights/beacon_lights_off"));

  landingLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/landing_lights_on"),
    XPlaneRef("sim/lights/landing_lights_off"));
 
  taxiLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/taxi_lights_on"),
    XPlaneRef("sim/lights/taxi_lights_off"));

  navLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/nav_lights_on"),
    XPlaneRef("sim/lights/nav_lights_off"));

  strobeLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/strobe_lights_on"),
    XPlaneRef("sim/lights/strobe_lights_off"));

  pitotHeatSwitch.setOnOffCommands(
    XPlaneRef("sim/ice/pitot_heat0_on"),     
    XPlaneRef("sim/ice/pitot_heat0_off"));   

  avionicsBus1Switch.setOnOffCommands(
    XPlaneRef("sim/systems/avionics_on"),
    XPlaneRef("sim/systems/avionics_off"));   

  avionicsBus2Switch.setOnOffCommands(
    XPlaneRef("sim/electrical/cross_tie_on"),
    XPlaneRef("sim/electrical/cross_tie_off"));


  // Set X-Plane datarefs and command for the Magnetos switch
  magnetosSwitch.setDatarefAndCommands(
    XPlaneRef("sim/cockpit2/engine/actuators/ignition_key[0]"),
    XPlaneRef("laminar/c172/ignition_up"),
    XPlaneRef("laminar/c172/ignition_down"));

  // The Magnetos switch on the C172 has a very particular issue:
  // The START position does not lock and immediately jumps back
  // to "BOTH" when triggered through command.once(). It therefore
  // acts like a pushbutton on one position only and must be set
  // with command.begin() and command.end(). The
  // MatrixUpDownCommandSwitch allows to set some positions as
  // pushbuttons that will be handled accordingly.
  // The START position is position index 3 (the fourth position)
  // in the switches position list.
  magnetosSwitch.setPushbuttonPosition(3);

  // provide a little feedback on the serial console
  switches.setDebug(DEBUG_SWITCHES);

  // Do not forget to call FlightSimSwitches.begin()!!
  switches.begin();
}

void loop() {
  FlightSim.update();
  switches.loop();
}

Joe Lavery

Quote from: XOrionFE on April 19, 2022, 08:53:50 AMOk, so my code had a number of typos that Jorg thankfully took a look at and pointed out so below is the working code and I am also linking a little video of testing.  Will get this in the post this afternoon to you Joe.

Scott



---------------------------CODE--------------------------
// The Magnetos switch is more complex. We have a switch with four
// positions and X-Plane wants "up" and "down" commands in order to
// control the setting. The current position is read from a dataref
// and the value is changed with commands. The switch actually has
// five positions, but only four (R, L, BOTH and START) are connected
// to the Teensy. Those four positions correspond with dataref values
// 1 (R), 2 (L), 3 (BOTH) and 4 (START). The fifth position corresponds
// to dataref value 0 and therefore does not need to be specified
// explicitly.
// PLEASE AVOID USING PIN 13 AS AN INPUT, THIS IS WHERE THE LED IS CONNECTED TO.
//                                             +--- pin numbers             +-- value for each pin
//                                             |                            |   number
//                                             v                            v
FlightSimUpDownCommandSwitch magnetosSwitch(4,SWITCH_POSITIONS(11,12,14,15),SWITCH_VALUES(1,2,3,4));

void setup() {
  // Serial output stuff, see Wiki (https://www.github.com/jbliesener/FlightSimSwitches/wiki/Serial)
  delay(1000);         // Teensy startup delay
  Serial.begin(9600);
  FlightSim.update();  // Call FlightSim.update to make serial output work. Must not take longer
                       // than 2 seconds for the next call to FlightSim.update()
  Serial.println(__FILE__ ", compiled on " __DATE__ " at "  __TIME__);

  // Set the X-Plane commands to turn the switches on or off
  alternatorSwitch.setOnOffCommands(
    XPlaneRef("sim/electrical/generator_1_on"), 
    XPlaneRef("sim/electrical/generator_1_off"));
 
  batterySwitch.setOnOffCommands(
    XPlaneRef("sim/electrical/battery_1_on"),
    XPlaneRef("sim/electrical/battery_1_off"));
 
  fuelPumpSwitch.setOnOffCommands(
    XPlaneRef("sim/fuel/fuel_pumps_on"),     
    XPlaneRef("sim/fuel/fuel_pumps_off"));

  beaconLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/beacon_lights_on"),
    XPlaneRef("sim/lights/beacon_lights_off"));

  landingLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/landing_lights_on"),
    XPlaneRef("sim/lights/landing_lights_off"));
 
  taxiLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/taxi_lights_on"),
    XPlaneRef("sim/lights/taxi_lights_off"));

  navLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/nav_lights_on"),
    XPlaneRef("sim/lights/nav_lights_off"));

  strobeLightSwitch.setOnOffCommands(
    XPlaneRef("sim/lights/strobe_lights_on"),
    XPlaneRef("sim/lights/strobe_lights_off"));

  pitotHeatSwitch.setOnOffCommands(
    XPlaneRef("sim/ice/pitot_heat0_on"),     
    XPlaneRef("sim/ice/pitot_heat0_off"));   

  avionicsBus1Switch.setOnOffCommands(
    XPlaneRef("sim/systems/avionics_on"),
    XPlaneRef("sim/systems/avionics_off"));   

  avionicsBus2Switch.setOnOffCommands(
    XPlaneRef("sim/electrical/cross_tie_on"),
    XPlaneRef("sim/electrical/cross_tie_off"));


  // Set X-Plane datarefs and command for the Magnetos switch
  magnetosSwitch.setDatarefAndCommands(
    XPlaneRef("sim/cockpit2/engine/actuators/ignition_key[0]"),
    XPlaneRef("laminar/c172/ignition_up"),
    XPlaneRef("laminar/c172/ignition_down"));

  // The Magnetos switch on the C172 has a very particular issue:
  // The START position does not lock and immediately jumps back
  // to "BOTH" when triggered through command.once(). It therefore
  // acts like a pushbutton on one position only and must be set
  // with command.begin() and command.end(). The
  // MatrixUpDownCommandSwitch allows to set some positions as
  // pushbuttons that will be handled accordingly.
  // The START position is position index 3 (the fourth position)
  // in the switches position list.
  magnetosSwitch.setPushbuttonPosition(3);

  // provide a little feedback on the serial console
  switches.setDebug(DEBUG_SWITCHES);

  // Do not forget to call FlightSimSwitches.begin()!!
  switches.begin();
}

void loop() {
  FlightSim.update();
  switches.loop();
}

What can I say Scott, that's brilliant. Thank you for taking the time, it;s much appreciated.

I have sent you a PM.

Best regards
Joe.
Life isn't about waiting for the storm to pass, it's about learning to dance in the rain

Journalist - writer for  PC Pilot Magazine

Like the Website ?
Support Cockpitbuilders.com and Click Below to Donate