#include <simgear/sound/soundmgr.hxx>
+#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include "ATC.hxx"
responseID = "";
responseReqd = false;
_type = INVALID;
+ _display = false;
+ _displaying = false;
+
+ // Transmission timing stuff
+ pending_transmission = "";
+ _timeout = 0;
+ _pending = false;
+ _callback_code = 0;
+ _transmit = false;
+ _transmitting = false;
+ _counter = 0.0;
+ _max_count = 5.0;
}
FGATC::~FGATC() {
_releaseCounter += dt;
}
}
+
+ // Transmission stuff cribbed from AIPlane.cxx
+ if(_pending) {
+ if(GetFreqClear()) {
+ //cout << "TUNED STATION FREQ CLEAR\n";
+ SetFreqInUse();
+ _pending = false;
+ _transmit = true;
+ _transmitting = false;
+ } else {
+ if(_timeout > 0.0) { // allows count down to be avoided by initially setting it to zero
+ _timeout -= dt;
+ if(_timeout <= 0.0) {
+ _timeout = 0.0;
+ _pending = false;
+ // timed out - don't render.
+ }
+ }
+ }
+ }
+
+ if(_transmit) {
+ _counter = 0.0;
+ _max_count = 5.0; // FIXME - hardwired length of message - need to calculate it!
+
+ //cout << "Transmission = " << pending_transmission << '\n';
+ if(_display) {
+ //Render(pending_transmission, ident, false);
+ // At the moment Render only works for ATIS
+ globals->get_ATC_display()->RegisterSingleMessage(pending_transmission);
+ }
+ // Run the callback regardless of whether on same freq as user or not.
+ //cout << "_callback_code = " << _callback_code << '\n';
+ if(_callback_code) {
+ ProcessCallback(_callback_code);
+ }
+ _transmit = false;
+ _transmitting = true;
+ } else if(_transmitting) {
+ if(_counter >= _max_count) {
+ //NoRender(plane.callsign); commented out since at the moment NoRender is designed just to stop repeating messages,
+ // and this will be primarily used on single messages.
+ _transmitting = false;
+ //if(tuned_station) tuned_station->NotifyTransmissionFinished(plane.callsign);
+ // TODO - need to let the plane the transmission is aimed at that it's finished.
+ }
+ _counter += dt;
+ }
}
void FGATC::ReceiveUserCallback(int code) {
}
}
-void FGATC::AddPlane(string pid) {
+void FGATC::Transmit(int callback_code) {
+ SG_LOG(SG_ATC, SG_INFO, "Transmit called by " << ident << " " << _type << ", msg = " << pending_transmission);
+ _pending = true;
+ _callback_code = callback_code;
+ _timeout = 0.0;
}
-int FGATC::RemovePlane() {
- return 0;
+void FGATC::ConditionalTransmit(double timeout, int callback_code) {
+ SG_LOG(SG_ATC, SG_INFO, "Timed transmit called by " << ident << " " << _type << ", msg = " << pending_transmission);
+ _pending = true;
+ _callback_code = callback_code;
+ _timeout = timeout;
+}
+
+void FGATC::ImmediateTransmit(int callback_code) {
+ SG_LOG(SG_ATC, SG_INFO, "Immediate transmit called by " << ident << " " << _type << ", msg = " << pending_transmission);
+ if(_display) {
+ //Render(pending_transmission, ident, false);
+ // At the moment Render doesn't work except for ATIS
+ globals->get_ATC_display()->RegisterSingleMessage(pending_transmission);
+ }
+ if(callback_code) {
+ ProcessCallback(callback_code);
+ }
}
-void FGATC::SetDisplay() {
+// Derived classes should override this.
+void FGATC::ProcessCallback(int code) {
}
-void FGATC::SetNoDisplay() {
+void FGATC::AddPlane(string pid) {
+}
+
+int FGATC::RemovePlane() {
+ return 0;
}
void FGATC::SetData(ATCData* d) {
virtual int RemovePlane();
// Indicate that this instance should output to the display if appropriate
- virtual void SetDisplay();
+ inline void SetDisplay() { _display = true; }
// Indicate that this instance should not output to the display
- virtual void SetNoDisplay();
+ inline void SetNoDisplay() { _display = false; }
// Generate the text of a message from its parameters and the current context.
virtual string GenText(const string& m, int c);
// Requires the sound manager refname if audio, else "".
void NoRender(string refname);
+ // Transmit a message when channel becomes free of other dialog
+ void Transmit(int callback_code = 0);
+
+ // Transmit a message if channel becomes free within timeout (seconds). timeout of zero implies no limit
+ void ConditionalTransmit(double timeout, int callback_code = 0);
+
+ // Transmit regardless of other dialog on the channel eg emergency
+ void ImmediateTransmit(int callback_code = 0);
+
+ virtual void ProcessCallback(int code);
+
double lon, lat, elev;
double x, y, z;
int freq;
bool playing; // Indicates a message in progress
bool voiceOK; // Flag - true if at least one voice has loaded OK
FGATCVoice* vPtr;
-
+
+ string pending_transmission; // derived classes set this string before calling Transmit(...)
bool freqClear; // Flag to indicate if the frequency is clear of ongoing dialog
bool receiving; // Flag to indicate we are receiving a transmission
bool responseReqd; // Flag to indicate we should be responding to a request/report
bool _runReleaseCounter; // A timer for releasing the frequency after giving the message enough time to display
double _releaseTime;
double _releaseCounter;
+
+ bool _display; // Flag to indicate whether we should be outputting to the ATC display.
+ bool _displaying; // Flag to indicate whether we are outputting to the ATC display.
+
+private:
+ // Transmission timing stuff.
+ bool _pending;
+ double _timeout;
+ int _callback_code; // A callback code to be notified and processed by the derived classes
+ // A value of zero indicates no callback required
+ bool _transmit; // we are to transmit
+ bool _transmitting; // we are transmitting
+ double _counter;
+ double _max_count;
};
inline istream&
}
void FGApproach::Init() {
- display = false;
}
double active_rw_lat;
double active_rw_len;
- bool display; // Flag to indicate whether we should be outputting to the display.
- bool displaying; // Flag to indicate whether we are outputting to the display.
int num_planes; // number of planes on the stack
PlaneApp planes[max_planes]; // Array of planes
string transmission;
// Remove plane from stack if out of range
int RemovePlane();
- //Indicate that this instance should be outputting to the ATC display
- inline void SetDisplay(void) {display = true;}
-
- //Indicate that this instance should not be outputting to the ATC display
- inline void SetNoDisplay(void) {display = false;}
-
inline double get_bucket() const { return bucket; }
inline int get_pnum() const { return num_planes; }
inline string get_trans_ident() { return trans_ident; }
#include "ATCmgr.hxx"
FGATIS::FGATIS() :
- display(false),
- displaying(false),
transmission(""),
trans_ident(""),
atis_failed(false),
// Main update function - checks whether we are displaying or not the correct message.
void FGATIS::Update(double dt) {
- if(display) {
- if(displaying) {
+ if(_display) {
+ if(_displaying) {
// Check if we need to update the message
// - basically every hour and if the weather changes significantly at the station
//globals->get_ATC_display()->ChangeRepeatingMessage(transmission);
UpdateTransmission();
//cout << "ATIS.CXX - calling ATCMgr to render transmission..." << endl;
Render(transmission, refname, true);
- displaying = true;
+ _displaying = true;
}
} else {
// We shouldn't be displaying
- if(displaying) {
+ if(_displaying) {
//cout << "ATIS.CXX - calling NoRender()..." << endl;
NoRender(refname);
- displaying = false;
+ _displaying = false;
}
}
}
class FGATIS : public FGATC {
//atc_type type;
- bool display; // Flag to indicate whether we should be outputting to the ATC display.
- bool displaying; // Flag to indicate whether we are outputting to the ATC display.
string transmission; // The actual ATIS transmission
// This is not stored in default.atis but is generated
// from the prevailing conditions when required.
//run the ATIS instance
void Update(double dt);
- //Indicate that this instance should be outputting to the ATC display
- inline void SetDisplay(void) {display = true;}
-
- //Indicate that this instance should not be outputting to the ATC display
- inline void SetNoDisplay(void) {display = false;}
-
//inline void set_type(const atc_type tp) {type = tp;}
inline string get_trans_ident() { return trans_ident; }
inline void set_refname(string r) { refname = r; }
FGGround::FGGround() {
ATCmgr = globals->get_ATC_mgr();
_type = GROUND;
- display = false;
networkLoadOK = false;
ground_traffic.erase(ground_traffic.begin(), ground_traffic.end());
ground_traffic_itr = ground_traffic.begin();
FGGround::FGGround(string id) {
ATCmgr = globals->get_ATC_mgr();
- display = false;
networkLoadOK = false;
ground_traffic.erase(ground_traffic.begin(), ground_traffic.end());
ground_traffic_itr = ground_traffic.begin();
}
void FGGround::Init() {
- display = false;
untowered = false;
// Figure out which is the active runway - TODO - it would be better to have ground call tower
trns += " taxi holding point runway "; // TODO - add the holding point name
// eg " taxi holding point G2 runway "
trns += ConvertRwyNumToSpokenString(activeRwy);
- if(display) {
+ if(_display) {
globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
}
g->planePtr->RegisterTransmission(1); // cleared to taxi
char buf[10];
sprintf(buf, "%.2f", f);
trns += buf;
- if(display) {
+ if(_display) {
globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
}
g->planePtr->RegisterTransmission(2); // contact tower
void Update(double dt);
inline string get_trans_ident() { return trans_ident; }
- inline void SetDisplay() {display = true;}
- inline void SetNoDisplay() {display = false;}
// Contact ground control on arrival, assumed to request any gate
//void NewArrival(plane_rec plane);
SGPropertyNode* wind_from_hdg; //degrees
SGPropertyNode* wind_speed_knots; //knots
- bool display; // Flag to indicate whether we should be outputting to the ATC display.
- bool displaying; // Flag to indicate whether we are outputting to the ATC display.
// for failure modeling
string trans_ident; // transmitted ident
bool ground_failed; // ground failed?
void FGTower::Init() {
//cout << "Initialising tower " << ident << '\n';
- display = false;
// Pointers to user's position
user_lon_node = fgGetNode("/position/longitude-deg", true);
ground = new FGGround(ident);
separateGround = false;
ground->Init();
- if(display) {
+ if(_display) {
ground->SetDisplay();
} else {
ground->SetNoDisplay();
ground = new FGGround(ident);
separateGround = false;
ground->Init();
- if(display) {
+ if(_display) {
ground->SetDisplay();
} else {
ground->SetNoDisplay();
ground = new FGGround(ident);
separateGround = false;
ground->Init();
- if(display) {
+ if(_display) {
ground->SetDisplay();
} else {
ground->SetNoDisplay();
// The display stuff might have to get more clever than this when not separate
// since the tower and ground might try communicating simultaneously even though
// they're mean't to be the same contoller/frequency!!
- if(display) {
+ // We could also get rid of this by overloading FGATC's Set(No)Display() functions.
+ if(_display) {
ground->SetDisplay();
} else {
ground->SetNoDisplay();
}
}
trns += ConvertRwyNumToSpokenString(activeRwy);
- if(display) {
+ if(_display) {
globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
} else {
//cout << "Not displaying, trns was " << trns << '\n';
t->clearedToLand = true;
if(!t->isUser) t->planePtr->RegisterTransmission(7);
}
- if(display) {
+ if(_display) {
globals->get_ATC_display()->RegisterSingleMessage(trns);
}
if(t->isUser) {
// Not currently sure under which circumstances we do or don't bother transmitting this.
string trns = t->plane.callsign;
trns += " hold position";
- if(display) {
+ if(_display) {
globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
}
// TODO - add some idea of what traffic is blocking him.
trns += " continue approach";
t->clearedToLand = false;
}
- if(display && disp) {
+ if(_display && disp) {
globals->get_ATC_display()->RegisterSingleMessage(trns);
}
t->finalAcknowledged = true;
if(!t->isUser) t->planePtr->RegisterTransmission(6); // TODO - this is a mega-hack!!
}
//cout << "trns = " << trns << '\n';
- if(display) {
+ if(_display) {
globals->get_ATC_display()->RegisterSingleMessage(trns);
}
// Maybe we should check that the plane really *has* vacated the runway!
departed = false;
timeSinceLastDeparture = 0.0;
}
- if(display) {
+ if(_display) {
globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
}
//cout << "Done ClearHoldingPlane " << endl;
// For now this should stop the AI plane landing on top of the user.
string trns = t->plane.callsign;
trns += " GO AROUND TRAFFIC ON RUNWAY I REPEAT GO AROUND";
- if(display) {
- globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
- }
+ pending_transmission = trns;
+ ImmediateTransmit();
t->instructedToGoAround = true;
t->clearedToLand = false;
// Assume it complies!!!
// For now this should stop the AI plane landing on top of the user.
string trns = t->plane.callsign;
trns += " GO AROUND TRAFFIC ON RUNWAY I REPEAT GO AROUND";
- if(display) {
- globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
- }
+ pending_transmission = trns;
+ ImmediateTransmit();
t->instructedToGoAround = true;
t->clearedToLand = false;
t->nextOnRwy = false; // But note this is recalculated so don't rely on it
if(distout > 10000) {
string trns = t->plane.callsign;
trns += " You are now clear of my airspace, good day";
- if(display) {
- globals->get_ATC_display()->RegisterSingleMessage(trns, 0);
- }
+ pending_transmission = trns;
+ Transmit();
if(t->isUser) {
// Change the communication options
RemoveAllUserDialogOptions();
// Get the pattern direction of the active rwy.
inline int GetPatternDirection() { return rwy.patternDirection; }
- inline void SetDisplay() { display = true; }
- inline void SetNoDisplay() { display = false; }
-
inline string get_trans_ident() { return trans_ident; }
inline FGGround* GetGroundPtr() { return ground; }
unsigned int update_count; // Convienince counter for speading computational load over several updates
unsigned int update_count_max; // ditto.
- bool display; // Flag to indicate whether we should be outputting to the ATC display.
- bool displaying; // Flag to indicate whether we are outputting to the ATC display.
-
double timeSinceLastDeparture; // Time in seconds since last departure from active rwy.
bool departed; // set true when the above needs incrementing with time, false when it doesn't.