1949 lines
72 KiB
C#
1949 lines
72 KiB
C#
/*
|
|
Copyright (c) 2014, 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;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.IO.Ports;
|
|
using System.Threading;
|
|
using System.Diagnostics;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using System.Globalization;
|
|
using Microsoft.Win32.SafeHandles;
|
|
|
|
using MatterHackers.MatterControl.FrostedSerial;
|
|
using MatterHackers.Agg;
|
|
using MatterHackers.Agg.UI;
|
|
using MatterHackers.MatterControl.DataStorage;
|
|
using MatterHackers.VectorMath;
|
|
using MatterHackers.SerialPortConnecton;
|
|
using MatterHackers.GCodeVisualizer;
|
|
using MatterHackers.MatterControl.VersionManagement;
|
|
using MatterHackers.MatterControl.PrintQueue;
|
|
using MatterHackers.Localizations;
|
|
|
|
namespace MatterHackers.MatterControl
|
|
{
|
|
/// <summary>
|
|
/// This is a class to pass temperatures to callbacks that expect them.
|
|
/// A call back can try and cast to this ( TemperatureEventArgs tempArgs = e as TemperatureEventArgs)
|
|
/// and then use the temperature if available.
|
|
/// </summary>
|
|
public class TemperatureEventArgs : EventArgs
|
|
{
|
|
double temperature;
|
|
|
|
public TemperatureEventArgs(double temperature)
|
|
{
|
|
this.temperature = temperature;
|
|
}
|
|
|
|
public double Temperature
|
|
{
|
|
get { return temperature; }
|
|
}
|
|
}
|
|
|
|
public class PrintItemWrapperEventArgs : EventArgs
|
|
{
|
|
PrintItemWrapper printItemWrapper;
|
|
|
|
public PrintItemWrapperEventArgs(PrintItemWrapper printItemWrapper)
|
|
{
|
|
this.printItemWrapper = printItemWrapper;
|
|
}
|
|
|
|
public PrintItemWrapper PrintItemWrapper
|
|
{
|
|
get { return printItemWrapper; }
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This is the class that comunicates with a RepRap printer over the serial port.
|
|
/// It handles opening and closing the serial port and does quite a bit of gcode parsing.
|
|
/// It should be refactoried into better moduals at some point.
|
|
/// </summary>
|
|
public class PrinterCommunication
|
|
{
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
|
internal static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr securityAttrs, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
|
|
|
|
public enum FirmwareTypes { Unknown, Repetier, Marlin, Sprinter };
|
|
FirmwareTypes firmwareType = FirmwareTypes.Unknown;
|
|
|
|
public FirmwareTypes FirmwareType
|
|
{
|
|
get { return firmwareType; }
|
|
}
|
|
|
|
static PrinterCommunication globalInstance;
|
|
string connectionFailureMessage = "Unknown Reason";
|
|
|
|
public string ConnectionFailureMessage { get { return connectionFailureMessage; } }
|
|
|
|
public RootedObjectEventHandler ActivePrintItemChanged = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler BedTemperatureRead = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler BedTemperatureSet = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler CommunicationUnconditionalFromPrinter = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler CommunicationUnconditionalToPrinter = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler ConnectionFailed = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler ConnectionStateChanged = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler ConnectionSucceeded = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler DestinationChanged = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler EnableChanged = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler ExtruderTemperatureRead = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler ExtruderTemperatureSet = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler FanSpeedSet = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler PrintFinished = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler PositionRead = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler ReadLine = new RootedObjectEventHandler();
|
|
public RootedObjectEventHandler WroteLine = new RootedObjectEventHandler();
|
|
|
|
FoundStringStartsWithCallbacks ReadLineStartCallBacks = new FoundStringStartsWithCallbacks();
|
|
FoundStringContainsCallbacks ReadLineContainsCallBacks = new FoundStringContainsCallbacks();
|
|
|
|
FoundStringStartsWithCallbacks WriteLineStartCallBacks = new FoundStringStartsWithCallbacks();
|
|
FoundStringContainsCallbacks WriteLineContainsCallBacks = new FoundStringContainsCallbacks();
|
|
|
|
int firstLineToResendIndex = 0;
|
|
List<string> allCheckSumLinesSent = new List<string>();
|
|
|
|
List<string> LinesToWriteQueue = new List<string>();
|
|
|
|
Stopwatch timeSinceLastReadAnything = new Stopwatch();
|
|
Stopwatch timeHaveBeenWaitingForOK = new Stopwatch();
|
|
|
|
public enum CommunicationStates { Disconnected, AttemptingToConnect, FailedToConnect, Connected, PreparingToPrint, Printing, Paused, FinishedPrint, Disconnecting, ConnectionLost };
|
|
CommunicationStates communicationState = CommunicationStates.Disconnected;
|
|
|
|
bool ForceImmediateWrites = false;
|
|
|
|
public CommunicationStates CommunicationState
|
|
{
|
|
get
|
|
{
|
|
return communicationState;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (communicationState != value)
|
|
{
|
|
// if it was printing
|
|
if (communicationState == CommunicationStates.Printing)
|
|
{
|
|
// and is changing to paused
|
|
if (value == CommunicationStates.Paused)
|
|
{
|
|
timeSinceStartedPrint.Stop();
|
|
}
|
|
else if (value == CommunicationStates.FinishedPrint)
|
|
{
|
|
OnPrintFinished(null);
|
|
timeSinceStartedPrint.Stop();
|
|
}
|
|
else
|
|
{
|
|
timeSinceStartedPrint.Stop();
|
|
timeSinceStartedPrint.Reset();
|
|
}
|
|
}
|
|
else if (communicationState == CommunicationStates.Paused) // was paused
|
|
{
|
|
// changing to printing
|
|
if (value == CommunicationStates.Printing)
|
|
{
|
|
timeSinceStartedPrint.Start();
|
|
}
|
|
}
|
|
|
|
communicationState = value;
|
|
OnConnectionStateChanged(null);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool stopTryingToConnect = false;
|
|
|
|
double actualExtruderTemperature;
|
|
double targetExtruderTemperature;
|
|
double actualBedTemperature;
|
|
double targetBedTemperature;
|
|
string printJobDisplayName = null;
|
|
GCodeFile loadedGCode = new GCodeFile();
|
|
FrostedSerialPort serialPort;
|
|
Thread readFromPrinterThread;
|
|
Thread connectThread;
|
|
|
|
private PrintItemWrapper activePrintItem;
|
|
|
|
int lastRemainingSecondsReported = 0;
|
|
int printerCommandQueueIndex = -1;
|
|
|
|
Thread sendGCodeToPrinterThread;
|
|
|
|
public bool DtrEnableOnConnect
|
|
{
|
|
get
|
|
{
|
|
if (ActivePrinter != null)
|
|
{
|
|
//return !ActivePrinter.SuppressDtrOnConnect;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
set
|
|
{
|
|
throw new NotImplementedException();
|
|
#if false
|
|
if (ActivePrinter != null)
|
|
{
|
|
bool enableDtrOnConnect = !ActivePrinter.SuppressDtrOnConnect;
|
|
if (enableDtrOnConnect != value)
|
|
{
|
|
ActivePrinter.SuppressDtrOnConnect = !value;
|
|
ActivePrinter.Commit();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
Vector3 currentDestination;
|
|
Vector3 lastReportedPosition;
|
|
|
|
public Vector3 CurrentDestination { get { return currentDestination; } }
|
|
public Vector3 LastReportedPosition { get { return lastReportedPosition; } }
|
|
|
|
PrinterMachineInstruction.MovementTypes extruderMode = PrinterMachineInstruction.MovementTypes.Absolute;
|
|
PrinterMachineInstruction.MovementTypes movementMode = PrinterMachineInstruction.MovementTypes.Absolute;
|
|
|
|
double extrusionRatio = 1;
|
|
double currentActualExtrusionPosition = 0;
|
|
double gcodeRequestedExtrusionPosition = 0;
|
|
double previousGcodeRequestedExtrusionPosition = 0;
|
|
public RootedObjectEventHandler ExtrusionRatioChanged = new RootedObjectEventHandler();
|
|
public double ExtrusionRatio
|
|
{
|
|
get { return extrusionRatio; }
|
|
set
|
|
{
|
|
if (value != extrusionRatio)
|
|
{
|
|
extrusionRatio = value;
|
|
ExtrusionRatioChanged.CallEvents(this, null);
|
|
}
|
|
}
|
|
}
|
|
double feedRateRatio = 1;
|
|
public RootedObjectEventHandler FeedRateRatioChanged = new RootedObjectEventHandler();
|
|
public double FeedRateRatio
|
|
{
|
|
get { return feedRateRatio; }
|
|
set
|
|
{
|
|
if (value != feedRateRatio)
|
|
{
|
|
feedRateRatio = value;
|
|
FeedRateRatioChanged.CallEvents(this, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
private Printer ActivePrinter
|
|
{
|
|
get
|
|
{
|
|
return ActivePrinterProfile.Instance.ActivePrinter;
|
|
}
|
|
set
|
|
{
|
|
ActivePrinterProfile.Instance.ActivePrinter = value;
|
|
}
|
|
}
|
|
|
|
public PrintItemWrapper ActivePrintItem
|
|
{
|
|
get
|
|
{
|
|
return this.activePrintItem;
|
|
}
|
|
set
|
|
{
|
|
if (!PrinterCommunication.Instance.PrinterIsPrinting)
|
|
{
|
|
if (this.activePrintItem != value)
|
|
{
|
|
this.activePrintItem = value;
|
|
if (CommunicationState == CommunicationStates.FinishedPrint)
|
|
{
|
|
CommunicationState = CommunicationStates.Connected;
|
|
}
|
|
OnActivePrintItemChanged(null);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("Cannot change active print while printing");
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool Disconnecting
|
|
{
|
|
get
|
|
{
|
|
return CommunicationState == CommunicationStates.Disconnecting;
|
|
}
|
|
}
|
|
|
|
public bool PrinterIsConnected
|
|
{
|
|
get
|
|
{
|
|
switch (CommunicationState)
|
|
{
|
|
case CommunicationStates.Disconnected:
|
|
case CommunicationStates.AttemptingToConnect:
|
|
case CommunicationStates.ConnectionLost:
|
|
case CommunicationStates.FailedToConnect:
|
|
return false;
|
|
|
|
case CommunicationStates.Disconnecting:
|
|
case CommunicationStates.Connected:
|
|
case CommunicationStates.PreparingToPrint:
|
|
case CommunicationStates.Printing:
|
|
case CommunicationStates.Paused:
|
|
case CommunicationStates.FinishedPrint:
|
|
return true;
|
|
|
|
default:
|
|
throw new NotImplementedException("Make sure very satus returns the correct connected state.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static PrinterCommunication Instance
|
|
{
|
|
get
|
|
{
|
|
if (globalInstance == null)
|
|
{
|
|
globalInstance = new PrinterCommunication();
|
|
}
|
|
return globalInstance;
|
|
}
|
|
|
|
}
|
|
|
|
PrinterCommunication()
|
|
{
|
|
MonitorPrinterTemperature = true;
|
|
|
|
StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
|
|
ReadLineStartCallBacks.AddCallBackToKey("start", FoundStart);
|
|
ReadLineStartCallBacks.AddCallBackToKey("start", PrintingCanContinue);
|
|
|
|
ReadLineStartCallBacks.AddCallBackToKey("ok", SuppressEcho);
|
|
ReadLineStartCallBacks.AddCallBackToKey("wait", SuppressEcho);
|
|
ReadLineStartCallBacks.AddCallBackToKey("T:", SuppressEcho); // repatier
|
|
|
|
ReadLineStartCallBacks.AddCallBackToKey("ok", PrintingCanContinue);
|
|
|
|
ReadLineStartCallBacks.AddCallBackToKey("ok T:", ReadTemperatures); // marlin
|
|
ReadLineStartCallBacks.AddCallBackToKey("T:", ReadTemperatures); // repatier
|
|
|
|
ReadLineStartCallBacks.AddCallBackToKey("C:", ReadPositions);
|
|
ReadLineStartCallBacks.AddCallBackToKey("X:", ReadPositions);
|
|
|
|
ReadLineContainsCallBacks.AddCallBackToKey("RS:", PrinterRequestsResend);
|
|
ReadLineContainsCallBacks.AddCallBackToKey("Resend:", PrinterRequestsResend);
|
|
ReadLineContainsCallBacks.AddCallBackToKey("FIRMWARE_NAME:", PrinterStatesFirmware);
|
|
|
|
WriteLineStartCallBacks.AddCallBackToKey("G28", HomeWasWritenToPrinter);
|
|
|
|
WriteLineStartCallBacks.AddCallBackToKey("M104", ExtruderTemperatureWasWritenToPrinter);
|
|
WriteLineStartCallBacks.AddCallBackToKey("M109", ExtruderTemperatureWasWritenToPrinter);
|
|
WriteLineStartCallBacks.AddCallBackToKey("M140", BedTemperatureWasWritenToPrinter);
|
|
WriteLineStartCallBacks.AddCallBackToKey("M190", BedTemperatureWasWritenToPrinter);
|
|
|
|
WriteLineStartCallBacks.AddCallBackToKey("M106", FanSpeedWasWritenToPrinter);
|
|
WriteLineStartCallBacks.AddCallBackToKey("M107", FanOffWasWritenToPrinter);
|
|
|
|
WriteLineStartCallBacks.AddCallBackToKey("M82", ExtruderWasSetToAbsoluteMode);
|
|
WriteLineStartCallBacks.AddCallBackToKey("M83", ExtruderWasSetToRelativeMode);
|
|
|
|
WriteLineStartCallBacks.AddCallBackToKey("G90", MovementWasSetToAbsoluteMode);
|
|
WriteLineStartCallBacks.AddCallBackToKey("G91", MovementWasSetToRelativeMode);
|
|
}
|
|
|
|
public bool MonitorPrinterTemperature
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public bool PrinterIsPrinting
|
|
{
|
|
get
|
|
{
|
|
switch (CommunicationState)
|
|
{
|
|
case CommunicationStates.Disconnected:
|
|
case CommunicationStates.Disconnecting:
|
|
case CommunicationStates.AttemptingToConnect:
|
|
case CommunicationStates.ConnectionLost:
|
|
case CommunicationStates.FailedToConnect:
|
|
case CommunicationStates.Connected:
|
|
case CommunicationStates.PreparingToPrint:
|
|
case CommunicationStates.Paused:
|
|
case CommunicationStates.FinishedPrint:
|
|
return false;
|
|
|
|
case CommunicationStates.Printing:
|
|
return true;
|
|
|
|
default:
|
|
throw new NotImplementedException("Make sure very satus returns the correct connected state.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum DetailedPrintingState { HomingAxis, HeatingBed, HeatingExtruder, Printing };
|
|
DetailedPrintingState detailedPrintingState;
|
|
|
|
public DetailedPrintingState PrintingState
|
|
{
|
|
get
|
|
{
|
|
return detailedPrintingState;
|
|
}
|
|
}
|
|
|
|
public string PrintingStateString
|
|
{
|
|
get
|
|
{
|
|
switch (detailedPrintingState)
|
|
{
|
|
case DetailedPrintingState.HomingAxis:
|
|
return "Homing Axis";
|
|
|
|
case DetailedPrintingState.HeatingBed:
|
|
return string.Format("Waiting for Bed to Heat to {0}°", TargetBedTemperature);
|
|
|
|
case DetailedPrintingState.HeatingExtruder:
|
|
return string.Format("Waiting for Extruder to Heat to {0}°", TargetExtruderTemperature);
|
|
|
|
case DetailedPrintingState.Printing:
|
|
return "Currently Printing:";
|
|
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
|
|
public string PrinterConnectionStatusVerbose
|
|
{
|
|
get
|
|
{
|
|
switch (CommunicationState)
|
|
{
|
|
case CommunicationStates.Disconnected:
|
|
return new LocalizedString("Not Connected").Translated;
|
|
case CommunicationStates.Disconnecting:
|
|
return new LocalizedString("Disconnecting").Translated;
|
|
case CommunicationStates.AttemptingToConnect:
|
|
return "Connecting...";
|
|
case CommunicationStates.ConnectionLost:
|
|
return new LocalizedString("Connection Lost").Translated;
|
|
case CommunicationStates.FailedToConnect:
|
|
return string.Format("Unable to Connect");
|
|
case CommunicationStates.Connected:
|
|
return new LocalizedString("Connected").Translated;
|
|
case CommunicationStates.PreparingToPrint:
|
|
return new LocalizedString("Preparing To Print").Translated;
|
|
case CommunicationStates.Printing:
|
|
return new LocalizedString("Printing").Translated;
|
|
case CommunicationStates.Paused:
|
|
return new LocalizedString("Paused").Translated;
|
|
case CommunicationStates.FinishedPrint:
|
|
return new LocalizedString("Finished Print").Translated;
|
|
default:
|
|
throw new NotImplementedException("Make sure very satus returns the correct connected state.");
|
|
}
|
|
}
|
|
}
|
|
|
|
public string PrintJobName
|
|
{
|
|
get
|
|
{
|
|
return printJobDisplayName;
|
|
}
|
|
}
|
|
|
|
public bool PrintIsFinished
|
|
{
|
|
get
|
|
{
|
|
return CommunicationState == CommunicationStates.FinishedPrint;
|
|
}
|
|
}
|
|
|
|
public bool PrinterIsPaused
|
|
{
|
|
get
|
|
{
|
|
return CommunicationState == CommunicationStates.Paused;
|
|
}
|
|
}
|
|
|
|
int NumberOfLinesInCurrentPrint
|
|
{
|
|
get
|
|
{
|
|
return loadedGCode.GCodeCommandQueue.Count;
|
|
}
|
|
}
|
|
|
|
public int TotalSecondsInPrint
|
|
{
|
|
get
|
|
{
|
|
if (loadedGCode.GCodeCommandQueue.Count > 0)
|
|
{
|
|
if (FeedRateRatio != 0)
|
|
{
|
|
return (int)(loadedGCode.GCodeCommandQueue[0].secondsToEndFromHere / FeedRateRatio);
|
|
}
|
|
|
|
return (int)(loadedGCode.GCodeCommandQueue[0].secondsToEndFromHere);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Stopwatch timeSinceStartedPrint = new Stopwatch();
|
|
public int SecondsRemaining
|
|
{
|
|
get
|
|
{
|
|
if (!timeSinceStartedPrint.IsRunning
|
|
&& PrinterIsPrinting)
|
|
{
|
|
timeSinceStartedPrint.Restart();
|
|
}
|
|
|
|
if (NumberOfLinesInCurrentPrint > 0)
|
|
{
|
|
if (printerCommandQueueIndex >= 0
|
|
&& printerCommandQueueIndex < loadedGCode.GCodeCommandQueue.Count
|
|
&& loadedGCode.GCodeCommandQueue[printerCommandQueueIndex].secondsToEndFromHere != 0)
|
|
{
|
|
if (FeedRateRatio != 0)
|
|
{
|
|
lastRemainingSecondsReported = (int)(loadedGCode.GCodeCommandQueue[printerCommandQueueIndex].secondsToEndFromHere / FeedRateRatio);
|
|
}
|
|
}
|
|
|
|
return lastRemainingSecondsReported;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public int SecondsPrinted
|
|
{
|
|
get
|
|
{
|
|
if (PrinterIsPrinting || PrinterIsPaused || PrintIsFinished)
|
|
{
|
|
return (int)(timeSinceStartedPrint.ElapsedMilliseconds / 1000);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public double PercentComplete
|
|
{
|
|
get
|
|
{
|
|
if (PrintIsFinished && !PrinterIsPaused)
|
|
{
|
|
return 100.0;
|
|
}
|
|
else if (NumberOfLinesInCurrentPrint > 0 && TotalSecondsInPrint > 0)
|
|
{
|
|
return Math.Min(99.9, ((1 - ((double)SecondsRemaining / (double)TotalSecondsInPrint)) * 100));
|
|
}
|
|
else
|
|
{
|
|
return 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void PrintingCanContinue(object sender, EventArgs e)
|
|
{
|
|
timeHaveBeenWaitingForOK.Stop();
|
|
}
|
|
|
|
System.Diagnostics.Stopwatch temperatureRequestTimer = new System.Diagnostics.Stopwatch();
|
|
public void OnIdle()
|
|
{
|
|
if (!temperatureRequestTimer.IsRunning)
|
|
{
|
|
temperatureRequestTimer.Start();
|
|
}
|
|
if (temperatureRequestTimer.ElapsedMilliseconds > 2000)
|
|
{
|
|
if (MonitorPrinterTemperature)
|
|
{
|
|
QueueLineToPrinter("M105");
|
|
}
|
|
temperatureRequestTimer.Restart();
|
|
}
|
|
|
|
bool waited30SeconsdForOk = timeHaveBeenWaitingForOK.Elapsed.Seconds > 30; // waited for more than 30 seconds
|
|
bool noResponseFor5Seconds = timeSinceLastReadAnything.Elapsed.Seconds > 5;
|
|
bool waitedToLongForOK = waited30SeconsdForOk && noResponseFor5Seconds;
|
|
while (LinesToWriteQueue.Count > 0 &&
|
|
(!timeHaveBeenWaitingForOK.IsRunning || waitedToLongForOK))
|
|
{
|
|
WriteNextLineFromQueue();
|
|
}
|
|
}
|
|
|
|
private void WriteNextLineFromQueue()
|
|
{
|
|
using (TimedLock.Lock(this, "WriteNextLine"))
|
|
{
|
|
string lineToWrite = LinesToWriteQueue[0];
|
|
|
|
WriteToPrinter(lineToWrite + "\r\n", lineToWrite);
|
|
LinesToWriteQueue.RemoveAt(0);
|
|
System.Threading.Thread.Sleep(1);
|
|
}
|
|
}
|
|
|
|
public double TargetExtruderTemperature
|
|
{
|
|
get
|
|
{
|
|
return targetExtruderTemperature;
|
|
}
|
|
set
|
|
{
|
|
if (targetExtruderTemperature != value)
|
|
{
|
|
targetExtruderTemperature = value;
|
|
OnExtruderTemperatureSet(new TemperatureEventArgs(TargetExtruderTemperature));
|
|
QueueLineToPrinter(string.Format("M104 S{0}", targetExtruderTemperature));
|
|
}
|
|
}
|
|
}
|
|
|
|
public double ActualExtruderTemperature
|
|
{
|
|
get
|
|
{
|
|
return actualExtruderTemperature;
|
|
}
|
|
}
|
|
|
|
public void HomeWasWritenToPrinter(object sender, EventArgs e)
|
|
{
|
|
if (ActivePrinter.DoPrintLeveling)
|
|
{
|
|
ReadPosition();
|
|
}
|
|
}
|
|
|
|
public void ExtruderTemperatureWasWritenToPrinter(object sender, EventArgs e)
|
|
{
|
|
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs;
|
|
|
|
string[] splitOnS = foundStringEventArgs.LineToCheck.Split('S');
|
|
if (splitOnS.Length == 2)
|
|
{
|
|
string temp = splitOnS[1];
|
|
try
|
|
{
|
|
double tempBeingSet = double.Parse(temp);
|
|
// we set the private variable so that we don't get the callbacks called and get in a loop of setting the temp
|
|
targetExtruderTemperature = tempBeingSet;
|
|
OnExtruderTemperatureSet(new TemperatureEventArgs(TargetExtruderTemperature));
|
|
}
|
|
catch
|
|
{
|
|
Debug.WriteLine(string.Format("Unable to Parse Extruder Temperature: {0}", temp));
|
|
}
|
|
}
|
|
}
|
|
|
|
int fanSpeed;
|
|
public int FanSpeed
|
|
{
|
|
get { return fanSpeed; }
|
|
set
|
|
{
|
|
fanSpeed = Math.Max(0, Math.Min(255, value));
|
|
OnFanSpeedSet(null);
|
|
QueueLineToPrinter(string.Format("M106 S{0}", fanSpeed));
|
|
}
|
|
}
|
|
|
|
public double TargetBedTemperature
|
|
{
|
|
get
|
|
{
|
|
return targetBedTemperature;
|
|
}
|
|
set
|
|
{
|
|
if (targetBedTemperature != value)
|
|
{
|
|
targetBedTemperature = value;
|
|
OnBedTemperatureSet(new TemperatureEventArgs(TargetBedTemperature));
|
|
QueueLineToPrinter(string.Format("M140 S{0}", targetBedTemperature));
|
|
}
|
|
}
|
|
}
|
|
|
|
public double ActualBedTemperature
|
|
{
|
|
get
|
|
{
|
|
return actualBedTemperature;
|
|
}
|
|
}
|
|
|
|
public void BedTemperatureWasWritenToPrinter(object sender, EventArgs e)
|
|
{
|
|
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs;
|
|
|
|
string[] splitOnS = foundStringEventArgs.LineToCheck.Split('S');
|
|
if (splitOnS.Length == 2)
|
|
{
|
|
string temp = splitOnS[1];
|
|
try
|
|
{
|
|
double tempBeingSet = double.Parse(temp);
|
|
if (TargetBedTemperature != tempBeingSet)
|
|
{
|
|
// we set the private variable so that we don't get the callbacks called and get in a loop of setting the temp
|
|
targetBedTemperature = tempBeingSet;
|
|
OnBedTemperatureSet(new TemperatureEventArgs(TargetBedTemperature));
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
Debug.WriteLine(string.Format("Unable to Parse Bed Temperature: {0}", temp));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void FanOffWasWritenToPrinter(object sender, EventArgs e)
|
|
{
|
|
fanSpeed = 0;
|
|
OnFanSpeedSet(null);
|
|
}
|
|
|
|
public void FanSpeedWasWritenToPrinter(object sender, EventArgs e)
|
|
{
|
|
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs;
|
|
|
|
string[] splitOnS = foundStringEventArgs.LineToCheck.Split('S');
|
|
if (splitOnS.Length != 2)
|
|
{
|
|
// when there is no explicit S value the assumption is 255
|
|
splitOnS = "M106 S255".Split('S');
|
|
}
|
|
|
|
if (splitOnS.Length == 2)
|
|
{
|
|
string fanSpeedString = splitOnS[1];
|
|
try
|
|
{
|
|
int fanSpeedBeingSet = int.Parse(fanSpeedString);
|
|
if (FanSpeed != fanSpeedBeingSet)
|
|
{
|
|
fanSpeed = fanSpeedBeingSet;
|
|
OnFanSpeedSet(null);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
Debug.WriteLine(string.Format("Unable to Parse Fan Speed: {0}", fanSpeed));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ReadPositions(object sender, EventArgs e)
|
|
{
|
|
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs;
|
|
|
|
string lineToParse = foundStringEventArgs.LineToCheck;
|
|
Vector3 positionRead = Vector3.Zero;
|
|
GCodeFile.GetFirstNumberAfter("X:", lineToParse, ref positionRead.x);
|
|
GCodeFile.GetFirstNumberAfter("Y:", lineToParse, ref positionRead.y);
|
|
GCodeFile.GetFirstNumberAfter("Z:", lineToParse, ref positionRead.z);
|
|
|
|
int xPosition = lineToParse.IndexOf('X');
|
|
int secondXPosition = lineToParse.IndexOf("Count", xPosition);
|
|
if (secondXPosition != -1)
|
|
{
|
|
Vector3 currentPositionRead = Vector3.Zero;
|
|
GCodeFile.GetFirstNumberAfter("X:", lineToParse, ref currentPositionRead.x, secondXPosition - 1);
|
|
GCodeFile.GetFirstNumberAfter("Y:", lineToParse, ref currentPositionRead.y, secondXPosition - 1);
|
|
GCodeFile.GetFirstNumberAfter("Z:", lineToParse, ref currentPositionRead.z, secondXPosition - 1);
|
|
|
|
lastReportedPosition = currentPositionRead;
|
|
}
|
|
else
|
|
{
|
|
// The firmware is only returning one x y z position so we need to use this as the position rather than
|
|
// assume the printer will hand us incremental positions
|
|
lastReportedPosition = positionRead;
|
|
}
|
|
|
|
if (currentDestination != positionRead)
|
|
{
|
|
currentDestination = positionRead;
|
|
DestinationChanged.CallEvents(this, null);
|
|
}
|
|
|
|
PositionRead.CallEvents(this, null);
|
|
}
|
|
|
|
public void ReadTemperatures(object sender, EventArgs e)
|
|
{
|
|
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs;
|
|
|
|
string temperatureString = foundStringEventArgs.LineToCheck;
|
|
{
|
|
int extruderTempLocationInString = temperatureString.IndexOf("T:");
|
|
if (extruderTempLocationInString > -1)
|
|
{
|
|
extruderTempLocationInString += 2;
|
|
int endOfExtruderTempInString = temperatureString.IndexOf(" ", extruderTempLocationInString);
|
|
if (endOfExtruderTempInString < 0)
|
|
{
|
|
endOfExtruderTempInString = temperatureString.Length;
|
|
}
|
|
|
|
string extruderTemp = temperatureString.Substring(extruderTempLocationInString, endOfExtruderTempInString - extruderTempLocationInString);
|
|
try
|
|
{
|
|
double readExtruderTemp = double.Parse(extruderTemp);
|
|
if (actualExtruderTemperature != readExtruderTemp)
|
|
{
|
|
actualExtruderTemperature = readExtruderTemp;
|
|
OnExtruderTemperatureRead(new TemperatureEventArgs(ActualExtruderTemperature));
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
Debug.WriteLine(string.Format("Unable to Parse Extruder Temperature: {0}", extruderTemp));
|
|
}
|
|
}
|
|
}
|
|
{
|
|
int bedTempLocationInString = temperatureString.IndexOf("B:");
|
|
if (bedTempLocationInString > -1)
|
|
{
|
|
bedTempLocationInString += 2;
|
|
int endOfbedTempInString = temperatureString.IndexOf(" ", bedTempLocationInString);
|
|
if (endOfbedTempInString < 0)
|
|
{
|
|
endOfbedTempInString = temperatureString.Length;
|
|
}
|
|
|
|
string bedTemp = temperatureString.Substring(bedTempLocationInString, endOfbedTempInString - bedTempLocationInString);
|
|
try
|
|
{
|
|
double readBedTemp = double.Parse(bedTemp);
|
|
if (actualBedTemperature != readBedTemp)
|
|
{
|
|
actualBedTemperature = readBedTemp;
|
|
OnBedTemperatureRead(new TemperatureEventArgs(ActualBedTemperature));
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
Debug.WriteLine(string.Format("Unable to Parse Bed Temperature: {0}", bedTemp));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MovementWasSetToAbsoluteMode(object sender, EventArgs e)
|
|
{
|
|
movementMode = PrinterMachineInstruction.MovementTypes.Absolute;
|
|
}
|
|
|
|
void MovementWasSetToRelativeMode(object sender, EventArgs e)
|
|
{
|
|
movementMode = PrinterMachineInstruction.MovementTypes.Relative;
|
|
}
|
|
|
|
void ExtruderWasSetToAbsoluteMode(object sender, EventArgs e)
|
|
{
|
|
extruderMode = PrinterMachineInstruction.MovementTypes.Absolute;
|
|
}
|
|
|
|
void ExtruderWasSetToRelativeMode(object sender, EventArgs e)
|
|
{
|
|
extruderMode = PrinterMachineInstruction.MovementTypes.Relative;
|
|
}
|
|
|
|
public void PrinterRequestsResend(object sender, EventArgs e)
|
|
{
|
|
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs;
|
|
|
|
string[] splitOnColon = foundStringEventArgs.LineToCheck.Split(':');
|
|
|
|
firstLineToResendIndex = int.Parse(splitOnColon[1]) - 1;
|
|
}
|
|
|
|
public void PrinterStatesFirmware(object sender, EventArgs e)
|
|
{
|
|
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs;
|
|
|
|
string firmwareName = "";
|
|
if (GCodeFile.GetFirstStringAfter("FIRMWARE_NAME:", foundStringEventArgs.LineToCheck, " ", ref firmwareName))
|
|
{
|
|
firmwareName = firmwareName.ToLower();
|
|
if (firmwareName.Contains("repetier"))
|
|
{
|
|
firmwareType = FirmwareTypes.Repetier;
|
|
}
|
|
else if (firmwareName.Contains("marlin"))
|
|
{
|
|
firmwareType = FirmwareTypes.Marlin;
|
|
}
|
|
else if (firmwareName.Contains("sprinter"))
|
|
{
|
|
firmwareType = FirmwareTypes.Sprinter;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void FoundStart(object sender, EventArgs e)
|
|
{
|
|
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs;
|
|
foundStringEventArgs.SendToDelegateFunctions = false;
|
|
}
|
|
|
|
public void SuppressEcho(object sender, EventArgs e)
|
|
{
|
|
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs;
|
|
foundStringEventArgs.SendToDelegateFunctions = false;
|
|
}
|
|
|
|
void ConnectionCallbackTimer(object state)
|
|
{
|
|
Timer t = (Timer)state;
|
|
if (!ContinueConnectionThread())
|
|
{
|
|
t.Dispose();
|
|
}
|
|
else
|
|
{
|
|
t.Change(100, 0);
|
|
}
|
|
}
|
|
|
|
bool ContinueConnectionThread()
|
|
{
|
|
if (CommunicationState == CommunicationStates.AttemptingToConnect)
|
|
{
|
|
if (this.stopTryingToConnect)
|
|
{
|
|
connectThread.Join(); //Halt connection thread
|
|
Disable();
|
|
connectionFailureMessage = "Cancelled";
|
|
OnConnectionFailed(null);
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else if (CommunicationState == CommunicationStates.FailedToConnect)
|
|
{
|
|
connectThread.Join();
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
connectThread.Join(); //Halt connection thread
|
|
OnConnectionSucceeded(null);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public void HaltConnectionThread()
|
|
{
|
|
this.stopTryingToConnect = true;
|
|
}
|
|
|
|
public void ConnectToActivePrinter()
|
|
{
|
|
if (PrinterCommunication.Instance.ActivePrinter != null)
|
|
{
|
|
ConnectToPrinter(PrinterCommunication.Instance.ActivePrinter);
|
|
}
|
|
}
|
|
|
|
public string ComPort
|
|
{
|
|
get
|
|
{
|
|
string comPort = null;
|
|
if (this.ActivePrinter != null)
|
|
{
|
|
comPort = this.ActivePrinter.ComPort;
|
|
|
|
}
|
|
return comPort;
|
|
}
|
|
}
|
|
|
|
public int BaudRate
|
|
{
|
|
get
|
|
{
|
|
int baudRate = 0;
|
|
if (this.ActivePrinter != null)
|
|
{
|
|
try
|
|
{
|
|
baudRate = Convert.ToInt32(this.ActivePrinter.BaudRate);
|
|
}
|
|
catch
|
|
{
|
|
Console.WriteLine("Unable to convert BaudRate to integer");
|
|
}
|
|
}
|
|
return baudRate;
|
|
}
|
|
}
|
|
|
|
private void ConnectToPrinter(Printer printerRecord)
|
|
{
|
|
LinesToWriteQueue.Clear();
|
|
//Attempt connecting to a specific printer
|
|
CommunicationState = CommunicationStates.AttemptingToConnect;
|
|
this.stopTryingToConnect = false;
|
|
firmwareType = FirmwareTypes.Unknown;
|
|
|
|
if (SerialPortIsAvailable(this.ActivePrinter.ComPort))
|
|
{
|
|
//Create a timed callback to determine whether connection succeeded
|
|
Timer connectionTimer = new Timer(new TimerCallback(ConnectionCallbackTimer));
|
|
connectionTimer.Change(100, 0);
|
|
|
|
//Create and start connection thread
|
|
connectThread = new Thread(Connect_Thread);
|
|
connectThread.Name = "Connect To Printer";
|
|
connectThread.IsBackground = true;
|
|
connectThread.Start();
|
|
}
|
|
else
|
|
{
|
|
Debug.WriteLine(string.Format("Connection failed: {0}", this.ActivePrinter.ComPort));
|
|
connectionFailureMessage = "Unavailable";
|
|
OnConnectionFailed(null);
|
|
}
|
|
}
|
|
|
|
void Connect_Thread()
|
|
{
|
|
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
|
// Allow the user to set the appropriate properties.
|
|
var portNames = SerialPort.GetPortNames();
|
|
//Debug.WriteLine(string.Format("Open ports: {0}", portNames.Length));
|
|
if (portNames.Length > 0)
|
|
{
|
|
//Debug.WriteLine(string.Format("Connecting to: {0} {1}", this.ActivePrinter.ComPort, this.BaudRate));
|
|
AttemptToConnect(this.ActivePrinter.ComPort, this.BaudRate);
|
|
if (CommunicationState == CommunicationStates.FailedToConnect)
|
|
{
|
|
OnConnectionFailed(null);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OnConnectionFailed(null);
|
|
}
|
|
}
|
|
|
|
public void OnConnectionSucceeded(EventArgs e)
|
|
{
|
|
CommunicationState = CommunicationStates.Connected;
|
|
|
|
ConnectionSucceeded.CallEvents(this, e);
|
|
|
|
OnEnabledChanged(e);
|
|
}
|
|
|
|
public void OnConnectionStateChanged(EventArgs e)
|
|
{
|
|
ConnectionStateChanged.CallEvents(this, e);
|
|
}
|
|
|
|
public void OnConnectionFailed(EventArgs e)
|
|
{
|
|
ConnectionFailed.CallEvents(this, e);
|
|
|
|
CommunicationState = CommunicationStates.FailedToConnect;
|
|
OnEnabledChanged(e);
|
|
}
|
|
|
|
//Function is not mac-friendly
|
|
bool SerialPortAlreadyOpen(string portName)
|
|
{
|
|
if (MatterHackers.Agg.UI.WindowsFormsAbstract.GetOSType() == WindowsFormsAbstract.OSType.Mac)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
int dwFlagsAndAttributes = 0x40000000;
|
|
|
|
//Borrowed from Microsoft's Serial Port Open Method :)
|
|
SafeFileHandle hFile = CreateFile(@"\\.\" + portName, -1073741824, 0, IntPtr.Zero, 3, dwFlagsAndAttributes, IntPtr.Zero);
|
|
if (hFile.IsInvalid)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
hFile.Close();
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool SerialPortIsAvailable(string portName)
|
|
//Check is serial port is in the list of available serial ports
|
|
{
|
|
try
|
|
{
|
|
string[] portNames = FrostedSerialPort.GetPortNames();
|
|
return portNames.Any(x => string.Compare(x, portName, true) == 0);
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
void AttemptToConnect(string serialPortName, int baudRate)
|
|
{
|
|
connectionFailureMessage = "Unknown Reason";
|
|
|
|
if (PrinterIsConnected)
|
|
{
|
|
throw new Exception("You can only connect when not currently connected.");
|
|
}
|
|
|
|
CommunicationState = CommunicationStates.AttemptingToConnect;
|
|
bool serialPortIsAvailable = SerialPortIsAvailable(serialPortName);
|
|
bool serialPortIsAlreadyOpen = SerialPortAlreadyOpen(serialPortName);
|
|
|
|
if (serialPortIsAvailable && !serialPortIsAlreadyOpen)
|
|
{
|
|
serialPort = new FrostedSerialPort(serialPortName);
|
|
serialPort.BaudRate = baudRate;
|
|
//serialPort.Parity = Parity.None;
|
|
//serialPort.DataBits = 8;
|
|
//serialPort.StopBits = StopBits.One;
|
|
//serialPort.Handshake = Handshake.None;
|
|
if (PrinterCommunication.Instance.DtrEnableOnConnect)
|
|
{
|
|
serialPort.DtrEnable = true;
|
|
}
|
|
|
|
// Set the read/write timeouts
|
|
serialPort.ReadTimeout = 500;
|
|
serialPort.WriteTimeout = 500;
|
|
|
|
if (CommunicationState == CommunicationStates.AttemptingToConnect)
|
|
{
|
|
try
|
|
{
|
|
serialPort.Open();
|
|
|
|
readFromPrinterThread = new Thread(ReadFromPrinter);
|
|
readFromPrinterThread.Name = "Read From Printer";
|
|
readFromPrinterThread.IsBackground = true;
|
|
readFromPrinterThread.Start();
|
|
|
|
// let's check if the printer will talk to us
|
|
ReadPosition();
|
|
QueueLineToPrinter("M105");
|
|
QueueLineToPrinter("M115");
|
|
}
|
|
catch (System.ArgumentOutOfRangeException)
|
|
{
|
|
connectionFailureMessage = "Unsupported Baud Rate";
|
|
OnConnectionFailed(null);
|
|
}
|
|
|
|
catch (Exception e)
|
|
{
|
|
OnConnectionFailed(null);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnPrintFinished(EventArgs e)
|
|
{
|
|
PrintFinished.CallEvents(this, new PrintItemWrapperEventArgs(this.ActivePrintItem));
|
|
}
|
|
|
|
void OnExtruderTemperatureRead(EventArgs e)
|
|
{
|
|
ExtruderTemperatureRead.CallEvents(this, e);
|
|
}
|
|
|
|
void OnBedTemperatureRead(EventArgs e)
|
|
{
|
|
BedTemperatureRead.CallEvents(this, e);
|
|
}
|
|
|
|
void OnExtruderTemperatureSet(EventArgs e)
|
|
{
|
|
ExtruderTemperatureSet.CallEvents(this, e);
|
|
}
|
|
|
|
void OnBedTemperatureSet(EventArgs e)
|
|
{
|
|
BedTemperatureSet.CallEvents(this, e);
|
|
}
|
|
|
|
void OnFanSpeedSet(EventArgs e)
|
|
{
|
|
FanSpeedSet.CallEvents(this, e);
|
|
}
|
|
|
|
void OnActivePrintItemChanged(EventArgs e)
|
|
{
|
|
ActivePrintItemChanged.CallEvents(this, e);
|
|
}
|
|
|
|
void OnEnabledChanged(EventArgs e)
|
|
{
|
|
EnableChanged.CallEvents(this, e);
|
|
}
|
|
|
|
string ApplyPrintLeveling(string lineBeingSent, bool addLFCR, bool includeSpaces)
|
|
{
|
|
if (lineBeingSent.StartsWith("G0 ") || lineBeingSent.StartsWith("G1 "))
|
|
{
|
|
Vector3 newDestination = currentDestination;
|
|
if (movementMode == PrinterMachineInstruction.MovementTypes.Relative)
|
|
{
|
|
newDestination = Vector3.Zero;
|
|
}
|
|
|
|
GCodeFile.GetFirstNumberAfter("X", lineBeingSent, ref newDestination.x);
|
|
GCodeFile.GetFirstNumberAfter("Y", lineBeingSent, ref newDestination.y);
|
|
GCodeFile.GetFirstNumberAfter("Z", lineBeingSent, ref newDestination.z);
|
|
|
|
if (movementMode == PrinterMachineInstruction.MovementTypes.Relative)
|
|
{
|
|
newDestination += currentDestination;
|
|
}
|
|
|
|
if (currentDestination != newDestination)
|
|
{
|
|
currentDestination = newDestination;
|
|
DestinationChanged.CallEvents(this, null);
|
|
}
|
|
|
|
if (ActivePrinter.DoPrintLeveling)
|
|
{
|
|
lineBeingSent = PrintLeveling.Instance.ApplyLeveling(currentDestination, movementMode, lineBeingSent, addLFCR, includeSpaces);
|
|
}
|
|
}
|
|
|
|
return lineBeingSent;
|
|
}
|
|
|
|
string ApplyExtrusionMultiplier(string lineBeingSent)
|
|
{
|
|
lineBeingSent = lineBeingSent.ToUpper().Trim();
|
|
if (lineBeingSent.StartsWith("G0") || lineBeingSent.StartsWith("G1"))
|
|
{
|
|
if (GCodeFile.GetFirstNumberAfter("E", lineBeingSent, ref gcodeRequestedExtrusionPosition))
|
|
{
|
|
double delta = gcodeRequestedExtrusionPosition - previousGcodeRequestedExtrusionPosition;
|
|
if (extruderMode == PrinterMachineInstruction.MovementTypes.Relative)
|
|
{
|
|
delta = gcodeRequestedExtrusionPosition;
|
|
}
|
|
double newActualExtruderPosition = currentActualExtrusionPosition + delta * ExtrusionRatio;
|
|
lineBeingSent = GCodeFile.ReplaceNumberAfter('E', lineBeingSent, newActualExtruderPosition);
|
|
previousGcodeRequestedExtrusionPosition = gcodeRequestedExtrusionPosition;
|
|
currentActualExtrusionPosition = newActualExtruderPosition;
|
|
}
|
|
}
|
|
else if (lineBeingSent.StartsWith("G92"))
|
|
{
|
|
if (GCodeFile.GetFirstNumberAfter("E", lineBeingSent, ref gcodeRequestedExtrusionPosition))
|
|
{
|
|
previousGcodeRequestedExtrusionPosition = gcodeRequestedExtrusionPosition;
|
|
currentActualExtrusionPosition = gcodeRequestedExtrusionPosition;
|
|
}
|
|
}
|
|
|
|
return lineBeingSent;
|
|
}
|
|
|
|
string ApplyFeedRateMultiplier(string lineBeingSent)
|
|
{
|
|
if (FeedRateRatio != 1)
|
|
{
|
|
lineBeingSent = lineBeingSent.ToUpper().Trim();
|
|
if (lineBeingSent.StartsWith("G0") || lineBeingSent.StartsWith("G1"))
|
|
{
|
|
double feedRate = 0;
|
|
if (GCodeFile.GetFirstNumberAfter("F", lineBeingSent, ref feedRate))
|
|
{
|
|
lineBeingSent = GCodeFile.ReplaceNumberAfter('F', lineBeingSent, feedRate * FeedRateRatio);
|
|
}
|
|
}
|
|
}
|
|
return lineBeingSent;
|
|
}
|
|
|
|
void SetDetailedPrintingState(string lineBeingSetToPrinter)
|
|
{
|
|
if (lineBeingSetToPrinter.StartsWith("G28"))
|
|
{
|
|
detailedPrintingState = DetailedPrintingState.HomingAxis;
|
|
}
|
|
else if (lineBeingSetToPrinter.StartsWith("M190"))
|
|
{
|
|
detailedPrintingState = DetailedPrintingState.HeatingBed;
|
|
}
|
|
else if (lineBeingSetToPrinter.StartsWith("M109"))
|
|
{
|
|
detailedPrintingState = DetailedPrintingState.HeatingExtruder;
|
|
}
|
|
else
|
|
{
|
|
detailedPrintingState = DetailedPrintingState.Printing;
|
|
}
|
|
}
|
|
|
|
public void QueueLineToPrinter(string lineToWrite)
|
|
{
|
|
//Check line for linebreaks, split and process separate if necessary
|
|
if (lineToWrite.Contains("\n"))
|
|
{
|
|
string[] lines = lineToWrite.Split(new string[] { "\n" }, StringSplitOptions.None);
|
|
foreach (string line in lines)
|
|
{
|
|
QueueLineToPrinter(line);
|
|
}
|
|
return;
|
|
}
|
|
|
|
lineToWrite = lineToWrite.Split(';')[0].Trim();
|
|
if (PrinterIsPrinting)
|
|
{
|
|
// Get the temperature during print.
|
|
if (printerCommandQueueIndex > 0
|
|
&& printerCommandQueueIndex < loadedGCode.GCodeCommandQueue.Count -1)
|
|
{
|
|
if (!loadedGCode.GCodeCommandQueue[printerCommandQueueIndex+1].Line.Contains(lineToWrite))
|
|
{
|
|
loadedGCode.GCodeCommandQueue.Insert(printerCommandQueueIndex + 1, new PrinterMachineInstruction(lineToWrite, loadedGCode.GCodeCommandQueue[printerCommandQueueIndex]));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// sometimes we need to send code without buffering (like when we are closing the program).
|
|
if (ForceImmediateWrites)
|
|
{
|
|
WriteToPrinter(lineToWrite + "\r\n", lineToWrite);
|
|
}
|
|
else
|
|
{
|
|
if (LinesToWriteQueue.Count == 0 || LinesToWriteQueue[LinesToWriteQueue.Count - 1] != lineToWrite)
|
|
{
|
|
LinesToWriteQueue.Add(lineToWrite);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void WriteChecksumLineToPrinter(string lineToWrite)
|
|
{
|
|
SetDetailedPrintingState(lineToWrite);
|
|
|
|
lineToWrite = ApplyExtrusionMultiplier(lineToWrite);
|
|
lineToWrite = ApplyFeedRateMultiplier(lineToWrite);
|
|
lineToWrite = ApplyPrintLeveling(lineToWrite, false, false);
|
|
|
|
string lineWithCount = "N" + (allCheckSumLinesSent.Count + 1).ToString() + " " + lineToWrite;
|
|
string lineWithChecksum = lineWithCount + "*" + GCodeFile.CalculateChecksum(lineWithCount);
|
|
WriteToPrinter(lineWithChecksum + "\r\n", lineToWrite);
|
|
allCheckSumLinesSent.Add(lineWithChecksum);
|
|
}
|
|
|
|
void WriteToPrinter(string lineToWrite, string lineWithoutChecksum)
|
|
{
|
|
if (PrinterIsConnected || CommunicationState == CommunicationStates.AttemptingToConnect)
|
|
{
|
|
if (serialPort != null && serialPort.IsOpen)
|
|
{
|
|
// write data to communication
|
|
{
|
|
StringEventArgs currentEvent = new StringEventArgs(lineToWrite);
|
|
CommunicationUnconditionalToPrinter.CallEvents(this, currentEvent);
|
|
|
|
if (lineWithoutChecksum != null)
|
|
{
|
|
FoundStringEventArgs foundStringEvent = new FoundStringEventArgs(lineWithoutChecksum);
|
|
WriteLineStartCallBacks.CheckForKeys(foundStringEvent);
|
|
WriteLineContainsCallBacks.CheckForKeys(foundStringEvent);
|
|
|
|
if (foundStringEvent.SendToDelegateFunctions)
|
|
{
|
|
WroteLine.CallEvents(this, currentEvent);
|
|
}
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
timeSinceLastReadAnything.Restart();
|
|
timeHaveBeenWaitingForOK.Restart();
|
|
serialPort.Write(lineToWrite);
|
|
}
|
|
catch (IOException)
|
|
{
|
|
OnConnectionFailed(null);
|
|
}
|
|
catch (TimeoutException)
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OnConnectionFailed(null);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void PulseRtsLow()
|
|
{
|
|
if (serialPort == null && this.ActivePrinter != null)
|
|
{
|
|
serialPort = new FrostedSerialPort(this.ActivePrinter.ComPort);
|
|
serialPort.BaudRate = this.BaudRate;
|
|
if (PrinterCommunication.Instance.DtrEnableOnConnect)
|
|
{
|
|
serialPort.DtrEnable = true;
|
|
}
|
|
|
|
// Set the read/write timeouts
|
|
serialPort.ReadTimeout = 500;
|
|
serialPort.WriteTimeout = 500;
|
|
serialPort.Open();
|
|
|
|
serialPort.RtsEnable = true;
|
|
serialPort.RtsEnable = false;
|
|
try
|
|
{
|
|
Thread.Sleep(1);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
serialPort.RtsEnable = true;
|
|
serialPort.Close();
|
|
}
|
|
}
|
|
|
|
public void Disable()
|
|
{
|
|
if (PrinterIsConnected)
|
|
{
|
|
// Make sure we send this without waiting for the printer to respond. We want to try and turn off the heaters.
|
|
// It may be possible in the future to make this go into the printer queue for assured sending but it means
|
|
// the program has to be smart about closing an able to wait until the printer has agreed that it shut off
|
|
// the motors and heaters (a good idea ane something for the future).
|
|
ForceImmediateWrites = true;
|
|
ReleaseMotors();
|
|
TargetExtruderTemperature = 0;
|
|
TargetBedTemperature = 0;
|
|
FanSpeed = 0;
|
|
ForceImmediateWrites = false;
|
|
|
|
CommunicationState = CommunicationStates.Disconnecting;
|
|
if (readFromPrinterThread != null)
|
|
{
|
|
readFromPrinterThread.Join();
|
|
}
|
|
serialPort.Close();
|
|
serialPort.Dispose();
|
|
serialPort = null;
|
|
CommunicationState = CommunicationStates.Disconnected;
|
|
LinesToWriteQueue.Clear();
|
|
}
|
|
OnEnabledChanged(null);
|
|
}
|
|
|
|
void SendCurrentGCodeFileToPrinter()
|
|
{
|
|
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
|
while (PrinterIsPrinting && PrinterIsConnected)
|
|
{
|
|
WriteNextLineFromGCodeFile();
|
|
}
|
|
}
|
|
|
|
Stopwatch timeSinceLastWrite = new Stopwatch();
|
|
void WriteNextLineFromGCodeFile()
|
|
{
|
|
timeSinceLastWrite.Restart();
|
|
if (PrinterIsConnected)
|
|
{
|
|
//bool forceResendInCaseOfOKError = false;
|
|
// wait until the printer responds from the last command with an ok OR we waited to long
|
|
while (PrinterIsPrinting && timeHaveBeenWaitingForOK.IsRunning)// && !forceResendInCaseOfOKError)
|
|
{
|
|
#if false
|
|
// this is a bunch of code to try and make sure the printer does not stop on transmission errors.
|
|
// It is not working and is currently disabled. It would be great to debug this and get it working. Lars.
|
|
// It has been more than 5 seconds since the printer responded anything
|
|
// and it was not ok, and it's been more than 10 second since we sent the command
|
|
if (timeSinceLastReadAnything.Elapsed.Seconds > 5 && timeSinceLastWrite.Elapsed.Seconds > 10)
|
|
{
|
|
// we are still sending commands
|
|
if (printerCommandQueueIndex > 0 && printerCommandQueueIndex < loadedGCode.GCodeCommandQueue.Count)
|
|
{
|
|
// the last instruction was a move
|
|
PrinterMachineInstruction lastInstruction = loadedGCode.GCodeCommandQueue[printerCommandQueueIndex - 1];
|
|
if (firstLineToResendIndex == allCheckSumLinesSent.Count)
|
|
{
|
|
// Basically we got some response but it did not contain an OK.
|
|
// The theory is that we may have recieved a transmission error (like 'OP' rather than 'OK')
|
|
// and in that event we don't want the print to just stop and wait forever.
|
|
forceResendInCaseOfOKError = true;
|
|
firstLineToResendIndex--; // we are going to resend the last command
|
|
}
|
|
}
|
|
}
|
|
|
|
bool printerWantsResend = firstLineToResendIndex < allCheckSumLinesSent.Count;
|
|
if (printerWantsResend)
|
|
{
|
|
forceResendInCaseOfOKError = true;
|
|
}
|
|
#endif
|
|
|
|
// we are waiting for ok so wait some time
|
|
System.Threading.Thread.Sleep(1);
|
|
}
|
|
|
|
using (TimedLock.Lock(this, "WriteNextLine"))
|
|
{
|
|
if (PrinterIsPrinting && printerCommandQueueIndex < loadedGCode.GCodeCommandQueue.Count)
|
|
{
|
|
if (firstLineToResendIndex < allCheckSumLinesSent.Count)
|
|
{
|
|
WriteToPrinter(allCheckSumLinesSent[firstLineToResendIndex++], null);
|
|
}
|
|
else
|
|
{
|
|
string lineToWrite = loadedGCode.GCodeCommandQueue[printerCommandQueueIndex].Line;
|
|
WriteChecksumLineToPrinter(lineToWrite);
|
|
printerCommandQueueIndex++;
|
|
firstLineToResendIndex++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (printerCommandQueueIndex == loadedGCode.GCodeCommandQueue.Count)
|
|
{
|
|
printJobDisplayName = null;
|
|
|
|
// never leave the extruder and the bed hot
|
|
ReleaseMotors();
|
|
TargetExtruderTemperature = 0;
|
|
TargetBedTemperature = 0;
|
|
|
|
CommunicationState = CommunicationStates.FinishedPrint;
|
|
}
|
|
else if (!PrinterIsPaused)
|
|
{
|
|
CommunicationState = CommunicationStates.Connected;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Pause()
|
|
{
|
|
if (PrinterIsPrinting)
|
|
{
|
|
CommunicationState = CommunicationStates.Paused;
|
|
if (sendGCodeToPrinterThread != null)
|
|
{
|
|
sendGCodeToPrinterThread.Join();
|
|
}
|
|
sendGCodeToPrinterThread = null;
|
|
|
|
#if PAUSE_INJECTION
|
|
// Add the pause_gcode to the loadedGCode.GCodeCommandQueue
|
|
string pauseGCode = ActiveSliceSettings.Instance.GetActiveValue("pause_gcode");
|
|
int lastIndexAdded = InjectGCode(pauseGCode, printerCommandQueueIndex);
|
|
|
|
// inject a marker to tell when we are done with the inserted pause code
|
|
lastIndexAdded = InjectGCode("MH_Pause", lastIndexAdded);
|
|
|
|
// inject the resume_gcode to execute when we resume printing
|
|
string resumeGCode = ActiveSliceSettings.Instance.GetActiveValue("resume_gcode");
|
|
lastIndexAdded = InjectGCode("MH_Pause", lastIndexAdded);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
private int InjectGCode(string codeToInject, int indexToStartInjection)
|
|
{
|
|
string[] lines = codeToInject.Split('\n');
|
|
|
|
foreach (string line in lines)
|
|
{
|
|
loadedGCode.GCodeCommandQueue.Insert(indexToStartInjection, new PrinterMachineInstruction(line, loadedGCode.GCodeCommandQueue[indexToStartInjection]));
|
|
indexToStartInjection++;
|
|
}
|
|
|
|
return indexToStartInjection;
|
|
}
|
|
|
|
public void Resume()
|
|
{
|
|
if (PrinterIsPaused)
|
|
{
|
|
CommunicationState = CommunicationStates.Printing;
|
|
sendGCodeToPrinterThread = new Thread(SendCurrentGCodeFileToPrinter);
|
|
sendGCodeToPrinterThread.Name = "sendGCodeToPrinterThread - Resume";
|
|
sendGCodeToPrinterThread.IsBackground = true;
|
|
sendGCodeToPrinterThread.Start();
|
|
}
|
|
}
|
|
|
|
public void ResetToReadyState()
|
|
{
|
|
if (CommunicationState == CommunicationStates.FinishedPrint)
|
|
{
|
|
CommunicationState = CommunicationStates.Connected;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("You should only reset after a print has finished.");
|
|
}
|
|
}
|
|
|
|
void ClearQueuedGCode()
|
|
{
|
|
loadedGCode.GCodeCommandQueue.Clear();
|
|
printerCommandQueueIndex = 0;
|
|
lastRemainingSecondsReported = 0;
|
|
|
|
allCheckSumLinesSent.Clear();
|
|
WriteChecksumLineToPrinter("M110 S1");
|
|
firstLineToResendIndex = 1;
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
switch (CommunicationState)
|
|
{
|
|
case CommunicationStates.Printing:
|
|
#if CANCEL_INJECTION
|
|
{
|
|
//Only run cancel gcode if actively printing.
|
|
string cancelGCode = ActiveSliceSettings.Instance.GetActiveValue("cancel_gcode");
|
|
WriteLineToPrinter(cancelGCode);
|
|
}
|
|
break;
|
|
#endif
|
|
{
|
|
CommunicationState = CommunicationStates.Connected;
|
|
if (sendGCodeToPrinterThread != null)
|
|
{
|
|
sendGCodeToPrinterThread.Join();
|
|
sendGCodeToPrinterThread = null;
|
|
}
|
|
ClearQueuedGCode();
|
|
ReleaseMotors();
|
|
TargetExtruderTemperature = 0;
|
|
TargetBedTemperature = 0;
|
|
}
|
|
break;
|
|
|
|
case CommunicationStates.Paused:
|
|
{
|
|
CommunicationState = CommunicationStates.Connected;
|
|
if (sendGCodeToPrinterThread != null)
|
|
{
|
|
sendGCodeToPrinterThread.Join();
|
|
sendGCodeToPrinterThread = null;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CommunicationStates.AttemptingToConnect:
|
|
CommunicationState = CommunicationStates.FailedToConnect;
|
|
connectThread.Join();
|
|
CommunicationState = CommunicationStates.Disconnecting;
|
|
if (readFromPrinterThread != null)
|
|
{
|
|
readFromPrinterThread.Join();
|
|
}
|
|
if (serialPort != null)
|
|
{
|
|
serialPort.Close();
|
|
serialPort.Dispose();
|
|
serialPort = null;
|
|
}
|
|
CommunicationState = CommunicationStates.Disconnected;
|
|
break;
|
|
|
|
case CommunicationStates.PreparingToPrint:
|
|
CommunicationState = CommunicationStates.Connected;
|
|
break;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
string lineBeingRead = "";
|
|
string lastLineRead = "";
|
|
public void ReadFromPrinter()
|
|
{
|
|
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
|
timeSinceLastReadAnything.Restart();
|
|
// we want this while loop to be as fast as possible. Don't allow any significant work to happen in here
|
|
while (CommunicationState == CommunicationStates.AttemptingToConnect
|
|
|| (PrinterIsConnected && serialPort.IsOpen && !Disconnecting))
|
|
{
|
|
try
|
|
{
|
|
while (serialPort.BytesToRead > 0)
|
|
{
|
|
char nextChar = (char)serialPort.ReadChar();
|
|
using (TimedLock.Lock(this, "ReadNextChar"))
|
|
{
|
|
if (nextChar == '\r' || nextChar == '\n')
|
|
{
|
|
lastLineRead = lineBeingRead;
|
|
lineBeingRead = "";
|
|
|
|
// process this command
|
|
{
|
|
StringEventArgs currentEvent = new StringEventArgs(lastLineRead);
|
|
CommunicationUnconditionalFromPrinter.CallEvents(this, currentEvent);
|
|
|
|
FoundStringEventArgs foundResponse = new FoundStringEventArgs(currentEvent.Data);
|
|
ReadLineStartCallBacks.CheckForKeys(foundResponse);
|
|
ReadLineContainsCallBacks.CheckForKeys(foundResponse);
|
|
|
|
if (foundResponse.SendToDelegateFunctions)
|
|
{
|
|
ReadLine.CallEvents(this, currentEvent);
|
|
}
|
|
}
|
|
|
|
if (CommunicationState == CommunicationStates.AttemptingToConnect)
|
|
{
|
|
CommunicationState = CommunicationStates.Connected;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lineBeingRead += nextChar;
|
|
}
|
|
timeSinceLastReadAnything.Restart();
|
|
}
|
|
}
|
|
|
|
Thread.Sleep(1);
|
|
}
|
|
catch (TimeoutException)
|
|
{
|
|
}
|
|
catch (IOException)
|
|
{
|
|
OnConnectionFailed(null);
|
|
}
|
|
catch (InvalidOperationException)
|
|
{
|
|
// this happens when the serial port closes after we check and before we read it.
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
OnConnectionFailed(null);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ReleaseMotors()
|
|
{
|
|
QueueLineToPrinter("M84");
|
|
}
|
|
|
|
[Flags]
|
|
public enum Axis { X = 1, Y = 2, Z = 4, E = 8, XYZ = (X | Y | Z) }
|
|
public void HomeAxis(Axis axis)
|
|
{
|
|
string command = "G28";
|
|
if ((axis & Axis.X) == Axis.X)
|
|
{
|
|
command += " X0";
|
|
}
|
|
if ((axis & Axis.Y) == Axis.Y)
|
|
{
|
|
command += " Y0";
|
|
}
|
|
if ((axis & Axis.Z) == Axis.Z)
|
|
{
|
|
command += " Z0";
|
|
}
|
|
|
|
QueueLineToPrinter(command);
|
|
ReadPosition();
|
|
}
|
|
|
|
public void SetMovementToAbsolute()
|
|
{
|
|
PrinterCommunication.Instance.QueueLineToPrinter("G90");
|
|
}
|
|
|
|
public void SetMovementToRelative()
|
|
{
|
|
PrinterCommunication.Instance.QueueLineToPrinter("G91");
|
|
}
|
|
|
|
public void MoveRelative(Axis axis, double moveAmountMm, double feedRateMmPerMinute)
|
|
{
|
|
if (moveAmountMm != 0)
|
|
{
|
|
SetMovementToRelative();
|
|
PrinterCommunication.Instance.QueueLineToPrinter(string.Format("G1 F{0}", feedRateMmPerMinute));
|
|
PrinterCommunication.Instance.QueueLineToPrinter(string.Format("G1 {0}{1}", axis, moveAmountMm));
|
|
SetMovementToAbsolute();
|
|
}
|
|
}
|
|
|
|
public void MoveAbsolute(Axis axis, double axisPositionMm, double feedRateMmPerMinute)
|
|
{
|
|
SetMovementToAbsolute();
|
|
PrinterCommunication.Instance.QueueLineToPrinter(string.Format("G1 F{0}", feedRateMmPerMinute));
|
|
PrinterCommunication.Instance.QueueLineToPrinter(string.Format("G1 {0}{1}", axis, axisPositionMm));
|
|
}
|
|
|
|
public void MoveAbsolute(Vector3 position, double feedRateMmPerMinute)
|
|
{
|
|
SetMovementToAbsolute();
|
|
PrinterCommunication.Instance.QueueLineToPrinter(string.Format("G1 F{0}", feedRateMmPerMinute));
|
|
PrinterCommunication.Instance.QueueLineToPrinter(string.Format("G1 X{0}Y{1}Z{2}", position.x, position.y, position.z));
|
|
}
|
|
|
|
public void ReadPosition()
|
|
{
|
|
QueueLineToPrinter("M114");
|
|
}
|
|
}
|
|
}
|