public GCodeRenderer(GCodeFile gCodeFileToDraw) { if (gCodeFileToDraw != null) { this.gCodeFileToDraw = gCodeFileToDraw; for (int i = 0; i < gCodeFileToDraw.NumChangesInZ; i++) { renderFeatures.Add(new List<RenderFeatureBase>()); } } }
public GCodeRenderer(GCodeFile gCodeFileToDraw) { if (gCodeFileToDraw != null) { this.gCodeFileToDraw = gCodeFileToDraw; if (gCodeFileToDraw is GCodeMemoryFile memoryFile) { this.ExtrusionColors = new ExtrusionColors(memoryFile.Speeds); } for (int i = 0; i < gCodeFileToDraw.LayerCount; i++) { renderFeatures.Add(new List <RenderFeatureBase>()); } } }
public void SetGCodeAfterLoad(GCodeFile loadedGCode) { this.loadedGCode = loadedGCode; if (loadedGCode == null) { TextWidget noGCodeLoaded = new TextWidget(string.Format("Not a valid GCode file.")); noGCodeLoaded.Margin = new BorderDouble(0, 0, 0, 0); noGCodeLoaded.VAnchor = Agg.UI.VAnchor.ParentCenter; noGCodeLoaded.HAnchor = Agg.UI.HAnchor.ParentCenter; this.AddChild(noGCodeLoaded); } else { SetInitalLayer(); CenterPartInView(); } }
public void ApplyLeveling(GCodeFile unleveledGCode) { for (int i = 0; i < unleveledGCode.LineCount; i++) { PrinterMachineInstruction instruction = unleveledGCode.Instruction(i); Vector3 currentDestination = instruction.Position; instruction.Line = ApplyLeveling(currentDestination, instruction.movementType, instruction.Line); } }
public static void ParseFileContents(object sender, DoWorkEventArgs doWorkEventArgs) { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; string gCodeString = (string)doWorkEventArgs.Argument; if (gCodeString == null) { return; } BackgroundWorker backgroundWorker = sender as BackgroundWorker; Stopwatch maxProgressReport = new Stopwatch(); maxProgressReport.Start(); PrinterMachineInstruction machineInstructionForLine = new PrinterMachineInstruction("None"); bool gcodeHasExplicitLayerChangeInfo = false; if (gCodeString.Contains("; LAYER:")) { gcodeHasExplicitLayerChangeInfo = true; } GCodeFile loadedGCodeFile = new GCodeFile(gcodeHasExplicitLayerChangeInfo); int crCount = CountNumLines(gCodeString); int lineIndex = 0; foreach (string outputString in CustomSplit(gCodeString, '\n')) { string lineString = outputString.Trim(); machineInstructionForLine = new PrinterMachineInstruction(lineString, machineInstructionForLine); // take off any comments before we check its length if (lineString.Length > 0) { switch (lineString[0]) { case 'M': loadedGCodeFile.ParseMLine(lineString, machineInstructionForLine); break; case 'G': loadedGCodeFile.ParseGLine(lineString, machineInstructionForLine); break; case ';': if (gcodeHasExplicitLayerChangeInfo && lineString.StartsWith("; LAYER:")) { loadedGCodeFile.IndexOfChangeInZ.Add(loadedGCodeFile.GCodeCommandQueue.Count); } if(lineString.StartsWith("; layerThickness")) { loadedGCodeFile.layerThickness = double.Parse(lineString.Split('=')[1]); } else if(lineString.StartsWith("; firstLayerThickness")) { loadedGCodeFile.firstLayerThickness = double.Parse(lineString.Split('=')[1]); } break; default: break; } } loadedGCodeFile.GCodeCommandQueue.Add(machineInstructionForLine); if (backgroundWorker != null) { if (backgroundWorker.CancellationPending) { return; } if (backgroundWorker.WorkerReportsProgress && maxProgressReport.ElapsedMilliseconds > 200) { backgroundWorker.ReportProgress(lineIndex * 100 / crCount / 2); maxProgressReport.Restart(); } } lineIndex++; } loadedGCodeFile.AnalyzeGCodeLines(backgroundWorker); doWorkEventArgs.Result = loadedGCodeFile; }
public void LoadInBackground(string gcodePathAndFileName) { this.FileNameAndPath = gcodePathAndFileName; backgroundWorker = new BackgroundWorker(); backgroundWorker.WorkerReportsProgress = true; backgroundWorker.WorkerSupportsCancellation = true; backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(initialLoading_ProgressChanged); backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(initialLoading_RunWorkerCompleted); loadedGCode = null; GCodeFile.LoadInBackground(backgroundWorker, gcodePathAndFileName); }
void CreateStreamProcessors(string gcodeFilename, bool recoveryEnabled) { totalGCodeStream?.Dispose(); GCodeStream firstStream = null; if (gcodeFilename != null) { loadedGCode = GCodeFile.Load(gcodeFilename); gCodeFileStream0 = new GCodeFileStream(loadedGCode); if (ActiveSliceSettings.Instance.GetValue<bool>(SettingsKey.recover_is_enabled) && activePrintTask != null) // We are resuming a failed print (do lots of interesting stuff). { pauseHandlingStream1 = new PauseHandlingStream(new PrintRecoveryStream(gCodeFileStream0, activePrintTask.PercentDone)); } else { pauseHandlingStream1 = new PauseHandlingStream(gCodeFileStream0); } firstStream = pauseHandlingStream1; } else { firstStream = new NotPrintingStream(); } queuedCommandStream2 = new QueuedCommandsStream(firstStream); relativeToAbsoluteStream3 = new RelativeToAbsoluteStream(queuedCommandStream2); printLevelingStream4 = new PrintLevelingStream(relativeToAbsoluteStream3, true); waitForTempStream5 = new WaitForTempStream(printLevelingStream4); babyStepsStream6 = new BabyStepsStream(waitForTempStream5); if (activePrintTask != null) { // make sure we are in the position we were when we stopped printing babyStepsStream6.Offset = new Vector3(activePrintTask.PrintingOffsetX, activePrintTask.PrintingOffsetY, activePrintTask.PrintingOffsetZ); } extrusionMultiplyerStream7 = new ExtrusionMultiplyerStream(babyStepsStream6); feedrateMultiplyerStream8 = new FeedRateMultiplyerStream(extrusionMultiplyerStream7); requestTemperaturesStream9 = new RequestTemperaturesStream(feedrateMultiplyerStream8); totalGCodeStream = requestTemperaturesStream9; }
public GCodeFileStream(GCodeFile fileStreaming, int startLine = 0) { this.fileStreaming = fileStreaming; printerCommandQueueLineIndex = startLine; }
void sliceItem_Done(object sender, EventArgs e) { PrintItemWrapper sliceItem = (PrintItemWrapper)sender; sliceItem.SlicingDone.UnregisterEvent(sliceItem_Done, ref unregisterEvents); sliceItem.SlicingOutputMessage.UnregisterEvent(printItemWrapper_SlicingOutputMessage, ref unregisterEvents); if (File.Exists(sliceItem.FileLocation)) { savedGCodeFileNames.Add(sliceItem.GetGCodePathAndFileName()); } itemCountBeingWorkedOn++; if (itemCountBeingWorkedOn < allFilesToExport.Count) { if (StartingNextPart != null) { StartingNextPart(this, new StringEventArgs(ItemNameBeingWorkedOn)); } } else { UpdatePartStatus(this, new StringEventArgs("Calculating Total cm3...")); if (savedGCodeFileNames.Count > 0) { double total = 0; foreach (string gcodeFileName in savedGCodeFileNames) { string[] lines = File.ReadAllLines(gcodeFileName); if (lines.Length > 0) { string filamentAmountLine = lines[lines.Length - 1]; bool foundAmountInGCode = false; int startPos = filamentAmountLine.IndexOf("("); if (startPos > 0) { int endPos = filamentAmountLine.IndexOf("cm3)", startPos); if (endPos > 0) { string value = filamentAmountLine.Substring(startPos + 1, endPos - (startPos + 1)); double amountForThisFile; if (double.TryParse(value, out amountForThisFile)) { foundAmountInGCode = true; total += amountForThisFile; } } } if (!foundAmountInGCode) { GCodeFile gcodeFile = new GCodeFile(gcodeFileName); total += gcodeFile.GetFilamentCubicMm(ActiveSliceSettings.Instance.FilamentDiameter) / 1000; } } } // now copy all the gcode to the path given for (int i = 0; i < savedGCodeFileNames.Count; i++) { string savedGcodeFileName = savedGCodeFileNames[i]; string originalFileName = Path.GetFileName(allFilesToExport[i].Name); string outputFileName = Path.ChangeExtension(originalFileName, ".gcode"); string outputPathAndName = Path.Combine(exportPath, outputFileName); if (ActivePrinterProfile.Instance.DoPrintLeveling) { GCodeFile unleveledGCode = new GCodeFile(savedGcodeFileName); PrintLevelingPlane.Instance.ApplyLeveling(unleveledGCode); unleveledGCode.Save(outputPathAndName); } else { File.Copy(savedGcodeFileName, outputPathAndName, true); } } if (DoneSaving != null) { DoneSaving(this, new StringEventArgs(string.Format("{0:0.0}", total))); } } } }
private void SaveGCodeToNewLocation(string source, string dest) { if (ActivePrinterProfile.Instance.DoPrintLeveling) { GCodeFile unleveledGCode = new GCodeFile(source); if (applyLeveling.Checked) { PrintLevelingPlane.Instance.ApplyLeveling(unleveledGCode); PrintLevelingData levelingData = PrintLevelingData.GetForPrinter(ActivePrinterProfile.Instance.ActivePrinter); if (levelingData != null) { for (int i = 0; i < unleveledGCode.Count; i++) { PrinterMachineInstruction instruction = unleveledGCode.Instruction(i); List<string> linesToWrite = null; switch (levelingData.levelingSystem) { case PrintLevelingData.LevelingSystem.Probe2Points: linesToWrite = LevelWizard2Point.ProcessCommand(instruction.Line); break; case PrintLevelingData.LevelingSystem.Probe3Points: linesToWrite = LevelWizard3Point.ProcessCommand(instruction.Line); break; } instruction.Line = linesToWrite[0]; linesToWrite.RemoveAt(0); // now insert any new lines foreach(string line in linesToWrite) { PrinterMachineInstruction newInstruction = new PrinterMachineInstruction(line); unleveledGCode.Insert(++i, newInstruction); } } } } unleveledGCode.Save(dest); } else { File.Copy(source, dest, true); } ShowFileIfRequested(dest); }
private void LoadGCodeToPrint(string gcodeFilename) { totalGCodeStream?.Dispose(); loadedGCode = GCodeFile.Load(gcodeFilename); gCodeFileStream0 = new GCodeFileStream(loadedGCode); if(activePrintTask != null) // We are resuming a failed print (do lots of interesting stuff). { pauseHandlingStream1 = new PauseHandlingStream(new ResumePrintingStream(gCodeFileStream0, activePrintTask.PercentDone)); } else { pauseHandlingStream1 = new PauseHandlingStream(gCodeFileStream0); } queuedCommandStream2 = new QueuedCommandsStream(pauseHandlingStream1); relativeToAbsoluteStream3 = new RelativeToAbsoluteStream(queuedCommandStream2); printLevelingStream4 = new PrintLevelingStream(relativeToAbsoluteStream3); waitForTempStream5 = new WaitForTempStream(printLevelingStream4); babyStepsStream6 = new BabyStepsStream(waitForTempStream5); if(activePrintTask != null) { // make sure we are in the position we were when we stopped printing babyStepsStream6.Offset = new Vector3(activePrintTask.PrintingOffsetX, activePrintTask.PrintingOffsetY, activePrintTask.PrintingOffsetZ); } extrusionMultiplyerStream7 = new ExtrusionMultiplyerStream(babyStepsStream6); feedrateMultiplyerStream8 = new FeedRateMultiplyerStream(extrusionMultiplyerStream7); requestTemperaturesStream9 = new RequestTemperaturesStream(feedrateMultiplyerStream8); totalGCodeStream = requestTemperaturesStream9; }
public PrinterIoGCodeFile(GCodeFile loadedGCode) { this.loadedGCode = loadedGCode; }
private void SaveGCodeToNewLocation(string source, string dest) { if (ActivePrinterProfile.Instance.DoPrintLeveling) { GCodeFile unleveledGCode = new GCodeFile(source); PrintLeveling.Instance.ApplyLeveling(unleveledGCode); unleveledGCode.Save(dest); } else { File.Copy(source, dest, true); } ShowFileIfRequested(dest); }
public TrackPrinterPosition(GCodeFile source) : base(source) { }
public void ApplyLeveling(GCodeFile unleveledGCode) { foreach (PrinterMachineInstruction instruction in unleveledGCode.GCodeCommandQueue) { Vector3 currentDestination = instruction.Position; instruction.Line = ApplyLeveling(currentDestination, instruction.movementType, instruction.Line, false, true); } }
public PrinterIoGCodeFile(GCodeFile loadedGCode) : base(null) { this.loadedGCode = loadedGCode; }
public void LoadFile(string gcodePathAndFileName) { loadedGCode = GCodeFile.Load(gcodePathAndFileName); SetInitalLayer(); CenterPartInView(); }
public GCodeFileProxy(GCodeFile source) { this.source = source; }
public bool StartPrint(string gcodeFileContents, int startIndex = 0) { gcodeFileContents = gcodeFileContents.Replace("\r\n", "\n"); gcodeFileContents = gcodeFileContents.Replace('\r', '\n'); string[] gcodeLines = gcodeFileContents.Split('\n'); List<string> printableGCode = new List<string>(); foreach (string line in gcodeLines) { string[] splitOnSemicolon = line.Split(';'); string trimedLine = splitOnSemicolon[0].Trim().ToUpper(); if (trimedLine.Length < 1) { continue; } printableGCode.Add(trimedLine); } if (!PrinterIsConnected || PrinterIsPrinting) { return false; } ExtrusionRatio = 1; FeedRateRatio = 1; CommunicationState = CommunicationStates.Printing; ClearQueuedGCode(); loadedGCode = GCodeFile.ParseGCodeString(string.Join("\n", printableGCode.ToArray())); if (printableGCode.Count == 0) { return true; } sendGCodeToPrinterThread = new Thread(SendCurrentGCodeFileToPrinter); sendGCodeToPrinterThread.Name = "sendGCodeToPrinterThread - StartPrint"; sendGCodeToPrinterThread.IsBackground = true; sendGCodeToPrinterThread.Start(); return true; }
void sliceItem_Done(object sender, EventArgs e) { PrintItemWrapper sliceItem = (PrintItemWrapper)sender; sliceItem.Done -= new EventHandler(sliceItem_Done); savedGCodeFileNames.Add(sliceItem.GCodePathAndFileName); itemCountBeingWorkedOn++; if (itemCountBeingWorkedOn < allFilesToExport.Count) { if (StartingNextPart != null) { StartingNextPart(this, new StringEventArgs(ItemNameBeingWorkedOn)); } } else { UpdatePartStatus(this, new StringEventArgs("Calculating Total cm3...")); if (savedGCodeFileNames.Count > 0) { double total = 0; foreach (string gcodeFileName in savedGCodeFileNames) { string[] lines = File.ReadAllLines(gcodeFileName); string filamentAmountLine = lines[lines.Length - 1]; int startPos = filamentAmountLine.IndexOf("("); int endPos = filamentAmountLine.IndexOf("cm3)"); string value = filamentAmountLine.Substring(startPos + 1, endPos - (startPos + 1)); double amountForThisFile; if (double.TryParse(value, out amountForThisFile)) { total += amountForThisFile; } else { GCodeFile gcodeFile = new GCodeFile(gcodeFileName); total += gcodeFile.GetFilamentCubicMm(ActiveSliceSettings.Instance.FillamentDiameter) / 1000; } } // now copy all the gcode to the path given for (int i = 0; i < savedGCodeFileNames.Count; i++) { string savedGcodeFileName = savedGCodeFileNames[i]; string originalFileName = Path.GetFileName(allFilesToExport[i].Name); string outputFileName = Path.ChangeExtension(originalFileName, ".gcode"); throw new NotImplementedException(); //string outputPathAndName = Path.Combine(exportPath, outputFileName); if (ActivePrinterProfile.Instance.DoPrintLeveling) { GCodeFile unleveledGCode = new GCodeFile(savedGcodeFileName); PrintLeveling.Instance.ApplyLeveling(unleveledGCode); //unleveledGCode.Save(outputPathAndName); } else { //File.Copy(savedGcodeFileName, outputPathAndName, true); } } if (DoneSaving != null) { DoneSaving(this, new StringEventArgs(string.Format("{0:0.0}", total))); } } } }
private void loadGCodeWorker_DoWork(object sender, DoWorkEventArgs e) { string gcodeFilename = e.Argument as string; loadedGCode = GCodeFile.Load(gcodeFilename); }
public ColorGradientWidget(GCodeFile gcodeFileTest) : base(FlowDirection.TopToBottom) { BackgroundColor = new RGBA_Bytes(0, 0, 0, 120); HashSet<float> speeds = new HashSet<float>(); PrinterMachineInstruction previousInstruction = gcodeFileTest.Instruction(0); for (int i = 1; i < gcodeFileTest.LineCount; i++) { PrinterMachineInstruction instruction = gcodeFileTest.Instruction(i); if (instruction.EPosition > previousInstruction.EPosition && (instruction.Line.IndexOf('X') != -1 || instruction.Line.IndexOf('Y') != -1)) { speeds.Add((float)instruction.FeedRate); } previousInstruction = instruction; } ExtrusionColors extrusionColors = new ExtrusionColors(); speeds.Select(speed => extrusionColors.GetColorForSpeed(speed)).ToArray(); if(speeds.Count <= 0) { // There are no paths so don't generate the rest of the widget. return; } float min = speeds.Min(); float max = speeds.Max(); int maxItems = Math.Min(7, speeds.Count()); int count = maxItems - 1; float increment = (max - min) / count; int index = 0; int[] rangeValues; if (speeds.Count < 8) { rangeValues = speeds.Select(s => (int)s).OrderBy(i => i).ToArray(); } else { rangeValues = Enumerable.Range(0, maxItems).Select(x => (int)(min + increment * index++)).ToArray(); } RGBA_Bytes[] speedColors = rangeValues.OrderBy(s => s).Select(speed => extrusionColors.GetColorForSpeed(speed)).ToArray(); for (int i = 0; i < speedColors.Length; i++) { RGBA_Bytes color = speedColors[i]; int speed = rangeValues[i]; GuiWidget colorWidget = new GuiWidget(); colorWidget.Width = 20; colorWidget.Height = 20; colorWidget.BackgroundColor = color; colorWidget.Margin = new BorderDouble(2); double feedRateToMMPerSecond = speed / 60; ColorToSpeedWidget colorToSpeedWidget = new ColorToSpeedWidget(colorWidget, feedRateToMMPerSecond); this.AddChild(colorToSpeedWidget); } Margin = new BorderDouble(5, 5, 200, 50); HAnchor |= Agg.UI.HAnchor.ParentLeft; VAnchor = Agg.UI.VAnchor.ParentTop; }
public void Load(string gcodePathAndFileName) { loadedGCode = new GCodeFile(gcodePathAndFileName); SetInitalLayer(); CenterPartInView(); }
private void ParseGLine(string lineString, PrinterMachineInstruction processingMachineState) { // take off any comments before we check its length int commentIndex = lineString.IndexOf(';'); if (commentIndex != -1) { lineString = lineString.Substring(0, commentIndex); } string[] splitOnSpace = lineString.Split(' '); string onlyNumber = splitOnSpace[0].Substring(1).Trim(); switch (onlyNumber) { case "0": goto case "1"; case "4": case "04": // wait a given number of miliseconds break; case "1": // get the x y z to move to { double valueX = 0; if (GCodeFile.GetFirstNumberAfter("X", lineString, ref valueX)) { processingMachineState.X = valueX; } double valueY = 0; if (GCodeFile.GetFirstNumberAfter("Y", lineString, ref valueY)) { processingMachineState.Y = valueY; } double valueZ = 0; if (GCodeFile.GetFirstNumberAfter("Z", lineString, ref valueZ)) { processingMachineState.Z = valueZ; } double valueE = 0; if (GCodeFile.GetFirstNumberAfter("E", lineString, ref valueE)) { if (processingMachineState.movementType == PrinterMachineInstruction.MovementTypes.Absolute) { processingMachineState.EPosition = valueE + amountOfAccumulatedEWhileParsing; } else { processingMachineState.EPosition += valueE; } } double valueF = 0; if (GCodeFile.GetFirstNumberAfter("F", lineString, ref valueF)) { processingMachineState.FeedRate = valueF; } } if (!gcodeHasExplicitLayerChangeInfo) { if (processingMachineState.Z != parsingLastZ || indexOfChangeInZ.Count == 0) { // if we changed z or there is a movement and we have never started a layer index indexOfChangeInZ.Add(GCodeCommandQueue.Count); } } parsingLastZ = processingMachineState.Position.z; break; case "10": // firmware retract break; case "11": // firmware unretract break; case "21": // set to metric break; case "28": // G28 Return to home position (machine zero, aka machine reference point) break; case "29": // G29 Probe the z-bed in 3 places break; case "30": // G30 Probe z in current position break; case "90": // G90 is Absolute Distance Mode processingMachineState.movementType = PrinterMachineInstruction.MovementTypes.Absolute; break; case "91": // G91 is Incremental Distance Mode processingMachineState.movementType = PrinterMachineInstruction.MovementTypes.Relative; break; case "92": // set current head position values (used to reset origin) double ePosition = 0; if (GetFirstNumberAfter("E", lineString, ref ePosition)) { // remember how much e position we just gave up amountOfAccumulatedEWhileParsing = (processingMachineState.EPosition - ePosition); } break; case "130": //Set Digital Potentiometer value break; case "161": // home x,y axis minimum break; case "162": // home z axis maximum break; default: break; } }
private void loadGCodeWorker_DoWork(object sender, DoWorkEventArgs e) { totalGCodeStream?.Dispose(); string gcodeFilename = e.Argument as string; loadedGCode = GCodeFile.Load(gcodeFilename); gCodeFileStream0 = new GCodeFileStream(loadedGCode); pauseHandlingStream1 = new PauseHandlingStream(gCodeFileStream0); queuedCommandStream2 = new QueuedCommandsStream(pauseHandlingStream1); relativeToAbsoluteStream3 = new RelativeToAbsoluteStream(queuedCommandStream2); printLevelingStream4 = new PrintLevelingStream(relativeToAbsoluteStream3); waitForTempStream5 = new WaitForTempStream(printLevelingStream4); babyStepsStream6 = new BabyStepsStream(waitForTempStream5); extrusionMultiplyerStream7 = new ExtrusionMultiplyerStream(babyStepsStream6); feedrateMultiplyerStream8 = new FeedRateMultiplyerStream(extrusionMultiplyerStream7); requestTemperaturesStream9 = new RequestTemperaturesStream(feedrateMultiplyerStream8); totalGCodeStream = requestTemperaturesStream9; }
public bool StartPrint(string gcodeFileContents) { if (!PrinterIsConnected || PrinterIsPrinting) { return false; } gcodeFileContents = gcodeFileContents.Replace("\r\n", "\n"); gcodeFileContents = gcodeFileContents.Replace('\r', '\n'); string[] gcodeLines = gcodeFileContents.Split('\n'); List<string> printableGCode = new List<string>(gcodeLines.Length); foreach (string line in gcodeLines) { printableGCode.Add(line); } ExtrusionRatio = 1; FeedRateRatio = 1; switch(communicationState) { case CommunicationStates.PreparingToPrintToSd: activePrintTask = null; CommunicationState = CommunicationStates.PrintingToSd; break; case CommunicationStates.PreparingToPrint: if (ActivePrintItem.PrintItem.Id == 0) { ActivePrintItem.PrintItem.Commit(); } activePrintTask = new PrintTask(); activePrintTask.PrintStart = DateTime.Now; activePrintTask.PrinterId = ActivePrinterProfile.Instance.ActivePrinter.Id; activePrintTask.PrintName = ActivePrintItem.PrintItem.Name; activePrintTask.PrintItemId = ActivePrintItem.PrintItem.Id; activePrintTask.PrintComplete = false; activePrintTask.Commit(); CommunicationState = CommunicationStates.Printing; break; default: throw new NotFiniteNumberException(); } ClearQueuedGCode(); loadedGCode = GCodeFile.ParseGCodeString(string.Join("\n", printableGCode.ToArray())); if (printableGCode.Count == 0) { return true; } sendGCodeToPrinterThread = new Thread(SendCurrentGCodeFileToPrinter); sendGCodeToPrinterThread.Name = "sendGCodeToPrinterThread - StartPrint"; sendGCodeToPrinterThread.IsBackground = true; sendGCodeToPrinterThread.Start(); return true; }