A new comm radio and atis implementation
This commit is contained in:
parent
c519b9262d
commit
dd6cccdda1
23 changed files with 1319 additions and 100 deletions
src
ATC
ATISEncoder.cxxATISEncoder.hxxCMakeLists.txtMetarPropertiesATISInformationProvider.cxxMetarPropertiesATISInformationProvider.hxx
ATCDCL
Airports
Instrumentation
Main
473
src/ATC/ATISEncoder.cxx
Normal file
473
src/ATC/ATISEncoder.cxx
Normal file
|
@ -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();
|
||||
}
|
||||
|
111
src/ATC/ATISEncoder.hxx
Normal file
111
src/ATC/ATISEncoder.hxx
Normal file
|
@ -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
|
|
@ -5,6 +5,8 @@ set(SOURCES
|
|||
atcdialog.cxx
|
||||
trafficcontrol.cxx
|
||||
CommStation.cxx
|
||||
ATISEncoder.cxx
|
||||
MetarPropertiesATISInformationProvider.cxx
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
|
@ -12,6 +14,8 @@ set(HEADERS
|
|||
atcdialog.hxx
|
||||
trafficcontrol.hxx
|
||||
CommStation.hxx
|
||||
ATISEncoder.hxx
|
||||
MetarPropertiesATISInformationProvider.hxx
|
||||
)
|
||||
|
||||
flightgear_component(ATC "${SOURCES}" "${HEADERS}")
|
||||
|
|
120
src/ATC/MetarPropertiesATISInformationProvider.cxx
Normal file
120
src/ATC/MetarPropertiesATISInformationProvider.cxx
Normal file
|
@ -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";
|
||||
}
|
||||
|
75
src/ATC/MetarPropertiesATISInformationProvider.hxx
Normal file
75
src/ATC/MetarPropertiesATISInformationProvider.hxx
Normal file
|
@ -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
|
|
@ -1,23 +1,11 @@
|
|||
include(FlightGearComponent)
|
||||
|
||||
set(SOURCES
|
||||
ATC.cxx
|
||||
atis.cxx
|
||||
ATCVoice.cxx
|
||||
ATISmgr.cxx
|
||||
ATCutils.cxx
|
||||
ATCProjection.cxx
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
ATC.hxx
|
||||
atis.hxx
|
||||
ATCVoice.hxx
|
||||
ATISmgr.hxx
|
||||
ATCutils.hxx
|
||||
ATCProjection.hxx
|
||||
atis_lexicon.hxx
|
||||
atis_remap.hxx
|
||||
)
|
||||
|
||||
flightgear_component(ATCDCL "${SOURCES}" "${HEADERS}")
|
||||
|
|
|
@ -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;
|
||||
|
||||
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);
|
||||
|
@ -257,10 +263,10 @@ FGRunwayRef FGAirport::findBestRunwayForHeading(double aHeading) const
|
|||
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 bad = fabs(deviationWeight * dev) + 1e-20;
|
||||
double bad = fabs( fbrfhp.deviationWeight * dev) + 1e-20;
|
||||
double quality = good / bad;
|
||||
|
||||
if (quality > currentBestQuality) {
|
||||
|
|
|
@ -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;
|
||||
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.
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
#include <simgear/debug/logstream.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Main/locale.hxx>
|
||||
#include <Airports/runways.hxx>
|
||||
#include <ATCDCL/ATCutils.hxx>
|
||||
#include <Navaids/NavDataCache.hxx>
|
||||
|
||||
#include "airport.hxx"
|
||||
|
@ -531,7 +531,11 @@ const std::string FGAirportDynamics::getAtisSequence()
|
|||
updateAtisSequence(1, false);
|
||||
}
|
||||
|
||||
return GetPhoneticLetter(atisSequenceIndex);
|
||||
char atisSequenceString[2];
|
||||
atisSequenceString[0] = 'a' + atisSequenceIndex;
|
||||
atisSequenceString[1] = 0;
|
||||
|
||||
return globals->get_locale()->getLocalizedString(atisSequenceString, "atc", "unknown");
|
||||
}
|
||||
|
||||
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;
|
||||
atisSequenceIndex = rand() % LTRS; // random initial sequence letters
|
||||
atisSequenceIndex = rand() % 26; // random initial sequence letters
|
||||
return atisSequenceIndex;
|
||||
}
|
||||
|
||||
|
@ -550,7 +554,7 @@ int FGAirportDynamics::updateAtisSequence(int interval, bool forceUpdate)
|
|||
++steps; // a "special" ATIS update is required
|
||||
}
|
||||
|
||||
atisSequenceIndex = (atisSequenceIndex + steps) % LTRS;
|
||||
atisSequenceIndex = (atisSequenceIndex + steps) % 26;
|
||||
// return a huge value if no update occurred
|
||||
return (atisSequenceIndex + (steps ? 0 : LTRS*1000));
|
||||
return (atisSequenceIndex + (steps ? 0 : 26*1000));
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ string FGRunway::reverseIdent(const string& aRunwayIdent)
|
|||
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
|
||||
|
@ -104,7 +104,9 @@ double FGRunway::score(double aLengthWt, double aWidthWt, double aSurfaceWt) con
|
|||
else if (_surface_code == 1 || _surface_code == 2) // asphalt & concrete
|
||||
surface = 3;
|
||||
|
||||
return _length * aLengthWt + _width * aWidthWt + surface * aSurfaceWt + 1e-20;
|
||||
int ils = (_ils != 0);
|
||||
|
||||
return _length * aLengthWt + _width * aWidthWt + surface * aSurfaceWt + ils * aIlsWt + 1e-20;
|
||||
}
|
||||
|
||||
SGGeod FGRunway::begin() const
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
* 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
|
||||
|
|
|
@ -23,6 +23,7 @@ set(SOURCES
|
|||
mrg.cxx
|
||||
navradio.cxx
|
||||
newnavradio.cxx
|
||||
commradio.cxx
|
||||
rad_alt.cxx
|
||||
rnav_waypt_controller.cxx
|
||||
slip_skid_ball.cxx
|
||||
|
@ -83,6 +84,7 @@ set(HEADERS
|
|||
mrg.hxx
|
||||
navradio.hxx
|
||||
newnavradio.hxx
|
||||
commradio.hxx
|
||||
rad_alt.hxx
|
||||
rnav_waypt_controller.hxx
|
||||
slip_skid_ball.hxx
|
||||
|
|
384
src/Instrumentation/commradio.cxx
Normal file
384
src/Instrumentation/commradio.cxx
Normal file
|
@ -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
|
||||
|
49
src/Instrumentation/commradio.hxx
Normal file
49
src/Instrumentation/commradio.hxx
Normal file
|
@ -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
|
47
src/Instrumentation/frequencyformatter.hxx
Normal file
47
src/Instrumentation/frequencyformatter.hxx
Normal file
|
@ -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
|
|
@ -36,6 +36,7 @@
|
|||
#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"
|
||||
|
@ -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 == "comm-radio" ) {
|
||||
set_subsystem( id, Instrumentation::CommRadio::createInstance( node ) );
|
||||
|
||||
} else if ( name == "nav-radio" ) {
|
||||
set_subsystem( id, Instrumentation::NavRadio::createInstance( node ) );
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#include <Sound/audioident.hxx>
|
||||
|
||||
#include "navradio.hxx"
|
||||
|
||||
#include "frequencyformatter.hxx"
|
||||
|
||||
namespace Instrumentation {
|
||||
|
||||
|
@ -793,49 +793,6 @@ void GS::display( NavIndicator & navIndicator )
|
|||
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 {
|
||||
|
|
|
@ -78,7 +78,6 @@
|
|||
|
||||
#include <AIModel/AIManager.hxx>
|
||||
|
||||
#include <ATCDCL/ATISmgr.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);
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -927,8 +916,6 @@ void fgReInitSubsystems()
|
|||
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 ) {
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
|
||||
#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>
|
||||
|
@ -146,7 +145,6 @@ FGGlobals::FGGlobals() :
|
|||
time_params( NULL ),
|
||||
ephem( NULL ),
|
||||
route_mgr( NULL ),
|
||||
ATIS_mgr( NULL ),
|
||||
controls( NULL ),
|
||||
viewmgr( NULL ),
|
||||
commands( SGCommandMgr::instance() ),
|
||||
|
@ -241,7 +239,6 @@ FGGlobals::~FGGlobals()
|
|||
delete time_params;
|
||||
set_matlib(NULL);
|
||||
delete route_mgr;
|
||||
delete ATIS_mgr;
|
||||
delete channel_options_list;
|
||||
delete initial_waypoints;
|
||||
delete fontcache;
|
||||
|
|
|
@ -55,7 +55,6 @@ class SGSubsystemMgr;
|
|||
class SGSubsystem;
|
||||
class SGSoundMgr;
|
||||
|
||||
class FGATISMgr;
|
||||
class FGControls;
|
||||
class FGTACANList;
|
||||
class FGLocale;
|
||||
|
@ -119,9 +118,6 @@ private:
|
|||
// Global autopilot "route"
|
||||
FGRouteMgr *route_mgr;
|
||||
|
||||
// ATC manager
|
||||
FGATISMgr *ATIS_mgr;
|
||||
|
||||
// control input state
|
||||
FGControls *controls;
|
||||
|
||||
|
@ -271,9 +267,6 @@ public:
|
|||
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; }
|
||||
|
||||
|
|
|
@ -191,6 +191,9 @@ FGLocale::selectLanguage(const char *language)
|
|||
// load resource for system messages (translations for fgfs internal messages)
|
||||
loadResource("sys");
|
||||
|
||||
// load resource for atc messages
|
||||
loadResource("atc");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
#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>
|
||||
|
@ -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(FGATISMgr, "atis");
|
||||
MAKE_SUB(FGATCManager, "atc");
|
||||
MAKE_SUB(FGMultiplayMgr, "mp");
|
||||
MAKE_SUB(FGTrafficManager, "traffic-manager");
|
||||
|
|
Loading…
Add table
Reference in a new issue