X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FScripting%2FNasalSys.cxx;h=936c515378a8683961f101ce8e09ad2144fc66c0;hb=3eff9a14c992a3ae29ce021040bf6a5e560a3ff1;hp=a210d03569c50bbafbc35ba4bda2f4720e1f9f03;hpb=7cde2e800bccd4883f03eceb5283add24755b377;p=flightgear.git diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index a210d0356..936c51537 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -14,12 +14,11 @@ #include #include -#include - #include #include #include #include +#include #include #include #include @@ -32,12 +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 @@ -186,8 +213,16 @@ static naRef f_getprop(naContext c, naRef me, int argc, naRef* args) case props::BOOL: case props::INT: case props::LONG: case props::FLOAT: case props::DOUBLE: - return naNum(p->getDoubleValue()); - + { + double dv = p->getDoubleValue(); + if (osg::isNaN(dv)) { + SG_LOG(SG_GENERAL, SG_ALERT, "Nasal getprop: property " << p->getPath() << " is NaN"); + return naNil(); + } + + return naNum(dv); + } + case props::STRING: case props::UNSPECIFIED: { @@ -212,6 +247,7 @@ static naRef f_setprop(naContext c, naRef me, int argc, naRef* args) buf[BUFLEN] = 0; char* p = buf; int buflen = BUFLEN; + if(argc < 2) naRuntimeError(c, "setprop() expects at least 2 arguments"); for(int i=0; isetDoubleValue(buf, n.num); } } catch (const string& err) { @@ -362,18 +403,33 @@ static naRef f_directory(naContext c, naRef me, int argc, naRef* args) { if(argc != 1 || !naIsString(args[0])) naRuntimeError(c, "bad arguments to directory()"); - naRef ldir = args[0]; - ulDir* dir = ulOpenDir(naStr_data(args[0])); - if(!dir) return naNil(); + + simgear::Dir d(SGPath(naStr_data(args[0]))); + if(!d.exists()) return naNil(); naRef result = naNewVector(c); - ulDirEnt* dent; - while((dent = ulReadDir(dir))) - naVec_append(result, naStr_fromdata(naNewString(c), dent->d_name, - strlen(dent->d_name))); - ulCloseDir(dir); + + simgear::PathList paths = d.children(simgear::Dir::TYPE_FILE | simgear::Dir::TYPE_DIR); + for (unsigned int i=0; iresolve_maybe_aircraft_path(naStr_data(args[0])); + const char* pdata = p.c_str(); + return naStr_fromdata(naNewString(c), const_cast(pdata), strlen(pdata)); +} + // Parse XML file. // parsexml( [, [, [, [, ]]]]); // @@ -422,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 } @@ -501,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 { @@ -599,6 +675,28 @@ static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args) HASHSET("ils_frequency_mhz", 17, naNum(rwy->ILS()->get_freq() / 100.0)); } + std::vector sids(rwy->getSIDs()); + naRef sidVec = naNewVector(c); + + for (unsigned int s=0; s < sids.size(); ++s) { + naRef procId = naStr_fromdata(naNewString(c), + const_cast(sids[s]->ident().c_str()), + sids[s]->ident().length()); + naVec_append(sidVec, procId); + } + HASHSET("sids", 4, sidVec); + + std::vector stars(rwy->getSTARs()); + naRef starVec = naNewVector(c); + + for (unsigned int s=0; s < stars.size(); ++s) { + naRef procId = naStr_fromdata(naNewString(c), + const_cast(stars[s]->ident().c_str()), + stars[s]->ident().length()); + naVec_append(starVec, procId); + } + HASHSET("stars", 5, starVec); + #undef HASHSET naHash_set(rwys, rwyid, rwydata); } @@ -620,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 }, @@ -635,12 +819,15 @@ static struct { const char* name; naCFunction func; } funcs[] = { { "srand", f_srand }, { "abort", f_abort }, { "directory", f_directory }, + { "resolvepath", f_resolveDataPath }, { "parsexml", f_parsexml }, { "systime", f_systime }, { "carttogeod", f_carttogeod }, { "geodtocart", f_geodtocart }, { "geodinfo", f_geodinfo }, { "airportinfo", f_airportinfo }, + { "navinfo", f_navinfo }, + { "radioTransmission", f_radioTransmission }, { 0, 0 } }; @@ -684,18 +871,17 @@ void FGNasalSys::init() hashset(_globals, "__gcsave", _gcHash); // Now load the various source files in the Nasal directory - SGPath p(globals->get_fg_root()); - p.append("Nasal"); - ulDirEnt* dent; - ulDir* dir = ulOpenDir(p.c_str()); - while(dir && (dent = ulReadDir(dir)) != 0) { - SGPath fullpath(p); - fullpath.append(dent->d_name); - SGPath file(dent->d_name); - if(file.extension() != "nas") continue; - loadModule(fullpath, file.base().c_str()); + simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal")); + loadScriptDirectory(nasalDir); + + // Add modules in Nasal subdirectories to property tree + simgear::PathList directories = nasalDir.children(simgear::Dir::TYPE_DIR+ + simgear::Dir::NO_DOT_OR_DOTDOT, ""); + 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->get_fg_root()); - p.append(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++; } @@ -762,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