SerialInterface::SerialInterface(const std::string& portname) { // Open the port //clog(info) << "open_weatherstation" << std::endl; if ((_sp = open(portname.c_str(), O_RDWR | O_NOCTTY)) < 0) throw HardwareException("Unable to open serial device"); if ( flock(_sp, LOCK_EX) < 0 ) throw HardwareException("Serial device is locked by other program"); // We want full control of what is set by simply resetting entire adtio // struct struct termios adtio; memset(&adtio, 0, sizeof(adtio)); // Serial control options adtio.c_cflag &= ~PARENB; // No parity adtio.c_cflag &= ~CSTOPB; // One stop bit adtio.c_cflag &= ~CSIZE; // Character size mask adtio.c_cflag |= CS8; // Character size 8 bits adtio.c_cflag |= CREAD; // Enable Receiver //adtio.c_cflag &= ~CREAD; // Disable Receiver adtio.c_cflag &= ~HUPCL; // No "hangup" adtio.c_cflag &= ~CRTSCTS; // No flowcontrol adtio.c_cflag |= CLOCAL; // Ignore modem control lines // Baudrate, for newer systems cfsetispeed(&adtio, BAUDRATE); cfsetospeed(&adtio, BAUDRATE); // Local options // Raw input = clear ICANON, ECHO, ECHOE, and ISIG // Disable misc other local features = clear FLUSHO, NOFLSH, TOSTOP, PENDIN, and IEXTEN // So we actually clear all flags in adtio.c_lflag adtio.c_lflag = 0; // Input options // Disable parity check = clear INPCK, PARMRK, and ISTRIP // Disable software flow control = clear IXON, IXOFF, and IXANY // Disable any translation of CR and LF = clear INLCR, IGNCR, and ICRNL // Ignore break condition on input = set IGNBRK // Ignore parity errors just in case = set IGNPAR; // So we can clear all flags except IGNBRK and IGNPAR adtio.c_iflag = IGNBRK|IGNPAR; // Output options // Raw output should disable all other output options adtio.c_oflag &= ~OPOST; // Time-out options adtio.c_cc[VTIME] = 10; // timer 1s adtio.c_cc[VMIN] = 0; // blocking read until 1 char if (tcsetattr(_sp, TCSANOW, &adtio) < 0) throw HardwareException("Unable to initialize serial device"); tcflush(_sp, TCIOFLUSH); }
//------------------------------------------------------------------------------ bool SolarPowerSystem::Initialize() { #ifdef DEBUG_SOLAR_POWER MessageInterface::ShowMessage("Calling Initialization on %s\n", instanceName.c_str()); MessageInterface::ShowMessage("number of shadow bodies = %d\n", (Integer) shadowBodyNames.size()); #endif PowerSystem::Initialize(); // Solar System is set by the spacecraft to which this is attached if (!solarSystem) { std::string errmsg = "SolarSystem has not been set on PowerSystem "; errmsg += instanceName + ".\n"; throw HardwareException(errmsg); } // if no names were added to the ShadowBodies list, add the Default body // This will cause "ShadowBodies = {'Earth'} to be written to the script << if ((shadowBodyNames.empty()) && (!settingNoBodies)) shadowBodyNames = defaultShadowBodyNames; // shadowBodyNames.push_back("Earth"); // Set up the list of shadowBodies using current solarSystem shadowBodies.clear(); for (unsigned int ii = 0; ii < shadowBodyNames.size(); ii++) { CelestialBody *body = solarSystem->GetBody(shadowBodyNames.at(ii)); if (!body) { std::string errmsg = "SolarPowerSystem "; errmsg += instanceName + " cannot find body "; errmsg += shadowBodyNames.at(ii) + ". ShadowBodies must be "; errmsg += "Celestial Bodies.\n"; throw HardwareException(errmsg); } shadowBodies.push_back(body); #ifdef DEBUG_SOLAR_POWER MessageInterface::ShowMessage("Adding shadow body %s to %s\n", body->GetName().c_str(), instanceName.c_str()); #endif } if (!shadowState) shadowState = new ShadowState(); shadowState->SetSolarSystem(solarSystem); return isInitialized; }
//--------------------------------------------------------------------------- bool ElectricThruster::SetStringParameter(const Integer id, const std::string &value) { #ifdef DEBUG_ELECTRIC_THRUSTER_SET MessageInterface::ShowMessage ("ElectricThruster::SetStringParameter() '%s' entered, id=%d, value='%s'\n", GetName().c_str(), id, value.c_str()); #endif switch (id) { case THRUST_MODEL: if (find(thrustModelLabels.begin(), thrustModelLabels.end(), value) == thrustModelLabels.end()) { std::string modellist = thrustModelLabels[0]; for (UnsignedInt n = 1; n < thrustModelLabels.size(); ++n) modellist += ", " + thrustModelLabels[n]; std::string msg = "The value of \"" + value + "\" for field \"ThrustModel\"" " on object \"" + instanceName + "\" is not an allowed value.\n" "The allowed values are: [ " + modellist + " ]. "; throw HardwareException(msg); } thrustModel = value; return true; default: return Thruster::SetStringParameter(id, value); } }
bool ChemicalTank::Validate() { if (density <= 0.0) return false; if ((volume - fuelMass / density) < 0.0) throw HardwareException("Fuel volume exceeds tank capacity\n"); return true; }
//------------------------------------------------------------------------------ void ChemicalTank::DepleteFuel(Real dm) { fuelMass -= dm; if (fuelMass < 0.0) // For now, throw if the fuel goes below 0 throw HardwareException("Fuel in tank " + instanceName + " completely exhausted.\n"); }
//------------------------------------------------------------------------------ bool ElectricThruster::Initialize() { #ifdef DEBUG_ELECTRIC_THRUSTER_INIT MessageInterface::ShowMessage ("ElectricThruster::Initialize() <%p>'%s' entered, thrustModel=%s\n", this, GetName().c_str(), thrustModel.c_str()); #endif bool retval = Thruster::Initialize(); if (!retval) return false; // CHECK maxUsablePower > minUsablePower if (maxUsablePower <= minUsablePower) { std::string msg = "The value of field \"MaximumUsablePower\" on Electric Thruster \""; msg += instanceName + "\" must be greater than "; msg += "the value of field \"MinimumUsablePower\".\n"; throw HardwareException(msg); } // Check that all attached tanks are ElectricTanks for (UnsignedInt i=0; i<tanks.size(); i++) { if (!tanks.at(i)->IsOfType("ElectricTank")) { std::string errmsg = "All tanks set on ElectricThruster "; errmsg += instanceName + " must be of type ElectricTank.\n"; throw HardwareException(errmsg); } } #ifdef DEBUG_ELECTRIC_THRUSTER_INIT MessageInterface::ShowMessage ("ElectricThruster::Initialize() <%p>'%s' returning %s\n", this, GetName().c_str(), retval ? "true" : "false"); #endif return retval; }
//--------------------------------------------------------------------------- bool ElectricThruster::CalculateThrustAndIsp() { #ifdef DEBUG_MASS_FLOW_THRUST_VECTOR MessageInterface::ShowMessage( "Entering ElectricThruster::CalculateThrustAndIsp, power = %12.10f, minUsablePower = %12.10f\n", power, minUsablePower); MessageInterface::ShowMessage(" powerToUse = %12.10f\n", powerToUse); MessageInterface::ShowMessage(" powerToUse2 = %12.10f\n", powerToUse2); MessageInterface::ShowMessage(" powerToUse3 = %12.10f\n", powerToUse3); MessageInterface::ShowMessage(" powerToUse4 = %12.10f\n", powerToUse4); #endif if (!thrusterFiring) { #ifdef DEBUG_MASS_FLOW_THRUST_VECTOR MessageInterface::ShowMessage( "In ElectricThruster::CalculateThrustAndIsp, thruster %s NOT FIRING!!\n", instanceName.c_str()); #endif thrust = 0.0; impulse = 0.0; } else { if (tanks.empty()) throw HardwareException("ElectricThruster \"" + instanceName + "\" does not have a fuel tank"); impulse = isp; // CORRECT? if (thrustModel == "ThrustMassPolynomial") { thrust = ((thrustCoeff[4] * powerToUse4) + (thrustCoeff[3] * powerToUse3) + (thrustCoeff[2] * powerToUse2) + (thrustCoeff[1] * powerToUse) + thrustCoeff[0]) / 1.0e3; // 1.0e6; } else if (thrustModel == "ConstantThrustAndIsp") { thrust = constantThrust; // / 1.0e-3; } else // FixedEfficiency { thrust = (2.0 * efficiency * powerToUse) / // * 0.001) / (isp * gravityAccel * 0.001); } } return true; }
//--------------------------------------------------------------------------- // std::string GetStringParameter(const Integer id,const Integer index) const //--------------------------------------------------------------------------- std::string SolarPowerSystem::GetStringParameter(const Integer id, const Integer index) const { if (id == SHADOW_BODIES) { try { return shadowBodyNames.at(index); } catch (const std::exception &) { throw HardwareException("SolarPowerSystem error: index out-of-range."); } } return PowerSystem::GetStringParameter(id, index); }
//--------------------------------------------------------------------------- // bool SetStringParameter(const Integer id, const std::string &value) //--------------------------------------------------------------------------- bool ChemicalTank::SetStringParameter(const Integer id, const std::string &value) { #ifdef DEBUG_FUELTANK_SET MessageInterface::ShowMessage ("ChemicalTank::SetStringParameter() entered, id=%d, value='%s'\n", id, value.c_str()); #endif if (id == PRESSURE_MODEL) { if (find(pressureModelList.begin(), pressureModelList.end(), value) != pressureModelList.end()) { for (UnsignedInt i=0; i<pressureModelList.size(); i++) if (value == pressureModelList[i]) pressureModel = i; } else { // write one warning per GMAT session static bool firstTimeWarning = true; std::string framelist = pressureModelList[0]; for (UnsignedInt n = 1; n < pressureModelList.size(); ++n) framelist += ", " + pressureModelList[n]; std::string msg = "The value of \"" + value + "\" for field \"PressureModel\"" " on object \"" + instanceName + "\" is not an allowed value.\n" "The allowed values are: [ " + framelist + " ]. "; if (firstTimeWarning) { firstTimeWarning = false; throw HardwareException(msg); } } return true; } return FuelTank::SetStringParameter(id, value); }
//--------------------------------------------------------------------------- // bool SetStringParameter(const Integer id, const std::string &value, // const Integer index) //--------------------------------------------------------------------------- bool SolarPowerSystem::SetStringParameter(const Integer id, const std::string &value, const Integer index) { #ifdef DEBUG_SET MessageInterface::ShowMessage( "Entering SetStringParameter with id = %d, value = %s, and index = %d\n", id, value.c_str(), index); #endif if (id == SHADOW_BODIES) { // Check to see if we are setting a blank list here; if we are, // then we do NOT want to use the default list of bodies Integer sz = value.length(); if ((sz <= 0) || (GmatStringUtil::IsBlank(value)) || ((value[0] == '{') && (value[sz-1] == '}'))) { settingNoBodies = true; #ifdef DEBUG_SET MessageInterface::ShowMessage( "In SetStringParameter, settingNoBodies = true!!\n"); #endif return true; } if ((index < 0) || (index > (Integer) shadowBodyNames.size())) { std::string errmsg = "For PowerSystem "; errmsg += instanceName + ", index into ShadowBodies is "; errmsg += "out-of-range\n"; throw HardwareException(errmsg); } if (value == GmatSolarSystemDefaults::SUN_NAME) { std::string errmsg = "The Sun cannot be set as a Shadow body "; errmsg += "on Power System " + instanceName; errmsg += "\n"; throw HardwareException(errmsg); } // Add to the end of the list ... if (index == (Integer) shadowBodyNames.size()) { if (find(shadowBodyNames.begin(), shadowBodyNames.end(), value) == shadowBodyNames.end()) { shadowBodyNames.push_back(GmatStringUtil::Trim(value)); settingNoBodies = false; #ifdef DEBUG_SET MessageInterface::ShowMessage( "In SetStringParameter, settingNoBodies = false\n"); #endif } } // ... or, replace current name else { shadowBodyNames.at(index) = GmatStringUtil::Trim(value); settingNoBodies = false; #ifdef DEBUG_SET MessageInterface::ShowMessage( "In SetStringParameter, settingNoBodies = false (2)\n"); #endif } return true; } return PowerSystem::SetStringParameter(id, value, index); }
//--------------------------------------------------------------------------- Real ElectricThruster::CalculateMassFlow() { #ifdef DEBUG_MASS_FLOW_THRUST_VECTOR MessageInterface::ShowMessage( "Entering ElectricThruster::CalculateMassFlow, power = %12.10f, minUsablePower = %12.10f\n", power, minUsablePower); #endif powerToUse = power; // power was set by FiniteBurn if (!thrusterFiring) { #ifdef DEBUG_MASS_FLOW_THRUST_VECTOR MessageInterface::ShowMessage("ElectricThruster %s is not firing\n", instanceName.c_str()); #endif return 0.0; } else { if (tanks.empty()) throw HardwareException("ElectricThruster \"" + instanceName + "\" does not have a fuel tank"); if (powerToUse < minUsablePower) { #ifdef DEBUG_MASS_FLOW_THRUST_VECTOR MessageInterface::ShowMessage("RETURNING zero!!!!\n"); #endif mDot = 0.0; thrust = 0.0; return 0.0; } if (powerToUse > maxUsablePower) powerToUse = maxUsablePower; powerToUse2 = powerToUse * powerToUse; powerToUse3 = powerToUse2 * powerToUse; powerToUse4 = powerToUse3 * powerToUse; #ifdef DEBUG_MASS_FLOW_THRUST_VECTOR MessageInterface::ShowMessage("power = %12.10f, powerToUse = %12.10f\n", power, powerToUse); #endif // For now, always calculate T and I_sp if (!CalculateThrustAndIsp()) throw HardwareException("ElectricThruster \"" + instanceName + "\" could not calculate dm/dt"); if (thrustModel == "ThrustMassPolynomial") { mDot = ((massFlowCoeff[4] * powerToUse4) + (massFlowCoeff[3] * powerToUse3) + (massFlowCoeff[2] * powerToUse2) + (massFlowCoeff[1] * powerToUse) + massFlowCoeff[0]) / 1.0e6; } else if (thrustModel == "ConstantThrustAndIsp") { mDot = constantThrust / (isp * gravityAccel); // do I need to divide by 1.0e-3 here? or put the 0.001 * in there? } else // "FixedEfficiency" { Real ispG = (isp * gravityAccel * 0.001); Real ispG2 = ispG * ispG; mDot = (2.0 * efficiency * powerToUse * 0.001) / ispG2; } // if (impulse == 0.0) // throw HardwareException("ElectricThruster \"" + instanceName + // "\" has specific impulse == 0.0"); } #ifdef DEBUG_MASS_FLOW_THRUST_VECTOR MessageInterface::ShowMessage( " Thrust = %15.10f, Isp = %15.10f, gravity accel = %12.10f, TSF = %12.10f, " "dutyCycle = %15.10f, MassFlow = %15.10f T/Isp = %12.10f\n", thrust, impulse, gravityAccel, thrustScaleFactor, dutyCycle, mDot, thrust/impulse); #endif return mDot * -dutyCycle; // Flow rate should be negative in ODEs - CORRECT? }
//------------------------------------------------------------------------------ Real ElectricThruster::SetRealParameter(const Integer id, const Real value) { #ifdef DEBUG_ELECTRIC_THRUSTER_SET MessageInterface::ShowMessage ("ElectricThruster::SetRealParameter() '%s' entered, id=%d, value=%f\n", GetName().c_str(), id, value); #endif switch (id) { case MAXIMUM_USABLE_POWER: if (value <= 0.0) { std::stringstream ss(""); ss << value; std::string errmsg = "The value of \"" + ss.str() + "\" for field \"MaximumUsablePower\"" " on object \"" + instanceName + "\" is not an allowed value.\n" "The allowed values are: [Real number > 0]. "; throw HardwareException(errmsg); } return maxUsablePower = value; case MINIMUM_USABLE_POWER: if (value <= 0.0) { std::stringstream ss(""); ss << value; std::string errmsg = "The value of \"" + ss.str() + "\" for field \"MinimumUsablePower\"" " on object \"" + instanceName + "\" is not an allowed value.\n" "The allowed values are: [Real number > 0]. "; throw HardwareException(errmsg); } return minUsablePower = value; case THRUST_COEFF1: return thrustCoeff[0] = value; case THRUST_COEFF2: return thrustCoeff[1] = value; case THRUST_COEFF3: return thrustCoeff[2] = value; case THRUST_COEFF4: return thrustCoeff[3] = value; case THRUST_COEFF5: return thrustCoeff[4] = value; case MASS_FLOW_COEFF1: return massFlowCoeff[0] = value; case MASS_FLOW_COEFF2: return massFlowCoeff[1] = value; case MASS_FLOW_COEFF3: return massFlowCoeff[2] = value; case MASS_FLOW_COEFF4: return massFlowCoeff[3] = value; case MASS_FLOW_COEFF5: return massFlowCoeff[4] = value; case EFFICIENCY: return efficiency = value; case ISP: return isp = value; case CONSTANT_THRUST: return constantThrust = value; default: break; // Default just drops through } return Thruster::SetRealParameter(id, value); }