diff --git a/src/ATC/atis.cxx b/src/ATC/atis.cxx index 0b2007aa0..27f2200c4 100644 --- a/src/ATC/atis.cxx +++ b/src/ATC/atis.cxx @@ -55,22 +55,23 @@ SG_USING_STD(cout); #include "atislist.hxx" #include "ATCdisplay.hxx" #include "ATCutils.hxx" +#include "ATCmgr.hxx" // Constructor FGATIS::FGATIS() - : type(0), - lon(0.0), lat(0.0), - elev(0.0), - x(0.0), y(0.0), z(0.0), - freq(0), - range(0), - display(false), - displaying(false), - ident(""), - name(""), - transmission(""), - trans_ident(""), - atis_failed(false) +: type(0), +lon(0.0), lat(0.0), +elev(0.0), +x(0.0), y(0.0), z(0.0), +freq(0), +range(0), +display(false), +displaying(false), +ident(""), +name(""), +transmission(""), +trans_ident(""), +atis_failed(false) { } @@ -80,166 +81,208 @@ FGATIS::~FGATIS() { // Main update function - checks whether we are displaying or not the correct message. void FGATIS::Update() { - if(display) { - if(displaying) { - // Check if we need to update the message - // - basically every hour and if the weather changes significantly at the station - //globals->get_ATC_display()->ChangeRepeatingMessage(transmission); + if(display) { + if(displaying) { + // Check if we need to update the message + // - basically every hour and if the weather changes significantly at the station + //globals->get_ATC_display()->ChangeRepeatingMessage(transmission); + } else { + // We need to get and display the message + UpdateTransmission(); + //cout << "ATIS.CXX - calling ATCMgr to render transmission..." << endl; + globals->get_ATC_mgr()->Render(transmission, true); + displaying = true; + } } else { - // We need to get and display the message - UpdateTransmission(); - globals->get_ATC_display()->RegisterRepeatingMessage(transmission); - displaying = true; + // We shouldn't be displaying + if(displaying) { + //cout << "ATIS.CXX - calling NoRender()..." << endl; + globals->get_ATC_mgr()->NoRender(); + displaying = false; + } } - } else { - // We shouldn't be displaying - if(displaying) { - globals->get_ATC_display()->CancelRepeatingMessage(); - displaying = false; - } - } } // Sets the actual broadcast ATIS transmission. void FGATIS::UpdateTransmission() { - double visibility; - char buf[10]; - int phonetic_id; - string phonetic_id_string; - string time_str = fgGetString("sim/time/gmt-string"); - int hours; - // int minutes; - -#ifdef FG_WEATHERCM - sgVec3 position = { lat, lon, elev }; - FGPhysicalProperty stationweather = WeatherDatabase->get(position); -#else - FGEnvironment stationweather = - globals->get_environment_mgr()->getEnvironment(lat, lon, elev); -#endif - - transmission = ""; - - // Start with the transmitted station name. - transmission += name; - // Add "Information" - transmission += " Information"; - - //cout << "In atis.cxx, time_str = " << time_str << '\n'; - // Add the recording identifier - // For now we will assume we only transmit every hour - hours = atoi((time_str.substr(1,2)).c_str()); //Warning - this is fragile if the - //time string format changes - //cout << "In atis.cxx, hours = " << hours << endl; - phonetic_id = current_atislist->GetCallSign(ident, hours, 0); - phonetic_id_string = GetPhoneticIdent(phonetic_id); - transmission += " "; - transmission += phonetic_id_string; - - // Output the recording time. - we'll just output the last whole hour for now. - // FIXME - this only gets GMT time but that appears to be all the clock outputs for now - //cout << "in atis.cxx, time = " << time_str << endl; - transmission = transmission + " Weather " + time_str.substr(0,3) + "00 hours Zulu"; - - // Get the temperature - // (Hardwire it for now since the global property returns the temperature at the current altitude - //temperature = fgGetDouble("/environment/weather/temperature-K"); -#ifdef FG_WEATHERCM - sprintf(buf, "%i", int(stationweather.Temperature - 273.15)); -#else - sprintf(buf, "%d", int(stationweather.get_temperature_degc())); -#endif - transmission += " Temperature "; - transmission += buf; - transmission += " degrees Celsius"; - + double visibility; + char buf[10]; + int phonetic_id; + string phonetic_id_string; + string time_str = fgGetString("sim/time/gmt-string"); + int hours; + // int minutes; + + #ifdef FG_WEATHERCM + sgVec3 position = { lat, lon, elev }; + FGPhysicalProperty stationweather = WeatherDatabase->get(position); + #else + FGEnvironment stationweather = + globals->get_environment_mgr()->getEnvironment(lat, lon, elev); + #endif + + transmission = ""; + + // UK CAA radiotelephony manual indicated ATIS transmissions start with "This is" + // Not sure about rest of the world though. + transmission += "This_is "; + // transmitted station name. + transmission += name; + // Add "Information" + transmission += " information"; + + //cout << "In atis.cxx, time_str = " << time_str << '\n'; + // Add the recording identifier + // For now we will assume we only transmit every hour + hours = atoi((time_str.substr(1,2)).c_str()); //Warning - this is fragile if the + //time string format changes + //cout << "In atis.cxx, hours = " << hours << endl; + phonetic_id = current_atislist->GetCallSign(ident, hours, 0); + phonetic_id_string = GetPhoneticIdent(phonetic_id); + transmission += " "; + transmission += phonetic_id_string; + + // Output the recording time. - we'll just output the last whole hour for now. + // FIXME - this only gets GMT time but that appears to be all the clock outputs for now + //cout << "in atis.cxx, time = " << time_str << endl; + transmission = transmission + " / Weather " + ConvertNumToSpokenDigits((time_str.substr(0,3) + "00")) + " hours zulu"; + + // Get the temperature + // (Hardwire it for now since the global property returns the temperature at the current altitude + //temperature = fgGetDouble("/environment/weather/temperature-K"); + #ifdef FG_WEATHERCM + sprintf(buf, "%i", int(stationweather.Temperature - 273.15)); + #else + // HACK ALERT - at the moment the new environment subsystem returns bogus temperatures + // FIXME - take out this hack when this gets fixed upstream + int temp = (int)stationweather.get_temperature_degc(); + if((temp < -50) || (temp > 60)) { + temp = 15; + } + // original: + //sprintf(buf, "%d", int(stationweather.get_temperature_degc())); + // hack: + sprintf(buf, "%d", temp); + #endif + transmission += " / Temperature "; + if(temp < 0) { + transmission += "minus "; + } + string tempstr1 = buf; + string tempstr2; + transmission += ConvertNumToSpokenDigits(tempstr1); + transmission += " degrees_Celsius"; + // Get the visibility -#ifdef FG_WEATHERCM + #ifdef FG_WEATHERCM visibility = fgGetDouble("/environment/visibility-m"); -#else - visibility = stationweather.get_visibility_m(); -#endif + #else + visibility = stationweather.get_visibility_m(); + #endif sprintf(buf, "%i", int(visibility/1600)); - transmission += " Visibility "; - transmission += buf; + transmission += " / Visibility "; + tempstr1 = buf; + transmission += ConvertNumToSpokenDigits(tempstr1); transmission += " miles"; - + // Get the cloudbase // FIXME: kludge for now if (strcmp(fgGetString("/environment/clouds/layer[0]/type"), "clear")) { - double cloudbase = - fgGetDouble("/environment/clouds/layer[0]/elevation-ft"); - // For some reason the altitude returned doesn't seem to correspond to the actual cloud altitude. - char buf3[10]; - // cout << "cloudbase = " << cloudbase << endl; - sprintf(buf3, "%i", int(cloudbase)); - transmission = transmission + " Cloudbase " + buf3 + " feet"; + double cloudbase = + fgGetDouble("/environment/clouds/layer[0]/elevation-ft"); + // For some reason the altitude returned doesn't seem to correspond to the actual cloud altitude. + char buf3[10]; + char buf4[10]; + // cout << "cloudbase = " << cloudbase << endl; + sprintf(buf3, "%i", int(cloudbase)/1000); + sprintf(buf4, "%i", ((int)cloudbase % 1000)/100); + transmission += " / Cloudbase"; + if(int(cloudbase)/1000) { + tempstr1 = buf3; + transmission = transmission + " " + ConvertNumToSpokenDigits(tempstr1) + " thousand"; + } + if(((int)cloudbase % 1000)/100) { + tempstr1 = buf4; + transmission = transmission + " " + ConvertNumToSpokenDigits(tempstr1) + " hundred"; + } + transmission += " feet"; } - + // Get the pressure / altimeter - -#ifndef FG_WEATHERCM - double altimeter = stationweather.get_pressure_sea_level_inhg(); - sprintf(buf, "%.2f", altimeter); - transmission += " Altimeter "; - transmission += buf; -#endif - + + #ifndef FG_WEATHERCM + double altimeter = stationweather.get_pressure_sea_level_inhg(); + sprintf(buf, "%.2f", altimeter); + transmission += " / Altimeter "; + tempstr1 = buf; + transmission += ConvertNumToSpokenDigits(tempstr1); + #endif + // Based on the airport-id and wind get the active runway //FGRunway *r; SGPath path( globals->get_fg_root() ); path.append( "Airports" ); path.append( "runways.mk4" ); FGRunways runways( path.c_str() ); - -#ifdef FG_WEATHERCM + + #ifdef FG_WEATHERCM //Set the heading to into the wind - double wind_x = stationweather.Wind[0]; - double wind_y = stationweather.Wind[1]; - - double speed = sqrt( wind_x*wind_x + wind_y*wind_y ) * SG_METER_TO_NM / (60.0*60.0); - double hdg; - + double wind_x = stationweather.Wind[0]; + double wind_y = stationweather.Wind[1]; + + double speed = sqrt( wind_x*wind_x + wind_y*wind_y ) * SG_METER_TO_NM / (60.0*60.0); + double hdg; + //If no wind use 270degrees if(speed == 0) { - hdg = 270; - transmission += " Winds light and variable"; + hdg = 270; + transmission += " / Winds_light_and_variable"; } else { - // //normalize the wind to get the direction - //wind_x /= speed; wind_y /= speed; - - hdg = - atan2 ( wind_x, wind_y ) * SG_RADIANS_TO_DEGREES ; - if (hdg < 0.0) - hdg += 360.0; - - //add a description of the wind to the transmission - char buf2[72]; - sprintf(buf2, "%s %i %s %i %s", " Winds ", int(speed), " knots from ", int(hdg), " degrees"); - transmission += buf2; + // //normalize the wind to get the direction + //wind_x /= speed; wind_y /= speed; + + hdg = - atan2 ( wind_x, wind_y ) * SG_RADIANS_TO_DEGREES ; + if (hdg < 0.0) + hdg += 360.0; + + //add a description of the wind to the transmission + char buf5[10]; + char buf6[10]; + sprintf(buf5, "%i", int(speed)); + sprintf(buf6, "%i", int(hdg)); + tempstr1 = buf5; + tempstr2 = buf6; + transmission = transmission + " / Winds " + ConvertNumToSpokenDigits(tempstr1) + " knots from " + + ConvertNumToSpokenDigits(tempstr2) + " degrees"; } -#else + #else double speed = stationweather.get_wind_speed_kt(); double hdg = stationweather.get_wind_from_heading_deg(); if (speed == 0) { - transmission += " Winds light and variable"; + transmission += " / Winds_light_and_variable"; } else { - // FIXME: get gust factor in somehow - char buf2[72]; - sprintf(buf2, "%s %i %s %i %s", " Winds ", int(speed), - " knots from ", int(hdg), " degrees"); - transmission += buf2; + // FIXME: get gust factor in somehow + char buf5[10]; + char buf6[10]; + sprintf(buf5, "%i", int(speed)); + sprintf(buf6, "%i", int(hdg)); + tempstr1 = buf5; + tempstr2 = buf6; + transmission = transmission + " / Winds " + ConvertNumToSpokenDigits(tempstr1) + " knots from " + + ConvertNumToSpokenDigits(tempstr2) + " degrees"; } -#endif - + #endif + string rwy_no = runways.search(ident, int(hdg)); if(rwy_no != (string)"NN") { - transmission += " Landing and departing runway "; - transmission += rwy_no; - //cout << "in atis.cxx, r.rwy_no = " << rwy_no << " r.id = " << r->id << " r.heading = " << r->heading << endl; + transmission += " / Landing_and_departing_runway "; + transmission += ConvertRwyNumToSpokenString(atoi(rwy_no.c_str())); + //cout << "in atis.cxx, r.rwy_no = " << rwy_no << " r.id = " << r->id << " r.heading = " << r->heading << endl; } - + // Anything else? - - transmission += " Advise controller on initial contact you have "; + + transmission += " / Advise_controller_on_initial_contact_you_have "; transmission += phonetic_id_string; + transmission += " /// "; } diff --git a/src/ATC/atis.hxx b/src/ATC/atis.hxx index 6d663a0ee..13f2b6b1a 100644 --- a/src/ATC/atis.hxx +++ b/src/ATC/atis.hxx @@ -33,14 +33,14 @@ #ifdef SG_HAVE_STD_INCLUDES # include -#include +# include #elif defined( SG_HAVE_NATIVE_SGI_COMPILERS ) # include #elif defined( __BORLANDC__ ) || (__APPLE__) # include #else # include -#include +# include #endif #if ! defined( SG_HAVE_NATIVE_SGI_COMPILERS ) @@ -57,131 +57,131 @@ SG_USING_STD(string); #define FG_ATIS_DEFAULT_RANGE 30 class FGATIS : public FGATC { - - char type; - double lon, lat; - double elev; - double x, y, z; - int freq; - int range; - bool display; // Flag to indicate whether we should be outputting to the ATC display. - bool displaying; // Flag to indicate whether we are outputting to the ATC display. - string ident; // Code of the airport its at. - string name; // Name transmitted in the broadcast. - string transmission; // The actual ATIS transmission - // This is not stored in default.atis but is generated - // from the prevailing conditions when required. - - // for failure modeling - string trans_ident; // transmitted ident - bool atis_failed; // atis failed? - - // Aircraft position - // ATIS is actually a special case in that unlike other ATC eg.tower it doesn't actually know about - // or the whereabouts of the aircraft it is transmitting to. However, to ensure consistancy of - // operation with the other ATC classes the ATIS class must calculate range to the aircraft in order - // to decide whether to render the transmission - hence the users plane details must be stored. - //SGPropertyNode *airplane_lon_node; - //SGPropertyNode *airplane_lat_node; - //SGPropertyNode *airplane_elev_node; - -public: - - FGATIS(void); - ~FGATIS(void); - - //run the ATIS instance - void Update(void); - - //Indicate that this instance should be outputting to the ATC display - inline void SetDisplay(void) {display = true;} - - //Indicate that this instance should not be outputting to the ATC display - inline void SetNoDisplay(void) {display = false;} - - inline char get_type() const { return type; } - inline double get_lon() const { return lon; } - inline double get_lat() const { return lat; } - inline double get_elev() const { return elev; } - inline double get_x() const { return x; } - inline double get_y() const { return y; } - inline double get_z() const { return z; } - inline int get_freq() const { return freq; } - inline int get_range() const { return range; } - inline const char* GetIdent() { return ident.c_str(); } - inline string get_trans_ident() { return trans_ident; } - inline atc_type GetType() { return ATIS; } - -private: - - //Update the transmission string - void UpdateTransmission(void); - - /* inline void set_type( char t ) { type = t; } - inline void set_lon( double l ) { lon = l; } - inline void set_lat( double l ) { lat = l; } - inline void set_elev( double e ) { elev = e; } - inline void set_freq( int f ) { freq = f; } - inline void set_range( int r ) { range = r; } - inline void set_dme( bool b ) { dme = b; } - inline void set_ident( char *i ) { strncpy( ident, i, 5 ); } */ - - friend istream& operator>> ( istream&, FGATIS& ); + + char type; + double lon, lat; + double elev; + double x, y, z; + int freq; + int range; + bool display; // Flag to indicate whether we should be outputting to the ATC display. + bool displaying; // Flag to indicate whether we are outputting to the ATC display. + string ident; // Code of the airport its at. + string name; // Name transmitted in the broadcast. + string transmission; // The actual ATIS transmission + // This is not stored in default.atis but is generated + // from the prevailing conditions when required. + + // for failure modeling + string trans_ident; // transmitted ident + bool atis_failed; // atis failed? + + // Aircraft position + // ATIS is actually a special case in that unlike other ATC eg.tower it doesn't actually know about + // or the whereabouts of the aircraft it is transmitting to. However, to ensure consistancy of + // operation with the other ATC classes the ATIS class must calculate range to the aircraft in order + // to decide whether to render the transmission - hence the users plane details must be stored. + //SGPropertyNode *airplane_lon_node; + //SGPropertyNode *airplane_lat_node; + //SGPropertyNode *airplane_elev_node; + + public: + + FGATIS(void); + ~FGATIS(void); + + //run the ATIS instance + void Update(void); + + //Indicate that this instance should be outputting to the ATC display + inline void SetDisplay(void) {display = true;} + + //Indicate that this instance should not be outputting to the ATC display + inline void SetNoDisplay(void) {display = false;} + + inline char get_type() const { return type; } + inline double get_lon() const { return lon; } + inline double get_lat() const { return lat; } + inline double get_elev() const { return elev; } + inline double get_x() const { return x; } + inline double get_y() const { return y; } + inline double get_z() const { return z; } + inline int get_freq() const { return freq; } + inline int get_range() const { return range; } + inline const char* GetIdent() { return ident.c_str(); } + inline string get_trans_ident() { return trans_ident; } + inline atc_type GetType() { return ATIS; } + + private: + + //Update the transmission string + void UpdateTransmission(void); + + /* inline void set_type( char t ) { type = t; } + inline void set_lon( double l ) { lon = l; } + inline void set_lat( double l ) { lat = l; } + inline void set_elev( double e ) { elev = e; } + inline void set_freq( int f ) { freq = f; } + inline void set_range( int r ) { range = r; } + inline void set_dme( bool b ) { dme = b; } + inline void set_ident( char *i ) { strncpy( ident, i, 5 ); } */ + + friend istream& operator>> ( istream&, FGATIS& ); }; inline istream& operator >> ( istream& in, FGATIS& a ) { - double f; - char ch; - - static bool first_time = true; - static double julian_date = 0; - static const double MJD0 = 2415020.0; - if ( first_time ) { - julian_date = sgTimeCurrentMJD(0, 0) + MJD0; - first_time = false; - } - - in >> a.type; - - if ( a.type == '[' ) - return in >> skipeol; - - in >> a.lat >> a.lon >> a.elev >> f >> a.range - >> a.ident; - - a.name = ""; - in >> ch; - a.name += ch; - while(1) { - //in >> noskipws - in.unsetf(ios::skipws); + double f; + char ch; + + static bool first_time = true; + static double julian_date = 0; + static const double MJD0 = 2415020.0; + if ( first_time ) { + julian_date = sgTimeCurrentMJD(0, 0) + MJD0; + first_time = false; + } + + in >> a.type; + + if ( a.type == '[' ) + return in >> skipeol; + + in >> a.lat >> a.lon >> a.elev >> f >> a.range + >> a.ident; + + a.name = ""; in >> ch; a.name += ch; - if((ch == '"') || (ch == 0x0A)) { - break; - } // we shouldn't need the 0x0A but it makes a nice safely in case someone leaves off the " - } - in.setf(ios::skipws); - //cout << "atis.name = " << a.name << '\n'; - - a.freq = (int)(f*100.0 + 0.5); - - // cout << a.ident << endl; - - // 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(); - - a.trans_ident = a.ident; - a.atis_failed = false; - - return in >> skipeol; + while(1) { + //in >> noskipws + in.unsetf(ios::skipws); + in >> ch; + a.name += ch; + if((ch == '"') || (ch == 0x0A)) { + break; + } // we shouldn't need the 0x0A but it makes a nice safely in case someone leaves off the " + } + in.setf(ios::skipws); + //cout << "atis.name = " << a.name << '\n'; + + a.freq = (int)(f*100.0 + 0.5); + + // cout << a.ident << endl; + + // 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(); + + a.trans_ident = a.ident; + a.atis_failed = false; + + return in >> skipeol; } #endif // _FG_ATIS_HXX