+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include <stdio.h>
#include <stdlib.h>
FGFDM::~FGFDM()
{
- int i;
- for(i=0; i<_axes.size(); i++) {
- AxisRec* a = (AxisRec*)_axes.get(i);
- delete[] a->name;
- delete a;
+ for(int i=0; i<_axes.size(); i++) {
+ AxisRec* a = (AxisRec*)_axes.get(i);
+ delete[] a->name;
+ delete a;
}
- for(i=0; i<_thrusters.size(); i++) {
- EngRec* er = (EngRec*)_thrusters.get(i);
- delete[] er->prefix;
- delete er->eng;
- delete er;
+
+ for(int i=0; i<_thrusters.size(); i++) {
+ EngRec* er = (EngRec*)_thrusters.get(i);
+ delete[] er->prefix;
+ delete er->eng;
+ delete er;
}
- for(i=0; i<_weights.size(); i++) {
- WeightRec* wr = (WeightRec*)_weights.get(i);
- delete[] wr->prop;
- delete wr;
+
+ for(int i=0; i<_weights.size(); i++) {
+ WeightRec* wr = (WeightRec*)_weights.get(i);
+ delete[] wr->prop;
+ delete wr;
}
- for(i=0; i<_controlProps.size(); i++)
+
+ for(int i=0; i<_controlProps.size(); i++)
delete (PropOut*)_controlProps.get(i);
+
delete _turb;
}
getExternalInput(dt);
_airplane.iterate(dt);
- // Do fuel stuff (FIXME: should stash SGPropertyNode objects here)
- char buf[256];
+ // Do fuel stuff
for(int i=0; i<_airplane.numThrusters(); i++) {
Thruster* t = _airplane.getThruster(i);
- sprintf(buf, "/engines/engine[%d]/out-of-fuel", i);
- t->setFuelState(!fgGetBool(buf));
+ bool out_of_fuel = _fuel_props[i]._out_of_fuel->getBoolValue();
+ t->setFuelState(!out_of_fuel);
- sprintf(buf, "/engines/engine[%d]/fuel-consumed-lbs", i);
- double consumed = fgGetDouble(buf) + dt * KG2LBS * t->getFuelFlow();
- fgSetDouble(buf, consumed);
+ double consumed = _fuel_props[i]._fuel_consumed_lbs->getDoubleValue();
+ _fuel_props[i]._fuel_consumed_lbs->setDoubleValue(
+ consumed + dt * KG2LBS * t->getFuelFlow());
}
for(int i=0; i<_airplane.numTanks(); i++) {
- sprintf(buf, "/consumables/fuel/tank[%d]/level-lbs", i);
- _airplane.setFuel(i, LBS2KG * fgGetFloat(buf));
- }
+ _airplane.setFuel(i, LBS2KG * _tank_level_lbs[i]->getFloatValue());
+ }
_airplane.calcFuelWeights();
setOutputProperties(dt);
void FGFDM::init()
{
+ _turb_magnitude_norm = fgGetNode("/environment/turbulence/magnitude-norm", true);
+ _turb_rate_hz = fgGetNode("/environment/turbulence/rate-hz", true);
+ _gross_weight_lbs = fgGetNode("/yasim/gross-weight-lbs", true);
+
// Allows the user to start with something other than full fuel
_airplane.setFuelFraction(fgGetFloat("/sim/fuel-fraction", 1));
- // Read out the resulting fuel state
- char buf[256];
+ // Read out the resulting fuel state and stash engine/thruster properties
+ _thrust_props.clear();
+ for (int i=0; i<_thrusters.size(); i++) {
+ SGPropertyNode_ptr node = fgGetNode("engines/engine", i, true);
+ Thruster* t = ((EngRec*)_thrusters.get(i))->eng;
+
+ ThrusterProps tp;
+ tp._running = node->getChild("running", 0, true);
+ tp._cranking = node->getChild("cranking", 0, true);
+ tp._prop_thrust = node->getChild("prop-thrust", 0, true); // Deprecated name
+ tp._thrust_lbs = node->getChild("thrust-lbs", 0, true);
+ tp._fuel_flow_gph = node->getChild("fuel-flow-gph", 0, true);
+
+ if(t->getPropEngine())
+ {
+ tp._rpm = node->getChild("rpm", 0, true);
+ tp._torque_ftlb = node->getChild("torque-ftlb", 0, true);
+
+ PropEngine* p = t->getPropEngine();
+ if(p->getEngine()->isPistonEngine())
+ {
+ tp._mp_osi = node->getChild("mp-osi", 0, true);
+ tp._mp_inhg = node->getChild("mp-inhg", 0, true);
+ tp._egt_degf = node->getChild("egt-degf", 0, true);
+
+ tp._oil_temperature_degf = node->getChild("oil-temperature-degf", 0, true);
+ tp._boost_gauge_inhg = node->getChild("boost-gauge-inhg", 0, true);
+ } else if(p->getEngine()->isTurbineEngine()) {
+ tp._n2 = node->getChild("n2", 0, true);
+ }
+ }
+
+ if(t->getJet())
+ {
+ tp._n1 = node->getChild("n1", 0, true);
+ tp._n2 = node->getChild("n2", 0, true);
+ tp._epr = node->getChild("epr", 0, true);
+ tp._egt_degf = node->getChild("egt-degf", 0, true);
+ }
+ _thrust_props.push_back(tp);
+ }
+
+ // stash properties for engines/fuel state
+ _thrust_props.clear();
+ for(int i=0; i<_airplane.numThrusters(); i++) {
+ SGPropertyNode_ptr e = fgGetNode("engines/engine", i, true);
+ FuelProps f;
+ f._out_of_fuel = e->getChild("out-of-fuel", 0, true);
+ f._fuel_consumed_lbs = e->getChild("fuel-consumed-lbs", 0, true);
+ _fuel_props.push_back(f);
+ }
+
+ // initialize tanks and stash properties for tank level
+ _tank_level_lbs.clear();
for(int i=0; i<_airplane.numTanks(); i++) {
+ char buf[256];
sprintf(buf, "/consumables/fuel/tank[%d]/level-lbs", i);
fgSetDouble(buf, _airplane.getFuel(i) * KG2LBS);
+ _tank_level_lbs.push_back(fgGetNode(buf, true));
double density = _airplane.getFuelDensity(i);
sprintf(buf, "/consumables/fuel/tank[%d]/density-ppg", i);
fgSetDouble(buf, density * (KG2LBS/CM2GALS));
- sprintf(buf, "/consumables/fuel/tank[%d]/level-gal_us", i);
- fgSetDouble(buf, _airplane.getFuel(i) * CM2GALS / density);
+// set in TankProperties class
+// sprintf(buf, "/consumables/fuel/tank[%d]/level-gal_us", i);
+// fgSetDouble(buf, _airplane.getFuel(i) * CM2GALS / density);
sprintf(buf, "/consumables/fuel/tank[%d]/capacity-gal_us", i);
fgSetDouble(buf, CM2GALS * _airplane.getTankCapacity(i)/density);
- }
+ }
// This has a nasty habit of being false at startup. That's not
// good.
{
char buf[256];
- _turb->setMagnitude(fgGetFloat("/environment/turbulence/magnitude-norm"));
- _turb->update(dt, fgGetFloat("/environment/turbulence/rate-hz"));
+ _turb->setMagnitude(_turb_magnitude_norm->getFloatValue());
+ _turb->update(dt, _turb_rate_hz->getFloatValue());
// The control axes
ControlMap* cm = _airplane.getControlMap();
cm->reset();
- int i;
- for(i=0; i<_axes.size(); i++) {
- AxisRec* a = (AxisRec*)_axes.get(i);
- float val = fgGetFloat(a->name, 0);
- cm->setInput(a->handle, val);
+
+ for(int i=0; i<_axes.size(); i++) {
+ AxisRec* a = (AxisRec*)_axes.get(i);
+ float val = fgGetFloat(a->name, 0);
+ cm->setInput(a->handle, val);
}
cm->applyControls(dt);
// Weights
- for(i=0; i<_weights.size(); i++) {
- WeightRec* wr = (WeightRec*)_weights.get(i);
- _airplane.setWeight(wr->handle, LBS2KG * fgGetFloat(wr->prop));
+ for(int i=0; i<_weights.size(); i++) {
+ WeightRec* wr = (WeightRec*)_weights.get(i);
+ _airplane.setWeight(wr->handle, LBS2KG * fgGetFloat(wr->prop));
}
- for(i=0; i<_thrusters.size(); i++) {
- EngRec* er = (EngRec*)_thrusters.get(i);
+ for(int i=0; i<_thrusters.size(); i++) {
+ EngRec* er = (EngRec*)_thrusters.get(i);
Thruster* t = er->eng;
- if(t->getPropEngine()) {
+ if(t->getPropEngine()) {
PropEngine* p = t->getPropEngine();
sprintf(buf, "%s/rpm", er->prefix);
p->setOmega(fgGetFloat(buf, 500) * RPM2RAD);
void FGFDM::setOutputProperties(float dt)
{
- // char buf[256];
- int i;
-
float grossWgt = _airplane.getModel()->getBody()->getTotalMass() * KG2LBS;
- fgSetFloat("/yasim/gross-weight-lbs", grossWgt);
+ _gross_weight_lbs->setFloatValue(grossWgt);
ControlMap* cm = _airplane.getControlMap();
- for(i=0; i<_controlProps.size(); i++) {
+ for(int i=0; i<_controlProps.size(); i++) {
PropOut* p = (PropOut*)_controlProps.get(i);
float val = (p->left
? cm->getOutput(p->handle)
p->prop->setFloatValue(val);
}
- for(i=0; i<_airplane.getRotorgear()->getNumRotors(); i++) {
+ for(int i=0; i<_airplane.getRotorgear()->getNumRotors(); i++) {
Rotor*r=(Rotor*)_airplane.getRotorgear()->getRotor(i);
int j = 0;
float f;
}
}
- float fuelDensity = _airplane.getFuelDensity(0); // HACK
- for(i=0; i<_thrusters.size(); i++) {
- EngRec* er = (EngRec*)_thrusters.get(i);
+ // Use the density of the first tank, or a dummy value if no tanks
+ float fuelDensity = 1.0;
+ if(_airplane.numTanks())
+ fuelDensity = _airplane.getFuelDensity(0);
+ for(int i=0; i<_thrusters.size(); i++) {
+ EngRec* er = (EngRec*)_thrusters.get(i);
Thruster* t = er->eng;
SGPropertyNode * node = fgGetNode("engines/engine", i, true);
+ ThrusterProps& tp = _thrust_props[i];
+
// Set: running, cranking, prop-thrust, max-hp, power-pct
- node->setBoolValue("running", t->isRunning());
- node->setBoolValue("cranking", t->isCranking());
+ tp._running->setBoolValue(t->isRunning());
+ tp._cranking->setBoolValue(t->isCranking());
float tmp[3];
t->getThrust(tmp);
float lbs = Math::mag3(tmp) * (KG2LBS/9.8);
- node->setFloatValue("prop-thrust", lbs); // Deprecated name
- node->setFloatValue("thrust-lbs", lbs);
- node->setFloatValue("fuel-flow-gph",
- (t->getFuelFlow()/fuelDensity) * 3600 * CM2GALS);
+ tp._prop_thrust->setFloatValue(lbs); // Deprecated name
+ tp._thrust_lbs->setFloatValue(lbs);
+ tp._fuel_flow_gph->setFloatValue(
+ (t->getFuelFlow()/fuelDensity) * 3600 * CM2GALS);
- if(t->getPropEngine()) {
+ if(t->getPropEngine()) {
PropEngine* p = t->getPropEngine();
- node->setFloatValue("rpm", p->getOmega() * (1/RPM2RAD));
- node->setFloatValue("torque-ftlb",
- p->getEngine()->getTorque() * NM2FTLB);
-
+ tp._rpm->setFloatValue(p->getOmega() * (1/RPM2RAD));
+ tp._torque_ftlb->setFloatValue(
+ p->getEngine()->getTorque() * NM2FTLB);
+
if(p->getEngine()->isPistonEngine()) {
PistonEngine* pe = p->getEngine()->isPistonEngine();
- node->setFloatValue("mp-osi", pe->getMP() * (1/INHG2PA));
- node->setFloatValue("mp-inhg", pe->getMP() * (1/INHG2PA));
- node->setFloatValue("egt-degf",
- pe->getEGT() * K2DEGF + K2DEGFOFFSET);
- node->setFloatValue("oil-temperature-degf",
- pe->getOilTemp() * K2DEGF + K2DEGFOFFSET);
- node->setFloatValue("boost-gauge-inhg",
- pe->getBoost() * (1/INHG2PA));
+ tp._mp_osi->setFloatValue(pe->getMP() * (1/INHG2PA));
+ tp._mp_inhg->setFloatValue(pe->getMP() * (1/INHG2PA));
+ tp._egt_degf->setFloatValue(
+ pe->getEGT() * K2DEGF + K2DEGFOFFSET);
+ tp._oil_temperature_degf->setFloatValue(
+ pe->getOilTemp() * K2DEGF + K2DEGFOFFSET);
+ tp._boost_gauge_inhg->setFloatValue(
+ pe->getBoost() * (1/INHG2PA));
} else if(p->getEngine()->isTurbineEngine()) {
TurbineEngine* te = p->getEngine()->isTurbineEngine();
- node->setFloatValue("n2", te->getN2());
+ tp._n2->setFloatValue(te->getN2());
}
}
if(t->getJet()) {
Jet* j = t->getJet();
- node->setFloatValue("n1", j->getN1());
- node->setFloatValue("n2", j->getN2());
- node->setFloatValue("epr", j->getEPR());
- node->setFloatValue("egt-degf",
- j->getEGT() * K2DEGF + K2DEGFOFFSET);
+ tp._n1->setFloatValue(j->getN1());
+ tp._n2->setFloatValue(j->getN2());
+ tp._epr->setFloatValue(j->getEPR());
+ tp._egt_degf->setFloatValue(
+ j->getEGT() * K2DEGF + K2DEGFOFFSET);
// These are "unmodeled" values that are still needed for
// many cockpits. Tie them all to the N1 speed, but
w->setTranslift(attrf(a, "translift", 0.05));
w->setC2(attrf(a, "dragfactor", 1));
w->setStepspersecond(attrf(a, "stepspersecond", 120));
+ w->setPhiNull((attrf(a, "phi0", 0))*YASIM_PI/180);
w->setRPM(attrf(a, "rpm", 424));
w->setRelLenHinge(attrf(a, "rellenflaphinge", 0.07));
w->setAlpha0((attrf(a, "flap0", -5))*YASIM_PI/180);
w->setTeeterdamp(attrf(a,"teeterdamp",.0001));
w->setMaxteeterdamp(attrf(a,"maxteeterdamp",1000));
w->setRelLenTeeterHinge(attrf(a,"rellenteeterhinge",0.01));
- void setAlphamin(float f);
- void setAlphamax(float f);
- void setAlpha0factor(float f);
-
+ w->setBalance(attrf(a,"balance",1.0));
+ w->setMinTiltYaw(attrf(a,"mintiltyaw",0.0));
+ w->setMinTiltPitch(attrf(a,"mintiltpitch",0.0));
+ w->setMinTiltRoll(attrf(a,"mintiltroll",0.0));
+ w->setMaxTiltYaw(attrf(a,"maxtiltyaw",0.0));
+ w->setMaxTiltPitch(attrf(a,"maxtiltpitch",0.0));
+ w->setMaxTiltRoll(attrf(a,"maxtiltroll",0.0));
+ w->setTiltCenterX(attrf(a,"tiltcenterx",0.0));
+ w->setTiltCenterY(attrf(a,"tiltcentery",0.0));
+ w->setTiltCenterZ(attrf(a,"tiltcenterz",0.0));
+ w->setDownwashFactor(attrf(a, "downwashfactor", 1));
if(attrb(a,"ccw"))
w->setCcw(1);
-
+ if(attrb(a,"sharedflaphinge"))
+ w->setSharedFlapHinge(true);
+
if(a->hasAttribute("name"))
w->setName(a->getValue("name") );
if(a->hasAttribute("alphaout0"))
if(a->hasAttribute("compression"))
eng->setCompression(attrf(a, "compression"));
+ if(a->hasAttribute("min-throttle"))
+ eng->setMinThrottle(attrf(a, "min-throttle"));
+
if(a->hasAttribute("turbo-mul")) {
float mul = attrf(a, "turbo-mul");
float mp = attrf(a, "wastegate-mp", 1e6) * INHG2PA;
// yet.
int FGFDM::parseAxis(const char* name)
{
- int i;
- for(i=0; i<_axes.size(); i++) {
- AxisRec* a = (AxisRec*)_axes.get(i);
- if(eq(a->name, name))
- return a->handle;
+ for(int i=0; i<_axes.size(); i++) {
+ AxisRec* a = (AxisRec*)_axes.get(i);
+ if(eq(a->name, name))
+ return a->handle;
}
// Not there, make a new one.
if(eq(name, "EXTEND")) return ControlMap::EXTEND;
if(eq(name, "HEXTEND")) return ControlMap::HEXTEND;
if(eq(name, "LEXTEND")) return ControlMap::LEXTEND;
+ if(eq(name, "LACCEL")) return ControlMap::LACCEL;
if(eq(name, "INCIDENCE")) return ControlMap::INCIDENCE;
if(eq(name, "FLAP0")) return ControlMap::FLAP0;
+ if(eq(name, "FLAP0EFFECTIVENESS")) return ControlMap::FLAP0EFFECTIVENESS;
if(eq(name, "FLAP1")) return ControlMap::FLAP1;
+ if(eq(name, "FLAP1EFFECTIVENESS")) return ControlMap::FLAP1EFFECTIVENESS;
if(eq(name, "SLAT")) return ControlMap::SLAT;
if(eq(name, "SPOILER")) return ControlMap::SPOILER;
if(eq(name, "CASTERING")) return ControlMap::CASTERING;
if(eq(name, "COLLECTIVE")) return ControlMap::COLLECTIVE;
if(eq(name, "CYCLICAIL")) return ControlMap::CYCLICAIL;
if(eq(name, "CYCLICELE")) return ControlMap::CYCLICELE;
+ if(eq(name, "TILTROLL")) return ControlMap::TILTROLL;
+ if(eq(name, "TILTPITCH")) return ControlMap::TILTPITCH;
+ if(eq(name, "TILTYAW")) return ControlMap::TILTYAW;
if(eq(name, "ROTORGEARENGINEON")) return ControlMap::ROTORENGINEON;
if(eq(name, "ROTORBRAKE")) return ControlMap::ROTORBRAKE;
+ if(eq(name, "ROTORENGINEMAXRELTORQUE"))
+ return ControlMap::ROTORENGINEMAXRELTORQUE;
+ if(eq(name, "ROTORRELTARGET")) return ControlMap::ROTORRELTARGET;
+ if(eq(name, "ROTORBALANCE")) return ControlMap::ROTORBALANCE;
if(eq(name, "REVERSE_THRUST")) return ControlMap::REVERSE_THRUST;
if(eq(name, "WASTEGATE")) return ControlMap::WASTEGATE;
if(eq(name, "WINCHRELSPEED")) return ControlMap::WINCHRELSPEED;
return s2;
}
-int FGFDM::attri(XMLAttributes* atts, char* attr)
+int FGFDM::attri(XMLAttributes* atts, const char* attr)
{
if(!atts->hasAttribute(attr)) {
SG_LOG(SG_FLIGHT,SG_ALERT,"Missing '" << attr <<
return attri(atts, attr, 0);
}
-int FGFDM::attri(XMLAttributes* atts, char* attr, int def)
+int FGFDM::attri(XMLAttributes* atts, const char* attr, int def)
{
const char* val = atts->getValue(attr);
if(val == 0) return def;
else return atol(val);
}
-float FGFDM::attrf(XMLAttributes* atts, char* attr)
+float FGFDM::attrf(XMLAttributes* atts, const char* attr)
{
if(!atts->hasAttribute(attr)) {
SG_LOG(SG_FLIGHT,SG_ALERT,"Missing '" << attr <<
return attrf(atts, attr, 0);
}
-float FGFDM::attrf(XMLAttributes* atts, char* attr, float def)
+float FGFDM::attrf(XMLAttributes* atts, const char* attr, float def)
{
const char* val = atts->getValue(attr);
if(val == 0) return def;
else return (float)atof(val);
}
-double FGFDM::attrd(XMLAttributes* atts, char* attr)
+double FGFDM::attrd(XMLAttributes* atts, const char* attr)
{
if(!atts->hasAttribute(attr)) {
SG_LOG(SG_FLIGHT,SG_ALERT,"Missing '" << attr <<
return attrd(atts, attr, 0);
}
-double FGFDM::attrd(XMLAttributes* atts, char* attr, double def)
+double FGFDM::attrd(XMLAttributes* atts, const char* attr, double def)
{
const char* val = atts->getValue(attr);
if(val == 0) return def;
// Unfortunately, this usage creeped into existing configuration files
// while I wasn't active, and it's going to be hard to remove. Issue
// a warning to nag people into changing their ways for now...
-bool FGFDM::attrb(XMLAttributes* atts, char* attr)
+bool FGFDM::attrb(XMLAttributes* atts, const char* attr)
{
const char* val = atts->getValue(attr);
if(val == 0) return false;