1
0
Fork 0

Begin work on revamping the ATC hardware interface so it is infinitely more

configurable.
This commit is contained in:
curt 2004-11-16 19:47:11 +00:00
parent 9a8eaae03d
commit 2eeddb8c9f
7 changed files with 1048 additions and 592 deletions

View file

@ -106,15 +106,21 @@ FGIO::parse_port_config( const string& config )
try try
{ {
if ( protocol == "atc610x" ) { if ( protocol == "atcsim" ) {
FGATC610x *atc610x = new FGATC610x; FGATC610x *atcsim = new FGATC610x;
atc610x->set_hz( 30 ); atcsim->set_hz( 30 );
if ( tokens.size() > 1 ) { if ( tokens.size() != 6 ) {
if ( tokens[1] == "no-rudder" ) { SG_LOG( SG_IO, SG_ALERT, "Usage: --atcsim=[no-]pedals,"
atc610x->set_use_rudder( false ); << "input0_config,input1_config,"
<< "output0_config,output1_config" );
} }
if ( tokens[1] == "no-pedals" ) {
fgSetBool( "/input/atcsim/ignore-pedal-controls", true );
} else {
fgSetBool( "/input/atcsim/ignore-pedal-controls", false );
} }
return atc610x; atcsim->set_path_names(tokens[2], tokens[3], tokens[4], tokens[5]);
return atcsim;
} else if ( protocol == "atlas" ) { } else if ( protocol == "atlas" ) {
FGAtlas *atlas = new FGAtlas; FGAtlas *atlas = new FGAtlas;
io = atlas; io = atlas;

View file

@ -1286,7 +1286,7 @@ struct OptionDesc {
{"start-date-gmt", true, OPTION_FUNC, "", false, "", fgOptStartDateGmt }, {"start-date-gmt", true, OPTION_FUNC, "", false, "", fgOptStartDateGmt },
{"hud-tris", false, OPTION_STRING, "/sim/hud/frame-stat-type", false, "tris", 0 }, {"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 }, {"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 }, {"atlas", true, OPTION_CHANNEL, "", false, "", 0 },
{"httpd", true, OPTION_CHANNEL, "", false, "", 0 }, {"httpd", true, OPTION_CHANNEL, "", false, "", 0 },
#ifdef FG_JPEG_SERVER #ifdef FG_JPEG_SERVER

885
src/Network/ATC-Inputs.cxx Normal file
View file

@ -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->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;
}

View file

@ -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

View file

@ -17,6 +17,7 @@ endif
libNetwork_a_SOURCES = \ libNetwork_a_SOURCES = \
protocol.cxx protocol.hxx \ protocol.cxx protocol.hxx \
ATC-Inputs.cxx ATC-Inputs.hxx \
atc610x.cxx atc610x.hxx \ atc610x.cxx atc610x.hxx \
atlas.cxx atlas.hxx \ atlas.cxx atlas.hxx \
garmin.cxx garmin.hxx \ garmin.cxx garmin.hxx \

View 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 // Write a radios command
static int ATC610xSetRadios( int fd, static int ATC610xSetRadios( int fd,
unsigned char data[ATC_RADIO_DISPLAY_BYTES] ) 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 // Turn a lamp on or off
void ATC610xSetLamp( int fd, int channel, bool value ) { void ATC610xSetLamp( int fd, int channel, bool value ) {
// lamp channels 0-63 are written to LampPort0, channels 64-127 // lamp channels 0-63 are written to LampPort0, channels 64-127
@ -227,11 +201,20 @@ bool FGATC610x::open() {
return false; return false;
} }
SG_LOG( SG_IO, SG_ALERT,
"Initializing ATC 610x hardware, please wait ..." );
// This loads the config parameters generated by "simcal" // This loads the config parameters generated by "simcal"
init_config(); init_config();
SG_LOG( SG_IO, SG_ALERT, if ( input0_path.str().length() ) {
"Initializing ATC 610x hardware, please wait ..." ); 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_hz( 30 ); // default to processing requests @ 30Hz
set_enabled( true ); set_enabled( true );
@ -239,11 +222,9 @@ bool FGATC610x::open() {
board = 0; // 610x uses a single board number = 0 board = 0; // 610x uses a single board number = 0
snprintf( lock_file, 256, "/proc/atc610x/board%d/lock", board ); 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( lamps_file, 256, "/proc/atc610x/board%d/lamps", board );
snprintf( radios_file, 256, "/proc/atc610x/board%d/radios", board ); snprintf( radios_file, 256, "/proc/atc610x/board%d/radios", board );
snprintf( stepper_file, 256, "/proc/atc610x/board%d/steppers", 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 // Open the /proc files
@ -258,15 +239,6 @@ bool FGATC610x::open() {
exit( -1 ); 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 ); lamps_fd = ::open( lamps_file, O_WRONLY );
if ( lamps_fd == -1 ) { if ( lamps_fd == -1 ) {
SG_LOG( SG_IO, SG_ALERT, "errno = " << errno ); SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
@ -294,14 +266,6 @@ bool FGATC610x::open() {
exit( -1 ); 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 // 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 // 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() { bool FGATC610x::process() {
// Lock the hardware, skip if it's not ready yet // Lock the hardware, skip if it's not ready yet
if ( ATC610xLock( lock_fd ) > 0 ) { if ( ATC610xLock( lock_fd ) > 0 ) {
do_analog_in(); if ( input0 != NULL ) {
input0->process();
}
if ( input1 != NULL ) {
input1->process();
}
do_lights(); do_lights();
do_radio_switches(); do_radio_switches();
do_radio_display(); do_radio_display();
do_steppers(); do_steppers();
do_switches();
ATC610xRelease( lock_fd ); ATC610xRelease( lock_fd );

View file

@ -34,42 +34,38 @@
#include "protocol.hxx" #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_COMPASS_CH 5
#define ATC_STEPPER_HOME 0xC0 #define ATC_STEPPER_HOME 0xC0
#define ATC_RADIO_DISPLAY_BYTES 48 #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 { 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 board;
int lock_fd; int lock_fd;
int analog_in_fd;
int lamps_fd; int lamps_fd;
int radios_fd; int radios_fd;
int stepper_fd; int stepper_fd;
int switches_fd;
char lock_file[256]; char lock_file[256];
char analog_in_file[256];
char lamps_file[256]; char lamps_file[256];
char radios_file[256]; char radios_file[256];
char stepper_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_display_data[ATC_RADIO_DISPLAY_BYTES];
unsigned char radio_switch_data[ATC_RADIO_SWITCH_BYTES]; unsigned char radio_switch_data[ATC_RADIO_SWITCH_BYTES];
unsigned char switch_data[ATC_SWITCH_BYTES];
float compass_position; float compass_position;
@ -122,12 +118,10 @@ class FGATC610x : public FGProtocol {
int dme_switch; int dme_switch;
bool do_analog_in();
bool do_lights(); bool do_lights();
bool do_radio_switches(); bool do_radio_switches();
bool do_radio_display(); bool do_radio_display();
bool do_steppers(); bool do_steppers();
bool do_switches();
// convenience // convenience
inline bool adf_has_power() const { inline bool adf_has_power() const {
@ -153,17 +147,37 @@ class FGATC610x : public FGProtocol {
public: 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(); bool open();
void init_config(); void init_config();
bool process(); bool process();
bool close(); 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;
}
}; };