1
0
Fork 0

A new comm radio and atis implementation

This commit is contained in:
Torsten Dreyer 2014-02-19 14:24:34 +01:00
parent c519b9262d
commit dd6cccdda1
23 changed files with 1319 additions and 100 deletions

473
src/ATC/ATISEncoder.cxx Normal file
View 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
View 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

View file

@ -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}")

View 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";
}

View 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

View file

@ -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}")

View 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;
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) {

View 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;
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.

View file

@ -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"
@ -530,8 +530,12 @@ const std::string FGAirportDynamics::getAtisSequence()
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)
@ -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));
}

View file

@ -96,15 +96,17 @@ 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
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

View file

@ -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

View file

@ -17,7 +17,7 @@ set(SOURCES
terrainsampler.cxx
presets.cxx
gravity.cxx
magvarmanager.cxx
magvarmanager.cxx
)
set(HEADERS
@ -37,7 +37,7 @@ set(HEADERS
terrainsampler.hxx
presets.hxx
gravity.hxx
magvarmanager.hxx
magvarmanager.hxx
)
flightgear_component(Environment "${SOURCES}" "${HEADERS}")

View file

@ -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

View 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

View 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

View 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

View file

@ -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 ) );

View file

@ -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 {

View file

@ -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 ) {

View file

@ -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;

View file

@ -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; }

View 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 atc messages
loadResource("atc");
return true;
}

View file

@ -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");