1
0
Fork 0

Cleanup Inheritance in ATC

This commit is contained in:
portree_kid 2022-01-31 22:34:05 +01:00
parent 276835f74c
commit cf0d90ef3d
21 changed files with 408 additions and 488 deletions

View file

@ -48,7 +48,8 @@ using std::string;
using std::cerr; using std::cerr;
using std::endl; using std::endl;
//#include <Airports/trafficcontroller.hxx> #include <ATC/ATCController.hxx>
#include <ATC/trafficcontrol.hxx>
FGAIAircraft::FGAIAircraft(FGAISchedule* ref) : /* HOT must be disabled for AI Aircraft, FGAIAircraft::FGAIAircraft(FGAISchedule* ref) : /* HOT must be disabled for AI Aircraft,
* otherwise traffic detection isn't working as expected.*/ * otherwise traffic detection isn't working as expected.*/
@ -651,7 +652,7 @@ void FGAIAircraft::announcePositionToController() {
// NOTE: As of July, 30, 2011, the post-creation leg updating is no longer happening. // NOTE: As of July, 30, 2011, the post-creation leg updating is no longer happening.
// Leg numbers are updated only once the aircraft passes the last waypoint created for that legm so I should probably just use // Leg numbers are updated only once the aircraft passes the last waypoint created for that legm so I should probably just use
// the original leg numbers here! // the original leg numbers here!
switch (leg) { switch (leg) {
case 1: // Startup and Push back case 1: // Startup and Push back
if (trafficRef->getDepartureAirport()->getDynamics()) if (trafficRef->getDepartureAirport()->getDynamics())
controller = trafficRef->getDepartureAirport()->getDynamics()->getStartupController(); controller = trafficRef->getDepartureAirport()->getDynamics()->getStartupController();
@ -755,10 +756,8 @@ void FGAIAircraft::processATC(const FGATCInstruction& instruction) {
} }
} }
if (instruction.getChangeAltitude()) {} if (instruction.getChangeAltitude()) {}
} }
void FGAIAircraft::handleFirstWaypoint() { void FGAIAircraft::handleFirstWaypoint() {
bool eraseWaypoints; //TODO YAGNI bool eraseWaypoints; //TODO YAGNI
headingError = 0; headingError = 0;

View file

@ -81,6 +81,7 @@ public:
const std::string& getCompany() const { return company; } const std::string& getCompany() const { return company; }
void setCompany(const std::string& comp) { company = comp;}; void setCompany(const std::string& comp) { company = comp;};
//ATC
void announcePositionToController(); //TODO have to be public? void announcePositionToController(); //TODO have to be public?
void processATC(const FGATCInstruction& instruction); void processATC(const FGATCInstruction& instruction);
void setTaxiClearanceRequest(bool arg) { needsTaxiClearance = arg; }; void setTaxiClearanceRequest(bool arg) { needsTaxiClearance = arg; };

View file

@ -79,6 +79,8 @@ FGATCController::~FGATCController()
auto mgr = globals->get_subsystem<FGATCManager>(); auto mgr = globals->get_subsystem<FGATCManager>();
mgr->removeController(this); mgr->removeController(this);
} }
_isDestroying = true;
clearTrafficControllers();
} }
void FGATCController::init() void FGATCController::init()
@ -124,44 +126,28 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
int ground_to_air=0; int ground_to_air=0;
//double commFreqD; //double commFreqD;
sender = rec->getAircraft()->getTrafficRef()->getCallSign(); sender = rec->getCallsign();
if (rec->getAircraft()->getTaxiClearanceRequest()) { if (rec->getAircraft()->getTaxiClearanceRequest()) {
instructionText = "push-back and taxi"; instructionText = "push-back and taxi";
} else { } else {
instructionText = "taxi"; instructionText = "taxi";
} }
SG_LOG(SG_ATC, SG_DEBUG, "transmitting for: " << sender << "Leg = " << rec->getLeg()); SG_LOG(SG_ATC, SG_DEBUG, "transmitting for: " << sender << "Leg = " << rec->getLeg());
auto depApt = rec->getAircraft()->getTrafficRef()->getDepartureAirport(); auto depApt = rec->getAircraft()->getTrafficRef()->getDepartureAirport();
//FIXME Must be transferred to controller and fallback for GROUND -> TOWER if GROUND not set if (!depApt) {
switch (rec->getLeg()) { SG_LOG(SG_ATC, SG_DEV_ALERT, "TrafficRec has empty departure airport, can't transmit");
case 1: return;
case 2:
// avoid crash FLIGHTGEAR-ER
if (!depApt) {
SG_LOG(SG_ATC, SG_DEV_ALERT, "TrafficRec has empty departure airport, can't transmit");
return;
}
freqId = rec->getNextFrequency();
stationFreq = depApt->getDynamics()->getGroundFrequency(rec->getLeg() + freqId);
taxiFreq = depApt->getDynamics()->getGroundFrequency(2);
towerFreq = depApt->getDynamics()->getTowerFrequency(2);
receiver = depApt->getName() + "-Ground";
atisInformation = depApt->getDynamics()->getAtisSequence();
break;
case 3:
if (!depApt) {
SG_LOG(SG_ATC, SG_DEV_ALERT, "TrafficRec has empty departure airport, can't transmit");
return;
}
receiver = depApt->getName() + "-Tower";
break;
} }
stationFreq = getFrequency();
taxiFreq = depApt->getDynamics()->getGroundFrequency(2);
towerFreq = depApt->getDynamics()->getTowerFrequency(2);
receiver = getName();
atisInformation = depApt->getDynamics()->getAtisSequence();
// Swap sender and receiver value in case of a ground to air transmission // Swap sender and receiver value in case of a ground to air transmission
if (msgDir == ATC_GROUND_TO_AIR) { if (msgDir == ATC_GROUND_TO_AIR) {
string tmp = sender; string tmp = sender;
@ -169,7 +155,7 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
receiver = tmp; receiver = tmp;
ground_to_air = 1; ground_to_air = 1;
} }
switch (msgId) { switch (msgId) {
case MSG_ANNOUNCE_ENGINE_START: case MSG_ANNOUNCE_ENGINE_START:
text = sender + ". Ready to Start up."; text = sender + ". Ready to Start up.";
@ -262,7 +248,7 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
if (rec->getAircraft()->getTaxiClearanceRequest()) { if (rec->getAircraft()->getTaxiClearanceRequest()) {
text = receiver + ". Push-back approved. " + sender + "."; text = receiver + ". Push-back approved. " + sender + ".";
} else { } else {
text = receiver + ". Cleared to Taxi. " + sender + "."; text = receiver + ". Cleared to Taxi. " + sender + ".";
} }
break; break;
case MSG_HOLD_PUSHBACK_CLEARANCE: case MSG_HOLD_PUSHBACK_CLEARANCE:
@ -306,6 +292,16 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
//text = "test2"; //text = "test2";
SG_LOG(SG_ATC, SG_DEBUG, "2 Currently at leg " << rec->getLeg()); SG_LOG(SG_ATC, SG_DEBUG, "2 Currently at leg " << rec->getLeg());
break; break;
case MSG_CLEARED_FOR_TAKEOFF:
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
//activeRunway = "test";
text = receiver + ". Cleared for takeoff runway " + activeRunway + ". " + sender + ".";
break;
case MSG_ACKNOWLEDGE_CLEARED_FOR_TAKEOFF:
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
text = receiver + " Roger. Cleared for takeoff runway " + activeRunway + ". " + sender + ".";
//text = "test2";
break;
case MSG_SWITCH_TOWER_FREQUENCY: case MSG_SWITCH_TOWER_FREQUENCY:
towerFreqStr = formatATCFrequency3_2(towerFreq); towerFreqStr = formatATCFrequency3_2(towerFreq);
text = receiver + " Contact Tower at " + towerFreqStr + ". " + sender + "."; text = receiver + " Contact Tower at " + towerFreqStr + ". " + sender + ".";
@ -323,7 +319,7 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
text = text + sender + ". Transmitting unknown Message."; text = text + sender + ". Transmitting unknown Message.";
break; break;
} }
const bool atcAudioEnabled = fgGetBool("/sim/sound/atc/enabled", false); const bool atcAudioEnabled = fgGetBool("/sim/sound/atc/enabled", false);
if (audible && atcAudioEnabled) { if (audible && atcAudioEnabled) {
double onBoardRadioFreq0 = double onBoardRadioFreq0 =
@ -333,35 +329,36 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
int onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 100 + 0.5); int onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 100 + 0.5);
int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5); int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5);
SG_LOG(SG_ATC, SG_DEBUG, "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl); SG_LOG(SG_ATC, SG_DEBUG, "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl);
if( stationFreq == 0 ) {
SG_LOG(SG_ATC, SG_DEBUG, getName() << " stationFreq not found");
}
// Display ATC message only when one of the radios is tuned // Display ATC message only when one of the radios is tuned
// the relevant frequency. // the relevant frequency.
// Note that distance attenuation is currently not yet implemented // Note that distance attenuation is currently not yet implemented
if ((stationFreq > 0)&& if ((stationFreq > 0)&&
((onBoardRadioFreqI0 == stationFreq)|| ((onBoardRadioFreqI0 == stationFreq)||
(onBoardRadioFreqI1 == stationFreq))) { (onBoardRadioFreqI1 == stationFreq))) {
if (rec->allowTransmissions()) { if (rec->allowTransmissions()) {
if( fgGetBool( "/sim/radio/use-itm-attenuation", false ) ) { if( fgGetBool( "/sim/radio/use-itm-attenuation", false ) ) {
SG_LOG(SG_ATC, SG_DEBUG, "Using ITM radio propagation"); SG_LOG(SG_ATC, SG_DEBUG, "Using ITM radio propagation");
FGRadioTransmission* radio = new FGRadioTransmission(); FGRadioTransmission* radio = new FGRadioTransmission();
SGGeod sender_pos; SGGeod sender_pos;
double sender_alt_ft, sender_alt; double sender_alt_ft, sender_alt;
if(ground_to_air) { if(ground_to_air) {
sender_pos = parent->parent()->geod(); sender_pos = parent->parent()->geod();
} }
else { else {
sender_alt_ft = rec->getAltitude(); sender_pos= rec->getPos();
sender_alt = sender_alt_ft * SG_FEET_TO_METER;
sender_pos= SGGeod::fromDegM( rec->getLongitude(),
rec->getLatitude(), sender_alt );
} }
double frequency = ((double)stationFreq) / 100; double frequency = ((double)stationFreq) / 100;
radio->receiveATC(sender_pos, frequency, text, ground_to_air); radio->receiveATC(sender_pos, frequency, text, ground_to_air);
delete radio; delete radio;
} }
else { else {
SG_LOG(SG_ATC, SG_BULK, "Transmitting " << text);
fgSetString("/sim/messages/atc", text.c_str()); fgSetString("/sim/messages/atc", text.c_str());
} }
} }
@ -371,6 +368,48 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
} }
} }
void FGATCController::signOff(int id)
{
TrafficVectorIterator i = searchActiveTraffic(id);
if (i == activeTraffic.end()) {
SG_LOG(SG_ATC, SG_ALERT,
"AI error: Aircraft without traffic record is signing off from " << getName() << " at " << SG_ORIGIN);
return;
}
activeTraffic.erase(i);
SG_LOG(SG_ATC, SG_DEBUG, i->getCallsign() << " signing off from " << getName() );
}
bool FGATCController::hasInstruction(int id)
{
// Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(id);
if (i == activeTraffic.end()) {
SG_LOG(SG_ATC, SG_ALERT,
"AI error: checking ATC instruction for aircraft without traffic record at " << SG_ORIGIN);
} else {
return i->hasInstruction();
}
return false;
}
FGATCInstruction FGATCController::getInstruction(int id)
{
// Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(id);
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_ATC, SG_ALERT,
"AI error: requesting ATC instruction for aircraft without traffic record at " << SG_ORIGIN);
} else {
return i->getInstruction();
}
return FGATCInstruction();
}
/* /*
* Format integer frequency xxxyy as xxx.yy * Format integer frequency xxxyy as xxx.yy
* @param freq - integer value * @param freq - integer value
@ -402,32 +441,33 @@ string FGATCController::genTransponderCode(const string& fltRules)
return std::to_string(val); return std::to_string(val);
} }
void FGATCController::eraseDeadTraffic(TrafficVector& vec) void FGATCController::eraseDeadTraffic()
{ {
auto it = std::remove_if(vec.begin(), vec.end(), [](const FGTrafficRecord& traffic) auto it = std::remove_if(activeTraffic.begin(), activeTraffic.end(), [](const FGTrafficRecord& traffic)
{ {
if (!traffic.getAircraft()) { return traffic.isDead();
return true;
}
return traffic.getAircraft()->getDie();
}); });
vec.erase(it, vec.end()); activeTraffic.erase(it, activeTraffic.end());
} }
void FGATCController::clearTrafficControllers(TrafficVector& vec) /*
* Search activeTraffic vector to find matching id
* @param id integer to search for in the vector
* @return the matching item OR activeTraffic.end()
*/
TrafficVectorIterator FGATCController::searchActiveTraffic(int id)
{ {
for (const auto& traffic : vec) { return std::find_if(activeTraffic.begin(), activeTraffic.end(),
if (!traffic.getAircraft()) { [id] (const FGTrafficRecord& rec)
continue; { return rec.getId() == id; }
} );
}
traffic.getAircraft()->clearATCController(); void FGATCController::clearTrafficControllers()
{
for (const auto& traffic : activeTraffic) {
traffic.clearATCController();
} }
} }
TrafficVectorIterator FGATCController::searchActiveTraffic(TrafficVector& vec, int id)
{
return std::find_if(vec.begin(), vec.end(), [id] (const FGTrafficRecord& rec)
{ return rec.getId() == id; });
}

View file

@ -28,8 +28,7 @@
#include <osg/Shape> #include <osg/Shape>
#include <simgear/compiler.h> #include <simgear/compiler.h>
// There is probably a better include than sg_geodesy to get the SG_NM_TO_METER... #include <simgear/constants.h>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGReferenced.hxx> #include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
@ -46,19 +45,25 @@ private:
protected: protected:
// guard variable to avoid modifying state during destruction
bool _isDestroying = false;
bool initialized; bool initialized;
bool available; bool available;
time_t lastTransmission; time_t lastTransmission;
TrafficVector activeTraffic;
double dt_count; double dt_count;
osg::Group* group; osg::Group* group;
FGAirportDynamics *parent = nullptr;
std::string formatATCFrequency3_2(int ); std::string formatATCFrequency3_2(int );
std::string genTransponderCode(const std::string& fltRules); std::string genTransponderCode(const std::string& fltRules);
bool isUserAircraft(FGAIAircraft*); bool isUserAircraft(FGAIAircraft*);
void clearTrafficControllers(TrafficVector& vec); void clearTrafficControllers();
TrafficVectorIterator searchActiveTraffic(TrafficVector& vec, int id); TrafficVectorIterator searchActiveTraffic(int id);
void eraseDeadTraffic(TrafficVector& vec); void eraseDeadTraffic();
/**Returns the frequency to be used. */
virtual int getFrequency() = 0;
public: public:
typedef enum { typedef enum {
MSG_ANNOUNCE_ENGINE_START, MSG_ANNOUNCE_ENGINE_START,
@ -81,6 +86,8 @@ public:
MSG_ACKNOWLEDGE_RESUME_TAXI, MSG_ACKNOWLEDGE_RESUME_TAXI,
MSG_REPORT_RUNWAY_HOLD_SHORT, MSG_REPORT_RUNWAY_HOLD_SHORT,
MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT, MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT,
MSG_CLEARED_FOR_TAKEOFF,
MSG_ACKNOWLEDGE_CLEARED_FOR_TAKEOFF,
MSG_SWITCH_TOWER_FREQUENCY, MSG_SWITCH_TOWER_FREQUENCY,
MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY
} AtcMsgId; } AtcMsgId;
@ -97,11 +104,19 @@ public:
double lat, double lon, double lat, double lon,
double hdg, double spd, double alt, double radius, int leg, double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft) = 0; FGAIAircraft *aircraft) = 0;
virtual void signOff(int id) = 0;
virtual void updateAircraftInformation(int id, double lat, double lon, virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt) = 0; double heading, double speed, double alt, double dt) = 0;
virtual bool hasInstruction(int id) = 0;
virtual FGATCInstruction getInstruction(int id) = 0; void signOff(int id);
bool hasInstruction(int id);
FGATCInstruction getInstruction(int id);
bool hasActiveTraffic() {
return ! activeTraffic.empty();
};
TrafficVector &getActiveTraffic() {
return activeTraffic;
};
double getDt() { double getDt() {
return dt_count; return dt_count;
@ -113,16 +128,10 @@ public:
std::string getGateName(FGAIAircraft *aircraft); std::string getGateName(FGAIAircraft *aircraft);
virtual void render(bool) = 0; virtual void render(bool) = 0;
virtual std::string getName() = 0; virtual std::string getName() = 0;
virtual void update(double) = 0; virtual void update(double) = 0;
protected:
// guard variable to avoid modifying state during destruction
bool _isDestroying = false;
private: private:
AtcMsgDir lastTransmissionDirection; AtcMsgDir lastTransmissionDirection;
}; };

View file

@ -63,7 +63,7 @@ using std::string;
* class FGApproachController * class FGApproachController
* subclass of FGATCController * subclass of FGATCController
**************************************************************************/ **************************************************************************/
FGApproachController::FGApproachController(FGAirportDynamics *par): FGApproachController::FGApproachController(FGAirportDynamics *par):
FGATCController() FGATCController()
{ {
@ -72,8 +72,6 @@ FGApproachController::FGApproachController(FGAirportDynamics *par):
FGApproachController::~FGApproachController() FGApproachController::~FGApproachController()
{ {
_isDestroying = true;
clearTrafficControllers(activeTraffic);
} }
@ -86,10 +84,10 @@ void FGApproachController::announcePosition(int id,
int leg, FGAIAircraft * ref) int leg, FGAIAircraft * ref)
{ {
init(); init();
// Search activeTraffic for a record matching our id // Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
// Add a new TrafficRecord if no one exsists for this aircraft. // Add a new TrafficRecord if no one exsists for this aircraft.
if (i == activeTraffic.end() || activeTraffic.empty()) { if (i == activeTraffic.end() || activeTraffic.empty()) {
FGTrafficRecord rec; FGTrafficRecord rec;
@ -98,7 +96,7 @@ void FGApproachController::announcePosition(int id,
rec.setPositionAndHeading(lat, lon, heading, speed, alt); rec.setPositionAndHeading(lat, lon, heading, speed, alt);
rec.setRunway(intendedRoute->getRunway()); rec.setRunway(intendedRoute->getRunway());
rec.setLeg(leg); rec.setLeg(leg);
//rec.setCallSign(callsign); rec.setCallsign(ref->getCallSign());
rec.setAircraft(ref); rec.setAircraft(ref);
activeTraffic.push_back(rec); activeTraffic.push_back(rec);
} else { } else {
@ -111,9 +109,9 @@ void FGApproachController::updateAircraftInformation(int id, double lat, double
double dt) double dt)
{ {
// Search activeTraffic for a record matching our id // Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
TrafficVectorIterator current; TrafficVectorIterator current;
// update position of the current aircraft // update position of the current aircraft
if (i == activeTraffic.end() || activeTraffic.empty()) { if (i == activeTraffic.end() || activeTraffic.empty()) {
SG_LOG(SG_ATC, SG_ALERT, SG_LOG(SG_ATC, SG_ALERT,
@ -122,85 +120,43 @@ void FGApproachController::updateAircraftInformation(int id, double lat, double
i->setPositionAndHeading(lat, lon, heading, speed, alt); i->setPositionAndHeading(lat, lon, heading, speed, alt);
current = i; current = i;
SG_LOG(SG_ATC, SG_BULK, "ApproachController: checking for speed"); SG_LOG(SG_ATC, SG_BULK, "ApproachController: checking for speed");
time_t time_diff = if(current->getAircraft()) {
current->getAircraft()-> //FIXME No call to aircraft! -> set instruction
checkForArrivalTime(string("final001")); time_t time_diff =
if (time_diff > 15) { current->getAircraft()->
current->setSpeedAdjustment(current->getAircraft()-> checkForArrivalTime(string("final001"));
getPerformance()->vDescent() * if (time_diff > 15) {
1.35); current->setSpeedAdjustment(current->getAircraft()->
} else if (time_diff > 5) { getPerformance()->vDescent() *
current->setSpeedAdjustment(current->getAircraft()-> 1.35);
getPerformance()->vDescent() * } else if (time_diff > 5) {
1.2); current->setSpeedAdjustment(current->getAircraft()->
} else if (time_diff < -15) { getPerformance()->vDescent() *
current->setSpeedAdjustment(current->getAircraft()-> 1.2);
getPerformance()->vDescent() * } else if (time_diff < -15) {
0.65); current->setSpeedAdjustment(current->getAircraft()->
} else if (time_diff < -5) { getPerformance()->vDescent() *
current->setSpeedAdjustment(current->getAircraft()-> 0.65);
getPerformance()->vDescent() * } else if (time_diff < -5) {
0.8); current->setSpeedAdjustment(current->getAircraft()->
} else { getPerformance()->vDescent() *
current->clearSpeedAdjustment(); 0.8);
} else {
current->clearSpeedAdjustment();
}
} }
//current->setSpeedAdjustment(current->getAircraft()->getPerformance()->vDescent() + time_diff); //current->setSpeedAdjustment(current->getAircraft()->getPerformance()->vDescent() + time_diff);
} }
setDt(getDt() + dt); setDt(getDt() + dt);
} }
/* Search for and erase traffic record with a specific id */
void FGApproachController::signOff(int id)
{
// ensure we don't modify activeTraffic during destruction
if (_isDestroying)
return;
// Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id);
if (i == activeTraffic.end() || activeTraffic.empty()) {
SG_LOG(SG_ATC, SG_ALERT,
"AI error: Aircraft without traffic record is signing off from approach at " << SG_ORIGIN);
} else {
i = activeTraffic.erase(i);
}
}
/* Periodically check for and remove dead traffic records */ /* Periodically check for and remove dead traffic records */
void FGApproachController::update(double dt) void FGApproachController::update(double dt)
{ {
FGATCController::eraseDeadTraffic(activeTraffic); FGATCController::eraseDeadTraffic();
} }
bool FGApproachController::hasInstruction(int id)
{
// Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id);
if (i == activeTraffic.end() || activeTraffic.empty()) {
SG_LOG(SG_ATC, SG_ALERT,
"AI error: checking ATC instruction for aircraft without traffic record at " << SG_ORIGIN);
} else {
return i->hasInstruction();
}
return false;
}
FGATCInstruction FGApproachController::getInstruction(int id)
{
// Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id);
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_ATC, SG_ALERT,
"AI error: requesting ATC instruction for aircraft without traffic record at " << SG_ORIGIN);
} else {
return i->getInstruction();
}
return FGATCInstruction();
}
ActiveRunway *FGApproachController::getRunway(const string& name) ActiveRunway *FGApproachController::getRunway(const string& name)
@ -228,5 +184,11 @@ void FGApproachController::render(bool visible) {
} }
string FGApproachController::getName() { string FGApproachController::getName() {
return string(parent->getId() + "-approach"); return string(parent->parent()->getName() + "-approach");
}
int FGApproachController::getFrequency() {
int groundFreq = parent->getApproachFrequency(2);
int towerFreq = parent->getTowerFrequency(2);
return groundFreq>0?groundFreq:towerFreq;
} }

View file

@ -28,8 +28,7 @@
#include <osg/Shape> #include <osg/Shape>
#include <simgear/compiler.h> #include <simgear/compiler.h>
// There is probably a better include than sg_geodesy to get the SG_NM_TO_METER... #include <simgear/constants.h>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGReferenced.hxx> #include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
@ -38,28 +37,24 @@
#include <ATC/trafficcontrol.hxx> #include <ATC/trafficcontrol.hxx>
/****************************************************************************** /******************************************************************************
* class FGTowerControl * class FGApproachController
*****************************************************************************/ *****************************************************************************/
class FGApproachController : public FGATCController class FGApproachController : public FGATCController
{ {
private: private:
TrafficVector activeTraffic;
ActiveRunwayVec activeRunways; ActiveRunwayVec activeRunways;
FGAirportDynamics *parent; /**Returns the frequency to be used. */
int getFrequency();
public: public:
FGApproachController(FGAirportDynamics * parent); FGApproachController(FGAirportDynamics * parent);
virtual ~FGApproachController(); virtual ~FGApproachController();
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon, double lat, double lon,
double hdg, double spd, double alt, double radius, int leg, double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft); FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon, virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt); double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
virtual void render(bool); virtual void render(bool);
virtual std::string getName(); virtual std::string getName();
@ -67,12 +62,6 @@ public:
ActiveRunway* getRunway(const std::string& name); ActiveRunway* getRunway(const std::string& name);
bool hasActiveTraffic() {
return ! activeTraffic.empty();
};
TrafficVector &getActiveTraffic() {
return activeTraffic;
};
}; };
#endif #endif

View file

@ -67,31 +67,23 @@ using std::string;
/*************************************************************************** /***************************************************************************
* FGGroundController() * FGGroundController()
**************************************************************************/ **************************************************************************/
FGGroundController::FGGroundController() : FGGroundController::FGGroundController(FGAirportDynamics *par)
parent(NULL)
{ {
hasNetwork = false; hasNetwork = false;
count = 0; count = 0;
currTraffic = activeTraffic.begin();
group = 0; group = 0;
version = 0; version = 0;
networkInitialized = false; networkInitialized = false;
FGATCController::init();
parent = par;
hasNetwork = true;
networkInitialized = true;
} }
FGGroundController::~FGGroundController() FGGroundController::~FGGroundController()
{ {
_isDestroying = true;
}
void FGGroundController::init(FGAirportDynamics* aDynamics)
{
FGATCController::init();
dynamics = aDynamics;
parent = dynamics->parent();
hasNetwork = true;
networkInitialized = true;
} }
bool compare_trafficrecords(FGTrafficRecord a, FGTrafficRecord b) bool compare_trafficrecords(FGTrafficRecord a, FGTrafficRecord b)
@ -99,19 +91,6 @@ bool compare_trafficrecords(FGTrafficRecord a, FGTrafficRecord b)
return (a.getIntentions().size() < b.getIntentions().size()); return (a.getIntentions().size() < b.getIntentions().size());
} }
/*
* Search activeTraffic vector to find matching id
* @param id integer to search for in the vector
* @return the matching item OR activeTraffic.end()
*/
TrafficVectorIterator FGGroundController::searchActiveTraffic(int id)
{
return std::find_if(activeTraffic.begin(), activeTraffic.end(),
[id] (const FGTrafficRecord& rec)
{ return rec.getId() == id; }
);
}
void FGGroundController::announcePosition(int id, void FGGroundController::announcePosition(int id,
FGAIFlightPlan * intendedRoute, FGAIFlightPlan * intendedRoute,
int currentPosition, double lat, int currentPosition, double lat,
@ -126,8 +105,8 @@ void FGGroundController::announcePosition(int id,
} }
// Search the activeTraffic vector to find a traffic vector with our id // Search the activeTraffic vector to find a traffic vector with our id
TrafficVectorIterator i = searchActiveTraffic(id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
// Add a new TrafficRecord if none exists for this aircraft // Add a new TrafficRecord if none exists for this aircraft
// otherwise set the information for the TrafficRecord // otherwise set the information for the TrafficRecord
if (i == activeTraffic.end() || (activeTraffic.empty())) { if (i == activeTraffic.end() || (activeTraffic.empty())) {
@ -137,6 +116,7 @@ void FGGroundController::announcePosition(int id,
rec.setPositionAndIntentions(currentPosition, intendedRoute); rec.setPositionAndIntentions(currentPosition, intendedRoute);
rec.setPositionAndHeading(lat, lon, heading, speed, alt); rec.setPositionAndHeading(lat, lon, heading, speed, alt);
rec.setRadius(radius); // only need to do this when creating the record. rec.setRadius(radius); // only need to do this when creating the record.
rec.setCallsign(aircraft->getCallSign());
rec.setAircraft(aircraft); rec.setAircraft(aircraft);
// add to the front of the list of activeTraffic if the aircraft is already taxiing // add to the front of the list of activeTraffic if the aircraft is already taxiing
if (leg == 2) { if (leg == 2) {
@ -150,26 +130,6 @@ void FGGroundController::announcePosition(int id,
} }
} }
/*
Search for and erase an aircraft with a certain id from the activeTraffic vector
*/
void FGGroundController::signOff(int id)
{
if (_isDestroying)
return;
// Search the activeTraffic vector to find a traffic vector with our id
TrafficVectorIterator i = searchActiveTraffic(id);
// If one is found erase the record, else give an error message
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT,
"AI error: Aircraft without traffic record is signing off at " << SG_ORIGIN);
} else {
i = activeTraffic.erase(i);
}
}
/* /*
* The ground network can deal with the following states: * The ground network can deal with the following states:
* 0 = Normal; no action required * 0 = Normal; no action required
@ -200,11 +160,11 @@ bool FGGroundController::checkTransmissionState(int minState, int maxState, Traf
//FGATCDialogNew::instance()->removeEntry(1); //FGATCDialogNew::instance()->removeEntry(1);
} else { } else {
SG_LOG(SG_ATC, SG_DEBUG, "creating message for " << i->getAircraft()->getCallSign()); SG_LOG(SG_ATC, SG_DEBUG, "creating message for " << i->getAircraft()->getCallSign());
transmit(&(*i), dynamics, msgId, msgDir, false); transmit(&(*i), parent, msgId, msgDir, false);
return false; return false;
} }
} }
transmit(&(*i), dynamics, msgId, msgDir, true); transmit(&(*i), parent, msgId, msgDir, true);
i->updateState(); i->updateState();
lastTransmission = now; lastTransmission = now;
available = false; available = false;
@ -224,18 +184,18 @@ void FGGroundController::updateAircraftInformation(int id, double lat, double lo
// Probably use a status mechanism similar to the Engine start procedure in the startup controller. // Probably use a status mechanism similar to the Engine start procedure in the startup controller.
// Search the activeTraffic vector to find a traffic vector with our id // Search the activeTraffic vector to find a traffic vector with our id
TrafficVectorIterator i = searchActiveTraffic(id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
// update position of the current aircraft // update position of the current aircraft
if (i == activeTraffic.end() || activeTraffic.empty()) { if (i == activeTraffic.end() || activeTraffic.empty()) {
SG_LOG(SG_GENERAL, SG_DEV_WARN, SG_LOG(SG_GENERAL, SG_DEV_WARN,
"AI error: updating aircraft without traffic record at " << SG_ORIGIN << ", id=" << id); "AI error: updating aircraft without traffic record at " << SG_ORIGIN << ", id=" << id);
return; return;
} }
i->setPositionAndHeading(lat, lon, heading, speed, alt); i->setPositionAndHeading(lat, lon, heading, speed, alt);
TrafficVectorIterator current = i; TrafficVectorIterator current = i;
setDt(getDt() + dt); setDt(getDt() + dt);
// Update every three secs, but add some randomness // Update every three secs, but add some randomness
@ -302,7 +262,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat,
TrafficVectorIterator current, closest, closestOnNetwork; TrafficVectorIterator current, closest, closestOnNetwork;
bool otherReasonToSlowDown = false; bool otherReasonToSlowDown = false;
// bool previousInstruction; // bool previousInstruction;
TrafficVectorIterator i = searchActiveTraffic(id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
if (!activeTraffic.size()) { if (!activeTraffic.size()) {
return; return;
} }
@ -315,7 +275,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat,
// previousInstruction = current->getSpeedAdjustment(); // previousInstruction = current->getSpeedAdjustment();
double mindist = HUGE_VAL; double mindist = HUGE_VAL;
// First check all our activeTraffic // First check all our activeTraffic
if (activeTraffic.size()) { if (activeTraffic.size()) {
double course, dist, bearing, az2; // minbearing, double course, dist, bearing, az2; // minbearing,
@ -329,9 +289,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat,
continue; continue;
} }
SGGeod other(SGGeod::fromDegM(i->getLongitude(), SGGeod other = i->getPos();
i->getLatitude(),
i->getAltitude()));
SGGeodesy::inverse(curr, other, course, az2, dist); SGGeodesy::inverse(curr, other, course, az2, dist);
bearing = fabs(heading - course); bearing = fabs(heading - course);
if (bearing > 180) if (bearing > 180)
@ -343,16 +301,14 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat,
// minbearing = bearing; // minbearing = bearing;
} }
} }
// Next check with the tower controller // Next check with the tower controller
if (towerController->hasActiveTraffic()) { if (towerController->hasActiveTraffic()) {
for (TrafficVectorIterator i = for (TrafficVectorIterator i =
towerController->getActiveTraffic().begin(); towerController->getActiveTraffic().begin();
i != towerController->getActiveTraffic().end(); i++) { i != towerController->getActiveTraffic().end(); i++) {
SG_LOG(SG_ATC, SG_BULK, "Comparing " << current->getId() << " and " << i->getId()); SG_LOG(SG_ATC, SG_BULK, "Comparing " << current->getId() << " and " << i->getId());
SGGeod other(SGGeod::fromDegM(i->getLongitude(), SGGeod other = i->getPos();
i->getLatitude(),
i->getAltitude()));
SGGeodesy::inverse(curr, other, course, az2, dist); SGGeodesy::inverse(curr, other, course, az2, dist);
bearing = fabs(heading - course); bearing = fabs(heading - course);
if (bearing > 180) if (bearing > 180)
@ -368,7 +324,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat,
} }
} }
} }
// Finally, check UserPosition // Finally, check UserPosition
// Note, as of 2011-08-01, this should no longer be necessecary. // Note, as of 2011-08-01, this should no longer be necessecary.
/* /*
@ -387,11 +343,11 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat,
otherReasonToSlowDown = true; otherReasonToSlowDown = true;
} }
*/ */
// Clear any active speed adjustment, check if the aircraft needs to brake // Clear any active speed adjustment, check if the aircraft needs to brake
current->clearSpeedAdjustment(); current->clearSpeedAdjustment();
bool needBraking = false; bool needBraking = false;
if (current->checkPositionAndIntentions(*closest) if (current->checkPositionAndIntentions(*closest)
|| otherReasonToSlowDown) { || otherReasonToSlowDown) {
double maxAllowableDistance = double maxAllowableDistance =
@ -402,7 +358,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat,
return; return;
else else
current->setWaitsForId(closest->getId()); current->setWaitsForId(closest->getId());
if (closest->getId() != current->getId()) { if (closest->getId() != current->getId()) {
current->setSpeedAdjustment(closest->getSpeed() * current->setSpeedAdjustment(closest->getSpeed() *
(mindist / 100)); (mindist / 100));
@ -417,7 +373,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat,
} else { } else {
current->setSpeedAdjustment(0); // This can only happen when the user aircraft is the one closest current->setSpeedAdjustment(0); // This can only happen when the user aircraft is the one closest
} }
if (mindist < maxAllowableDistance) { if (mindist < maxAllowableDistance) {
//double newSpeed = (maxAllowableDistance-mindist); //double newSpeed = (maxAllowableDistance-mindist);
//current->setSpeedAdjustment(newSpeed); //current->setSpeedAdjustment(newSpeed);
@ -428,7 +384,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat,
} }
} }
} }
if ((closest->getId() == closestOnNetwork->getId()) && (current->getPriority() < closest->getPriority()) && needBraking) { if ((closest->getId() == closestOnNetwork->getId()) && (current->getPriority() < closest->getPriority()) && needBraking) {
swap(current, closest); swap(current, closest);
} }
@ -447,7 +403,7 @@ void FGGroundController::checkHoldPosition(int id, double lat,
double lon, double heading, double lon, double heading,
double speed, double alt) double speed, double alt)
{ {
FGGroundNetwork* network = dynamics->parent()->groundNetwork(); FGGroundNetwork* network = parent->parent()->groundNetwork();
TrafficVectorIterator current; TrafficVectorIterator current;
TrafficVectorIterator i = activeTraffic.begin(); TrafficVectorIterator i = activeTraffic.begin();
if (activeTraffic.size()) { if (activeTraffic.size()) {
@ -499,7 +455,7 @@ void FGGroundController::checkHoldPosition(int id, double lat,
//if (tx->hasBlock(now) || nx->hasBlock(now) ) { //if (tx->hasBlock(now) || nx->hasBlock(now) ) {
// current->setHoldPosition(true); // current->setHoldPosition(true);
//} //}
SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude()))); SGGeod start = i->getPos();
SGGeod end (nx->getStart()->geod()); SGGeod end (nx->getStart()->geod());
double distance = SGGeodesy::distanceM(start, end); double distance = SGGeodesy::distanceM(start, end);
@ -530,11 +486,11 @@ void FGGroundController::checkHoldPosition(int id, double lat,
if ((origStatus != currStatus) && available) { if ((origStatus != currStatus) && available) {
SG_LOG(SG_ATC, SG_DEBUG, "Issuing hold short instruction " << currStatus << " " << available); SG_LOG(SG_ATC, SG_DEBUG, "Issuing hold short instruction " << currStatus << " " << available);
if (currStatus == true) { // No has a hold short instruction if (currStatus == true) { // No has a hold short instruction
transmit(&(*current), dynamics, MSG_HOLD_POSITION, ATC_GROUND_TO_AIR, true); transmit(&(*current), parent, MSG_HOLD_POSITION, ATC_GROUND_TO_AIR, true);
SG_LOG(SG_ATC, SG_DEBUG, "Transmitting hold short instruction " << currStatus << " " << available); SG_LOG(SG_ATC, SG_DEBUG, "Transmitting hold short instruction " << currStatus << " " << available);
current->setState(1); current->setState(1);
} else { } else {
transmit(&(*current), dynamics, MSG_RESUME_TAXI, ATC_GROUND_TO_AIR, true); transmit(&(*current), parent, MSG_RESUME_TAXI, ATC_GROUND_TO_AIR, true);
SG_LOG(SG_ATC, SG_DEBUG, "Transmitting resume instruction " << currStatus << " " << available); SG_LOG(SG_ATC, SG_DEBUG, "Transmitting resume instruction " << currStatus << " " << available);
current->setState(2); current->setState(2);
} }
@ -668,35 +624,6 @@ bool FGGroundController::checkForCircularWaits(int id)
} }
} }
// Note that this function is probably obsolete...
bool FGGroundController::hasInstruction(int id)
{
// Search the activeTraffic vector to find a traffic vector with our id
TrafficVectorIterator i = searchActiveTraffic(id);
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT,
"AI error: checking ATC instruction for aircraft without traffic record at " << SG_ORIGIN);
} else {
return i->hasInstruction();
}
return false;
}
FGATCInstruction FGGroundController::getInstruction(int id)
{
// Search the activeTraffic vector to find a traffic vector with our id
TrafficVectorIterator i = searchActiveTraffic(id);
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT,
"AI error: requesting ATC instruction for aircraft without traffic record at " << SG_ORIGIN);
} else {
return i->getInstruction();
}
return FGATCInstruction();
}
// Note that this function is copied from simgear. for maintanance purposes, it's probabtl better to make a general function out of that. // Note that this function is copied from simgear. for maintanance purposes, it's probabtl better to make a general function out of that.
static void WorldCoordinate(osg::Matrix& obj_pos, double lat, static void WorldCoordinate(osg::Matrix& obj_pos, double lat,
double lon, double elev, double hdg, double slope) double lon, double elev, double hdg, double slope)
@ -715,7 +642,7 @@ static void WorldCoordinate(osg::Matrix& obj_pos, double lat,
void FGGroundController::render(bool visible) void FGGroundController::render(bool visible)
{ {
SGMaterialLib *matlib = globals->get_matlib(); SGMaterialLib *matlib = globals->get_matlib();
FGGroundNetwork* network = dynamics->parent()->groundNetwork(); FGGroundNetwork* network = parent->parent()->groundNetwork();
if (group) { if (group) {
//int nr = ; //int nr = ;
@ -745,7 +672,7 @@ void FGGroundController::render(bool visible)
const int pos = i->getCurrentPosition(); const int pos = i->getCurrentPosition();
if (pos > 0) { if (pos > 0) {
FGTaxiSegment* segment = network->findSegment(pos); FGTaxiSegment* segment = network->findSegment(pos);
SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude()))); SGGeod start = i->getPos();
SGGeod end (segment->getEnd()->geod()); SGGeod end (segment->getEnd()->geod());
double length = SGGeodesy::distanceM(start, end); double length = SGGeodesy::distanceM(start, end);
@ -903,17 +830,17 @@ void FGGroundController::render(bool visible)
} }
string FGGroundController::getName() { string FGGroundController::getName() {
return string(parent->getId() + "-ground"); return string(parent->parent()->getName() + "-ground");
} }
void FGGroundController::update(double dt) void FGGroundController::update(double dt)
{ {
time_t now = globals->get_time_params()->get_cur_time(); time_t now = globals->get_time_params()->get_cur_time();
FGGroundNetwork* network = dynamics->parent()->groundNetwork(); FGGroundNetwork* network = parent->parent()->groundNetwork();
network->unblockAllSegments(now); network->unblockAllSegments(now);
int priority = 1; int priority = 1;
TrafficVector& startupTraffic(dynamics->getStartupController()->getActiveTraffic()); TrafficVector& startupTraffic(parent->getStartupController()->getActiveTraffic());
TrafficVectorIterator i; TrafficVectorIterator i;
//sort(activeTraffic.begin(), activeTraffic.end(), compare_trafficrecords); //sort(activeTraffic.begin(), activeTraffic.end(), compare_trafficrecords);
@ -927,8 +854,9 @@ void FGGroundController::update(double dt)
updateActiveTraffic(i, priority, now); updateActiveTraffic(i, priority, now);
} }
FGATCController::eraseDeadTraffic(startupTraffic); //FIXME
FGATCController::eraseDeadTraffic(activeTraffic); //FGATCController::eraseDeadTraffic(startupTraffic);
FGATCController::eraseDeadTraffic();
} }
void FGGroundController::updateStartupTraffic(TrafficVectorIterator i, void FGGroundController::updateStartupTraffic(TrafficVectorIterator i,
@ -953,7 +881,7 @@ void FGGroundController::updateStartupTraffic(TrafficVectorIterator i,
return; return;
} }
FGGroundNetwork* network = dynamics->parent()->groundNetwork(); FGGroundNetwork* network = parent->parent()->groundNetwork();
if (!network) { if (!network) {
SG_LOG(SG_ATC, SG_ALERT, "updateStartupTraffic: missing ground network"); SG_LOG(SG_ATC, SG_ALERT, "updateStartupTraffic: missing ground network");
@ -1021,7 +949,7 @@ bool FGGroundController::updateActiveTraffic(TrafficVectorIterator i,
double length = 0; double length = 0;
double vTaxi = (i->getAircraft()->getPerformance()->vTaxi() * SG_NM_TO_METER) / 3600; double vTaxi = (i->getAircraft()->getPerformance()->vTaxi() * SG_NM_TO_METER) / 3600;
FGGroundNetwork* network = dynamics->parent()->groundNetwork(); FGGroundNetwork* network = parent->parent()->groundNetwork();
if (!network) { if (!network) {
SG_LOG(SG_ATC, SG_ALERT, "updateActiveTraffic: missing ground network"); SG_LOG(SG_ATC, SG_ALERT, "updateActiveTraffic: missing ground network");
@ -1038,7 +966,7 @@ bool FGGroundController::updateActiveTraffic(TrafficVectorIterator i,
} }
} }
intVecIterator ivi; intVecIterator ivi;
for (ivi = i->getIntentions().begin(); ivi != i->getIntentions().end(); ivi++) { for (ivi = i->getIntentions().begin(); ivi != i->getIntentions().end(); ivi++) {
int segIndex = (*ivi); int segIndex = (*ivi);
@ -1049,7 +977,7 @@ bool FGGroundController::updateActiveTraffic(TrafficVectorIterator i,
} }
} }
} }
//after this, ivi points just behind the last valid unblocked taxi segment. //after this, ivi points just behind the last valid unblocked taxi segment.
for (intVecIterator j = i->getIntentions().begin(); j != ivi; j++) { for (intVecIterator j = i->getIntentions().begin(); j != ivi; j++) {
int pos = (*j); int pos = (*j);
@ -1063,3 +991,9 @@ bool FGGroundController::updateActiveTraffic(TrafficVectorIterator i,
return true; return true;
} }
int FGGroundController::getFrequency() {
int groundFreq = parent->getGroundFrequency(2);
int towerFreq = parent->getTowerFrequency(2);
return groundFreq>0?groundFreq:towerFreq;
}

View file

@ -32,7 +32,7 @@
class FGAirportDynamics; class FGAirportDynamics;
/************************************************************************************** /**************************************************************************************
* class FGGroundNetWork * class FGGroundController
*************************************************************************************/ *************************************************************************************/
class FGGroundController : public FGATCController class FGGroundController : public FGATCController
{ {
@ -42,14 +42,10 @@ private:
bool networkInitialized; bool networkInitialized;
int count; int count;
int version; int version;
TrafficVector activeTraffic;
TrafficVectorIterator currTraffic;
FGTowerController *towerController; FGTowerController *towerController;
FGAirport *parent; /**Returns the frequency to be used. */
FGAirportDynamics* dynamics; int getFrequency();
void checkSpeedAdjustment(int id, double lat, double lon, void checkSpeedAdjustment(int id, double lat, double lon,
@ -61,13 +57,12 @@ private:
void updateStartupTraffic(TrafficVectorIterator i, int& priority, time_t now); void updateStartupTraffic(TrafficVectorIterator i, int& priority, time_t now);
bool updateActiveTraffic(TrafficVectorIterator i, int& priority, time_t now); bool updateActiveTraffic(TrafficVectorIterator i, int& priority, time_t now);
public: public:
FGGroundController(); FGGroundController(FGAirportDynamics *par);
~FGGroundController(); ~FGGroundController();
void setVersion (int v) { version = v;}; void setVersion (int v) { version = v;};
int getVersion() { return version; }; int getVersion() { return version; };
void init(FGAirportDynamics* pr);
bool exists() { bool exists() {
return hasNetwork; return hasNetwork;
}; };
@ -76,14 +71,10 @@ public:
}; };
virtual TrafficVectorIterator searchActiveTraffic(int id);
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon, double hdg, double spd, double alt, double lat, double lon, double hdg, double spd, double alt,
double radius, int leg, FGAIAircraft *aircraft); double radius, int leg, FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt); virtual void updateAircraftInformation(int id, double lat, double lon, double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId, bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
AtcMsgDir msgDir); AtcMsgDir msgDir);

View file

@ -71,8 +71,6 @@ FGStartupController::FGStartupController(FGAirportDynamics *par):
FGStartupController::~FGStartupController() FGStartupController::~FGStartupController()
{ {
_isDestroying = true;
clearTrafficControllers(activeTraffic);
} }
void FGStartupController::announcePosition(int id, void FGStartupController::announcePosition(int id,
@ -85,8 +83,8 @@ void FGStartupController::announcePosition(int id,
{ {
init(); init();
// Search activeTraffic for a record matching our id // Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
// Add a new TrafficRecord if no one exsists for this aircraft. // Add a new TrafficRecord if no one exsists for this aircraft.
if (i == activeTraffic.end() || activeTraffic.empty()) { if (i == activeTraffic.end() || activeTraffic.empty()) {
FGTrafficRecord rec; FGTrafficRecord rec;
@ -96,7 +94,7 @@ void FGStartupController::announcePosition(int id,
rec.setRunway(intendedRoute->getRunway()); rec.setRunway(intendedRoute->getRunway());
rec.setLeg(leg); rec.setLeg(leg);
rec.setPositionAndIntentions(currentPosition, intendedRoute); rec.setPositionAndIntentions(currentPosition, intendedRoute);
//rec.setCallSign(callsign); rec.setCallsign(ref->getCallSign());
rec.setAircraft(ref); rec.setAircraft(ref);
rec.setHoldPosition(true); rec.setHoldPosition(true);
activeTraffic.push_back(rec); activeTraffic.push_back(rec);
@ -107,59 +105,6 @@ void FGStartupController::announcePosition(int id,
} }
} }
// NOTE:
// IF WE MAKE TRAFFICRECORD A MEMBER OF THE BASE CLASS
// THE FOLLOWING THREE FUNCTIONS: SIGNOFF, HAS INSTRUCTION AND GETINSTRUCTION CAN
// BECOME DEVIRTUALIZED AND BE A MEMBER OF THE BASE ATCCONTROLLER CLASS
// WHICH WOULD SIMPLIFY CODE MAINTENANCE.
// Note that this function is probably obsolete
bool FGStartupController::hasInstruction(int id)
{
// Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id);
if (i == activeTraffic.end() || activeTraffic.empty()) {
SG_LOG(SG_ATC, SG_ALERT,
"AI error: checking ATC instruction for aircraft without traffic record at " << SG_ORIGIN);
} else {
return i->hasInstruction();
}
return false;
}
FGATCInstruction FGStartupController::getInstruction(int id)
{
// Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id);
if (i == activeTraffic.end() || activeTraffic.empty()) {
SG_LOG(SG_ATC, SG_ALERT,
"AI error: requesting ATC instruction for aircraft without traffic record at " << SG_ORIGIN);
} else {
return i->getInstruction();
}
return FGATCInstruction();
}
void FGStartupController::signOff(int id)
{
// ensure we don't modify activeTraffic during destruction
if (_isDestroying)
return;
// Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id);
if (i == activeTraffic.end() || activeTraffic.empty()) {
SG_LOG(SG_ATC, SG_ALERT,
"AI error: Aircraft without traffic record is signing off from tower at " << SG_ORIGIN);
} else {
SG_LOG(SG_ATC, SG_DEBUG, i->getAircraft()->getCallSign() << " signing off from startupcontroller");
i = activeTraffic.erase(i);
}
}
bool FGStartupController::checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId, bool FGStartupController::checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
AtcMsgDir msgDir) AtcMsgDir msgDir)
{ {
@ -198,9 +143,9 @@ void FGStartupController::updateAircraftInformation(int id, double lat, double l
double dt) double dt)
{ {
// Search activeTraffic for a record matching our id // Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
TrafficVectorIterator current, closest; TrafficVectorIterator current, closest;
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) { if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_ATC, SG_ALERT, SG_LOG(SG_ATC, SG_ALERT,
"AI error: updating aircraft without traffic record at " << SG_ORIGIN); "AI error: updating aircraft without traffic record at " << SG_ORIGIN);
@ -225,9 +170,10 @@ void FGStartupController::updateAircraftInformation(int id, double lat, double l
time_t startTime = i->getAircraft()->getTrafficRef()->getDepartureTime(); time_t startTime = i->getAircraft()->getTrafficRef()->getDepartureTime();
time_t now = globals->get_time_params()->get_cur_time(); time_t now = globals->get_time_params()->get_cur_time();
SG_LOG(SG_ATC, SG_BULK, i->getAircraft()->getTrafficRef()->getCallSign()
<< " is scheduled to depart in " << startTime-now << " seconds. Available = " << available if ((startTime - now) > 0) {
<< " at parking " << getGateName(i->getAircraft())); SG_LOG(SG_ATC, SG_BULK, i->getAircraft()->getTrafficRef()->getCallSign() << " is scheduled to depart in " << startTime - now << " seconds. Available = " << available << " at parking " << getGateName(i->getAircraft()));
}
if ((now - lastTransmission) > 3 + (rand() % 15)) { if ((now - lastTransmission) > 3 + (rand() % 15)) {
available = true; available = true;
@ -317,7 +263,7 @@ void FGStartupController::render(bool visible)
SG_LOG(SG_ATC, SG_BULK, "rendering for " << i->getAircraft()->getCallSign() << "pos = " << pos); SG_LOG(SG_ATC, SG_BULK, "rendering for " << i->getAircraft()->getCallSign() << "pos = " << pos);
if (pos > 0) { if (pos > 0) {
FGTaxiSegment *segment = groundNet->findSegment(pos); FGTaxiSegment *segment = groundNet->findSegment(pos);
SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude()))); SGGeod start = i->getPos();
SGGeod end (segment->getEnd()->geod()); SGGeod end (segment->getEnd()->geod());
double length = SGGeodesy::distanceM(start, end); double length = SGGeodesy::distanceM(start, end);
@ -480,11 +426,17 @@ void FGStartupController::render(bool visible)
} }
string FGStartupController::getName() { string FGStartupController::getName() {
return string(parent->getId() + "-startup"); return string(parent->parent()->getName() + "-Startup");
} }
void FGStartupController::update(double dt) void FGStartupController::update(double dt)
{ {
FGATCController::eraseDeadTraffic(activeTraffic); FGATCController::eraseDeadTraffic();
}
int FGStartupController::getFrequency() {
int groundFreq = parent->getGroundFrequency(2);
int towerFreq = parent->getTowerFrequency(2);
return groundFreq>0?groundFreq:towerFreq;
} }

View file

@ -28,8 +28,7 @@
#include <osg/Shape> #include <osg/Shape>
#include <simgear/compiler.h> #include <simgear/compiler.h>
// There is probably a better include than sg_geodesy to get the SG_NM_TO_METER... #include <simgear/constants.h>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGReferenced.hxx> #include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
@ -45,9 +44,8 @@
class FGStartupController : public FGATCController class FGStartupController : public FGATCController
{ {
private: private:
TrafficVector activeTraffic; /**Returns the frequency to be used. */
//ActiveRunwayVec activeRunways; int getFrequency();
FGAirportDynamics *parent;
public: public:
FGStartupController(FGAirportDynamics *parent); FGStartupController(FGAirportDynamics *parent);
@ -57,23 +55,13 @@ public:
double lat, double lon, double lat, double lon,
double hdg, double spd, double alt, double radius, int leg, double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft); FGAIAircraft *aircraft);
virtual void signOff(int id);
virtual void updateAircraftInformation(int id, double lat, double lon, virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt); double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
virtual void render(bool); virtual void render(bool);
virtual std::string getName(); virtual std::string getName();
virtual void update(double dt); virtual void update(double dt);
bool hasActiveTraffic() {
return ! activeTraffic.empty();
};
TrafficVector &getActiveTraffic() {
return activeTraffic;
};
// Hpoefully, we can move this function to the base class, but I need to verify what is needed for the other controllers before doing so. // Hpoefully, we can move this function to the base class, but I need to verify what is needed for the other controllers before doing so.
bool checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId, bool checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
AtcMsgDir msgDir); AtcMsgDir msgDir);

View file

@ -63,7 +63,7 @@ using std::string;
* class FGTowerController * class FGTowerController
s * subclass of FGATCController s * subclass of FGATCController
**************************************************************************/ **************************************************************************/
FGTowerController::FGTowerController(FGAirportDynamics *par) : FGTowerController::FGTowerController(FGAirportDynamics *par) :
FGATCController() FGATCController()
{ {
@ -72,8 +72,6 @@ FGTowerController::FGTowerController(FGAirportDynamics *par) :
FGTowerController::~FGTowerController() FGTowerController::~FGTowerController()
{ {
_isDestroying = true;
clearTrafficControllers(activeTraffic);
} }
// //
@ -86,10 +84,10 @@ void FGTowerController::announcePosition(int id,
FGAIAircraft * ref) FGAIAircraft * ref)
{ {
init(); init();
// Search activeTraffic for a record matching our id // Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
// Add a new TrafficRecord if no one exsists for this aircraft. // Add a new TrafficRecord if no one exsists for this aircraft.
if (i == activeTraffic.end() || (activeTraffic.empty())) { if (i == activeTraffic.end() || (activeTraffic.empty())) {
FGTrafficRecord rec; FGTrafficRecord rec;
@ -132,8 +130,8 @@ void FGTowerController::updateAircraftInformation(int id, double lat, double lon
double dt) double dt)
{ {
// Search activeTraffic for a record matching our id // Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
setDt(getDt() + dt); setDt(getDt() + dt);
if (i == activeTraffic.end() || (activeTraffic.empty())) { if (i == activeTraffic.end() || (activeTraffic.empty())) {
@ -150,14 +148,14 @@ void FGTowerController::updateAircraftInformation(int id, double lat, double lon
// see if we already have a clearance record for the currently active runway // see if we already have a clearance record for the currently active runway
// NOTE: dd. 2011-08-07: Because the active runway has been constructed in the announcePosition function, we may safely assume that is // NOTE: dd. 2011-08-07: Because the active runway has been constructed in the announcePosition function, we may safely assume that is
// already exists here. So, we can simplify the current code. // already exists here. So, we can simplify the current code.
ActiveRunwayVecIterator rwy = activeRunways.begin(); ActiveRunwayVecIterator rwy = activeRunways.begin();
//if (parent->getId() == fgGetString("/sim/presets/airport-id")) { //if (parent->getId() == fgGetString("/sim/presets/airport-id")) {
// for (rwy = activeRunways.begin(); rwy != activeRunways.end(); rwy++) { // for (rwy = activeRunways.begin(); rwy != activeRunways.end(); rwy++) {
// rwy->printdepartureQueue(); // rwy->printdepartureQueue();
// } // }
//} //}
rwy = activeRunways.begin(); rwy = activeRunways.begin();
while (rwy != activeRunways.end()) { while (rwy != activeRunways.end()) {
if (rwy->getRunwayName() == current.getRunway()) { if (rwy->getRunwayName() == current.getRunway()) {
@ -186,9 +184,11 @@ void FGTowerController::updateAircraftInformation(int id, double lat, double lon
if (ac->getTakeOffStatus() == 1) { if (ac->getTakeOffStatus() == 1) {
// transmit takeoff clearance // transmit takeoff clearance
ac->setTakeOffStatus(2); ac->setTakeOffStatus(2);
transmit(&(*i), &(*parent), MSG_CLEARED_FOR_TAKEOFF, ATC_GROUND_TO_AIR, true);
i->setState(10);
} }
} }
//FIXME Make it an member of traffic record
if (current.getAircraft()->getTakeOffStatus() == 2) { if (current.getAircraft()->getTakeOffStatus() == 2) {
current.setHoldPosition(false); current.setHoldPosition(false);
} else { } else {
@ -208,7 +208,7 @@ void FGTowerController::updateAircraftInformation(int id, double lat, double lon
// transmit takeoff clearacne? But why twice? // transmit takeoff clearacne? But why twice?
} }
} }
} }
void FGTowerController::signOff(int id) void FGTowerController::signOff(int id)
@ -218,7 +218,7 @@ void FGTowerController::signOff(int id)
return; return;
// Search activeTraffic for a record matching our id // Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
if (i == activeTraffic.end() || (activeTraffic.empty())) { if (i == activeTraffic.end() || (activeTraffic.empty())) {
SG_LOG(SG_ATC, SG_ALERT, SG_LOG(SG_ATC, SG_ALERT,
"AI error: Aircraft without traffic record is signing off from tower at " << SG_ORIGIN); "AI error: Aircraft without traffic record is signing off from tower at " << SG_ORIGIN);
@ -240,8 +240,7 @@ void FGTowerController::signOff(int id)
} }
i->getAircraft()->resetTakeOffStatus(); i->getAircraft()->resetTakeOffStatus();
activeTraffic.erase(i); FGATCController::signOff(id);
SG_LOG(SG_ATC, SG_DEBUG, "Signing off from tower controller");
} }
// NOTE: // NOTE:
@ -253,8 +252,8 @@ void FGTowerController::signOff(int id)
bool FGTowerController::hasInstruction(int id) bool FGTowerController::hasInstruction(int id)
{ {
// Search activeTraffic for a record matching our id // Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
if (i == activeTraffic.end() || activeTraffic.empty()) { if (i == activeTraffic.end() || activeTraffic.empty()) {
SG_LOG(SG_ATC, SG_ALERT, SG_LOG(SG_ATC, SG_ALERT,
"AI error: checking ATC instruction for aircraft without traffic record at " << SG_ORIGIN); "AI error: checking ATC instruction for aircraft without traffic record at " << SG_ORIGIN);
@ -268,8 +267,8 @@ bool FGTowerController::hasInstruction(int id)
FGATCInstruction FGTowerController::getInstruction(int id) FGATCInstruction FGTowerController::getInstruction(int id)
{ {
// Search activeTraffic for a record matching our id // Search activeTraffic for a record matching our id
TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
if (i == activeTraffic.end() || activeTraffic.empty()) { if (i == activeTraffic.end() || activeTraffic.empty()) {
SG_LOG(SG_ATC, SG_ALERT, SG_LOG(SG_ATC, SG_ALERT,
"AI error: requesting ATC instruction for aircraft without traffic record at " << SG_ORIGIN); "AI error: requesting ATC instruction for aircraft without traffic record at " << SG_ORIGIN);
@ -290,5 +289,10 @@ string FGTowerController::getName() {
void FGTowerController::update(double dt) void FGTowerController::update(double dt)
{ {
FGATCController::eraseDeadTraffic(activeTraffic); FGATCController::eraseDeadTraffic();
}
int FGTowerController::getFrequency() {
int towerFreq = parent->getTowerFrequency(2);
return towerFreq;
} }

View file

@ -28,8 +28,7 @@
#include <osg/Shape> #include <osg/Shape>
#include <simgear/compiler.h> #include <simgear/compiler.h>
// There is probably a better include than sg_geodesy to get the SG_NM_TO_METER... #include <simgear/constants.h>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGReferenced.hxx> #include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
@ -43,9 +42,9 @@
class FGTowerController : public FGATCController class FGTowerController : public FGATCController
{ {
private: private:
TrafficVector activeTraffic;
ActiveRunwayVec activeRunways; ActiveRunwayVec activeRunways;
FGAirportDynamics *parent; /**Returns the frequency to be used. */
int getFrequency();
public: public:
FGTowerController(FGAirportDynamics *parent); FGTowerController(FGAirportDynamics *parent);
@ -55,21 +54,15 @@ public:
double lat, double lon, double lat, double lon,
double hdg, double spd, double alt, double radius, int leg, double hdg, double spd, double alt, double radius, int leg,
FGAIAircraft *aircraft); FGAIAircraft *aircraft);
virtual void signOff(int id); void signOff(int id);
bool hasInstruction(int id);
FGATCInstruction getInstruction(int id);
virtual void updateAircraftInformation(int id, double lat, double lon, virtual void updateAircraftInformation(int id, double lat, double lon,
double heading, double speed, double alt, double dt); double heading, double speed, double alt, double dt);
virtual bool hasInstruction(int id);
virtual FGATCInstruction getInstruction(int id);
virtual void render(bool); virtual void render(bool);
virtual std::string getName(); virtual std::string getName();
virtual void update(double dt); virtual void update(double dt);
bool hasActiveTraffic() {
return ! activeTraffic.empty();
};
TrafficVector &getActiveTraffic() {
return activeTraffic;
};
}; };
#endif #endif

View file

@ -334,7 +334,7 @@ void FGATCManager::update ( double time ) {
} }
#if 0 #if 0
// Test code: Print how far we're progressing along the taxi route. // Test code: Print how far we're progressing along the taxi route.
SG_LOG(SG_ATC, SG_DEBUG, "Size of waypoint cue " << size); SG_LOG(SG_ATC, SG_DEBUG, "Size of waypoint queue " << size);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
int val = fp->getRouteIndex(i); int val = fp->getRouteIndex(i);
SG_LOG(SG_ATC, SG_BULK, fp->getWayPoint(i)->getName() << " "); SG_LOG(SG_ATC, SG_BULK, fp->getWayPoint(i)->getName() << " ");

View file

@ -36,6 +36,7 @@
#include <simgear/scene/material/mat.hxx> #include <simgear/scene/material/mat.hxx>
#include <simgear/scene/util/OsgMath.hxx> #include <simgear/scene/util/OsgMath.hxx>
#include <simgear/timing/sg_time.hxx> #include <simgear/timing/sg_time.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <Scenery/scenery.hxx> #include <Scenery/scenery.hxx>
@ -58,7 +59,7 @@ using std::string;
/*************************************************************************** /***************************************************************************
* ActiveRunway * ActiveRunway
**************************************************************************/ **************************************************************************/
ActiveRunway::ActiveRunway(const std::string& r, int cc) : ActiveRunway::ActiveRunway(const std::string& r, int cc) :
rwy(r) rwy(r)
{ {
@ -87,7 +88,7 @@ time_t ActiveRunway::requestTimeSlot(time_t eta)
// time_t separation = 120; // time_t separation = 120;
//} //}
bool found = false; bool found = false;
// if the aircraft is the first arrival, add to the vector and return eta directly // if the aircraft is the first arrival, add to the vector and return eta directly
if (estimatedArrivalTimes.empty()) { if (estimatedArrivalTimes.empty()) {
estimatedArrivalTimes.push_back(eta); estimatedArrivalTimes.push_back(eta);
@ -97,13 +98,13 @@ time_t ActiveRunway::requestTimeSlot(time_t eta)
// First check the already assigned slots to see where we need to fit the flight in // First check the already assigned slots to see where we need to fit the flight in
TimeVectorIterator i = estimatedArrivalTimes.begin(); TimeVectorIterator i = estimatedArrivalTimes.begin();
SG_LOG(SG_ATC, SG_DEBUG, "Checking eta slots " << eta << ": "); SG_LOG(SG_ATC, SG_DEBUG, "Checking eta slots " << eta << ": ");
// is this needed - just a debug output? // is this needed - just a debug output?
for (i = estimatedArrivalTimes.begin(); for (i = estimatedArrivalTimes.begin();
i != estimatedArrivalTimes.end(); i++) { i != estimatedArrivalTimes.end(); i++) {
SG_LOG(SG_ATC, SG_BULK, "Stored time : " << (*i)); SG_LOG(SG_ATC, SG_BULK, "Stored time : " << (*i));
} }
// if the flight is before the first scheduled slot + separation // if the flight is before the first scheduled slot + separation
i = estimatedArrivalTimes.begin(); i = estimatedArrivalTimes.begin();
if ((eta + separation) < (*i)) { if ((eta + separation) < (*i)) {
@ -113,11 +114,11 @@ time_t ActiveRunway::requestTimeSlot(time_t eta)
slotHousekeeping(newEta); slotHousekeeping(newEta);
return newEta; return newEta;
} }
// else, look through the rest of the slots // else, look through the rest of the slots
while ((i != estimatedArrivalTimes.end()) && (!found)) { while ((i != estimatedArrivalTimes.end()) && (!found)) {
TimeVectorIterator j = i + 1; TimeVectorIterator j = i + 1;
// if the flight is after the last scheduled slot check if separation is needed // if the flight is after the last scheduled slot check if separation is needed
if (j == estimatedArrivalTimes.end()) { if (j == estimatedArrivalTimes.end()) {
if (((*i) + separation) < eta) { if (((*i) + separation) < eta) {
@ -180,7 +181,7 @@ void ActiveRunway::slotHousekeeping(time_t newEta)
// add the slot to the vector and resort the vector // add the slot to the vector and resort the vector
estimatedArrivalTimes.push_back(newEta); estimatedArrivalTimes.push_back(newEta);
sort(estimatedArrivalTimes.begin(), estimatedArrivalTimes.end()); sort(estimatedArrivalTimes.begin(), estimatedArrivalTimes.end());
// do some housekeeping : remove any slots that are past // do some housekeeping : remove any slots that are past
time_t now = globals->get_time_params()->get_cur_time(); time_t now = globals->get_time_params()->get_cur_time();
@ -204,7 +205,7 @@ void ActiveRunway::printDepartureQueue()
SG_LOG(SG_ATC, SG_DEBUG, " " << acft->getCallSign() << " " << acft->getTakeOffStatus()); SG_LOG(SG_ATC, SG_DEBUG, " " << acft->getCallSign() << " " << acft->getTakeOffStatus());
SG_LOG(SG_ATC, SG_DEBUG, " " << acft->_getLatitude() << " " << acft->_getLongitude() << acft->getSpeed() << " " << acft->getAltitude()); SG_LOG(SG_ATC, SG_DEBUG, " " << acft->_getLatitude() << " " << acft->_getLongitude() << acft->getSpeed() << " " << acft->getAltitude());
} }
} }
/* Fetch the first aircraft in the departure cue with a certain status */ /* Fetch the first aircraft in the departure cue with a certain status */
@ -213,11 +214,11 @@ SGSharedPtr<FGAIAircraft>ActiveRunway::getFirstOfStatus(int stat) const
auto it = std::find_if(departureQueue.begin(), departureQueue.end(), [stat](const SGSharedPtr<FGAIAircraft>& acft) { auto it = std::find_if(departureQueue.begin(), departureQueue.end(), [stat](const SGSharedPtr<FGAIAircraft>& acft) {
return acft->getTakeOffStatus() == stat; return acft->getTakeOffStatus() == stat;
}); });
if (it == departureQueue.end()) { if (it == departureQueue.end()) {
return {}; return {};
} }
return *it; return *it;
} }
@ -226,7 +227,7 @@ SGSharedPtr<FGAIAircraft> ActiveRunway::getFirstAircraftInDepartureQueue() const
if (departureQueue.empty()) { if (departureQueue.empty()) {
return {}; return {};
} }
return departureQueue.front(); return departureQueue.front();
}; };
@ -241,7 +242,7 @@ void ActiveRunway::addToDepartureQueue(FGAIAircraft *ac)
/*************************************************************************** /***************************************************************************
* FGTrafficRecord * FGTrafficRecord
**************************************************************************/ **************************************************************************/
FGTrafficRecord::FGTrafficRecord(): FGTrafficRecord::FGTrafficRecord():
id(0), waitsForId(0), id(0), waitsForId(0),
currentPos(0), currentPos(0),
@ -252,7 +253,7 @@ FGTrafficRecord::FGTrafficRecord():
allowPushback(true), allowPushback(true),
priority(0), priority(0),
timer(0), timer(0),
latitude(0), longitude(0), heading(0), speed(0), altitude(0), radius(0) heading(0), speed(0), altitude(0), radius(0)
{ {
} }
@ -289,12 +290,27 @@ void FGTrafficRecord::setAircraft(FGAIAircraft *ref)
aircraft = ref; aircraft = ref;
} }
FGAIAircraft* FGTrafficRecord::getAircraft() const bool FGTrafficRecord::isDead() const {
{ if (!aircraft) {
return aircraft.ptr(); return true;
} }
return aircraft->getDie();
}
/* void FGTrafficRecord::clearATCController() const {
if (aircraft) {
aircraft->clearATCController();
}
}
FGAIAircraft* FGTrafficRecord::getAircraft() const
{
if(aircraft.valid()) {
return aircraft.ptr();
}
return 0;
}
/**
* Check if another aircraft is ahead of the current one, and on the same taxiway * Check if another aircraft is ahead of the current one, and on the same taxiway
* @return true / false if this is/isn't the case. * @return true / false if this is/isn't the case.
*/ */
@ -339,8 +355,7 @@ void FGTrafficRecord::setPositionAndHeading(double lat, double lon,
double hdg, double spd, double hdg, double spd,
double alt) double alt)
{ {
latitude = lat; this->pos = SGGeod::fromDegFt(lon, lat, alt);
longitude = lon;
heading = hdg; heading = hdg;
speed = spd; speed = spd;
altitude = alt; altitude = alt;
@ -504,7 +519,7 @@ bool FGTrafficRecord::isActive(int margin) const
if (aircraft->getDie()) { if (aircraft->getDie()) {
return false; return false;
} }
time_t now = globals->get_time_params()->get_cur_time(); time_t now = globals->get_time_params()->get_cur_time();
time_t deptime = aircraft->getTrafficRef()->getDepartureTime(); time_t deptime = aircraft->getTrafficRef()->getDepartureTime();
return ((now + margin) > deptime); return ((now + margin) > deptime);
@ -532,9 +547,9 @@ bool FGTrafficRecord::pushBackAllowed() const
/*************************************************************************** /***************************************************************************
* FGATCInstruction * FGATCInstruction
* *
**************************************************************************/ **************************************************************************/
FGATCInstruction::FGATCInstruction() FGATCInstruction::FGATCInstruction()
{ {
holdPattern = false; holdPattern = false;

View file

@ -75,7 +75,7 @@ private:
double alt; double alt;
public: public:
FGATCInstruction(); FGATCInstruction();
bool hasInstruction () const; bool hasInstruction () const;
bool getHoldPattern () const { bool getHoldPattern () const {
return holdPattern; return holdPattern;
@ -95,7 +95,7 @@ public:
bool getCheckForCircularWait() const { bool getCheckForCircularWait() const {
return resolveCircularWait; return resolveCircularWait;
}; };
double getSpeed () const { double getSpeed () const {
return speed; return speed;
}; };
@ -124,7 +124,7 @@ public:
void setResolveCircularWait (bool val) { void setResolveCircularWait (bool val) {
resolveCircularWait = val; resolveCircularWait = val;
}; };
void setSpeed (double val) { void setSpeed (double val) {
speed = val; speed = val;
}; };
@ -142,11 +142,12 @@ public:
/************************************************************************************** /**************************************************************************************
* class FGTrafficRecord * class FGTrafficRecord
* Represents the interaction of an AI Aircraft and ATC
*************************************************************************************/ *************************************************************************************/
class FGTrafficRecord class FGTrafficRecord
{ {
private: private:
int id; int id;
int waitsForId; int waitsForId;
int currentPos; int currentPos;
int leg; int leg;
@ -158,7 +159,9 @@ private:
time_t timer; time_t timer;
intVec intentions; intVec intentions;
FGATCInstruction instruction; FGATCInstruction instruction;
double latitude, longitude, heading, speed, altitude, radius; SGGeod pos;
double heading, speed, altitude, radius;
std::string callsign;
std::string runway; std::string runway;
SGSharedPtr<FGAIAircraft> aircraft; SGSharedPtr<FGAIAircraft> aircraft;
@ -192,15 +195,17 @@ public:
FGATCInstruction getInstruction() const { FGATCInstruction getInstruction() const {
return instruction; return instruction;
}; };
bool hasInstruction() { bool hasInstruction() const {
return instruction.hasInstruction(); return instruction.hasInstruction();
}; };
void setPositionAndHeading(double lat, double lon, double hdg, double spd, double alt); void setPositionAndHeading(double lat, double lon, double hdg, double spd, double alt);
bool checkPositionAndIntentions(FGTrafficRecord &other); bool checkPositionAndIntentions(FGTrafficRecord &other);
int crosses (FGGroundNetwork *, FGTrafficRecord &other); int crosses (FGGroundNetwork *, FGTrafficRecord &other);
bool isOpposing (FGGroundNetwork *, FGTrafficRecord &other, int node); bool isOpposing (FGGroundNetwork *, FGTrafficRecord &other, int node);
bool isActive(int margin) const; bool isActive(int margin) const;
bool isDead() const;
void clearATCController() const;
bool onRoute(FGGroundNetwork *, FGTrafficRecord &other); bool onRoute(FGGroundNetwork *, FGTrafficRecord &other);
@ -208,19 +213,16 @@ public:
return instruction.getChangeSpeed(); return instruction.getChangeSpeed();
}; };
double getLatitude () const { SGGeod getPos() {
return latitude ; return pos;
}; }
double getLongitude() const {
return longitude;
};
double getHeading () const { double getHeading () const {
return heading ; return heading ;
}; };
double getSpeed () const { double getSpeed () const {
return speed ; return speed ;
}; };
double getAltitude () const { double getFAltitude () const {
return altitude ; return altitude ;
}; };
double getRadius () const { double getRadius () const {
@ -261,10 +263,15 @@ public:
instruction.setResolveCircularWait(false); instruction.setResolveCircularWait(false);
}; };
void setCallsign(std::string clsgn) { callsign = clsgn; };
const std::string& getCallsign() const {
return callsign;
};
const std::string& getRunway() const { const std::string& getRunway() const {
return runway; return runway;
}; };
//void setCallSign(string clsgn) { callsign = clsgn; };
void setAircraft(FGAIAircraft *ref); void setAircraft(FGAIAircraft *ref);
void updateState() { void updateState() {
@ -323,7 +330,7 @@ private:
int currentlyCleared; int currentlyCleared;
double distanceToFinal; double distanceToFinal;
TimeVector estimatedArrivalTimes; TimeVector estimatedArrivalTimes;
using AircraftRefVec = std::vector<SGSharedPtr<FGAIAircraft>>; using AircraftRefVec = std::vector<SGSharedPtr<FGAIAircraft>>;
AircraftRefVec departureQueue; AircraftRefVec departureQueue;
@ -356,13 +363,13 @@ public:
int getdepartureQueueSize() { int getdepartureQueueSize() {
return departureQueue.size(); return departureQueue.size();
}; };
SGSharedPtr<FGAIAircraft> getFirstAircraftInDepartureQueue() const; SGSharedPtr<FGAIAircraft> getFirstAircraftInDepartureQueue() const;
SGSharedPtr<FGAIAircraft> getFirstOfStatus(int stat) const; SGSharedPtr<FGAIAircraft> getFirstOfStatus(int stat) const;
void updateDepartureQueue(); void updateDepartureQueue();
void printDepartureQueue(); void printDepartureQueue();
}; };

View file

@ -86,7 +86,7 @@ public:
unsigned int refCount; unsigned int refCount;
FGParkingRef parking; FGParkingRef parking;
// we don't want an owning ref here, otherwise we // we don't want an owning ref here, otherwise we
// have a circular ownership from AirportDynamics -> us // have a circular ownership from AirportDynamics -> us
SGWeakPtr<FGAirportDynamics> dynamics; SGWeakPtr<FGAirportDynamics> dynamics;
@ -215,6 +215,7 @@ FGAirportDynamics::FGAirportDynamics(FGAirport * ap):
startupController (this), startupController (this),
towerController (this), towerController (this),
approachController (this), approachController (this),
groundController (this),
atisSequenceIndex(-1), atisSequenceIndex(-1),
atisSequenceTimeStamp(0.0) atisSequenceTimeStamp(0.0)
@ -232,7 +233,7 @@ FGAirportDynamics::~FGAirportDynamics()
void FGAirportDynamics::init() void FGAirportDynamics::init()
{ {
groundController.setTowerController(&towerController); groundController.setTowerController(&towerController);
groundController.init(this); groundController.init();
} }
FGParking* FGAirportDynamics::innerGetAvailableParking(double radius, const string & flType, FGParking* FGAirportDynamics::innerGetAvailableParking(double radius, const string & flType,
@ -342,13 +343,13 @@ ParkingAssignment FGAirportDynamics::getAvailableParkingByName(const std::string
auto it = std::find_if(parkings.begin(), parkings.end(), [this, name] (FGParkingRef parking){ auto it = std::find_if(parkings.begin(), parkings.end(), [this, name] (FGParkingRef parking){
if (parking->name() != name) if (parking->name() != name)
return false; return false;
return this->isParkingAvailable(parking); return this->isParkingAvailable(parking);
}); });
if (it == parkings.end()) if (it == parkings.end())
return {}; // no assignment possible return {}; // no assignment possible
return {*it, this}; return {*it, this};
} }
@ -812,7 +813,7 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
if (!landing.empty()) { if (!landing.empty()) {
runway = chooseRwyByHeading(landing, heading); runway = chooseRwyByHeading(landing, heading);
} }
if (runway.empty()) { //fallback if (runway.empty()) { //fallback
runway = chooseRunwayFallback(); runway = chooseRunwayFallback();
} }
@ -887,6 +888,34 @@ const string FGAirportDynamics::getId() const
// so that at least I can start working on assigning different frequencies to different // so that at least I can start working on assigning different frequencies to different
// operations. // operations.
int FGAirportDynamics::getApproachFrequency(unsigned nr)
{
int approachFreq = 0;
if (nr < 2) {
SG_LOG(SG_ATC, SG_ALERT,
"Leg value is smaller than two at " << SG_ORIGIN);
}
const intVec& freqApproach(parent()->groundNetwork()->getApproachFrequencies());
if (freqApproach.size() == 0) {
return 0;
}
if ((freqApproach.size() > nr - 1) && (nr > 1)) {
approachFreq = freqApproach[nr - 1];
}
if ((freqApproach.size() < nr - 1) && (nr > 1)) {
approachFreq =
(freqApproach.size() <
(nr - 1)) ? freqApproach[freqApproach.size() -
1] : freqApproach[nr - 2];
}
if ((freqApproach.size() >= nr - 1) && (nr > 1)) {
approachFreq = freqApproach[nr - 2];
}
return approachFreq;
}
int FGAirportDynamics::getGroundFrequency(unsigned leg) int FGAirportDynamics::getGroundFrequency(unsigned leg)
{ {
//return freqGround.size() ? freqGround[0] : 0; }; //return freqGround.size() ? freqGround[0] : 0; };

View file

@ -42,16 +42,16 @@ class ParkingAssignment
public: public:
ParkingAssignment(); ParkingAssignment();
~ParkingAssignment(); ~ParkingAssignment();
// create a parking assignment (and mark it as unavailable) // create a parking assignment (and mark it as unavailable)
ParkingAssignment(FGParking* pk, FGAirportDynamics* apt); ParkingAssignment(FGParking* pk, FGAirportDynamics* apt);
ParkingAssignment(const ParkingAssignment& aOther); ParkingAssignment(const ParkingAssignment& aOther);
void operator=(const ParkingAssignment& aOther); void operator=(const ParkingAssignment& aOther);
bool isValid() const; bool isValid() const;
FGParking* parking() const; FGParking* parking() const;
void release(); void release();
private: private:
void clear(); void clear();
@ -107,13 +107,13 @@ public:
virtual ~FGAirportDynamics(); virtual ~FGAirportDynamics();
void init(); void init();
double getElevation() const; double getElevation() const;
const std::string getId() const; const std::string getId() const;
FGAirport* parent() const FGAirport* parent() const
{ return _ap; } { return _ap; }
void getActiveRunway( const std::string& trafficType, void getActiveRunway( const std::string& trafficType,
int action, int action,
std::string& runway, std::string& runway,
@ -131,9 +131,9 @@ public:
const std::string& acType, const std::string& airline); const std::string& acType, const std::string& airline);
void setParkingAvailable(FGParking* park, bool available); void setParkingAvailable(FGParking* park, bool available);
bool isParkingAvailable(FGParking* parking) const; bool isParkingAvailable(FGParking* parking) const;
void releaseParking(FGParking* id); void releaseParking(FGParking* id);
FGParkingList getParkings(bool onlyAvailable, const std::string& type) const; FGParkingList getParkings(bool onlyAvailable, const std::string& type) const;
@ -150,7 +150,7 @@ public:
* availabiity (i.e try them all) * availabiity (i.e try them all)
*/ */
ParkingAssignment getAvailableParkingByName(const std::string & name); ParkingAssignment getAvailableParkingByName(const std::string & name);
FGParkingRef getOccupiedParkingByName(const std::string& name) const; FGParkingRef getOccupiedParkingByName(const std::string& name) const;
// ATC related functions. // ATC related functions.
@ -167,6 +167,7 @@ public:
return &approachController; return &approachController;
}; };
int getApproachFrequency (unsigned nr);
int getGroundFrequency(unsigned leg); int getGroundFrequency(unsigned leg);
int getTowerFrequency (unsigned nr); int getTowerFrequency (unsigned nr);

View file

@ -250,13 +250,13 @@ FGTaxiNodeRef FGGroundNetwork::findNearestNodeOffRunway(const SGGeod& aGeod, FGR
[runwayLine, cartPos, marginMSqr] (const FGTaxiNodeRef& a) [runwayLine, cartPos, marginMSqr] (const FGTaxiNodeRef& a)
{ {
if (a->getIsOnRunway()) return false; if (a->getIsOnRunway()) return false;
// exclude parking positions from consideration. This helps to // exclude parking positions from consideration. This helps to
// exclude airports whose ground nets only list parking positions, // exclude airports whose ground nets only list parking positions,
// since these typically produce bad results. See discussion in // since these typically produce bad results. See discussion in
// https://sourceforge.net/p/flightgear/codetickets/2110/ // https://sourceforge.net/p/flightgear/codetickets/2110/
if (a->type() == FGPositioned::PARKING) return false; if (a->type() == FGPositioned::PARKING) return false;
return (distSqr(runwayLine, a->cart()) >= marginMSqr); return (distSqr(runwayLine, a->cart()) >= marginMSqr);
}); });
@ -564,7 +564,10 @@ FGTaxiSegment* FGGroundNetwork::findSegmentByHeading(const FGTaxiNode* from, con
return best; // not found return best; // not found
} }
const intVec& FGGroundNetwork::getApproachFrequencies() const
{
return freqApproach;
}
const intVec& FGGroundNetwork::getTowerFrequencies() const const intVec& FGGroundNetwork::getTowerFrequencies() const
{ {

View file

@ -63,7 +63,7 @@ private:
// the ground-network owns the nodes // the ground-network owns the nodes
const FGTaxiNode* startNode; const FGTaxiNode* startNode;
const FGTaxiNode* endNode; const FGTaxiNode* endNode;
bool isActive; bool isActive;
BlockList blockTimes; BlockList blockTimes;
@ -73,26 +73,26 @@ private:
friend class FGGroundNetwork; friend class FGGroundNetwork;
public: public:
FGTaxiSegment(FGTaxiNode* start, FGTaxiNode* end); FGTaxiSegment(FGTaxiNode* start, FGTaxiNode* end);
void setIndex (int val) { void setIndex (int val) {
index = val; index = val;
}; };
void setDimensions(double elevation); void setDimensions(double elevation);
void block(int id, time_t blockTime, time_t now); void block(int id, time_t blockTime, time_t now);
void unblock(time_t now); void unblock(time_t now);
bool hasBlock(time_t now); bool hasBlock(time_t now);
FGTaxiNodeRef getEnd() const; FGTaxiNodeRef getEnd() const;
FGTaxiNodeRef getStart() const; FGTaxiNodeRef getStart() const;
double getLength() const; double getLength() const;
// compute the center of the arc // compute the center of the arc
SGGeod getCenter() const; SGGeod getCenter() const;
double getHeading() const; double getHeading() const;
int getIndex() { int getIndex() {
return index; return index;
}; };
@ -154,7 +154,7 @@ public:
return nodes.empty(); return nodes.empty();
}; };
bool next(FGTaxiNodeRef& nde, int *rte); bool next(FGTaxiNodeRef& nde, int *rte);
void first() { void first() {
currNode = nodes.begin(); currNode = nodes.begin();
currRoute = routes.begin(); currRoute = routes.begin();
@ -179,7 +179,7 @@ private:
bool networkInitialized; bool networkInitialized;
int version; int version;
FGTaxiSegmentVector segments; FGTaxiSegmentVector segments;
FGAirport *parent; FGAirport *parent;
@ -234,7 +234,7 @@ private:
public: public:
FGGroundNetwork(FGAirport* pr); FGGroundNetwork(FGAirport* pr);
~FGGroundNetwork(); ~FGGroundNetwork();
void setVersion (int v) { version = v;}; void setVersion (int v) { version = v;};
int getVersion() { return version; }; int getVersion() { return version; };
@ -274,7 +274,7 @@ public:
*/ */
FGTaxiNodeVector findSegmentsFrom(const FGTaxiNodeRef& from) const; FGTaxiNodeVector findSegmentsFrom(const FGTaxiNodeRef& from) const;
FGTaxiRoute findShortestRoute(FGTaxiNode* start, FGTaxiNode* end, bool fullSearch=true); FGTaxiRoute findShortestRoute(FGTaxiNode* start, FGTaxiNode* end, bool fullSearch=true);
@ -284,9 +284,10 @@ public:
void addVersion(int v) {version = v; }; void addVersion(int v) {version = v; };
void unblockAllSegments(time_t now); void unblockAllSegments(time_t now);
const intVec& getApproachFrequencies() const;
const intVec& getTowerFrequencies() const; const intVec& getTowerFrequencies() const;
const intVec& getGroundFrequencies() const; const intVec& getGroundFrequencies() const;
}; };

View file

@ -28,6 +28,6 @@
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(AIFlightPlanTests, "Unit tests"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(AIFlightPlanTests, "Unit tests");
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(AIManagerTests, "Unit tests"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(AIManagerTests, "Unit tests");
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(GroundnetTests, "Unit tests"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(GroundnetTests, "Unit tests");
// CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(TrafficTests, "Unit tests"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(TrafficTests, "Unit tests");
// CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(TrafficMgrTests, "Unit tests"); // CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(TrafficMgrTests, "Unit tests");
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(SubmodelsTests, "Unit tests"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(SubmodelsTests, "Unit tests");

View file

@ -73,6 +73,8 @@ void TrafficTests::setUp()
fgSetBool("/environment/realwx/enabled", false); fgSetBool("/environment/realwx/enabled", false);
fgSetBool("/environment/metar/valid", false); fgSetBool("/environment/metar/valid", false);
fgSetBool("/sim/terrasync/ai-data-update-now", false); fgSetBool("/sim/terrasync/ai-data-update-now", false);
fgSetBool("/sim/sound/atc/enabled", true);
fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", 121.70);
globals->append_data_path(SGPath::fromUtf8(FG_TEST_SUITE_DATA), false); globals->append_data_path(SGPath::fromUtf8(FG_TEST_SUITE_DATA), false);