1
0
Fork 0

Further progress towards interactive ATC

This commit is contained in:
daveluff 2003-11-05 17:24:58 +00:00
parent 6162d4462b
commit 430a44a803
5 changed files with 149 additions and 40 deletions

View file

@ -19,6 +19,17 @@
// 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

View 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);

View 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);

View 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);
@ -416,15 +447,20 @@ void FGTower::Respond() {
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(display) {
globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
if(i == 1) {
trns += "Cleared to land";
t->clearedToLand = true;
}
if(t->isUser && t->opType == TTT_UNKNOWN) {
t->opType = CIRCUIT;
if(display) {
globals->get_ATC_display()->RegisterSingleMessage(trns);
}
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;

View 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; }