#include <algorithm>
#include "trafficcontrol.hxx"
+#include "atc_mgr.hxx"
#include <AIModel/AIAircraft.hxx>
#include <AIModel/AIFlightPlan.hxx>
#include <AIModel/performancedata.hxx>
#include <AIModel/performancedb.hxx>
+#include <ATC/atc_mgr.hxx>
#include <Traffic/TrafficMgr.hxx>
#include <Airports/groundnetwork.hxx>
#include <Airports/dynamics.hxx>
bool FGTrafficRecord::pushBackAllowed()
{
+ // With the user ATC / AI integration, checking whether the user's aircraft is near no longer works, because
+ // this will effectively block the user's aircraft itself from receiving pushback clearance.
+ // So, what can we do?
+ /*
double course, az2, dist;
SGGeod curr(SGGeod::fromDegM(getLongitude(),
getLatitude(), getAltitude()));
SGGeodesy::inverse(curr, user, course, az2, dist);
//cerr << "Distance to user : " << dist << endl;
return (dist > 250);
+ */
+
+ // In essence, we should check whether the pusbback route itself, as well as the associcated
+ // taxiways near the pushback point are free of traffic.
+ // To do so, we need to
+ return true;
}
FGATCController::FGATCController()
{
+ cerr << "running FGATController constructor" << endl;
dt_count = 0;
available = true;
lastTransmission = 0;
+ initialized = false;
+}
+
+FGATCController::~FGATCController()
+{
+ cerr << "running FGATController destructor" << endl;
}
string FGATCController::getGateName(FGAIAircraft * ref)
return ref->atGate();
}
+bool FGATCController::isUserAircraft(FGAIAircraft* ac)
+{
+ return (ac->getCallSign() == fgGetString("/sim/multiplay/callsign")) ? true : false;
+};
+
void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
- AtcMsgDir msgDir)
+ AtcMsgDir msgDir, bool audible)
{
string sender, receiver;
int stationFreq = 0;
text = text + sender + ". Transmitting unknown Message";
break;
}
- double onBoardRadioFreq0 =
- fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
- double onBoardRadioFreq1 =
- fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
- int onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 100 + 0.5);
- int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5);
- //cerr << "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl;
-
- // Display ATC message only when one of the radios is tuned
- // the relevant frequency.
- // Note that distance attenuation is currently not yet implemented
- if ((onBoardRadioFreqI0 == stationFreq)
- || (onBoardRadioFreqI1 == stationFreq)) {
- if (rec->allowTransmissions()) {
- fgSetString("/sim/messages/atc", text.c_str());
+ if (audible) {
+ double onBoardRadioFreq0 =
+ fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
+ double onBoardRadioFreq1 =
+ fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz");
+ int onBoardRadioFreqI0 = (int) floor(onBoardRadioFreq0 * 100 + 0.5);
+ int onBoardRadioFreqI1 = (int) floor(onBoardRadioFreq1 * 100 + 0.5);
+ //cerr << "Using " << onBoardRadioFreq0 << ", " << onBoardRadioFreq1 << " and " << stationFreq << " for " << text << endl;
+
+ // Display ATC message only when one of the radios is tuned
+ // the relevant frequency.
+ // Note that distance attenuation is currently not yet implemented
+ if ((onBoardRadioFreqI0 == stationFreq)
+ || (onBoardRadioFreqI1 == stationFreq)) {
+ if (rec->allowTransmissions()) {
+ fgSetString("/sim/messages/atc", text.c_str());
+ }
}
+ } else {
+ FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
+ atc->getATCDialog()->addEntry(1, text);
+
}
}
}
}
+void FGATCController::init()
+{
+ if (!initialized) {
+ FGATCManager *mgr = (FGATCManager*) globals->get_subsystem("ATC");
+ mgr->addController(this);
+ initialized = true;
+ }
+}
+
/***************************************************************************
* class FGTowerController
*
double radius, int leg,
FGAIAircraft * ref)
{
+ init();
TrafficVectorIterator i = activeTraffic.begin();
// Search whether the current id alread has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
}
}
-void FGTowerController::update(int id, double lat, double lon,
- double heading, double speed, double alt,
- double dt)
+void FGTowerController::updateAircraftInformation(int id, double lat, double lon,
+ double heading, double speed, double alt,
+ double dt)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search whether the current id has an entry
double radius, int leg,
FGAIAircraft * ref)
{
+ init();
TrafficVectorIterator i = activeTraffic.begin();
// Search whether the current id alread has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
}
}
-void FGStartupController::update(int id, double lat, double lon,
- double heading, double speed, double alt,
- double dt)
+bool FGStartupController::checkTransmissionState(int st, time_t now, time_t startTime, TrafficVectorIterator i, AtcMsgId msgId,
+ AtcMsgDir msgDir)
+{
+ int state = i->getState();
+ if ((state == st) && available) {
+ if ((msgDir == ATC_AIR_TO_GROUND) && isUserAircraft(i->getAircraft())) {
+
+ cerr << "Checking state " << st << " for " << i->getAircraft()->getCallSign() << endl;
+ static 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);
+ cerr << "Selected transmission message" << n << endl;
+ FGATCManager *atc = (FGATCManager*) globals->get_subsystem("atc");
+ atc->getATCDialog()->removeEntry(1);
+ } else {
+ cerr << "creading message for " << i->getAircraft()->getCallSign() << endl;
+ transmit(&(*i), msgId, msgDir, false);
+ return false;
+ }
+ }
+ if (now > startTime) {
+ //cerr << "Transmitting startup msg" << endl;
+ transmit(&(*i), msgId, msgDir, true);
+ i->updateState();
+ lastTransmission = now;
+ available = false;
+ return true;
+ }
+ }
+ return false;
+}
+
+void FGStartupController::updateAircraftInformation(int id, double lat, double lon,
+ double heading, double speed, double alt,
+ double dt)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry
}
}
// // update position of the current aircraft
+
if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
SG_LOG(SG_GENERAL, SG_ALERT,
"AI error: updating aircraft without traffic record");
setDt(getDt() + dt);
int state = i->getState();
- time_t startTime =
- i->getAircraft()->getTrafficRef()->getDepartureTime();
+
+ // The user controlled aircraft should have crased here, because it doesn't have a traffic reference.
+ // NOTE: if we create a traffic schedule for the user aircraft, we can use this to plan a flight.
+ time_t startTime = i->getAircraft()->getTrafficRef()->getDepartureTime();
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
//cerr << i->getAircraft()->getTrafficRef()->getCallSign()
// << " is scheduled to depart in " << startTime-now << " seconds. Available = " << available
available = true;
}
- if ((state == 0) && available) {
- if (now > startTime) {
- //cerr << "Transmitting startup msg" << endl;
- transmit(&(*i), MSG_ANNOUNCE_ENGINE_START, ATC_AIR_TO_GROUND);
- i->updateState();
- lastTransmission = now;
- available = false;
- }
- }
- if ((state == 1) && available) {
- if (now > startTime + 60) {
- transmit(&(*i), MSG_REQUEST_ENGINE_START, ATC_AIR_TO_GROUND);
- i->updateState();
- lastTransmission = now;
- available = false;
- }
- }
- if ((state == 2) && available) {
- if (now > startTime + 80) {
- transmit(&(*i), MSG_PERMIT_ENGINE_START, ATC_GROUND_TO_AIR);
- i->updateState();
- lastTransmission = now;
- available = false;
- }
- }
- if ((state == 3) && available) {
- if (now > startTime + 100) {
- transmit(&(*i), MSG_ACKNOWLEDGE_ENGINE_START,
- ATC_AIR_TO_GROUND);
- i->updateState();
- lastTransmission = now;
- available = false;
- }
- }
- // Note: The next four stages are only necessesary when Startup control is
- // on a different frequency, compared to ground control
- if ((state == 4) && available) {
- if (now > startTime + 130) {
- transmit(&(*i), MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY,
- ATC_AIR_TO_GROUND);
- i->updateState();
- i->nextFrequency();
- lastTransmission = now;
- available = false;
- }
- }
- if ((state == 5) && available) {
- if (now > startTime + 140) {
- transmit(&(*i), MSG_INITIATE_CONTACT, ATC_AIR_TO_GROUND);
- i->updateState();
- lastTransmission = now;
- available = false;
- }
- }
- if ((state == 6) && available) {
- if (now > startTime + 150) {
- transmit(&(*i), MSG_ACKNOWLEDGE_INITIATE_CONTACT,
- ATC_GROUND_TO_AIR);
- i->updateState();
- lastTransmission = now;
- available = false;
- }
+ checkTransmissionState(0, now, (startTime + 0 ), i, MSG_ANNOUNCE_ENGINE_START, ATC_AIR_TO_GROUND);
+ checkTransmissionState(1, now, (startTime + 60 ), i, MSG_REQUEST_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);
+ checkTransmissionState(6, now, (startTime + 150), i, MSG_ACKNOWLEDGE_INITIATE_CONTACT, ATC_GROUND_TO_AIR);
+ checkTransmissionState(7, now, (startTime + 180), i, MSG_REQUEST_PUSHBACK_CLEARANCE, ATC_AIR_TO_GROUND);
- // TODO: Switch to APRON control and request pushback Clearance.
- // Get Push back clearance
- if ((state == 7) && available) {
- if (now > startTime + 180) {
- transmit(&(*i), MSG_REQUEST_PUSHBACK_CLEARANCE,
- ATC_AIR_TO_GROUND);
- i->updateState();
- lastTransmission = now;
- available = false;
- }
- }
+
+
if ((state == 8) && available) {
if (now > startTime + 200) {
if (i->pushBackAllowed()) {
i->allowRepeatedTransmissions();
transmit(&(*i), MSG_PERMIT_PUSHBACK_CLEARANCE,
- ATC_GROUND_TO_AIR);
+ ATC_GROUND_TO_AIR, true);
i->updateState();
} else {
transmit(&(*i), MSG_HOLD_PUSHBACK_CLEARANCE,
- ATC_GROUND_TO_AIR);
+ ATC_GROUND_TO_AIR, true);
i->suppressRepeatedTransmissions();
}
lastTransmission = now;
double alt, double radius,
int leg, FGAIAircraft * ref)
{
+ init();
TrafficVectorIterator i = activeTraffic.begin();
// Search whether the current id alread has an entry
// This might be faster using a map instead of a vector, but let's start by taking a safe route
}
}
-void FGApproachController::update(int id, double lat, double lon,
- double heading, double speed, double alt,
- double dt)
+void FGApproachController::updateAircraftInformation(int id, double lat, double lon,
+ double heading, double speed, double alt,
+ double dt)
{
TrafficVectorIterator i = activeTraffic.begin();
// Search search if the current id has an entry