]> git.mxchange.org Git - flightgear.git/commitdiff
Begin work on revamping the ATC hardware interface so it is infinitely more
authorcurt <curt>
Tue, 16 Nov 2004 19:47:11 +0000 (19:47 +0000)
committercurt <curt>
Tue, 16 Nov 2004 19:47:11 +0000 (19:47 +0000)
configurable.

src/Main/fg_io.cxx
src/Main/options.cxx
src/Network/ATC-Inputs.cxx [new file with mode: 0644]
src/Network/ATC-Inputs.hxx [new file with mode: 0644]
src/Network/Makefile.am
src/Network/atc610x.cxx
src/Network/atc610x.hxx

index d898baec4dfabfc2660f4c5ee5c97d846ae7bc53..ab6f34b2ccb68ad98b4c4edbba4fff4dd1cfb946 100644 (file)
@@ -106,15 +106,21 @@ FGIO::parse_port_config( const string& config )
 
     try
     {
-       if ( protocol == "atc610x" ) {
-            FGATC610x *atc610x = new FGATC610x;
-           atc610x->set_hz( 30 );
-            if ( tokens.size() > 1 ) {
-                if ( tokens[1] == "no-rudder" ) {
-                    atc610x->set_use_rudder( false );
-                }
+       if ( protocol == "atcsim" ) {
+            FGATC610x *atcsim = new FGATC610x;
+           atcsim->set_hz( 30 );
+            if ( tokens.size() != 6 ) {
+                SG_LOG( SG_IO, SG_ALERT, "Usage: --atcsim=[no-]pedals,"
+                        << "input0_config,input1_config,"
+                        << "output0_config,output1_config" );
             }
-           return atc610x;
+            if ( tokens[1] == "no-pedals" ) {
+                fgSetBool( "/input/atcsim/ignore-pedal-controls", true );
+            } else {
+                fgSetBool( "/input/atcsim/ignore-pedal-controls", false );
+            }
+            atcsim->set_path_names(tokens[2], tokens[3], tokens[4], tokens[5]);
+           return atcsim;
        } else if ( protocol == "atlas" ) {
            FGAtlas *atlas = new FGAtlas;
            io = atlas;
index e4e33c7798777d7ba6ad14387f1690a32f42b174..aef5b0577cdbea4da2220b793bf4dab21d70848d 100644 (file)
@@ -1286,7 +1286,7 @@ struct OptionDesc {
     {"start-date-gmt",               true,  OPTION_FUNC,   "", false, "", fgOptStartDateGmt },
     {"hud-tris",                     false, OPTION_STRING, "/sim/hud/frame-stat-type", false, "tris", 0 },
     {"hud-culled",                   false, OPTION_STRING, "/sim/hud/frame-stat-type", false, "culled", 0 },
-    {"atc610x",                      true,  OPTION_CHANNEL, "", false, "dummy", 0 },
+    {"atcsim",                       true,  OPTION_CHANNEL, "", false, "dummy", 0 },
     {"atlas",                        true,  OPTION_CHANNEL, "", false, "", 0 },
     {"httpd",                        true,  OPTION_CHANNEL, "", false, "", 0 },
 #ifdef FG_JPEG_SERVER
diff --git a/src/Network/ATC-Inputs.cxx b/src/Network/ATC-Inputs.cxx
new file mode 100644 (file)
index 0000000..b43f1e1
--- /dev/null
@@ -0,0 +1,885 @@
+// ATC-Inputs.hxx -- Translate ATC hardware inputs to FGFS properties
+//
+// Written by Curtis Olson, started November 2004.
+//
+// Copyright (C) 2004  Curtis L. Olson - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <simgear/compiler.h>
+
+#include STL_STRING
+
+#include <simgear/debug/logstream.hxx>
+
+#include <Main/fg_props.hxx>
+
+#include "ATC-Inputs.hxx"
+
+SG_USING_STD(string);
+
+
+
+// Constructor: The _board parameter specifies which board to
+// reference.  Possible values are 0 or 1.  The _config_file parameter
+// specifies the location of the input config file (xml)
+FGATCInput::FGATCInput( const int _board, const SGPath &_config_file ) :
+    is_open(false),
+    ignore_flight_controls(NULL),
+    ignore_pedal_controls(NULL),
+    analog_in_node(NULL),
+    radio_in_node(NULL),
+    switches_node(NULL)
+{
+    board = _board;
+    config = _config_file;
+}
+
+
+// Read analog inputs
+static void ATCReadAnalogInputs( int fd, unsigned char *analog_in_bytes ) {
+    // rewind
+    lseek( fd, 0, SEEK_SET );
+
+    int result = read( fd, analog_in_bytes, ATC_ANAL_IN_BYTES );
+    if ( result != ATC_ANAL_IN_BYTES ) {
+       SG_LOG( SG_IO, SG_ALERT, "Read failed" );
+       exit( -1 );
+    }
+}
+
+
+// Read status of radio switches and knobs
+static void ATCReadRadios( int fd, unsigned char *switch_data ) {
+    // rewind
+    lseek( fd, 0, SEEK_SET );
+
+    int result = read( fd, switch_data, ATC_RADIO_SWITCH_BYTES );
+    if ( result != ATC_RADIO_SWITCH_BYTES ) {
+       SG_LOG( SG_IO, SG_ALERT, "Read failed" );
+       exit( -1 );
+    }
+}
+
+
+// Read switch inputs
+static void ATCReadSwitches( int fd, unsigned char *switch_bytes ) {
+    // rewind
+    lseek( fd, 0, SEEK_SET );
+
+    int result = read( fd, switch_bytes, ATC_SWITCH_BYTES );
+    if ( result != ATC_SWITCH_BYTES ) {
+       SG_LOG( SG_IO, SG_ALERT, "Read failed" );
+       exit( -1 );
+    }
+}
+
+
+void FGATCInput::init_config() {
+#if defined( unix ) || defined( __CYGWIN__ )
+    if ( config.str()[0] != '/' ) {
+        // not an absolute path, prepend the standard location
+        SGPath tmp;
+        char *envp = ::getenv( "HOME" );
+        if ( envp != NULL ) {
+            tmp = envp;
+            tmp.append( ".atcflightsim" );
+            tmp.append( config.str() );
+            config = tmp;
+        }
+    }
+    readProperties( config.str(), globals->get_props() );
+#endif
+}
+
+
+// Open and initialize the ATC hardware
+bool FGATCInput::open() {
+    if ( is_open ) {
+       SG_LOG( SG_IO, SG_ALERT, "This board is already open for input! "
+                << board );
+       return false;
+    }
+
+    // This loads the config parameters generated by "simcal"
+    init_config();
+
+    SG_LOG( SG_IO, SG_ALERT,
+           "Initializing ATC 610x hardware, please wait ..." );
+
+    snprintf( lock_file, 256, "/proc/atc610x/board%d/lock", board );
+    snprintf( analog_in_file, 256, "/proc/atc610x/board%d/analog_in", board );
+    snprintf( radios_file, 256, "/proc/atc610x/board%d/radios", board );
+    snprintf( switches_file, 256, "/proc/atc610x/board%d/switches", board );
+
+    /////////////////////////////////////////////////////////////////////
+    // Open the /proc files
+    /////////////////////////////////////////////////////////////////////
+
+    lock_fd = ::open( lock_file, O_RDWR );
+    if ( lock_fd == -1 ) {
+       SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
+       char msg[256];
+       snprintf( msg, 256, "Error opening %s", lock_file );
+       perror( msg );
+       exit( -1 );
+    }
+
+    analog_in_fd = ::open( analog_in_file, O_RDONLY );
+    if ( analog_in_fd == -1 ) {
+       SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
+       char msg[256];
+       snprintf( msg, 256, "Error opening %s", analog_in_file );
+       perror( msg );
+       exit( -1 );
+    }
+
+    radios_fd = ::open( radios_file, O_RDWR );
+    if ( radios_fd == -1 ) {
+       SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
+       char msg[256];
+       snprintf( msg, 256, "Error opening %s", radios_file );
+       perror( msg );
+       exit( -1 );
+    }
+
+    switches_fd = ::open( switches_file, O_RDONLY );
+    if ( switches_fd == -1 ) {
+       SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
+       char msg[256];
+       snprintf( msg, 256, "Error opening %s", switches_file );
+       perror( msg );
+       exit( -1 );
+    }
+
+    /////////////////////////////////////////////////////////////////////
+    // Finished initing hardware
+    /////////////////////////////////////////////////////////////////////
+
+    SG_LOG( SG_IO, SG_ALERT,
+           "Done initializing ATC 610x hardware." );
+
+    is_open = true;
+
+    /////////////////////////////////////////////////////////////////////
+    // Connect up to property values
+    /////////////////////////////////////////////////////////////////////
+
+    ignore_flight_controls
+        = fgGetNode( "/input/atcsim/ignore-flight-controls", true );
+    ignore_pedal_controls
+        = fgGetNode( "/input/atcsim/ignore-pedal-controls", true );
+
+    char base_name[256];
+
+    snprintf( base_name, 256, "/input/atc-board[%d]/analog-in", board );
+    analog_in_node = fgGetNode( base_name );
+
+    snprintf( base_name, 256, "/input/atc-board[%d]/radio-switches", board );
+    radio_in_node = fgGetNode( base_name );
+
+    snprintf( base_name, 256, "/input/atc-board[%d]/switches", board );
+    switches_node = fgGetNode( base_name );
+
+    return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////
+// Read analog inputs
+/////////////////////////////////////////////////////////////////////
+
+// scale a number between min and max (with center defined) to a scale
+// from -1.0 to 1.0
+static double scale( int center, int min, int max, int value ) {
+    // cout << center << " " << min << " " << max << " " << value << " ";
+    double result;
+    double range;
+
+    if ( value <= center ) {
+        range = center - min;
+        result = (value - center) / range;
+    } else {
+        range = max - center;
+        result = (value - center) / range;            
+    }
+
+    if ( result < -1.0 ) result = -1.0;
+    if ( result > 1.0 ) result = 1.0;
+
+    // cout << result << endl;
+
+    return result;
+}
+
+
+// scale a number between min and max to a scale from 0.0 to 1.0
+static double scale( int min, int max, int value ) {
+    // cout << center << " " << min << " " << max << " " << value << " ";
+    double result;
+    double range;
+
+    range = max - min;
+    result = (value - min) / range;
+
+    if ( result < 0.0 ) result = 0.0;
+    if ( result > 1.0 ) result = 1.0;
+
+    // cout << result << endl;
+
+    return result;
+}
+
+
+static int tony_magic( int raw, int obs[3] ) {
+    int result = 0;
+
+    obs[0] = raw;
+
+    if ( obs[1] < 30 ) {
+        if ( obs[2] >= 68 && obs[2] < 480 ) {
+            result = -6;
+        } else if ( obs[2] >= 480 ) {
+            result = 6;
+        }
+        obs[2] = obs[1];
+        obs[1] = obs[0];
+    } else if ( obs[1] < 68 ) {
+        // do nothing
+        obs[1] = obs[0];
+    } else if ( obs[2] < 30 ) {
+        if ( obs[1] >= 68 && obs[1] < 480 ) {
+            result = 6;
+           obs[2] = obs[1];
+           obs[1] = obs[0];
+        } else if ( obs[1] >= 480 ) {
+           result = -6;
+            if ( obs[0] < obs[1] ) {
+               obs[2] = obs[1];
+               obs[1] = obs[0];
+           } else {
+               obs[2] = obs[0];
+               obs[1] = obs[0];
+           }
+        }
+    } else if ( obs[1] > 980 ) {
+        if ( obs[2] <= 956 && obs[2] > 480 ) {
+            result = 6;
+        } else if ( obs[2] <= 480 ) {
+            result = -6;
+        }
+        obs[2] = obs[1];
+        obs[1] = obs[0];
+    } else if ( obs[1] > 956 ) {
+        // do nothing
+        obs[1] = obs[0];
+    } else if ( obs[2] > 980 ) {
+        if ( obs[1] <= 956 && obs[1] > 480 ) {
+            result = -6;
+           obs[2] = obs[1];
+           obs[1] = obs[0];
+        } else if ( obs[1] <= 480 ) {
+           result = 6;
+            if ( obs[0] > obs[1] ) {
+               obs[2] = obs[1];
+               obs[1] = obs[0];
+           } else {
+               obs[2] = obs[0];
+               obs[1] = obs[0];
+           }
+        }
+    } else {
+        if ( obs[1] < 480 && obs[2] > 480 ) {
+           // crossed gap going up
+           if ( obs[0] < obs[1] ) {
+               // caught a bogus intermediate value coming out of the gap
+               obs[1] = obs[0];
+           }
+       } else if ( obs[1] > 480 && obs[2] < 480 ) {
+           // crossed gap going down
+           if ( obs[0] > obs[1] ) {
+               // caught a bogus intermediate value coming out of the gap
+             obs[1] = obs[0];
+           }
+       } else if ( obs[0] > 480 && obs[1] < 480 && obs[2] < 480 ) {
+            // crossed the gap going down
+           if ( obs[1] > obs[2] ) {
+               // caught a bogus intermediate value coming out of the gap
+               obs[1] = obs[2];
+           }
+       } else if ( obs[0] < 480 && obs[1] > 480 && obs[2] > 480 ) {
+            // crossed the gap going up
+           if ( obs[1] < obs[2] ) {
+               // caught a bogus intermediate value coming out of the gap
+               obs[1] = obs[2];
+           }
+       }
+        result = obs[1] - obs[2];
+        if ( abs(result) > 400 ) {
+            // ignore
+            result = 0;
+        }
+        obs[2] = obs[1];
+        obs[1] = obs[0];
+    }
+
+    // cout << " result = " << result << endl;
+    if ( result < -500 ) { result += 1024; }
+    if ( result > 500 ) { result -= 1024; }
+
+    return result;
+}
+
+
+static double instr_pot_filter( double ave, double val ) {
+    if ( fabs(ave - val) < 400 || fabs(val) < fabs(ave) ) {
+        return 0.5 * ave + 0.5 * val;
+    } else {
+        return ave;
+    }
+}
+
+
+bool FGATCInput::do_analog_in() {
+    // Read raw data in byte form
+    ATCReadAnalogInputs( analog_in_fd, analog_in_bytes );
+
+    // Convert to integer values
+    for ( int channel = 0; channel < ATC_ANAL_IN_VALUES; ++channel ) {
+       unsigned char hi = analog_in_bytes[2 * channel] & 0x03;
+       unsigned char lo = analog_in_bytes[2 * channel + 1];
+       analog_in_data[channel] = hi * 256 + lo;
+
+       // printf("%02x %02x ", hi, lo );
+       // printf("%04d ", value );
+    }
+
+    // Process analog inputs
+    if ( analog_in_node != NULL ) {
+        for ( int i = 0; i < analog_in_node->nChildren(); ++i ) {
+            // read the next config entry from the property tree
+
+            SGPropertyNode *child = analog_in_node->getChild(i);
+            string cname = child->getName();
+            int index = child->getIndex();
+            string name = "";
+            string type = "";
+            string subtype = "";
+            vector <SGPropertyNode *> output_nodes; output_nodes.clear();
+            int center = -1;
+            int min = 0;
+            int max = 1023;
+            float factor = 1.0;
+            if ( cname == "channel" ) {
+                SGPropertyNode *prop;
+                prop = child->getChild( "name" );
+                if ( prop != NULL ) {
+                    name = prop->getStringValue();
+                }
+                prop = child->getChild( "type", 0 );
+                if ( prop != NULL ) {
+                    type = prop->getStringValue();
+                }
+                prop = child->getChild( "type", 1 );
+                if ( prop != NULL ) {
+                    subtype = prop->getStringValue();
+                }
+                int j = 0;
+                while ( (prop = child->getChild("prop", j)) != NULL ) {
+                    SGPropertyNode *tmp
+                        = fgGetNode( prop->getStringValue(), true );
+                    output_nodes.push_back( tmp );
+                    j++;
+                }
+                prop = child->getChild( "center" );
+                if ( prop != NULL ) {
+                    center = prop->getIntValue();
+                }
+                prop = child->getChild( "min" );
+                if ( prop != NULL ) {
+                    min = prop->getIntValue();
+                }
+                prop = child->getChild( "max" );
+                if ( prop != NULL ) {
+                    max = prop->getIntValue();
+                }
+                prop = child->getChild( "factor" );
+                if ( prop != NULL ) {
+                    factor = prop->getFloatValue();
+                }
+
+                // Fetch the raw value
+
+                int raw_value = analog_in_data[index];
+
+                // Update the target properties
+
+                if ( type == "flight"
+                     && !ignore_flight_controls->getBoolValue() )
+                {
+                    if ( subtype != "pedals" ||
+                         ( subtype == "pedals"
+                           && !ignore_pedal_controls->getBoolValue() ) )
+                    {
+                        // "Cook" the raw value
+                        float scaled_value = 0.0f;
+                        if ( center >= 0 ) {
+                            scaled_value = scale( center, min, max, raw_value );
+                        } else {
+                            scaled_value = scale( min, max, raw_value );
+                        }
+                        scaled_value *= factor;
+
+                        // update the property tree values
+                        for ( j = 0; j < (int)output_nodes.size(); ++j ) {
+                            output_nodes[j]->setDoubleValue( scaled_value );
+                        }
+                    }
+                } else if ( type == "avionics-simple" ) {
+                    // "Cook" the raw value
+                    float scaled_value = 0.0f;
+                    if ( center >= 0 ) {
+                        scaled_value = scale( center, min, max, raw_value );
+                    } else {
+                        scaled_value = scale( min, max, raw_value );
+                    }
+                    scaled_value *= factor;
+
+                    // update the property tree values
+                    for ( j = 0; j < (int)output_nodes.size(); ++j ) {
+                        output_nodes[j]->setDoubleValue( scaled_value );
+                    }
+                } else if ( type == "avionics-resolver" ) {
+                    // this type of analog input impliments a
+                    // rotational knob.  We first caclulate the amount
+                    // of knob rotation (slightly complex to work with
+                    // hardware specific goofiness) and then multiply
+                    // that amount of movement by a scaling factor,
+                    // and finally add the result to the original
+                    // value.
+
+                    bool do_init = false;
+                    float scaled_value = 0.0f;
+
+                    // fetch intermediate values from property tree
+
+                    prop = child->getChild( "is-inited", 0 );
+                    if ( prop == NULL ) {
+                        do_init = true;
+                        prop = child->getChild( "is-inited", 0, true );
+                        prop->setBoolValue( true );
+                    }
+
+                    int raw[3];
+                    for ( j = 0; j < 3; ++j ) {
+                        prop = child->getChild( "raw", j, true );
+                        if ( do_init ) {
+                            raw[j] = analog_in_data[index];
+                        } else {
+                            raw[j] = prop->getIntValue();
+                        }
+                    }
+
+                    // do Tony's magic to calculate knob movement
+                    // based on current analog input position and
+                    // historical data.
+                    int diff = tony_magic( analog_in_data[index], raw );
+
+                    // write raw intermediate values (updated by
+                    // tony_magic()) back to property tree
+                    for ( j = 0; j < 3; ++j ) {
+                        prop = child->getChild( "raw", j, true );
+                        prop->setIntValue( raw[j] );
+                    }
+
+                    // filter knob position
+                    prop = child->getChild( "diff-average", 0, true );
+                    double diff_ave = prop->getDoubleValue();
+                    diff_ave = instr_pot_filter( diff_ave, diff );
+                    prop->setDoubleValue( diff_ave );
+
+                    // calculate value adjustment in real world units
+                    scaled_value = diff_ave * factor;
+
+                    // update the property tree values
+                    for ( j = 0; j < (int)output_nodes.size(); ++j ) {
+                        float value = output_nodes[j]->getDoubleValue();
+                        value += scaled_value;
+
+                        prop = child->getChild( "min-clamp" );
+                        if ( prop != NULL ) {
+                            double min = prop->getDoubleValue();
+                            if ( value < min ) { value = min; }
+                        }
+
+                        prop = child->getChild( "max-clamp" );
+                        if ( prop != NULL ) {
+                            double max = prop->getDoubleValue();
+                            if ( value > max ) { value = max; }
+                        }
+
+                        prop = child\0->getChild( "compass-heading" );
+                        if ( prop != NULL ) {
+                            bool compass = prop->getBoolValue();
+                            if ( compass ) {
+                                while ( value >= 360.0 ) { value -= 360.0; }
+                                while ( value < 0.0 ) { value += 360.0; }
+                            }
+                        }
+
+                        output_nodes[j]->setDoubleValue( value );
+                    }
+
+                } else {
+                    SG_LOG( SG_IO, SG_DEBUG, "Invalid channel type =  "
+                            << type );
+                }
+            } else {
+                SG_LOG( SG_IO, SG_DEBUG,
+                        "Input config error, expecting 'channel' but found "
+                        << cname );
+            }
+        }
+    }
+
+    return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////
+// Read the switch positions
+/////////////////////////////////////////////////////////////////////
+
+// decode the packed switch data
+static void update_switch_matrix(
+        int board,
+       unsigned char switch_data[ATC_SWITCH_BYTES],
+       int switch_matrix[2][ATC_NUM_COLS][ATC_SWITCH_BYTES] )
+{
+    for ( int row = 0; row < ATC_SWITCH_BYTES; ++row ) {
+       unsigned char switches = switch_data[row];
+
+       for( int column = 0; column < ATC_NUM_COLS; ++column ) {
+           switch_matrix[board][column][row] = switches & 1;
+           switches = switches >> 1;
+       }                       
+    }
+}                     
+
+bool FGATCInput::do_switches() {
+    // Read the raw data
+    ATCReadSwitches( switches_fd, switch_data );
+
+    // unpack the switch data
+    int switch_matrix[2][ATC_NUM_COLS][ATC_SWITCH_BYTES];
+    update_switch_matrix( board, switch_data, switch_matrix );
+
+    // Process the switch inputs
+    if ( switches_node != NULL ) {
+        for ( int i = 0; i < switches_node->nChildren(); ++i ) {
+            // read the next config entry from the property tree
+
+            SGPropertyNode *child = switches_node->getChild(i);
+            string cname = child->getName();
+            string name = "";
+            string type = "";
+            vector <SGPropertyNode *> output_nodes; output_nodes.clear();
+            int row = -1;
+            int col = -1;
+            float factor = 1.0;
+            int filter = -1;
+            float scaled_value = 0.0f;
+
+            // get common options
+
+            SGPropertyNode *prop;
+            prop = child->getChild( "name" );
+            if ( prop != NULL ) {
+                name = prop->getStringValue();
+            }
+            prop = child->getChild( "type" );
+            if ( prop != NULL ) {
+                type = prop->getStringValue();
+            }
+            int j = 0;
+            while ( (prop = child->getChild("prop", j)) != NULL ) {
+                SGPropertyNode *tmp
+                    = fgGetNode( prop->getStringValue(), true );
+                output_nodes.push_back( tmp );
+                j++;
+            }
+            prop = child->getChild( "factor" );
+            if ( prop != NULL ) {
+                factor = prop->getFloatValue();
+            }
+            prop = child->getChild( "steady-state-filter" );
+            if ( prop != NULL ) {
+                filter = prop->getIntValue();
+            }
+
+            // handle different types of switches
+
+            if ( cname == "switch" ) {
+                prop = child->getChild( "row" );
+                if ( prop != NULL ) {
+                    row = prop->getIntValue();
+                }
+                prop = child->getChild( "col" );
+                if ( prop != NULL ) {
+                    col = prop->getIntValue();
+                }
+
+                // Fetch the raw value
+                int raw_value = switch_matrix[board][row][col];
+
+                // Cook the value
+                scaled_value = (float)raw_value * factor;
+
+            } else if ( cname == "combo-switch" ) {
+                float combo_value = 0.0f;
+
+                SGPropertyNode *pos;
+                int k = 0;
+                while ( (pos = child->getChild("position", k++)) != NULL ) {
+                    // read the combo position entries from the property tree
+
+                    prop = pos->getChild( "row" );
+                    if ( prop != NULL ) {
+                        row = prop->getIntValue();
+                    }
+                    prop = pos->getChild( "col" );
+                    if ( prop != NULL ) {
+                        col = prop->getIntValue();
+                    }
+                    prop = pos->getChild( "value" );
+                    if ( prop != NULL ) {
+                        combo_value = prop->getFloatValue();
+                    }
+
+                    // Fetch the raw value
+                    int raw_value = switch_matrix[board][row][col];
+                    // cout << "sm[" << board << "][" << row << "][" << col
+                    //      << "] = " << raw_value << endl;
+
+                    if ( raw_value ) {
+                        // set scaled_value to the first combo_value
+                        // that matches and jump out of loop.
+                        scaled_value = combo_value;
+                        break;
+                    }
+                }
+
+                // Cook the value
+                scaled_value *= factor;
+            }
+
+            // handle filter request.  The value of the switch must be
+            // steady-state for "n" frames before the property value
+            // is updated.
+
+            bool update_prop = true;
+
+            if ( filter > 1 ) {
+                SGPropertyNode *fv = child->getChild( "filter-value", 0, true );
+                float filter_value = fv->getFloatValue();
+                SGPropertyNode *fc = child->getChild( "filter-count", 0, true );
+                int filter_count = fc->getIntValue();
+
+                if ( fabs(scaled_value - filter_value) < 0.0001 ) {
+                    filter_count++;
+                } else {
+                    filter_count = 0;
+                }
+
+                if ( filter_count < filter ) {
+                    update_prop = false;
+                }
+
+                fv->setFloatValue( scaled_value );
+                fc->setIntValue( filter_count );
+            }
+
+            if ( update_prop ) {
+                if ( type == "engine" || type == "flight" ) {
+                    if ( ! ignore_flight_controls->getBoolValue() ) {
+                        // update the property tree values
+                        for ( j = 0; j < (int)output_nodes.size(); ++j ) {
+                            output_nodes[j]->setDoubleValue( scaled_value );
+                        }
+                    }
+                } else if ( type == "avionics" ) {
+                    // update the property tree values
+                    for ( j = 0; j < (int)output_nodes.size(); ++j ) {
+                        output_nodes[j]->setDoubleValue( scaled_value );
+                    }
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////
+// Read radio switches 
+/////////////////////////////////////////////////////////////////////
+
+bool FGATCInput::do_radio_switches() {
+    // Read the raw data
+    ATCReadRadios( radios_fd, radio_switch_data );
+
+    // Process the radio switch/knob inputs
+    if ( radio_in_node != NULL ) {
+        for ( int i = 0; i < radio_in_node->nChildren(); ++i ) {
+            // read the next config entry from the property tree
+
+            SGPropertyNode *child = radio_in_node->getChild(i);
+            string cname = child->getName();
+
+            if ( cname == "switch" ) {
+                string name = "";
+                string type = "";
+                vector <SGPropertyNode *> output_nodes; output_nodes.clear();
+                int byte_num = -1;
+                int right_shift = -1;
+                int mask = 0xff;
+                int factor = 1;
+                int offset = 0;
+                int scaled_value = 0;
+
+                // get common options
+
+                SGPropertyNode *prop;
+                prop = child->getChild( "name" );
+                if ( prop != NULL ) {
+                    name = prop->getStringValue();
+                }
+                prop = child->getChild( "type" );
+                if ( prop != NULL ) {
+                    type = prop->getStringValue();
+                }
+                int j = 0;
+                while ( (prop = child->getChild("prop", j)) != NULL ) {
+                    SGPropertyNode *tmp
+                        = fgGetNode( prop->getStringValue(), true );
+                    output_nodes.push_back( tmp );
+                    j++;
+                }
+                prop = child->getChild( "byte" );
+                if ( prop != NULL ) {
+                    byte_num = prop->getIntValue();
+                }
+                prop = child->getChild( "right-shift" );
+                if ( prop != NULL ) {
+                    right_shift = prop->getIntValue();
+                }
+                prop = child->getChild( "mask" );
+                if ( prop != NULL ) {
+                    mask = prop->getIntValue();
+                }
+                prop = child->getChild( "factor" );
+                if ( prop != NULL ) {
+                    factor = prop->getIntValue();
+                }
+                prop = child->getChild( "offset" );
+                if ( prop != NULL ) {
+                    offset = prop->getIntValue();
+                }
+
+                // Fetch the raw value
+                int raw_value
+                    = (radio_switch_data[byte_num] >> right_shift) & mask;
+
+                // Cook the value
+                scaled_value = raw_value * factor + offset;
+
+                // update the property tree values
+                for ( j = 0; j < (int)output_nodes.size(); ++j ) {
+                    output_nodes[j]->setIntValue( scaled_value );
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+
+// process the hardware inputs.  This code assumes the calling layer
+// will lock the hardware.
+bool FGATCInput::process() {
+    if ( !is_open ) {
+       SG_LOG( SG_IO, SG_ALERT, "This board has not been opened for input! "
+                << board );
+       return false;
+    }
+
+    do_analog_in();
+    do_switches();
+    do_radio_switches();
+       
+    return true;
+}
+
+
+bool FGATCInput::close() {
+    int result;
+
+    result = ::close( lock_fd );
+    if ( result == -1 ) {
+       SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
+       char msg[256];
+       snprintf( msg, 256, "Error closing %s", lock_file );
+       perror( msg );
+       exit( -1 );
+    }
+
+    result = ::close( analog_in_fd );
+    if ( result == -1 ) {
+       SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
+       char msg[256];
+       snprintf( msg, 256, "Error closing %s", analog_in_file );
+       perror( msg );
+       exit( -1 );
+    }
+
+    result = ::close( radios_fd );
+    if ( result == -1 ) {
+       SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
+       char msg[256];
+       snprintf( msg, 256, "Error closing %s", radios_file );
+       perror( msg );
+       exit( -1 );
+    }
+
+    result = ::close( switches_fd );
+    if ( result == -1 ) {
+       SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
+       char msg[256];
+       snprintf( msg, 256, "Error closing %s", switches_file );
+       perror( msg );
+       exit( -1 );
+    }
+
+    return true;
+}
diff --git a/src/Network/ATC-Inputs.hxx b/src/Network/ATC-Inputs.hxx
new file mode 100644 (file)
index 0000000..146d7c8
--- /dev/null
@@ -0,0 +1,96 @@
+// ATC-Inputs.hxx -- Translate ATC hardware inputs to FGFS properties
+//
+// Written by Curtis Olson, started November 2004.
+//
+// Copyright (C) 2004  Curtis L. Olson - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#ifndef _FG_ATC_INPUTS_HXX
+#define _FG_ATC_INPUTS_HXX
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <Main/fg_props.hxx>
+
+#define ATC_ANAL_IN_VALUES 32
+#define ATC_ANAL_IN_BYTES (2 * ATC_ANAL_IN_VALUES)
+#define ATC_RADIO_SWITCH_BYTES 32
+#define ATC_SWITCH_BYTES 16
+#define ATC_NUM_COLS 8
+
+
+class FGATCInput {
+
+    int is_open;
+
+    int board;
+    SGPath config;
+
+    int lock_fd;
+    int analog_in_fd;
+    int radios_fd;
+    int switches_fd;
+
+    char lock_file[256];
+    char analog_in_file[256];
+    char lamps_file[256];
+    char radios_file[256];
+    char stepper_file[256];
+    char switches_file[256];
+
+    unsigned char analog_in_bytes[ATC_ANAL_IN_BYTES];
+    int analog_in_data[ATC_ANAL_IN_VALUES];
+    unsigned char radio_switch_data[ATC_RADIO_SWITCH_BYTES];
+    unsigned char switch_data[ATC_SWITCH_BYTES];
+
+    SGPropertyNode *ignore_flight_controls;
+    SGPropertyNode *ignore_pedal_controls;
+
+    SGPropertyNode *analog_in_node;
+    SGPropertyNode *radio_in_node;
+    SGPropertyNode *switches_node;
+
+    void init_config();
+    bool do_analog_in();
+    bool do_radio_switches();
+    bool do_switches();
+
+public:
+
+    // Constructor: The _board parameter specifies which board to
+    // reference.  Possible values are 0 or 1.  The _config_file
+    // parameter specifies the location of the input config file (xml)
+    FGATCInput( const int _board, const SGPath &_config_file );
+
+    // Destructor
+    ~FGATCInput() { }
+
+    bool open();
+
+    // process the hardware inputs.  This code assumes the calling
+    // layer will lock the hardware.
+    bool process();
+
+    bool close();
+};
+
+
+#endif // _FG_ATC_INPUTS_HXX
index ccf643273691f48a6eefc03b5b110277b9494796..d4fa7dc7c571f27dd7236cfcd2d5fdcbeb2d056c 100644 (file)
@@ -17,6 +17,7 @@ endif
 
 libNetwork_a_SOURCES = \
        protocol.cxx protocol.hxx \
+       ATC-Inputs.cxx ATC-Inputs.hxx \
        atc610x.cxx atc610x.hxx \
        atlas.cxx atlas.hxx \
        garmin.cxx garmin.hxx \
index 0f164ddf6d88fabad99257bf9f4cbcc069f38eb9..9d71e176ab97b52c5c1d3a34dca3c0cdaeb6e3a8 100644 (file)
@@ -86,19 +86,6 @@ static int ATC610xRelease( int fd ) {
 }
 
 
-// Read analog inputs
-static void ATC610xReadAnalogInputs( int fd, unsigned char *analog_in_bytes ) {
-    // rewind
-    lseek( fd, 0, SEEK_SET );
-
-    int result = read( fd, analog_in_bytes, ATC_ANAL_IN_BYTES );
-    if ( result != ATC_ANAL_IN_BYTES ) {
-       SG_LOG( SG_IO, SG_ALERT, "Read failed" );
-       exit( -1 );
-    }
-}
-
-
 // Write a radios command
 static int ATC610xSetRadios( int fd,
                             unsigned char data[ATC_RADIO_DISPLAY_BYTES] )
@@ -170,19 +157,6 @@ static unsigned char ATC610xReadStepper( int fd ) {
 }
 
 
-// Read switch inputs
-static void ATC610xReadSwitches( int fd, unsigned char *switch_bytes ) {
-    // rewind
-    lseek( fd, 0, SEEK_SET );
-
-    int result = read( fd, switch_bytes, ATC_SWITCH_BYTES );
-    if ( result != ATC_SWITCH_BYTES ) {
-       SG_LOG( SG_IO, SG_ALERT, "Read failed" );
-       exit( -1 );
-    }
-}
-
-
 // Turn a lamp on or off
 void ATC610xSetLamp( int fd, int channel, bool value ) {
     // lamp channels 0-63 are written to LampPort0, channels 64-127
@@ -227,11 +201,20 @@ bool FGATC610x::open() {
        return false;
     }
 
+    SG_LOG( SG_IO, SG_ALERT,
+           "Initializing ATC 610x hardware, please wait ..." );
+
     // This loads the config parameters generated by "simcal"
     init_config();
 
-    SG_LOG( SG_IO, SG_ALERT,
-           "Initializing ATC 610x hardware, please wait ..." );
+    if ( input0_path.str().length() ) {
+        input0 = new FGATCInput( 0, input0_path );
+        input0->open();
+    }
+    if ( input1_path.str().length() ) {
+        input1 = new FGATCInput( 1, input1_path );
+        input1->open();
+    }
 
     set_hz( 30 );              // default to processing requests @ 30Hz
     set_enabled( true );
@@ -239,11 +222,9 @@ bool FGATC610x::open() {
     board = 0;                 // 610x uses a single board number = 0
 
     snprintf( lock_file, 256, "/proc/atc610x/board%d/lock", board );
-    snprintf( analog_in_file, 256, "/proc/atc610x/board%d/analog_in", board );
     snprintf( lamps_file, 256, "/proc/atc610x/board%d/lamps", board );
     snprintf( radios_file, 256, "/proc/atc610x/board%d/radios", board );
     snprintf( stepper_file, 256, "/proc/atc610x/board%d/steppers", board );
-    snprintf( switches_file, 256, "/proc/atc610x/board%d/switches", board );
 
     /////////////////////////////////////////////////////////////////////
     // Open the /proc files
@@ -258,15 +239,6 @@ bool FGATC610x::open() {
        exit( -1 );
     }
 
-    analog_in_fd = ::open( analog_in_file, O_RDONLY );
-    if ( analog_in_fd == -1 ) {
-       SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
-       char msg[256];
-       snprintf( msg, 256, "Error opening %s", analog_in_file );
-       perror( msg );
-       exit( -1 );
-    }
-
     lamps_fd = ::open( lamps_file, O_WRONLY );
     if ( lamps_fd == -1 ) {
        SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
@@ -294,14 +266,6 @@ bool FGATC610x::open() {
        exit( -1 );
     }
 
-    switches_fd = ::open( switches_file, O_RDONLY );
-    if ( switches_fd == -1 ) {
-       SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
-       char msg[256];
-       snprintf( msg, 256, "Error opening %s", switches_file );
-       perror( msg );
-       exit( -1 );
-    }
 
     /////////////////////////////////////////////////////////////////////
     // Home the compass stepper motor
@@ -536,314 +500,6 @@ bool FGATC610x::open() {
 }
 
 
-/////////////////////////////////////////////////////////////////////
-// Read analog inputs
-/////////////////////////////////////////////////////////////////////
-
-// scale a number between min and max (with center defined) to a scale
-// from -1.0 to 1.0
-static double scale( int center, int min, int max, int value ) {
-    // cout << center << " " << min << " " << max << " " << value << " ";
-    double result;
-    double range;
-
-    if ( value <= center ) {
-        range = center - min;
-        result = (value - center) / range;
-    } else {
-        range = max - center;
-        result = (value - center) / range;            
-    }
-
-    if ( result < -1.0 ) result = -1.0;
-    if ( result > 1.0 ) result = 1.0;
-
-    // cout << result << endl;
-
-    return result;
-}
-
-
-// scale a number between min and max to a scale from 0.0 to 1.0
-static double scale( int min, int max, int value ) {
-    // cout << center << " " << min << " " << max << " " << value << " ";
-    double result;
-    double range;
-
-    range = max - min;
-    result = (value - min) / range;
-
-    if ( result < 0.0 ) result = 0.0;
-    if ( result > 1.0 ) result = 1.0;
-
-    // cout << result << endl;
-
-    return result;
-}
-
-
-static int tony_magic( int raw, int obs[3] ) {
-    int result = 0;
-
-    obs[0] = raw;
-
-    if ( obs[1] < 30 ) {
-        if ( obs[2] >= 68 && obs[2] < 480 ) {
-            result = -6;
-        } else if ( obs[2] >= 480 ) {
-            result = 6;
-        }
-        obs[2] = obs[1];
-        obs[1] = obs[0];
-    } else if ( obs[1] < 68 ) {
-        // do nothing
-        obs[1] = obs[0];
-    } else if ( obs[2] < 30 ) {
-        if ( obs[1] >= 68 && obs[1] < 480 ) {
-            result = 6;
-           obs[2] = obs[1];
-           obs[1] = obs[0];
-        } else if ( obs[1] >= 480 ) {
-           result = -6;
-            if ( obs[0] < obs[1] ) {
-               obs[2] = obs[1];
-               obs[1] = obs[0];
-           } else {
-               obs[2] = obs[0];
-               obs[1] = obs[0];
-           }
-        }
-    } else if ( obs[1] > 980 ) {
-        if ( obs[2] <= 956 && obs[2] > 480 ) {
-            result = 6;
-        } else if ( obs[2] <= 480 ) {
-            result = -6;
-        }
-        obs[2] = obs[1];
-        obs[1] = obs[0];
-    } else if ( obs[1] > 956 ) {
-        // do nothing
-        obs[1] = obs[0];
-    } else if ( obs[2] > 980 ) {
-        if ( obs[1] <= 956 && obs[1] > 480 ) {
-            result = -6;
-           obs[2] = obs[1];
-           obs[1] = obs[0];
-        } else if ( obs[1] <= 480 ) {
-           result = 6;
-            if ( obs[0] > obs[1] ) {
-               obs[2] = obs[1];
-               obs[1] = obs[0];
-           } else {
-               obs[2] = obs[0];
-               obs[1] = obs[0];
-           }
-        }
-    } else {
-        if ( obs[1] < 480 && obs[2] > 480 ) {
-           // crossed gap going up
-           if ( obs[0] < obs[1] ) {
-               // caught a bogus intermediate value coming out of the gap
-               obs[1] = obs[0];
-           }
-       } else if ( obs[1] > 480 && obs[2] < 480 ) {
-           // crossed gap going down
-           if ( obs[0] > obs[1] ) {
-               // caught a bogus intermediate value coming out of the gap
-             obs[1] = obs[0];
-           }
-       } else if ( obs[0] > 480 && obs[1] < 480 && obs[2] < 480 ) {
-            // crossed the gap going down
-           if ( obs[1] > obs[2] ) {
-               // caught a bogus intermediate value coming out of the gap
-               obs[1] = obs[2];
-           }
-       } else if ( obs[0] < 480 && obs[1] > 480 && obs[2] > 480 ) {
-            // crossed the gap going up
-           if ( obs[1] < obs[2] ) {
-               // caught a bogus intermediate value coming out of the gap
-               obs[1] = obs[2];
-           }
-       }
-        result = obs[1] - obs[2];
-        if ( abs(result) > 400 ) {
-            // ignore
-            result = 0;
-        }
-        obs[2] = obs[1];
-        obs[1] = obs[0];
-    }
-
-    // cout << " result = " << result << endl;
-    if ( result < -500 ) { result += 1024; }
-    if ( result > 500 ) { result -= 1024; }
-
-    return result;
-}
-
-
-static double instr_pot_filter( double ave, double val ) {
-    if ( fabs(ave - val) < 400 || fabs(val) < fabs(ave) ) {
-        return 0.5 * ave + 0.5 * val;
-    } else {
-        return ave;
-    }
-}
-
-
-bool FGATC610x::do_analog_in() {
-    // Read raw data in byte form
-    ATC610xReadAnalogInputs( analog_in_fd, analog_in_bytes );
-
-    // Convert to integer values
-    for ( int channel = 0; channel < ATC_ANAL_IN_VALUES; ++channel ) {
-       unsigned char hi = analog_in_bytes[2 * channel] & 0x03;
-       unsigned char lo = analog_in_bytes[2 * channel + 1];
-       analog_in_data[channel] = hi * 256 + lo;
-
-       // printf("%02x %02x ", hi, lo );
-       // printf("%04d ", value );
-    }
-
-    float tmp;
-
-    if ( !ignore_flight_controls->getBoolValue() ) {
-        // aileron
-        tmp = scale( ailerons_center->getIntValue(),
-                     ailerons_min->getIntValue(),
-                     ailerons_max->getIntValue(), analog_in_data[0] );
-        fgSetFloat( "/controls/flight/aileron", tmp );
-        // cout << "aileron = " << analog_in_data[0] << " = " << tmp;
-
-        // elevator
-        tmp = -scale( elevator_center->getIntValue(),
-                      elevator_min->getIntValue(),
-                      elevator_max->getIntValue(), analog_in_data[5] );
-        fgSetFloat( "/controls/flight/elevator", tmp );
-        // cout << "trim = " << analog_in_data[4] << " = " << tmp;
-
-        // elevator trim
-        tmp = scale( trim_center->getIntValue(), trim_min->getIntValue(),
-                     trim_max->getIntValue(), analog_in_data[4] );
-        fgSetFloat( "/controls/flight/elevator-trim", tmp );
-        // cout << " elev = " << analog_in_data[5] << " = " << tmp << endl;
-
-        // mixture
-        tmp = scale( mixture_min->getIntValue(), mixture_max->getIntValue(),
-                     analog_in_data[6] );
-        fgSetFloat( "/controls/engines/engine[0]/mixture", tmp );
-        fgSetFloat( "/controls/engines/engine[1]/mixture", tmp );
-
-        // throttle
-        tmp = scale( throttle_min->getIntValue(), throttle_max->getIntValue(),
-                     analog_in_data[8] );
-        fgSetFloat( "/controls/engines/engine[0]/throttle", tmp );
-        fgSetFloat( "/controls/engines/engine[1]/throttle", tmp );
-        // cout << "throttle = " << tmp << endl;
-
-        if ( use_rudder ) {
-            // rudder
-            tmp = scale( rudder_center->getIntValue(),
-                         rudder_min->getIntValue(),
-                         rudder_max->getIntValue(), analog_in_data[10] );
-            fgSetFloat( "/controls/flight/rudder", -tmp );
-
-            // toe brakes
-            tmp = scale( brake_left_min->getIntValue(),
-                         brake_left_max->getIntValue(),
-                         analog_in_data[20] );
-            fgSetFloat( "/controls/gear/brake-left", tmp );
-            tmp = scale( brake_right_min->getIntValue(),
-                         brake_right_max->getIntValue(),
-                         analog_in_data[21] );
-            fgSetFloat( "/controls/gear/brake-right", tmp );
-        }
-    }
-
-    // nav1 volume
-    tmp = (float)analog_in_data[25] / 1024.0f;
-    fgSetFloat( "/radios/nav[0]/volume", tmp );
-
-    // nav2 volume
-    tmp = (float)analog_in_data[24] / 1024.0f;
-    fgSetFloat( "/radios/nav[1]/volume", tmp );
-
-    // adf volume
-    tmp = (float)analog_in_data[26] / 1024.0f;
-    fgSetFloat( "/radios/kr-87/inputs/volume", tmp );
-
-    // instrument panel pots
-    static bool first = true;
-    static int obs1[3], obs2[3], obs3[3], obs4[3], obs5[3], obs6[3];
-    static double diff1_ave = 0.0;
-    static double diff2_ave = 0.0;
-    static double diff3_ave = 0.0;
-    static double diff4_ave = 0.0;
-    static double diff5_ave = 0.0;
-    static double diff6_ave = 0.0;
-
-    if ( first ) {
-        first = false;
-        obs1[0] = obs1[1] = obs1[2] = analog_in_data[11];
-        obs2[0] = obs2[1] = obs2[2] = analog_in_data[28];
-        obs3[0] = obs3[1] = obs3[2] = analog_in_data[29];
-        obs4[0] = obs4[1] = obs4[2] = analog_in_data[30];
-        obs5[0] = obs5[1] = obs5[2] = analog_in_data[31];
-        obs6[0] = obs6[1] = obs6[2] = analog_in_data[14];
-    }
-
-    int diff1 = tony_magic( analog_in_data[11], obs1 );
-    int diff2 = tony_magic( analog_in_data[28], obs2 );
-    int diff3 = tony_magic( analog_in_data[29], obs3 );
-    int diff4 = tony_magic( analog_in_data[30], obs4 );
-    int diff5 = tony_magic( analog_in_data[31], obs5 );
-    int diff6 = tony_magic( analog_in_data[14], obs6 );
-
-    diff1_ave = instr_pot_filter( diff1_ave, diff1 );
-    diff2_ave = instr_pot_filter( diff2_ave, diff2 );
-    diff3_ave = instr_pot_filter( diff3_ave, diff3 );
-    diff4_ave = instr_pot_filter( diff4_ave, diff4 );
-    diff5_ave = instr_pot_filter( diff5_ave, diff5 );
-    diff6_ave = instr_pot_filter( diff6_ave, diff6 );
-
-    tmp = alt_press->getDoubleValue() + (diff1_ave * (0.25/888.0) );
-    if ( tmp < 27.9 ) { tmp = 27.9; }
-    if ( tmp > 31.4 ) { tmp = 31.4; }
-    fgSetFloat( "/instrumentation/altimeter/setting-inhg", tmp );
-
-    tmp = ati_bird->getDoubleValue() + (diff2_ave * (20.0/888.0) );
-    if ( tmp < -10.0 ) { tmp = -10.0; }
-    if ( tmp > 10.0 ) { tmp = 10.0; }
-    fgSetFloat( "/instrumentation/attitude-indicator/horizon-offset-deg", tmp );
-
-    tmp = nav1_obs->getDoubleValue() + (diff3_ave * (72.0/888.0) );
-    while ( tmp >= 360.0 ) { tmp -= 360.0; }
-    while ( tmp < 0.0 ) { tmp += 360.0; }
-    // cout << " obs = " << tmp << endl;
-    fgSetFloat( "/radios/nav[0]/radials/selected-deg", tmp );
-
-    tmp = nav2_obs->getDoubleValue() + (diff4_ave * (72.0/888.0) );
-    while ( tmp >= 360.0 ) { tmp -= 360.0; }
-    while ( tmp < 0.0 ) { tmp += 360.0; }
-    // cout << " obs = " << tmp << endl;
-    fgSetFloat( "/radios/nav[1]/radials/selected-deg", tmp );
-
-    tmp = adf_hdg->getDoubleValue() + (diff5_ave * (72.0/888.0) );
-    while ( tmp >= 360.0 ) { tmp -= 360.0; }
-    while ( tmp < 0.0 ) { tmp += 360.0; }
-    // cout << " obs = " << tmp << endl;
-    fgSetFloat( "/radios/kr-87/inputs/rotation-deg", tmp );
-
-    tmp = hdg_bug->getDoubleValue() + (diff6_ave * (72.0/888.0) );
-    while ( tmp >= 360.0 ) { tmp -= 360.0; }
-    while ( tmp < 0.0 ) { tmp += 360.0; }
-    // cout << " obs = " << tmp << endl;
-    fgSetFloat( "/autopilot/settings/heading-bug-deg", tmp );
-
-    return true;
-}
-
-
 /////////////////////////////////////////////////////////////////////
 // Write the lights
 /////////////////////////////////////////////////////////////////////
@@ -1749,224 +1405,22 @@ bool FGATC610x::do_steppers() {
 }
 
 
-/////////////////////////////////////////////////////////////////////
-// Read the switch positions
-/////////////////////////////////////////////////////////////////////
-
-// decode the packed switch data
-static void update_switch_matrix(
-        int board,
-       unsigned char switch_data[ATC_SWITCH_BYTES],
-       int switch_matrix[2][ATC_NUM_COLS][ATC_SWITCH_BYTES] )
-{
-    for ( int row = 0; row < ATC_SWITCH_BYTES; ++row ) {
-       unsigned char switches = switch_data[row];
-
-       for( int column = 0; column < ATC_NUM_COLS; ++column ) {
-           switch_matrix[board][column][row] = switches & 1;
-           switches = switches >> 1;
-       }                       
-    }
-}                     
-
-bool FGATC610x::do_switches() {
-    ATC610xReadSwitches( switches_fd, switch_data );
-
-    // unpack the switch data
-    int switch_matrix[2][ATC_NUM_COLS][ATC_SWITCH_BYTES];
-    update_switch_matrix( board, switch_data, switch_matrix );
-
-    // master switches
-#define CURT_HARDWARE
-#ifdef CURT_HARDWARE
-    fgSetBool( "/controls/engines/engine[0]/master-bat",
-               switch_matrix[board][5][1] );
-    fgSetBool( "/controls/engines/engine[1]/master-bat",
-               switch_matrix[board][5][1] );
-
-    fgSetBool( "/controls/engines/engine[0]/master-alt",
-               switch_matrix[board][4][1] );
-    fgSetBool( "/controls/engines/engine[1]/master-alt",
-               switch_matrix[board][4][1] );
-#else
-    fgSetBool( "/controls/engines/engine[0]/master-bat",
-               switch_matrix[board][4][1] );
-    fgSetBool( "/controls/engines/engine[1]/master-bat",
-               switch_matrix[board][4][1] );
-
-    fgSetBool( "/controls/engines/engine[0]/master-alt",
-               switch_matrix[board][5][1] );
-    fgSetBool( "/controls/engines/engine[1]/master-alt",
-               switch_matrix[board][5][1] );
-#endif
-
-    fgSetBool( "/controls/switches/master-avionics",
-               switch_matrix[board][0][3] );
-
-    if ( !ignore_flight_controls->getBoolValue() ) {
-        // magnetos and starter switch
-        int magnetos = 0;
-        bool starter = false;
-        if ( switch_matrix[board][3][1] == 1 ) {
-            magnetos = 3;
-            starter = true;
-        } else if ( switch_matrix[board][2][1] == 1 ) {
-            magnetos = 3;
-            starter = false;
-        } else if ( switch_matrix[board][1][1] == 1 ) {
-            magnetos = 2;
-            starter = false;
-        } else if ( switch_matrix[board][0][1] == 1 ) {
-            magnetos = 1;
-            starter = false;
-        } else {
-            magnetos = 0;
-            starter = false;
-        }
-
-        // do a bit of filtering on the magneto/starter switch and the
-        // flap lever because these are not well debounced in hardware
-        static int mag1, mag2, mag3;
-        mag3 = mag2;
-        mag2 = mag1;
-        mag1 = magnetos;
-        if ( mag1 == mag2 && mag2 == mag3 ) {
-            fgSetInt( "/controls/engines/engine[0]/magnetos", magnetos );
-            fgSetInt( "/controls/engines/engine[1]/magnetos", magnetos );
-        }
-        static bool start1, start2, start3;
-        start3 = start2;
-        start2 = start1;
-        start1 = starter;
-        if ( start1 == start2 && start2 == start3 ) {
-            fgSetBool( "/controls/engines/engine[0]/starter", starter );
-            fgSetBool( "/controls/engines/engine[1]/starter", starter );
-        }
-    }
-
-    // other toggle switches
-    fgSetBool( "/controls/engines/engine[0]/fuel-pump",
-               switch_matrix[board][0][2] );
-    fgSetBool( "/controls/engines/engine[1]/fuel-pump",
-               switch_matrix[board][0][2] );
-    fgSetBool( "/controls/switches/flashing-beacon",
-               switch_matrix[board][1][2] );
-    fgSetBool( "/controls/switches/landing-light", switch_matrix[board][2][2] );
-    fgSetBool( "/controls/switches/taxi-lights", switch_matrix[board][3][2] );
-    fgSetBool( "/controls/switches/nav-lights",
-               switch_matrix[board][4][2] );
-    fgSetBool( "/controls/switches/strobe-lights", switch_matrix[board][5][2] );
-    fgSetBool( "/controls/switches/pitot-heat", switch_matrix[board][6][2] );
-
-    // flaps
-    if ( !ignore_flight_controls->getBoolValue() ) {
-        float flaps = 0.0;
-        if ( switch_matrix[board][6][3] ) {
-            flaps = 1.0;
-        } else if ( switch_matrix[board][5][3] ) {
-            flaps = 2.0 / 3.0;
-        } else if ( switch_matrix[board][4][3] ) {
-            flaps = 1.0 / 3.0;
-        } else if ( !switch_matrix[board][4][3] ) {
-            flaps = 0.0;
-        }
-
-        // do a bit of filtering on the magneto/starter switch and the
-        // flap lever because these are not well debounced in hardware
-        static float flap1, flap2, flap3;
-        flap3 = flap2;
-        flap2 = flap1;
-        flap1 = flaps;
-        if ( flap1 == flap2 && flap2 == flap3 ) {
-            fgSetFloat( "/controls/flight/flaps", flaps );
-        }
-    }
-
-    // fuel selector (also filtered)
-    int fuel = 0;
-    if ( switch_matrix[board][2][3] ) {
-        // both
-        fuel = 3;
-    } else if ( switch_matrix[board][1][3] ) {
-        // left
-        fuel = 1;
-    } else if ( switch_matrix[board][3][3] ) {
-        // right
-        fuel = 2;
-    } else {
-        // fuel cutoff
-        fuel = 0;
-    }
-
-    const int max_fuel = 60;
-    static int fuel_list[max_fuel];
-    int i;
-    for ( i = max_fuel - 1; i >= 0; --i ) {
-      fuel_list[i+1] = fuel_list[i];
-    }
-    fuel_list[0] = fuel;
-    bool all_same = true;
-    for ( i = 0; i < max_fuel - 1; ++i ) {
-      if ( fuel_list[i] != fuel_list[i+1] ) {
-       all_same = false;
-      }
-    }
-    if ( all_same ) {
-        fgSetBool( "/controls/fuel/tank[0]/fuel_selector", (fuel & 0x01) > 0 );
-        fgSetBool( "/controls/fuel/tank[1]/fuel_selector", (fuel & 0x02) > 0 );
-    }
-
-    // circuit breakers
-#ifdef ATC_SUPPORT_CIRCUIT_BREAKERS_NOT_THE_DEFAULT
-    fgSetBool( "/controls/circuit-breakers/cabin-lights-pwr",
-               switch_matrix[board][0][0] );
-    fgSetBool( "/controls/circuit-breakers/instr-ignition-switch",
-               switch_matrix[board][1][0] );
-    fgSetBool( "/controls/circuit-breakers/flaps",
-               switch_matrix[board][2][0] );
-    fgSetBool( "/controls/circuit-breakers/avn-bus-1",
-               switch_matrix[board][3][0] );
-    fgSetBool( "/controls/circuit-breakers/avn-bus-2",
-               switch_matrix[board][4][0] );
-    fgSetBool( "/controls/circuit-breakers/turn-coordinator",
-               switch_matrix[board][5][0] );
-    fgSetBool( "/controls/circuit-breakers/instrument-lights",
-               switch_matrix[board][6][0] );
-    fgSetBool( "/controls/circuit-breakers/annunciators",
-               switch_matrix[board][7][0] );
-#else
-    fgSetBool( "/controls/circuit-breakers/cabin-lights-pwr", true );
-    fgSetBool( "/controls/circuit-breakers/instr-ignition-switch", true );
-    fgSetBool( "/controls/circuit-breakers/flaps", true );
-    fgSetBool( "/controls/circuit-breakers/avn-bus-1", true );
-    fgSetBool( "/controls/circuit-breakers/avn-bus-2", true );
-    fgSetBool( "/controls/circuit-breakers/turn-coordinator", true );
-    fgSetBool( "/controls/circuit-breakers/instrument-lights", true );
-    fgSetBool( "/controls/circuit-breakers/annunciators", true );
-#endif
-
-    if ( !ignore_flight_controls->getBoolValue() ) {
-        fgSetDouble( "/controls/gear/brake-parking",
-                     switch_matrix[board][7][3] );
-    }
-
-    fgSetDouble( "/radios/marker-beacon/power-btn",
-                 switch_matrix[board][6][1] );
-
-    return true;
-}
-
-
 bool FGATC610x::process() {
+    
     // Lock the hardware, skip if it's not ready yet
     if ( ATC610xLock( lock_fd ) > 0 ) {
 
-       do_analog_in();
+        if ( input0 != NULL ) {
+            input0->process();
+        }
+        if ( input1 != NULL ) {
+            input1->process();
+        }
+
        do_lights();
        do_radio_switches();
        do_radio_display();
        do_steppers();
-       do_switches();
        
        ATC610xRelease( lock_fd );
 
index cc57e4fca27ee05361e702a98efa4236d5334d20..21b519e1e1d17eed95b1331add3f8d0b82aa00ea 100644 (file)
 
 #include "protocol.hxx"
 
+#include "ATC-Inputs.hxx"
+
 
-#define ATC_ANAL_IN_VALUES 32
-#define ATC_ANAL_IN_BYTES (2 * ATC_ANAL_IN_VALUES)
 #define ATC_COMPASS_CH 5
 #define ATC_STEPPER_HOME 0xC0
 #define ATC_RADIO_DISPLAY_BYTES 48
-#define ATC_RADIO_SWITCH_BYTES 32
-#define ATC_SWITCH_BYTES 16
-#define ATC_NUM_COLS 8
 
 
 class FGATC610x : public FGProtocol {
 
-    bool use_rudder;
+    FGATCInput *input0;         // board0 input interface class
+    FGATCInput *input1;         // board1 input interface class
+
+    SGPath input0_path;
+    SGPath input1_path;
+    SGPath output0_path;
+    SGPath output1_path;
 
     int board;
 
     int lock_fd;
-    int analog_in_fd;
     int lamps_fd;
     int radios_fd;
     int stepper_fd;
-    int switches_fd;
 
     char lock_file[256];
-    char analog_in_file[256];
     char lamps_file[256];
     char radios_file[256];
     char stepper_file[256];
-    char switches_file[256];
 
-    unsigned char analog_in_bytes[ATC_ANAL_IN_BYTES];
-    int analog_in_data[ATC_ANAL_IN_VALUES];
     unsigned char radio_display_data[ATC_RADIO_DISPLAY_BYTES];
     unsigned char radio_switch_data[ATC_RADIO_SWITCH_BYTES];
-    unsigned char switch_data[ATC_SWITCH_BYTES];
 
     float compass_position;
 
@@ -122,12 +118,10 @@ class FGATC610x : public FGProtocol {
 
     int dme_switch;
 
-    bool do_analog_in();
     bool do_lights();
     bool do_radio_switches();
     bool do_radio_display();
     bool do_steppers();
-    bool do_switches();
 
     // convenience
     inline bool adf_has_power() const {
@@ -153,17 +147,37 @@ class FGATC610x : public FGProtocol {
 
 public:
 
-    FGATC610x() : use_rudder(true) { }
-    ~FGATC610x() { }
+    FGATC610x() :
+        input0(NULL),
+        input1(NULL),
+        input0_path(""),
+        input1_path(""),
+        output0_path(""),
+        output1_path("")
+    { }
+
+    ~FGATC610x() {
+        delete input0;
+        delete input1;
+    }
 
+    // Open and initialize ATC 610x hardware
     bool open();
+
     void init_config();
 
     bool process();
 
     bool close();
 
-    inline void set_use_rudder( bool value ) { use_rudder = value; }
+    inline void set_path_names( const SGPath &in0, const SGPath &in1,
+                                const SGPath &out0, const SGPath &out1 )
+    {
+        input0_path = in0;
+        input1_path = in1;
+        output0_path = out0;
+        output1_path = out1;
+    }
 };