]> git.mxchange.org Git - flightgear.git/commitdiff
Progress towards AI/ATC communication without speaking all at once
authordaveluff <daveluff>
Mon, 6 Oct 2003 15:20:47 +0000 (15:20 +0000)
committerdaveluff <daveluff>
Mon, 6 Oct 2003 15:20:47 +0000 (15:20 +0000)
src/ATC/AILocalTraffic.cxx
src/ATC/AIPlane.cxx
src/ATC/AIPlane.hxx
src/ATC/ATC.cxx
src/ATC/ATC.hxx
src/ATC/tower.cxx
src/ATC/tower.hxx

index b62f4b4c027c30bdd5d683809cf1c17cabecda75..f1a866e263e6a9bb1cfb017bb0f7ded0df8f01d5 100644 (file)
@@ -319,7 +319,8 @@ void FGAILocalTraffic::Update(double dt) {
                trns += buf;
                trns += " ";
                trns += plane.callsign;
-               Transmit(trns);
+               pending_transmission = trns;
+               Transmit(30.0);
                responseCounter = 0.0;
                contactTower = false;
                changeFreq = true;
@@ -414,7 +415,8 @@ void FGAILocalTraffic::Update(double dt) {
                        holdingShort = false;
                        string trns = "Cleared for take-off ";
                        trns += plane.callsign;
-                       Transmit(trns);
+                       pending_transmission = trns;
+                       Transmit();
                        StartTaxi();
                }
                //cout << "^" << flush;
@@ -476,7 +478,8 @@ void FGAILocalTraffic::Update(double dt) {
                                trns += plane.callsign;
                                trns += " on apron parking request taxi for traffic pattern";
                                //cout << "trns = " << trns << endl;
-                               Transmit(trns);
+                               pending_transmission = trns;
+                               Transmit();
                                taxiRequestCleared = false;
                                taxiRequestPending = true;
                        }
@@ -504,6 +507,9 @@ void FGAILocalTraffic::Update(double dt) {
        fgSetDouble("/AI/Local1/ortho-x", (ortho.ConvertToLocal(pos)).x());
        fgSetDouble("/AI/Local1/ortho-y", (ortho.ConvertToLocal(pos)).y());
        fgSetDouble("/AI/Local1/elev", pos.elev() * SG_METER_TO_FEET);
+       
+       // And finally, call parent for transmission rendering
+       FGAIPlane::Update(dt);
 }
 
 void FGAILocalTraffic::RegisterTransmission(int code) {
@@ -947,7 +953,8 @@ void FGAILocalTraffic::TransmitPatternPositionReport(void) {
        // And add the airport name again
        trns += tower->get_name();
        
-       Transmit(trns);
+       pending_transmission = trns;    // FIXME - make up pending_transmission natively        
+       Transmit(90.0);         // Assume a report of this leg will be invalid if we can't transmit within a minute and a half.
 }
 
 void FGAILocalTraffic::ExitRunway(Point3D orthopos) {
index 7d224f65f1562c0b59c07302b46883dcc6a826ac..5ce556b472705ca157670acf127749eacf8c2729 100644 (file)
@@ -22,6 +22,7 @@
 #include <Main/fg_props.hxx>
 #include <simgear/math/point3d.hxx>
 #include <simgear/debug/logstream.hxx>
+#include <simgear/sound/soundmgr.hxx>
 #include <math.h>
 #include <string>
 SG_USING_STD(string);
@@ -32,12 +33,73 @@ SG_USING_STD(string);
 
 FGAIPlane::FGAIPlane() {
        leg = LEG_UNKNOWN;
+       tuned_station = NULL;
+       pending_transmission = "";
+       _timeout = 0;
+       _pending = false;
+       _callback = NULL;
+       _transmit = false;
+       _transmitting = false;
+       voice = false;
+       playing = false;
+       voiceOK = false;
+       vPtr = NULL;
 }
 
 FGAIPlane::~FGAIPlane() {
 }
 
 void FGAIPlane::Update(double dt) {
+       if(_pending) {
+               if(tuned_station) {
+                       if(tuned_station->FreqClear()) {
+                               _pending = false;
+                               _transmit = true;
+                               _transmitting = false;
+                       } else {
+                               if(_timeout > 0.0) {    // allows count down to be avoided by initially setting it to zero
+                                       _timeout -= dt;
+                                       if(_timeout <= 0.0) {
+                                               _timeout = 0.0;
+                                               _pending = false;
+                                               // timed out - don't render.
+                                       }
+                               }
+                       }
+               } else {
+                       // Not tuned to ATC - Just go ahead and transmit
+                       _pending = false;
+                       _transmit = true;
+                       _transmitting = false;
+               }
+       }
+       
+       // This turns on rendering if on the same freq as the user
+       // TODO - turn it off if user switches to another freq - keep track of where in message we are etc.
+       if(_transmit) {
+               double user_freq0 = fgGetDouble("/radios/comm[0]/frequencies/selected-mhz");
+               //comm1 is not used yet.
+               _counter = 0.0;
+               _max_count = 5.0;               // FIXME - hardwired length of message - need to calculate it!
+               
+               if(freq == user_freq0) {
+                       //cout << "Transmitting..." << endl;
+                       // we are on the same frequency, so check distance to the user plane
+                       if(1) {
+                               // For now assume in range !!!
+                               // TODO - implement range checking
+                               Render(plane.callsign, false);
+                               _transmit = false;
+                               _transmitting = true;
+                       }
+               }
+       } else if(_transmitting) {
+               if(_counter >= _max_count) {
+                       NoRender(plane.callsign);
+                       _transmitting = false;
+               }
+               _counter += dt;
+       }
 }
 
 void FGAIPlane::Bank(double angle) {
@@ -55,23 +117,85 @@ void FGAIPlane::LevelWings(void) {
        }
 }
 
-void FGAIPlane::Transmit(string msg) {
-       SG_LOG(SG_ATC, SG_INFO, "Transmit called, msg = " << msg);
-       double user_freq0 = fgGetDouble("/radios/comm[0]/frequencies/selected-mhz");
-       //double user_freq0 = ("/radios/comm[0]/frequencies/selected-mhz");
-       //comm1 is not used yet.
-       
-       if(freq == user_freq0) {
-               //cout << "Transmitting..." << endl;
-               // we are on the same frequency, so check distance to the user plane
-               if(1) {
-                       // For now (testing) assume in range !!!
-                       // TODO - implement range checking
-                       globals->get_ATC_display()->RegisterSingleMessage(msg, 0);
+void FGAIPlane::Transmit(ai_plane_callback_t callback) {
+       SG_LOG(SG_ATC, SG_INFO, "Transmit called for plane " << plane.callsign << ", msg = " << pending_transmission);
+       _pending = true;
+       _callback = callback;
+       _timeout = 0.0;
+}
+
+void FGAIPlane::Transmit(double timeout, ai_plane_callback_t callback) {
+       SG_LOG(SG_ATC, SG_INFO, "Timed transmit called for plane " << plane.callsign << ", msg = " << pending_transmission);
+       _pending = true;
+       _callback = callback;
+       _timeout = timeout;
+}
+
+void FGAIPlane::ImmediateTransmit(ai_plane_callback_t callback) {
+       Render(plane.callsign, false);
+       if(_callback) {
+               (*_callback)();
+       }
+}
+
+// Render a transmission
+// Outputs the transmission either on screen or as audio depending on user preference
+// The refname is a string to identify this sample to the sound manager
+// The repeating flag indicates whether the message should be repeated continuously or played once.
+void FGAIPlane::Render(string refname, bool repeating) {
+#ifdef ENABLE_AUDIO_SUPPORT
+       voice = (voiceOK && fgGetBool("/sim/sound/audible")
+                 && fgGetBool("/sim/sound/voice"));
+       if(voice) {
+               int len;
+               unsigned char* buf = vPtr->WriteMessage((char*)pending_transmission.c_str(), len, voice);
+               if(voice) {
+                       SGSimpleSound* simple = new SGSimpleSound(buf, len);
+                       // TODO - at the moment the volume is always set off comm1 
+                       // and can't be changed after the transmission has started.
+                       simple->set_volume(5.0 * fgGetDouble("/radios/comm[0]/volume"));
+                       globals->get_soundmgr()->add(simple, refname);
+                       if(repeating) {
+                               globals->get_soundmgr()->play_looped(refname);
+                       } else {
+                               globals->get_soundmgr()->play_once(refname);
+                       }
+               }
+               delete[] buf;
+       }
+#endif // ENABLE_AUDIO_SUPPORT
+       if(!voice) {
+               // first rip the underscores and the pause hints out of the string - these are for the convienience of the voice parser
+               for(unsigned int i = 0; i < pending_transmission.length(); ++i) {
+                       if((pending_transmission.substr(i,1) == "_") || (pending_transmission.substr(i,1) == "/")) {
+                               pending_transmission[i] = ' ';
+                       }
                }
+               globals->get_ATC_display()->RegisterSingleMessage(pending_transmission, 0.0);
        }
+       playing = true; 
 }
 
+
+// Cease rendering a transmission.
+void FGAIPlane::NoRender(string refname) {
+       if(playing) {
+               if(voice) {
+#ifdef ENABLE_AUDIO_SUPPORT            
+                       globals->get_soundmgr()->stop(refname);
+                       globals->get_soundmgr()->remove(refname);
+#endif
+               } else {
+                       globals->get_ATC_display()->CancelRepeatingMessage();
+               }
+               playing = false;
+       }
+}
+
+/*
+
+*/
+
 void FGAIPlane::RegisterTransmission(int code) {
 }
 
index a757bf26ad0d12b20069c47243350f734e5a74ff..544212ee08f1be0f3ae7ad041b7034c60fc1d9b4 100644 (file)
@@ -72,7 +72,7 @@ public:
     virtual ~FGAIPlane();
 
     // Run the internal calculations
-    virtual void Update(double dt);
+       void Update(double dt);
        
        // Send a transmission *TO* the AIPlane.
        // FIXME int code is a hack - eventually this will receive Alexander's coded messages.
@@ -85,6 +85,9 @@ public:
        LandingType GetLandingOption();
 
 protected:
+       // callback type for derived classes to use
+       typedef void (*ai_plane_callback_t) (void);
+
        PlaneRec plane;
 
     double mag_hdg;    // degrees - the heading that the physical aircraft is *pointing*
@@ -106,12 +109,47 @@ protected:
     // Make radio transmission - this simply sends the transmission for physical rendering if the users
     // aircraft is on the same frequency and in range.  It is up to the derived classes to let ATC know
     // what is going on.
-    void Transmit(string msg);
+       string pending_transmission;    // derived classes set this string before calling Transmit(...)
+       FGATC* tuned_station;                   // and this if they are tuned to ATC
+       
+       // Transmit a message when channel becomes free of other dialog
+    void Transmit(ai_plane_callback_t callback = NULL);
+       
+       // Transmit a message if channel becomes free within timeout (seconds). timeout of zero implies no limit
+       void Transmit(double timeout, ai_plane_callback_t callback = NULL);
+       
+       // Transmit regardless of other dialog on the channel eg emergency
+       void ImmediateTransmit(ai_plane_callback_t callback = NULL);
 
     void Bank(double angle);
     void LevelWings(void);
        
        PatternLeg leg;
+       
+private:
+       bool _pending;
+       double _timeout;
+       ai_plane_callback_t _callback;
+       bool _transmit;         // we are to transmit
+       bool _transmitting;     // we are transmitting
+       double _counter;
+       double _max_count;
+       
+       // Render a transmission (in string pending_transmission)
+       // Outputs the transmission either on screen or as audio depending on user preference
+       // The refname is a string to identify this sample to the sound manager
+       // The repeating flag indicates whether the message should be repeated continuously or played once.
+       void Render(string refname, bool repeating);
+
+       // Cease rendering a transmission.
+       // Requires the sound manager refname if audio, else "".
+       void NoRender(string refname);
+       
+       // Rendering related stuff
+       bool voice;                     // Flag - true if we are using voice
+       bool playing;           // Indicates a message in progress      
+       bool voiceOK;           // Flag - true if at least one voice has loaded OK
+       FGATCVoice* vPtr;
 };
 
 #endif  // _FG_AI_PLANE_HXX
index d8fc4b737c6538aae41652f52a121235c07e6aa3..120c00e98d50f444b7d9933b9227e1982544bd48 100644 (file)
 #include "ATC.hxx"
 #include "ATCdisplay.hxx"
 
+FGATC::FGATC() {
+       freqClear = true;
+}
+
 FGATC::~FGATC() {
 }
 
@@ -39,7 +43,7 @@ void FGATC::AddPlane(string pid) {
 }
 
 int FGATC::RemovePlane() {
-    return 0;
+       return 0;
 }
 
 void FGATC::SetDisplay() {
@@ -49,7 +53,7 @@ void FGATC::SetNoDisplay() {
 }
 
 atc_type FGATC::GetType() {
-    return INVALID;
+       return INVALID;
 }
 
 void FGATC::SetData(ATCData* d) {
@@ -70,9 +74,9 @@ void FGATC::SetData(ATCData* d) {
 // The refname is a string to identify this sample to the sound manager
 // The repeating flag indicates whether the message should be repeated continuously or played once.
 void FGATC::Render(string msg, string refname, bool repeating) {
-#ifdef ENABLE_AUDIO_SUPPORT
+       #ifdef ENABLE_AUDIO_SUPPORT
        voice = (voiceOK && fgGetBool("/sim/sound/audible")
-                 && fgGetBool("/sim/sound/voice"));
+       && fgGetBool("/sim/sound/voice"));
        if(voice) {
                int len;
                unsigned char* buf = vPtr->WriteMessage((char*)msg.c_str(), len, voice);
@@ -90,7 +94,7 @@ void FGATC::Render(string msg, string refname, bool repeating) {
                }
                delete[] buf;
        }
-#endif // ENABLE_AUDIO_SUPPORT
+       #endif  // ENABLE_AUDIO_SUPPORT
        if(!voice) {
                // first rip the underscores and the pause hints out of the string - these are for the convienience of the voice parser
                for(unsigned int i = 0; i < msg.length(); ++i) {
@@ -108,10 +112,10 @@ void FGATC::Render(string msg, string refname, bool repeating) {
 void FGATC::NoRender(string refname) {
        if(playing) {
                if(voice) {
-#ifdef ENABLE_AUDIO_SUPPORT            
+                       #ifdef ENABLE_AUDIO_SUPPORT             
                        globals->get_soundmgr()->stop(refname);
                        globals->get_soundmgr()->remove(refname);
-#endif
+                       #endif
                } else {
                        globals->get_ATC_display()->CancelRepeatingMessage();
                }
@@ -120,21 +124,14 @@ void FGATC::NoRender(string refname) {
 }
 
 ostream& operator << (ostream& os, atc_type atc) {
-    switch(atc) {
-    case(INVALID):
-       return(os << "INVALID");
-    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");
-    }
-    return(os << "ERROR - Unknown switch in atc_type operator << ");
+       switch(atc) {
+               case(INVALID):    return(os << "INVALID");
+               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");
+       }
+       return(os << "ERROR - Unknown switch in atc_type operator << ");
 }
index 38750898ace9fb214b35286b284968b181de0461..1249e6e1f44fa6b357880fa2628816c993ea8b43 100644 (file)
@@ -58,13 +58,13 @@ 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,
-    ATIS,
-    GROUND,
-    TOWER,
-    APPROACH,
-    DEPARTURE,
-    ENROUTE
+       INVALID,
+       ATIS,
+       GROUND,
+       TOWER,
+       APPROACH,
+       DEPARTURE,
+       ENROUTE
 }; 
 
 // DCL - new experimental ATC data store
@@ -98,28 +98,39 @@ struct RunwayDetails {
 ostream& operator << (ostream& os, atc_type atc);
 
 class FGATC {
-
-public:
-
-    virtual ~FGATC();
-
-    // Run the internal calculations
-    virtual void Update(double dt);
-
-    // Add plane to a stack
-    virtual void AddPlane(string pid);
-
-    // Remove plane from stack
-    virtual int RemovePlane();
-
-    // Indicate that this instance should output to the display if appropriate 
-    virtual void SetDisplay();
-
-    // Indicate that this instance should not output to the display
-    virtual void SetNoDisplay();
-
-    // Return the type of ATC station that the class represents
-    virtual atc_type GetType();
+       
+       public:
+       
+       FGATC();
+       virtual ~FGATC();
+       
+       // Run the internal calculations
+       virtual void Update(double dt);
+       
+       // Add plane to a stack
+       virtual void AddPlane(string pid);
+       
+       // Remove plane from stack
+       virtual int RemovePlane();
+       
+       // Indicate that this instance should output to the display if appropriate 
+       virtual void SetDisplay();
+       
+       // Indicate that this instance should not output to the display
+       virtual void SetNoDisplay();
+       
+       // Returns true if OK to transmit on this frequency
+       inline bool FreqClear() { return freqClear; }
+       // Indicate that the frequency is in use
+       inline void FreqInUse() { freqClear = false; }
+       // Under development!!
+       // The idea is that AI traffic or the user ATC dialog box calls FreqInUse() when they begin transmitting,
+       // and that the tower control sets freqClear back to true following a reply.
+       // AI traffic should check FreqClear() is true prior to transmitting.
+       // The user will just have to wait for a gap in dialog as in real life.
+       
+       // Return the type of ATC station that the class represents
+       virtual atc_type GetType();
        
        // Set the core ATC data
        void SetData(ATCData* d);
@@ -145,18 +156,18 @@ public:
        inline const char* get_name() {return name.c_str();}
        inline void set_name(const string nm) {name = nm;}
        
-protected:
-
+       protected:
+       
        // Render a transmission
        // Outputs the transmission either on screen or as audio depending on user preference
        // The refname is a string to identify this sample to the sound manager
        // The repeating flag indicates whether the message should be repeated continuously or played once.
        void Render(string msg, string refname, bool repeating);
-
+       
        // Cease rendering a transmission.
        // Requires the sound manager refname if audio, else "".
        void NoRender(string refname);
-
+       
        double lon, lat, elev;
        double x, y, z;
        int freq;
@@ -169,6 +180,8 @@ protected:
        bool playing;           // Indicates a message in progress      
        bool voiceOK;           // Flag - true if at least one voice has loaded OK
        FGATCVoice* vPtr;
+       
+       bool freqClear;         // Flag to indicate if the frequency is clear of ongoing dialog
 };
 
 inline istream&
@@ -177,7 +190,7 @@ operator >> ( istream& fin, ATCData& a )
        double f;
        char ch;
        char tp;
-
+       
        fin >> tp;
        
        switch(tp) {
@@ -201,7 +214,7 @@ operator >> ( istream& fin, ATCData& a )
                a.type = INVALID;
                return fin >> skipeol;
        }
-
+       
        fin >> a.lat >> a.lon >> a.elev >> f >> a.range 
        >> a.ident;
        
index 1fd7dab04d1928591674d842e0d7902fd0471b1b..dee428491a096d13e8e87db66ea279b6bfcf7e43 100644 (file)
@@ -1248,6 +1248,10 @@ void FGTower::ReportRunwayVacated(string ID) {
        //cout << "Report Runway Vacated Called...\n";
 }
 
+void FGTower::ReportDownwind(string ID) {
+       // Tell the plane reporting what number she is in the circuit
+}
+
 ostream& operator << (ostream& os, tower_traffic_type ttt) {
        switch(ttt) {
        case(CIRCUIT):      return(os << "CIRCUIT");
index c8eef6a43864f08cde7d49315307972ef0a894e5..0225919642c40ef113b4d515bf1fcd49a303ec73 100644 (file)
@@ -124,6 +124,7 @@ public:
        void ReportGoingAround(string ID);
        void ReportRunwayVacated(string ID);
        void ReportReadyForDeparture(string ID);
+       void ReportDownwind(string ID);
        
        // Contact tower when at a hold short for departure - for now we'll assume plane - maybe vehicles might want to cross runway eventually?
        void ContactAtHoldShort(PlaneRec plane, FGAIPlane* requestee, tower_traffic_type operation);
@@ -146,15 +147,6 @@ public:
        bool GetCrosswindConstraint(double& cpos);
        bool GetDownwindConstraint(double& dpos);
        bool GetBaseConstraint(double& bpos);
-       
-       // Returns true if OK to transmit on this frequency
-       inline bool FreqClear() { return freqClear; }
-       // Indicate that the frequency is in use
-       inline void FreqInUse() { freqClear = false; }
-       // The idea is that AI traffic or the user ATC dialog box calls FreqInUse() when they begin transmitting,
-       // and that the tower control sets freqClear back to true following a reply.
-       // AI traffic should check FreqClear() is true prior to transmitting.
-       // The user will just have to wait for a gap in dialog as in real life.
 
 private:
        FGATCMgr* ATCmgr;       
@@ -198,8 +190,6 @@ private:
        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.
        
-       bool freqClear;         // Flag to indicate if the frequency is clear of ongoing dialog
-       
        double timeSinceLastDeparture;  // Time in seconds since last departure from active rwy.
        bool departed;  // set true when the above needs incrementing with time, false when it doesn't.