New FGCom standalone re-wrote from scratch
- positions.txt and special.txt are integrated in the binary - Reduce CPU load - New mode: OBS for listening a frequency - Source code ready to be used with another library - Support for COM1 and COM2 - Fix bug where frequencies conflict avoid switching between similar frequency in range - Better logging information and debug information - Range depends on altitude
This commit is contained in:
parent
a4b0be3d8a
commit
b0b272e4d2
15 changed files with 56882 additions and 13163 deletions
|
@ -1,56 +1,34 @@
|
|||
# 20130904 - build of fgcom standalone - geoff
|
||||
set(name fgcom)
|
||||
|
||||
if (MSVC)
|
||||
set( RESOURCE_FILE fgcom.rc )
|
||||
endif (MSVC)
|
||||
# Copy positions.txt content in const char* _positionsData[];
|
||||
file(READ utils/positions.txt POSITIONS_DATA)
|
||||
string(REGEX REPLACE "\n" "\"%
|
||||
\"" POSITIONS_DATA ${POSITIONS_DATA})
|
||||
string(REGEX REPLACE "%" "," POSITIONS_DATA ${POSITIONS_DATA})
|
||||
file(WRITE positions.hxx "const char* _positionsData[] = {
|
||||
\"")
|
||||
file(APPEND positions.hxx ${POSITIONS_DATA})
|
||||
file(APPEND positions.hxx "\"
|
||||
};")
|
||||
|
||||
if (NOT FGCOM_DATA_PATH)
|
||||
# use relative paths (for standalone and custom installation)
|
||||
set(FGCOM_DATA_PATH "${CMAKE_INSTALL_PREFIX}/share/flightgear")
|
||||
if (APPLE)
|
||||
# on Mac "share" directory doesn't exist
|
||||
# .txt files are moved in the Resources directory because of Mac convention
|
||||
# This movement is handled by the fgmeta.git/hudson_mac_package_release.rb line 139
|
||||
set(DEFAULT_POSITIONS_FILE "../Resources/positions.txt")
|
||||
set(SPECIAL_FREQUENCIES_FILE "../Resources/special_frequencies.txt")
|
||||
else (APPLE)
|
||||
set(DEFAULT_POSITIONS_FILE "../share/flightgear/positions.txt")
|
||||
set(SPECIAL_FREQUENCIES_FILE "../share/flightgear/special_frequencies.txt")
|
||||
endif (APPLE)
|
||||
else()
|
||||
# use absolute paths, useful for package creation (e.g -DFGCOM_DATA_PATH=/usr/share/fgcom)
|
||||
set(DEFAULT_POSITIONS_FILE "${FGCOM_DATA_PATH}/positions.txt")
|
||||
set(SPECIAL_FREQUENCIES_FILE "${FGCOM_DATA_PATH}/special_frequencies.txt")
|
||||
endif()
|
||||
if(MSVC)
|
||||
set(RESOURCE_FILE fgcom.rc)
|
||||
endif(MSVC)
|
||||
|
||||
# pass these to the compiler
|
||||
add_definitions( -DDEFAULT_POSITIONS_FILE="${DEFAULT_POSITIONS_FILE}" )
|
||||
add_definitions( -DSPECIAL_FREQUENCIES_FILE="${SPECIAL_FREQUENCIES_FILE}" )
|
||||
set(SOURCES fgcom.cxx)
|
||||
set(HEADERS fgcom.hxx positions.hxx)
|
||||
|
||||
# Project fgcom, type Console Application
|
||||
set(name fgcom)
|
||||
set( ${name}_SOURCES fgcom.cxx fgcom_init.cxx position.cxx utils.cxx ${RESOURCE_FILE} )
|
||||
set( ${name}_HEADERS fgcom.hxx fgcom_init.hxx position.hxx utils.hxx )
|
||||
if(WIN32)
|
||||
list(APPEND ${name}_SOURCES fgcom_getopt.c)
|
||||
list(APPEND ${name}_HEADERS fgcom_getopt.h)
|
||||
endif()
|
||||
add_executable( ${name} ${${name}_SOURCES} ${${name}_HEADERS} )
|
||||
if(WIN32)
|
||||
set_target_properties( ${name} PROPERTIES DEBUG_POSTFIX d )
|
||||
endif()
|
||||
target_link_libraries( ${name} iaxclient_lib )
|
||||
# this could be just on a target basis, but for now
|
||||
include_directories( ${CMAKE_SOURCE_DIR}/3rdparty/iaxclient/lib ) # for iaxclient.h
|
||||
# Now include simgear libraries
|
||||
target_link_Libraries( ${name}
|
||||
add_executable(${name}
|
||||
${SOURCES}
|
||||
${HEADERS}
|
||||
${RESOURCE_FILE}
|
||||
)
|
||||
|
||||
target_link_Libraries(${name}
|
||||
iaxclient_lib
|
||||
${OPENAL_LIBRARY}
|
||||
${SIMGEAR_CORE_LIBRARIES}
|
||||
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES} )
|
||||
# deal with install
|
||||
install(TARGETS ${name} RUNTIME DESTINATION bin)
|
||||
# then install, from their source to install destination
|
||||
set( inst_FILES utils/positions.txt
|
||||
utils/special_frequencies.txt )
|
||||
install(FILES ${inst_FILES} DESTINATION ${FGCOM_DATA_PATH})
|
||||
# eof
|
||||
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
|
||||
)
|
||||
|
||||
install(TARGETS ${name} RUNTIME DESTINATION bin)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,13 @@
|
|||
/*
|
||||
* fgcom - VoIP-Client for the FlightGear-Radio-Infrastructure
|
||||
*
|
||||
* This program realizes the usage of the VoIP infractructure based
|
||||
* on flight data which is send from FlightGear with an external
|
||||
* protocol to this application.
|
||||
*
|
||||
* Clement de l'Hamaide - Jan 2014
|
||||
* Re-writting of FGCom standalone
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
|
@ -21,58 +28,12 @@
|
|||
#ifndef __FGCOM_H__
|
||||
#define __FGCOM_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <iaxclient.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning ( disable : 4244 ) // from double to float
|
||||
#pragma warning ( disable : 4996 ) // depreciaed, really
|
||||
#include <io.h> // for open. read, ...
|
||||
#else
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define DEFAULT_USER "guest"
|
||||
#define DEFAULT_PASSWORD "guest"
|
||||
#define DEFAULT_FG_SERVER "localhost"
|
||||
#define DEFAULT_FG_PORT 16661
|
||||
#define DEFAULT_CODE 1
|
||||
#define ATIS_CODE 99
|
||||
#define DEFAULT_VOIP_SERVER "fgcom.flightgear.org"
|
||||
#define DEFAULT_CODEC 'u'
|
||||
#define DEFAULT_IAX_CODEC IAXC_FORMAT_ULAW
|
||||
#define DEFAULT_IAX_AUDIO AUDIO_INTERNAL
|
||||
#define DEFAULT_MAX_CALLS 2
|
||||
#define DEFAULT_MILLISLEEP 100
|
||||
#define DEFAULT_RANGE 100.0
|
||||
#define DEFAULT_LOWER_FRQ_LIMIT 108.0
|
||||
#define DEFAULT_UPPER_FRQ_LIMIT 140.0
|
||||
#define MAXBUFLEN 1024
|
||||
#define DEFAULT_ALARM_TIMER 5
|
||||
#define ALLOC_CHUNK_SIZE 5 //Size of a memory chunk to allocate
|
||||
#define MX_REPORT_BUF 1024
|
||||
#define MX_PATH_SIZE 2000
|
||||
|
||||
|
||||
/* avoid name clash with winerror.h */
|
||||
// avoid name clash with winerror.h
|
||||
#define FGC_SUCCESS(__x__) (__x__ == 0)
|
||||
#define FGC_FAILED(__x__) (__x__ < 0)
|
||||
|
||||
#ifndef SPECIAL_FREQUENCIES_FILE
|
||||
#define SPECIAL_FREQUENCIES_FILE "fgcom-data\\special_frequencies.txt"
|
||||
#endif
|
||||
#ifndef DEFAULT_POSITIONS_FILE
|
||||
#define DEFAULT_POSITIONS_FILE "fgcom-data\\positions.txt"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#define inline __inline
|
||||
#ifdef WIN64
|
||||
typedef __int64 ssize_t;
|
||||
#else
|
||||
|
@ -80,87 +41,84 @@ typedef int ssize_t;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "version.h"
|
||||
|
||||
#ifndef FGCOM_VERSION
|
||||
#ifndef FLIGHTGEAR_VERSION
|
||||
#ifdef FLIGHTGEAR_VERSION
|
||||
#define FGCOM_VERSION FLIGHTGEAR_VERSION
|
||||
#else
|
||||
#define FGCOM_VERSION "2.99"
|
||||
#define FGCOM_VERSION "unknown"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct airport
|
||||
{
|
||||
char icao[5];
|
||||
float frequency;
|
||||
double lat;
|
||||
double lon;
|
||||
char type[33];
|
||||
char text[129];
|
||||
struct airport *next;
|
||||
#define MAXBUFLEN 1024
|
||||
|
||||
enum Modes {
|
||||
ATC,
|
||||
PILOT,
|
||||
OBS,
|
||||
TEST
|
||||
};
|
||||
|
||||
struct pos
|
||||
enum ActiveComm {
|
||||
COM1,
|
||||
COM2
|
||||
};
|
||||
|
||||
struct Data
|
||||
{
|
||||
int ptt;
|
||||
float com1;
|
||||
float com2;
|
||||
double lon;
|
||||
double lat;
|
||||
double alt;
|
||||
float outputVol;
|
||||
float silenceThd;
|
||||
std::string callsign;
|
||||
};
|
||||
|
||||
struct fgdata
|
||||
struct Airport
|
||||
{
|
||||
float COM1_FRQ;
|
||||
float COM2_FRQ;
|
||||
float NAV1_FRQ;
|
||||
float NAV2_FRQ;
|
||||
int COM1_SRV;
|
||||
int COM2_SRV;
|
||||
int NAV1_SRV;
|
||||
int NAV2_SRV;
|
||||
int PTT;
|
||||
int TRANSPONDER;
|
||||
float IAS;
|
||||
float GS;
|
||||
double LON;
|
||||
double LAT;
|
||||
int ALT;
|
||||
float HEAD;
|
||||
float OUTPUT_VOL;
|
||||
float SILENCE_THD;
|
||||
char* CALLSIGN;
|
||||
double frequency;
|
||||
double latitude;
|
||||
double longitude;
|
||||
double distanceNm;
|
||||
std::string icao;
|
||||
std::string type;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
/* function declaratons */
|
||||
void quit (int signal);
|
||||
void alarm_handler (int signal);
|
||||
void strtoupper (const char *str, char *buf, size_t len);
|
||||
void usage (char *prog);
|
||||
int create_socket (int port);
|
||||
void fatal_error (const char *err);
|
||||
int iaxc_callback (iaxc_event e);
|
||||
void event_state (int state, char *remote, char *remote_name, char *local,
|
||||
char *local_context);
|
||||
void event_text (int type, char *message);
|
||||
void event_register (int id, int reply, int count);
|
||||
void report (char *text);
|
||||
const char *map_state (int state);
|
||||
void event_unknown (int type);
|
||||
void event_netstats (struct iaxc_ev_netstats stat);
|
||||
void event_level (double in, double out);
|
||||
void icao2number (char *icao, float frequency, char *buf);
|
||||
void icao2atisnumber (char *icao, float frequency, char *buf);
|
||||
void ptt (int mode);
|
||||
double distance (double lat1, double lon1, double lat2, double lon2);
|
||||
int split (char *string, char *fields[], int nfields, const char *sep);
|
||||
char *readln (FILE * fp, char *buf, int len);
|
||||
double *read_special_frequencies(const char *file);
|
||||
struct airport *read_airports (const char *file);
|
||||
const char *icaobypos (struct airport *airports, double frequency,
|
||||
double plane_lat, double plane_lon, double range);
|
||||
void vor (char *icao, double frequency, int mode);
|
||||
char *report_devices (int in);
|
||||
int set_device (const char *name, int out);
|
||||
struct pos posbyicao (struct airport *airports, char *icao);
|
||||
void parse_fgdata (struct fgdata *data, char *buf);
|
||||
int check_special_frq (double frq);
|
||||
void do_iaxc_call (const char *username, const char *password,
|
||||
const char *voipserver, char *number);
|
||||
// Internal functions
|
||||
int usage();
|
||||
int version();
|
||||
void quit(int state);
|
||||
bool isInRange(std::string icao, double acftLat, double acftLon, double acftAlt);
|
||||
std::string computePhoneNumber(double freq, std::string icao, bool atis = false);
|
||||
std::string getClosestAirportForFreq(double freq, double acftLat, double acftLon, double acftAlt);
|
||||
std::multimap<int, Airport> getAirportsData();
|
||||
|
||||
// Library functions
|
||||
bool lib_init();
|
||||
bool lib_hangup();
|
||||
bool lib_shutdown();
|
||||
bool lib_call(std::string icao, double freq);
|
||||
bool lib_directCall(std::string icao, double freq, std::string num);
|
||||
|
||||
int lib_registration();
|
||||
int iaxc_callback(iaxc_event e);
|
||||
|
||||
void lib_setSilenceThreshold(double thd);
|
||||
void lib_setCallerId(std::string callsign);
|
||||
void lib_setVolume(double input, double output);
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,186 +0,0 @@
|
|||
/* getopt.h */
|
||||
/* Declarations for getopt.
|
||||
Copyright (C) 1989-1994, 1996-1999, 2001 Free Software
|
||||
Foundation, Inc. This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute
|
||||
it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software
|
||||
Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with the GNU C Library; if not, write
|
||||
to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA. */
|
||||
|
||||
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
|
||||
#ifndef __need_getopt
|
||||
# define _GETOPT_H 1
|
||||
#endif
|
||||
|
||||
/* If __GNU_LIBRARY__ is not already defined, either we are being used
|
||||
standalone, or this is the first header included in the source file.
|
||||
If we are being used with glibc, we need to include <features.h>, but
|
||||
that does not exist if we are standalone. So: if __GNU_LIBRARY__ is
|
||||
not defined, include <ctype.h>, which will pull in <features.h> for us
|
||||
if it's from glibc. (Why ctype.h? It's guaranteed to exist and it
|
||||
doesn't flood the namespace with stuff the way some other headers do.) */
|
||||
#if !defined __GNU_LIBRARY__
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns -1, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int opterr;
|
||||
|
||||
/* Set to an option character which was unrecognized. */
|
||||
|
||||
extern int optopt;
|
||||
|
||||
#ifndef __need_getopt
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct option
|
||||
{
|
||||
# if (defined __STDC__ && __STDC__) || defined __cplusplus
|
||||
const char *name;
|
||||
# else
|
||||
char *name;
|
||||
# endif
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
# define no_argument 0
|
||||
# define required_argument 1
|
||||
# define optional_argument 2
|
||||
#endif /* need getopt */
|
||||
|
||||
|
||||
/* Get definitions and prototypes for functions to process the
|
||||
arguments in ARGV (ARGC of them, minus the program name) for
|
||||
options given in OPTS.
|
||||
|
||||
Return the option character from OPTS just read. Return -1 when
|
||||
there are no more options. For unrecognized options, or options
|
||||
missing arguments, `optopt' is set to the option letter, and '?' is
|
||||
returned.
|
||||
|
||||
The OPTS string is a list of characters which are recognized option
|
||||
letters, optionally followed by colons, specifying that that letter
|
||||
takes an argument, to be placed in `optarg'.
|
||||
|
||||
If a letter in OPTS is followed by two colons, its argument is
|
||||
optional. This behavior is specific to the GNU `getopt'.
|
||||
|
||||
The argument `--' causes premature termination of argument
|
||||
scanning, explicitly telling `getopt' that there are no more
|
||||
options.
|
||||
|
||||
If OPTS begins with `--', then non-option arguments are treated as
|
||||
arguments to the option '\0'. This behavior is specific to the GNU
|
||||
`getopt'. */
|
||||
|
||||
#if (defined __STDC__ && __STDC__) || defined __cplusplus
|
||||
# ifdef __GNU_LIBRARY__
|
||||
/* Many other libraries have conflicting prototypes for getopt, with
|
||||
differences in the consts, in stdlib.h. To avoid compilation
|
||||
errors, only prototype getopt for the GNU C library. */
|
||||
extern int getopt (int ___argc, char *const *___argv, const char *__shortopts);
|
||||
# else /* not __GNU_LIBRARY__ */
|
||||
extern int getopt ();
|
||||
# endif /* __GNU_LIBRARY__ */
|
||||
|
||||
# ifndef __need_getopt
|
||||
extern int getopt_long (int ___argc, char *const *___argv,
|
||||
const char *__shortopts,
|
||||
const struct option *__longopts, int *__longind);
|
||||
extern int getopt_long_only (int ___argc, char *const *___argv,
|
||||
const char *__shortopts,
|
||||
const struct option *__longopts, int *__longind);
|
||||
|
||||
/* Internal only. Users should not call this directly. */
|
||||
extern int _getopt_internal (int ___argc, char *const *___argv,
|
||||
const char *__shortopts,
|
||||
const struct option *__longopts, int *__longind,
|
||||
int __long_only);
|
||||
# endif
|
||||
#else /* not __STDC__ */
|
||||
extern int getopt ();
|
||||
# ifndef __need_getopt
|
||||
extern int getopt_long ();
|
||||
extern int getopt_long_only ();
|
||||
|
||||
extern int _getopt_internal ();
|
||||
# endif
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make sure we later can get all the definitions and declarations. */
|
||||
#undef __need_getopt
|
||||
|
||||
#endif /* getopt.h */
|
|
@ -1,690 +0,0 @@
|
|||
//
|
||||
// fgcom_init.cxx -- FGCOM configuration parsing and initialization
|
||||
// FGCOM: Copyright (C) H. Wirtz <wirtz@dfn.de>
|
||||
//
|
||||
// Adaption of fg_init.cxx from FlightGear
|
||||
// FlightGear: Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||
//
|
||||
// Huge part rewritten by Tobias Ramforth to fit needs of FGCOM.
|
||||
// <tobias@ramforth.com>
|
||||
//
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#if defined( _MSC_VER) || defined(__MINGW32__)
|
||||
# include <direct.h> // for getcwd()
|
||||
# define getcwd _getcwd
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "fgcom_getopt.h"
|
||||
#else
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
|
||||
#include "fgcom_init.hxx"
|
||||
#include "fgcom.hxx"
|
||||
#include "utils.hxx"
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
using namespace std;
|
||||
using std::string;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
|
||||
|
||||
// Manipulators
|
||||
istream& skip_eol( istream& in ) {
|
||||
char c = '\0';
|
||||
// skip to end of line.
|
||||
while ( in.get(c) ) {
|
||||
if ( (c == '\n') || (c == '\r') ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
istream& skip_ws( istream& in ) {
|
||||
char c;
|
||||
while ( in.get(c) ) {
|
||||
if ( ! isspace( c ) ) {
|
||||
// put back the non-space character
|
||||
in.putback(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
istream& skip_comment( istream& in )
|
||||
{
|
||||
while ( in ) {
|
||||
// skip whitespace
|
||||
in >> skip_ws;
|
||||
char c;
|
||||
if ( in.get( c ) && c != '#' ) {
|
||||
// not a comment
|
||||
in.putback(c);
|
||||
break;
|
||||
}
|
||||
in >> skip_eol;
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
/* program name */
|
||||
extern char *prog;
|
||||
extern const char * default_root;
|
||||
|
||||
static std::string config;
|
||||
|
||||
static OptionEntry *fgcomOptionArray = 0;
|
||||
|
||||
static void _doOptions (int argc, char **argv);
|
||||
static int _parseOption (const std::string & arg, const std::string & next_arg);
|
||||
static void _fgcomParseArgs (int argc, char **argv);
|
||||
static void _fgcomParseOptions (const std::string & path);
|
||||
|
||||
// Read in configuration (file and command line)
|
||||
bool fgcomInitOptions (const OptionEntry * fgcomOptions, int argc, char **argv)
|
||||
{
|
||||
if (!fgcomOptions) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Error! Uninitialized fgcomOptionArray!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// set option array
|
||||
int n_options;
|
||||
for (n_options = 0; fgcomOptions[n_options].long_option != NULL; n_options++) {}
|
||||
|
||||
fgcomOptionArray = (OptionEntry *) realloc (fgcomOptionArray, sizeof (OptionEntry) * (n_options + 1));
|
||||
memcpy (fgcomOptionArray, fgcomOptions, sizeof (OptionEntry) * (n_options + 1));
|
||||
|
||||
// parse options
|
||||
_doOptions (argc, argv);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create usage information out of fgcomOptionArray
|
||||
void
|
||||
fgcomUsage ()
|
||||
{
|
||||
size_t
|
||||
max_length = 0;
|
||||
|
||||
if (!fgcomOptionArray)
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Error! Options need to be initialized by calling 'fgcomInitConfig'!" );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// find longest long_option
|
||||
const OptionEntry *
|
||||
currentEntry = &fgcomOptionArray[0];
|
||||
while (currentEntry->long_option != 0)
|
||||
{
|
||||
size_t
|
||||
current_length = strlen (currentEntry->long_option);
|
||||
if (current_length > max_length)
|
||||
{
|
||||
max_length = current_length;
|
||||
}
|
||||
currentEntry++;
|
||||
}
|
||||
|
||||
max_length *= 2;
|
||||
max_length += 10; // for "-o, --option=, -option"
|
||||
|
||||
// print head
|
||||
std::cout << " OPTION" << std::string (max_length - 8,
|
||||
' ') << "\t\t" << "DESCRIPTION" <<
|
||||
std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
// iterate through option array
|
||||
currentEntry = &fgcomOptionArray[0];
|
||||
while (currentEntry->long_option != 0)
|
||||
{
|
||||
size_t
|
||||
current_length = strlen (currentEntry->long_option);
|
||||
|
||||
current_length *= 2;
|
||||
current_length += 10;
|
||||
|
||||
std::string option = std::string (" -")
|
||||
+ std::string (¤tEntry->option);
|
||||
if (option.size() > 4)
|
||||
option = option.substr(0,4);
|
||||
option += std::string (", -")
|
||||
+ std::string (currentEntry->long_option)
|
||||
+ std::string (", --")
|
||||
+ std::string (currentEntry->long_option)
|
||||
+ std::string ("=") + std::string (max_length - current_length, ' ');
|
||||
|
||||
std::cout << option << "\t\t" << currentEntry->description;
|
||||
|
||||
if (currentEntry->has_param && (currentEntry->type != OPTION_NONE)
|
||||
&& (currentEntry->default_value != 0))
|
||||
{
|
||||
std::cout << " (default: '";
|
||||
|
||||
if (currentEntry->type == OPTION_NONE)
|
||||
{
|
||||
|
||||
}
|
||||
else if (currentEntry->type == OPTION_BOOL)
|
||||
{
|
||||
std::cout << *(bool *) currentEntry->default_value;
|
||||
}
|
||||
else if (currentEntry->type == OPTION_STRING)
|
||||
{
|
||||
std::cout << (char *) currentEntry->default_value;
|
||||
}
|
||||
else if (currentEntry->type == OPTION_FLOAT)
|
||||
{
|
||||
std::cout << *(float *) currentEntry->default_value;
|
||||
}
|
||||
else if (currentEntry->type == OPTION_DOUBLE)
|
||||
{
|
||||
std::cout << *(double *) currentEntry->default_value;
|
||||
}
|
||||
else if (currentEntry->type == OPTION_FREQ)
|
||||
{
|
||||
std::cout << std::setw (7) << std::
|
||||
setprecision (3) << *(double *) currentEntry->default_value;
|
||||
}
|
||||
else if (currentEntry->type == OPTION_INT)
|
||||
{
|
||||
std::cout << *(int *) currentEntry->default_value;
|
||||
}
|
||||
else if (currentEntry->type == OPTION_CHAR)
|
||||
{
|
||||
std::cout << *(char *) currentEntry->default_value;
|
||||
}
|
||||
|
||||
std::cout << "')";
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
currentEntry++;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << " Available codecs:" << std::endl;
|
||||
std::cout << " \t" <<
|
||||
"u - ulaw (default and best codec because the mixing is based onto ulaw)"
|
||||
<< std::endl;
|
||||
std::cout << " \t" << "a - alaw" << std::endl;
|
||||
std::cout << " \t" << "g - gsm" << std::endl;
|
||||
std::cout << " \t" << "s - speex" << std::endl;
|
||||
std::cout << " \t" << "7 - G.723" << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << " Mode 1: client for COM1 of flightgear:" << std::endl;
|
||||
std::cout << " \t" << "$ " << prog << std::endl;
|
||||
std::cout << " - connects " << prog << " to fgfs at localhost:" <<
|
||||
DEFAULT_FG_PORT << std::endl;
|
||||
std::cout << " \t" << "$ " << prog << " -sother.host.tld -p23456" <<
|
||||
std::endl;
|
||||
std::cout << " - connects " << prog << " to fgfs at other.host.tld:23456" << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << " Mode 2: client for an ATC at <airport> on <frequency>:" <<
|
||||
std::endl;
|
||||
std::cout << " \t" << "$ " << prog << " -aKSFO -f120.500" << std::endl;
|
||||
std::cout << " - sets up " << prog <<
|
||||
" for an ATC radio at KSFO 120.500 MHz" << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "Note that " << prog <<
|
||||
" starts with a guest account unless you use -U and -P!" << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_alternate_home(void)
|
||||
{
|
||||
char *ah = 0;
|
||||
#ifdef _MSC_VER
|
||||
char *app_data = getenv("LOCALAPPDATA");
|
||||
if (app_data) {
|
||||
ah = _strdup(app_data);
|
||||
}
|
||||
#else
|
||||
struct passwd *
|
||||
pwd = getpwent ();
|
||||
ah = strdup (pwd->pw_dir);
|
||||
#endif
|
||||
return ah;
|
||||
}
|
||||
|
||||
// Attempt to locate and parse the various non-XML config files in order
|
||||
// from least precidence to greatest precidence
|
||||
static void
|
||||
_doOptions (int argc, char **argv)
|
||||
{
|
||||
char *
|
||||
homedir = getenv ("HOME");
|
||||
|
||||
if (homedir == NULL)
|
||||
{
|
||||
homedir = get_alternate_home();
|
||||
}
|
||||
|
||||
// Check for ~/.fgfsrc
|
||||
if (homedir != NULL)
|
||||
{
|
||||
config = string (homedir);
|
||||
|
||||
#ifdef _WIN32
|
||||
config.append ("\\");
|
||||
#else
|
||||
config.append ("/");
|
||||
#endif
|
||||
|
||||
config.append (".fgcomrc");
|
||||
_fgcomParseOptions (config);
|
||||
}
|
||||
|
||||
// Parse remaining command line options
|
||||
// These will override anything specified in a config file
|
||||
_fgcomParseArgs (argc, argv);
|
||||
}
|
||||
|
||||
// lookup maps
|
||||
static std::map<string, string> fgcomOptionMap;
|
||||
static std::map<string, size_t> fgcomLongOptionMap;
|
||||
|
||||
// Parse a single option
|
||||
static int
|
||||
_parseOption (const std::string & arg, const std::string & next_arg)
|
||||
{
|
||||
if (fgcomLongOptionMap.size () == 0)
|
||||
{
|
||||
size_t i = 0;
|
||||
const OptionEntry * entry = &fgcomOptionArray[0];
|
||||
while (entry->long_option != 0)
|
||||
{
|
||||
fgcomLongOptionMap.insert (std::pair < std::string,
|
||||
size_t >
|
||||
(std::string (entry->long_option), i));
|
||||
fgcomOptionMap.insert (std::pair < std::string,
|
||||
std::string >
|
||||
(std::string (1, entry->option),
|
||||
std::string (entry->long_option)));
|
||||
i += 1;
|
||||
entry += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// General Options
|
||||
if ((arg == "--help") || (arg == "-h") || (arg == "-?"))
|
||||
{
|
||||
// help/usage request
|
||||
return FGCOM_OPTIONS_HELP;
|
||||
}
|
||||
else if ((arg == "--verbose") || (arg == "-v"))
|
||||
{
|
||||
// verbose help/usage request
|
||||
return FGCOM_OPTIONS_VERBOSE_HELP;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map < string, size_t >::iterator it;
|
||||
std::string arg_name, arg_value;
|
||||
|
||||
if (arg.find ("--") == 0)
|
||||
{
|
||||
size_t
|
||||
pos = arg.find ('=');
|
||||
if (pos == string::npos)
|
||||
{
|
||||
// did not find a value
|
||||
arg_name = arg.substr (2);
|
||||
|
||||
// now there are two possibilities:
|
||||
// 1: this is an option without a value
|
||||
// 2: the value can be found in next_arg
|
||||
if (next_arg.empty ())
|
||||
{
|
||||
// ok, value cannot be in next_arg
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "option '" << arg_name << "'" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (next_arg.at (0) == '-')
|
||||
{
|
||||
// there is no value, new option starts in next_arg
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "option '" << arg_name << "'" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// the value is in next_arg
|
||||
arg_value = std::string (next_arg);
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "option '" << arg_name << "' with argument '" << arg_value << "'" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// found a value
|
||||
arg_name = arg.substr (2, pos - 2);
|
||||
arg_value = arg.substr (pos + 1);
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "option '" << arg_name << "' with argument '" << arg_value << "'" );
|
||||
}
|
||||
|
||||
it = fgcomLongOptionMap.find (arg_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map < string, string >::iterator it_b;
|
||||
arg_name = arg.substr (1, 1);
|
||||
arg_value = arg.substr (2);
|
||||
|
||||
if (arg_name.empty ())
|
||||
{
|
||||
SG_LOG (SG_GENERAL, SG_ALERT, "Unknown option '" << arg << "'");
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "option '" << arg_name << "' with argument '" << arg_value << "'" );
|
||||
|
||||
it_b = fgcomOptionMap.find (arg_name);
|
||||
|
||||
if (it_b != fgcomOptionMap.end ())
|
||||
{
|
||||
it = fgcomLongOptionMap.find (it_b->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Unknown option '" << arg << "'" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (it != fgcomLongOptionMap.end ())
|
||||
{
|
||||
const OptionEntry *
|
||||
entry = &fgcomOptionArray[it->second];
|
||||
switch (entry->type)
|
||||
{
|
||||
case OPTION_BOOL:
|
||||
*(bool *) entry->parameter = true;
|
||||
break;
|
||||
case OPTION_STRING:
|
||||
if (entry->has_param && !arg_value.empty ())
|
||||
{
|
||||
*(char **) entry->parameter = strdup (arg_value.c_str ());
|
||||
}
|
||||
else if (entry->has_param)
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' needs a parameter" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' does not have a parameter" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
break;
|
||||
case OPTION_FLOAT:
|
||||
if (!arg_value.empty ())
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
float temp = atof(arg_value.c_str ());
|
||||
#else // !_MSC_VER
|
||||
char *
|
||||
end;
|
||||
float
|
||||
temp = strtof (arg_value.c_str (), &end);
|
||||
|
||||
errno = 0;
|
||||
|
||||
if (*end != '\0')
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot parse float value '" << arg_value << "' for option " << arg_name << "!" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
#endif // _MSC_VER y/n
|
||||
|
||||
*(float *) (entry->parameter) = temp;
|
||||
if (*(float *) (entry->parameter) != temp
|
||||
|| errno == ERANGE)
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Float value '" << arg_value << "' for option " << arg_name << " out of range!" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' needs a parameter" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
break;
|
||||
case OPTION_DOUBLE:
|
||||
case OPTION_FREQ:
|
||||
if (!arg_value.empty ())
|
||||
{
|
||||
char *
|
||||
end;
|
||||
double
|
||||
temp = strtod (arg_value.c_str (), &end);
|
||||
|
||||
errno = 0;
|
||||
|
||||
if (*end != '\0')
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot parse double value '" << arg_value << "' for option " << arg_name << "!" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
|
||||
*(double *) (entry->parameter) = temp;
|
||||
if (*(double *) (entry->parameter) != temp
|
||||
|| errno == ERANGE)
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Double value '" << arg_value << "' for option " << arg_name << " out of range!" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' needs a parameter" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
break;
|
||||
case OPTION_INT:
|
||||
if (!arg_value.empty ())
|
||||
{
|
||||
char *
|
||||
end;
|
||||
long
|
||||
temp = strtol (arg_value.c_str (), &end, 0);
|
||||
|
||||
errno = 0;
|
||||
|
||||
if (*end != '\0')
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot parse integer value '" << arg_value << "' for option " << arg_name << "!" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
|
||||
*(int *) (entry->parameter) = temp;
|
||||
if (*(int *) (entry->parameter) != temp || errno == ERANGE)
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Integer value '" << arg_value << "' for option " << arg_name << " out of range!" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' needs a parameter" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
break;
|
||||
case OPTION_CHAR:
|
||||
if (entry->has_param && !arg_value.empty ())
|
||||
{
|
||||
if (arg_value.length () > 1)
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' needs a single char as parameter" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(char *) entry->parameter = arg_value.c_str ()[0];
|
||||
}
|
||||
}
|
||||
else if (entry->has_param)
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' needs a parameter" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Option '" << arg << "' does not have a parameter" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
break;
|
||||
case OPTION_NONE:
|
||||
*(bool *) entry->parameter = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Unknown option '" << arg << "'" );
|
||||
return FGCOM_OPTIONS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return FGCOM_OPTIONS_OK;
|
||||
}
|
||||
|
||||
// Parse the command line options
|
||||
static void
|
||||
_fgcomParseArgs (int argc, char **argv)
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Processing commandline options" );
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
std::string arg = std::string (argv[i]);
|
||||
std::string next_arg;
|
||||
if (i < argc - 1)
|
||||
{
|
||||
next_arg = std::string (argv[i + 1]);
|
||||
}
|
||||
|
||||
if (arg.find ('-') == 0)
|
||||
{
|
||||
if (arg == "--")
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
int
|
||||
result = _parseOption (arg, next_arg);
|
||||
|
||||
if (result == FGCOM_OPTIONS_OK)
|
||||
{
|
||||
// that is great
|
||||
}
|
||||
else if (result == FGCOM_OPTIONS_HELP)
|
||||
{
|
||||
fgcomUsage ();
|
||||
exit (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Error parsing commandline options !" );
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Successfully parsed commandline options" );
|
||||
}
|
||||
|
||||
// Parse config file options
|
||||
static void
|
||||
_fgcomParseOptions (const std::string & path)
|
||||
{
|
||||
if (is_file_or_directory(path.c_str()) != 1) {
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Error: Unable to open " << path );
|
||||
return;
|
||||
}
|
||||
|
||||
std::fstream in;
|
||||
std::ios_base::openmode mode = std::ios_base::in;
|
||||
in.open(path.c_str(),mode);
|
||||
if (!in.is_open ()) {
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Error: DEBUG: Unable to open " << path );
|
||||
return;
|
||||
}
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Processing config file: " << path );
|
||||
|
||||
in >> skip_comment;
|
||||
while (!in.eof ()) {
|
||||
std::string line;
|
||||
getline (in, line, '\n');
|
||||
|
||||
// catch extraneous (DOS) line ending character
|
||||
int i;
|
||||
for (i = line.length(); i > 0; i--) {
|
||||
if (line[i - 1] > 32) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
line = line.substr(0, i);
|
||||
|
||||
std::string next_arg;
|
||||
if (_parseOption (line, next_arg) == FGCOM_OPTIONS_ERROR) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "ERROR: Config file parse error: " << path << " '" << line << "'" );
|
||||
fgcomUsage ();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
in >> skip_comment;
|
||||
}
|
||||
}
|
||||
|
||||
/* eof - fgcom_init.cpp */
|
|
@ -1,86 +0,0 @@
|
|||
//
|
||||
// fgcom_init.hxx -- FGCOM configuration parsing and initialization
|
||||
// FGCOM: Copyright (C) H. Wirtz <wirtz@dfn.de>
|
||||
//
|
||||
// Adaption of fg_init.h from FlightGear
|
||||
// FlightGear: Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||
//
|
||||
// Huge part rewritten by Tobias Ramforth to fit needs of FGCOM.
|
||||
// <tobias@ramforth.com>
|
||||
//
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef __INIT_H__
|
||||
#define __INIT_H__
|
||||
|
||||
enum
|
||||
{
|
||||
FGCOM_OPTIONS_OK = 0,
|
||||
FGCOM_OPTIONS_HELP = 1,
|
||||
FGCOM_OPTIONS_ERROR = 2,
|
||||
FGCOM_OPTIONS_EXIT = 3,
|
||||
FGCOM_OPTIONS_VERBOSE_HELP = 4
|
||||
};
|
||||
|
||||
/*
|
||||
option has_param type property b_param s_param func
|
||||
|
||||
where:
|
||||
option : name of the option
|
||||
has_param : option is --name=value if true or --name if false
|
||||
type : OPTION_BOOL - property is a boolean
|
||||
OPTION_STRING - property is a string
|
||||
OPTION_FLOAT - property is a float
|
||||
OPTION_DOUBLE - property is a double
|
||||
OPTION_FREQ - property is a double and stands for a frequency
|
||||
OPTION_INT - property is an integer
|
||||
OPTION_INT - property is a char
|
||||
|
||||
For OPTION_FLOAT, OPTION_DOUBLE and OPTION_INT, the parameter value is converted into a
|
||||
float, double or an integer and set to the property.
|
||||
*/
|
||||
enum OptionType
|
||||
{
|
||||
OPTION_NONE,
|
||||
OPTION_BOOL,
|
||||
OPTION_STRING,
|
||||
OPTION_FLOAT,
|
||||
OPTION_DOUBLE,
|
||||
OPTION_FREQ,
|
||||
OPTION_INT,
|
||||
OPTION_CHAR
|
||||
};
|
||||
|
||||
typedef struct _OptionEntry OptionEntry;
|
||||
|
||||
struct _OptionEntry
|
||||
{
|
||||
const char *long_option;
|
||||
char option;
|
||||
bool has_param;
|
||||
enum OptionType type;
|
||||
void *parameter;
|
||||
char property;
|
||||
const char *description;
|
||||
const void *default_value;
|
||||
};
|
||||
|
||||
// Read in configuration (file and command line)
|
||||
bool fgcomInitOptions (const OptionEntry * fgcomOptions, int argc, char **argv);
|
||||
void fgcomUsage (); // fgcom usage
|
||||
|
||||
#endif
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* fgcom - VoIP-Client for the FlightGear-Radio-Infrastructure
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include "fgcom.hxx"
|
||||
|
||||
#define EARTHRADIUS 6370.0 //radius of earth
|
||||
#define UF 0.01745329251994329509 //conversion factor pi/180 degree->rad
|
||||
|
||||
double
|
||||
distance (double lat1, double lon1, double lat2, double lon2)
|
||||
{
|
||||
double d;
|
||||
|
||||
d = sin (lat1 * UF) * sin (lat2 * UF);
|
||||
d += cos (lat1 * UF) * cos (lat2 * UF) * cos ((lon2 - lon1) * UF);
|
||||
|
||||
return (acos (d) * EARTHRADIUS);
|
||||
}
|
||||
|
||||
void
|
||||
icao2number (char *icao, float frequency, char *buf)
|
||||
{
|
||||
char icao_work[5];
|
||||
|
||||
if (strlen (icao) == 0)
|
||||
strcpy (icao, "ZZZZ");
|
||||
|
||||
sprintf (icao_work, "%4s", icao);
|
||||
sprintf (buf, "%02d%02d%02d%02d%02d%06d", DEFAULT_CODE, icao_work[0],
|
||||
icao_work[1], icao_work[2], icao_work[3],
|
||||
(int) (frequency * 1000 + 0.5));
|
||||
buf[16] = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
icao2atisnumber (char *icao, float frequency, char *buf)
|
||||
{
|
||||
char icao_work[5];
|
||||
|
||||
if (strlen (icao) == 0)
|
||||
strcpy (icao, "ZZZZ");
|
||||
|
||||
sprintf (icao_work, "%4s", icao);
|
||||
sprintf (buf, "%02d%02d%02d%02d%02d%06d", ATIS_CODE, icao_work[0],
|
||||
icao_work[1], icao_work[2], icao_work[3],
|
||||
(int) (frequency * 1000 + 0.5));
|
||||
buf[16] = '\0';
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
icaobypos (struct airport *airports, double frequency,
|
||||
double plane_lat, double plane_lon, double range)
|
||||
{
|
||||
double r;
|
||||
int frq = (int) (frequency * 1000 + 0.5);
|
||||
|
||||
if( (frq%10) !=0 && (frq%5) == 0 ){
|
||||
frequency -= 0.005;
|
||||
frequency = ceilf(frequency*1000.0)/1000.0;
|
||||
}
|
||||
|
||||
if (frequency >= DEFAULT_LOWER_FRQ_LIMIT
|
||||
&& frequency <= DEFAULT_UPPER_FRQ_LIMIT)
|
||||
{
|
||||
while (airports->next != NULL)
|
||||
{
|
||||
if ( ceilf(airports->frequency*1000.0)/1000.0 == frequency || airports->frequency == frequency)
|
||||
{
|
||||
r = distance(plane_lat, plane_lon, airports->lat, airports->lon);
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "icaobypos() - APT: " << airports->text << " (" << airports->icao << " " << airports->type << ")" );
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "icaobypos() - APT lat: " << airports->lat << " APT lon: " << airports->lon );
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "icaobypos() - Plane lat: " << plane_lat << " Plane lon: " << plane_lon );
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "icaobypos() - Distance to " << airports->icao << ": " << r << " Km" );
|
||||
if (r <= range)
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Airport " << airports->text << " (" << airports->icao
|
||||
<< " " << airports->type << " at " << frequency << " MHz)"
|
||||
<< " is in range (" << r << " km)" );
|
||||
return (airports->icao);
|
||||
}
|
||||
}
|
||||
airports = airports->next;
|
||||
}
|
||||
return ("");
|
||||
}
|
||||
|
||||
return ("");
|
||||
}
|
||||
|
||||
struct pos
|
||||
posbyicao (struct airport *airports, char *icao)
|
||||
{
|
||||
struct pos p;
|
||||
|
||||
p.lon = 0.0;
|
||||
p.lat = 0.0;
|
||||
|
||||
while (airports->next != NULL)
|
||||
{
|
||||
if (!strcmp (airports->icao, icao))
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "posbyicao() - APT: " << airports->text << " (" << airports->icao << " " << airports->type << ")" );
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "posbyicao() - APT lat: " << airports->lat << " APT lon:" << airports->lon );
|
||||
p.lon = airports->lon;
|
||||
p.lat = airports->lat;
|
||||
return (p);
|
||||
}
|
||||
airports = airports->next;
|
||||
}
|
||||
return p;
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* fgcom - VoIP-Client for the FlightGear-Radio-Infrastructure
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __POSITION_H__
|
||||
#define __POSITION_H__
|
||||
|
||||
/* Compute distance between two points. */
|
||||
double distance (double lat1, double lon1, double lat2, double lon2);
|
||||
|
||||
/* Build the phone number based on the ICAO code and airport frequency. */
|
||||
void icao2number (char *icao, float frequency, char *buf);
|
||||
void icao2atisnumber (char *icao, float frequency, char *buf);
|
||||
|
||||
/* Search for the closest airport on selected frequency. */
|
||||
const char *
|
||||
icaobypos (struct airport *airports, double frequency, double plane_lat,
|
||||
double plane_lon, double range);
|
||||
|
||||
#endif
|
47174
utils/fgcom/positions.hxx
Normal file
47174
utils/fgcom/positions.hxx
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,289 +0,0 @@
|
|||
/*
|
||||
* fgcom - VoIP-Client for the FlightGear-Radio-Infrastructure
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <WinSock2.h> // which included <Windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <mach-o/dyld.h> /* for _NSGetExecutablePath() */
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include "fgcom.hxx"
|
||||
|
||||
#ifndef bcopy
|
||||
#define bcopy(from, to, n) memcpy(to, from, n)
|
||||
#endif
|
||||
|
||||
static int s_index;
|
||||
static int s_file_handle;
|
||||
static char *s_content;
|
||||
static int s_size;
|
||||
|
||||
/**
|
||||
*
|
||||
* \fn void parser_init(void)
|
||||
*
|
||||
* \brief Starts parser initialization.
|
||||
*
|
||||
*/
|
||||
int parser_init(const char *filename)
|
||||
{
|
||||
struct stat l_stat;
|
||||
ssize_t l_nbytes;
|
||||
int l_status;
|
||||
int oflag = O_RDONLY;
|
||||
#ifdef _MSC_VER
|
||||
oflag |= _O_BINARY; /* if comparing to stat size then must be binary */
|
||||
#endif
|
||||
|
||||
s_index = 0;
|
||||
|
||||
if((s_file_handle = open(filename, oflag)) < 0)
|
||||
return (s_file_handle);
|
||||
|
||||
fstat(s_file_handle, &l_stat);
|
||||
|
||||
l_status = -1;
|
||||
if((s_content = (char *)malloc((l_stat.st_size + 1) * sizeof(char))) != NULL)
|
||||
{
|
||||
if((l_nbytes = read(s_file_handle, s_content, l_stat.st_size)) == l_stat.st_size)
|
||||
{
|
||||
l_status = 0;
|
||||
s_size = l_stat.st_size;
|
||||
}
|
||||
}
|
||||
close(s_file_handle);
|
||||
|
||||
return(l_status);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* \fn void parser_exit(void)
|
||||
*
|
||||
* \brief Exits parser.
|
||||
*
|
||||
*/
|
||||
void parser_exit(void)
|
||||
{
|
||||
free(s_content);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* \fn int parser_get_next_value(const char *line, float *value)
|
||||
*
|
||||
* \brief Extract a numeric value.
|
||||
*
|
||||
* \param line pointer on the line extracted from the input file.
|
||||
* \param value pointer on the returned value.
|
||||
*
|
||||
* \return Returns 0 if value successfully extracted. Otherwhise, returns
|
||||
* a negative value meaning that an error occured.
|
||||
*
|
||||
*/
|
||||
int parser_get_next_value(double *value)
|
||||
{
|
||||
int l_status = 0;
|
||||
unsigned int l_j;
|
||||
unsigned int l_size;
|
||||
char *l_buf;
|
||||
|
||||
/* Check if we are already at the end of the string. */
|
||||
if(s_index >= s_size)
|
||||
return(-1);
|
||||
|
||||
/* Enter main parser loop. */
|
||||
while((s_index < s_size) && (l_status == 0))
|
||||
{
|
||||
/* Search for something different than an espace or tab. */
|
||||
while( (s_content[s_index] == ' ' || s_content[s_index] == '\t') &&
|
||||
(s_index < s_size) )
|
||||
s_index++;
|
||||
|
||||
/* If we have reached end of file, we exit now. */
|
||||
if (s_index >= s_size)
|
||||
return(-1);
|
||||
|
||||
/* If character is a CR, we restart for next line. */
|
||||
if(s_content[s_index] == '\n')
|
||||
{
|
||||
s_index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Is it a comment ? */
|
||||
if(s_content[s_index] == '#')
|
||||
{
|
||||
/* Yes, go until end of line. */
|
||||
while((s_content[s_index] != '\n') && (s_index < s_size))
|
||||
s_index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have found something that is not a comment. */
|
||||
while((s_content[s_index] < '0' || s_content[s_index] > '9') && (s_index < s_size))
|
||||
s_index++;
|
||||
|
||||
if(s_index < s_size)
|
||||
{
|
||||
l_j = s_index + 1;
|
||||
while( ((s_content[l_j] >= '0' && s_content[l_j] <= '9') ||
|
||||
(s_content[l_j] == '.' || s_content[l_j] == ',')) &&
|
||||
((s_content[l_j] != '\n') && (l_j < (unsigned int)s_size)) )
|
||||
l_j++;
|
||||
|
||||
l_size = l_j - s_index + 1;
|
||||
if((l_buf = (char *)malloc(l_size * sizeof(char))) != NULL)
|
||||
{
|
||||
/* Initialize buffer with O. */
|
||||
memset((void *)l_buf, 0, l_size);
|
||||
bcopy((const void *)(s_content + s_index), (void *)l_buf, l_size - 1);
|
||||
/* Convert string into double. */
|
||||
*value = atof(l_buf);
|
||||
/* Buffer is not needed any longer. */
|
||||
free(l_buf);
|
||||
/* Prepare for next value. */
|
||||
s_index = l_j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* while((s_index < s_size) && (l_status == 0)) */
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* cross-platform stat and check if directory or file
|
||||
* return 2 == directory
|
||||
* return 1 == file
|
||||
* return 0 == neither
|
||||
* NOTE: Think this fails in Windows if
|
||||
* the path has a trailing path separator
|
||||
* and in some cases even if the path contains a forward (unix) separator
|
||||
* TODO: Should copy the path, and fix it for stat
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define M_ISDIR(a) (a & _S_IFDIR)
|
||||
#else
|
||||
#define M_ISDIR S_ISDIR
|
||||
#endif
|
||||
|
||||
int is_file_or_directory( const char * path )
|
||||
{
|
||||
struct stat buf;
|
||||
if ( stat(path,&buf) == 0 ) {
|
||||
if (M_ISDIR(buf.st_mode))
|
||||
return 2;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* trim to base binary path IN BUFFER,
|
||||
* essentially removing the executable name
|
||||
*/
|
||||
void trim_base_path_ib( char *path )
|
||||
{
|
||||
size_t len = strlen(path);
|
||||
size_t i, off;
|
||||
int c;
|
||||
off = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
c = path[i];
|
||||
if (( c == '/' ) || ( c == '\\')) {
|
||||
off = i + 1; // get after separator
|
||||
#ifdef _MSC_VER
|
||||
if ( c == '/' )
|
||||
path[i] = '\\';
|
||||
#endif // _MSC_VER
|
||||
}
|
||||
}
|
||||
path[off] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get data path per OS
|
||||
* In Windows and OSX the compiler only supplies a partial data file path,
|
||||
* so this is to get the current binary installed path.
|
||||
* In *nix the full path is supplied, so this does nothing, except zero the path
|
||||
*
|
||||
*/
|
||||
int get_data_path_per_os( char *path, size_t len )
|
||||
{
|
||||
#if defined(MACOSX)
|
||||
// if we're running as part of an application bundle, return the bundle's
|
||||
// resources directory
|
||||
// The following code looks for the base package inside the application
|
||||
// bundle, in the standard Contents/Resources location.
|
||||
|
||||
CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
|
||||
if (resourcesUrl) {
|
||||
CFURLGetFileSystemRepresentation(resourcesUrl, true, (UInt8*) path, len);
|
||||
CFRelease(resourcesUrl);
|
||||
// append trailing seperator since CF doesn't
|
||||
len = strlen(path);
|
||||
path[len] = '/';
|
||||
path[len+1] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we're unbundled, simply return the executable path
|
||||
unsigned int size = (unsigned int) len;
|
||||
if (_NSGetExecutablePath(path, &size) == 0) {
|
||||
// success
|
||||
trim_base_path_ib(path);
|
||||
} else {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "ERROR: path buffer too small; need size " << size );
|
||||
return 1;
|
||||
}
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned int size = GetModuleFileName(NULL,path, len);
|
||||
if (size && (size != len)) {
|
||||
// success
|
||||
trim_base_path_ib(path);
|
||||
} else {
|
||||
if (size) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "ERROR: GetModuleFileName: path buffer too small; need size more than " << len );
|
||||
} else {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "ERROR: GetModuleFileName FAILED!" );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
path[0] = 0;
|
||||
#endif // MACOSX | _MSC_VER | others
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* eof - utils.cpp */
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* fgcom - VoIP-Client for the FlightGear-Radio-Infrastructure
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
/* Initialize the file parser. */
|
||||
int parser_init(const char *filename);
|
||||
|
||||
/* Exits parser. */
|
||||
void parser_exit(void);
|
||||
|
||||
int parser_get_next_value(double *value);
|
||||
|
||||
extern int is_file_or_directory( const char * path ); /* 1=file, 2=dir, else 0 */
|
||||
extern void trim_base_path_ib( char *path ); /* trim to base path IN BUFFER */
|
||||
extern int get_data_path_per_os( char *path, size_t len ); /* get data path per OS - 0=ok, 1=error */
|
||||
|
||||
#endif
|
|
@ -4,31 +4,6 @@
|
|||
# 26 sept, 2013 - Clément de l'Hamaide
|
||||
|
||||
|
||||
============================================
|
||||
==== positions.txt =====
|
||||
============================================
|
||||
|
||||
This file is used by fgcom binary, it's a dictionary of
|
||||
available frequency. You can set a specific path with:
|
||||
|
||||
./fgcom --positions=/path/to/positions.txt
|
||||
|
||||
THIS FILE IS REQUIRED TO RUN FGCOM !
|
||||
|
||||
|
||||
============================================
|
||||
==== special_frequencies.txt =====
|
||||
============================================
|
||||
|
||||
This file is used by fgcom binary, it's a dictionary of
|
||||
specific frequency who require to be not associated with
|
||||
and ICAO but use "ZZZZ" instead. You can set a specific path with:
|
||||
|
||||
./fgcom --special=/path/to/special_frequencies.txt
|
||||
|
||||
This file is not required to run FGCom
|
||||
|
||||
|
||||
============================================
|
||||
==== fgcom.conf =====
|
||||
============================================
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,15 +0,0 @@
|
|||
#
|
||||
# Special frequencies file. To use any of the frequencies listed here,
|
||||
# there is no need to be closed to an airport.
|
||||
#
|
||||
# Echo test
|
||||
910.000
|
||||
# Radio test
|
||||
911.000
|
||||
700.000
|
||||
# Auto information
|
||||
123.450
|
||||
122.750
|
||||
123.500
|
||||
121.500
|
||||
|
Loading…
Reference in a new issue