diff --git a/src/Main/fg_io.cxx b/src/Main/fg_io.cxx index d898baec4..ab6f34b2c 100644 --- a/src/Main/fg_io.cxx +++ b/src/Main/fg_io.cxx @@ -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; diff --git a/src/Main/options.cxx b/src/Main/options.cxx index e4e33c779..aef5b0577 100644 --- a/src/Main/options.cxx +++ b/src/Main/options.cxx @@ -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 index 000000000..b43f1e18b --- /dev/null +++ b/src/Network/ATC-Inputs.cxx @@ -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 +#endif + +#include + +#include STL_STRING + +#include + +#include
+ +#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 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->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 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 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 index 000000000..146d7c858 --- /dev/null +++ b/src/Network/ATC-Inputs.hxx @@ -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 +#endif + +#include
+ +#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 diff --git a/src/Network/Makefile.am b/src/Network/Makefile.am index ccf643273..d4fa7dc7c 100644 --- a/src/Network/Makefile.am +++ b/src/Network/Makefile.am @@ -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 \ diff --git a/src/Network/atc610x.cxx b/src/Network/atc610x.cxx index 0f164ddf6..9d71e176a 100644 --- a/src/Network/atc610x.cxx +++ b/src/Network/atc610x.cxx @@ -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 ); diff --git a/src/Network/atc610x.hxx b/src/Network/atc610x.hxx index cc57e4fca..21b519e1e 100644 --- a/src/Network/atc610x.hxx +++ b/src/Network/atc610x.hxx @@ -34,42 +34,38 @@ #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; + } };