1
0
Fork 0
flightgear/src/Network/ATC-Main.cxx
2016-07-01 04:54:29 -05:00

284 lines
7.3 KiB
C++

// ATC-Main.cxx -- FGFS interface to ATC hardware
//
// Written by Curtis Olson, started January 2002
//
// Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <simgear/compiler.h>
#include <stdlib.h> // atoi() atof() abs()
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h> //snprintf
#ifdef _WIN32
# include <io.h> //lseek, read, write
#endif
#include <string>
#include <simgear/debug/logstream.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/io/iochannel.hxx>
#include <simgear/math/sg_types.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/structure/exception.hxx>
#include <Scripting/NasalSys.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include "ATC-Main.hxx"
using std::string;
using std::cout;
using std::endl;
using std::vector;
// Lock the ATC hardware
static int fgATCMainLock( int fd ) {
// rewind
lseek( fd, 0, SEEK_SET );
char tmp[2];
int result = read( fd, tmp, 1 );
if ( result != 1 ) {
SG_LOG( SG_IO, SG_DEBUG, "Lock failed" );
}
return result;
}
// Write a radios command
static int fgATCMainRelease( int fd ) {
// rewind
lseek( fd, 0, SEEK_SET );
char tmp[2];
tmp[0] = tmp[1] = 0;
int result = write( fd, tmp, 1 );
if ( result != 1 ) {
SG_LOG( SG_IO, SG_DEBUG, "Release failed" );
}
return result;
}
void FGATCMain::init_config() {
#if defined( unix ) || defined( __CYGWIN__ )
// Next check home directory for .fgfsrc.hostname file
SGPath atcsim_config = SGPath::home();
atcsim_config.append( ".fgfs-atc610x.xml" );
try {
SG_LOG(SG_NETWORK, SG_ALERT,
"Warning: loading deprecated config file: " << atcsim_config);
readProperties( atcsim_config, globals->get_props() );
} catch (const sg_exception &e) {
// fail silently, this is an old style config file I want to continue
// to support if it exists.
}
#endif
}
// Open and initialize ATC hardware
bool FGATCMain::open() {
if ( is_enabled() ) {
SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
<< "is already in use, ignoring" );
return false;
}
SG_LOG( SG_IO, SG_ALERT,
"Initializing ATC hardware, please wait ..." );
// This loads the config parameters generated by "simcal"
init_config();
/////////////////////////////////////////////////////////////////////
// Open the /proc files
/////////////////////////////////////////////////////////////////////
string lock0_file = "/proc/atcflightsim/board0/lock";
string lock1_file = "/proc/atcflightsim/board1/lock";
lock0_fd = ::open( lock0_file.c_str(), O_RDWR );
if ( lock0_fd == -1 ) {
SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
char msg[256];
snprintf( msg, 256, "Error opening %s", lock0_file.c_str() );
perror( msg );
exit( -1 );
}
lock1_fd = ::open( lock1_file.c_str(), O_RDWR );
if ( lock1_fd == -1 ) {
SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
char msg[256];
snprintf( msg, 256, "Error opening %s", lock1_file.c_str() );
perror( msg );
exit( -1 );
}
if ( !input0_path.isNull() ) {
input0 = new FGATCInput( 0, input0_path );
input0->open();
}
if ( !input1_path.isNull() ) {
input1 = new FGATCInput( 1, input1_path );
input1->open();
}
if ( !output0_path.isNull() ) {
output0 = new FGATCOutput( 0, output0_path );
output0->open( lock0_fd );
}
if ( !output1_path.isNull() ) {
output1 = new FGATCOutput( 1, output1_path );
output1->open( lock1_fd );
}
set_hz( 30 ); // default to processing requests @ 30Hz
set_enabled( true );
/////////////////////////////////////////////////////////////////////
// Finished initing hardware
/////////////////////////////////////////////////////////////////////
SG_LOG( SG_IO, SG_ALERT,
"Done initializing ATC hardware." );
return true;
}
bool FGATCMain::process() {
// cout << "Main::process()\n";
bool board0_locked = false;
bool board1_locked = false;
if ( input0 != NULL || output0 != NULL ) {
// Lock board0 if we have a configuration for it
if ( fgATCMainLock( lock0_fd ) > 0 ) {
board0_locked = true;
}
}
if ( input1 != NULL || output1 != NULL ) {
// Lock board1 if we have a configuration for it
if ( fgATCMainLock( lock1_fd ) > 0 ) {
board1_locked = true;
}
}
// cout << " locks: ";
// if ( board0_locked ) { cout << "board0 "; }
// if ( board1_locked ) { cout << "board1 "; }
// cout << endl;
// process the ATC inputs
if ( input0 != NULL && board0_locked ) {
input0->process();
}
if ( input1 != NULL && board1_locked ) {
input1->process();
}
// run our custom nasal script. This is a layer above the raw
// hardware inputs. It handles situations where there isn't a
// direct 1-1 linear mapping between ATC functionality and FG
// functionality, and handles situations where FG expects more
// functionality from the interface than the ATC hardware can
// directly provide.
FGNasalSys *n = (FGNasalSys*)globals->get_subsystem("nasal");
bool result = n->parseAndRun( "atcsim.update()" );
if ( !result ) {
SG_LOG( SG_NETWORK, SG_ALERT, "Nasal: atcsim.update() failed!" );
}
// process the ATC outputs
if ( output0 != NULL && board0_locked ) {
output0->process();
}
if ( output1 != NULL && board1_locked ) {
output1->process();
}
if ( board0_locked ) {
fgATCMainRelease( lock0_fd );
}
if ( board1_locked ) {
fgATCMainRelease( lock1_fd );
}
return true;
}
bool FGATCMain::close() {
cout << "FGATCMain::close()" << endl;
int result;
if ( input0 != NULL ) {
input0->close();
}
if ( input1 != NULL ) {
input1->close();
}
if ( output0 != NULL ) {
output0->close();
}
if ( output1 != NULL ) {
output1->close();
}
result = ::close( lock0_fd );
if ( result == -1 ) {
SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
char msg[256];
snprintf( msg, 256, "Error closing lock0_fd" );
perror( msg );
exit( -1 );
}
result = ::close( lock1_fd );
if ( result == -1 ) {
SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
char msg[256];
snprintf( msg, 256, "Error closing lock1_fd" );
perror( msg );
exit( -1 );
}
return true;
}