From: curt Date: Fri, 24 Dec 2004 01:23:27 +0000 (+0000) Subject: More work on the ATC FS hardware interface. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=ec827732226e905a8a0ce9af700b63b183b18c5c;p=flightgear.git More work on the ATC FS hardware interface. --- diff --git a/src/Network/ATC-Main.cxx b/src/Network/ATC-Main.cxx new file mode 100644 index 000000000..45f491d36 --- /dev/null +++ b/src/Network/ATC-Main.cxx @@ -0,0 +1,243 @@ +// 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., 675 Mass Ave, Cambridge, MA 02139, 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/atc610x/board0/lock"; + string lock1_file = "/proc/atc610x/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() { + // Lock the hardware, skip if it's not ready yet + if ( fgATCMainLock( lock0_fd ) <= 0 ) { + return false; + } + if ( fgATCMainLock( lock1_fd ) <= 0 ) { + // lock0 will be locked here, so release before we return + fgATCMainRelease( lock0_fd ); + return false; + } + + // process the ATC inputs + if ( input0 != NULL ) { + input0->process(); + } + if ( input1 != NULL ) { + 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.do_hardware()" ); + if ( !result ) { + SG_LOG( SG_GENERAL, SG_ALERT, + "Nasal: atcsim.do_hardware() failed!" ); + } + + // process the ATC outputs + if ( output0 != NULL ) { + output0->process(); + } + if ( output1 != NULL ) { + output1->process(); + } + + fgATCMainRelease( lock0_fd ); + fgATCMainRelease( lock1_fd ); + + return true; +} + + +bool FGATCMain::close() { + int result; + + 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; +} diff --git a/src/Network/ATC-Main.hxx b/src/Network/ATC-Main.hxx new file mode 100644 index 000000000..b6f4598a9 --- /dev/null +++ b/src/Network/ATC-Main.hxx @@ -0,0 +1,98 @@ +// ATC-Main.hxx -- FGFS interface to ATC 610x 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., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + + +#ifndef _FG_ATC_MAIN_HXX +#define _FG_ATC_MAIN_HXX + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include
+ +#include "protocol.hxx" + +#include "ATC-Inputs.hxx" +#include "ATC-Outputs.hxx" + + +class FGATCMain : public FGProtocol { + + FGATCInput *input0; // board0 input interface class + FGATCInput *input1; // board1 input interface class + FGATCOutput *output0; // board0 output interface class + FGATCOutput *output1; // board1 output interface class + + SGPath input0_path; + SGPath input1_path; + SGPath output0_path; + SGPath output1_path; + + int board; + + int lock0_fd; + int lock1_fd; + +public: + + FGATCMain() : + input0(NULL), + input1(NULL), + output0(NULL), + output1(NULL), + input0_path(""), + input1_path(""), + output0_path(""), + output1_path("") + { } + + ~FGATCMain() { + delete input0; + delete input1; + delete output0; + delete output1; + } + + // Open and initialize ATC 610x hardware + bool open(); + + void init_config(); + + bool process(); + + bool close(); + + 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; + } +}; + + +#endif // _FG_ATC_MAIN_HXX diff --git a/src/Network/ATC-Outputs.cxx b/src/Network/ATC-Outputs.cxx new file mode 100644 index 000000000..b73637f80 --- /dev/null +++ b/src/Network/ATC-Outputs.cxx @@ -0,0 +1,950 @@ +// ATC-Outputs.hxx -- Translate FGFS properties to ATC hardware outputs. +// +// 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 +#endif + +#include + +#if defined( unix ) || defined( __CYGWIN__ ) +# include +# include +# include +#endif + +#include STL_STRING + +#include + +#include
+ +#include "ATC-Outputs.hxx" + +SG_USING_STD(string); + + + +// Lock the ATC hardware +static int ATCLock( 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; +} + + +// Release the ATC hardware +static int ATCRelease( 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; +} + + +// Constructor: The _board parameter specifies which board to +// reference. Possible values are 0 or 1. The _config_file parameter +// specifies the location of the output config file (xml) +FGATCOutput::FGATCOutput( const int _board, const SGPath &_config_file ) : + is_open(false), + lamps_out_node(NULL), + radio_display_node(NULL), + steppers_node(NULL) +{ + board = _board; + config = _config_file; +} + + +// Write a radios command +static int ATCSetRadios( int fd, unsigned char data[ATC_RADIO_DISPLAY_BYTES] ) { + // rewind + lseek( fd, 0, SEEK_SET ); + + int result = write( fd, data, ATC_RADIO_DISPLAY_BYTES ); + + if ( result != ATC_RADIO_DISPLAY_BYTES ) { + SG_LOG( SG_IO, SG_DEBUG, "Write failed" ); + } + + return result; +} + + +// Write a stepper command +static int ATCSetStepper( int fd, unsigned char channel, + unsigned char value ) +{ + // rewind + lseek( fd, 0, SEEK_SET ); + + // Write the value + unsigned char buf[3]; + buf[0] = channel; + buf[1] = value; + buf[2] = 0; + int result = write( fd, buf, 2 ); + if ( result != 2 ) { + SG_LOG( SG_IO, SG_INFO, "Write failed" ); + } + SG_LOG( SG_IO, SG_DEBUG, + "Sent cmd = " << (int)channel << " value = " << (int)value ); + return result; +} + + +// Read status of last stepper written to +static unsigned char ATCReadStepper( int fd ) { + int result; + + // rewind + lseek( fd, 0, SEEK_SET ); + + // Write the value + unsigned char buf[2]; + result = read( fd, buf, 1 ); + if ( result != 1 ) { + SG_LOG( SG_IO, SG_ALERT, "Read failed" ); + exit( -1 ); + } + SG_LOG( SG_IO, SG_DEBUG, "Read result = " << (int)buf[0] ); + + return buf[0]; +} + + +// Turn a lamp on or off +void ATCSetLamp( int fd, int channel, bool value ) { + // lamp channels 0-63 are written to LampPort0, channels 64-127 + // are written to LampPort1 + + // bits 0-6 are the lamp address + // bit 7 is the value (on/off) + + int result; + + // Write the value + unsigned char buf[3]; + buf[0] = channel; + buf[1] = value; + buf[2] = 0; + result = write( fd, buf, 2 ); + if ( result != 2 ) { + SG_LOG( SG_IO, SG_ALERT, "Write failed" ); + exit( -1 ); + } +} + + +void FGATCOutput::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 FGATCOutput::open( int lock_fd ) { + if ( is_open ) { + SG_LOG( SG_IO, SG_ALERT, "This board is already open for output! " + << board ); + return false; + } + + // This loads the config parameters generated by "simcal" + init_config(); + + SG_LOG( SG_IO, SG_ALERT, + "Initializing ATC hardware, please wait ..." ); + + snprintf( lamps_file, 256, "/proc/atc610x/board%d/lamps", board ); + snprintf( radio_display_file, 256, "/proc/atc610x/board%d/radios", board ); + snprintf( stepper_file, 256, "/proc/atc610x/board%d/steppers", board ); + +#if defined( unix ) || defined( __CYGWIN__ ) + + ///////////////////////////////////////////////////////////////////// + // Open the /proc files + ///////////////////////////////////////////////////////////////////// + + lamps_fd = ::open( lamps_file, O_WRONLY ); + if ( lamps_fd == -1 ) { + SG_LOG( SG_IO, SG_ALERT, "errno = " << errno ); + char msg[256]; + snprintf( msg, 256, "Error opening %s", lamps_file ); + perror( msg ); + exit( -1 ); + } + + radio_display_fd = ::open( radio_display_file, O_RDWR ); + if ( radio_display_fd == -1 ) { + SG_LOG( SG_IO, SG_ALERT, "errno = " << errno ); + char msg[256]; + snprintf( msg, 256, "Error opening %s", radio_display_file ); + perror( msg ); + exit( -1 ); + } + + stepper_fd = ::open( stepper_file, O_RDWR ); + if ( stepper_fd == -1 ) { + SG_LOG( SG_IO, SG_ALERT, "errno = " << errno ); + char msg[256]; + snprintf( msg, 256, "Error opening %s", stepper_file ); + perror( msg ); + exit( -1 ); + } + +#endif + + ///////////////////////////////////////////////////////////////////// + // Home the compass stepper motor + ///////////////////////////////////////////////////////////////////// + + SG_LOG( SG_IO, SG_ALERT, + " - Homing the compass stepper motor" ); + + // Lock the hardware, keep trying until we succeed + while ( ATCLock( lock_fd ) <= 0 ); + + // Send the stepper home command + ATCSetStepper( stepper_fd, ATC_COMPASS_CH, ATC_STEPPER_HOME ); + + // Release the hardware + ATCRelease( lock_fd ); + + SG_LOG( SG_IO, SG_ALERT, + " - Waiting for compass to come home." ); + + bool home = false; + int timeout = 900; // about 30 seconds + timeout = 0; + while ( ! home && timeout > 0 ) { + if ( timeout % 150 == 0 ) { + SG_LOG( SG_IO, SG_INFO, "waiting for compass = " << timeout ); + } else { + SG_LOG( SG_IO, SG_DEBUG, "Checking if compass home ..." ); + } + + while ( ATCLock( lock_fd ) <= 0 ); + + unsigned char result = ATCReadStepper( stepper_fd ); + if ( result == 0 ) { + home = true; + } + + ATCRelease( lock_fd ); + +#if defined( _MSC_VER ) + ulMilliSecondSleep(33); +#elif defined (WIN32) && !defined(__CYGWIN__) + Sleep (33); +#else + usleep(33); +#endif + + --timeout; + } + + compass_position = 0.0; + + ///////////////////////////////////////////////////////////////////// + // Blank the radio display + ///////////////////////////////////////////////////////////////////// + + SG_LOG( SG_IO, SG_ALERT, + " - Clearing the radios displays." ); + + // Prepair the data + unsigned char value = 0xff; + 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 ); + + ///////////////////////////////////////////////////////////////////// + // Blank the lamps + ///////////////////////////////////////////////////////////////////// + + for ( int i = 0; i < 128; ++i ) { + ATCSetLamp( lamps_fd, i, false ); + } + + ///////////////////////////////////////////////////////////////////// + // Finished initing hardware + ///////////////////////////////////////////////////////////////////// + + SG_LOG( SG_IO, SG_ALERT, + "Done initializing ATC hardware." ); + + is_open = true; + + ///////////////////////////////////////////////////////////////////// + // Connect up to property values + ///////////////////////////////////////////////////////////////////// + + char base_name[256]; + + snprintf( base_name, 256, "/output/atc-board[%d]/lamps", board ); + lamps_out_node = fgGetNode( base_name ); + + snprintf( base_name, 256, "/output/atc-board[%d]/radio-display", board ); + radio_display_node = fgGetNode( base_name ); + + snprintf( base_name, 256, "/output/atc-board[%d]/steppers", board ); + steppers_node = fgGetNode( base_name ); + + return true; +} + + +///////////////////////////////////////////////////////////////////// +// Write the lights +///////////////////////////////////////////////////////////////////// + +bool FGATCOutput::do_lamps() { + + if ( lamps_out_node != NULL ) { + for ( int i = 0; i < lamps_out_node->nChildren(); ++i ) { + // read the next config entry from the property tree + + SGPropertyNode *child = lamps_out_node->getChild(i); + string cname = child->getName(); + int index = child->getIndex(); + string name = ""; + string type = ""; + SGPropertyNode *src_prop = NULL; + if ( cname == "lamp" ) { + 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 ); + } + ATCSetLamp( lamps_fd, index, src_prop->getBoolValue() ); + } else { + SG_LOG( SG_IO, SG_DEBUG, + "Input config error, expecting 'lamp' but found " + << cname ); + } + } + } + + return true; +} + + +///////////////////////////////////////////////////////////////////// +// Update the radio display +///////////////////////////////////////////////////////////////////// + + +static bool navcom1_has_power() { + static SGPropertyNode *navcom1_bus_power + = fgGetNode( "/systems/electrical/outputs/nav[0]", true ); + static SGPropertyNode *navcom1_power_btn + = fgGetNode( "/instrumentation/comm[0]/inputs/power-btn", true ); + + return (navcom1_bus_power->getDoubleValue() > 1.0) + && navcom1_power_btn->getBoolValue(); +} + +static bool navcom2_has_power() { + static SGPropertyNode *navcom2_bus_power + = fgGetNode( "/systems/electrical/outputs/nav[1]", true ); + static SGPropertyNode *navcom2_power_btn + = fgGetNode( "/instrumentation/comm[1]/inputs/power-btn", true ); + + return (navcom2_bus_power->getDoubleValue() > 1.0) + && navcom2_power_btn->getBoolValue(); +} + +static bool dme_has_power() { + static SGPropertyNode *dme_bus_power + = fgGetNode( "/systems/electrical/outputs/dme", true ); + + return (dme_bus_power->getDoubleValue() > 1.0); +} + +static bool adf_has_power() { + static SGPropertyNode *adf_bus_power + = fgGetNode( "/systems/electrical/outputs/adf", true ); + static SGPropertyNode *adf_power_btn + = fgGetNode( "/instrumentation/kr-87/inputs/power-btn", true ); + + return (adf_bus_power->getDoubleValue() > 1.0) + && adf_power_btn->getBoolValue(); +} + +static bool xpdr_has_power() { + static SGPropertyNode *xpdr_bus_power + = fgGetNode( "/systems/electrical/outputs/transponder", true ); + static SGPropertyNode *xpdr_func_knob + = fgGetNode( "/instrumentation/kt-70/inputs/func-knob", true ); + + return (xpdr_bus_power->getDoubleValue() > 1.0) + && (xpdr_func_knob->getIntValue() > 0); +} + +bool FGATCOutput::do_radio_display() { + static SGPropertyNode *dme_serviceable + = fgGetNode( "/instrumentation/dme/serviceable", true ); + static SGPropertyNode *dme_in_range + = fgGetNode( "/instrumentation/dme/in-range", true ); + static SGPropertyNode *dme_min + = fgGetNode( "/instrumentation/dme/indicated-time-min", true ); + static SGPropertyNode *dme_kt + = fgGetNode( "/instrumentation/dme/indicated-ground-speed-kt", true ); + static SGPropertyNode *dme_nm + = fgGetNode( "/instrumentation/dme/indicated-distance-nm", true ); + + static SGPropertyNode *comm1_serviceable + = fgGetNode( "/instrumentation/comm[0]/serviceable", true ); + static SGPropertyNode *com1_freq + = fgGetNode( "/instrumentation/comm[0]/frequencies/selected-mhz", true); + static SGPropertyNode *com1_stby_freq + = fgGetNode( "/instrumentation/comm[0]/frequencies/standby-mhz", true ); + + static SGPropertyNode *comm2_serviceable + = fgGetNode( "/instrumentation/comm[1]/serviceable", true ); + static SGPropertyNode *com2_freq + = fgGetNode( "/instrumentation/comm[1]/frequencies/selected-mhz", true); + static SGPropertyNode *com2_stby_freq + = fgGetNode( "/instrumentation/comm[1]/frequencies/standby-mhz", true ); + + static SGPropertyNode *nav1_serviceable + = fgGetNode( "/instrumentation/nav[0]/serviceable", true ); + static SGPropertyNode *nav1_freq + = fgGetNode( "/instrumentation/nav[0]/frequencies/selected-mhz", true ); + static SGPropertyNode *nav1_stby_freq + = fgGetNode( "/instrumentation/nav[0]/frequencies/standby-mhz", true ); + + static SGPropertyNode *nav2_serviceable + = fgGetNode( "/instrumentation/nav[1]/serviceable", true ); + static SGPropertyNode *nav2_freq + = fgGetNode( "/instrumentation/nav[1]/frequencies/selected-mhz", true ); + static SGPropertyNode *nav2_stby_freq + = fgGetNode( "/instrumentation/nav[1]/frequencies/standby-mhz", true ); + + static SGPropertyNode *adf_serviceable + = fgGetNode( "/instrumentation/adf/serviceable", true ); + static SGPropertyNode *adf_freq + = fgGetNode( "/instrumentation/kr-87/outputs/selected-khz", true ); + static SGPropertyNode *adf_stby_freq + = fgGetNode( "/instrumentation/kr-87/outputs/standby-khz", true ); + static SGPropertyNode *adf_stby_mode + = fgGetNode( "/instrumentation/kr-87/modes/stby", true ); + static SGPropertyNode *adf_timer_mode + = fgGetNode( "/instrumentation/kr-87/modes/timer", true ); + // static SGPropertyNode *adf_count_mode + // = fgGetNode( "/instrumentation/kr-87/modes/count", true ); + static SGPropertyNode *adf_flight_timer + = fgGetNode( "/instrumentation/kr-87/outputs/flight-timer", true ); + static SGPropertyNode *adf_elapsed_timer + = fgGetNode( "/instrumentation/kr-87/outputs/elapsed-timer", true ); + + static SGPropertyNode *xpdr_serviceable + = fgGetNode( "/instrumentation/kt-70/inputs/serviceable", true ); + static SGPropertyNode *xpdr_func_knob + = fgGetNode( "/instrumentation/kt-70/inputs/func-knob", true ); + static SGPropertyNode *xpdr_flight_level + = fgGetNode( "/instrumentation/kt-70/outputs/flight-level", true ); + static SGPropertyNode *xpdr_id_code + = fgGetNode( "/instrumentation/kt-70/outputs/id-code", true ); + + char digits[10]; + int i; + + if ( dme_has_power() && dme_serviceable->getBoolValue() ) { + if ( dme_in_range->getBoolValue() ) { + // DME minutes + float minutes = dme_min->getFloatValue(); + if ( minutes > 999 ) { + minutes = 999.0; + } + snprintf(digits, 7, "%03.0f", minutes); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[0] = digits[1] << 4 | digits[2]; + radio_display_data[1] = 0xf0 | digits[0]; + + // DME knots + float knots = dme_kt->getFloatValue(); + if ( knots > 999 ) { + knots = 999.0; + } + snprintf(digits, 7, "%03.0f", knots); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[2] = digits[1] << 4 | digits[2]; + radio_display_data[3] = 0xf0 | digits[0]; + + // DME distance (nm) + float nm = dme_nm->getFloatValue(); + if ( nm > 99 ) { + nm = 99.0; + } + snprintf(digits, 7, "%04.1f", nm); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[4] = digits[1] << 4 | digits[3]; + radio_display_data[5] = 0x00 | digits[0]; + // the 0x00 in the upper nibble of the 6th byte of each + // display turns on the decimal point + } else { + // out of range + radio_display_data[0] = 0xbb; + radio_display_data[1] = 0xfb; + radio_display_data[2] = 0xbb; + radio_display_data[3] = 0xfb; + radio_display_data[4] = 0xbb; + radio_display_data[5] = 0x0b; + } + } else { + // blank dem display + for ( i = 0; i < 6; ++i ) { + radio_display_data[i] = 0xff; + } + } + + if ( navcom1_has_power() && comm1_serviceable->getBoolValue() ) { + // Com1 standby frequency + float com1_stby = com1_stby_freq->getFloatValue(); + if ( fabs(com1_stby) > 999.99 ) { + com1_stby = 0.0; + } + snprintf(digits, 7, "%06.3f", com1_stby); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[6] = digits[4] << 4 | digits[5]; + radio_display_data[7] = digits[1] << 4 | digits[2]; + radio_display_data[8] = 0xf0 | digits[0]; + + // Com1 in use frequency + float com1 = com1_freq->getFloatValue(); + if ( fabs(com1) > 999.99 ) { + com1 = 0.0; + } + snprintf(digits, 7, "%06.3f", com1); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[9] = digits[4] << 4 | digits[5]; + radio_display_data[10] = digits[1] << 4 | digits[2]; + radio_display_data[11] = 0x00 | digits[0]; + // the 0x00 in the upper nibble of the 6th byte of each display + // turns on the decimal point + } else { + radio_display_data[6] = 0xff; + radio_display_data[7] = 0xff; + radio_display_data[8] = 0xff; + radio_display_data[9] = 0xff; + radio_display_data[10] = 0xff; + radio_display_data[11] = 0xff; + } + + if ( navcom2_has_power() && comm2_serviceable->getBoolValue() ) { + // Com2 standby frequency + float com2_stby = com2_stby_freq->getFloatValue(); + if ( fabs(com2_stby) > 999.99 ) { + com2_stby = 0.0; + } + snprintf(digits, 7, "%06.3f", com2_stby); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[18] = digits[4] << 4 | digits[5]; + radio_display_data[19] = digits[1] << 4 | digits[2]; + radio_display_data[20] = 0xf0 | digits[0]; + + // Com2 in use frequency + float com2 = com2_freq->getFloatValue(); + if ( fabs(com2) > 999.99 ) { + com2 = 0.0; + } + snprintf(digits, 7, "%06.3f", com2); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[21] = digits[4] << 4 | digits[5]; + radio_display_data[22] = digits[1] << 4 | digits[2]; + radio_display_data[23] = 0x00 | digits[0]; + // the 0x00 in the upper nibble of the 6th byte of each display + // turns on the decimal point + } else { + radio_display_data[18] = 0xff; + radio_display_data[19] = 0xff; + radio_display_data[20] = 0xff; + radio_display_data[21] = 0xff; + radio_display_data[22] = 0xff; + radio_display_data[23] = 0xff; + } + + if ( navcom1_has_power() && nav1_serviceable->getBoolValue() ) { + // Nav1 standby frequency + float nav1_stby = nav1_stby_freq->getFloatValue(); + if ( fabs(nav1_stby) > 999.99 ) { + nav1_stby = 0.0; + } + snprintf(digits, 7, "%06.2f", nav1_stby); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[12] = digits[4] << 4 | digits[5]; + radio_display_data[13] = digits[1] << 4 | digits[2]; + radio_display_data[14] = 0xf0 | digits[0]; + + // Nav1 in use frequency + float nav1 = nav1_freq->getFloatValue(); + if ( fabs(nav1) > 999.99 ) { + nav1 = 0.0; + } + snprintf(digits, 7, "%06.2f", nav1); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[15] = digits[4] << 4 | digits[5]; + radio_display_data[16] = digits[1] << 4 | digits[2]; + radio_display_data[17] = 0x00 | digits[0]; + // the 0x00 in the upper nibble of the 6th byte of each display + // turns on the decimal point + } else { + radio_display_data[12] = 0xff; + radio_display_data[13] = 0xff; + radio_display_data[14] = 0xff; + radio_display_data[15] = 0xff; + radio_display_data[16] = 0xff; + radio_display_data[17] = 0xff; + } + + if ( navcom2_has_power() && nav2_serviceable->getBoolValue() ) { + // Nav2 standby frequency + float nav2_stby = nav2_stby_freq->getFloatValue(); + if ( fabs(nav2_stby) > 999.99 ) { + nav2_stby = 0.0; + } + snprintf(digits, 7, "%06.2f", nav2_stby); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[24] = digits[4] << 4 | digits[5]; + radio_display_data[25] = digits[1] << 4 | digits[2]; + radio_display_data[26] = 0xf0 | digits[0]; + + // Nav2 in use frequency + float nav2 = nav2_freq->getFloatValue(); + if ( fabs(nav2) > 999.99 ) { + nav2 = 0.0; + } + snprintf(digits, 7, "%06.2f", nav2); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[27] = digits[4] << 4 | digits[5]; + radio_display_data[28] = digits[1] << 4 | digits[2]; + radio_display_data[29] = 0x00 | digits[0]; + // the 0x00 in the upper nibble of the 6th byte of each display + // turns on the decimal point + } else { + radio_display_data[24] = 0xff; + radio_display_data[25] = 0xff; + radio_display_data[26] = 0xff; + radio_display_data[27] = 0xff; + radio_display_data[28] = 0xff; + radio_display_data[29] = 0xff; + } + + // ADF standby frequency / timer + if ( adf_has_power() && adf_serviceable->getBoolValue() ) { + if ( adf_stby_mode->getIntValue() == 0 ) { + // frequency + float adf_stby = adf_stby_freq->getFloatValue(); + if ( fabs(adf_stby) > 1799 ) { + adf_stby = 1799; + } + snprintf(digits, 7, "%04.0f", adf_stby); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[30] = digits[3] << 4 | 0x0f; + radio_display_data[31] = digits[1] << 4 | digits[2]; + if ( digits[0] == 0 ) { + radio_display_data[32] = 0xff; + } else { + radio_display_data[32] = 0xf0 | digits[0]; + } + } else { + // timer + double time; + int hours, min, sec; + if ( adf_timer_mode->getIntValue() == 0 ) { + time = adf_flight_timer->getDoubleValue(); + } else { + time = adf_elapsed_timer->getDoubleValue(); + } + // cout << time << endl; + hours = (int)(time / 3600.0); + time -= hours * 3600.00; + min = (int)(time / 60.0); + time -= min * 60.0; + sec = (int)time; + int big, little; + if ( hours > 0 ) { + big = hours; + if ( big > 99 ) { + big = 99; + } + little = min; + } else { + big = min; + little = sec; + } + if ( big > 99 ) { + big = 99; + } + // cout << big << ":" << little << endl; + snprintf(digits, 7, "%02d%02d", big, little); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[30] = digits[2] << 4 | digits[3]; + radio_display_data[31] = digits[0] << 4 | digits[1]; + radio_display_data[32] = 0xff; + } + + // ADF in use frequency + float adf = adf_freq->getFloatValue(); + if ( fabs(adf) > 1799 ) { + adf = 1799; + } + snprintf(digits, 7, "%04.0f", adf); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[33] = digits[2] << 4 | digits[3]; + if ( digits[0] == 0 ) { + radio_display_data[34] = 0xf0 | digits[1]; + } else { + radio_display_data[34] = digits[0] << 4 | digits[1]; + } + if ( adf_stby_mode->getIntValue() == 0 ) { + radio_display_data[35] = 0xff; + } else { + radio_display_data[35] = 0x0f; + } + } else { + radio_display_data[30] = 0xff; + radio_display_data[31] = 0xff; + radio_display_data[32] = 0xff; + radio_display_data[33] = 0xff; + radio_display_data[34] = 0xff; + radio_display_data[35] = 0xff; + } + + // Transponder code and flight level + if ( xpdr_has_power() && xpdr_serviceable->getBoolValue() ) { + if ( xpdr_func_knob->getIntValue() == 2 ) { + // test mode + radio_display_data[36] = 8 << 4 | 8; + radio_display_data[37] = 8 << 4 | 8; + radio_display_data[38] = 0xff; + radio_display_data[39] = 8 << 4 | 0x0f; + radio_display_data[40] = 8 << 4 | 8; + } else { + // other on modes + int id_code = xpdr_id_code->getIntValue(); + int place = 1000; + for ( i = 0; i < 4; ++i ) { + digits[i] = id_code / place; + id_code -= digits[i] * place; + place /= 10; + } + radio_display_data[36] = digits[2] << 4 | digits[3]; + radio_display_data[37] = digits[0] << 4 | digits[1]; + radio_display_data[38] = 0xff; + + if ( xpdr_func_knob->getIntValue() == 3 || + xpdr_func_knob->getIntValue() == 5 ) + { + // do flight level display + snprintf(digits, 7, "%03d", xpdr_flight_level->getIntValue() ); + for ( i = 0; i < 6; ++i ) { + digits[i] -= '0'; + } + radio_display_data[39] = digits[2] << 4 | 0x0f; + radio_display_data[40] = digits[0] << 4 | digits[1]; + } else { + // blank flight level display + radio_display_data[39] = 0xff; + radio_display_data[40] = 0xff; + } + } + } else { + // off + radio_display_data[36] = 0xff; + radio_display_data[37] = 0xff; + radio_display_data[38] = 0xff; + radio_display_data[39] = 0xff; + radio_display_data[40] = 0xff; + } + + ATCSetRadios( radio_display_fd, radio_display_data ); + + return true; +} + + +///////////////////////////////////////////////////////////////////// +// Drive the stepper motors +///////////////////////////////////////////////////////////////////// + +bool FGATCOutput::do_steppers() { + SGPropertyNode *mag_compass + = fgGetNode( "/instrumentation/magnetic-compass/indicated-heading-deg", + true ); + + float diff = mag_compass->getFloatValue() - compass_position; + while ( diff < -180.0 ) { diff += 360.0; } + while ( diff > 180.0 ) { diff -= 360.0; } + + int steps = (int)(diff * 4); + // cout << "steps = " << steps << endl; + if ( steps > 4 ) { steps = 4; } + if ( steps < -4 ) { steps = -4; } + + if ( abs(steps) > 0 ) { + unsigned char cmd = 0x80; // stepper command + if ( steps > 0 ) { + cmd |= 0x20; // go up + } else { + cmd |= 0x00; // go down + } + cmd |= abs(steps); + + // sync compass_position with hardware position + compass_position += (float)steps / 4.0; + + ATCSetStepper( stepper_fd, ATC_COMPASS_CH, cmd ); + } + + return true; +} + + +// process the hardware outputs. This code assumes the calling layer +// will lock the hardware. +bool FGATCOutput::process() { + if ( !is_open ) { + SG_LOG( SG_IO, SG_ALERT, "This board has not been opened for output! " + << board ); + return false; + } + + do_lamps(); + do_radio_display(); + do_steppers(); + + return true; +} + + +bool FGATCOutput::close() { + +#if defined( unix ) || defined( __CYGWIN__ ) + + int result; + + result = ::close( lamps_fd ); + if ( result == -1 ) { + SG_LOG( SG_IO, SG_ALERT, "errno = " << errno ); + char msg[256]; + snprintf( msg, 256, "Error closing %s", lamps_file ); + perror( msg ); + exit( -1 ); + } + + result = ::close( radio_display_fd ); + if ( result == -1 ) { + SG_LOG( SG_IO, SG_ALERT, "errno = " << errno ); + char msg[256]; + snprintf( msg, 256, "Error closing %s", radio_display_file ); + perror( msg ); + exit( -1 ); + } + + result = ::close( stepper_fd ); + if ( result == -1 ) { + SG_LOG( SG_IO, SG_ALERT, "errno = " << errno ); + char msg[256]; + snprintf( msg, 256, "Error closing %s", stepper_file ); + perror( msg ); + exit( -1 ); + } + +#endif + + return true; +} diff --git a/src/Network/ATC-Outputs.hxx b/src/Network/ATC-Outputs.hxx new file mode 100644 index 000000000..ee43d136c --- /dev/null +++ b/src/Network/ATC-Outputs.hxx @@ -0,0 +1,90 @@ +// ATC-Outputs.hxx -- Translate FGFS properties into ATC hardware outputs +// +// 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_OUTPUTS_HXX +#define _FG_ATC_OUTPUTS_HXX + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include
+ +#define ATC_RADIO_DISPLAY_BYTES 48 +#define ATC_COMPASS_CH 5 +#define ATC_STEPPER_HOME 0xC0 + + +class FGATCOutput { + + int is_open; + + int board; + SGPath config; + + int lock_fd; + int lamps_fd; + int radio_display_fd; + int stepper_fd; + + char lamps_file[256]; + char radio_display_file[256]; + char stepper_file[256]; + + unsigned char radio_display_data[ATC_RADIO_DISPLAY_BYTES]; + + SGPropertyNode *lamps_out_node; + SGPropertyNode *radio_display_node; + SGPropertyNode *steppers_node; + + void init_config(); + bool do_lamps(); + bool do_radio_display(); + bool do_steppers(); + + // hardwired stepper motor code + float compass_position; + +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 output config file (xml) + FGATCOutput( const int _board, const SGPath &_config_file ); + + // Destructor + ~FGATCOutput() { } + + // need to pass in atc hardware lock_fd so that the radios and + // lamps can be blanked and so that the compass can be homed. + bool open( int lock_fd ); + + // process the hardware outputs. This code assumes the calling + // layer will lock the hardware. + bool process(); + + bool close(); +}; + + +#endif // _FG_ATC_OUTPUTS_HXX diff --git a/src/Network/Makefile.am b/src/Network/Makefile.am index d4fa7dc7c..7c90fe0d2 100644 --- a/src/Network/Makefile.am +++ b/src/Network/Makefile.am @@ -17,8 +17,9 @@ endif libNetwork_a_SOURCES = \ protocol.cxx protocol.hxx \ + ATC-Main.cxx ATC-Main.hxx \ ATC-Inputs.cxx ATC-Inputs.hxx \ - atc610x.cxx atc610x.hxx \ + ATC-Outputs.cxx ATC-Outputs.hxx \ atlas.cxx atlas.hxx \ garmin.cxx garmin.hxx \ httpd.cxx httpd.hxx \ diff --git a/src/Network/atc610x.cxx b/src/Network/atc610x.cxx deleted file mode 100644 index 34c3d10f2..000000000 --- a/src/Network/atc610x.cxx +++ /dev/null @@ -1,966 +0,0 @@ -// atc610x.cxx -- FGFS interface to ATC 610x 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., 675 Mass Ave, Cambridge, MA 02139, 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 "atc610x.hxx" - -SG_USING_STD(string); - - -// Lock the ATC 610 hardware -static int ATC610xLock( 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 ATC610xRelease( 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; -} - - -// Write a radios command -static int ATC610xSetRadios( int fd, - unsigned char data[ATC_RADIO_DISPLAY_BYTES] ) -{ - // rewind - lseek( fd, 0, SEEK_SET ); - - int result = write( fd, data, ATC_RADIO_DISPLAY_BYTES ); - - if ( result != ATC_RADIO_DISPLAY_BYTES ) { - SG_LOG( SG_IO, SG_DEBUG, "Write failed" ); - } - - return result; -} - - -// Write a stepper command -static int ATC610xSetStepper( int fd, unsigned char channel, - unsigned char value ) -{ - // rewind - lseek( fd, 0, SEEK_SET ); - - // Write the value - unsigned char buf[3]; - buf[0] = channel; - buf[1] = value; - buf[2] = 0; - int result = write( fd, buf, 2 ); - if ( result != 2 ) { - SG_LOG( SG_IO, SG_INFO, "Write failed" ); - } - SG_LOG( SG_IO, SG_DEBUG, - "Sent cmd = " << (int)channel << " value = " << (int)value ); - return result; -} - - -// Read status of last stepper written to -static unsigned char ATC610xReadStepper( int fd ) { - int result; - - // rewind - lseek( fd, 0, SEEK_SET ); - - // Write the value - unsigned char buf[2]; - result = read( fd, buf, 1 ); - if ( result != 1 ) { - SG_LOG( SG_IO, SG_ALERT, "Read failed" ); - exit( -1 ); - } - SG_LOG( SG_IO, SG_DEBUG, "Read result = " << (int)buf[0] ); - - return buf[0]; -} - - -// Turn a lamp on or off -void ATC610xSetLamp( int fd, int channel, bool value ) { - // lamp channels 0-63 are written to LampPort0, channels 64-127 - // are written to LampPort1 - - // bits 0-6 are the lamp address - // bit 7 is the value (on/off) - - int result; - - // Write the value - unsigned char buf[3]; - buf[0] = channel; - buf[1] = value; - buf[2] = 0; - result = write( fd, buf, 2 ); - if ( result != 2 ) { - SG_LOG( SG_IO, SG_ALERT, "Write failed" ); - exit( -1 ); - } -} - - -void FGATC610x::init_config() { -#if defined( unix ) || defined( __CYGWIN__ ) - // Next check home directory for .fgfsrc.hostname file - char *envp = ::getenv( "HOME" ); - if ( envp != NULL ) { - SGPath atc610x_config( envp ); - atc610x_config.append( ".fgfs-atc610x.xml" ); - readProperties( atc610x_config.str(), globals->get_props() ); - } -#endif -} - - -// Open and initialize ATC 610x hardware -bool FGATC610x::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 610x hardware, please wait ..." ); - - // This loads the config parameters generated by "simcal" - init_config(); - - 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(); - } - - set_hz( 30 ); // default to processing requests @ 30Hz - set_enabled( true ); - - board = 0; // 610x uses a single board number = 0 - - snprintf( lock_file, 256, "/proc/atc610x/board%d/lock", board ); - snprintf( lamps_file, 256, "/proc/atc610x/board%d/lamps", board ); - snprintf( radios_file, 256, "/proc/atc610x/board%d/radios", board ); - snprintf( stepper_file, 256, "/proc/atc610x/board%d/steppers", 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 ); - } - - lamps_fd = ::open( lamps_file, O_WRONLY ); - if ( lamps_fd == -1 ) { - SG_LOG( SG_IO, SG_ALERT, "errno = " << errno ); - char msg[256]; - snprintf( msg, 256, "Error opening %s", lamps_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 ); - } - - stepper_fd = ::open( stepper_file, O_RDWR ); - if ( stepper_fd == -1 ) { - SG_LOG( SG_IO, SG_ALERT, "errno = " << errno ); - char msg[256]; - snprintf( msg, 256, "Error opening %s", stepper_file ); - perror( msg ); - exit( -1 ); - } - - - ///////////////////////////////////////////////////////////////////// - // Home the compass stepper motor - ///////////////////////////////////////////////////////////////////// - - SG_LOG( SG_IO, SG_ALERT, - " - Homing the compass stepper motor" ); - - // Lock the hardware, keep trying until we succeed - while ( ATC610xLock( lock_fd ) <= 0 ); - - // Send the stepper home command - ATC610xSetStepper( stepper_fd, ATC_COMPASS_CH, ATC_STEPPER_HOME ); - - // Release the hardware - ATC610xRelease( lock_fd ); - - SG_LOG( SG_IO, SG_ALERT, - " - Waiting for compass to come home." ); - - bool home = false; - int timeout = 900; // about 30 seconds - timeout = 0; - while ( ! home && timeout > 0 ) { - if ( timeout % 150 == 0 ) { - SG_LOG( SG_IO, SG_INFO, "waiting for compass = " << timeout ); - } else { - SG_LOG( SG_IO, SG_DEBUG, "Checking if compass home ..." ); - } - - while ( ATC610xLock( lock_fd ) <= 0 ); - - unsigned char result = ATC610xReadStepper( stepper_fd ); - if ( result == 0 ) { - home = true; - } - - ATC610xRelease( lock_fd ); - -#if defined( _MSC_VER ) - ulMilliSecondSleep(33); -#elif defined (WIN32) && !defined(__CYGWIN__) - Sleep (33); -#else - usleep(33); -#endif - - --timeout; - } - - compass_position = 0.0; - - ///////////////////////////////////////////////////////////////////// - // Blank the radio display - ///////////////////////////////////////////////////////////////////// - - SG_LOG( SG_IO, SG_ALERT, - " - Clearing the radios displays." ); - - // Prepair the data - unsigned char value = 0xff; - for ( int channel = 0; channel < ATC_RADIO_DISPLAY_BYTES; ++channel ) { - radio_display_data[channel] = value; - } - - // Lock the hardware, keep trying until we succeed - while ( ATC610xLock( lock_fd ) <= 0 ); - - // Set radio display - ATC610xSetRadios( radios_fd, radio_display_data ); - - ATC610xRelease( lock_fd ); - - ///////////////////////////////////////////////////////////////////// - // Blank the lamps - ///////////////////////////////////////////////////////////////////// - - for ( int i = 0; i < 128; ++i ) { - ATC610xSetLamp( lamps_fd, i, false ); - } - - ///////////////////////////////////////////////////////////////////// - // Finished initing hardware - ///////////////////////////////////////////////////////////////////// - - SG_LOG( SG_IO, SG_ALERT, - "Done initializing ATC 610x hardware." ); - - ///////////////////////////////////////////////////////////////////// - // Connect up to property values - ///////////////////////////////////////////////////////////////////// - - mag_compass - = fgGetNode( "/instrumentation/magnetic-compass/indicated-heading-deg", - true ); - - dme_min = fgGetNode( "/instrumentation/dme/indicated-time-min", true ); - dme_kt = fgGetNode( "/instrumentation/dme/indicated-ground-speed-kt", - true ); - dme_nm = fgGetNode( "/instrumentation/dme/indicated-distance-nm", true ); - dme_in_range = fgGetNode( "/instrumentation/dme/in-range", true ); - - adf_bus_power = fgGetNode( "/systems/electrical/outputs/adf", true ); - dme_bus_power = fgGetNode( "/systems/electrical/outputs/dme", true ); - navcom1_bus_power = fgGetNode( "/systems/electrical/outputs/nav[0]", - true ); - navcom2_bus_power = fgGetNode( "/systems/electrical/outputs/nav[1]", - true ); - xpdr_bus_power = fgGetNode( "/systems/electrical/outputs/transponder", - true ); - - navcom1_power_btn = fgGetNode( "/instrumentation/comm[0]/inputs/power-btn", true ); - navcom2_power_btn = fgGetNode( "/instrumentation/comm[1]/inputs/power-btn", true ); - - com1_freq = fgGetNode( "/instrumentation/comm[0]/frequencies/selected-mhz", true ); - com1_stby_freq - = fgGetNode( "/instrumentation/comm[0]/frequencies/standby-mhz", true ); - - com2_freq = fgGetNode( "/instrumentation/comm[1]/frequencies/selected-mhz", true ); - com2_stby_freq - = fgGetNode( "/instrumentation/comm[1]/frequencies/standby-mhz", true ); - - nav1_freq = fgGetNode( "/instrumentation/nav[0]/frequencies/selected-mhz", true ); - nav1_stby_freq - = fgGetNode( "/instrumentation/nav[0]/frequencies/standby-mhz", true ); - nav1_obs = fgGetNode( "/instrumentation/nav[0]/radials/selected-deg", true ); - - nav2_freq = fgGetNode( "/instrumentation/nav[1]/frequencies/selected-mhz", true ); - nav2_stby_freq - = fgGetNode( "/instrumentation/nav[1]/frequencies/standby-mhz", true ); - nav2_obs = fgGetNode( "/instrumentation/nav[1]/radials/selected-deg", true ); - - adf_power_btn - = fgGetNode( "/instrumentation/kr-87/inputs/power-btn", true ); - adf_vol = fgGetNode( "/instrumentation/kr-87/inputs/volume", true ); - adf_adf_btn = fgGetNode( "/instrumentation/kr-87/inputs/adf-btn", true ); - adf_bfo_btn = fgGetNode( "/instrumentation/kr-87/inputs/bfo-btn", true ); - adf_freq = fgGetNode( "/instrumentation/kr-87/outputs/selected-khz", true ); - adf_stby_freq - = fgGetNode( "/instrumentation/kr-87/outputs/standby-khz", true ); - adf_stby_mode = fgGetNode( "/instrumentation/kr-87/modes/stby", true ); - adf_timer_mode = fgGetNode( "/instrumentation/kr-87/modes/timer", true ); - adf_count_mode = fgGetNode( "/instrumentation/kr-87/modes/count", true ); - adf_flight_timer - = fgGetNode( "/instrumentation/kr-87/outputs/flight-timer", true ); - adf_elapsed_timer - = fgGetNode( "/instrumentation/kr-87/outputs/elapsed-timer", - true ); - adf_ant_ann = fgGetNode( "/instrumentation/kr-87/annunciators/ant", true ); - adf_adf_ann = fgGetNode( "/instrumentation/kr-87/annunciators/adf", true ); - adf_bfo_ann = fgGetNode( "/instrumentation/kr-87/annunciators/bfo", true ); - adf_frq_ann = fgGetNode( "/instrumentation/kr-87/annunciators/frq", true ); - adf_flt_ann = fgGetNode( "/instrumentation/kr-87/annunciators/flt", true ); - adf_et_ann = fgGetNode( "/instrumentation/kr-87/annunciators/et", true ); - - inner = fgGetNode( "/instrumentation/marker-beacon/inner", true ); - middle = fgGetNode( "/instrumentation/marker-beacon/middle", true ); - outer = fgGetNode( "/instrumentation/marker-beacon/outer", true ); - - xpdr_ident_btn - = fgGetNode( "/instrumentation/kt-70/inputs/ident-btn", true ); - xpdr_digit1 = fgGetNode( "/instrumentation/kt-70/inputs/digit1", true ); - xpdr_digit2 = fgGetNode( "/instrumentation/kt-70/inputs/digit2", true ); - xpdr_digit3 = fgGetNode( "/instrumentation/kt-70/inputs/digit3", true ); - xpdr_digit4 = fgGetNode( "/instrumentation/kt-70/inputs/digit4", true ); - xpdr_func_knob - = fgGetNode( "/instrumentation/kt-70/inputs/func-knob", true ); - xpdr_id_code = fgGetNode( "/instrumentation/kt-70/outputs/id-code", true ); - xpdr_flight_level - = fgGetNode( "/instrumentation/kt-70/outputs/flight-level", true ); - xpdr_fl_ann = fgGetNode( "/instrumentation/kt-70/annunciators/fl", true ); - xpdr_alt_ann = fgGetNode( "/instrumentation/kt-70/annunciators/alt", true ); - xpdr_gnd_ann = fgGetNode( "/instrumentation/kt-70/annunciators/gnd", true ); - xpdr_on_ann = fgGetNode( "/instrumentation/kt-70/annunciators/on", true ); - xpdr_sby_ann = fgGetNode( "/instrumentation/kt-70/annunciators/sby", true ); - xpdr_reply_ann - = fgGetNode( "/instrumentation/kt-70/annunciators/reply", true ); - - ati_bird - = fgGetNode( "/instrumentation/attitude-indicator/horizon-offset-deg", - true ); - alt_press = fgGetNode( "/instrumentation/altimeter/setting-inhg", true ); - adf_hdg = fgGetNode( "/instrumentation/kr-87/inputs/rotation-deg", true ); - hdg_bug = fgGetNode( "/autopilot/settings/heading-bug-deg", true ); - - elevator_center = fgGetNode( "/input/atc610x/elevator/center", true ); - elevator_min = fgGetNode( "/input/atc610x/elevator/min", true ); - elevator_max = fgGetNode( "/input/atc610x/elevator/max", true ); - - ailerons_center = fgGetNode( "/input/atc610x/ailerons/center", true ); - ailerons_min = fgGetNode( "/input/atc610x/ailerons/min", true ); - ailerons_max = fgGetNode( "/input/atc610x/ailerons/max", true ); - - rudder_center = fgGetNode( "/input/atc610x/rudder/center", true ); - rudder_min = fgGetNode( "/input/atc610x/rudder/min", true ); - rudder_max = fgGetNode( "/input/atc610x/rudder/max", true ); - - brake_left_min = fgGetNode( "/input/atc610x/brake-left/min", true ); - brake_left_max = fgGetNode( "/input/atc610x/brake-left/max", true ); - - brake_right_min = fgGetNode( "/input/atc610x/brake-right/min", true ); - brake_right_max = fgGetNode( "/input/atc610x/brake-right/max", true ); - - throttle_min = fgGetNode( "/input/atc610x/throttle/min", true ); - throttle_max = fgGetNode( "/input/atc610x/throttle/max", true ); - - mixture_min = fgGetNode( "/input/atc610x/mixture/min", true ); - mixture_max = fgGetNode( "/input/atc610x/mixture/max", true ); - - trim_center = fgGetNode( "/input/atc610x/trim/center", true ); - trim_min = fgGetNode( "/input/atc610x/trim/min", true ); - trim_max = fgGetNode( "/input/atc610x/trim/max", true ); - - nav1vol_min = fgGetNode( "/input/atc610x/nav1vol/min", true ); - nav1vol_max = fgGetNode( "/input/atc610x/nav1vol/max", true ); - - nav2vol_min = fgGetNode( "/input/atc610x/nav2vol/min", true ); - nav2vol_max = fgGetNode( "/input/atc610x/nav2vol/max", true ); - - ignore_flight_controls - = fgGetNode( "/input/atc610x/ignore-flight-controls", true ); - - comm1_serviceable - = fgGetNode( "/instrumentation/comm[0]/serviceable", true ); - comm2_serviceable - = fgGetNode( "/instrumentation/comm[1]/serviceable", true ); - nav1_serviceable = fgGetNode( "/instrumentation/nav[0]/serviceable", true ); - nav2_serviceable = fgGetNode( "/instrumentation/nav[1]/serviceable", true ); - adf_serviceable = fgGetNode( "/instrumentation/adf/serviceable", true ); - xpdr_serviceable - = fgGetNode( "/instrumentation/kt-70/inputs/serviceable", true ); - dme_serviceable = fgGetNode( "/instrumentation/dme/serviceable", true ); - - dme_selector - = fgGetNode( "/input/atc-board/radio-switches/raw/dme-switch-position"); - - // default to having everything serviceable - comm1_serviceable->setBoolValue( true ); - comm2_serviceable->setBoolValue( true ); - nav1_serviceable->setBoolValue( true ); - nav2_serviceable->setBoolValue( true ); - adf_serviceable->setBoolValue( true ); - xpdr_serviceable->setBoolValue( true ); - dme_serviceable->setBoolValue( true ); - - return true; -} - - -///////////////////////////////////////////////////////////////////// -// Write the lights -///////////////////////////////////////////////////////////////////// - -bool FGATC610x::do_lights() { - - // Marker beacons - ATC610xSetLamp( lamps_fd, 4, inner->getBoolValue() ); - ATC610xSetLamp( lamps_fd, 5, middle->getBoolValue() ); - ATC610xSetLamp( lamps_fd, 3, outer->getBoolValue() ); - - // ADF annunciators - ATC610xSetLamp( lamps_fd, 11, adf_ant_ann->getBoolValue() ); // ANT - ATC610xSetLamp( lamps_fd, 12, adf_adf_ann->getBoolValue() ); // ADF - ATC610xSetLamp( lamps_fd, 13, adf_bfo_ann->getBoolValue() ); // BFO - ATC610xSetLamp( lamps_fd, 14, adf_frq_ann->getBoolValue() ); // FRQ - ATC610xSetLamp( lamps_fd, 15, adf_flt_ann->getBoolValue() ); // FLT - ATC610xSetLamp( lamps_fd, 16, adf_et_ann->getBoolValue() ); // ET - - // Transponder annunciators - ATC610xSetLamp( lamps_fd, 17, xpdr_fl_ann->getBoolValue() ); // FL - ATC610xSetLamp( lamps_fd, 18, xpdr_alt_ann->getBoolValue() ); // ALT - ATC610xSetLamp( lamps_fd, 19, xpdr_gnd_ann->getBoolValue() ); // GND - ATC610xSetLamp( lamps_fd, 20, xpdr_on_ann->getBoolValue() ); // ON - ATC610xSetLamp( lamps_fd, 21, xpdr_sby_ann->getBoolValue() ); // SBY - ATC610xSetLamp( lamps_fd, 22, xpdr_reply_ann->getBoolValue() ); // R - - return true; -} - - -///////////////////////////////////////////////////////////////////// -// Update the radio display -///////////////////////////////////////////////////////////////////// - -bool FGATC610x::do_radio_display() { - - char digits[10]; - int i; - - if ( dme_has_power() && dme_serviceable->getBoolValue() ) { - if ( dme_in_range->getBoolValue() ) { - // DME minutes - float minutes = dme_min->getFloatValue(); - if ( minutes > 999 ) { - minutes = 999.0; - } - snprintf(digits, 7, "%03.0f", minutes); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[0] = digits[1] << 4 | digits[2]; - radio_display_data[1] = 0xf0 | digits[0]; - - // DME knots - float knots = dme_kt->getFloatValue(); - if ( knots > 999 ) { - knots = 999.0; - } - snprintf(digits, 7, "%03.0f", knots); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[2] = digits[1] << 4 | digits[2]; - radio_display_data[3] = 0xf0 | digits[0]; - - // DME distance (nm) - float nm = dme_nm->getFloatValue(); - if ( nm > 99 ) { - nm = 99.0; - } - snprintf(digits, 7, "%04.1f", nm); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[4] = digits[1] << 4 | digits[3]; - radio_display_data[5] = 0x00 | digits[0]; - // the 0x00 in the upper nibble of the 6th byte of each - // display turns on the decimal point - } else { - // out of range - radio_display_data[0] = 0xbb; - radio_display_data[1] = 0xfb; - radio_display_data[2] = 0xbb; - radio_display_data[3] = 0xfb; - radio_display_data[4] = 0xbb; - radio_display_data[5] = 0x0b; - } - } else { - // blank dem display - for ( i = 0; i < 6; ++i ) { - radio_display_data[i] = 0xff; - } - } - - if ( navcom1_has_power() && comm1_serviceable->getBoolValue() ) { - // Com1 standby frequency - float com1_stby = com1_stby_freq->getFloatValue(); - if ( fabs(com1_stby) > 999.99 ) { - com1_stby = 0.0; - } - snprintf(digits, 7, "%06.3f", com1_stby); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[6] = digits[4] << 4 | digits[5]; - radio_display_data[7] = digits[1] << 4 | digits[2]; - radio_display_data[8] = 0xf0 | digits[0]; - - // Com1 in use frequency - float com1 = com1_freq->getFloatValue(); - if ( fabs(com1) > 999.99 ) { - com1 = 0.0; - } - snprintf(digits, 7, "%06.3f", com1); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[9] = digits[4] << 4 | digits[5]; - radio_display_data[10] = digits[1] << 4 | digits[2]; - radio_display_data[11] = 0x00 | digits[0]; - // the 0x00 in the upper nibble of the 6th byte of each display - // turns on the decimal point - } else { - radio_display_data[6] = 0xff; - radio_display_data[7] = 0xff; - radio_display_data[8] = 0xff; - radio_display_data[9] = 0xff; - radio_display_data[10] = 0xff; - radio_display_data[11] = 0xff; - } - - if ( navcom2_has_power() && comm2_serviceable->getBoolValue() ) { - // Com2 standby frequency - float com2_stby = com2_stby_freq->getFloatValue(); - if ( fabs(com2_stby) > 999.99 ) { - com2_stby = 0.0; - } - snprintf(digits, 7, "%06.3f", com2_stby); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[18] = digits[4] << 4 | digits[5]; - radio_display_data[19] = digits[1] << 4 | digits[2]; - radio_display_data[20] = 0xf0 | digits[0]; - - // Com2 in use frequency - float com2 = com2_freq->getFloatValue(); - if ( fabs(com2) > 999.99 ) { - com2 = 0.0; - } - snprintf(digits, 7, "%06.3f", com2); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[21] = digits[4] << 4 | digits[5]; - radio_display_data[22] = digits[1] << 4 | digits[2]; - radio_display_data[23] = 0x00 | digits[0]; - // the 0x00 in the upper nibble of the 6th byte of each display - // turns on the decimal point - } else { - radio_display_data[18] = 0xff; - radio_display_data[19] = 0xff; - radio_display_data[20] = 0xff; - radio_display_data[21] = 0xff; - radio_display_data[22] = 0xff; - radio_display_data[23] = 0xff; - } - - if ( navcom1_has_power() && nav1_serviceable->getBoolValue() ) { - // Nav1 standby frequency - float nav1_stby = nav1_stby_freq->getFloatValue(); - if ( fabs(nav1_stby) > 999.99 ) { - nav1_stby = 0.0; - } - snprintf(digits, 7, "%06.2f", nav1_stby); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[12] = digits[4] << 4 | digits[5]; - radio_display_data[13] = digits[1] << 4 | digits[2]; - radio_display_data[14] = 0xf0 | digits[0]; - - // Nav1 in use frequency - float nav1 = nav1_freq->getFloatValue(); - if ( fabs(nav1) > 999.99 ) { - nav1 = 0.0; - } - snprintf(digits, 7, "%06.2f", nav1); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[15] = digits[4] << 4 | digits[5]; - radio_display_data[16] = digits[1] << 4 | digits[2]; - radio_display_data[17] = 0x00 | digits[0]; - // the 0x00 in the upper nibble of the 6th byte of each display - // turns on the decimal point - } else { - radio_display_data[12] = 0xff; - radio_display_data[13] = 0xff; - radio_display_data[14] = 0xff; - radio_display_data[15] = 0xff; - radio_display_data[16] = 0xff; - radio_display_data[17] = 0xff; - } - - if ( navcom2_has_power() && nav2_serviceable->getBoolValue() ) { - // Nav2 standby frequency - float nav2_stby = nav2_stby_freq->getFloatValue(); - if ( fabs(nav2_stby) > 999.99 ) { - nav2_stby = 0.0; - } - snprintf(digits, 7, "%06.2f", nav2_stby); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[24] = digits[4] << 4 | digits[5]; - radio_display_data[25] = digits[1] << 4 | digits[2]; - radio_display_data[26] = 0xf0 | digits[0]; - - // Nav2 in use frequency - float nav2 = nav2_freq->getFloatValue(); - if ( fabs(nav2) > 999.99 ) { - nav2 = 0.0; - } - snprintf(digits, 7, "%06.2f", nav2); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[27] = digits[4] << 4 | digits[5]; - radio_display_data[28] = digits[1] << 4 | digits[2]; - radio_display_data[29] = 0x00 | digits[0]; - // the 0x00 in the upper nibble of the 6th byte of each display - // turns on the decimal point - } else { - radio_display_data[24] = 0xff; - radio_display_data[25] = 0xff; - radio_display_data[26] = 0xff; - radio_display_data[27] = 0xff; - radio_display_data[28] = 0xff; - radio_display_data[29] = 0xff; - } - - // ADF standby frequency / timer - if ( adf_has_power() && adf_serviceable->getBoolValue() ) { - if ( adf_stby_mode->getIntValue() == 0 ) { - // frequency - float adf_stby = adf_stby_freq->getFloatValue(); - if ( fabs(adf_stby) > 1799 ) { - adf_stby = 1799; - } - snprintf(digits, 7, "%04.0f", adf_stby); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[30] = digits[3] << 4 | 0x0f; - radio_display_data[31] = digits[1] << 4 | digits[2]; - if ( digits[0] == 0 ) { - radio_display_data[32] = 0xff; - } else { - radio_display_data[32] = 0xf0 | digits[0]; - } - } else { - // timer - double time; - int hours, min, sec; - if ( adf_timer_mode->getIntValue() == 0 ) { - time = adf_flight_timer->getDoubleValue(); - } else { - time = adf_elapsed_timer->getDoubleValue(); - } - // cout << time << endl; - hours = (int)(time / 3600.0); - time -= hours * 3600.00; - min = (int)(time / 60.0); - time -= min * 60.0; - sec = (int)time; - int big, little; - if ( hours > 0 ) { - big = hours; - if ( big > 99 ) { - big = 99; - } - little = min; - } else { - big = min; - little = sec; - } - if ( big > 99 ) { - big = 99; - } - // cout << big << ":" << little << endl; - snprintf(digits, 7, "%02d%02d", big, little); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[30] = digits[2] << 4 | digits[3]; - radio_display_data[31] = digits[0] << 4 | digits[1]; - radio_display_data[32] = 0xff; - } - - // ADF in use frequency - float adf = adf_freq->getFloatValue(); - if ( fabs(adf) > 1799 ) { - adf = 1799; - } - snprintf(digits, 7, "%04.0f", adf); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[33] = digits[2] << 4 | digits[3]; - if ( digits[0] == 0 ) { - radio_display_data[34] = 0xf0 | digits[1]; - } else { - radio_display_data[34] = digits[0] << 4 | digits[1]; - } - if ( adf_stby_mode->getIntValue() == 0 ) { - radio_display_data[35] = 0xff; - } else { - radio_display_data[35] = 0x0f; - } - } else { - radio_display_data[30] = 0xff; - radio_display_data[31] = 0xff; - radio_display_data[32] = 0xff; - radio_display_data[33] = 0xff; - radio_display_data[34] = 0xff; - radio_display_data[35] = 0xff; - } - - // Transponder code and flight level - if ( xpdr_has_power() && xpdr_serviceable->getBoolValue() ) { - if ( xpdr_func_knob->getIntValue() == 2 ) { - // test mode - radio_display_data[36] = 8 << 4 | 8; - radio_display_data[37] = 8 << 4 | 8; - radio_display_data[38] = 0xff; - radio_display_data[39] = 8 << 4 | 0x0f; - radio_display_data[40] = 8 << 4 | 8; - } else { - // other on modes - int id_code = xpdr_id_code->getIntValue(); - int place = 1000; - for ( i = 0; i < 4; ++i ) { - digits[i] = id_code / place; - id_code -= digits[i] * place; - place /= 10; - } - radio_display_data[36] = digits[2] << 4 | digits[3]; - radio_display_data[37] = digits[0] << 4 | digits[1]; - radio_display_data[38] = 0xff; - - if ( xpdr_func_knob->getIntValue() == 3 || - xpdr_func_knob->getIntValue() == 5 ) - { - // do flight level display - snprintf(digits, 7, "%03d", xpdr_flight_level->getIntValue() ); - for ( i = 0; i < 6; ++i ) { - digits[i] -= '0'; - } - radio_display_data[39] = digits[2] << 4 | 0x0f; - radio_display_data[40] = digits[0] << 4 | digits[1]; - } else { - // blank flight level display - radio_display_data[39] = 0xff; - radio_display_data[40] = 0xff; - } - } - } else { - // off - radio_display_data[36] = 0xff; - radio_display_data[37] = 0xff; - radio_display_data[38] = 0xff; - radio_display_data[39] = 0xff; - radio_display_data[40] = 0xff; - } - - ATC610xSetRadios( radios_fd, radio_display_data ); - - return true; -} - - -///////////////////////////////////////////////////////////////////// -// Drive the stepper motors -///////////////////////////////////////////////////////////////////// - -bool FGATC610x::do_steppers() { - float diff = mag_compass->getFloatValue() - compass_position; - while ( diff < -180.0 ) { diff += 360.0; } - while ( diff > 180.0 ) { diff -= 360.0; } - - int steps = (int)(diff * 4); - // cout << "steps = " << steps << endl; - if ( steps > 4 ) { steps = 4; } - if ( steps < -4 ) { steps = -4; } - - if ( abs(steps) > 0 ) { - unsigned char cmd = 0x80; // stepper command - if ( steps > 0 ) { - cmd |= 0x20; // go up - } else { - cmd |= 0x00; // go down - } - cmd |= abs(steps); - - // sync compass_position with hardware position - compass_position += (float)steps / 4.0; - - ATC610xSetStepper( stepper_fd, ATC_COMPASS_CH, cmd ); - } - - return true; -} - - -bool FGATC610x::process() { - - // Lock the hardware, skip if it's not ready yet - if ( ATC610xLock( lock_fd ) > 0 ) { - - // process the ATC inputs - if ( input0 != NULL ) { - input0->process(); - } - if ( input1 != NULL ) { - 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.do_hardware()" ); - if ( !result ) { - SG_LOG( SG_GENERAL, SG_ALERT, - "do_atcflightsim_hardware() failed!" ); - } - - do_lights(); - do_radio_display(); - do_steppers(); - - ATC610xRelease( lock_fd ); - - return true; - } else { - return false; - } -} - - -bool FGATC610x::close() { - - return true; -} diff --git a/src/Network/atc610x.hxx b/src/Network/atc610x.hxx deleted file mode 100644 index 98c3fcd03..000000000 --- a/src/Network/atc610x.hxx +++ /dev/null @@ -1,185 +0,0 @@ -// atc610x.hxx -- FGFS interface to ATC 610x 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., 675 Mass Ave, Cambridge, MA 02139, USA. -// -// $Id$ - - -#ifndef _FG_ATC610X_HXX -#define _FG_ATC610X_HXX - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include - -#include
- -#include "protocol.hxx" - -#include "ATC-Inputs.hxx" - - -#define ATC_COMPASS_CH 5 -#define ATC_STEPPER_HOME 0xC0 -#define ATC_RADIO_DISPLAY_BYTES 48 - - -class FGATC610x : public FGProtocol { - - 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 lock_fd; - int lamps_fd; - int radios_fd; - int stepper_fd; - - char lock_file[256]; - char lamps_file[256]; - char radios_file[256]; - char stepper_file[256]; - - unsigned char radio_display_data[ATC_RADIO_DISPLAY_BYTES]; - unsigned char radio_switch_data[ATC_RADIO_SWITCH_BYTES]; - - float compass_position; - - // Electrical system state - SGPropertyNode *adf_bus_power, *dme_bus_power, *xpdr_bus_power; - SGPropertyNode *navcom1_bus_power, *navcom2_bus_power; - - // Property tree variables - SGPropertyNode *mag_compass; - SGPropertyNode *dme_min, *dme_kt, *dme_nm; - SGPropertyNode *dme_in_range; - SGPropertyNode *navcom1_power_btn, *navcom2_power_btn; - SGPropertyNode *com1_freq, *com1_stby_freq; - SGPropertyNode *com2_freq, *com2_stby_freq; - SGPropertyNode *nav1_freq, *nav1_stby_freq, *nav1_obs; - SGPropertyNode *nav2_freq, *nav2_stby_freq, *nav2_obs; - SGPropertyNode *adf_adf_btn, *adf_bfo_btn; - SGPropertyNode *adf_power_btn, *adf_vol; - SGPropertyNode *adf_freq, *adf_stby_freq; - SGPropertyNode *adf_stby_mode, *adf_timer_mode; - SGPropertyNode *adf_count_mode, *adf_flight_timer, *adf_elapsed_timer; - SGPropertyNode *adf_ant_ann, *adf_adf_ann, *adf_bfo_ann, *adf_frq_ann; - SGPropertyNode *adf_flt_ann, *adf_et_ann, *adf_hdg, *hdg_bug; - SGPropertyNode *inner, *middle, *outer; - SGPropertyNode *xpdr_ident_btn; - SGPropertyNode *xpdr_digit1, *xpdr_digit2, *xpdr_digit3, *xpdr_digit4; - SGPropertyNode *xpdr_func_knob, *xpdr_id_code, *xpdr_flight_level; - SGPropertyNode *xpdr_fl_ann, *xpdr_alt_ann, *xpdr_gnd_ann, *xpdr_on_ann; - SGPropertyNode *xpdr_sby_ann, *xpdr_reply_ann; - SGPropertyNode *ati_bird, *alt_press; - - // Faults - SGPropertyNode *comm1_serviceable, *comm2_serviceable; - SGPropertyNode *nav1_serviceable, *nav2_serviceable; - SGPropertyNode *adf_serviceable, *xpdr_serviceable, *dme_serviceable; - - // Configuration values - SGPropertyNode *elevator_center, *elevator_min, *elevator_max; - SGPropertyNode *ailerons_center, *ailerons_min, *ailerons_max; - SGPropertyNode *rudder_center, *rudder_min, *rudder_max; - SGPropertyNode *brake_left_min, *brake_left_max; - SGPropertyNode *brake_right_min, *brake_right_max; - SGPropertyNode *throttle_min, *throttle_max; - SGPropertyNode *mixture_min, *mixture_max; - SGPropertyNode *trim_center, *trim_min, *trim_max; - SGPropertyNode *nav1vol_min, *nav1vol_max; - SGPropertyNode *nav2vol_min, *nav2vol_max; - - // raw switch positions - SGPropertyNode *dme_selector; - SGPropertyNode *ignore_flight_controls; - - int dme_switch; - - bool do_lights(); - bool do_radio_display(); - bool do_steppers(); - - // convenience - inline bool adf_has_power() const { - return (adf_bus_power->getDoubleValue() > 1.0) - && adf_power_btn->getBoolValue(); - } - inline bool dme_has_power() const { - return (dme_bus_power->getDoubleValue() > 1.0) - && dme_switch; - } - inline bool navcom1_has_power() const { - return (navcom1_bus_power->getDoubleValue() > 1.0) - && navcom1_power_btn->getBoolValue(); - } - inline bool navcom2_has_power() const { - return (navcom2_bus_power->getDoubleValue() > 1.0) - && navcom2_power_btn->getBoolValue(); - } - inline bool xpdr_has_power() const { - return (xpdr_bus_power->getDoubleValue() > 1.0) - && (xpdr_func_knob->getIntValue() > 0); - } - -public: - - 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(); - - void init_config(); - - bool process(); - - bool close(); - - 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; - } -}; - - -#endif // _FG_ATC610X_HXX