/// <summary> /// Writes a SmcSettings object as text to the specified streamwriter. /// </summary> /// <param name="settings">The settings to read from.</param> /// <param name="sw">The file to write to.</param> /// <param name="device">The device that these settings came from.</param> public static void save(SmcSettings settings, StreamWriter sw, Smc device) { sw.WriteLine("# Pololu Simple Motor Controller G2 settings file."); sw.WriteLine("# " + Smc.documentationUrl); sw.WriteLine("product: " + Smc.productIdToShortModelString(device.productId)); // [Add-new-settings-here] writeInputMode(sw, settings.inputMode); writeMixingMode(sw, settings.mixingMode); writeSerialMode(sw, settings.serialMode); writeBool(sw, "enable_i2c", settings.enableI2C); writeU32(sw, "serial_device_number", settings.serialDeviceNumber); writeBool(sw, "crc_for_commands", settings.crcForCommands); writeBool(sw, "crc_for_responses", settings.crcForResponses); writeBool(sw, "uart_response_delay", settings.uartResponseDelay); writeBool(sw, "use_fixed_baud_rate", settings.useFixedBaudRate); writeU32(sw, "fixed_baud_rate", settings.fixedBaudRateBps); // Channel settings writeChannelSettings(sw, "rc1", false, settings.rc1); writeChannelSettings(sw, "rc2", false, settings.rc2); writeChannelSettings(sw, "analog1", true, settings.analog1); writeChannelSettings(sw, "analog2", true, settings.analog2); // Motor settings writeU32(sw, "pwm_period_factor", settings.pwmPeriodFactor); writeBool(sw, "motor_invert", settings.motorInvert); writeBool(sw, "coast_when_off", settings.coastWhenOff); writeU32(sw, "speed_update_period", settings.speedUpdatePeriod); writeMotorLimits(sw, "forward", settings.forwardLimits); writeMotorLimits(sw, "reverse", settings.reverseLimits); writeU32(sw, "current_limit", settings.currentLimit); writeU32(sw, "current_offset_calibration", settings.currentOffsetCalibration); writeU32(sw, "current_scale_calibration", settings.currentScaleCalibration); // Advanced settings writeU32(sw, "min_pulse_period", settings.minPulsePeriod); writeU32(sw, "max_pulse_period", settings.maxPulsePeriod); writeU32(sw, "rc_timeout", settings.rcTimeout); writeU32(sw, "consec_good_pulses", settings.consecGoodPulses); writeS32(sw, "vin_scale_calibration", settings.vinScaleCalibration); writeBool(sw, "temp_limit_gradual", settings.tempLimitGradual); writeU32(sw, "over_temp_complete_shutoff_threshold", settings.overTempCompleteShutoffThreshold); writeU32(sw, "over_temp_normal_operation_threshold", settings.overTempNormalOperationThreshold); writeU32(sw, "low_vin_shutoff_timeout", settings.lowVinShutoffTimeout); writeU32(sw, "low_vin_shutoff_mv", settings.lowVinShutoffMv); writeU32(sw, "low_vin_startup_mv", settings.lowVinStartupMv); writeU32(sw, "high_vin_shutoff_mv", settings.highVinShutoffMv); writeBool(sw, "disable_safe_start", settings.disableSafeStart); writeBool(sw, "ignore_pot_disconnect", settings.ignorePotDisconnect); writeBool(sw, "ignore_err_line_high", settings.ignoreErrLineHigh); writeBool(sw, "never_sleep", settings.neverSleep); writeU32(sw, "command_timeout", settings.commandTimeout); }
/// <summary> /// Fixes certain things about a setttings object so that it doesn't make the device /// do something invalid. /// For each thing that gets fixed, a warning is added to the warnings list that is passed in. /// </summary> /// <param name="newSettings">The settings to fix.</param> /// <param name="warnings">A list of warnings. This function will add items to the list.</param> /// <param name="productId">The product ID of the device these settings will be used for.</param> /// <param name="firmwareVersion">The firmware version of the device these settings will be used for. /// If unknown, this argument should be 0.</param> public static void fixSettings(SmcSettings newSettings, List <string> warnings, UInt16 productId, UInt16 firmwareVersion) { if (productId == 0) { throw new Exception("Internal error: an invalid product ID was passed to fixSettings."); } if (newSettings.productId != productId) { throw new Exception( "These settings are for a different device. " + "The settings are for the " + Smc.productIdToShortModelString(newSettings.productId) + ", " + "not the " + Smc.productIdToShortModelString(productId) + "."); } // TODO: change the messages here to use present tense and future tense (like the Tic and Jrk). if (newSettings.overTempCompleteShutoffThreshold < newSettings.overTempNormalOperationThreshold) { warnings.Add( "The over-temperature complete shutoff threshold was " + "lower than the over-temperature normal operation threshold. " + "Both settings will be set to " + Smc.temperatureToString(newSettings.overTempCompleteShutoffThreshold) + " so the motor will shut off at that temperature."); newSettings.overTempNormalOperationThreshold = newSettings.overTempCompleteShutoffThreshold; } if (newSettings.lowVinStartupMv < newSettings.lowVinShutoffMv) { if (newSettings.lowVinShutoffMv + 500 > UInt16.MaxValue) { newSettings.lowVinStartupMv = UInt16.MaxValue; } else { newSettings.lowVinStartupMv = (UInt16)(newSettings.lowVinShutoffMv + 500); } warnings.Add("The Low VIN Startup voltage was lower than the Low VIN Shutoff voltage (" + newSettings.lowVinShutoffMv / (decimal)1000 + " V). " + "The Low VIN Startup voltage will be changed to " + newSettings.lowVinStartupMv / (decimal)1000 + " V."); } if (newSettings.highVinShutoffMv < newSettings.lowVinStartupMv) { newSettings.highVinShutoffMv = (new SmcSettings(productId).highVinShutoffMv); warnings.Add("The High VIN Shutoff voltage was lower than the Low VIN Startup voltage (" + newSettings.lowVinStartupMv / (decimal)1000 + " V). " + "The High VIN Shutoff voltage will be changed to " + newSettings.highVinShutoffMv / (decimal)1000 + " V."); } if (newSettings.vinScaleCalibration > 1500) { newSettings.vinScaleCalibration = 1500; warnings.Add("The VIN scale calibration was too high. It will be changed to 1500."); } if (newSettings.currentScaleCalibration > 20000) { newSettings.currentScaleCalibration = 20000; warnings.Add("The current scale calibration was too high. It will be changed to 20000."); } // Prevent the channel scaling values from being out of order (it's okay if they are equal) foreach (SmcChannel channel in Smc.channels) { SmcChannelSettings cs = newSettings.getChannelSettings(channel); if (cs.errorMin > cs.inputMin || cs.inputMin > cs.inputNeutralMin || cs.inputNeutralMin > cs.inputNeutralMax || cs.inputNeutralMax > cs.inputMax || cs.inputMax > cs.errorMax) { warnings.Add("The scaling values for " + channel.name() + " are out of order. They will be reset to their default settings."); SmcChannelSettings defaults = SmcChannelSettings.defaults(channel); cs.errorMin = defaults.errorMin; cs.inputMin = defaults.inputMin; cs.inputNeutralMin = defaults.inputNeutralMin; cs.inputNeutralMax = defaults.inputNeutralMax; cs.inputMax = defaults.inputMax; cs.errorMax = defaults.errorMax; } } fixMotorLimits(newSettings.forwardLimits, "forward", warnings); fixMotorLimits(newSettings.reverseLimits, "reverse", warnings); }