X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FScripting%2FNasalSys.cxx;h=936c515378a8683961f101ce8e09ad2144fc66c0;hb=3eff9a14c992a3ae29ce021040bf6a5e560a3ff1;hp=158d852e5bc7ef2d824189fd99ddf6df54489e40;hpb=ce2a1126397ad96b94ebf020195115cf59690756;p=flightgear.git diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index 158d852e5..936c51537 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -31,13 +31,40 @@ #include
#include
#include -#include +#include #include +#include + #include "NasalSys.hxx" static FGNasalSys* nasalSys = 0; +// Listener class for loading Nasal modules on demand +class FGNasalModuleListener : public SGPropertyChangeListener +{ +public: + FGNasalModuleListener(SGPropertyNode* node); + + virtual void valueChanged(SGPropertyNode* node); + +private: + SGPropertyNode_ptr _node; +}; + +FGNasalModuleListener::FGNasalModuleListener(SGPropertyNode* node) : _node(node) +{ +} + +void FGNasalModuleListener::valueChanged(SGPropertyNode*) +{ + if (_node->getBoolValue("enabled",false)&& + !_node->getBoolValue("loaded",true)) + { + nasalSys->loadPropertyScripts(_node); + } +} + // Read and return file contents in a single buffer. Note use of // stat() to get the file size. This is a win32 function, believe it @@ -190,7 +217,7 @@ static naRef f_getprop(naContext c, naRef me, int argc, naRef* args) double dv = p->getDoubleValue(); if (osg::isNaN(dv)) { SG_LOG(SG_GENERAL, SG_ALERT, "Nasal getprop: property " << p->getPath() << " is NaN"); - naRuntimeError(c, "getprop() would have read NaN"); + return naNil(); } return naNum(dv); @@ -451,10 +478,9 @@ static naRef f_systime(naContext c, naRef me, int argc, naRef* args) // Converts from 100ns units in 1601 epoch to unix epoch in sec return naNum((t * 1e-7) - 11644473600.0); #else - time_t t; struct timeval td; - do { t = time(0); gettimeofday(&td, 0); } while(t != time(0)); - return naNum(t + 1e-6 * td.tv_usec); + gettimeofday(&td, 0); + return naNum(td.tv_sec + 1e-6 * td.tv_usec); #endif } @@ -530,6 +556,27 @@ static naRef f_geodinfo(naContext c, naRef me, int argc, naRef* args) #undef HASHSET } +// Expose a radio transmission interface to Nasal. +static naRef f_radioTransmission(naContext c, naRef me, int argc, naRef* args) +{ + double lat, lon, elev, heading, pitch; + if(argc != 5) naRuntimeError(c, "radioTransmission() expects 5 arguments"); + for(int i=0; ireceiveBeacon(geod, heading, pitch); + delete radio; + return naNum(signal); +} + class AirportInfoFilter : public FGAirport::AirportFilter { @@ -671,6 +718,92 @@ static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args) } +// Returns vector of data hash for navaid of a , nil on error +// navaids sorted by ascending distance +// navinfo([,],[],[]) +// lat/lon (numeric): use latitude/longitude instead of ac position +// type: ("fix"|"vor"|"ndb"|"ils"|"dme"|"tacan"|"any") +// id: (partial) id of the fix +// examples: +// navinfo("vor") returns all vors +// navinfo("HAM") return all navaids who's name start with "HAM" +// navinfo("vor", "HAM") return all vor who's name start with "HAM" +//navinfo(34,48,"vor","HAM") return all vor who's name start with "HAM" +// sorted by distance relative to lat=34, lon=48 +static naRef f_navinfo(naContext c, naRef me, int argc, naRef* args) +{ + static SGConstPropertyNode_ptr latn = fgGetNode("/position/latitude-deg", true); + static SGConstPropertyNode_ptr lonn = fgGetNode("/position/longitude-deg", true); + SGGeod pos; + + if(argc >= 2 && naIsNum(args[0]) && naIsNum(args[1])) { + pos = SGGeod::fromDeg(args[1].num, args[0].num); + args += 2; + argc -= 2; + } else { + pos = SGGeod::fromDeg(lonn->getDoubleValue(), latn->getDoubleValue()); + } + + FGPositioned::Type type = FGPositioned::INVALID; + nav_list_type navlist; + const char * id = ""; + + if(argc > 0 && naIsString(args[0])) { + const char *s = naStr_data(args[0]); + if(!strcmp(s, "any")) type = FGPositioned::INVALID; + else if(!strcmp(s, "fix")) type = FGPositioned::FIX; + else if(!strcmp(s, "vor")) type = FGPositioned::VOR; + else if(!strcmp(s, "ndb")) type = FGPositioned::NDB; + else if(!strcmp(s, "ils")) type = FGPositioned::ILS; + else if(!strcmp(s, "dme")) type = FGPositioned::DME; + else if(!strcmp(s, "tacan")) type = FGPositioned::TACAN; + else id = s; // this is an id + ++args; + --argc; + } + + if(argc > 0 && naIsString(args[0])) { + if( *id != 0 ) { + naRuntimeError(c, "navinfo() called with navaid id"); + return naNil(); + } + id = naStr_data(args[0]); + ++args; + --argc; + } + + if( argc > 0 ) { + naRuntimeError(c, "navinfo() called with too many arguments"); + return naNil(); + } + + navlist = globals->get_navlist()->findByIdentAndFreq( pos, id, 0.0, type ); + + naRef reply = naNewVector(c); + for( nav_list_type::const_iterator it = navlist.begin(); it != navlist.end(); ++it ) { + const FGNavRecord * nav = *it; + + // set navdata hash + naRef navdata = naNewHash(c); +#define HASHSET(s,l,n) naHash_set(navdata, naStr_fromdata(naNewString(c),s,l),n) + HASHSET("id", 2, naStr_fromdata(naNewString(c), + const_cast(nav->ident().c_str()), nav->ident().length())); + HASHSET("name", 4, naStr_fromdata(naNewString(c), + const_cast(nav->name().c_str()), nav->name().length())); + HASHSET("frequency", 9, naNum(nav->get_freq())); + HASHSET("lat", 3, naNum(nav->get_lat())); + HASHSET("lon", 3, naNum(nav->get_lon())); + HASHSET("elevation", 9, naNum(nav->get_elev_ft() * SG_FEET_TO_METER)); + HASHSET("type", 4, naStr_fromdata(naNewString(c), + const_cast(nav->nameForType(nav->type())), strlen(nav->nameForType(nav->type())))); + HASHSET("distance", 8, naNum(SGGeodesy::distanceNm( pos, nav->geod() ) * SG_NM_TO_METER ) ); + HASHSET("bearing", 7, naNum(SGGeodesy::courseDeg( pos, nav->geod() ) ) ); +#undef HASHSET + naVec_append( reply, navdata ); + } + return reply; +} + // Table of extension functions. Terminate with zeros. static struct { const char* name; naCFunction func; } funcs[] = { { "getprop", f_getprop }, @@ -693,6 +826,8 @@ static struct { const char* name; naCFunction func; } funcs[] = { { "geodtocart", f_geodtocart }, { "geodinfo", f_geodinfo }, { "airportinfo", f_airportinfo }, + { "navinfo", f_navinfo }, + { "radioTransmission", f_radioTransmission }, { 0, 0 } }; @@ -737,12 +872,15 @@ void FGNasalSys::init() // Now load the various source files in the Nasal directory simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal")); - simgear::PathList scripts = nasalDir.children(simgear::Dir::TYPE_FILE, ".nas"); - - for (unsigned int i=0; i0) + { + SGPropertyNode* nasal = globals->get_props()->getNode("nasal"); + SGPropertyNode* module_node = nasal->getChild(moduleName,0,true); + for (unsigned int i=0; igetChild("file",i,true); + pFileNode->setStringValue(scripts[i].c_str()); + } + if (!module_node->hasChild("enabled",0)) + { + SGPropertyNode* node = module_node->getChild("enabled",0,true); + node->setBoolValue(true); + node->setAttribute(SGPropertyNode::USERARCHIVE,true); + } + } +} + // Loads the scripts found under /nasal in the global tree void FGNasalSys::loadPropertyScripts() { SGPropertyNode* nasal = globals->get_props()->getNode("nasal"); if(!nasal) return; - for(int i=0; inChildren(); i++) { + for(int i=0; inChildren(); i++) + { SGPropertyNode* n = nasal->getChild(i); + loadPropertyScripts(n); + } +} - const char* module = n->getName(); - if(n->hasChild("module")) - module = n->getStringValue("module"); +// Loads the scripts found under /nasal in the global tree +void FGNasalSys::loadPropertyScripts(SGPropertyNode* n) +{ + bool is_loaded = false; + const char* module = n->getName(); + if(n->hasChild("module")) + module = n->getStringValue("module"); + if (n->getBoolValue("enabled",true)) + { // allow multiple files to be specified within a single // Nasal module tag int j = 0; SGPropertyNode *fn; bool file_specified = false; + bool ok=true; while((fn = n->getChild("file", j)) != NULL) { file_specified = true; const char* file = fn->getStringValue(); - SGPath p = globals->resolve_maybe_aircraft_path(file); - loadModule(p, module); + SGPath p(file); + if (!p.isAbsolute() || !p.exists()) + { + p = globals->resolve_maybe_aircraft_path(file); + if (p.isNull()) + { + SG_LOG(SG_NASAL, SG_ALERT, "Cannot find Nasal script '" << + file << "' for module '" << module << "'."); + } + } + ok &= p.isNull() ? false : loadModule(p, module); j++; } @@ -809,10 +1007,32 @@ void FGNasalSys::loadPropertyScripts() createModule(module, n->getPath().c_str(), src, strlen(src)); if(!file_specified && !src) + { + // module no longer exists - clear the archived "enable" flag + n->setAttribute(SGPropertyNode::USERARCHIVE,false); + SGPropertyNode* node = n->getChild("enabled",0,false); + if (node) + node->setAttribute(SGPropertyNode::USERARCHIVE,false); + SG_LOG(SG_NASAL, SG_ALERT, "Nasal error: " << - "no or