]> git.mxchange.org Git - flightgear.git/commitdiff
A new comm radio and atis implementation
authorTorsten Dreyer <torsten@t3r.de>
Wed, 19 Feb 2014 13:24:34 +0000 (14:24 +0100)
committerTorsten Dreyer <torsten@t3r.de>
Fri, 28 Feb 2014 10:45:49 +0000 (11:45 +0100)
23 files changed:
src/ATC/ATISEncoder.cxx [new file with mode: 0644]
src/ATC/ATISEncoder.hxx [new file with mode: 0644]
src/ATC/CMakeLists.txt
src/ATC/MetarPropertiesATISInformationProvider.cxx [new file with mode: 0644]
src/ATC/MetarPropertiesATISInformationProvider.hxx [new file with mode: 0644]
src/ATCDCL/CMakeLists.txt
src/Airports/airport.cxx
src/Airports/airport.hxx
src/Airports/dynamics.cxx
src/Airports/runways.cxx
src/Airports/runways.hxx
src/Environment/CMakeLists.txt
src/Instrumentation/CMakeLists.txt
src/Instrumentation/commradio.cxx [new file with mode: 0644]
src/Instrumentation/commradio.hxx [new file with mode: 0644]
src/Instrumentation/frequencyformatter.hxx [new file with mode: 0644]
src/Instrumentation/instrument_mgr.cxx
src/Instrumentation/newnavradio.cxx
src/Main/fg_init.cxx
src/Main/globals.cxx
src/Main/globals.hxx
src/Main/locale.cxx
src/Main/subsystemFactory.cxx

diff --git a/src/ATC/ATISEncoder.cxx b/src/ATC/ATISEncoder.cxx
new file mode 100644 (file)
index 0000000..5edc4b2
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+Encode an ATIS into spoken words
+Copyright (C) 2014 Torsten Dreyer
+
+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.
+*/
+
+#include "ATISEncoder.hxx"
+#include <Airports/dynamics.hxx>
+#include <Main/globals.hxx>
+#include <Main/locale.hxx>
+#include <simgear/structure/exception.hxx>
+#include <simgear/props/props_io.hxx>
+#include <boost/lexical_cast.hpp>
+
+#include <map>
+#include <vector>
+
+using std::string;
+using std::vector;
+using simgear::PropertyList;
+
+static string NO_ATIS("nil");
+static string EMPTY("");
+#define SPACE append(1,' ')
+
+const char * ATCSpeech::getSpokenDigit( int i )
+{
+  string key = "n" + boost::lexical_cast<std::string>( i );
+  return globals->get_locale()->getLocalizedString(key.c_str(), "atc", "" );
+}
+
+string ATCSpeech::getSpokenNumber( string number )
+{
+  string result;
+  for( string::iterator it = number.begin(); it != number.end(); ++it ) {
+    result.append( getSpokenDigit( (*it) - '0' )).SPACE;
+  }
+  return result;
+}
+
+string ATCSpeech::getSpokenNumber( int number, bool leadingZero, int digits )
+{
+  vector<const char *> spokenDigits;
+  int n = 0;
+  while( number > 0 ) {
+    spokenDigits.push_back( getSpokenDigit(number%10) );
+    number /= 10;
+    n++;
+  }
+
+  if( digits > 0 ) {
+    while( n++ < digits ) {
+      spokenDigits.push_back( getSpokenDigit(0) );
+    }
+  }
+
+  string result;
+  while( false == spokenDigits.empty() ) {
+    if( false == spokenDigits.empty() )
+      result.SPACE;
+
+    result.append( spokenDigits.back() );
+    spokenDigits.pop_back();
+  }
+
+  return result;
+}
+
+string ATCSpeech::getSpokenAltitude( int altitude )
+{
+  string result;
+  int thousands = altitude / 1000;
+  int hundrets = (altitude % 1000) / 100;
+
+  if( thousands > 0 ) {
+    result.append( getSpokenNumber(thousands) );
+    result.SPACE;
+    result.append( getSpokenDigit(1000) );
+    result.SPACE;
+  }
+  if( hundrets > 0 )
+      result.append( getSpokenNumber(hundrets) )
+            .SPACE
+            .append( getSpokenDigit(100) );
+
+  return result;
+}
+
+ATISEncoder::ATISEncoder()
+{
+  handlerMap.insert( std::make_pair( "text", &ATISEncoder::processTextToken ));
+  handlerMap.insert( std::make_pair( "token", &ATISEncoder::processTokenToken ));
+  handlerMap.insert( std::make_pair( "if", &ATISEncoder::processIfToken ));
+
+  handlerMap.insert( std::make_pair( "id", &ATISEncoder::getAtisId ));
+  handlerMap.insert( std::make_pair( "airport-name", &ATISEncoder::getAirportName ));
+  handlerMap.insert( std::make_pair( "time", &ATISEncoder::getTime ));
+  handlerMap.insert( std::make_pair( "approach-type", &ATISEncoder::getApproachType ));
+  handlerMap.insert( std::make_pair( "rwy-land", &ATISEncoder::getLandingRunway ));
+  handlerMap.insert( std::make_pair( "rwy-to", &ATISEncoder::getTakeoffRunway ));
+  handlerMap.insert( std::make_pair( "transition-level", &ATISEncoder::getTransitionLevel ));
+  handlerMap.insert( std::make_pair( "wind-dir", &ATISEncoder::getWindDirection ));
+  handlerMap.insert( std::make_pair( "wind-speed-kn", &ATISEncoder::getWindspeedKnots ));
+  handlerMap.insert( std::make_pair( "gusts", &ATISEncoder::getGustsKnots ));
+  handlerMap.insert( std::make_pair( "visibility-metric", &ATISEncoder::getVisibilityMetric ));
+  handlerMap.insert( std::make_pair( "phenomena", &ATISEncoder::getPhenomena ));
+  handlerMap.insert( std::make_pair( "clouds", &ATISEncoder::getClouds ));
+  handlerMap.insert( std::make_pair( "cavok", &ATISEncoder::getCavok ));
+  handlerMap.insert( std::make_pair( "temperature-deg", &ATISEncoder::getTemperatureDeg ));
+  handlerMap.insert( std::make_pair( "dewpoint-deg", &ATISEncoder::getDewpointDeg ));
+  handlerMap.insert( std::make_pair( "qnh", &ATISEncoder::getQnh ));
+  handlerMap.insert( std::make_pair( "inhg", &ATISEncoder::getInhg ));
+  handlerMap.insert( std::make_pair( "trend", &ATISEncoder::getTrend ));
+}
+
+ATISEncoder::~ATISEncoder()
+{
+}
+
+SGPropertyNode_ptr findAtisTemplate( const std::string & stationId, SGPropertyNode_ptr atisSchemaNode )
+{
+  using simgear::strutils::starts_with;
+  SGPropertyNode_ptr atisTemplate;
+
+  PropertyList schemaNodes = atisSchemaNode->getChildren("atis-schema");
+  for( PropertyList::iterator asit = schemaNodes.begin(); asit != schemaNodes.end(); ++asit ) {
+    SGPropertyNode_ptr ppp = (*asit)->getNode("station-starts-with", false );
+    atisTemplate = (*asit)->getNode("atis", false );
+    if( false == atisTemplate.valid() ) continue; // no <atis> node - ignore entry
+
+    PropertyList startsWithNodes = (*asit)->getChildren("station-starts-with");
+    for( PropertyList::iterator swit = startsWithNodes.begin(); swit != startsWithNodes.end(); ++swit ) {
+   
+      if( starts_with( stationId,  (*swit)->getStringValue() ) ) {
+        return atisTemplate;
+      }
+    }
+
+  }
+
+  return atisTemplate;
+}
+
+string ATISEncoder::encodeATIS( ATISInformationProvider * atisInformation )
+{
+  using simgear::strutils::lowercase;
+
+  if( false == atisInformation->isValid() ) return NO_ATIS;
+
+  airport = FGAirport::getByIdent( atisInformation->airportId() );
+  if( false == airport.valid() ) {
+    SG_LOG( SG_ATC, SG_WARN, "ATISEncoder: unknown airport id " << atisInformation->airportId() );
+    return NO_ATIS;
+  }
+
+  _atis = atisInformation;
+
+  // lazily load the schema file on the first call
+  if( false == atisSchemaNode.valid() ) {
+    atisSchemaNode = new SGPropertyNode();
+    try
+    {
+      SGPath path = globals->resolve_maybe_aircraft_path("ATC/atis.xml");
+      readProperties( path.str(), atisSchemaNode );
+    }
+    catch (const sg_exception& e)
+    {
+      SG_LOG( SG_ATC, SG_ALERT, "ATISEncoder: Failed to load atis schema definition: " << e.getMessage());
+      return NO_ATIS;
+    }
+  }
+
+  string stationId = lowercase( airport->ident() );
+  
+  SGPropertyNode_ptr atisTemplate = findAtisTemplate( stationId, atisSchemaNode );;
+  if( false == atisTemplate.valid() ) {
+    SG_LOG(SG_ATC, SG_WARN, "no matching atis template for station " << stationId  );
+    return NO_ATIS; // no template for this station!?
+  }
+
+  return processTokens( atisTemplate );
+}
+
+string ATISEncoder::processTokens( SGPropertyNode_ptr node )
+{
+  string result;
+  if( node.valid() ) {
+    for( int i = 0; i < node->nChildren(); i++ ) {
+      result.append(processToken( node->getChild(i) ));
+    }
+  }
+  return result;
+}
+
+string ATISEncoder::processToken( SGPropertyNode_ptr token ) 
+{
+  HandlerMap::iterator it = handlerMap.find( token->getName());
+  if( it == handlerMap.end() ) {
+    SG_LOG(SG_ATC, SG_WARN, "ATISEncoder: unknown token: " << token->getName() );
+    return EMPTY;
+  }
+  handler_t h = it->second;
+  return (this->*h)( token );
+}
+
+string ATISEncoder::processTextToken( SGPropertyNode_ptr token )
+{
+  return token->getStringValue();
+}
+
+string ATISEncoder::processTokenToken( SGPropertyNode_ptr token )
+{
+  HandlerMap::iterator it = handlerMap.find( token->getStringValue());
+  if( it == handlerMap.end() ) {
+    SG_LOG(SG_ATC, SG_WARN, "ATISEncoder: unknown token: " << token->getStringValue() );
+    return EMPTY;
+  }
+  handler_t h = it->second;
+  return (this->*h)( token );
+
+  token->getStringValue();
+}
+
+string ATISEncoder::processIfToken( SGPropertyNode_ptr token )
+{
+  SGPropertyNode_ptr n;
+
+  if( (n = token->getChild("empty", false )).valid() ) {
+    return checkEmptyCondition( n, true) ? 
+           processTokens(token->getChild("then",false)) : 
+           processTokens(token->getChild("else",false));
+  }
+
+  if( (n = token->getChild("not-empty", false )).valid() ) {
+    return checkEmptyCondition( n, false) ? 
+           processTokens(token->getChild("then",false)) : 
+           processTokens(token->getChild("else",false));
+  }
+
+  if( (n = token->getChild("equals", false )).valid() ) {
+    return checkEqualsCondition( n, true) ? 
+           processTokens(token->getChild("then",false)) : 
+           processTokens(token->getChild("else",false));
+  }
+
+  if( (n = token->getChild("not-equals", false )).valid() ) {
+    return checkEqualsCondition( n, false) ? 
+           processTokens(token->getChild("then",false)) : 
+           processTokens(token->getChild("else",false));
+  }
+
+  SG_LOG(SG_ATC, SG_WARN, "ATISEncoder: no valid token found for <if> element" );
+
+  return EMPTY;
+}
+
+bool ATISEncoder::checkEmptyCondition( SGPropertyNode_ptr node, bool isEmpty ) 
+{
+  SGPropertyNode_ptr n1 = node->getNode( "token", false );
+  if( false == n1.valid() ) {
+      SG_LOG(SG_ATC, SG_WARN, "missing <token> node for (not)-empty"  );
+      return false;
+  }
+  return processToken( n1 ).empty() == isEmpty;
+}
+
+bool ATISEncoder::checkEqualsCondition( SGPropertyNode_ptr node, bool isEqual ) 
+{
+  SGPropertyNode_ptr n1 = node->getNode( "token", 0, false );
+  SGPropertyNode_ptr n2 = node->getNode( "token", 1, false );
+  if( false == n1.valid() || false == n2.valid()) {
+    SG_LOG(SG_ATC, SG_WARN, "missing <token> node for (not)-equals"  );
+    return false;
+  }
+
+  bool comp = processToken( n1 ).compare( processToken( n2 ) ) == 0;
+  return comp == isEqual;
+}
+
+string ATISEncoder::getAtisId( SGPropertyNode_ptr )
+{
+  FGAirportDynamics * dynamics = airport->getDynamics();
+  if( NULL != dynamics ) {
+    dynamics->updateAtisSequence( 30*60, false );
+    return dynamics->getAtisSequence();
+  }
+  return EMPTY;
+}
+
+string ATISEncoder::getAirportName( SGPropertyNode_ptr )
+{
+  return airport->getName();
+}
+
+string ATISEncoder::getTime( SGPropertyNode_ptr )
+{
+  return getSpokenNumber( _atis->getTime() % (100*100), true, 4 );
+}
+
+static inline FGRunwayRef findBestRunwayForWind( FGAirportRef airport, int windDeg, int windKt )
+{
+  struct FGAirport::FindBestRunwayForHeadingParams p;
+  //TODO: ramp down the heading weight with wind speed
+  p.ilsWeight = 4;
+  return airport->findBestRunwayForHeading( windDeg, &p );
+}
+
+string ATISEncoder::getApproachType( SGPropertyNode_ptr )
+{
+  FGRunwayRef runway = findBestRunwayForWind( airport, _atis->getWindDeg(), _atis->getWindSpeedKt() );
+  if( runway.valid() ) {
+    if( NULL != runway->ILS() ) return globals->get_locale()->getLocalizedString("ils", "atc", "ils" );
+    //TODO: any chance to find other approach types? localizer-dme, vor-dme, vor, ndb?
+  }
+
+  return globals->get_locale()->getLocalizedString("visual", "atc", "visual" );
+}
+
+string ATISEncoder::getLandingRunway( SGPropertyNode_ptr )
+{
+  FGRunwayRef runway = findBestRunwayForWind( airport, _atis->getWindDeg(), _atis->getWindSpeedKt() );
+  if( runway.valid() ) {
+    string runwayIdent = runway->ident();
+    if(runwayIdent != "NN") {
+      return getSpokenNumber(runwayIdent);
+    }
+  }
+  return EMPTY;
+}
+
+string ATISEncoder::getTakeoffRunway( SGPropertyNode_ptr p )
+{
+  //TODO: if the airport has more than one runway, probably pick another one?
+  return getLandingRunway( p );
+}
+
+string ATISEncoder::getTransitionLevel( SGPropertyNode_ptr )
+{
+  double hPa = _atis->getQnh();
+
+  /* Transition level is the flight level above which aircraft must use standard pressure and below
+   * which airport pressure settings must be used.
+   * Following definitions are taken from German ATIS:
+   *      QNH <=  977 hPa: TRL 80
+   *      QNH <= 1013 hPa: TRL 70
+   *      QNH >  1013 hPa: TRL 60
+   * (maybe differs slightly for other countries...)
+   */
+  int tl;
+  if (hPa <= 978) {
+    tl = 80;
+  } else if( hPa > 978 && hPa <= 1013 ) {
+    tl = 70;
+  } else if( hPa > 1013 && hPa <= 1046 ) {
+    tl = 60;
+  } else {
+    tl = 50;
+  }
+
+  // add an offset to the transition level for high altitude airports (just guessing here,
+  // seems reasonable)
+  int e = int(airport->getElevation() / 1000.0);
+  if (e >= 3) {
+    // TL steps in 10(00)ft
+    tl += (e-2)*10;
+  }
+
+  return getSpokenNumber(tl);
+}
+
+string ATISEncoder::getWindDirection( SGPropertyNode_ptr )
+{
+  return getSpokenNumber( _atis->getWindDeg() );
+}
+
+string ATISEncoder::getWindspeedKnots( SGPropertyNode_ptr )
+{
+  return getSpokenNumber( _atis->getWindSpeedKt() );
+}
+
+string ATISEncoder::getGustsKnots( SGPropertyNode_ptr )
+{
+  int g = _atis->getGustsKt();
+  return g > 0 ? getSpokenNumber( g ) : EMPTY;
+}
+
+string ATISEncoder::getCavok( SGPropertyNode_ptr )
+{
+  string CAVOK = globals->get_locale()->getLocalizedString("cavok", "atc", "cavok" );
+
+  return _atis->isCavok() ? CAVOK : EMPTY;
+}
+
+string ATISEncoder::getVisibilityMetric( SGPropertyNode_ptr )
+{
+  string m = globals->get_locale()->getLocalizedString("meters", "atc", "meters" );
+  string km = globals->get_locale()->getLocalizedString("kilometersmeters", "atc", "kilometersmeters" );
+  string or_more = globals->get_locale()->getLocalizedString("ormore", "atc", "or more" );
+
+  int v = _atis->getVisibilityMeters();
+  string reply;
+  if( v < 5000 ) return reply.append( getSpokenAltitude( v ) ).SPACE.append( m );
+  if( v >= 10000 ) return reply.append( getSpokenNumber(10) ).SPACE.append( km ).SPACE.append(or_more);
+  return reply.append( getSpokenNumber( v/1000 ).append( km ) );
+}
+
+string ATISEncoder::getPhenomena( SGPropertyNode_ptr )
+{
+  return _atis->getPhenomena();
+}
+
+string ATISEncoder::getClouds( SGPropertyNode_ptr )
+{
+  string FEET =  globals->get_locale()->getLocalizedString("feet", "atc", "feet" );
+  string reply;
+
+  ATISInformationProvider::CloudEntries cloudEntries = _atis->getClouds();
+
+  for( ATISInformationProvider::CloudEntries::iterator it = cloudEntries.begin(); it != cloudEntries.end(); it++ ) {
+    if( false == reply.empty() ) reply.SPACE;
+    reply.append( it->second ).SPACE.append( getSpokenAltitude(it->first).SPACE.append( FEET ) );
+  }
+  return reply;
+}
+
+string ATISEncoder::getTemperatureDeg( SGPropertyNode_ptr )
+{
+  return getSpokenNumber( _atis->getTemperatureDeg() );
+}
+
+string ATISEncoder::getDewpointDeg( SGPropertyNode_ptr )
+{
+  return getSpokenNumber( _atis->getDewpointDeg() );
+}
+
+string ATISEncoder::getQnh( SGPropertyNode_ptr )
+{
+  return getSpokenNumber( _atis->getQnh() );
+}
+
+string ATISEncoder::getInhg( SGPropertyNode_ptr )
+{
+  string DECIMAL = globals->get_locale()->getLocalizedString("dp", "atc", "decimal" );
+  double intpart = .0;
+  int fractpart = 1000 * ::modf( _atis->getQnh() * 100.0 / SG_INHG_TO_PA, &intpart );
+  fractpart += 5;
+  fractpart /= 10; 
+
+  string reply;
+  reply.append( getSpokenNumber( (int)intpart ) )
+       .append( DECIMAL ).SPACE
+       .append( getSpokenNumber( fractpart ) );
+  return reply;
+}
+
+string ATISEncoder::getTrend( SGPropertyNode_ptr )
+{
+  return _atis->getTrend();
+}
+
diff --git a/src/ATC/ATISEncoder.hxx b/src/ATC/ATISEncoder.hxx
new file mode 100644 (file)
index 0000000..2696929
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+Encode an ATIS into spoken words
+Copyright (C) 2014 Torsten Dreyer
+
+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.
+*/
+
+#ifndef __ATIS_ENCODER_HXX
+#define __ATIS_ENCODER_HXX
+
+#include <string>
+#include <Airports/airport.hxx>
+#include <simgear/props/props.hxx>
+#include <map>
+
+class ATCSpeech {
+public:
+    static const char * getSpokenDigit( int i );
+    static std::string getSpokenNumber( std::string number );
+    static std::string getSpokenNumber( int number, bool leadingZero = false, int digits = 1 );
+    static std::string getSpokenAltitude( int altitude );
+};
+
+class ATISInformationProvider {
+public:
+    virtual ~ATISInformationProvider() {}
+    virtual bool isValid() = 0;
+    virtual std::string airportId() = 0;
+
+    static long makeAtisTime( int day, int hour, int minute ) {
+      return  100*100l* day + 100l * hour + minute;
+    }
+    inline int getAtisTimeDay( long atisTime ) { return atisTime / (100l*100l); }
+    inline int getAtisTimeHour( long atisTime ) { return (atisTime % (100l*100l)) / 100l; }
+    inline int getAtisTimeMinute( long atisTime ) { return atisTime % 100l; }
+    virtual long getTime() = 0; // see makeAtisTime
+
+    virtual int getWindDeg() = 0;
+    virtual int getWindSpeedKt() = 0;
+    virtual int getGustsKt() = 0;
+    virtual int getQnh() = 0;
+    virtual bool isCavok() = 0;
+    virtual int getVisibilityMeters() = 0;
+    virtual std::string getPhenomena() = 0;
+
+    typedef std::map<int,std::string> CloudEntries;
+    virtual CloudEntries getClouds() = 0;
+    virtual int getTemperatureDeg() = 0;
+    virtual int getDewpointDeg() = 0;
+    virtual std::string getTrend() = 0;
+};
+
+class ATISEncoder : public ATCSpeech {
+public:
+  ATISEncoder();
+  virtual ~ATISEncoder();
+  virtual std::string encodeATIS( ATISInformationProvider * atisInformationProvider );
+
+protected:
+  virtual std::string getAtisId( SGPropertyNode_ptr );
+  virtual std::string getAirportName( SGPropertyNode_ptr );
+  virtual std::string getTime( SGPropertyNode_ptr );
+  virtual std::string getApproachType( SGPropertyNode_ptr );
+  virtual std::string getLandingRunway( SGPropertyNode_ptr );
+  virtual std::string getTakeoffRunway( SGPropertyNode_ptr );
+  virtual std::string getTransitionLevel( SGPropertyNode_ptr );
+  virtual std::string getWindDirection( SGPropertyNode_ptr );
+  virtual std::string getWindspeedKnots( SGPropertyNode_ptr );
+  virtual std::string getGustsKnots( SGPropertyNode_ptr );
+  virtual std::string getCavok( SGPropertyNode_ptr );
+  virtual std::string getVisibilityMetric( SGPropertyNode_ptr );
+  virtual std::string getPhenomena( SGPropertyNode_ptr );
+  virtual std::string getClouds( SGPropertyNode_ptr );
+  virtual std::string getTemperatureDeg( SGPropertyNode_ptr );
+  virtual std::string getDewpointDeg( SGPropertyNode_ptr );
+  virtual std::string getQnh( SGPropertyNode_ptr );
+  virtual std::string getInhg( SGPropertyNode_ptr );
+  virtual std::string getTrend( SGPropertyNode_ptr );
+
+  typedef std::string (ATISEncoder::*handler_t)( SGPropertyNode_ptr baseNode );
+  typedef std::map<std::string, handler_t > HandlerMap;
+  HandlerMap handlerMap;
+
+  SGPropertyNode_ptr atisSchemaNode;
+
+  std::string processTokens( SGPropertyNode_ptr baseNode );
+  std::string processToken( SGPropertyNode_ptr baseNode );
+
+  std::string processTextToken( SGPropertyNode_ptr baseNode );
+  std::string processTokenToken( SGPropertyNode_ptr baseNode );
+  std::string processIfToken( SGPropertyNode_ptr baseNode );
+  bool checkEmptyCondition( SGPropertyNode_ptr node, bool isEmpty );
+  bool checkEqualsCondition( SGPropertyNode_ptr node, bool isEmpty );
+
+  FGAirportRef airport;
+  ATISInformationProvider * _atis;
+};
+
+#endif
index f7dd1f2dfb0820105cb63bcc3272111742147e54..35b48884a82e0f58ec896e2216e64ec53c4354de 100644 (file)
@@ -5,6 +5,8 @@ set(SOURCES
        atcdialog.cxx
        trafficcontrol.cxx
        CommStation.cxx
        atcdialog.cxx
        trafficcontrol.cxx
        CommStation.cxx
+        ATISEncoder.cxx
+        MetarPropertiesATISInformationProvider.cxx
        )
 
 set(HEADERS
        )
 
 set(HEADERS
@@ -12,6 +14,8 @@ set(HEADERS
        atcdialog.hxx
        trafficcontrol.hxx
        CommStation.hxx
        atcdialog.hxx
        trafficcontrol.hxx
        CommStation.hxx
+        ATISEncoder.hxx
+        MetarPropertiesATISInformationProvider.hxx
        )
        
 flightgear_component(ATC "${SOURCES}" "${HEADERS}")
        )
        
 flightgear_component(ATC "${SOURCES}" "${HEADERS}")
diff --git a/src/ATC/MetarPropertiesATISInformationProvider.cxx b/src/ATC/MetarPropertiesATISInformationProvider.cxx
new file mode 100644 (file)
index 0000000..4a68792
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+Provide Data for the ATIS Encoder from metarproperties
+Copyright (C) 2014 Torsten Dreyer
+
+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.
+*/
+
+#include "MetarPropertiesATISInformationProvider.hxx"
+#include <Main/globals.hxx>
+#include <simgear/constants.h>
+
+using std::string;
+
+static string EMPTY("");
+static string CAVOK("cavok");
+MetarPropertiesATISInformationProvider::MetarPropertiesATISInformationProvider( SGPropertyNode_ptr metar ) :
+  _metar( metar )
+{
+}
+
+MetarPropertiesATISInformationProvider::~MetarPropertiesATISInformationProvider()
+{
+}
+
+bool MetarPropertiesATISInformationProvider::isValid()
+{
+  return _metar->getBoolValue( "valid", false );
+}
+
+string MetarPropertiesATISInformationProvider::airportId()
+{
+  return _metar->getStringValue( "station-id", "xxxx" );
+}
+
+long MetarPropertiesATISInformationProvider::getTime()
+{
+  return makeAtisTime( 0,
+    _metar->getIntValue( "hour" ) % 24, 
+    _metar->getIntValue( "minute" ) % 60 );
+}
+
+int MetarPropertiesATISInformationProvider::getWindDeg()
+{
+   return _metar->getIntValue( "base-wind-dir-deg" );
+}
+
+int MetarPropertiesATISInformationProvider::getWindSpeedKt()
+{
+  return _metar->getIntValue( "base-wind-speed-kt" );
+}
+
+int MetarPropertiesATISInformationProvider::getGustsKt()
+{
+  return _metar->getIntValue( "gust-wind-speed-kt" );
+}
+
+
+int MetarPropertiesATISInformationProvider::getQnh()
+{
+  return _metar->getDoubleValue("pressure-sea-level-inhg") * SG_INHG_TO_PA / 100.0;
+}
+
+bool MetarPropertiesATISInformationProvider::isCavok()
+{
+  return _metar->getBoolValue( "cavok" );
+}
+
+int MetarPropertiesATISInformationProvider::getVisibilityMeters()
+{
+  return _metar->getIntValue( "min-visibility-m" );
+}
+
+string MetarPropertiesATISInformationProvider::getPhenomena()
+{
+  return _metar->getStringValue( "decoded" );
+}
+
+ATISInformationProvider::CloudEntries MetarPropertiesATISInformationProvider::getClouds()
+{
+  CloudEntries reply;
+
+  using simgear::PropertyList;
+  PropertyList layers = _metar->getNode("clouds", true )->getChildren("layer");
+  for( PropertyList::iterator it = layers.begin(); it != layers.end(); ++it ) {
+    const char * coverage = (*it)->getStringValue("coverage","clear");
+    double elevation = (*it)->getDoubleValue("elevation-ft", -9999 );
+    if( elevation > 0 ) {
+      reply[elevation] = coverage;
+    }
+  }
+  return reply;
+}
+
+int MetarPropertiesATISInformationProvider::getTemperatureDeg()
+{
+  return _metar->getIntValue( "temperature-degc" );
+}
+
+int MetarPropertiesATISInformationProvider::getDewpointDeg()
+{
+  return _metar->getIntValue( "dewpoint-degc" );
+}
+
+string MetarPropertiesATISInformationProvider::getTrend()
+{
+  return "nosig";
+}
+
diff --git a/src/ATC/MetarPropertiesATISInformationProvider.hxx b/src/ATC/MetarPropertiesATISInformationProvider.hxx
new file mode 100644 (file)
index 0000000..95b2b4d
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+Provide Data for the ATIS Encoder from metarproperties
+Copyright (C) 2014 Torsten Dreyer
+
+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.
+*/
+
+#ifndef __METARPROPERTIES_ATIS_ENCODER_HXX
+#define __METARPROPERTIES_ATIS_ENCODER_HXX
+
+/* ATIS encoder from metarproperties */
+
+#include <simgear/props/props.hxx>
+
+#include <string>
+#include "ATISEncoder.hxx"
+
+class MetarPropertiesATISInformationProvider : public ATISInformationProvider
+{
+public:
+    MetarPropertiesATISInformationProvider( SGPropertyNode_ptr metar );
+    virtual ~MetarPropertiesATISInformationProvider();
+
+protected:
+    virtual bool isValid();
+    virtual std::string airportId();
+    virtual long getTime();
+    virtual int getWindDeg();
+    virtual int getWindSpeedKt();
+    virtual int getGustsKt();
+    virtual int getQnh();
+    virtual bool isCavok();
+    virtual int getVisibilityMeters();
+    virtual std::string getPhenomena();
+    virtual CloudEntries getClouds();
+    virtual int getTemperatureDeg();
+    virtual int getDewpointDeg();
+    virtual std::string getTrend();
+#if 0
+    virtual std::string getStationId();
+    virtual std::string getAtisId();
+    virtual std::string getTime();
+    virtual std::string getApproachType();
+    virtual std::string getLandingRunway();
+    virtual std::string getTakeoffRunway();
+    virtual std::string getTransitionLevel();
+    virtual std::string getWindDirection();
+    virtual std::string getWindspeedKnots();
+    virtual std::string getGustsKnots();
+    virtual std::string getVisibilityMetric();
+    virtual std::string getPhenomena();
+    virtual std::string getClouds();
+    virtual std::string getCavok();
+    virtual std::string getTemperatureDeg();
+    virtual std::string getDewpointDeg();
+    virtual std::string getQnh();
+    virtual std::string getTrend();
+#endif
+private:
+    SGPropertyNode_ptr _metar;
+};
+
+#endif
index fd1a3736b07914abed13226048df969909741ddd..98d253a97d09f9c2a026926aa59289ee97972953 100644 (file)
@@ -1,23 +1,11 @@
 include(FlightGearComponent)
 
 set(SOURCES
 include(FlightGearComponent)
 
 set(SOURCES
-       ATC.cxx
-       atis.cxx
-       ATCVoice.cxx
-       ATISmgr.cxx
-       ATCutils.cxx
        ATCProjection.cxx
        )
 
 set(HEADERS
        ATCProjection.cxx
        )
 
 set(HEADERS
-       ATC.hxx
-       atis.hxx
-       ATCVoice.hxx
-       ATISmgr.hxx
-       ATCutils.hxx
        ATCProjection.hxx
        ATCProjection.hxx
-       atis_lexicon.hxx
-       atis_remap.hxx
        )
        
 flightgear_component(ATCDCL "${SOURCES}" "${HEADERS}")
        )
        
 flightgear_component(ATCDCL "${SOURCES}" "${HEADERS}")
index 1a1fa7b1a1a50b27229a09e9c8e9104f8f047b60..5a511eb996854c32042aed4b34eaa76ee73b1862 100644 (file)
@@ -236,18 +236,24 @@ FGHelipadRef FGAirport::getHelipadByIdent(const std::string& aIdent) const
 }
 
 //------------------------------------------------------------------------------
 }
 
 //------------------------------------------------------------------------------
-FGRunwayRef FGAirport::findBestRunwayForHeading(double aHeading) const
+FGRunwayRef FGAirport::findBestRunwayForHeading(double aHeading, struct FindBestRunwayForHeadingParams * parms ) const
 {
   loadRunways();
   
   FGRunway* result = NULL;
   double currentBestQuality = 0.0;
   
 {
   loadRunways();
   
   FGRunway* result = NULL;
   double currentBestQuality = 0.0;
   
-  SGPropertyNode *param = fgGetNode("/sim/airport/runways/search", true);
-  double lengthWeight = param->getDoubleValue("length-weight", 0.01);
-  double widthWeight = param->getDoubleValue("width-weight", 0.01);
-  double surfaceWeight = param->getDoubleValue("surface-weight", 10);
-  double deviationWeight = param->getDoubleValue("deviation-weight", 1);
+  struct FindBestRunwayForHeadingParams fbrfhp;
+  if( NULL != parms ) fbrfhp = *parms;
+
+  SGPropertyNode_ptr searchNode = fgGetNode("/sim/airport/runways/search");
+  if( searchNode.valid() ) {
+    fbrfhp.lengthWeight = searchNode->getDoubleValue("length-weight", fbrfhp.lengthWeight );
+    fbrfhp.widthWeight = searchNode->getDoubleValue("width-weight", fbrfhp.widthWeight );
+    fbrfhp.surfaceWeight = searchNode->getDoubleValue("surface-weight", fbrfhp.surfaceWeight );
+    fbrfhp.deviationWeight = searchNode->getDoubleValue("deviation-weight", fbrfhp.deviationWeight );
+    fbrfhp.ilsWeight = searchNode->getDoubleValue("ils-weight", fbrfhp.ilsWeight );
+  }
     
   BOOST_FOREACH(PositionedID id, mRunways) {
     FGRunway* rwy = loadById<FGRunway>(id);
     
   BOOST_FOREACH(PositionedID id, mRunways) {
     FGRunway* rwy = loadById<FGRunway>(id);
@@ -257,10 +263,10 @@ FGRunwayRef FGAirport::findBestRunwayForHeading(double aHeading) const
       continue;
     }
       
       continue;
     }
       
-    double good = rwy->score(lengthWeight, widthWeight, surfaceWeight);
+    double good = rwy->score( fbrfhp.lengthWeight,  fbrfhp.widthWeight,  fbrfhp.surfaceWeight,  fbrfhp.ilsWeight );
     double dev = aHeading - rwy->headingDeg();
     SG_NORMALIZE_RANGE(dev, -180.0, 180.0);
     double dev = aHeading - rwy->headingDeg();
     SG_NORMALIZE_RANGE(dev, -180.0, 180.0);
-    double bad = fabs(deviationWeight * dev) + 1e-20;
+    double bad = fabs( fbrfhp.deviationWeight * dev) + 1e-20;
     double quality = good / bad;
     
     if (quality > currentBestQuality) {
     double quality = good / bad;
     
     if (quality > currentBestQuality) {
index a35354075fda71c412e81cbd4c9c0bd064b98302..8301069802ea1a6f6e9c4a987acd5d06838614cf 100644 (file)
@@ -94,7 +94,22 @@ class FGAirport : public FGPositioned
     bool hasHelipadWithIdent(const std::string& aIdent) const;
     FGRunwayRef getRunwayByIdent(const std::string& aIdent) const;
     FGHelipadRef getHelipadByIdent(const std::string& aIdent) const;
     bool hasHelipadWithIdent(const std::string& aIdent) const;
     FGRunwayRef getRunwayByIdent(const std::string& aIdent) const;
     FGHelipadRef getHelipadByIdent(const std::string& aIdent) const;
-    FGRunwayRef findBestRunwayForHeading(double aHeading) const;
+
+    struct FindBestRunwayForHeadingParams {
+      FindBestRunwayForHeadingParams() {
+        lengthWeight =  0.01;
+        widthWeight =  0.01;
+        surfaceWeight =  10;
+        deviationWeight =  1;
+        ilsWeight = 0;
+      }
+      double lengthWeight;
+      double widthWeight;
+      double surfaceWeight;
+      double deviationWeight;
+      double ilsWeight;
+    };
+    FGRunwayRef findBestRunwayForHeading(double aHeading, struct FindBestRunwayForHeadingParams * parms = NULL ) const;
     
     /**
      * return the most likely target runway based on a position.
     
     /**
      * return the most likely target runway based on a position.
index a88a44149d48bec8cc96592f4aa14081c116aabd..5916c68b0645080e0933249d3833bb040bfb7cb7 100644 (file)
@@ -38,8 +38,8 @@
 #include <simgear/debug/logstream.hxx>
 #include <Main/globals.hxx>
 #include <Main/fg_props.hxx>
 #include <simgear/debug/logstream.hxx>
 #include <Main/globals.hxx>
 #include <Main/fg_props.hxx>
+#include <Main/locale.hxx>
 #include <Airports/runways.hxx>
 #include <Airports/runways.hxx>
-#include <ATCDCL/ATCutils.hxx>
 #include <Navaids/NavDataCache.hxx>
 
 #include "airport.hxx"
 #include <Navaids/NavDataCache.hxx>
 
 #include "airport.hxx"
@@ -530,8 +530,12 @@ const std::string FGAirportDynamics::getAtisSequence()
    if (atisSequenceIndex == -1) {
        updateAtisSequence(1, false);
    }
    if (atisSequenceIndex == -1) {
        updateAtisSequence(1, false);
    }
+
+   char atisSequenceString[2];
+   atisSequenceString[0] = 'a' + atisSequenceIndex;
+   atisSequenceString[1] = 0;
    
    
-   return GetPhoneticLetter(atisSequenceIndex);
+   return globals->get_locale()->getLocalizedString(atisSequenceString, "atc", "unknown");
 }
 
 int FGAirportDynamics::updateAtisSequence(int interval, bool forceUpdate)
 }
 
 int FGAirportDynamics::updateAtisSequence(int interval, bool forceUpdate)
@@ -540,7 +544,7 @@ int FGAirportDynamics::updateAtisSequence(int interval, bool forceUpdate)
     if (atisSequenceIndex == -1) {
         // first computation
         atisSequenceTimeStamp = now;
     if (atisSequenceIndex == -1) {
         // first computation
         atisSequenceTimeStamp = now;
-        atisSequenceIndex = rand() % LTRS; // random initial sequence letters
+        atisSequenceIndex = rand() % 26; // random initial sequence letters
         return atisSequenceIndex;
     }
 
         return atisSequenceIndex;
     }
 
@@ -550,7 +554,7 @@ int FGAirportDynamics::updateAtisSequence(int interval, bool forceUpdate)
         ++steps; // a "special" ATIS update is required
     } 
     
         ++steps; // a "special" ATIS update is required
     } 
     
-    atisSequenceIndex = (atisSequenceIndex + steps) % LTRS;
+    atisSequenceIndex = (atisSequenceIndex + steps) % 26;
     // return a huge value if no update occurred
     // return a huge value if no update occurred
-    return (atisSequenceIndex + (steps ? 0 : LTRS*1000));
+    return (atisSequenceIndex + (steps ? 0 : 26*1000));
 }
 }
index 4dc8660767be7d0dc745f8a72af91148385c356f..9f2291f7ba90f31f10f31da246a4a978975572d4 100644 (file)
@@ -96,15 +96,17 @@ string FGRunway::reverseIdent(const string& aRunwayIdent)
   return buf;
 }
 
   return buf;
 }
 
-double FGRunway::score(double aLengthWt, double aWidthWt, double aSurfaceWt) const
+double FGRunway::score(double aLengthWt, double aWidthWt, double aSurfaceWt, double aIlsWt) const
 {
   int surface = 1;
   if (_surface_code == 12 || _surface_code == 5) // dry lakebed & gravel
     surface = 2;
   else if (_surface_code == 1 || _surface_code == 2) // asphalt & concrete
     surface = 3;
 {
   int surface = 1;
   if (_surface_code == 12 || _surface_code == 5) // dry lakebed & gravel
     surface = 2;
   else if (_surface_code == 1 || _surface_code == 2) // asphalt & concrete
     surface = 3;
+
+  int ils = (_ils != 0);
     
     
-  return _length * aLengthWt + _width * aWidthWt + surface * aSurfaceWt + 1e-20;
+  return _length * aLengthWt + _width * aWidthWt + surface * aSurfaceWt + ils * aIlsWt + 1e-20;
 }
 
 SGGeod FGRunway::begin() const
 }
 
 SGGeod FGRunway::begin() const
index ae440475359793e4090e30a89179dbd110fbcf76..e795d9ee5c9cc3fcdaea53799ae87a7326a7c54d 100644 (file)
@@ -58,7 +58,7 @@ public:
    * score this runway according to the specified weights. Used by
    * FGAirport::findBestRunwayForHeading
    */
    * score this runway according to the specified weights. Used by
    * FGAirport::findBestRunwayForHeading
    */
-  double score(double aLengthWt, double aWidthWt, double aSurfaceWt) const;
+  double score(double aLengthWt, double aWidthWt, double aSurfaceWt, double aIlsWt) const;
 
   /**
    * Get the runway beginning point - this is syntatic sugar, equivalent to
 
   /**
    * Get the runway beginning point - this is syntatic sugar, equivalent to
index e75dde258693cba999603796cdef644c91c531b5..ccff9f7e0fa43944448840bedcb3f3d0e8122b91 100644 (file)
@@ -17,7 +17,7 @@ set(SOURCES
        terrainsampler.cxx
        presets.cxx
        gravity.cxx
        terrainsampler.cxx
        presets.cxx
        gravity.cxx
-    magvarmanager.cxx
+        magvarmanager.cxx
        )
 
 set(HEADERS
        )
 
 set(HEADERS
@@ -37,7 +37,7 @@ set(HEADERS
        terrainsampler.hxx
        presets.hxx
        gravity.hxx
        terrainsampler.hxx
        presets.hxx
        gravity.hxx
-    magvarmanager.hxx
+        magvarmanager.hxx
        )
                
 flightgear_component(Environment "${SOURCES}" "${HEADERS}")
        )
                
 flightgear_component(Environment "${SOURCES}" "${HEADERS}")
index a955a3cd394296a26434d2627cef4b19263cfedb..ee3cd55fce58f219c36a57449f17bf179de5c9c3 100644 (file)
@@ -23,6 +23,7 @@ set(SOURCES
     mrg.cxx
     navradio.cxx
     newnavradio.cxx
     mrg.cxx
     navradio.cxx
     newnavradio.cxx
+    commradio.cxx
     rad_alt.cxx
     rnav_waypt_controller.cxx
     slip_skid_ball.cxx
     rad_alt.cxx
     rnav_waypt_controller.cxx
     slip_skid_ball.cxx
@@ -83,6 +84,7 @@ set(HEADERS
     mrg.hxx
     navradio.hxx
     newnavradio.hxx
     mrg.hxx
     navradio.hxx
     newnavradio.hxx
+    commradio.hxx
     rad_alt.hxx
     rnav_waypt_controller.hxx
     slip_skid_ball.hxx
     rad_alt.hxx
     rnav_waypt_controller.hxx
     slip_skid_ball.hxx
diff --git a/src/Instrumentation/commradio.cxx b/src/Instrumentation/commradio.cxx
new file mode 100644 (file)
index 0000000..a16fe60
--- /dev/null
@@ -0,0 +1,384 @@
+// commradio.cxx -- class to manage a nav radio instance
+//
+// Written by Torsten Dreyer, February 2014
+//
+// Copyright (C) 2000 - 2011  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.
+//
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "commradio.hxx"
+
+#include <assert.h>
+#include <boost/foreach.hpp>
+
+#include <simgear/sg_inlines.h>
+#include <simgear/props/propertyObject.hxx>
+#include <simgear/misc/strutils.hxx>
+
+#include <ATC/CommStation.hxx>
+#include <ATC/MetarPropertiesATISInformationProvider.hxx>
+#include <Airports/airport.hxx>
+#include <Main/fg_props.hxx>
+#include <Navaids/navlist.hxx>
+
+#include "frequencyformatter.hxx"
+
+namespace Instrumentation {
+
+using simgear::PropertyObject;
+using std::string;
+
+
+SignalQualityComputer::~SignalQualityComputer()
+{
+}
+
+class SimpleDistanceSquareSignalQualityComputer : public SignalQualityComputer
+{
+public:
+  SimpleDistanceSquareSignalQualityComputer( double range ) : _rangeM(range), _rangeM2(range*range) {}
+  virtual double computeSignalQuality( const SGGeod & sender, const SGGeod & receiver ) const;
+  virtual double computeSignalQuality( const SGVec3d & sender, const SGVec3d & receiver ) const;
+  virtual double computeSignalQuality( double slantDistanceM ) const;
+private:
+  double _rangeM;
+  double _rangeM2;
+};
+
+double SimpleDistanceSquareSignalQualityComputer::computeSignalQuality( const SGVec3d & sender, const SGVec3d & receiver ) const
+{
+    return computeSignalQuality( dist( sender, receiver ) );
+}
+
+double SimpleDistanceSquareSignalQualityComputer::computeSignalQuality( const SGGeod & sender, const SGGeod & receiver ) const
+{
+    return computeSignalQuality( SGGeodesy::distanceM( sender, receiver ) );
+}
+
+double SimpleDistanceSquareSignalQualityComputer::computeSignalQuality( double distanceM ) const
+{
+    return distanceM < _rangeM ? 1.0 : ( _rangeM2 / (distanceM*distanceM) );
+}
+
+class OnExitHandler {
+  public:
+    virtual void onExit() = 0;
+};
+
+class OnExit {
+  public:
+    OnExit( OnExitHandler * onExitHandler ) : _onExitHandler( onExitHandler ) {}
+    ~OnExit() { _onExitHandler->onExit(); }
+  private:
+    OnExitHandler * _onExitHandler;
+};
+
+
+class OutputProperties : public OnExitHandler {
+  public:
+    OutputProperties( SGPropertyNode_ptr rootNode ) : 
+      _rootNode(rootNode),
+      _signalQuality_norm(0.0),
+      _slantDistance_m(0.0),
+      _trueBearingTo_deg(0.0),
+      _trueBearingFrom_deg(0.0),
+      _trackDistance_m(0.0),
+      _heightAboveStation_ft(0.0),
+
+      _PO_stationType( rootNode->getNode("station-type", true ) ),
+      _PO_stationName( rootNode->getNode("station-name", true ) ),
+      _PO_airportId( rootNode->getNode("airport-id", true ) ),
+      _PO_signalQuality_norm( rootNode->getNode("signal-quality-norm",true) ),
+      _PO_slantDistance_m( rootNode->getNode("slant-distance-m",true) ),
+      _PO_trueBearingTo_deg( rootNode->getNode("true-bearing-to-deg",true) ),
+      _PO_trueBearingFrom_deg( rootNode->getNode("true-bearing-from-deg",true) ),
+      _PO_trackDistance_m( rootNode->getNode("track-distance-m",true) ),
+      _PO_heightAboveStation_ft( rootNode->getNode("height-above-station-ft",true) )
+      {}
+
+protected:
+    SGPropertyNode_ptr _rootNode;
+
+    std::string  _stationType;
+    std::string  _stationName;
+    std::string  _airportId;
+    double       _signalQuality_norm;
+    double       _slantDistance_m;
+    double       _trueBearingTo_deg;
+    double       _trueBearingFrom_deg;
+    double       _trackDistance_m;
+    double       _heightAboveStation_ft;
+
+private:
+    PropertyObject<string> _PO_stationType;
+    PropertyObject<string> _PO_stationName;
+    PropertyObject<string> _PO_airportId;
+    PropertyObject<double> _PO_signalQuality_norm;
+    PropertyObject<double> _PO_slantDistance_m;
+    PropertyObject<double> _PO_trueBearingTo_deg;
+    PropertyObject<double> _PO_trueBearingFrom_deg;
+    PropertyObject<double> _PO_trackDistance_m;
+    PropertyObject<double> _PO_heightAboveStation_ft;
+
+    virtual void onExit() {
+        _PO_stationType = _stationType;
+        _PO_stationName = _stationName;
+        _PO_airportId = _airportId;
+        _PO_signalQuality_norm = _signalQuality_norm;
+        _PO_slantDistance_m = _slantDistance_m;
+        _PO_trueBearingTo_deg = _trueBearingTo_deg;
+        _PO_trueBearingFrom_deg = _trueBearingFrom_deg;
+        _PO_trackDistance_m = _trackDistance_m;
+        _PO_heightAboveStation_ft = _heightAboveStation_ft;
+    }
+};
+
+/* ------------- The CommRadio implementation ---------------------- */
+
+class MetarBridge : public SGReferenced, public SGPropertyChangeListener {
+public:
+  MetarBridge();
+  ~MetarBridge();
+
+  void bind();
+  void unbind();
+  void requestMetarForId( std::string & id );
+  void clearMetar();
+  void setMetarPropertiesRoot( SGPropertyNode_ptr n ) { _metarPropertiesNode = n; }
+  void setAtisNode( SGPropertyNode * n ) { _atisNode = n; }
+
+protected:
+  virtual void valueChanged(SGPropertyNode * );
+
+private:
+  std::string _requestedId;
+  SGPropertyNode_ptr _metarPropertiesNode;
+  SGPropertyNode * _atisNode;
+  ATISEncoder _atisEncoder;
+};
+typedef SGSharedPtr<MetarBridge> MetarBridgeRef;
+
+MetarBridge::MetarBridge() :
+  _atisNode(0)
+{
+}
+
+MetarBridge::~MetarBridge()
+{
+}
+
+void MetarBridge::bind()
+{
+  _metarPropertiesNode->getNode( "valid", true )->addChangeListener( this );
+}
+
+void MetarBridge::unbind()
+{
+  _metarPropertiesNode->getNode( "valid", true )->removeChangeListener( this );
+}
+
+void MetarBridge::requestMetarForId( std::string & id )
+{
+  std::string uppercaseId = simgear::strutils::uppercase( id );
+  if( _requestedId == uppercaseId ) return;
+  _requestedId = uppercaseId;
+  _metarPropertiesNode->getNode( "station-id", true )->setStringValue( uppercaseId );
+  _metarPropertiesNode->getNode( "valid", true )->setBoolValue( false );
+  _metarPropertiesNode->getNode( "time-to-live", true )->setDoubleValue( 0.0 );
+}
+
+void MetarBridge::clearMetar()
+{
+  string empty;
+  requestMetarForId( empty );
+}
+
+void MetarBridge::valueChanged(SGPropertyNode * node )
+{
+  // check for raising edge of valid flag
+  if( NULL == node || false == node->getBoolValue() )
+    return;
+
+  std::string responseId = simgear::strutils::uppercase(
+     _metarPropertiesNode->getNode( "station-id", true )->getStringValue() );
+
+  // unrequested metar!?
+  if( responseId != _requestedId )
+    return;
+
+  if( NULL != _atisNode ) {
+    MetarPropertiesATISInformationProvider provider( _metarPropertiesNode );
+    _atisNode->setStringValue( _atisEncoder.encodeATIS( &provider ) );
+  }
+}
+
+/* ------------- The CommRadio implementation ---------------------- */
+
+class CommRadioImpl : public CommRadio, OutputProperties {
+
+public:
+  CommRadioImpl( SGPropertyNode_ptr node );
+  virtual ~CommRadioImpl();
+
+  virtual void update( double dt );
+  virtual void init();
+  void bind();
+  void unbind();
+
+private:
+  MetarBridgeRef     _metarBridge;
+  FrequencyFormatter _useFrequencyFormatter;
+  FrequencyFormatter _stbyFrequencyFormatter;
+  const SignalQualityComputerRef _signalQualityComputer; 
+
+  double _stationTTL;
+  double _frequency;
+  flightgear::CommStationRef _commStationForFrequency;
+
+  PropertyObject<bool>   _serviceable;
+  PropertyObject<bool>   _power_btn;
+  PropertyObject<bool>   _power_good;
+  PropertyObject<double> _volume_norm;
+  PropertyObject<string> _atis;
+
+
+};
+
+CommRadioImpl::CommRadioImpl( SGPropertyNode_ptr node ) :
+    OutputProperties( fgGetNode("/instrumentation",true)->getNode(
+                        node->getStringValue("name", "nav"),
+                        node->getIntValue("number", 0), true)),
+    _metarBridge( new MetarBridge() ),
+    _useFrequencyFormatter( _rootNode->getNode("frequencies/selected-mhz",true), 
+                            _rootNode->getNode("frequencies/selected-mhz-fmt",true), 0.025 ),
+    _stbyFrequencyFormatter( _rootNode->getNode("frequencies/standby-mhz",true), 
+                            _rootNode->getNode("frequencies/standby-mhz-fmt",true), 0.025 ),
+    _signalQualityComputer( new SimpleDistanceSquareSignalQualityComputer(10*SG_NM_TO_METER) ),
+
+    _stationTTL(0.0),
+    _frequency(-1.0),
+    _commStationForFrequency(NULL),
+
+    _serviceable( _rootNode->getNode("serviceable",true) ),
+    _power_btn( _rootNode->getNode("power-btn",true) ),
+    _power_good( _rootNode->getNode("power-good",true) ),
+    _volume_norm( _rootNode->getNode("volume",true) ),
+    _atis( _rootNode->getNode("atis",true) )
+{
+}
+
+CommRadioImpl::~CommRadioImpl()
+{
+}
+
+void CommRadioImpl::bind()
+{
+  _metarBridge->setAtisNode( _atis.node() );
+  _metarBridge->setMetarPropertiesRoot( fgGetNode( "/environment/metar[3]", true ) );
+  _metarBridge->bind();
+}
+
+void CommRadioImpl::unbind()
+{
+  _metarBridge->unbind();
+}
+
+void CommRadioImpl::init()
+{
+}
+
+void CommRadioImpl::update( double dt )
+{
+    if( dt < SGLimitsd::min() ) return;
+    _stationTTL -= dt;
+
+    // Ensure all output properties get written on exit of this method
+    OnExit onExit(this);
+
+    SGGeod position;
+    try { position = globals->get_aircraft_position(); }
+    catch( std::exception & ) { return; }
+
+    if( false == (_power_btn )) {
+        _stationTTL = 0.0;
+        return;
+    }
+
+
+    if( _frequency != _useFrequencyFormatter.getFrequency() ) {
+        _frequency = _useFrequencyFormatter.getFrequency();
+        _stationTTL = 0.0;
+    }
+
+    if( _stationTTL <= 0.0 ) {
+        _stationTTL = 30.0;
+
+        // Note:  122.375 must be rounded DOWN to 122370
+        // in order to be consistent with apt.dat et cetera.
+        int freqKhz = 10 * static_cast<int>(_frequency * 100 + 0.25);
+        _commStationForFrequency = flightgear::CommStation::findByFreq( freqKhz, position, NULL );
+
+    }
+
+    if( false == _commStationForFrequency.valid() ) return;
+
+    _slantDistance_m = dist(_commStationForFrequency->cart(), SGVec3d::fromGeod(position));
+
+    SGGeodesy::inverse(position, _commStationForFrequency->geod(), 
+        _trueBearingTo_deg,
+        _trueBearingFrom_deg,
+        _trackDistance_m );
+
+    _heightAboveStation_ft = 
+         SGMiscd::max(0.0, position.getElevationFt() 
+           - _commStationForFrequency->airport()->elevation());
+    
+    _signalQuality_norm = _signalQualityComputer->computeSignalQuality( _slantDistance_m );
+    _stationType = _commStationForFrequency->nameForType( _commStationForFrequency->type() );
+    _stationName = _commStationForFrequency->ident();
+    _airportId = _commStationForFrequency->airport()->getId();
+
+    switch( _commStationForFrequency->type() ) {
+      case FGPositioned::FREQ_ATIS:
+      case FGPositioned::FREQ_AWOS: {
+        if( _signalQuality_norm > 0.01 ) {
+          _metarBridge->requestMetarForId( _airportId );
+        } else {
+          _metarBridge->clearMetar();
+          _atis = "";
+        }
+      }
+      break;
+
+      default:
+        _metarBridge->clearMetar();
+        _atis = "";
+        break;
+    }
+
+}
+
+SGSubsystem * CommRadio::createInstance( SGPropertyNode_ptr rootNode )
+{
+    return new CommRadioImpl( rootNode );
+}
+
+} // namespace Instrumentation
+
diff --git a/src/Instrumentation/commradio.hxx b/src/Instrumentation/commradio.hxx
new file mode 100644 (file)
index 0000000..746bd12
--- /dev/null
@@ -0,0 +1,49 @@
+// commradio.hxx -- class to manage a nav radio instance
+//
+// Written by Torsten Dreyer, started February 2014
+//
+// Copyright (C) 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.
+//
+
+
+#ifndef _FG_INSTRUMENTATION_COMMRADIO_HXX
+#define _FG_INSTRUMENTATION_COMMRADIO_HXX
+
+#include <simgear/props/props.hxx>
+#include <simgear/structure/subsystem_mgr.hxx>
+
+namespace Instrumentation {
+
+class SignalQualityComputer : public SGReferenced {
+public:
+  virtual ~SignalQualityComputer();
+  virtual double computeSignalQuality( const SGGeod & sender, const SGGeod & receiver ) const = 0;
+  virtual double computeSignalQuality( const SGVec3d & sender, const SGVec3d & receiver ) const = 0;
+  virtual double computeSignalQuality( double slantDistanceM ) const = 0;
+};
+
+typedef SGSharedPtr<SignalQualityComputer> SignalQualityComputerRef;
+
+class CommRadio : public SGSubsystem
+{
+public:
+  static SGSubsystem * createInstance( SGPropertyNode_ptr rootNode );
+};
+
+}
+
+#endif // _FG_INSTRUMENTATION_COMMRADIO_HXX
diff --git a/src/Instrumentation/frequencyformatter.hxx b/src/Instrumentation/frequencyformatter.hxx
new file mode 100644 (file)
index 0000000..d231eb0
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __FREQUENCY_FORMATTER_HXX
+#define __FREQUENCY_FORMATTER_HXX
+
+/* ------------- A NAV/COMM Frequency formatter ---------------------- */
+
+class FrequencyFormatter : public SGPropertyChangeListener {
+public:
+  FrequencyFormatter( SGPropertyNode_ptr freqNode, SGPropertyNode_ptr fmtFreqNode, double channelSpacing ) :
+    _freqNode( freqNode ),
+    _fmtFreqNode( fmtFreqNode ),
+    _channelSpacing(channelSpacing)
+  {
+    _freqNode->addChangeListener( this );
+    valueChanged(_freqNode);
+  }
+  ~FrequencyFormatter()
+  {
+    _freqNode->removeChangeListener( this );
+  }
+
+  void valueChanged (SGPropertyNode * prop)
+  {
+    // format as fixed decimal "nnn.nn"
+    std::ostringstream buf;
+    buf << std::fixed 
+        << std::setw(5) 
+        << std::setfill('0') 
+        << std::setprecision(2)
+        << getFrequency();
+    _fmtFreqNode->setStringValue( buf.str() );
+  }
+
+  double getFrequency() const 
+  {
+    double d = SGMiscd::roundToInt(_freqNode->getDoubleValue() / _channelSpacing) * _channelSpacing;
+    // strip last digit, do not round
+    return ((int)(d*100))/100.0;
+  }
+
+private:
+  SGPropertyNode_ptr _freqNode;
+  SGPropertyNode_ptr _fmtFreqNode;
+  double _channelSpacing;
+};
+
+
+#endif //__FREQUENCY_FORMATTER_HXX
index c21bf7cbaac2684f04b24468c4e43f922d5ae473..44d6366838b740fc772d8b4090ff3708d6374aa4 100644 (file)
@@ -36,6 +36,7 @@
 #include "mag_compass.hxx"
 #include "marker_beacon.hxx"
 #include "newnavradio.hxx"
 #include "mag_compass.hxx"
 #include "marker_beacon.hxx"
 #include "newnavradio.hxx"
+#include "commradio.hxx"
 #include "slip_skid_ball.hxx"
 #include "transponder.hxx"
 #include "turn_indicator.hxx"
 #include "slip_skid_ball.hxx"
 #include "transponder.hxx"
 #include "turn_indicator.hxx"
@@ -169,6 +170,9 @@ bool FGInstrumentMgr::build (SGPropertyNode* config_props)
         } else if ( name == "marker-beacon" ) {
             set_subsystem( id, new FGMarkerBeacon( node ), 0.2 );
 
         } else if ( name == "marker-beacon" ) {
             set_subsystem( id, new FGMarkerBeacon( node ), 0.2 );
 
+        } else if ( name == "comm-radio" ) {
+            set_subsystem( id, Instrumentation::CommRadio::createInstance( node ) );
+
         } else if ( name == "nav-radio" ) {
             set_subsystem( id, Instrumentation::NavRadio::createInstance( node ) );
 
         } else if ( name == "nav-radio" ) {
             set_subsystem( id, Instrumentation::NavRadio::createInstance( node ) );
 
index 41b606c152bbe3b49702815e98d9bb4693bc5456..0c97a7c6d2507907616a864ede5c275c8e99cec9 100644 (file)
@@ -40,7 +40,7 @@
 #include <Sound/audioident.hxx>
 
 #include "navradio.hxx"
 #include <Sound/audioident.hxx>
 
 #include "navradio.hxx"
-
+#include "frequencyformatter.hxx"
 
 namespace Instrumentation {
 
 
 namespace Instrumentation {
 
@@ -793,49 +793,6 @@ void GS::display( NavIndicator & navIndicator )
   navIndicator.setGS( _glideslopeOffset_norm );
 }
 
   navIndicator.setGS( _glideslopeOffset_norm );
 }
 
-/* ------------- A NAV/COMM Frequency formatter ---------------------- */
-
-class FrequencyFormatter : public SGPropertyChangeListener {
-public:
-  FrequencyFormatter( SGPropertyNode_ptr freqNode, SGPropertyNode_ptr fmtFreqNode, double channelSpacing ) :
-    _freqNode( freqNode ),
-    _fmtFreqNode( fmtFreqNode ),
-    _channelSpacing(channelSpacing)
-  {
-    _freqNode->addChangeListener( this );
-    valueChanged(_freqNode);
-  }
-  ~FrequencyFormatter()
-  {
-    _freqNode->removeChangeListener( this );
-  }
-
-  void valueChanged (SGPropertyNode * prop)
-  {
-    // format as fixed decimal "nnn.nn"
-    std::ostringstream buf;
-    buf << std::fixed 
-        << std::setw(5) 
-        << std::setfill('0') 
-        << std::setprecision(2)
-        << getFrequency();
-    _fmtFreqNode->setStringValue( buf.str() );
-  }
-
-  double getFrequency() const 
-  {
-    double d = SGMiscd::roundToInt(_freqNode->getDoubleValue() / _channelSpacing) * _channelSpacing;
-    // strip last digit, do not round
-    return ((int)(d*100))/100.0;
-  }
-
-private:
-  SGPropertyNode_ptr _freqNode;
-  SGPropertyNode_ptr _fmtFreqNode;
-  double _channelSpacing;
-};
-
-
 /* ------------- The NavRadio implementation ---------------------- */
 
 class NavRadioImpl : public NavRadio {
 /* ------------- The NavRadio implementation ---------------------- */
 
 class NavRadioImpl : public NavRadio {
index 86494da846f2509b7b287240743e9c9bdff37ef2..4712eb4c568cf092c5554b22da4d46ee520a7205 100644 (file)
@@ -78,7 +78,6 @@
 
 #include <AIModel/AIManager.hxx>
 
 
 #include <AIModel/AIManager.hxx>
 
-#include <ATCDCL/ATISmgr.hxx>
 #include <ATC/atc_mgr.hxx>
 
 #include <Autopilot/route_mgr.hxx>
 #include <ATC/atc_mgr.hxx>
 
 #include <Autopilot/route_mgr.hxx>
@@ -702,16 +701,6 @@ void fgCreateSubsystems(bool duringReset) {
     globals->add_subsystem("Canvas", new CanvasMgr, SGSubsystemMgr::DISPLAY);
     globals->add_subsystem("CanvasGUI", new GUIMgr, SGSubsystemMgr::DISPLAY);
 
     globals->add_subsystem("Canvas", new CanvasMgr, SGSubsystemMgr::DISPLAY);
     globals->add_subsystem("CanvasGUI", new GUIMgr, SGSubsystemMgr::DISPLAY);
 
-    ////////////////////////////////////////////////////////////////////
-    // Initialise the ATIS Manager
-    // Note that this is old stuff, but is necessary for the
-    // current ATIS implementation. Therefore, leave it in here
-    // until the ATIS system is ported over to make use of the ATIS 
-    // sub system infrastructure.
-    ////////////////////////////////////////////////////////////////////
-
-    globals->add_subsystem("ATIS", new FGATISMgr, SGSubsystemMgr::INIT, 0.4);
-
     ////////////////////////////////////////////////////////////////////
    // Initialize the ATC subsystem
     ////////////////////////////////////////////////////////////////////
     ////////////////////////////////////////////////////////////////////
    // Initialize the ATC subsystem
     ////////////////////////////////////////////////////////////////////
@@ -927,8 +916,6 @@ void fgReInitSubsystems()
     globals->get_subsystem("systems")->reinit();
     globals->get_subsystem("instrumentation")->reinit();
 
     globals->get_subsystem("systems")->reinit();
     globals->get_subsystem("instrumentation")->reinit();
 
-    globals->get_subsystem("ATIS")->reinit();
-
 // setup state to end re-init
     fgSetBool("/sim/signals/reinit", false);
     if ( !freeze ) {
 // setup state to end re-init
     fgSetBool("/sim/signals/reinit", false);
     if ( !freeze ) {
index d57defc0fe88594d857a65413954fc464f786e1f..29377bb36a85d21115e7c6219ceca8ffd705a1a2 100644 (file)
@@ -46,7 +46,6 @@
 
 #include <Aircraft/controls.hxx>
 #include <Airports/runways.hxx>
 
 #include <Aircraft/controls.hxx>
 #include <Airports/runways.hxx>
-#include <ATCDCL/ATISmgr.hxx>
 #include <Autopilot/route_mgr.hxx>
 #include <GUI/FGFontCache.hxx>
 #include <GUI/gui.h>
 #include <Autopilot/route_mgr.hxx>
 #include <GUI/FGFontCache.hxx>
 #include <GUI/gui.h>
@@ -146,7 +145,6 @@ FGGlobals::FGGlobals() :
     time_params( NULL ),
     ephem( NULL ),
     route_mgr( NULL ),
     time_params( NULL ),
     ephem( NULL ),
     route_mgr( NULL ),
-    ATIS_mgr( NULL ),
     controls( NULL ),
     viewmgr( NULL ),
     commands( SGCommandMgr::instance() ),
     controls( NULL ),
     viewmgr( NULL ),
     commands( SGCommandMgr::instance() ),
@@ -241,7 +239,6 @@ FGGlobals::~FGGlobals()
     delete time_params;
     set_matlib(NULL);
     delete route_mgr;
     delete time_params;
     set_matlib(NULL);
     delete route_mgr;
-    delete ATIS_mgr;
     delete channel_options_list;
     delete initial_waypoints;
     delete fontcache;
     delete channel_options_list;
     delete initial_waypoints;
     delete fontcache;
index d36090846047ad871131c59e7695dffe86598550..61ee6ebfc7d5c7c8c48e3702808635ed55d1d5bc 100644 (file)
@@ -55,7 +55,6 @@ class SGSubsystemMgr;
 class SGSubsystem;
 class SGSoundMgr;
 
 class SGSubsystem;
 class SGSoundMgr;
 
-class FGATISMgr;
 class FGControls;
 class FGTACANList;
 class FGLocale;
 class FGControls;
 class FGTACANList;
 class FGLocale;
@@ -119,9 +118,6 @@ private:
     // Global autopilot "route"
     FGRouteMgr *route_mgr;
 
     // Global autopilot "route"
     FGRouteMgr *route_mgr;
 
-    // ATC manager
-    FGATISMgr *ATIS_mgr;
-
     // control input state
     FGControls *controls;
 
     // control input state
     FGControls *controls;
 
@@ -271,9 +267,6 @@ public:
     inline SGMaterialLib *get_matlib() const { return matlib; }
     void set_matlib( SGMaterialLib *m );
 
     inline SGMaterialLib *get_matlib() const { return matlib; }
     void set_matlib( SGMaterialLib *m );
 
-    inline FGATISMgr *get_ATIS_mgr() const { return ATIS_mgr; }
-    inline void set_ATIS_mgr( FGATISMgr *a ) {ATIS_mgr = a; }
-
     inline FGControls *get_controls() const { return controls; }
     inline void set_controls( FGControls *c ) { controls = c; }
 
     inline FGControls *get_controls() const { return controls; }
     inline void set_controls( FGControls *c ) { controls = c; }
 
index 783b3f24743c0d022fcdcf99205d93476a998e02..7572f42e9de03e45bc26eec630d17131a5826f9e 100644 (file)
@@ -191,6 +191,9 @@ FGLocale::selectLanguage(const char *language)
     // load resource for system messages (translations for fgfs internal messages)
     loadResource("sys");
 
     // load resource for system messages (translations for fgfs internal messages)
     loadResource("sys");
 
+    // load resource for atc messages
+    loadResource("atc");
+
     return true;
 }
 
     return true;
 }
 
index 0c92aed912016d803fdaf23a9dfbfd5afacc5600..2a8d7e56a3f3ef16f6b464a7a6c66c7cfaa5fc71 100644 (file)
@@ -49,7 +49,6 @@
 #include <Cockpit/cockpitDisplayManager.hxx>
 #include <GUI/new_gui.hxx>
 #include <Main/logger.hxx>
 #include <Cockpit/cockpitDisplayManager.hxx>
 #include <GUI/new_gui.hxx>
 #include <Main/logger.hxx>
-#include <ATCDCL/ATISmgr.hxx>
 #include <ATC/atc_mgr.hxx>
 #include <AIModel/AIManager.hxx>
 #include <MultiPlayer/multiplaymgr.hxx>
 #include <ATC/atc_mgr.hxx>
 #include <AIModel/AIManager.hxx>
 #include <MultiPlayer/multiplaymgr.hxx>
@@ -90,7 +89,6 @@ SGSubsystem* createSubsystemByName(const std::string& name)
     MAKE_SUB(FGRouteMgr, "route-manager");
     MAKE_SUB(FGLogger, "logger");
     MAKE_SUB(NewGUI, "gui");
     MAKE_SUB(FGRouteMgr, "route-manager");
     MAKE_SUB(FGLogger, "logger");
     MAKE_SUB(NewGUI, "gui");
-    MAKE_SUB(FGATISMgr, "atis");
     MAKE_SUB(FGATCManager, "atc");
     MAKE_SUB(FGMultiplayMgr, "mp");
     MAKE_SUB(FGTrafficManager, "traffic-manager");
     MAKE_SUB(FGATCManager, "atc");
     MAKE_SUB(FGMultiplayMgr, "mp");
     MAKE_SUB(FGTrafficManager, "traffic-manager");