diff --git a/MatterControl.csproj b/MatterControl.csproj index 7991a46e8..795325f9c 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -226,6 +226,7 @@ + diff --git a/PrinterCommunication/Io/MacroProcessingStream.cs b/PrinterCommunication/Io/MacroProcessingStream.cs new file mode 100644 index 000000000..024bdf8bb --- /dev/null +++ b/PrinterCommunication/Io/MacroProcessingStream.cs @@ -0,0 +1,264 @@ +/* +Copyright (c) 2015, Lars Brubaker +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.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text.RegularExpressions; +using System.Threading; +using MatterHackers.Agg.Image; +using MatterHackers.Agg.PlatformAbstract; +using MatterHackers.Agg.UI; +using MatterHackers.MatterControl.PrinterControls; +using MatterHackers.MatterControl.SlicerConfiguration; + +namespace MatterHackers.MatterControl.PrinterCommunication.Io +{ + public class MacroProcessingStream : GCodeStreamProxy + { + public const string MacroPrefix = "; host."; + private List commandsToRepeat = new List(); + private object locker = new object(); + private double maxTimeToWaitForOk = 0; + private int repeatCommandIndex = 0; + private bool runningMacro = false; + private double startingBedTemp = 0; + private List startingExtruderTemps = new List(); + private Stopwatch timeHaveBeenWaiting = new Stopwatch(); + private bool waitingForUserInput = false; + private PrinterConnection printerConnection; + QueuedCommandsStream queuedCommandsStream; + + public MacroProcessingStream(QueuedCommandsStream queuedCommandsStream, PrinterConnection printerConnection) + : base(queuedCommandsStream) + { + this.queuedCommandsStream = queuedCommandsStream; + this.printerConnection = printerConnection; + } + + public void Cancel() + { + Reset(); + } + + public void Continue() + { + waitingForUserInput = false; + timeHaveBeenWaiting.Reset(); + maxTimeToWaitForOk = 0; + commandsToRepeat.Clear(); + } + + public ImageBuffer LoadImageAsset(string uri) + { + string filePath = Path.Combine("Images", "Macros", uri); + bool imageOnDisk = false; + if (uri.IndexOfAny(Path.GetInvalidFileNameChars()) == -1) + { + try + { + imageOnDisk = StaticData.Instance.FileExists(filePath); + } + catch + { + imageOnDisk = false; + } + } + + if (imageOnDisk) + { + return StaticData.Instance.LoadImage(filePath); + } + else + { + var imageBuffer = new ImageBuffer(320, 10); + + ApplicationController.Instance.DownloadToImageAsync(imageBuffer, uri, true); + + return imageBuffer; + } + } + + public override string ReadLine() + { + string lineToSend = null; + + if (waitingForUserInput) + { + lineToSend = ""; + Thread.Sleep(100); + + if (timeHaveBeenWaiting.IsRunning + && timeHaveBeenWaiting.Elapsed.TotalSeconds > maxTimeToWaitForOk) + { + if (commandsToRepeat.Count > 0) + { + // We timed out without the user responding. Cancel the operation. + Reset(); + } + else + { + // everything normal continue after time waited + Continue(); + } + } + + if (maxTimeToWaitForOk > 0 + && timeHaveBeenWaiting.Elapsed.TotalSeconds < maxTimeToWaitForOk + && commandsToRepeat.Count > 0) + { + lineToSend = commandsToRepeat[repeatCommandIndex % commandsToRepeat.Count]; + repeatCommandIndex++; + } + } + else + { + lineToSend = base.ReadLine(); + + if (lineToSend != null) + { + if (lineToSend.StartsWith(MacroPrefix) && lineToSend.TrimEnd().EndsWith(")")) + { + if (!runningMacro) + { + runningMacro = true; + int extruderCount = printerConnection.PrinterSettings.GetValue(SettingsKey.extruder_count); + for (int i = 0; i < extruderCount; i++) + { + startingExtruderTemps.Add(printerConnection.GetTargetExtruderTemperature(i)); + } + + if (printerConnection.PrinterSettings.GetValue(SettingsKey.has_heated_bed)) + { + startingBedTemp = printerConnection.TargetBedTemperature; + } + } + int parensAfterCommand = lineToSend.IndexOf('(', MacroPrefix.Length); + string command = ""; + if (parensAfterCommand > 0) + { + command = lineToSend.Substring(MacroPrefix.Length, parensAfterCommand - MacroPrefix.Length); + } + + RunningMacroPage.MacroCommandData macroData = new RunningMacroPage.MacroCommandData(); + + string value = ""; + if (TryGetAfterString(lineToSend, "title", out value)) + { + macroData.title = value; + } + if (TryGetAfterString(lineToSend, "expire", out value)) + { + double.TryParse(value, out macroData.expireTime); + maxTimeToWaitForOk = macroData.expireTime; + } + if (TryGetAfterString(lineToSend, "count_down", out value)) + { + double.TryParse(value, out macroData.countDown); + } + if (TryGetAfterString(lineToSend, "image", out value)) + { + macroData.image = LoadImageAsset(value); + } + if (TryGetAfterString(lineToSend, "wait_ok", out value)) + { + macroData.waitOk = value == "true"; + } + if (TryGetAfterString(lineToSend, "repeat_gcode", out value)) + { + foreach (string line in value.Split('|')) + { + commandsToRepeat.Add(line); + } + } + + switch (command) + { + case "choose_material": + waitingForUserInput = true; + macroData.showMaterialSelector = true; + macroData.waitOk = true; + UiThread.RunOnIdle(() => RunningMacroPage.Show(macroData)); + break; + + case "close": + runningMacro = false; + UiThread.RunOnIdle(() => WizardWindow.Close("Macro")); + break; + + case "ding": + MatterControlApplication.Instance.PlaySound("timer-done.wav"); + break; + + case "show_message": + waitingForUserInput = macroData.waitOk | macroData.expireTime > 0; + UiThread.RunOnIdle(() => RunningMacroPage.Show(macroData)); + break; + + default: + // Don't know the command. Print to terminal log? + break; + } + } + } + } + + return lineToSend; + } + + public void Reset() + { + if (runningMacro) + { + runningMacro = false; + for (int i = 0; i < startingExtruderTemps.Count; i++) + { + printerConnection.SetTargetExtruderTemperature(i, startingExtruderTemps[i]); + } + + if (printerConnection.PrinterSettings.GetValue(SettingsKey.has_heated_bed)) + { + printerConnection.TargetBedTemperature = startingBedTemp; + } + } + waitingForUserInput = false; + timeHaveBeenWaiting.Reset(); + maxTimeToWaitForOk = 0; + UiThread.RunOnIdle(() => WizardWindow.Close("Macro")); + } + + private bool TryGetAfterString(string macroLine, string variableName, out string value) + { + var macroMatch = Regex.Match(macroLine, variableName + ":\"([^\"]+)"); + value = macroMatch.Success ? macroMatch.Groups[1].Value : null; + + return macroMatch.Success; + } + } +} \ No newline at end of file diff --git a/PrinterCommunication/Io/PrintRecoveryStream.cs b/PrinterCommunication/Io/PrintRecoveryStream.cs index 847b53c0d..e8c579849 100644 --- a/PrinterCommunication/Io/PrintRecoveryStream.cs +++ b/PrinterCommunication/Io/PrintRecoveryStream.cs @@ -43,7 +43,7 @@ namespace MatterHackers.MatterControl.PrinterCommunication.Io private double percentDone; double recoverFeedRate; PrinterMove lastDestination; - QueuedCommandsStream queuedCommands; + QueuedCommandsStream queuedCommands; RectangleDouble boundsOfSkippedLayers = RectangleDouble.ZeroIntersection; RecoveryState recoveryState = RecoveryState.RemoveHeating; diff --git a/PrinterCommunication/Io/QueuedCommandsStream.cs b/PrinterCommunication/Io/QueuedCommandsStream.cs index 9525f2314..c1d2b01ef 100644 --- a/PrinterCommunication/Io/QueuedCommandsStream.cs +++ b/PrinterCommunication/Io/QueuedCommandsStream.cs @@ -42,17 +42,8 @@ namespace MatterHackers.MatterControl.PrinterCommunication.Io { public class QueuedCommandsStream : GCodeStreamProxy { - public const string MacroPrefix = "; host."; private List commandQueue = new List(); - private List commandsToRepeat = new List(); private object locker = new object(); - private double maxTimeToWaitForOk = 0; - private int repeatCommandIndex = 0; - private bool runningMacro = false; - private double startingBedTemp = 0; - private List startingExtruderTemps = new List(); - private Stopwatch timeHaveBeenWaiting = new Stopwatch(); - private bool waitingForUserInput = false; public QueuedCommandsStream(GCodeStream internalStream) : base(internalStream) @@ -80,14 +71,6 @@ namespace MatterHackers.MatterControl.PrinterCommunication.Io Reset(); } - public void Continue() - { - waitingForUserInput = false; - timeHaveBeenWaiting.Reset(); - maxTimeToWaitForOk = 0; - commandsToRepeat.Clear(); - } - public ImageBuffer LoadImageAsset(string uri) { string filePath = Path.Combine("Images", "Macros", uri); @@ -122,35 +105,6 @@ namespace MatterHackers.MatterControl.PrinterCommunication.Io { string lineToSend = null; - if (waitingForUserInput) - { - lineToSend = ""; - Thread.Sleep(100); - - if (timeHaveBeenWaiting.IsRunning - && timeHaveBeenWaiting.Elapsed.TotalSeconds > maxTimeToWaitForOk) - { - if (commandsToRepeat.Count > 0) - { - // We timed out without the user responding. Cancel the operation. - Reset(); - } - else - { - // everything normal continue after time waited - Continue(); - } - } - - if (maxTimeToWaitForOk > 0 - && timeHaveBeenWaiting.Elapsed.TotalSeconds < maxTimeToWaitForOk - && commandsToRepeat.Count > 0) - { - lineToSend = commandsToRepeat[repeatCommandIndex % commandsToRepeat.Count]; - repeatCommandIndex++; - } - } - else { // lock queue lock (locker) @@ -163,93 +117,7 @@ namespace MatterHackers.MatterControl.PrinterCommunication.Io } } - if (lineToSend != null) - { - if (lineToSend.StartsWith(MacroPrefix) && lineToSend.TrimEnd().EndsWith(")")) - { - if (!runningMacro) - { - runningMacro = true; - int extruderCount = ActiveSliceSettings.Instance.GetValue(SettingsKey.extruder_count); - for (int i = 0; i < extruderCount; i++) - { - startingExtruderTemps.Add(PrinterConnection.Instance.GetTargetExtruderTemperature(i)); - } - - if (ActiveSliceSettings.Instance.GetValue(SettingsKey.has_heated_bed)) - { - startingBedTemp = PrinterConnection.Instance.TargetBedTemperature; - } - } - int parensAfterCommand = lineToSend.IndexOf('(', MacroPrefix.Length); - string command = ""; - if (parensAfterCommand > 0) - { - command = lineToSend.Substring(MacroPrefix.Length, parensAfterCommand - MacroPrefix.Length); - } - - RunningMacroPage.MacroCommandData macroData = new RunningMacroPage.MacroCommandData(); - - string value = ""; - if (TryGetAfterString(lineToSend, "title", out value)) - { - macroData.title = value; - } - if (TryGetAfterString(lineToSend, "expire", out value)) - { - double.TryParse(value, out macroData.expireTime); - maxTimeToWaitForOk = macroData.expireTime; - } - if (TryGetAfterString(lineToSend, "count_down", out value)) - { - double.TryParse(value, out macroData.countDown); - } - if (TryGetAfterString(lineToSend, "image", out value)) - { - macroData.image = LoadImageAsset(value); - } - if (TryGetAfterString(lineToSend, "wait_ok", out value)) - { - macroData.waitOk = value == "true"; - } - if (TryGetAfterString(lineToSend, "repeat_gcode", out value)) - { - foreach (string line in value.Split('|')) - { - commandsToRepeat.Add(line); - } - } - - switch (command) - { - case "choose_material": - waitingForUserInput = true; - macroData.showMaterialSelector = true; - macroData.waitOk = true; - UiThread.RunOnIdle(() => RunningMacroPage.Show(macroData)); - break; - - case "close": - runningMacro = false; - UiThread.RunOnIdle(() => WizardWindow.Close("Macro")); - break; - - case "ding": - MatterControlApplication.Instance.PlaySound("timer-done.wav"); - break; - - case "show_message": - waitingForUserInput = macroData.waitOk | macroData.expireTime > 0; - UiThread.RunOnIdle(() => RunningMacroPage.Show(macroData)); - break; - - default: - // Don't know the command. Print to terminal log? - break; - } - } - } - else + if (lineToSend == null) { lineToSend = base.ReadLine(); } @@ -264,32 +132,6 @@ namespace MatterHackers.MatterControl.PrinterCommunication.Io { commandQueue.Clear(); } - - if (runningMacro) - { - runningMacro = false; - for (int i = 0; i < startingExtruderTemps.Count; i++) - { - PrinterConnection.Instance.SetTargetExtruderTemperature(i, startingExtruderTemps[i]); - } - - if (ActiveSliceSettings.Instance.GetValue(SettingsKey.has_heated_bed)) - { - PrinterConnection.Instance.TargetBedTemperature = startingBedTemp; - } - } - waitingForUserInput = false; - timeHaveBeenWaiting.Reset(); - maxTimeToWaitForOk = 0; - UiThread.RunOnIdle(() => WizardWindow.Close("Macro")); - } - - private bool TryGetAfterString(string macroLine, string variableName, out string value) - { - var macroMatch = Regex.Match(macroLine, variableName + ":\"([^\"]+)"); - value = macroMatch.Success ? macroMatch.Groups[1].Value : null; - - return macroMatch.Success; } } } \ No newline at end of file diff --git a/PrinterCommunication/PrinterConnection.cs b/PrinterCommunication/PrinterConnection.cs index d03c9912d..f6d807bf2 100644 --- a/PrinterCommunication/PrinterConnection.cs +++ b/PrinterCommunication/PrinterConnection.cs @@ -220,14 +220,15 @@ namespace MatterHackers.MatterControl.PrinterCommunication private GCodeFileStream gCodeFileStream0 = null; private PauseHandlingStream pauseHandlingStream1 = null; private QueuedCommandsStream queuedCommandStream2 = null; - private RelativeToAbsoluteStream relativeToAbsoluteStream3 = null; - private PrintLevelingStream printLevelingStream4 = null; - private WaitForTempStream waitForTempStream5 = null; - private BabyStepsStream babyStepsStream6 = null; - private ExtrusionMultiplyerStream extrusionMultiplyerStream7 = null; - private FeedRateMultiplyerStream feedrateMultiplyerStream8 = null; - private RequestTemperaturesStream requestTemperaturesStream9 = null; - private ProcessWriteRegexStream processWriteRegExStream10 = null; + private MacroProcessingStream macroProcessingStream3 = null; + private RelativeToAbsoluteStream relativeToAbsoluteStream4 = null; + private PrintLevelingStream printLevelingStream5 = null; + private WaitForTempStream waitForTempStream6 = null; + private BabyStepsStream babyStepsStream7 = null; + private ExtrusionMultiplyerStream extrusionMultiplyerStream8 = null; + private FeedRateMultiplyerStream feedrateMultiplyerStream9 = null; + private RequestTemperaturesStream requestTemperaturesStream10 = null; + private ProcessWriteRegexStream processWriteRegExStream11 = null; private GCodeStream totalGCodeStream = null; @@ -2328,20 +2329,21 @@ namespace MatterHackers.MatterControl.PrinterCommunication } queuedCommandStream2 = new QueuedCommandsStream(firstStream); - relativeToAbsoluteStream3 = new RelativeToAbsoluteStream(queuedCommandStream2); - printLevelingStream4 = new PrintLevelingStream(relativeToAbsoluteStream3, true); - waitForTempStream5 = new WaitForTempStream(printLevelingStream4); - babyStepsStream6 = new BabyStepsStream(waitForTempStream5, gcodeFilename == null ? 2000 : 1); + macroProcessingStream3 = new MacroProcessingStream(queuedCommandStream2, this); + relativeToAbsoluteStream4 = new RelativeToAbsoluteStream(macroProcessingStream3); + printLevelingStream5 = new PrintLevelingStream(relativeToAbsoluteStream4, true); + waitForTempStream6 = new WaitForTempStream(printLevelingStream5); + babyStepsStream7 = new BabyStepsStream(waitForTempStream6, gcodeFilename == null ? 2000 : 1); 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); + babyStepsStream7.Offset = new Vector3(activePrintTask.PrintingOffsetX, activePrintTask.PrintingOffsetY, activePrintTask.PrintingOffsetZ); } - extrusionMultiplyerStream7 = new ExtrusionMultiplyerStream(babyStepsStream6); - feedrateMultiplyerStream8 = new FeedRateMultiplyerStream(extrusionMultiplyerStream7); - requestTemperaturesStream9 = new RequestTemperaturesStream(feedrateMultiplyerStream8); - processWriteRegExStream10 = new ProcessWriteRegexStream(requestTemperaturesStream9, queuedCommandStream2); - totalGCodeStream = processWriteRegExStream10; + extrusionMultiplyerStream8 = new ExtrusionMultiplyerStream(babyStepsStream7); + feedrateMultiplyerStream9 = new FeedRateMultiplyerStream(extrusionMultiplyerStream8); + requestTemperaturesStream10 = new RequestTemperaturesStream(feedrateMultiplyerStream9); + processWriteRegExStream11 = new ProcessWriteRegexStream(requestTemperaturesStream10, queuedCommandStream2); + totalGCodeStream = processWriteRegExStream11; // Get the current position of the printer any time we reset our streams ReadPosition(); @@ -2467,11 +2469,11 @@ namespace MatterHackers.MatterControl.PrinterCommunication { PrintingState = DetailedPrintingState.HomingAxis; } - else if (waitForTempStream5?.HeatingBed ?? false) + else if (waitForTempStream6?.HeatingBed ?? false) { PrintingState = DetailedPrintingState.HeatingBed; } - else if (waitForTempStream5?.HeatingExtruder ?? false) + else if (waitForTempStream6?.HeatingExtruder ?? false) { PrintingState = DetailedPrintingState.HeatingExtruder; } @@ -2567,13 +2569,13 @@ namespace MatterHackers.MatterControl.PrinterCommunication // Only update the amount done if it is greater than what is recorded. // We don't want to mess up the resume before we actually resume it. if (activePrintTask != null - && babyStepsStream6 != null + && babyStepsStream7 != null && activePrintTask.PercentDone < currentDone) { activePrintTask.PercentDone = currentDone; - activePrintTask.PrintingOffsetX = (float)babyStepsStream6.Offset.x; - activePrintTask.PrintingOffsetY = (float)babyStepsStream6.Offset.y; - activePrintTask.PrintingOffsetZ = (float)babyStepsStream6.Offset.z; + activePrintTask.PrintingOffsetX = (float)babyStepsStream7.Offset.x; + activePrintTask.PrintingOffsetY = (float)babyStepsStream7.Offset.y; + activePrintTask.PrintingOffsetZ = (float)babyStepsStream7.Offset.z; try { Task.Run(() => activePrintTask.Commit()); @@ -2772,14 +2774,14 @@ namespace MatterHackers.MatterControl.PrinterCommunication public void MacroCancel() { - babyStepsStream6?.CancelMoves(); - waitForTempStream5?.Cancel(); + babyStepsStream7?.CancelMoves(); + waitForTempStream6?.Cancel(); queuedCommandStream2?.Cancel(); } public void MacroContinue() { - queuedCommandStream2?.Continue(); + macroProcessingStream3?.Continue(); } public class ReadThread diff --git a/SlicerConfiguration/Settings/GCodeMacro.cs b/SlicerConfiguration/Settings/GCodeMacro.cs index 98e051364..9e15b812a 100644 --- a/SlicerConfiguration/Settings/GCodeMacro.cs +++ b/SlicerConfiguration/Settings/GCodeMacro.cs @@ -68,9 +68,9 @@ namespace MatterHackers.MatterControl.SlicerConfiguration { PrinterConnection.Instance.MacroStart(); SendCommandToPrinter(GCode); - if (GCode.Contains(QueuedCommandsStream.MacroPrefix)) + if (GCode.Contains(MacroProcessingStream.MacroPrefix)) { - SendCommandToPrinter("\n" + QueuedCommandsStream.MacroPrefix + "close()"); + SendCommandToPrinter("\n" + MacroProcessingStream.MacroPrefix + "close()"); } } } diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index de4578e53..c4d79959c 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit de4578e53b9fc874a04056ddf104a75505445999 +Subproject commit c4d79959c335a5e773520e60b3236b211a5a76f7