284 lines
7.3 KiB
C++
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;
|
|
}
|