Add analog output support to the ATC hardware interface.
This commit is contained in:
parent
4b5353d396
commit
67c4eec677
2 changed files with 133 additions and 5 deletions
|
@ -97,6 +97,7 @@ static int ATCRelease( int fd ) {
|
|||
// specifies the location of the output config file (xml)
|
||||
FGATCOutput::FGATCOutput( const int _board, const SGPath &_config_file ) :
|
||||
is_open(false),
|
||||
analog_out_node(NULL),
|
||||
lamps_out_node(NULL),
|
||||
radio_display_node(NULL),
|
||||
steppers_node(NULL)
|
||||
|
@ -106,6 +107,27 @@ FGATCOutput::FGATCOutput( const int _board, const SGPath &_config_file ) :
|
|||
}
|
||||
|
||||
|
||||
// Write analog out data
|
||||
static int ATCSetAnalogOut( int fd,
|
||||
unsigned char data[ATC_ANALOG_OUT_CHANNELS*2] )
|
||||
{
|
||||
#if defined( unix ) || defined( __CYGWIN__ )
|
||||
// rewind
|
||||
lseek( fd, 0, SEEK_SET );
|
||||
|
||||
int result = write( fd, data, ATC_ANALOG_OUT_CHANNELS*2 );
|
||||
|
||||
if ( result != ATC_ANALOG_OUT_CHANNELS*2 ) {
|
||||
SG_LOG( SG_IO, SG_DEBUG, "Write failed" );
|
||||
}
|
||||
|
||||
return result;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Write a radios command
|
||||
static int ATCSetRadios( int fd, unsigned char data[ATC_RADIO_DISPLAY_BYTES] ) {
|
||||
#if defined( unix ) || defined( __CYGWIN__ )
|
||||
|
@ -232,6 +254,8 @@ bool FGATCOutput::open( int lock_fd ) {
|
|||
SG_LOG( SG_IO, SG_ALERT,
|
||||
"Initializing ATC output hardware, please wait ..." );
|
||||
|
||||
snprintf( analog_out_file, 256,
|
||||
"/proc/atcflightsim/board%d/analog_out", board );
|
||||
snprintf( lamps_file, 256,
|
||||
"/proc/atcflightsim/board%d/lamps", board );
|
||||
snprintf( radio_display_file, 256,
|
||||
|
@ -245,6 +269,15 @@ bool FGATCOutput::open( int lock_fd ) {
|
|||
// Open the /proc files
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
analog_out_fd = ::open( analog_out_file, O_WRONLY );
|
||||
if ( analog_out_fd == -1 ) {
|
||||
SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
|
||||
char msg[256];
|
||||
snprintf( msg, 256, "Error opening %s", analog_out_file );
|
||||
perror( msg );
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
lamps_fd = ::open( lamps_file, O_WRONLY );
|
||||
if ( lamps_fd == -1 ) {
|
||||
SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
|
||||
|
@ -327,6 +360,23 @@ bool FGATCOutput::open( int lock_fd ) {
|
|||
compass_position = 0.0;
|
||||
#endif
|
||||
|
||||
// Lock the hardware, keep trying until we succeed
|
||||
while ( ATCLock( lock_fd ) <= 0 );
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Zero the analog outputs
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
SG_LOG( SG_IO, SG_ALERT,
|
||||
" - Zeroing Analog Outputs." );
|
||||
|
||||
for ( int channel = 0; channel < ATC_ANALOG_OUT_CHANNELS; ++channel ) {
|
||||
analog_out_data[2*channel] = 0;
|
||||
analog_out_data[2*channel + 1] = 0;
|
||||
}
|
||||
ATCSetAnalogOut( analog_out_fd, analog_out_data );
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Blank the radio display
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
@ -339,11 +389,6 @@ bool FGATCOutput::open( int lock_fd ) {
|
|||
for ( int channel = 0; channel < ATC_RADIO_DISPLAY_BYTES; ++channel ) {
|
||||
radio_display_data[channel] = value;
|
||||
}
|
||||
|
||||
// Lock the hardware, keep trying until we succeed
|
||||
while ( ATCLock( lock_fd ) <= 0 );
|
||||
|
||||
// Set radio display
|
||||
ATCSetRadios( radio_display_fd, radio_display_data );
|
||||
|
||||
ATCRelease( lock_fd );
|
||||
|
@ -371,6 +416,9 @@ bool FGATCOutput::open( int lock_fd ) {
|
|||
|
||||
char base_name[256];
|
||||
|
||||
snprintf( base_name, 256, "/output/atc-board[%d]/analog-outputs", board );
|
||||
analog_out_node = fgGetNode( base_name );
|
||||
|
||||
snprintf( base_name, 256, "/output/atc-board[%d]/lamps", board );
|
||||
lamps_out_node = fgGetNode( base_name );
|
||||
|
||||
|
@ -384,6 +432,79 @@ bool FGATCOutput::open( int lock_fd ) {
|
|||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Write the lanalog outputs
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool FGATCOutput::do_analog_out() {
|
||||
if ( analog_out_node != NULL ) {
|
||||
for ( int i = 0; i < analog_out_node->nChildren(); ++i ) {
|
||||
// read the next config entry from the property tree
|
||||
|
||||
SGPropertyNode *child = analog_out_node->getChild(i);
|
||||
string cname = child->getName();
|
||||
int index = child->getIndex();
|
||||
string name = "";
|
||||
string type = "";
|
||||
SGPropertyNode *src_prop = NULL;
|
||||
double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0;
|
||||
if ( cname == "analog-out" ) {
|
||||
SGPropertyNode *prop;
|
||||
prop = child->getChild( "name" );
|
||||
if ( prop != NULL ) {
|
||||
name = prop->getStringValue();
|
||||
}
|
||||
prop = child->getChild( "type" );
|
||||
if ( prop != NULL ) {
|
||||
type = prop->getStringValue();
|
||||
}
|
||||
prop = child->getChild( "prop" );
|
||||
if ( prop != NULL ) {
|
||||
src_prop = fgGetNode( prop->getStringValue(), true );
|
||||
}
|
||||
prop = child->getChild( "value-lo" );
|
||||
if ( prop != NULL ) {
|
||||
prop = fgGetNode( prop->getStringValue(), true );
|
||||
x0 = prop->getDoubleValue();
|
||||
}
|
||||
prop = child->getChild( "meter-lo" );
|
||||
if ( prop != NULL ) {
|
||||
prop = fgGetNode( prop->getStringValue(), true );
|
||||
y0 = prop->getDoubleValue();
|
||||
}
|
||||
prop = child->getChild( "value-hi" );
|
||||
if ( prop != NULL ) {
|
||||
prop = fgGetNode( prop->getStringValue(), true );
|
||||
x1 = prop->getDoubleValue();
|
||||
}
|
||||
prop = child->getChild( "meter-hi" );
|
||||
if ( prop != NULL ) {
|
||||
prop = fgGetNode( prop->getStringValue(), true );
|
||||
y1 = prop->getDoubleValue();
|
||||
}
|
||||
// crunch linear interpolation formula
|
||||
double dx = x1 - x0;
|
||||
double dy = y1 - y0;
|
||||
double slope = dy / dx;
|
||||
double value = src_prop->getDoubleValue();
|
||||
int meter = (value - x0) * slope + y0;
|
||||
if ( meter < 0 ) { meter = 0; }
|
||||
if ( meter > 1023 ) { meter = 1023; }
|
||||
analog_out_data[2*index] = meter / 256;
|
||||
analog_out_data[2*index + 1] = meter - analog_out_data[2*index] * 256;
|
||||
} else {
|
||||
SG_LOG( SG_IO, SG_DEBUG,
|
||||
"Input config error, expecting 'analog-out' but found "
|
||||
<< cname );
|
||||
}
|
||||
ATCSetAnalogOut( analog_out_fd, analog_out_data );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Write the lights
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
@ -936,6 +1057,7 @@ bool FGATCOutput::process() {
|
|||
return false;
|
||||
}
|
||||
|
||||
do_analog_out();
|
||||
do_lamps();
|
||||
do_radio_display();
|
||||
#ifdef ATCFLIGHTSIM_HAVE_COMPASS
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <Main/fg_props.hxx>
|
||||
|
||||
#define ATC_RADIO_DISPLAY_BYTES 48
|
||||
#define ATC_ANALOG_OUT_CHANNELS 48
|
||||
#define ATC_COMPASS_CH 5
|
||||
#define ATC_STEPPER_HOME 0xC0
|
||||
|
||||
|
@ -43,21 +44,26 @@ class FGATCOutput {
|
|||
SGPath config;
|
||||
|
||||
int lock_fd;
|
||||
int analog_out_fd;
|
||||
int lamps_fd;
|
||||
int radio_display_fd;
|
||||
int stepper_fd;
|
||||
|
||||
char analog_out_file[256];
|
||||
char lamps_file[256];
|
||||
char radio_display_file[256];
|
||||
char stepper_file[256];
|
||||
|
||||
unsigned char analog_out_data[ATC_ANALOG_OUT_CHANNELS*2];
|
||||
unsigned char radio_display_data[ATC_RADIO_DISPLAY_BYTES];
|
||||
|
||||
SGPropertyNode_ptr analog_out_node;
|
||||
SGPropertyNode_ptr lamps_out_node;
|
||||
SGPropertyNode_ptr radio_display_node;
|
||||
SGPropertyNode_ptr steppers_node;
|
||||
|
||||
void init_config();
|
||||
bool do_analog_out();
|
||||
bool do_lamps();
|
||||
bool do_radio_display();
|
||||
bool do_steppers();
|
||||
|
|
Loading…
Reference in a new issue