// 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 #endif #include #include // atoi() atof() abs() #include #include #include #include //snprintf #if defined( _MSC_VER ) || defined(__MINGW32__) # include //lseek, read, write #endif #include STL_STRING #include #include #include #include #include #include #include #include
#include
#include "ATC-Main.hxx" SG_USING_STD(string); // 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 char *envp = ::getenv( "HOME" ); if ( envp != NULL ) { SGPath atcsim_config( envp ); atcsim_config.append( ".fgfs-atc610x.xml" ); readProperties( atcsim_config.str(), globals->get_props() ); } #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.str().length() ) { input0 = new FGATCInput( 0, input0_path ); input0->open(); } if ( input1_path.str().length() ) { input1 = new FGATCInput( 1, input1_path ); input1->open(); } if ( output0_path.str().length() ) { output0 = new FGATCOutput( 0, output0_path ); output0->open( lock0_fd ); } if ( output1_path.str().length() ) { 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_GENERAL, 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; }