]> git.mxchange.org Git - flightgear.git/commitdiff
Further progress towards interactive ATC
authordaveluff <daveluff>
Wed, 5 Nov 2003 17:24:58 +0000 (17:24 +0000)
committerdaveluff <daveluff>
Wed, 5 Nov 2003 17:24:58 +0000 (17:24 +0000)
src/ATC/AILocalTraffic.cxx
src/ATC/ATC.hxx
src/ATC/ATCDialog.cxx
src/ATC/tower.cxx
src/ATC/tower.hxx

index 9f39be091a38cbd2477dc09dea0c4bfbf82a8167..e427bb382cd5c8fa62f3943a91a3938f1f7a6809 100644 (file)
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
+/*==========================================================
+
+TODO list.
+
+Should get pattern direction from tower.
+
+Need to continually monitor and adjust deviation from glideslope
+during descent to avoid occasionally landing short or long.
+
+============================================================*/
+
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
index c0ba92241cdb76bd53346bfe9826ce5ff8e2e24a..8c7210dc236a7a6aff2ee21df5588879634de1e8 100644 (file)
@@ -95,6 +95,7 @@ struct RunwayDetails {
        double length;  // In *METERS*
        double width;   // ditto
        string rwyID;
+       int patternDirection;   // -1 for left, 1 for right
 };
 
 ostream& operator << (ostream& os, atc_type atc);
index 8d390f1b874d476dc613ab9fab0224ecc85e29a3..c83b514ede2da6ad0056e7cfce1a634be49a9bd6 100644 (file)
@@ -254,41 +254,33 @@ void FGATCDialog::add_entry(string station, string transmission, string menutext
   a.menuentry = menutext;
   a.callback_code = code;
 
-  //atcmentrylist_station[station.c_str()].push_back(a);
   (available_dialog[type])[station.c_str()].push_back(a);
 
 }
 
 void FGATCDialog::remove_entry( const string &station, const string &trans, atc_type type ) {
-  atcmentry_vec_type     atcmlist = (available_dialog[type])[station];
-  atcmentry_vec_iterator current  = atcmlist.begin();
-  atcmentry_vec_iterator last     = atcmlist.end();
-  
-  while(current != last) {
-    if(current->transmission == trans) current = atcmlist.erase(current);
+  atcmentry_vec_type* p = &((available_dialog[type])[station]);
+  atcmentry_vec_iterator current  = p->begin();  
+  while(current != p->end()) {
+    if(current->transmission == trans) current = p->erase(current);
        else ++current;
   }
 }
 
 void FGATCDialog::remove_entry( const string &station, int code, atc_type type ) {
-  atcmentry_vec_type     atcmlist = (available_dialog[type])[station];
-  atcmentry_vec_iterator current  = atcmlist.begin();
-  atcmentry_vec_iterator last     = atcmlist.end();
-  
-  while(current != last) {
-    if(current->callback_code == code) current = atcmlist.erase(current);
+  atcmentry_vec_type* p = &((available_dialog[type])[station]);
+  atcmentry_vec_iterator current  = p->begin();
+  while(current != p->end()) {
+    if(current->callback_code == code) current = p->erase(current);
        else ++current;
   }
 }
 
 // query the database whether the transmission is already registered; 
 bool FGATCDialog::trans_reg( const string &station, const string &trans, atc_type type ) {
-  //atcmentry_list_type     atcmlist = atcmentrylist_station[station];
-  atcmentry_vec_type     atcmlist = (available_dialog[type])[station];
-  atcmentry_vec_iterator current  = atcmlist.begin();
-  atcmentry_vec_iterator last     = atcmlist.end();
-  
-  for ( ; current != last ; ++current ) {
+  atcmentry_vec_type* p = &((available_dialog[type])[station]);
+  atcmentry_vec_iterator current  = p->begin();
+  for ( ; current != p->end() ; ++current ) {
     if ( current->transmission == trans ) return true;
   }
   return false;
@@ -296,12 +288,9 @@ bool FGATCDialog::trans_reg( const string &station, const string &trans, atc_typ
 
 // query the database whether the transmission is already registered; 
 bool FGATCDialog::trans_reg( const string &station, int code, atc_type type ) {
-  //atcmentry_list_type     atcmlist = atcmentrylist_station[station];
-  atcmentry_vec_type     atcmlist = (available_dialog[type])[station];
-  atcmentry_vec_iterator current  = atcmlist.begin();
-  atcmentry_vec_iterator last     = atcmlist.end();
-  
-  for ( ; current != last ; ++current ) {
+  atcmentry_vec_type* p = &((available_dialog[type])[station]);
+  atcmentry_vec_iterator current  = p->begin();
+  for ( ; current != p->end() ; ++current ) {
     if ( current->callback_code == code ) return true;
   }
   return false;
@@ -366,7 +355,7 @@ void FGATCDialog::PopupDialog() {
                                } 
                                optList[k] = NULL;
                                atcDialogCommunicationOptions->newList(optList);
-                               atcDialogCommunicationOptions->setSize(w-100, h-100);
+                               atcDialogCommunicationOptions->setSize(w-100, h-90);
                                atcDialogCommunicationOptions->reveal();
                                atcDialogMessage -> setLabel( "ATC Menu" );
                                atcDialogMessage -> setPosition(w / 2, h - 30);
index d7fb6c9ff738fd9249d10cb0f1e1c7682007910d..4d809fec8b8c6c15a335efe6364e4ec67df817ca 100644 (file)
@@ -45,6 +45,8 @@ TowerPlaneRec::TowerPlaneRec() :
        longFinalAcknowledged(false),
        finalReported(false),
        finalAcknowledged(false),
+       rwyVacatedReported(false),
+       rwyVacatedAcknowledged(false),
        instructedToGoAround(false),
        onRwy(false),
        nextOnRwy(false),
@@ -68,6 +70,8 @@ TowerPlaneRec::TowerPlaneRec(PlaneRec p) :
        longFinalAcknowledged(false),
        finalReported(false),
        finalAcknowledged(false),
+       rwyVacatedReported(false),
+       rwyVacatedAcknowledged(false),
        instructedToGoAround(false),
        onRwy(false),
        nextOnRwy(false),
@@ -91,6 +95,8 @@ TowerPlaneRec::TowerPlaneRec(Point3D pt) :
        longFinalAcknowledged(false),
        finalReported(false),
        finalAcknowledged(false),
+       rwyVacatedReported(false),
+       rwyVacatedAcknowledged(false),
        instructedToGoAround(false),
        onRwy(false),
        nextOnRwy(false),
@@ -115,6 +121,8 @@ TowerPlaneRec::TowerPlaneRec(PlaneRec p, Point3D pt) :
        longFinalAcknowledged(false),
        finalReported(false),
        finalAcknowledged(false),
+       rwyVacatedReported(false),
+       rwyVacatedAcknowledged(false),
        instructedToGoAround(false),
        onRwy(false),
        nextOnRwy(false),
@@ -388,6 +396,13 @@ void FGTower::ReceiveUserCallback(int code) {
                VFRArrivalContact("USER", FULL_STOP);
        } else if(code == (int)USER_REQUEST_VFR_ARRIVAL_TOUCH_AND_GO) {
                VFRArrivalContact("USER", TOUCH_AND_GO);
+       } else if(code == (int)USER_REPORT_DOWNWIND) {
+               ReportDownwind("USER");
+       } else if(code == (int)USER_REPORT_3_MILE_FINAL) {
+               // For now we'll just call report final instead of report long final to avoid having to alter the response code
+               ReportFinal("USER");
+       } else if(code == (int)USER_REPORT_RWY_VACATED) {
+               ReportRunwayVacated("USER");
        }
 }
 
@@ -401,7 +416,23 @@ void FGTower::Respond() {
                        string trns = t->plane.callsign;
                        trns += " ";
                        trns += name;
-                       trns += " tower Report three mile straight in for runway ";
+                       trns += " Tower";
+                       // Should we clear staight in or for downwind entry?
+                       // For now we'll clear straight in if greater than 1km from a line drawn through the threshold perpendicular to the rwy.
+                       // Later on we might check the actual heading and direct some of those to enter on downwind or base.
+                       Point3D op = ortho.ConvertToLocal(t->pos);
+                       if(op.y() < -1000) {
+                               trns += " Report three mile straight-in runway ";
+                               current_atcdialog->add_entry(ident, "@AP Tower @CS @MI mile final Runway @RW", "Report Final", TOWER, (int)USER_REPORT_3_MILE_FINAL);
+                       } else {
+                               // For now we'll just request reporting downwind.
+                               // TODO - In real life something like 'report 2 miles southwest right downwind rwy 19R' might be used
+                               // but I'm not sure how to handle all permutations of which direction to tell to report from yet.
+                               trns += " Report ";
+                               trns += (rwy.patternDirection ? "right " : "left ");
+                               trns += "downwind runway ";
+                               current_atcdialog->add_entry(ident, "@AP Tower @CS Downwind @RW", "Report Downwind", TOWER, (int)USER_REPORT_DOWNWIND);
+                       }
                        trns += ConvertRwyNumToSpokenString(activeRwy);
                        if(display) {
                                globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
@@ -415,16 +446,21 @@ void FGTower::Respond() {
                        for(tower_plane_rec_list_iterator twrItr = circuitList.begin(); twrItr != circuitList.end(); twrItr++) {
                                if((*twrItr)->plane.callsign == responseID) break;
                                ++i;
-                       }                       
-                       string trns = "Number ";
+                       }
+                       string trns = t->plane.callsign;
+                       trns += " Number ";
                        trns += ConvertNumToSpokenDigits(i);
                        trns += " ";
-                       trns += t->plane.callsign;
+                       if(i == 1) {
+                               trns += "Cleared to land";
+                               t->clearedToLand = true;
+                       }
                        if(display) {
-                               globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
+                               globals->get_ATC_display()->RegisterSingleMessage(trns);
                        }
-                       if(t->isUser && t->opType == TTT_UNKNOWN) {
-                               t->opType = CIRCUIT;
+                       if(t->isUser) {
+                               if(t->opType == TTT_UNKNOWN) t->opType = CIRCUIT;
+                               current_atcdialog->add_entry(ident, "@CS Clear of the runway", "Report runway vacated", TOWER, USER_REPORT_RWY_VACATED);
                        }
                } else if(t->holdShortReported) {
                        if(t->nextOnRwy) {
@@ -469,6 +505,7 @@ void FGTower::Respond() {
                                }
                                // TODO - add winds
                                t->clearedToLand = true;
+                               if(t->isUser) current_atcdialog->add_entry(ident, "@CS Clear of the runway", "Report runway vacated", TOWER, USER_REPORT_RWY_VACATED);
                        } else if(t->eta < 20) {
                                // Do nothing - we'll be telling it to go around in less than 10 seconds if the
                                // runway doesn't clear so no point in calling "continue approach".
@@ -478,9 +515,27 @@ void FGTower::Respond() {
                                t->clearedToLand = false;
                        }
                        if(display && disp) {
-                               globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
+                               globals->get_ATC_display()->RegisterSingleMessage(trns);
                        }
                        t->finalAcknowledged = true;
+               } else if(t->rwyVacatedReported && !(t->rwyVacatedAcknowledged)) {
+                       string trns = t->plane.callsign;
+                       if(separateGround) {
+                               trns += " Contact ground on ";
+                               double f = globals->get_ATC_mgr()->GetFrequency(ident, GROUND) / 100.0; 
+                               char buf[10];
+                               sprintf(buf, "%.2f", f);
+                               trns += buf;
+                               trns += " Good Day";
+                       } else {
+                               // Cop-out!!
+                               trns += " cleared for taxi to the GA parking";
+                       }
+                       if(display) {
+                               globals->get_ATC_display()->RegisterSingleMessage(trns);
+                       }
+                       t->rwyVacatedAcknowledged = true;
+                       // Maybe we should check that the plane really *has* vacated the runway!
                }
        }
        freqClear = true;       // FIXME - set this to come true after enough time to render the message
@@ -978,6 +1033,14 @@ void FGTower::DoRwyDetails() {
                ortho.Init(rwy.threshold_pos, rwy.hdg); 
                rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos);        // should come out as zero
                rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
+               
+               // Set the pattern direction
+               // TODO - we'll check for a facilities file with this in eventually - for now assume left traffic except
+               // for certain circumstances (RH parallel rwy).
+               rwy.patternDirection = -1;              // Left
+               if(rwy.rwyID.size() == 3) {
+                       rwy.patternDirection = (rwy.rwyID.substr(2,1) == "R" ? 1 : -1);
+               }
        } else {
                SG_LOG(SG_ATC, SG_ALERT, "Help  - can't get good runway in FGTower!!");
                activeRwy = "NN";
@@ -1429,14 +1492,14 @@ void FGTower::VFRArrivalContact(string ID, LandingType opt) {
        if(ID == "USER" || ID == usercall) {
                t = FindPlane(usercall);
                if(!t) {
-                       cout << "NOT t\n";
+                       //cout << "NOT t\n";
                        t = new TowerPlaneRec;
                        t->isUser = true;
                        t->pos.setlon(user_lon_node->getDoubleValue());
                        t->pos.setlat(user_lat_node->getDoubleValue());
                        t->pos.setelev(user_elev_node->getDoubleValue());
                } else {
-                       cout << "IS t\n";
+                       //cout << "IS t\n";
                        // Oops - the plane is already registered with this tower - maybe we took off and flew a giant circuit without
                        // quite getting out of tower airspace - just ignore for now and treat as new arrival.
                        // TODO - Maybe should remove from departure and circuit list if in there though!!
@@ -1463,6 +1526,10 @@ void FGTower::VFRArrivalContact(string ID, LandingType opt) {
        
        appList.push_back(t);   // Not necessarily permanent
        AddToTrafficList(t);
+       
+       current_atcdialog->remove_entry(ident, USER_REQUEST_VFR_ARRIVAL, TOWER);
+       current_atcdialog->remove_entry(ident, USER_REQUEST_VFR_ARRIVAL_FULL_STOP, TOWER);
+       current_atcdialog->remove_entry(ident, USER_REQUEST_VFR_ARRIVAL_TOUCH_AND_GO, TOWER);
 }
 
 void FGTower::RequestDepartureClearance(string ID) {
@@ -1470,6 +1537,10 @@ void FGTower::RequestDepartureClearance(string ID) {
 }
        
 void FGTower::ReportFinal(string ID) {
+       if(ID == "USER") {
+               ID = fgGetString("/sim/user/callsign");
+               current_atcdialog->remove_entry(ident, USER_REPORT_3_MILE_FINAL, TOWER);
+       }
        TowerPlaneRec* t = FindPlane(ID);
        if(t) {
                t->finalReported = true;
@@ -1482,7 +1553,23 @@ void FGTower::ReportFinal(string ID) {
        }
 }
 
-//void FGTower::ReportLongFinal(string ID);
+void FGTower::ReportLongFinal(string ID) {
+       if(ID == "USER") {
+               ID = fgGetString("/sim/user/callsign");
+               current_atcdialog->remove_entry(ident, USER_REPORT_3_MILE_FINAL, TOWER);
+       }
+       TowerPlaneRec* t = FindPlane(ID);
+       if(t) {
+               t->longFinalReported = true;
+               t->longFinalAcknowledged = false;
+               if(!(t->clearedToLand)) {
+                       responseReqd = true;
+               } // possibly respond with wind even if already cleared to land?
+       } else {
+               SG_LOG(SG_ATC, SG_WARN, "WARNING: Unable to find plane " << ID << " in FGTower::ReportLongFinal(...)");
+       }
+}
+
 //void FGTower::ReportOuterMarker(string ID);
 //void FGTower::ReportMiddleMarker(string ID);
 //void FGTower::ReportInnerMarker(string ID);
@@ -1490,6 +1577,17 @@ void FGTower::ReportFinal(string ID) {
 
 void FGTower::ReportRunwayVacated(string ID) {
        //cout << "Report Runway Vacated Called...\n";
+       if(ID == "USER") {
+               ID = fgGetString("/sim/user/callsign");
+               current_atcdialog->remove_entry(ident, USER_REPORT_RWY_VACATED, TOWER);
+       }
+       TowerPlaneRec* t = FindPlane(ID);
+       if(t) {
+               t->rwyVacatedReported = true;
+               responseReqd = true;
+       } else {
+               SG_LOG(SG_ATC, SG_WARN, "WARNING: Unable to find plane " << ID << " in FGTower::ReportRunwayVacated(...)");
+       }
 }
 
 TowerPlaneRec* FGTower::FindPlane(string ID) {
@@ -1512,7 +1610,10 @@ TowerPlaneRec* FGTower::FindPlane(string ID) {
 
 void FGTower::ReportDownwind(string ID) {
        //cout << "ReportDownwind(...) called\n";
-       // Tell the plane reporting what number she is in the circuit
+       if(ID == "USER") {
+               ID = fgGetString("/sim/user/callsign");
+               current_atcdialog->remove_entry(ident, USER_REPORT_DOWNWIND, TOWER);
+       }
        TowerPlaneRec* t = FindPlane(ID);
        if(t) {
                t->downwindReported = true;
index 57341e913f38511210624e49f0334db933b377a1..f06faeb56455c0eeab74e4844c4ae750bea3647b 100644 (file)
@@ -57,7 +57,10 @@ enum tower_callback_type {
        USER_REQUEST_VFR_DEPARTURE = 1,
        USER_REQUEST_VFR_ARRIVAL = 2,
        USER_REQUEST_VFR_ARRIVAL_FULL_STOP = 3,
-       USER_REQUEST_VFR_ARRIVAL_TOUCH_AND_GO = 4
+       USER_REQUEST_VFR_ARRIVAL_TOUCH_AND_GO = 4,
+       USER_REPORT_3_MILE_FINAL = 5,
+       USER_REPORT_DOWNWIND = 6,
+       USER_REPORT_RWY_VACATED = 7
 };
 
 // TODO - need some differentiation of IFR and VFR traffic in order to give the former priority.
@@ -89,6 +92,8 @@ public:
        bool longFinalAcknowledged;
        bool finalReported;
        bool finalAcknowledged;
+       bool rwyVacatedReported;
+       bool rwyVacatedAcknowledged;
        bool instructedToGoAround;      // set true if told by tower to go around
        bool onRwy;             // is physically on the runway
        bool nextOnRwy;         // currently projected by tower to be the next on the runway
@@ -153,6 +158,8 @@ public:
        // in the future and consider multi-runway use, airplane weight etc.
        inline string GetActiveRunway() { return activeRwy; }
        inline RunwayDetails GetActiveRunwayDetails() { return rwy; }
+       // Get the pattern direction of the active rwy.
+       inline int GetPatternDirection() { return rwy.patternDirection; }
        
        inline void SetDisplay() { display = true; }
        inline void SetNoDisplay() { display = false; }