2014-01-29 19:09:30 -08:00
/ *
2014-02-15 18:06:03 -08:00
Copyright ( c ) 2014 , Lars Brubaker
2014-01-29 19:09:30 -08:00
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.Diagnostics ;
2014-03-05 10:33:19 -08:00
using System.Globalization ;
2014-01-29 19:09:30 -08:00
using System.IO ;
2014-03-05 10:33:19 -08:00
using System.Linq ;
2014-01-29 19:09:30 -08:00
using System.Runtime.InteropServices ;
2014-03-05 10:33:19 -08:00
using System.Threading ;
2014-01-29 19:09:30 -08:00
using MatterHackers.Agg ;
2014-06-19 16:09:38 -07:00
using MatterHackers.Agg.PlatformAbstract ;
2014-01-29 19:09:30 -08:00
using MatterHackers.Agg.UI ;
using MatterHackers.GCodeVisualizer ;
using MatterHackers.Localizations ;
2014-06-11 14:52:58 -07:00
using MatterHackers.MatterControl.ConfigurationPage.PrintLeveling ;
2014-03-05 10:33:19 -08:00
using MatterHackers.MatterControl.DataStorage ;
using MatterHackers.MatterControl.PrintQueue ;
2014-06-11 14:52:58 -07:00
using MatterHackers.MatterControl.SlicerConfiguration ;
2014-03-05 10:33:19 -08:00
using MatterHackers.SerialPortCommunication ;
using M atterHackers.SerialPortCommunication.FrostedSerial ;
using MatterHackers.VectorMath ;
using Microsoft.Win32.SafeHandles ;
2014-01-29 19:09:30 -08:00
2014-06-11 14:52:58 -07:00
namespace MatterHackers.MatterControl.PrinterCommunication
2014-01-29 19:09:30 -08:00
{
/// <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
{
2014-10-15 17:04:14 -07:00
int index0Based ;
2014-01-29 19:09:30 -08:00
double temperature ;
2014-10-15 17:04:14 -07:00
public int Index0Based
2014-01-29 19:09:30 -08:00
{
2014-10-15 17:04:14 -07:00
get { return index0Based ; }
2014-01-29 19:09:30 -08:00
}
public double Temperature
{
get { return temperature ; }
}
2014-10-15 17:04:14 -07:00
public TemperatureEventArgs ( int index0Based , double temperature )
{
this . index0Based = index0Based ;
this . temperature = temperature ;
}
2014-01-29 19:09:30 -08:00
}
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>
2014-06-11 14:52:58 -07:00
public class PrinterConnectionAndCommunication
2014-01-29 19:09:30 -08:00
{
2014-06-23 17:12:55 -07:00
readonly int JoinThreadTimeoutMs = 5000 ;
2014-01-29 19:09:30 -08:00
[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 ) ;
2014-02-18 17:52:50 -08:00
public enum FirmwareTypes { Unknown , Repetier , Marlin , Sprinter } ;
FirmwareTypes firmwareType = FirmwareTypes . Unknown ;
public FirmwareTypes FirmwareType
{
get { return firmwareType ; }
}
2014-03-05 12:16:52 -08:00
string firmwareVersion ;
public string FirmwareVersion
{
get { return firmwareVersion ; }
}
2014-08-19 11:13:52 -07:00
string deviceCode ;
public string DeviceCode
{
get { return deviceCode ; }
}
2014-06-11 14:52:58 -07:00
static PrinterConnectionAndCommunication globalInstance ;
2014-01-29 19:09:30 -08:00
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 ( ) ;
2014-02-20 18:25:23 -08:00
public RootedObjectEventHandler CommunicationUnconditionalFromPrinter = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler CommunicationUnconditionalToPrinter = new RootedObjectEventHandler ( ) ;
2014-01-29 19:09:30 -08:00
public RootedObjectEventHandler ConnectionFailed = new RootedObjectEventHandler ( ) ;
2014-05-30 14:37:30 -07:00
public RootedObjectEventHandler CommunicationStateChanged = new RootedObjectEventHandler ( ) ;
2014-01-29 19:09:30 -08:00
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 ( ) ;
2014-03-05 12:16:52 -08:00
public RootedObjectEventHandler FirmwareVersionRead = new RootedObjectEventHandler ( ) ;
2014-01-29 19:09:30 -08:00
public RootedObjectEventHandler PrintFinished = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler PositionRead = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler ReadLine = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler WroteLine = new RootedObjectEventHandler ( ) ;
2014-06-23 13:18:51 -07:00
public RootedObjectEventHandler PrintingStateChanged = new RootedObjectEventHandler ( ) ;
2014-01-29 19:09:30 -08:00
FoundStringStartsWithCallbacks ReadLineStartCallBacks = new FoundStringStartsWithCallbacks ( ) ;
FoundStringContainsCallbacks ReadLineContainsCallBacks = new FoundStringContainsCallbacks ( ) ;
FoundStringStartsWithCallbacks WriteLineStartCallBacks = new FoundStringStartsWithCallbacks ( ) ;
FoundStringContainsCallbacks WriteLineContainsCallBacks = new FoundStringContainsCallbacks ( ) ;
2014-03-17 14:41:36 -07:00
bool printWasCanceled = false ;
2014-01-29 19:09:30 -08:00
int firstLineToResendIndex = 0 ;
2014-03-25 17:31:57 -07:00
PrintTask activePrintTask ;
2014-01-29 19:09:30 -08:00
List < string > allCheckSumLinesSent = new List < string > ( ) ;
List < string > LinesToWriteQueue = new List < string > ( ) ;
Stopwatch timeSinceLastReadAnything = new Stopwatch ( ) ;
Stopwatch timeHaveBeenWaitingForOK = new Stopwatch ( ) ;
2014-06-26 18:13:53 -07:00
public enum CommunicationStates
{
Disconnected ,
AttemptingToConnect ,
FailedToConnect ,
Connected ,
PreparingToPrint ,
Printing ,
PreparingToPrintToSd ,
PrintingToSd ,
PrintingFromSd ,
Paused ,
FinishedPrint ,
Disconnecting ,
ConnectionLost
} ;
2014-01-29 19:09:30 -08:00
CommunicationStates communicationState = CommunicationStates . Disconnected ;
2014-02-04 10:51:06 -08:00
bool ForceImmediateWrites = false ;
2014-01-29 19:09:30 -08:00
public CommunicationStates CommunicationState
{
get
{
return communicationState ;
}
set
{
if ( communicationState ! = value )
{
2014-06-25 17:28:28 -07:00
switch ( communicationState )
2014-01-29 19:09:30 -08:00
{
2014-06-25 17:28:28 -07:00
// if it was printing
case CommunicationStates . PrintingToSd :
case CommunicationStates . Printing :
2014-03-25 17:31:57 -07:00
{
2014-06-25 17:28:28 -07:00
// and is changing to paused
if ( value = = CommunicationStates . Paused )
{
timeSinceStartedPrint . Stop ( ) ;
}
else if ( value = = CommunicationStates . FinishedPrint )
{
if ( activePrintTask ! = null )
{
TimeSpan printTimeSpan = DateTime . Now . Subtract ( activePrintTask . PrintStart ) ;
activePrintTask . PrintEnd = DateTime . Now ;
activePrintTask . PrintComplete = true ;
activePrintTask . Commit ( ) ;
}
// Set this early as we always want our functions to know the state we are in.
communicationState = value ;
timeSinceStartedPrint . Stop ( ) ;
OnPrintFinished ( null ) ;
}
else
{
timeSinceStartedPrint . Stop ( ) ;
timeSinceStartedPrint . Reset ( ) ;
}
}
break ;
2014-03-25 17:31:57 -07:00
2014-06-25 17:28:28 -07:00
// was paused
case CommunicationStates . Paused :
{
// changing to printing
if ( value = = CommunicationStates . Printing )
{
timeSinceStartedPrint . Start ( ) ;
}
2014-03-25 17:31:57 -07:00
}
2014-06-25 17:28:28 -07:00
break ;
2014-01-29 19:09:30 -08:00
}
communicationState = value ;
2014-05-30 14:37:30 -07:00
OnCommunicationStateChanged ( null ) ;
2014-01-29 19:09:30 -08:00
}
}
}
bool stopTryingToConnect = false ;
2014-10-20 17:02:25 -07:00
static readonly int MAX_EXTRUDERS = 16 ;
2014-10-15 17:04:14 -07:00
double [ ] actualExtruderTemperature = new double [ MAX_EXTRUDERS ] ;
double [ ] targetExtruderTemperature = new double [ MAX_EXTRUDERS ] ;
2014-01-29 19:09:30 -08:00
double actualBedTemperature ;
double targetBedTemperature ;
string printJobDisplayName = null ;
GCodeFile loadedGCode = new GCodeFile ( ) ;
2014-10-19 08:46:20 -07:00
IFrostedSerialPort serialPort ;
2014-01-29 19:09:30 -08:00
Thread readFromPrinterThread ;
Thread connectThread ;
private PrintItemWrapper activePrintItem ;
int lastRemainingSecondsReported = 0 ;
int printerCommandQueueIndex = - 1 ;
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 ) ;
}
}
}
2014-02-14 12:06:44 -08:00
private Printer ActivePrinter
2014-01-29 19:09:30 -08:00
{
get
{
2014-02-14 11:54:21 -08:00
return ActivePrinterProfile . Instance . ActivePrinter ;
2014-01-29 19:09:30 -08:00
}
set
{
2014-02-14 11:54:21 -08:00
ActivePrinterProfile . Instance . ActivePrinter = value ;
2014-01-29 19:09:30 -08:00
}
}
public PrintItemWrapper ActivePrintItem
{
get
{
return this . activePrintItem ;
}
set
{
2014-06-11 14:52:58 -07:00
if ( ! PrinterConnectionAndCommunication . Instance . PrinterIsPrinting )
2014-01-29 19:09:30 -08:00
{
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 :
2014-06-25 17:28:28 -07:00
case CommunicationStates . PreparingToPrintToSd :
2014-01-29 19:09:30 -08:00
case CommunicationStates . Printing :
2014-06-25 17:28:28 -07:00
case CommunicationStates . PrintingToSd :
2014-06-20 17:54:39 -07:00
case CommunicationStates . PrintingFromSd :
2014-01-29 19:09:30 -08:00
case CommunicationStates . Paused :
case CommunicationStates . FinishedPrint :
return true ;
default :
throw new NotImplementedException ( "Make sure very satus returns the correct connected state." ) ;
}
}
}
2014-06-11 14:52:58 -07:00
public static PrinterConnectionAndCommunication Instance
2014-01-29 19:09:30 -08:00
{
get
{
if ( globalInstance = = null )
{
2014-06-11 14:52:58 -07:00
globalInstance = new PrinterConnectionAndCommunication ( ) ;
2014-01-29 19:09:30 -08:00
}
return globalInstance ;
}
}
2014-06-11 14:52:58 -07:00
PrinterConnectionAndCommunication ( )
2014-01-29 19:09:30 -08:00
{
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 ) ;
2014-06-25 17:28:28 -07:00
ReadLineStartCallBacks . AddCallBackToKey ( "Done saving file" , PrintingCanContinue ) ;
2014-01-29 19:09:30 -08:00
2014-02-18 17:52:50 -08:00
ReadLineStartCallBacks . AddCallBackToKey ( "ok T:" , ReadTemperatures ) ; // marlin
2014-10-15 17:04:14 -07:00
ReadLineStartCallBacks . AddCallBackToKey ( "ok T0:" , ReadTemperatures ) ; // marlin
2014-01-29 19:09:30 -08:00
ReadLineStartCallBacks . AddCallBackToKey ( "T:" , ReadTemperatures ) ; // repatier
2014-10-18 15:50:03 -07:00
ReadLineStartCallBacks . AddCallBackToKey ( "B:" , ReadTemperatures ) ; // smoothie
2014-01-29 19:09:30 -08:00
2014-06-26 18:13:53 -07:00
ReadLineStartCallBacks . AddCallBackToKey ( "SD printing byte" , ReadSdProgress ) ; // repatier
2014-05-13 13:28:34 -07:00
ReadLineStartCallBacks . AddCallBackToKey ( "C:" , ReadTargetPositions ) ;
2014-08-01 17:46:39 -07:00
ReadLineStartCallBacks . AddCallBackToKey ( "ok C:" , ReadTargetPositions ) ; // smoothie is reporting the C: with an ok first.
2014-05-13 13:28:34 -07:00
ReadLineStartCallBacks . AddCallBackToKey ( "X:" , ReadTargetPositions ) ;
2014-01-29 19:09:30 -08:00
ReadLineContainsCallBacks . AddCallBackToKey ( "RS:" , PrinterRequestsResend ) ;
ReadLineContainsCallBacks . AddCallBackToKey ( "Resend:" , PrinterRequestsResend ) ;
2014-02-18 17:52:50 -08:00
ReadLineContainsCallBacks . AddCallBackToKey ( "FIRMWARE_NAME:" , PrinterStatesFirmware ) ;
2014-01-29 19:09:30 -08:00
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 ;
}
2014-11-06 13:47:09 -08:00
public bool PrintIsActive
{
get
{
switch ( CommunicationState )
{
case CommunicationStates . Disconnected :
case CommunicationStates . Disconnecting :
case CommunicationStates . AttemptingToConnect :
case CommunicationStates . ConnectionLost :
case CommunicationStates . FailedToConnect :
case CommunicationStates . Connected :
case CommunicationStates . FinishedPrint :
return false ;
case CommunicationStates . Printing :
case CommunicationStates . PrintingToSd :
case CommunicationStates . PrintingFromSd :
case CommunicationStates . PreparingToPrint :
case CommunicationStates . PreparingToPrintToSd :
case CommunicationStates . Paused :
return true ;
default :
throw new NotImplementedException ( "Make sure every status returns the correct connected state." ) ;
}
}
}
2014-01-29 19:09:30 -08:00
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 :
2014-06-25 17:28:28 -07:00
case CommunicationStates . PreparingToPrintToSd :
2014-01-29 19:09:30 -08:00
case CommunicationStates . Paused :
case CommunicationStates . FinishedPrint :
return false ;
case CommunicationStates . Printing :
2014-06-25 17:28:28 -07:00
case CommunicationStates . PrintingToSd :
2014-06-23 09:31:14 -07:00
case CommunicationStates . PrintingFromSd :
2014-01-29 19:09:30 -08:00
return true ;
default :
2014-11-06 13:47:09 -08:00
throw new NotImplementedException ( "Make sure every status returns the correct connected state." ) ;
2014-01-29 19:09:30 -08:00
}
}
}
public enum DetailedPrintingState { HomingAxis , HeatingBed , HeatingExtruder , Printing } ;
2014-06-23 13:18:51 -07:00
DetailedPrintingState printingStatePrivate ;
2014-01-29 19:09:30 -08:00
public DetailedPrintingState PrintingState
{
get
{
2014-06-23 13:18:51 -07:00
return printingStatePrivate ;
}
set
{
if ( printingStatePrivate ! = value )
{
printingStatePrivate = value ;
PrintingStateChanged . CallEvents ( this , null ) ;
}
2014-01-29 19:09:30 -08:00
}
}
public string PrintingStateString
{
get
{
2014-06-23 13:18:51 -07:00
switch ( PrintingState )
2014-01-29 19:09:30 -08:00
{
case DetailedPrintingState . HomingAxis :
return "Homing Axis" ;
case DetailedPrintingState . HeatingBed :
2014-03-16 10:23:56 -07:00
return "Waiting for Bed to Heat to {0}°" . FormatWith ( TargetBedTemperature ) ;
2014-01-29 19:09:30 -08:00
case DetailedPrintingState . HeatingExtruder :
2014-10-15 17:04:14 -07:00
return "Waiting for Extruder to Heat to {0}°" . FormatWith ( GetTargetExtruderTemperature ( 0 ) ) ;
2014-01-29 19:09:30 -08:00
case DetailedPrintingState . Printing :
return "Currently Printing:" ;
default :
return "" ;
}
}
}
public string PrinterConnectionStatusVerbose
{
get
{
switch ( CommunicationState )
{
case CommunicationStates . Disconnected :
2014-06-25 17:28:28 -07:00
return "Not Connected" . Localize ( ) ;
2014-01-29 19:09:30 -08:00
case CommunicationStates . Disconnecting :
2014-06-25 17:28:28 -07:00
return "Disconnecting" . Localize ( ) ;
2014-10-19 08:46:20 -07:00
case CommunicationStates . AttemptingToConnect :
2014-06-25 17:28:28 -07:00
string connectingMessageTxt = "Connecting" . Localize ( ) ;
2014-10-19 08:46:20 -07:00
return "{0}..." . FormatWith ( connectingMessageTxt ) ;
2014-01-29 19:09:30 -08:00
case CommunicationStates . ConnectionLost :
2014-06-25 17:28:28 -07:00
return "Connection Lost" . Localize ( ) ;
2014-01-29 19:09:30 -08:00
case CommunicationStates . FailedToConnect :
2014-03-16 10:23:56 -07:00
return "Unable to Connect" ;
2014-01-29 19:09:30 -08:00
case CommunicationStates . Connected :
2014-06-25 17:28:28 -07:00
return "Connected" . Localize ( ) ;
2014-01-29 19:09:30 -08:00
case CommunicationStates . PreparingToPrint :
2014-06-25 17:28:28 -07:00
return "Preparing To Print" . Localize ( ) ;
case CommunicationStates . PreparingToPrintToSd :
return "Preparing To Send To SD Card" . Localize ( ) ;
2014-01-29 19:09:30 -08:00
case CommunicationStates . Printing :
2014-06-25 17:28:28 -07:00
return "Printing" . Localize ( ) ;
case CommunicationStates . PrintingToSd :
return "Sending To SD Card" . Localize ( ) ;
2014-06-23 09:31:14 -07:00
case CommunicationStates . PrintingFromSd :
return "Printing From SD Card" . Localize ( ) ;
2014-01-29 19:09:30 -08:00
case CommunicationStates . Paused :
2014-06-25 17:28:28 -07:00
return "Paused" . Localize ( ) ;
2014-01-29 19:09:30 -08:00
case CommunicationStates . FinishedPrint :
2014-06-25 17:28:28 -07:00
return "Finished Print" . Localize ( ) ;
2014-01-29 19:09:30 -08:00
default :
2014-06-23 09:31:14 -07:00
throw new NotImplementedException ( "Make sure every satus returns the correct connected state." ) ;
2014-01-29 19:09:30 -08:00
}
}
}
public string PrintJobName
{
get
{
return printJobDisplayName ;
}
}
public bool PrintIsFinished
{
get
{
return CommunicationState = = CommunicationStates . FinishedPrint ;
}
}
public bool PrinterIsPaused
{
get
{
return CommunicationState = = CommunicationStates . Paused ;
}
2014-03-05 12:16:52 -08:00
}
2014-01-29 19:09:30 -08:00
int NumberOfLinesInCurrentPrint
{
get
{
2014-05-23 14:19:20 -07:00
return loadedGCode . Count ;
2014-01-29 19:09:30 -08:00
}
}
public int TotalSecondsInPrint
{
get
{
2014-05-23 14:19:20 -07:00
if ( loadedGCode . Count > 0 )
2014-01-29 19:09:30 -08:00
{
if ( FeedRateRatio ! = 0 )
{
2014-05-23 14:19:20 -07:00
return ( int ) ( loadedGCode . Instruction ( 0 ) . secondsToEndFromHere / FeedRateRatio ) ;
2014-01-29 19:09:30 -08:00
}
2014-05-23 14:19:20 -07:00
return ( int ) ( loadedGCode . Instruction ( 0 ) . secondsToEndFromHere ) ;
}
return 0 ;
}
}
int backupAmount = 16 ;
public int CurrentlyPrintingLayer
{
get
{
int currentIndex = printerCommandQueueIndex - backupAmount ;
if ( currentIndex > = 0
& & currentIndex < loadedGCode . Count )
{
for ( int zIndex = 0 ; zIndex < loadedGCode . NumChangesInZ ; zIndex + + )
{
if ( currentIndex < loadedGCode . IndexOfChangeInZ [ zIndex ] )
{
return zIndex - 1 ;
}
}
return loadedGCode . NumChangesInZ - 1 ;
}
return - 1 ;
}
}
2014-06-22 20:53:38 -07:00
public int TotalLayersInPrint
{
get
{
try
{
int layerCount = loadedGCode . NumChangesInZ ;
return layerCount ;
}
catch
{
return - 1 ;
}
}
}
2014-05-23 14:19:20 -07:00
public double RatioIntoCurrentLayer
{
get
{
int currentIndex = printerCommandQueueIndex - backupAmount ;
if ( currentIndex > = 0
& & currentIndex < loadedGCode . Count )
{
int currentLayer = CurrentlyPrintingLayer ;
int startIndex = loadedGCode . IndexOfChangeInZ [ currentLayer ] ;
int endIndex = loadedGCode . Count - 1 ;
if ( currentLayer < loadedGCode . NumChangesInZ - 2 )
{
endIndex = loadedGCode . IndexOfChangeInZ [ currentLayer + 1 ] - 1 ;
}
int deltaFromStart = Math . Max ( 0 , currentIndex - startIndex ) ;
return deltaFromStart / ( double ) ( endIndex - startIndex ) ;
2014-01-29 19:09:30 -08:00
}
return 0 ;
}
}
Stopwatch timeSinceStartedPrint = new Stopwatch ( ) ;
public int SecondsRemaining
{
get
{
if ( ! timeSinceStartedPrint . IsRunning
& & PrinterIsPrinting )
{
timeSinceStartedPrint . Restart ( ) ;
}
if ( NumberOfLinesInCurrentPrint > 0 )
{
if ( printerCommandQueueIndex > = 0
2014-05-23 14:19:20 -07:00
& & printerCommandQueueIndex < loadedGCode . Count
& & loadedGCode . Instruction ( printerCommandQueueIndex ) . secondsToEndFromHere ! = 0 )
2014-01-29 19:09:30 -08:00
{
if ( FeedRateRatio ! = 0 )
{
2014-05-23 14:19:20 -07:00
lastRemainingSecondsReported = ( int ) ( loadedGCode . Instruction ( printerCommandQueueIndex ) . secondsToEndFromHere / FeedRateRatio ) ;
2014-01-29 19:09:30 -08:00
}
}
return lastRemainingSecondsReported ;
}
return 0 ;
}
}
public int SecondsPrinted
{
get
{
if ( PrinterIsPrinting | | PrinterIsPaused | | PrintIsFinished )
{
return ( int ) ( timeSinceStartedPrint . ElapsedMilliseconds / 1000 ) ;
}
return 0 ;
}
}
public double PercentComplete
{
get
{
2014-06-26 18:13:53 -07:00
if ( CommunicationState = = CommunicationStates . PrintingFromSd )
{
if ( totalSdBytes > 0 )
{
return currentSdBytes / totalSdBytes * 100 ;
}
return 0 ;
}
2014-01-29 19:09:30 -08:00
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 ;
}
}
}
2014-11-10 20:15:59 -08:00
// this is to make it misbehave
//int okCount = 1;
2014-01-29 19:09:30 -08:00
public void PrintingCanContinue ( object sender , EventArgs e )
{
2014-11-10 20:15:59 -08:00
//if ((okCount++ % 67) != 0)
2014-11-10 13:00:14 -08:00
{
timeHaveBeenWaitingForOK . Stop ( ) ;
}
2014-01-29 19:09:30 -08:00
}
2014-06-26 18:13:53 -07:00
Stopwatch timeWaitingForTemperature = new Stopwatch ( ) ;
Stopwatch timeWaitingForSdProgress = new Stopwatch ( ) ;
2014-01-29 19:09:30 -08:00
System . Diagnostics . Stopwatch temperatureRequestTimer = new System . Diagnostics . Stopwatch ( ) ;
public void OnIdle ( )
{
if ( ! temperatureRequestTimer . IsRunning )
{
temperatureRequestTimer . Start ( ) ;
}
if ( temperatureRequestTimer . ElapsedMilliseconds > 2000 )
{
2014-06-26 18:13:53 -07:00
if ( MonitorPrinterTemperature
& & ( ! timeWaitingForTemperature . IsRunning | | timeWaitingForTemperature . Elapsed . TotalSeconds > 60 ) )
2014-01-29 19:09:30 -08:00
{
2014-06-26 18:13:53 -07:00
timeWaitingForTemperature . Restart ( ) ;
2014-04-09 16:53:08 -07:00
SendLineToPrinterNow ( "M105" ) ;
2014-01-29 19:09:30 -08:00
}
2014-06-26 18:13:53 -07:00
if ( CommunicationState = = CommunicationStates . PrintingFromSd
& & ( ! timeWaitingForSdProgress . IsRunning | | timeWaitingForSdProgress . Elapsed . TotalSeconds > 60 ) )
{
timeWaitingForSdProgress . Restart ( ) ;
SendLineToPrinterNow ( "M27" ) ; // : Report SD print status
}
2014-01-29 19:09:30 -08:00
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 ( ) ;
}
}
2014-12-03 17:20:33 -08:00
string doNotShowAgainMessage = "Do not show this message again" . Localize ( ) ;
string gcodeWarningMessage = "The file you are attempting to print is a GCode file.\n\nIt is recommendended that you only print Gcode files known to match your printer's configuration.\n\nAre you sure you want to print this GCode file?" . Localize ( ) ;
string removeFromQueueMessage = "Cannot find this file\nWould you like to remove it from the queue?" . Localize ( ) ;
2014-11-04 21:00:38 -08:00
string itemNotFoundMessage = "Item not found" . Localize ( ) ;
event EventHandler unregisterEvents ;
public void PrintActivePartIfPossible ( )
{
if ( CommunicationState = = CommunicationStates . Connected | | CommunicationState = = CommunicationStates . FinishedPrint )
{
PrintActivePart ( ) ;
}
}
public void PrintActivePart ( )
{
PrintLevelingData levelingData = PrintLevelingData . GetForPrinter ( ActivePrinterProfile . Instance . ActivePrinter ) ;
if ( levelingData . needsPrintLeveling
& & levelingData . sampledPosition0 . z = = 0
& & levelingData . sampledPosition1 . z = = 0
& & levelingData . sampledPosition2 . z = = 0 )
{
LevelWizardBase . ShowPrintLevelWizard ( LevelWizardBase . RuningState . InitialStartupCalibration ) ;
return ;
}
string pathAndFile = PrinterConnectionAndCommunication . Instance . ActivePrintItem . FileLocation ;
if ( ActiveSliceSettings . Instance . HasSdCardReader ( )
& & pathAndFile = = QueueData . SdCardFileName )
{
PrinterConnectionAndCommunication . Instance . StartSdCardPrint ( ) ;
}
else if ( ActiveSliceSettings . Instance . IsValid ( ) )
{
if ( File . Exists ( pathAndFile ) )
{
2014-11-07 10:12:47 -08:00
// clear the output cache prior to starting a print
PrinterOutputCache . Instance . Clear ( ) ;
2014-11-04 21:00:38 -08:00
string hideGCodeWarning = ApplicationSettings . Instance . get ( "HideGCodeWarning" ) ;
if ( Path . GetExtension ( pathAndFile ) . ToUpper ( ) = = ".GCODE" & & hideGCodeWarning = = null )
{
CheckBox hideGCodeWarningCheckBox = new CheckBox ( doNotShowAgainMessage ) ;
hideGCodeWarningCheckBox . TextColor = ActiveTheme . Instance . PrimaryTextColor ;
2014-12-03 17:20:33 -08:00
hideGCodeWarningCheckBox . Margin = new BorderDouble ( top : 6 , left : 6 ) ;
hideGCodeWarningCheckBox . HAnchor = Agg . UI . HAnchor . ParentLeft ;
2014-11-04 21:00:38 -08:00
hideGCodeWarningCheckBox . Click + = ( sender , e ) = >
{
if ( hideGCodeWarningCheckBox . Checked )
{
ApplicationSettings . Instance . set ( "HideGCodeWarning" , "true" ) ;
}
else
{
ApplicationSettings . Instance . set ( "HideGCodeWarning" , null ) ;
}
} ;
StyledMessageBox . ShowMessageBox ( onConfirmPrint , gcodeWarningMessage , "Warning - GCode file" . Localize ( ) , new GuiWidget [ ] { hideGCodeWarningCheckBox } , StyledMessageBox . MessageType . YES_NO ) ;
}
PrinterConnectionAndCommunication . Instance . CommunicationState = PrinterConnectionAndCommunication . CommunicationStates . PreparingToPrint ;
PrintItemWrapper partToPrint = PrinterConnectionAndCommunication . Instance . ActivePrintItem ;
SlicingQueue . Instance . QueuePartForSlicing ( partToPrint ) ;
partToPrint . SlicingDone . RegisterEvent ( partToPrint_SliceDone , ref unregisterEvents ) ;
}
else
{
string message = String . Format ( removeFromQueueMessage , pathAndFile ) ;
StyledMessageBox . ShowMessageBox ( onRemoveMessageConfirm , message , itemNotFoundMessage , StyledMessageBox . MessageType . YES_NO ) ;
}
}
}
void onConfirmPrint ( bool messageBoxResponse )
{
if ( ! messageBoxResponse )
{
PrinterConnectionAndCommunication . Instance . CommunicationState = PrinterConnectionAndCommunication . CommunicationStates . PreparingToPrint ;
PrintItemWrapper partToPrint = PrinterConnectionAndCommunication . Instance . ActivePrintItem ;
SlicingQueue . Instance . QueuePartForSlicing ( partToPrint ) ;
partToPrint . SlicingDone . RegisterEvent ( partToPrint_SliceDone , ref unregisterEvents ) ;
}
}
void onRemoveMessageConfirm ( bool messageBoxResponse )
{
if ( messageBoxResponse )
{
QueueData . Instance . RemoveAt ( QueueData . Instance . SelectedIndex ) ;
}
}
void partToPrint_SliceDone ( object sender , EventArgs e )
{
PrintItemWrapper partToPrint = sender as PrintItemWrapper ;
if ( partToPrint ! = null )
{
partToPrint . SlicingDone . UnregisterEvent ( partToPrint_SliceDone , ref unregisterEvents ) ;
string gcodePathAndFileName = partToPrint . GetGCodePathAndFileName ( ) ;
if ( gcodePathAndFileName ! = "" )
{
bool originalIsGCode = Path . GetExtension ( partToPrint . FileLocation ) . ToUpper ( ) = = ".GCODE" ;
if ( File . Exists ( gcodePathAndFileName )
& & ( originalIsGCode | | File . ReadAllText ( gcodePathAndFileName ) . Contains ( "filament used" ) ) )
{
string gcodeFileContents = "" ;
using ( FileStream fileStream = new FileStream ( gcodePathAndFileName , FileMode . Open , FileAccess . Read , FileShare . ReadWrite ) )
{
using ( StreamReader gcodeStreamReader = new StreamReader ( fileStream ) )
{
gcodeFileContents = gcodeStreamReader . ReadToEnd ( ) ;
}
}
PrinterConnectionAndCommunication . Instance . StartPrint ( gcodeFileContents ) ;
}
else
{
PrinterConnectionAndCommunication . Instance . CommunicationState = PrinterConnectionAndCommunication . CommunicationStates . Connected ;
}
}
}
}
2014-01-29 19:09:30 -08:00
private void WriteNextLineFromQueue ( )
{
2014-09-10 12:11:27 -07:00
string lineToWrite = LinesToWriteQueue [ 0 ] ;
2014-03-17 14:41:36 -07:00
using ( TimedLock . Lock ( this , "WriteNextLineFromQueue" ) )
2014-01-29 19:09:30 -08:00
{
2014-06-13 10:05:56 -07:00
lineToWrite = KeepTrackOfPostionAndDestination ( lineToWrite ) ;
2014-08-26 17:38:23 -07:00
lineToWrite = RunPrintLevelingTranslations ( lineToWrite ) ;
2014-03-07 16:09:07 -08:00
2014-04-07 14:04:38 -07:00
LinesToWriteQueue . RemoveAt ( 0 ) ; // remove the line first (in case we inject another command)
2014-01-29 19:09:30 -08:00
WriteToPrinter ( lineToWrite + "\r\n" , lineToWrite ) ;
}
2014-09-09 11:06:23 -07:00
System . Threading . Thread . Sleep ( 1 ) ;
2014-01-29 19:09:30 -08:00
}
2014-10-15 17:04:14 -07:00
public double GetTargetExtruderTemperature ( int extruderIndex0Based )
2014-01-29 19:09:30 -08:00
{
2014-10-22 10:35:38 -07:00
extruderIndex0Based = Math . Min ( extruderIndex0Based , MAX_EXTRUDERS - 1 ) ;
2014-10-20 17:02:25 -07:00
2014-10-15 17:04:14 -07:00
return targetExtruderTemperature [ extruderIndex0Based ] ;
}
public void SetTargetExtruderTemperature ( int extruderIndex0Based , double temperature )
{
2014-10-22 10:35:38 -07:00
extruderIndex0Based = Math . Min ( extruderIndex0Based , MAX_EXTRUDERS - 1 ) ;
2014-10-20 17:02:25 -07:00
2014-10-15 17:04:14 -07:00
if ( targetExtruderTemperature [ extruderIndex0Based ] ! = temperature )
2014-01-29 19:09:30 -08:00
{
2014-10-15 17:04:14 -07:00
targetExtruderTemperature [ extruderIndex0Based ] = temperature ;
OnExtruderTemperatureSet ( new TemperatureEventArgs ( extruderIndex0Based , temperature ) ) ;
if ( PrinterIsConnected )
2014-01-29 19:09:30 -08:00
{
2014-10-15 17:04:14 -07:00
SendLineToPrinterNow ( "M104 T{0} S{1}" . FormatWith ( extruderIndex0Based , targetExtruderTemperature [ extruderIndex0Based ] ) ) ;
2014-01-29 19:09:30 -08:00
}
}
}
2014-10-15 17:04:14 -07:00
public double GetActualExtruderTemperature ( int extruderIndex0Based )
2014-01-29 19:09:30 -08:00
{
2014-10-22 10:35:38 -07:00
extruderIndex0Based = Math . Min ( extruderIndex0Based , MAX_EXTRUDERS - 1 ) ;
2014-10-20 17:02:25 -07:00
2014-10-15 17:04:14 -07:00
return actualExtruderTemperature [ extruderIndex0Based ] ;
2014-01-29 19:09:30 -08:00
}
public void ExtruderTemperatureWasWritenToPrinter ( object sender , EventArgs e )
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
2014-10-15 17:04:14 -07:00
double tempBeingSet = 0 ;
if ( GCodeFile . GetFirstNumberAfter ( "S" , foundStringEventArgs . LineToCheck , ref tempBeingSet ) )
2014-01-29 19:09:30 -08:00
{
2014-10-15 17:04:14 -07:00
double exturderIndex = 0 ;
if ( GCodeFile . GetFirstNumberAfter ( "T" , foundStringEventArgs . LineToCheck , ref exturderIndex ) )
2014-01-29 19:09:30 -08:00
{
2014-10-15 17:04:14 -07:00
SetTargetExtruderTemperature ( ( int ) exturderIndex , tempBeingSet ) ;
2014-01-29 19:09:30 -08:00
}
2014-10-15 17:04:14 -07:00
else
2014-01-29 19:09:30 -08:00
{
2014-10-15 17:04:14 -07:00
// we set the private variable so that we don't get the callbacks called and get in a loop of setting the temp
SetTargetExtruderTemperature ( 0 , tempBeingSet ) ;
2014-01-29 19:09:30 -08:00
}
2014-10-15 17:04:14 -07:00
OnExtruderTemperatureSet ( e ) ;
2014-01-29 19:09:30 -08:00
}
}
int fanSpeed ;
2014-05-05 17:02:22 -07:00
public int FanSpeed0To255
2014-01-29 19:09:30 -08:00
{
get { return fanSpeed ; }
set
{
fanSpeed = Math . Max ( 0 , Math . Min ( 255 , value ) ) ;
OnFanSpeedSet ( null ) ;
2014-05-04 14:49:31 -07:00
if ( PrinterIsConnected )
{
SendLineToPrinterNow ( "M106 S{0}" . FormatWith ( fanSpeed ) ) ;
}
2014-01-29 19:09:30 -08:00
}
}
public double TargetBedTemperature
{
get
{
return targetBedTemperature ;
}
set
{
if ( targetBedTemperature ! = value )
{
targetBedTemperature = value ;
2014-10-15 17:04:14 -07:00
OnBedTemperatureSet ( new TemperatureEventArgs ( 0 , TargetBedTemperature ) ) ;
2014-05-04 14:49:31 -07:00
if ( PrinterIsConnected )
{
SendLineToPrinterNow ( "M140 S{0}" . FormatWith ( targetBedTemperature ) ) ;
}
2014-01-29 19:09:30 -08:00
}
}
}
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 ;
2014-10-15 17:04:14 -07:00
OnBedTemperatureSet ( new TemperatureEventArgs ( 0 , TargetBedTemperature ) ) ;
2014-01-29 19:09:30 -08:00
}
}
catch
{
2014-03-16 10:23:56 -07:00
Debug . WriteLine ( "Unable to Parse Bed Temperature: {0}" . FormatWith ( temp ) ) ;
2014-01-29 19:09:30 -08:00
}
}
}
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 ) ;
2014-05-05 17:02:22 -07:00
if ( FanSpeed0To255 ! = fanSpeedBeingSet )
2014-01-29 19:09:30 -08:00
{
fanSpeed = fanSpeedBeingSet ;
OnFanSpeedSet ( null ) ;
}
}
catch
{
2014-03-16 10:23:56 -07:00
Debug . WriteLine ( "Unable to Parse Fan Speed: {0}" . FormatWith ( fanSpeed ) ) ;
2014-01-29 19:09:30 -08:00
}
}
}
2014-05-13 13:28:34 -07:00
public void ReadTargetPositions ( object sender , EventArgs e )
2014-01-29 19:09:30 -08:00
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
string lineToParse = foundStringEventArgs . LineToCheck ;
Vector3 positionRead = Vector3 . Zero ;
2014-03-07 16:09:07 -08:00
GCodeFile . GetFirstNumberAfter ( "X:" , lineToParse , ref positionRead . x ) ;
GCodeFile . GetFirstNumberAfter ( "Y:" , lineToParse , ref positionRead . y ) ;
GCodeFile . GetFirstNumberAfter ( "Z:" , lineToParse , ref positionRead . z ) ;
2014-01-29 19:09:30 -08:00
2014-05-13 13:28:34 -07:00
// The first position read is the target position.
lastReportedPosition = positionRead ;
#if false
// The second position (if available) is the actual current position of the extruder.
2014-01-29 19:09:30 -08:00
int xPosition = lineToParse . IndexOf ( 'X' ) ;
int secondXPosition = lineToParse . IndexOf ( "Count" , xPosition ) ;
if ( secondXPosition ! = - 1 )
{
Vector3 currentPositionRead = Vector3 . Zero ;
2014-03-07 16:09:07 -08:00
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 ) ;
2014-01-29 19:09:30 -08:00
lastReportedPosition = currentPositionRead ;
}
2014-05-13 13:28:34 -07:00
#endif
2014-01-29 19:09:30 -08:00
if ( currentDestination ! = positionRead )
{
currentDestination = positionRead ;
DestinationChanged . CallEvents ( this , null ) ;
}
PositionRead . CallEvents ( this , null ) ;
}
2014-06-26 18:13:53 -07:00
double currentSdBytes = 0 ;
double totalSdBytes = 0 ;
public void ReadSdProgress ( object sender , EventArgs e )
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
if ( foundStringEventArgs ! = null )
{
string sdProgressString = foundStringEventArgs . LineToCheck . Substring ( "Sd printing byte " . Length ) ;
string [ ] values = sdProgressString . Split ( '/' ) ;
currentSdBytes = long . Parse ( values [ 0 ] ) ;
totalSdBytes = long . Parse ( values [ 1 ] ) ;
}
// We read it so we are no longer waiting
timeWaitingForSdProgress . Stop ( ) ;
}
2014-01-29 19:09:30 -08:00
public void ReadTemperatures ( object sender , EventArgs e )
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
string temperatureString = foundStringEventArgs . LineToCheck ;
{
2014-10-15 17:04:14 -07:00
double readExtruderTemp = 0 ;
if ( GCodeFile . GetFirstNumberAfter ( "T:" , temperatureString , ref readExtruderTemp ) )
2014-01-29 19:09:30 -08:00
{
2014-10-15 17:04:14 -07:00
if ( actualExtruderTemperature [ 0 ] ! = readExtruderTemp )
2014-01-29 19:09:30 -08:00
{
2014-10-15 17:04:14 -07:00
actualExtruderTemperature [ 0 ] = readExtruderTemp ;
OnExtruderTemperatureRead ( new TemperatureEventArgs ( 0 , GetActualExtruderTemperature ( 0 ) ) ) ;
2014-01-29 19:09:30 -08:00
}
}
2014-11-17 17:42:15 -08:00
for ( int extruderIndex = 0 ; extruderIndex < MAX_EXTRUDERS ; extruderIndex + + )
{
string multiExtruderCheck = "T{0}:" . FormatWith ( extruderIndex ) ;
if ( GCodeFile . GetFirstNumberAfter ( multiExtruderCheck , temperatureString , ref readExtruderTemp ) )
2014-01-29 19:09:30 -08:00
{
2014-11-17 17:42:15 -08:00
if ( actualExtruderTemperature [ extruderIndex ] ! = readExtruderTemp )
2014-01-29 19:09:30 -08:00
{
2014-11-17 17:42:15 -08:00
actualExtruderTemperature [ extruderIndex ] = readExtruderTemp ;
OnExtruderTemperatureRead ( new TemperatureEventArgs ( extruderIndex , GetActualExtruderTemperature ( extruderIndex ) ) ) ;
2014-01-29 19:09:30 -08:00
}
}
2014-11-17 17:42:15 -08:00
else
{
break ;
}
2014-10-15 17:04:14 -07:00
}
}
{
double readBedTemp = 0 ;
if ( GCodeFile . GetFirstNumberAfter ( "B:" , temperatureString , ref readBedTemp ) )
{
if ( actualBedTemperature ! = readBedTemp )
2014-01-29 19:09:30 -08:00
{
2014-10-15 17:04:14 -07:00
actualBedTemperature = readBedTemp ;
OnBedTemperatureRead ( new TemperatureEventArgs ( 0 , ActualBedTemperature ) ) ;
2014-01-29 19:09:30 -08:00
}
}
}
2014-06-26 18:13:53 -07:00
// We read them so we are no longer waiting
timeWaitingForTemperature . Stop ( ) ;
2014-01-29 19:09:30 -08:00
}
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 ;
}
2014-02-18 17:52:50 -08:00
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 ;
}
}
2014-03-05 12:16:52 -08:00
string firmwareVersionReported = "" ;
2014-03-12 14:57:25 -07:00
if ( GCodeFile . GetFirstStringAfter ( "MACHINE_TYPE:" , foundStringEventArgs . LineToCheck , " EXTRUDER_COUNT" , ref firmwareVersionReported ) )
2014-03-05 12:16:52 -08:00
{
2014-08-19 11:13:52 -07:00
char splitChar = '^' ;
if ( firmwareVersionReported . Contains ( splitChar ) )
{
string [ ] split = firmwareVersionReported . Split ( splitChar ) ;
if ( split . Count ( ) = = 2 )
{
deviceCode = split [ 0 ] ;
firmwareVersionReported = split [ 1 ] ;
}
}
2014-03-05 12:16:52 -08:00
//Firmware version was detected and is different
if ( firmwareVersionReported ! = "" & & firmwareVersion ! = firmwareVersionReported )
{
firmwareVersion = firmwareVersionReported ;
OnFirmwareVersionRead ( null ) ;
}
}
2014-02-18 17:52:50 -08:00
}
2014-01-29 19:09:30 -08:00
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 )
{
2014-06-23 17:12:55 -07:00
connectThread . Join ( JoinThreadTimeoutMs ) ; //Halt connection thread
2014-01-29 19:09:30 -08:00
Disable ( ) ;
2014-10-19 10:26:09 -07:00
connectionFailureMessage = LocalizedString . Get ( "Cancelled" ) ;
2014-01-29 19:09:30 -08:00
OnConnectionFailed ( null ) ;
return false ;
}
else
{
return true ;
}
}
else
{
2014-10-31 13:31:38 -07:00
// If we're no longer in the .AttemptingToConnect state, shutdown the connection thread and fire the
2014-11-04 09:26:24 -08:00
// OnConnectonSuccess event if we're connected and not Disconnecting
2014-10-31 13:31:38 -07:00
connectThread . Join ( JoinThreadTimeoutMs ) ;
2014-11-04 09:26:24 -08:00
if ( PrinterIsConnected & & CommunicationState ! = CommunicationStates . Disconnecting )
2014-10-31 13:31:38 -07:00
{
OnConnectionSucceeded ( null ) ;
}
2014-01-29 19:09:30 -08:00
return false ;
}
}
public void HaltConnectionThread ( )
{
this . stopTryingToConnect = true ;
}
public void ConnectToActivePrinter ( )
{
2014-06-11 14:52:58 -07:00
if ( PrinterConnectionAndCommunication . Instance . ActivePrinter ! = null )
2014-01-29 19:09:30 -08:00
{
2014-06-11 14:52:58 -07:00
ConnectToPrinter ( PrinterConnectionAndCommunication . Instance . ActivePrinter ) ;
2014-01-29 19:09:30 -08:00
}
}
2014-02-26 09:22:42 -08:00
public string ComPort
{
get
{
string comPort = null ;
if ( this . ActivePrinter ! = null )
{
comPort = this . ActivePrinter . ComPort ;
}
return comPort ;
}
}
2014-01-29 19:09:30 -08:00
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 )
{
2014-11-07 10:12:47 -08:00
PrinterOutputCache . Instance . Clear ( ) ;
2014-01-29 19:09:30 -08:00
LinesToWriteQueue . Clear ( ) ;
//Attempt connecting to a specific printer
CommunicationState = CommunicationStates . AttemptingToConnect ;
this . stopTryingToConnect = false ;
2014-02-18 17:52:50 -08:00
firmwareType = FirmwareTypes . Unknown ;
2014-03-05 12:16:52 -08:00
firmwareVersion = null ;
2014-01-29 19:09:30 -08:00
2014-12-24 12:12:11 -08:00
// On Android, there will never be more than one serial port available for us to connect to. Override the current .ComPort value to account for
// this aspect to ensure the validation logic that verifies port availablity/in use status can proceed without additional workarounds for Android
#if __ANDROID__
string currentPortName = FrostedSerialPort . GetPortNames ( ) . Where ( p = > p ! = "/dev/bus/usb/002/002" ) . FirstOrDefault ( ) ;
if ( ! string . IsNullOrEmpty ( currentPortName ) )
{
this . ActivePrinter . ComPort = currentPortName ;
}
#endif
2014-01-29 19:09:30 -08:00
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 ) ;
2014-10-19 08:46:20 -07:00
connectThread . Name = "Connect To Printer" ;
2014-01-29 19:09:30 -08:00
connectThread . IsBackground = true ;
connectThread . Start ( ) ;
}
else
{
2014-03-16 10:23:56 -07:00
Debug . WriteLine ( "Connection failed: {0}" . FormatWith ( this . ActivePrinter . ComPort ) ) ;
2014-11-03 18:03:58 -08:00
connectionFailureMessage = string . Format (
"{0} is not available" . Localize ( ) ,
this . ActivePrinter . ComPort ) ;
2014-01-29 19:09:30 -08:00
OnConnectionFailed ( null ) ;
}
}
void Connect_Thread ( )
{
Thread . CurrentThread . CurrentCulture = CultureInfo . InvariantCulture ;
// Allow the user to set the appropriate properties.
2014-06-27 10:57:14 -07:00
var portNames = FrostedSerialPort . GetPortNames ( ) ;
2014-03-16 10:23:56 -07:00
//Debug.WriteLine("Open ports: {0}".FormatWith(portNames.Length));
2014-01-29 19:09:30 -08:00
if ( portNames . Length > 0 )
{
2014-03-16 10:23:56 -07:00
//Debug.WriteLine("Connecting to: {0} {1}".FormatWith(this.ActivePrinter.ComPort, this.BaudRate));
2014-01-29 19:09:30 -08:00
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 ) ;
}
2014-05-30 14:37:30 -07:00
public void OnCommunicationStateChanged ( EventArgs e )
2014-01-29 19:09:30 -08:00
{
2014-05-30 14:37:30 -07:00
CommunicationStateChanged . CallEvents ( this , e ) ;
2014-01-29 19:09:30 -08:00
}
public void OnConnectionFailed ( EventArgs e )
{
ConnectionFailed . CallEvents ( this , e ) ;
CommunicationState = CommunicationStates . FailedToConnect ;
OnEnabledChanged ( e ) ;
}
2014-08-05 10:34:26 -07:00
//Windows-only function
2014-01-29 19:09:30 -08:00
bool SerialPortAlreadyOpen ( string portName )
{
2014-10-19 08:46:20 -07:00
if ( OsInformation . OperatingSystem = = OSType . Windows )
{
const int dwFlagsAndAttributes = 0x40000000 ;
const int GENERIC_READ = unchecked ( ( int ) 0x80000000 ) ;
const int GENERIC_WRITE = 0x40000000 ;
2014-08-05 10:34:26 -07:00
2014-10-19 08:46:20 -07:00
//Borrowed from Microsoft's Serial Port Open Method :)
2014-10-19 10:34:09 -07:00
using ( SafeFileHandle hFile = CreateFile ( @"\\.\" + portName , GENERIC_READ | GENERIC_WRITE , 0 , IntPtr . Zero , 3 , dwFlagsAndAttributes , IntPtr . Zero ) )
2014-10-19 08:46:20 -07:00
{
2014-10-19 10:34:09 -07:00
hFile . Close ( ) ;
return hFile . IsInvalid ;
2014-10-19 08:46:20 -07:00
}
}
2014-01-29 19:09:30 -08:00
else
{
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 )
{
2014-10-19 10:26:09 -07:00
connectionFailureMessage = LocalizedString . Get ( "Unknown Reason" ) ;
2014-01-29 19:09:30 -08:00
if ( PrinterIsConnected )
{
2014-10-19 10:26:09 -07:00
throw new Exception ( LocalizedString . Get ( "You can only connect when not currently connected." ) ) ;
2014-01-29 19:09:30 -08:00
}
CommunicationState = CommunicationStates . AttemptingToConnect ;
bool serialPortIsAvailable = SerialPortIsAvailable ( serialPortName ) ;
bool serialPortIsAlreadyOpen = SerialPortAlreadyOpen ( serialPortName ) ;
if ( serialPortIsAvailable & & ! serialPortIsAlreadyOpen )
{
if ( CommunicationState = = CommunicationStates . AttemptingToConnect )
{
try
{
2014-10-19 08:46:20 -07:00
serialPort = FrostedSerialPort . CreateAndOpen ( serialPortName , baudRate , DtrEnableOnConnect ) ;
2014-04-01 11:03:38 -07:00
2014-10-19 08:46:20 -07:00
readFromPrinterThread = new Thread ( ReadFromPrinter ) ;
2014-01-29 19:09:30 -08:00
readFromPrinterThread . Name = "Read From Printer" ;
readFromPrinterThread . IsBackground = true ;
readFromPrinterThread . Start ( ) ;
// let's check if the printer will talk to us
ReadPosition ( ) ;
2014-04-09 16:53:08 -07:00
SendLineToPrinterNow ( "M105" ) ;
SendLineToPrinterNow ( "M115" ) ;
2014-01-29 19:09:30 -08:00
}
catch ( System . ArgumentOutOfRangeException )
{
2014-10-19 10:26:09 -07:00
connectionFailureMessage = LocalizedString . Get ( "Unsupported Baud Rate" ) ;
2014-01-29 19:09:30 -08:00
OnConnectionFailed ( null ) ;
}
2014-12-24 12:12:11 -08:00
catch ( Exception ex )
2014-01-29 19:09:30 -08:00
{
2014-12-24 12:12:11 -08:00
Debug . WriteLine ( "An unexpected exception occurred: " + ex . Message ) ;
2014-01-29 19:09:30 -08:00
OnConnectionFailed ( null ) ;
}
}
}
2014-10-19 10:13:23 -07:00
else
{
2014-10-21 14:56:19 -07:00
// If the serial port isn't avaiable (i.e. the specified port name wasn't found in GetPortNames()) or the serial
// port is already opened in another instance or process, then report the connection problem back to the user
2014-10-19 10:26:09 -07:00
connectionFailureMessage = ( serialPortIsAlreadyOpen ?
2014-11-04 21:12:57 -08:00
string . Format ( "{0} in use" , PrinterConnectionAndCommunication . Instance . ActivePrinter . ComPort ) :
2014-10-19 10:26:09 -07:00
LocalizedString . Get ( "Port not found" ) ) ;
2014-10-19 10:13:23 -07:00
OnConnectionFailed ( null ) ;
}
2014-01-29 19:09:30 -08:00
}
public void OnPrintFinished ( EventArgs e )
{
PrintFinished . CallEvents ( this , new PrintItemWrapperEventArgs ( this . ActivePrintItem ) ) ;
}
2014-03-05 12:16:52 -08:00
void OnFirmwareVersionRead ( EventArgs e )
{
FirmwareVersionRead . CallEvents ( this , e ) ;
}
2014-01-29 19:09:30 -08:00
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 ) ;
}
2014-06-13 10:05:56 -07:00
string KeepTrackOfPostionAndDestination ( string lineBeingSent )
2014-01-29 19:09:30 -08:00
{
2014-02-14 20:31:00 -08:00
if ( lineBeingSent . StartsWith ( "G0 " ) | | lineBeingSent . StartsWith ( "G1 " ) )
2014-01-29 19:09:30 -08:00
{
Vector3 newDestination = currentDestination ;
if ( movementMode = = PrinterMachineInstruction . MovementTypes . Relative )
{
newDestination = Vector3 . Zero ;
}
2014-03-07 16:09:07 -08:00
GCodeFile . GetFirstNumberAfter ( "X" , lineBeingSent , ref newDestination . x ) ;
GCodeFile . GetFirstNumberAfter ( "Y" , lineBeingSent , ref newDestination . y ) ;
GCodeFile . GetFirstNumberAfter ( "Z" , lineBeingSent , ref newDestination . z ) ;
2014-01-29 19:09:30 -08:00
if ( movementMode = = PrinterMachineInstruction . MovementTypes . Relative )
{
newDestination + = currentDestination ;
}
if ( currentDestination ! = newDestination )
{
currentDestination = newDestination ;
DestinationChanged . CallEvents ( this , null ) ;
}
2014-08-26 17:38:23 -07:00
}
2014-01-29 19:09:30 -08:00
2014-08-26 17:38:23 -07:00
return lineBeingSent ;
}
string RunPrintLevelingTranslations ( string lineBeingSent )
{
2014-08-27 09:18:59 -07:00
if ( ActivePrinter ! = null
& & ActivePrinter . DoPrintLeveling
2014-09-02 12:49:14 -07:00
& & ( lineBeingSent . StartsWith ( "G0 " ) | | lineBeingSent . StartsWith ( "G1 " ) ) )
2014-08-26 17:38:23 -07:00
{
string inputLine = lineBeingSent ;
lineBeingSent = PrintLevelingPlane . Instance . ApplyLeveling ( currentDestination , movementMode , inputLine ) ;
2014-01-29 19:09:30 -08:00
}
2014-06-11 14:52:58 -07:00
PrintLevelingData levelingData = PrintLevelingData . GetForPrinter ( ActivePrinterProfile . Instance . ActivePrinter ) ;
2014-08-26 17:38:23 -07:00
if ( levelingData ! = null )
2014-06-11 14:52:58 -07:00
{
2014-06-12 18:35:11 -07:00
List < string > linesToWrite = null ;
2014-06-12 16:51:22 -07:00
switch ( levelingData . levelingSystem )
{
case PrintLevelingData . LevelingSystem . Probe2Points :
2014-06-16 18:13:02 -07:00
linesToWrite = LevelWizard2Point . ProcessCommand ( lineBeingSent ) ;
2014-06-12 16:51:22 -07:00
break ;
case PrintLevelingData . LevelingSystem . Probe3Points :
2014-06-16 18:13:02 -07:00
linesToWrite = LevelWizard3Point . ProcessCommand ( lineBeingSent ) ;
2014-06-12 16:51:22 -07:00
break ;
}
2014-06-12 18:35:11 -07:00
2014-06-16 18:14:59 -07:00
lineBeingSent = linesToWrite [ 0 ] ;
linesToWrite . RemoveAt ( 0 ) ;
2014-06-16 18:13:02 -07:00
2014-06-12 18:35:11 -07:00
SendLinesToPrinterNow ( linesToWrite . ToArray ( ) ) ;
2014-06-11 14:52:58 -07:00
}
2014-01-29 19:09:30 -08:00
return lineBeingSent ;
}
string ApplyExtrusionMultiplier ( string lineBeingSent )
{
lineBeingSent = lineBeingSent . ToUpper ( ) . Trim ( ) ;
if ( lineBeingSent . StartsWith ( "G0" ) | | lineBeingSent . StartsWith ( "G1" ) )
{
2014-03-07 16:09:07 -08:00
if ( GCodeFile . GetFirstNumberAfter ( "E" , lineBeingSent , ref gcodeRequestedExtrusionPosition ) )
2014-01-29 19:09:30 -08:00
{
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" ) )
{
2014-03-07 16:09:07 -08:00
if ( GCodeFile . GetFirstNumberAfter ( "E" , lineBeingSent , ref gcodeRequestedExtrusionPosition ) )
2014-01-29 19:09:30 -08:00
{
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 ;
2014-03-07 16:09:07 -08:00
if ( GCodeFile . GetFirstNumberAfter ( "F" , lineBeingSent , ref feedRate ) )
2014-01-29 19:09:30 -08:00
{
lineBeingSent = GCodeFile . ReplaceNumberAfter ( 'F' , lineBeingSent , feedRate * FeedRateRatio ) ;
}
}
}
return lineBeingSent ;
}
void SetDetailedPrintingState ( string lineBeingSetToPrinter )
{
if ( lineBeingSetToPrinter . StartsWith ( "G28" ) )
{
2014-06-23 13:18:51 -07:00
PrintingState = DetailedPrintingState . HomingAxis ;
2014-01-29 19:09:30 -08:00
}
else if ( lineBeingSetToPrinter . StartsWith ( "M190" ) )
{
2014-06-23 13:18:51 -07:00
PrintingState = DetailedPrintingState . HeatingBed ;
2014-01-29 19:09:30 -08:00
}
else if ( lineBeingSetToPrinter . StartsWith ( "M109" ) )
{
2014-06-23 13:18:51 -07:00
PrintingState = DetailedPrintingState . HeatingExtruder ;
2014-01-29 19:09:30 -08:00
}
else
{
2014-06-23 13:18:51 -07:00
PrintingState = DetailedPrintingState . Printing ;
2014-01-29 19:09:30 -08:00
}
}
2014-06-12 18:35:11 -07:00
public void SendLinesToPrinterNow ( string [ ] linesToWrite )
2014-01-29 19:09:30 -08:00
{
2014-06-23 09:31:14 -07:00
if ( PrinterIsPrinting & & CommunicationState ! = CommunicationStates . PrintingFromSd )
2014-01-29 19:09:30 -08:00
{
2014-06-12 18:35:11 -07:00
for ( int i = linesToWrite . Length - 1 ; i > = 0 ; i - - )
2014-01-29 19:09:30 -08:00
{
2014-06-12 18:35:11 -07:00
string line = linesToWrite [ i ] . Trim ( ) ;
if ( line . Length > 0 )
2014-04-07 14:04:38 -07:00
{
2014-06-12 18:35:11 -07:00
SendLineToPrinterNow ( line ) ;
2014-06-12 16:51:22 -07:00
}
2014-06-12 18:35:11 -07:00
}
}
else
{
for ( int i = 0 ; i < linesToWrite . Length ; i + + )
{
string line = linesToWrite [ i ] . Trim ( ) ;
if ( line . Length > 0 )
2014-06-12 16:51:22 -07:00
{
2014-06-12 18:35:11 -07:00
SendLineToPrinterNow ( line ) ;
2014-04-07 14:04:38 -07:00
}
2014-06-12 18:35:11 -07:00
}
}
}
public void SendLineToPrinterNow ( string lineToWrite )
{
using ( TimedLock . Lock ( this , "QueueLineToPrinter" ) )
{
//Check line for linebreaks, split and process separate if necessary
if ( lineToWrite . Contains ( "\n" ) )
{
string [ ] linesToWrite = lineToWrite . Split ( new string [ ] { "\n" } , StringSplitOptions . None ) ;
SendLinesToPrinterNow ( linesToWrite ) ;
2014-04-07 14:04:38 -07:00
return ;
2014-01-29 19:09:30 -08:00
}
2014-04-07 14:04:38 -07:00
lineToWrite = lineToWrite . Split ( ';' ) [ 0 ] . Trim ( ) ;
2014-10-30 16:44:16 -07:00
if ( lineToWrite . Trim ( ) . Length > 0 )
2014-01-29 19:09:30 -08:00
{
2014-10-30 16:44:16 -07:00
if ( PrinterIsPrinting & & CommunicationState ! = CommunicationStates . PrintingFromSd )
2014-02-04 10:51:06 -08:00
{
2014-10-30 16:44:16 -07:00
// insert the command into the printing queue at the head
if ( printerCommandQueueIndex > = 0
& & printerCommandQueueIndex < loadedGCode . Count - 1 )
2014-03-17 14:41:36 -07:00
{
2014-10-30 16:44:16 -07:00
if ( ! loadedGCode . Instruction ( printerCommandQueueIndex + 1 ) . Line . Contains ( lineToWrite ) )
{
loadedGCode . Insert ( printerCommandQueueIndex + 1 , new PrinterMachineInstruction ( lineToWrite , loadedGCode . Instruction ( printerCommandQueueIndex ) ) ) ;
}
2014-03-17 14:41:36 -07:00
}
2014-02-04 10:51:06 -08:00
}
2014-04-07 14:04:38 -07:00
else
2014-02-04 10:51:06 -08:00
{
2014-10-30 16:44:16 -07:00
// sometimes we need to send code without buffering (like when we are closing the program).
if ( ForceImmediateWrites )
{
WriteToPrinter ( lineToWrite + "\r\n" , lineToWrite ) ;
}
else
2014-04-07 14:04:38 -07:00
{
2014-10-30 16:44:16 -07:00
// try not to write the exact same command twice (like M105)
if ( LinesToWriteQueue . Count = = 0 | | LinesToWriteQueue [ LinesToWriteQueue . Count - 1 ] ! = lineToWrite )
{
LinesToWriteQueue . Add ( lineToWrite ) ;
}
2014-04-07 14:04:38 -07:00
}
2014-02-04 10:51:06 -08:00
}
2014-01-29 19:09:30 -08:00
}
}
}
2014-11-10 20:15:59 -08:00
// this is to make it misbehave
//int checkSumCount = 1;
2014-01-29 19:09:30 -08:00
private void WriteChecksumLineToPrinter ( string lineToWrite )
{
SetDetailedPrintingState ( lineToWrite ) ;
lineToWrite = ApplyExtrusionMultiplier ( lineToWrite ) ;
lineToWrite = ApplyFeedRateMultiplier ( lineToWrite ) ;
2014-06-13 10:05:56 -07:00
lineToWrite = KeepTrackOfPostionAndDestination ( lineToWrite ) ;
2014-08-26 17:38:23 -07:00
lineToWrite = RunPrintLevelingTranslations ( lineToWrite ) ;
2014-01-29 19:09:30 -08:00
string lineWithCount = "N" + ( allCheckSumLinesSent . Count + 1 ) . ToString ( ) + " " + lineToWrite ;
2014-11-10 20:15:59 -08:00
string lineWithChecksum = lineWithCount + "*" + GCodeFile . CalculateChecksum ( lineWithCount ) . ToString ( ) ;
2014-01-29 19:09:30 -08:00
allCheckSumLinesSent . Add ( lineWithChecksum ) ;
2014-11-10 20:15:59 -08:00
//if ((checkSumCount++ % 71) == 0)
{
//lineWithChecksum = lineWithCount + "*" + (GCodeFile.CalculateChecksum(lineWithCount) + checkSumCount).ToString();
//WriteToPrinter(lineWithChecksum + "\r\n", lineToWrite);
}
//else
{
WriteToPrinter ( lineWithChecksum + "\r\n" , lineToWrite ) ;
}
2014-01-29 19:09:30 -08:00
}
void WriteToPrinter ( string lineToWrite , string lineWithoutChecksum )
{
if ( PrinterIsConnected | | CommunicationState = = CommunicationStates . AttemptingToConnect )
{
if ( serialPort ! = null & & serialPort . IsOpen )
{
2014-03-17 14:41:36 -07:00
FoundStringEventArgs foundStringEvent = new FoundStringEventArgs ( lineWithoutChecksum ) ;
2014-01-29 19:09:30 -08:00
// write data to communication
{
StringEventArgs currentEvent = new StringEventArgs ( lineToWrite ) ;
2014-02-20 18:25:23 -08:00
CommunicationUnconditionalToPrinter . CallEvents ( this , currentEvent ) ;
2014-01-29 19:09:30 -08:00
if ( lineWithoutChecksum ! = null )
{
WriteLineStartCallBacks . CheckForKeys ( foundStringEvent ) ;
WriteLineContainsCallBacks . CheckForKeys ( foundStringEvent ) ;
if ( foundStringEvent . SendToDelegateFunctions )
{
WroteLine . CallEvents ( this , currentEvent ) ;
}
}
}
try
{
2014-11-11 12:09:09 -08:00
timeSinceLastWrite . Restart ( ) ;
2014-01-29 19:09:30 -08:00
timeHaveBeenWaitingForOK . Restart ( ) ;
serialPort . Write ( lineToWrite ) ;
2014-11-10 20:15:59 -08:00
//Debug.Write("w: " + lineToWrite);
2014-01-29 19:09:30 -08:00
}
catch ( IOException )
{
OnConnectionFailed ( null ) ;
}
catch ( TimeoutException )
{
}
}
else
{
OnConnectionFailed ( null ) ;
}
}
}
2014-02-26 09:22:42 -08:00
public void PulseRtsLow ( )
{
if ( serialPort = = null & & this . ActivePrinter ! = null )
2014-04-01 11:03:38 -07:00
{
2014-05-13 17:00:50 -07:00
serialPort = FrostedSerialPort . Create ( this . ActivePrinter . ComPort ) ;
2014-02-26 09:22:42 -08:00
serialPort . BaudRate = this . BaudRate ;
2014-06-11 14:52:58 -07:00
if ( PrinterConnectionAndCommunication . Instance . DtrEnableOnConnect )
2014-02-26 09:22:42 -08:00
{
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 ( ) ;
}
}
2014-11-04 21:09:05 -08:00
/// <summary>
/// Abort an ongoing attempt to establish communcation with a printer due to the specified problem. This is a specialized
/// version of the functionality that's previously been in .Disable but focused specifically on the task of aborting an
/// ongoing connection. Ideally we should unify all abort invocations to use this implementation rather than the mix
/// of occasional OnConnectionFailed calls, .Disable and .stopTryingToConnect
/// </summary>
/// <param name="abortReason">The concise message which will be used to describe the connection failure</param>
/// <param name="shutdownReadLoop">Shutdown/join the readFromPrinterThread</param>
public void AbortConnectionAttempt ( string abortReason , bool shutdownReadLoop = true )
{
CommunicationState = CommunicationStates . Disconnecting ;
// Shudown the connectionAttempt thread
if ( connectThread ! = null )
{
connectThread . Join ( JoinThreadTimeoutMs ) ; //Halt connection thread
}
// Shutdown the readFromPrinter thread
if ( shutdownReadLoop & & readFromPrinterThread ! = null )
{
readFromPrinterThread . Join ( JoinThreadTimeoutMs ) ;
}
// Shudown the serial port
if ( serialPort ! = null )
{
// Close and dispose the serial port
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
serialPort = null ;
}
// Set the final communication state
CommunicationState = CommunicationStates . Disconnected ;
// Set the connection failure message and call OnConnectionFailed
connectionFailureMessage = abortReason ;
// Notify
OnConnectionFailed ( null ) ;
}
2014-01-29 19:09:30 -08:00
public void Disable ( )
{
if ( PrinterIsConnected )
{
2014-02-04 10:51:06 -08:00
// 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 ;
2014-01-29 19:09:30 -08:00
ReleaseMotors ( ) ;
2014-10-15 17:04:14 -07:00
TurnOffBedAndExtruders ( ) ;
2014-05-05 17:02:22 -07:00
FanSpeed0To255 = 0 ;
2014-02-04 10:51:06 -08:00
ForceImmediateWrites = false ;
2014-01-29 19:09:30 -08:00
CommunicationState = CommunicationStates . Disconnecting ;
if ( readFromPrinterThread ! = null )
{
2014-06-23 17:12:55 -07:00
readFromPrinterThread . Join ( JoinThreadTimeoutMs ) ;
2014-01-29 19:09:30 -08:00
}
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
serialPort = null ;
CommunicationState = CommunicationStates . Disconnected ;
LinesToWriteQueue . Clear ( ) ;
}
2014-05-04 14:49:31 -07:00
else
{
//Need to reset UI - even if manual disconnect
2014-10-15 17:04:14 -07:00
TurnOffBedAndExtruders ( ) ;
2014-05-05 17:02:22 -07:00
FanSpeed0To255 = 0 ;
2014-05-04 14:49:31 -07:00
}
2014-01-29 19:09:30 -08:00
OnEnabledChanged ( null ) ;
}
Stopwatch timeSinceLastWrite = new Stopwatch ( ) ;
2014-11-10 20:15:59 -08:00
void TryWriteNextLineFromGCodeFile ( )
2014-01-29 19:09:30 -08:00
{
2014-11-10 20:15:59 -08:00
bool forceContinueInCaseOfNoResponse = false ;
// wait until the printer responds from the last command with an ok OR we waited too long
if ( timeHaveBeenWaitingForOK . IsRunning
& & ! forceContinueInCaseOfNoResponse )
2014-01-29 19:09:30 -08:00
{
2014-11-10 20:15:59 -08:00
using ( TimedLock . Lock ( this , "WriteNextLineFromGCodeFile1" ) )
2014-11-10 13:00:14 -08:00
{
// we are still sending commands
if ( printerCommandQueueIndex > 0 & & printerCommandQueueIndex < loadedGCode . Count - 1 )
2014-01-29 19:09:30 -08:00
{
2014-11-10 13:00:14 -08:00
// the last instruction was a move
PrinterMachineInstruction lastInstruction = loadedGCode . Instruction ( printerCommandQueueIndex - 1 ) ;
bool wasMoveAndNoOK = ( lastInstruction . Line . Contains ( "G0 " ) | | lastInstruction . Line . Contains ( "G1 " ) ) & & timeHaveBeenWaitingForOK . Elapsed . TotalSeconds > 5 ;
2014-01-29 19:09:30 -08:00
{
2014-11-10 13:00:14 -08:00
// This code is to try and make sure the printer does not stop on transmission errors.
2014-11-10 20:23:34 -08:00
// If it has been more than 10 seconds since the printer responded anything
// and it was not ok, and it's been more than 30 second since we sent the command.
if ( ( timeSinceLastReadAnything . Elapsed . TotalSeconds > 10 & & timeSinceLastWrite . Elapsed . TotalSeconds > 30 )
2014-11-10 13:00:14 -08:00
| | wasMoveAndNoOK )
2014-01-29 19:09:30 -08:00
{
2014-11-10 20:15:59 -08:00
//if (firstLineToResendIndex == allCheckSumLinesSent.Count)
2014-11-10 13:00:14 -08:00
{
// 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.
2014-11-10 20:15:59 -08:00
forceContinueInCaseOfNoResponse = true ;
2014-11-10 13:00:14 -08:00
firstLineToResendIndex - - ; // we are going to resend the last command
}
2014-01-29 19:09:30 -08:00
}
2014-11-10 20:15:59 -08:00
else
{
// we are wating for the ok so let's wait
return ;
}
2014-01-29 19:09:30 -08:00
}
}
}
2014-11-10 20:15:59 -08:00
}
2014-01-29 19:09:30 -08:00
2014-11-10 20:15:59 -08:00
bool pauseRequested = false ;
using ( TimedLock . Lock ( this , "WriteNextLineFromGCodeFile2" ) )
{
if ( printerCommandQueueIndex < loadedGCode . Count )
2014-01-29 19:09:30 -08:00
{
2014-11-10 20:15:59 -08:00
if ( firstLineToResendIndex < allCheckSumLinesSent . Count )
2014-01-29 19:09:30 -08:00
{
2014-11-10 20:15:59 -08:00
WriteToPrinter ( allCheckSumLinesSent [ firstLineToResendIndex + + ] + "\n" , "resend" ) ;
}
else
{
string lineToWrite = loadedGCode . Instruction ( printerCommandQueueIndex ) . Line ;
string [ ] splitOnSemicolon = lineToWrite . Split ( ';' ) ;
string trimedLine = splitOnSemicolon [ 0 ] . Trim ( ) . ToUpper ( ) ;
if ( trimedLine . Length > 0 )
2014-01-29 19:09:30 -08:00
{
2014-11-10 20:15:59 -08:00
if ( lineToWrite = = "MH_PAUSE" )
2014-03-17 14:41:36 -07:00
{
2014-11-10 20:15:59 -08:00
pauseRequested = true ;
2014-08-18 16:42:04 -07:00
}
2014-11-10 20:15:59 -08:00
else if ( lineToWrite = = "M226" | | lineToWrite = = "@pause" )
{
RequestPause ( printerCommandQueueIndex + 1 ) ;
}
else
{
WriteChecksumLineToPrinter ( lineToWrite ) ;
}
firstLineToResendIndex + + ;
2014-01-29 19:09:30 -08:00
}
2014-11-10 20:15:59 -08:00
printerCommandQueueIndex + + ;
2014-01-29 19:09:30 -08:00
}
2014-11-10 20:15:59 -08:00
}
else if ( printWasCanceled )
{
CommunicationState = CommunicationStates . Connected ;
// never leave the extruder and the bed hot
ReleaseMotors ( ) ;
TurnOffBedAndExtruders ( ) ;
printWasCanceled = false ;
}
else
{
if ( printerCommandQueueIndex = = loadedGCode . Count )
2014-03-17 14:41:36 -07:00
{
2014-11-10 20:15:59 -08:00
CommunicationState = CommunicationStates . FinishedPrint ;
printJobDisplayName = null ;
2014-03-17 14:41:36 -07:00
// never leave the extruder and the bed hot
ReleaseMotors ( ) ;
2014-10-15 17:04:14 -07:00
TurnOffBedAndExtruders ( ) ;
2014-03-17 14:41:36 -07:00
}
2014-11-10 20:15:59 -08:00
else if ( ! PrinterIsPaused )
2014-01-29 19:09:30 -08:00
{
2014-11-10 20:15:59 -08:00
CommunicationState = CommunicationStates . Connected ;
2014-01-29 19:09:30 -08:00
}
}
2014-11-10 20:15:59 -08:00
}
2014-03-17 14:41:36 -07:00
2014-11-10 20:15:59 -08:00
if ( pauseRequested )
{
DoPause ( ) ;
2014-01-29 19:09:30 -08:00
}
}
2014-09-03 10:43:23 -07:00
public void RequestPause ( int injectionStartIndex = 0 )
2014-03-17 14:41:36 -07:00
{
2014-09-03 10:43:23 -07:00
if ( injectionStartIndex = = 0 )
{
injectionStartIndex = printerCommandQueueIndex ;
}
2014-03-17 14:41:36 -07:00
if ( PrinterIsPrinting )
{
2014-06-26 18:13:53 -07:00
if ( CommunicationState = = CommunicationStates . PrintingFromSd )
{
CommunicationState = CommunicationStates . Paused ;
SendLineToPrinterNow ( "M25" ) ; // : Pause SD print
return ;
}
2014-03-17 14:41:36 -07:00
// Add the pause_gcode to the loadedGCode.GCodeCommandQueue
2014-11-21 12:39:13 -08:00
double currentFeedRate = loadedGCode . Instruction ( injectionStartIndex ) . FeedRate ;
2014-03-17 14:41:36 -07:00
string pauseGCode = ActiveSliceSettings . Instance . GetActiveValue ( "pause_gcode" ) ;
if ( pauseGCode . Trim ( ) = = "" )
{
2014-11-21 12:39:13 -08:00
int lastIndexAdded = InjectGCode ( "G0 X{0:0.000} Y{1:0.000} Z{2:0.000} F{3}" . FormatWith ( currentDestination . x , currentDestination . y , currentDestination . z , currentFeedRate ) , injectionStartIndex ) ;
2014-03-17 14:41:36 -07:00
DoPause ( ) ;
}
else
{
using ( TimedLock . Lock ( this , "RequestPause" ) )
{
2014-09-03 10:43:23 -07:00
int lastIndexAdded = InjectGCode ( pauseGCode , injectionStartIndex ) ;
2014-03-17 14:41:36 -07:00
// 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 ( resumeGCode , lastIndexAdded ) ;
2014-11-12 12:16:09 -08:00
lastIndexAdded = InjectGCode ( "G0 X{0:0.000} Y{1:0.000} Z{2:0.000} F{3}" . FormatWith ( currentDestination . x , currentDestination . y , currentDestination . z , currentFeedRate ) , lastIndexAdded ) ;
2014-03-17 14:41:36 -07:00
}
}
}
}
void DoPause ( )
2014-01-29 19:09:30 -08:00
{
if ( PrinterIsPrinting )
{
CommunicationState = CommunicationStates . Paused ;
}
}
private int InjectGCode ( string codeToInject , int indexToStartInjection )
{
2014-12-10 12:07:06 -08:00
codeToInject = GCodeProcessing . ReplaceMacroValues ( codeToInject ) ;
2014-03-17 14:41:36 -07:00
codeToInject = codeToInject . Replace ( "\\n" , "\n" ) ;
2014-01-29 19:09:30 -08:00
string [ ] lines = codeToInject . Split ( '\n' ) ;
2014-03-17 14:41:36 -07:00
int linesAdded = 0 ;
for ( int i = lines . Length - 1 ; i > = 0 ; i - - )
2014-01-29 19:09:30 -08:00
{
2014-03-17 14:41:36 -07:00
string [ ] splitOnSemicolon = lines [ i ] . Split ( ';' ) ;
string trimedLine = splitOnSemicolon [ 0 ] . Trim ( ) . ToUpper ( ) ;
if ( trimedLine ! = "" )
{
2014-05-23 14:19:20 -07:00
if ( loadedGCode . Count > indexToStartInjection )
2014-03-17 14:41:36 -07:00
{
2014-05-23 14:19:20 -07:00
loadedGCode . Insert ( indexToStartInjection , new PrinterMachineInstruction ( trimedLine , loadedGCode . Instruction ( indexToStartInjection ) ) ) ;
2014-03-17 14:41:36 -07:00
}
else
{
2014-05-23 14:19:20 -07:00
loadedGCode . Add ( new PrinterMachineInstruction ( trimedLine ) ) ;
2014-03-17 14:41:36 -07:00
}
linesAdded + + ;
}
2014-01-29 19:09:30 -08:00
}
2014-03-17 14:41:36 -07:00
return indexToStartInjection + linesAdded ;
2014-01-29 19:09:30 -08:00
}
public void Resume ( )
{
if ( PrinterIsPaused )
{
2014-06-26 18:13:53 -07:00
if ( ActivePrintItem . PrintItem . FileLocation = = QueueData . SdCardFileName )
{
CommunicationState = CommunicationStates . PrintingFromSd ;
SendLineToPrinterNow ( "M24" ) ; // Start/resume SD print
}
else
{
CommunicationState = CommunicationStates . Printing ;
}
2014-01-29 19:09:30 -08:00
}
}
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 ( )
{
2014-05-23 14:19:20 -07:00
loadedGCode . Clear ( ) ;
2014-01-29 19:09:30 -08:00
printerCommandQueueIndex = 0 ;
lastRemainingSecondsReported = 0 ;
allCheckSumLinesSent . Clear ( ) ;
WriteChecksumLineToPrinter ( "M110 S1" ) ;
firstLineToResendIndex = 1 ;
}
public void Stop ( )
{
switch ( CommunicationState )
{
2014-07-01 15:08:50 -07:00
case CommunicationStates . PrintingFromSd :
2014-06-26 12:55:43 -07:00
using ( TimedLock . Lock ( this , "CancelingPrint" ) )
{
// get rid of all the gcode we have left to print
ClearQueuedGCode ( ) ;
// let the process know we canceled not ended normaly.
2014-07-01 15:08:50 -07:00
CommunicationState = CommunicationStates . Connected ;
2014-06-26 18:13:53 -07:00
SendLineToPrinterNow ( "M25" ) ; // : Pause SD print
2014-07-01 14:44:27 -07:00
SendLineToPrinterNow ( "M26" ) ; // : Set SD position
2014-07-01 15:08:50 -07:00
// never leave the extruder and the bed hot
2014-12-17 12:45:29 -08:00
DonePrintingSdFile ( this , null ) ;
2014-06-26 12:55:43 -07:00
}
break ;
2014-07-01 15:08:50 -07:00
case CommunicationStates . PrintingToSd :
2014-06-26 18:13:53 -07:00
CommunicationState = CommunicationStates . Connected ;
printWasCanceled = true ;
2014-06-26 12:55:43 -07:00
break ;
2014-01-29 19:09:30 -08:00
case CommunicationStates . Printing :
{
2014-03-17 14:41:36 -07:00
using ( TimedLock . Lock ( this , "CancelingPrint" ) )
2014-01-29 19:09:30 -08:00
{
2014-03-17 14:41:36 -07:00
// get rid of all the gcode we have left to print
ClearQueuedGCode ( ) ;
string cancelGCode = ActiveSliceSettings . Instance . GetActiveValue ( "cancel_gcode" ) ;
if ( cancelGCode . Trim ( ) ! = "" )
{
// add any gcode we want to print while canceling
InjectGCode ( cancelGCode , printerCommandQueueIndex ) ;
}
// let the process know we canceled not ended normaly.
printWasCanceled = true ;
2014-01-29 19:09:30 -08:00
}
2014-03-25 17:31:57 -07:00
if ( activePrintTask ! = null )
{
TimeSpan printTimeSpan = DateTime . Now . Subtract ( activePrintTask . PrintStart ) ;
activePrintTask . PrintEnd = DateTime . Now ;
activePrintTask . PrintComplete = false ;
activePrintTask . Commit ( ) ;
}
2014-01-29 19:09:30 -08:00
}
2014-03-25 17:31:57 -07:00
2014-01-29 19:09:30 -08:00
break ;
case CommunicationStates . Paused :
{
CommunicationState = CommunicationStates . Connected ;
2014-03-25 17:31:57 -07:00
if ( activePrintTask ! = null )
{
TimeSpan printTimeSpan = DateTime . Now . Subtract ( activePrintTask . PrintStart ) ;
activePrintTask . PrintEnd = DateTime . Now ;
activePrintTask . PrintComplete = false ;
activePrintTask . Commit ( ) ;
}
}
2014-01-29 19:09:30 -08:00
break ;
case CommunicationStates . AttemptingToConnect :
CommunicationState = CommunicationStates . FailedToConnect ;
2014-06-23 17:12:55 -07:00
connectThread . Join ( JoinThreadTimeoutMs ) ;
2014-01-29 19:09:30 -08:00
CommunicationState = CommunicationStates . Disconnecting ;
if ( readFromPrinterThread ! = null )
{
2014-06-23 17:12:55 -07:00
readFromPrinterThread . Join ( JoinThreadTimeoutMs ) ;
2014-01-29 19:09:30 -08:00
}
if ( serialPort ! = null )
{
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
serialPort = null ;
}
CommunicationState = CommunicationStates . Disconnected ;
break ;
case CommunicationStates . PreparingToPrint :
CommunicationState = CommunicationStates . Connected ;
break ;
}
2014-06-20 17:54:39 -07:00
}
public bool StartSdCardPrint ( )
{
if ( ! PrinterIsConnected
| | PrinterIsPrinting
| | ActivePrintItem . PrintItem . FileLocation ! = QueueData . SdCardFileName )
{
return false ;
}
2014-12-17 12:45:29 -08:00
currentSdBytes = 0 ;
2014-06-20 17:54:39 -07:00
ClearQueuedGCode ( ) ;
CommunicationState = CommunicationStates . PrintingFromSd ;
2014-06-23 09:31:14 -07:00
SendLineToPrinterNow ( "M23 {0}" . FormatWith ( ActivePrintItem . PrintItem . Name . ToLower ( ) ) ) ; // Select SD File
SendLineToPrinterNow ( "M24" ) ; // Start/resume SD print
2014-06-20 17:54:39 -07:00
2014-06-25 17:28:28 -07:00
ReadLineStartCallBacks . AddCallBackToKey ( "Done printing file" , DonePrintingSdFile ) ;
2014-06-20 17:54:39 -07:00
return true ;
}
2014-10-15 17:04:14 -07:00
void TurnOffBedAndExtruders ( )
{
SetTargetExtruderTemperature ( 0 , 0 ) ;
SetTargetExtruderTemperature ( 1 , 0 ) ;
TargetBedTemperature = 0 ;
}
2014-06-25 17:28:28 -07:00
void DonePrintingSdFile ( object sender , EventArgs e )
{
2014-06-25 17:57:10 -07:00
UiThread . RunOnIdle ( ( state ) = >
{
ReadLineStartCallBacks . RemoveCallBackFromKey ( "Done printing file" , DonePrintingSdFile ) ;
} ) ;
2014-06-25 17:28:28 -07:00
CommunicationState = CommunicationStates . FinishedPrint ;
printJobDisplayName = null ;
// never leave the extruder and the bed hot
2014-10-15 17:04:14 -07:00
TurnOffBedAndExtruders ( ) ;
2014-06-25 17:28:28 -07:00
ReleaseMotors ( ) ;
}
2014-06-20 17:54:39 -07:00
public bool StartPrint ( string gcodeFileContents )
{
if ( ! PrinterIsConnected | | PrinterIsPrinting )
{
return false ;
}
2014-01-29 19:09:30 -08:00
gcodeFileContents = gcodeFileContents . Replace ( "\r\n" , "\n" ) ;
gcodeFileContents = gcodeFileContents . Replace ( '\r' , '\n' ) ;
string [ ] gcodeLines = gcodeFileContents . Split ( '\n' ) ;
2014-08-18 16:42:04 -07:00
List < string > printableGCode = new List < string > ( gcodeLines . Length ) ;
2014-01-29 19:09:30 -08:00
foreach ( string line in gcodeLines )
{
2014-08-18 16:42:04 -07:00
printableGCode . Add ( line ) ;
2014-01-29 19:09:30 -08:00
}
2014-06-25 17:28:28 -07:00
ExtrusionRatio = 1 ;
FeedRateRatio = 1 ;
2014-11-25 14:14:37 -08:00
LinesToWriteQueue . Clear ( ) ;
2014-11-10 20:15:59 -08:00
ClearQueuedGCode ( ) ;
loadedGCode = GCodeFile . ParseGCodeString ( string . Join ( "\n" , printableGCode . ToArray ( ) ) ) ;
switch ( communicationState )
2014-03-25 17:31:57 -07:00
{
2014-06-25 17:28:28 -07:00
case CommunicationStates . PreparingToPrintToSd :
activePrintTask = null ;
CommunicationState = CommunicationStates . PrintingToSd ;
break ;
2014-03-25 17:31:57 -07:00
2014-06-25 17:28:28 -07:00
case CommunicationStates . PreparingToPrint :
if ( ActivePrintItem . PrintItem . Id = = 0 )
{
ActivePrintItem . PrintItem . Commit ( ) ;
}
2014-03-25 17:31:57 -07:00
2014-06-25 17:28:28 -07:00
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 ( ) ;
}
2014-01-29 19:09:30 -08:00
if ( printableGCode . Count = = 0 )
{
return true ;
}
return true ;
}
2014-11-04 15:38:41 -08:00
const int MAX_INVALID_CONNECTION_CHARS = 3 ;
2014-11-10 20:15:59 -08:00
string dataLastRead = "" ;
2014-01-29 19:09:30 -08:00
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 ) )
{
2014-12-17 12:45:29 -08:00
if ( PrinterIsPrinting
& & PrinterIsConnected
& & CommunicationState ! = CommunicationStates . PrintingFromSd )
2014-11-10 20:15:59 -08:00
{
TryWriteNextLineFromGCodeFile ( ) ;
}
2014-01-29 19:09:30 -08:00
try
{
2014-11-10 20:15:59 -08:00
while ( serialPort ! = null
2014-06-23 17:12:55 -07:00
& & serialPort . BytesToRead > 0 )
2014-01-29 19:09:30 -08:00
{
2014-11-10 20:15:59 -08:00
using ( TimedLock . Lock ( this , "ReadFromPrinter" ) )
2014-01-29 19:09:30 -08:00
{
2014-11-10 20:15:59 -08:00
string allDataRead = serialPort . ReadExisting ( ) ;
//Debug.Write("r: " + allDataRead);
//Console.Write(indata);
dataLastRead + = allDataRead . Replace ( '\r' , '\n' ) ;
do
2014-01-29 19:09:30 -08:00
{
2014-11-10 20:15:59 -08:00
int returnPosition = dataLastRead . IndexOf ( '\n' ) ;
if ( returnPosition < 0 )
{
// there is no return keep getting characters
break ;
}
if ( dataLastRead . Length > 0 )
2014-01-29 19:09:30 -08:00
{
2014-11-10 20:15:59 -08:00
lastLineRead = dataLastRead . Substring ( 0 , returnPosition ) ;
dataLastRead = dataLastRead . Substring ( returnPosition + 1 ) ;
2014-01-29 19:09:30 -08:00
2014-09-10 12:11:27 -07:00
// process this command
{
StringEventArgs currentEvent = new StringEventArgs ( lastLineRead ) ;
CommunicationUnconditionalFromPrinter . CallEvents ( this , currentEvent ) ;
FoundStringEventArgs foundResponse = new FoundStringEventArgs ( currentEvent . Data ) ;
ReadLineStartCallBacks . CheckForKeys ( foundResponse ) ;
ReadLineContainsCallBacks . CheckForKeys ( foundResponse ) ;
2014-01-29 19:09:30 -08:00
2014-09-10 12:11:27 -07:00
if ( foundResponse . SendToDelegateFunctions )
{
ReadLine . CallEvents ( this , currentEvent ) ;
}
}
2014-11-04 15:38:41 -08:00
// If we've encountered a newline character and we're still in .AttemptingToConnect
2014-09-10 12:11:27 -07:00
if ( CommunicationState = = CommunicationStates . AttemptingToConnect )
2014-01-29 19:09:30 -08:00
{
2014-11-04 15:38:41 -08:00
// TODO: This is an initial proof of concept for validating the printer response after DTR. More work is
// needed to test this technique across existing hardware and/or edge cases where this simple approach
// (initial line having more than 3 non-ascii characters) may not be adequate or appropriate.
// TODO: Revise the INVALID char count to an agreed upon threshold
string [ ] segments = lastLineRead . Split ( '?' ) ;
if ( segments . Length < = MAX_INVALID_CONNECTION_CHARS )
{
CommunicationState = CommunicationStates . Connected ;
}
else
{
// Force port shutdown and cleanup
2014-11-04 21:09:05 -08:00
AbortConnectionAttempt ( "Invalid printer response" . Localize ( ) , false ) ;
2014-11-04 15:38:41 -08:00
}
2014-01-29 19:09:30 -08:00
}
}
2014-11-10 20:15:59 -08:00
} while ( true ) ;
2014-01-29 19:09:30 -08:00
}
2014-11-10 20:15:59 -08:00
timeSinceLastReadAnything . Restart ( ) ;
2014-01-29 19:09:30 -08:00
}
Thread . Sleep ( 1 ) ;
}
catch ( TimeoutException )
{
}
catch ( IOException )
{
OnConnectionFailed ( null ) ;
}
2014-12-24 12:12:11 -08:00
catch ( InvalidOperationException ex )
2014-01-29 19:09:30 -08:00
{
2014-12-24 12:12:11 -08:00
Debug . WriteLine ( ex . Message ) ;
2014-01-29 19:09:30 -08:00
// this happens when the serial port closes after we check and before we read it.
}
catch ( UnauthorizedAccessException )
{
OnConnectionFailed ( null ) ;
}
}
}
public void ReleaseMotors ( )
{
2014-04-09 16:53:08 -07:00
SendLineToPrinterNow ( "M84" ) ;
2014-01-29 19:09:30 -08:00
}
[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" ;
}
2014-04-09 16:53:08 -07:00
SendLineToPrinterNow ( command ) ;
2014-01-29 19:09:30 -08:00
ReadPosition ( ) ;
}
public void SetMovementToAbsolute ( )
{
2014-06-11 14:52:58 -07:00
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "G90" ) ;
2014-01-29 19:09:30 -08:00
}
public void SetMovementToRelative ( )
{
2014-06-11 14:52:58 -07:00
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "G91" ) ;
2014-01-29 19:09:30 -08:00
}
public void MoveRelative ( Axis axis , double moveAmountMm , double feedRateMmPerMinute )
{
if ( moveAmountMm ! = 0 )
{
SetMovementToRelative ( ) ;
2014-06-11 14:52:58 -07:00
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "G1 F{0}" . FormatWith ( feedRateMmPerMinute ) ) ;
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "G1 {0}{1}" . FormatWith ( axis , moveAmountMm ) ) ;
2014-01-29 19:09:30 -08:00
SetMovementToAbsolute ( ) ;
}
}
2014-10-13 18:06:14 -07:00
public void MoveExtruderRelative ( double moveAmountMm , double feedRateMmPerMinute , int extruderNumber = 0 )
{
if ( moveAmountMm ! = 0 )
{
SetMovementToRelative ( ) ;
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "T{0}" . FormatWith ( extruderNumber ) ) ; //Set active extruder
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "G1 F{0}" . FormatWith ( feedRateMmPerMinute ) ) ;
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "G1 E{0}" . FormatWith ( moveAmountMm ) ) ;
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "T0" . FormatWith ( extruderNumber ) ) ; //Reset back to extruder one
SetMovementToAbsolute ( ) ;
}
}
2014-01-29 19:09:30 -08:00
public void MoveAbsolute ( Axis axis , double axisPositionMm , double feedRateMmPerMinute )
{
SetMovementToAbsolute ( ) ;
2014-06-11 14:52:58 -07:00
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "G1 F{0}" . FormatWith ( feedRateMmPerMinute ) ) ;
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "G1 {0}{1}" . FormatWith ( axis , axisPositionMm ) ) ;
2014-01-29 19:09:30 -08:00
}
public void MoveAbsolute ( Vector3 position , double feedRateMmPerMinute )
{
SetMovementToAbsolute ( ) ;
2014-06-11 14:52:58 -07:00
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "G1 F{0}" . FormatWith ( feedRateMmPerMinute ) ) ;
PrinterConnectionAndCommunication . Instance . SendLineToPrinterNow ( "G1 X{0}Y{1}Z{2}" . FormatWith ( position . x , position . y , position . z ) ) ;
2014-01-29 19:09:30 -08:00
}
public void ReadPosition ( )
{
2014-04-09 16:53:08 -07:00
SendLineToPrinterNow ( "M114" ) ;
2014-01-29 19:09:30 -08:00
}
2014-06-26 12:55:43 -07:00
public void DeleteFileFromSdCard ( string fileName )
{
// Register to detect the file deleted confirmation.
// This should have worked without this by getting the normal 'ok' on the next line. But the ok is not on its own line.
ReadLineStartCallBacks . AddCallBackToKey ( "File deleted:" , FileDelteConfirmed ) ;
// and send the line to delete the file
SendLineToPrinterNow ( "M30 {0}" . FormatWith ( fileName . ToLower ( ) ) ) ;
}
void FileDelteConfirmed ( object sender , EventArgs e )
{
UiThread . RunOnIdle ( ( state ) = >
{
ReadLineStartCallBacks . RemoveCallBackFromKey ( "File deleted:" , FileDelteConfirmed ) ;
} ) ;
PrintingCanContinue ( this , null ) ;
}
2014-01-29 19:09:30 -08:00
}
}