From d0d70bebd731e4bf77acc5b24faec0d13390e354 Mon Sep 17 00:00:00 2001 From: daveluff Date: Wed, 15 Oct 2003 21:50:05 +0000 Subject: [PATCH] Move responding to a plane announcing itself at hold short over to the response mechanism. Beware that a particularly nasty assumption that only one plane is ever holding for the runway at once remains for now though. --- src/ATC/tower.cxx | 370 ++++++++++++++++++++++------------------------ src/ATC/tower.hxx | 4 + 2 files changed, 181 insertions(+), 193 deletions(-) diff --git a/src/ATC/tower.cxx b/src/ATC/tower.cxx index e33e62f60..5a0e7ef86 100644 --- a/src/ATC/tower.cxx +++ b/src/ATC/tower.cxx @@ -229,7 +229,7 @@ void FGTower::Init() { } void FGTower::Update(double dt) { - //cout << "T" << flush; + //cout << "T" << endl; // Each time step, what do we need to do? // We need to go through the list of outstanding requests and acknowedgements // and process at least one of them. @@ -335,10 +335,12 @@ void FGTower::Update(double dt) { fgSetDouble("/AI/user/ortho-y", user_ortho_pos.y()); fgSetDouble("/AI/user/elev", user_elev_node->getDoubleValue()); } + + //cout << "Done T" << endl; } void FGTower::Respond() { - //cout << "Respond() called\n"; + //cout << "Entering Respond..." << endl; TowerPlaneRec* t = FindPlane(responseID); if(t) { // This will grow!!! @@ -356,17 +358,155 @@ void FGTower::Respond() { if(display) { globals->get_ATC_display()->RegisterSingleMessage(trns, 0); } - freqClear = true; // FIXME - set this to come true after enough time to render the message if(t->isUser && t->opType == TTT_UNKNOWN) { t->opType = CIRCUIT; } + } else if(t->holdShortReported) { + if(t->nextOnRwy) { + if(rwyOccupied) { // TODO - ought to add a sanity check that it isn't this plane only on the runway (even though it shouldn't be!!) + // Do nothing for now - consider acknowloging hold short eventually + } else { + ClearHoldingPlane(t); + t->leg = TAKEOFF_ROLL; + rwyList.push_back(t); + rwyOccupied = true; + // WARNING - WE ARE ASSUMING ONLY ONE PLANE REPORTING HOLD AT A TIME BELOW + // FIXME TODO - FIX THIS!!! + if(holdList.size()) { + if(holdListItr == holdList.end()) { + holdListItr = holdList.begin(); + } + holdList.erase(holdListItr); + holdListItr = holdList.begin(); + } + } + } else { + // Tell him to hold and what position he is. + // Not currently sure under which circumstances we do or don't bother transmitting this. + string trns = t->plane.callsign; + trns += " hold position"; + if(display) { + globals->get_ATC_display()->RegisterSingleMessage(trns, 0); + } + // TODO - add some idea of what traffic is blocking him. + } + t->holdShortReported = false; } } + freqClear = true; // FIXME - set this to come true after enough time to render the message + //cout << "Done Respond" << endl; +} + +// Currently this assumes we *are* next on the runway and doesn't check for planes about to land - +// this should be done prior to calling this function. +void FGTower::ClearHoldingPlane(TowerPlaneRec* t) { + //cout << "Entering ClearHoldingPlane..." << endl; + // Lets Roll !!!! + string trns = t->plane.callsign; + //if(departed plane < some threshold in time away) { + if(0) { // FIXME + //if(timeSinceLastDeparture <= 60.0 && departed == true) { + trns += " line up"; + t->clearedToLineUp = true; + t->planePtr->RegisterTransmission(3); // cleared to line-up + //} else if(arriving plane < some threshold away) { + } else if(GetTrafficETA(2) < 150.0 && (timeSinceLastDeparture > 60.0 || departed == false)) { // Hack - hardwired time + trns += " cleared immediate take-off"; + if(trafficList.size()) { + tower_plane_rec_list_iterator trfcItr = trafficList.begin(); + trfcItr++; // At the moment the holding plane should be first in trafficList. + // Note though that this will break if holding planes aren't put in trafficList in the future. + TowerPlaneRec* trfc = *trfcItr; + trns += "... traffic is"; + switch(trfc->plane.type) { + case UNKNOWN: + break; + case GA_SINGLE: + trns += " a Cessna"; // TODO - add ability to specify actual plane type somewhere + break; + case GA_HP_SINGLE: + trns += " a Piper"; + break; + case GA_TWIN: + trns += " a King-air"; + break; + case GA_JET: + trns += " a Learjet"; + break; + case MEDIUM: + trns += " a Regional"; + break; + case HEAVY: + trns += " a Heavy"; + break; + case MIL_JET: + trns += " Military"; + break; + } + //if(trfc->opType == STRAIGHT_IN || trfc->opType == TTT_UNKNOWN) { + if(trfc->opType == STRAIGHT_IN) { + double miles_out = CalcDistOutMiles(trfc); + if(miles_out < 2) { + trns += " on final"; + } else { + trns += " on "; + trns += ConvertNumToSpokenDigits((int)miles_out); + trns += " mile final"; + } + } else if(trfc->opType == CIRCUIT) { + //cout << "Getting leg of " << trfc->plane.callsign << '\n'; + switch(trfc->leg) { + case FINAL: + trns += " on final"; + break; + case TURN4: + trns += " turning final"; + break; + case BASE: + trns += " on base"; + break; + case TURN3: + trns += " turning base"; + break; + case DOWNWIND: + trns += " in circuit"; // At the moment the user plane is generally flagged as unknown opType when downwind incase its a downwind departure which means we won't get here. + break; + // And to eliminate compiler warnings... + case TAKEOFF_ROLL: break; + case CLIMBOUT: break; + case TURN1: break; + case CROSSWIND: break; + case TURN2: break; + case LANDING_ROLL: break; + case LEG_UNKNOWN: break; + } + } + } else { + // By definition there should be some arriving traffic if we're cleared for immediate takeoff + SG_LOG(SG_ATC, SG_WARN, "Warning: Departing traffic cleared for *immediate* take-off despite no arriving traffic in FGTower"); + } + t->clearedToTakeOff = true; + t->planePtr->RegisterTransmission(4); // cleared to take-off - TODO differentiate between immediate and normal take-off + departed = false; + timeSinceLastDeparture = 0.0; + } else { + //} else if(timeSinceLastDeparture > 60.0 || departed == false) { // Hack - test for timeSinceLastDeparture should be in lineup block eventually + trns += " cleared for take-off"; + // TODO - add traffic is... ? + t->clearedToTakeOff = true; + t->planePtr->RegisterTransmission(4); // cleared to take-off + departed = false; + timeSinceLastDeparture = 0.0; + } + if(display) { + globals->get_ATC_display()->RegisterSingleMessage(trns, 0); + } + //cout << "Done ClearHoldingPlane " << endl; } // Do one plane from the hold list void FGTower::CheckHoldList(double dt) { - //cout << "ug\n"; + //cout << "Entering CheckHoldList..." << endl; if(holdList.size()) { //cout << "*holdListItr = " << *holdListItr << endl; if(holdListItr == holdList.end()) { @@ -377,197 +517,34 @@ void FGTower::CheckHoldList(double dt) { TowerPlaneRec* t = *holdListItr; //cout << "t = " << t << endl; if(t->holdShortReported) { - //cout << "ding\n"; - double responseTime = 10.0; // seconds - this should get more sophisticated at some point - if(t->clearanceCounter > responseTime) { - if(t->nextOnRwy) { - if(rwyOccupied) { // TODO - ought to add a sanity check that it isn't this plane only on the runway (even though it shouldn't be!!) - // Do nothing for now - consider acknowloging hold short eventually - } else { - // Lets Roll !!!! - string trns = t->plane.callsign; - //if(departed plane < some threshold in time away) { - if(0) { // FIXME - trns += " line up"; - t->clearedToLineUp = true; - t->planePtr->RegisterTransmission(3); // cleared to line-up - t->leg = TAKEOFF_ROLL; - //} else if(arriving plane < some threshold away) { - } else if(GetTrafficETA(2) < 150.0) { - trns += " cleared immediate take-off"; - if(trafficList.size()) { - tower_plane_rec_list_iterator trfcItr = trafficList.begin(); - trfcItr++; // At the moment the holding plane should be first in trafficList. - // Note though that this will break if holding planes aren't put in trafficList in the future. - TowerPlaneRec* trfc = *trfcItr; - trns += "... traffic is"; - switch(trfc->plane.type) { - case UNKNOWN: - break; - case GA_SINGLE: - trns += " a Cessna"; // TODO - add ability to specify actual plane type somewhere - break; - case GA_HP_SINGLE: - trns += " a Piper"; - break; - case GA_TWIN: - trns += " a King-air"; - break; - case GA_JET: - trns += " a Learjet"; - break; - case MEDIUM: - trns += " a Regional"; - break; - case HEAVY: - trns += " a Heavy"; - break; - case MIL_JET: - trns += " Military"; - break; - } - //if(trfc->opType == STRAIGHT_IN || trfc->opType == TTT_UNKNOWN) { - if(trfc->opType == STRAIGHT_IN) { - double miles_out = CalcDistOutMiles(trfc); - if(miles_out < 2) { - trns += " on final"; - } else { - trns += " on "; - trns += ConvertNumToSpokenDigits((int)miles_out); - trns += " mile final"; - } - } else if(trfc->opType == CIRCUIT) { - cout << "Getting leg of " << trfc->plane.callsign << '\n'; - switch(trfc->leg) { - case FINAL: - trns += " on final"; - break; - case TURN4: - trns += " turning final"; - break; - case BASE: - trns += " on base"; - break; - case TURN3: - trns += " turning base"; - break; - case DOWNWIND: - trns += " in circuit"; // At the moment the user plane is generally flagged as unknown opType when downwind incase its a downwind departure which means we won't get here. - break; - // And to eliminate compiler warnings... - case TAKEOFF_ROLL: break; - case CLIMBOUT: break; - case TURN1: break; - case CROSSWIND: break; - case TURN2: break; - case LANDING_ROLL: break; - case LEG_UNKNOWN: break; - } - } - } else { - // By definition there should be some arriving traffic if we're cleared for immediate takeoff - SG_LOG(SG_ATC, SG_WARN, "Warning: Departing traffic cleared for *immediate* take-off despite no arriving traffic in FGTower"); - } - t->clearedToTakeOff = true; - t->planePtr->RegisterTransmission(4); // cleared to take-off - TODO differentiate between immediate and normal take-off - t->leg = TAKEOFF_ROLL; - departed = false; - timeSinceLastDeparture = 0.0; - } else { - trns += " cleared for take-off"; - // TODO - add traffic is... ? - t->clearedToTakeOff = true; - t->planePtr->RegisterTransmission(4); // cleared to take-off - t->leg = TAKEOFF_ROLL; - departed = false; - timeSinceLastDeparture = 0.0; - } - if(display) { - globals->get_ATC_display()->RegisterSingleMessage(trns, 0); - } - t->holdShortReported = false; - t->clearanceCounter = 0; - rwyList.push_back(t); - rwyOccupied = true; - holdList.erase(holdListItr); - holdListItr = holdList.begin(); - } - } else { - // Tell him to hold and what position he is. - // Not currently sure under which circumstances we do or don't bother transmitting this. - string trns = t->plane.callsign; - trns += " hold position"; - if(display) { - globals->get_ATC_display()->RegisterSingleMessage(trns, 0); - } - t->holdShortReported = false; - t->clearanceCounter = 0; - // TODO - add some idea of what traffic is blocking him. - } - } else { - t->clearanceCounter += (dt * holdList.size() * update_count_max); - } + // NO-OP - leave it to the response handler. } else { // not responding to report, but still need to clear if clear - //cout << "dong\n"; if(t->nextOnRwy) { //cout << "departed = " << departed << '\n'; //cout << "timeSinceLastDeparture = " << timeSinceLastDeparture << '\n'; if(rwyOccupied) { - // Do nothing for now - consider acknowloging hold short eventually + // Do nothing } else if(timeSinceLastDeparture <= 60.0 && departed == true) { // Do nothing - this is a bit of a hack - should maybe do line up be ready here } else { - // Lets Roll !!!! - string trns = t->plane.callsign; - //cout << "******************* squaggle\n"; - //cout << "departed = " << departed << '\n'; - //cout << "timeSinceLastDeparture = " << timeSinceLastDeparture << '\n'; - //if(departed plane < some threshold in time away) { - if(0) { // FIXME - //cout << "A\n"; - trns += " line up"; - t->clearedToLineUp = true; - t->planePtr->RegisterTransmission(3); // cleared to line-up - t->leg = TAKEOFF_ROLL; - //} else if(arriving plane < some threshold away) { - } else if(GetTrafficETA(2) < 150.0 && (timeSinceLastDeparture > 60.0 || departed == false)) { // Hack - hardwired time - //cout << "B\n"; - trns += " cleared immediate take-off"; - // TODO - add traffic is... ? - t->clearedToTakeOff = true; - t->planePtr->RegisterTransmission(4); // cleared to take-off - TODO differentiate between immediate and normal take-off - t->leg = TAKEOFF_ROLL; - departed = false; - timeSinceLastDeparture = 0.0; - } else if(timeSinceLastDeparture > 60.0 || departed == false) { // Hack - test for timeSinceLastDeparture should be in lineup block eventually - //cout << "C\n"; - trns += " cleared for take-off"; - // TODO - add traffic is... ? - t->clearedToTakeOff = true; - t->planePtr->RegisterTransmission(4); // cleared to take-off - t->leg = TAKEOFF_ROLL; - departed = false; - timeSinceLastDeparture = 0.0; - } else { - //cout << "D\n"; - } - if(display) { - globals->get_ATC_display()->RegisterSingleMessage(trns, 0); - } - rwyList.push_back(t); - rwyOccupied = true; - holdList.erase(holdListItr); - holdListItr = holdList.begin(); + ClearHoldingPlane(t); + t->leg = TAKEOFF_ROLL; + rwyList.push_back(t); + rwyOccupied = true; + holdList.erase(holdListItr); + holdListItr = holdList.begin(); } } // TODO - rationalise the considerable code duplication above! } ++holdListItr; } + //cout << "Done CheckHoldList" << endl; } // do the ciruit list void FGTower::CheckCircuitList(double dt) { + //cout << "Entering CheckCircuitList..." << endl; // Clear the constraints - we recalculate here. base_leg_pos = 0.0; downwind_leg_pos = 0.0; @@ -734,6 +711,7 @@ void FGTower::CheckCircuitList(double dt) { } ++circuitListItr; } + //cout << "Done CheckCircuitList" << endl; } // Do the runway list - we'll do the whole runway list since it's important and there'll never be many planes on the rwy at once!! @@ -741,6 +719,7 @@ void FGTower::CheckCircuitList(double dt) { // (However, at the moment there should only be one airplane on the rwy at once, until we // start allowing planes to line up whilst previous arrival clears the rwy.) void FGTower::CheckRunwayList(double dt) { + //cout << "Entering CheckRunwayList..." << endl; if(rwyOccupied) { if(!rwyList.size()) { rwyOccupied = false; @@ -784,6 +763,7 @@ void FGTower::CheckRunwayList(double dt) { } } } + //cout << "Done CheckRunwayList" << endl; } // Do one plane from the approach list @@ -967,7 +947,7 @@ bool FGTower::RemoveFromTrafficList(string id) { // See the comments in FGTower::doThresholdUseOrder for notes on the ordering bool FGTower::AddToTrafficList(TowerPlaneRec* t, bool holding) { //cout << "ADD: " << trafficList.size(); - //cout << "AddToTrafficList called, currently size = " << trafficList.size() << ", holding = " << holding << '\n'; + //cout << "AddToTrafficList called, currently size = " << trafficList.size() << ", holding = " << holding << endl; double separation_time = 90.0; // seconds - this is currently a guess for light plane separation, and includes a few seconds for a holding plane to taxi onto the rwy. double departure_sep_time = 60.0; // Separation time behind departing airplanes. Comments above also apply. bool conflict = false; @@ -1030,7 +1010,7 @@ bool FGTower::AddToTrafficList(TowerPlaneRec* t, bool holding) { // conflict and firstTime should be false and true respectively in this case anyway. } trafficList.push_back(t); - //cout << "\tE\t" << trafficList.size() << '\n'; + //cout << "\tE\t" << trafficList.size() << endl; return(holding ? firstTime : conflict); } @@ -1046,8 +1026,9 @@ void FGTower::CalcETA(TowerPlaneRec* tpr, bool printout) { double final_ias = 70.0 * 0.514444; // Speed during final approach //if(printout) { - // cout << "In CalcETA, airplane ident = " << tpr->plane.callsign << '\n'; - // cout << (tpr->isUser ? "USER\n" : "AI\n"); + //cout << "In CalcETA, airplane ident = " << tpr->plane.callsign << '\n'; + //cout << (tpr->isUser ? "USER\n" : "AI\n"); + //cout << flush; //} // Sign convention - dist_out is -ve for approaching planes and +ve for departing planes @@ -1152,6 +1133,7 @@ double FGTower::CalcDistOutMiles(TowerPlaneRec* tpr) { // Iterate through all the lists and call CalcETA for all the planes. void FGTower::doThresholdETACalc() { + //cout << "Entering doThresholdETACalc..." << endl; tower_plane_rec_list_iterator twrItr; // Do the approach list first for(twrItr = appList.begin(); twrItr != appList.end(); twrItr++) { @@ -1163,6 +1145,7 @@ void FGTower::doThresholdETACalc() { TowerPlaneRec* tpr = *twrItr; CalcETA(tpr); } + //cout << "Done doThresholdETCCalc" << endl; } @@ -1170,6 +1153,7 @@ void FGTower::doThresholdETACalc() { // that the nearest (timewise) is flagged next on rwy, and return // true if any threshold use conflicts are detected, false otherwise. bool FGTower::doThresholdUseOrder() { + //cout << "Entering doThresholdUseOrder..." << endl; bool conflict = false; // Wipe out traffic list, go through circuit, app and hold list, and reorder them in traffic list. @@ -1186,16 +1170,19 @@ bool FGTower::doThresholdUseOrder() { tower_plane_rec_list_iterator twrItr; // Do the approach list first + //cout << "A" << flush; for(twrItr = appList.begin(); twrItr != appList.end(); twrItr++) { TowerPlaneRec* tpr = *twrItr; conflict = AddToTrafficList(tpr); } // Then the circuit list + //cout << "C" << flush; for(twrItr = circuitList.begin(); twrItr != circuitList.end(); twrItr++) { TowerPlaneRec* tpr = *twrItr; conflict = AddToTrafficList(tpr); } // And finally the hold list + //cout << "H" << endl; for(twrItr = holdList.begin(); twrItr != holdList.end(); twrItr++) { TowerPlaneRec* tpr = *twrItr; AddToTrafficList(tpr, true); @@ -1207,16 +1194,13 @@ bool FGTower::doThresholdUseOrder() { TowerPlaneRec* tpr = *twrItr; cout << tpr->plane.callsign << '\t' << tpr->eta << '\t'; } - cout << '\n'; + cout << endl; } + //cout << "Done doThresholdUseOrder" << endl; return(conflict); } -/* -void FGTower::doCommunication() { -} -*/ // Return the ETA of plane no. list_pos (1-based) in the traffic list. // i.e. list_pos = 1 implies next to use runway. @@ -1247,23 +1231,23 @@ void FGTower::ContactAtHoldShort(PlaneRec plane, FGAIPlane* requestee, tower_tra t->opType = operation; //cout << "Hold Short reported by " << plane.callsign << '\n'; - + +/* bool next = AddToTrafficList(t, true); - if(next) { - //cout << "Next to take off - respond with clearance\n"; double teta = GetTrafficETA(2); if(teta < 150.0) { t->clearanceCounter = 7.0; // This reduces the delay before response to 3 secs if an immediate takeoff is reqd //cout << "Reducing response time to request due imminent traffic\n"; } } else { - //cout << "Not next to take off - respond with hold\n"; } - - //cout << "t = " << t << '\n'; - +*/ + // TODO - possibly add the reduced interval to clearance when immediate back in under the new scheme + holdList.push_back(t); + + responseReqd = true; } void FGTower::RequestLandingClearance(string ID) { diff --git a/src/ATC/tower.hxx b/src/ATC/tower.hxx index a8fb76af7..aa23ce17f 100644 --- a/src/ATC/tower.hxx +++ b/src/ATC/tower.hxx @@ -164,6 +164,10 @@ private: void CheckApproachList(double dt); + // Currently this assumes we *are* next on the runway and doesn't check for planes about to land - + // this should be done prior to calling this function. + void ClearHoldingPlane(TowerPlaneRec* t); + // Find a pointer to plane of callsign ID within the internal data structures TowerPlaneRec* FindPlane(string ID);