Board index FlightGear Support Interfacing

SOLUTION : Arduino code button *and* switch matrix diodes  Topic is solved

Connecting two computers, using generic protocol, connecting with Matlab?

SOLUTION : Arduino code button *and* switch matrix diodes  

Postby Volador » Sat May 01, 2021 9:54 am

Arduino code solution for button and switch matrix (with diodes)

Tom_nl and myself have been building arduino based interfaces that have both switches and push buttons in a matrix that uses diodes. This code solution assumes you're already down the path using serial interfacing with buttons and switches but want to maximise how many you can use with just one micro-controller. For example using a matrix you can 64 inputs using 16 pins arranged as 8 columns that feed 8 rows via the button and a signal diode (64 diodes in total and you can buy in packs of 100 for a couple of pounds/dollars/euros).

There are libraries out there for buttons and for switches but Tom_nl figured this out with some little tweaks from myself. It also has the debounce delay to stop the misreading of the multiple changes as switch contacts physically bounce very rapidly on being switched.

The code reads the matrix and populates two arrays with the current state of the switch 1 or 0 and if it has been toggled from its previous state toggled=1 or =0. If a change is detected to the matrix (has a button been pressed or a switch switched) I'm then jumping out of this loop to my checkswitches() void subroutine to figure out what action is to be taken and what needs to be sent via serial to FG.

In this example I'm using a Arduino Mega and a 7x8 array giving 56 buttons or switch positions. Note, you can accommodate a rotary switch by connecting a column to the common pin on the switch and then connecting the switch pins to individual rows (but only rows that are fed by that column).

The only thing to note is I couldn't get the very first array position array[0] to trigger the checkswitches void even though I could see the array address value changing from 1 to 0 and the toggle value changing too, so if you're going to use it just don't connect a switch or button to the very first location - or, if you're good at this you might be able to figure out why and share your thoughts.

In your variables:

Code: Select all
// ===================   new variables for button array  =====================
const int butcols = 7;
const int butrows = 8;
const int bcArray[butcols] = {22,24,26,28,30,32,34};      //7 col pins can link to up to 8 buttons or switch (positions)
const int brArray[butrows] = {23,25,27,29,31,33,35,37};   //'make' or 'on' makes a circuit connect to these rows with diodes pointing towards rows
int arrayelement;
const int numbuttons = butrows*butcols;
unsigned long debouncedelay = 70;          // minimum time between button presses to filter out bounces (in milliseconds).
unsigned long lastdebouncetime[numbuttons] = {}; // array storing the last time the output pin was toggled - stores time in milliseconds
bool buttonpressed = false;                 // bool "flag" to indicate a button press event. checkSwitches() then decides what to do
// arrays
bool buttonstate[numbuttons];               // array for storing button state (on/off)
bool buttontoggle[numbuttons] = {};         // array on/off button toggle switch (toggles between 1 and 0 when button pressed) initialises to zero
bool lastbuttonstate[numbuttons] = {};      // array for storing previous button state - for debouncing


In setup:

Code: Select all
 // set up button rows
 for (int i = 0; i < butrows; i++)
   {
   pinMode(brArray[i], OUTPUT);
   }
 // set up button columns
 for (int i = 0; i < butcols; i++)
   {
   pinMode(bcArray[i], INPUT_PULLUP);
   }


In my main loop I call the read matrix subroutine using: readbuttons_array()
The readbuttons void will then call checkSwitches() if a change is detected, your checkswitches void decides what to send over serial for that particular switch or button.

Big thanks to Tom_nl for this:

Code: Select all
void readbuttons_array()
{
    // reads the buttons as an array function
    for (int j = 0; j < butrows; j++)         // sets up the loop for the row
       {
       digitalWrite(brArray[j], LOW);         // sets the row pins to ground
       for (int i = 0; i < butcols; i++)      // sets up the loop for the columns
          {
          int arrayelement = i + (j * butcols); // set array element to update, saves having to compute (j* butcols) each time
          lastbuttonstate[arrayelement] = buttonstate[arrayelement];
          if (digitalRead(bcArray[i]) == 0)
              {
              // check if enough time has passed from lastpress to consider it a switch press
              if ((millis() - lastdebouncetime[arrayelement]) > debouncedelay && lastbuttonstate[arrayelement] == 0)
                  {
                  buttonstate[arrayelement] = 1;              // set button state to 1
                  checkSwitches();
                  if (buttontoggle[arrayelement] == 0)        // do the toggling
                     {
                     buttontoggle[arrayelement] = 1;          // set toggle to 1
                     }
                  else // if (buttontoggle[arrayelement] == 1)
                     {
                     buttontoggle[arrayelement] = 0;          // set toggle to 0
                     }
                  }
               }
           else if ((millis() - lastdebouncetime[arrayelement]) > debouncedelay && lastbuttonstate[arrayelement] == 1)  // or by implication button not pressed - i.e. pin

is 'high;
              {
              buttonstate[arrayelement] = 0; // sets button state to off
              checkSwitches();
              }           
           }
       digitalWrite(brArray[j], HIGH);
       lastdebouncetime[arrayelement] = millis();  // set last pressed time for debounce     
       }
}


Example within checkswitches() to read the autothrottle toggle switch, assuming ATarmSW = x where x is the array position you're switch is connected to.

Code: Select all
  if(buttonstate[ATarmSW] == 1 )               
     {
     AtArm = true;
     SendData();
     }
  else if(buttonstate[ATarmSW] == 0 )
     {     
     AtArm = false;
     SendData();
     }


Example of checking for a pushbutton for the radar traffic

Code: Select all
//RdrTfc
 if(buttonstate[RdrTfcBut] )                 
   {
   RdrTfc = buttontoggle[RdrTfcBut];
   SendData();
   }


Example of checking the alt hold push button, note sending false then true each time. Flightgear seemed to like the state to change from 0 to 1 each time to trigger things and I'm guessing this is something to do with how the listeners are monitoring the property tree for changes.

Code: Select all
  if(buttonstate[AltHoldBut] )       
    {
    altholdbut = false;
    SendData();
    altholdbut = true;
    SendData();
    altholdbut = false;
    } 


Volador
Last edited by Volador on Sat May 01, 2021 12:06 pm, edited 2 times in total.
User avatar
Volador
 
Posts: 1140
Joined: Tue Sep 01, 2020 4:58 pm
Callsign: Volador, G-VLDR
Version: 2020.4
OS: Windows 10, 64 bit

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby tom_nl » Sat May 01, 2021 11:58 am

That code looks familiar :D Nicely done, and glad to help.

Something else we worked on was only sending a serial event to flightgear when a button state has changed. This reduces serial traffic considerably, which when you're both reading from serial and sending a lot of states via serial can overload the Arduino. This is especially if you're additionally doing computationally heavy things such as time critical updating of a TFT display and reading a touchscreen both via SPI, as one of the Arduinos in my panel is doing for the radio displays. My code is still a bit messy, but it's working so i've not updated it yet. I'll have to clean it up and get it posted.

Tom
tom_nl
 
Posts: 84
Joined: Tue Aug 04, 2020 11:41 am
Location: Netherlands
OS: OS X Big Sur

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby Isaak » Sat May 01, 2021 12:14 pm

I'll definitely look into this! My current code is working, but it's sending the 90 button states at 10 Hz so this might be a better solution, especially since I experience a 10-20 fps drop in FlightGear when sending/receiving via serial.
Want to support medical research with your pc? Start Folding at Home and join team FlightGear!
Isaak
 
Posts: 768
Joined: Sat Jun 04, 2011 3:52 pm
Location: Hamme, Belgium
Pronouns: he, him
Callsign: OO-ISA
Version: next
OS: Windows 10

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby tom_nl » Sat May 01, 2021 12:52 pm

My method for reducing the serial traffic is basically as below. For each loop:

1 - before you read the switch/button/pot etc, copy the current variable into a corresponding 'lastvalue' variable for comparing.
2 - read all the buttons etc on the Arduino (in my case including rotary encoders, pots etc) and write them into the corresponding variables.
3 - compare each variable value to the 'lastvalue' to see if it's changed
4 - if it's the same, do nothing
5 - if it's changed, set a 'changed' flag
6 - check the 'changed' flag, and if it's 'true', call the function that sends the state of all buttons etc via serial. if not changed, don't send serial.

First, you need to add a 'statechange' variable to the variables
Code: Select all
bool statechange = 0; // boolean to store if state changed


You then need to add one more logical test to Volador's code above:
Code: Select all
void readbuttons_array()
{
    // reads the buttons as an array function
    for (int j = 0; j < butrows; j++)         // sets up the loop for the row
       {
       digitalWrite(brArray[j], LOW);         // sets the row pins to ground
       for (int i = 0; i < butcols; i++)      // sets up the loop for the columns
          {
          int arrayelement = i + (j * butcols); // set array element to update, saves having to compute (j* butcols) each time
          lastbuttonstate[arrayelement] = buttonstate[arrayelement];
          if (digitalRead(bcArray[i]) == 0)
              {
              // check if enough time has passed from lastpress to consider it a switch press
              if ((millis() - lastdebouncetime[arrayelement]) > debouncedelay && lastbuttonstate[arrayelement] == 0)
                  {
                  buttonstate[arrayelement] = 1;              // set button state to 1
                  checkSwitches();
                  if (buttontoggle[arrayelement] == 0)        // do the toggling
                     {
                     buttontoggle[arrayelement] = 1;          // set toggle to 1
                     }
                  else // if (buttontoggle[arrayelement] == 1)
                     {
                     buttontoggle[arrayelement] = 0;          // set toggle to 0
                     }
                  }
               }
           else if ((millis() - lastdebouncetime[arrayelement]) > debouncedelay && lastbuttonstate[arrayelement] == 1)  // or by implication button not pressed - i.e. pin is 'high;
              {
              buttonstate[arrayelement] = 0; // sets button state to off
              checkSwitches();
              }           
           }
       digitalWrite(brArray[j], HIGH);
       lastdebouncetime[arrayelement] = millis();  // set last pressed time for debounce     
       }

// START OF ADDED CODE - lines below check for the state change
    for (int i = 0; i < numbuttons; i++)
    {
        if (buttonstate[i] != lastbuttonstate[i]) // check if current button state has changed compared to last button state
        {
            statechange = 1; // set statechange to true
            break; // once a state change is found, break out of loop to save some cycles, no need to check remaining states.
        }
    }

// END OF ADDED CODE
}


And then, for the part of the code that handles the serial send, you just need to do a logical test to check the 'statechange' variable, and it it's true, you call the sendserial, otherwise skip this to not send the serial:
Code: Select all
if (statechange == 1) // only send serial on state change
    {
        sendserial();
        delay(1);
    }
statechange = 0; // set statechange back to zero for checking in next loop


It's easy to implement this for any button/switch/encoder/pot value - you just need to add a corresponding 'lastvalue' variable which stores the previous value for comparison. Though what i've found with pots is they can be jittery, so I take 10 readings and average them.

Tom
tom_nl
 
Posts: 84
Joined: Tue Aug 04, 2020 11:41 am
Location: Netherlands
OS: OS X Big Sur

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby Volador » Sat May 01, 2021 1:44 pm

Isaak wrote in Sat May 01, 2021 12:14 pm:I'll definitely look into this! My current code is working, but it's sending the 90 button states at 10 Hz so this might be a better solution, especially since I experience a 10-20 fps drop in FlightGear when sending/receiving via serial.


Hi Isaak, have you also tried to increase the serial baud rate? - I too found I was flooding in serial input (I think anyway) and am currently transmitting at 10hz at a baud rate of 56000 - but I'm receiving at 7 Hz (two different arduinos) - although, like Tom, I'm only transmitting when there is a change in status.
User avatar
Volador
 
Posts: 1140
Joined: Tue Sep 01, 2020 4:58 pm
Callsign: Volador, G-VLDR
Version: 2020.4
OS: Windows 10, 64 bit

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby rooman » Thu Sep 01, 2022 10:25 am

I'm currently finishing a small panel with a wifi tablette on Phi and some switches wired through to an usb joystick pcb.

I have ordered an Arduino and would like to go that way , ie; more switches, buttons etc.

Would it be possible to find a copy complete of your Arduino code please?
Grew up with Dr Who then discovered Monty Python and Middle Earth. The world was never the same.
rooman
 
Posts: 169
Joined: Sun Apr 12, 2015 7:26 pm
Location: Lausanne, Switzerland
Callsign: HB-ROO
Version: Next + LTS
OS: Ubuntu latest stable

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby Volador » Sun Sep 11, 2022 4:20 pm

Hi Rooman,

The code I have is specific to this hybrid custom interface (I designed based on the 747 but included other functions).

Image

There are actually two sets of code because this uses two arduinos to overcome the Windows comm port limitations. One set of code handles input (buttons switches (using the matrix code above)), the other output (LED numerical displays and LED indicators on the buttons). The theory was to keep the interface as a 'dumb terminal' and let FG do all the calculations. You may have more mileage using the code above and writing your own code around that.
User avatar
Volador
 
Posts: 1140
Joined: Tue Sep 01, 2020 4:58 pm
Callsign: Volador, G-VLDR
Version: 2020.4
OS: Windows 10, 64 bit

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby rooman » Mon Oct 03, 2022 10:06 am

Your code is impressive work nevetheless, as you suggest I'll certainly inspire myself with bits of your code, thanks for the reply.
Andrew
Grew up with Dr Who then discovered Monty Python and Middle Earth. The world was never the same.
rooman
 
Posts: 169
Joined: Sun Apr 12, 2015 7:26 pm
Location: Lausanne, Switzerland
Callsign: HB-ROO
Version: Next + LTS
OS: Ubuntu latest stable

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby MariuszXC » Mon Oct 03, 2022 2:25 pm

Volador wrote in Sun Sep 11, 2022 4:20 pm:The code I have is specific to this hybrid custom interface (I designed based on the 747 but included other functions)...


Very nice panel. One suggestion, if you cover the displays with a piece of smoked lexan / acrylic it will greatly help with readability.
INOP
MariuszXC
 
Posts: 1061
Joined: Tue May 18, 2021 5:38 pm
Location: Europe
Callsign: SP-MRM
Version: 2020.4
OS: Ubuntu 16.04

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby Volador » Tue Oct 04, 2022 8:03 pm

Andrew, I tried to post the Arduino code but the forum says there are too many smiles (must be the code) here are the xml protocol files

The input and output xml protocol files are here, they tell flightgear what's coming in from the switches arduino and the other xml tells flightgear what to send to the LED and displays arduino.

FG_747_input_arduino.xml
Code: Select all

<?xml version="1.0"?>
<PropertyList>
  <generic>
    <input>
      <line_separator>\n</line_separator>
      <var_separator>,</var_separator>
 



   <chunk>
      <name>IAS increment decrement</name>
      <node>autopilot/settings/target-speed-kt</node>
      <type>int</type>
      <format>%d</format>
      <relative>true</relative>
      <min>100</min>
      <max>399</max>
      <factor>1</factor>
      <wrap>false</wrap>
   </chunk> 

   <chunk>
      <name>Mach increment decrement</name>
      <node>autopilot/settings/target-speed-mach</node>
      <type>float</type>
      <format>%.3f</format>
      <relative>true</relative>
      <min>0.400</min>
      <max>0.999</max>
      <factor>0.001</factor>
      <wrap>false</wrap>
   </chunk>


<chunk>
     <name>HDG increment decrement</name>
    <node>autopilot/settings/heading-bug-deg</node>
   <type>int</type>
   <format>%d</format>
   <relative>true</relative>
   <min>000</min>
   <max>360</max>
   <factor>1</factor>
   <wrap>true</wrap>
</chunk>

<chunk>
        <name>Hdg Trk mode</name>
     <type>bool</type>
     <format>%d</format>
     <node>instrumentation/efis/hdg-trk-selected</node>
</chunk>




<chunk>
   <name>ALT increment decrement</name>
   <node>autopilot/settings/alt-display-ft</node>
   <type>int</type>
   <format>%d</format>
   <value>10100</value>
   <relative>true</relative>
   <min>000</min>
   <max>45000</max>
   <factor>100</factor>
   <wrap>false</wrap>
</chunk>
 
<chunk>
   <name>VS increment decrement</name>
   <node>autopilot/settings/vertical-speed-fpm</node>
   <type>int</type>
   <format>%d</format>
   <relative>true</relative>
   <min>-8000</min>
   <max>6000</max>
   <factor>100</factor>
   <wrap>false</wrap>
</chunk>

<chunk>
   <name>Hpa barometer inc dec</name>
   <node>instrumentation/altimeter/setting-inhg</node>
   <type>float</type>
   <format>%f</format>
   <value>29.92</value>
   <relative>true</relative>
   <min>26.0</min>
   <max>33.0</max>
   <factor>0.01</factor>
   <wrap>false</wrap>
</chunk>

<chunk>
        <name>inhg kpa switch 1=kpa 0=inhg</name>
     <type>bool</type>
     <format>%d</format>
     <node>instrumentation/efis/inputs/kpa-mode</node>
</chunk>





   <chunk>
   <name>master-warning</name>
   <type>bool</type>
   <format>%d</format>
   <node>instrumentation/annunciators/master-warning</node>
   </chunk>

   <chunk>
   <name>master-caution</name>
   <type>bool</type>
   <format>%d</format>
   <node>/instrumentation/annunciators/master-caution</node>
   </chunk>







   <chunk>
   <name>APP VOR MAP PLAN switch 0 1 2 3</name>
   <type>int</type>
   <format>%d</format>
   <node>instrumentation/efis/mfd/mode-num</node>
   </chunk>

   <chunk>
   <name>radar-mode changed bool</name>
   <type>bool</type>
   <format>%d</format>
   <node>input/arduino/radar-mode-change</node>
   </chunk>







   <chunk>
        <name>nd-centered button</name>
        <type>bool</type>
        <format>%d</format>
        <node>instrumentation/efis/inputs/nd-centered</node>
   </chunk>


   <chunk>
    <name>radar range rotary switch 10,20,40,80,160,320,640</name>
      <type>int</type>
      <format>%d</format>
      <node>instrumentation/efis/inputs/range</node>
   </chunk>

   <chunk>
    <name>traffic button</name>
      <type>int</type>
      <format>%d</format>
      <node>instrumentation/efis/inputs/tfc</node>
   </chunk>







   <chunk>
    <name>Hdg Sel button on rotary tikibar nasal code</name>
    <type>bool</type>
    <format>%d</format>
    <node>autopilot/panel/pushbuttons/button[11]</node>
   </chunk>

   <chunk>
    <name>Baro std button on rotary</name>
    <type>bool</type>
    <format>%d</format>
    <node>input/arduino/altimeter/baro-std-but</node>
   </chunk>

   <chunk>
    <name>IAS Mach select</name>
    <type>bool</type>
    <format>%d</format>
    <node>/instrumentation/afds/inputs/ias-mach-selected</node>
   </chunk>






   <chunk>
    <name>ADF VOR L switch</name>
      <type>int</type>
      <format>%d</format>
      <node>instrumentation/efis/inputs/lh-vor-adf</node>
   </chunk>

   <chunk>
    <name> ADF VOR R switch</name>
      <type>int</type>
      <format>%d</format>
      <node>instrumentation/efis/inputs/rh-vor-adf</node>
   </chunk>







   <chunk>
   <name> WXR button</name>
   <type>bool</type>
   <format>%d</format>
   <node>instrumentation/efis/inputs/wxr</node>
   </chunk>

   <chunk>
   <name> STA button</name>
   <type>bool</type>
   <format>%d</format>
   <node>instrumentation/efis/inputs/sta</node>
   </chunk>

   <chunk>
   <name> WPT button</name>
   <type>bool</type>
   <format>%d</format>
   <node>instrumentation/efis/inputs/wpt</node>
   </chunk>

   <chunk>
   <name> ARPT button</name>
   <type>bool</type>
   <format>%d</format>
   <node>instrumentation/efis/inputs/arpt</node>
   </chunk>

   <chunk>
   <name> DATA button</name>
   <type>bool</type>
   <format>%d</format>
   <node>instrumentation/radar/display-controls/data</node>
   </chunk>






   <chunk>
   <name> FD on-off bool</name>
   <type>bool</type>
   <format>%d</format>
   <node>instrumentation/afds/inputs/FD</node>
   </chunk>


   <chunk>
   <name> AT on-off bool</name>
   <type>bool</type>
   <format>%d</format>
   <node>instrumentation/afds/inputs/at-armed[0]</node>
   </chunk>






             <chunk>
                <name> AP on-off bool</name>
                <type>bool</type>
                <format>%d</format>
                <node>input/arduino/ap/ap-but</node>
            </chunk>

             <chunk>
                <name> Gear down bool</name>
                <type>bool</type>
                <format>%d</format>
                <node>controls/gear/gear-down</node>
            </chunk>
 
             <chunk>
                <name> hdg-hold-but</name>
                <type>bool</type>
                <format>%d</format>
                <node>input/arduino/ap/hdg-hold-but</node>
             </chunk>

             <chunk>
                <name> vs-but</name>
                <type>bool</type>
                <format>%d</format>
                <node>input/arduino/ap/vs-but</node>
            </chunk>

             <chunk>
                <name> alt-hold-but</name>
                <type>bool</type>
                <format>%d</format>
                <node>input/arduino/ap/alt-hold-but</node>
            </chunk>

             <chunk>
                <name> loc-but</name>
                <type>bool</type>
                <format>%d</format>
                <node>input/arduino/ap/loc-but</node>
            </chunk>

             <chunk>
                <name> appr-but</name>
                <type>bool</type>
                <format>%d</format>
                <node>input/arduino/ap/appr-but</node>
            </chunk>

             <chunk>
                <name> thr-but</name>
                <type>bool</type>
                <format>%d</format>
                <node>input/arduino/ap/thr-but</node>
            </chunk>

             <chunk>
                <name> spd-but</name>
                <type>bool</type>
                <format>%d</format>
                <node>input/arduino/ap/spd-but</node>
            </chunk>

             <chunk>
                <name>flch-but</name>
                <type>bool</type>
                <format>%d</format>
                <node>input/arduino/ap/flch-but</node>
            </chunk>

             <chunk>
                <name>lnav-but</name>
                <type>bool</type>
                <format>%d</format>
                <node>input/arduino/ap/lnav-but</node>
            </chunk>

             <chunk>
                <name>vnav-but</name>
                <type>bool</type>
                <format>%d</format>
                <node>input/arduino/ap/vnav-but</node>
            </chunk>

             <chunk>
                <name>ap-dis-but</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/pushbuttons/button[12]</node>
            </chunk>


        </input>
    </generic>
</PropertyList>



FG_747_output_arduino.xml
Code: Select all

<PropertyList>

<generic>
 
   <output>
        <binary_mode>false</binary_mode>
        <line_separator>\n</line_separator>
        <var_separator>,</var_separator>
        <preamble></preamble>
        <postamble></postamble>

            <chunk>
               <name>Target ALT 'a' before % serial start marker</name>
               <type>float</type>
               <format>a%.2f</format>
               <node>autopilot/settings/alt-display-ft</node>
            </chunk>

            <chunk>
                <name>Indicated Alt </name>
                <type>float</type>
                 <format>%.2f</format>
                <node>instrumentation/altimeter/indicated-altitude-ft</node>
            </chunk>

            <chunk>
                <name>VS Target</name>
                <type>integer</type>
                <format>%d</format>
                <node>autopilot/settings/vertical-speed-fpm</node>
            </chunk>

            <chunk>
                <name>VS Indicated</name>
                <type>integer</type>
                <format>%d</format>
                <node>instrumentation/vertical-speed-indicator/indicated-speed-fpm</node>
            </chunk>






            <chunk>
                <name>HDG BUG</name>
                <type>integer</type>
                <format>%d</format>
                <node>/autopilot/settings/heading-bug-deg</node>
            </chunk>

            <chunk>
                <name>Hdg Trk selected hdg=false trk=true</name>
                <type>bool</type>
                <format>%d</format>
                <node>instrumentation/efis/hdg-trk-selected</node>
            </chunk>






            <chunk>
                <name>IAS Target kt</name>
                <type>integer</type>
                <format>%d</format>
                <node>/autopilot/settings/target-speed-kt</node>
            </chunk>

            <chunk>
                <name>Mach Target</name>
                <type>float</type>
                <format>%.3f</format>
                <node>/autopilot/settings/target-speed-mach</node>
      <factor>1000</factor>
            </chunk>

            <chunk>
                <name>IAS Mach selected</name>
                <type>bool</type>
                <format>%d</format>
                <node>instrumentation/afds/inputs/ias-mach-selected</node>
            </chunk>







              <chunk>
                <name>AP on-off bool int</name>
                <type>bool</type>
                <format>%d</format>
                <node>/instrumentation/afds/inputs/AP</node>
              </chunk>





            <chunk>
                <name>hpa eg1013</name>
                <type>integer</type>
                <format>%d</format>
                <node>/instrumentation/altimeter/setting-hpa</node>
            </chunk>

            <chunk>
                <name>inhg eg29.92 float to 2 dp</name>
                 <type>float</type>
                 <format>%.2f</format>
                <node>/instrumentation/altimeter/setting-inhg</node>
            </chunk>

             <chunk>
                <name>inhg kpa switch 1True kpa eg1013 0False inhg eg29.92</name>
                <type>bool</type>
                <format>%d</format>
                <node>instrumentation/efis/inputs/kpa-mode</node>
            </chunk>







            <chunk>
                <name>gear down bool is int</name>
                <type>bool</type>
                <format>%d</format>
                <node>/controls/gear/gear-down</node>
            </chunk>

            <chunk>
                <name>Gear position float factor 10 for int</name>
                <type>integer</type>
                <format>%d</format>
                <node>/gear/gear/position-norm</node>
      <factor>10</factor>
            </chunk>


       <chunk>
           <name>master-warning</name>
           <type>bool</type>
           <format>%d</format>
           <node>instrumentation/annunciators/master-warning</node>
       </chunk>

       <chunk>
            <name>master-caution</name>
            <type>bool</type>
            <format>%d</format>
            <node>instrumentation/annunciators/master-caution</node>
       </chunk>


            <chunk>
                <name>SPD led</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/indicators/indicator</node>
            </chunk>
            <chunk>
                <name>THR led</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/indicators/indicator[1]</node>
            </chunk>
            <chunk>
                <name>LNAV led</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/indicators/indicator[2]</node>
            </chunk>
            <chunk>
                <name>VNAV led</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/indicators/indicator[3]</node>
            </chunk>
            <chunk>
                <name>FLCH led</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/indicators/indicator[4]</node>
            </chunk>
            <chunk>
                <name>HDG HOLD led</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/indicators/indicator[5]</node>
            </chunk>
            <chunk>
                <name>VS led</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/indicators/indicator[6]</node>
            </chunk>
            <chunk>
                <name>ALT HOLD led</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/indicators/indicator[7]</node>
            </chunk>
            <chunk>
                <name>LOC led</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/indicators/indicator[8]</node>
            </chunk>
            <chunk>
                <name>APP led</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/indicators/indicator[9]</node>
            </chunk>
            <chunk>
                <name>CMD AP led</name>
                <type>bool</type>
                <format>%d</format>
                <node>autopilot/panel/indicators/indicator[10]</node>
            </chunk>



</output>

</generic>

</PropertyList>

User avatar
Volador
 
Posts: 1140
Joined: Tue Sep 01, 2020 4:58 pm
Callsign: Volador, G-VLDR
Version: 2020.4
OS: Windows 10, 64 bit

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby Volador » Tue Oct 04, 2022 8:11 pm

MariuszXC wrote in Mon Oct 03, 2022 2:25 pm:
Volador wrote in Sun Sep 11, 2022 4:20 pm:The code I have is specific to this hybrid custom interface (I designed based on the 747 but included other functions)...


Very nice panel. One suggestion, if you cover the displays with a piece of smoked lexan / acrylic it will greatly help with readability.


Nice tip Mariusz
User avatar
Volador
 
Posts: 1140
Joined: Tue Sep 01, 2020 4:58 pm
Callsign: Volador, G-VLDR
Version: 2020.4
OS: Windows 10, 64 bit

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby wkitty42 » Tue Oct 04, 2022 10:29 pm

Volador wrote in Tue Oct 04, 2022 8:03 pm:Andrew, I tried to post the Arduino code but the forum says there are too many smiles (must be the code) here are the xml protocol files

when you are posting a message using the full editor, look at the bottom of the screen under the Options and check the "disable smilies" box...
"You get more air close to the ground," said Angalo. "I read that in a book. You get lots of air low down, and not much when you go up."
"Why not?" said Gurder.
"Dunno. It's frightened of heights, I guess."
User avatar
wkitty42
 
Posts: 9146
Joined: Fri Feb 20, 2015 4:46 pm
Location: central NC, USA
Callsign: wk42
Version: git next
OS: Kubuntu 20.04

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby Volador » Wed Oct 05, 2022 8:42 am

Thanks for the tip Wkitty!

ok, Andrew, for what it's worth here is the Arduino code for my custom panel that parses the data sent from flightgear and then controls the Led's and numerical displays. It's probably not the most efficient piece of code you'll ever see but the comments should help if you want to refine it for your project. You'll also find on your interface adventure (using .xml protocol) that not everything is controllable just by flicking a single property on/off or adjusting it's value, there are other ways to write to Flighgear that might be easier in the long run and you'll find ideas on the forum.

Code: Select all

#include <avdweb_Switch.h>
#include <HCMAX7219.h>
#include "SPI.h"
#define LOAD 10             //pin for 7 seg displays data
#define NUMBEROFDRIVERS 4
HCMAX7219 HCMAX7219(LOAD);
#define Bright 0x01
/*
MODULE.....UNO/NANO.....MEGA PINS
VCC........+5V..........+5V
GND........GND..........GND
DIN........11...........51
CS (LOAD)..10...........10
CLK........13...........52
*/
#include <SoftEasyTransfer.h>
#include <SoftwareSerial.h>
SoftwareSerial FGserial(12, 13); //pins 12, 13 go to 13, 12 on other ardiono, and join grounds


//create object
SoftEasyTransfer ET;
struct SEND_DATA_STRUCTURE
{
// variables to send SAME ON THE OTHER ARDUINO

long  TXAltIndi =0L;
//bool  TXAPbool = false;
//bool  TXIsaMachSel = false;
bool  TXLocArmed = false;
bool  TXGSArmed  = false;
bool  TXPitchEng = false;
bool  TXGearDown = true;

};
SEND_DATA_STRUCTURE FGdataTX;      // group name data TX to other arduino


//============== 7 segment LED display position. 4 x 8 numerals = 32 locations

byte QNHpos =          32;   // position of leading numeral of QNH on 7 seg LED modules
byte speedPos =        23;   // position of leading numeral of target speed on 7 seg LED modules
byte hdgPos =          17;   // position of leading numeral of TargtHdgBug on 7 seg LED modules
byte VsTargetPos =     12;   // position of leading numeral of VsTarget on 7 seg LED modules
byte TargetAltDispPos = 8;   // position of leading numeral of TargetAlt on 7 seg LED modules

// =========== LED pinouts ====================================================

byte MWarnLedPin   = 26;
byte APledPin      = 27;     //AP button led
byte ThrLedPin     = 28;     //pin for THR button led
byte SpeedLedPin   = 29;     //pin for SPD button LED
byte LnavLedPin    = 30;     //pin for LNAV Led
byte VNavLedPin    = 31; 
byte LocLedPin     = 32;
byte HdgHoldLedPin = 33;     //pin for Hdg hold Led
byte FLchLedPin    = 34;
byte VSLedPin      = 35;
byte AppLedPin     = 36;
byte AltHoldLedPin = 37;     //pin for Alt hold Led
byte GearLockedLed = 38;


//==================== Parsing routine varibales and counters =================


int serialIndex = 0;             // keep track of where we are in the buffer
const byte numChars = 92;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing
boolean newData = false;         // for input and parsing section


// ====================   FG main variables (hold parsed data from FG)    ==========

double   AltIndiF    = 0.0;      // rounded to hundreds sent from FG
long     AltIndi = 0L;
double   TargetAltF  = 10000.0;     
long     TargetAlt = 10000L;

int16_t  HdgBugDeg  = 0;
bool     HdgTrkSel  = false;

int      VsTarget   = 0;
int      VsIndi     = 0;          // indicated VS - could use for low altitude gear warning on decent
int      targetSpeedKt;
int      targetSpeedMach = 400;   // *factor of 1000 because of float display problem
bool     IasMachSel = false;

byte     LatIndx    = 0;
byte     VertIndx   = 0;          // vertical-index 0,1,13. 13 SPD LED on. Alt Hold 1=on 0=off
byte     AthrIndx  = 0;           // FG autothrottle-index 0, 1 or 5 for THR/SPD led status
byte     ThrIndx   = 0;

int      Hpa = 1013;              // kpa factor 10 in FG then display dp 1013.7
float    Inhg = 29.92;            // inhg
bool     KpaMode = false;         // For display. False = inhg True = kpa

bool     APbool     = false;
bool     GSArmed    = false;
bool     LocArmed   = false;
bool     PitchEng   = false;
bool     GearDown   = true;       // gear lever position
int      GearLocked = 10.0;       // is float in FG but transmit with factor 100 as integer

bool     MWarn = false;
bool     MCaution = false;
//bool     MWarnLed = false;
//bool     MCautionLed = false;
bool     WarnBlinkState = false;

unsigned long newTime;            //variables for blinking the Gear LEDs
unsigned long oldTime = 0;        //variables for blinking the Gear LEDs
bool GearLedState = false;
bool GearBlinkState = false;

bool FLCHmode = false;

bool SpdLed = false;
bool ThrLed = false;
bool LnavLed = false;
bool VnavLed = false;
bool FlchLed = false;
bool HdgHoldLed = false;
bool VSLed = false;
bool AltHoldLed = false;
bool LocLed = false;
bool AppLed = false;
bool APLed = false;

  const byte SerPin = 48;
  Switch SerStop = Switch(SerPin);

//========================== void setup =======================================

void setup()
{
  Serial.begin(56000);
  FGserial.begin(56000);
  ET.begin(details(FGdataTX), &FGserial);

  HCMAX7219.Init();
  HCMAX7219.Intensity(Bright, 0);
  HCMAX7219.Intensity(Bright, 1);
  HCMAX7219.Intensity(Bright, 2);
  HCMAX7219.Intensity(Bright, 3);
  HCMAX7219.Clear();

  pinMode(MWarnLedPin, OUTPUT); 
  pinMode(APledPin, OUTPUT);     
  pinMode(ThrLedPin, OUTPUT);
  pinMode(SpeedLedPin, OUTPUT);
  pinMode(LnavLedPin, OUTPUT);   
  pinMode(VNavLedPin, OUTPUT);   
  pinMode(LocLedPin, OUTPUT);
  pinMode(HdgHoldLedPin, OUTPUT);     
  pinMode(FLchLedPin, OUTPUT);   
  pinMode(VSLedPin, OUTPUT);   
  pinMode(AppLedPin, OUTPUT);   
  pinMode(AltHoldLedPin, OUTPUT);
  pinMode(GearLockedLed, OUTPUT);


}

// ================================  Main Loop  ======================================

void loop()
{
  recvWithStartEndMarkers();
  if (newData == true)
    {
    strcpy(tempChars, receivedChars);
    // this temporary copy is necessary to protect the original data
    // because strtok() used in parseData() replaces the commas with \0
    parseData();
    newData = false;   
    showParsedData();   //LED numeric readouts and LEDs subroutine
    TXupdate();         //update and send variables to other arduino
    }

  SerStop.poll();       //poll serial stop pin to halt serial to prevent BSOD powering down Windows
  if(SerStop.pushed())
    {
    Serial.print("Ending serial reading Displays Arduino, adios :)");
//    FGSerial.end();
    Serial.end();
    }

   
}

void TXupdate()  // ====================== update and transmit FGdataTX.variables
  {

  FGdataTX.TXAltIndi   = AltIndi;

//  FGdataTX.TXVsIndi    = VsIndi;
//  FGdataTX.TXFLCHmode  = FLCHmode;
  FGdataTX.TXPitchEng  = PitchEng;
 

//  FGdataTX.TXAPbool   = APbool;

//  FGdataTX.TXHpa       = Hpa;

  FGdataTX.TXLocArmed  = LocArmed;
  FGdataTX.TXGSArmed   = GSArmed;
  FGdataTX.TXGearDown  = GearDown;

  ET.sendData();    //send variables to update the switches arduino

  }  //End void TXupdate

//================================================================================


void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = 'a';
  char endMarker = '\n';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}




//================================================================================

void parseData() {      // split the data into its parts

  char * strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(tempChars, ",");   
  TargetAltF = atof(strtokIndx);           // Target Altitude
  TargetAlt = round(TargetAltF);

  strtokIndx = strtok(NULL, ",");         
  AltIndiF = atof(strtokIndx);             // Indicated Altitude / chage to radar alt
  AltIndi = round(AltIndiF);           

  strtokIndx = strtok(NULL, ",");
  VsTarget = atoi(strtokIndx);             // VS Target


  strtokIndx = strtok(NULL, ",");
  VsIndi = atoi(strtokIndx);               // VS Indicated


 
  strtokIndx = strtok(NULL, ",");           // Target heading bug
  HdgBugDeg = atoi(strtokIndx);

  strtokIndx = strtok(NULL, ",");           // Hdg Trk Selected bool
  HdgTrkSel = atoi(strtokIndx);



                   
  strtokIndx = strtok(NULL, ",");
  targetSpeedKt = atoi(strtokIndx);        // Airspeed Target

  strtokIndx = strtok(NULL, ",");         
  targetSpeedMach = atoi(strtokIndx);      // Airspeed target Mach

  strtokIndx = strtok(NULL, ",");
  IasMachSel = atoi(strtokIndx);           // ias mach selector bool
 



  strtokIndx = strtok(NULL, ",");         
  APbool = atoi (strtokIndx);              // bool as int



  strtokIndx = strtok(NULL, ",");         
  Hpa = atoi(strtokIndx);                 // Hpa barometer reading eg 1013
             
  strtokIndx = strtok(NULL, ",");         
  Inhg = atof(strtokIndx);                // Inhg barometer eg 29.92

  strtokIndx = strtok(NULL, ",");           
  KpaMode = atoi(strtokIndx);             // bool as int


 
  strtokIndx = strtok(NULL, ",");         
  GearDown = atoi(strtokIndx);            // bool as int Gear lever position

  strtokIndx = strtok(NULL, ",");         
  GearLocked = atoi(strtokIndx);          // Gear transition float 0-1 as int multiplied by 10



  strtokIndx = strtok(NULL, ",");           
  MWarn = atoi(strtokIndx);           

  strtokIndx = strtok(NULL, ",");           
  MCaution = atoi(strtokIndx);         


// tikibars property tree

  strtokIndx = strtok(NULL, ",");         
  SpdLed = atoi (strtokIndx);           

  strtokIndx = strtok(NULL, ",");         
  ThrLed = atoi (strtokIndx);       
 
  strtokIndx = strtok(NULL, ",");         
  LnavLed = atoi (strtokIndx);       

  strtokIndx = strtok(NULL, ",");         
  VnavLed = atoi (strtokIndx);       

  strtokIndx = strtok(NULL, ",");         
  FlchLed = atoi (strtokIndx);       

  strtokIndx = strtok(NULL, ",");         
  HdgHoldLed = atoi (strtokIndx);       

  strtokIndx = strtok(NULL, ",");         
  VSLed = atoi (strtokIndx);       

  strtokIndx = strtok(NULL, ",");         
  AltHoldLed = atoi (strtokIndx);       

  strtokIndx = strtok(NULL, ",");         
  LocLed = atoi (strtokIndx);       

  strtokIndx = strtok(NULL, ",");         
  AppLed = atoi (strtokIndx);       

  strtokIndx = strtok(NULL, ",");         
  APLed = atoi (strtokIndx);       

}

//==============================================================================


void showParsedData() {
/*
  if (GearLocked == 10) {digitalWrite(GearLockedLed,HIGH);GearBlinkState = false; }
  if (GearLocked ==0) {digitalWrite(GearLockedLed,LOW);GearBlinkState = false;}
  if ((GearLocked <=9) && (GearLocked >=1) ) { GearBlinkState = true; }
  newTime = millis();
  if(GearBlinkState && newTime - oldTime >= 250)
     {
     GearLedState = !GearLedState;
     digitalWrite(GearLockedLed,GearLedState);
     oldTime = newTime;
     }

  WarnBlinkState 

*/
  if (MWarn == true || MCaution == true)
    {
    digitalWrite(MWarnLedPin,HIGH);
    }
  else if (MWarn == false && MCaution == false)
    {
    digitalWrite(MWarnLedPin,LOW);
    }

   digitalWrite(SpeedLedPin,SpdLed);
   digitalWrite(ThrLedPin,ThrLed);
   digitalWrite(LnavLedPin,LnavLed);   
   digitalWrite(VNavLedPin,VnavLed);
   digitalWrite(FLchLedPin,FlchLed);
   digitalWrite(HdgHoldLedPin,HdgHoldLed);   
   digitalWrite(VSLedPin,VSLed);
   digitalWrite(AltHoldLedPin,AltHoldLed);
   digitalWrite(LocLedPin,LocLed);
   digitalWrite(AppLedPin,AppLed);
   digitalWrite(APledPin,APLed);

   // SPD THR Led's ===================================================================
 /* 
   if (AthrIndx == 5) {
   digitalWrite(ThrLedPin, LOW);
   digitalWrite(SpeedLedPin, HIGH);
   }
   if (AthrIndx == 1) {
   digitalWrite(ThrLedPin, HIGH);
   digitalWrite(SpeedLedPin, LOW);
   }
   if (AthrIndx == 0) {
   digitalWrite(ThrLedPin, LOW);
   digitalWrite(SpeedLedPin, LOW);
   }

   // ALT Hold Led ==================================================================

   if (VertIndx == 13) {   digitalWrite(SpeedLedPin, HIGH);   }
   if (VertIndx == 1) {   digitalWrite(AltHoldLed, HIGH);   }
   else if (VertIndx == 0) {   digitalWrite(AltHoldLed, LOW);   }

   // AP Led ========================================================================
   
  digitalWrite(APledPin,APbool);
*/
  // Gear down Led's ================================================================

  if (GearLocked == 10) {digitalWrite(GearLockedLed,HIGH);GearBlinkState = false; }
  if (GearLocked ==0) {digitalWrite(GearLockedLed,LOW);GearBlinkState = false;}
  if ((GearLocked <=9) && (GearLocked >=1) ) { GearBlinkState = true; }
  newTime = millis();
  if(GearBlinkState && newTime - oldTime >= 250)
     {
     GearLedState = !GearLedState;
     digitalWrite(GearLockedLed,GearLedState);
     oldTime = newTime;
     }
/*
  // LNAV Led's =======================================================================   
 
  if ((LatIndx==0)) { digitalWrite(HdgHoldLedPin,LOW);  digitalWrite(LnavLedPin,LOW); }
  if ((LatIndx==2)) { digitalWrite(HdgHoldLedPin,HIGH); digitalWrite(LnavLedPin,LOW); }
  if ((LatIndx==3)) { digitalWrite(HdgHoldLedPin,LOW);  digitalWrite(LnavLedPin,HIGH); }
*/
  HCMAX7219.Clear();
//  HCMAX7219.print7Seg(AltIndi, 16);       //testing
//  HCMAX7219.print7Seg(GearLocked, 14);    //testing

  if (KpaMode == true)        //check if we display inhg 29.92 or Kpa 1013.88 on the baro readout
     {
     if (Hpa <=999) { QNHpos = 31 ;}  //move the numerals to the right by 1 to display 999 and below
     else { QNHpos = 32 ;}            //position the numerals to display >= 1000
     HCMAX7219.print7Seg(Hpa,QNHpos); // 1013
     }
  else if (KpaMode == false) 
     {
     QNHpos = 32; //reset position of numerals on 7 segmentdisplay
     HCMAX7219.print7Seg(Inhg,2,4,QNHpos);  // 4 arguments displays float. value,dp's,numerals(4), position
//   HCMAX7219.print7Seg("_", QNHpos+1);    // displays "_" as indicator for inhg on the display
     if (Inhg == 30.0)                      //check to pad out 00 after the dp
        {
        HCMAX7219.print7Seg("0",QNHpos-3);
        }
     }



  //======================= Target IAS 7 segment LED address and leading zeros ============

if  (IasMachSel == false)
  {
  HCMAX7219.print7Seg("a", speedPos+1);   // display floating '_' indicator, modified 'a' in HXMAX7219.h
  if ( targetSpeedKt <= 9)
    {
    HCMAX7219.print7Seg("00", speedPos);
    HCMAX7219.print7Seg(targetSpeedKt, speedPos - 2);
    }
  if ((targetSpeedKt >= 10) && (targetSpeedKt <= 99))
    {
    HCMAX7219.print7Seg("0", speedPos);
    HCMAX7219.print7Seg(targetSpeedKt, speedPos - 1);
    }
  else if (targetSpeedKt > 99)
    {
    HCMAX7219.print7Seg(targetSpeedKt, speedPos);
    }
  }
else if (IasMachSel == true) // mach display mode
  {
  HCMAX7219.print7Seg(targetSpeedMach,speedPos); 
  HCMAX7219.print7Seg("b", speedPos+1);     // display _. indicator for Mach and decimal point modified HXMAX7219.h Hex 88 = _.
  }




  //======================== Target altitude LED address and leading zeros ================

  if (TargetAlt < 100)
    {
    HCMAX7219.print7Seg("0000", TargetAltDispPos);
    HCMAX7219.print7Seg(TargetAlt, TargetAltDispPos - 4);
    }
  if ((TargetAlt >= 100) && (TargetAlt <= 999))
    {
    HCMAX7219.print7Seg("00", TargetAltDispPos);
    HCMAX7219.print7Seg(TargetAlt, TargetAltDispPos - 2);
    }
  if ((TargetAlt >= 1000) && (TargetAlt <= 9999))
    {
    HCMAX7219.print7Seg("0", TargetAltDispPos);
    HCMAX7219.print7Seg(TargetAlt, TargetAltDispPos - 1);
    }
  else if ((TargetAlt >= 10000) && (TargetAlt < 99999))
    {
    HCMAX7219.print7Seg(TargetAlt, TargetAltDispPos);
    }


 
  //====================== Heading 0-360 LED display address and leading zeros ============

  if (HdgBugDeg <= 9)                         // if HdgBugDeg less than 9 add 00 at Pos+2
    {
    HCMAX7219.print7Seg("00", hdgPos + 2);
    HCMAX7219.print7Seg(HdgBugDeg, hdgPos);
    }
  if ((HdgBugDeg >= 10) && (HdgBugDeg <= 99)) //if heading between 10 and 99 add 0 at Pos+1
    {
    HCMAX7219.print7Seg("0", hdgPos + 2);
    HCMAX7219.print7Seg(HdgBugDeg, hdgPos + 1);
    }
  else if (HdgBugDeg > 99)            // if HdgBugDeg greater than 99 just display at Pos+2
    {
    HCMAX7219.print7Seg(HdgBugDeg, hdgPos +2);
    }
// display the indicator bar for HDG or TrK
if (HdgTrkSel == 1)
   {     HCMAX7219.print7Seg("_", hdgPos + 3); }
else if (HdgTrkSel ==0)
   {     HCMAX7219.print7Seg("a", hdgPos + 3); }  //letter 'a' is modified in HCMAX7219.h to display floating '_'



  //=========================== vertical speed indicator change display position according to -/+ values
  // negative or zero values for target speed display
if (VSLed == 1)
  {
    if ((VsTarget < 1) && (VsTarget >= 0))
     {
     HCMAX7219.print7Seg(VsTarget, VsTargetPos - 3);
     }
   else if ((VsTarget <= -1) && (VsTarget >= -9)) {
     HCMAX7219.print7Seg(VsTarget, VsTargetPos - 2);
     }
   else if ((VsTarget <= -10) && (VsTarget >= -99)) {
     HCMAX7219.print7Seg(VsTarget, VsTargetPos - 1);
     }
   else if ((VsTarget <= -100) && (VsTarget >= -999))  {
     HCMAX7219.print7Seg(VsTarget, VsTargetPos);
     }
   else if ((VsTarget <= -1000) && (VsTarget >= -9999))  {
     HCMAX7219.print7Seg(VsTarget, VsTargetPos + 1);
     }
   // ======= positive values for target vertical speed display

   else if ((VsTarget >= 1) && (VsTarget <= 9))  {
     HCMAX7219.print7Seg(VsTarget, VsTargetPos - 3);
     }
   else if ((VsTarget >= 10) && (VsTarget <= 99)) {
      HCMAX7219.print7Seg(VsTarget, VsTargetPos - 2);
     }
   else if ((VsTarget >= 100) && (VsTarget <= 999)) {
     HCMAX7219.print7Seg(VsTarget, VsTargetPos - 1);
     }
   else if ((VsTarget >= 999) && (VsTarget <= 9999)) {
     HCMAX7219.print7Seg(VsTarget, VsTargetPos);
     }
  }
else if (VSLed == 0)
  {
  HCMAX7219.print7Seg("----", VsTargetPos);
  }
 

  HCMAX7219.Refresh();

} //================ end of show parse data



And here is the Arduino code that reads the switches and rotary encoders then sends serial data to Flightgear when there is an input event, again not the most efficient except for Tom's matrix code :)

Code: Select all

#include <avdweb_Switch.h>

#include <MD_REncoder.h>
#include <MD_UISwitch.h>
#include <stdio.h>

#include <SoftEasyTransfer.h>
#include <SoftwareSerial.h>
SoftwareSerial FGSerial(12, 13); // connect 12,13 to 13,12 on other arduino


//create object
SoftEasyTransfer ET;
struct RECEIVE_DATA_STRUCTURE
{
// variables to recieve, make the SAME ON OTHER ARDUINO
//long  TXAltIndi       = 0L;
//bool  TXAPbool        = false;
//bool  TXIsaMachSel    = false;
bool  TXLocArmed      = false;
bool  TXGSArmed       = false;
bool  TXPitchEng      = false;
bool  TXGearDown      = true;
};
RECEIVE_DATA_STRUCTURE FGdataTX;  // group name data TX/RX from other arduino



// ===================   new variables for button array  =====================
const int butcols = 7;
const int butrows = 8;
const int bcArray[butcols] = {22,24,26,28,30,32,34};      //7 col pins can link to up to 8 buttons or switch (positions)
const int brArray[butrows] = {23,25,27,29,31,33,35,37};   //'make' or 'on' makes a circuit connect to these rows with diodes pointing towards rows
int arrayelement;
const int numbuttons = butrows*butcols;           // calculate total number of buttons
unsigned long debouncedelay = 80;                 // minimum time between button presses to filter out bounces (in milliseconds).
unsigned long lastdebouncetime[numbuttons] = {};  // array storing the last time the output pin was toggled - stores time in milliseconds
bool buttonpressed = false;                       // bool "flag" to indicate a button press event. checkSwitches() then decides what to do
// arrays
bool buttonstate[numbuttons];                     // array for storing button state (on/off)
bool buttontoggle[numbuttons] = {};               // array on/off button toggle switch (toggles between 1 and 0 when button pressed) initialises to zero
bool lastbuttonstate[numbuttons] = {};            // array for storing previous button state - for debouncing



// ===================  switch or button names and their array address number =====================
uint8_t BaroSw     = 12;            //COL 5
uint8_t WarnCanBut = 7;   //COL 0

uint8_t RdrSwApp   = 14;  //COL 0
uint8_t RdrSwVor   = 21;  //COL 0
uint8_t RdrSwMap   = 28;  //COL 0
uint8_t RdrSwPlan  = 35;  //COL 0

uint8_t RdrCenBut  = 42;  //COL 0
uint8_t RdrTfcBut  = 49;  //COL 0

uint8_t RdrSwZ10   = 43;    //COL 1 was pin 1
uint8_t RdrSwZ20   = 36;    //COL 1 was pin 8
uint8_t RdrSwZ40   = 29;    //COL 1 was pin 15
uint8_t RdrSwZ80   = 22;    //COL 1 was pin 22
uint8_t RdrSwZ160  = 15;    //COL 1 was pin 29
uint8_t RdrSwZ320  = 8;     //COL 1 was pin 36
uint8_t RdrSwZ640  = 1;     //COL 1 was pin 43

uint8_t VorLSw     = 30;      //COL 2
uint8_t AdfLSw     = 37;      //COL 2
uint8_t VorRSw     = 44;      //COL 2
uint8_t AdfRSw     = 51;      //COL 2

uint8_t WxrBut     = 50;   //COL 1
uint8_t StaBut     =  9;      //COL 2
uint8_t WptBut     = 16;      //COL 2
uint8_t ArptBut    = 23;      //COL 2
uint8_t DataBut    =  2;      //COL 2

uint8_t FDonSW     =  3;        //COL 3
uint8_t ATarmSW    = 10;        //COL 3
uint8_t APBut      = 17;        //COL 3

uint8_t ThrBut     = 24;        //COL 3
uint8_t SpdBut     = 31;        //COL 3
uint8_t MacIasBut  = 38;        //COL 3

uint8_t LnavBut    = 45;        //COL 3
uint8_t VnavBut    = 52;        //COL 3
uint8_t LocBut     =  4;          //COL 4
uint8_t HdgTrkBut  = 11;          //COL 4
uint8_t HdgHoldBut = 18;          //COL 4
uint8_t FlchBut    = 25;          //COL 4
uint8_t VSBut      = 32;          //COL 4
uint8_t ApprBut    = 39;          //COL 4
uint8_t AltHoldBut = 46;          //COL 4

uint8_t APdisengBut= 53;          //COL 4
uint8_t GearSw     =  5;            //COL 5



// ================     variables for serial comunications with FG USB port   ================
bool NewData=false;
int x = 0; // counter to output serial buffer

//variables for rotary encoder library
unsigned long lastDebounceTime = 0;    // the last time the output pin was toggled
unsigned long debounceDelay = 20;      // rotary debounce time; increase if the output flickers

//variables for the update transmission once every (TXinterval) to FG
unsigned long TXstartTime;           
unsigned long TXcurrentTime;
const unsigned long TXinterval = 1000; 



// ============================   FG main variables   ===========================
// some can be deleted once the Nasal stuff is working to update property tree
int      TargetAlt = 0;                 //used to inc dec TargetAlt value rotary position
//long     AltIndi   = 0L;                //rounded value recieved on update TargetAlt on altitude hold

int16_t  HdgBugDeg = 0;                 //used to inc dec HdgBugDeg rotary position

int      VsTarget  = 0;
int      TargetIas = 0;
int      TargetMc  = 0;

byte     LatIndx   = 0;                 //Heading hold lateral-index 0 OFF or 2 ON
byte     VertIndx  = 0;                 // 0,1,2,5,8

bool     warnCan   = false;             // master warning/caution cancel button
int      Hpa       = 0;                 // eg 1013
float    Inhg      = 0;                 // was 29.92
bool     kpaMode   = true;              // True=kpa (eg 1013)     False=inhg (eg 29.92)
 
uint16_t RdrRange      = 10;            // radar zoom value 10,20,40,80,160,320,640
uint8_t  AppVorMapPlan = 3;             // 0 1 2 3 = App Vor Map Plan - Plan is default
bool     AVMPchange    = false;   

bool   RdrCen        = 0;
bool   RdrTfc        = 0;
int    LhVor         = 0;             // 3pos switch 1 0 -1 = VOR L/OFF/ADF L
int    RhVor         = 0;             // 3pos switch 1 0 -1 = VOR R, OFF, ADF R

bool   FdOn        = false;
bool   AtArm       = false;
bool   MachIasMode = false;        // /instrumentation/afds/inputs/ias-mach-selected F=ias T=mach
bool   HdgTrk      = false;

bool   wxr   = false;
bool   sta   = false;
bool   wpt   = false;
bool   arpt  = false;
bool   data  = false;

bool   APbool    = false;               //AP on or off
bool   GSArmed   = false;
bool   LocArmed  = false;
bool   PitchEng  = false;
bool   GearDown  = true;
//bool   FLCHmode  = false;

bool  hdgholdbut = false;
bool  vsbut      = false;
bool  altholdbut = false;
bool  locbut     = false;
bool  apprbut    = false;
bool  thrbut     = false;
bool  spdbut     = false;
bool  flchbut    = false;
bool  lnavbut    = false;
bool  vnavbut    = false;
bool  apdis      = false;

// push buttons on the rotary encoders. Not part of matrix because of the rotary pcb routing.
bool       HdgSelPress = false;
bool       BaroStdBool = false;
const byte HdgSelPin   = 44;  //pin
const byte BaroStdPin  = 45;  //pin
Switch     HdgSel      = Switch(HdgSelPin);
Switch     BaroStd     = Switch(BaroStdPin);

const byte SerPin = 48;
Switch SerStop = Switch(SerPin);

// autopilot/panel/pushbuttons/button[11] # HDG SEL knob press # Tikibar's code




// rotary encoder pin A to Arduino pin 2, encoder pin B to Arduino pin 3
// set up encoder objects
MD_REncoder BaroEnc      = MD_REncoder(10, 11);
MD_REncoder TargetIasEnc = MD_REncoder(8, 9);
MD_REncoder HdgEnc       = MD_REncoder(6, 7);    // encoders could share pin 6 clock to save pins
MD_REncoder VSEnc        = MD_REncoder(4, 5);
MD_REncoder AltEnc       = MD_REncoder(2, 3);


//=================================   void setup  =======================================

void setup()
{
  Serial.begin(56000);
  FGSerial.begin(56000);
  ET.begin(details(FGdataTX), &FGSerial);
  ET.receiveData();   

  TargetIasEnc.begin();
  HdgEnc.begin();
  AltEnc.begin();
  VSEnc.begin();   
  BaroEnc.begin();

  TXstartTime = millis();  //initial start time for the rgular serial transmit interval


 // set up button rows Tom's code
 for (int i = 0; i < butrows; i++)
   {
   pinMode(brArray[i], OUTPUT);
   }
 // set up button columns
 for (int i = 0; i < butcols; i++)
   {
   pinMode(bcArray[i], INPUT_PULLUP);
   }

// update variables that have been transmitted by I2C from the other arduino
//  AltIndi = FGdataTX.TXAltIndi;
//  MagHdg = FGdataTX.TXmaghdg;
  LocArmed =   FGdataTX.TXLocArmed ;
  GSArmed =    FGdataTX.TXGSArmed ;
// PitchEng =  FGdataTX.TXPitchEng;
// FLCHmode =  FGdataTX.TXFLCHmode;
  GearDown =   FGdataTX.TXGearDown;
 
}

//=====================================    MAIN LOOP    ==================================

void loop()
{
    ET.receiveData();  //get i2c data from other arduino
    readbuttons_array();
   //    if (buttonpressed == true) {checkSwitches();}
   //GearDown = buttonstate[GearSw];
   //checkSwitches(); not here. Now in readbuttons_array() using bool buttonpressed
    checkEncoders();

//    printArray(); // for testing only. print input/output from matrix with array addresses
//    delay (300);  // for testing only.

/*
// once every second, send all data to FG regardless of other switch and rotary events
    TXcurrentTime = millis();  //get the current "time"
    if (TXcurrentTime - TXstartTime >= TXinterval)  //test whether the period has elapsed
       {
       updateTX();
//     Serial.print(buttonstate[BaroSw]);
//     Serial.println("=BaroSW butt state");
       SendData();
//       printArray(); // for testing only. print input/output from matrix     
       TXstartTime = TXcurrentTime;  //IMPORTANT to save the start time of the current
       }


// Not needed for Windows 10
    SerStop.poll();       //poll serial stop pin to halt serial to prevent BSOD powering down Windows 7.
    if(SerStop.pushed())
       {
       Serial.print("Ending serial output from Switches Arduino, bye bye :)");
       FGSerial.end();
       Serial.end();
       }
*/         
}
   

void readbuttons_array()
{
    // reads the buttons as an array function
    for (int j = 0; j < butrows; j++)           // sets up the loop for the row
       {
       digitalWrite(brArray[j], LOW);           // sets the row pins to ground
       for (int i = 0; i < butcols; i++)        // sets up the loop for the columns
          {
          int arrayelement = i + (j * butcols); // set array element to update, saves having to compute (j* butcols) each time
          lastbuttonstate[arrayelement] = buttonstate[arrayelement];
          if (digitalRead(bcArray[i]) == 0)
              {
              // switch pressed? check after debounce time
              if ((millis() - lastdebouncetime[arrayelement]) > debouncedelay && lastbuttonstate[arrayelement] == 0)
                  {
                  buttonstate[arrayelement] = 1;                 // switch is pressed, set button state to 1
                  // buttonpressed = true;
                  // Serial.println("Switch/Button detected");
                  checkSwitches();
                  // buttonpressed = false;                 
                  // lastdebouncetime[arrayelement] = millis();  // set last pressed time for the debounce timer 
                  if (buttontoggle[arrayelement] == 0)           // do the toggling
                     {
                     buttontoggle[arrayelement] = 1;             // set toggle to 1
                     }
                  else                                           // if (buttontoggle[arrayelement] == 1)
                     {
                     buttontoggle[arrayelement] = 0;             // set toggle to 0
                     }
                  }
               }
           else if ((millis() - lastdebouncetime[arrayelement]) > debouncedelay && lastbuttonstate[arrayelement] == 1)  // or by implication button not pressed - i.e. pin is 'high;
              {
              buttonstate[arrayelement] = 0; // sets button state to off
              // buttonpressed = true;
              // Serial.println("SW to 0 detected");
              checkSwitches();
              // buttonpressed = false;   
              }           
           }
       digitalWrite(brArray[j], HIGH);
       lastdebouncetime[arrayelement] = millis();  // set last pressed time for the debounce timer 
       }
}

// ========================= void check switches ========================== 


void checkSwitches()
  {

  if ( buttonstate[BaroSw] == 1)              //switch gives 1 for HPA,  true=HPA mode in 747
     {
     kpaMode = true;
     SendData();
     }

  else if ( buttonstate[BaroSw] == 0 )        //switch gives 0 for INHG,  false=INHG mode in 747
     {
     kpaMode = false;
     SendData();
     }


 if(buttonstate[FDonSW] == 1 )                // array  pins
     {
     FdOn = true;
     SendData();
     }
 else if(buttonstate[FDonSW] == 0 )
     {     
     FdOn = false;
     SendData();
     }



  if(buttonstate[ATarmSW] == 1 )               // array  pins
     {
     AtArm = true;
     SendData();
     }
  else if(buttonstate[ATarmSW] == 0 )
     {     
     AtArm = false;
     SendData();
     }


  if ( GearDown == 1 && buttonstate[GearSw] == 0 )  // Gear is down but switch in up position
     {
     GearDown = buttonstate[GearSw];                // send current switch (0) state array 5  pins 23,32
     SendData();
     }
  else if ( GearDown == 0 && buttonstate[GearSw] == 1 )  // Gear is up but switch is in down position
     {
     GearDown = buttonstate[GearSw];                // send current switch state (1) (array 5  pins 23,32)
     SendData();
     }
   
// MachIasMode
  if(buttonstate[MacIasBut] )                // array 38 pins 33,28
    {
    if (MachIasMode == false)
       {
       MachIasMode = true;
       SendData();
       }
    else if (MachIasMode == true)
       {
       MachIasMode = false;
       SendData();
       }     
    }


// HDG TRK selected push button
 if ( buttonstate[HdgTrkBut] )
    {
    HdgTrk = buttontoggle[HdgTrkBut];                // array 11
    }

// WarnCanBut (array 7)
// property /instrumentation/annunciators/master-warning
// property /instrumentation/annunciators/master-caution
if(buttonstate[WarnCanBut] )                          // array 7
    {
    warnCan = false;
    SendData();
    warnCan = true;
    SendData();
    warnCan = false;
    }
 
 //AppVorMapPlan switch
 if ( buttonstate[RdrSwApp] )
    {
    AppVorMapPlan = 0;
    AVMPchange = false;
    SendData();
    AVMPchange = true;
    SendData();
    AVMPchange = false;
    } 
           
 if ( buttonstate[RdrSwVor] )
     {
     AppVorMapPlan = 1;
     AVMPchange = false;
     SendData();
     AVMPchange = true;
     SendData();
     AVMPchange = false;
     } 
 if ( buttonstate[RdrSwMap] )
     {
     AppVorMapPlan = 2;
     AVMPchange = false;
     SendData();
     AVMPchange = true;
     SendData();
     AVMPchange = false;
     } 
 if ( buttonstate[RdrSwPlan])
     {
     AppVorMapPlan = 3;
     AVMPchange = false;
     SendData();
     AVMPchange = true;
     SendData();
     AVMPchange = false;
     } 


 if(buttonstate[RdrCenBut] )                 
    {
    RdrCen = buttontoggle[RdrCenBut] ;
    SendData();
    }
   
 if ( buttonstate[RdrSwZ10] )  { RdrRange = 10;   SendData(); } 
 if ( buttonstate[RdrSwZ20] )  { RdrRange = 20;   SendData(); } 
 if ( buttonstate[RdrSwZ40] )  { RdrRange = 40;   SendData(); } 
 if ( buttonstate[RdrSwZ80] )  { RdrRange = 80;   SendData(); } 
 if ( buttonstate[RdrSwZ160])  { RdrRange = 160;  SendData(); } 
 if ( buttonstate[RdrSwZ320])  { RdrRange = 320;  SendData(); } 
 if ( buttonstate[RdrSwZ640])  { RdrRange = 640;  SendData(); } 
 
//RdrTfc
 if(buttonstate[RdrTfcBut] )                // array
   {
   RdrTfc = buttontoggle[RdrTfcBut];
   SendData();
   }

 // 3pos switches Left and Right ADF/OFF/VOR  VOR= 1  OFF= 0  ADF= -1
 if(buttonstate[AdfLSw] ==1 && buttonstate[VorLSw] ==0 )  { LhVor = -1;  SendData(); }   // array 30
 if(buttonstate[AdfLSw] ==0 && buttonstate[VorLSw] ==1 )  { LhVor =  1;  SendData(); }   //       37
 if(buttonstate[AdfLSw] ==0 && buttonstate[VorLSw] ==0 )  { LhVor =  0;  SendData(); }   // if neither ADF or VOR then must be off
 // 3pos switch Right
 if(buttonstate[AdfRSw] ==1 && buttonstate[VorRSw] ==0 )  { RhVor = -1;  SendData(); }   // array 44
 if(buttonstate[AdfRSw] ==0 && buttonstate[VorRSw] ==1 )  { RhVor =  1;  SendData(); }   //       51
 if(buttonstate[AdfRSw] ==0 && buttonstate[VorRSw] ==0 )  { RhVor =  0;  SendData(); }   // if neither ADF or VOR then must be off

  if(buttonstate[WxrBut] )          // array 2
    {
    wxr = buttontoggle[WxrBut];
    SendData();   
    }     

  if(buttonstate[StaBut] )          // array 9
    {
    sta = buttontoggle[StaBut];
    SendData(); 
    }
       
  if(buttonstate[WptBut] )          // array 16
    {
    wpt = buttontoggle[WptBut];
    SendData(); 
    }

  if(buttonstate[ArptBut] )          // array 23
    {
    arpt = buttontoggle[ArptBut];
    SendData();     
    }     
       
  if(buttonstate[DataBut] )          // array 50
    {
    data = buttontoggle[DataBut];
    SendData();   
    }         
   
  if(buttonstate[AltHoldBut] )          // array 46 pins 35,30
    {
    altholdbut = false;
    SendData();
    altholdbut = true;
    SendData();
    altholdbut = false;
    }     

  if(buttonstate[HdgHoldBut])            // array 18  pins 27,30
    {
    hdgholdbut = false;
    SendData();
    hdgholdbut = true;
    SendData();
    hdgholdbut = false;
    }     

  if(buttonstate[LnavBut] )               // array 45  pins 35,28
    {
    lnavbut = false;
    SendData();
    lnavbut = true;
    SendData();
    lnavbut = false; 
    }     

  if(buttonstate[APBut] )
    {
    APbool = false;
    SendData();
    APbool = true;
    SendData();
    APbool = false;       
    }   

 
//    {
//    APbool = FGdataTX.TXAPbool;
//    if (APbool == false)
//       {
//       APbool = true;
//       SendData();
//       }
//    else if (APbool == true)
//       {
//       APbool = false;
//       SendData();
//       }     
//    }
 
  if(buttonstate[ApprBut] )
    {
    apprbut = false;
    SendData();
    apprbut = true;
    SendData();
    apprbut = false;       
    }     
   
if (buttonstate[LocBut])
    {
    locbut = false;
    SendData();
    locbut = true;
    SendData();
    locbut = false;   
    }

  if(buttonstate[FlchBut])
    {
    flchbut = false;
    SendData();
    flchbut = true;
    SendData();
    flchbut = false;     
    }     

  if(buttonstate[VSBut])
    {
    vsbut = false;
    SendData();
    vsbut = true;
    SendData();
    vsbut = false;       
    }     

  if(buttonstate[APdisengBut])
    {
     apdis = true;
//    apdis = buttontoggle[APdisengBut];
    SendData();
    apdis = false;
    } 

  if(buttonstate[SpdBut])
    {
    spdbut = false;
    SendData();
    spdbut = true;
    SendData();
    spdbut = false;       
    } 

 //buttonpressed = false;
 
  }   
 
  //   ==========    end void check switches



//=========================================================================================

void updateTX() 
{
    // update local variables from the ones sent via IC2 from the first adrdino
//    APbool  = FGdataTX.TXAPbool;      // update current FG autopilot status engaged or disengaged
//    AltIndi = FGdataTX.TXAltIndi;     // get indicated altitude and round to nearest 100
//    AltIndi /= 100;
//   AltIndi = round (AltIndi);
//    AltIndi *= 100;

//    IasMachSel = FGdataTX.TXIsaMachSel;

//    PitchEng = FGdataTX.TXPitchEng;
//    GearDown = FGdataTX.TXGearDown;

}

//=========================================================================================

void checkEncoders()
{

// autopilot/panel/pushbuttons/button [11]
//Switch HdgSel     = Switch(HdgSelPin); //HdgSelPress
  HdgSel.poll();
  if(HdgSel.pushed())
    {
    HdgSelPress = false;
    SendData();
    HdgSelPress = true;
    SendData();
    HdgSelPress = false;       
    } 

 // BaroStdBool property input/arduino/altimeter/baro-std-but
  BaroStd.poll();
  if(BaroStd.pushed())
    {
    BaroStdBool = false;
    SendData();
    BaroStdBool = true;
    SendData();
    BaroStdBool = false;       
    }
 
 
  // check HdgBugDeg encoder
  uint8_t h = HdgEnc.read();   //use h (byte) for reading the Heading rotary encoder
  if (h)
    {
    if (h == DIR_CW )
      {
      if (HdgEnc.speed() > 9) {HdgBugDeg = 10;}
      else{ HdgBugDeg = 1;}
      SendData();
      HdgBugDeg = 0;
      }
    else if (h == DIR_CCW )
      {
      if (HdgEnc.speed() > 9) {HdgBugDeg = - 10;}
      else{ HdgBugDeg = -1;}
      SendData();
      HdgBugDeg = 0;
      }
    }
 
  //check TargetAlt encoder
  uint8_t a = AltEnc.read();   //use a (byte) for reading the TargetAltitude rotary encoder
  if (a)
    {
    if (a == DIR_CW )
       {
       if (AltEnc.speed() > 8) {TargetAlt = 10;}
       else {TargetAlt = 1;}
       SendData();
       TargetAlt = 0;   
       }
    else if (a == DIR_CCW )
       {
       if (AltEnc.speed() > 8)  {TargetAlt = -10;}
       else {TargetAlt = -1;}
       SendData();
       TargetAlt = 0;     
       }
    }
 
 
  //check TargetIas Indicated Air Speed encoder
  if(MachIasMode == 0) //we are altering ISA settings
  {
  uint8_t s = TargetIasEnc.read();   //use a (byte) for reading the Altitude rotary encoder
  if (s)
    {
    if (s == DIR_CW )
       {
       if (TargetIasEnc.speed() > 8)
          {TargetIas = 10;}
       else
          {TargetIas = 1;}   
       SendData();
       TargetIas = 0;
       }
    else if (s == DIR_CCW )
      {
      if (TargetIasEnc.speed() > 8)
         {TargetIas = -10;}
      else
         {TargetIas = -1;}
      SendData();
      TargetIas = 0;
      }
    }
  }

  if(MachIasMode == 1) //we are altering Mach settings
  {
  uint8_t m = TargetIasEnc.read();   //use m (byte) for reading the Altitude rotary encoder
  if (m)
    {
    if (m == DIR_CW )
       {
       if (TargetIasEnc.speed() > 8)
          {TargetMc = 10;}
       else
          {TargetMc = 1;}   
       SendData();
       TargetMc = 0;
       }
    else if (m == DIR_CCW )
      {
      if (TargetIasEnc.speed() > 8)
         {TargetMc = -10;}
      else
         {TargetMc = -1;}
      SendData();
      TargetMc = 0;
      }
    }
  }


//check VS encoder
  uint8_t v = VSEnc.read();   //use a (byte) for reading the TargetAltitude rotary encoder
  if (v)
    {
    if (v == DIR_CW )
       {
       if (VSEnc.speed() > 9) {VsTarget = 10;}
       else {VsTarget = 1;}   
       SendData();
       VsTarget =0;
       }
    else if (v == DIR_CCW )
      {
      if (VSEnc.speed() > 9)  {VsTarget = -10;}
      else {VsTarget = -1;}
      SendData();
      VsTarget =0;       
      }
   }
 
//check Baro encoder
  uint8_t b = BaroEnc.read();   //use b (byte) for reading the Heading rotary encoder
  if (b)
    {
    if (b == DIR_CW )
      {
      if (BaroEnc.speed() > 8) {Hpa = 5;}
      else{ Hpa = 1;}
      SendData();
      Hpa =0;
      }
    else if (b == DIR_CCW )
      {
      if (BaroEnc.speed() > 8) {Hpa = -5;}
      else{ Hpa = -1;}
      SendData();
      Hpa =0;
      }
    }
}   
// End void check encoders


// ==================== void send serial data stream to FG ===========================

void SendData()
  {
// /* to isolate write data
  Serial.print(TargetIas);
  Serial.print(",");
  Serial.print(TargetMc);
  Serial.print(",");
 
  Serial.print(HdgBugDeg);
  Serial.print(",");
  Serial.print(HdgTrk);
  Serial.print(",");
 
  Serial.print(TargetAlt);
  Serial.print(",");
  Serial.print(VsTarget);
  Serial.print(",");
  Serial.print(Hpa);
 
  //Serial.print(", kpa mode=");
  Serial.print(",");
  Serial.print(kpaMode); 
  Serial.print(",");

  Serial.print(warnCan);  // and see below
  Serial.print(",");
  Serial.print(warnCan);  // yes, this is sent twice so that xml canceles both Warning and Caution with one button :)
  Serial.print(",");


  Serial.print(AppVorMapPlan); 
  Serial.print(",");
  Serial.print(AVMPchange); 
  Serial.print(",");


  Serial.print(RdrCen); 
  Serial.print(","); 
  Serial.print(RdrRange); 
  Serial.print(",");
  Serial.print(RdrTfc); 
  Serial.print(","); 

//
  Serial.print(HdgSelPress); 
  Serial.print(","); 
  Serial.print(BaroStdBool); 
  Serial.print(","); 
  Serial.print(MachIasMode); 
  Serial.print(","); 


// Vor switches
  Serial.print(LhVor); 
  Serial.print(",");
  Serial.print(RhVor); 
  Serial.print(",");

  Serial.print(wxr); 
  Serial.print(",");
  Serial.print(sta); 
  Serial.print(",");
  Serial.print(wpt); 
  Serial.print(",");
  Serial.print(arpt); 
  Serial.print(",");
  Serial.print(data); 
  Serial.print(",");

  Serial.print(FdOn);
  Serial.print(",");
  Serial.print(AtArm);
  Serial.print(",");
 
  Serial.print(APbool);
  Serial.print(",");
  Serial.print(GearDown);
  Serial.print(",");
  Serial.print(hdgholdbut);
  Serial.print(",");
  Serial.print(vsbut);
  Serial.print(",");
  Serial.print(altholdbut);
  Serial.print(",");
  Serial.print(locbut);
  Serial.print(",");
  Serial.print(apprbut);
  Serial.print(",");
  Serial.print(thrbut);
  Serial.print(",");
  Serial.print(spdbut);
  Serial.print(",");
  Serial.print(flchbut);
  Serial.print(",");
  Serial.print(lnavbut);
  Serial.print(",");
  Serial.print(vnavbut);
  Serial.print(",");
  Serial.print(apdis);

  Serial.println();
// */ // to isolate void for testing
  }

//only used for testing
void printArray()
   {       
       for (int n = 0; n < numbuttons; n++)
         {
         Serial.print (" a");
         Serial.print (n);
         Serial.print (" "); 
//       if (buttontoggle[n] == 1 ) {Serial.print"T"} else {Serial.print"t"};
         if (buttonstate[n] == 1) {Serial.print("X");} else Serial.print(".");     
//         Serial.print (buttontoggle[n]);
//         Serial.print (buttonstate[n]);
         Serial.print (" ");   
         }
       Serial.println(); 
   }
 
User avatar
Volador
 
Posts: 1140
Joined: Tue Sep 01, 2020 4:58 pm
Callsign: Volador, G-VLDR
Version: 2020.4
OS: Windows 10, 64 bit

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby Isaak » Wed Oct 05, 2022 8:59 am

Very nice work, Volador. As of FG 2020.4.0 bidirectional serial traffic has been repaired FG-side, so you should be able to run everything on one Arduino, if you have enough pins.

I'm planning on building a 777 MCP and Efis control panel for my setup this fall, and will definitely revisit your code to get some pointers. The Led and Switch matrix on my overhead panel do their job nicely, but I didn't find the courage yet to rewrite the code for biderectional serial traffic.
Want to support medical research with your pc? Start Folding at Home and join team FlightGear!
Isaak
 
Posts: 768
Joined: Sat Jun 04, 2011 3:52 pm
Location: Hamme, Belgium
Pronouns: he, him
Callsign: OO-ISA
Version: next
OS: Windows 10

Re: SOLUTION : Arduino code button *and* switch matrix diode

Postby wkitty42 » Wed Oct 05, 2022 11:17 am

Volador wrote in Wed Oct 05, 2022 8:42 am:Thanks for the tip Wkitty!

Image
FWIW: you are correct... the forums is/was seeing in the code all the closing parentheses followed by the semi-colons at the ends of the code lines and interpreting them as smilies... this is the same problem seen when someone writes a number that ends with an eight followed by a closing parenthesis and the forums shows it as "2 * (3 + 8)" instead of
Code: Select all
2 * (3 + 8)
;)
"You get more air close to the ground," said Angalo. "I read that in a book. You get lots of air low down, and not much when you go up."
"Why not?" said Gurder.
"Dunno. It's frightened of heights, I guess."
User avatar
wkitty42
 
Posts: 9146
Joined: Fri Feb 20, 2015 4:46 pm
Location: central NC, USA
Callsign: wk42
Version: git next
OS: Kubuntu 20.04

Next

Return to Interfacing

Who is online

Users browsing this forum: No registered users and 3 guests