From dd690909afbbfbdec1796da65680389751981911 Mon Sep 17 00:00:00 2001 From: Dave Luff Date: Wed, 5 Jan 2011 00:27:18 +0000 Subject: [PATCH] ATIS improvements from John Denker Primarily an improvment to the internationalisation. Previously the ATIS considered the world as either the UK or the rest of the world. Now it considers it as US+Canada or the rest of the world. This is much more consistent with global usage of pressure units as either inches or millibars, which is the most important difference. Also some other tweaks and cleanups. --- src/ATCDCL/atis.cxx | 127 ++++++++++++++++++++++++------------ src/ATCDCL/atis.hxx | 19 ++++-- src/ATCDCL/atis_lexicon.hxx | 6 ++ src/ATCDCL/atis_remap.hxx | 4 ++ 4 files changed, 110 insertions(+), 46 deletions(-) diff --git a/src/ATCDCL/atis.cxx b/src/ATCDCL/atis.cxx index dfc1381c6..16e94f67a 100644 --- a/src/ATCDCL/atis.cxx +++ b/src/ATCDCL/atis.cxx @@ -151,6 +151,7 @@ void FGATIS::Update(double dt) { // If !_prev_display, the radio had been detuned for a while and our // "transmission" variable was lost when we were de-instantiated. int rslt = GenTransmission(!_prev_display, attention); + TreeOut(msg_OK); if (rslt || volume != old_volume) { //cout << "ATIS calling ATC::render volume: " << volume << endl; Render(transmission, volume, refname, true); @@ -207,6 +208,28 @@ const int minute(60); // measured in seconds const int ATIS_interval(60*minute); #endif +// FIXME: This is heuristic. It gets the right answer for +// more than 90% of the world's airports, which is a lot +// better than nothing ... but it's not 100%. +// We know "most" of the world uses millibars, +// but the US, Canada and *some* other places use inches of mercury, +// but (a) we have not implemented a reliable method of +// ascertaining which airports are in the US, let alone +// (b) ascertaining which other places use inches. +// +int Apt_US_CA(const string id) { +// Assume all IDs have length 3 or 4. +// No counterexamples have been seen. + if (id.length() == 4) { + if (id.substr(0,1) == "K") return 1; + if (id.substr(0,2) == "CY") return 1; + } + for (string::const_iterator ptr = id.begin(); ptr != id.end(); ptr++) { + if (isdigit(*ptr)) return 1; + } + return 0; +} + // Generate the actual broadcast ATIS transmission. // Regen means regenerate the /current/ transmission. // Special means generate a new transmission, with a new sequence. @@ -238,7 +261,9 @@ int FGATIS::GenTransmission(const int regen, const int special) { transmission = ""; - if (ident.substr(0,2) == "EG") { + int US_CA = Apt_US_CA(ident); + + if (!US_CA) { // UK CAA radiotelephony manual indicates ATIS transmissions start // with "This is ..." transmission += This_is + " "; @@ -338,29 +363,39 @@ int FGATIS::GenTransmission(const int regen, const int special) { snprintf(buf, bs, "/environment/clouds/layer[%i]/elevation-ft", layer); double ceiling = int(fgGetDouble(buf) - _geod.getElevationFt()); if (ceiling > 12000) continue; - if (coverage == scattered) { - if (!did_some) transmission += " " + Sky_condition + ": "; - did_some++; + +// BEWARE: At the present time, the environment system has no +// way (so far as I know) to represent a "thin broken" or +// "thin overcast" layer. If/when such things are implemented +// in the environment system, code will have to be written here +// to handle them. + +// First, do the prefix if any: + if (coverage == scattered || coverage == few) { + if (!did_some) { + transmission += " " + Sky_condition + ": "; + did_some++; + } } else /* must be a ceiling */ if (!did_ceiling) { transmission += " " + Ceiling + ": "; did_ceiling++; did_some++; } else { - transmission += " "; + transmission += " "; // no prefix required } int cig00 = int(SGMiscd::round(ceiling/100)); // hundreds of feet if (cig00) { int cig000 = cig00/10; cig00 -= cig000*10; // just the hundreds digit if (cig000) { - snprintf(buf, bs, "%i", cig000); - transmission += ConvertNumToSpokenDigits(buf); - transmission += " " + thousand + " "; + snprintf(buf, bs, "%i", cig000); + transmission += ConvertNumToSpokenDigits(buf); + transmission += " " + thousand + " "; } if (cig00) { - snprintf(buf, bs, "%i", cig00); - transmission += ConvertNumToSpokenDigits(buf); - transmission += " " + hundred + " "; + snprintf(buf, bs, "%i", cig00); + transmission += ConvertNumToSpokenDigits(buf); + transmission += " " + hundred + " "; } } else { // Should this be "sky obscured?" @@ -368,6 +403,7 @@ int FGATIS::GenTransmission(const int regen, const int special) { } transmission += coverage + BRK; } + if (!did_some) transmission += " " + Sky + " " + clear + BRK; transmission += Temperature + ": "; double Tsl = fgGetDouble("/environment/temperature-sea-level-degc"); @@ -377,7 +413,7 @@ int FGATIS::GenTransmission(const int regen, const int special) { } snprintf(buf, bs, "%i", abs(temp)); transmission += ConvertNumToSpokenDigits(buf); - transmission += " " + Celsius; + if (US_CA) transmission += " " + Celsius; transmission += " " + dewpoint + " "; double dpsl = fgGetDouble("/environment/dewpoint-sea-level-degc"); temp = int(SGMiscd::round(FGAtmo().fake_dp_vs_a_us(dpsl, _geod.getElevationFt()))); @@ -386,7 +422,8 @@ int FGATIS::GenTransmission(const int regen, const int special) { } snprintf(buf, bs, "%i", abs(temp)); transmission += ConvertNumToSpokenDigits(buf); - transmission += " " + Celsius + BRK; + if (US_CA) transmission += " " + Celsius; + transmission += BRK; transmission += Visibility + ": "; double visibility = fgGetDouble("/environment/config/boundary/entry[0]/visibility-m"); @@ -409,7 +446,6 @@ int FGATIS::GenTransmission(const int regen, const int special) { } transmission += BRK; - transmission += Altimeter + ": "; double myQNH; double Psl = fgGetDouble("/environment/pressure-sea-level-inhg"); { @@ -424,17 +460,21 @@ int FGATIS::GenTransmission(const int regen, const int special) { #endif myQNH = FGAtmo().QNH(_geod.getElevationM(), press); } - if(ident.substr(0,2) == "EG" && fgGetBool("/sim/atc/use-millibars")) { - // Convert to millibars for the UK! + +// Convert to millibars for most of the world (not US, not CA) + if((!US_CA) || fgGetBool("/sim/atc/use-millibars")) { + transmission += QNH + ": "; myQNH /= mbar; if (myQNH > 1000) myQNH -= 1000; // drop high digit snprintf(buf, bs, "%03.0f", myQNH); + transmission += ConvertNumToSpokenDigits(buf) + " " + millibars + BRK; } else { - myQNH /= inHg; - myQNH *= 100.; // shift two decimal places - snprintf(buf, bs, "%04.0f", myQNH); + transmission += Altimeter + ": "; + double asetting = myQNH / inHg; // use inches of mercury + asetting *= 100.; // shift two decimal places + snprintf(buf, bs, "%04.0f", asetting); + transmission += ConvertNumToSpokenDigits(buf) + BRK; } - transmission += ConvertNumToSpokenDigits(buf) + BRK; if (_type == ATIS /* as opposed to AWOS */) { const FGAirport* apt = fgFindAirportID(ident); @@ -456,27 +496,8 @@ int FGATIS::GenTransmission(const int regen, const int special) { transmission += phonetic_seq_string; transmission += "... " + BRK + PAUSE + PAUSE; } -#ifdef ATIS_TEST - cout << "**** ATIS active on:"; -#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(), - ("
\n" + transmission + "
\n").c_str()); -#ifdef ATIS_TEST - cout << " " << prop; -#endif - } -#ifdef ATIS_TEST - cout << " ****" << endl; - cout << transmission << endl; -// Note that even if we aren't outputting the transmission -// on stdout, you can still see it by pointing a web browser -// at the property tree. The second comm radio is: -// http://localhost:5400/instrumentation/comm[1] -#endif - -// Take the previous English-looking string and munge it to + transmission_readable = transmission; +// Take the previous readable string and munge it to // be relatively-more acceptable to the primitive tts system. // Note that : ; and . are among the token-delimeters recognized // by the tts system. @@ -487,3 +508,27 @@ int FGATIS::GenTransmission(const int regen, const int special) { } return 1; } + +// Put the transmission into the property tree, +// possibly in multiple places if multiple radios +// are tuned to the same ATIS. +// You can see it by pointing a web browser +// at the property tree. The second comm radio is: +// http://localhost:5400/instrumentation/comm[1] +// +// (Also, if in debug mode, dump it to the console.) +void FGATIS::TreeOut(int msg_OK){ + 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(), + ("
\n" + transmission_readable + "
\n").c_str()); +#ifdef ATIS_TEST + if (msg_OK) cout << "**** ATIS active on: " << prop << endl; +#endif + } +#ifdef ATIS_TEST + if (msg_OK) cout << transmission_readable << endl; +#endif +} diff --git a/src/ATCDCL/atis.hxx b/src/ATCDCL/atis.hxx index cd35ea476..76809eb09 100644 --- a/src/ATCDCL/atis.hxx +++ b/src/ATCDCL/atis.hxx @@ -39,10 +39,15 @@ typedef std::map MSS; class FGATIS : public FGATC { //atc_type type; - std::string transmission; // The actual ATIS transmission - // This is not stored in default.atis but is generated - // from the prevailing conditions when required. + + // The actual ATIS transmission + // This is generated from the prevailing conditions when required. + // This is the version with markup, suitable for voice synthesis: + std::string transmission; + // Same as above, but in a form more readable as text. + std::string transmission_readable; + // for failure modeling std::string trans_ident; // transmitted ident double old_volume; @@ -82,9 +87,13 @@ class FGATIS : public FGATC { std::string refname; // Holds the refname of a transmission in progress - int GenTransmission(const int regen, - const int special); // Generate the transmission string + // Generate the ATIS transmission text: + int GenTransmission(const int regen, const int special); + // Put the text into the property tree + // (and in debug mode, print it on the console): + void TreeOut(int msgOK); + friend std::istream& operator>> ( std::istream&, FGATIS& ); }; diff --git a/src/ATCDCL/atis_lexicon.hxx b/src/ATCDCL/atis_lexicon.hxx index 37c2a03df..d201674ff 100644 --- a/src/ATCDCL/atis_lexicon.hxx +++ b/src/ATCDCL/atis_lexicon.hxx @@ -3,6 +3,9 @@ #include +// NOTE: This file serves as a database. +// It is read by some utility programs that synthesize +// the library of spoken words. #define Q(word) const std::string word(#word); @@ -41,6 +44,7 @@ Q(broken) Q(overcast) Q(thin) Q(Sky_condition) +Q(Sky) Q(Ceiling) Q(minus) Q(dewpoint) @@ -51,6 +55,8 @@ Q(one_half) Q(three_quarters) Q(one_and_one_half) Q(Altimeter) +Q(QNH) +Q(millibars) Q(Landing_and_departing_runway) Q(On_initial_contact_advise_you_have_information) Q(This_is) diff --git a/src/ATCDCL/atis_remap.hxx b/src/ATCDCL/atis_remap.hxx index c2341a2f0..2497197b3 100644 --- a/src/ATCDCL/atis_remap.hxx +++ b/src/ATCDCL/atis_remap.hxx @@ -1,3 +1,7 @@ +// NOTE: This file serves as a database. +// It is read by some utility programs that synthesize +// the library of spoken words. + REMAP(Intl, International) REMAP(Rgnl, Regional) REMAP(Co, County) -- 2.39.5