void T_AxisMapper::putBackIntoCfg(SimpleXMLTransfer* cfgfile)
{
#if DEBUG_TX_INTERFACE > 0
  printf("T_AxisMapper::putBackIntoCfg(SimpleXMLTransfer* config)\n");
  printf(" --> %s\n", child_in_cfg.c_str());
#endif
  SimpleXMLTransfer* item;
  SimpleXMLTransfer* group;
  SimpleXMLTransfer* item2;

  try
  {
    item = cfgfile->getChild(child_in_cfg);
    group = item->getChild("bindings.axes");

    for (int i = T_AxisMapper::AILERON; i <= T_AxisMapper::PITCH; i++)
    {
      item2 = group->getChild(Global::inputDev->AxisStringsXML[i], true);
      item2->setAttributeOverwrite("axis", c_func[i]);
      item2->setAttributeOverwrite("polarity", doubleToString(c_inv[i]));
    }
  
    item2 = item->getChild("bindings");
    item2->setAttributeOverwrite("radio_type", RadioTypeStrings[radio_type]);
  }
  catch (XMLException e)
  {
    fprintf(stderr, "*** T_AxisMapper: XMLException: %s\n", e.what());
  }
}
void T_AxisMapper::init(SimpleXMLTransfer* cfgfile, std::string childname)
{
#if DEBUG_TX_INTERFACE > 0
  printf("T_AxisMapper::init(cfg, child)\n");
  printf(" <-- %s\n", childname.c_str());
#endif
  SimpleXMLTransfer* inter;
  SimpleXMLTransfer* bindings;
  SimpleXMLTransfer* group;
  SimpleXMLTransfer* item;
  
  child_in_cfg = childname;

  // try to load config
  try
  {
    inter = cfgfile->getChild(childname, true);
    bindings  = inter->getChild("bindings", true);
    group     = bindings->getChild("axes", true);
  
    for (int i = T_AxisMapper::AILERON; i <= T_AxisMapper::PITCH; i++)
    {
      int default_axis = -1;
      float default_polarity = 1.0;

      // special handling for some default values
      if (i == T_AxisMapper::AILERON)
      {
        default_axis = 0;
      }
      else if (i == T_AxisMapper::ELEVATOR)
      {
        default_axis = 1;
        if (iface->inputMethod() != T_TX_Interface::eIM_joystick)
        {
          default_polarity = -1.0;
        }
      }
      
      item = group->getChild(Global::inputDev->AxisStringsXML[i], true);
      c_func[i] = item->attributeAsInt("axis", default_axis);
      c_inv[i]  = item->attributeAsDouble("polarity", default_polarity);
    }

    std::string radio = 
      strU(bindings->attribute("radio_type", RadioTypeStrings[CUSTOM]));

    for (int n=0; n < NR_OF_RADIO_TYPES; n++)
    {
      if (radio.compare(strU(RadioTypeStrings[n])) == 0)
      {
        setRadioType(n);
      }
    }
  }
  catch (XMLException e)
  {
    fprintf(stderr, "*** T_AxisMapper: XMLException: %s\n", e.what());
  }
}
/** \brief Initialize the mixer from a config file.
 *
 *  The mixer object will be initialized from the given config file.
 *  This file may contain more than one branch with interface settings,
 *  so the name of the child has to be specified.
 */
int T_TX_Mixer::init(SimpleXMLTransfer* cfg, std::string child)
{
#if DEBUG_TX_INTERFACE > 0
  printf("T_TX_Mixer::init(cfg, child)\n");
  printf(" <-- %s\n", child.c_str());
#endif

  SimpleXMLTransfer* mixer;
  SimpleXMLTransfer* item;
  SimpleXMLTransfer* inter;

  // store the child's name for writing back the settings
  child_in_cfg = child;

  printf("Loading mixer settings from %s:\n", child.c_str());
  try
  {
    inter = cfg->getChild(child, true);
    mixer = inter->getChild("mixer", true);

    enabled = mixer->attributeAsInt("enabled", 1);
    dr_enabled = mixer->attributeAsInt("dr_enabled", 0);
 
    for (int i = T_AxisMapper::AILERON; i <= T_AxisMapper::PITCH; i++)
    { 
      item = mixer->getChild(Global::inputDev->AxisStringsXML[i], true);

      trim_val[i]   = item->getDouble("trim",   0.0);
      nrate_val[i]  = item->getDouble("nrate",  1.0);
      srate_val[i]  = item->getDouble("srate",  1.0);
      exp_val[i]    = item->getDouble("exp",    0.0);

      mtravel_val[i] = item->getDouble("mtravel", -0.5);
      ptravel_val[i] = item->getDouble("ptravel", 0.5);
    }
      
    for (int i = 0; i < T_TX_Mixer::NUM_MIXERS; i++)
    { 
      item = mixer->getChild(Global::inputDev->MixerStringsXML[i], true);
      mixer_enabled[i] = item->attributeAsInt("enabled", 0);
      mixer_src[i]     = item->getDouble("src", T_AxisMapper::NOTHING);
      mixer_dst[i]     = item->getDouble("dst", T_AxisMapper::NOTHING);
      mixer_val[i]     = item->getDouble("val", 0.0);
    }
  }
  catch (XMLException e)
  {
    errMsg = e.what();
    return 1;
  }

  return 0;
}
void T_Calibration::putBackIntoCfg(SimpleXMLTransfer* cfgfile)
{
#if DEBUG_TX_INTERFACE > 0
  printf("T_Calibration::putBackIntoCfg(cfg)\n");
  printf(" --> %s\n", child_in_cfg.c_str());
#endif
  int size;
  SimpleXMLTransfer* item;
  SimpleXMLTransfer* group;
  SimpleXMLTransfer* item2;

  item = cfgfile->getChild(child_in_cfg);
  group = item->getChild("calibration");
  group->setAttributeOverwrite("version", "2");

  // clean list
  size = group->getChildCount();
  for (int n = 0; n < size; n++)
  {
    item2 = group->getChildAt(0);
    group->removeChildAt(0);
    delete item2;
  }
  // create new list
  for (int n = 0; n < TX_MAXAXIS; n++)
  {
    item2 = new SimpleXMLTransfer();
    item2->setName("axis");
    item2->addAttribute("val_min", doubleToString(val_min[n]));
    item2->addAttribute("val_mid", doubleToString(val_mid[n]));
    item2->addAttribute("val_max", doubleToString(val_max[n]));
    group->addChild(item2);
  }
}
void T_Calibration::init(SimpleXMLTransfer* cfgfile,
                         std::string childname)
{
#if DEBUG_TX_INTERFACE > 0
  printf("T_Calibration::init(cfg, child)\n");
  printf(" <-- %s\n", childname.c_str());
#endif
  int size;
  SimpleXMLTransfer* item;
  SimpleXMLTransfer* group;
  SimpleXMLTransfer* item2;
  
  child_in_cfg = childname;

  // try to load config
  printf("Loading calibration settings from %s:\n", childname.c_str());
  try
  {
    item = cfgfile->getChild(childname, true);
    group = item->getChild("calibration", true);
    int nVer = group->getInt("version", 1);
  
    size  = group->getChildCount();
    if (size > TX_MAXAXIS)
      size = TX_MAXAXIS;
    for (int n = 0; n < size; n++)
    {
      item2 = group->getChildAt(n);
      switch (nVer)
      {
        case 1:
          {
            float scale = item2->getDouble("scale", 1.0);
            float off = item2->getDouble("offset", 0.0);
            // old:   out = scale * in + offset
            val_min[n] = (-0.5 - off) / scale;
            val_max[n] = ( 0.5 - off) / scale;
            val_mid[n] = 0.5 * (val_min[n] + val_max[n]);
            printf("  (1)");
          }
          break;
          
        case 2:      
          val_min[n] = item2->getDouble("val_min", -1.0);
          val_mid[n] = item2->getDouble("val_mid",  0.0);
          val_max[n] = item2->getDouble("val_max",  1.0);
          printf("  (2)");
          break;
      }
      printf(" axis=%i val_min=%f val_mid=%f val_max=%f\n", n, val_min[n], val_mid[n], val_max[n]);
    }
  }
  catch (XMLException e)
  {
    fprintf(stderr, "*** T_Calibration::init(): %s\n", e.what());
  }
}
/** \brief Transfers all settings back to the config file.
 *
 *  The mixer settings will be stored in the same branch of the config
 *  file that they were read from on initialization.
 *
 *  \param config Pointer to the config file's SimpleXMLTransfer.
 */
void T_TX_Mixer::putBackIntoCfg(SimpleXMLTransfer* config)
{
#if DEBUG_TX_INTERFACE > 0
  printf("T_TX_Mixer::putBackIntoCfg(SimpleXMLTransfer* config)\n");
  printf(" --> %s\n", child_in_cfg.c_str());
#endif

  SimpleXMLTransfer* inter = config->getChild(child_in_cfg);
  SimpleXMLTransfer* mixer = inter->getChild("mixer");
  SimpleXMLTransfer* item;

  mixer->setAttributeOverwrite("enabled", enabled);
  mixer->setAttributeOverwrite("dr_enabled", dr_enabled);

  item = mixer->getChild(Global::inputDev->AxisStringsXML[T_AxisMapper::AILERON], true);
  item->setAttributeOverwrite("trim",  doubleToString(trim_val[T_AxisMapper::AILERON]));
  item->setAttributeOverwrite("nrate", doubleToString(nrate_val[T_AxisMapper::AILERON]));
  item->setAttributeOverwrite("srate", doubleToString(srate_val[T_AxisMapper::AILERON]));
  item->setAttributeOverwrite("exp",   doubleToString(exp_val[T_AxisMapper::AILERON]));

  item = mixer->getChild(Global::inputDev->AxisStringsXML[T_AxisMapper::ELEVATOR], true);
  item->setAttributeOverwrite("trim",  doubleToString(trim_val[T_AxisMapper::ELEVATOR]));
  item->setAttributeOverwrite("nrate", doubleToString(nrate_val[T_AxisMapper::ELEVATOR]));
  item->setAttributeOverwrite("srate", doubleToString(srate_val[T_AxisMapper::ELEVATOR]));
  item->setAttributeOverwrite("exp",   doubleToString(exp_val[T_AxisMapper::ELEVATOR]));

  item = mixer->getChild(Global::inputDev->AxisStringsXML[T_AxisMapper::RUDDER], true);
  item->setAttributeOverwrite("trim",  doubleToString(trim_val[T_AxisMapper::RUDDER]));
  item->setAttributeOverwrite("nrate", doubleToString(nrate_val[T_AxisMapper::RUDDER]));
  item->setAttributeOverwrite("srate", doubleToString(srate_val[T_AxisMapper::RUDDER]));
  item->setAttributeOverwrite("exp",   doubleToString(exp_val[T_AxisMapper::RUDDER]));

  item = mixer->getChild(Global::inputDev->AxisStringsXML[T_AxisMapper::FLAP], true);
  item->setAttributeOverwrite("trim",    doubleToString(trim_val[T_AxisMapper::FLAP]));
  item->setAttributeOverwrite("mtravel", doubleToString(mtravel_val[T_AxisMapper::FLAP]));
  item->setAttributeOverwrite("ptravel", doubleToString(ptravel_val[T_AxisMapper::FLAP]));
  
  for (int i = 0; i < T_TX_Mixer::NUM_MIXERS; i++)
  {
    item = mixer->getChild(Global::inputDev->MixerStringsXML[i], true);
    item->setAttributeOverwrite("enabled", mixer_enabled[i]);
    item->setAttributeOverwrite("src", mixer_src[i]);
    item->setAttributeOverwrite("dst", mixer_dst[i]);
    item->setAttributeOverwrite("val", doubleToString(mixer_val[i]));
  }
}
void CRRCAirplaneLaRCSim::initSound(SimpleXMLTransfer* xml)
{
  SimpleXMLTransfer* cfg = XMLModelFile::getConfig(xml);
  SimpleXMLTransfer* sndcfg = cfg->getChild("sound", true);
  int children = sndcfg->getChildCount();
  int units = sndcfg->getInt("units", 0);
  
  for (int i = 0; i < children; i++)
  {
    SimpleXMLTransfer *child = sndcfg->getChildAt(i);
    std::string name = child->getName();
    
    if (name.compare("sample") == 0)
    {
      T_AirplaneSound *sample;

      // assemble relative path
      std::string soundfile;
      soundfile           = child->attribute("filename");

      // other sound attributes
      int sound_type      = child->getInt("type", SOUND_TYPE_GLIDER);
      double dPitchFactor = child->getDouble("pitchfactor", 0.002);
      double dMaxVolume   = child->getDouble("maxvolume", 1.0);
  
      if (dMaxVolume < 0.0)
      {
        dMaxVolume = 0.0;
      }
      else if (dMaxVolume > 1.0)
      {
        dMaxVolume = 1.0;
      }

  //~ if (cfg->indexOfChild("power") < 0)
    //~ max_thrust = 0;
  //~ else
    //~ max_thrust = 1;
  
      if (soundfile != "")
      {
        // Get full path (considering search paths). 
        soundfile = FileSysTools::getDataPath("sounds/" + soundfile);
      }
      
      // File ok? Use default otherwise.
      if (!FileSysTools::fileExists(soundfile))
        soundfile = FileSysTools::getDataPath("sounds/fan.wav");
    
      std::cout << "soundfile: " << soundfile << "\n";
      //~ std::cout << "max_thrust: " << max_thrust << "\n";
      std::cout << "soundserver: " << Global::soundserver << "\n";
  
      // Only make noise if a sound file is available
      if (soundfile != "" && Global::soundserver != (CRRCAudioServer*)0)
      {        
        std::cout << "Using airplane sound " << soundfile << ", type " << sound_type << ", max vol " << dMaxVolume << std::endl;
        
        if (sound_type == SOUND_TYPE_GLIDER)
        {
          T_GliderSound *glidersound;
          float flMinRelV, flMaxRelV, flMaxDist;
          flMinRelV = (float)child->getDouble("v_min", 1.5);
          flMaxRelV = (float)child->getDouble("v_max", 4.0);
          flMaxDist = (float)child->getDouble("dist_max", 300);
          
          if (units == 1)
          {
            // convert from metric units to ft.
            flMaxDist *= M_TO_FT;
          }
          
          glidersound = new T_GliderSound(soundfile.c_str(), Global::soundserver->getAudioSpec());
          glidersound->setMinRelVelocity(flMinRelV);
          glidersound->setMaxRelVelocity(flMaxRelV);
          glidersound->setMaxDistanceFeet(flMaxDist);
          sample = glidersound;
        }
        else
        {
          sample = new T_EngineSound(soundfile.c_str(), Global::soundserver->getAudioSpec());
        }
                
        sample->setType(sound_type);
        sample->setPitchFactor(dPitchFactor);
        sample->setMaxVolume(dMaxVolume);
        sample->setChannel(Global::soundserver->playSample((T_SoundSample*)sample));
        sound.push_back(sample);
      }
    }
  }
}
void CRRC_AirplaneSim_MCopter01::LoadFromXML(SimpleXMLTransfer* xml, int nVerbosity)
{
  if (xml->getString("type").compare("mcopter01") != 0 ||
      xml->getInt("version") != 1)
  {
    throw XMLException("file is not for mcopter01");
  }    
    
  SimpleXMLTransfer* i;
  SimpleXMLTransfer* cfg = XMLModelFile::getConfig(xml);  
  
  {
    double to_slug;
    double to_slug_ft_ft;
    
    i = cfg->getChild("mass_inertia");
    switch (i->getInt("units"))
    {
     case 0:    
      to_slug       = 1;
      to_slug_ft_ft = 1;
      break;
     case 1:
      to_slug       = KG_TO_SLUG;
      to_slug_ft_ft = KG_M_M_TO_SLUG_FT_FT;
      break;
     default:
      {
        throw std::runtime_error("Unknown units in mass_inertia");
      }
      break;
    }
    Mass  = i->getDouble("Mass") * to_slug;
    I_xx  = i->getDouble("I_xx") * to_slug_ft_ft;
    I_yy  = i->getDouble("I_yy") * to_slug_ft_ft;
    I_zz  = i->getDouble("I_zz") * to_slug_ft_ft;
    I_xz  = i->getDouble("I_xz") * to_slug_ft_ft;
  }
    
  {
    speed_damp       = cfg->getDouble("aero.speed.damp");
    roll_damp1       = cfg->getDouble("aero.roll.damp1", 0);
    yaw_damp1        = cfg->getDouble("aero.yaw.damp1",  0);    
    roll_damp2       = cfg->getDouble("aero.roll.damp2", 0);    
    yaw_damp2        = cfg->getDouble("aero.yaw.damp2",  0);    
        
    yaw_dist         = cfg->getDouble("aero.yaw.dist", 0);    
    roll_dist        = cfg->getDouble("aero.roll.dist", 0);
    pitch_dist       = cfg->getDouble("aero.pitch.dist", roll_dist);
    
    // The ground effect parameters should be quite independent of the helicopter
    // parameters...shouldn't they? However, they can be adjusted.
    dGEDistMul  = xml->getDouble("GroundEffect.dist.mul",  1.5);

    {
      double tau  = xml->getDouble("Disturbance.tau_filter", 0.2);
      dist_t_init = xml->getDouble("Disturbance.time",       0.2);

      filt_rnd_yaw.SetTau(tau);
      filt_rnd_roll.SetTau(tau);
      filt_rnd_pitch.SetTau(tau);
    }
  }  
  
  wheels.init(xml, 0);
  dRotorRadius = wheels.getWingspan()*0.5;
  dRotorZ      = wheels.getZHigh();

  wheels.init(xml, 0);
  dRotorRadius = wheels.getWingspan()*0.5;
  dRotorZ      = wheels.getZHigh();

  props.clear();
  i = cfg->getChild("aero.props");
  for (int n=0; n<i->getChildCount(); n++)
    props.push_back(Propdata(i->getChildAt(n)));

  if (power.size() == 0)
  {    
    for (unsigned int n=0; n<props.size(); n++)
      power.push_back(new Power::Power(cfg, nVerbosity));
    dURef = 0.7 * cfg->getDouble("power.battery.U_0");
  }
  else
  {
    for (unsigned int n=0; n<power.size(); n++)
      power[n]->ReloadParams(cfg, nVerbosity);
  }
  
  controllers.clear();  
  Controller::LoadList(cfg->getChild("controllers"), controllers);  
}