#include "ATCutils.hxx"
FGAILocalTraffic::FGAILocalTraffic() {
+ ATC = globals->get_ATC_mgr();
+
roll = 0.0;
pitch = 0.0;
hdg = 270.0;
// 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';
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
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");
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; i<exitNodes.size(); ++i) {
}
++nItr;
}
- 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
operatingState = PARKED;
return;
}
- path = airport.GetPath(rwyExit, ourGate);
+ path = ground->GetPath(rwyExit, ourGate);
/*
cout << "path returned was:" << endl;
for(unsigned int i=0; i<path.size(); ++i) {
void ReturnToBase(double dt);
private:
+ FGATCMgr* ATC;
+ // This is purely for synactic convienience to avoid writing globals->get_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
// 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
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#include <Airports/simple.hxx>
#include <Main/fgfs.hxx>
#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include <Simgear/misc/sg_path.hxx>
+#include <Simgear/bucket/newbucket.hxx>
#include <list>
+#ifdef _MSC_VER
+# include <io.h>
+#else
+# include <sys/types.h> // for directory reading
+# include <dirent.h> // 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");
#include <list>
+#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 <FGAIEntity*> ai_list_type;
// 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)
#include <simgear/misc/sg_path.hxx>
#include <simgear/debug/logstream.hxx>
+#include <Airports/simple.hxx>
#include "ATCmgr.hxx"
#include "commlist.hxx"
//#include "approachlist.hxx"
#include "ATCdisplay.hxx"
#include "ATCDialog.hxx"
+#include "ATCutils.hxx"
/*
// periodic radio station search wrapper
ground_freq(0.0),
ground_active(false),
set_by_AI(false),
+ numAI(0),
set_by_comm_search(false) {
}
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);
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.
//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) {
// 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';
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;
//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?
};
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.
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
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();
networkLoadOK = false;
}
+FGGround::FGGround(string id) {
+ display = false;
+ networkLoadOK = false;
+ ident = id;
+}
+
FGGround::~FGGround() {
}
public:
FGGround();
+ FGGround(string id);
~FGGround();
void Init();