1
0
Fork 0

Progress towards AI/ATC communication without speaking all at once

This commit is contained in:
daveluff 2003-10-06 15:20:47 +00:00
parent ea0751eaa2
commit 380c69c8a0
7 changed files with 263 additions and 90 deletions

View file

@ -319,7 +319,8 @@ void FGAILocalTraffic::Update(double dt) {
trns += buf;
trns += " ";
trns += plane.callsign;
Transmit(trns);
pending_transmission = trns;
Transmit(30.0);
responseCounter = 0.0;
contactTower = false;
changeFreq = true;
@ -414,7 +415,8 @@ void FGAILocalTraffic::Update(double dt) {
holdingShort = false;
string trns = "Cleared for take-off ";
trns += plane.callsign;
Transmit(trns);
pending_transmission = trns;
Transmit();
StartTaxi();
}
//cout << "^" << flush;
@ -476,7 +478,8 @@ void FGAILocalTraffic::Update(double dt) {
trns += plane.callsign;
trns += " on apron parking request taxi for traffic pattern";
//cout << "trns = " << trns << endl;
Transmit(trns);
pending_transmission = trns;
Transmit();
taxiRequestCleared = false;
taxiRequestPending = true;
}
@ -504,6 +507,9 @@ void FGAILocalTraffic::Update(double dt) {
fgSetDouble("/AI/Local1/ortho-x", (ortho.ConvertToLocal(pos)).x());
fgSetDouble("/AI/Local1/ortho-y", (ortho.ConvertToLocal(pos)).y());
fgSetDouble("/AI/Local1/elev", pos.elev() * SG_METER_TO_FEET);
// And finally, call parent for transmission rendering
FGAIPlane::Update(dt);
}
void FGAILocalTraffic::RegisterTransmission(int code) {
@ -947,7 +953,8 @@ void FGAILocalTraffic::TransmitPatternPositionReport(void) {
// And add the airport name again
trns += tower->get_name();
Transmit(trns);
pending_transmission = trns; // FIXME - make up pending_transmission natively
Transmit(90.0); // Assume a report of this leg will be invalid if we can't transmit within a minute and a half.
}
void FGAILocalTraffic::ExitRunway(Point3D orthopos) {

View file

@ -22,6 +22,7 @@
#include <Main/fg_props.hxx>
#include <simgear/math/point3d.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/sound/soundmgr.hxx>
#include <math.h>
#include <string>
SG_USING_STD(string);
@ -32,12 +33,73 @@ SG_USING_STD(string);
FGAIPlane::FGAIPlane() {
leg = LEG_UNKNOWN;
tuned_station = NULL;
pending_transmission = "";
_timeout = 0;
_pending = false;
_callback = NULL;
_transmit = false;
_transmitting = false;
voice = false;
playing = false;
voiceOK = false;
vPtr = NULL;
}
FGAIPlane::~FGAIPlane() {
}
void FGAIPlane::Update(double dt) {
if(_pending) {
if(tuned_station) {
if(tuned_station->FreqClear()) {
_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.
}
}
}
} else {
// Not tuned to ATC - Just go ahead and transmit
_pending = false;
_transmit = true;
_transmitting = false;
}
}
// This turns on rendering if on the same freq as the user
// TODO - turn it off if user switches to another freq - keep track of where in message we are etc.
if(_transmit) {
double user_freq0 = fgGetDouble("/radios/comm[0]/frequencies/selected-mhz");
//comm1 is not used yet.
_counter = 0.0;
_max_count = 5.0; // FIXME - hardwired length of message - need to calculate it!
if(freq == user_freq0) {
//cout << "Transmitting..." << endl;
// we are on the same frequency, so check distance to the user plane
if(1) {
// For now assume in range !!!
// TODO - implement range checking
Render(plane.callsign, false);
_transmit = false;
_transmitting = true;
}
}
} else if(_transmitting) {
if(_counter >= _max_count) {
NoRender(plane.callsign);
_transmitting = false;
}
_counter += dt;
}
}
void FGAIPlane::Bank(double angle) {
@ -55,23 +117,85 @@ void FGAIPlane::LevelWings(void) {
}
}
void FGAIPlane::Transmit(string msg) {
SG_LOG(SG_ATC, SG_INFO, "Transmit called, msg = " << msg);
double user_freq0 = fgGetDouble("/radios/comm[0]/frequencies/selected-mhz");
//double user_freq0 = ("/radios/comm[0]/frequencies/selected-mhz");
//comm1 is not used yet.
void FGAIPlane::Transmit(ai_plane_callback_t callback) {
SG_LOG(SG_ATC, SG_INFO, "Transmit called for plane " << plane.callsign << ", msg = " << pending_transmission);
_pending = true;
_callback = callback;
_timeout = 0.0;
}
if(freq == user_freq0) {
//cout << "Transmitting..." << endl;
// we are on the same frequency, so check distance to the user plane
if(1) {
// For now (testing) assume in range !!!
// TODO - implement range checking
globals->get_ATC_display()->RegisterSingleMessage(msg, 0);
}
void FGAIPlane::Transmit(double timeout, ai_plane_callback_t callback) {
SG_LOG(SG_ATC, SG_INFO, "Timed transmit called for plane " << plane.callsign << ", msg = " << pending_transmission);
_pending = true;
_callback = callback;
_timeout = timeout;
}
void FGAIPlane::ImmediateTransmit(ai_plane_callback_t callback) {
Render(plane.callsign, false);
if(_callback) {
(*_callback)();
}
}
// Render a transmission
// Outputs the transmission either on screen or as audio depending on user preference
// The refname is a string to identify this sample to the sound manager
// The repeating flag indicates whether the message should be repeated continuously or played once.
void FGAIPlane::Render(string refname, bool repeating) {
#ifdef ENABLE_AUDIO_SUPPORT
voice = (voiceOK && fgGetBool("/sim/sound/audible")
&& fgGetBool("/sim/sound/voice"));
if(voice) {
int len;
unsigned char* buf = vPtr->WriteMessage((char*)pending_transmission.c_str(), len, voice);
if(voice) {
SGSimpleSound* simple = new SGSimpleSound(buf, len);
// TODO - at the moment the volume is always set off comm1
// and can't be changed after the transmission has started.
simple->set_volume(5.0 * fgGetDouble("/radios/comm[0]/volume"));
globals->get_soundmgr()->add(simple, refname);
if(repeating) {
globals->get_soundmgr()->play_looped(refname);
} else {
globals->get_soundmgr()->play_once(refname);
}
}
delete[] buf;
}
#endif // ENABLE_AUDIO_SUPPORT
if(!voice) {
// first rip the underscores and the pause hints out of the string - these are for the convienience of the voice parser
for(unsigned int i = 0; i < pending_transmission.length(); ++i) {
if((pending_transmission.substr(i,1) == "_") || (pending_transmission.substr(i,1) == "/")) {
pending_transmission[i] = ' ';
}
}
globals->get_ATC_display()->RegisterSingleMessage(pending_transmission, 0.0);
}
playing = true;
}
// Cease rendering a transmission.
void FGAIPlane::NoRender(string refname) {
if(playing) {
if(voice) {
#ifdef ENABLE_AUDIO_SUPPORT
globals->get_soundmgr()->stop(refname);
globals->get_soundmgr()->remove(refname);
#endif
} else {
globals->get_ATC_display()->CancelRepeatingMessage();
}
playing = false;
}
}
/*
*/
void FGAIPlane::RegisterTransmission(int code) {
}

View file

@ -72,7 +72,7 @@ public:
virtual ~FGAIPlane();
// Run the internal calculations
virtual void Update(double dt);
void Update(double dt);
// Send a transmission *TO* the AIPlane.
// FIXME int code is a hack - eventually this will receive Alexander's coded messages.
@ -85,6 +85,9 @@ public:
LandingType GetLandingOption();
protected:
// callback type for derived classes to use
typedef void (*ai_plane_callback_t) (void);
PlaneRec plane;
double mag_hdg; // degrees - the heading that the physical aircraft is *pointing*
@ -106,12 +109,47 @@ protected:
// Make radio transmission - this simply sends the transmission for physical rendering if the users
// aircraft is on the same frequency and in range. It is up to the derived classes to let ATC know
// what is going on.
void Transmit(string msg);
string pending_transmission; // derived classes set this string before calling Transmit(...)
FGATC* tuned_station; // and this if they are tuned to ATC
// Transmit a message when channel becomes free of other dialog
void Transmit(ai_plane_callback_t callback = NULL);
// Transmit a message if channel becomes free within timeout (seconds). timeout of zero implies no limit
void Transmit(double timeout, ai_plane_callback_t callback = NULL);
// Transmit regardless of other dialog on the channel eg emergency
void ImmediateTransmit(ai_plane_callback_t callback = NULL);
void Bank(double angle);
void LevelWings(void);
PatternLeg leg;
private:
bool _pending;
double _timeout;
ai_plane_callback_t _callback;
bool _transmit; // we are to transmit
bool _transmitting; // we are transmitting
double _counter;
double _max_count;
// Render a transmission (in string pending_transmission)
// Outputs the transmission either on screen or as audio depending on user preference
// The refname is a string to identify this sample to the sound manager
// The repeating flag indicates whether the message should be repeated continuously or played once.
void Render(string refname, bool repeating);
// Cease rendering a transmission.
// Requires the sound manager refname if audio, else "".
void NoRender(string refname);
// Rendering related stuff
bool voice; // Flag - true if we are using voice
bool playing; // Indicates a message in progress
bool voiceOK; // Flag - true if at least one voice has loaded OK
FGATCVoice* vPtr;
};
#endif // _FG_AI_PLANE_HXX

View file

@ -29,6 +29,10 @@
#include "ATC.hxx"
#include "ATCdisplay.hxx"
FGATC::FGATC() {
freqClear = true;
}
FGATC::~FGATC() {
}
@ -70,7 +74,7 @@ void FGATC::SetData(ATCData* d) {
// The refname is a string to identify this sample to the sound manager
// The repeating flag indicates whether the message should be repeated continuously or played once.
void FGATC::Render(string msg, string refname, bool repeating) {
#ifdef ENABLE_AUDIO_SUPPORT
#ifdef ENABLE_AUDIO_SUPPORT
voice = (voiceOK && fgGetBool("/sim/sound/audible")
&& fgGetBool("/sim/sound/voice"));
if(voice) {
@ -90,7 +94,7 @@ void FGATC::Render(string msg, string refname, bool repeating) {
}
delete[] buf;
}
#endif // ENABLE_AUDIO_SUPPORT
#endif // ENABLE_AUDIO_SUPPORT
if(!voice) {
// first rip the underscores and the pause hints out of the string - these are for the convienience of the voice parser
for(unsigned int i = 0; i < msg.length(); ++i) {
@ -108,10 +112,10 @@ void FGATC::Render(string msg, string refname, bool repeating) {
void FGATC::NoRender(string refname) {
if(playing) {
if(voice) {
#ifdef ENABLE_AUDIO_SUPPORT
#ifdef ENABLE_AUDIO_SUPPORT
globals->get_soundmgr()->stop(refname);
globals->get_soundmgr()->remove(refname);
#endif
#endif
} else {
globals->get_ATC_display()->CancelRepeatingMessage();
}
@ -121,20 +125,13 @@ void FGATC::NoRender(string refname) {
ostream& operator << (ostream& os, atc_type atc) {
switch(atc) {
case(INVALID):
return(os << "INVALID");
case(ATIS):
return(os << "ATIS");
case(GROUND):
return(os << "GROUND");
case(TOWER):
return(os << "TOWER");
case(APPROACH):
return(os << "APPROACH");
case(DEPARTURE):
return(os << "DEPARTURE");
case(ENROUTE):
return(os << "ENROUTE");
case(INVALID): return(os << "INVALID");
case(ATIS): return(os << "ATIS");
case(GROUND): return(os << "GROUND");
case(TOWER): return(os << "TOWER");
case(APPROACH): return(os << "APPROACH");
case(DEPARTURE): return(os << "DEPARTURE");
case(ENROUTE): return(os << "ENROUTE");
}
return(os << "ERROR - Unknown switch in atc_type operator << ");
}

View file

@ -99,8 +99,9 @@ ostream& operator << (ostream& os, atc_type atc);
class FGATC {
public:
public:
FGATC();
virtual ~FGATC();
// Run the internal calculations
@ -118,6 +119,16 @@ public:
// Indicate that this instance should not output to the display
virtual void SetNoDisplay();
// Returns true if OK to transmit on this frequency
inline bool FreqClear() { return freqClear; }
// Indicate that the frequency is in use
inline void FreqInUse() { freqClear = false; }
// Under development!!
// The idea is that AI traffic or the user ATC dialog box calls FreqInUse() when they begin transmitting,
// and that the tower control sets freqClear back to true following a reply.
// AI traffic should check FreqClear() is true prior to transmitting.
// The user will just have to wait for a gap in dialog as in real life.
// Return the type of ATC station that the class represents
virtual atc_type GetType();
@ -145,7 +156,7 @@ public:
inline const char* get_name() {return name.c_str();}
inline void set_name(const string nm) {name = nm;}
protected:
protected:
// Render a transmission
// Outputs the transmission either on screen or as audio depending on user preference
@ -169,6 +180,8 @@ protected:
bool playing; // Indicates a message in progress
bool voiceOK; // Flag - true if at least one voice has loaded OK
FGATCVoice* vPtr;
bool freqClear; // Flag to indicate if the frequency is clear of ongoing dialog
};
inline istream&

View file

@ -1248,6 +1248,10 @@ void FGTower::ReportRunwayVacated(string ID) {
//cout << "Report Runway Vacated Called...\n";
}
void FGTower::ReportDownwind(string ID) {
// Tell the plane reporting what number she is in the circuit
}
ostream& operator << (ostream& os, tower_traffic_type ttt) {
switch(ttt) {
case(CIRCUIT): return(os << "CIRCUIT");

View file

@ -124,6 +124,7 @@ public:
void ReportGoingAround(string ID);
void ReportRunwayVacated(string ID);
void ReportReadyForDeparture(string ID);
void ReportDownwind(string ID);
// Contact tower when at a hold short for departure - for now we'll assume plane - maybe vehicles might want to cross runway eventually?
void ContactAtHoldShort(PlaneRec plane, FGAIPlane* requestee, tower_traffic_type operation);
@ -147,15 +148,6 @@ public:
bool GetDownwindConstraint(double& dpos);
bool GetBaseConstraint(double& bpos);
// Returns true if OK to transmit on this frequency
inline bool FreqClear() { return freqClear; }
// Indicate that the frequency is in use
inline void FreqInUse() { freqClear = false; }
// The idea is that AI traffic or the user ATC dialog box calls FreqInUse() when they begin transmitting,
// and that the tower control sets freqClear back to true following a reply.
// AI traffic should check FreqClear() is true prior to transmitting.
// The user will just have to wait for a gap in dialog as in real life.
private:
FGATCMgr* ATCmgr;
// This is purely for synactic convienience to avoid writing globals->get_ATC_mgr()-> all through the code!
@ -198,8 +190,6 @@ private:
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.
bool freqClear; // Flag to indicate if the frequency is clear of ongoing dialog
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.