Put in improved terminal filtering

This commit is contained in:
Lars Brubaker 2019-03-25 14:23:45 -07:00 committed by LarsBrubaker
parent 2cb8d521af
commit e7fe7bb8da
9 changed files with 269 additions and 145 deletions

View file

@ -127,9 +127,14 @@ namespace MatterControl.Printing
}
public static bool GetFirstNumberAfter(string stringToCheckAfter, string stringWithNumber, ref int readValue, int startIndex = 0, string stopCheckingString = ";")
{
return GetFirstNumberAfter(stringToCheckAfter, stringWithNumber, ref readValue, out _, startIndex, stopCheckingString);
}
public static bool GetFirstNumberAfter(string stringToCheckAfter, string stringWithNumber, ref int readValue, out int numberEnd, int startIndex = 0, string stopCheckingString = ";")
{
double doubleValue = readValue;
if(GetFirstNumberAfter(stringToCheckAfter, stringWithNumber, ref doubleValue, startIndex, stopCheckingString))
if(GetFirstNumberAfter(stringToCheckAfter, stringWithNumber, ref doubleValue, out numberEnd, startIndex, stopCheckingString))
{
readValue = (int)doubleValue;
return true;
@ -139,6 +144,11 @@ namespace MatterControl.Printing
}
public static bool GetFirstNumberAfter(string stringToCheckAfter, string stringWithNumber, ref double readValue, int startIndex = 0, string stopCheckingString = ";")
{
return GetFirstNumberAfter(stringToCheckAfter, stringWithNumber, ref readValue, out _, startIndex, stopCheckingString);
}
public static bool GetFirstNumberAfter(string stringToCheckAfter, string stringWithNumber, ref double readValue, out int numberEnd, int startIndex = 0, string stopCheckingString = ";")
{
int stringPos = stringWithNumber.IndexOf(stringToCheckAfter, Math.Min(stringWithNumber.Length, startIndex));
int stopPos = stringWithNumber.IndexOf(stopCheckingString);
@ -147,10 +157,12 @@ namespace MatterControl.Printing
{
stringPos += stringToCheckAfter.Length;
readValue = agg_basics.ParseDouble(stringWithNumber, ref stringPos, true);
numberEnd = stringPos;
return true;
}
numberEnd = -1;
return false;
}

View file

@ -1964,34 +1964,37 @@ You will then need to logout and log back in to the computer for the changes to
case CommunicationStates.PreparingToPrint:
{
string filePath = this.Printer.Bed.EditContext.SourceFilePath;
string fileName = Path.GetFileName(filePath);
var activePrintItem = new PrintItemWrapper(new PrintItem(fileName, filePath));
if (activePrintItem.PrintItem.Id == 0)
if (gcodeFileNameForTask != null)
{
activePrintItem.PrintItem.Commit();
}
string filePath = this.Printer.Bed.EditContext.SourceFilePath;
string fileName = Path.GetFileName(filePath);
if (gcodeFileNameForTask !=null
&& activePrintTask == null
&& allowRecovery)
{
// TODO: Fix printerItemID int requirement
activePrintTask = new PrintTask
var activePrintItem = new PrintItemWrapper(new PrintItem(fileName, filePath));
if (activePrintItem.PrintItem.Id == 0)
{
PrintStart = DateTime.Now,
PrinterId = this.Printer.Settings.ID.GetHashCode(),
PrintName = activePrintItem.PrintItem.Name,
PrintItemId = activePrintItem.PrintItem.Id,
PrintingGCodeFileName = gcodeFileNameForTask,
PrintComplete = false
};
activePrintItem.PrintItem.Commit();
}
activePrintTask.Commit();
if (gcodeFileNameForTask != null
&& activePrintTask == null
&& allowRecovery)
{
// TODO: Fix printerItemID int requirement
activePrintTask = new PrintTask
{
PrintStart = DateTime.Now,
PrinterId = this.Printer.Settings.ID.GetHashCode(),
PrintName = activePrintItem.PrintItem.Name,
PrintItemId = activePrintItem.PrintItem.Id,
PrintingGCodeFileName = gcodeFileNameForTask,
PrintComplete = false
};
Task.Run(() => this.SyncProgressToDB(printingCancellation.Token)).ConfigureAwait(false);
activePrintTask.Commit();
Task.Run(() => this.SyncProgressToDB(printingCancellation.Token)).ConfigureAwait(false);
}
}
}

View file

@ -39,9 +39,9 @@ namespace MatterHackers.MatterControl
{
private static readonly bool Is32Bit = IntPtr.Size == 4;
public List<string> PrinterLines = new List<string>();
public List<(string line, bool output)> PrinterLines = new List<(string line, bool output)>();
public RootedObjectEventHandler HasChanged = new RootedObjectEventHandler();
public event EventHandler<(string line, bool output)> HasChanged;
private int maxLinesToBuffer = int.MaxValue - 1;
public TerminalLog(PrinterConnection printerConnection)
@ -59,9 +59,9 @@ namespace MatterHackers.MatterControl
}
}
private void OnHasChanged(EventArgs e)
private void OnHasChanged((string line, bool output) lineData)
{
HasChanged.CallEvents(this, e);
HasChanged?.Invoke(this, lineData);
if (PrinterLines.Count > maxLinesToBuffer)
{
Clear();
@ -70,25 +70,30 @@ namespace MatterHackers.MatterControl
private void Printer_LineReceived(object sender, string line)
{
PrinterLines.Add(line);
OnHasChanged(new StringEventArgs("<-" + line));
PrinterLines.Add((line, false));
OnHasChanged((line, false));
}
private void Printer_LineSent(object sender, string line)
{
PrinterLines.Add(line);
OnHasChanged(new StringEventArgs("->" + line));
PrinterLines.Add((line, true));
OnHasChanged((line, true));
}
public void WriteLine(string line)
{
PrinterLines.Add(line);
OnHasChanged(new StringEventArgs(line));
this.WriteLine((line, true));
}
public void WriteLine((string line, bool output) lineData)
{
PrinterLines.Add(lineData);
OnHasChanged(lineData);
}
private void Instance_ConnectionFailed(object sender, EventArgs e)
{
OnHasChanged(null);
OnHasChanged((null, true));
if (e is ConnectFailedEventArgs args)
{
@ -113,12 +118,12 @@ namespace MatterHackers.MatterControl
break;
}
PrinterLines.Add("Connection Failed".Localize() + ": " + message);
PrinterLines.Add(("Connection Failed".Localize() + ": " + message, true));
}
StringEventArgs eventArgs = new StringEventArgs("Lost connection to printer.");
PrinterLines.Add(eventArgs.Data);
OnHasChanged(eventArgs);
PrinterLines.Add((eventArgs.Data, true));
OnHasChanged((eventArgs.Data, true));
}
public void Clear()
@ -128,7 +133,7 @@ namespace MatterHackers.MatterControl
PrinterLines.Clear();
}
OnHasChanged(null);
OnHasChanged((null, true));
}
}
}

View file

@ -30,21 +30,27 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using MatterControl.Printing;
using MatterHackers.Agg;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.PartPreviewWindow;
namespace MatterHackers.MatterControl
{
public class TerminalWidget : FlowLayoutWidget, ICloseableTab
{
private CheckBox filterOutput;
private CheckBox autoUppercase;
private MHTextEditWidget manualCommandTextEdit;
private TextScrollWidget textScrollWidget;
private PrinterConfig printer;
private string writeFailedWaring = "WARNING: Write Failed!".Localize();
private string cantAccessPath = "Can't access '{0}'.".Localize();
private List<string> commandHistory = new List<string>();
private int commandHistoryIndex = 0;
public TerminalWidget(PrinterConfig printer, ThemeConfig theme)
: base(FlowDirection.TopToBottom)
@ -61,32 +67,14 @@ namespace MatterHackers.MatterControl
};
this.AddChild(headerRow);
filterOutput = new CheckBox("Filter Output".Localize(), textSize: theme.DefaultFontSize)
{
TextColor = theme.TextColor,
VAnchor = VAnchor.Bottom,
};
filterOutput.CheckedStateChanged += (s, e) =>
{
if (filterOutput.Checked)
{
textScrollWidget.SetLineStartFilter(new string[] { "<-wait", "<-ok", "<-T" });
}
else
{
textScrollWidget.SetLineStartFilter(null);
}
UserSettings.Instance.Fields.SetBool(UserSettingsKey.TerminalFilterOutput, filterOutput.Checked);
};
headerRow.AddChild(filterOutput);
headerRow.AddChild(CreateFilterOptions(theme));
autoUppercase = new CheckBox("Auto Uppercase".Localize(), textSize: theme.DefaultFontSize)
{
Margin = new BorderDouble(left: 25),
Checked = UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalAutoUppercase, true),
TextColor = theme.TextColor,
VAnchor = VAnchor.Bottom
VAnchor = VAnchor.Center
};
autoUppercase.CheckedStateChanged += (s, e) =>
{
@ -120,6 +108,72 @@ namespace MatterHackers.MatterControl
Margin = 0
});
textScrollWidget.LineFilterFunction = lineData =>
{
var line = lineData.line;
var lineWithoutChecksum = line;
var outputLine = line;
if (lineWithoutChecksum.StartsWith("N"))
{
int lineNumber = 0;
if (GCodeFile.GetFirstNumberAfter("N", lineWithoutChecksum, ref lineNumber, out int numberEnd))
{
lineWithoutChecksum = lineWithoutChecksum.Substring(numberEnd).Trim();
int checksumStart = lineWithoutChecksum.IndexOf('*');
if (checksumStart != -1)
{
lineWithoutChecksum = lineWithoutChecksum.Substring(0, checksumStart);
// and set this as the output if desired
if(!UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowChecksum, true))
{
outputLine = lineWithoutChecksum;
}
}
}
}
if (lineWithoutChecksum.StartsWith("ok")
&& !UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowOks, true))
{
return null;
}
else if (lineWithoutChecksum.StartsWith("M105")
&& !UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowTempRequests, true))
{
return null;
}
else if ((lineWithoutChecksum.StartsWith("G0 ") || lineWithoutChecksum.StartsWith("G1 "))
&& !UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowMovementRequests, true))
{
return null;
}
else if (( lineWithoutChecksum.StartsWith("T") || lineWithoutChecksum.StartsWith("ok T"))
&& !UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowTempResponse, true))
{
return null;
}
else if (lineWithoutChecksum.StartsWith("wait")
&& !UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowWaitResponse, true))
{
return null;
}
if (UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowInputOutputMarks, true))
{
if (lineData.output)
{
outputLine = "->" + outputLine;
}
else
{
outputLine = "<-" + outputLine;
}
}
return outputLine;
};
// Input Row
var inputRow = new FlowLayoutWidget(FlowDirection.LeftToRight)
{
@ -228,10 +282,10 @@ namespace MatterHackers.MatterControl
{
Debug.Print(ex.Message);
printer.Connection.TerminalLog.PrinterLines.Add("");
printer.Connection.TerminalLog.PrinterLines.Add(writeFaildeWaring);
printer.Connection.TerminalLog.PrinterLines.Add(cantAccessPath.FormatWith(filePathToSave));
printer.Connection.TerminalLog.PrinterLines.Add("");
printer.Connection.TerminalLog.PrinterLines.Add(("", true));
printer.Connection.TerminalLog.PrinterLines.Add((writeFailedWaring, true));
printer.Connection.TerminalLog.PrinterLines.Add((cantAccessPath.FormatWith(filePathToSave), true));
printer.Connection.TerminalLog.PrinterLines.Add(("", true));
UiThread.RunOnIdle(() =>
{
@ -250,20 +304,83 @@ namespace MatterHackers.MatterControl
this.AnchorAll();
}
#if !__ANDROID__
public override void OnLoad(EventArgs args)
private GuiWidget CreateFilterOptions(ThemeConfig theme)
{
filterOutput.Checked = UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalFilterOutput, false);
UiThread.RunOnIdle(manualCommandTextEdit.Focus);
base.OnLoad(args);
var filterOptionsButton = new PopupMenuButton("Filter Options", theme)
{
VAnchor = VAnchor.Center
};
var popupMenu = new PopupMenu(ApplicationController.Instance.MenuTheme);
filterOptionsButton.PopupContent = popupMenu;
// put in options for filtering various output
popupMenu.CreateBoolMenuItem(
"Show 'Ok' response".Localize(),
() => UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowOks, true),
(isChecked) =>
{
UserSettings.Instance.Fields.SetBool(UserSettingsKey.TerminalShowOks, isChecked);
textScrollWidget.RebuildFilteredList();
});
popupMenu.CreateBoolMenuItem(
"Show Checksum".Localize(),
() => UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowChecksum, true),
(isChecked) =>
{
UserSettings.Instance.Fields.SetBool(UserSettingsKey.TerminalShowChecksum, isChecked);
textScrollWidget.RebuildFilteredList();
});
popupMenu.CreateBoolMenuItem(
"Show In / Out Indicators".Localize(),
() => UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowInputOutputMarks, true),
(isChecked) =>
{
UserSettings.Instance.Fields.SetBool(UserSettingsKey.TerminalShowInputOutputMarks, isChecked);
textScrollWidget.RebuildFilteredList();
});
popupMenu.CreateBoolMenuItem(
"Show Temperature Requests".Localize(),
() => UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowTempRequests, true),
(isChecked) =>
{
UserSettings.Instance.Fields.SetBool(UserSettingsKey.TerminalShowTempRequests, isChecked);
textScrollWidget.RebuildFilteredList();
});
popupMenu.CreateBoolMenuItem(
"Show Movement Requests".Localize(),
() => UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowMovementRequests, true),
(isChecked) =>
{
UserSettings.Instance.Fields.SetBool(UserSettingsKey.TerminalShowMovementRequests, isChecked);
textScrollWidget.RebuildFilteredList();
});
popupMenu.CreateBoolMenuItem(
"Show Temperature Responses".Localize(),
() => UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowTempResponse, true),
(isChecked) =>
{
UserSettings.Instance.Fields.SetBool(UserSettingsKey.TerminalShowTempResponse, isChecked);
textScrollWidget.RebuildFilteredList();
});
popupMenu.CreateBoolMenuItem(
"Show Wait Responses".Localize(),
() => UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowWaitResponse, true),
(isChecked) =>
{
UserSettings.Instance.Fields.SetBool(UserSettingsKey.TerminalShowWaitResponse, isChecked);
textScrollWidget.RebuildFilteredList();
});
return filterOptionsButton;
}
#endif
string writeFaildeWaring = "WARNING: Write Failed!".Localize();
string cantAccessPath = "Can't access '{0}'.".Localize();
private List<string> commandHistory = new List<string>();
private int commandHistoryIndex = 0;
private void SendManualCommand()
{
@ -278,4 +395,4 @@ namespace MatterHackers.MatterControl
manualCommandTextEdit.Text = "";
}
}
}
}

View file

@ -29,6 +29,7 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.Collections.Generic;
using System.Linq;
using MatterHackers.Agg;
using MatterHackers.Agg.Font;
using MatterHackers.Agg.UI;
@ -40,14 +41,22 @@ namespace MatterHackers.MatterControl
{
object locker = new object();
private string[] StartLineStringFilters = null;
private Func<(string line, bool output), string> _lineFilterFunction;
public Func<(string line, bool output), string> LineFilterFunction
{
get => _lineFilterFunction;
set
{
_lineFilterFunction = value;
RebuildFilteredList();
}
}
private EventHandler unregisterEvents;
private List<string> allSourceLines;
private List<(string line, bool output)> allSourceLines;
private List<string> visibleLines;
private TypeFacePrinter printer = null;
private TypeFacePrinter typeFacePrinter = null;
private PrinterConfig printer = null;
public Color TextColor = new Color(102, 102, 102);
private int forceStartLine = -1;
@ -82,98 +91,69 @@ namespace MatterHackers.MatterControl
}
}
public int NumVisibleLines => (int)Math.Ceiling(Height / printer.TypeFaceStyle.EmSizeInPixels);
public int NumVisibleLines => (int)Math.Ceiling(Height / typeFacePrinter.TypeFaceStyle.EmSizeInPixels);
public TextScrollWidget(PrinterConfig printer, List<string> sourceLines)
public TextScrollWidget(PrinterConfig printer, List<(string line, bool output)> sourceLines)
{
this.printer = new TypeFacePrinter("", new StyledTypeFace(ApplicationController.GetTypeFace(NamedTypeFace.Liberation_Mono), 12));
this.printer.DrawFromHintedCache = true;
this.printer = printer;
printer.Connection.TerminalLog.HasChanged += RecievedNewLine;
this.typeFacePrinter = new TypeFacePrinter("", new StyledTypeFace(ApplicationController.GetTypeFace(NamedTypeFace.Liberation_Mono), 12));
this.typeFacePrinter.DrawFromHintedCache = true;
this.allSourceLines = sourceLines;
this.visibleLines = sourceLines;
printer.Connection.TerminalLog.HasChanged.RegisterEvent(RecievedNewLine, ref unregisterEvents);
this.visibleLines = sourceLines.Select(ld => ld.line).ToList();
}
private void ConditionalyAddToVisible(string line)
private void ConditionalyAddToVisible((string line, bool output) lineData)
{
if (StartLineStringFilters != null
&& StartLineStringFilters.Length > 0)
var line = lineData.line;
if (LineFilterFunction != null)
{
bool lineIsVisible = true;
foreach (string startFilter in StartLineStringFilters)
{
if (line == null
|| line.Contains("M105")
|| line.Length < 3
|| line.StartsWith(startFilter))
{
lineIsVisible = false;
break;
}
}
line = LineFilterFunction(lineData);
}
if (lineIsVisible)
{
visibleLines.Add(line);
}
if(!string.IsNullOrEmpty(line))
{
visibleLines.Add(line);
}
}
private void RecievedNewLine(object sender, EventArgs e)
private void RecievedNewLine(object sender, (string line, bool output) lineData)
{
var stringEvent = e as StringEventArgs;
if (stringEvent != null)
if (lineData.line != null)
{
ConditionalyAddToVisible(stringEvent.Data);
ConditionalyAddToVisible(lineData);
}
else // the list changed in some big way (probably cleared)
{
if (StartLineStringFilters != null
&& StartLineStringFilters.Length > 0)
{
CreateFilteredList();
}
RebuildFilteredList();
}
Invalidate();
}
private void CreateFilteredList()
public void RebuildFilteredList()
{
lock (locker)
{
visibleLines = new List<string>();
string[] allSourceLinesTemp = allSourceLines.ToArray();
foreach (string line in allSourceLinesTemp)
(string, bool)[] allSourceLinesTemp = allSourceLines.ToArray();
foreach (var lineData in allSourceLinesTemp)
{
ConditionalyAddToVisible(line);
ConditionalyAddToVisible(lineData);
}
}
}
public void SetLineStartFilter(string[] startLineStringsToFilter)
{
if (startLineStringsToFilter != null
&& startLineStringsToFilter.Length > 0)
{
StartLineStringFilters = startLineStringsToFilter;
CreateFilteredList();
}
else
{
visibleLines = allSourceLines;
}
}
public void WriteToFile(string filePath)
{
// Make a copy so we don't have it change while writing.
string[] allSourceLinesTemp = allSourceLines.ToArray();
string[] allSourceLinesTemp = allSourceLines.Select(ld => ld.line).ToArray();
System.IO.File.WriteAllLines(filePath, allSourceLinesTemp);
}
public override void OnClosed(EventArgs e)
{
unregisterEvents?.Invoke(this, null);
printer.Connection.TerminalLog.HasChanged -= RecievedNewLine;
base.OnClosed(e);
}
@ -183,7 +163,7 @@ namespace MatterHackers.MatterControl
int numLinesToDraw = NumVisibleLines;
double y = LocalBounds.Bottom + printer.TypeFaceStyle.EmSizeInPixels * numLinesToDraw;
double y = LocalBounds.Bottom + typeFacePrinter.TypeFaceStyle.EmSizeInPixels * numLinesToDraw;
lock (visibleLines)
{
lock (locker)
@ -210,13 +190,13 @@ namespace MatterHackers.MatterControl
{
if (visibleLines[lineIndex] != null)
{
printer.Text = visibleLines[lineIndex];
printer.Origin = new Vector2(Bounds.Left + 2, y);
printer.Render(graphics2D, TextColor);
typeFacePrinter.Text = visibleLines[lineIndex];
typeFacePrinter.Origin = new Vector2(Bounds.Left + 2, y);
typeFacePrinter.Render(graphics2D, TextColor);
}
}
y -= printer.TypeFaceStyle.EmSizeInPixels;
if (y < -printer.TypeFaceStyle.EmSizeInPixels)
y -= typeFacePrinter.TypeFaceStyle.EmSizeInPixels;
if (y < -typeFacePrinter.TypeFaceStyle.EmSizeInPixels)
{
break;
}

View file

@ -35,6 +35,13 @@ namespace MatterHackers.MatterControl
public const string GcodeViewerRenderRetractions = nameof(GcodeViewerRenderRetractions);
public const string GcodeViewerSimulateExtrusion = nameof(GcodeViewerSimulateExtrusion);
public const string GcodeViewerTransparentExtrusion = nameof(GcodeViewerTransparentExtrusion);
public const string TerminalShowInputOutputMarks = nameof(TerminalShowInputOutputMarks);
public const string TerminalShowChecksum = nameof(TerminalShowChecksum);
public const string TerminalShowOks = nameof(TerminalShowOks);
public const string TerminalShowMovementRequests = nameof(TerminalShowMovementRequests);
public const string TerminalShowTempRequests = nameof(TerminalShowTempRequests);
public const string TerminalShowTempResponse = nameof(TerminalShowTempResponse);
public const string TerminalShowWaitResponse = nameof(TerminalShowWaitResponse);
public const string Language = nameof(Language);
public const string LayerViewDefault = nameof(LayerViewDefault);
public const string LayerViewSyncToPrint = nameof(LayerViewSyncToPrint);
@ -66,7 +73,6 @@ namespace MatterHackers.MatterControl
public const string SnapGridDistance = nameof(SnapGridDistance);
public const string SoftwareLicenseAccepted = nameof(SoftwareLicenseAccepted);
public const string TerminalAutoUppercase = nameof(TerminalAutoUppercase);
public const string TerminalFilterOutput = nameof(TerminalFilterOutput);
public const string TerminalTabVisible = nameof(TerminalTabVisible);
public const string ThemeName = nameof(ThemeName);
public const string ThumbnailRenderingMode = nameof(ThumbnailRenderingMode);

@ -1 +1 @@
Subproject commit 30894e795b4db540e080a63855c577eabd8eb08e
Subproject commit 597d99742a190bb138d1f3be17c4c0d7488a6997

View file

@ -111,7 +111,7 @@ namespace MatterHackers.MatterControl.Tests.Automation
Assert.AreEqual(printer.Connection.CommunicationState, PrinterCommunication.CommunicationStates.Connected);
// Assert that two G28s were output to the terminal
int g28Count = printer.Connection.TerminalLog.PrinterLines.Where(line => line.Contains("G28")).Count();
int g28Count = printer.Connection.TerminalLog.PrinterLines.Where(lineData => lineData.line.Contains("G28")).Count();
Assert.AreEqual(2, g28Count, "The terminal log should contain one G28 from Start-GCode and one G28 from Cancel-GCode");
}

View file

@ -783,6 +783,7 @@ namespace MatterControl.Tests.MatterControl
// start a print
var inputStream = new MemoryStream(Encoding.ASCII.GetBytes(string.Join("\n", inputGCode)));
printer.Connection.CommunicationState = MatterHackers.MatterControl.PrinterCommunication.CommunicationStates.PreparingToPrint;
await printer.Connection.StartPrint(inputStream);
// wait for the print to finish (or 3 minutes to pass)