1
0
Fork 0
* Added Messages for Takeoff
* Added Messages for Hold & Holdpatterns
* More enums instead of Magic Numbers
This commit is contained in:
portree_kid 2022-12-29 22:21:23 +01:00
parent 11eca7825d
commit 3667e5de3c
16 changed files with 400 additions and 252 deletions

View file

@ -69,10 +69,10 @@ FGAIAircraft::FGAIAircraft(FGAISchedule* ref) : /* HOT must be disabled for AI A
groundOffset = 0; groundOffset = 0;
} }
fp = 0; fp = nullptr;
controller = 0; controller = nullptr;
prevController = 0; prevController = nullptr;
towerController = 0; towerController = nullptr;
dt_count = 0; dt_count = 0;
dt_elev_count = 0; dt_elev_count = 0;
use_perf_vs = true; use_perf_vs = true;
@ -604,11 +604,13 @@ bool FGAIAircraft::loadNextLeg(double distance) {
} else { } else {
double cruiseAlt = trafficRef->getCruiseAlt() * 100; double cruiseAlt = trafficRef->getCruiseAlt() * 100;
SG_LOG(SG_AI, SG_BULK, getCallSign() << "|Loading Leg " << leg+1); int nextLeg = determineNextLeg(leg);
SG_LOG(SG_AI, SG_BULK, getCallSign() << "|Loading Leg " << nextLeg);
bool ok = fp->create (this, bool ok = fp->create (this,
dep, dep,
arr, arr,
leg+1, nextLeg,
cruiseAlt, cruiseAlt,
trafficRef->getSpeed(), trafficRef->getSpeed(),
_getLatitude(), _getLatitude(),
@ -721,10 +723,10 @@ void FGAIAircraft::announcePositionToController() {
} }
break; break;
case AILeg::APPROACH: case AILeg::APPROACH:
if (trafficRef->getArrivalAirport()->getDynamics()) { if (trafficRef->getArrivalAirport()->getDynamics()) {
controller = trafficRef->getArrivalAirport()->getDynamics()->getApproachController(); controller = trafficRef->getArrivalAirport()->getDynamics()->getApproachController();
} }
break; break;
case AILeg::PARKING_TAXI: // Taxiing for parking case AILeg::PARKING_TAXI: // Taxiing for parking
if (trafficRef->getArrivalAirport()->getDynamics()->getGroundController()->exists()) if (trafficRef->getArrivalAirport()->getDynamics()->getGroundController()->exists())
controller = trafficRef->getArrivalAirport()->getDynamics()->getGroundController(); controller = trafficRef->getArrivalAirport()->getDynamics()->getGroundController();
@ -749,7 +751,7 @@ void FGAIAircraft::announcePositionToController() {
} }
} }
void FGAIAircraft::scheduleForATCTowerDepartureControl(int state) { void FGAIAircraft::scheduleForATCTowerDepartureControl() {
if (!takeOffStatus) { if (!takeOffStatus) {
int leg = fp->getLeg(); int leg = fp->getLeg();
if (trafficRef) { if (trafficRef) {
@ -765,7 +767,7 @@ void FGAIAircraft::scheduleForATCTowerDepartureControl(int state) {
} }
} }
} }
takeOffStatus = state; takeOffStatus = AITakeOffStatus::QUEUED;
} }
// Process ATC instructions and report back // Process ATC instructions and report back
@ -782,7 +784,17 @@ void FGAIAircraft::processATC(const FGATCInstruction& instruction) {
// let an offending aircraft take an evasive action // let an offending aircraft take an evasive action
// for instance taxi back a little bit. // for instance taxi back a little bit.
} }
if (instruction.getHoldPattern ()) {} switch (fp->getLeg())
{
case AILeg::STARTUP_PUSHBACK:
case AILeg::APPROACH:
break;
default:
break;
}
if (instruction.getHoldPattern ()) {
//holdtime = instruction.getHoldTime();
}
// Hold Position // Hold Position
if (instruction.getHoldPosition ()) { if (instruction.getHoldPosition ()) {
@ -1048,11 +1060,14 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIWaypoint* prev, time_t now) {
AccelTo(0.0); AccelTo(0.0);
} }
if (prev->contains("legend")) { if (prev->contains("legend")) {
fp->incrementLeg(); int nextLeg = determineNextLeg(fp->getLeg());
while (nextLeg!=fp->getLeg()) {
fp->incrementLeg();
}
} }
if (prev->contains(string("DepartureHold"))) { if (prev->contains(string("DepartureHold"))) {
//cerr << "Passing point DepartureHold" << endl; //cerr << "Passing point DepartureHold" << endl;
scheduleForATCTowerDepartureControl(1); scheduleForATCTowerDepartureControl();
} }
if (prev->contains(string("Accel"))) { if (prev->contains(string("Accel"))) {
takeOffStatus = AITakeOffStatus::CLEARED_FOR_TAKEOFF; takeOffStatus = AITakeOffStatus::CLEARED_FOR_TAKEOFF;
@ -1387,6 +1402,20 @@ const string& FGAIAircraft::atGate()
return empty; return empty;
} }
int FGAIAircraft::determineNextLeg(int leg) {
if (leg==AILeg::APPROACH) {
time_t now = globals->get_time_params()->get_cur_time();
if (controller->getInstruction(getID()).getRunwaySlot()
> now) {
return AILeg::HOLD;
} else {
return AILeg::LANDING;
}
} else {
return leg+1;
}
}
void FGAIAircraft::handleATCRequests(double dt) void FGAIAircraft::handleATCRequests(double dt)
{ {
if (!this->getTrafficRef()) { if (!this->getTrafficRef()) {

View file

@ -44,9 +44,10 @@ namespace AILeg
CLIMB = 4, CLIMB = 4,
CRUISE = 5, CRUISE = 5,
APPROACH = 6, APPROACH = 6,
LANDING = 7, HOLD = 7,
PARKING_TAXI = 8, LANDING = 8,
PARKING = 9 PARKING_TAXI = 9,
PARKING = 10
}; };
} }
@ -122,7 +123,7 @@ public:
int getTakeOffStatus() { return takeOffStatus; }; int getTakeOffStatus() { return takeOffStatus; };
void setTakeOffSlot(time_t timeSlot) { takeOffTimeSlot = timeSlot;}; void setTakeOffSlot(time_t timeSlot) { takeOffTimeSlot = timeSlot;};
time_t getTakeOffSlot(){return takeOffTimeSlot;}; time_t getTakeOffSlot(){return takeOffTimeSlot;};
void scheduleForATCTowerDepartureControl(int state); void scheduleForATCTowerDepartureControl();
const std::string& GetTransponderCode() { return transponderCode; }; const std::string& GetTransponderCode() { return transponderCode; };
void SetTransponderCode(const std::string& tc) { transponderCode = tc;}; void SetTransponderCode(const std::string& tc) { transponderCode = tc;};
@ -200,6 +201,8 @@ private:
/**Handle special cases for the User AI shadow*/ /**Handle special cases for the User AI shadow*/
void updateUserFlightPlan(double dt); void updateUserFlightPlan(double dt);
/**Calculate the next leg (hold or not)*/
int determineNextLeg(int leg);
void handleATCRequests(double dt); void handleATCRequests(double dt);
inline bool isStationary() { inline bool isStationary() {

View file

@ -185,7 +185,7 @@ public:
double checkTrackLength(const std::string& wptName) const; double checkTrackLength(const std::string& wptName) const;
time_t getStartTime() const { return start_time; } time_t getStartTime() const { return start_time; }
time_t getArrivalTime() const { return arrivalTime; } time_t getArrivalTime() const { return arrivalTime; }
bool create(FGAIAircraft *, FGAirport *dep, FGAirport *arr, int leg, double alt, double speed, double lat, double lon, bool create(FGAIAircraft *, FGAirport *dep, FGAirport *arr, int leg, double alt, double speed, double lat, double lon,
bool firstLeg, double radius, const std::string& fltType, const std::string& aircraftType, const std::string& airline, double distance); bool firstLeg, double radius, const std::string& fltType, const std::string& aircraftType, const std::string& airline, double distance);
@ -268,6 +268,7 @@ private:
bool createClimb(FGAIAircraft *, bool, FGAirport *, FGAirport* arrival, double, double, const std::string&); bool createClimb(FGAIAircraft *, bool, FGAirport *, FGAirport* arrival, double, double, const std::string&);
bool createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, const SGGeod& current, double, double, const std::string&); bool createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, const SGGeod& current, double, double, const std::string&);
bool createDescent(FGAIAircraft *, FGAirport *, const SGGeod& current, double speed, double alt,const std::string&, double distance); bool createDescent(FGAIAircraft *, FGAirport *, const SGGeod& current, double speed, double alt,const std::string&, double distance);
bool createHold(FGAIAircraft *, FGAirport *, const SGGeod& current, double speed, double alt,const std::string&, double distance);
bool createLanding(FGAIAircraft *, FGAirport *, const std::string&); bool createLanding(FGAIAircraft *, FGAirport *, const std::string&);
bool createParking(FGAIAircraft *, FGAirport *, double radius); bool createParking(FGAIAircraft *, FGAirport *, double radius);
void deleteWaypoints(); void deleteWaypoints();

View file

@ -101,6 +101,10 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
retVal = createDescent(ac, arr, SGGeod::fromDeg(longitude, latitude), speed, alt, fltType, retVal = createDescent(ac, arr, SGGeod::fromDeg(longitude, latitude), speed, alt, fltType,
distance); distance);
break; break;
case AILeg::HOLD:
retVal = createHold(ac, arr, SGGeod::fromDeg(longitude, latitude), speed, alt, fltType,
distance);
break;
case AILeg::LANDING: case AILeg::LANDING:
retVal = createLanding(ac, arr, fltType); retVal = createLanding(ac, arr, fltType);
break; break;
@ -775,7 +779,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac,
heading); heading);
if (!apt->hasRunwayWithIdent(activeRunway)) { if (!apt->hasRunwayWithIdent(activeRunway)) {
SG_LOG(SG_AI, SG_WARN, ac->getCallSign() << SG_LOG(SG_AI, SG_WARN, ac->getCallSign() <<
"| FGAIFlightPlan::createLanding: No such runway " << activeRunway << " at " << apt->ident()); "| FGAIFlightPlan::createDescent: No such runway " << activeRunway << " at " << apt->ident());
return false; return false;
} }
@ -1018,63 +1022,56 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac,
createArc(ac, secondaryTarget, ac->_getHeading()+rightAngle, heading+rightAngle, firstTurnIncrement, initialTurnRadius, ac->getAltitude(), altDiff/3, vDescent, "straight_turn_%03d"); createArc(ac, secondaryTarget, ac->_getHeading()+rightAngle, heading+rightAngle, firstTurnIncrement, initialTurnRadius, ac->getAltitude(), altDiff/3, vDescent, "straight_turn_%03d");
} }
// To prevent absurdly steep approaches, compute the origin from where the approach should have started
SGGeod origin;
if (distance < requiredDistance * 0.8) {
reposition = true;
SGGeodesy::direct(waypoints.back()->getPos(), azimuth,
requiredDistance, origin, dummyAz2);
double addDD = SGGeodesy::courseDeg(refPoint, initialTarget);
distance = SGGeodesy::distanceM(current, initialTarget);
azimuth = SGGeodesy::courseDeg(current, initialTarget);
} else {
// We project a new point out of line so the aircraft has room to turn to new heading.
origin = SGGeodesy::direct(current, ac->getTrueHeadingDeg(), initialTurnRadius);
distance = SGGeodesy::distanceM(origin, initialTarget);
azimuth = SGGeodesy::courseDeg(origin, initialTarget);
}
// Calculate the ETA at final, based on remaining distance, and approach speed.
// distance should really consist of flying time to terniary target, plus circle
// but the distance to secondary target should work as a reasonable approximation
// aditionally add the amount of distance covered by making a turn of "side"
time_t remaining =
(initialTurnRadius + distance) / ((vDescent * SG_NM_TO_METER) / 3600.0);
time_t now = globals->get_time_params()->get_cur_time(); time_t now = globals->get_time_params()->get_cur_time();
//if (ac->getTrafficRef()->getCallSign() == fgGetString("/ai/track-callsign")) { arrivalTime = now;
// cerr << " Arrival time estimation: turn angle " << side << ". Turn distance " << turnDistance << ". Linear distance " << distance << ". Time to go " << remaining << endl;
// //exit(1);
//}
time_t eta = now + remaining;
//choose a distance to the runway such that it will take at least 60 seconds more //choose a distance to the runway such that it will take at least 60 seconds more
// time to get there than the previous aircraft. // time to get there than the previous aircraft.
// Don't bother when aircraft need to be repositioned, because that marks the initialization phased... // Don't bother when aircraft need to be repositioned, because that marks the initialization phased...
time_t newEta;
if (reposition == false) {
newEta =
apt->getDynamics()->getApproachController()->getRunway(rwy->name())->requestTimeSlot(eta);
} else {
newEta = eta;
}
arrivalTime = newEta;
time_t additionalTimeNeeded = newEta - eta;
SG_LOG(SG_AI, SG_BULK, "Additional time required " << additionalTimeNeeded << " ");
//Number of holds
double holdsPatterns = (additionalTimeNeeded-additionalTimeNeeded%240)/240;
additionalTimeNeeded -= holdsPatterns*240;
return true; return true;
} }
/*******************************************************************
* CreateHold
* Generate a hold flight path from the permission to land point
* Exactly one hold pattern
******************************************************************/
bool FGAIFlightPlan::createHold(FGAIAircraft * ac,
FGAirport * apt,
const SGGeod& current,
double speed,
double alt,
const string & fltType,
double requiredDistance)
{
//Beginning of Descent
const string& rwyClass = getRunwayClassFromTrafficType(fltType);
double vDescent = ac->getPerformance()->vDescent();
double vApproach = ac->getPerformance()->vApproach();
double initialTurnRadius = getTurnRadius(vDescent, true);
double heading = ac->getTrueHeadingDeg();
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway,
heading);
if (!apt->hasRunwayWithIdent(activeRunway)) {
SG_LOG(SG_AI, SG_WARN, ac->getCallSign() <<
"| FGAIFlightPlan::createHold: No such runway " << activeRunway << " at " << apt->ident());
return false;
}
FGRunwayRef rwy = apt->getRunwayByIdent(activeRunway);
double currentAltitude = waypoints.back()->getAltitude();
double distanceOut = apt->getDynamics()->getApproachController()->getRunway(rwy->name())->getApproachDistance(); //12 * SG_NM_TO_METER;
double lateralOffset = initialTurnRadius;
SGGeod secondaryTarget = rwy->pointOffCenterline(-2 * distanceOut, lateralOffset);
SGGeod secondHoldCenter = rwy->pointOffCenterline(-4 * distanceOut, lateralOffset);
createArc(ac, secondaryTarget, rwy->headingDeg()-90, rwy->headingDeg()+90, 5, initialTurnRadius,
currentAltitude, 0, vDescent, "hold_1_%03d");
createArc(ac, secondHoldCenter, rwy->headingDeg()+90, rwy->headingDeg()-90, 5, initialTurnRadius,
currentAltitude, 0, vDescent, "hold_2_%03d");
return true;
}
/** /**
* compute the distance along the centerline, to the ILS glideslope * compute the distance along the centerline, to the ILS glideslope
* transmitter. Return -1 if there's no GS for the runway * transmitter. Return -1 if there's no GS for the runway

View file

@ -102,6 +102,36 @@ bool FGATCController::isUserAircraft(FGAIAircraft* ac)
return (ac->getCallSign() == fgGetString("/sim/multiplay/callsign")) ? true : false; return (ac->getCallSign() == fgGetString("/sim/multiplay/callsign")) ? true : false;
}; };
bool FGATCController::checkTransmissionState(int minState, int maxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
AtcMsgDir msgDir)
{
int state = i->getState();
if ((state >= minState) && (state <= maxState) && available) {
if ((msgDir == ATC_AIR_TO_GROUND) && isUserAircraft(i->getAircraft())) {
SG_LOG(SG_ATC, SG_BULK, "Checking state " << state << " for " << i->getAircraft()->getCallSign());
SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
int n = trans_num->getIntValue();
if (n == 0) {
trans_num->setIntValue(-1);
// PopupCallback(n);
SG_LOG(SG_ATC, SG_DEBUG, "Selected transmission message " << n);
//auto atc = globals->get_subsystem<FGATCManager>();
//FGATCDialogNew::instance()->removeEntry(1);
} else {
SG_LOG(SG_ATC, SG_BULK, "Sending message for " << i->getAircraft()->getCallSign());
transmit(&(*i), parent, msgId, msgDir, false);
return false;
}
}
transmit(&(*i), parent, msgId, msgDir, true);
i->updateState();
lastTransmission = now;
available = false;
return true;
}
return false;
}
void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, AtcMsgId msgId, void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, AtcMsgId msgId,
AtcMsgDir msgDir, bool audible) AtcMsgDir msgDir, bool audible)
{ {
@ -109,7 +139,6 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
int stationFreq = 0; int stationFreq = 0;
int taxiFreq = 0; int taxiFreq = 0;
int towerFreq = 0; int towerFreq = 0;
int freqId = 0;
string atisInformation; string atisInformation;
string text; string text;
string taxiFreqStr; string taxiFreqStr;
@ -133,14 +162,20 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
instructionText = "taxi"; instructionText = "taxi";
} }
SG_LOG(SG_ATC, SG_DEBUG, "transmitting for: " << sender << "Leg = " << rec->getLeg()); SG_LOG(SG_ATC, SG_BULK, "transmitting for: " << sender << " at Leg " << rec->getLeg());
//FIXME move departure and arrival to rec
auto depApt = rec->getAircraft()->getTrafficRef()->getDepartureAirport(); auto depApt = rec->getAircraft()->getTrafficRef()->getDepartureAirport();
auto arrApt = rec->getAircraft()->getTrafficRef()->getArrivalAirport();
if (!depApt) { if (!depApt) {
SG_LOG(SG_ATC, SG_DEV_ALERT, "TrafficRec has empty departure airport, can't transmit"); SG_LOG(SG_ATC, SG_DEV_ALERT, "TrafficRec has empty departure airport, can't transmit");
return; return;
} }
if (!arrApt) {
SG_LOG(SG_ATC, SG_DEV_ALERT, "TrafficRec has empty arrival airport, can't transmit");
return;
}
stationFreq = getFrequency(); stationFreq = getFrequency();
taxiFreq = depApt->getDynamics()->getGroundFrequency(2); taxiFreq = depApt->getDynamics()->getGroundFrequency(2);
@ -281,16 +316,12 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
text = receiver + ". Holding short runway " text = receiver + ". Holding short runway "
+ activeRunway + activeRunway
+ ". " + sender + "."; + ". " + sender + ".";
//text = "test1";
SG_LOG(SG_ATC, SG_DEBUG, "1 Currently at leg " << rec->getLeg());
break; break;
case MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT: case MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT:
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway(); activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
text = receiver + " Roger. Holding short runway " text = receiver + " Roger. Holding short runway "
// + activeRunway // + activeRunway
+ ". " + sender + "."; + ". " + sender + ".";
//text = "test2";
SG_LOG(SG_ATC, SG_DEBUG, "2 Currently at leg " << rec->getLeg());
break; break;
case MSG_CLEARED_FOR_TAKEOFF: case MSG_CLEARED_FOR_TAKEOFF:
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway(); activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
@ -300,23 +331,40 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
case MSG_ACKNOWLEDGE_CLEARED_FOR_TAKEOFF: case MSG_ACKNOWLEDGE_CLEARED_FOR_TAKEOFF:
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway(); activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
text = receiver + " Roger. Cleared for takeoff runway " + activeRunway + ". " + sender + "."; text = receiver + " Roger. Cleared for takeoff runway " + activeRunway + ". " + sender + ".";
//text = "test2";
break; 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 + ".";
//text = "test3";
SG_LOG(SG_ATC, SG_DEBUG, "3 Currently at leg " << rec->getLeg());
break; break;
case MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY: case MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY:
towerFreqStr = formatATCFrequency3_2(towerFreq); towerFreqStr = formatATCFrequency3_2(towerFreq);
text = receiver + " Roger, switching to tower at " + towerFreqStr + ". " + sender + "."; text = receiver + " Roger, switching to tower at " + towerFreqStr + ". " + sender + ".";
//text = "test4"; break;
SG_LOG(SG_ATC, SG_DEBUG, "4 Currently at leg " << rec->getLeg()); case MSG_ARRIVAL:
text = receiver + ". " + sender + " Information delta.";
break;
case MSG_ACKNOWLEDGE_ARRIVAL:
activeRunway = rec->getRunway();
text = receiver + " expect ILS approach " + activeRunway + ". " + sender;
break;
case MSG_CLEARED_TO_LAND:
activeRunway = rec->getRunway();
//TODO Weather
text = receiver + " runway " + activeRunway + " cleared to land. " + sender;
break;
case MSG_ACKNOWLEDGE_CLEARED_TO_LAND:
activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway();
text = receiver + " runway " + activeRunway + " cleared to land. " + sender;
break;
case MSG_HOLD:
text = receiver + " hold as published . " + sender;
break;
case MSG_ACKNOWLEDGE_HOLD:
text = receiver + " holding as published . " + sender;
break; break;
default: default:
//text = "test3"; //text = "test3";
text = text + sender + ". Transmitting unknown Message."; text = text + sender + ". Transmitting unknown Message. MsgId " + std::to_string(msgId);
break; break;
} }
@ -341,12 +389,10 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
((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;
if(ground_to_air) { if(ground_to_air) {
sender_pos = parent->parent()->geod(); sender_pos = parent->parent()->geod();
} }
@ -368,6 +414,11 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent,
} }
} }
/**
* Sign off the aircraft with the id from this controller.
* @param id the id of the aircraft
*/
void FGATCController::signOff(int id) void FGATCController::signOff(int id)
{ {
TrafficVectorIterator i = searchActiveTraffic(id); TrafficVectorIterator i = searchActiveTraffic(id);
@ -377,8 +428,12 @@ void FGATCController::signOff(int id)
"AI error: Aircraft without traffic record is signing off from " << getName() << " at " << SG_ORIGIN << " list " << activeTraffic.empty()); "AI error: Aircraft without traffic record is signing off from " << getName() << " at " << SG_ORIGIN << " list " << activeTraffic.empty());
return; return;
} }
SG_LOG(SG_ATC, SG_DEBUG, i->getCallsign() << " (" << i->getId() << ") signing off from " << getName() << "(" << getFrequency() << ")");
int oldSize = activeTraffic.size();
activeTraffic.erase(i); activeTraffic.erase(i);
SG_LOG(SG_ATC, SG_DEBUG, i->getCallsign() << " signing off from " << getName() ); if ((oldSize-activeTraffic.size()) != 1) {
SG_LOG(SG_ATC, SG_WARN, i->getCallsign() << " not removed ");
}
} }
bool FGATCController::hasInstruction(int id) bool FGATCController::hasInstruction(int id)

View file

@ -39,28 +39,35 @@ namespace ATCMessageState
{ {
enum Type enum Type
{ {
// 0 = Normal; no action required // 0 = Normal; no action required
NORMAL = 0, NORMAL,
// 1 = "Acknowledge "Hold position // 1 = "Acknowledge "Hold position
ACK_HOLD = 1, ACK_HOLD,
// 2 = "Acknowledge "Resume taxi". // 2 = "Acknowledge "Resume taxi".
ACK_RESUME_TAXI = 2, ACK_RESUME_TAXI,
// 3 = "Issue TaxiClearance" // 3 = "Issue TaxiClearance"
TAXI_CLEARED = 3, TAXI_CLEARED = 3,
// 4 = Acknowledge Taxi Clearance" // 4 = Acknowledge Taxi Clearance"
ACK_TAXI_CLEARED = 4, ACK_TAXI_CLEARED = 4,
// 5 = Post acknowlegde taxiclearance: Start taxiing // 5 = Post acknowlegde taxiclearance: Start taxiing
START_TAXI = 5, START_TAXI = 5,
// 6 = Report runway // 6 = Report runway
REPORT_RUNWAY = 6, REPORT_RUNWAY = 6,
// 7 = Acknowledge report runway // 7 = Acknowledge report runway
ACK_REPORT_RUNWAY = 7, ACK_REPORT_RUNWAY = 7,
// 8 = Switch tower frequency // 8 = Switch tower frequency
SWITCH_TOWER = 8, SWITCH_GROUND_TOWER = 8,
// 9 = Acknowledge switch tower frequency // 9 = Acknowledge switch tower frequency
ACK_SWITCH_TOWER = 9, ACK_SWITCH_GROUND_TOWER = 9,
// 10 = Cleared for takeoff // 10 = Cleared for takeoff
CLEARED_TAKEOFF = 10, CLEARED_TAKEOFF,
ACK_CLEARED_TAKEOFF,
ANNOUNCE_ARRIVAL,
ACK_ARRIVAL,
HOLD,
CLEARED_TO_LAND,
ACK_CLEARED_TO_LAND,
LANDING_TAXI
}; };
} }
@ -118,7 +125,13 @@ public:
MSG_CLEARED_FOR_TAKEOFF, MSG_CLEARED_FOR_TAKEOFF,
MSG_ACKNOWLEDGE_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,
MSG_ARRIVAL,
MSG_ACKNOWLEDGE_ARRIVAL,
MSG_HOLD,
MSG_ACKNOWLEDGE_HOLD,
MSG_CLEARED_TO_LAND,
MSG_ACKNOWLEDGE_CLEARED_TO_LAND
} AtcMsgId; } AtcMsgId;
typedef enum { typedef enum {
@ -135,6 +148,8 @@ public:
FGAIAircraft *aircraft) = 0; FGAIAircraft *aircraft) = 0;
virtual void updateAircraftInformation(int id, SGGeod geod, virtual void updateAircraftInformation(int id, SGGeod geod,
double heading, double speed, double alt, double dt) = 0; double heading, double speed, double alt, double dt) = 0;
bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
AtcMsgDir msgDir);
virtual void signOff(int id); virtual void signOff(int id);
bool hasInstruction(int id); bool hasInstruction(int id);

View file

@ -98,9 +98,11 @@ void FGApproachController::announcePosition(int id,
rec.setLeg(leg); rec.setLeg(leg);
rec.setCallsign(ref->getCallSign()); rec.setCallsign(ref->getCallSign());
rec.setAircraft(ref); rec.setAircraft(ref);
rec.setPlannedArrivalTime(intendedRoute->getArrivalTime());
activeTraffic.push_back(rec); activeTraffic.push_back(rec);
} else { } else {
i->setPositionAndHeading(lat, lon, heading, speed, alt); i->setPositionAndHeading(lat, lon, heading, speed, alt);
i->setPlannedArrivalTime(intendedRoute->getArrivalTime());
} }
} }
@ -108,6 +110,7 @@ void FGApproachController::updateAircraftInformation(int id, SGGeod geod,
double heading, double speed, double alt, double heading, double speed, double alt,
double dt) double dt)
{ {
time_t now = globals->get_time_params()->get_cur_time();
// Search activeTraffic for a record matching our id // Search activeTraffic for a record matching our id
TrafficVectorIterator i = FGATCController::searchActiveTraffic(id); TrafficVectorIterator i = FGATCController::searchActiveTraffic(id);
TrafficVectorIterator current; TrafficVectorIterator current;
@ -115,7 +118,7 @@ void FGApproachController::updateAircraftInformation(int id, SGGeod geod,
// 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,
"AI error: updating aircraft without traffic record at " << SG_ORIGIN); "FGApproachController updating aircraft without traffic record at " << SG_ORIGIN);
} else { } else {
i->setPositionAndHeading(geod.getLatitudeDeg(), geod.getLongitudeDeg(), heading, speed, alt); i->setPositionAndHeading(geod.getLatitudeDeg(), geod.getLongitudeDeg(), heading, speed, alt);
current = i; current = i;
@ -146,13 +149,42 @@ void FGApproachController::updateAircraftInformation(int id, SGGeod geod,
} else { } else {
current->clearSpeedAdjustment(); current->clearSpeedAdjustment();
} }
if ((now - lastTransmission) > 15) {
available = true;
}
//Start of our status runimplicit "announce arrival"
if (checkTransmissionState(ATCMessageState::NORMAL, ATCMessageState::NORMAL, current, now, MSG_ARRIVAL, ATC_AIR_TO_GROUND)) {
current->setRunwaySlot(getRunway(current->getRunway())->requestTimeSlot(current->getPlannedArrivalTime()));
current->setState(ATCMessageState::ACK_ARRIVAL);
}
if (checkTransmissionState(ATCMessageState::ACK_ARRIVAL, ATCMessageState::ACK_ARRIVAL, current, now, MSG_ACKNOWLEDGE_ARRIVAL, ATC_GROUND_TO_AIR)) {
if (current->getRunwaySlot() > current->getPlannedArrivalTime()) {
current->setState(ATCMessageState::HOLD);
} else {
current->setState(ATCMessageState::CLEARED_TO_LAND);
}
}
if (checkTransmissionState(ATCMessageState::HOLD, ATCMessageState::HOLD, current, now, MSG_ACKNOWLEDGE_HOLD, ATC_AIR_TO_GROUND)) {
current->setState(ATCMessageState::ACK_HOLD);
}
if (checkTransmissionState(ATCMessageState::CLEARED_TO_LAND, ATCMessageState::CLEARED_TO_LAND, current, now, MSG_CLEARED_TO_LAND, ATC_GROUND_TO_AIR)) {
current->setState(ATCMessageState::ACK_CLEARED_TO_LAND);
}
if (checkTransmissionState(ATCMessageState::ACK_CLEARED_TO_LAND, ATCMessageState::ACK_CLEARED_TO_LAND, current, now, MSG_ACKNOWLEDGE_CLEARED_TO_LAND, ATC_AIR_TO_GROUND)) {
current->setState(ATCMessageState::SWITCH_GROUND_TOWER);
}
if (checkTransmissionState(ATCMessageState::SWITCH_GROUND_TOWER, ATCMessageState::SWITCH_GROUND_TOWER, current, now, MSG_SWITCH_TOWER_FREQUENCY, ATC_GROUND_TO_AIR)) {
}
if (checkTransmissionState(ATCMessageState::ACK_SWITCH_GROUND_TOWER, ATCMessageState::ACK_SWITCH_GROUND_TOWER, current, now, MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY, ATC_AIR_TO_GROUND)) {
current->setState(ATCMessageState::LANDING_TAXI);
}
} }
//current->setSpeedAdjustment(current->getAircraft()->getPerformance()->vDescent() + time_diff); //current->setSpeedAdjustment(current->getAircraft()->getPerformance()->vDescent() + time_diff);
} }
setDt(getDt() + dt); setDt(getDt() + dt);
} }
/* 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(); FGATCController::eraseDeadTraffic();

View file

@ -130,7 +130,7 @@ void FGGroundController::announcePosition(int id,
} }
} }
/* /**
* 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
* 1 = "Acknowledge "Hold position * 1 = "Acknowledge "Hold position
@ -143,35 +143,6 @@ void FGGroundController::announcePosition(int id,
* 8 = Switch tower frequency * 8 = Switch tower frequency
* 9 = Acknowledge switch tower frequency * 9 = Acknowledge switch tower frequency
*/ */
bool FGGroundController::checkTransmissionState(int minState, int maxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId,
AtcMsgDir msgDir)
{
int state = i->getState();
if ((state >= minState) && (state <= maxState) && available) {
if ((msgDir == ATC_AIR_TO_GROUND) && isUserAircraft(i->getAircraft())) {
SG_LOG(SG_ATC, SG_DEBUG, "Checking state " << state << " for " << i->getAircraft()->getCallSign());
SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
int n = trans_num->getIntValue();
if (n == 0) {
trans_num->setIntValue(-1);
// PopupCallback(n);
SG_LOG(SG_ATC, SG_DEBUG, "Selected transmission message " << n);
//auto atc = globals->get_subsystem<FGATCManager>();
//FGATCDialogNew::instance()->removeEntry(1);
} else {
SG_LOG(SG_ATC, SG_DEBUG, "creating message for " << i->getAircraft()->getCallSign());
transmit(&(*i), parent, msgId, msgDir, false);
return false;
}
}
transmit(&(*i), parent, msgId, msgDir, true);
i->updateState();
lastTransmission = now;
available = false;
return true;
}
return false;
}
void FGGroundController::updateAircraftInformation(int id, SGGeod geod, void FGGroundController::updateAircraftInformation(int id, SGGeod geod,
double heading, double speed, double alt, double heading, double speed, double alt,
@ -221,26 +192,25 @@ void FGGroundController::updateAircraftInformation(int id, SGGeod geod,
if ((now - lastTransmission) > 15) { if ((now - lastTransmission) > 15) {
available = true; available = true;
} }
if (checkTransmissionState(0,2, current, now, MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) { if (checkTransmissionState(ATCMessageState::NORMAL,ATCMessageState::ACK_RESUME_TAXI, current, now, MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
current->setState(ATCMessageState::TAXI_CLEARED); current->setState(ATCMessageState::TAXI_CLEARED);
} }
if (checkTransmissionState(3,3, current, now, MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR)) { if (checkTransmissionState(ATCMessageState::TAXI_CLEARED,ATCMessageState::TAXI_CLEARED, current, now, MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR)) {
current->setState(ATCMessageState::ACK_TAXI_CLEARED); current->setState(ATCMessageState::ACK_TAXI_CLEARED);
} }
if (checkTransmissionState(4,4, current, now, MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) { if (checkTransmissionState(ATCMessageState::ACK_TAXI_CLEARED,ATCMessageState::ACK_TAXI_CLEARED, current, now, MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
current->setState(ATCMessageState::START_TAXI); current->setState(ATCMessageState::START_TAXI);
} }
if ((state == 5) && available) { if ((state == ATCMessageState::START_TAXI) && available) {
current->setState(ATCMessageState::NORMAL); current->setState(ATCMessageState::NORMAL);
current->getAircraft()->setTaxiClearanceRequest(false); current->getAircraft()->setTaxiClearanceRequest(false);
current->setHoldPosition(false); current->setHoldPosition(false);
available = false; available = false;
} }
} }
} }
/* /**
* Scan for a speed adjustment change. Find the nearest aircraft that is in front * Scan for a speed adjustment change. Find the nearest aircraft that is in front
* and adjust speed when we get too close. Only do this when current position and/or * and adjust speed when we get too close. Only do this when current position and/or
* intentions of the current aircraft match current taxiroute position of the proximate * intentions of the current aircraft match current taxiroute position of the proximate
@ -310,7 +280,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat,
if( current->getId() == i->getId()) { if( current->getId() == i->getId()) {
continue; continue;
} }
SG_LOG(SG_ATC, SG_BULK, "Comparing " << current->getCallsign() << " and " << i->getCallsign()); SG_LOG(SG_ATC, SG_BULK, current->getCallsign() << "| Comparing with " << i->getCallsign() << " Id: " << i->getId());
SGGeod other = i->getPos(); SGGeod other = i->getPos();
SGGeodesy::inverse(curr, other, course, az2, dist); SGGeodesy::inverse(curr, other, course, az2, dist);
bearing = fabs(heading - course); bearing = fabs(heading - course);
@ -394,7 +364,7 @@ void FGGroundController::checkSpeedAdjustment(int id, double lat,
} }
} }
/* /**
* Check for "Hold position instruction". * Check for "Hold position instruction".
* The hold position should be issued under the following conditions: * The hold position should be issued under the following conditions:
* 1) For aircraft entering or crossing a runway with active traffic on it, or landing aircraft near it * 1) For aircraft entering or crossing a runway with active traffic on it, or landing aircraft near it
@ -427,12 +397,15 @@ void FGGroundController::checkHoldPosition(int id, double lat,
"AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkHoldPosition at " << SG_ORIGIN); "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkHoldPosition at " << SG_ORIGIN);
} }
current = i; current = i;
if (current->getAircraft()->getTakeOffStatus() == 1) { if (current->getAircraft()->getTakeOffStatus() == AITakeOffStatus::QUEUED) {
current->setHoldPosition(true); current->setHoldPosition(true);
return; return;
} }
if (current->getAircraft()->getTakeOffStatus() == 2) { if ((now - lastTransmission) > 15) {
SG_LOG(SG_ATC, SG_DEBUG, current->getAircraft()->getCallSign() << ". Taxi in position and hold"); available = true;
}
if (current->getAircraft()->getTakeOffStatus() == AITakeOffStatus::CLEARED_FOR_TAKEOFF) {
current->setHoldPosition(false); current->setHoldPosition(false);
current->clearSpeedAdjustment(); current->clearSpeedAdjustment();
return; return;
@ -485,7 +458,7 @@ void FGGroundController::checkHoldPosition(int id, double lat,
if ((now - lastTransmission) > 2) { if ((now - lastTransmission) > 2) {
available = true; available = true;
} }
if (current->getState() == 0) { if (current->getState() == ATCMessageState::NORMAL) {
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
@ -511,11 +484,11 @@ void FGGroundController::checkHoldPosition(int id, double lat,
//9 = Acknowledge switch tower frequency //9 = Acknowledge switch tower frequency
//int state = current->getState(); //int state = current->getState();
if (checkTransmissionState(1,1, current, now, MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND)) { if (checkTransmissionState(ATCMessageState::ACK_HOLD, ATCMessageState::ACK_HOLD, current, now, MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND)) {
current->setState(ATCMessageState::NORMAL); current->setState(ATCMessageState::NORMAL);
current->setHoldPosition(true); current->setHoldPosition(true);
} }
if (checkTransmissionState(2,2, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) { if (checkTransmissionState(ATCMessageState::ACK_RESUME_TAXI, ATCMessageState::ACK_RESUME_TAXI, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) {
current->setState(ATCMessageState::NORMAL); current->setState(ATCMessageState::NORMAL);
current->setHoldPosition(false); current->setHoldPosition(false);
} }
@ -523,13 +496,13 @@ void FGGroundController::checkHoldPosition(int id, double lat,
SG_LOG(SG_ATC, SG_DEBUG, "Scheduling " << current->getAircraft()->getCallSign() << " for hold short"); SG_LOG(SG_ATC, SG_DEBUG, "Scheduling " << current->getAircraft()->getCallSign() << " for hold short");
current->setState(ATCMessageState::REPORT_RUNWAY); current->setState(ATCMessageState::REPORT_RUNWAY);
} }
if (checkTransmissionState(6,6, current, now, MSG_REPORT_RUNWAY_HOLD_SHORT, ATC_AIR_TO_GROUND)) { if (checkTransmissionState(ATCMessageState::REPORT_RUNWAY ,ATCMessageState::REPORT_RUNWAY , current, now, MSG_REPORT_RUNWAY_HOLD_SHORT, ATC_AIR_TO_GROUND)) {
} }
if (checkTransmissionState(7,7, current, now, MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT, ATC_GROUND_TO_AIR)) { if (checkTransmissionState(ATCMessageState::ACK_REPORT_RUNWAY, ATCMessageState::ACK_REPORT_RUNWAY, current, now, MSG_ACKNOWLEDGE_REPORT_RUNWAY_HOLD_SHORT, ATC_GROUND_TO_AIR)) {
} }
if (checkTransmissionState(8,8, current, now, MSG_SWITCH_TOWER_FREQUENCY, ATC_GROUND_TO_AIR)) { if (checkTransmissionState(ATCMessageState::SWITCH_GROUND_TOWER, ATCMessageState::SWITCH_GROUND_TOWER, current, now, MSG_SWITCH_TOWER_FREQUENCY, ATC_GROUND_TO_AIR)) {
} }
if (checkTransmissionState(9,9, current, now, MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY, ATC_AIR_TO_GROUND)) { if (checkTransmissionState(ATCMessageState::ACK_SWITCH_GROUND_TOWER, ATCMessageState::ACK_SWITCH_GROUND_TOWER, current, now, MSG_ACKNOWLEDGE_SWITCH_TOWER_FREQUENCY, ATC_AIR_TO_GROUND)) {
} }
@ -580,7 +553,7 @@ bool FGGroundController::checkForCircularWaits(int id)
int counter = 0; int counter = 0;
if (id == target) { if (id == target) {
SG_LOG(SG_ATC, SG_DEBUG, "aircraft waits for user"); SG_LOG(SG_ATC, SG_DEBUG, "aircraft is waiting for user");
return false; return false;
} }
@ -641,7 +614,7 @@ static void WorldCoordinate(osg::Matrix& obj_pos, double lat,
0.0, 1.0, 0.0)); 0.0, 1.0, 0.0));
} }
/* Draw visible taxi routes */ /** Draw visible taxi routes */
void FGGroundController::render(bool visible) void FGGroundController::render(bool visible)
{ {
SGMaterialLib *matlib = globals->get_matlib(); SGMaterialLib *matlib = globals->get_matlib();

View file

@ -76,9 +76,7 @@ public:
double radius, int leg, FGAIAircraft *aircraft); double radius, int leg, FGAIAircraft *aircraft);
virtual void updateAircraftInformation(int id, SGGeod geod, double heading, double speed, double alt, double dt); virtual void updateAircraftInformation(int id, SGGeod geod, double heading, double speed, double alt, double dt);
bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId, bool checkForCircularWaits(int id);
AtcMsgDir msgDir);
bool checkForCircularWaits(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);

View file

@ -105,41 +105,7 @@ void FGStartupController::announcePosition(int id,
} }
} }
bool FGStartupController::checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId, void FGStartupController::updateAircraftInformation(int id, SGGeod geod, double heading, double speed, double alt,
AtcMsgDir msgDir)
{
int state = i->getState();
if ((state == st) && available) {
if ((msgDir == ATC_AIR_TO_GROUND) && isUserAircraft(i->getAircraft())) {
SG_LOG(SG_ATC, SG_BULK, "Checking state " << st << " for " << i->getAircraft()->getCallSign());
SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
int n = trans_num->getIntValue();
if (n == 0) {
trans_num->setIntValue(-1);
// PopupCallback(n);
SG_LOG(SG_ATC, SG_BULK, "Selected transmission message " << n);
//FGATCDialogNew::instance()->removeEntry(1);
} else {
SG_LOG(SG_ATC, SG_BULK, "Creating message for " << i->getAircraft()->getCallSign());
transmit(&(*i), &(*parent), msgId, msgDir, false);
return false;
}
}
if (now > startTime) {
SG_LOG(SG_ATC, SG_BULK, "Transmitting startup msg");
transmit(&(*i), &(*parent), msgId, msgDir, true);
i->updateState();
lastTransmission = now;
available = false;
return true;
}
}
return false;
}
void FGStartupController::updateAircraftInformation(int id, SGGeod geod,
double heading, double speed, double alt,
double dt) double dt)
{ {
// Search activeTraffic for a record matching our id // Search activeTraffic for a record matching our id
@ -171,7 +137,8 @@ void FGStartupController::updateAircraftInformation(int id, SGGeod geod,
time_t now = globals->get_time_params()->get_cur_time(); time_t now = globals->get_time_params()->get_cur_time();
if ((startTime - now) > 0) { if (((startTime - now) > 60 && (startTime - now)%60 == 0) ||
((startTime - now) < 60 && (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())); 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()));
} }
@ -179,20 +146,31 @@ void FGStartupController::updateAircraftInformation(int id, SGGeod geod,
available = true; available = true;
} }
checkTransmissionState(0, now, (startTime + 0 ), i, MSG_ANNOUNCE_ENGINE_START, ATC_AIR_TO_GROUND); if (now >(startTime + 0)) {
checkTransmissionState(1, now, (startTime + 60 ), i, MSG_REQUEST_ENGINE_START, ATC_AIR_TO_GROUND); checkTransmissionState(ATCMessageState::NORMAL, ATCMessageState::NORMAL, i, now, MSG_ANNOUNCE_ENGINE_START, ATC_AIR_TO_GROUND);
checkTransmissionState(2, now, (startTime + 80 ), i, MSG_PERMIT_ENGINE_START, ATC_GROUND_TO_AIR);
checkTransmissionState(3, now, (startTime + 100), i, MSG_ACKNOWLEDGE_ENGINE_START, ATC_AIR_TO_GROUND);
if (checkTransmissionState(4, now, (startTime + 130), i, MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY, ATC_AIR_TO_GROUND)) {
i->nextFrequency();
} }
checkTransmissionState(5, now, (startTime + 140), i, MSG_INITIATE_CONTACT, ATC_AIR_TO_GROUND); if (now >(startTime + 60)) {
checkTransmissionState(6, now, (startTime + 150), i, MSG_ACKNOWLEDGE_INITIATE_CONTACT, ATC_GROUND_TO_AIR); checkTransmissionState(ATCMessageState::ACK_HOLD, ATCMessageState::ACK_HOLD, i, now, MSG_REQUEST_ENGINE_START, ATC_AIR_TO_GROUND);
checkTransmissionState(7, now, (startTime + 180), i, MSG_REQUEST_PUSHBACK_CLEARANCE, ATC_AIR_TO_GROUND); }
if (now >(startTime + 80)) {
checkTransmissionState(ATCMessageState::ACK_RESUME_TAXI, ATCMessageState::ACK_RESUME_TAXI, i, now, MSG_PERMIT_ENGINE_START, ATC_GROUND_TO_AIR);
}
if ((state == 8) && available) { if (now >(startTime + 100)) {
checkTransmissionState(ATCMessageState::TAXI_CLEARED, ATCMessageState::TAXI_CLEARED, i, now, MSG_ACKNOWLEDGE_ENGINE_START, ATC_AIR_TO_GROUND);
}
if (now >(startTime + 130)) {
checkTransmissionState(ATCMessageState::ACK_TAXI_CLEARED, ATCMessageState::ACK_TAXI_CLEARED, i, now, MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY, ATC_AIR_TO_GROUND);
}
if (now >(startTime + 140)) {
checkTransmissionState(ATCMessageState::START_TAXI, ATCMessageState::START_TAXI, i, now, MSG_INITIATE_CONTACT, ATC_AIR_TO_GROUND);
}
if (now >(startTime + 150)) {
checkTransmissionState(ATCMessageState::REPORT_RUNWAY, ATCMessageState::REPORT_RUNWAY, i, now, MSG_ACKNOWLEDGE_INITIATE_CONTACT, ATC_GROUND_TO_AIR);
}
if (now >(startTime + 180)) {
checkTransmissionState(ATCMessageState::ACK_REPORT_RUNWAY, ATCMessageState::ACK_REPORT_RUNWAY, i, now, MSG_REQUEST_PUSHBACK_CLEARANCE, ATC_AIR_TO_GROUND);
}
if ((state == ATCMessageState::SWITCH_GROUND_TOWER) && available) {
if (now > startTime + 200) { if (now > startTime + 200) {
if (i->pushBackAllowed()) { if (i->pushBackAllowed()) {
i->allowRepeatedTransmissions(); i->allowRepeatedTransmissions();
@ -208,7 +186,7 @@ void FGStartupController::updateAircraftInformation(int id, SGGeod geod,
available = false; available = false;
} }
} }
if ((state == 9) && available) { if ((state == ATCMessageState::ACK_SWITCH_GROUND_TOWER) && available) {
i->setHoldPosition(false); i->setHoldPosition(false);
} }
} }
@ -230,7 +208,6 @@ static void WorldCoordinate(osg::Matrix& obj_pos, double lat,
void FGStartupController::render(bool visible) void FGStartupController::render(bool visible)
{ {
SG_LOG(SG_ATC, SG_DEBUG, "Rendering startup controller");
SGMaterialLib *matlib = globals->get_matlib(); SGMaterialLib *matlib = globals->get_matlib();
if (group) { if (group) {
//int nr = ; //int nr = ;
@ -245,6 +222,7 @@ void FGStartupController::render(bool visible)
group = 0; group = 0;
} }
if (visible) { if (visible) {
SG_LOG(SG_ATC, SG_BULK, "Rendering startup controller");
group = new osg::Group; group = new osg::Group;
FGScenery * local_scenery = globals->get_scenery(); FGScenery * local_scenery = globals->get_scenery();
//double elevation_meters = 0.0; //double elevation_meters = 0.0;

View file

@ -61,11 +61,6 @@ public:
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);
// 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);
}; };
#endif #endif

View file

@ -96,7 +96,7 @@ void FGTowerController::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.setRadius(radius); rec.setRadius(radius);
rec.setAircraft(ref); rec.setAircraft(ref);
activeTraffic.push_back(rec); activeTraffic.push_back(rec);
@ -113,13 +113,19 @@ void FGTowerController::announcePosition(int id,
if (rwy == activeRunways.end()) { if (rwy == activeRunways.end()) {
ActiveRunway aRwy(intendedRoute->getRunway(), id); ActiveRunway aRwy(intendedRoute->getRunway(), id);
aRwy.addToDepartureQueue(ref); aRwy.addToDepartureQueue(ref);
time_t now = globals->get_time_params()->get_cur_time();
rec.setPlannedArrivalTime(now);
rec.setRunwaySlot(aRwy.requestTimeSlot(now));
activeRunways.push_back(aRwy); activeRunways.push_back(aRwy);
rwy = (activeRunways.end()-1); rwy = (activeRunways.end()-1);
} else { } else {
time_t now = globals->get_time_params()->get_cur_time();
rec.setPlannedArrivalTime(now);
rec.setRunwaySlot(rwy->requestTimeSlot(now));
rwy->addToDepartureQueue(ref); rwy->addToDepartureQueue(ref);
} }
SG_LOG(SG_ATC, SG_DEBUG, ref->getTrafficRef()->getCallSign() << " You are number " << rwy->getdepartureQueueSize() << " for takeoff "); SG_LOG(SG_ATC, SG_DEBUG, ref->getTrafficRef()->getCallSign() << " You are number " << rwy->getdepartureQueueSize() << " for takeoff from " << rwy->getRunwayName());
} else { } else {
i->setPositionAndHeading(lat, lon, heading, speed, alt); i->setPositionAndHeading(lat, lon, heading, speed, alt);
} }
@ -134,6 +140,7 @@ void FGTowerController::updateAircraftInformation(int id, SGGeod geod,
setDt(getDt() + dt); setDt(getDt() + dt);
time_t now = globals->get_time_params()->get_cur_time();
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: updating aircraft without traffic record at " << "AI error: updating aircraft without traffic record at " <<
@ -184,30 +191,43 @@ void FGTowerController::updateAircraftInformation(int id, SGGeod geod,
if (ac->getTakeOffStatus() == AITakeOffStatus::QUEUED) { if (ac->getTakeOffStatus() == AITakeOffStatus::QUEUED) {
// transmit takeoff clearance // transmit takeoff clearance
ac->setTakeOffStatus(AITakeOffStatus::CLEARED_FOR_TAKEOFF); ac->setTakeOffStatus(AITakeOffStatus::CLEARED_FOR_TAKEOFF);
transmit(&(*i), &(*parent), MSG_CLEARED_FOR_TAKEOFF, ATC_GROUND_TO_AIR, true); TrafficVectorIterator first = searchActiveTraffic(ac->getID());
i->setState(ATCMessageState::CLEARED_TAKEOFF); //FIXME use checkTransmissionState
if (first == activeTraffic.end() || activeTraffic.empty()) {
SG_LOG(SG_ATC, SG_ALERT,
"FGApproachController updating aircraft without traffic record at " << SG_ORIGIN);
} else {
first->setState(ATCMessageState::CLEARED_TAKEOFF);
transmit(&(*first), &(*parent), MSG_CLEARED_FOR_TAKEOFF, ATC_GROUND_TO_AIR, true);
}
} }
} }
//FIXME Make it an member of traffic record //FIXME Make it an member of traffic record
if (current.getAircraft()->getTakeOffStatus() == AITakeOffStatus::CLEARED_FOR_TAKEOFF) { if (current.getAircraft()->getTakeOffStatus() == AITakeOffStatus::CLEARED_FOR_TAKEOFF &&
current.getRunwaySlot() < now) {
current.setHoldPosition(false); current.setHoldPosition(false);
if (checkTransmissionState(ATCMessageState::CLEARED_TAKEOFF, ATCMessageState::CLEARED_TAKEOFF, i, now, MSG_ACKNOWLEDGE_CLEARED_FOR_TAKEOFF, ATC_AIR_TO_GROUND)) {
current.setState(ATCMessageState::ANNOUNCE_ARRIVAL);
}
} else { } else {
current.setHoldPosition(true); current.setHoldPosition(true);
SG_LOG(SG_ATC, SG_BULK,
current.getCallsign() << "| Waiting for " << (current.getRunwaySlot() - now) << " seconds");
} }
int clearanceId = rwy->getCleared(); int clearanceId = rwy->getCleared();
if (clearanceId) { if (clearanceId) {
if (id == clearanceId) { if (id == clearanceId) {
SG_LOG(SG_ATC, SG_BULK, "Unset Hold " << clearanceId << " for " << rwy->getRunwayName()); SG_LOG(SG_ATC, SG_BULK, current.getCallsign() << "| Unset Hold " << clearanceId << " for rwy " << rwy->getRunwayName());
current.setHoldPosition(false); current.setHoldPosition(false);
} else { } else {
SG_LOG(SG_ATC, SG_WARN, "Not cleared " << id << " Currently cleared " << clearanceId); SG_LOG(SG_ATC, SG_BULK, current.getCallsign() << "| Not cleared " << id << " Currently cleared " << clearanceId);
} }
} else { } else {
if (current.getAircraft() == rwy->getFirstAircraftInDepartureQueue()) { if (current.getAircraft() == rwy->getFirstAircraftInDepartureQueue()) {
SG_LOG(SG_ATC, SG_BULK, SG_LOG(SG_ATC, SG_BULK,
"Cleared " << current.getAircraft()->getCallSign() << " for " << rwy->getRunwayName() << " Id " << id); current.getCallsign() << "| Cleared for runway " << getName() << " " << rwy->getRunwayName() << " Id " << id);
rwy->setCleared(id); rwy->setCleared(id);
auto ac = rwy->getFirstOfStatus(1); auto ac = rwy->getFirstOfStatus(AITakeOffStatus::QUEUED);
if (ac) { if (ac) {
ac->setTakeOffStatus(AITakeOffStatus::QUEUED); ac->setTakeOffStatus(AITakeOffStatus::QUEUED);
// transmit takeoff clearacne? But why twice? // transmit takeoff clearacne? But why twice?
@ -241,9 +261,8 @@ void FGTowerController::signOff(int id)
}); });
if (runwayIt != activeRunways.end()) { if (runwayIt != activeRunways.end()) {
SG_LOG(SG_ATC, SG_BULK, "Cleared " << id << " from " << runwayIt->getRunwayName() ); SG_LOG(SG_ATC, SG_BULK, i->getCallsign() << "|Cleared " << id << " from " << runwayIt->getRunwayName() << " cleared " << runwayIt->getCleared() );
runwayIt->setCleared(0); runwayIt->removeFromDepartureQueue(id);
runwayIt->updateDepartureQueue();
} else { } else {
SG_LOG(SG_ATC, SG_ALERT, SG_LOG(SG_ATC, SG_ALERT,
"AI error: Attempting to erase non-existing runway clearance record in FGTowerController::signoff at " << SG_ORIGIN); "AI error: Attempting to erase non-existing runway clearance record in FGTowerController::signoff at " << SG_ORIGIN);
@ -294,9 +313,10 @@ void FGTowerController::render(bool visible) {
} }
string FGTowerController::getName() { string FGTowerController::getName() {
return string(parent->getId() + "-tower"); return string(parent->parent()->getName() + "-tower");
} }
void FGTowerController::update(double dt) void FGTowerController::update(double dt)
{ {
FGATCController::eraseDeadTraffic(); FGATCController::eraseDeadTraffic();

View file

@ -59,9 +59,9 @@ FGATCManager::~FGATCManager() {
} }
/** /**
Sets up ATC subsystem parts depending on other subsystems * Sets up ATC subsystem parts depending on other subsystems
Override of SGSubsystem::postinit() * Override of SGSubsystem::postinit()
Will set private boolean flag "initSucceeded" to true upon conclusion * Will set private boolean flag "initSucceeded" to true upon conclusion
*/ */
void FGATCManager::postinit() void FGATCManager::postinit()
{ {

View file

@ -67,12 +67,23 @@ ActiveRunway::ActiveRunway(const std::string& r, int cc) :
distanceToFinal = 6.0 * SG_NM_TO_METER; distanceToFinal = 6.0 * SG_NM_TO_METER;
}; };
void ActiveRunway::removeFromDepartureQueue(int id) {
if (id!=currentlyCleared) {
printDepartureQueue();
SG_LOG(SG_ATC, SG_WARN, "Not cleared id being removed from DepartureQueue " << id << " currently cleared " << currentlyCleared);
} else {
setCleared(0);
updateDepartureQueue();
printDepartureQueue();
}
}
void ActiveRunway::updateDepartureQueue() void ActiveRunway::updateDepartureQueue()
{ {
departureQueue.erase(departureQueue.begin()); departureQueue.erase(departureQueue.begin());
} }
/* /**
* Fetch next slot for the active runway * Fetch next slot for the active runway
* @param eta time of slot requested * @param eta time of slot requested
* @return newEta: next slot available; starts at eta paramater * @return newEta: next slot available; starts at eta paramater
@ -92,12 +103,12 @@ time_t ActiveRunway::requestTimeSlot(time_t eta)
// 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);
SG_LOG(SG_ATC, SG_DEBUG, getRunwayName() << "Checked eta slots, using " << eta); SG_LOG(SG_ATC, SG_BULK, getRunwayName() << " Checked eta slots, using " << eta);
return eta; return eta;
} else { } else {
// 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, getRunwayName() << " Checking eta slots " << eta << " : " << estimatedArrivalTimes.size() << " Timediff " << (eta - globals->get_time_params()->get_cur_time())); SG_LOG(SG_ATC, SG_BULK, getRunwayName() << " Checking eta slots " << eta << " : " << estimatedArrivalTimes.size() << " Timediff : " << (eta - globals->get_time_params()->get_cur_time()));
// is this needed - just a debug output? // is this needed - just a debug output?
for (i = estimatedArrivalTimes.begin(); for (i = estimatedArrivalTimes.begin();
@ -110,7 +121,7 @@ time_t ActiveRunway::requestTimeSlot(time_t eta)
if ((eta + separation) < (*i)) { if ((eta + separation) < (*i)) {
newEta = eta; newEta = eta;
SG_LOG(SG_ATC, SG_BULK, "Storing at beginning"); SG_LOG(SG_ATC, SG_BULK, "Storing at beginning");
SG_LOG(SG_ATC, SG_DEBUG, "Done. New ETA : " << newEta); SG_LOG(SG_ATC, SG_DEBUG, "Done. New ETA : " << newEta );
slotHousekeeping(newEta); slotHousekeeping(newEta);
return newEta; return newEta;
} }
@ -128,7 +139,7 @@ time_t ActiveRunway::requestTimeSlot(time_t eta)
newEta = (*i) + separation; newEta = (*i) + separation;
SG_LOG(SG_ATC, SG_BULK, "Storing at end + separation"); SG_LOG(SG_ATC, SG_BULK, "Storing at end + separation");
} }
SG_LOG(SG_ATC, SG_DEBUG, "Done. New ETA : " << newEta); SG_LOG(SG_ATC, SG_DEBUG, "Done. New ETA : " << newEta << " Timediff : " << (newEta-eta));
slotHousekeeping(newEta); slotHousekeeping(newEta);
return newEta; return newEta;
} else { } else {
@ -197,7 +208,7 @@ void ActiveRunway::slotHousekeeping(time_t newEta)
} }
} }
/* Output the contents of the departure queue vector nicely formatted*/ /** Output the contents of the departure queue vector nicely formatted*/
void ActiveRunway::printDepartureQueue() void ActiveRunway::printDepartureQueue()
{ {
SG_LOG(SG_ATC, SG_DEBUG, "Departure queue for " << rwy << ": "); SG_LOG(SG_ATC, SG_DEBUG, "Departure queue for " << rwy << ": ");
@ -208,7 +219,7 @@ void ActiveRunway::printDepartureQueue()
} }
/* Fetch the first aircraft in the departure queue with a certain status */ /** Fetch the first aircraft in the departure queue with a certain status */
SGSharedPtr<FGAIAircraft>ActiveRunway::getFirstOfStatus(int stat) const 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) {
@ -316,10 +327,14 @@ bool FGTrafficRecord::isDead() const {
bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord & other) bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord & other)
{ {
bool result = false; bool result = false;
SG_LOG(SG_ATC, SG_BULK, getCallsign() << "|checkPositionAndIntentions"); SG_LOG(SG_ATC, SG_BULK, getCallsign() << "| checkPositionAndIntentions CurrentPos : " << currentPos << " Other : " << other.currentPos << " Leg : " << leg << " Other Leg : " << other.leg );
if (currentPos == other.currentPos && getId() != other.getId() ) { if (currentPos == other.currentPos && getId() != other.getId() ) {
SG_LOG(SG_ATC, SG_BULK, getCallsign() << "|Check Position and intentions: " << other.getCallsign() << " we are on the same taxiway; Index = " << currentPos); SG_LOG(SG_ATC, SG_BULK, getCallsign() << "| Check Position and intentions: " << other.getCallsign() << " we are on the same taxiway; Index = " << currentPos);
result = true; int headingTowards = SGGeodesy::courseDeg( other.getPos(), getPos() );
int headingDiff = SGMiscd::normalizePeriodic(-180, 180, headingTowards - getHeading() );
SG_LOG(SG_ATC, SG_BULK, getCallsign() << "| " << heading << "\t" << headingTowards << "\t" << headingDiff);
// getHeading()
result = abs(headingDiff) < 89;
} }
// else if (! other.intentions.empty()) // else if (! other.intentions.empty())
// { // {
@ -331,8 +346,8 @@ bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord & other)
// SG_LOG(SG_ATC, SG_BULK, "Check Position and intentions: current matches other.intentions"); // SG_LOG(SG_ATC, SG_BULK, "Check Position and intentions: current matches other.intentions");
// result = true; // result = true;
// } // }
else if (! intentions.empty()) { else if (!intentions.empty()) {
SG_LOG(SG_ATC, SG_BULK, getCallsign() << "|Itentions " << intentions.size()); SG_LOG(SG_ATC, SG_BULK, getCallsign() << "| Itentions Size " << intentions.size());
intVecIterator i = intentions.begin(); intVecIterator i = intentions.begin();
//while (!((i == intentions.end()) || ((*i) == other.currentPos))) //while (!((i == intentions.end()) || ((*i) == other.currentPos)))
while (i != intentions.end()) { while (i != intentions.end()) {
@ -343,7 +358,13 @@ bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord & other)
} }
if (i != intentions.end()) { if (i != intentions.end()) {
SG_LOG(SG_ATC, SG_BULK, getCallsign() << "| Check Position and intentions: " << other.getCallsign()<< " matches Index = " << (*i)); SG_LOG(SG_ATC, SG_BULK, getCallsign() << "| Check Position and intentions: " << other.getCallsign()<< " matches Index = " << (*i));
result = true; int headingTowards = SGGeodesy::courseDeg( other.getPos(), getPos() );
int distanceM = SGGeodesy::distanceM( other.getPos(), getPos() );
int headingDiff = SGMiscd::normalizePeriodic(-180, 180, headingTowards - getHeading() );
SG_LOG(SG_ATC, SG_BULK, getCallsign() << "| Heading : " << heading << "\t Heading Other->Current" << headingTowards << "\t Heading Diff :" << headingDiff << "\t Distance : " << distanceM);
// difference of heading is small and it's actually near
result = abs(headingDiff) < 89 && distanceM < 400;
// result = true;
} }
} }
return result; return result;

View file

@ -64,6 +64,7 @@ class FGATCInstruction
{ {
private: private:
bool holdPattern; bool holdPattern;
int requestedArrivalTime;
bool holdPosition; bool holdPosition;
bool changeSpeed; bool changeSpeed;
bool changeHeading; bool changeHeading;
@ -80,6 +81,12 @@ public:
bool getHoldPattern () const { bool getHoldPattern () const {
return holdPattern; return holdPattern;
}; };
void setRunwaySlot (int val) {
requestedArrivalTime = val;
};
int getRunwaySlot () const {
return requestedArrivalTime;
};
bool getHoldPosition () const { bool getHoldPosition () const {
return holdPosition; return holdPosition;
}; };
@ -156,6 +163,7 @@ private:
bool allowTransmission; bool allowTransmission;
bool allowPushback; bool allowPushback;
int priority; int priority;
int plannedArrivalTime;
time_t timer; time_t timer;
intVec intentions; intVec intentions;
FGATCInstruction instruction; FGATCInstruction instruction;
@ -186,9 +194,15 @@ public:
int getId() const { int getId() const {
return id; return id;
}; };
/**
* Return the current ATC State of type @see ATCMessageState
*/
int getState() const { int getState() const {
return state; return state;
}; };
/**
* Set the current ATC State of type @see ATCMessageState
*/
void setState(int s) { void setState(int s) {
state = s; state = s;
} }
@ -212,7 +226,23 @@ public:
bool getSpeedAdjustment() const { bool getSpeedAdjustment() const {
return instruction.getChangeSpeed(); return instruction.getChangeSpeed();
}; };
void setPlannedArrivalTime (int val) {
plannedArrivalTime = val;
};
/**Arrival time planned by aircraft.*/
int getPlannedArrivalTime () const {
return plannedArrivalTime;
};
void setRunwaySlot( int val ) {
if (plannedArrivalTime) {
SG_LOG(SG_ATC, SG_BULK, callsign << "| Runwayslot " << (val-plannedArrivalTime));
}
instruction.setRunwaySlot(val);
};
/**Arrival time requested by ATC.*/
int getRunwaySlot() {
return instruction.getRunwaySlot();
};
SGGeod getPos() { SGGeod getPos() {
return pos; return pos;
} }
@ -251,7 +281,6 @@ public:
void setHoldPosition (bool inst) { void setHoldPosition (bool inst) {
instruction.setHoldPosition(inst); instruction.setHoldPosition(inst);
}; };
void setWaitsForId(int id) { void setWaitsForId(int id) {
waitsForId = id; waitsForId = id;
}; };
@ -368,6 +397,8 @@ public:
SGSharedPtr<FGAIAircraft> getFirstOfStatus(int stat) const; SGSharedPtr<FGAIAircraft> getFirstOfStatus(int stat) const;
void removeFromDepartureQueue(int id);
void updateDepartureQueue(); void updateDepartureQueue();
void printDepartureQueue(); void printDepartureQueue();

View file

@ -1031,7 +1031,7 @@ FGAIAircraft * TrafficTests::flyAI(SGSharedPtr<FGAIAircraft> aiAircraft, std::st
int startSpeed = aiAircraft->GetFlightPlan()->getCurrentWaypoint()->getSpeed(); int startSpeed = aiAircraft->GetFlightPlan()->getCurrentWaypoint()->getSpeed();
aiAircraft->AccelTo(startSpeed); aiAircraft->AccelTo(startSpeed);
for (size_t i = 0; i < 12000000 && !(aiAircraft->getDie()) && aiAircraft->GetFlightPlan()->getLeg() < 10; i++) { for (size_t i = 0; i < 12000000 && !(aiAircraft->getDie()) && aiAircraft->GetFlightPlan()->getLeg() <= AILeg::PARKING; i++) {
CPPUNIT_ASSERT_EQUAL(aiAircraft->GetFlightPlan()->isValidPlan(), true); CPPUNIT_ASSERT_EQUAL(aiAircraft->GetFlightPlan()->isValidPlan(), true);
if (!aiAircraft->getDie()) { if (!aiAircraft->getDie()) {
// collect position // collect position
@ -1072,7 +1072,7 @@ FGAIAircraft * TrafficTests::flyAI(SGSharedPtr<FGAIAircraft> aiAircraft, std::st
aiAircraft->dumpCSV(csvFile, lineIndex++); aiAircraft->dumpCSV(csvFile, lineIndex++);
// A flight without loops should never reach 400° // A flight without loops should never reach 400°
CPPUNIT_ASSERT_LESSEQUAL(400.0, headingSum); CPPUNIT_ASSERT_LESSEQUAL(400.0, headingSum);
CPPUNIT_ASSERT_LESSEQUAL(10, aiAircraft->GetFlightPlan()->getLeg()); CPPUNIT_ASSERT_LESSEQUAL( 10, aiAircraft->GetFlightPlan()->getLeg());
CPPUNIT_ASSERT_MESSAGE( "Aircraft has not completed test in time.", i < 3000000); CPPUNIT_ASSERT_MESSAGE( "Aircraft has not completed test in time.", i < 3000000);
// Arrived at a parking // Arrived at a parking
int beforeNextDepTime = aiAircraft->getTrafficRef()->getDepartureTime() - 30; int beforeNextDepTime = aiAircraft->getTrafficRef()->getDepartureTime() - 30;