1
0
Fork 0

Add findCommByFrequencyMHz to Nasal

SF-ID: https://sourceforge.net/p/flightgear/codetickets/2836/
This commit is contained in:
James Turner 2023-11-11 13:47:48 +00:00
parent 9eccf6b55b
commit 5e1be2d893
8 changed files with 245 additions and 89 deletions

View file

@ -1,3 +1,9 @@
/*
* SPDX-FileName: CommStation.cxx
* SPDX-FileComment: class describing a single comm station in the Nav DB
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include "CommStation.hxx"

View file

@ -1,5 +1,10 @@
#ifndef FG_ATC_COMM_STATION_HXX
#define FG_ATC_COMM_STATION_HXX
/*
* SPDX-FileName: CommStation.hxx
* SPDX-FileComment: class describing a single comm station in the Nav DB
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <Airports/airports_fwd.hxx>
#include <Navaids/positioned.hxx>
@ -24,13 +29,16 @@ public:
double freqMHz() const;
static CommStationRef findByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt = NULL);
static bool isType(FGPositioned::Type ty)
{
return (ty >= FGPositioned::FREQ_GROUND) && (ty <= FGPositioned::FREQ_UNICOM);
}
private:
int mRangeNM;
int mFreqKhz;
PositionedID mAirport;
};
} // of namespace flightgear
#endif // of FG_ATC_COMM_STATION_HXX
} // namespace flightgear

View file

@ -439,6 +439,14 @@ FGPositioned::TypeFilter::TypeFilter(std::initializer_list<Type> types)
}
}
FGPositioned::TypeFilter::TypeFilter(Type aMinType, Type aMaxType)
{
for (int t = aMinType; t <= aMaxType; t++) {
addType(static_cast<FGPositioned::Type>(t));
}
}
void FGPositioned::TypeFilter::addType(Type aTy)
{
if (aTy == INVALID) {

View file

@ -63,16 +63,18 @@ public:
OM,
MM,
IM,
/// important that DME & TACAN are adjacent to keep the TacanFilter
/// efficient - DMEs are proxies for TACAN/VORTAC stations
/// important that DME & TACAN are adjacent to keep the TacanFilter
/// efficient - DMEs are proxies for TACAN/VORTAC stations
DME,
TACAN,
MOBILE_TACAN,
OBSTACLE,
/// an actual airport tower - not a radio comms facility!
/// some airports have multiple towers, eg EHAM, although our data source
/// doesn't necessarily include them
/// an actual airport tower - not a radio comms facility!
/// some airports have multiple towers, eg EHAM, although our data source
/// doesn't necessarily include them
TOWER,
//comm stations : if extending this, be sure to update the isType check in
// CommStation.hxx
FREQ_GROUND,
FREQ_TOWER,
FREQ_ATIS,
@ -81,10 +83,10 @@ public:
FREQ_ENROUTE,
FREQ_CLEARANCE,
FREQ_UNICOM,
// groundnet items
// groundnet items
PARKING, ///< parking position - might be a gate, or stand
TAXI_NODE,
// POI items
// POI items
COUNTRY,
CITY,
TOWN,
@ -96,7 +98,9 @@ public:
virtual ~FGPositioned();
Type type() const
{ return mType; }
{
return mType;
}
// True for the following types: AIRPORT, HELIPORT, SEAPORT.
// False for other types, as well as if pos == nullptr.
@ -178,6 +182,14 @@ public:
TypeFilter(std::initializer_list<Type> types);
/**
* @brief Construct a new Type Filter based on a sequential range of types
*
* @param aMinType
* @param aMaxType
*/
TypeFilter(Type aMinType, Type aMaxType);
bool pass(FGPositioned* aPos) const override;
Type minType() const override

View file

@ -69,6 +69,9 @@ static naGhostType TaxiwayGhostType = { positionedGhostDestroy, "taxiway", runwa
static const char* fixGhostGetMember(naContext c, void* g, naRef field, naRef* out);
static naGhostType FixGhostType = { positionedGhostDestroy, "fix", fixGhostGetMember, nullptr };
static const char* commGhostGetMember(naContext c, void* g, naRef field, naRef* out);
static naGhostType CommGhostType = {positionedGhostDestroy, "comm", commGhostGetMember, nullptr};
static void hashset(naContext c, naRef hash, const char* key, naRef val)
{
naRef s = naNewString(c);
@ -88,8 +91,8 @@ FGPositioned* positionedGhost(naRef r)
if ((naGhost_type(r) == &AirportGhostType) ||
(naGhost_type(r) == &NavaidGhostType) ||
(naGhost_type(r) == &RunwayGhostType) ||
(naGhost_type(r) == &FixGhostType))
{
(naGhost_type(r) == &FixGhostType) ||
(naGhost_type(r) == &CommGhostType)) {
return (FGPositioned*) naGhost_ptr(r);
}
@ -131,6 +134,12 @@ static FGFix* fixGhost(naRef r)
return 0;
}
static flightgear::CommStation* commGhost(naRef r)
{
if (naGhost_type(r) == &CommGhostType)
return (flightgear::CommStation*)naGhost_ptr(r);
return nullptr;
}
static void positionedGhostDestroy(void* g)
{
@ -203,6 +212,16 @@ naRef ghostForFix(naContext c, const FGFix* r)
return naNewGhost2(c, &FixGhostType, (void*) r);
}
naRef ghostForComm(naContext c, const flightgear::CommStation* comm)
{
if (!c) {
return naNil();
}
FGPositioned::get(comm); // take a ref
return naNewGhost2(c, &CommGhostType, (void*)comm);
}
naRef ghostForPositioned(naContext c, FGPositionedRef pos)
{
if (!pos) {
@ -222,6 +241,16 @@ naRef ghostForPositioned(naContext c, FGPositionedRef pos)
return ghostForHelipad(c, fgpositioned_cast<FGHelipad>(pos));
case FGPositioned::RUNWAY:
return ghostForRunway(c, fgpositioned_cast<FGRunway>(pos));
case FGPositioned::FREQ_APP_DEP:
case FGPositioned::FREQ_AWOS:
case FGPositioned::FREQ_GROUND:
case FGPositioned::FREQ_TOWER:
case FGPositioned::FREQ_ATIS:
case FGPositioned::FREQ_CLEARANCE:
case FGPositioned::FREQ_UNICOM:
case FGPositioned::FREQ_ENROUTE:
return ghostForComm(c, fgpositioned_cast<flightgear::CommStation>(pos));
default:
SG_LOG(SG_NASAL, SG_DEV_ALERT, "Type lacks Nasal ghost mapping:" << pos->typeString());
return naNil();
@ -387,6 +416,31 @@ static const char* fixGhostGetMember(naContext c, void* g, naRef field, naRef* o
return "";
}
static const char* commGhostGetMember(naContext c, void* g, naRef field, naRef* out)
{
const char* fieldName = naStr_data(field);
auto comm = static_cast<flightgear::CommStation*>(g);
if (!strcmp(fieldName, "id"))
*out = stringToNasal(c, comm->ident());
else if (!strcmp(fieldName, "lat"))
*out = naNum(comm->latitude());
else if (!strcmp(fieldName, "lon"))
*out = naNum(comm->longitude());
else if (!strcmp(fieldName, "type")) {
*out = stringToNasal(c, comm->nameForType(comm->type()));
} else if (!strcmp(fieldName, "name"))
*out = stringToNasal(c, comm->name());
else if (!strcmp(fieldName, "frequency")) {
*out = naNum(comm->freqMHz());
} else {
return 0;
}
return "";
}
static bool hashIsCoord(naRef h)
{
naRef parents = naHash_cget(h, (char*) "parents");
@ -1364,6 +1418,34 @@ static naRef f_findNavaidsByFrequency(naContext c, naRef me, int argc, naRef* ar
return r;
}
static naRef f_findCommByFrequency(naContext c, naRef me, int argc, naRef* args)
{
int argOffset = 0;
SGGeod pos = globals->get_aircraft_position();
argOffset += geodFromArgs(args, 0, argc, pos);
if (!naIsNum(args[argOffset])) {
naRuntimeError(c, "findCommByFrequencyMhz expectes frequency (in Mhz) as arg %d", argOffset);
}
// initial filter is all comm types
FGPositioned::TypeFilter filter(FGPositioned::FREQ_GROUND, FGPositioned::FREQ_UNICOM);
double freqMhz = args[argOffset++].num;
if (argOffset < argc) {
// allow specifying an explicitly type by name
filter = FGPositioned::TypeFilter{FGPositioned::typeFromName(naStr_data(args[argOffset]))};
}
auto ref = NavDataCache::instance()->findCommByFreq(static_cast<int>(freqMhz * 1000), pos, &filter);
if (!ref) {
return naNil();
}
auto comm = fgpositioned_cast<flightgear::CommStation>(ref);
return ghostForComm(c, comm);
}
static naRef f_findNavaidsByIdent(naContext c, naRef me, int argc, naRef* args)
{
int argOffset = 0;
@ -1600,33 +1682,36 @@ FGPositionedRef positionedFromArg(naRef ref)
}
// Table of extension functions. Terminate with zeros.
static struct { const char* name; naCFunction func; } funcs[] = {
{ "carttogeod", f_carttogeod },
{ "geodtocart", f_geodtocart },
{ "geodinfo", f_geodinfo },
{ "formatLatLon", f_formatLatLon },
{ "parseStringAsLatLonValue", f_parseStringAsLatLonValue},
{ "get_cart_ground_intersection", f_get_cart_ground_intersection },
{ "aircraftToCart", f_aircraftToCart },
{ "airportinfo", f_airportinfo },
{ "findAirportsWithinRange", f_findAirportsWithinRange },
{ "findAirportsByICAO", f_findAirportsByICAO },
{ "navinfo", f_navinfo },
{ "findNavaidsWithinRange", f_findNavaidsWithinRange },
{ "findNDBByFrequencyKHz", f_findNDBByFrequency },
{ "findNDBsByFrequencyKHz", f_findNDBsByFrequency },
{ "findNavaidByFrequencyMHz", f_findNavaidByFrequency },
{ "findNavaidsByFrequencyMHz", f_findNavaidsByFrequency },
{ "findNavaidsByID", f_findNavaidsByIdent },
{ "findFixesByID", f_findFixesByIdent },
{ "findByIdent", f_findByIdent },
{ "magvar", f_magvar },
{ "courseAndDistance", f_courseAndDistance },
{ "greatCircleMove", f_greatCircleMove },
{ "tileIndex", f_tileIndex },
{ "tilePath", f_tilePath },
{ 0, 0 }
};
static struct {
const char* name;
naCFunction func;
} funcs[] = {
{"carttogeod", f_carttogeod},
{"geodtocart", f_geodtocart},
{"geodinfo", f_geodinfo},
{"formatLatLon", f_formatLatLon},
{"parseStringAsLatLonValue", f_parseStringAsLatLonValue},
{"get_cart_ground_intersection", f_get_cart_ground_intersection},
{"aircraftToCart", f_aircraftToCart},
{"airportinfo", f_airportinfo},
{"findAirportsWithinRange", f_findAirportsWithinRange},
{"findAirportsByICAO", f_findAirportsByICAO},
{"navinfo", f_navinfo},
{"findNavaidsWithinRange", f_findNavaidsWithinRange},
{"findNDBByFrequencyKHz", f_findNDBByFrequency},
{"findNDBsByFrequencyKHz", f_findNDBsByFrequency},
{"findNavaidByFrequencyMHz", f_findNavaidByFrequency},
{"findNavaidsByFrequencyMHz", f_findNavaidsByFrequency},
{"findCommByFrequencyMHz", f_findCommByFrequency},
{"findNavaidsByID", f_findNavaidsByIdent},
{"findFixesByID", f_findFixesByIdent},
{"findByIdent", f_findByIdent},
{"magvar", f_magvar},
{"courseAndDistance", f_courseAndDistance},
{"greatCircleMove", f_greatCircleMove},
{"tileIndex", f_tileIndex},
{"tilePath", f_tilePath},
{0, 0}};
naRef initNasalPositioned(naRef globals, naContext c)

View file

@ -29,7 +29,7 @@ void CommandsTests::setUp()
void CommandsTests::tearDown()
{
delete SGCommandMgr::instance();
FGTestApi::tearDown::shutdownTestGlobals();
}
void CommandsTests::testPropertyAdjustCommand()

View file

@ -29,6 +29,8 @@
#include <Main/globals.hxx>
#include <Main/util.hxx>
#include <Airports/airport.hxx>
#include <Scripting/NasalSys.hxx>
#include <Main/FGInterpolator.hxx>
@ -59,6 +61,12 @@ void NasalSysTests::tearDown()
FGTestApi::tearDown::shutdownTestGlobals();
}
bool NasalSysTests::checkNoNasalErrors()
{
auto nasalSys = globals->get_subsystem<FGNasalSys>();
auto errors = nasalSys->getAndClearErrorList();
return errors.empty();
}
// Test test
void NasalSysTests::testStructEquality()
@ -169,6 +177,31 @@ void NasalSysTests::testAirportGhost()
}
void NasalSysTests::testFindComm()
{
FGAirportRef apt = FGAirport::getByIdent("EDDM");
FGTestApi::setPositionAndStabilise(apt->geod());
auto nasalSys = globals->get_subsystem<FGNasalSys>();
nasalSys->getAndClearErrorList();
bool ok = FGTestApi::executeNasal(R"(
var comm = findCommByFrequencyMHz(123.125);
unitTest.assert_equal(comm.id, "ATIS");
# explicit filter, should't match
var noComm = findCommByFrequencyMHz(123.125, "tower");
unitTest.assert_equal(noComm, nil);
# match with filter
var comm2 = findCommByFrequencyMHz(121.725, "clearance");
unitTest.assert_equal(comm2.id, "CLNC DEL");
)");
CPPUNIT_ASSERT(ok && checkNoNasalErrors());
}
// https://sourceforge.net/p/flightgear/codetickets/2246/
void NasalSysTests::testCompileLarge()

View file

@ -40,8 +40,11 @@ class NasalSysTests : public CppUnit::TestFixture
CPPUNIT_TEST(testKeywordArgInHash);
CPPUNIT_TEST(testNullAccess);
CPPUNIT_TEST(testNullishChain);
CPPUNIT_TEST(testFindComm);
CPPUNIT_TEST_SUITE_END();
bool checkNoNasalErrors();
public:
// Set up function for each test.
void setUp();
@ -59,6 +62,7 @@ public:
void testKeywordArgInHash();
void testNullAccess();
void testNullishChain();
void testFindComm();
};
#endif // _FG_NASALSYS_UNIT_TESTS_HXX