David Luff writes:
Heres an update to the ATIS stuff. In brief: The possible buffer overflow in the display with wind should hopefully be fixed. Temperature is taken from the global temperature property instead of being hardwired. The display class now includes an implementation of the member function to change the repeating message. The message callsign is no longer hardwired. The first message from each station is generated with a random callsign. Subsequent messages from the same station have the callsign incremented every hour. A map of airport-id vs. last callsign and transmission time is kept for each station that has transmitted for the duration of the FlightGear session. The logic might be flaky if FlightGear is run for more than 24 hours at a stretch between visiting the same ATIS station though! (ie I don't check the day.) This map is kept in the atislist class. This might not be the best long-term place for it (in an ATC class of some sort might be better), but it works for now.
This commit is contained in:
parent
36de63366b
commit
e35fffa035
9 changed files with 172 additions and 32 deletions
2
aclocal.m4
vendored
2
aclocal.m4
vendored
|
@ -1,4 +1,4 @@
|
||||||
dnl aclocal.m4 generated automatically by aclocal 1.4-p4
|
dnl aclocal.m4 generated automatically by aclocal 1.4
|
||||||
|
|
||||||
dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
|
dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
|
||||||
dnl This file is free software; the Free Software Foundation
|
dnl This file is free software; the Free Software Foundation
|
||||||
|
|
|
@ -37,6 +37,7 @@ FGATCDisplay *current_atcdisplay;
|
||||||
// Constructor
|
// Constructor
|
||||||
FGATCDisplay::FGATCDisplay( void ) {
|
FGATCDisplay::FGATCDisplay( void ) {
|
||||||
rep_msg = false;
|
rep_msg = false;
|
||||||
|
change_msg_flag = false;
|
||||||
dsp_offset1 = 0;
|
dsp_offset1 = 0;
|
||||||
dsp_offset2 = 0;
|
dsp_offset2 = 0;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +54,30 @@ void FGATCDisplay::init( void ) {
|
||||||
// update - this actually draws the visuals and should be called from the main Flightgear rendering loop.
|
// update - this actually draws the visuals and should be called from the main Flightgear rendering loop.
|
||||||
void FGATCDisplay::update() {
|
void FGATCDisplay::update() {
|
||||||
|
|
||||||
|
// These strings are used for temporary storage of the transmission string in order
|
||||||
|
// that the string we view only changes when the next repitition starts scrolling
|
||||||
|
// even though the master string (rep_msg_str) may change at any time.
|
||||||
|
static string msg1 = "";
|
||||||
|
static string msg2 = "";
|
||||||
|
|
||||||
if(rep_msg) {
|
if(rep_msg) {
|
||||||
|
//cout << "dsp_offset1 = " << dsp_offset1 << " dsp_offset2 = " << dsp_offset2 << endl;
|
||||||
|
if(dsp_offset1 == 0) {
|
||||||
|
msg1 = rep_msg_str;
|
||||||
|
}
|
||||||
|
if(dsp_offset2 == 0) {
|
||||||
|
msg2 = rep_msg_str;
|
||||||
|
}
|
||||||
|
// Check for the situation where one offset is negative and the message is changed
|
||||||
|
if(change_msg_flag) {
|
||||||
|
if(dsp_offset1 < 0) {
|
||||||
|
msg1 = rep_msg_str;
|
||||||
|
} else if(dsp_offset2 < 0) {
|
||||||
|
msg2 = rep_msg_str;
|
||||||
|
}
|
||||||
|
change_msg_flag = false;
|
||||||
|
}
|
||||||
|
|
||||||
float fps = general.get_frame_rate();
|
float fps = general.get_frame_rate();
|
||||||
|
|
||||||
//cout << "In FGATC::update()" << endl;
|
//cout << "In FGATC::update()" << endl;
|
||||||
|
@ -62,13 +86,6 @@ void FGATCDisplay::update() {
|
||||||
int iwidth = xsize_node->getIntValue();
|
int iwidth = xsize_node->getIntValue();
|
||||||
int iheight = ysize_node->getIntValue();
|
int iheight = ysize_node->getIntValue();
|
||||||
|
|
||||||
//TODO - if the string is bigger than the buffer the program exits - we really ought to have a robust check here
|
|
||||||
char buf[256];
|
|
||||||
//float fps = visibility/1600;
|
|
||||||
// sprintf(buf,"%-4.1f %7.0f %7.0f", fps, tris, culled);
|
|
||||||
// sprintf(buf,"%s %-5.1f", "visibility ", visibility);
|
|
||||||
sprintf(buf,"%s", rep_msg_str.c_str());
|
|
||||||
|
|
||||||
glMatrixMode( GL_PROJECTION );
|
glMatrixMode( GL_PROJECTION );
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
@ -82,13 +99,13 @@ void FGATCDisplay::update() {
|
||||||
|
|
||||||
glColor3f( 0.9, 0.4, 0.2 );
|
glColor3f( 0.9, 0.4, 0.2 );
|
||||||
|
|
||||||
// guiFnt.drawString( buf,
|
// guiFnt.drawString( rep_msg_str.c_str(),
|
||||||
// int(iwidth - guiFnt.getStringWidth(buf) - 10 - (int)dsp_offset),
|
// int(iwidth - guiFnt.getStringWidth(buf) - 10 - (int)dsp_offset),
|
||||||
// (iheight - 20) );
|
// (iheight - 20) );
|
||||||
guiFnt.drawString( buf,
|
guiFnt.drawString( msg1.c_str(),
|
||||||
int(iwidth - 10 - dsp_offset1),
|
int(iwidth - 10 - dsp_offset1),
|
||||||
(iheight - 20) );
|
(iheight - 20) );
|
||||||
guiFnt.drawString( buf,
|
guiFnt.drawString( msg2.c_str(),
|
||||||
int(iwidth - 10 - dsp_offset2),
|
int(iwidth - 10 - dsp_offset2),
|
||||||
(iheight - 20) );
|
(iheight - 20) );
|
||||||
glEnable( GL_DEPTH_TEST );
|
glEnable( GL_DEPTH_TEST );
|
||||||
|
@ -123,7 +140,8 @@ void FGATCDisplay::RegisterRepeatingMessage(string msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGATCDisplay::ChangeRepeatingMessage(string newmsg) {
|
void FGATCDisplay::ChangeRepeatingMessage(string newmsg) {
|
||||||
//Not implemented yet
|
rep_msg_str = newmsg;
|
||||||
|
change_msg_flag = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ class FGATCDisplay {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool rep_msg; // Flag to indicate there is a repeating transmission to display
|
bool rep_msg; // Flag to indicate there is a repeating transmission to display
|
||||||
|
bool change_msg_flag; // Flag to indicate that the repeating message has changed
|
||||||
float dsp_offset1; // Used to set the correct position of scrolling display
|
float dsp_offset1; // Used to set the correct position of scrolling display
|
||||||
float dsp_offset2;
|
float dsp_offset2;
|
||||||
string rep_msg_str; // The repeating transmission to play
|
string rep_msg_str; // The repeating transmission to play
|
||||||
|
|
|
@ -25,17 +25,17 @@
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include <stdlib.h> // atoi()
|
||||||
#include <string>
|
#include <string>
|
||||||
SG_USING_STD(string);
|
SG_USING_STD(string);
|
||||||
|
|
||||||
//#include STL_IOSTREAM
|
#include STL_IOSTREAM
|
||||||
//#if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
|
#if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
|
||||||
//SG_USING_STD(cout);
|
SG_USING_STD(cout);
|
||||||
//#endif
|
#endif
|
||||||
|
|
||||||
//#include <simgear/debug/logstream.hxx>
|
//#include <simgear/debug/logstream.hxx>
|
||||||
//#include <simgear/misc/sgstream.hxx>
|
//#include <simgear/misc/sgstream.hxx>
|
||||||
//#include <simgear/math/sg_geodesy.hxx>
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
//#ifndef FG_OLD_WEATHER
|
//#ifndef FG_OLD_WEATHER
|
||||||
|
@ -48,6 +48,41 @@ SG_USING_STD(string);
|
||||||
#include <Airports/runways.hxx>
|
#include <Airports/runways.hxx>
|
||||||
|
|
||||||
#include "atis.hxx"
|
#include "atis.hxx"
|
||||||
|
#include "atislist.hxx"
|
||||||
|
|
||||||
|
string GetPhoneticIdent(int i) {
|
||||||
|
// TODO - Check i is between 1 and 26 and wrap if necessary
|
||||||
|
switch(i) {
|
||||||
|
case 1 : return("Alpha");
|
||||||
|
case 2 : return("Bravo");
|
||||||
|
case 3 : return("Charlie");
|
||||||
|
case 4 : return("Delta");
|
||||||
|
case 5 : return("Echo");
|
||||||
|
case 6 : return("Foxtrot");
|
||||||
|
case 7 : return("Golf");
|
||||||
|
case 8 : return("Hotel");
|
||||||
|
case 9 : return("Indigo");
|
||||||
|
case 10 : return("Juliet");
|
||||||
|
case 11 : return("Kilo");
|
||||||
|
case 12 : return("Lima");
|
||||||
|
case 13 : return("Mike");
|
||||||
|
case 14 : return("November");
|
||||||
|
case 15 : return("Oscar");
|
||||||
|
case 16 : return("Papa");
|
||||||
|
case 17 : return("Quebec");
|
||||||
|
case 18 : return("Romeo");
|
||||||
|
case 19 : return("Sierra");
|
||||||
|
case 20 : return("Tango");
|
||||||
|
case 21 : return("Uniform");
|
||||||
|
case 22 : return("Victor");
|
||||||
|
case 23 : return("Whiskey");
|
||||||
|
case 24 : return("X-ray");
|
||||||
|
case 25 : return("Yankee");
|
||||||
|
case 26 : return("Zulu");
|
||||||
|
}
|
||||||
|
// We shouldn't get here
|
||||||
|
return("Error");
|
||||||
|
}
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
FGATIS::FGATIS() {
|
FGATIS::FGATIS() {
|
||||||
|
@ -64,6 +99,11 @@ string FGATIS::get_transmission() {
|
||||||
double visibility;
|
double visibility;
|
||||||
double temperature;
|
double temperature;
|
||||||
char buf[10];
|
char buf[10];
|
||||||
|
int phonetic_id;
|
||||||
|
string phonetic_id_string;
|
||||||
|
string time_str = fgGetString("sim/time/gmt-string");
|
||||||
|
int hours;
|
||||||
|
int minutes;
|
||||||
|
|
||||||
// Only update every so-many loops - FIXME - possibly register this with the event scheduler
|
// Only update every so-many loops - FIXME - possibly register this with the event scheduler
|
||||||
// Ack this doesn't work since the static counter is shared between all instances of FGATIS
|
// Ack this doesn't work since the static counter is shared between all instances of FGATIS
|
||||||
|
@ -76,25 +116,34 @@ string FGATIS::get_transmission() {
|
||||||
// Start with the transmitted station name.
|
// Start with the transmitted station name.
|
||||||
transmission += name;
|
transmission += name;
|
||||||
|
|
||||||
|
//cout << "In atis.cxx, time_str = " << time_str << '\n';
|
||||||
// Add the recording identifier
|
// Add the recording identifier
|
||||||
// TODO - this is hardwired for now - ultimately we need to start with a random one and then increment it with each recording
|
// For now we will assume we only transmit every hour
|
||||||
transmission += " Charlie";
|
hours = atoi((time_str.substr(1,2)).c_str()); //Warning - this is fragile if the
|
||||||
|
//time string format changes
|
||||||
|
//cout << "In atis.cxx, hours = " << hours << endl;
|
||||||
|
phonetic_id = current_atislist->GetCallSign(ident, hours, 0);
|
||||||
|
phonetic_id_string = GetPhoneticIdent(phonetic_id);
|
||||||
|
transmission += " ";
|
||||||
|
transmission += phonetic_id_string;
|
||||||
|
|
||||||
// Output the recording time. - we'll just output the last whole hour for now.
|
// Output the recording time. - we'll just output the last whole hour for now.
|
||||||
string time_str = fgGetString("sim/time/gmt-string");
|
|
||||||
// FIXME - this only gets GMT time but that appears to be all the clock outputs for now
|
// FIXME - this only gets GMT time but that appears to be all the clock outputs for now
|
||||||
//cout << "in atis.cxx, time = " << time_str << endl;
|
//cout << "in atis.cxx, time = " << time_str << endl;
|
||||||
transmission = transmission + " Weather " + time_str.substr(0,3) + "00 hours Zulu";
|
transmission = transmission + " Weather " + time_str.substr(0,3) + "00 hours Zulu";
|
||||||
|
|
||||||
// Get the temperature
|
// Get the temperature
|
||||||
// Hardwire the temperature for now - is the local weather database running yet?
|
temperature = fgGetDouble("/environment/weather/temperature-K");
|
||||||
transmission += " Temperature 25 degrees Celcius";
|
sprintf(buf, "%i", int(temperature - 273.15));
|
||||||
|
transmission += " Temperature ";
|
||||||
|
transmission += buf;
|
||||||
|
transmission += " degrees Celcius";
|
||||||
|
|
||||||
// Get the pressure / altimeter
|
// Get the pressure / altimeter
|
||||||
|
|
||||||
// Get the visibility
|
// Get the visibility
|
||||||
visibility = fgGetDouble("/environment/visibility-m");
|
visibility = fgGetDouble("/environment/visibility-m");
|
||||||
sprintf(buf, "%d", int(visibility/1600));
|
sprintf(buf, "%i", int(visibility/1600));
|
||||||
transmission += " Visibility ";
|
transmission += " Visibility ";
|
||||||
transmission += buf;
|
transmission += buf;
|
||||||
transmission += " miles";
|
transmission += " miles";
|
||||||
|
@ -128,7 +177,7 @@ string FGATIS::get_transmission() {
|
||||||
transmission += " Winds light and variable";
|
transmission += " Winds light and variable";
|
||||||
} else {
|
} else {
|
||||||
//add a description of the wind to the transmission
|
//add a description of the wind to the transmission
|
||||||
char buf2[48];
|
char buf2[72];
|
||||||
sprintf(buf2, "%s %i %s %i %s", " Winds ", int(speed), " knots from ", int(hdg), " degrees");
|
sprintf(buf2, "%s %i %s %i %s", " Winds ", int(speed), " knots from ", int(hdg), " degrees");
|
||||||
transmission += buf2;
|
transmission += buf2;
|
||||||
}
|
}
|
||||||
|
@ -143,7 +192,8 @@ string FGATIS::get_transmission() {
|
||||||
// Anything else?
|
// Anything else?
|
||||||
|
|
||||||
// TODO - unhardwire the identifier
|
// TODO - unhardwire the identifier
|
||||||
transmission += " Advise controller on initial contact you have Charlie";
|
transmission += " Advise controller on initial contact you have ";
|
||||||
|
transmission += phonetic_id_string;
|
||||||
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/misc/sgstream.hxx>
|
#include <simgear/misc/sgstream.hxx>
|
||||||
#include <simgear/math/sg_geodesy.hxx>
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
|
#include <simgear/math/sg_random.h>
|
||||||
|
|
||||||
#include "atislist.hxx"
|
#include "atislist.hxx"
|
||||||
|
|
||||||
|
@ -147,3 +148,53 @@ bool FGATISList::query( double lon, double lat, double elev, double freq,
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FGATISList::GetCallSign( string apt_id, int hours, int mins )
|
||||||
|
{
|
||||||
|
atis_transmission_type tran;
|
||||||
|
|
||||||
|
if(atislog.find(apt_id) == atislog.end()) {
|
||||||
|
// This station has not transmitted yet - return a random identifier
|
||||||
|
// and add the transmission to the log
|
||||||
|
tran.hours = hours;
|
||||||
|
tran.mins = mins;
|
||||||
|
sg_srandom_time();
|
||||||
|
tran.callsign = int(sg_random() * 25) + 1; // This *should* give a random int between 1 and 26
|
||||||
|
//atislog[apt_id].push_back(tran);
|
||||||
|
atislog[apt_id] = tran;
|
||||||
|
} else {
|
||||||
|
// This station has transmitted - calculate the appropriate identifier
|
||||||
|
// and add the transmission to the log if it has changed
|
||||||
|
tran = atislog[apt_id];
|
||||||
|
// This next bit assumes that no-one comes back to the same ATIS station
|
||||||
|
// after running FlightGear for more than 24 hours !!
|
||||||
|
if((tran.hours == hours) && (tran.mins == mins)) {
|
||||||
|
return(tran.callsign);
|
||||||
|
} else {
|
||||||
|
if(tran.hours == hours) {
|
||||||
|
// The minutes must have changed
|
||||||
|
tran.mins = mins;
|
||||||
|
tran.callsign++;
|
||||||
|
} else {
|
||||||
|
if(hours < tran.hours) {
|
||||||
|
hours += 24;
|
||||||
|
}
|
||||||
|
tran.callsign += (hours - tran.hours);
|
||||||
|
if(mins != 0) {
|
||||||
|
// Assume transmissions were made on every hour
|
||||||
|
tran.callsign++;
|
||||||
|
}
|
||||||
|
tran.hours = hours;
|
||||||
|
tran.mins = mins;
|
||||||
|
}
|
||||||
|
// Wrap if we've exceeded Zulu
|
||||||
|
if(tran.callsign > 26) {
|
||||||
|
tran.callsign -= 26;
|
||||||
|
}
|
||||||
|
// And write the new transmission to the log
|
||||||
|
atislog[apt_id] = tran;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(tran.callsign);
|
||||||
|
}
|
||||||
|
|
|
@ -28,11 +28,13 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "atis.hxx"
|
#include "atis.hxx"
|
||||||
|
|
||||||
SG_USING_STD(map);
|
SG_USING_STD(map);
|
||||||
SG_USING_STD(vector);
|
SG_USING_STD(vector);
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
|
||||||
class FGATISList {
|
class FGATISList {
|
||||||
|
@ -49,6 +51,21 @@ class FGATISList {
|
||||||
|
|
||||||
atis_map_type atislist;
|
atis_map_type atislist;
|
||||||
|
|
||||||
|
// Add structure and map for storing a log of atis transmissions
|
||||||
|
// made in this session of FlightGear. This allows the callsign
|
||||||
|
// to be allocated correctly wrt time.
|
||||||
|
typedef struct {
|
||||||
|
int hours;
|
||||||
|
int mins;
|
||||||
|
int callsign;
|
||||||
|
} atis_transmission_type;
|
||||||
|
|
||||||
|
typedef map < string, atis_transmission_type > atis_log_type;
|
||||||
|
typedef atis_log_type::iterator atis_log_iterator;
|
||||||
|
typedef atis_log_type::const_iterator atis_log_const_iterator;
|
||||||
|
|
||||||
|
atis_log_type atislog;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FGATISList();
|
FGATISList();
|
||||||
|
@ -60,6 +77,9 @@ public:
|
||||||
// query the database for the specified frequency, lon and lat are
|
// query the database for the specified frequency, lon and lat are
|
||||||
// in degrees, elev is in meters
|
// in degrees, elev is in meters
|
||||||
bool query( double lon, double lat, double elev, double freq, FGATIS *a );
|
bool query( double lon, double lat, double elev, double freq, FGATIS *a );
|
||||||
|
|
||||||
|
// Return the callsign for a transmission given transmission time and airpord id
|
||||||
|
int GetCallSign( string apt_id, int hours, int mins );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -429,14 +429,14 @@ FGRadioStack::update()
|
||||||
// TODO - only get the transmission and register every now and then
|
// TODO - only get the transmission and register every now and then
|
||||||
if(dcl_i == 0) {
|
if(dcl_i == 0) {
|
||||||
transmission = atis.get_transmission();
|
transmission = atis.get_transmission();
|
||||||
//ChangeRepeatingMessage(transmission);
|
current_atcdisplay->ChangeRepeatingMessage(transmission);
|
||||||
}
|
}
|
||||||
if(!repeating_message_registered) {
|
if(!repeating_message_registered) {
|
||||||
current_atcdisplay->RegisterRepeatingMessage( transmission );
|
current_atcdisplay->RegisterRepeatingMessage(transmission);
|
||||||
repeating_message_registered = true;
|
repeating_message_registered = true;
|
||||||
}
|
}
|
||||||
dcl_i++;
|
dcl_i++;
|
||||||
if(dcl_i == 3000) {
|
if(dcl_i == 2000) {
|
||||||
dcl_i = 0;
|
dcl_i = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -270,12 +270,12 @@ void guiMotionFunc ( int x, int y )
|
||||||
|
|
||||||
if (mouse_mode == MOUSE_POINTER) {
|
if (mouse_mode == MOUSE_POINTER) {
|
||||||
// TURN MENU ON IF MOUSE AT TOP
|
// TURN MENU ON IF MOUSE AT TOP
|
||||||
if( y < 2 ) {
|
if( y == 0 ) {
|
||||||
if( !gui_menu_on )
|
if( !gui_menu_on )
|
||||||
guiToggleMenu();
|
guiToggleMenu();
|
||||||
}
|
}
|
||||||
// TURN MENU OFF IF MOUSE AT BOTTOM
|
// TURN MENU OFF IF MOUSE AT BOTTOM
|
||||||
else if( y > wh-2 ) {
|
else if( y > wh-1 ) {
|
||||||
if( gui_menu_on )
|
if( gui_menu_on )
|
||||||
guiToggleMenu();
|
guiToggleMenu();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* src/Include/config.h.in. Generated automatically from configure.in by autoheader 2.13. */
|
/* src/Include/config.h.in. Generated automatically from configure.in by autoheader. */
|
||||||
|
|
||||||
/* Define to empty if the keyword does not work. */
|
/* Define to empty if the keyword does not work. */
|
||||||
#undef const
|
#undef const
|
||||||
|
|
Loading…
Reference in a new issue