Improvements to Nasal hold API
Ensure changes from Nasal are picked up by delegates (such as GPS) when they are made. Add a route-manager test which sets and exits a hold using Nasal. As part of this, update the test API to make it easy to run Nasal from a test.
This commit is contained in:
parent
fafc9e3e64
commit
18c19885c6
10 changed files with 294 additions and 114 deletions
|
@ -567,8 +567,8 @@ void GPS::currentWaypointChanged()
|
|||
int index = _route->currentIndex(),
|
||||
count = _route->numLegs();
|
||||
if ((index < 0) || (index >= count)) {
|
||||
_currentWaypt=NULL;
|
||||
_prevWaypt=NULL;
|
||||
_currentWaypt=nullptr;
|
||||
_prevWaypt=nullptr;
|
||||
// no active leg on the route
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1576,46 +1576,55 @@ double FlightPlan::Leg::distanceAlongRoute() const
|
|||
return _distanceAlongPath;
|
||||
}
|
||||
|
||||
|
||||
bool FlightPlan::Leg::convertWaypointToHold()
|
||||
{
|
||||
const auto wty = _waypt->type();
|
||||
if (wty == "hold") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((wty != "basic") && (wty != "navaid")) {
|
||||
SG_LOG(SG_INSTR, SG_WARN, "convertWaypointToHold: cannot convert waypt " << index() << " " << _waypt->ident() << " to a hold");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto hold = new Hold(_waypt->position(), _waypt->ident(), const_cast<FlightPlan*>(_parent));
|
||||
|
||||
// default to a 1 minute hold with the radial being our arrival radial
|
||||
hold->setHoldTime(60.0);
|
||||
hold->setHoldRadial(_courseDeg);
|
||||
_waypt = hold; // we drop our reference to the old waypoint
|
||||
|
||||
markWaypointDirty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlightPlan::Leg::setHoldCount(int count)
|
||||
{
|
||||
if (count == 0) {
|
||||
_holdCount = count;
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto wty = _waypt->type();
|
||||
bool fireWaypointsChanged = false;
|
||||
|
||||
if (wty != "hold") {
|
||||
// upgrade to a hold if possible
|
||||
if ((wty == "basic") || (wty == "navaid")) {
|
||||
auto hold = new Hold(_waypt->position(), _waypt->ident(), const_cast<FlightPlan*>(_parent));
|
||||
|
||||
// default to a 1 minute hold with the radial being our arrival radial
|
||||
hold->setHoldTime(60.0);
|
||||
hold->setHoldRadial(_courseDeg);
|
||||
fireWaypointsChanged = true;
|
||||
_waypt = hold; // we drop our reference to the old waypoint
|
||||
} else {
|
||||
SG_LOG(SG_INSTR, SG_WARN, "setHoldCount: cannot convert waypt " << index() << " " << _waypt->ident() << " to a hold");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!convertWaypointToHold()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_holdCount = count;
|
||||
markWaypointDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fireWaypointsChanged) {
|
||||
SG_LOG(SG_INSTR, SG_INFO, "setHoldCount: changed waypoint type, notifying deleagtes the FP changed");
|
||||
|
||||
void FlightPlan::Leg::markWaypointDirty()
|
||||
{
|
||||
auto fp = owner();
|
||||
fp->lockDelegates();
|
||||
fp->_waypointsChanged = true;
|
||||
fp->unlockDelegates();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int FlightPlan::Leg::holdCount() const
|
||||
{
|
||||
return _holdCount;
|
||||
|
|
|
@ -104,6 +104,9 @@ public:
|
|||
|
||||
int holdCount() const;
|
||||
|
||||
|
||||
bool convertWaypointToHold();
|
||||
|
||||
unsigned int index() const;
|
||||
|
||||
int altitudeFt() const;
|
||||
|
@ -122,6 +125,12 @@ public:
|
|||
double distanceNm() const;
|
||||
double distanceAlongRoute() const;
|
||||
|
||||
/**
|
||||
* helper function, if the waypoint is modified in some way, to
|
||||
* notify the flightplan owning this leg, and hence any delegates
|
||||
* obsering us
|
||||
*/
|
||||
void markWaypointDirty();
|
||||
private:
|
||||
friend class FlightPlan;
|
||||
|
||||
|
|
|
@ -584,7 +584,7 @@ static const char* waypointCommonGetMember(naContext c, Waypt* wpt, const char*
|
|||
return "";
|
||||
}
|
||||
|
||||
static void waypointCommonSetMember(naContext c, Waypt* wpt, const char* fieldName, naRef value)
|
||||
static bool waypointCommonSetMember(naContext c, Waypt* wpt, const char* fieldName, naRef value)
|
||||
{
|
||||
if (!strcmp(fieldName, "wp_role")) {
|
||||
if (!naIsString(value)) naRuntimeError(c, "wp_role must be a string");
|
||||
|
@ -612,7 +612,12 @@ static void waypointCommonSetMember(naContext c, Waypt* wpt, const char* fieldNa
|
|||
hold->setRightHanded();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// nothing changed
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char* wayptGhostGetMember(naContext c, void* g, naRef field, naRef* out)
|
||||
|
@ -744,13 +749,25 @@ static void legGhostSetMember(naContext c, void* g, naRef field, naRef value)
|
|||
{
|
||||
const char* fieldName = naStr_data(field);
|
||||
FlightPlan::Leg* leg = (FlightPlan::Leg*) g;
|
||||
|
||||
|
||||
bool didChange = false;
|
||||
if (!strcmp(fieldName, "hold_count")) {
|
||||
const int count = static_cast<int>(value.num);
|
||||
// this may upgrade the waypoint to a hold
|
||||
leg->setHoldCount(count);
|
||||
if (!leg->setHoldCount(count))
|
||||
naRuntimeError(c, "unable to set hold on leg waypoint: maybe unsuitable waypt type?");
|
||||
} else if (!strcmp(fieldName, "hold_heading_radial_deg")) {
|
||||
if (!leg->convertWaypointToHold())
|
||||
naRuntimeError(c, "couldn't convert leg waypoint into a hold");
|
||||
|
||||
// now we can call the base method
|
||||
didChange = waypointCommonSetMember(c, leg->waypoint(), fieldName, value);
|
||||
} else {
|
||||
waypointCommonSetMember(c, leg->waypoint(), fieldName, value);
|
||||
didChange = waypointCommonSetMember(c, leg->waypoint(), fieldName, value);
|
||||
}
|
||||
|
||||
if (didChange) {
|
||||
leg->markWaypointDirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -230,6 +230,15 @@ void setPosition(const SGGeod& g)
|
|||
globals->get_props()->setDoubleValue("position/longitude-deg", g.getLongitudeDeg());
|
||||
globals->get_props()->setDoubleValue("position/altitude-ft", g.getElevationFt());
|
||||
}
|
||||
|
||||
void setPositionAndStabilise(const SGGeod& g)
|
||||
{
|
||||
setPosition(g);
|
||||
for (int i=0; i<60; ++i) {
|
||||
globals->get_subsystem_mgr()->update(0.015);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void runForTime(double t)
|
||||
{
|
||||
|
@ -306,6 +315,22 @@ void writeGeodsToKML(const std::string &label, const flightgear::SGGeodVec& geod
|
|||
endCurrentLineString();
|
||||
}
|
||||
|
||||
bool executeNasal(const std::string& code)
|
||||
{
|
||||
auto nasal = globals->get_subsystem<FGNasalSys>();
|
||||
if (!nasal) {
|
||||
throw sg_exception("Nasal not available");
|
||||
}
|
||||
|
||||
std::string output, errors;
|
||||
bool ok = nasal->parseAndRunWithOutput(code, output, errors);
|
||||
if (!errors.empty()) {
|
||||
SG_LOG(SG_NASAL, SG_ALERT, "Errors running Nasal:" << errors);
|
||||
return false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
namespace tearDown {
|
||||
|
||||
|
|
|
@ -38,17 +38,22 @@ void populateFPWithNasal(flightgear::FlightPlanRef f,
|
|||
|
||||
} // End of namespace setUp.
|
||||
|
||||
// helpers during tests
|
||||
|
||||
void setPosition(const SGGeod& g);
|
||||
|
||||
void setPositionAndStabilise(const SGGeod& g);
|
||||
|
||||
void runForTime(double t);
|
||||
|
||||
using RunCheck = std::function<bool(void)>;
|
||||
using RunCheck = std::function<bool(void)>;
|
||||
|
||||
bool runForTimeWithCheck(double t, RunCheck check);
|
||||
|
||||
void writeFlightPlanToKML(flightgear::FlightPlanRef fp);
|
||||
|
||||
void writeGeodsToKML(const std::string &label, const flightgear::SGGeodVec& geods);
|
||||
|
||||
bool executeNasal(const std::string& code);
|
||||
|
||||
namespace tearDown {
|
||||
|
||||
|
|
|
@ -82,14 +82,6 @@ void GPSTests::tearDown()
|
|||
FGTestApi::tearDown::shutdownTestGlobals();
|
||||
}
|
||||
|
||||
void GPSTests::setPositionAndStabilise(GPS* gps, const SGGeod& g)
|
||||
{
|
||||
FGTestApi::setPosition(g);
|
||||
for (int i=0; i<60; ++i) {
|
||||
gps->update(0.015);
|
||||
}
|
||||
}
|
||||
|
||||
GPS* GPSTests::setupStandardGPS(SGPropertyNode_ptr config,
|
||||
const std::string name, const int index)
|
||||
{
|
||||
|
@ -123,13 +115,13 @@ void GPSTests::setupRouteManager()
|
|||
|
||||
void GPSTests::testBasic()
|
||||
{
|
||||
auto gps = setupStandardGPS();
|
||||
setupStandardGPS();
|
||||
|
||||
FGPositioned::TypeFilter f{FGPositioned::VOR};
|
||||
auto bodrumVOR = fgpositioned_cast<FGNavRecord>(FGPositioned::findClosestWithIdent("BDR", SGGeod::fromDeg(27.6, 37), &f));
|
||||
SGGeod p1 = SGGeodesy::direct(bodrumVOR->geod(), 45.0, 5.0 * SG_NM_TO_METER);
|
||||
|
||||
setPositionAndStabilise(gps, p1);
|
||||
FGTestApi::setPositionAndStabilise(p1);
|
||||
|
||||
auto gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(p1.getLongitudeDeg(), gpsNode->getDoubleValue("indicated-longitude-deg"), 0.01);
|
||||
|
@ -156,14 +148,14 @@ void GPSTests::testBasic()
|
|||
|
||||
void GPSTests::testOBSMode()
|
||||
{
|
||||
auto gps = setupStandardGPS();
|
||||
setupStandardGPS();
|
||||
|
||||
FGPositioned::TypeFilter f{FGPositioned::VOR};
|
||||
auto bodrumVOR = fgpositioned_cast<FGNavRecord>(FGPositioned::findClosestWithIdent("BDR", SGGeod::fromDeg(27.6, 37), &f));
|
||||
SGGeod p1 = SGGeodesy::direct(bodrumVOR->geod(), 45.0, 5.0 * SG_NM_TO_METER);
|
||||
|
||||
setPositionAndStabilise(gps, p1);
|
||||
|
||||
FGTestApi::setPositionAndStabilise(p1);
|
||||
|
||||
auto gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(p1.getLongitudeDeg(), gpsNode->getDoubleValue("indicated-longitude-deg"), 0.01);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(p1.getLatitudeDeg(), gpsNode->getDoubleValue("indicated-latitude-deg"), 0.01);
|
||||
|
@ -182,7 +174,7 @@ void GPSTests::testOBSMode()
|
|||
// select OBS mode one it
|
||||
gpsNode->setStringValue("command", "obs");
|
||||
|
||||
setPositionAndStabilise(gps, p1);
|
||||
FGTestApi::setPositionAndStabilise(p1);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(std::string{"obs"}, std::string{gpsNode->getStringValue("mode")});
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(5.0, gpsNode->getDoubleValue("wp/wp[1]/distance-nm"), 0.01);
|
||||
|
@ -196,7 +188,7 @@ void GPSTests::testOBSMode()
|
|||
|
||||
// off axis, angular
|
||||
SGGeod p2 = SGGeodesy::direct(bodrumVOR->geod(), 40.0, 4.0 * SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, p2);
|
||||
FGTestApi::setPositionAndStabilise(p2);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(std::string{"obs"}, std::string{gpsNode->getStringValue("mode")});
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(4.0, gpsNode->getDoubleValue("wp/wp[1]/distance-nm"), 0.01);
|
||||
|
@ -206,7 +198,7 @@ void GPSTests::testOBSMode()
|
|||
|
||||
// off axis, perpendicular
|
||||
SGGeod p3 = SGGeodesy::direct(p1, 135, 0.5 * SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, p3);
|
||||
FGTestApi::setPositionAndStabilise(p3);
|
||||
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(225.0, gpsNode->getDoubleValue("desired-course-deg"), 0.01);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.5, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.05);
|
||||
|
@ -214,15 +206,13 @@ void GPSTests::testOBSMode()
|
|||
|
||||
void GPSTests::testDirectTo()
|
||||
{
|
||||
auto gps = setupStandardGPS();
|
||||
|
||||
|
||||
setupStandardGPS();
|
||||
|
||||
FGPositioned::TypeFilter f{FGPositioned::VOR};
|
||||
auto bodrumVOR = fgpositioned_cast<FGNavRecord>(FGPositioned::findClosestWithIdent("BDR", SGGeod::fromDeg(27.6, 37), &f));
|
||||
SGGeod p1 = SGGeodesy::direct(bodrumVOR->geod(), 30.0, 16.0 * SG_NM_TO_METER);
|
||||
|
||||
setPositionAndStabilise(gps, p1);
|
||||
FGTestApi::setPositionAndStabilise(p1);
|
||||
|
||||
auto gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||
|
||||
|
@ -251,16 +241,16 @@ void GPSTests::testDirectTo()
|
|||
// move off the direct-to line, check everything works
|
||||
|
||||
SGGeod p2 = SGGeodesy::direct(bodrumVOR->geod(), 35.0, 12.0 * SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, p2);
|
||||
FGTestApi::setPositionAndStabilise(p2);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(5, gpsNode->getDoubleValue("wp/wp[1]/course-deviation-deg"), 0.1);
|
||||
|
||||
SGGeod p3 = SGGeodesy::direct(p1, 210, 6.0 * SG_NM_TO_METER);
|
||||
SGGeod xtk = SGGeodesy::direct(p3, 120, 0.8 * SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, xtk);
|
||||
FGTestApi::setPositionAndStabilise(xtk);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.8, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||
|
||||
SGGeod xtk2 = SGGeodesy::direct(p3, 120, -1.8 * SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, xtk2);
|
||||
FGTestApi::setPositionAndStabilise(xtk2);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.8, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||
}
|
||||
|
||||
|
@ -288,9 +278,9 @@ void GPSTests::testLegMode()
|
|||
CPPUNIT_ASSERT(rm->activate());
|
||||
|
||||
fp->addDelegate(testDelegate);
|
||||
auto gps = setupStandardGPS();
|
||||
setupStandardGPS();
|
||||
|
||||
setPositionAndStabilise(gps, fp->departureRunway()->pointOnCenterline(0.0));
|
||||
FGTestApi::setPositionAndStabilise(fp->departureRunway()->pointOnCenterline(0.0));
|
||||
|
||||
auto gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||
gpsNode->setBoolValue("config/delegate-sequencing", true);
|
||||
|
@ -320,7 +310,7 @@ void GPSTests::testLegMode()
|
|||
|
||||
SGGeod nikPos = fp->currentLeg()->waypoint()->position();
|
||||
SGGeod p2 = SGGeodesy::direct(nikPos, 90, 5 * SG_NM_TO_METER); // due east of NIK
|
||||
setPositionAndStabilise(gps, p2);
|
||||
FGTestApi::setPositionAndStabilise(p2);
|
||||
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(270, gpsNode->getDoubleValue("wp/wp[1]/bearing-true-deg"), 0.5);
|
||||
|
||||
|
@ -356,11 +346,11 @@ void GPSTests::testLegMode()
|
|||
double course = SGGeodesy::courseDeg(coaPos, doverPos);
|
||||
double revCourse = SGGeodesy::courseDeg(doverPos, coaPos);
|
||||
|
||||
setPositionAndStabilise(gps, coaPos);
|
||||
FGTestApi::setPositionAndStabilise(coaPos);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(course, gpsNode->getDoubleValue("wp/leg-true-course-deg"), 0.5);
|
||||
|
||||
SGGeod off1 = SGGeodesy::direct(doverPos, revCourse - 5.0, 16 * SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, off1);
|
||||
FGTestApi::setPositionAndStabilise(off1);
|
||||
|
||||
double courseToDover = SGGeodesy::courseDeg(off1, doverPos);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(courseToDover, gpsNode->getDoubleValue("wp/wp[1]/bearing-true-deg"), 0.5);
|
||||
|
@ -370,7 +360,7 @@ void GPSTests::testLegMode()
|
|||
CPPUNIT_ASSERT_EQUAL(false, gpsNode->getBoolValue("wp/wp[1]/from-flag"));
|
||||
|
||||
SGGeod off2 = SGGeodesy::direct(doverPos, revCourse + 8.0, 40 * SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, off2);
|
||||
FGTestApi::setPositionAndStabilise(off2);
|
||||
|
||||
courseToDover = SGGeodesy::courseDeg(off2, doverPos);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(courseToDover, gpsNode->getDoubleValue("wp/wp[1]/bearing-true-deg"), 0.5);
|
||||
|
@ -382,20 +372,20 @@ void GPSTests::testLegMode()
|
|||
SGGeod alongTrack = SGGeodesy::direct(coaPos, course, 20 * SG_NM_TO_METER);
|
||||
SGGeod offTrack = SGGeodesy::direct(alongTrack, course + 90, SG_NM_TO_METER * 0.7);
|
||||
|
||||
setPositionAndStabilise(gps, offTrack);
|
||||
FGTestApi::setPositionAndStabilise(offTrack);
|
||||
courseToDover = SGGeodesy::courseDeg(offTrack, doverPos);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(courseToDover, gpsNode->getDoubleValue("wp/wp[1]/bearing-true-deg"), 0.5);
|
||||
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(-0.7, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||
|
||||
SGGeod offTrack2 = SGGeodesy::direct(alongTrack, courseToDover - 90, SG_NM_TO_METER * 3.4);
|
||||
setPositionAndStabilise(gps, offTrack2);
|
||||
FGTestApi::setPositionAndStabilise(offTrack2);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(3.4, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||
|
||||
// check cross track very close to COA
|
||||
SGGeod alongTrack11 = SGGeodesy::direct(coaPos, course, 0.3);
|
||||
SGGeod offTrack25 = SGGeodesy::direct(alongTrack11, course + 90, SG_NM_TO_METER * -3.2);
|
||||
setPositionAndStabilise(gps, offTrack25);
|
||||
FGTestApi::setPositionAndStabilise(offTrack25);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(3.2, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(course, gpsNode->getDoubleValue("wp/leg-true-course-deg"), 0.1);
|
||||
|
||||
|
@ -403,14 +393,14 @@ void GPSTests::testLegMode()
|
|||
double distanceCOA_DVR = SGGeodesy::distanceM(coaPos, doverPos);
|
||||
SGGeod alongTrack2 = SGGeodesy::direct(coaPos, course, distanceCOA_DVR - 0.3);
|
||||
SGGeod offTrack3 = SGGeodesy::direct(alongTrack2, course + 90, SG_NM_TO_METER * 1.6);
|
||||
setPositionAndStabilise(gps, offTrack3);
|
||||
FGTestApi::setPositionAndStabilise(offTrack3);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(-1.6, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(revCourse + 180.0, gpsNode->getDoubleValue("wp/leg-true-course-deg"), 0.1);
|
||||
|
||||
// check cross track in the middle
|
||||
SGGeod alongTrack3 = SGGeodesy::direct(coaPos, course, distanceCOA_DVR * 0.52);
|
||||
SGGeod offTrack4 = SGGeodesy::direct(alongTrack3, course + 90, SG_NM_TO_METER * 15.6);
|
||||
setPositionAndStabilise(gps, offTrack4);
|
||||
FGTestApi::setPositionAndStabilise(offTrack4);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(-15.6, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(261.55, gpsNode->getDoubleValue("wp/leg-true-course-deg"), 0.1);
|
||||
}
|
||||
|
@ -437,14 +427,14 @@ void GPSTests::testBuiltinRevertToOBSAtEnd()
|
|||
fp->addDelegate(testDelegate);
|
||||
auto gps = setupStandardGPS();
|
||||
|
||||
setPositionAndStabilise(gps, fp->departureRunway()->pointOnCenterline(0.0));
|
||||
FGTestApi::setPositionAndStabilise(fp->departureRunway()->pointOnCenterline(0.0));
|
||||
|
||||
auto gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||
gpsNode->setStringValue("command", "leg");
|
||||
|
||||
// move to point 18.0 nm after BDN
|
||||
auto posNearApproach = fp->pointAlongRoute(5, 18.0);
|
||||
setPositionAndStabilise(gps, posNearApproach);
|
||||
FGTestApi::setPositionAndStabilise(posNearApproach);
|
||||
fp->setCurrentIndex(6);
|
||||
|
||||
auto pilot = SGSharedPtr<FGTestApi::TestPilot>(new FGTestApi::TestPilot);
|
||||
|
@ -482,10 +472,9 @@ void GPSTests::testDirectToLegOnFlightplan()
|
|||
CPPUNIT_ASSERT(rm->activate());
|
||||
|
||||
fp->addDelegate(testDelegate);
|
||||
auto gps = setupStandardGPS();
|
||||
setupStandardGPS();
|
||||
|
||||
|
||||
setPositionAndStabilise(gps, fp->departureRunway()->pointOnCenterline(0.0));
|
||||
FGTestApi::setPositionAndStabilise(fp->departureRunway()->pointOnCenterline(0.0));
|
||||
|
||||
auto gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||
gpsNode->setBoolValue("config/delegate-sequencing", true);
|
||||
|
@ -499,7 +488,7 @@ void GPSTests::testDirectToLegOnFlightplan()
|
|||
|
||||
// initiate a direct to
|
||||
SGGeod p2 = fp->departureRunway()->pointOnCenterline(5.0* SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, p2);
|
||||
FGTestApi::setPositionAndStabilise(p2);
|
||||
|
||||
auto doverVOR = fp->legAtIndex(3)->waypoint()->source();
|
||||
|
||||
|
@ -545,7 +534,7 @@ void GPSTests::testDirectToLegOnFlightplanAndResumeBuiltin()
|
|||
CPPUNIT_ASSERT(rm->activate());
|
||||
auto gps = setupStandardGPS();
|
||||
|
||||
setPositionAndStabilise(gps, fp->departureRunway()->pointOnCenterline(0.0));
|
||||
FGTestApi::setPositionAndStabilise(fp->departureRunway()->pointOnCenterline(0.0));
|
||||
|
||||
auto gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||
gpsNode->setStringValue("command", "leg");
|
||||
|
@ -558,7 +547,7 @@ void GPSTests::testDirectToLegOnFlightplanAndResumeBuiltin()
|
|||
|
||||
// initiate a direct to
|
||||
SGGeod p2 = fp->departureRunway()->pointOnCenterline(5.0* SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, p2);
|
||||
FGTestApi::setPositionAndStabilise(p2);
|
||||
|
||||
auto doverVOR = fp->legAtIndex(3)->waypoint()->source();
|
||||
|
||||
|
@ -576,7 +565,7 @@ void GPSTests::testDirectToLegOnFlightplanAndResumeBuiltin()
|
|||
// note this behaviour is from the old C++ sequencing
|
||||
|
||||
SGGeod posNearDover = SGGeodesy::direct(p2, bearingToDover, (distanceToDover - 8.0) * SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, posNearDover);
|
||||
FGTestApi::setPositionAndStabilise(posNearDover);
|
||||
|
||||
auto pilot = SGSharedPtr<FGTestApi::TestPilot>(new FGTestApi::TestPilot);
|
||||
pilot->resetAtPosition(posNearDover);
|
||||
|
@ -608,7 +597,7 @@ void GPSTests::testLongLeg()
|
|||
CPPUNIT_ASSERT(rm->activate());
|
||||
|
||||
fp->addDelegate(testDelegate);
|
||||
auto gps = setupStandardGPS();
|
||||
setupStandardGPS();
|
||||
auto gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||
gpsNode->setBoolValue("config/delegate-sequencing", true);
|
||||
gpsNode->setStringValue("command", "leg");
|
||||
|
@ -625,7 +614,7 @@ void GPSTests::testLongLeg()
|
|||
|
||||
fp->setCurrentIndex(2);
|
||||
// initial course at VNY
|
||||
setPositionAndStabilise(gps, vanNuysVOR->geod());
|
||||
FGTestApi::setPositionAndStabilise(vanNuysVOR->geod());
|
||||
|
||||
const double initialCourse = SGGeodesy::courseDeg(vanNuysVOR->geod(), teterboroVOR->geod());
|
||||
const double distanceM = SGGeodesy::distanceM(vanNuysVOR->geod(), teterboroVOR->geod());
|
||||
|
@ -640,7 +629,7 @@ void GPSTests::testLongLeg()
|
|||
|
||||
// part of the way, check enroute leg course
|
||||
const SGGeod onTheWay = SGGeodesy::direct(vanNuysVOR->geod(), initialCourse, distanceM * 0.7);
|
||||
setPositionAndStabilise(gps, onTheWay);
|
||||
FGTestApi::setPositionAndStabilise(onTheWay);
|
||||
|
||||
const double courseNow = SGGeodesy::courseDeg(onTheWay, teterboroVOR->geod());
|
||||
const double distNow = SGGeodesy::distanceM(onTheWay, teterboroVOR->geod());
|
||||
|
@ -656,7 +645,7 @@ void GPSTests::testLongLeg()
|
|||
// check a seriously abeam point, we got far of course
|
||||
// to the right of the course, i.e desired track is to our left, so -ve
|
||||
const SGGeod offTheWay = SGGeodesy::direct(onTheWay, courseNow + 90, SG_NM_TO_METER * 13.5);
|
||||
setPositionAndStabilise(gps, offTheWay);
|
||||
FGTestApi::setPositionAndStabilise(offTheWay);
|
||||
const double courseFromOff1 = SGGeodesy::courseDeg(offTheWay, teterboroVOR->geod());
|
||||
const double dist2 = SGGeodesy::distanceM(offTheWay, teterboroVOR->geod());
|
||||
|
||||
|
@ -673,7 +662,7 @@ void GPSTests::testLongLeg()
|
|||
const SGGeod onTheWay2 = SGGeodesy::direct(vanNuysVOR->geod(), initialCourse, distanceM * 0.92);
|
||||
const double courseOn2 = SGGeodesy::courseDeg(onTheWay2, teterboroVOR->geod());
|
||||
const SGGeod off2 = SGGeodesy::direct(onTheWay2, courseOn2 - 90, SG_NM_TO_METER * 31.2);
|
||||
setPositionAndStabilise(gps, off2);
|
||||
FGTestApi::setPositionAndStabilise(off2);
|
||||
const double courseFromOff2 = SGGeodesy::courseDeg(off2, teterboroVOR->geod());
|
||||
const double dist3 = SGGeodesy::distanceM(off2, teterboroVOR->geod());
|
||||
|
||||
|
@ -701,7 +690,7 @@ void GPSTests::testLongLegWestbound()
|
|||
CPPUNIT_ASSERT(rm->activate());
|
||||
|
||||
fp->addDelegate(testDelegate);
|
||||
auto gps = setupStandardGPS();
|
||||
setupStandardGPS();
|
||||
|
||||
auto gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||
gpsNode->setBoolValue("config/delegate-sequencing", true);
|
||||
|
@ -717,7 +706,7 @@ void GPSTests::testLongLegWestbound()
|
|||
|
||||
fp->setCurrentIndex(2);
|
||||
// initial course at VNY
|
||||
setPositionAndStabilise(gps, volloVOR->geod());
|
||||
FGTestApi::setPositionAndStabilise(volloVOR->geod());
|
||||
|
||||
const double initialCourse = SGGeodesy::courseDeg(volloVOR->geod(), gaktu->geod());
|
||||
const double distanceM = SGGeodesy::distanceM(volloVOR->geod(), gaktu->geod());
|
||||
|
@ -732,7 +721,7 @@ void GPSTests::testLongLegWestbound()
|
|||
|
||||
// part of the way, check enroute leg course
|
||||
const SGGeod onTheWay = SGGeodesy::direct(volloVOR->geod(), initialCourse, distanceM * 0.4);
|
||||
setPositionAndStabilise(gps, onTheWay);
|
||||
FGTestApi::setPositionAndStabilise(onTheWay);
|
||||
|
||||
const double courseNow = SGGeodesy::courseDeg(onTheWay, gaktu->geod());
|
||||
const double distNow = SGGeodesy::distanceM(onTheWay, gaktu->geod());
|
||||
|
@ -748,7 +737,7 @@ void GPSTests::testLongLegWestbound()
|
|||
// check a seriously abeam point, we got far of course
|
||||
// to the right of the course, i.e desired track is to our left, so -ve
|
||||
const SGGeod offTheWay = SGGeodesy::direct(onTheWay, courseNow + 90, SG_NM_TO_METER * 18.6);
|
||||
setPositionAndStabilise(gps, offTheWay);
|
||||
FGTestApi::setPositionAndStabilise(offTheWay);
|
||||
const double courseFromOff1 = SGGeodesy::courseDeg(offTheWay, gaktu->geod());
|
||||
const double dist2 = SGGeodesy::distanceM(offTheWay, gaktu->geod());
|
||||
|
||||
|
@ -797,7 +786,7 @@ void GPSTests::testOverflightSequencing()
|
|||
// enroute to NELSON VOR
|
||||
fp->setCurrentIndex(2);
|
||||
SGGeod pos = fp->pointAlongRoute(2, -5.0);
|
||||
setPositionAndStabilise(gps, pos);
|
||||
FGTestApi::setPositionAndStabilise(pos);
|
||||
|
||||
auto pilot = SGSharedPtr<FGTestApi::TestPilot>(new FGTestApi::TestPilot);
|
||||
pilot->resetAtPosition(pos);
|
||||
|
@ -831,7 +820,7 @@ void GPSTests::testOverflightSequencing()
|
|||
|
||||
// point a bit before MAMOD
|
||||
SGGeod pos2 = fp->pointAlongRoute(5, -5.0);
|
||||
setPositionAndStabilise(gps, pos2);
|
||||
FGTestApi::setPositionAndStabilise(pos2);
|
||||
fp->setCurrentIndex(5);
|
||||
auto mamod = fp->legAtIndex(5)->waypoint()->source();
|
||||
|
||||
|
@ -893,7 +882,7 @@ void GPSTests::testOffcourseSequencing()
|
|||
SGGeod pos = fp->pointAlongRoute(2, -5.0);
|
||||
|
||||
pos = SGGeodesy::direct(pos, 180, 1.5 * SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, pos);
|
||||
FGTestApi::setPositionAndStabilise(pos);
|
||||
|
||||
|
||||
auto nelsonVOR = fp->legAtIndex(2)->waypoint()->source();
|
||||
|
@ -952,7 +941,7 @@ void GPSTests::testOffcourseSequencing()
|
|||
pos2 = SGGeodesy::direct(pos2, 180, 0.8 * SG_NM_TO_METER);
|
||||
|
||||
fp->setCurrentIndex(5);
|
||||
setPositionAndStabilise(gps, pos2);
|
||||
FGTestApi::setPositionAndStabilise(pos2);
|
||||
// start facing the right way
|
||||
pilot->setCourseTrue(gpsNode->getDoubleValue("wp/leg-true-course-deg"));
|
||||
pilot->flyHeading(gpsNode->getDoubleValue("wp/leg-true-course-deg"));
|
||||
|
@ -991,7 +980,7 @@ void GPSTests::testOffcourseSequencing()
|
|||
pos3 = SGGeodesy::direct(pos3, 90, 1.8 * SG_NM_TO_METER);
|
||||
|
||||
fp->setCurrentIndex(6);
|
||||
setPositionAndStabilise(gps, pos3);
|
||||
FGTestApi::setPositionAndStabilise(pos3);
|
||||
// start facing the right way
|
||||
pilot->setCourseTrue(gpsNode->getDoubleValue("wp/leg-true-course-deg"));
|
||||
pilot->flyHeading(gpsNode->getDoubleValue("wp/leg-true-course-deg"));
|
||||
|
@ -1040,7 +1029,7 @@ void GPSTests::testOffsetFlight()
|
|||
|
||||
SGGeod pos = fp->pointAlongRoute(2, -10.0);
|
||||
pos = SGGeodesy::direct(pos, 180, 2.0 * SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, pos);
|
||||
FGTestApi::setPositionAndStabilise(pos);
|
||||
|
||||
auto pilot = SGSharedPtr<FGTestApi::TestPilot>(new FGTestApi::TestPilot);
|
||||
pilot->resetAtPosition(pos);
|
||||
|
@ -1079,7 +1068,7 @@ void GPSTests::testOffsetFlight()
|
|||
fp->setCurrentIndex(3);
|
||||
pos = fp->pointAlongRoute(3, -18.0);
|
||||
pos = SGGeodesy::direct(pos, 180, 2.0 * SG_NM_TO_METER);
|
||||
setPositionAndStabilise(gps, pos);
|
||||
FGTestApi::setPositionAndStabilise(pos);
|
||||
pilot->resetAtPosition(pos);
|
||||
// start facing the right way
|
||||
pilot->setCourseTrue(gpsNode->getDoubleValue("wp/leg-true-course-deg"));
|
||||
|
@ -1132,7 +1121,7 @@ void GPSTests::testLegIntercept()
|
|||
SGGeod pos = fp->pointAlongRoute(1, 5.0);
|
||||
pos = SGGeodesy::direct(pos, 0, 12.0 * SG_NM_TO_METER);
|
||||
|
||||
setPositionAndStabilise(gps, pos);
|
||||
FGTestApi::setPositionAndStabilise(pos);
|
||||
auto pilot = SGSharedPtr<FGTestApi::TestPilot>(new FGTestApi::TestPilot);
|
||||
pilot->resetAtPosition(pos);
|
||||
pilot->setCourseTrue(180.0); // start facing an annoying direction
|
||||
|
@ -1151,7 +1140,7 @@ void GPSTests::testLegIntercept()
|
|||
pos = SGGeodesy::direct(pos, 240, 10.0 * SG_NM_TO_METER);
|
||||
|
||||
// cycle the GPS mode to re-do the intercept logic
|
||||
setPositionAndStabilise(gps, pos);
|
||||
FGTestApi::setPositionAndStabilise(pos);
|
||||
gpsNode->setStringValue("command", "obs");
|
||||
gpsNode->setStringValue("command", "leg");
|
||||
|
||||
|
@ -1170,7 +1159,7 @@ void GPSTests::testLegIntercept()
|
|||
pos = SGGeodesy::direct(pos, 180, 5.0 * SG_NM_TO_METER);
|
||||
|
||||
// cycle the GPS mode to re-do the intercept logic
|
||||
setPositionAndStabilise(gps, pos);
|
||||
FGTestApi::setPositionAndStabilise(pos);
|
||||
gpsNode->setStringValue("command", "obs");
|
||||
gpsNode->setStringValue("command", "leg");
|
||||
|
||||
|
@ -1189,7 +1178,7 @@ void GPSTests::testLegIntercept()
|
|||
pos = SGGeodesy::direct(pos, 160, 18.0 * SG_NM_TO_METER);
|
||||
|
||||
// cycle the GPS mode to re-do the intercept logic
|
||||
setPositionAndStabilise(gps, pos);
|
||||
FGTestApi::setPositionAndStabilise(pos);
|
||||
gpsNode->setStringValue("command", "obs");
|
||||
gpsNode->setStringValue("command", "leg");
|
||||
|
||||
|
|
|
@ -124,14 +124,14 @@ void HoldControllerTests::setupRouteManager()
|
|||
|
||||
void HoldControllerTests::testHoldEntryDirect()
|
||||
{
|
||||
FGTestApi::setUp::logPositionToKML("hold_direct_entry");
|
||||
// FGTestApi::setUp::logPositionToKML("hold_direct_entry");
|
||||
|
||||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||
auto fp = new FlightPlan;
|
||||
rm->setFlightPlan(fp);
|
||||
FGTestApi::setUp::populateFPWithoutNasal(fp, "EBBR", "07L", "EGGD", "27",
|
||||
"NIK COA DVR TAWNY WOD");
|
||||
FGTestApi::writeFlightPlanToKML(fp);
|
||||
// FGTestApi::writeFlightPlanToKML(fp);
|
||||
|
||||
auto testDelegate = new TestFPDelegate;
|
||||
testDelegate->thePlan = fp;
|
||||
|
@ -238,14 +238,14 @@ void HoldControllerTests::testHoldEntryDirect()
|
|||
|
||||
void HoldControllerTests::testHoldEntryTeardrop()
|
||||
{
|
||||
FGTestApi::setUp::logPositionToKML("hold_teardrop_entry");
|
||||
// FGTestApi::setUp::logPositionToKML("hold_teardrop_entry");
|
||||
|
||||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||
auto fp = new FlightPlan;
|
||||
rm->setFlightPlan(fp);
|
||||
FGTestApi::setUp::populateFPWithoutNasal(fp, "EBBR", "07L", "EGGD", "27",
|
||||
"NIK COA DVR TAWNY WOD");
|
||||
FGTestApi::writeFlightPlanToKML(fp);
|
||||
// FGTestApi::writeFlightPlanToKML(fp);
|
||||
|
||||
auto testDelegate = new TestFPDelegate;
|
||||
testDelegate->thePlan = fp;
|
||||
|
@ -352,14 +352,14 @@ void HoldControllerTests::testHoldEntryTeardrop()
|
|||
|
||||
void HoldControllerTests::testHoldEntryParallel()
|
||||
{
|
||||
FGTestApi::setUp::logPositionToKML("hold_parallel_entry");
|
||||
//FGTestApi::setUp::logPositionToKML("hold_parallel_entry");
|
||||
|
||||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||
auto fp = new FlightPlan;
|
||||
rm->setFlightPlan(fp);
|
||||
FGTestApi::setUp::populateFPWithoutNasal(fp, "EBBR", "07L", "EGGD", "27",
|
||||
"NIK COA DVR TAWNY WOD");
|
||||
FGTestApi::writeFlightPlanToKML(fp);
|
||||
// FGTestApi::writeFlightPlanToKML(fp);
|
||||
|
||||
auto testDelegate = new TestFPDelegate;
|
||||
testDelegate->thePlan = fp;
|
||||
|
@ -456,14 +456,14 @@ void HoldControllerTests::testHoldEntryParallel()
|
|||
|
||||
void HoldControllerTests::testLeftHoldEntryDirect()
|
||||
{
|
||||
FGTestApi::setUp::logPositionToKML("hold_left_direct_entry");
|
||||
// FGTestApi::setUp::logPositionToKML("hold_left_direct_entry");
|
||||
|
||||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||
auto fp = new FlightPlan;
|
||||
rm->setFlightPlan(fp);
|
||||
FGTestApi::setUp::populateFPWithoutNasal(fp, "EBBR", "07L", "EGGD", "27",
|
||||
"NIK COA DVR TAWNY WOD");
|
||||
FGTestApi::writeFlightPlanToKML(fp);
|
||||
// FGTestApi::writeFlightPlanToKML(fp);
|
||||
|
||||
auto testDelegate = new TestFPDelegate;
|
||||
testDelegate->thePlan = fp;
|
||||
|
@ -571,14 +571,14 @@ void HoldControllerTests::testLeftHoldEntryDirect()
|
|||
|
||||
void HoldControllerTests::testLeftHoldEntryTeardrop()
|
||||
{
|
||||
FGTestApi::setUp::logPositionToKML("hold_left_teardrop_entry");
|
||||
//FGTestApi::setUp::logPositionToKML("hold_left_teardrop_entry");
|
||||
|
||||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||
auto fp = new FlightPlan;
|
||||
rm->setFlightPlan(fp);
|
||||
FGTestApi::setUp::populateFPWithoutNasal(fp, "EBBR", "07L", "EGGD", "27",
|
||||
"NIK COA DVR TAWNY WOD");
|
||||
FGTestApi::writeFlightPlanToKML(fp);
|
||||
// FGTestApi::writeFlightPlanToKML(fp);
|
||||
|
||||
auto testDelegate = new TestFPDelegate;
|
||||
testDelegate->thePlan = fp;
|
||||
|
@ -683,14 +683,14 @@ void HoldControllerTests::testLeftHoldEntryTeardrop()
|
|||
|
||||
void HoldControllerTests::testLeftHoldEntryParallel()
|
||||
{
|
||||
FGTestApi::setUp::logPositionToKML("hold_left_parallel_entry");
|
||||
// FGTestApi::setUp::logPositionToKML("hold_left_parallel_entry");
|
||||
|
||||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||
auto fp = new FlightPlan;
|
||||
rm->setFlightPlan(fp);
|
||||
FGTestApi::setUp::populateFPWithoutNasal(fp, "EBBR", "07L", "EGGD", "27",
|
||||
"NIK COA DVR TAWNY WOD");
|
||||
FGTestApi::writeFlightPlanToKML(fp);
|
||||
// FGTestApi::writeFlightPlanToKML(fp);
|
||||
|
||||
auto testDelegate = new TestFPDelegate;
|
||||
testDelegate->thePlan = fp;
|
||||
|
@ -789,14 +789,14 @@ void HoldControllerTests::testLeftHoldEntryParallel()
|
|||
|
||||
void HoldControllerTests::testHoldNotEntered()
|
||||
{
|
||||
FGTestApi::setUp::logPositionToKML("hold_no_entry");
|
||||
// FGTestApi::setUp::logPositionToKML("hold_no_entry");
|
||||
|
||||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||
auto fp = new FlightPlan;
|
||||
rm->setFlightPlan(fp);
|
||||
FGTestApi::setUp::populateFPWithoutNasal(fp, "EBBR", "07L", "EGGD", "27",
|
||||
"NIK COA DVR TAWNY WOD");
|
||||
FGTestApi::writeFlightPlanToKML(fp);
|
||||
// FGTestApi::writeFlightPlanToKML(fp);
|
||||
|
||||
auto testDelegate = new TestFPDelegate;
|
||||
testDelegate->thePlan = fp;
|
||||
|
@ -877,14 +877,14 @@ void HoldControllerTests::testHoldNotEntered()
|
|||
|
||||
void HoldControllerTests::testHoldEntryOffCourse()
|
||||
{
|
||||
FGTestApi::setUp::logPositionToKML("hold_entry_off-course");
|
||||
// FGTestApi::setUp::logPositionToKML("hold_entry_off-course");
|
||||
|
||||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||
auto fp = new FlightPlan;
|
||||
rm->setFlightPlan(fp);
|
||||
FGTestApi::setUp::populateFPWithoutNasal(fp, "EBBR", "07L", "EGGD", "27",
|
||||
"NIK COA DVR TAWNY WOD");
|
||||
FGTestApi::writeFlightPlanToKML(fp);
|
||||
// FGTestApi::writeFlightPlanToKML(fp);
|
||||
|
||||
auto testDelegate = new TestFPDelegate;
|
||||
testDelegate->thePlan = fp;
|
||||
|
|
|
@ -198,7 +198,6 @@ void RouteManagerTests::testDefaultSID()
|
|||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||
rm->setFlightPlan(fp1);
|
||||
|
||||
auto gpsNode = globals->get_props()->getNode("instrumentation/gps", true);
|
||||
auto rmNode = globals->get_props()->getNode("autopilot/route-manager", true);
|
||||
rmNode->setStringValue("departure/sid", "DEFAULT");
|
||||
|
||||
|
@ -285,3 +284,130 @@ void RouteManagerTests::testDefaultApproach()
|
|||
|
||||
}
|
||||
|
||||
void RouteManagerTests::testHoldFromNasal()
|
||||
{
|
||||
// FGTestApi::setUp::logPositionToKML("rm_hold_from_nasal");
|
||||
|
||||
// test that Nasal can set a hold-count (implicitly converting a leg
|
||||
// to a Hold waypt), configure the hold radial, and exit the hold
|
||||
|
||||
FlightPlanRef fp1 = makeTestFP("NZCH", "02", "NZAA", "05L",
|
||||
"ALADA NS WB WN MAMOD KAPTI OH");
|
||||
fp1->setIdent("testplan");
|
||||
fp1->setCruiseFlightLevel(360);
|
||||
|
||||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||
rm->setFlightPlan(fp1);
|
||||
// FGTestApi::writeFlightPlanToKML(fp1);
|
||||
|
||||
auto gpsNode = globals->get_props()->getNode("instrumentation/gps", true);
|
||||
CPPUNIT_ASSERT(!strcmp("obs", gpsNode->getStringValue("mode")));
|
||||
|
||||
rm->activate();
|
||||
|
||||
CPPUNIT_ASSERT(fp1->isActive());
|
||||
CPPUNIT_ASSERT(!strcmp("leg", gpsNode->getStringValue("mode")));
|
||||
|
||||
SGGeod posEnrouteToWB = fp1->pointAlongRoute(3, -10.0);
|
||||
FGTestApi::setPositionAndStabilise(posEnrouteToWB);
|
||||
|
||||
// sequence everything to the correct wp
|
||||
fp1->setCurrentIndex(3);
|
||||
|
||||
// setup some hold data from Nasal. To make it more challenging,
|
||||
// do it once the wp is already active
|
||||
bool ok = FGTestApi::executeNasal(R"(
|
||||
var fp = flightplan(); # retrieve the global flightplan
|
||||
var leg = fp.getWP(3);
|
||||
leg.hold_count = 4;
|
||||
leg.hold_heading_radial_deg = 310;
|
||||
)");
|
||||
CPPUNIT_ASSERT(ok);
|
||||
|
||||
// check the value updated in the leg
|
||||
CPPUNIT_ASSERT_EQUAL(4, fp1->legAtIndex(3)->holdCount());
|
||||
|
||||
// check we converted to a hold
|
||||
auto wp = fp1->legAtIndex(3)->waypoint();
|
||||
auto holdWpt = static_cast<flightgear::Hold*>(wp);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(wp->type(), std::string{"hold"});
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(310.0, holdWpt->headingRadialDeg(), 0.5);
|
||||
|
||||
// establish the test pilot at this position too
|
||||
auto pilot = SGSharedPtr<FGTestApi::TestPilot>(new FGTestApi::TestPilot);
|
||||
pilot->resetAtPosition(posEnrouteToWB);
|
||||
pilot->setSpeedKts(250);
|
||||
pilot->flyGPSCourse(m_gps);
|
||||
pilot->setCourseTrue(gpsNode->getDoubleValue("wp/leg-true-course-deg"));
|
||||
|
||||
// run for a bit to stabilize everything
|
||||
FGTestApi::runForTime(5.0);
|
||||
|
||||
// check we upgraded to a hold controller internally, and are flying to it :)
|
||||
auto statusNode = gpsNode->getNode("rnav-controller-status");
|
||||
CPPUNIT_ASSERT_EQUAL(std::string{"leg-to-hold"}, std::string{statusNode->getStringValue()});
|
||||
|
||||
// check we're on the leg
|
||||
|
||||
auto wbPos = fp1->legAtIndex(3)->waypoint()->position();
|
||||
auto nsPos = fp1->legAtIndex(2)->waypoint()->position();
|
||||
const double crsToWB = SGGeodesy::courseDeg(globals->get_aircraft_position(), wbPos);
|
||||
const double crsNSWB = SGGeodesy::courseDeg(nsPos,wbPos);
|
||||
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(crsToWB, gpsNode->getDoubleValue("wp/wp[1]/bearing-true-deg"), 0.5);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(crsNSWB, gpsNode->getDoubleValue("wp/leg-true-course-deg"), 0.5);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.05);
|
||||
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, gpsNode->getDoubleValue("wp/wp[1]/course-deviation-deg"), 0.5);
|
||||
|
||||
// fly into the hold, should be teardrop entry
|
||||
ok = FGTestApi::runForTimeWithCheck(600.0, [statusNode] () {
|
||||
std::string s = statusNode->getStringValue();
|
||||
if (s == "entry-teardrop") return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
CPPUNIT_ASSERT(ok);
|
||||
|
||||
ok = FGTestApi::runForTimeWithCheck(600.0, [statusNode] () {
|
||||
std::string s = statusNode->getStringValue();
|
||||
if (s == "hold-inbound") return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
ok = FGTestApi::runForTimeWithCheck(600.0, [statusNode] () {
|
||||
std::string s = statusNode->getStringValue();
|
||||
if (s == "hold-outbound") return true;
|
||||
return false;
|
||||
});
|
||||
CPPUNIT_ASSERT(ok);
|
||||
|
||||
// half way through the outbound turn
|
||||
FGTestApi::runForTime(30.0);
|
||||
|
||||
ok = FGTestApi::executeNasal(R"(
|
||||
setprop("/instrumentation/gps/command", "exit-hold");
|
||||
)");
|
||||
CPPUNIT_ASSERT(ok);
|
||||
|
||||
// no change yet
|
||||
CPPUNIT_ASSERT_EQUAL(std::string{"hold-outbound"}, std::string{statusNode->getStringValue()});
|
||||
|
||||
// then we fly inbound
|
||||
ok = FGTestApi::runForTimeWithCheck(600.0, [statusNode] () {
|
||||
std::string s = statusNode->getStringValue();
|
||||
if (s == "hold-inbound") return true;
|
||||
return false;
|
||||
});
|
||||
CPPUNIT_ASSERT(ok);
|
||||
|
||||
// and then we exit
|
||||
ok = FGTestApi::runForTimeWithCheck(600.0, [fp1] () {
|
||||
if (fp1->currentIndex() == 4) return true;
|
||||
return false;
|
||||
});
|
||||
CPPUNIT_ASSERT(ok);
|
||||
|
||||
// get back on course
|
||||
FGTestApi::runForTime(60.0);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class RouteManagerTests : public CppUnit::TestFixture
|
|||
CPPUNIT_TEST(testDefaultSID);
|
||||
CPPUNIT_TEST(testDefaultApproach);
|
||||
CPPUNIT_TEST(testDirectToLegOnFlightplanAndResume);
|
||||
|
||||
CPPUNIT_TEST(testHoldFromNasal);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
// void setPositionAndStabilise(FGNavRadio* r, const SGGeod& g);
|
||||
|
@ -56,7 +56,7 @@ public:
|
|||
void testDefaultSID();
|
||||
void testDefaultApproach();
|
||||
void testDirectToLegOnFlightplanAndResume();
|
||||
|
||||
void testHoldFromNasal();
|
||||
private:
|
||||
GPS* m_gps = nullptr;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue