Start roughing in interactive tower control. AI planes now get the ground control pointer through tower control, which then handles the difference between larger airports with separate ground and smaller ones where tower handles it
This commit is contained in:
parent
3a2495e47a
commit
aabe4da5ca
3 changed files with 132 additions and 32 deletions
|
@ -169,25 +169,14 @@ bool FGAILocalTraffic::Init(string ICAO, OperatingState initialState, PatternLeg
|
|||
return(false);
|
||||
}
|
||||
freq = (double)tower->get_freq() / 100.0;
|
||||
} else {
|
||||
// Check CTAF, unicom etc
|
||||
}
|
||||
if(a.ground_freq) { // Ground control
|
||||
ground = (FGGround*)ATC->GetATCPointer((string)airportID, GROUND); // Maybe need some error checking here
|
||||
ground = tower->GetGroundPtr();
|
||||
if(ground == NULL) {
|
||||
// Something has gone wrong :-(
|
||||
cout << "ERROR - ground has frequency but can't get ground pointer :-(\n";
|
||||
cout << "ERROR - can't get a ground pointer from tower control in FGAILocalTraffic::Init() :-(\n";
|
||||
return(false);
|
||||
}
|
||||
freq = (double)tower->get_freq() / 100.0;
|
||||
} else {
|
||||
// Initialise ground anyway to do the shortest path stuff!
|
||||
// This is a bit of a hack - might need to be altered sometime, but
|
||||
// in theory AILocalTraffic doesn't get called unless we have a logical
|
||||
// network for ground to use so it should work for now!
|
||||
ground = new FGGround(airportID); // TODO - ought to set a flag saying that we're responsible
|
||||
// for deleting ground in this instance, since normally we're not.
|
||||
ground->Init();
|
||||
// Check CTAF, unicom etc
|
||||
}
|
||||
} else {
|
||||
//cout << "Unable to find airport details in FGAILocalTraffic::Init()\n";
|
||||
|
@ -199,7 +188,7 @@ bool FGAILocalTraffic::Init(string ICAO, OperatingState initialState, PatternLeg
|
|||
// WARNING - we use this elev for the whole airport - some assumptions in the code
|
||||
// might fall down with very slopey airports.
|
||||
|
||||
//cout << "In Init(), initialState = " << initialState << '\n';
|
||||
//cout << "In Init(), initialState = " << initialState << endl;
|
||||
operatingState = initialState;
|
||||
switch(operatingState) {
|
||||
case PARKED:
|
||||
|
|
|
@ -76,13 +76,55 @@ finalAcknowledged(false)
|
|||
// FGTower
|
||||
|
||||
FGTower::FGTower() {
|
||||
ATCmgr = globals->get_ATC_mgr();
|
||||
}
|
||||
|
||||
FGTower::~FGTower() {
|
||||
if(!separateGround) {
|
||||
delete ground;
|
||||
}
|
||||
}
|
||||
|
||||
void FGTower::Init() {
|
||||
display = false;
|
||||
|
||||
// Need some way to initialise rwyOccupied flag correctly if the user is on the runway and to know its the user.
|
||||
// I'll punt the startup issue for now though!!!
|
||||
rwyOccupied = false;
|
||||
|
||||
// Setup the ground control at this airport
|
||||
AirportATC a;
|
||||
if(ATCmgr->GetAirportATCDetails(ident, &a)) {
|
||||
if(a.ground_freq) { // Ground control
|
||||
ground = (FGGround*)ATCmgr->GetATCPointer(ident, GROUND);
|
||||
separateGround = true;
|
||||
if(ground == NULL) {
|
||||
// Something has gone wrong :-(
|
||||
cout << "ERROR - ground has frequency but can't get ground pointer :-(\n";
|
||||
ground = new FGGround(ident);
|
||||
separateGround = false;
|
||||
ground->Init();
|
||||
if(display) {
|
||||
ground->SetDisplay();
|
||||
} else {
|
||||
ground->SetNoDisplay();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Initialise ground anyway to do the shortest path stuff!
|
||||
// Note that we're now responsible for updating and deleting this - NOT the ATCMgr.
|
||||
ground = new FGGround(ident);
|
||||
separateGround = false;
|
||||
ground->Init();
|
||||
if(display) {
|
||||
ground->SetDisplay();
|
||||
} else {
|
||||
ground->SetNoDisplay();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//cout << "Unable to find airport details in FGTower::Init()\n";
|
||||
}
|
||||
}
|
||||
|
||||
void FGTower::Update() {
|
||||
|
@ -94,14 +136,58 @@ void FGTower::Update() {
|
|||
// We need to check for planes not under our control coming within our
|
||||
// control area and address if necessary.
|
||||
|
||||
// Hardwired for testing
|
||||
static int play = 0;
|
||||
if(play == 200) {
|
||||
//cout << "Registering message in tower.cxx ****************************\n";
|
||||
//globals->get_ATC_display()->RegisterSingleMessage((string)"Cessna eight-two-zero Cleared for takeoff", 2);
|
||||
// TODO - a lot of the below probably doesn't need to be called every frame and should be staggered.
|
||||
|
||||
// Sort the arriving planes
|
||||
|
||||
// Calculate the eta of each plane to the threshold.
|
||||
// For ground traffic this is the fastest they can get there.
|
||||
// For air traffic this is the middle approximation.
|
||||
doThresholdETACalc();
|
||||
|
||||
// Order the list of traffic as per expected threshold use and flag any conflicts
|
||||
bool conflicts = doThresholdUseOrder();
|
||||
|
||||
// sortConficts() !!!
|
||||
|
||||
doCommunication();
|
||||
|
||||
if(!separateGround) {
|
||||
// The display stuff might have to get more clever than this when not separate
|
||||
// since the tower and ground might try communicating simultaneously even though
|
||||
// they're mean't to be the same contoller/frequency!!
|
||||
if(display) {
|
||||
ground->SetDisplay();
|
||||
} else {
|
||||
ground->SetNoDisplay();
|
||||
}
|
||||
++play;
|
||||
ground->Update();
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the eta of each plane to the threshold.
|
||||
// For ground traffic this is the fastest they can get there.
|
||||
// For air traffic this is the middle approximation.
|
||||
void FGTower::doThresholdETACalc() {
|
||||
// For now we'll be very crude and hardwire expected speeds to C172-like values
|
||||
double app_ias = 100.0; // Speed during straight-in approach
|
||||
double circuit_ias = 80.0; // Speed around circuit
|
||||
double final_ias = 70.0; // Speed during final approach
|
||||
|
||||
tower_plane_rec_list_iterator twrItr;
|
||||
|
||||
for(twrItr = trafficList.begin(); twrItr != trafficList.end(); twrItr++) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool FGTower::doThresholdUseOrder() {
|
||||
return(true);
|
||||
}
|
||||
|
||||
void FGTower::doCommunication() {
|
||||
}
|
||||
|
||||
|
||||
void FGTower::RequestLandingClearance(string ID) {
|
||||
cout << "Request Landing Clearance called...\n";
|
||||
|
|
|
@ -40,6 +40,14 @@ SG_USING_STD(ios);
|
|||
//DCL - a complete guess for now.
|
||||
#define FG_TOWER_DEFAULT_RANGE 30
|
||||
|
||||
enum tower_traffic_type {
|
||||
CIRCUIT,
|
||||
INBOUND,
|
||||
OUTBOUND,
|
||||
STRAIGHT_IN
|
||||
// Umm - what's the difference between INBOUND and STRAIGHT_IN ?
|
||||
};
|
||||
|
||||
// Structure for holding details of a plane under tower control.
|
||||
// Not fixed yet - may include more stuff later.
|
||||
class TowerPlaneRec {
|
||||
|
@ -64,8 +72,12 @@ class TowerPlaneRec {
|
|||
bool finalAcknowledged;
|
||||
bool onRwy;
|
||||
// enum type - light, medium, heavy etc - we need someway of approximating the aircraft type and performance.
|
||||
|
||||
// Type of operation the plane is doing
|
||||
tower_traffic_type opType;
|
||||
};
|
||||
|
||||
|
||||
typedef list < TowerPlaneRec* > tower_plane_rec_list_type;
|
||||
typedef tower_plane_rec_list_type::iterator tower_plane_rec_list_iterator;
|
||||
typedef tower_plane_rec_list_type::const_iterator tower_plane_rec_list_const_iterator;
|
||||
|
@ -92,20 +104,27 @@ class FGTower : public FGATC {
|
|||
void ReportGoingAround(string ID);
|
||||
void ReportRunwayVacated(string ID);
|
||||
|
||||
// Parse a literal message to decide which of above it represents.
|
||||
// (a long term project that eventually will hopefully receive the output from voice recognition software.)
|
||||
void LiteralTransmission(string trns, string ID);
|
||||
|
||||
inline void SetDisplay() {display = true;}
|
||||
inline void SetNoDisplay() {display = false;}
|
||||
|
||||
inline string get_trans_ident() { return trans_ident; }
|
||||
inline atc_type GetType() { return TOWER; }
|
||||
|
||||
// Make a request of tower control
|
||||
//void Request(tower_request request);
|
||||
inline FGGround* GetGroundPtr() {return ground; }
|
||||
|
||||
private:
|
||||
FGATCMgr* ATCmgr;
|
||||
// This is purely for synactic convienience to avoid writing globals->get_ATC_mgr()-> all through the code!
|
||||
|
||||
// Calculate the eta of each plane to the threshold.
|
||||
// For ground traffic this is the fastest they can get there.
|
||||
// For air traffic this is the middle approximation.
|
||||
void doThresholdETACalc();
|
||||
|
||||
// Order the list of traffic as per expected threshold use and flag any conflicts
|
||||
bool doThresholdUseOrder();
|
||||
|
||||
void doCommunication();
|
||||
|
||||
void IssueLandingClearance(TowerPlaneRec* tpr);
|
||||
void IssueGoAround(TowerPlaneRec* tpr);
|
||||
|
@ -114,10 +133,12 @@ class FGTower : public FGATC {
|
|||
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 rwyOccupied; // Active runway occupied flag. For now we'll disregard multiple runway and land-and-hold-short operations
|
||||
|
||||
// Need a data structure to hold details of the various active planes
|
||||
// or possibly another data structure with the positions of the inactive planes.
|
||||
// Need a data structure to hold outstanding communications from aircraft.
|
||||
|
||||
/*
|
||||
// Linked-list of planes on approach ordered with nearest first (timewise).
|
||||
// Includes planes that have landed but not yet vacated runway.
|
||||
// Somewhat analagous to the paper strips used (used to be used?) in real life.
|
||||
|
@ -131,12 +152,16 @@ class FGTower : public FGATC {
|
|||
|
||||
// List of planes on rwy
|
||||
tower_plane_rec_list_type rwyList;
|
||||
*/
|
||||
|
||||
// Linked list of all planes due to use a given rwy arranged in projected order of rwy use
|
||||
tower_plane_rec_list_type trafficList; // TODO - needs to be expandable to more than one rwy
|
||||
|
||||
// Ground can be separate or handled by tower in real life.
|
||||
// In the program we will always use a separate FGGround class, but we need to know
|
||||
// whether it is supposed to be separate or not to give the correct instructions.
|
||||
bool separateGround; // true if ground control is separate
|
||||
FGGround* groundPtr; // The ground control associated with this airport.
|
||||
FGGround* ground; // The ground control associated with this airport.
|
||||
|
||||
|
||||
// for failure modeling
|
||||
|
|
Loading…
Reference in a new issue