diff --git a/src/AIModel/AIAircraft.cxx b/src/AIModel/AIAircraft.cxx index 3ec758314..63c9a7eeb 100644 --- a/src/AIModel/AIAircraft.cxx +++ b/src/AIModel/AIAircraft.cxx @@ -48,7 +48,8 @@ using std::string; using std::cerr; using std::endl; -//#include +#include +#include FGAIAircraft::FGAIAircraft(FGAISchedule* ref) : /* HOT must be disabled for AI Aircraft, * 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. // 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! - switch (leg) { + switch (leg) { case 1: // Startup and Push back if (trafficRef->getDepartureAirport()->getDynamics()) controller = trafficRef->getDepartureAirport()->getDynamics()->getStartupController(); @@ -755,10 +756,8 @@ void FGAIAircraft::processATC(const FGATCInstruction& instruction) { } } if (instruction.getChangeAltitude()) {} - } - void FGAIAircraft::handleFirstWaypoint() { bool eraseWaypoints; //TODO YAGNI headingError = 0; diff --git a/src/AIModel/AIAircraft.hxx b/src/AIModel/AIAircraft.hxx index 58d3fc5fb..7103c4c0a 100644 --- a/src/AIModel/AIAircraft.hxx +++ b/src/AIModel/AIAircraft.hxx @@ -81,6 +81,7 @@ public: const std::string& getCompany() const { return company; } void setCompany(const std::string& comp) { company = comp;}; +//ATC void announcePositionToController(); //TODO have to be public? void processATC(const FGATCInstruction& instruction); void setTaxiClearanceRequest(bool arg) { needsTaxiClearance = arg; }; diff --git a/src/ATC/ATCController.cxx b/src/ATC/ATCController.cxx index 188833c4d..691dd391b 100644 --- a/src/ATC/ATCController.cxx +++ b/src/ATC/ATCController.cxx @@ -79,6 +79,8 @@ FGATCController::~FGATCController() auto mgr = globals->get_subsystem(); mgr->removeController(this); } + _isDestroying = true; + clearTrafficControllers(); } void FGATCController::init() @@ -124,44 +126,28 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, int ground_to_air=0; //double commFreqD; - sender = rec->getAircraft()->getTrafficRef()->getCallSign(); + sender = rec->getCallsign(); if (rec->getAircraft()->getTaxiClearanceRequest()) { instructionText = "push-back and taxi"; } else { instructionText = "taxi"; } - + SG_LOG(SG_ATC, SG_DEBUG, "transmitting for: " << sender << "Leg = " << rec->getLeg()); auto depApt = rec->getAircraft()->getTrafficRef()->getDepartureAirport(); - //FIXME Must be transferred to controller and fallback for GROUND -> TOWER if GROUND not set - switch (rec->getLeg()) { - case 1: - 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; + if (!depApt) { + SG_LOG(SG_ATC, SG_DEV_ALERT, "TrafficRec has empty departure airport, can't transmit"); + return; } - + + 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 if (msgDir == ATC_GROUND_TO_AIR) { string tmp = sender; @@ -169,7 +155,7 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, receiver = tmp; ground_to_air = 1; } - + switch (msgId) { case MSG_ANNOUNCE_ENGINE_START: text = sender + ". Ready to Start up."; @@ -262,7 +248,7 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, if (rec->getAircraft()->getTaxiClearanceRequest()) { text = receiver + ". Push-back approved. " + sender + "."; } else { - text = receiver + ". Cleared to Taxi. " + sender + "."; + text = receiver + ". Cleared to Taxi. " + sender + "."; } break; case MSG_HOLD_PUSHBACK_CLEARANCE: @@ -306,6 +292,16 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, //text = "test2"; SG_LOG(SG_ATC, SG_DEBUG, "2 Currently at leg " << rec->getLeg()); 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: towerFreqStr = formatATCFrequency3_2(towerFreq); text = receiver + " Contact Tower at " + towerFreqStr + ". " + sender + "."; @@ -323,7 +319,7 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, text = text + sender + ". Transmitting unknown Message."; break; } - + const bool atcAudioEnabled = fgGetBool("/sim/sound/atc/enabled", false); if (audible && atcAudioEnabled) { double onBoardRadioFreq0 = @@ -333,35 +329,36 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, int onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 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); + if( stationFreq == 0 ) { + SG_LOG(SG_ATC, SG_DEBUG, getName() << " stationFreq not found"); + } // Display ATC message only when one of the radios is tuned // the relevant frequency. // Note that distance attenuation is currently not yet implemented - + if ((stationFreq > 0)&& ((onBoardRadioFreqI0 == stationFreq)|| (onBoardRadioFreqI1 == stationFreq))) { if (rec->allowTransmissions()) { - + if( fgGetBool( "/sim/radio/use-itm-attenuation", false ) ) { SG_LOG(SG_ATC, SG_DEBUG, "Using ITM radio propagation"); FGRadioTransmission* radio = new FGRadioTransmission(); SGGeod sender_pos; double sender_alt_ft, sender_alt; if(ground_to_air) { - sender_pos = parent->parent()->geod(); - } + sender_pos = parent->parent()->geod(); + } else { - sender_alt_ft = rec->getAltitude(); - sender_alt = sender_alt_ft * SG_FEET_TO_METER; - sender_pos= SGGeod::fromDegM( rec->getLongitude(), - rec->getLatitude(), sender_alt ); + sender_pos= rec->getPos(); } double frequency = ((double)stationFreq) / 100; radio->receiveATC(sender_pos, frequency, text, ground_to_air); delete radio; } else { + SG_LOG(SG_ATC, SG_BULK, "Transmitting " << text); 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 * @param freq - integer value @@ -402,32 +441,33 @@ string FGATCController::genTransponderCode(const string& fltRules) 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 true; - } - return traffic.getAircraft()->getDie(); + return traffic.isDead(); }); - 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) { - if (!traffic.getAircraft()) { - continue; - } + return std::find_if(activeTraffic.begin(), activeTraffic.end(), + [id] (const FGTrafficRecord& rec) + { 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; }); -} diff --git a/src/ATC/ATCController.hxx b/src/ATC/ATCController.hxx index 5d381a0eb..a58d73537 100644 --- a/src/ATC/ATCController.hxx +++ b/src/ATC/ATCController.hxx @@ -28,8 +28,7 @@ #include #include -// There is probably a better include than sg_geodesy to get the SG_NM_TO_METER... -#include +#include #include #include #include @@ -46,19 +45,25 @@ private: protected: + // guard variable to avoid modifying state during destruction + bool _isDestroying = false; bool initialized; bool available; time_t lastTransmission; + TrafficVector activeTraffic; double dt_count; osg::Group* group; + FGAirportDynamics *parent = nullptr; std::string formatATCFrequency3_2(int ); std::string genTransponderCode(const std::string& fltRules); bool isUserAircraft(FGAIAircraft*); - void clearTrafficControllers(TrafficVector& vec); - TrafficVectorIterator searchActiveTraffic(TrafficVector& vec, int id); - void eraseDeadTraffic(TrafficVector& vec); + void clearTrafficControllers(); + TrafficVectorIterator searchActiveTraffic(int id); + void eraseDeadTraffic(); + /**Returns the frequency to be used. */ + virtual int getFrequency() = 0; public: typedef enum { MSG_ANNOUNCE_ENGINE_START, @@ -81,6 +86,8 @@ public: MSG_ACKNOWLEDGE_RESUME_TAXI, MSG_REPORT_RUNWAY_HOLD_SHORT, MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT, + MSG_CLEARED_FOR_TAKEOFF, + MSG_ACKNOWLEDGE_CLEARED_FOR_TAKEOFF, MSG_SWITCH_TOWER_FREQUENCY, MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY } AtcMsgId; @@ -97,11 +104,19 @@ public: double lat, double lon, double hdg, double spd, double alt, double radius, int leg, FGAIAircraft *aircraft) = 0; - virtual void signOff(int id) = 0; virtual void updateAircraftInformation(int id, double lat, double lon, 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() { return dt_count; @@ -113,16 +128,10 @@ public: std::string getGateName(FGAIAircraft *aircraft); virtual void render(bool) = 0; virtual std::string getName() = 0; - virtual void update(double) = 0; -protected: - // guard variable to avoid modifying state during destruction - bool _isDestroying = false; - private: - AtcMsgDir lastTransmissionDirection; }; diff --git a/src/ATC/ApproachController.cxx b/src/ATC/ApproachController.cxx index 041d8cbea..9c97d693e 100644 --- a/src/ATC/ApproachController.cxx +++ b/src/ATC/ApproachController.cxx @@ -63,7 +63,7 @@ using std::string; * class FGApproachController * subclass of FGATCController **************************************************************************/ - + FGApproachController::FGApproachController(FGAirportDynamics *par): FGATCController() { @@ -72,8 +72,6 @@ FGApproachController::FGApproachController(FGAirportDynamics *par): FGApproachController::~FGApproachController() { - _isDestroying = true; - clearTrafficControllers(activeTraffic); } @@ -86,10 +84,10 @@ void FGApproachController::announcePosition(int id, int leg, FGAIAircraft * ref) { init(); - + // 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. if (i == activeTraffic.end() || activeTraffic.empty()) { FGTrafficRecord rec; @@ -98,7 +96,7 @@ void FGApproachController::announcePosition(int id, rec.setPositionAndHeading(lat, lon, heading, speed, alt); rec.setRunway(intendedRoute->getRunway()); rec.setLeg(leg); - //rec.setCallSign(callsign); + rec.setCallsign(ref->getCallSign()); rec.setAircraft(ref); activeTraffic.push_back(rec); } else { @@ -111,9 +109,9 @@ void FGApproachController::updateAircraftInformation(int id, double lat, double double dt) { // Search activeTraffic for a record matching our id - TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); + TrafficVectorIterator i = FGATCController::searchActiveTraffic(id); TrafficVectorIterator current; - + // update position of the current aircraft if (i == activeTraffic.end() || activeTraffic.empty()) { 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); current = i; SG_LOG(SG_ATC, SG_BULK, "ApproachController: checking for speed"); - time_t time_diff = - current->getAircraft()-> - checkForArrivalTime(string("final001")); - if (time_diff > 15) { - current->setSpeedAdjustment(current->getAircraft()-> - getPerformance()->vDescent() * - 1.35); - } else if (time_diff > 5) { - current->setSpeedAdjustment(current->getAircraft()-> - getPerformance()->vDescent() * - 1.2); - } else if (time_diff < -15) { - current->setSpeedAdjustment(current->getAircraft()-> - getPerformance()->vDescent() * - 0.65); - } else if (time_diff < -5) { - current->setSpeedAdjustment(current->getAircraft()-> - getPerformance()->vDescent() * - 0.8); - } else { - current->clearSpeedAdjustment(); + if(current->getAircraft()) { + //FIXME No call to aircraft! -> set instruction + time_t time_diff = + current->getAircraft()-> + checkForArrivalTime(string("final001")); + if (time_diff > 15) { + current->setSpeedAdjustment(current->getAircraft()-> + getPerformance()->vDescent() * + 1.35); + } else if (time_diff > 5) { + current->setSpeedAdjustment(current->getAircraft()-> + getPerformance()->vDescent() * + 1.2); + } else if (time_diff < -15) { + current->setSpeedAdjustment(current->getAircraft()-> + getPerformance()->vDescent() * + 0.65); + } else if (time_diff < -5) { + current->setSpeedAdjustment(current->getAircraft()-> + getPerformance()->vDescent() * + 0.8); + } else { + current->clearSpeedAdjustment(); + } + } //current->setSpeedAdjustment(current->getAircraft()->getPerformance()->vDescent() + time_diff); } 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 */ 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) @@ -228,5 +184,11 @@ void FGApproachController::render(bool visible) { } 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; } diff --git a/src/ATC/ApproachController.hxx b/src/ATC/ApproachController.hxx index 9bd52571a..5394e4d3a 100644 --- a/src/ATC/ApproachController.hxx +++ b/src/ATC/ApproachController.hxx @@ -28,8 +28,7 @@ #include #include -// There is probably a better include than sg_geodesy to get the SG_NM_TO_METER... -#include +#include #include #include #include @@ -38,28 +37,24 @@ #include /****************************************************************************** - * class FGTowerControl + * class FGApproachController *****************************************************************************/ class FGApproachController : public FGATCController { private: - TrafficVector activeTraffic; ActiveRunwayVec activeRunways; - FGAirportDynamics *parent; - + /**Returns the frequency to be used. */ + int getFrequency(); public: FGApproachController(FGAirportDynamics * parent); virtual ~FGApproachController(); - + virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, double lat, double lon, double hdg, double spd, double alt, 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 bool hasInstruction(int id); - virtual FGATCInstruction getInstruction(int id); virtual void render(bool); virtual std::string getName(); @@ -67,12 +62,6 @@ public: ActiveRunway* getRunway(const std::string& name); - bool hasActiveTraffic() { - return ! activeTraffic.empty(); - }; - TrafficVector &getActiveTraffic() { - return activeTraffic; - }; }; #endif diff --git a/src/ATC/GroundController.cxx b/src/ATC/GroundController.cxx index a71325108..1bf1040c3 100644 --- a/src/ATC/GroundController.cxx +++ b/src/ATC/GroundController.cxx @@ -67,31 +67,23 @@ using std::string; /*************************************************************************** * FGGroundController() **************************************************************************/ -FGGroundController::FGGroundController() : - parent(NULL) +FGGroundController::FGGroundController(FGAirportDynamics *par) { hasNetwork = false; count = 0; - currTraffic = activeTraffic.begin(); group = 0; version = 0; networkInitialized = false; + FGATCController::init(); + + parent = par; + hasNetwork = true; + networkInitialized = true; } 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) @@ -99,19 +91,6 @@ bool compare_trafficrecords(FGTrafficRecord a, FGTrafficRecord b) 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, FGAIFlightPlan * intendedRoute, 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 - TrafficVectorIterator i = searchActiveTraffic(id); - + TrafficVectorIterator i = FGATCController::searchActiveTraffic(id); + // Add a new TrafficRecord if none exists for this aircraft // otherwise set the information for the TrafficRecord if (i == activeTraffic.end() || (activeTraffic.empty())) { @@ -137,6 +116,7 @@ void FGGroundController::announcePosition(int id, rec.setPositionAndIntentions(currentPosition, intendedRoute); rec.setPositionAndHeading(lat, lon, heading, speed, alt); rec.setRadius(radius); // only need to do this when creating the record. + rec.setCallsign(aircraft->getCallSign()); rec.setAircraft(aircraft); // add to the front of the list of activeTraffic if the aircraft is already taxiing 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: * 0 = Normal; no action required @@ -200,11 +160,11 @@ bool FGGroundController::checkTransmissionState(int minState, int maxState, Traf //FGATCDialogNew::instance()->removeEntry(1); } else { 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; } } - transmit(&(*i), dynamics, msgId, msgDir, true); + transmit(&(*i), parent, msgId, msgDir, true); i->updateState(); lastTransmission = now; 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. // 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 if (i == activeTraffic.end() || activeTraffic.empty()) { SG_LOG(SG_GENERAL, SG_DEV_WARN, "AI error: updating aircraft without traffic record at " << SG_ORIGIN << ", id=" << id); return; } - + i->setPositionAndHeading(lat, lon, heading, speed, alt); TrafficVectorIterator current = i; - + setDt(getDt() + dt); // Update every three secs, but add some randomness @@ -302,7 +262,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat, TrafficVectorIterator current, closest, closestOnNetwork; bool otherReasonToSlowDown = false; // bool previousInstruction; - TrafficVectorIterator i = searchActiveTraffic(id); + TrafficVectorIterator i = FGATCController::searchActiveTraffic(id); if (!activeTraffic.size()) { return; } @@ -315,7 +275,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat, // previousInstruction = current->getSpeedAdjustment(); double mindist = HUGE_VAL; - + // First check all our activeTraffic if (activeTraffic.size()) { double course, dist, bearing, az2; // minbearing, @@ -329,9 +289,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat, continue; } - SGGeod other(SGGeod::fromDegM(i->getLongitude(), - i->getLatitude(), - i->getAltitude())); + SGGeod other = i->getPos(); SGGeodesy::inverse(curr, other, course, az2, dist); bearing = fabs(heading - course); if (bearing > 180) @@ -343,16 +301,14 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat, // minbearing = bearing; } } - + // Next check with the tower controller if (towerController->hasActiveTraffic()) { for (TrafficVectorIterator i = towerController->getActiveTraffic().begin(); i != towerController->getActiveTraffic().end(); i++) { SG_LOG(SG_ATC, SG_BULK, "Comparing " << current->getId() << " and " << i->getId()); - SGGeod other(SGGeod::fromDegM(i->getLongitude(), - i->getLatitude(), - i->getAltitude())); + SGGeod other = i->getPos(); SGGeodesy::inverse(curr, other, course, az2, dist); bearing = fabs(heading - course); if (bearing > 180) @@ -368,7 +324,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat, } } } - + // Finally, check UserPosition // 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; } */ - + // Clear any active speed adjustment, check if the aircraft needs to brake current->clearSpeedAdjustment(); bool needBraking = false; - + if (current->checkPositionAndIntentions(*closest) || otherReasonToSlowDown) { double maxAllowableDistance = @@ -402,7 +358,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat, return; else current->setWaitsForId(closest->getId()); - + if (closest->getId() != current->getId()) { current->setSpeedAdjustment(closest->getSpeed() * (mindist / 100)); @@ -417,7 +373,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat, } else { current->setSpeedAdjustment(0); // This can only happen when the user aircraft is the one closest } - + if (mindist < maxAllowableDistance) { //double newSpeed = (maxAllowableDistance-mindist); //current->setSpeedAdjustment(newSpeed); @@ -428,7 +384,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat, } } } - + if ((closest->getId() == closestOnNetwork->getId()) && (current->getPriority() < closest->getPriority()) && needBraking) { swap(current, closest); } @@ -447,7 +403,7 @@ void FGGroundController::checkHoldPosition(int id, double lat, double lon, double heading, double speed, double alt) { - FGGroundNetwork* network = dynamics->parent()->groundNetwork(); + FGGroundNetwork* network = parent->parent()->groundNetwork(); TrafficVectorIterator current; TrafficVectorIterator i = activeTraffic.begin(); if (activeTraffic.size()) { @@ -499,7 +455,7 @@ void FGGroundController::checkHoldPosition(int id, double lat, //if (tx->hasBlock(now) || nx->hasBlock(now) ) { // current->setHoldPosition(true); //} - SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude()))); + SGGeod start = i->getPos(); SGGeod end (nx->getStart()->geod()); double distance = SGGeodesy::distanceM(start, end); @@ -530,11 +486,11 @@ void FGGroundController::checkHoldPosition(int id, double lat, if ((origStatus != currStatus) && available) { SG_LOG(SG_ATC, SG_DEBUG, "Issuing hold short instruction " << currStatus << " " << available); 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); current->setState(1); } 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); 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. static void WorldCoordinate(osg::Matrix& obj_pos, double lat, 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) { SGMaterialLib *matlib = globals->get_matlib(); - FGGroundNetwork* network = dynamics->parent()->groundNetwork(); + FGGroundNetwork* network = parent->parent()->groundNetwork(); if (group) { //int nr = ; @@ -745,7 +672,7 @@ void FGGroundController::render(bool visible) const int pos = i->getCurrentPosition(); if (pos > 0) { FGTaxiSegment* segment = network->findSegment(pos); - SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude()))); + SGGeod start = i->getPos(); SGGeod end (segment->getEnd()->geod()); double length = SGGeodesy::distanceM(start, end); @@ -903,17 +830,17 @@ void FGGroundController::render(bool visible) } string FGGroundController::getName() { - return string(parent->getId() + "-ground"); + return string(parent->parent()->getName() + "-ground"); } void FGGroundController::update(double dt) { time_t now = globals->get_time_params()->get_cur_time(); - FGGroundNetwork* network = dynamics->parent()->groundNetwork(); + FGGroundNetwork* network = parent->parent()->groundNetwork(); network->unblockAllSegments(now); int priority = 1; - TrafficVector& startupTraffic(dynamics->getStartupController()->getActiveTraffic()); + TrafficVector& startupTraffic(parent->getStartupController()->getActiveTraffic()); TrafficVectorIterator i; //sort(activeTraffic.begin(), activeTraffic.end(), compare_trafficrecords); @@ -927,8 +854,9 @@ void FGGroundController::update(double dt) updateActiveTraffic(i, priority, now); } - FGATCController::eraseDeadTraffic(startupTraffic); - FGATCController::eraseDeadTraffic(activeTraffic); + //FIXME + //FGATCController::eraseDeadTraffic(startupTraffic); + FGATCController::eraseDeadTraffic(); } void FGGroundController::updateStartupTraffic(TrafficVectorIterator i, @@ -953,7 +881,7 @@ void FGGroundController::updateStartupTraffic(TrafficVectorIterator i, return; } - FGGroundNetwork* network = dynamics->parent()->groundNetwork(); + FGGroundNetwork* network = parent->parent()->groundNetwork(); if (!network) { SG_LOG(SG_ATC, SG_ALERT, "updateStartupTraffic: missing ground network"); @@ -1021,7 +949,7 @@ bool FGGroundController::updateActiveTraffic(TrafficVectorIterator i, double length = 0; double vTaxi = (i->getAircraft()->getPerformance()->vTaxi() * SG_NM_TO_METER) / 3600; - FGGroundNetwork* network = dynamics->parent()->groundNetwork(); + FGGroundNetwork* network = parent->parent()->groundNetwork(); if (!network) { SG_LOG(SG_ATC, SG_ALERT, "updateActiveTraffic: missing ground network"); @@ -1038,7 +966,7 @@ bool FGGroundController::updateActiveTraffic(TrafficVectorIterator i, } } - + intVecIterator ivi; for (ivi = i->getIntentions().begin(); ivi != i->getIntentions().end(); 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. for (intVecIterator j = i->getIntentions().begin(); j != ivi; j++) { int pos = (*j); @@ -1063,3 +991,9 @@ bool FGGroundController::updateActiveTraffic(TrafficVectorIterator i, return true; } + +int FGGroundController::getFrequency() { + int groundFreq = parent->getGroundFrequency(2); + int towerFreq = parent->getTowerFrequency(2); + return groundFreq>0?groundFreq:towerFreq; +} diff --git a/src/ATC/GroundController.hxx b/src/ATC/GroundController.hxx index 2481de733..328c3b629 100644 --- a/src/ATC/GroundController.hxx +++ b/src/ATC/GroundController.hxx @@ -32,7 +32,7 @@ class FGAirportDynamics; /************************************************************************************** - * class FGGroundNetWork + * class FGGroundController *************************************************************************************/ class FGGroundController : public FGATCController { @@ -42,14 +42,10 @@ private: bool networkInitialized; int count; int version; - - - TrafficVector activeTraffic; - TrafficVectorIterator currTraffic; FGTowerController *towerController; - FGAirport *parent; - FGAirportDynamics* dynamics; + /**Returns the frequency to be used. */ + int getFrequency(); void checkSpeedAdjustment(int id, double lat, double lon, @@ -61,13 +57,12 @@ private: void updateStartupTraffic(TrafficVectorIterator i, int& priority, time_t now); bool updateActiveTraffic(TrafficVectorIterator i, int& priority, time_t now); public: - FGGroundController(); + FGGroundController(FGAirportDynamics *par); ~FGGroundController(); - + void setVersion (int v) { version = v;}; int getVersion() { return version; }; - void init(FGAirportDynamics* pr); bool exists() { return hasNetwork; }; @@ -76,14 +71,10 @@ public: }; - virtual TrafficVectorIterator searchActiveTraffic(int id); virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, double lat, double lon, double hdg, double spd, double alt, 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 bool hasInstruction(int id); - virtual FGATCInstruction getInstruction(int id); bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId, AtcMsgDir msgDir); diff --git a/src/ATC/StartupController.cxx b/src/ATC/StartupController.cxx index 068ec9d43..fb6da561e 100644 --- a/src/ATC/StartupController.cxx +++ b/src/ATC/StartupController.cxx @@ -71,8 +71,6 @@ FGStartupController::FGStartupController(FGAirportDynamics *par): FGStartupController::~FGStartupController() { - _isDestroying = true; - clearTrafficControllers(activeTraffic); } void FGStartupController::announcePosition(int id, @@ -85,8 +83,8 @@ void FGStartupController::announcePosition(int id, { init(); // 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. if (i == activeTraffic.end() || activeTraffic.empty()) { FGTrafficRecord rec; @@ -96,7 +94,7 @@ void FGStartupController::announcePosition(int id, rec.setRunway(intendedRoute->getRunway()); rec.setLeg(leg); rec.setPositionAndIntentions(currentPosition, intendedRoute); - //rec.setCallSign(callsign); + rec.setCallsign(ref->getCallSign()); rec.setAircraft(ref); rec.setHoldPosition(true); 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, AtcMsgDir msgDir) { @@ -198,9 +143,9 @@ void FGStartupController::updateAircraftInformation(int id, double lat, double l double dt) { // Search activeTraffic for a record matching our id - TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); + TrafficVectorIterator i = FGATCController::searchActiveTraffic(id); TrafficVectorIterator current, closest; - + if (i == activeTraffic.end() || (activeTraffic.size() == 0)) { SG_LOG(SG_ATC, SG_ALERT, "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 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 - << " at parking " << getGateName(i->getAircraft())); + + if ((startTime - now) > 0) { + 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)) { available = true; @@ -317,7 +263,7 @@ void FGStartupController::render(bool visible) SG_LOG(SG_ATC, SG_BULK, "rendering for " << i->getAircraft()->getCallSign() << "pos = " << pos); if (pos > 0) { FGTaxiSegment *segment = groundNet->findSegment(pos); - SGGeod start(SGGeod::fromDeg((i->getLongitude()), (i->getLatitude()))); + SGGeod start = i->getPos(); SGGeod end (segment->getEnd()->geod()); double length = SGGeodesy::distanceM(start, end); @@ -480,11 +426,17 @@ void FGStartupController::render(bool visible) } string FGStartupController::getName() { - return string(parent->getId() + "-startup"); + return string(parent->parent()->getName() + "-Startup"); } 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; } diff --git a/src/ATC/StartupController.hxx b/src/ATC/StartupController.hxx index 47daf96dd..29d608972 100644 --- a/src/ATC/StartupController.hxx +++ b/src/ATC/StartupController.hxx @@ -28,8 +28,7 @@ #include #include -// There is probably a better include than sg_geodesy to get the SG_NM_TO_METER... -#include +#include #include #include #include @@ -45,9 +44,8 @@ class FGStartupController : public FGATCController { private: - TrafficVector activeTraffic; - //ActiveRunwayVec activeRunways; - FGAirportDynamics *parent; + /**Returns the frequency to be used. */ + int getFrequency(); public: FGStartupController(FGAirportDynamics *parent); @@ -57,23 +55,13 @@ public: double lat, double lon, double hdg, double spd, double alt, 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 bool hasInstruction(int id); - virtual FGATCInstruction getInstruction(int id); virtual void render(bool); virtual std::string getName(); 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. bool checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId, AtcMsgDir msgDir); diff --git a/src/ATC/TowerController.cxx b/src/ATC/TowerController.cxx index 890a3ae1f..059727ce2 100644 --- a/src/ATC/TowerController.cxx +++ b/src/ATC/TowerController.cxx @@ -63,7 +63,7 @@ using std::string; * class FGTowerController s * subclass of FGATCController **************************************************************************/ - + FGTowerController::FGTowerController(FGAirportDynamics *par) : FGATCController() { @@ -72,8 +72,6 @@ FGTowerController::FGTowerController(FGAirportDynamics *par) : FGTowerController::~FGTowerController() { - _isDestroying = true; - clearTrafficControllers(activeTraffic); } // @@ -86,10 +84,10 @@ void FGTowerController::announcePosition(int id, FGAIAircraft * ref) { init(); - + // 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. if (i == activeTraffic.end() || (activeTraffic.empty())) { FGTrafficRecord rec; @@ -132,8 +130,8 @@ void FGTowerController::updateAircraftInformation(int id, double lat, double lon double dt) { // Search activeTraffic for a record matching our id - TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); - + TrafficVectorIterator i = FGATCController::searchActiveTraffic(id); + setDt(getDt() + dt); 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 // 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. - + ActiveRunwayVecIterator rwy = activeRunways.begin(); //if (parent->getId() == fgGetString("/sim/presets/airport-id")) { // for (rwy = activeRunways.begin(); rwy != activeRunways.end(); rwy++) { // rwy->printdepartureQueue(); // } //} - + rwy = activeRunways.begin(); while (rwy != activeRunways.end()) { if (rwy->getRunwayName() == current.getRunway()) { @@ -186,9 +184,11 @@ void FGTowerController::updateAircraftInformation(int id, double lat, double lon if (ac->getTakeOffStatus() == 1) { // transmit takeoff clearance 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) { current.setHoldPosition(false); } else { @@ -208,7 +208,7 @@ void FGTowerController::updateAircraftInformation(int id, double lat, double lon // transmit takeoff clearacne? But why twice? } } -} +} void FGTowerController::signOff(int id) @@ -218,7 +218,7 @@ void FGTowerController::signOff(int id) return; // Search activeTraffic for a record matching our id - TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); + TrafficVectorIterator i = FGATCController::searchActiveTraffic(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); @@ -240,8 +240,7 @@ void FGTowerController::signOff(int id) } i->getAircraft()->resetTakeOffStatus(); - activeTraffic.erase(i); - SG_LOG(SG_ATC, SG_DEBUG, "Signing off from tower controller"); + FGATCController::signOff(id); } // NOTE: @@ -253,8 +252,8 @@ void FGTowerController::signOff(int id) bool FGTowerController::hasInstruction(int 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()) { SG_LOG(SG_ATC, SG_ALERT, "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) { // Search activeTraffic for a record matching our id - TrafficVectorIterator i = searchActiveTraffic(activeTraffic, id); - + TrafficVectorIterator i = FGATCController::searchActiveTraffic(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); @@ -290,5 +289,10 @@ string FGTowerController::getName() { void FGTowerController::update(double dt) { - FGATCController::eraseDeadTraffic(activeTraffic); + FGATCController::eraseDeadTraffic(); +} + +int FGTowerController::getFrequency() { + int towerFreq = parent->getTowerFrequency(2); + return towerFreq; } diff --git a/src/ATC/TowerController.hxx b/src/ATC/TowerController.hxx index 670fcd216..4199d37c7 100644 --- a/src/ATC/TowerController.hxx +++ b/src/ATC/TowerController.hxx @@ -28,8 +28,7 @@ #include #include -// There is probably a better include than sg_geodesy to get the SG_NM_TO_METER... -#include +#include #include #include #include @@ -43,9 +42,9 @@ class FGTowerController : public FGATCController { private: - TrafficVector activeTraffic; ActiveRunwayVec activeRunways; - FGAirportDynamics *parent; + /**Returns the frequency to be used. */ + int getFrequency(); public: FGTowerController(FGAirportDynamics *parent); @@ -55,21 +54,15 @@ public: double lat, double lon, double hdg, double spd, double alt, double radius, int leg, 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, double heading, double speed, double alt, double dt); - virtual bool hasInstruction(int id); - virtual FGATCInstruction getInstruction(int id); virtual void render(bool); virtual std::string getName(); virtual void update(double dt); - bool hasActiveTraffic() { - return ! activeTraffic.empty(); - }; - TrafficVector &getActiveTraffic() { - return activeTraffic; - }; }; #endif \ No newline at end of file diff --git a/src/ATC/atc_mgr.cxx b/src/ATC/atc_mgr.cxx index 509c847f3..f060e40d3 100644 --- a/src/ATC/atc_mgr.cxx +++ b/src/ATC/atc_mgr.cxx @@ -334,7 +334,7 @@ void FGATCManager::update ( double time ) { } #if 0 // 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++) { int val = fp->getRouteIndex(i); SG_LOG(SG_ATC, SG_BULK, fp->getWayPoint(i)->getName() << " "); diff --git a/src/ATC/trafficcontrol.cxx b/src/ATC/trafficcontrol.cxx index 92c23e24e..0f2fa086f 100644 --- a/src/ATC/trafficcontrol.cxx +++ b/src/ATC/trafficcontrol.cxx @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -58,7 +59,7 @@ using std::string; /*************************************************************************** * ActiveRunway **************************************************************************/ - + ActiveRunway::ActiveRunway(const std::string& r, int cc) : rwy(r) { @@ -87,7 +88,7 @@ time_t ActiveRunway::requestTimeSlot(time_t eta) // time_t separation = 120; //} bool found = false; - + // if the aircraft is the first arrival, add to the vector and return eta directly if (estimatedArrivalTimes.empty()) { 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 TimeVectorIterator i = estimatedArrivalTimes.begin(); SG_LOG(SG_ATC, SG_DEBUG, "Checking eta slots " << eta << ": "); - + // is this needed - just a debug output? for (i = estimatedArrivalTimes.begin(); i != estimatedArrivalTimes.end(); i++) { SG_LOG(SG_ATC, SG_BULK, "Stored time : " << (*i)); } - + // if the flight is before the first scheduled slot + separation i = estimatedArrivalTimes.begin(); if ((eta + separation) < (*i)) { @@ -113,11 +114,11 @@ time_t ActiveRunway::requestTimeSlot(time_t eta) slotHousekeeping(newEta); return newEta; } - + // else, look through the rest of the slots while ((i != estimatedArrivalTimes.end()) && (!found)) { TimeVectorIterator j = i + 1; - + // if the flight is after the last scheduled slot check if separation is needed if (j == estimatedArrivalTimes.end()) { if (((*i) + separation) < eta) { @@ -180,7 +181,7 @@ void ActiveRunway::slotHousekeeping(time_t newEta) // add the slot to the vector and resort the vector estimatedArrivalTimes.push_back(newEta); sort(estimatedArrivalTimes.begin(), estimatedArrivalTimes.end()); - + // do some housekeeping : remove any slots that are past 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->_getLatitude() << " " << acft->_getLongitude() << acft->getSpeed() << " " << acft->getAltitude()); } - + } /* Fetch the first aircraft in the departure cue with a certain status */ @@ -213,11 +214,11 @@ SGSharedPtrActiveRunway::getFirstOfStatus(int stat) const auto it = std::find_if(departureQueue.begin(), departureQueue.end(), [stat](const SGSharedPtr& acft) { return acft->getTakeOffStatus() == stat; }); - + if (it == departureQueue.end()) { return {}; } - + return *it; } @@ -226,7 +227,7 @@ SGSharedPtr ActiveRunway::getFirstAircraftInDepartureQueue() const if (departureQueue.empty()) { return {}; } - + return departureQueue.front(); }; @@ -241,7 +242,7 @@ void ActiveRunway::addToDepartureQueue(FGAIAircraft *ac) /*************************************************************************** * FGTrafficRecord **************************************************************************/ - + FGTrafficRecord::FGTrafficRecord(): id(0), waitsForId(0), currentPos(0), @@ -252,7 +253,7 @@ FGTrafficRecord::FGTrafficRecord(): allowPushback(true), priority(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; } -FGAIAircraft* FGTrafficRecord::getAircraft() const -{ - return aircraft.ptr(); -} +bool FGTrafficRecord::isDead() const { + if (!aircraft) { + 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 * @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 alt) { - latitude = lat; - longitude = lon; + this->pos = SGGeod::fromDegFt(lon, lat, alt); heading = hdg; speed = spd; altitude = alt; @@ -504,7 +519,7 @@ bool FGTrafficRecord::isActive(int margin) const if (aircraft->getDie()) { return false; } - + time_t now = globals->get_time_params()->get_cur_time(); time_t deptime = aircraft->getTrafficRef()->getDepartureTime(); return ((now + margin) > deptime); @@ -532,9 +547,9 @@ bool FGTrafficRecord::pushBackAllowed() const /*************************************************************************** * FGATCInstruction - * + * **************************************************************************/ - + FGATCInstruction::FGATCInstruction() { holdPattern = false; diff --git a/src/ATC/trafficcontrol.hxx b/src/ATC/trafficcontrol.hxx index be10cf0d2..6bf7ac786 100644 --- a/src/ATC/trafficcontrol.hxx +++ b/src/ATC/trafficcontrol.hxx @@ -75,7 +75,7 @@ private: double alt; public: FGATCInstruction(); - + bool hasInstruction () const; bool getHoldPattern () const { return holdPattern; @@ -95,7 +95,7 @@ public: bool getCheckForCircularWait() const { return resolveCircularWait; }; - + double getSpeed () const { return speed; }; @@ -124,7 +124,7 @@ public: void setResolveCircularWait (bool val) { resolveCircularWait = val; }; - + void setSpeed (double val) { speed = val; }; @@ -142,11 +142,12 @@ public: /************************************************************************************** * class FGTrafficRecord + * Represents the interaction of an AI Aircraft and ATC *************************************************************************************/ class FGTrafficRecord { private: - int id; + int id; int waitsForId; int currentPos; int leg; @@ -158,7 +159,9 @@ private: time_t timer; intVec intentions; FGATCInstruction instruction; - double latitude, longitude, heading, speed, altitude, radius; + SGGeod pos; + double heading, speed, altitude, radius; + std::string callsign; std::string runway; SGSharedPtr aircraft; @@ -192,15 +195,17 @@ public: FGATCInstruction getInstruction() const { return instruction; }; - bool hasInstruction() { + bool hasInstruction() const { return instruction.hasInstruction(); }; void setPositionAndHeading(double lat, double lon, double hdg, double spd, double alt); bool checkPositionAndIntentions(FGTrafficRecord &other); int crosses (FGGroundNetwork *, FGTrafficRecord &other); bool isOpposing (FGGroundNetwork *, FGTrafficRecord &other, int node); - + bool isActive(int margin) const; + bool isDead() const; + void clearATCController() const; bool onRoute(FGGroundNetwork *, FGTrafficRecord &other); @@ -208,19 +213,16 @@ public: return instruction.getChangeSpeed(); }; - double getLatitude () const { - return latitude ; - }; - double getLongitude() const { - return longitude; - }; + SGGeod getPos() { + return pos; + } double getHeading () const { return heading ; }; double getSpeed () const { return speed ; }; - double getAltitude () const { + double getFAltitude () const { return altitude ; }; double getRadius () const { @@ -261,10 +263,15 @@ public: instruction.setResolveCircularWait(false); }; + void setCallsign(std::string clsgn) { callsign = clsgn; }; + const std::string& getCallsign() const { + return callsign; + }; + const std::string& getRunway() const { return runway; }; - //void setCallSign(string clsgn) { callsign = clsgn; }; + void setAircraft(FGAIAircraft *ref); void updateState() { @@ -323,7 +330,7 @@ private: int currentlyCleared; double distanceToFinal; TimeVector estimatedArrivalTimes; - + using AircraftRefVec = std::vector>; AircraftRefVec departureQueue; @@ -356,13 +363,13 @@ public: int getdepartureQueueSize() { return departureQueue.size(); }; - + SGSharedPtr getFirstAircraftInDepartureQueue() const; - + SGSharedPtr getFirstOfStatus(int stat) const; - + void updateDepartureQueue(); - + void printDepartureQueue(); }; diff --git a/src/Airports/dynamics.cxx b/src/Airports/dynamics.cxx index 9234d00c7..55444b29f 100644 --- a/src/Airports/dynamics.cxx +++ b/src/Airports/dynamics.cxx @@ -86,7 +86,7 @@ public: unsigned int refCount; FGParkingRef parking; - + // we don't want an owning ref here, otherwise we // have a circular ownership from AirportDynamics -> us SGWeakPtr dynamics; @@ -215,6 +215,7 @@ FGAirportDynamics::FGAirportDynamics(FGAirport * ap): startupController (this), towerController (this), approachController (this), + groundController (this), atisSequenceIndex(-1), atisSequenceTimeStamp(0.0) @@ -232,7 +233,7 @@ FGAirportDynamics::~FGAirportDynamics() void FGAirportDynamics::init() { groundController.setTowerController(&towerController); - groundController.init(this); + groundController.init(); } 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){ if (parking->name() != name) return false; - + return this->isParkingAvailable(parking); }); - + if (it == parkings.end()) return {}; // no assignment possible - + return {*it, this}; } @@ -812,7 +813,7 @@ bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType, if (!landing.empty()) { runway = chooseRwyByHeading(landing, heading); } - + if (runway.empty()) { //fallback 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 // 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) { //return freqGround.size() ? freqGround[0] : 0; }; diff --git a/src/Airports/dynamics.hxx b/src/Airports/dynamics.hxx index 670f2a52d..4a7a31c17 100644 --- a/src/Airports/dynamics.hxx +++ b/src/Airports/dynamics.hxx @@ -42,16 +42,16 @@ class ParkingAssignment public: ParkingAssignment(); ~ParkingAssignment(); - + // create a parking assignment (and mark it as unavailable) ParkingAssignment(FGParking* pk, FGAirportDynamics* apt); - + ParkingAssignment(const ParkingAssignment& aOther); void operator=(const ParkingAssignment& aOther); - + bool isValid() const; FGParking* parking() const; - + void release(); private: void clear(); @@ -107,13 +107,13 @@ public: virtual ~FGAirportDynamics(); void init(); - + double getElevation() const; const std::string getId() const; - + FGAirport* parent() const { return _ap; } - + void getActiveRunway( const std::string& trafficType, int action, std::string& runway, @@ -131,9 +131,9 @@ public: const std::string& acType, const std::string& airline); void setParkingAvailable(FGParking* park, bool available); - + bool isParkingAvailable(FGParking* parking) const; - + void releaseParking(FGParking* id); FGParkingList getParkings(bool onlyAvailable, const std::string& type) const; @@ -150,7 +150,7 @@ public: * availabiity (i.e try them all) */ ParkingAssignment getAvailableParkingByName(const std::string & name); - + FGParkingRef getOccupiedParkingByName(const std::string& name) const; // ATC related functions. @@ -167,6 +167,7 @@ public: return &approachController; }; + int getApproachFrequency (unsigned nr); int getGroundFrequency(unsigned leg); int getTowerFrequency (unsigned nr); diff --git a/src/Airports/groundnetwork.cxx b/src/Airports/groundnetwork.cxx index d4d590149..1193821b1 100644 --- a/src/Airports/groundnetwork.cxx +++ b/src/Airports/groundnetwork.cxx @@ -250,13 +250,13 @@ FGTaxiNodeRef FGGroundNetwork::findNearestNodeOffRunway(const SGGeod& aGeod, FGR [runwayLine, cartPos, marginMSqr] (const FGTaxiNodeRef& a) { if (a->getIsOnRunway()) return false; - + // exclude parking positions from consideration. This helps to // exclude airports whose ground nets only list parking positions, // since these typically produce bad results. See discussion in // https://sourceforge.net/p/flightgear/codetickets/2110/ if (a->type() == FGPositioned::PARKING) return false; - + return (distSqr(runwayLine, a->cart()) >= marginMSqr); }); @@ -564,7 +564,10 @@ FGTaxiSegment* FGGroundNetwork::findSegmentByHeading(const FGTaxiNode* from, con return best; // not found } - +const intVec& FGGroundNetwork::getApproachFrequencies() const +{ + return freqApproach; +} const intVec& FGGroundNetwork::getTowerFrequencies() const { diff --git a/src/Airports/groundnetwork.hxx b/src/Airports/groundnetwork.hxx index 90a0c4395..27ae53fdf 100644 --- a/src/Airports/groundnetwork.hxx +++ b/src/Airports/groundnetwork.hxx @@ -63,7 +63,7 @@ private: // the ground-network owns the nodes const FGTaxiNode* startNode; const FGTaxiNode* endNode; - + bool isActive; BlockList blockTimes; @@ -73,26 +73,26 @@ private: friend class FGGroundNetwork; public: FGTaxiSegment(FGTaxiNode* start, FGTaxiNode* end); - + void setIndex (int val) { index = val; }; - + void setDimensions(double elevation); 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); FGTaxiNodeRef getEnd() const; FGTaxiNodeRef getStart() const; - + double getLength() const; - + // compute the center of the arc SGGeod getCenter() const; - + double getHeading() const; - + int getIndex() { return index; }; @@ -154,7 +154,7 @@ public: return nodes.empty(); }; bool next(FGTaxiNodeRef& nde, int *rte); - + void first() { currNode = nodes.begin(); currRoute = routes.begin(); @@ -179,7 +179,7 @@ private: bool networkInitialized; int version; - + FGTaxiSegmentVector segments; FGAirport *parent; @@ -234,7 +234,7 @@ private: public: FGGroundNetwork(FGAirport* pr); ~FGGroundNetwork(); - + void setVersion (int v) { version = v;}; int getVersion() { return version; }; @@ -274,7 +274,7 @@ public: */ FGTaxiNodeVector findSegmentsFrom(const FGTaxiNodeRef& from) const; - + FGTaxiRoute findShortestRoute(FGTaxiNode* start, FGTaxiNode* end, bool fullSearch=true); @@ -284,9 +284,10 @@ public: void addVersion(int v) {version = v; }; void unblockAllSegments(time_t now); + const intVec& getApproachFrequencies() const; const intVec& getTowerFrequencies() const; const intVec& getGroundFrequencies() const; - + }; diff --git a/test_suite/unit_tests/AI/TestSuite.cxx b/test_suite/unit_tests/AI/TestSuite.cxx index 20905e73a..006a9eecc 100644 --- a/test_suite/unit_tests/AI/TestSuite.cxx +++ b/test_suite/unit_tests/AI/TestSuite.cxx @@ -28,6 +28,6 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(AIFlightPlanTests, "Unit tests"); CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(AIManagerTests, "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(SubmodelsTests, "Unit tests"); diff --git a/test_suite/unit_tests/AI/test_traffic.cxx b/test_suite/unit_tests/AI/test_traffic.cxx index a37180ab1..0d7e0be61 100644 --- a/test_suite/unit_tests/AI/test_traffic.cxx +++ b/test_suite/unit_tests/AI/test_traffic.cxx @@ -73,6 +73,8 @@ void TrafficTests::setUp() fgSetBool("/environment/realwx/enabled", false); fgSetBool("/environment/metar/valid", 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);