diff --git a/src/ATC/AILocalTraffic.cxx b/src/ATC/AILocalTraffic.cxx index 15eb6a3..878611f 100644 --- a/src/ATC/AILocalTraffic.cxx +++ b/src/ATC/AILocalTraffic.cxx @@ -573,6 +573,7 @@ void FGAILocalTraffic::Update(double dt) { break; // And to avoid compiler warnings... case APPROACH: break; + case AWOS: break; case ATIS: break; case ENROUTE: break; case DEPARTURE: break; diff --git a/src/ATC/ATC.cxx b/src/ATC/ATC.cxx index 244131f..b985d8f 100644 --- a/src/ATC/ATC.cxx +++ b/src/ATC/ATC.cxx @@ -199,6 +199,7 @@ int FGATC::RemovePlane() { } void FGATC::SetData(ATCData* d) { + _type = d->type; lon = d->lon; lat = d->lat; elev = d->elev; @@ -281,13 +282,14 @@ string FGATC::GenText(const string& m, int c) { ostream& operator << (ostream& os, atc_type atc) { switch(atc) { - case(INVALID): return(os << "INVALID"); + case(AWOS): return(os << "AWOS"); case(ATIS): return(os << "ATIS"); case(GROUND): return(os << "GROUND"); case(TOWER): return(os << "TOWER"); case(APPROACH): return(os << "APPROACH"); case(DEPARTURE): return(os << "DEPARTURE"); case(ENROUTE): return(os << "ENROUTE"); + case(INVALID): return(os << "INVALID"); } return(os << "ERROR - Unknown switch in atc_type operator << "); } diff --git a/src/ATC/ATC.hxx b/src/ATC/ATC.hxx index d8ccddb..eb17bf0 100644 --- a/src/ATC/ATC.hxx +++ b/src/ATC/ATC.hxx @@ -59,16 +59,17 @@ struct PlaneRec { // Possible types of ATC type that the radios may be tuned to. // INVALID implies not tuned in to anything. enum atc_type { - INVALID, + AWOS, ATIS, GROUND, TOWER, APPROACH, DEPARTURE, - ENROUTE + ENROUTE, + INVALID /* must be last element; see ATC_NUM_TYPES */ }; -const int ATC_NUM_TYPES = 7; +const int ATC_NUM_TYPES = 1 + INVALID; // DCL - new experimental ATC data store struct ATCData { @@ -245,6 +246,8 @@ private: double _max_count; }; +// This code parallels code found in fgAirportDBLoad(...) in apt_loader.cxx +// FIXME: unify the code. inline istream& operator >> ( istream& fin, ATCData& a ) { diff --git a/src/ATC/ATCDialog.cxx b/src/ATC/ATCDialog.cxx index 9e47682..7af17bc 100644 --- a/src/ATC/ATCDialog.cxx +++ b/src/ATC/ATCDialog.cxx @@ -219,7 +219,7 @@ void FGATCDialog::PopupDialog() { return; } - if(atcptr->GetType() == ATIS) { + if(atcptr->GetType() == ATIS || atcptr->GetType() == AWOS) { label = "Tuned to ATIS - no communication possible"; mkDialog(label.c_str()); return; diff --git a/src/ATC/ATCmgr.cxx b/src/ATC/ATCmgr.cxx index c15b185..bf3ebae 100644 --- a/src/ATC/ATCmgr.cxx +++ b/src/ATC/ATCmgr.cxx @@ -92,11 +92,6 @@ void FGATCMgr::init() { // Is this still true after the reorganization of the event managar?? // -EMH- - // Initialise the frequency search map - current_commlist = new FGCommList; - SGPath p_comm( globals->get_fg_root() ); - current_commlist->init( p_comm ); - #ifdef ENABLE_AUDIO_SUPPORT // Load all available voices. // For now we'll do one hardwired one @@ -221,7 +216,8 @@ bool FGATCMgr::AIRegisterAirport(const string& ident) { a->lon = ap->getLongitude(); a->lat = ap->getLatitude(); a->elev = ap->getElevation(); - a->atis_freq = GetFrequency(ident, ATIS); + a->atis_freq = GetFrequency(ident, ATIS) + || GetFrequency(ident, AWOS); //cout << "ATIS freq = " << a->atis_freq << '\n'; a->atis_active = false; a->tower_freq = GetFrequency(ident, TOWER); @@ -250,7 +246,7 @@ bool FGATCMgr::CommRegisterAirport(const string& ident, int chan, const atc_type if(airport_atc_map.find(ident) != airport_atc_map.end()) { //cout << "IN MAP - flagging set by comm..." << endl; //xx airport_atc_map[ident]->set_by_comm[chan][tp] = true; - if(tp == ATIS) { + if(tp == ATIS || tp == AWOS) { airport_atc_map[ident]->atis_active = true; } else if(tp == TOWER) { airport_atc_map[ident]->tower_active = true; @@ -269,13 +265,14 @@ bool FGATCMgr::CommRegisterAirport(const string& ident, int chan, const atc_type a->lon = ap->getLongitude(); a->lat = ap->getLatitude(); a->elev = ap->getElevation(); - a->atis_freq = GetFrequency(ident, ATIS); + a->atis_freq = GetFrequency(ident, ATIS) + || GetFrequency(ident, AWOS); a->atis_active = false; a->tower_freq = GetFrequency(ident, TOWER); a->tower_active = false; a->ground_freq = GetFrequency(ident, GROUND); a->ground_active = false; - if(tp == ATIS) { + if(tp == ATIS || tp == AWOS) { a->atis_active = true; } else if(tp == TOWER) { a->tower_active = true; @@ -381,7 +378,7 @@ FGATC* FGATCMgr::GetATCPointer(const string& icao, const atc_type& type) { break; case APPROACH: break; - case ATIS: + case ATIS: case AWOS: SG_LOG(SG_ATC, SG_ALERT, "ERROR - ATIS station should not be requested from FGATCMgr::GetATCPointer"); break; case GROUND: @@ -429,7 +426,7 @@ FGATCVoice* FGATCMgr::GetVoicePointer(const atc_type& type) { // TODO - implement me better - maintain a list of loaded voices and other voices!! if(voice) { switch(type) { - case ATIS: + case ATIS: case AWOS: if(voiceOK) { return(v1); } @@ -495,7 +492,8 @@ void FGATCMgr::FreqSearch(const string navcomm, const int unit) { // This was a switch-case statement but the compiler didn't like // the new variable creation with it. - if (data.type == ATIS) (*atc_list)[svc_name] = new FGATIS; + if (data.type == ATIS + || data.type == AWOS) (*atc_list)[svc_name] = new FGATIS; else if (data.type == TOWER) (*atc_list)[svc_name] = new FGTower; else if (data.type == GROUND) (*atc_list)[svc_name] = new FGGround; else if (data.type == APPROACH) (*atc_list)[svc_name] = new FGApproach; diff --git a/src/ATC/atis.cxx b/src/ATC/atis.cxx index 59ea5a3..91493f6 100644 --- a/src/ATC/atis.cxx +++ b/src/ATC/atis.cxx @@ -67,7 +67,9 @@ FGATIS::FGATIS() : { _vPtr = globals->get_ATC_mgr()->GetVoicePointer(ATIS); _voiceOK = (_vPtr == NULL ? false : true); - _type = ATIS; + if (!(_type != ATIS || _type == AWOS)) { + SG_LOG(SG_ATC, SG_ALERT, "ERROR - _type not ATIS or AWOS in atis.cxx"); + } fgTie("/environment/attention", this, (int_getter)0, &FGATIS::attend); } @@ -138,6 +140,16 @@ Called from: attention = 0; } +string replace(const string orig, const string ooo, const string nnn){ + string work = orig; + size_t where(0); + for ( ; (where = work.find(ooo, where)) != string::npos ; ) { + work.replace(where, ooo.length(), nnn); + where += nnn.length(); + } + return work; +} + // Generate the actual broadcast ATIS transmission. // Regen means regenerate the /current/ transmission. // Special means generate a new transmission, with a new sequence. @@ -157,6 +169,7 @@ int FGATIS::GenTransmission(const int regen, const int special) { char buf[bs]; string time_str = fgGetString("sim/time/gmt-string"); string hours, mins; + string phonetic_seq_string; FGEnvironment stationweather = ((FGEnvironmentMgr *)globals->get_subsystem("environment")) @@ -169,18 +182,34 @@ int FGATIS::GenTransmission(const int regen, const int special) { /// transmission += "This_is "; // transmitted station name. //cout << "In atis.cxx, airport name = " << name << endl; - transmission += name; - transmission += " airport information "; +/////////////// +// FIXME: This would be more flexible and more extensible +// if the mappings were taken from an XML file, not hard-coded. +/////////////// + +// Remap some abbreviations that occur in apt.dat, to +// make things nicer for the text-to-speech system: + string name2 = name + " "; + name2 = replace(name2, "Intl ", "International "); + name2 = replace(name2, "Rgnl ", "Field "); + name2 = replace(name2, "Muni ", "Municipal "); + name2 = replace(name2, "Mem ", "Memorial "); + name2 = replace(name2, "Fld ", "Field "); + name2 = replace(name2, "AFB ", "Air Force Base "); + name2 = replace(name2, "AAF ", "Army Air Field "); + name2 = replace(name2, "MCAS ", "Marine Corps Air Station "); + transmission += name2; + if (_type == ATIS /* as opposed to AWOS */) { + transmission += "airport information "; // Add the sequence letter - // Warning - this is fragile if the time string format changes - hours = time_str.substr(0,2).c_str(); - mins = time_str.substr(3,2).c_str(); - //cout << "In atis.cxx, time " << time_str - // << " --> " << hours << ":" << mins << endl; - string phonetic_seq_string = GetPhoneticLetter(sequence); + phonetic_seq_string = GetPhoneticLetter(sequence); transmission += phonetic_seq_string + BRK; + } transmission += "Automated weather observation "; +// Warning - this is fragile if the time string format changes + hours = time_str.substr(0,2).c_str(); + mins = time_str.substr(3,2).c_str(); // speak each digit separately: transmission += ConvertNumToSpokenDigits(hours + mins); transmission += " zulu weather" + BRK; @@ -315,9 +344,7 @@ int FGATIS::GenTransmission(const int regen, const int special) { snprintf(buf, bs, "%.0f", QNH); transmission += ConvertNumToSpokenDigits(buf) + BRK; - - int has_tower(1); // FIXME: assume all have towers for now.. - if (has_tower) { + if (_type == ATIS /* as opposed to AWOS */) { string rwy_no = globals->get_runways()->search(ident, int(wind_dir)); if(rwy_no != "NN") { transmission += "Landing and departing runway "; @@ -337,7 +364,8 @@ int FGATIS::GenTransmission(const int regen, const int special) { #endif for (map::iterator act = active_on.begin(); act != active_on.end(); act++){ string prop = "/instrumentation/" + act->first + "/atis"; - globals->get_props()->setStringValue(prop.c_str(), transmission.c_str()); + globals->get_props()->setStringValue(prop.c_str(), + ("
\n" + transmission + "
\n").c_str()); #ifdef ATIS_TEST cout << " " << prop; #endif diff --git a/src/ATC/commlist.cxx b/src/ATC/commlist.cxx index d41eba1..336a9df 100644 --- a/src/ATC/commlist.cxx +++ b/src/ATC/commlist.cxx @@ -99,7 +99,7 @@ bool FGCommList::LoadComms(const SGPath& path) { // Push non-atis stations onto bucket map as well // In fact, push all stations onto bucket map for now so FGATCMgr::GetFrequency() works. - //if(a.type != ATIS) { + //if(a.type != ATIS and/or AWOS?) { // get bucket number SGBucket bucket(a.lon, a.lat); int bucknum = bucket.gen_index(); diff --git a/src/ATC/commlist.hxx b/src/ATC/commlist.hxx index 6a39971..bec6c37 100644 --- a/src/ATC/commlist.hxx +++ b/src/ATC/commlist.hxx @@ -104,7 +104,6 @@ public: int GetAtisSequence( const string& apt_id, const double tstamp, const int flush); -private: // Comm stations mapped by frequency comm_map_type commlist_freq; @@ -113,6 +112,8 @@ private: comm_map_type commlist_bck; // Load comms from a specified path (which must include the filename) +private: + bool LoadComms(const SGPath& path); //----------- This stuff is left over from atislist.[ch]xx and maybe should move somewhere else diff --git a/src/Airports/apt_loader.cxx b/src/Airports/apt_loader.cxx index 7f83b06..906cf9a 100644 --- a/src/Airports/apt_loader.cxx +++ b/src/Airports/apt_loader.cxx @@ -43,12 +43,15 @@ #include "runways.hxx" #include "apt_loader.hxx" - +#include +#include +#include // Load the airport data base from the specified aptdb file. The // metar file is used to mark the airports as having metar available // or not. bool fgAirportDBLoad( FGAirportList *airports, FGRunwayList *runways, + FGCommList *comm_list, const string &aptdb_file, const string &metar_file ) { // @@ -201,8 +204,51 @@ bool fgAirportDBLoad( FGAirportList *airports, FGRunwayList *runways, // windsock entry (ignore) } else if ( line_id == 15 ) { // custom startup locations (ignore) - } else if ( line_id >= 50 && line_id <= 56 ) { - // frequency entries (ignore) + } else if ( line_id == 50 ) { +// This assumes/requires that any code-50 line (ATIS or AWOS) +// applies to the preceding code-1 line (airport ID and name) +// and that a full set of code-10 lines (runway descriptors) +// has come between the code-1 and code-50 lines. + // typical code-50 lines: + // 50 11770 ATIS + // 50 11770 AWOS 3 +// This code parallels code found in operator>> in ATC.hxx; +// FIXME: unify the code. + if ( rwy_count > 0 ) { + ATCData a; + a.lat = rwy_lat_accum / (double)rwy_count; + a.lon = rwy_lon_accum / (double)rwy_count; + a.elev = last_apt_elev; + a.range = 50; // give all ATISs small range + a.ident = last_apt_id; + a.name = last_apt_name; + token.clear(); + token = simgear::strutils::split(line); + // short int representing tens of kHz: + a.freq = atoi(token[1].c_str()); + if (token[2] == "ATIS") a.type = ATIS; + else a.type = AWOS; // ASOS same as AWOS + + // generate cartesian coordinates + Point3D geod( a.lon * SGD_DEGREES_TO_RADIANS, + a.lat * SGD_DEGREES_TO_RADIANS, a.elev ); + Point3D cart = sgGeodToCart( geod ); + a.x = cart.x(); + a.y = cart.y(); + a.z = cart.z(); + + comm_list->commlist_freq[a.freq].push_back(a); + + SGBucket bucket(a.lon, a.lat); + int bucknum = bucket.gen_index(); + comm_list->commlist_bck[bucknum].push_back(a); + } else { + SG_LOG( SG_GENERAL, SG_ALERT, + "No runways; skipping AWOS for " + last_apt_id); + cout << "skipping AWOS for " + last_apt_id << endl; + } + } else if ( line_id >= 51 && line_id <= 56 ) { + // other frequency entries (ignore) } else if ( line_id == 99 ) { SG_LOG( SG_GENERAL, SG_DEBUG, "End of file reached" ); } else { diff --git a/src/Airports/apt_loader.hxx b/src/Airports/apt_loader.hxx index 4d70d12..636404a 100644 --- a/src/Airports/apt_loader.hxx +++ b/src/Airports/apt_loader.hxx @@ -38,12 +38,13 @@ SG_USING_STD(string); #include "simple.hxx" #include "runways.hxx" - +#include "ATC/commlist.hxx" // Load the airport data base from the specified aptdb file. The // metar file is used to mark the airports as having metar available // or not. bool fgAirportDBLoad( FGAirportList *airports, FGRunwayList *runways, + FGCommList * comm_list, const string &aptdb_file, const string &metar_file ); diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 94324eb..cd759a2 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -127,6 +127,7 @@ #include "logger.hxx" #include "viewmgr.hxx" #include "main.hxx" +#include "ATC/commlist.hxx" #if defined(FX) && defined(XMESA) #include @@ -1121,7 +1122,13 @@ fgInitNav () FGRunwayList *runways = new FGRunwayList(); globals->set_runways( runways ); - fgAirportDBLoad( airports, runways, aptdb.str(), p_metar.str() ); +// Initialise the frequency search map BEFORE reading +// the airport database: + current_commlist = new FGCommList; + current_commlist->init( globals->get_fg_root() ); + + fgAirportDBLoad( airports, runways, current_commlist, + aptdb.str(), p_metar.str() ); FGNavList *navlist = new FGNavList; FGNavList *loclist = new FGNavList;