From 96970dcbaf2008bddcbc5b53dc3e077d3855e451 Mon Sep 17 00:00:00 2001 From: daveluff Date: Fri, 7 Mar 2003 13:58:33 +0000 Subject: [PATCH] More stuff to make the AI/ATC system less hardwired and more generic. Most of the hardwired stuff is now gone - there's just a little bit left in FGAIMgr --- src/ATC/AILocalTraffic.cxx | 44 +++++++++++------ src/ATC/AILocalTraffic.hxx | 5 +- src/ATC/AIMgr.cxx | 84 ++++++++++++++++++++++++++++++++ src/ATC/AIMgr.hxx | 9 ++++ src/ATC/ATCmgr.cxx | 98 +++++++++++++++++++++++++++++--------- src/ATC/ATCmgr.hxx | 16 ++++++- src/ATC/commlist.cxx | 9 +++- src/ATC/ground.cxx | 6 +++ src/ATC/ground.hxx | 1 + 9 files changed, 232 insertions(+), 40 deletions(-) diff --git a/src/ATC/AILocalTraffic.cxx b/src/ATC/AILocalTraffic.cxx index f4dc8dbea..8404f3237 100644 --- a/src/ATC/AILocalTraffic.cxx +++ b/src/ATC/AILocalTraffic.cxx @@ -41,6 +41,8 @@ SG_USING_STD(string); #include "ATCutils.hxx" FGAILocalTraffic::FGAILocalTraffic() { + ATC = globals->get_ATC_mgr(); + roll = 0.0; pitch = 0.0; hdg = 270.0; @@ -159,24 +161,38 @@ bool FGAILocalTraffic::Init(string ICAO, OperatingState initialState, PatternLeg // Find the tower frequency - this is dependent on the ATC system being initialised before the AI system airportID = ICAO; AirportATC a; - if(globals->get_ATC_mgr()->GetAirportATCDetails(airportID, &a)) { + if(ATC->GetAirportATCDetails(airportID, &a)) { if(a.tower_freq) { // Has a tower - tower = (FGTower*)globals->get_ATC_mgr()->GetATCPointer((string)airportID, TOWER); // Maybe need some error checking here + tower = (FGTower*)ATC->GetATCPointer((string)airportID, TOWER); // Maybe need some error checking here + if(tower == NULL) { + // Something has gone wrong - abort or carry on with un-towered operation? + return(false); + } freq = (double)tower->get_freq() / 100.0; - //cout << "***********************************AILocalTraffic freq = " << freq << '\n'; } else { // Check CTAF, unicom etc } + if(a.ground_freq) { // Ground control + ground = (FGGround*)ATC->GetATCPointer((string)airportID, GROUND); // Maybe need some error checking here + if(ground == NULL) { + // Something has gone wrong :-( + cout << "ERROR - ground has frequency but can't get ground pointer :-(\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(); + } } else { //cout << "Unable to find airport details in FGAILocalTraffic::Init()\n"; } - // Initialise the relevant FGGround - // This needs a complete overhaul soon - what happens if we have 2 AI planes at same airport - they don't both need a structure - // This needs to be handled by the ATC manager or similar so only one set of physical data per airport is instantiated - // ie. TODO TODO FIXME FIXME - airport.Init(); - // Get the airport elevation aptElev = dclGetAirportElev(airportID.c_str()) * SG_FEET_TO_METER; //cout << "Airport elev in AILocalTraffic = " << aptElev << '\n'; @@ -187,7 +203,7 @@ bool FGAILocalTraffic::Init(string ICAO, OperatingState initialState, PatternLeg operatingState = initialState; switch(operatingState) { case PARKED: - ourGate = airport.GetGateNode(); + ourGate = ground->GetGateNode(); if(ourGate == NULL) { // Implies no available gates - what shall we do? // For now just vanish the plane - possibly we can make this more elegant in the future @@ -282,7 +298,7 @@ void FGAILocalTraffic::FlyCircuits(int numCircuits, bool tag) { GetRwyDetails(); // Get the takeoff node for the active runway, get a path to it and start taxiing - path = airport.GetPath(ourGate, rwy.rwyID); + path = ground->GetPath(ourGate, rwy.rwyID); if(path.size() < 2) { // something has gone wrong SG_LOG(SG_GENERAL, SG_ALERT, "Invalid path from gate to theshold in FGAILocalTraffic::FlyCircuits\n"); @@ -694,7 +710,7 @@ void FGAILocalTraffic::TransmitPatternPositionReport(void) { void FGAILocalTraffic::ExitRunway(Point3D orthopos) { //cout << "In ExitRunway" << endl; //cout << "Runway ID is " << rwy.ID << endl; - node_array_type exitNodes = airport.GetExits(rwy.ID); //I suppose we ought to have some fallback for rwy with no defined exits? + node_array_type exitNodes = ground->GetExits(rwy.ID); //I suppose we ought to have some fallback for rwy with no defined exits? /* cout << "Node ID's of exits are "; for(unsigned int i=0; iGetGateNode(); if(ourGate == NULL) { // Implies no available gates - what shall we do? // For now just vanish the plane - possibly we can make this more elegant in the future @@ -734,7 +750,7 @@ void FGAILocalTraffic::ExitRunway(Point3D orthopos) { operatingState = PARKED; return; } - path = airport.GetPath(rwyExit, ourGate); + path = ground->GetPath(rwyExit, ourGate); /* cout << "path returned was:" << endl; for(unsigned int i=0; iget_ATC_mgr()-> all through the code! + // High-level stuff OperatingState operatingState; int circuitsToFly; //Number of circuits still to do in this session NOT INCLUDING THE CURRENT ONE @@ -117,7 +120,7 @@ private: // Airport/runway/pattern details string airportID; // The ICAO code of the airport that we're operating around double aptElev; // Airport elevation - FGGround airport; // FIXME FIXME FIXME This is a complete hardwired cop-out at the moment - we need to connect to the correct ground in the same way we do to the tower. + FGGround* ground; // A pointer to the ground control. FGTower* tower; // A pointer to the tower control. RunwayDetails rwy; double patternDirection; // 1 for right, -1 for left (This is double because we multiply/divide turn rates diff --git a/src/ATC/AIMgr.cxx b/src/ATC/AIMgr.cxx index 85ec94783..d2cff20f0 100644 --- a/src/ATC/AIMgr.cxx +++ b/src/ATC/AIMgr.cxx @@ -19,26 +19,110 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +#include #include
#include
+#include
+#include +#include #include +#ifdef _MSC_VER +# include +#else +# include // for directory reading +# include // for directory reading +#endif + #include "AIMgr.hxx" #include "AILocalTraffic.hxx" +#include "ATCutils.hxx" SG_USING_STD(list); FGAIMgr::FGAIMgr() { + ATC = globals->get_ATC_mgr(); } FGAIMgr::~FGAIMgr() { } void FGAIMgr::init() { + // go through the $FG_ROOT/ATC directory and find all *.taxi files + SGPath path(globals->get_fg_root()); + path.append("ATC/"); + string dir = path.dir(); + string ext; + string file, f_ident; + int pos; + + // WARNING - I (DCL) haven't tested this on MSVC - this is simply cribbed from TerraGear +#ifdef _MSC_VER + long hfile; + struct _finddata_t de; + string path_str; + + path_str = dir + "\\*.*"; + + if ( ( hfile = _findfirst( path.c_str(), &de ) ) == -1 ) { + cout << "cannot open directory " << dir << "\n"; + } else { + // load all .taxi files + do { + file = de.name; + pos = file.find("."); + ext = file.substr(pos + 1); + if(ext == "taxi") { + cout << "TAXI FILE FOUND!!!\n"; + f_ident = file.substr(0, pos); + FGAirport a; + if(dclFindAirportID(f_ident, &a)) { + SGBucket sgb(a.longitude, a.latitude); + int idx = sgb.gen_index(); + airports[idx] = f_ident; + cout << "Mapping " << f_ident << " to bucket " << idx << '\n'; + } + } + } while ( _findnext( hfile, &de ) == 0 ); + } +#else + + DIR *d; + struct dirent *de; + + if ( (d = opendir( dir.c_str() )) == NULL ) { + cout << "cannot open directory " << dir << "\n"; + } else { + cout << "Opened directory " << dir << " OK :-)\n"; + cout << "Contents are:\n"; + // load all .taxi files + while ( (de = readdir(d)) != NULL ) { + file = de->d_name; + pos = file.find("."); + cout << file << '\n'; + + ext = file.substr(pos + 1); + if(ext == "taxi") { + cout << "TAXI FILE FOUND!!!\n"; + f_ident = file.substr(0, pos); + FGAirport a; + if(dclFindAirportID(f_ident, &a)) { + SGBucket sgb(a.longitude, a.latitude); + int idx = sgb.gen_index(); + airports[idx] = f_ident; + cout << "Mapping " << f_ident << " to bucket " << idx << '\n'; + } + } + } + closedir(d); + } +#endif + // Hard wire some local traffic for now. // This is regardless of location and hence *very* ugly but it is a start. + ATC->AIRegisterAirport("KEMT"); FGAILocalTraffic* local_traffic = new FGAILocalTraffic; //local_traffic->Init("KEMT", IN_PATTERN, TAKEOFF_ROLL); local_traffic->Init("KEMT"); diff --git a/src/ATC/AIMgr.hxx b/src/ATC/AIMgr.hxx index ec4c4e40c..8b002744f 100644 --- a/src/ATC/AIMgr.hxx +++ b/src/ATC/AIMgr.hxx @@ -27,14 +27,18 @@ #include +#include "ATCMgr.hxx" #include "AIEntity.hxx" SG_USING_STD(list); + class FGAIMgr : public FGSubsystem { private: + FGATCMgr* ATC; + // This is purely for synactic convienience to avoid writing globals->get_ATC_mgr()-> all through the code! // A list of pointers to all currently active AI stuff typedef list ai_list_type; @@ -48,6 +52,11 @@ private: // Any member function of FGATCMgr is permitted to leave this iterator pointing // at any point in or at the end of the list. // Hence any new access must explicitly first check for atc_list.end() before dereferencing. + + // A map of airport-IDs that have taxiway network files against bucket number + typedef map < int, string > ai_apt_map_type; + typedef ai_apt_map_type::iterator ai_apt_map_iterator; + ai_apt_map_type airports; // Position of the Users Aircraft // (This may be needed to calculate the distance from the user when deciding which 3D model to render) diff --git a/src/ATC/ATCmgr.cxx b/src/ATC/ATCmgr.cxx index f2de05d23..b2532db33 100644 --- a/src/ATC/ATCmgr.cxx +++ b/src/ATC/ATCmgr.cxx @@ -22,6 +22,7 @@ #include #include +#include #include "ATCmgr.hxx" #include "commlist.hxx" @@ -31,6 +32,7 @@ //#include "approachlist.hxx" #include "ATCdisplay.hxx" #include "ATCDialog.hxx" +#include "ATCutils.hxx" /* // periodic radio station search wrapper @@ -50,6 +52,7 @@ AirportATC::AirportATC() : ground_freq(0.0), ground_active(false), set_by_AI(false), + numAI(0), set_by_comm_search(false) { } @@ -83,6 +86,7 @@ void FGATCMgr::init() { lat_node = fgGetNode("/position/latitude-deg", true); elev_node = fgGetNode("/position/altitude-ft", true); atc_list_itr = atc_list.begin(); + // Search for connected ATC stations once per 0.8 seconds or so // global_events.Register( "fgATCSearch()", fgATCSearch, // fgEVENT::FG_EVENT_READY, 800); @@ -92,23 +96,6 @@ void FGATCMgr::init() { current_commlist = new FGCommList; SGPath p_comm( globals->get_fg_root() ); current_commlist->init( p_comm ); - - // Initialise the airport_atc_map - we'll cheat for now and just hardcode KEMT and any others that may be needed for development - AirportATC *a = new AirportATC; - a->lon = -118.034719; - a->lat = 34.086114; - a->elev = 296.0; - a->atis_freq = 118.75; - a->atis_active = false; - a->tower_freq = 121.2; - a->tower_active = false; - a->ground_freq = 125.9; - a->ground_active = false; - - //a->set_by_AI = true; - //a->set_by_comm_search = false; - - airport_atc_map[(string)"KEMT"] = a; #ifdef ENABLE_AUDIO_SUPPORT // Load all available voices. @@ -191,6 +178,53 @@ void FGATCMgr::update(double dt) { //cout << "comm1 type = " << comm_type[0] << '\n'; } + +// Returns frequency in KHz - should I alter this to return in MHz? +unsigned short int FGATCMgr::GetFrequency(string ident, atc_type tp) { + ATCData test; + bool ok = current_commlist->FindByCode(ident, test, tp); + return(ok ? test.freq : 0); +} + + +// Register the fact that the AI system wants to activate an airport +// Might need more sophistication in this in the future - eg registration by aircraft call-sign. +bool FGATCMgr::AIRegisterAirport(string ident) { + if(airport_atc_map.find(ident) != airport_atc_map.end()) { + airport_atc_map[ident]->set_by_AI = true; + return(true); + } else { + FGAirport ap; + if(dclFindAirportID(ident, &ap)) { + AirportATC *a = new AirportATC; + // I'm not entirely sure that this AirportATC structure business is actually needed - it just duplicates what we can find out anyway! + a->lon = ap.longitude; + a->lat = ap.latitude; + a->elev = ap.elevation; + a->atis_freq = GetFrequency(ident, ATIS); + a->atis_active = false; + a->tower_freq = GetFrequency(ident, TOWER); + a->tower_active = false; + a->ground_freq = GetFrequency(ident, GROUND); + a->ground_active = false; + // TODO - some airports will have a tower/ground frequency but be inactive overnight. + a->set_by_AI = true; + a->numAI++; + airport_atc_map[ident] = a; + return(true); + } + } + return(false); +} + + +// Register the fact that the comm radio is tuned to an airport +bool FGATCMgr::CommRegisterAirport(string ident) { // Later we'll differentiate between comm 1 and comm2 + // TODO - implement me! + return(false); +} + + // Remove from list only if not needed by the AI system or the other comm channel // TODO - implement me!! void FGATCMgr::CommRemoveFromList(const char* id, atc_type tp, int chan) { @@ -263,10 +297,11 @@ bool FGATCMgr::GetAirportATCDetails(string icao, AirportATC* a) { // Return a pointer to a given sort of ATC at a given airport and activate if necessary -// ONLY CALL THIS FUNCTION AFTER FIRST CHECKING THE SERVICE EXISTS BY CALLING GetAirportATCDetails -// FIXME - we really ought to take out the necessity for two function calls by simply returning -// a NULL pointer if the service doesn't exist and requiring the caller to check for it (NULL). +// Returns NULL if service doesn't exist - calling function should check for this. FGATC* FGATCMgr::GetATCPointer(string icao, atc_type type) { + if(airport_atc_map.find(icao) == airport_atc_map.end()) { + return NULL; + } AirportATC *a = airport_atc_map[icao]; //cout << "a->lon = " << a->lon << '\n'; //cout << "a->elev = " << a->elev << '\n'; @@ -275,28 +310,45 @@ FGATC* FGATCMgr::GetATCPointer(string icao, atc_type type) { case TOWER: if(a->tower_active) { // Get the pointer from the list - return(FindInList(icao.c_str(), type)); // DCL - this untested so far. + return(FindInList(icao.c_str(), type)); } else { - FGTower* t = new FGTower; ATCData data; if(current_commlist->FindByFreq(a->lon, a->lat, a->elev, a->tower_freq, &data, TOWER)) { + FGTower* t = new FGTower; t->SetData(&data); atc_list.push_back(t); a->tower_active = true; airport_atc_map[icao] = a; + t->Init(); return(t); } else { cout << "ERROR - tower that should exist in FGATCMgr::GetATCPointer for airport " << icao << " not found\n"; } } break; - // Lets add the rest to get rid of the compiler warnings even though we don't need them yet. case APPROACH: break; case ATIS: SG_LOG(SG_GENERAL, SG_ALERT, "ERROR - ATIS station should not be requested from FGATCMgr::GetATCPointer"); break; case GROUND: + if(a->ground_active) { + // Get the pointer from the list + return(FindInList(icao.c_str(), type)); + } else { + ATCData data; + if(current_commlist->FindByFreq(a->lon, a->lat, a->elev, a->ground_freq, &data, GROUND)) { + FGGround* g = new FGGround; + g->SetData(&data); + atc_list.push_back(g); + a->ground_active = true; + airport_atc_map[icao] = a; + g->Init(); + return(g); + } else { + cout << "ERROR - ground control that should exist in FGATCMgr::GetATCPointer for airport " << icao << " not found\n"; + } + } break; case INVALID: break; diff --git a/src/ATC/ATCmgr.hxx b/src/ATC/ATCmgr.hxx index 483568f3a..be9032128 100644 --- a/src/ATC/ATCmgr.hxx +++ b/src/ATC/ATCmgr.hxx @@ -62,10 +62,13 @@ struct AirportATC { //bool approach_active; //float departure_freq; //bool departure_active; + + // NOTE - the *_active flags determine whether the service is active in atc_list, + // *NOT* whether the tower etc is closed or not!!!! // Flags to ensure the stations don't get wrongly deactivated bool set_by_AI; // true when the AI manager has activated this station - // Do we need to ref-count the number of AI planes setting this? + unsigned int numAI; // Ref count of the number of AI planes registered bool set_by_comm_search; // true when the comm_search has activated this station // Do we need to distingiush comm1 and comm2? }; @@ -159,6 +162,7 @@ public: bool GetAirportATCDetails(string icao, AirportATC* a); // Return a pointer to a given sort of ATC at a given airport and activate if necessary + // Returns NULL if service doesn't exist - calling function should check for this. FGATC* GetATCPointer(string icao, atc_type type); // Display a dialog box with options relevant to the currently tuned ATC service. @@ -178,6 +182,16 @@ public: atc_type GetComm2ATCType() { return(comm_type[1]); } FGATC* GetComm2ATCPointer() { return(comm_atc_ptr[1]); } + // Get the frequency of a given service at a given airport + // Returns zero if not found + unsigned short int GetFrequency(string ident, atc_type tp); + + // Register the fact that the AI system wants to activate an airport + bool AIRegisterAirport(string ident); + + // Register the fact that the comm radio is tuned to an airport + bool CommRegisterAirport(string ident); // Later we'll differentiate between comm 1 and comm2 + private: // Remove a class from the atc_list and delete it from memory diff --git a/src/ATC/commlist.cxx b/src/ATC/commlist.cxx index 509b095c3..eb0201e92 100644 --- a/src/ATC/commlist.cxx +++ b/src/ATC/commlist.cxx @@ -120,7 +120,14 @@ bool FGCommList::FindByFreq( double lon, double lat, double elev, double freq, lon *= SGD_DEGREES_TO_RADIANS; lat *= SGD_DEGREES_TO_RADIANS; - comm_list_type stations = commlist_freq[(int)(freq*100.0 + 0.5)]; + // HACK - if freq > 1000 assume it's in KHz, otherwise assume MHz. + // A bit ugly but it works for now!!!! + comm_list_type stations; + if(freq > 1000.0) { + stations = commlist_freq[(int)freq]; + } else { + stations = commlist_freq[(int)(freq*100.0 + 0.5)]; + } comm_list_iterator current = stations.begin(); comm_list_iterator last = stations.end(); diff --git a/src/ATC/ground.cxx b/src/ATC/ground.cxx index 89a9665ff..6734b8be3 100644 --- a/src/ATC/ground.cxx +++ b/src/ATC/ground.cxx @@ -53,6 +53,12 @@ FGGround::FGGround() { networkLoadOK = false; } +FGGround::FGGround(string id) { + display = false; + networkLoadOK = false; + ident = id; +} + FGGround::~FGGround() { } diff --git a/src/ATC/ground.hxx b/src/ATC/ground.hxx index 5770d2d7b..fdc2dd0ea 100644 --- a/src/ATC/ground.hxx +++ b/src/ATC/ground.hxx @@ -208,6 +208,7 @@ class FGGround : public FGATC { public: FGGround(); + FGGround(string id); ~FGGround(); void Init();