FlightGear next
fg_props.cxx
Go to the documentation of this file.
1// fg_props.cxx -- support for FlightGear properties.
2//
3// Written by David Megginson, started 2000.
4//
5// Copyright (C) 2000, 2001 David Megginson - david@megginson.com
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License as
9// published by the Free Software Foundation; either version 2 of the
10// License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful, but
13// WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15// General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20//
21// $Id$
22
23#include "config.h"
24
25#include <simgear/compiler.h>
26#include <simgear/structure/exception.hxx>
27#include <simgear/props/props_io.hxx>
28#include <simgear/misc/strutils.hxx>
29#include <simgear/timing/sg_time.hxx>
30#include <simgear/misc/sg_path.hxx>
31#include <simgear/scene/model/particles.hxx>
32#include <simgear/sound/soundmgr.hxx>
33
34#include <GUI/gui.h>
35
36#include "globals.hxx"
37#include "fg_props.hxx"
38
39using std::string;
41// Default property bindings (not yet handled by any module).
43
47// XXX Making the result buffer be global is a band-aid that hopefully
48// delays its destruction 'til after its last use.
49namespace
50{
51string loggingResult;
52}
53
54static const char *
56{
57 loggingResult = sglog().getLogClassesAsString();
58 return loggingResult.c_str();
59}
60
64void
65setLoggingClasses (const char * c)
66{
67 sglog().parseLogClasses(c);
68}
69
73static const char *
75{
76 switch (sglog().get_log_priority()) {
77 case SG_BULK:
78 return "bulk";
79 case SG_DEBUG:
80 return "debug";
81 case SG_INFO:
82 return "info";
83 case SG_WARN:
84 return "warn";
85 case SG_ALERT:
86 case SG_POPUP:
87 return "alert";
88 default:
89 SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
90 << sglog().get_log_priority());
91 return "unknown";
92 }
93}
94
95
99void
100setLoggingPriority (const char * p)
101{
102 if (p == 0)
103 return;
104
105 string priority = p;
106 if (priority.empty()) {
107 sglog().set_log_priority(SG_INFO);
108 } else {
109 try {
110 sglog().set_log_priority(logstream::priorityFromString(priority));
111 } catch (std::exception& e) {
112 SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority: " << priority);
113 }
114 }
115
116 SG_LOG(SG_GENERAL, SG_DEBUG, "Logging priority is " << getLoggingPriority());
117}
118
119
123bool FGProperties::getFreeze() const
124{
125 return _simFreeze;
126}
127
128
132void FGProperties::setFreeze(bool f)
133{
134 if (_simFreeze == f)
135 return;
136
137 _simFreeze = f;
138
139 // Pause the particle system
140 auto p = simgear::ParticlesGlobalManager::instance();
141 p->setFrozen(f);
142
143 _simFreezeNode->fireValueChanged();
144}
145
146
150static double
152{
153 return globals->get_sim_time_sec();
154}
155
156
160static const char *
162{
163 static char buf[64]; // FIXME
164
165 SGTime * st = globals->get_time_params();
166 if (!st) {
167 buf[0] = 0;
168 return buf;
169 }
170
171 struct tm * t = st->getGmt();
172 snprintf(buf, 64, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
173 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
174 t->tm_hour, t->tm_min, t->tm_sec);
175 return buf;
176}
177
178
182static void
183setDateString (const char * date_string)
184{
185 SGTime * st = globals->get_time_params();
186 struct tm * current_time = st->getGmt();
187 struct tm new_time;
188
189 // Scan for basic ISO format
190 // YYYY-MM-DDTHH:MM:SS
191 new_time.tm_isdst = 0;
192 int ret = sscanf(date_string, "%d-%d-%dT%d:%d:%d",
193 &(new_time.tm_year), &(new_time.tm_mon),
194 &(new_time.tm_mday), &(new_time.tm_hour),
195 &(new_time.tm_min), &(new_time.tm_sec));
196
197 // Be pretty picky about this, so
198 // that strange things don't happen
199 // if the save file has been edited
200 // by hand.
201 if (ret != 6) {
202 SG_LOG(SG_INPUT, SG_WARN, "Date/time string " << date_string
203 << " not in YYYY-MM-DDTHH:MM:SS format; skipped");
204 return;
205 }
206 // OK, it looks like we got six
207 // values, one way or another.
208 new_time.tm_year -= 1900;
209 new_time.tm_mon -= 1;
210 // Now, tell flight gear to use
211 // the new time. This was far
212 // too difficult, by the way.
213 long int warp =
214 mktime(&new_time) - mktime(current_time) + globals->get_warp();
215
216 fgSetInt("/sim/time/warp", warp);
217}
218
222static const char *
224{
225 static char buf[16];
226 SGTime * st = globals->get_time_params();
227 if (!st) {
228 buf[0] = 0;
229 return buf;
230 }
231
232 struct tm *t = st->getGmt();
233 snprintf(buf, 16, "%.2d:%.2d:%.2d",
234 t->tm_hour, t->tm_min, t->tm_sec);
235 return buf;
236}
237
239// Tie the properties.
241SGConstPropertyNode_ptr FGProperties::_longDeg;
242SGConstPropertyNode_ptr FGProperties::_latDeg;
243SGConstPropertyNode_ptr FGProperties::_lonLatformat;
244
245using namespace simgear;
246
247const char* FGProperties::getLongitudeString ()
248{
249 const double d = _longDeg->getDoubleValue();
250 auto format = static_cast<strutils::LatLonFormat>(_lonLatformat->getIntValue());
251 const char c = d < 0.0 ? 'W' : 'E';
252
253 static char longitudeBuffer[64];
254 const auto s = strutils::formatLatLonValueAsString(d, format, c);
255 memcpy(longitudeBuffer, s.c_str(), s.size() + 1);
256 return longitudeBuffer;
257}
258
259const char* FGProperties::getLatitudeString ()
260{
261 const double d = _latDeg->getDoubleValue();
262 auto format = static_cast<strutils::LatLonFormat>(_lonLatformat->getIntValue());
263 const char c = d < 0.0 ? 'S' : 'N';
264
265 static char latitudeBuffer[64];
266 const auto s = strutils::formatLatLonValueAsString(d, format, c);
267 memcpy(latitudeBuffer, s.c_str(), s.size() + 1);
268 return latitudeBuffer;
269}
270
271
275
279
280void
282{
283 memset(&_lastUtc, 0, sizeof(struct tm));
284 memset(&_lastRealTime, 0, sizeof(struct tm));
285 _simFreeze = false;
286}
287
288static SGPropertyNode_ptr initDoubleNode(const std::string& path, const double v)
289{
290 auto r = fgGetNode(path, true);
291 if (r->getType() == simgear::props::NONE) {
292 r->setDoubleValue(v);
293 }
294 return r;
295}
296
297void
299{
300 _longDeg = fgGetNode("/position/longitude-deg", true);
301 _latDeg = fgGetNode("/position/latitude-deg", true);
302 _lonLatformat = fgGetNode("/sim/lon-lat-format", true);
303
304 _offset = fgGetNode("/sim/time/local-offset", true);
305
306 // utc date/time
307 _uyear = fgGetNode("/sim/time/utc/year", true);
308 _umonth = fgGetNode("/sim/time/utc/month", true);
309 _uday = fgGetNode("/sim/time/utc/day", true);
310 _uhour = fgGetNode("/sim/time/utc/hour", true);
311 _umin = fgGetNode("/sim/time/utc/minute", true);
312 _usec = fgGetNode("/sim/time/utc/second", true);
313 _uwday = fgGetNode("/sim/time/utc/weekday", true);
314 _udsec = fgGetNode("/sim/time/utc/day-seconds", true);
315
316 // real local date/time
317 _ryear = fgGetNode("/sim/time/real/year", true);
318 _rmonth = fgGetNode("/sim/time/real/month", true);
319 _rday = fgGetNode("/sim/time/real/day", true);
320 _rhour = fgGetNode("/sim/time/real/hour", true);
321 _rmin = fgGetNode("/sim/time/real/minute", true);
322 _rsec = fgGetNode("/sim/time/real/second", true);
323 _rwday = fgGetNode("/sim/time/real/weekday", true);
324
325 _tiedProperties.setRoot(globals->get_props());
326
327 // Simulation
328 _tiedProperties.Tie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
329 _tiedProperties.Tie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
330 _simFreezeNode = fgGetNode("/sim/freeze/master", true);
331 _tiedProperties.Tie(_simFreezeNode, this, &FGProperties::getFreeze, &FGProperties::setFreeze);
332 _simFreezeNode->setAttribute(SGPropertyNode::LISTENER_SAFE, true);
333
334 _tiedProperties.Tie<double>("/sim/time/elapsed-sec", getElapsedTime_sec);
335 _timeGmtNode = _tiedProperties.Tie("/sim/time/gmt", getDateString, setDateString);
336 _timeGmtNode->setAttribute(SGPropertyNode::LISTENER_SAFE, true);
337 fgSetArchivable("/sim/time/gmt");
338 _timeGmtStringNode = _tiedProperties.Tie<const char*>("/sim/time/gmt-string", getGMTString);
339 _timeGmtStringNode->setAttribute(SGPropertyNode::LISTENER_SAFE, true);
340 // Position
341 _tiedProperties.Tie<const char*>("/position/latitude-string", getLatitudeString);
342 _tiedProperties.Tie<const char*>("/position/longitude-string", getLongitudeString);
343
344 _headingMagnetic = initDoubleNode("/orientation/heading-magnetic-deg", 0.0);
345 _trackMagnetic = initDoubleNode("/orientation/track-magnetic-deg", 0.0);
346 _magVar = initDoubleNode("/environment/magnetic-variation-deg", 0.0);
347 _trueHeading = initDoubleNode("/orientation/heading-deg", 0.0);
348 _trueTrack = initDoubleNode("/orientation/track-deg", 0.0);
349}
350
351void
353{
354 _tiedProperties.Untie();
355
356 // drop static references to properties
357 _longDeg = 0;
358 _latDeg = 0;
359 _lonLatformat = 0;
360
361 _timeGmtNode.clear();
362 _timeGmtStringNode.clear();
363 _simFreezeNode.clear();
364}
365
366void
368{
369 _offset->setIntValue(globals->get_time_params()->get_local_offset());
370
371 // utc date/time
372 struct tm *u = globals->get_time_params()->getGmt();
373 if (memcmp(u, &_lastUtc, sizeof(struct tm)) != 0) {
374 _lastUtc = *u;
375 _uyear->setIntValue(u->tm_year + 1900);
376 _umonth->setIntValue(u->tm_mon + 1);
377 _uday->setIntValue(u->tm_mday);
378 _uhour->setIntValue(u->tm_hour);
379 _umin->setIntValue(u->tm_min);
380 _usec->setIntValue(u->tm_sec);
381 _uwday->setIntValue(u->tm_wday);
382 _udsec->setIntValue(u->tm_hour * 3600 + u->tm_min * 60 + u->tm_sec);
383
384 _timeGmtNode->fireValueChanged();
385 _timeGmtStringNode->fireValueChanged();
386 }
387
388
389 // real local date/time
390 time_t real = time(0);
391 struct tm *r = localtime(&real);
392 if (memcmp(r, &_lastRealTime, sizeof(struct tm)) != 0) {
393 _lastRealTime = *r;
394 _ryear->setIntValue(r->tm_year + 1900);
395 _rmonth->setIntValue(r->tm_mon + 1);
396 _rday->setIntValue(r->tm_mday);
397 _rhour->setIntValue(r->tm_hour);
398 _rmin->setIntValue(r->tm_min);
399 _rsec->setIntValue(r->tm_sec);
400 _rwday->setIntValue(r->tm_wday);
401 }
402
403 const double magvar = _magVar->getDoubleValue();
404 const auto hdgMag = SGMiscd::normalizePeriodic(0, 360.0, _trueHeading->getDoubleValue() - magvar);
405 _headingMagnetic->setDoubleValue(hdgMag);
406
407 const auto trackMag = SGMiscd::normalizePeriodic(0, 360.0, _trueTrack->getDoubleValue() - magvar);
408 _trackMagnetic->setDoubleValue(trackMag);
409}
410
411
412// Register the subsystem.
413SGSubsystemMgr::Registrant<FGProperties> registrantFGProperties;
414
416// Save and restore.
418
419
423bool
424fgSaveFlight (std::ostream &output, bool write_all)
425{
426
427 fgSetBool("/sim/presets/onground", false);
428 fgSetArchivable("/sim/presets/onground");
429 fgSetBool("/sim/presets/trim", false);
430 fgSetArchivable("/sim/presets/trim");
431 fgSetString("/sim/presets/speed-set", "UVW");
432 fgSetArchivable("/sim/presets/speed-set");
433
434 try {
435 writeProperties(output, globals->get_props(), write_all);
436 } catch (const sg_exception &e) {
437 guiErrorMessage("Error saving flight: ", e);
438 return false;
439 }
440 return true;
441}
442
443
447bool
448fgLoadFlight (std::istream &input)
449{
450 SGPropertyNode props;
451 try {
452 readProperties(input, &props);
453 } catch (const sg_exception &e) {
454 guiErrorMessage("Error reading saved flight: ", e);
455 return false;
456 }
457
458 fgSetBool("/sim/presets/onground", false);
459 fgSetBool("/sim/presets/trim", false);
460 fgSetString("/sim/presets/speed-set", "UVW");
461
462 copyProperties(&props, globals->get_props());
463
464 return true;
465}
466
467
468bool
469fgLoadProps (const std::string& path, SGPropertyNode * props, bool in_fg_root, int default_mode)
470{
471 SGPath fullpath;
472 if (in_fg_root) {
473 SGPath loadpath(globals->get_fg_root());
474 loadpath.append(path);
475 fullpath = loadpath;
476 } else {
477 fullpath = SGPath::fromUtf8(path);
478 }
479
480 try {
481 readProperties(fullpath, props, default_mode);
482 } catch (const sg_exception &e) {
483 guiErrorMessage("Error reading properties: ", e);
484 return false;
485 }
486 return true;
487}
488
489
491// Property convenience functions.
493
494SGPropertyNode *
495fgGetNode (const char * path, bool create)
496{
497 return globals->get_props()->getNode(path, create);
498}
499
500SGPropertyNode *
501fgGetNode (const char * path, int index, bool create)
502{
503 return globals->get_props()->getNode(path, index, create);
504}
505
506bool
507fgHasNode (const char * path)
508{
509 return (fgGetNode(path, false) != 0);
510}
511
512void
513fgAddChangeListener (SGPropertyChangeListener * listener, const char * path)
514{
515 fgGetNode(path, true)->addChangeListener(listener);
516}
517
518void
519fgAddChangeListener (SGPropertyChangeListener * listener,
520 const char * path, int index)
521{
522 fgGetNode(path, index, true)->addChangeListener(listener);
523}
524
525bool
526fgGetBool (const char * name, bool defaultValue)
527{
528 return globals->get_props()->getBoolValue(name, defaultValue);
529}
530
531int
532fgGetInt (const char * name, int defaultValue)
533{
534 return globals->get_props()->getIntValue(name, defaultValue);
535}
536
537long
538fgGetLong (const char * name, long defaultValue)
539{
540 return globals->get_props()->getLongValue(name, defaultValue);
541}
542
543float
544fgGetFloat (const char * name, float defaultValue)
545{
546 return globals->get_props()->getFloatValue(name, defaultValue);
547}
548
549double
550fgGetDouble (const char * name, double defaultValue)
551{
552 return globals->get_props()->getDoubleValue(name, defaultValue);
553}
554
555std::string
556fgGetString (const char * name, const char * defaultValue)
557{
558 return globals->get_props()->getStringValue(name, defaultValue);
559}
560
561bool
562fgSetBool (const char * name, bool val)
563{
564 return globals->get_props()->setBoolValue(name, val);
565}
566
567bool
568fgSetInt (const char * name, int val)
569{
570 return globals->get_props()->setIntValue(name, val);
571}
572
573bool
574fgSetLong (const char * name, long val)
575{
576 return globals->get_props()->setLongValue(name, val);
577}
578
579bool
580fgSetFloat (const char * name, float val)
581{
582 return globals->get_props()->setFloatValue(name, val);
583}
584
585bool
586fgSetDouble (const char * name, double val)
587{
588 return globals->get_props()->setDoubleValue(name, val);
589}
590
591bool
592fgSetString (const char * name, const char * val)
593{
594 return globals->get_props()->setStringValue(name, val);
595}
596
597void
598fgSetArchivable (const char * name, bool state)
599{
600 SGPropertyNode * node = globals->get_props()->getNode(name);
601 if (node == 0)
602 SG_LOG(SG_GENERAL, SG_DEBUG,
603 "Attempt to set archive flag for non-existant property "
604 << name);
605 else
606 node->setAttribute(SGPropertyNode::ARCHIVE, state);
607}
608
609void
610fgSetReadable (const char * name, bool state)
611{
612 SGPropertyNode * node = globals->get_props()->getNode(name);
613 if (node == 0)
614 SG_LOG(SG_GENERAL, SG_DEBUG,
615 "Attempt to set read flag for non-existant property "
616 << name);
617 else
618 node->setAttribute(SGPropertyNode::READ, state);
619}
620
621void
622fgSetWritable (const char * name, bool state)
623{
624 SGPropertyNode * node = globals->get_props()->getNode(name);
625 if (node == 0)
626 SG_LOG(SG_GENERAL, SG_DEBUG,
627 "Attempt to set write flag for non-existant property "
628 << name);
629 else
630 node->setAttribute(SGPropertyNode::WRITE, state);
631}
632
633void
634fgUntie(const char * name)
635{
636 SGPropertyNode* node = globals->get_props()->getNode(name);
637 if (!node) {
638 SG_LOG(SG_GENERAL, SG_WARN, "fgUntie: unknown property " << name);
639 return;
640 }
641
642 if (!node->isTied()) {
643 return;
644 }
645
646 if (!node->untie()) {
647 SG_LOG(SG_GENERAL, SG_WARN, "Failed to untie property " << name);
648 }
649}
650
651void fgUntieIfDefined(const std::string& name)
652{
653 SGPropertyNode* node = globals->get_props()->getNode(name);
654 if (!node) {
655 return;
656 }
657
658 if (!node->isTied()) {
659 return;
660 }
661
662 if (!node->untie()) {
663 SG_LOG(SG_GENERAL, SG_WARN, "Failed to untie property " << name);
664 }
665}
666
667
668// end of fg_props.cxx
#define p(x)
void unbind() override
Definition fg_props.cxx:352
void init() override
Definition fg_props.cxx:281
void update(double dt) override
Definition fg_props.cxx:367
virtual ~FGProperties()
Definition fg_props.cxx:276
void bind() override
Definition fg_props.cxx:298
const char * name
long fgGetLong(const char *name, long defaultValue)
Get a long value for a property.
Definition fg_props.cxx:538
void fgAddChangeListener(SGPropertyChangeListener *listener, const char *path)
Add a listener to a node.
Definition fg_props.cxx:513
static void setDateString(const char *date_string)
Set the current Zulu time.
Definition fg_props.cxx:183
bool fgHasNode(const char *path)
Test whether a given node exists.
Definition fg_props.cxx:507
double fgGetDouble(const char *name, double defaultValue)
Get a double value for a property.
Definition fg_props.cxx:550
void fgSetReadable(const char *name, bool state)
Set the state of the read attribute for a property.
Definition fg_props.cxx:610
void fgUntie(const char *name)
Untie a property from an external data source.
Definition fg_props.cxx:634
bool fgLoadProps(const std::string &path, SGPropertyNode *props, bool in_fg_root, int default_mode)
Load properties from a file.
Definition fg_props.cxx:469
bool fgGetBool(const char *name, bool defaultValue)
Get a bool value for a property.
Definition fg_props.cxx:526
SGSubsystemMgr::Registrant< FGProperties > registrantFGProperties
Definition fg_props.cxx:413
static const char * getDateString()
Return the current Zulu time.
Definition fg_props.cxx:161
static double getElapsedTime_sec()
Return the number of milliseconds elapsed since simulation started.
Definition fg_props.cxx:151
static const char * getLoggingPriority()
Get the logging priority.
Definition fg_props.cxx:74
bool fgSaveFlight(std::ostream &output, bool write_all)
Save the current state of the simulator to a stream.
Definition fg_props.cxx:424
bool fgSetDouble(const char *name, double val)
Set a double value for a property.
Definition fg_props.cxx:586
bool fgSetBool(const char *name, bool val)
Set a bool value for a property.
Definition fg_props.cxx:562
void setLoggingPriority(const char *p)
Set the logging priority.
Definition fg_props.cxx:100
void fgUntieIfDefined(const std::string &name)
@brfief variant of the above which doesn't warn if the property does not exist
Definition fg_props.cxx:651
bool fgLoadFlight(std::istream &input)
Restore the current state of the simulator from a stream.
Definition fg_props.cxx:448
static SGPropertyNode_ptr initDoubleNode(const std::string &path, const double v)
Definition fg_props.cxx:288
int fgGetInt(const char *name, int defaultValue)
Get an int value for a property.
Definition fg_props.cxx:532
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition fg_props.cxx:495
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
Definition fg_props.cxx:556
float fgGetFloat(const char *name, float defaultValue)
Get a float value for a property.
Definition fg_props.cxx:544
bool fgSetLong(const char *name, long val)
Set a long value for a property.
Definition fg_props.cxx:574
bool fgSetInt(const char *name, int val)
Set an int value for a property.
Definition fg_props.cxx:568
bool fgSetString(const char *name, const char *val)
Set a string value for a property.
Definition fg_props.cxx:592
void fgSetWritable(const char *name, bool state)
Set the state of the write attribute for a property.
Definition fg_props.cxx:622
bool fgSetFloat(const char *name, float val)
Set a float value for a property.
Definition fg_props.cxx:580
void setLoggingClasses(const char *c)
Set the logging classes.
Definition fg_props.cxx:65
static const char * getGMTString()
Return the GMT as a string.
Definition fg_props.cxx:223
static const char * getLoggingClasses()
Definition fg_props.cxx:55
void fgSetArchivable(const char *name, bool state)
Set the state of the archive attribute for a property.
Definition fg_props.cxx:598
SGPropertyNode * fgGetNode(const char *path, bool create=false)
Get a property node.
Definition proptest.cpp:27
void setLoggingPriority(const char *p)
Set the logging priority.
Definition fg_props.cxx:100
void setLoggingClasses(const char *c)
Set the logging classes.
Definition fg_props.cxx:65
void fgSetArchivable(const char *name, bool state=true)
Set the state of the archive attribute for a property.
Definition fg_props.cxx:598
FGGlobals * globals
Definition globals.cxx:142
void guiErrorMessage(const char *txt)