Extract PrinterSettings from MatterControl

This commit is contained in:
John Lewin 2018-11-27 08:48:49 -08:00
parent e53d1f614f
commit ed16199978
9 changed files with 9 additions and 9 deletions

View file

@ -1,55 +0,0 @@
/*
Copyright (c) 2018, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Text.RegularExpressions;
namespace MatterHackers.MatterControl.SlicerConfiguration
{
public class GCodeMacro
{
public string Name { get; set; }
public string GCode { get; set; }
public DateTime LastModified { get; set; }
public static string FixMacroName(string input)
{
int lengthLimit = 24;
string result = Regex.Replace(input, @"\r\n?|\n", " ");
if (result.Length > lengthLimit)
{
result = result.Substring(0, lengthLimit) + "...";
}
return result;
}
}
}

View file

@ -1,967 +0,0 @@
/*
Copyright (c) 2018, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using MatterHackers.Agg;
using MatterHackers.Agg.Platform;
using MatterHackers.VectorMath;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
namespace MatterHackers.MatterControl.SlicerConfiguration
{
public enum NamedSettingsLayers { MHBaseSettings, OEMSettings, Quality, Material, User, All }
public enum BedShape { Rectangular, Circular };
[JsonConverter(typeof(StringEnumConverter))]
public enum LevelingSystem { Probe3Points, Probe7PointRadial, Probe13PointRadial, Probe100PointRadial, Probe3x3Mesh, Probe5x5Mesh, Probe10x10Mesh, ProbeCustom }
public class PrinterSettings
{
// Latest version should be in the form of:
// Year|month|day|versionForDay (to support multiple revisions on a given day)
public static int LatestVersion { get; } = 201606271;
public static EventHandler AnyPrinterSettingChanged;
public event EventHandler SettingChanged;
public event EventHandler MaterialPresetChanged;
public void OnMaterialPresetChanged()
{
MaterialPresetChanged?.Invoke(null, null);
}
public void OnSettingChanged(string slicerConfigName)
{
SettingChanged?.Invoke(this, new StringEventArgs(slicerConfigName));
AnyPrinterSettingChanged?.Invoke(this, new StringEventArgs(slicerConfigName));
}
public event EventHandler PrintLevelingEnabledChanged;
public event EventHandler MacrosChanged;
public static PrinterSettings Empty { get; }
public int DocumentVersion { get; set; } = LatestVersion;
public string ID { get; set; }
[JsonIgnore]
internal PrinterSettingsLayer QualityLayer { get; private set; }
[JsonIgnore]
internal PrinterSettingsLayer MaterialLayer { get; private set; }
public PrinterSettingsLayer StagedUserSettings { get; set; } = new PrinterSettingsLayer();
static PrinterSettings()
{
Empty = new PrinterSettings() { ID = "EmptyProfile" };
Empty.UserLayer[SettingsKey.printer_name] = "Empty Printer";
}
public PrinterSettings()
{
this.Helpers = new SettingsHelpers(this);
}
public List<GCodeMacro> Macros { get; set; } = new List<GCodeMacro>();
/// <summary>
/// Restore deactivated user overrides by iterating the active preset and removing/restoring matching items
/// </summary>
public void RestoreConflictingUserOverrides(PrinterSettingsLayer settingsLayer)
{
if (settingsLayer == null)
{
return;
}
foreach (var settingsKey in settingsLayer.Keys)
{
RestoreUserOverride(settingsLayer, settingsKey);
}
}
private void RestoreUserOverride(PrinterSettingsLayer settingsLayer, string settingsKey)
{
string stagedUserOverride;
if (StagedUserSettings.TryGetValue(settingsKey, out stagedUserOverride))
{
StagedUserSettings.Remove(settingsKey);
UserLayer[settingsKey] = stagedUserOverride;
}
}
internal void NotifyMacrosChanged()
{
this.MacrosChanged?.Invoke(this, null);
}
/// <summary>
/// Move conflicting user overrides to the temporary staging area, allowing presets values to take effect
/// </summary>
public void DeactivateConflictingUserOverrides(PrinterSettingsLayer settingsLayer)
{
if (settingsLayer == null)
{
return;
}
foreach (var settingsKey in settingsLayer.Keys)
{
StashUserOverride(settingsLayer, settingsKey);
}
}
/// <summary>
/// Determines if a given field should be shown given its filter
/// </summary>
/// <param name="filter">The view filter - order of precedence &amp;, |, !, =</param>
/// <returns>An indicator if the field should be shown given the current filter</returns>
public bool ParseShowString(string filter)
{
if (!string.IsNullOrEmpty(filter))
{
string[] splitOnAnd = filter.Split('&');
foreach (var andGroup in splitOnAnd)
{
bool orResult = false;
string[] splitOnOr = andGroup.Split('|');
foreach (var orGroup in splitOnOr)
{
var matchString = "1";
var orItem = orGroup;
bool negate = orItem.StartsWith("!");
if (negate)
{
orItem = orItem.Substring(1);
}
string sliceSettingValue = "";
if (orItem.Contains("="))
{
string[] splitOnEquals = orItem.Split('=');
sliceSettingValue = this.GetValue(splitOnEquals[0]);
matchString = splitOnEquals[1];
}
else if (orItem.Contains(">"))
{
matchString = "no_match";
string[] splitOnGreater = orItem.Split('>');
sliceSettingValue = this.GetValue(splitOnGreater[0]);
if (double.TryParse(sliceSettingValue, out double doubleValue))
{
if (double.TryParse(splitOnGreater[1], out double greater))
{
if (doubleValue > greater)
{
matchString = sliceSettingValue;
}
}
}
}
else
{
sliceSettingValue = this.GetValue(orItem);
}
if ((!negate && sliceSettingValue == matchString)
|| (negate && sliceSettingValue != matchString))
{
orResult = true;
}
}
if (orResult == false)
{
return false;
}
}
}
return true;
}
/// <summary>
/// Move conflicting user overrides to the temporary staging area, allowing presets values to take effect
/// </summary>
private void StashUserOverride(PrinterSettingsLayer settingsLayer, string settingsKey)
{
string userOverride;
if (this.UserLayer.TryGetValue(settingsKey, out userOverride))
{
this.UserLayer.Remove(settingsKey);
this.StagedUserSettings.Add(settingsKey, userOverride);
}
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
QualityLayer = GetQualityLayer(ActiveQualityKey);
if (!string.IsNullOrEmpty(ActiveMaterialKey))
{
MaterialLayer = GetMaterialLayer(ActiveMaterialKey);
}
}
public PrinterSettingsLayer OemLayer { get; set; }
public void Merge(PrinterSettingsLayer destinationLayer, PrinterSettings settingsToImport, List<PrinterSettingsLayer> rawSourceFilter, bool setLayerName)
{
HashSet<string> skipKeys = new HashSet<string>
{
"layer_id",
};
if (!setLayerName)
{
skipKeys.Add(SettingsKey.layer_name);
}
var destinationFilter = new List<PrinterSettingsLayer>
{
OemLayer,
BaseLayer,
destinationLayer,
}.Where(layer => layer != null);
var sourceFilter = rawSourceFilter.Where(layer => layer != null);
foreach (var keyName in PrinterSettings.KnownSettings)
{
if (settingsToImport.Contains(keyName))
{
// Compare the value to import to the layer cascade value and only set if different
string currentValue = this.GetValue(keyName, destinationFilter).Trim();
string importValue = settingsToImport.GetValue(keyName, sourceFilter).Trim();
if (!string.IsNullOrEmpty(importValue)
&& currentValue != importValue
&& !skipKeys.Contains(keyName))
{
destinationLayer[keyName] = importValue;
}
}
}
if (setLayerName)
{
destinationLayer[SettingsKey.layer_name] = settingsToImport.GetValue(SettingsKey.layer_name, sourceFilter);
}
this.Save();
}
internal PrinterSettingsLayer GetMaterialLayer(string layerID)
{
if (string.IsNullOrEmpty(layerID))
{
return null;
}
return MaterialLayers.Where(layer => layer.LayerID == layerID).FirstOrDefault();
}
private PrinterSettingsLayer GetQualityLayer(string layerID)
{
return QualityLayers.Where(layer => layer.LayerID == layerID).FirstOrDefault();
}
public string ActiveQualityKey
{
get
{
return GetValue(SettingsKey.active_quality_key);
}
internal set
{
SetValue(SettingsKey.active_quality_key, value);
QualityLayer = GetQualityLayer(value);
this.OnSettingChanged(SettingsKey.active_quality_key);
}
}
public string ActiveMaterialKey
{
get
{
if (MaterialSettingsKeys.Count > 0)
{
return MaterialSettingsKeys[0];
}
return null;
}
internal set
{
if (MaterialSettingsKeys.Count == 0 || value != MaterialSettingsKeys[0])
{
MaterialSettingsKeys.Clear();
MaterialSettingsKeys.Add(value);
MaterialLayer = GetMaterialLayer(value);
this.OnMaterialPresetChanged();
this.OnSettingChanged(SettingsKey.active_material_key);
}
}
}
public List<string> MaterialSettingsKeys { get; set; } = new List<string>();
[JsonIgnore]
public bool AutoSave { get; set; } = true;
internal string ComputeSHA1()
{
return ComputeSHA1(this.ToJson());
}
public string ComputeSHA1(string json)
{
// SHA1 value is based on UTF8 encoded file contents
using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
return HashGenerator.ComputeSHA1(memoryStream);
}
}
/// <summary>
/// User settings overrides
/// </summary>
public PrinterSettingsLayer UserLayer { get; } = new PrinterSettingsLayer();
public static PrinterSettings LoadFile(string printerProfilePath, bool performMigrations = false)
{
if (performMigrations)
{
JObject jObject = null;
try
{
jObject = JObject.Parse(File.ReadAllText(printerProfilePath));
}
catch
{
return null;
}
int documentVersion = jObject?.GetValue("DocumentVersion")?.Value<int>() ?? PrinterSettings.LatestVersion;
if (documentVersion < PrinterSettings.LatestVersion)
{
printerProfilePath = ProfileMigrations.MigrateDocument(printerProfilePath, documentVersion);
}
}
try
{
return JsonConvert.DeserializeObject<PrinterSettings>(File.ReadAllText(printerProfilePath));
}
catch
{
return null;
}
}
internal void OnPrintLevelingEnabledChanged(object s, EventArgs e)
{
PrintLevelingEnabledChanged?.Invoke(s, e);
}
/// <summary>
/// Should contain both user created and oem specified material layers
/// </summary>
public ObservableCollection<PrinterSettingsLayer> MaterialLayers { get; } = new ObservableCollection<PrinterSettingsLayer>();
/// <summary>
/// Should contain both user created and oem specified quality layers
/// </summary>
public ObservableCollection<PrinterSettingsLayer> QualityLayers { get; } = new ObservableCollection<PrinterSettingsLayer>();
///<summary>
///Returns the settings value at the 'top' of the stack
///Returns the first matching value discovered while enumerating the settings layers
///</summary>
public string GetValue(string sliceSetting, IEnumerable<PrinterSettingsLayer> layerCascade = null)
{
if (layerCascade == null)
{
layerCascade = defaultLayerCascade;
}
foreach (PrinterSettingsLayer layer in layerCascade)
{
string value;
if (layer.TryGetValue(sliceSetting, out value))
{
return value;
}
}
return "";
}
public bool IsOverride(string sliceSetting)
{
var values = new List<string>();
string firstBaseValue = null;
foreach (PrinterSettingsLayer layer in defaultLayerCascade)
{
if (layer.TryGetValue(sliceSetting, out string value))
{
if (layer == this.BaseLayer
|| layer == this.OemLayer)
{
firstBaseValue = value;
break;
}
values.Add(value);
}
}
string currentValue = values.FirstOrDefault();
string firstPresetValue = values.Skip(1).FirstOrDefault();
bool differsFromPreset = values.Count > 0
&& firstPresetValue != null
&& firstPresetValue != currentValue;
bool differsFromBase = currentValue != firstBaseValue;
return currentValue != null
&& (differsFromPreset || differsFromBase);
}
// Helper method to debug settings layers per setting
public List<(string layerName, string currentValue)> GetLayerValues(string sliceSetting, IEnumerable<PrinterSettingsLayer> layerCascade = null)
{
if (layerCascade == null)
{
layerCascade = defaultLayerCascade;
}
var results = new List<(string layerName, string currentValue)>();
foreach (PrinterSettingsLayer layer in layerCascade)
{
if (layer.TryGetValue(sliceSetting, out string value))
{
string layerName = "User";
if (layer == this.BaseLayer)
{
layerName = "Base";
}
else if (layer == this.OemLayer)
{
layerName = "Oem";
}
else if (layer == this.MaterialLayer)
{
layerName = "Material";
}
else if (layer == this.QualityLayer)
{
layerName = "Quality";
}
results.Add((layerName, value));
}
}
return results;
}
public (string currentValue, string layerName) GetValueAndLayerName(string sliceSetting, IEnumerable<PrinterSettingsLayer> layerCascade = null)
{
if (layerCascade == null)
{
layerCascade = defaultLayerCascade;
}
foreach (PrinterSettingsLayer layer in layerCascade)
{
string value;
if (layer.TryGetValue(sliceSetting, out value))
{
string layerName = "User";
if (layer == this.BaseLayer)
{
layerName = "Base";
}
else if (layer == this.OemLayer)
{
layerName = "Oem";
}
else if (layer == this.MaterialLayer)
{
layerName = "Material";
}
else if (layer == this.QualityLayer)
{
layerName = "Quality";
}
return (value, layerName);
}
}
return ("", "");
}
public bool Contains(string sliceSetting, IEnumerable<PrinterSettingsLayer> layerCascade = null)
{
if (layerCascade == null)
{
layerCascade = defaultLayerCascade;
}
foreach (PrinterSettingsLayer layer in layerCascade)
{
if (layer.ContainsKey(sliceSetting))
{
return true;
}
}
return false;
}
PrinterSettingsLayer _baseLayer;
[JsonIgnore]
public PrinterSettingsLayer BaseLayer
{
get
{
if (_baseLayer == null)
{
string propertiesFileContents = AggContext.StaticData.ReadAllText(Path.Combine("SliceSettings", "Properties.json"));
var settingsLayer = new PrinterSettingsLayer();
foreach (var settingsData in JsonConvert.DeserializeObject<List<SliceSettingData>>(propertiesFileContents))
{
settingsLayer[settingsData.SlicerConfigName] = settingsData.DefaultValue;
}
_baseLayer = settingsLayer;
}
return _baseLayer;
}
}
internal IEnumerable<PrinterSettingsLayer> defaultLayerCascade
{
get
{
if (this.UserLayer != null)
{
yield return this.UserLayer;
}
if (this.MaterialLayer != null)
{
yield return this.MaterialLayer;
}
if (this.QualityLayer != null)
{
yield return this.QualityLayer;
}
if (this.OemLayer != null)
{
yield return this.OemLayer;
}
yield return this.BaseLayer;
}
}
[JsonIgnore]
public SettingsHelpers Helpers { get; set; }
[JsonIgnore]
public bool PrinterSelected => OemLayer?.Keys.Count > 0;
internal void RunInTransaction(Action<PrinterSettings> action)
{
// TODO: Implement RunInTransaction
// Suspend writes
action(this);
// Commit
}
public void ClearUserOverrides()
{
var userOverrides = this.UserLayer.Keys.ToArray();
// Leave user layer items that have no Organizer definition and thus cannot be changed by the user
var keysToRetain = new HashSet<string>(userOverrides.Except(KnownSettings));
// Print leveling data has no SliceSettingsWidget editor but should be removed on 'Reset to Defaults'
keysToRetain.Remove(SettingsKey.print_leveling_data);
keysToRetain.Remove(SettingsKey.print_leveling_enabled);
// Iterate all items that have .ShowAsOverride = false and conditionally add to the retention list
foreach (var item in SettingsOrganizer.SettingsData.Values.Where(settingsItem => settingsItem.ShowAsOverride == false))
{
switch (item.SlicerConfigName)
{
case SettingsKey.baud_rate:
case SettingsKey.auto_connect:
// Items *should* reset to defaults
break;
default:
//Items should *not* reset to defaults
keysToRetain.Add(item.SlicerConfigName);
break;
}
}
var keysToRemove = (from keyValue in this.UserLayer
where !keysToRetain.Contains(keyValue.Key)
select keyValue.Key).ToList();
foreach (string key in keysToRemove)
{
this.UserLayer.Remove(key);
}
}
#region Migrate to LayeredProfile
static Dictionary<string, Type> expectedMappingTypes = new Dictionary<string, Type>()
{
[SettingsKey.extruders_share_temperature] = typeof(int),
[SettingsKey.extruders_share_temperature] = typeof(bool),
[SettingsKey.has_heated_bed] = typeof(bool),
[SettingsKey.nozzle_diameter] = typeof(double),
[SettingsKey.bed_temperature] = typeof(double),
};
void ValidateType<T>(string settingsKey)
{
if (expectedMappingTypes.ContainsKey(settingsKey))
{
if (expectedMappingTypes[settingsKey] != typeof(T))
{
throw new Exception("You must request the correct type of this settingsKey.");
}
}
if (settingsKey.Contains("%"))
{
if (typeof(T) != typeof(double))
{
throw new Exception("To get processing of a % you must request the type as double.");
}
}
}
///<summary>
///Returns the first matching value discovered while enumerating the settings layers
///</summary>
public T GetValue<T>(string settingsKey) where T : IConvertible
{
#if DEBUG
ValidateType<T>(settingsKey);
#endif
if (typeof(T) == typeof(string))
{
// this way we can use the common pattern without error
return (T)(object)this.GetValue(settingsKey);
}
else if(typeof(T) == typeof(LevelingSystem))
{
switch(this.GetValue(settingsKey))
{
case "3 Point Plane":
return (T)(object)(LevelingSystem.Probe3Points);
case "7 Point Disk":
return (T)(object)(LevelingSystem.Probe7PointRadial);
case "13 Point Disk":
return (T)(object)(LevelingSystem.Probe13PointRadial);
case "100 Point Disk":
return (T)(object)(LevelingSystem.Probe100PointRadial);
case "3x3 Mesh":
return (T)(object)(LevelingSystem.Probe3x3Mesh);
case "5x5 Mesh":
return (T)(object)(LevelingSystem.Probe5x5Mesh);
case "10x10 Mesh":
return (T)(object)(LevelingSystem.Probe10x10Mesh);
case "Custom Points":
return (T)(object)(LevelingSystem.ProbeCustom);
default:
#if DEBUG
throw new NotImplementedException();
#else
break;
#endif
}
return (T)(object)(LevelingSystem.Probe3Points);
}
else if (typeof(T) == typeof(bool))
{
return (T)(object)(this.GetValue(settingsKey) == "1");
}
else if (typeof(T) == typeof(int))
{
int result;
int.TryParse(this.GetValue(settingsKey), out result);
return (T)(object)(result);
}
else if (typeof(T) == typeof(Vector2))
{
string[] twoValues = GetValue(settingsKey).Split(',');
if (twoValues.Length != 2)
{
throw new Exception("Not parsing {0} as a Vector2".FormatWith(settingsKey));
}
Vector2 valueAsVector2 = new Vector2();
valueAsVector2.X = Helpers.ParseDouble(twoValues[0]);
valueAsVector2.Y = Helpers.ParseDouble(twoValues[1]);
return (T)(object)(valueAsVector2);
}
else if (typeof(T) == typeof(double))
{
string settingsStringh = GetValue(settingsKey);
if (settingsStringh.Contains("%"))
{
string onlyNumber = settingsStringh.Replace("%", "");
double ratio = Helpers.ParseDouble(onlyNumber) / 100;
if (settingsKey == SettingsKey.first_layer_height)
{
return (T)(object)(GetValue<double>(SettingsKey.layer_height) * ratio);
}
else if (settingsKey == SettingsKey.first_layer_extrusion_width
|| settingsKey == SettingsKey.external_perimeter_extrusion_width)
{
return (T)(object)(GetValue<double>(SettingsKey.nozzle_diameter) * ratio);
}
return (T)(object)(ratio);
}
else if (settingsKey == SettingsKey.first_layer_extrusion_width
|| settingsKey == SettingsKey.external_perimeter_extrusion_width)
{
double extrusionResult;
double.TryParse(this.GetValue(settingsKey), out extrusionResult);
return (T)(object)(extrusionResult == 0 ? GetValue<double>(SettingsKey.nozzle_diameter) : extrusionResult);
}
if (settingsKey == SettingsKey.bed_temperature
&& !this.GetValue<bool>(SettingsKey.has_heated_bed))
{
return (T)Convert.ChangeType(0, typeof(double));
}
double result;
double.TryParse(this.GetValue(settingsKey), out result);
return (T)(object)(result);
}
else if (typeof(T) == typeof(BedShape))
{
switch (GetValue(settingsKey))
{
case "rectangular":
return (T)(object)BedShape.Rectangular;
case "circular":
return (T)(object)BedShape.Circular;
default:
#if DEBUG
throw new NotImplementedException("{0} is not a known bed_shape.".FormatWith(GetValue(SettingsKey.bed_shape)));
#else
return (T)(object)BedShape.Rectangular;
#endif
}
}
return (T)default(T);
}
/// <summary>
/// Returns whether or not the setting is overridden by the active layer
/// </summary>
public bool SettingExistsInLayer(string sliceSetting, NamedSettingsLayers layer)
{
switch (layer)
{
case NamedSettingsLayers.Quality:
return QualityLayer?.ContainsKey(sliceSetting) == true;
case NamedSettingsLayers.Material:
return MaterialLayer?.ContainsKey(sliceSetting) == true;
case NamedSettingsLayers.User:
return UserLayer?.ContainsKey(sliceSetting) == true;
default:
return false;
}
}
public long GetLongHashCode()
{
var bigStringForHashCode = new StringBuilder();
foreach (var keyValue in this.BaseLayer)
{
// Add key/value to accumulating string for hash
SliceSettingData data = SettingsOrganizer.Instance.GetSettingsData(keyValue.Key);
if (data?.RebuildGCodeOnChange == true)
{
bigStringForHashCode.Append(keyValue.Key);
bigStringForHashCode.Append(this.GetValue(keyValue.Key));
}
}
return agg_basics.ComputeHash(bigStringForHashCode.ToString());
}
#endregion
private static HashSet<string> knownSettings;
[JsonIgnore]
public static HashSet<string> KnownSettings
{
get
{
if (knownSettings == null)
{
knownSettings = LoadSettingsNamesFromPropertiesJson();
}
return knownSettings;
}
}
private static HashSet<string> LoadSettingsNamesFromPropertiesJson()
{
string propertiesJson = AggContext.StaticData.ReadAllText(Path.Combine("SliceSettings", "Properties.json"));
var settingsData = JArray.Parse(propertiesJson);
return new HashSet<string>(settingsData.Select(s => s["SlicerConfigName"].Value<string>()));
}
public void SetValue(string settingsKey, string settingsValue, PrinterSettingsLayer layer = null)
{
// Stash user overrides if a non-user override is being set
if (layer != null && layer != UserLayer)
{
StashUserOverride(layer, settingsKey);
}
else
{
// Remove any staged/conflicting user override, making this the new and active user override
if (StagedUserSettings.ContainsKey(settingsKey))
{
StagedUserSettings.Remove(settingsKey);
}
}
var persistenceLayer = layer ?? UserLayer;
// If the setting exists and is set to the requested value, exit without setting or saving
string existingValue;
if (persistenceLayer.TryGetValue(settingsKey, out existingValue) && existingValue == settingsValue)
{
return;
}
// Otherwise, set and save
persistenceLayer[settingsKey] = settingsValue;
this.OnSettingChanged(settingsKey);
}
public string ToJson()
{
return JsonConvert.SerializeObject(this, Formatting.Indented);
}
internal void ClearValue(string settingsKey, PrinterSettingsLayer layer = null)
{
var persistenceLayer = layer ?? UserLayer;
if (persistenceLayer.ContainsKey(settingsKey))
{
persistenceLayer.Remove(settingsKey);
// Restore user overrides if a non-user override is being cleared
if (layer != null && layer != UserLayer)
{
RestoreUserOverride(layer, settingsKey);
}
if (SettingsOrganizer.SettingsData.TryGetValue(settingsKey, out SliceSettingData settingData))
{
if (settingData.DataEditType == SliceSettingData.DataEditTypes.CHECK_BOX)
{
string checkedKey = this.GetValue<bool>(settingsKey) ? "OnValue" : "OffValue";
// Linked settings should be updated in all cases (user clicked checkbox, user clicked clear)
foreach (var setSettingsData in settingData.SetSettingsOnChange)
{
if (setSettingsData.TryGetValue(checkedKey, out string targetValue))
{
if (this.GetValue(setSettingsData["TargetSetting"]) != targetValue)
{
this.SetValue(setSettingsData["TargetSetting"], targetValue);
}
}
}
}
}
this.OnSettingChanged(settingsKey);
}
}
}
}

View file

@ -1,166 +0,0 @@
/*
Copyright (c) 2018, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace MatterHackers.MatterControl.SlicerConfiguration
{
using SettingsDictionary = Dictionary<string, string>;
public class PrinterSettingsLayer : SettingsDictionary
{
public PrinterSettingsLayer() { }
public PrinterSettingsLayer(Dictionary<string, string> settingsDictionary)
{
foreach(var keyValue in settingsDictionary)
{
this[keyValue.Key] = keyValue.Value;
}
}
public string LayerID
{
get
{
string layerKey = ValueOrDefault("layer_id");
if (string.IsNullOrEmpty(layerKey))
{
// Generate a new GUID when missing or empty. We can't do this in the constructor as the dictionary deserialization will fail if
// an existing key exists for layer_id and on new empty layers, we still need to construct an initial identifier.
layerKey = Guid.NewGuid().ToString();
LayerID = layerKey;
}
return layerKey;
}
set
{
this["layer_id"] = value;
}
}
public string Name
{
get
{
return ValueOrDefault(SettingsKey.layer_name);
}
set
{
this[SettingsKey.layer_name] = value;
}
}
public string Source
{
get
{
return ValueOrDefault("layer_source");
}
set
{
this["layer_source"] = value;
}
}
public string ETag
{
get
{
return ValueOrDefault("layer_etag");
}
set
{
this["layer_etag"] = value;
}
}
public string ValueOrDefault(string key, string defaultValue = "")
{
string foundValue;
this.TryGetValue(key, out foundValue);
return foundValue ?? defaultValue;
}
public static PrinterSettingsLayer LoadFromIni(TextReader reader)
{
var layer = new PrinterSettingsLayer();
string line;
while ((line = reader.ReadLine()) != null)
{
var segments = line.Split('=');
if (!line.StartsWith("#") && !string.IsNullOrEmpty(line))
{
string key = segments[0].Trim();
layer[key] = segments[1].Trim();
}
}
return layer;
}
public static PrinterSettingsLayer LoadFromIni(string filePath)
{
var settings = from line in File.ReadAllLines(filePath)
let segments = line.Split('=')
where !line.StartsWith("#") && !string.IsNullOrEmpty(line) && segments.Length == 2
select new
{
Key = segments[0].Trim(),
Value = segments[1].Trim()
};
var layer = new PrinterSettingsLayer();
foreach (var setting in settings)
{
layer[setting.Key] = setting.Value;
}
return layer;
}
public PrinterSettingsLayer Clone()
{
string id = Guid.NewGuid().ToString();
return new PrinterSettingsLayer(this as Dictionary<string, string>)
{
LayerID = id,
Name = this.Name,
ETag = this.ETag,
Source = this.Source
};
}
}
}

View file

@ -1,119 +0,0 @@
/*
Copyright (c) 2016, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System;
using System.IO;
using Newtonsoft.Json.Linq;
using System.Text;
namespace MatterHackers.MatterControl.SlicerConfiguration
{
public static class ProfileMigrations
{
public static string MigrateDocument(string filePath, int fromVersion = -1)
{
var jObject = JObject.Parse(File.ReadAllText(filePath));
/*
if (fromVersion < 201605131)
{
var materialLayers = jObject["MaterialLayers"] as JObject;
if (materialLayers != null)
{
foreach (JProperty layer in materialLayers.Properties().ToList())
{
layer.Remove();
string layerID = Guid.NewGuid().ToString();
var body = layer.Value as JObject;
body["MatterControl.LayerID"] = layerID;
body["MatterControl.LayerName"] = layer.Name;
materialLayers[layerID] = layer.Value;
}
}
var qualityLayers = jObject["QualityLayers"] as JObject;
if (qualityLayers != null)
{
foreach (JProperty layer in qualityLayers.Properties().ToList())
{
layer.Remove();
string layerID = Guid.NewGuid().ToString();
var body = layer.Value as JObject;
body["MatterControl.LayerID"] = layerID;
body["MatterControl.LayerName"] = layer.Name;
qualityLayers[layerID] = layer.Value;
}
}
jObject["DocumentVersion"] = 201605131;
}
if (fromVersion < 201605132)
{
string printerID = Guid.NewGuid().ToString();
jObject.Remove("DocumentPath");
jObject["ID"] = printerID;
jObject["DocumentVersion"] = 201605132;
File.Delete(filePath);
filePath = Path.Combine(Path.GetDirectoryName(filePath), printerID + ProfileManager.ProfileExtension);
}
*/
if (fromVersion < 201606271)
{
JObject oemProfile = jObject["OemProfile"] as JObject;
if (oemProfile != null)
{
jObject.Property("OemProfile").Remove();
jObject["OemLayer"] = oemProfile["OemLayer"];
}
jObject["DocumentVersion"] = 201606271;
}
File.WriteAllText(
filePath,
JsonConvert.SerializeObject(jObject, Formatting.Indented));
return filePath;
}
}
}

View file

@ -1,251 +0,0 @@
/*
Copyright (c) 2018, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using MatterHackers.VectorMath;
using Newtonsoft.Json;
namespace MatterHackers.MatterControl.SlicerConfiguration
{
public class SettingsHelpers
{
private PrinterSettings printerSettings;
public SettingsHelpers(PrinterSettings printerSettings)
{
this.printerSettings = printerSettings;
}
public double ExtruderTemperature(int extruderIndex)
{
if (extruderIndex == 0)
{
return printerSettings.GetValue<double>(SettingsKey.temperature);
}
else
{
// Check if there is a material override for this extruder
// Otherwise, use the SettingsLayers that is bound to this extruder
if (extruderIndex < printerSettings.GetValue<int>(SettingsKey.extruder_count))
{
return printerSettings.GetValue<double>($"{SettingsKey.temperature}{extruderIndex}");
}
// else return the normal settings cascade
return printerSettings.GetValue<double>(SettingsKey.temperature);
}
}
public int[] LayerToPauseOn()
{
string[] userValues = printerSettings.GetValue("layer_to_pause").Split(';');
int temp;
return userValues.Where(v => int.TryParse(v, out temp)).Select(v =>
{
//Convert from 0 based index to 1 based index
int val = int.Parse(v);
// Special case for user entered zero that pushes 0 to 1, otherwise val = val - 1 for 1 based index
return val == 0 ? 1 : val - 1;
}).ToArray();
}
internal double ParseDouble(string firstLayerValueString)
{
double firstLayerValue;
if (!double.TryParse(firstLayerValueString, out firstLayerValue))
{
throw new Exception(string.Format("Format cannot be parsed. FirstLayerHeight '{0}'", firstLayerValueString));
}
return firstLayerValue;
}
public void SetBaudRate(string baudRate)
{
printerSettings.SetValue(SettingsKey.baud_rate, baudRate);
}
public string ComPort()
{
return printerSettings.GetValue($"{Environment.MachineName}_com_port");
}
public void SetComPort(string port)
{
printerSettings.SetValue($"{Environment.MachineName}_com_port", port);
}
public void SetComPort(string port, PrinterSettingsLayer layer)
{
printerSettings.SetValue($"{Environment.MachineName}_com_port", port, layer);
}
public void SetDriverType(string driver)
{
printerSettings.SetValue("driver_type", driver);
}
public void SetDeviceToken(string token)
{
if (printerSettings.GetValue(SettingsKey.device_token) != token)
{
printerSettings.SetValue(SettingsKey.device_token, token);
}
}
public void SetName(string name)
{
printerSettings.SetValue(SettingsKey.printer_name, name);
}
public PrintLevelingData GetPrintLevelingData()
{
PrintLevelingData printLevelingData = null;
var jsonData = printerSettings.GetValue(SettingsKey.print_leveling_data);
if (!string.IsNullOrEmpty(jsonData))
{
printLevelingData = JsonConvert.DeserializeObject<PrintLevelingData>(jsonData);
}
// if it is still null
if (printLevelingData == null)
{
printLevelingData = new PrintLevelingData();
}
return printLevelingData;
}
public void SetPrintLevelingData(PrintLevelingData data, bool clearUserZOffset)
{
if (clearUserZOffset)
{
printerSettings.SetValue(SettingsKey.baby_step_z_offset, "0");
}
printerSettings.SetValue(SettingsKey.print_leveling_data, JsonConvert.SerializeObject(data));
}
public void DoPrintLeveling(bool doLeveling)
{
// Early exit if already set
if (doLeveling == printerSettings.GetValue<bool>(SettingsKey.print_leveling_enabled))
{
return;
}
printerSettings.SetValue(SettingsKey.print_leveling_enabled, doLeveling ? "1" : "0");
printerSettings.OnPrintLevelingEnabledChanged(this, null);
}
public Vector2 ExtruderOffset(int extruderIndex)
{
string currentOffsets = printerSettings.GetValue("extruder_offset");
string[] offsets = currentOffsets.Split(',');
int count = 0;
foreach (string offset in offsets)
{
if (count == extruderIndex)
{
string[] xy = offset.Split('x');
return new Vector2(double.Parse(xy[0]), double.Parse(xy[1]));
}
count++;
}
return Vector2.Zero;
}
public void ExportAsCuraConfig()
{
throw new NotImplementedException();
}
public Vector3 ManualMovementSpeeds()
{
Vector3 feedRate = new Vector3(3000, 3000, 315);
string savedSettings = printerSettings.GetValue(SettingsKey.manual_movement_speeds);
if (!string.IsNullOrEmpty(savedSettings))
{
var segments = savedSettings.Split(',');
feedRate.X = double.Parse(segments[1]);
feedRate.Y = double.Parse(segments[3]);
feedRate.Z = double.Parse(segments[5]);
}
return feedRate;
}
public Dictionary<string, double> GetMovementSpeeds()
{
Dictionary<string, double> speeds = new Dictionary<string, double>();
string movementSpeedsString = GetMovementSpeedsString();
string[] allSpeeds = movementSpeedsString.Split(',');
for (int i = 0; i < allSpeeds.Length / 2; i++)
{
speeds.Add(allSpeeds[i * 2 + 0], double.Parse(allSpeeds[i * 2 + 1]));
}
return speeds;
}
public string GetMovementSpeedsString()
{
string presets = "x,3000,y,3000,z,315,e0,150"; // stored x,value,y,value,z,value,e1,value,e2,value,e3,value,...
string savedSettings = printerSettings.GetValue(SettingsKey.manual_movement_speeds);
if (!string.IsNullOrEmpty(savedSettings))
{
presets = savedSettings;
}
return presets;
}
public int NumberOfHotends()
{
if (printerSettings.GetValue<bool>(SettingsKey.extruders_share_temperature))
{
return 1;
}
return printerSettings.GetValue<int>(SettingsKey.extruder_count);
}
public bool UseZProbe()
{
return printerSettings.GetValue<bool>(SettingsKey.has_z_probe) && printerSettings.GetValue<bool>(SettingsKey.use_z_probe);
}
}
}

View file

@ -1,155 +0,0 @@
/*
Copyright (c) 2018, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
namespace MatterHackers.MatterControl.SlicerConfiguration
{
public static class SettingsKey
{
public const string active_quality_key = nameof(active_quality_key);
public const string active_material_key = nameof(active_material_key);
public const string auto_connect = nameof(auto_connect);
public const string auto_release_motors = nameof(auto_release_motors);
public const string baby_step_z_offset = nameof(baby_step_z_offset);
public const string backup_firmware_before_update = nameof(backup_firmware_before_update);
public const string baud_rate = nameof(baud_rate);
public const string bed_remove_part_temperature = nameof(bed_remove_part_temperature);
public const string bed_shape = nameof(bed_shape);
public const string bed_size = nameof(bed_size);
public const string bed_temperature = nameof(bed_temperature);
public const string build_height = nameof(build_height);
public const string calibration_files = nameof(calibration_files);
public const string cancel_gcode = nameof(cancel_gcode);
public const string com_port = nameof(com_port);
public const string connect_gcode = nameof(connect_gcode);
public const string created_date = nameof(created_date);
public const string default_material_presets = nameof(default_material_presets);
public const string device_token = nameof(device_token);
public const string device_type = nameof(device_type);
public const string enable_line_splitting = nameof(enable_line_splitting);
public const string enable_network_printing = nameof(enable_network_printing);
public const string enable_retractions = nameof(enable_retractions);
public const string enable_sailfish_communication = nameof(enable_sailfish_communication);
public const string end_gcode = nameof(end_gcode);
public const string expand_thin_walls = nameof(expand_thin_walls);
public const string external_perimeter_extrusion_width = nameof(external_perimeter_extrusion_width);
public const string extruder_count = nameof(extruder_count);
public const string extruders_share_temperature = nameof(extruders_share_temperature);
public const string extrusion_ratio = nameof(extrusion_ratio);
public const string feedrate_ratio = nameof(feedrate_ratio);
public const string filament_cost = nameof(filament_cost);
public const string filament_density = nameof(filament_density);
public const string filament_diameter = nameof(filament_diameter);
public const string filament_runout_sensor = nameof(filament_runout_sensor);
public const string fill_density = nameof(fill_density);
public const string fill_thin_gaps = nameof(fill_thin_gaps);
public const string first_layer_extrusion_width = nameof(first_layer_extrusion_width);
public const string first_layer_height = nameof(first_layer_height);
public const string first_layer_speed = nameof(first_layer_speed);
public const string g0 = nameof(g0);
public const string has_fan = nameof(has_fan);
public const string has_hardware_leveling = nameof(has_hardware_leveling);
public const string has_heated_bed = nameof(has_heated_bed);
public const string has_power_control = nameof(has_power_control);
public const string has_sd_card_reader = nameof(has_sd_card_reader);
public const string has_z_probe = nameof(has_z_probe);
public const string has_z_servo = nameof(has_z_servo);
public const string heat_extruder_before_homing = nameof(heat_extruder_before_homing);
public const string include_firmware_updater = nameof(include_firmware_updater);
public const string infill_overlap_perimeter = nameof(infill_overlap_perimeter);
public const string infill_type = nameof(infill_type);
public const string insert_filament_markdown2 = nameof(insert_filament_markdown2);
public const string ip_address = nameof(ip_address);
public const string ip_port = nameof(ip_port);
public const string jerk_velocity = nameof(jerk_velocity);
public const string print_time_estimate_multiplier = nameof(print_time_estimate_multiplier);
public const string laser_speed_025 = nameof(laser_speed_025);
public const string laser_speed_100 = nameof(laser_speed_100);
public const string layer_gcode = nameof(layer_gcode);
public const string layer_height = nameof(layer_height);
public const string layer_name = nameof(layer_name);
public const string layer_to_pause = nameof(layer_to_pause);
public const string load_filament_length = nameof(load_filament_length);
public const string make = nameof(make);
public const string manual_movement_speeds = nameof(manual_movement_speeds);
public const string max_acceleration = nameof(max_acceleration);
public const string max_velocity = nameof(max_velocity);
public const string merge_overlapping_lines = nameof(merge_overlapping_lines);
public const string min_fan_speed = nameof(min_fan_speed);
public const string max_fan_speed = nameof(max_fan_speed);
public const string model = nameof(model);
public const string nozzle_diameter = nameof(nozzle_diameter);
public const string number_of_first_layers = nameof(number_of_first_layers);
public const string oem_profile_token = nameof(oem_profile_token);
public const string pause_gcode = nameof(pause_gcode);
public const string perimeter_start_end_overlap = nameof(perimeter_start_end_overlap);
public const string print_center = nameof(print_center);
public const string print_leveling_data = nameof(print_leveling_data);
public const string print_leveling_enabled = nameof(print_leveling_enabled);
public const string print_leveling_probe_start = nameof(print_leveling_probe_start);
public const string probe_has_been_calibrated = nameof(probe_has_been_calibrated);
public const string print_leveling_required_to_print = nameof(print_leveling_required_to_print);
public const string print_leveling_solution = nameof(print_leveling_solution);
public const string leveling_sample_points = nameof(leveling_sample_points);
public const string load_filament_speed = nameof(load_filament_speed);
public const string probe_offset_sample_point = nameof(probe_offset_sample_point);
public const string printer_name = nameof(printer_name);
public const string progress_reporting = nameof(progress_reporting);
public const string publish_bed_image = nameof(publish_bed_image);
public const string read_regex = nameof(read_regex);
public const string recover_first_layer_speed = nameof(recover_first_layer_speed);
public const string recover_is_enabled = nameof(recover_is_enabled);
public const string recover_position_before_z_home = nameof(recover_position_before_z_home);
public const string resume_gcode = nameof(resume_gcode);
public const string running_clean_markdown2 = nameof(running_clean_markdown2);
public const string selector_ip_address = nameof(selector_ip_address);
public const string send_with_checksum = nameof(send_with_checksum);
public const string filament_has_been_loaded = nameof(filament_has_been_loaded);
public const string show_reset_connection = nameof(show_reset_connection);
public const string sla_printer = nameof(sla_printer);
public const string spiral_vase = nameof(spiral_vase);
public const string start_gcode = nameof(start_gcode);
public const string temperature = nameof(temperature);
public const string temperature1 = nameof(temperature1);
public const string temperature2 = nameof(temperature2);
public const string temperature3 = nameof(temperature3);
public const string top_solid_infill_speed = nameof(top_solid_infill_speed);
public const string trim_filament_markdown = nameof(trim_filament_markdown);
public const string unload_filament_length = nameof(unload_filament_length);
public const string use_z_probe = nameof(use_z_probe);
public const string validate_layer_height = nameof(validate_layer_height);
public const string windows_driver = nameof(windows_driver);
public const string write_regex = nameof(write_regex);
public const string z_homes_to_max = nameof(z_homes_to_max);
public const string z_probe_samples = nameof(z_probe_samples);
public const string z_probe_xy_offset = nameof(z_probe_xy_offset);
public const string z_probe_z_offset = nameof(z_probe_z_offset);
public const string z_servo_depolyed_angle = nameof(z_servo_depolyed_angle);
public const string z_servo_retracted_angle = nameof(z_servo_retracted_angle);
}
}