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
2015-04-08 15:20:10 -07:00
modification , are permitted provided that the following conditions are met :
2014-01-29 19:09:30 -08:00
1. Redistributions of source code must retain the above copyright notice , this
2015-04-08 15:20:10 -07:00
list of conditions and the following disclaimer .
2014-01-29 19:09:30 -08:00
2. Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
2015-04-08 15:20:10 -07:00
and / or other materials provided with the distribution .
2014-01-29 19:09:30 -08:00
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
2015-04-08 15:20:10 -07:00
of the authors and should not be interpreted as representing official policies ,
2014-01-29 19:09:30 -08:00
either expressed or implied , of the FreeBSD Project .
* /
2017-06-13 17:32:38 -07:00
using System ;
using System.Diagnostics ;
using System.Globalization ;
using System.IO ;
using System.Linq ;
using System.Runtime.InteropServices ;
using System.Threading ;
using System.Threading.Tasks ;
2016-04-06 11:56:48 -07:00
using Gaming.Game ;
2014-01-29 19:09:30 -08:00
using MatterHackers.Agg ;
using MatterHackers.GCodeVisualizer ;
using MatterHackers.Localizations ;
2014-03-05 10:33:19 -08:00
using MatterHackers.MatterControl.DataStorage ;
2015-11-28 19:59:14 -08:00
using MatterHackers.MatterControl.PrinterCommunication.Io ;
2014-03-05 10:33:19 -08:00
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 MatterHackers.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
{
2017-06-13 17:32:38 -07:00
public enum CommunicationStates
{
Disconnected ,
AttemptingToConnect ,
FailedToConnect ,
Connected ,
PreparingToPrint ,
Printing ,
PrintingFromSd ,
Paused ,
FinishedPrint ,
Disconnecting ,
ConnectionLost
} ;
public enum DetailedPrintingState { HomingAxis , HeatingBed , HeatingExtruder , Printing } ;
public enum FirmwareTypes { Unknown , Repetier , Marlin , Sprinter } ;
2017-06-03 09:03:02 -07:00
public static class PrintItemWrapperExtensionMethods
2017-01-18 17:02:58 -08:00
{
private static TextInfo textInfo = new CultureInfo ( "en-US" , false ) . TextInfo ;
public static string GetFriendlyName ( this PrintItemWrapper printItemWrapper )
{
2017-01-19 11:58:19 -08:00
if ( printItemWrapper ? . Name = = null )
{
return "" ;
}
return textInfo ? . ToTitleCase ( printItemWrapper . Name . Replace ( '_' , ' ' ) ) ;
2017-01-18 17:02:58 -08:00
}
2017-06-03 09:03:02 -07:00
public static string GetFriendlyName ( string fileName )
{
if ( fileName = = null )
{
return "" ;
}
return textInfo ? . ToTitleCase ( fileName . Replace ( '_' , ' ' ) ) ;
}
2017-01-18 17:02:58 -08:00
}
2015-04-08 15:20:10 -07:00
/// <summary>
2016-01-05 14:31:17 -08:00
/// This is the class that communicates with a RepRap printer over the serial port.
2015-04-08 15:20:10 -07:00
/// It handles opening and closing the serial port and does quite a bit of gcode parsing.
2016-01-05 14:31:17 -08:00
/// It should be refactored into better modules at some point.
2015-04-08 15:20:10 -07:00
/// </summary>
2017-06-13 17:22:49 -07:00
public class PrinterConnection
2015-04-08 15:20:10 -07:00
{
public RootedObjectEventHandler BedTemperatureRead = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler BedTemperatureSet = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler CommunicationStateChanged = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler CommunicationUnconditionalFromPrinter = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler CommunicationUnconditionalToPrinter = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler ConnectionFailed = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler ConnectionSucceeded = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler DestinationChanged = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler EnableChanged = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler ExtruderTemperatureRead = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler ExtruderTemperatureSet = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler FanSpeedSet = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler FirmwareVersionRead = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler PositionRead = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler PrintFinished = new RootedObjectEventHandler ( ) ;
2017-04-13 14:25:46 -07:00
public RootedObjectEventHandler PauseOnLayer = new RootedObjectEventHandler ( ) ;
2017-05-19 14:39:57 -07:00
public RootedObjectEventHandler FilamentRunout = new RootedObjectEventHandler ( ) ;
2017-04-13 14:25:46 -07:00
2015-04-08 15:20:10 -07:00
public RootedObjectEventHandler PrintingStateChanged = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler ReadLine = new RootedObjectEventHandler ( ) ;
public RootedObjectEventHandler WroteLine = new RootedObjectEventHandler ( ) ;
2017-05-19 14:39:57 -07:00
public bool WatingForPositionRead
{
get
{
// make sure the longest we will wait under any circumstance is 60 seconds
if ( waitingForPosition . ElapsedMilliseconds > 60000 )
{
waitingForPosition . Reset ( ) ;
PositionReadQueued = false ;
}
return waitingForPosition . IsRunning | | PositionReadQueued ;
}
}
2017-04-11 10:41:23 -07:00
2015-04-23 20:19:00 -07:00
public RootedObjectEventHandler AtxPowerStateChanged = new RootedObjectEventHandler ( ) ;
private bool atxPowerIsOn = false ;
2016-04-18 11:31:31 -07:00
internal const int MAX_EXTRUDERS = 16 ;
2015-04-08 15:20:10 -07:00
private const int MAX_INVALID_CONNECTION_CHARS = 3 ;
2017-06-13 17:22:49 -07:00
private static PrinterConnection globalInstance ;
2015-04-08 15:20:10 -07:00
2017-04-11 10:41:23 -07:00
private object locker = new object ( ) ;
2016-01-07 16:45:16 -08:00
2015-04-08 15:20:10 -07:00
private readonly int JoinThreadTimeoutMs = 5000 ;
private PrintTask activePrintTask ;
private double actualBedTemperature ;
2016-07-25 12:29:43 -07:00
private int currentlyActiveExtruderIndex = 0 ;
2015-04-08 15:20:10 -07:00
private double [ ] actualExtruderTemperature = new double [ MAX_EXTRUDERS ] ;
private CheckSumLines allCheckSumLinesSent = new CheckSumLines ( ) ;
2016-09-20 14:32:22 -07:00
private int backupAmount = 0 ;
2015-04-08 15:20:10 -07:00
private CommunicationStates communicationState = CommunicationStates . Disconnected ;
private string connectionFailureMessage = "Unknown Reason" ;
private Thread connectThread ;
2016-01-19 15:16:05 -08:00
private PrinterMove currentDestination ;
2015-04-08 15:20:10 -07:00
2016-01-19 15:16:05 -08:00
public double CurrentExtruderDestination { get { return currentDestination . extrusion ; } }
2015-04-08 15:20:10 -07:00
2016-01-19 15:16:05 -08:00
public double CurrentFeedRate { get { return currentDestination . feedRate ; } }
2015-12-01 14:18:01 -08:00
2016-01-14 10:32:25 -08:00
private double currentSdBytes = 0 ;
2015-04-08 15:20:10 -07:00
private PrinterMachineInstruction . MovementTypes extruderMode = PrinterMachineInstruction . MovementTypes . Absolute ;
private int fanSpeed ;
private bool firmwareUriGcodeSend = false ;
2016-12-02 13:51:58 -08:00
private int currentLineIndexToSend = 0 ;
2015-04-08 15:20:10 -07:00
private bool ForceImmediateWrites = false ;
private string itemNotFoundMessage = "Item not found" . Localize ( ) ;
private string lastLineRead = "" ;
2016-01-19 15:16:05 -08:00
private PrinterMove lastReportedPosition ;
2015-04-08 15:20:10 -07:00
2017-04-11 10:41:23 -07:00
private DataViewGraph sendTimeAfterOkGraph ;
2016-04-06 11:56:48 -07:00
2016-01-14 10:32:25 -08:00
private GCodeFile loadedGCode = new GCodeFileLoaded ( ) ;
2015-11-28 07:46:57 -08:00
2016-01-14 10:32:25 -08:00
private GCodeFileStream gCodeFileStream0 = null ;
2016-01-19 15:16:05 -08:00
private PauseHandlingStream pauseHandlingStream1 = null ;
private QueuedCommandsStream queuedCommandStream2 = null ;
private RelativeToAbsoluteStream relativeToAbsoluteStream3 = null ;
private PrintLevelingStream printLevelingStream4 = null ;
private WaitForTempStream waitForTempStream5 = null ;
private BabyStepsStream babyStepsStream6 = null ;
private ExtrusionMultiplyerStream extrusionMultiplyerStream7 = null ;
private FeedRateMultiplyerStream feedrateMultiplyerStream8 = null ;
private RequestTemperaturesStream requestTemperaturesStream9 = null ;
2015-11-28 19:59:14 -08:00
2016-01-14 10:32:25 -08:00
private GCodeStream totalGCodeStream = null ;
2015-04-08 15:20:10 -07:00
private PrinterMachineInstruction . MovementTypes movementMode = PrinterMachineInstruction . MovementTypes . Absolute ;
2017-03-07 17:52:44 -08:00
public CommunicationStates PrePauseCommunicationState { get ; private set ; } = CommunicationStates . Printing ;
2015-04-08 15:20:10 -07:00
private DetailedPrintingState printingStatePrivate ;
private FoundStringContainsCallbacks ReadLineContainsCallBacks = new FoundStringContainsCallbacks ( ) ;
private FoundStringStartsWithCallbacks ReadLineStartCallBacks = new FoundStringStartsWithCallbacks ( ) ;
// we start out by setting it to a nothing file
private IFrostedSerialPort serialPort ;
private bool stopTryingToConnect = false ;
private double targetBedTemperature ;
private double [ ] targetExtruderTemperature = new double [ MAX_EXTRUDERS ] ;
private Stopwatch timeHaveBeenWaitingForOK = new Stopwatch ( ) ;
private Stopwatch timeSinceLastReadAnything = new Stopwatch ( ) ;
private Stopwatch timeSinceLastWrite = new Stopwatch ( ) ;
2016-04-06 11:56:48 -07:00
private Stopwatch timeSinceRecievedOk = new Stopwatch ( ) ;
2015-04-08 15:20:10 -07:00
private Stopwatch timeSinceStartedPrint = new Stopwatch ( ) ;
private Stopwatch timeWaitingForSdProgress = new Stopwatch ( ) ;
private double totalSdBytes = 0 ;
2017-04-11 10:41:23 -07:00
private bool PositionReadQueued { get ; set ; } = false ;
2015-04-08 15:20:10 -07:00
private Stopwatch waitingForPosition = new Stopwatch ( ) ;
private FoundStringContainsCallbacks WriteLineContainsCallBacks = new FoundStringContainsCallbacks ( ) ;
private FoundStringStartsWithCallbacks WriteLineStartCallBacks = new FoundStringStartsWithCallbacks ( ) ;
2016-04-14 14:34:30 -07:00
private double secondsSinceUpdateHistory = 0 ;
2017-02-01 17:36:33 -08:00
private EventHandler unregisterEvents ;
private double feedRateRatio = 1 ;
2017-06-13 17:22:49 -07:00
private PrinterConnection ( )
2015-01-19 18:26:09 -08:00
{
2015-04-08 15:20:10 -07:00
MonitorPrinterTemperature = true ;
2015-01-19 18:26:09 -08:00
2015-04-08 15:20:10 -07:00
StringComparer stringComparer = StringComparer . OrdinalIgnoreCase ;
2015-10-13 10:17:20 -07:00
ReadLineStartCallBacks . AddCallbackToKey ( "start" , FoundStart ) ;
ReadLineStartCallBacks . AddCallbackToKey ( "start" , PrintingCanContinue ) ;
2015-01-19 18:26:09 -08:00
2015-10-13 10:17:20 -07:00
ReadLineStartCallBacks . AddCallbackToKey ( "ok" , SuppressEcho ) ;
ReadLineStartCallBacks . AddCallbackToKey ( "wait" , SuppressEcho ) ;
2016-01-04 21:18:57 -08:00
ReadLineStartCallBacks . AddCallbackToKey ( "T:" , SuppressEcho ) ; // repetier
2015-04-08 15:20:10 -07:00
2015-10-13 10:17:20 -07:00
ReadLineStartCallBacks . AddCallbackToKey ( "ok" , PrintingCanContinue ) ;
ReadLineStartCallBacks . AddCallbackToKey ( "Done saving file" , PrintingCanContinue ) ;
2015-04-08 15:20:10 -07:00
2015-10-13 10:17:20 -07:00
ReadLineStartCallBacks . AddCallbackToKey ( "B:" , ReadTemperatures ) ; // smoothie
2017-03-21 14:26:54 -07:00
ReadLineContainsCallBacks . AddCallbackToKey ( "T0:" , ReadTemperatures ) ; // marlin
ReadLineContainsCallBacks . AddCallbackToKey ( "T:" , ReadTemperatures ) ; // repatier
2015-04-08 15:20:10 -07:00
2017-06-27 16:48:54 -07:00
ReadLineStartCallBacks . AddCallbackToKey ( "SD printing byte" , ReadSdProgress ) ; // repetier
2015-04-08 15:20:10 -07:00
2015-10-13 10:17:20 -07:00
ReadLineStartCallBacks . AddCallbackToKey ( "C:" , ReadTargetPositions ) ;
ReadLineStartCallBacks . AddCallbackToKey ( "ok C:" , ReadTargetPositions ) ; // smoothie is reporting the C: with an ok first.
ReadLineStartCallBacks . AddCallbackToKey ( "X:" , ReadTargetPositions ) ;
2017-06-27 16:48:54 -07:00
ReadLineStartCallBacks . AddCallbackToKey ( "ok X:" , ReadTargetPositions ) ; //
2015-04-08 15:20:10 -07:00
2016-12-14 15:03:37 -08:00
ReadLineStartCallBacks . AddCallbackToKey ( "rs " , PrinterRequestsResend ) ; // smoothie is lower case and no :
ReadLineStartCallBacks . AddCallbackToKey ( "RS:" , PrinterRequestsResend ) ;
2015-10-13 10:17:20 -07:00
ReadLineContainsCallBacks . AddCallbackToKey ( "Resend:" , PrinterRequestsResend ) ;
2015-04-08 15:20:10 -07:00
2015-10-13 10:17:20 -07:00
ReadLineContainsCallBacks . AddCallbackToKey ( "FIRMWARE_NAME:" , PrinterStatesFirmware ) ;
ReadLineStartCallBacks . AddCallbackToKey ( "EXTENSIONS:" , PrinterStatesExtensions ) ;
2015-04-08 15:20:10 -07:00
2016-01-05 17:31:11 -08:00
#region hardware failure callbacks
2017-04-11 10:41:23 -07:00
2016-01-05 17:31:11 -08:00
// smoothie temperature failures
2016-01-06 12:09:37 -08:00
ReadLineContainsCallBacks . AddCallbackToKey ( "T:inf" , PrinterReportsError ) ;
ReadLineContainsCallBacks . AddCallbackToKey ( "B:inf" , PrinterReportsError ) ;
2016-01-05 17:31:11 -08:00
// marlin temperature failures
ReadLineContainsCallBacks . AddCallbackToKey ( "MINTEMP" , PrinterReportsError ) ;
ReadLineContainsCallBacks . AddCallbackToKey ( "MAXTEMP" , PrinterReportsError ) ;
2016-01-06 12:09:37 -08:00
ReadLineContainsCallBacks . AddCallbackToKey ( "M999" , PrinterReportsError ) ;
2016-01-20 09:56:12 -08:00
ReadLineContainsCallBacks . AddCallbackToKey ( "Error: Extruder switched off" , PrinterReportsError ) ;
2016-03-09 12:36:24 -08:00
ReadLineContainsCallBacks . AddCallbackToKey ( "Heater decoupled" , PrinterReportsError ) ;
2016-09-22 17:26:27 -07:00
ReadLineContainsCallBacks . AddCallbackToKey ( "cold extrusion prevented" , PrinterReportsError ) ;
2016-09-29 12:05:55 -07:00
ReadLineContainsCallBacks . AddCallbackToKey ( "Error:Thermal Runaway, system stopped!" , PrinterReportsError ) ;
2017-04-13 16:32:32 -07:00
ReadLineContainsCallBacks . AddCallbackToKey ( "Error:Heating failed" , PrinterReportsError ) ;
2016-01-06 12:09:37 -08:00
2016-09-22 17:26:27 -07:00
// repetier temperature failures
2016-01-05 17:31:11 -08:00
ReadLineContainsCallBacks . AddCallbackToKey ( "dry run mode" , PrinterReportsError ) ;
2016-12-14 16:26:46 -08:00
ReadLineStartCallBacks . AddCallbackToKey ( "accelerometer send i2c error" , PrinterReportsError ) ;
ReadLineStartCallBacks . AddCallbackToKey ( "accelerometer i2c recv error" , PrinterReportsError ) ;
2016-12-12 16:37:09 -08:00
// s3g temperature failures
ReadLineContainsCallBacks . AddCallbackToKey ( "Bot is Shutdown due to Overheat" , PrinterReportsError ) ;
2017-04-11 10:41:23 -07:00
#endregion hardware failure callbacks
2016-01-05 16:48:04 -08:00
2015-10-13 10:17:20 -07:00
WriteLineStartCallBacks . AddCallbackToKey ( "G90" , MovementWasSetToAbsoluteMode ) ;
WriteLineStartCallBacks . AddCallbackToKey ( "G91" , MovementWasSetToRelativeMode ) ;
WriteLineStartCallBacks . AddCallbackToKey ( "M80" , AtxPowerUpWasWritenToPrinter ) ;
WriteLineStartCallBacks . AddCallbackToKey ( "M81" , AtxPowerDownWasWritenToPrinter ) ;
2017-05-19 14:39:57 -07:00
WriteLineStartCallBacks . AddCallbackToKey ( "M82" , ExtruderWasSetToAbsoluteMode ) ;
WriteLineStartCallBacks . AddCallbackToKey ( "M83" , ExtruderWasSetToRelativeMode ) ;
WriteLineStartCallBacks . AddCallbackToKey ( "M104" , ExtruderTemperatureWasWritenToPrinter ) ;
WriteLineStartCallBacks . AddCallbackToKey ( "M106" , FanSpeedWasWritenToPrinter ) ;
WriteLineStartCallBacks . AddCallbackToKey ( "M107" , FanOffWasWritenToPrinter ) ;
WriteLineStartCallBacks . AddCallbackToKey ( "M109" , ExtruderTemperatureWasWritenToPrinter ) ;
WriteLineStartCallBacks . AddCallbackToKey ( "M140" , BedTemperatureWasWritenToPrinter ) ;
WriteLineStartCallBacks . AddCallbackToKey ( "M190" , BedTemperatureWasWritenToPrinter ) ;
2016-07-25 12:29:43 -07:00
WriteLineStartCallBacks . AddCallbackToKey ( "T" , ExtruderIndexSet ) ;
2017-02-01 17:36:33 -08:00
ActiveSliceSettings . SettingChanged . RegisterEvent ( ( s , e ) = >
{
var eventArgs = e as StringEventArgs ;
if ( eventArgs ? . Data = = SettingsKey . feedrate_ratio )
{
feedRateRatio = ActiveSliceSettings . Instance . GetValue < double > ( SettingsKey . feedrate_ratio ) ;
}
} , ref unregisterEvents ) ;
2016-07-25 12:29:43 -07:00
}
private void ExtruderIndexSet ( object sender , EventArgs e )
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
double extruderBeingSet = 0 ;
if ( GCodeFile . GetFirstNumberAfter ( "T" , foundStringEventArgs . LineToCheck , ref extruderBeingSet ) )
{
currentlyActiveExtruderIndex = ( int ) extruderBeingSet ;
}
2015-04-08 15:20:10 -07:00
}
2016-01-14 10:32:25 -08:00
[Flags]
2015-04-08 15:20:10 -07:00
public enum Axis { X = 1 , Y = 2 , Z = 4 , E = 8 , XYZ = ( X | Y | Z ) }
2017-06-13 17:22:49 -07:00
public static PrinterConnection Instance
2015-04-08 15:20:10 -07:00
{
get
2015-01-19 18:26:09 -08:00
{
2015-04-08 15:20:10 -07:00
if ( globalInstance = = null )
2015-01-19 18:26:09 -08:00
{
2017-06-13 17:22:49 -07:00
globalInstance = new PrinterConnection ( ) ;
2015-01-19 18:26:09 -08:00
}
2015-04-08 15:20:10 -07:00
return globalInstance ;
}
}
2015-01-19 18:26:09 -08:00
2015-04-08 15:20:10 -07:00
public double ActualBedTemperature
{
get
2015-01-19 18:26:09 -08:00
{
2015-04-08 15:20:10 -07:00
return actualBedTemperature ;
2015-01-19 18:26:09 -08:00
}
2015-04-08 15:20:10 -07:00
}
2015-01-19 18:26:09 -08:00
2015-04-08 15:20:10 -07:00
public int BaudRate
{
get
2015-01-19 18:26:09 -08:00
{
2015-04-08 15:20:10 -07:00
int baudRate = 250000 ;
if ( this . ActivePrinter ! = null )
{
try
{
2016-07-12 17:46:48 -07:00
if ( ! string . IsNullOrEmpty ( ActiveSliceSettings . Instance . GetValue ( SettingsKey . baud_rate ) ) )
2015-04-08 15:20:10 -07:00
{
2016-07-12 17:46:48 -07:00
baudRate = Convert . ToInt32 ( ActiveSliceSettings . Instance . GetValue ( SettingsKey . baud_rate ) ) ;
2015-04-08 15:20:10 -07:00
}
}
catch
{
}
}
return baudRate ;
2015-01-19 18:26:09 -08:00
}
}
2015-04-08 15:20:10 -07:00
public CommunicationStates CommunicationState
{
get
{
return communicationState ;
}
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
set
{
2015-03-13 12:25:33 -07:00
switch ( value )
{
case CommunicationStates . AttemptingToConnect :
2016-01-14 10:32:25 -08:00
#if DEBUG
2015-03-13 12:25:33 -07:00
if ( serialPort = = null )
{
throw new Exception ( "The serial port should be constructed prior to setting this or we can fail our connection on a write before it has a chance to be created." ) ;
}
2016-01-14 10:32:25 -08:00
#endif
2015-03-13 12:25:33 -07:00
break ;
2015-04-27 15:42:31 -07:00
case CommunicationStates . Connected :
2016-01-18 11:07:00 -08:00
SendLineToPrinterNow ( "M115" ) ;
2017-02-10 14:44:07 -08:00
ReadPosition ( ) ;
2015-04-27 15:42:31 -07:00
break ;
2016-09-16 15:27:58 -07:00
case CommunicationStates . ConnectionLost :
case CommunicationStates . Disconnected :
TurnOffBedAndExtruders ( ) ;
for ( int extruderIndex = 0 ; extruderIndex < MAX_EXTRUDERS ; extruderIndex + + )
{
actualExtruderTemperature [ extruderIndex ] = 0 ;
OnExtruderTemperatureRead ( new TemperatureEventArgs ( extruderIndex , GetActualExtruderTemperature ( extruderIndex ) ) ) ;
}
actualBedTemperature = 0 ;
OnBedTemperatureRead ( new TemperatureEventArgs ( 0 , ActualBedTemperature ) ) ;
break ;
2015-03-13 12:25:33 -07:00
}
2015-04-08 15:20:10 -07:00
if ( communicationState ! = value )
{
2015-04-27 15:42:31 -07:00
CommunicationUnconditionalToPrinter . CallEvents ( this , new StringEventArgs ( "Communication State: {0}\n" . FormatWith ( value . ToString ( ) ) ) ) ;
2015-04-08 15:20:10 -07:00
switch ( communicationState )
{
// if it was printing
2015-04-07 10:19:49 -07:00
case CommunicationStates . PrintingFromSd :
2015-04-08 15:20:10 -07:00
case CommunicationStates . Printing :
{
// and is changing to paused
if ( value = = CommunicationStates . Paused )
{
if ( communicationState = = CommunicationStates . Printing )
2015-04-07 10:19:49 -07:00
{
2017-03-07 17:52:44 -08:00
PrePauseCommunicationState = CommunicationStates . Printing ;
2015-04-07 10:19:49 -07:00
}
else
{
2017-03-07 17:52:44 -08:00
PrePauseCommunicationState = CommunicationStates . PrintingFromSd ;
2015-04-07 10:19:49 -07:00
}
2015-04-08 15:20:10 -07:00
timeSinceStartedPrint . Stop ( ) ;
}
else if ( value = = CommunicationStates . FinishedPrint )
{
if ( activePrintTask ! = null )
{
TimeSpan printTimeSpan = DateTime . Now . Subtract ( activePrintTask . PrintStart ) ;
activePrintTask . PrintEnd = DateTime . Now ;
2016-04-14 10:34:47 -07:00
activePrintTask . PercentDone = 100 ;
2015-04-08 15:20:10 -07:00
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 ;
// was paused
case CommunicationStates . Paused :
{
// changing to printing
if ( value = = CommunicationStates . Printing )
{
timeSinceStartedPrint . Start ( ) ;
}
}
break ;
2015-01-28 10:50:06 -08:00
default :
if ( ! timeSinceStartedPrint . IsRunning
& & value = = CommunicationStates . Printing )
{
2016-01-05 14:31:17 -08:00
// If we are just starting to print (we know we were not paused or it would have stopped above)
2015-01-28 10:50:06 -08:00
timeSinceStartedPrint . Restart ( ) ;
}
break ;
2015-04-08 15:20:10 -07:00
}
2015-02-05 07:50:57 -08:00
2015-04-08 15:20:10 -07:00
communicationState = value ;
OnCommunicationStateChanged ( null ) ;
}
}
}
2016-07-18 14:15:37 -07:00
public string ComPort = > ActiveSliceSettings . Instance ? . Helpers . ComPort ( ) ;
2016-04-27 17:34:33 -07:00
2016-06-16 17:09:50 -07:00
public string DriverType = > ActiveSliceSettings . Instance ? . GetValue ( "driver_type" ) ;
2015-02-05 07:50:57 -08:00
2015-04-23 20:19:00 -07:00
public bool AtxPowerEnabled
{
get
{
return atxPowerIsOn ;
}
set
{
if ( value )
{
2017-02-09 13:51:16 -08:00
SendLineToPrinterNow ( "M80" ) ;
2015-04-23 20:19:00 -07:00
}
else
{
2017-02-09 13:51:16 -08:00
SendLineToPrinterNow ( "M81" ) ;
2015-04-23 20:19:00 -07:00
}
}
}
2015-04-08 15:20:10 -07:00
public string ConnectionFailureMessage { get { return connectionFailureMessage ; } }
2015-02-05 07:50:57 -08:00
2016-01-19 15:16:05 -08:00
public Vector3 CurrentDestination { get { return currentDestination . position ; } }
2015-04-08 15:20:10 -07:00
public int CurrentlyPrintingLayer
{
get
2015-02-05 07:50:57 -08:00
{
2016-01-14 10:32:25 -08:00
if ( gCodeFileStream0 ! = null )
{
int instructionIndex = gCodeFileStream0 . LineIndex - backupAmount ;
return loadedGCode . GetLayerIndex ( instructionIndex ) ;
}
2015-11-28 07:46:57 -08:00
2016-01-14 10:32:25 -08:00
return 0 ;
2015-02-06 08:23:19 -08:00
}
2015-04-08 15:20:10 -07:00
}
2015-02-05 07:50:57 -08:00
2016-12-29 12:52:12 -08:00
public string DeviceCode { get ; private set ; }
2015-02-06 08:23:19 -08:00
2015-04-08 15:20:10 -07:00
public bool Disconnecting
{
get
{
return CommunicationState = = CommunicationStates . Disconnecting ;
}
}
2015-02-06 08:23:19 -08:00
2015-04-08 15:20:10 -07:00
public int FanSpeed0To255
{
get { return fanSpeed ; }
set
2015-02-05 07:50:57 -08:00
{
2015-04-08 15:20:10 -07:00
fanSpeed = Math . Max ( 0 , Math . Min ( 255 , value ) ) ;
OnFanSpeedSet ( null ) ;
if ( PrinterIsConnected )
{
SendLineToPrinterNow ( "M106 S{0}" . FormatWith ( fanSpeed ) ) ;
}
2015-02-05 07:50:57 -08:00
}
2015-04-08 15:20:10 -07:00
}
2015-02-05 07:50:57 -08:00
2017-02-01 17:36:33 -08:00
public FirmwareTypes FirmwareType { get ; private set ; } = FirmwareTypes . Unknown ;
2015-03-14 16:00:04 -07:00
2016-12-28 13:10:39 -08:00
public string FirmwareVersion { get ; private set ; }
2014-01-29 19:09:30 -08:00
2016-01-19 15:16:05 -08:00
public Vector3 LastReportedPosition { get { return lastReportedPosition . position ; } }
2014-01-29 19:09:30 -08:00
2017-02-01 17:36:33 -08:00
public bool MonitorPrinterTemperature { get ; set ; }
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
public double PercentComplete
{
get
{
if ( CommunicationState = = CommunicationStates . PrintingFromSd
2017-03-07 17:52:44 -08:00
| | ( communicationState = = CommunicationStates . Paused & & PrePauseCommunicationState = = CommunicationStates . PrintingFromSd ) )
2015-04-08 15:20:10 -07:00
{
if ( totalSdBytes > 0 )
{
return currentSdBytes / totalSdBytes * 100 ;
}
return 0 ;
}
if ( PrintIsFinished & & ! PrinterIsPaused )
{
return 100.0 ;
}
else if ( NumberOfLinesInCurrentPrint > 0
2016-09-28 12:51:46 -07:00
& & loadedGCode ! = null
2016-11-04 16:00:54 -07:00
& & gCodeFileStream0 ! = null )
2015-04-08 15:20:10 -07:00
{
2015-11-28 19:59:14 -08:00
return loadedGCode . PercentComplete ( gCodeFileStream0 . LineIndex ) ;
2015-04-08 15:20:10 -07:00
}
else
{
return 0.0 ;
}
}
}
public string PrinterConnectionStatusVerbose
{
get
{
switch ( CommunicationState )
{
case CommunicationStates . Disconnected :
return "Not Connected" . Localize ( ) ;
case CommunicationStates . Disconnecting :
return "Disconnecting" . Localize ( ) ;
case CommunicationStates . AttemptingToConnect :
2016-03-22 07:39:14 -07:00
return "Connecting" . Localize ( ) + "..." ;
2015-04-08 15:20:10 -07:00
case CommunicationStates . ConnectionLost :
return "Connection Lost" . Localize ( ) ;
case CommunicationStates . FailedToConnect :
2016-03-22 07:39:14 -07:00
return "Unable to Connect" . Localize ( ) ;
2015-04-08 15:20:10 -07:00
case CommunicationStates . Connected :
return "Connected" . Localize ( ) ;
case CommunicationStates . PreparingToPrint :
return "Preparing To Print" . Localize ( ) ;
case CommunicationStates . Printing :
return "Printing" . Localize ( ) ;
case CommunicationStates . PrintingFromSd :
return "Printing From SD Card" . Localize ( ) ;
case CommunicationStates . Paused :
return "Paused" . Localize ( ) ;
case CommunicationStates . FinishedPrint :
return "Finished Print" . Localize ( ) ;
default :
2016-01-05 14:31:17 -08:00
throw new NotImplementedException ( "Make sure every status returns the correct connected state." ) ;
2015-04-08 15:20:10 -07:00
}
}
}
public bool PrinterIsConnected
{
get
{
switch ( CommunicationState )
{
case CommunicationStates . Disconnected :
case CommunicationStates . AttemptingToConnect :
case CommunicationStates . ConnectionLost :
case CommunicationStates . FailedToConnect :
return false ;
case CommunicationStates . Disconnecting :
case CommunicationStates . Connected :
case CommunicationStates . PreparingToPrint :
case CommunicationStates . Printing :
case CommunicationStates . PrintingFromSd :
case CommunicationStates . Paused :
case CommunicationStates . FinishedPrint :
return true ;
default :
2016-01-05 14:31:17 -08:00
throw new NotImplementedException ( "Make sure every status returns the correct connected state." ) ;
2015-04-08 15:20:10 -07:00
}
}
}
public bool PrinterIsPaused
{
get
{
return CommunicationState = = CommunicationStates . Paused ;
}
}
public bool PrinterIsPrinting
{
get
{
switch ( CommunicationState )
{
case CommunicationStates . Disconnected :
case CommunicationStates . Disconnecting :
case CommunicationStates . AttemptingToConnect :
case CommunicationStates . ConnectionLost :
case CommunicationStates . FailedToConnect :
case CommunicationStates . Connected :
case CommunicationStates . PreparingToPrint :
case CommunicationStates . Paused :
case CommunicationStates . FinishedPrint :
return false ;
case CommunicationStates . Printing :
case CommunicationStates . PrintingFromSd :
return true ;
default :
throw new NotImplementedException ( "Make sure every status returns the correct connected state." ) ;
}
}
}
public DetailedPrintingState PrintingState
{
get
{
return printingStatePrivate ;
}
set
{
if ( printingStatePrivate ! = value )
{
printingStatePrivate = value ;
PrintingStateChanged . CallEvents ( this , null ) ;
}
}
}
public string PrintingStateString
{
get
{
switch ( PrintingState )
{
case DetailedPrintingState . HomingAxis :
2017-02-15 09:44:45 -08:00
return "Homing Axis" . Localize ( ) ;
2015-04-08 15:20:10 -07:00
case DetailedPrintingState . HeatingBed :
2017-02-15 09:44:45 -08:00
return "Waiting for Bed to Heat to" . Localize ( ) + $" {TargetBedTemperature}°" ;
2015-04-08 15:20:10 -07:00
case DetailedPrintingState . HeatingExtruder :
2017-02-15 09:44:45 -08:00
return "Waiting for Extruder to Heat to" . Localize ( ) + $" {GetTargetExtruderTemperature(0)}°" ;
2015-04-08 15:20:10 -07:00
case DetailedPrintingState . Printing :
2017-02-15 09:44:45 -08:00
return "Currently Printing" . Localize ( ) + ":" ;
2015-04-08 15:20:10 -07:00
default :
return "" ;
}
}
}
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 . PrintingFromSd :
case CommunicationStates . PreparingToPrint :
case CommunicationStates . Paused :
return true ;
default :
throw new NotImplementedException ( "Make sure every status returns the correct connected state." ) ;
}
}
}
public bool PrintIsFinished
{
get
{
return CommunicationState = = CommunicationStates . FinishedPrint ;
}
}
2017-02-01 17:36:33 -08:00
public string PrintJobName { get ; private set ; } = null ;
2015-04-08 15:20:10 -07:00
2017-02-01 17:36:33 -08:00
public bool PrintWasCanceled { get ; set ; } = false ;
2015-04-08 15:20:10 -07:00
public double RatioIntoCurrentLayer
{
get
{
2017-01-19 10:53:17 -08:00
if ( gCodeFileStream0 = = null )
{
return 0 ;
}
2015-11-28 19:59:14 -08:00
int instructionIndex = gCodeFileStream0 . LineIndex - backupAmount ;
2015-04-08 15:20:10 -07:00
return loadedGCode . Ratio0to1IntoContainedLayer ( instructionIndex ) ;
}
}
public int SecondsPrinted
{
get
{
if ( PrinterIsPrinting | | PrinterIsPaused | | PrintIsFinished )
{
return ( int ) ( timeSinceStartedPrint . ElapsedMilliseconds / 1000 ) ;
}
return 0 ;
}
}
public double TargetBedTemperature
{
get
{
return targetBedTemperature ;
}
set
{
if ( targetBedTemperature ! = value )
{
targetBedTemperature = value ;
OnBedTemperatureSet ( new TemperatureEventArgs ( 0 , TargetBedTemperature ) ) ;
if ( PrinterIsConnected )
{
SendLineToPrinterNow ( "M140 S{0}" . FormatWith ( targetBedTemperature ) ) ;
}
}
}
}
public int TotalLayersInPrint
{
get
{
try
{
int layerCount = loadedGCode . NumChangesInZ ;
return layerCount ;
}
2016-12-29 13:39:16 -08:00
catch ( Exception )
2015-04-08 15:20:10 -07:00
{
return - 1 ;
}
}
}
public int TotalSecondsInPrint
{
get
{
if ( loadedGCode . LineCount > 0 )
{
2017-02-01 17:36:33 -08:00
if ( feedRateRatio ! = 0 )
2015-04-08 15:20:10 -07:00
{
2017-02-01 17:36:33 -08:00
return ( int ) ( loadedGCode . TotalSecondsInPrint / feedRateRatio ) ;
2015-04-08 15:20:10 -07:00
}
return ( int ) ( loadedGCode . TotalSecondsInPrint ) ;
}
return 0 ;
}
}
2016-04-18 11:31:31 -07:00
// TODO: Consider having callers use the source rather than this proxy? Maybe better to change after arriving on a final type and location for printer settings
2016-07-18 15:20:19 -07:00
public PrinterSettings ActivePrinter = > ActiveSliceSettings . Instance ;
2015-04-08 15:20:10 -07:00
private int NumberOfLinesInCurrentPrint
{
get
{
return loadedGCode . LineCount ;
}
}
/// <summary>
2016-01-05 14:31:17 -08:00
/// Abort an ongoing attempt to establish communication with a printer due to the specified problem. This is a specialized
2015-04-08 15:20:10 -07:00
/// 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 )
{
2016-01-05 14:31:17 -08:00
// Set .Disconnecting to allow the read loop to exit gracefully before a forced thread join (and extended timeout)
2015-04-08 15:20:10 -07:00
CommunicationState = CommunicationStates . Disconnecting ;
2016-01-05 14:31:17 -08:00
// Shutdown the connectionAttempt thread
2015-04-08 15:20:10 -07:00
if ( connectThread ! = null )
{
connectThread . Join ( JoinThreadTimeoutMs ) ; //Halt connection thread
}
// Shutdown the readFromPrinter thread
if ( shutdownReadLoop )
{
2015-11-04 17:13:53 -08:00
ReadThread . Join ( ) ;
2015-04-08 15:20:10 -07:00
}
2016-01-05 14:31:17 -08:00
// Shutdown the serial port
2015-04-08 15:20:10 -07:00
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 ) ;
}
public void BedTemperatureWasWritenToPrinter ( object sender , EventArgs e )
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
string [ ] splitOnS = foundStringEventArgs . LineToCheck . Split ( 'S' ) ;
if ( splitOnS . Length = = 2 )
{
string temp = splitOnS [ 1 ] ;
try
{
double tempBeingSet = double . Parse ( temp ) ;
if ( TargetBedTemperature ! = tempBeingSet )
{
// we set the private variable so that we don't get the callbacks called and get in a loop of setting the temp
targetBedTemperature = tempBeingSet ;
OnBedTemperatureSet ( new TemperatureEventArgs ( 0 , TargetBedTemperature ) ) ;
}
}
2016-12-29 13:39:16 -08:00
catch ( Exception )
2015-04-08 15:20:10 -07:00
{
}
}
}
2016-07-28 19:02:45 -07:00
public void ConnectToActivePrinter ( bool showHelpIfNoPort = false )
2015-04-08 15:20:10 -07:00
{
2017-02-09 13:51:16 -08:00
if ( ActivePrinter ! = null )
2015-04-08 15:20:10 -07:00
{
// Start the process of requesting permission and exit if permission is not currently granted
2017-04-11 10:41:23 -07:00
if ( ! ActiveSliceSettings . Instance . GetValue < bool > ( SettingsKey . enable_network_printing )
& & ! FrostedSerialPort . EnsureDeviceAccess ( ) )
2015-04-08 15:20:10 -07:00
{
CommunicationState = CommunicationStates . FailedToConnect ;
return ;
}
2016-07-28 19:02:45 -07:00
PrinterOutputCache . Instance . Clear ( ) ;
//Attempt connecting to a specific printer
this . stopTryingToConnect = false ;
2017-02-01 17:36:33 -08:00
this . FirmwareType = FirmwareTypes . Unknown ;
2016-07-28 19:02:45 -07:00
firmwareUriGcodeSend = false ;
// 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 availability/in use status can proceed without additional workarounds for Android
#if __ANDROID__
string currentPortName = FrostedSerialPort . GetPortNames ( ) . FirstOrDefault ( ) ;
if ( ! string . IsNullOrEmpty ( currentPortName ) )
{
// TODO: Ensure that this does *not* cause a write to the settings file and should be an in memory update only
ActiveSliceSettings . Instance ? . Helpers . SetComPort ( currentPortName ) ;
}
#endif
if ( SerialPortIsAvailable ( this . ComPort ) )
{
//Create a timed callback to determine whether connection succeeded
Timer connectionTimer = new Timer ( new TimerCallback ( ConnectionCallbackTimer ) ) ;
connectionTimer . Change ( 100 , 0 ) ;
//Create and start connection thread
connectThread = new Thread ( Connect_Thread ) ;
connectThread . Name = "Connect To Printer" ;
connectThread . IsBackground = true ;
connectThread . Start ( ) ;
}
else
{
Debug . WriteLine ( "Connection failed: {0}" . FormatWith ( this . ComPort ) ) ;
connectionFailureMessage = string . Format (
"{0} is not available" . Localize ( ) ,
this . ComPort ) ;
OnConnectionFailed ( null ) ;
#if ! __ANDROID__
// Only pop up the com port helper if the USER actually CLICKED the connect button.
if ( showHelpIfNoPort )
{
WizardWindow . ShowComPortSetup ( ) ;
}
#endif
}
2015-04-08 15:20:10 -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.
2015-10-13 10:17:20 -07:00
ReadLineStartCallBacks . AddCallbackToKey ( "File deleted:" , FileDeleteConfirmed ) ;
2015-04-08 15:20:10 -07:00
// and send the line to delete the file
SendLineToPrinterNow ( "M30 {0}" . FormatWith ( fileName . ToLower ( ) ) ) ;
}
public void Disable ( )
{
if ( PrinterIsConnected )
{
// Make sure we send this without waiting for the printer to respond. We want to try and turn off the heaters.
// It may be possible in the future to make this go into the printer queue for assured sending but it means
// the program has to be smart about closing an able to wait until the printer has agreed that it shut off
2016-01-05 14:31:17 -08:00
// the motors and heaters (a good idea and something for the future).
2015-04-08 15:20:10 -07:00
ForceImmediateWrites = true ;
ReleaseMotors ( ) ;
TurnOffBedAndExtruders ( ) ;
FanSpeed0To255 = 0 ;
ForceImmediateWrites = false ;
CommunicationState = CommunicationStates . Disconnecting ;
2015-11-04 17:13:53 -08:00
ReadThread . Join ( ) ;
2015-04-08 15:20:10 -07:00
if ( serialPort ! = null )
{
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
}
serialPort = null ;
CommunicationState = CommunicationStates . Disconnected ;
}
else
{
//Need to reset UI - even if manual disconnect
TurnOffBedAndExtruders ( ) ;
FanSpeed0To255 = 0 ;
}
OnEnabledChanged ( null ) ;
}
public void ExtruderTemperatureWasWritenToPrinter ( object sender , EventArgs e )
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
double tempBeingSet = 0 ;
2015-07-29 13:23:38 -07:00
if ( GCodeFile . GetFirstNumberAfter ( "S" , foundStringEventArgs . LineToCheck , ref tempBeingSet ) )
2015-04-08 15:20:10 -07:00
{
double exturderIndex = 0 ;
2015-07-29 13:23:38 -07:00
if ( GCodeFile . GetFirstNumberAfter ( "T" , foundStringEventArgs . LineToCheck , ref exturderIndex ) )
2015-04-08 15:20:10 -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
int extruderIndex0Based = Math . Min ( ( int ) exturderIndex , MAX_EXTRUDERS - 1 ) ;
2016-04-11 11:52:44 -07:00
targetExtruderTemperature [ extruderIndex0Based ] = tempBeingSet ;
2015-04-08 15:20:10 -07:00
}
else
{
// we set the private variable so that we don't get the callbacks called and get in a loop of setting the temp
2016-07-25 12:29:43 -07:00
targetExtruderTemperature [ currentlyActiveExtruderIndex ] = tempBeingSet ;
2015-04-08 15:20:10 -07:00
}
2016-04-11 12:04:30 -07:00
OnExtruderTemperatureSet ( new TemperatureEventArgs ( ( int ) exturderIndex , tempBeingSet ) ) ;
2015-04-08 15:20:10 -07: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 ) ;
if ( FanSpeed0To255 ! = fanSpeedBeingSet )
{
fanSpeed = fanSpeedBeingSet ;
OnFanSpeedSet ( null ) ;
}
}
2016-12-29 13:39:16 -08:00
catch ( Exception )
2015-04-08 15:20:10 -07:00
{
}
}
}
public void FoundStart ( object sender , EventArgs e )
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
foundStringEventArgs . SendToDelegateFunctions = false ;
}
public double GetActualExtruderTemperature ( int extruderIndex0Based )
{
extruderIndex0Based = Math . Min ( extruderIndex0Based , MAX_EXTRUDERS - 1 ) ;
return actualExtruderTemperature [ extruderIndex0Based ] ;
}
public double GetTargetExtruderTemperature ( int extruderIndex0Based )
{
extruderIndex0Based = Math . Min ( extruderIndex0Based , MAX_EXTRUDERS - 1 ) ;
return targetExtruderTemperature [ extruderIndex0Based ] ;
}
public void HaltConnectionThread ( )
{
this . stopTryingToConnect = true ;
}
public void HomeAxis ( Axis axis )
{
string command = "G28" ;
2016-05-11 17:04:30 -07:00
// If we are homing everything we don't need to add any details
if ( ! axis . HasFlag ( Axis . XYZ ) )
2015-04-08 15:20:10 -07:00
{
2016-05-11 17:04:30 -07:00
if ( ( axis & Axis . X ) = = Axis . X )
{
command + = " X0" ;
}
if ( ( axis & Axis . Y ) = = Axis . Y )
{
command + = " Y0" ;
}
if ( ( axis & Axis . Z ) = = Axis . Z )
{
command + = " Z0" ;
}
2015-04-08 15:20:10 -07:00
}
SendLineToPrinterNow ( command ) ;
ReadPosition ( ) ;
}
public void MoveAbsolute ( Axis axis , double axisPositionMm , double feedRateMmPerMinute )
{
SetMovementToAbsolute ( ) ;
2017-02-09 13:51:16 -08:00
SendLineToPrinterNow ( "G1 {0}{1:0.###} F{2}" . FormatWith ( axis , axisPositionMm , feedRateMmPerMinute ) ) ;
2015-04-08 15:20:10 -07:00
}
public void MoveAbsolute ( Vector3 position , double feedRateMmPerMinute )
{
SetMovementToAbsolute ( ) ;
2017-02-09 13:51:16 -08:00
SendLineToPrinterNow ( "G1 X{0:0.###}Y{1:0.###}Z{2:0.###} F{3}" . FormatWith ( position . x , position . y , position . z , feedRateMmPerMinute ) ) ;
2015-04-08 15:20:10 -07:00
}
public void MoveExtruderRelative ( double moveAmountMm , double feedRateMmPerMinute , int extruderNumber = 0 )
{
if ( moveAmountMm ! = 0 )
{
2016-01-27 15:02:01 -08:00
// TODO: Long term we need to track the active extruder and make requiresToolChange be driven by the extruder you're actually on
bool requiresToolChange = extruderNumber ! = 0 ;
2015-04-08 15:20:10 -07:00
SetMovementToRelative ( ) ;
2016-01-27 15:02:01 -08:00
if ( requiresToolChange )
{
2017-02-09 13:51:16 -08:00
SendLineToPrinterNow ( "T{0}" . FormatWith ( extruderNumber ) ) ; //Set active extruder
2016-01-27 15:02:01 -08:00
}
2017-02-09 13:51:16 -08:00
SendLineToPrinterNow ( "G1 E{0:0.###} F{1}" . FormatWith ( moveAmountMm , feedRateMmPerMinute ) ) ;
2016-01-27 15:02:01 -08:00
if ( requiresToolChange )
{
2017-02-09 13:51:16 -08:00
SendLineToPrinterNow ( "T0" ) ; //Reset back to extruder one
2016-01-27 15:02:01 -08:00
}
2015-04-08 15:20:10 -07:00
SetMovementToAbsolute ( ) ;
}
}
public void MoveRelative ( Axis axis , double moveAmountMm , double feedRateMmPerMinute )
{
if ( moveAmountMm ! = 0 )
{
SetMovementToRelative ( ) ;
2017-02-09 13:51:16 -08:00
SendLineToPrinterNow ( "G1 {0}{1:0.###} F{2}" . FormatWith ( axis , moveAmountMm , feedRateMmPerMinute ) ) ;
2015-04-08 15:20:10 -07:00
SetMovementToAbsolute ( ) ;
}
}
public void OnCommunicationStateChanged ( EventArgs e )
{
CommunicationStateChanged . CallEvents ( this , e ) ;
2015-12-22 18:18:28 -08:00
#if __ANDROID__
2017-04-11 10:41:23 -07:00
//Path to the printer output file
2015-12-22 18:18:28 -08:00
string pathToPrintOutputFile = Path . Combine ( ApplicationDataStorage . Instance . PublicDataStoragePath , "print_output.txt" ) ;
if ( CommunicationState = = CommunicationStates . FinishedPrint )
{
2017-04-11 10:41:23 -07:00
//Only write to the text file if file exists
2015-12-22 18:18:28 -08:00
if ( File . Exists ( pathToPrintOutputFile ) )
{
Task . Run ( ( ) = >
{
File . WriteAllLines ( pathToPrintOutputFile , PrinterOutputCache . Instance . PrinterLines ) ;
} ) ;
}
}
#endif
2015-04-08 15:20:10 -07:00
}
public void OnConnectionFailed ( EventArgs e )
{
ConnectionFailed . CallEvents ( this , e ) ;
CommunicationState = CommunicationStates . FailedToConnect ;
OnEnabledChanged ( e ) ;
}
public void OnIdle ( )
{
2015-11-04 17:13:53 -08:00
if ( PrinterIsConnected & & ReadThread . NumRunning = = 0 )
2015-04-27 15:42:31 -07:00
{
2015-11-04 17:13:53 -08:00
ReadThread . Start ( ) ;
2015-04-27 15:42:31 -07:00
}
2015-04-08 15:20:10 -07:00
}
public void OnPrintFinished ( EventArgs e )
{
2017-06-16 18:04:47 -07:00
PrintFinished . CallEvents ( this , new PrintItemWrapperEventArgs ( this . activePrintItem ) ) ;
2016-04-26 09:20:31 -07:00
2016-04-18 11:31:31 -07:00
// TODO: Shouldn't this logic be in the UI layer where the controls are owned and hooked in via PrintFinished?
bool oneOrMoreValuesReset = false ;
2016-04-29 15:00:10 -07:00
foreach ( var keyValue in ActiveSliceSettings . Instance . BaseLayer )
2016-04-26 09:20:31 -07:00
{
2016-06-15 17:18:39 -07:00
string currentValue = ActiveSliceSettings . Instance . GetValue ( keyValue . Key ) ;
2016-04-26 09:20:31 -07:00
bool valueIsClear = currentValue = = "0" | currentValue = = "" ;
2016-06-13 13:44:53 -07:00
SliceSettingData data = SliceSettingsOrganizer . Instance . GetSettingsData ( keyValue . Key ) ;
2016-04-18 11:31:31 -07:00
if ( data ? . ResetAtEndOfPrint = = true & & ! valueIsClear )
2016-04-26 09:20:31 -07:00
{
2016-04-18 11:31:31 -07:00
oneOrMoreValuesReset = true ;
2016-04-29 15:00:10 -07:00
ActiveSliceSettings . Instance . ClearValue ( keyValue . Key ) ;
2016-04-26 09:20:31 -07:00
}
}
2016-11-04 16:00:54 -07:00
if ( oneOrMoreValuesReset )
2016-04-26 09:20:31 -07:00
{
ApplicationController . Instance . ReloadAdvancedControlsPanel ( ) ;
}
2015-04-08 15:20:10 -07:00
}
public void PrinterRequestsResend ( object sender , EventArgs e )
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
2016-12-14 15:03:37 -08:00
if ( foundStringEventArgs ! = null
& & ! string . IsNullOrEmpty ( foundStringEventArgs . LineToCheck ) )
2015-04-27 17:05:19 -07:00
{
2016-12-14 15:03:37 -08:00
string line = foundStringEventArgs . LineToCheck ;
// marlin and repetier send a : before the number and then and ok
if ( ! GCodeFile . GetFirstNumberAfter ( ":" , line , ref currentLineIndexToSend ) )
2015-04-27 17:05:19 -07:00
{
2017-06-27 10:14:48 -07:00
if ( currentLineIndexToSend = = allCheckSumLinesSent . Count )
2017-06-07 15:56:02 -07:00
{
// asking for the next line don't do anything, conitue with sending next instruction
return ;
}
2016-12-14 15:03:37 -08:00
// smoothie sends an N before the number and no ok
if ( GCodeFile . GetFirstNumberAfter ( "N" , line , ref currentLineIndexToSend ) )
{
// clear waiting for ok because smoothie will not send it
PrintingCanContinue ( null , null ) ;
}
2016-12-02 13:51:58 -08:00
}
2017-06-27 10:14:48 -07:00
if ( currentLineIndexToSend = = allCheckSumLinesSent . Count )
{
// asking for the next line don't do anything, conitue with sending next instruction
return ;
}
2017-05-19 14:39:57 -07:00
if ( currentLineIndexToSend > = allCheckSumLinesSent . Count
| | currentLineIndexToSend = = 1 )
2016-12-02 13:51:58 -08:00
{
SendLineToPrinterNow ( "M110 N1" ) ;
2017-05-19 14:39:57 -07:00
allCheckSumLinesSent . SetStartingIndex ( 1 ) ;
waitingForPosition . Reset ( ) ;
PositionReadQueued = false ;
2015-04-27 17:05:19 -07:00
}
}
2015-04-08 15:20:10 -07:00
}
2017-04-11 10:41:23 -07:00
private bool haveReportedError = false ;
2017-06-16 18:04:47 -07:00
public event EventHandler ErrorReported ;
2016-01-05 16:48:04 -08:00
public void PrinterReportsError ( object sender , EventArgs e )
{
2016-11-09 09:22:19 -08:00
if ( ! haveReportedError )
2016-01-05 16:48:04 -08:00
{
2016-11-09 09:22:19 -08:00
haveReportedError = true ;
2017-06-16 18:04:47 -07:00
2016-01-06 12:09:37 -08:00
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
if ( foundStringEventArgs ! = null )
{
2017-06-16 18:04:47 -07:00
ErrorReported ? . Invoke ( null , foundStringEventArgs ) ;
2016-01-06 12:09:37 -08:00
}
2016-01-05 16:48:04 -08:00
}
}
2015-04-08 15:20:10 -07:00
public void PrinterStatesExtensions ( object sender , EventArgs e )
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
if ( foundStringEventArgs ! = null )
{
if ( foundStringEventArgs . LineToCheck . Contains ( "URI_GCODE_SEND" ) )
{
firmwareUriGcodeSend = true ;
}
}
}
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" ) )
{
2017-02-01 17:36:33 -08:00
this . FirmwareType = FirmwareTypes . Repetier ;
2015-04-08 15:20:10 -07:00
}
else if ( firmwareName . Contains ( "marlin" ) )
{
2017-02-01 17:36:33 -08:00
this . FirmwareType = FirmwareTypes . Marlin ;
2015-04-08 15:20:10 -07:00
}
else if ( firmwareName . Contains ( "sprinter" ) )
{
2017-02-01 17:36:33 -08:00
this . FirmwareType = FirmwareTypes . Sprinter ;
2015-04-08 15:20:10 -07:00
}
}
string firmwareVersionReported = "" ;
if ( GCodeFile . GetFirstStringAfter ( "MACHINE_TYPE:" , foundStringEventArgs . LineToCheck , " EXTRUDER_COUNT" , ref firmwareVersionReported ) )
{
char splitChar = '^' ;
if ( firmwareVersionReported . Contains ( splitChar ) )
{
string [ ] split = firmwareVersionReported . Split ( splitChar ) ;
if ( split . Count ( ) = = 2 )
{
2016-12-29 12:52:12 -08:00
DeviceCode = split [ 0 ] ;
2015-04-08 15:20:10 -07:00
firmwareVersionReported = split [ 1 ] ;
}
}
//Firmware version was detected and is different
2016-12-28 13:10:39 -08:00
if ( firmwareVersionReported ! = "" & & FirmwareVersion ! = firmwareVersionReported )
2015-04-08 15:20:10 -07:00
{
2016-12-28 13:10:39 -08:00
FirmwareVersion = firmwareVersionReported ;
2015-04-08 15:20:10 -07:00
OnFirmwareVersionRead ( null ) ;
}
}
}
// this is to make it misbehave
//int okCount = 1;
public void PrintingCanContinue ( object sender , EventArgs e )
{
//if ((okCount++ % 67) != 0)
{
timeHaveBeenWaitingForOK . Stop ( ) ;
}
}
2015-06-05 15:28:37 -07:00
public void ArduinoDtrReset ( )
2015-04-08 15:20:10 -07:00
{
2015-06-05 15:28:37 -07:00
// TODO: Ideally we would shutdown the printer connection when this method is called and we're connected. The
2017-04-11 10:41:23 -07:00
// current approach results in unpredictable behavior if the caller fails to close the connection
2015-04-08 15:20:10 -07:00
if ( serialPort = = null & & this . ActivePrinter ! = null )
{
2016-04-27 17:34:33 -07:00
IFrostedSerialPort resetSerialPort = FrostedSerialPortFactory . GetAppropriateFactory ( this . DriverType ) . Create ( this . ComPort ) ;
2015-06-05 15:28:37 -07:00
resetSerialPort . Open ( ) ;
2015-04-08 15:20:10 -07:00
2015-06-05 15:28:37 -07:00
Thread . Sleep ( 500 ) ;
2015-04-08 15:20:10 -07:00
2017-03-02 09:47:24 -08:00
ToggleHighLowHigh ( resetSerialPort ) ;
2015-06-05 15:28:37 -07:00
resetSerialPort . Close ( ) ;
2015-04-08 15:20:10 -07:00
}
}
2016-11-04 16:00:54 -07:00
public void ReadFromPrinter ( ReadThread readThreadHolder )
2015-04-08 15:20:10 -07:00
{
2015-06-22 15:15:46 -07:00
string dataLastRead = string . Empty ;
2015-04-08 15:20:10 -07:00
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
2015-05-21 16:34:30 -07:00
| | ( PrinterIsConnected & & serialPort ! = null & & serialPort . IsOpen & & ! Disconnecting & & readThreadHolder . IsCurrentThread ( ) ) )
2015-04-08 15:20:10 -07:00
{
2016-11-29 14:58:24 -08:00
if ( ( PrinterIsConnected
| | this . communicationState = = CommunicationStates . AttemptingToConnect )
2015-04-08 15:20:10 -07:00
& & CommunicationState ! = CommunicationStates . PrintingFromSd )
{
TryWriteNextLineFromGCodeFile ( ) ;
}
try
{
while ( serialPort ! = null
& & serialPort . BytesToRead > 0
& & readThreadHolder . IsCurrentThread ( ) )
{
2016-01-14 10:32:25 -08:00
lock ( locker )
{
2015-06-25 12:19:23 -07:00
string allDataRead = serialPort . ReadExisting ( ) ;
2015-04-08 15:20:10 -07:00
//Debug.Write("r: " + allDataRead);
2016-10-18 17:29:23 -07:00
allDataRead = allDataRead . Replace ( "\r\n" , "\n" ) ;
allDataRead = allDataRead . Replace ( '\r' , '\n' ) ;
dataLastRead + = allDataRead ;
2015-04-08 15:20:10 -07:00
do
{
int returnPosition = dataLastRead . IndexOf ( '\n' ) ;
2015-06-22 15:15:46 -07:00
// Abort if we're AttemptingToConnect, no newline was found in the accumulator string and there's too many non-ascii chars
2016-01-14 10:32:25 -08:00
if ( this . communicationState = = CommunicationStates . AttemptingToConnect & & returnPosition < 0 )
2015-06-22 15:15:46 -07:00
{
int totalInvalid = dataLastRead . Count ( c = > c = = '?' ) ;
if ( totalInvalid > MAX_INVALID_CONNECTION_CHARS )
{
AbortConnectionAttempt ( "Invalid printer response" . Localize ( ) , false ) ;
}
}
2016-01-14 10:32:25 -08:00
2015-04-08 15:20:10 -07:00
if ( returnPosition < 0 )
{
// there is no return keep getting characters
break ;
}
if ( dataLastRead . Length > 0 )
{
2016-11-04 16:00:54 -07:00
if ( lastLineRead . StartsWith ( "ok" ) )
2016-04-06 13:53:04 -07:00
{
timeSinceRecievedOk . Restart ( ) ;
}
2015-04-08 15:20:10 -07:00
lastLineRead = dataLastRead . Substring ( 0 , returnPosition ) ;
dataLastRead = dataLastRead . Substring ( returnPosition + 1 ) ;
// process this command
{
StringEventArgs currentEvent = new StringEventArgs ( lastLineRead ) ;
if ( PrinterIsPrinting )
{
CommunicationUnconditionalFromPrinter . CallEvents ( this , new StringEventArgs ( "{0} [{1:0.000}]\n" . FormatWith ( lastLineRead , timeSinceStartedPrint . Elapsed . TotalSeconds ) ) ) ;
}
else
{
CommunicationUnconditionalFromPrinter . CallEvents ( this , currentEvent ) ;
}
FoundStringEventArgs foundResponse = new FoundStringEventArgs ( currentEvent . Data ) ;
2016-10-05 14:57:31 -07:00
2015-04-08 15:20:10 -07:00
ReadLineStartCallBacks . CheckForKeys ( foundResponse ) ;
ReadLineContainsCallBacks . CheckForKeys ( foundResponse ) ;
if ( foundResponse . SendToDelegateFunctions )
{
ReadLine . CallEvents ( this , currentEvent ) ;
}
}
// If we've encountered a newline character and we're still in .AttemptingToConnect
if ( CommunicationState = = CommunicationStates . AttemptingToConnect )
{
// 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
2016-01-05 14:37:40 -08:00
// (initial line having more than 3 non-ASCII characters) may not be adequate or appropriate.
2015-04-08 15:20:10 -07:00
// 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 ;
2017-05-19 14:39:57 -07:00
TurnOffBedAndExtruders ( ) ; // make sure our ui and the printer agree and that the printer is in a known state (not heating).
2016-11-09 09:22:19 -08:00
haveReportedError = false ;
2016-02-11 15:26:14 -08:00
// now send any command that initialize this printer
2016-11-04 12:04:49 -07:00
ClearQueuedGCode ( ) ;
2016-07-12 17:46:48 -07:00
string connectGCode = ActiveSliceSettings . Instance . GetValue ( SettingsKey . connect_gcode ) ;
2015-05-18 16:58:09 -07:00
SendLineToPrinterNow ( connectGCode ) ;
2016-02-22 10:14:07 -08:00
2016-04-14 14:34:30 -07:00
// and call back anyone who would like to know we connected
2017-06-16 18:04:47 -07:00
ConnectionSucceeded . CallEvents ( this , null ) ;
2015-04-08 15:20:10 -07:00
}
else
{
// Force port shutdown and cleanup
AbortConnectionAttempt ( "Invalid printer response" . Localize ( ) , false ) ;
}
}
}
} while ( true ) ;
}
timeSinceLastReadAnything . Restart ( ) ;
}
2016-04-06 11:56:48 -07:00
if ( PrinterIsPrinting )
{
Thread . Sleep ( 0 ) ;
}
else
{
Thread . Sleep ( 1 ) ;
}
2015-04-08 15:20:10 -07:00
}
2016-12-29 13:39:16 -08:00
catch ( TimeoutException )
2015-04-08 15:20:10 -07:00
{
}
2015-09-11 10:48:24 -07:00
catch ( IOException e2 )
2015-04-08 15:20:10 -07:00
{
2016-12-29 13:39:16 -08:00
PrinterOutputCache . Instance . WriteLine ( "Exception:" + e2 . Message ) ;
2015-04-08 15:20:10 -07:00
OnConnectionFailed ( null ) ;
}
catch ( InvalidOperationException ex )
{
2016-12-29 13:39:16 -08:00
PrinterOutputCache . Instance . WriteLine ( "Exception:" + ex . Message ) ;
2015-04-08 15:20:10 -07:00
// this happens when the serial port closes after we check and before we read it.
2016-12-29 12:52:12 -08:00
OnConnectionFailed ( null ) ;
2015-04-08 15:20:10 -07:00
}
2015-09-11 10:48:24 -07:00
catch ( UnauthorizedAccessException e3 )
2015-04-08 15:20:10 -07:00
{
2016-12-29 13:39:16 -08:00
PrinterOutputCache . Instance . WriteLine ( "Exception:" + e3 . Message ) ;
2015-04-08 15:20:10 -07:00
OnConnectionFailed ( null ) ;
}
2016-12-29 13:39:16 -08:00
catch ( Exception )
2015-04-24 18:24:21 -07:00
{
}
2015-04-08 15:20:10 -07:00
}
}
2017-06-14 18:01:38 -07:00
public void ReadPosition ( bool forceToTopOfQueue = false )
2015-04-08 15:20:10 -07:00
{
2017-06-14 18:01:38 -07:00
SendLineToPrinterNow ( "M114" , forceToTopOfQueue ) ;
2017-04-11 10:41:23 -07:00
PositionReadQueued = true ;
2015-04-08 15:20:10 -07:00
}
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 ( ) ;
}
public void ReadTargetPositions ( object sender , EventArgs e )
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
string lineToParse = foundStringEventArgs . LineToCheck ;
2016-01-19 15:16:05 -08:00
GCodeFile . GetFirstNumberAfter ( "X:" , lineToParse , ref lastReportedPosition . position . x ) ;
GCodeFile . GetFirstNumberAfter ( "Y:" , lineToParse , ref lastReportedPosition . position . y ) ;
GCodeFile . GetFirstNumberAfter ( "Z:" , lineToParse , ref lastReportedPosition . position . z ) ;
GCodeFile . GetFirstNumberAfter ( "E:" , lineToParse , ref lastReportedPosition . extrusion ) ;
2015-04-08 15:20:10 -07:00
2015-12-03 13:54:18 -08:00
//if (currentDestination != positionRead)
2015-04-08 15:20:10 -07:00
{
2016-01-19 15:16:05 -08:00
currentDestination = lastReportedPosition ;
2015-04-08 15:20:10 -07:00
DestinationChanged . CallEvents ( this , null ) ;
2016-11-04 16:00:54 -07:00
if ( totalGCodeStream ! = null )
2016-01-14 10:32:25 -08:00
{
totalGCodeStream . SetPrinterPosition ( currentDestination ) ;
}
}
2015-04-08 15:20:10 -07:00
PositionRead . CallEvents ( this , null ) ;
waitingForPosition . Reset ( ) ;
2017-04-11 10:41:23 -07:00
PositionReadQueued = false ;
2015-04-08 15:20:10 -07:00
}
2017-03-21 14:26:54 -07:00
public static void ParseTemperatureString ( string temperatureString ,
double [ ] actualExtruderTemperature , Action < TemperatureEventArgs > extruderTemperatureChange ,
ref double actualBedTemperature , Action < TemperatureEventArgs > bedTemperatureChanged )
2015-04-08 15:20:10 -07:00
{
{
double readExtruderTemp = 0 ;
2015-07-29 13:23:38 -07:00
if ( GCodeFile . GetFirstNumberAfter ( "T:" , temperatureString , ref readExtruderTemp ) )
2015-04-08 15:20:10 -07:00
{
if ( actualExtruderTemperature [ 0 ] ! = readExtruderTemp )
{
actualExtruderTemperature [ 0 ] = readExtruderTemp ;
2017-03-21 14:26:54 -07:00
extruderTemperatureChange ? . Invoke ( new TemperatureEventArgs ( 0 , readExtruderTemp ) ) ;
2015-04-08 15:20:10 -07:00
}
}
for ( int extruderIndex = 0 ; extruderIndex < MAX_EXTRUDERS ; extruderIndex + + )
{
string multiExtruderCheck = "T{0}:" . FormatWith ( extruderIndex ) ;
2015-07-29 13:23:38 -07:00
if ( GCodeFile . GetFirstNumberAfter ( multiExtruderCheck , temperatureString , ref readExtruderTemp ) )
2015-04-08 15:20:10 -07:00
{
if ( actualExtruderTemperature [ extruderIndex ] ! = readExtruderTemp )
{
actualExtruderTemperature [ extruderIndex ] = readExtruderTemp ;
2017-03-21 14:26:54 -07:00
extruderTemperatureChange ? . Invoke ( new TemperatureEventArgs ( extruderIndex , readExtruderTemp ) ) ;
2015-04-08 15:20:10 -07:00
}
}
else
{
break ;
}
}
}
{
double readBedTemp = 0 ;
2015-07-29 13:23:38 -07:00
if ( GCodeFile . GetFirstNumberAfter ( "B:" , temperatureString , ref readBedTemp ) )
2015-04-08 15:20:10 -07:00
{
if ( actualBedTemperature ! = readBedTemp )
{
actualBedTemperature = readBedTemp ;
2017-03-21 14:26:54 -07:00
bedTemperatureChanged ? . Invoke ( new TemperatureEventArgs ( 0 , readBedTemp ) ) ;
2015-04-08 15:20:10 -07:00
}
}
}
}
2017-03-21 14:26:54 -07:00
public void ReadTemperatures ( object sender , FoundStringEventArgs foundStringEventArgs )
{
ParseTemperatureString ( foundStringEventArgs . LineToCheck , actualExtruderTemperature , OnExtruderTemperatureRead ,
ref actualBedTemperature , OnBedTemperatureRead ) ;
}
2015-04-08 15:20:10 -07:00
public void RebootBoard ( )
{
2015-06-10 10:19:25 -07:00
try
2015-04-08 15:20:10 -07:00
{
2017-02-08 10:02:39 -08:00
if ( ActiveSliceSettings . Instance . PrinterSelected )
2015-06-10 10:19:25 -07:00
{
// first make sure we are not printing if possible (cancel slicing)
if ( serialPort ! = null ) // we still have a serial port
{
2017-02-07 18:49:06 -08:00
Stop ( false ) ;
2015-06-10 10:19:25 -07:00
ClearQueuedGCode ( ) ;
2015-04-08 15:20:10 -07:00
2017-02-07 18:49:06 -08:00
CommunicationState = CommunicationStates . Disconnecting ;
ReadThread . Join ( ) ;
2017-03-02 09:47:24 -08:00
ToggleHighLowHigh ( serialPort ) ;
2017-02-07 18:49:06 -08:00
if ( serialPort ! = null )
{
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
}
serialPort = null ;
2017-02-09 13:51:16 -08:00
// make sure we clear out the stream processors
CreateStreamProcessors ( null , false ) ;
2017-02-07 18:49:06 -08:00
CommunicationState = CommunicationStates . Disconnected ;
2017-02-08 10:02:39 -08:00
// We were connected to a printer so try to reconnect
2017-06-16 18:04:47 -07:00
ConnectToActivePrinter ( ) ;
2015-06-10 10:19:25 -07:00
}
else
{
// We reset the board while attempting to connect, so now we don't have a serial port.
// Create one and do the DTR to reset
2016-04-27 17:34:33 -07:00
var resetSerialPort = FrostedSerialPortFactory . GetAppropriateFactory ( this . DriverType ) . Create ( this . ComPort ) ;
2015-06-10 10:19:25 -07:00
resetSerialPort . Open ( ) ;
2015-04-08 15:20:10 -07:00
2015-06-10 10:19:25 -07:00
Thread . Sleep ( 500 ) ;
2017-03-02 09:47:24 -08:00
ToggleHighLowHigh ( resetSerialPort ) ;
2015-06-10 10:19:25 -07:00
resetSerialPort . Close ( ) ;
2015-12-31 09:40:17 -08:00
// let the process know we canceled not ended normally.
2015-06-10 10:19:25 -07:00
CommunicationState = CommunicationStates . Disconnected ;
}
2015-04-08 15:20:10 -07:00
}
}
2016-12-29 13:39:16 -08:00
catch ( Exception )
2015-06-10 10:19:25 -07:00
{
}
}
2017-03-02 09:47:24 -08:00
private void ToggleHighLowHigh ( IFrostedSerialPort serialPort )
2015-06-10 10:19:25 -07:00
{
serialPort . RtsEnable = true ;
serialPort . DtrEnable = true ;
Thread . Sleep ( 100 ) ;
serialPort . RtsEnable = false ;
serialPort . DtrEnable = false ;
Thread . Sleep ( 100 ) ;
serialPort . RtsEnable = true ;
serialPort . DtrEnable = true ;
2015-04-08 15:20:10 -07:00
}
public void ReleaseMotors ( )
{
SendLineToPrinterNow ( "M84" ) ;
}
2015-11-28 07:46:57 -08:00
public void RequestPause ( )
2015-04-08 15:20:10 -07:00
{
if ( PrinterIsPrinting )
{
if ( CommunicationState = = CommunicationStates . PrintingFromSd )
{
CommunicationState = CommunicationStates . Paused ;
SendLineToPrinterNow ( "M25" ) ; // : Pause SD print
return ;
}
2017-04-13 14:25:46 -07:00
pauseHandlingStream1 . DoPause ( PauseHandlingStream . PauseReason . UserRequested ) ;
2015-04-08 15:20:10 -07:00
}
}
public void ResetToReadyState ( )
{
if ( CommunicationState = = CommunicationStates . FinishedPrint )
{
CommunicationState = CommunicationStates . Connected ;
}
else
{
throw new Exception ( "You should only reset after a print has finished." ) ;
}
}
public void Resume ( )
{
if ( PrinterIsPaused )
{
2017-03-07 17:52:44 -08:00
if ( PrePauseCommunicationState = = CommunicationStates . PrintingFromSd )
2015-04-08 15:20:10 -07:00
{
CommunicationState = CommunicationStates . PrintingFromSd ;
SendLineToPrinterNow ( "M24" ) ; // Start/resume SD print
}
else
{
2016-01-19 15:16:05 -08:00
pauseHandlingStream1 . Resume ( ) ;
2015-04-08 15:20:10 -07:00
CommunicationState = CommunicationStates . Printing ;
}
}
}
public void SendLinesToPrinterNow ( string [ ] linesToWrite )
{
if ( PrinterIsPrinting & & CommunicationState ! = CommunicationStates . PrintingFromSd )
{
for ( int i = linesToWrite . Length - 1 ; i > = 0 ; i - - )
{
string line = linesToWrite [ i ] . Trim ( ) ;
if ( line . Length > 0 )
{
SendLineToPrinterNow ( line ) ;
}
}
}
else
{
for ( int i = 0 ; i < linesToWrite . Length ; i + + )
{
string line = linesToWrite [ i ] . Trim ( ) ;
if ( line . Length > 0 )
{
SendLineToPrinterNow ( line ) ;
}
}
}
}
2017-04-11 10:41:23 -07:00
public void SendLineToPrinterNow ( string lineToWrite , bool forceTopOfQueue = false )
2015-04-08 15:20:10 -07:00
{
2016-01-14 10:32:25 -08:00
lock ( locker )
2015-04-08 15:20:10 -07:00
{
2015-05-18 16:58:09 -07:00
if ( lineToWrite . Contains ( "\\n" ) )
{
lineToWrite = lineToWrite . Replace ( "\\n" , "\n" ) ;
}
2015-12-31 09:40:17 -08:00
//Check line for line breaks, split and process separate if necessary
2015-04-08 15:20:10 -07:00
if ( lineToWrite . Contains ( "\n" ) )
{
string [ ] linesToWrite = lineToWrite . Split ( new string [ ] { "\n" } , StringSplitOptions . None ) ;
SendLinesToPrinterNow ( linesToWrite ) ;
return ;
}
2016-11-04 16:00:54 -07:00
if ( CommunicationState = = CommunicationStates . PrintingFromSd
| | ForceImmediateWrites )
2015-04-08 15:20:10 -07:00
{
2016-11-04 16:00:54 -07:00
lineToWrite = lineToWrite . Split ( ';' ) [ 0 ] . Trim ( ) ;
if ( lineToWrite . Trim ( ) . Length > 0 )
2015-04-08 15:20:10 -07:00
{
2016-11-03 17:34:36 -07:00
// sometimes we need to send code without buffering (like when we are closing the program).
2016-11-29 14:07:37 -08:00
WriteRawToPrinter ( lineToWrite + "\n" , lineToWrite ) ;
2015-04-08 15:20:10 -07:00
}
2016-11-04 16:00:54 -07:00
}
else
{
if ( lineToWrite . Trim ( ) . Length > 0 )
2015-04-08 15:20:10 -07:00
{
2016-11-03 17:34:36 -07:00
// insert the command into the printing queue at the head
2017-04-11 10:41:23 -07:00
InjectGCode ( lineToWrite , forceTopOfQueue ) ;
2015-04-08 15:20:10 -07:00
}
}
}
}
public bool SerialPortIsAvailable ( string portName )
//Check is serial port is in the list of available serial ports
{
2017-04-11 10:41:23 -07:00
if ( IsNetworkPrinting ( ) )
2016-07-29 14:48:41 -07:00
{
return true ;
}
2015-04-08 15:20:10 -07:00
try
{
string [ ] portNames = FrostedSerialPort . GetPortNames ( ) ;
return portNames . Any ( x = > string . Compare ( x , portName , true ) = = 0 ) ;
}
2016-12-29 13:39:16 -08:00
catch ( Exception )
2015-04-08 15:20:10 -07:00
{
return false ;
}
}
public void SetMovementToAbsolute ( )
{
2017-02-09 13:51:16 -08:00
SendLineToPrinterNow ( "G90" ) ;
2015-04-08 15:20:10 -07:00
}
public void SetMovementToRelative ( )
{
2017-02-09 13:51:16 -08:00
SendLineToPrinterNow ( "G91" ) ;
2015-04-08 15:20:10 -07:00
}
2016-07-25 12:29:43 -07:00
public void SetTargetExtruderTemperature ( int extruderIndex0Based , double temperature , bool forceSend = false )
2015-04-08 15:20:10 -07:00
{
extruderIndex0Based = Math . Min ( extruderIndex0Based , MAX_EXTRUDERS - 1 ) ;
2016-07-25 12:29:43 -07:00
if ( targetExtruderTemperature [ extruderIndex0Based ] ! = temperature
| | forceSend )
2015-04-08 15:20:10 -07:00
{
targetExtruderTemperature [ extruderIndex0Based ] = temperature ;
OnExtruderTemperatureSet ( new TemperatureEventArgs ( extruderIndex0Based , temperature ) ) ;
if ( PrinterIsConnected )
{
SendLineToPrinterNow ( "M104 T{0} S{1}" . FormatWith ( extruderIndex0Based , targetExtruderTemperature [ extruderIndex0Based ] ) ) ;
}
}
}
2016-04-14 18:01:45 -07:00
public async void StartPrint ( string gcodeFilename , PrintTask printTaskToUse = null )
2015-04-08 15:20:10 -07:00
{
if ( ! PrinterIsConnected | | PrinterIsPrinting )
{
return ;
}
2016-11-09 09:22:19 -08:00
haveReportedError = false ;
2017-02-01 17:36:33 -08:00
PrintWasCanceled = false ;
2017-02-02 13:37:03 -08:00
waitingForPosition . Reset ( ) ;
2017-04-11 10:41:23 -07:00
PositionReadQueued = false ;
2015-04-08 15:20:10 -07:00
ClearQueuedGCode ( ) ;
2016-04-14 18:01:45 -07:00
activePrintTask = printTaskToUse ;
2015-04-08 15:20:10 -07:00
2016-04-14 18:01:45 -07:00
await Task . Run ( ( ) = >
{
LoadGCodeToPrint ( gcodeFilename ) ;
} ) ;
DoneLoadingGCodeToPrint ( ) ;
2015-04-08 15:20:10 -07:00
}
public bool StartSdCardPrint ( )
{
if ( ! PrinterIsConnected
| | PrinterIsPrinting
2017-06-16 18:04:47 -07:00
| | activePrintItem . PrintItem . FileLocation ! = QueueData . SdCardFileName )
2015-04-08 15:20:10 -07:00
{
return false ;
}
currentSdBytes = 0 ;
ClearQueuedGCode ( ) ;
CommunicationState = CommunicationStates . PrintingFromSd ;
2017-06-16 18:04:47 -07:00
SendLineToPrinterNow ( "M23 {0}" . FormatWith ( activePrintItem . PrintItem . Name . ToLower ( ) ) ) ; // Select SD File
2015-04-08 15:20:10 -07:00
SendLineToPrinterNow ( "M24" ) ; // Start/resume SD print
2015-10-13 10:17:20 -07:00
ReadLineStartCallBacks . AddCallbackToKey ( "Done printing file" , DonePrintingSdFile ) ;
2015-04-08 15:20:10 -07:00
return true ;
}
2016-12-01 10:59:03 -08:00
public void Stop ( bool markPrintCanceled = true )
2015-04-08 15:20:10 -07:00
{
switch ( CommunicationState )
{
case CommunicationStates . PrintingFromSd :
2015-04-13 12:28:33 -07:00
CancelSDCardPrint ( ) ;
2015-04-08 15:20:10 -07:00
break ;
case CommunicationStates . Printing :
2017-02-09 13:51:16 -08:00
CancelPrint ( markPrintCanceled ) ;
2015-04-08 15:20:10 -07:00
break ;
case CommunicationStates . Paused :
{
2017-03-07 17:52:44 -08:00
if ( PrePauseCommunicationState = = CommunicationStates . PrintingFromSd )
2015-04-08 15:20:10 -07:00
{
2015-04-13 12:28:33 -07:00
CancelSDCardPrint ( ) ;
CommunicationState = CommunicationStates . Connected ;
}
else
{
2016-12-01 10:59:03 -08:00
CancelPrint ( markPrintCanceled ) ;
2015-06-10 10:19:25 -07:00
// We have to continue printing the end gcode, so we set this to Printing.
2015-05-21 16:34:30 -07:00
CommunicationState = CommunicationStates . Printing ;
2015-04-08 15:20:10 -07:00
}
}
break ;
case CommunicationStates . AttemptingToConnect :
CommunicationState = CommunicationStates . FailedToConnect ;
connectThread . Join ( JoinThreadTimeoutMs ) ;
CommunicationState = CommunicationStates . Disconnecting ;
2015-11-04 17:13:53 -08:00
ReadThread . Join ( ) ;
2015-04-08 15:20:10 -07:00
if ( serialPort ! = null )
{
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
serialPort = null ;
}
CommunicationState = CommunicationStates . Disconnected ;
break ;
case CommunicationStates . PreparingToPrint :
SlicingQueue . Instance . CancelCurrentSlicing ( ) ;
CommunicationState = CommunicationStates . Connected ;
break ;
}
}
2016-12-01 10:59:03 -08:00
private void CancelPrint ( bool markPrintCanceled )
2015-04-13 12:28:33 -07:00
{
2016-01-14 10:32:25 -08:00
lock ( locker )
2015-04-13 12:28:33 -07:00
{
// get rid of all the gcode we have left to print
ClearQueuedGCode ( ) ;
2016-07-12 17:46:48 -07:00
string cancelGCode = ActiveSliceSettings . Instance . GetValue ( SettingsKey . cancel_gcode ) ;
2015-04-13 12:28:33 -07:00
if ( cancelGCode . Trim ( ) ! = "" )
{
// add any gcode we want to print while canceling
2015-11-28 07:46:57 -08:00
InjectGCode ( cancelGCode ) ;
2015-04-13 12:28:33 -07:00
}
2015-12-31 09:40:17 -08:00
// let the process know we canceled not ended normally.
2017-02-01 17:36:33 -08:00
this . PrintWasCanceled = true ;
2016-12-01 10:59:03 -08:00
if ( markPrintCanceled
& & activePrintTask ! = null )
{
TimeSpan printTimeSpan = DateTime . Now . Subtract ( activePrintTask . PrintStart ) ;
activePrintTask . PrintEnd = DateTime . Now ;
activePrintTask . PrintComplete = false ;
activePrintTask . PrintingGCodeFileName = "" ;
activePrintTask . Commit ( ) ;
}
// no matter what we no longer have a print task
activePrintTask = null ;
2015-04-13 12:28:33 -07:00
}
}
private void CancelSDCardPrint ( )
{
2016-01-14 10:32:25 -08:00
lock ( locker )
2015-04-13 12:28:33 -07:00
{
// get rid of all the gcode we have left to print
ClearQueuedGCode ( ) ;
2015-12-31 09:40:17 -08:00
// let the process know we canceled not ended normally.
2015-04-13 12:28:33 -07:00
CommunicationState = CommunicationStates . Connected ;
SendLineToPrinterNow ( "M25" ) ; // : Pause SD print
SendLineToPrinterNow ( "M26" ) ; // : Set SD position
2016-01-14 10:32:25 -08:00
// never leave the extruder and the bed hot
2015-04-13 12:28:33 -07:00
DonePrintingSdFile ( this , null ) ;
}
}
2017-04-11 10:41:23 -07:00
public void SuppressEcho ( object sender , EventArgs e )
2015-04-08 15:20:10 -07:00
{
FoundStringEventArgs foundStringEventArgs = e as FoundStringEventArgs ;
foundStringEventArgs . SendToDelegateFunctions = false ;
}
[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 ) ;
private void AttemptToConnect ( string serialPortName , int baudRate )
{
2016-12-14 11:26:53 -08:00
// make sure we don't have a left over print task
activePrintTask = null ;
2017-01-04 07:23:30 -08:00
connectionFailureMessage = "Unknown Reason" . Localize ( ) ;
2015-04-08 15:20:10 -07:00
if ( PrinterIsConnected )
{
2016-10-17 12:40:19 -07:00
#if DEBUG
2017-01-04 07:23:30 -08:00
throw new Exception ( "You can only connect when not currently connected." . Localize ( ) ) ;
2016-10-17 12:40:19 -07:00
#else
return ;
#endif
2015-04-08 15:20:10 -07:00
}
2017-03-02 09:48:21 -08:00
var portFactory = FrostedSerialPortFactory . GetAppropriateFactory ( this . DriverType ) ;
2017-03-15 21:57:13 -07:00
bool serialPortIsAvailable = portFactory . SerialPortIsAvailable ( serialPortName ) ;
2017-03-02 09:48:21 -08:00
bool serialPortIsAlreadyOpen = portFactory . SerialPortAlreadyOpen ( serialPortName ) ;
2015-04-08 15:20:10 -07:00
if ( serialPortIsAvailable & & ! serialPortIsAlreadyOpen )
{
if ( ! PrinterIsConnected )
{
try
{
2017-03-02 09:48:21 -08:00
serialPort = portFactory . CreateAndOpen ( serialPortName , baudRate , true ) ;
2015-10-16 16:30:07 -07:00
#if __ANDROID__
2017-03-02 09:47:24 -08:00
ToggleHighLowHigh ( serialPort ) ;
2015-10-16 16:30:07 -07:00
#endif
2015-04-08 15:20:10 -07:00
// wait a bit of time to let the firmware start up
Thread . Sleep ( 500 ) ;
CommunicationState = CommunicationStates . AttemptingToConnect ;
2015-11-04 17:13:53 -08:00
ReadThread . Join ( ) ;
2015-04-08 15:20:10 -07:00
Console . WriteLine ( "ReadFromPrinter thread created." ) ;
2015-11-04 17:13:53 -08:00
ReadThread . Start ( ) ;
2015-04-08 15:20:10 -07:00
2016-11-03 17:34:36 -07:00
CreateStreamProcessors ( null , false ) ;
2015-12-31 09:40:17 -08:00
// We have to send a line because some printers (like old print-r-bots) do not send anything when connecting and there is no other way to know they are there.
2016-12-02 13:51:58 -08:00
SendLineToPrinterNow ( "M110 N1" ) ;
2016-11-29 16:05:30 -08:00
ClearQueuedGCode ( ) ;
2016-02-11 16:32:05 -08:00
// We do not need to wait for the M105
PrintingCanContinue ( null , null ) ;
2015-04-08 15:20:10 -07:00
}
2015-09-11 10:48:24 -07:00
catch ( System . ArgumentOutOfRangeException e )
2015-04-08 15:20:10 -07:00
{
2016-12-29 13:39:16 -08:00
PrinterOutputCache . Instance . WriteLine ( "Exception:" + e . Message ) ;
2017-01-04 07:23:30 -08:00
connectionFailureMessage = "Unsupported Baud Rate" . Localize ( ) ;
2015-04-08 15:20:10 -07:00
OnConnectionFailed ( null ) ;
}
catch ( Exception ex )
{
2016-12-29 13:39:16 -08:00
PrinterOutputCache . Instance . WriteLine ( "Exception:" + ex . Message ) ;
2015-04-08 15:20:10 -07:00
OnConnectionFailed ( null ) ;
}
}
}
else
{
2015-12-31 09:40:17 -08:00
// If the serial port isn't available (i.e. the specified port name wasn't found in GetPortNames()) or the serial
2015-04-08 15:20:10 -07:00
// port is already opened in another instance or process, then report the connection problem back to the user
connectionFailureMessage = ( serialPortIsAlreadyOpen ?
2017-06-23 17:00:44 -07:00
this . ComPort + " " + "in use" . Localize ( ) :
2017-01-04 07:23:30 -08:00
"Port not found" . Localize ( ) ) ;
2015-04-08 15:20:10 -07:00
OnConnectionFailed ( null ) ;
}
}
private void ClearQueuedGCode ( )
{
loadedGCode . Clear ( ) ;
2016-12-02 13:51:58 -08:00
WriteChecksumLineToPrinter ( "M110 N1" ) ;
2015-04-08 15:20:10 -07:00
}
private void Connect_Thread ( )
{
Thread . CurrentThread . CurrentCulture = CultureInfo . InvariantCulture ;
// Allow the user to set the appropriate properties.
var portNames = FrostedSerialPort . GetPortNames ( ) ;
//Debug.WriteLine("Open ports: {0}".FormatWith(portNames.Length));
2016-10-07 15:19:32 -07:00
if ( portNames . Length > 0 | | IsNetworkPrinting ( ) )
2015-04-08 15:20:10 -07:00
{
2016-04-27 17:34:33 -07:00
AttemptToConnect ( this . ComPort , this . BaudRate ) ;
2015-04-08 15:20:10 -07:00
if ( CommunicationState = = CommunicationStates . FailedToConnect )
{
OnConnectionFailed ( null ) ;
}
}
else
{
OnConnectionFailed ( null ) ;
}
}
private void ConnectionCallbackTimer ( object state )
{
Timer t = ( Timer ) state ;
if ( ! ContinueConnectionThread ( ) )
{
t . Dispose ( ) ;
}
else
{
t . Change ( 100 , 0 ) ;
}
}
private bool ContinueConnectionThread ( )
{
if ( CommunicationState = = CommunicationStates . AttemptingToConnect )
{
if ( this . stopTryingToConnect )
{
connectThread . Join ( JoinThreadTimeoutMs ) ; //Halt connection thread
Disable ( ) ;
2017-01-04 07:23:30 -08:00
connectionFailureMessage = "Canceled" . Localize ( ) ;
2015-04-08 15:20:10 -07:00
OnConnectionFailed ( null ) ;
return false ;
}
else
{
return true ;
}
}
else
{
// If we're no longer in the .AttemptingToConnect state, shutdown the connection thread and fire the
// OnConnectonSuccess event if we're connected and not Disconnecting
connectThread . Join ( JoinThreadTimeoutMs ) ;
return false ;
}
}
2017-03-21 14:26:54 -07:00
private void DonePrintingSdFile ( object sender , FoundStringEventArgs e )
2015-04-08 15:20:10 -07:00
{
2017-06-16 18:04:47 -07:00
ReadLineStartCallBacks . RemoveCallbackFromKey ( "Done printing file" , DonePrintingSdFile ) ;
2015-04-08 15:20:10 -07:00
CommunicationState = CommunicationStates . FinishedPrint ;
2017-02-01 17:36:33 -08:00
this . PrintJobName = null ;
2015-04-08 15:20:10 -07:00
// never leave the extruder and the bed hot
TurnOffBedAndExtruders ( ) ;
ReleaseMotors ( ) ;
}
private void ExtruderWasSetToAbsoluteMode ( object sender , EventArgs e )
{
extruderMode = PrinterMachineInstruction . MovementTypes . Absolute ;
}
private void ExtruderWasSetToRelativeMode ( object sender , EventArgs e )
{
extruderMode = PrinterMachineInstruction . MovementTypes . Relative ;
}
private void FileDeleteConfirmed ( object sender , EventArgs e )
{
2017-06-16 18:04:47 -07:00
ReadLineStartCallBacks . RemoveCallbackFromKey ( "File deleted:" , FileDeleteConfirmed ) ;
2015-04-08 15:20:10 -07:00
PrintingCanContinue ( this , null ) ;
}
2017-04-11 10:41:23 -07:00
private void InjectGCode ( string codeToInject , bool forceTopOfQueue = false )
2015-04-08 15:20:10 -07:00
{
codeToInject = codeToInject . Replace ( "\\n" , "\n" ) ;
string [ ] lines = codeToInject . Split ( '\n' ) ;
2015-12-31 09:40:17 -08:00
for ( int i = 0 ; i < lines . Length ; i + + )
2015-04-08 15:20:10 -07:00
{
2017-04-11 10:41:23 -07:00
queuedCommandStream2 ? . Add ( lines [ i ] , forceTopOfQueue ) ;
2015-04-08 15:20:10 -07:00
}
}
2016-01-14 10:32:25 -08:00
private void KeepTrackOfAbsolutePostionAndDestination ( string lineBeingSent )
{
if ( lineBeingSent . StartsWith ( "G0 " )
| | lineBeingSent . StartsWith ( "G1 " )
| | lineBeingSent . StartsWith ( "G2 " )
| | lineBeingSent . StartsWith ( "G3 " ) )
{
2016-01-19 15:16:05 -08:00
PrinterMove newDestination = currentDestination ;
2016-01-14 10:32:25 -08:00
if ( movementMode = = PrinterMachineInstruction . MovementTypes . Relative )
{
2016-01-19 15:16:05 -08:00
newDestination . position = Vector3 . Zero ;
2016-01-14 10:32:25 -08:00
}
2015-11-30 12:26:55 -08:00
2016-01-19 15:16:05 -08:00
GCodeFile . GetFirstNumberAfter ( "X" , lineBeingSent , ref newDestination . position . x ) ;
GCodeFile . GetFirstNumberAfter ( "Y" , lineBeingSent , ref newDestination . position . y ) ;
GCodeFile . GetFirstNumberAfter ( "Z" , lineBeingSent , ref newDestination . position . z ) ;
2015-11-30 12:26:55 -08:00
2016-01-19 15:16:05 -08:00
GCodeFile . GetFirstNumberAfter ( "E" , lineBeingSent , ref newDestination . extrusion ) ;
GCodeFile . GetFirstNumberAfter ( "F" , lineBeingSent , ref newDestination . feedRate ) ;
2015-11-30 12:26:55 -08:00
2016-01-14 10:32:25 -08:00
if ( movementMode = = PrinterMachineInstruction . MovementTypes . Relative )
{
2016-01-19 15:16:05 -08:00
newDestination . position + = currentDestination . position ;
2016-01-14 10:32:25 -08:00
}
2015-11-30 12:26:55 -08:00
2016-01-19 15:16:05 -08:00
if ( currentDestination . position ! = newDestination . position )
2016-01-14 10:32:25 -08:00
{
currentDestination = newDestination ;
DestinationChanged . CallEvents ( this , null ) ;
}
}
}
2015-11-30 12:26:55 -08:00
2017-04-11 10:41:23 -07:00
private void CreateStreamProcessors ( string gcodeFilename , bool recoveryEnabled )
2015-04-08 15:20:10 -07:00
{
2016-01-14 10:32:25 -08:00
totalGCodeStream ? . Dispose ( ) ;
2015-12-01 14:49:50 -08:00
2016-11-03 17:34:36 -07:00
GCodeStream firstStream = null ;
if ( gcodeFilename ! = null )
2016-04-14 18:01:45 -07:00
{
2016-11-03 17:34:36 -07:00
loadedGCode = GCodeFile . Load ( gcodeFilename ) ;
gCodeFileStream0 = new GCodeFileStream ( loadedGCode ) ;
if ( ActiveSliceSettings . Instance . GetValue < bool > ( SettingsKey . recover_is_enabled )
& & activePrintTask ! = null ) // We are resuming a failed print (do lots of interesting stuff).
{
pauseHandlingStream1 = new PauseHandlingStream ( new PrintRecoveryStream ( gCodeFileStream0 , activePrintTask . PercentDone ) ) ;
2016-12-14 11:26:53 -08:00
// And increment the recovery count
activePrintTask . RecoveryCount + + ;
activePrintTask . Commit ( ) ;
2016-11-03 17:34:36 -07:00
}
else
{
pauseHandlingStream1 = new PauseHandlingStream ( gCodeFileStream0 ) ;
}
firstStream = pauseHandlingStream1 ;
2016-04-14 18:01:45 -07:00
}
else
{
2016-11-03 17:34:36 -07:00
firstStream = new NotPrintingStream ( ) ;
2016-04-14 18:01:45 -07:00
}
2016-11-03 17:34:36 -07:00
queuedCommandStream2 = new QueuedCommandsStream ( firstStream ) ;
2016-01-19 15:16:05 -08:00
relativeToAbsoluteStream3 = new RelativeToAbsoluteStream ( queuedCommandStream2 ) ;
2016-10-11 14:56:36 -07:00
printLevelingStream4 = new PrintLevelingStream ( relativeToAbsoluteStream3 , true ) ;
2016-01-19 15:16:05 -08:00
waitForTempStream5 = new WaitForTempStream ( printLevelingStream4 ) ;
2017-06-23 17:00:44 -07:00
babyStepsStream6 = new BabyStepsStream ( waitForTempStream5 , gcodeFilename = = null ? 2000 : 1 ) ;
2016-11-03 17:34:36 -07:00
if ( activePrintTask ! = null )
2016-04-20 11:53:08 -07:00
{
// make sure we are in the position we were when we stopped printing
babyStepsStream6 . Offset = new Vector3 ( activePrintTask . PrintingOffsetX , activePrintTask . PrintingOffsetY , activePrintTask . PrintingOffsetZ ) ;
}
2016-01-19 15:16:05 -08:00
extrusionMultiplyerStream7 = new ExtrusionMultiplyerStream ( babyStepsStream6 ) ;
feedrateMultiplyerStream8 = new FeedRateMultiplyerStream ( extrusionMultiplyerStream7 ) ;
requestTemperaturesStream9 = new RequestTemperaturesStream ( feedrateMultiplyerStream8 ) ;
totalGCodeStream = requestTemperaturesStream9 ;
2017-02-10 14:44:07 -08:00
// Get the current position of the printer any time we reset our streams
ReadPosition ( ) ;
2016-01-14 10:32:25 -08:00
}
2015-11-28 07:46:57 -08:00
2016-11-03 17:34:36 -07:00
private void LoadGCodeToPrint ( string gcodeFilename )
{
CreateStreamProcessors ( gcodeFilename , ActiveSliceSettings . Instance . GetValue < bool > ( SettingsKey . recover_is_enabled ) ) ;
}
2017-06-16 18:04:47 -07:00
internal PrintItemWrapper activePrintItem ;
2016-04-14 18:01:45 -07:00
private void DoneLoadingGCodeToPrint ( )
2015-04-08 15:20:10 -07:00
{
switch ( communicationState )
{
case CommunicationStates . Connected :
2015-12-31 09:40:17 -08:00
// This can happen if the printer is reset during the slicing of the part.
2015-04-08 15:20:10 -07:00
break ;
case CommunicationStates . PreparingToPrint :
2017-06-16 18:04:47 -07:00
if ( activePrintItem . PrintItem . Id = = 0 )
2015-04-08 15:20:10 -07:00
{
2017-06-16 18:04:47 -07:00
activePrintItem . PrintItem . Commit ( ) ;
2015-04-08 15:20:10 -07:00
}
2016-04-14 18:01:45 -07:00
if ( activePrintTask = = null )
{
2016-04-18 11:31:31 -07:00
// TODO: Fix printerItemID int requirement
2016-04-14 18:01:45 -07:00
activePrintTask = new PrintTask ( ) ;
activePrintTask . PrintStart = DateTime . Now ;
2016-05-16 16:21:42 -07:00
activePrintTask . PrinterId = this . ActivePrinter . ID . GetHashCode ( ) ;
2017-06-16 18:04:47 -07:00
activePrintTask . PrintName = activePrintItem . PrintItem . Name ;
activePrintTask . PrintItemId = activePrintItem . PrintItem . Id ;
activePrintTask . PrintingGCodeFileName = activePrintItem . GetGCodePathAndFileName ( ) ;
2016-04-14 18:01:45 -07:00
activePrintTask . PrintComplete = false ;
activePrintTask . Commit ( ) ;
}
2015-04-08 15:20:10 -07:00
CommunicationState = CommunicationStates . Printing ;
break ;
default :
2016-01-14 10:32:25 -08:00
#if DEBUG
2015-04-08 15:20:10 -07:00
throw new Exception ( "We are not preparing to print so we should not be starting to print" ) ;
//#else
CommunicationState = CommunicationStates . Connected ;
2016-01-14 10:32:25 -08:00
#endif
2015-04-08 15:54:31 -07:00
break ;
2015-04-08 15:20:10 -07:00
}
}
private void MovementWasSetToAbsoluteMode ( object sender , EventArgs e )
{
movementMode = PrinterMachineInstruction . MovementTypes . Absolute ;
}
private void MovementWasSetToRelativeMode ( object sender , EventArgs e )
{
movementMode = PrinterMachineInstruction . MovementTypes . Relative ;
}
2015-04-23 20:19:00 -07:00
private void AtxPowerUpWasWritenToPrinter ( object sender , EventArgs e )
{
OnAtxPowerStateChanged ( true ) ;
}
private void AtxPowerDownWasWritenToPrinter ( object sender , EventArgs e )
{
OnAtxPowerStateChanged ( false ) ;
}
2015-04-08 15:20:10 -07:00
private void OnBedTemperatureRead ( EventArgs e )
{
BedTemperatureRead . CallEvents ( this , e ) ;
}
private void OnBedTemperatureSet ( EventArgs e )
{
BedTemperatureSet . CallEvents ( this , e ) ;
}
private void OnEnabledChanged ( EventArgs e )
{
EnableChanged . CallEvents ( this , e ) ;
}
private void OnExtruderTemperatureRead ( EventArgs e )
{
ExtruderTemperatureRead . CallEvents ( this , e ) ;
}
private void OnExtruderTemperatureSet ( EventArgs e )
{
ExtruderTemperatureSet . CallEvents ( this , e ) ;
}
private void OnFanSpeedSet ( EventArgs e )
{
FanSpeedSet . CallEvents ( this , e ) ;
}
private void OnFirmwareVersionRead ( EventArgs e )
{
FirmwareVersionRead . CallEvents ( this , e ) ;
}
2016-10-07 15:19:32 -07:00
private bool IsNetworkPrinting ( )
{
2016-12-12 12:14:30 -08:00
return ActiveSliceSettings . Instance . GetValue < bool > ( SettingsKey . enable_network_printing ) ;
2016-10-07 15:19:32 -07:00
}
2015-04-23 20:19:00 -07:00
private void OnAtxPowerStateChanged ( bool enableAtxPower )
{
atxPowerIsOn = enableAtxPower ;
AtxPowerStateChanged . CallEvents ( this , null ) ;
}
2015-04-08 15:20:10 -07:00
private void SetDetailedPrintingState ( string lineBeingSetToPrinter )
2015-02-21 12:01:59 -08:00
{
2015-04-08 15:20:10 -07:00
if ( lineBeingSetToPrinter . StartsWith ( "G28" ) )
2015-02-21 12:01:59 -08:00
{
2015-04-08 15:20:10 -07:00
PrintingState = DetailedPrintingState . HomingAxis ;
}
2016-01-19 15:16:05 -08:00
else if ( waitForTempStream5 ? . HeatingBed ? ? false )
2015-04-08 15:20:10 -07:00
{
PrintingState = DetailedPrintingState . HeatingBed ;
}
2016-01-19 15:16:05 -08:00
else if ( waitForTempStream5 ? . HeatingExtruder ? ? false )
2015-04-08 15:20:10 -07:00
{
PrintingState = DetailedPrintingState . HeatingExtruder ;
}
else
{
PrintingState = DetailedPrintingState . Printing ;
2015-02-21 12:01:59 -08:00
}
}
2017-04-11 10:41:23 -07:00
private string currentSentLine ;
private string previousSentLine ;
private int ExpectedWaitSeconds ( string lastInstruction )
{
if ( lastInstruction . Contains ( "G0 " ) | | lastInstruction . Contains ( "G1 " ) )
{
// for moves we wait only as much as 2 seconds
return 2 ;
}
return 10 ;
}
2015-11-28 07:46:57 -08:00
2016-01-14 10:32:25 -08:00
private void TryWriteNextLineFromGCodeFile ( )
2015-04-08 15:20:10 -07:00
{
2017-04-11 10:41:23 -07:00
if ( totalGCodeStream = = null )
2016-12-02 13:51:58 -08:00
{
// don't try to write until we are initialized
return ;
}
2015-12-31 09:40:17 -08:00
// wait until the printer responds from the last command with an OK OR we waited too long
2015-11-28 07:46:57 -08:00
if ( timeHaveBeenWaitingForOK . IsRunning )
2015-04-08 15:20:10 -07:00
{
2016-01-14 10:32:25 -08:00
lock ( locker )
2015-04-08 15:20:10 -07:00
{
// we are still sending commands
2015-11-28 07:46:57 -08:00
if ( currentSentLine ! = null )
2015-04-08 15:20:10 -07:00
{
2016-01-14 10:32:25 -08:00
// This code is to try and make sure the printer does not stop on transmission errors.
// 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 )
2017-04-11 10:41:23 -07:00
| | timeHaveBeenWaitingForOK . Elapsed . TotalSeconds > ExpectedWaitSeconds ( currentSentLine ) )
2016-01-14 10:32:25 -08:00
{
// Basically we got some response but it did not contain an OK.
// The theory is that we may have received a transmission error (like 'OP' rather than 'OK')
// and in that event we don't want the print to just stop and wait forever.
2016-12-02 13:51:58 -08:00
currentLineIndexToSend - - ; // we are going to resend the last command
2016-01-14 10:32:25 -08:00
}
else
2015-04-08 15:20:10 -07:00
{
2016-01-14 10:32:25 -08:00
// we are waiting for the ok so let's wait
return ;
}
}
}
}
lock ( locker )
{
2016-12-02 13:51:58 -08:00
if ( currentLineIndexToSend < allCheckSumLinesSent . Count )
2016-01-14 10:32:25 -08:00
{
2016-12-02 13:51:58 -08:00
WriteRawToPrinter ( allCheckSumLinesSent [ currentLineIndexToSend + + ] + "\n" , "resend" ) ;
2016-01-14 10:32:25 -08:00
}
else
{
int waitTimeInMs = 60000 ; // 60 seconds
2017-04-11 10:41:23 -07:00
if ( waitingForPosition . IsRunning
2017-02-14 11:42:48 -08:00
& & waitingForPosition . ElapsedMilliseconds < waitTimeInMs
& & PrinterIsConnected )
2016-01-14 10:32:25 -08:00
{
// we are waiting for a position response don't print more
return ;
}
previousSentLine = this . currentSentLine ;
currentSentLine = totalGCodeStream . ReadLine ( ) ;
if ( currentSentLine ! = null )
{
string [ ] splitOnSemicolon = currentSentLine . Split ( ';' ) ;
string trimedLine = splitOnSemicolon [ 0 ] . Trim ( ) . ToUpper ( ) ;
2017-04-11 10:41:23 -07:00
if ( trimedLine . Contains ( "M114" )
2017-02-14 11:42:48 -08:00
& & PrinterIsConnected )
2016-01-14 10:32:25 -08:00
{
waitingForPosition . Restart ( ) ;
}
2016-04-14 14:34:30 -07:00
double secondsSinceStartedPrint = timeSinceStartedPrint . Elapsed . TotalSeconds ;
if ( secondsSinceUpdateHistory > secondsSinceStartedPrint
2016-04-19 11:24:09 -07:00
| | secondsSinceUpdateHistory + 1 < secondsSinceStartedPrint )
2016-02-23 15:39:26 -08:00
{
2016-04-20 12:31:44 -07:00
double currentDone = loadedGCode . PercentComplete ( gCodeFileStream0 . LineIndex ) ;
// Only update the amount done if it is greater than what is recorded.
// We don't want to mess up the resume before we actually resume it.
2016-10-21 11:59:39 -07:00
if ( activePrintTask ! = null
& & babyStepsStream6 ! = null
& & activePrintTask . PercentDone < currentDone )
2016-04-20 12:31:44 -07:00
{
activePrintTask . PercentDone = currentDone ;
activePrintTask . PrintingOffsetX = ( float ) babyStepsStream6 . Offset . x ;
activePrintTask . PrintingOffsetY = ( float ) babyStepsStream6 . Offset . y ;
activePrintTask . PrintingOffsetZ = ( float ) babyStepsStream6 . Offset . z ;
2016-10-21 11:59:39 -07:00
try
{
2016-10-21 13:52:40 -07:00
Task . Run ( ( ) = > activePrintTask . Commit ( ) ) ;
2016-10-21 11:59:39 -07:00
}
catch
{
// Can't write for some reason, continue with the write.
}
2016-04-20 12:31:44 -07:00
}
2016-04-14 14:34:30 -07:00
secondsSinceUpdateHistory = secondsSinceStartedPrint ;
2016-04-20 11:53:08 -07:00
}
2016-02-23 15:39:26 -08:00
2016-01-14 10:32:25 -08:00
if ( trimedLine . Length > 0 )
{
2016-01-19 15:16:05 -08:00
WriteChecksumLineToPrinter ( currentSentLine ) ;
2016-01-14 10:32:25 -08:00
2016-12-02 13:51:58 -08:00
currentLineIndexToSend + + ;
2015-04-08 15:20:10 -07:00
}
2016-01-14 10:32:25 -08:00
}
2017-02-01 17:36:33 -08:00
else if ( this . PrintWasCanceled )
2016-01-14 10:32:25 -08:00
{
CommunicationState = CommunicationStates . Connected ;
// never leave the extruder and the bed hot
ReleaseMotors ( ) ;
TurnOffBedAndExtruders ( ) ;
2017-02-01 17:36:33 -08:00
this . PrintWasCanceled = false ;
2016-01-14 10:32:25 -08:00
}
2017-04-11 10:41:23 -07:00
else if ( communicationState = = CommunicationStates . Printing ) // we finished printing normally
2016-01-14 10:32:25 -08:00
{
CommunicationState = CommunicationStates . FinishedPrint ;
2017-02-01 17:36:33 -08:00
this . PrintJobName = null ;
2016-01-14 10:32:25 -08:00
2017-01-03 10:45:16 -08:00
// get us back to the no printing setting (this will clear the queued commands)
CreateStreamProcessors ( null , false ) ;
2016-01-14 10:32:25 -08:00
// never leave the extruder and the bed hot
ReleaseMotors ( ) ;
TurnOffBedAndExtruders ( ) ;
2015-04-08 15:20:10 -07:00
}
}
2016-01-14 10:32:25 -08:00
}
2015-03-04 17:59:28 -08:00
}
2015-04-08 15:20:10 -07:00
private void TurnOffBedAndExtruders ( )
{
2016-06-16 10:31:18 -07:00
for ( int i = 0 ; i < ActiveSliceSettings . Instance . GetValue < int > ( SettingsKey . extruder_count ) ; i + + )
2016-01-14 10:32:25 -08:00
{
2016-07-25 12:29:43 -07:00
SetTargetExtruderTemperature ( i , 0 , true ) ;
2016-01-14 10:32:25 -08:00
}
2015-04-08 15:20:10 -07:00
TargetBedTemperature = 0 ;
}
2014-01-29 19:09:30 -08:00
2016-12-02 13:51:58 -08:00
// this is to make it misbehave, chaos monkey, bad checksum
2017-01-11 17:18:42 -08:00
//int checkSumCount = 1;
2015-04-08 15:20:10 -07:00
private void WriteChecksumLineToPrinter ( string lineToWrite )
2016-01-14 10:32:25 -08:00
{
SetDetailedPrintingState ( lineToWrite ) ;
// remove the comment if any
lineToWrite = RemoveCommentIfAny ( lineToWrite ) ;
KeepTrackOfAbsolutePostionAndDestination ( lineToWrite ) ;
2016-12-02 13:51:58 -08:00
// always send the reset line number without a checksum so that it is accepted
string lineWithCount ;
if ( lineToWrite . StartsWith ( "M110" ) )
2016-01-14 10:32:25 -08:00
{
2017-01-11 17:08:36 -08:00
lineWithCount = $"N1 {lineToWrite}" ;
2016-12-02 13:51:58 -08:00
GCodeFile . GetFirstNumberAfter ( "N" , lineToWrite , ref currentLineIndexToSend ) ;
2017-01-11 17:08:36 -08:00
allCheckSumLinesSent . SetStartingIndex ( currentLineIndexToSend ) ;
2016-01-14 10:32:25 -08:00
}
2016-12-02 13:51:58 -08:00
else
2016-01-14 10:32:25 -08:00
{
2016-12-02 13:51:58 -08:00
lineWithCount = $"N{allCheckSumLinesSent.Count} {lineToWrite}" ;
2017-05-19 14:39:57 -07:00
if ( lineToWrite . StartsWith ( "M999" ) )
{
allCheckSumLinesSent . SetStartingIndex ( 1 ) ;
}
2016-01-14 10:32:25 -08:00
}
2016-12-02 13:51:58 -08:00
string lineWithChecksum = lineWithCount + "*" + GCodeFile . CalculateChecksum ( lineWithCount ) . ToString ( ) ;
2017-04-11 10:41:23 -07:00
2016-12-02 13:51:58 -08:00
allCheckSumLinesSent . Add ( lineWithChecksum ) ;
2017-01-11 17:18:42 -08:00
//if ((checkSumCount++ % 11) == 0)
2017-04-11 10:41:23 -07:00
//lineWithChecksum = lineWithCount + "*" + (GCodeFile.CalculateChecksum(lineWithCount) + checkSumCount).ToString();
2016-12-02 13:51:58 -08:00
WriteRawToPrinter ( lineWithChecksum + "\n" , lineToWrite ) ;
2016-01-14 10:32:25 -08:00
}
private static string RemoveCommentIfAny ( string lineToWrite )
{
int commentIndex = lineToWrite . IndexOf ( ';' ) ;
if ( commentIndex > 0 ) // there is content in front of the ;
{
lineToWrite = lineToWrite . Substring ( 0 , commentIndex ) . Trim ( ) ;
}
return lineToWrite ;
}
2016-11-03 17:34:36 -07:00
private void WriteRawToPrinter ( string lineToWrite , string lineWithoutChecksum )
2015-02-04 14:57:56 -08:00
{
2015-04-08 15:20:10 -07:00
if ( PrinterIsConnected | | CommunicationState = = CommunicationStates . AttemptingToConnect )
2015-02-04 14:57:56 -08:00
{
2015-04-08 15:20:10 -07:00
if ( serialPort ! = null & & serialPort . IsOpen )
{
FoundStringEventArgs foundStringEvent = new FoundStringEventArgs ( lineWithoutChecksum ) ;
2015-03-11 11:02:27 -07:00
2016-01-14 10:32:25 -08:00
// If we get a home command, ask the printer where it is after sending it.
2016-08-03 16:49:48 -07:00
if ( lineWithoutChecksum . StartsWith ( "G28" ) // is a home
| | lineWithoutChecksum . StartsWith ( "G29" ) // is a bed level
2017-02-22 14:50:23 -08:00
| | lineWithoutChecksum . StartsWith ( "G30" ) // is a bed level
2016-08-03 16:49:48 -07:00
| | lineWithoutChecksum . StartsWith ( "G92" ) // is a reset of printer position
| | ( lineWithoutChecksum . StartsWith ( "T" ) & & ! lineWithoutChecksum . StartsWith ( "T:" ) ) ) // is a switch extruder (verify this is the right time to ask this)
2016-01-14 10:32:25 -08:00
{
2017-06-14 18:01:38 -07:00
ReadPosition ( true ) ;
2016-01-14 10:32:25 -08:00
}
2015-12-01 14:18:01 -08:00
2016-01-14 10:32:25 -08:00
// write data to communication
{
StringEventArgs currentEvent = new StringEventArgs ( lineToWrite ) ;
2015-04-08 15:20:10 -07:00
if ( PrinterIsPrinting )
{
2016-04-19 15:14:22 -07:00
string lineWidthoutCR = lineToWrite . TrimEnd ( ) ;
2015-04-08 15:20:10 -07:00
CommunicationUnconditionalToPrinter . CallEvents ( this , new StringEventArgs ( "{0} [{1:0.000}]\n" . FormatWith ( lineWidthoutCR , timeSinceStartedPrint . Elapsed . TotalSeconds ) ) ) ;
}
else
{
CommunicationUnconditionalToPrinter . CallEvents ( this , currentEvent ) ;
}
if ( lineWithoutChecksum ! = null )
{
WriteLineStartCallBacks . CheckForKeys ( foundStringEvent ) ;
WriteLineContainsCallBacks . CheckForKeys ( foundStringEvent ) ;
if ( foundStringEvent . SendToDelegateFunctions )
{
WroteLine . CallEvents ( this , currentEvent ) ;
}
}
2015-02-04 14:57:56 -08:00
}
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
try
{
2016-01-14 10:32:25 -08:00
lock ( locker )
2015-04-24 18:24:21 -07:00
{
2015-11-12 11:19:32 -08:00
serialPort . Write ( lineToWrite ) ;
2016-04-11 12:04:30 -07:00
if ( false ) // this is for debugging. Eventually it could be hooked up to a user config option so it can be turned on in the field.
2016-04-06 11:56:48 -07:00
{
timeSinceRecievedOk . Stop ( ) ;
2016-04-06 13:53:04 -07:00
if ( ! haveHookedDrawing )
2016-04-06 11:56:48 -07:00
{
2016-04-07 09:57:40 -07:00
sendTimeAfterOkGraph = new DataViewGraph ( 150 , 150 , 0 , 30 ) ;
MatterControlApplication . Instance . AddChild ( sendTimeAfterOkGraph ) ;
2016-04-06 11:56:48 -07:00
haveHookedDrawing = true ;
}
2016-04-07 09:57:40 -07:00
sendTimeAfterOkGraph . AddData ( "ok->send" , timeSinceRecievedOk . ElapsedMilliseconds ) ;
2016-04-06 11:56:48 -07:00
}
2015-11-12 11:19:32 -08:00
timeSinceLastWrite . Restart ( ) ;
timeHaveBeenWaitingForOK . Restart ( ) ;
2015-04-24 18:24:21 -07:00
}
2015-04-08 15:20:10 -07:00
//Debug.Write("w: " + lineToWrite);
}
catch ( IOException ex )
{
2016-12-29 13:39:16 -08:00
PrinterOutputCache . Instance . WriteLine ( "Exception:" + ex . Message ) ;
2015-02-04 14:57:56 -08:00
2016-12-29 12:52:12 -08:00
if ( CommunicationState = = CommunicationStates . AttemptingToConnect )
{
// Handle hardware disconnects by relaying the failure reason and shutting down open resources
AbortConnectionAttempt ( "Connection Lost - " + ex . Message ) ;
}
2015-04-08 15:20:10 -07:00
}
2017-05-19 14:39:57 -07:00
catch ( TimeoutException e2 ) // known ok
2015-04-08 15:20:10 -07:00
{
2017-05-19 14:39:57 -07:00
// This writes on the next line, and there may have been another write attempt before it is printer. Write indented to attempt to show its association.
PrinterOutputCache . Instance . WriteLine ( " Error writing command:" + e2 . Message ) ;
2015-11-12 11:19:32 -08:00
}
2016-01-14 10:32:25 -08:00
catch ( UnauthorizedAccessException e3 )
2015-11-12 11:19:32 -08:00
{
2016-12-29 13:39:16 -08:00
PrinterOutputCache . Instance . WriteLine ( "Exception:" + e3 . Message ) ;
2015-11-12 11:19:32 -08:00
AbortConnectionAttempt ( e3 . Message ) ;
2015-04-08 15:20:10 -07:00
}
2016-12-29 13:39:16 -08:00
catch ( Exception )
2015-04-24 18:24:21 -07:00
{
}
2015-04-08 15:20:10 -07:00
}
else
{
OnConnectionFailed ( null ) ;
}
}
}
2015-02-04 14:57:56 -08:00
2016-11-29 14:17:37 -08:00
public void MacroStart ( )
2016-11-04 16:00:54 -07:00
{
2016-12-03 12:08:39 -08:00
queuedCommandStream2 ? . Reset ( ) ;
2016-11-04 16:00:54 -07:00
}
2017-02-01 17:49:26 -08:00
public void MacroCancel ( )
{
2017-02-03 13:06:08 -08:00
babyStepsStream6 ? . CancelMoves ( ) ;
waitForTempStream5 ? . Cancel ( ) ;
2017-02-01 17:49:26 -08:00
queuedCommandStream2 ? . Cancel ( ) ;
}
2016-11-29 14:17:37 -08:00
public void MacroContinue ( )
2016-11-04 16:00:54 -07:00
{
2016-12-03 12:08:39 -08:00
queuedCommandStream2 ? . Continue ( ) ;
2016-11-04 16:00:54 -07:00
}
2017-04-11 10:41:23 -07:00
private bool haveHookedDrawing = false ;
2016-04-06 11:56:48 -07:00
2015-11-04 17:13:53 -08:00
public class ReadThread
2015-04-08 15:20:10 -07:00
{
private static int currentReadThreadIndex = 0 ;
private int creationIndex ;
2017-04-11 10:41:23 -07:00
private static int numRunning = 0 ;
2015-04-27 15:42:31 -07:00
public static int NumRunning
{
get
{
return numRunning ;
}
}
2015-11-04 17:13:53 -08:00
private ReadThread ( )
2015-04-08 15:20:10 -07:00
{
2015-04-27 15:42:31 -07:00
numRunning + + ;
2015-04-08 15:20:10 -07:00
currentReadThreadIndex + + ;
creationIndex = currentReadThreadIndex ;
2015-11-04 17:13:53 -08:00
Task . Run ( ( ) = >
{
try
{
2017-06-13 17:22:49 -07:00
PrinterConnection . Instance . ReadFromPrinter ( this ) ;
2015-11-04 17:13:53 -08:00
}
catch
{
}
2016-01-14 10:32:25 -08:00
2017-06-13 17:22:49 -07:00
PrinterConnection . Instance . CommunicationUnconditionalToPrinter . CallEvents ( this , new StringEventArgs ( "Read Thread Has Exited.\n" ) ) ;
2015-11-04 17:13:53 -08:00
numRunning - - ;
} ) ;
2015-04-27 15:42:31 -07:00
}
2015-04-08 15:20:10 -07:00
internal static void Join ( )
{
currentReadThreadIndex + + ;
}
2015-11-04 17:13:53 -08:00
internal static void Start ( )
2015-04-08 15:20:10 -07:00
{
2015-11-04 17:13:53 -08:00
new ReadThread ( ) ;
2015-04-08 15:20:10 -07:00
}
2017-04-11 10:41:23 -07:00
2015-04-08 15:20:10 -07:00
internal bool IsCurrentThread ( )
{
return currentReadThreadIndex = = creationIndex ;
2015-02-04 14:57:56 -08:00
}
}
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
private class CheckSumLines
{
2016-01-14 10:32:25 -08:00
private static readonly int RingBufferCount = 64 ;
2015-02-06 08:23:19 -08:00
2015-04-08 15:20:10 -07:00
private int addedCount = 0 ;
private string [ ] ringBuffer = new string [ RingBufferCount ] ;
2014-11-10 20:15:59 -08:00
2015-04-08 15:20:10 -07:00
public int Count { get { return addedCount ; } }
public string this [ int index ]
{
get
{
return ringBuffer [ index % RingBufferCount ] ;
}
set
{
ringBuffer [ index % RingBufferCount ] = value ;
}
}
internal void Add ( string lineWithChecksum )
{
this [ addedCount + + ] = lineWithChecksum ;
}
2016-12-02 13:51:58 -08:00
internal void SetStartingIndex ( int startingIndex )
2015-04-08 15:20:10 -07:00
{
2016-12-02 13:51:58 -08:00
addedCount = startingIndex ;
2015-04-08 15:20:10 -07:00
}
}
}
public class PrintItemWrapperEventArgs : EventArgs
{
public PrintItemWrapperEventArgs ( PrintItemWrapper printItemWrapper )
{
2017-01-23 14:03:04 -08:00
this . PrintItemWrapper = printItemWrapper ;
2015-04-08 15:20:10 -07:00
}
2017-01-23 14:03:04 -08:00
public PrintItemWrapper PrintItemWrapper { get ; }
2015-04-08 15:20:10 -07:00
}
/// <summary>
/// This is a class to pass temperatures to callbacks that expect them.
/// </summary>
public class TemperatureEventArgs : EventArgs
{
public TemperatureEventArgs ( int index0Based , double temperature )
{
2017-01-23 14:03:04 -08:00
this . Index0Based = index0Based ;
this . Temperature = temperature ;
2015-04-08 15:20:10 -07:00
}
2017-01-23 14:03:04 -08:00
public int Index0Based { get ; }
public double Temperature { get ; }
2015-04-08 15:20:10 -07:00
}
2017-04-11 10:41:23 -07:00
}