2014-01-29 19:09:30 -08:00
/ *
2018-01-06 13:26:28 -08:00
Copyright ( c ) 2018 , Lars Brubaker , John Lewin
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 .
* /
2019-04-29 11:46:25 -07:00
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Globalization ;
using System.IO ;
using System.Linq ;
using System.Text ;
using System.Text.RegularExpressions ;
using System.Threading ;
using System.Threading.Tasks ;
2018-01-05 12:44:57 -08:00
using MatterControl.Printing ;
2014-01-29 19:09:30 -08:00
using MatterHackers.Agg ;
2018-12-19 16:43:39 -08:00
using MatterHackers.Agg.Platform ;
2018-01-30 15:47:12 -08:00
using MatterHackers.Agg.UI ;
2018-12-19 16:43:39 -08:00
using MatterHackers.Localizations ;
2019-04-25 16:04:24 -07:00
using MatterHackers.MatterControl.ConfigurationPage.PrintLeveling ;
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 ;
2018-12-05 17:07:55 -08:00
using MatterHackers.MatterControl.PrintQueue ;
2018-10-09 14:29:51 -07:00
using MatterHackers.MatterControl.SlicerConfiguration ;
2014-03-05 10:33:19 -08:00
using MatterHackers.SerialPortCommunication ;
using MatterHackers.SerialPortCommunication.FrostedSerial ;
using MatterHackers.VectorMath ;
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
{
2019-04-26 15:53:02 -07:00
public enum TurnOff
{
Now ,
AfterDelay
}
2018-03-21 14:20:43 -07:00
2019-02-22 09:23:45 -08:00
[Flags]
public enum PositionReadType
{
None = 0 ,
2019-04-26 15:53:02 -07:00
HomeX = 1 < < 1 ,
HomeY = 1 < < 2 ,
HomeZ = 1 < < 3 ,
Other = 1 < < 4 ,
2019-02-22 09:23:45 -08:00
HomeAll = HomeX | HomeY | HomeZ ,
}
2017-06-13 17:32:38 -07:00
public enum CommunicationStates
{
Disconnected ,
AttemptingToConnect ,
FailedToConnect ,
Connected ,
PreparingToPrint ,
Printing ,
PrintingFromSd ,
Paused ,
FinishedPrint ,
Disconnecting ,
ConnectionLost
2019-04-26 15:53:02 -07:00
}
2017-06-13 17:32:38 -07:00
2019-04-26 15:53:02 -07:00
public enum DetailedPrintingState
{
HomingAxis ,
HeatingBed ,
HeatingT0 ,
HeatingT1 ,
Printing
}
2017-06-13 17:32:38 -07:00
2019-04-26 15:53:02 -07:00
public enum FirmwareTypes
{
Unknown ,
Repetier ,
Marlin ,
2020-04-11 09:42:07 -07:00
Sprinter ,
Smoothie
2019-04-26 15:53:02 -07:00
}
2017-06-13 17:32:38 -07: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>
2018-11-09 13:58:43 -08:00
public class PrinterConnection : IDisposable
2015-04-08 15:20:10 -07:00
{
2019-03-22 14:14:29 -07:00
public static event EventHandler AnyCommunicationStateChanged ;
2018-11-09 13:58:43 -08:00
public event EventHandler Disposed ;
2018-11-08 17:16:35 -08:00
public event EventHandler TemporarilyHoldingTemp ;
2019-04-01 15:51:42 -07:00
2018-11-09 08:57:30 -08:00
public event EventHandler < string > ErrorReported ;
2017-10-10 16:40:59 -07:00
2018-11-08 17:16:35 -08:00
public event EventHandler BedTemperatureRead ;
2015-04-08 15:20:10 -07:00
2018-11-13 16:52:23 -08:00
public event EventHandler CommunicationStateChanged ;
2019-03-25 17:55:52 -07:00
2019-03-20 13:26:15 -07:00
public event EventHandler DetailedPrintingStateChanged ;
2015-04-08 15:20:10 -07:00
2018-11-13 16:52:23 -08:00
public event EventHandler ConnectionFailed ;
2015-04-08 15:20:10 -07:00
2018-11-09 13:58:43 -08:00
public event EventHandler ConnectionSucceeded ;
2015-04-08 15:20:10 -07:00
2019-01-18 09:49:38 -08:00
public void OnPauseOnLayer ( PrintPauseEventArgs printPauseEventArgs )
2018-11-09 11:47:19 -08:00
{
2019-01-18 09:49:38 -08:00
PauseOnLayer ? . Invoke ( this , printPauseEventArgs ) ;
2018-11-09 11:47:19 -08:00
}
2018-11-09 13:50:43 -08:00
public event EventHandler DestinationChanged ;
2015-04-08 15:20:10 -07:00
2019-02-22 09:23:45 -08:00
public event EventHandler HomingPositionChanged ;
2018-11-09 10:21:40 -08:00
public event EventHandler HotendTemperatureRead ;
2015-04-08 15:20:10 -07:00
2019-03-18 14:12:09 -07:00
public event EventHandler < int > HotendTargetTemperatureChanged ;
2019-04-01 15:51:42 -07:00
2019-03-18 14:12:09 -07:00
public event EventHandler BedTargetTemperatureChanged ;
2018-11-13 16:52:23 -08:00
public event EventHandler FanSpeedSet ;
2015-04-08 15:20:10 -07:00
2018-11-13 16:52:23 -08:00
public event EventHandler FirmwareVersionRead ;
2015-04-08 15:20:10 -07:00
2019-01-18 09:49:38 -08:00
public void OnFilamentRunout ( PrintPauseEventArgs printPauseEventArgs )
2018-11-09 11:47:19 -08:00
{
2019-01-18 09:49:38 -08:00
FilamentRunout ? . Invoke ( this , printPauseEventArgs ) ;
2018-11-09 11:47:19 -08:00
}
2022-01-27 16:49:46 -08:00
public event EventHandler < ( string printerName , string itemName ) > PrintFinished ;
2019-04-26 15:53:02 -07:00
2020-07-03 12:05:28 -07:00
public event EventHandler PrintStarted ;
2021-02-09 16:54:31 -08:00
public event EventHandler CanceleRequested ;
public event EventHandler CancelCompleted ;
2015-04-08 15:20:10 -07:00
2019-01-18 09:49:38 -08:00
public event EventHandler < PrintPauseEventArgs > PauseOnLayer ;
2017-04-13 14:25:46 -07:00
2019-01-18 09:49:38 -08:00
public event EventHandler < PrintPauseEventArgs > FilamentRunout ;
2017-04-13 14:25:46 -07:00
2018-11-09 08:57:30 -08:00
public event EventHandler < string > LineReceived ;
2015-04-08 15:20:10 -07:00
2018-11-09 08:57:30 -08:00
public event EventHandler < string > LineSent ;
2015-04-08 15:20:10 -07:00
2018-01-06 22:06:42 -08:00
public bool WaitingForPositionRead
2017-05-19 14:39:57 -07:00
{
get
{
// make sure the longest we will wait under any circumstance is 60 seconds
if ( waitingForPosition . ElapsedMilliseconds > 60000 )
{
waitingForPosition . Reset ( ) ;
2019-02-22 09:23:45 -08:00
PositionReadType = PositionReadType . None ;
2017-05-19 14:39:57 -07:00
}
2019-02-22 09:23:45 -08:00
return waitingForPosition . IsRunning | | ( PositionReadType ! = PositionReadType . None ) ;
2017-05-19 14:39:57 -07:00
}
}
2017-04-11 10:41:23 -07:00
2019-03-19 13:13:14 -07:00
public bool ContinueHoldingTemperature { get ; set ; }
2018-07-17 10:04:08 -07:00
public double SecondsToHoldTemperature { get ; private set ; }
2018-01-31 12:32:25 -08:00
2017-08-03 16:35:22 -07:00
public TerminalLog TerminalLog { get ; }
2017-08-03 15:24:41 -07:00
2019-04-01 15:51:42 -07:00
public event EventHandler AtxPowerStateChanged ;
2015-04-23 20:19:00 -07:00
private bool atxPowerIsOn = false ;
2019-04-26 15:53:02 -07:00
internal const int MaxExtruders = 16 ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private const int MaxInvalidConnectionChars = 3 ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly object locker = new object ( ) ;
2015-04-08 15:20:10 -07:00
private double actualBedTemperature ;
2019-05-07 14:47:43 -07:00
public int ActiveExtruderIndex
{
get
{
if ( toolChangeStream ! = null )
{
return toolChangeStream . RequestedTool ;
}
return 0 ;
}
}
2016-07-25 12:29:43 -07:00
2019-04-26 15:53:02 -07:00
private readonly double [ ] actualHotendTemperature = new double [ MaxExtruders ] ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly CheckSumLines allCheckSumLinesSent = new CheckSumLines ( ) ;
2015-04-08 15:20:10 -07:00
2019-04-30 15:51:44 -07:00
private CommunicationStates _communicationState = CommunicationStates . Disconnected ;
2015-04-08 15:20:10 -07:00
2016-01-19 15:16:05 -08:00
private PrinterMove currentDestination ;
2015-04-08 15:20:10 -07:00
2016-01-14 10:32:25 -08:00
private double currentSdBytes = 0 ;
2015-04-08 15:20:10 -07:00
2020-05-05 09:26:09 -07:00
private double [ ] fanSpeed = new double [ MaxExtruders ] ;
2015-04-08 15:20:10 -07:00
2016-12-02 13:51:58 -08:00
private int currentLineIndexToSend = 0 ;
2015-04-08 15:20:10 -07:00
2018-01-04 17:30:48 -08:00
private bool forceImmediateWrites = false ;
2015-04-08 15:20:10 -07:00
private string lastLineRead = "" ;
2018-07-17 10:04:08 -07:00
public Stopwatch TimeHaveBeenHoldingTemperature { get ; set ; }
2018-01-31 12:32:25 -08:00
2019-02-20 17:03:54 -08:00
private PrinterMove lastReportedPosition = PrinterMove . Unknown ;
2015-04-08 15:20:10 -07:00
2019-03-01 19:38:59 -08:00
private GCodeSwitcher gCodeFileSwitcher = null ;
private PauseHandlingStream pauseHandlingStream = null ;
private QueuedCommandsStream queuedCommandStream = null ;
private MaxLengthStream maxLengthStream ;
2019-05-07 14:47:43 -07:00
private ToolChangeStream toolChangeStream ;
2019-03-01 19:38:59 -08:00
private PrintLevelingStream printLevelingStream = null ;
private WaitForTempStream waitForTempStream = 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
2017-03-07 17:52:44 -08:00
public CommunicationStates PrePauseCommunicationState { get ; private set ; } = CommunicationStates . Printing ;
2015-04-08 15:20:10 -07:00
2019-03-20 23:50:56 -07:00
private DetailedPrintingState _detailedPrintingState ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly ContainsStringLineActions readLineContainsCallBacks = new ContainsStringLineActions ( ) ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly StartsWithLineActions readLineStartCallBacks = new StartsWithLineActions ( ) ;
2015-04-08 15:20:10 -07:00
// we start out by setting it to a nothing file
2019-05-02 20:41:16 -07:00
public IFrostedSerialPort serialPort { get ; private set ; }
2015-04-08 15:20:10 -07:00
2018-01-30 14:48:53 -08:00
private double _targetBedTemperature ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly double [ ] targetHotendTemperature = new double [ MaxExtruders ] ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly Stopwatch timeHaveBeenWaitingForOK = new Stopwatch ( ) ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly Stopwatch timeSinceLastReadAnything = new Stopwatch ( ) ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly Stopwatch timeSinceLastWrite = new Stopwatch ( ) ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly Stopwatch timeSinceRecievedOk = new Stopwatch ( ) ;
2016-04-06 11:56:48 -07:00
2019-04-26 15:53:02 -07:00
private readonly Stopwatch timePrinting = new Stopwatch ( ) ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly Stopwatch timeWaitingForSdProgress = new Stopwatch ( ) ;
2015-04-08 15:20:10 -07:00
private double totalSdBytes = 0 ;
2019-02-22 09:23:45 -08:00
private PositionReadType PositionReadType { get ; set ; } = PositionReadType . None ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly Stopwatch waitingForPosition = new Stopwatch ( ) ;
private readonly ContainsStringLineActions writeLineContainsCallBacks = new ContainsStringLineActions ( ) ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
private readonly StartsWithLineActions writeLineStartCallBacks = new StartsWithLineActions ( ) ;
2015-04-08 15:20:10 -07:00
2016-04-14 14:34:30 -07:00
private double secondsSinceUpdateHistory = 0 ;
2017-11-01 13:57:45 -07:00
private long lineSinceUpdateHistory = 0 ;
2016-04-14 14:34:30 -07:00
2017-09-20 15:25:54 -07:00
public PrinterConnection ( PrinterConfig printer )
2015-01-19 18:26:09 -08:00
{
2018-12-05 13:48:25 -08:00
this . Printer = printer ;
2017-09-20 15:25:54 -07:00
2018-11-09 13:58:43 -08:00
TerminalLog = new TerminalLog ( this ) ;
2017-08-03 15:24:41 -07:00
2015-04-08 15:20:10 -07:00
MonitorPrinterTemperature = true ;
2015-01-19 18:26:09 -08:00
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Register ( "start" , FoundStart ) ;
readLineStartCallBacks . Register ( "start" , PrintingCanContinue ) ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Register ( "ok" , SuppressEcho ) ;
readLineStartCallBacks . Register ( "wait" , SuppressEcho ) ;
readLineStartCallBacks . Register ( "T:" , SuppressEcho ) ; // repetier
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Register ( "ok" , PrintingCanContinue ) ;
readLineStartCallBacks . Register ( "Done saving file" , PrintingCanContinue ) ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Register ( "B:" , ReadTemperatures ) ; // smoothie
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Register ( "SD printing byte" , ReadSdProgress ) ; // repetier
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Register ( "C:" , ReadTargetPositions ) ;
readLineStartCallBacks . Register ( "ok C:" , ReadTargetPositions ) ; // smoothie is reporting the C: with an ok first.
readLineStartCallBacks . Register ( "X:" , ReadTargetPositions ) ;
readLineStartCallBacks . Register ( "ok X:" , ReadTargetPositions ) ;
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Register ( "rs " , PrinterRequestsResend ) ; // smoothie is lower case and no :
readLineStartCallBacks . Register ( "RS:" , PrinterRequestsResend ) ;
2017-04-11 10:41:23 -07:00
2019-05-17 08:11:59 -07:00
// smoothie failures
2019-05-30 11:41:50 -07:00
readLineStartCallBacks . Register ( "ERROR: Homing cycle failed" , PrinterReportsError ) ;
2016-01-06 12:09:37 -08:00
2019-05-17 08:11:59 -07:00
// marlin failures
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Register ( "temp sensor defect" , PrinterReportsError ) ;
readLineStartCallBacks . Register ( "Error:Printer halted" , PrinterReportsError ) ;
2016-01-06 12:09:37 -08:00
2019-05-17 08:11:59 -07:00
// repetier failures
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Register ( "accelerometer send i2c error" , PrinterReportsError ) ;
readLineStartCallBacks . Register ( "accelerometer i2c recv error" , PrinterReportsError ) ;
2016-12-12 16:37:09 -08:00
2019-05-17 08:11:59 -07:00
// s3g failures
2019-04-26 15:53:02 -07:00
writeLineStartCallBacks . Register ( "M80" , AtxPowerUpWasWritenToPrinter ) ;
writeLineStartCallBacks . Register ( "M81" , AtxPowerDownWasWritenToPrinter ) ;
writeLineStartCallBacks . Register ( "M104" , HotendTemperatureWasWritenToPrinter ) ;
writeLineStartCallBacks . Register ( "M106" , FanSpeedWasWritenToPrinter ) ;
writeLineStartCallBacks . Register ( "M107" , FanOffWasWritenToPrinter ) ;
writeLineStartCallBacks . Register ( "M109" , HotendTemperatureWasWritenToPrinter ) ;
writeLineStartCallBacks . Register ( "M140" , BedTemperatureWasWritenToPrinter ) ;
writeLineStartCallBacks . Register ( "M190" , BedTemperatureWasWritenToPrinter ) ;
2018-11-16 16:21:30 -08:00
Task . Run ( ( ) = >
{
this . OnIdle ( ) ;
Thread . Sleep ( 10 ) ;
} ) ;
2019-03-18 14:12:09 -07:00
printer . Settings . SettingChanged + = ( s , stringEvent ) = >
{
var extruder = - 1 ;
switch ( stringEvent . Data )
{
case SettingsKey . temperature :
extruder = 0 ;
break ;
2019-04-29 09:13:43 -07:00
2019-03-18 14:12:09 -07:00
case SettingsKey . temperature1 :
extruder = 1 ;
break ;
2019-04-29 09:13:43 -07:00
2019-03-18 14:12:09 -07:00
case SettingsKey . temperature2 :
extruder = 2 ;
break ;
2019-04-29 09:13:43 -07:00
2019-03-18 14:12:09 -07:00
case SettingsKey . temperature3 :
extruder = 3 ;
break ;
}
if ( extruder > - 1 )
{
2019-03-18 14:23:10 -07:00
if ( this . Printing
& & ( this . DetailedPrintingState = = DetailedPrintingState . HeatingT0
| | this . DetailedPrintingState = = DetailedPrintingState . HeatingT1 ) )
2019-03-18 14:12:09 -07:00
{
}
else
{
2019-03-18 14:23:10 -07:00
double goalTemp = this . GetTargetHotendTemperature ( extruder ) ;
2019-03-18 14:12:09 -07:00
if ( goalTemp > 0 )
{
var newGoal = printer . Settings . GetValue < double > ( stringEvent . Data ) ;
2019-03-18 14:23:10 -07:00
this . SetTargetHotendTemperature ( extruder , newGoal ) ;
2019-03-18 14:12:09 -07:00
}
}
}
2022-01-17 11:33:22 -08:00
if ( stringEvent . Data = = Printer . Settings . Helpers . ActiveBedTemperatureSetting
| | stringEvent . Data = = SettingsKey . bed_temperature
| | stringEvent . Data = = SettingsKey . bed_surface )
2019-03-18 14:12:09 -07:00
{
2019-03-18 14:23:10 -07:00
if ( this . Printing
& & this . DetailedPrintingState = = DetailedPrintingState . HeatingBed )
2019-03-18 14:12:09 -07:00
{
}
else
{
2019-03-18 14:23:10 -07:00
double goalTemp = this . TargetBedTemperature ;
2019-03-18 14:12:09 -07:00
if ( goalTemp > 0 )
{
2022-01-17 11:33:22 -08:00
var newGoal = printer . Settings . Helpers . ActiveBedTemperature ;
2019-03-18 14:23:10 -07:00
this . TargetBedTemperature = newGoal ;
2019-03-18 14:12:09 -07:00
}
}
}
} ;
2016-07-25 12:29:43 -07:00
}
2016-01-14 10:32:25 -08:00
[Flags]
2019-04-26 15:53:02 -07:00
public enum Axis
{
X = 1 ,
Y = 2 ,
Z = 4 ,
E = 8 ,
2020-05-01 07:51:44 -07:00
XYZ = X | Y | Z ,
C = 16 , // used by e3d quad extruder
2019-04-26 15:53:02 -07:00
}
2015-04-08 15:20:10 -07:00
2021-05-18 17:06:37 -07:00
private void RegisterReadlineContainsCallbacks ( )
{
readLineContainsCallBacks . Clear ( ) ;
readLineContainsCallBacks . Register ( "T0:" , ReadTemperatures ) ; // marlin
readLineContainsCallBacks . Register ( "T:" , ReadTemperatures ) ; // repetier
readLineContainsCallBacks . Register ( "Resend:" , PrinterRequestsResend ) ;
readLineContainsCallBacks . Register ( "FIRMWARE_NAME:" , PrinterStatesFirmware ) ;
// smoothie failures
readLineContainsCallBacks . Register ( "T:inf" , PrinterReportsError ) ;
readLineContainsCallBacks . Register ( "B:inf" , PrinterReportsError ) ;
readLineContainsCallBacks . Register ( "ZProbe not triggered" , PrinterReportsError ) ;
// marlin failures
readLineContainsCallBacks . Register ( "MINTEMP" , PrinterReportsError ) ;
readLineContainsCallBacks . Register ( "MAXTEMP" , PrinterReportsError ) ;
readLineContainsCallBacks . Register ( "M999" , PrinterReportsError ) ;
readLineContainsCallBacks . Register ( "Error: Extruder switched off" , PrinterReportsError ) ;
readLineContainsCallBacks . Register ( "Heater decoupled" , PrinterReportsError ) ;
readLineContainsCallBacks . Register ( "cold extrusion prevented" , PrinterReportsError ) ;
readLineContainsCallBacks . Register ( "Error:Thermal Runaway, system stopped!" , PrinterReportsError ) ;
readLineContainsCallBacks . Register ( "Error:Probing Failed" , PrinterReportsError ) ;
readLineContainsCallBacks . Register ( "Error:Heating failed" , PrinterReportsError ) ;
// repetier failures
readLineContainsCallBacks . Register ( "dry run mode" , PrinterReportsError ) ;
// s3g failures
readLineContainsCallBacks . Register ( "Bot is Shutdown due to Overheat" , PrinterReportsError ) ;
if ( CommunicationState = = CommunicationStates . PreparingToPrint )
{
foreach ( var error in Printer . Settings . GetValue ( SettingsKey . additional_printing_errors ) . Split ( ',' ) )
{
var trimmedLine = error . Trim ( ) ;
if ( ! string . IsNullOrEmpty ( trimmedLine ) )
{
readLineContainsCallBacks . Register ( trimmedLine , PrinterReportsError ) ;
}
}
}
}
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
2018-01-06 13:26:28 -08:00
// PrinterSettings/Options {{
2019-03-25 17:55:52 -07:00
public int BaudRate
{
get
{
2019-04-05 15:12:35 -07:00
if ( string . IsNullOrEmpty ( Printer . Settings . GetValue ( SettingsKey . baud_rate ) ) )
2019-03-25 17:55:52 -07:00
{
return 250000 ;
}
return Printer . Settings . GetValue < int > ( SettingsKey . baud_rate ) ;
}
}
2018-01-06 13:26:28 -08:00
2019-03-25 17:55:52 -07:00
public double FeedRateRatio = > Printer . Settings . GetValue < double > ( SettingsKey . feedrate_ratio ) ;
2018-01-06 13:26:28 -08:00
2019-03-25 17:55:52 -07:00
public string ConnectGCode = > Printer . Settings . GetValue ( SettingsKey . connect_gcode ) ;
2018-01-06 13:26:28 -08:00
2019-03-25 17:55:52 -07:00
public string CancelGCode = > Printer . Settings . GetValue ( SettingsKey . cancel_gcode ) ;
2018-01-06 13:26:28 -08:00
2019-03-25 17:55:52 -07:00
public int ExtruderCount = > Printer . Settings . GetValue < int > ( SettingsKey . extruder_count ) ;
2018-01-06 13:26:28 -08:00
2019-03-25 17:55:52 -07:00
public bool SendWithChecksum = > Printer . Settings . GetValue < bool > ( SettingsKey . send_with_checksum ) ;
2018-01-06 13:26:28 -08:00
2019-03-25 17:55:52 -07:00
public bool EnableNetworkPrinting = > Printer . Settings . GetValue < bool > ( SettingsKey . enable_network_printing ) ;
2018-01-06 13:26:28 -08:00
2019-03-25 17:55:52 -07:00
public bool AutoReleaseMotors = > Printer . Settings . GetValue < bool > ( SettingsKey . auto_release_motors ) ;
2018-01-06 13:26:28 -08:00
2019-03-25 17:55:52 -07:00
public bool RecoveryIsEnabled = > Printer . Settings . GetValue < bool > ( SettingsKey . recover_is_enabled ) ;
2019-04-01 15:51:42 -07:00
2018-11-14 16:54:23 -08:00
public string LastPrintedItemName { get ; private set ; } = "" ;
2019-04-01 15:51:42 -07:00
2018-11-14 16:54:23 -08:00
public string PrintingItemName { get ; set ; } = "" ;
2018-01-06 13:26:28 -08:00
2019-04-26 15:53:02 -07:00
private readonly List < ( Regex Regex , string Replacement ) > readLineReplacements = new List < ( Regex Regex , string Replacement ) > ( ) ;
2018-01-06 16:03:03 -08:00
2019-04-04 10:37:18 -07:00
public void InitializeReadLineReplacements ( )
2018-01-06 16:03:03 -08:00
{
2019-04-04 10:37:18 -07:00
var readRegEx = Printer . Settings . GetValue ( SettingsKey . read_regex ) ;
2018-01-06 16:03:03 -08:00
2019-04-04 10:37:18 -07:00
// Clear and rebuild the replacement list
readLineReplacements . Clear ( ) ;
2018-01-06 16:03:03 -08:00
2019-04-04 10:37:18 -07:00
foreach ( string regExLine in readRegEx . Split ( new string [ ] { "\\n" } , StringSplitOptions . RemoveEmptyEntries ) )
{
2019-04-08 13:38:20 -07:00
var matches = ProcessWriteRegexStream . GetQuotedParts . Matches ( regExLine ) ;
2019-04-04 10:37:18 -07:00
if ( matches . Count = = 2 )
{
var search = matches [ 0 ] . Value . Substring ( 1 , matches [ 0 ] . Value . Length - 2 ) ;
var replace = matches [ 1 ] . Value . Substring ( 1 , matches [ 1 ] . Value . Length - 2 ) ;
readLineReplacements . Add ( ( new Regex ( search , RegexOptions . Compiled ) , replace ) ) ;
2018-01-06 16:03:03 -08:00
}
}
}
2018-01-06 13:26:28 -08:00
// PrinterSettings/Options }}
2015-01-19 18:26:09 -08:00
2017-12-31 14:20:06 -08:00
private bool communicationPossible = false ;
2015-04-08 15:20:10 -07:00
public CommunicationStates CommunicationState
{
2019-04-30 15:51:44 -07:00
get = > _communicationState ;
2015-04-08 15:20:10 -07:00
set
{
2015-03-13 12:25:33 -07:00
switch ( value )
{
case CommunicationStates . AttemptingToConnect :
2018-11-14 16:54:23 -08:00
PrintingItemName = "" ;
2019-04-05 17:11:05 -07:00
// TODO: Investigate the validity of this claim/warning
2019-04-26 15:53:02 -07:00
// #if DEBUG
// 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.");
// }
// #endif
2015-03-13 12:25:33 -07:00
break ;
2015-04-27 15:42:31 -07:00
case CommunicationStates . Connected :
2017-12-31 14:20:06 -08:00
communicationPossible = true ;
2018-01-04 17:30:48 -08:00
QueueLine ( "M115" ) ;
2019-02-22 09:23:45 -08:00
ReadPosition ( PositionReadType . Other ) ;
2018-11-14 16:54:23 -08:00
PrintingItemName = "" ;
2015-04-27 15:42:31 -07:00
break ;
2016-09-16 15:27:58 -07:00
case CommunicationStates . ConnectionLost :
case CommunicationStates . Disconnected :
2018-11-14 16:54:23 -08:00
PrintingItemName = "" ;
2017-12-31 14:20:06 -08:00
if ( communicationPossible )
2016-09-16 15:27:58 -07:00
{
2018-03-21 14:20:43 -07:00
TurnOffBedAndExtruders ( TurnOff . Now ) ;
2019-04-26 15:53:02 -07:00
for ( int hotendIndex = 0 ; hotendIndex < MaxExtruders ; hotendIndex + + )
2017-12-31 14:20:06 -08:00
{
actualHotendTemperature [ hotendIndex ] = 0 ;
OnHotendTemperatureRead ( new TemperatureEventArgs ( hotendIndex , GetActualHotendTemperature ( hotendIndex ) ) ) ;
}
actualBedTemperature = 0 ;
OnBedTemperatureRead ( new TemperatureEventArgs ( 0 , ActualBedTemperature ) ) ;
2016-09-16 15:27:58 -07:00
}
2017-12-31 14:20:06 -08:00
communicationPossible = false ;
2016-09-16 15:27:58 -07:00
break ;
2015-03-13 12:25:33 -07:00
}
2019-04-30 15:51:44 -07:00
if ( _communicationState ! = value )
2015-04-08 15:20:10 -07:00
{
2019-04-05 14:00:37 -07:00
this . TerminalLog . WriteLine ( string . Format ( "Communication State: {0}" , value ) ) ;
2015-04-27 15:42:31 -07:00
2019-04-30 15:51:44 -07:00
switch ( _communicationState )
2015-04-08 15:20:10 -07:00
{
// 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 )
{
2019-04-30 15:51:44 -07:00
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
}
2019-04-26 15:53:02 -07:00
2019-03-22 11:51:45 -07:00
timePrinting . Stop ( ) ;
2015-04-08 15:20:10 -07:00
}
else if ( value = = CommunicationStates . FinishedPrint )
{
2019-04-26 15:53:02 -07:00
if ( ActivePrintTask ! = null )
2015-04-08 15:20:10 -07:00
{
2019-04-26 15:53:02 -07:00
ActivePrintTask . PrintEnd = DateTime . Now ;
ActivePrintTask . PercentDone = 100 ;
ActivePrintTask . PrintComplete = true ;
2020-10-23 16:57:26 -07:00
ActivePrintTask . CommitAndPushToServer ( ) ;
2015-04-08 15:20:10 -07:00
}
2018-11-14 16:54:23 -08:00
LastPrintedItemName = PrintingItemName ;
PrintingItemName = "" ;
2015-04-08 15:20:10 -07:00
// Set this early as we always want our functions to know the state we are in.
2019-04-30 15:51:44 -07:00
_communicationState = value ;
2019-03-22 11:51:45 -07:00
timePrinting . Stop ( ) ;
2019-03-25 17:55:52 -07:00
if ( Printer . Bed ? . EditContext ? . SourceItem . Name ! = null )
{
2022-01-27 16:49:46 -08:00
PrintFinished ? . Invoke ( this , ( Printer . PrinterName , Printer . Bed . EditContext . SourceItem . Name ) ) ;
2019-03-25 17:55:52 -07:00
}
2015-04-08 15:20:10 -07:00
}
else
{
2019-03-22 11:51:45 -07:00
timePrinting . Stop ( ) ;
timePrinting . Reset ( ) ;
2015-04-08 15:20:10 -07:00
}
}
2019-04-26 15:53:02 -07:00
2015-04-08 15:20:10 -07:00
break ;
// was paused
case CommunicationStates . Paused :
{
// changing to printing
if ( value = = CommunicationStates . Printing )
{
2019-03-22 11:51:45 -07:00
timePrinting . Start ( ) ;
2015-04-08 15:20:10 -07:00
}
}
2021-10-17 16:11:31 -07:00
break ;
2019-04-26 15:53:02 -07:00
2021-10-17 16:11:31 -07:00
case CommunicationStates . PreparingToPrint :
// clear the canceled flag as soon as we start to prepare the print
cancelPrintNextWriteLine = false ;
PrintWasCanceled = false ;
2015-04-08 15:20:10 -07:00
break ;
2015-01-28 10:50:06 -08:00
default :
2019-03-22 11:51:45 -07:00
if ( ! timePrinting . IsRunning
2015-01-28 10:50:06 -08:00
& & 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)
2019-03-22 11:51:45 -07:00
timePrinting . Restart ( ) ;
2015-01-28 10:50:06 -08:00
}
2019-04-26 15:53:02 -07:00
2015-01-28 10:50:06 -08:00
break ;
2015-04-08 15:20:10 -07:00
}
2015-02-05 07:50:57 -08:00
2019-04-30 15:51:44 -07:00
_communicationState = value ;
2019-03-20 13:26:15 -07:00
CommunicationStateChanged ? . Invoke ( this , null ) ;
2019-03-22 14:14:29 -07:00
AnyCommunicationStateChanged ? . Invoke ( this , null ) ;
2015-04-08 15:20:10 -07:00
}
}
}
2018-09-21 13:29:39 -07:00
public void SwitchToGCode ( string gCodeFilePath )
{
2019-03-01 19:38:59 -08:00
gCodeFileSwitcher . SwitchTo ( gCodeFilePath ) ;
2018-09-21 13:29:39 -07:00
}
2018-12-05 13:48:25 -08:00
public string ComPort = > Printer . Settings ? . Helpers . ComPort ( ) ;
2016-04-27 17:34:33 -07:00
2019-01-11 14:39:40 -08:00
public string DriverType = > ( this . ComPort = = "Emulator" ) ? "Emulator" : Printer . Settings ? . GetValue ( SettingsKey . driver_type ) ;
2015-02-05 07:50:57 -08:00
2015-04-23 20:19:00 -07:00
public bool AtxPowerEnabled
{
get
{
return atxPowerIsOn ;
}
2019-04-26 15:53:02 -07:00
2015-04-23 20:19:00 -07:00
set
{
if ( value )
{
2018-01-04 17:30:48 -08:00
QueueLine ( "M80" ) ;
2015-04-23 20:19:00 -07:00
}
else
{
2018-01-04 17:30:48 -08:00
QueueLine ( "M81" ) ;
2015-04-23 20:19:00 -07:00
}
}
}
2018-11-02 16:14:37 -07:00
public double CurrentExtruderDestination { get { return currentDestination . extrusion ; } }
2018-02-16 14:50:12 -08:00
public Vector3 CurrentDestination = > currentDestination . position ;
2015-04-08 15:20:10 -07:00
public int CurrentlyPrintingLayer
{
get
2015-02-05 07:50:57 -08:00
{
2019-03-01 19:38:59 -08:00
if ( gCodeFileSwitcher ! = null )
2016-01-14 10:32:25 -08:00
{
2019-03-01 19:38:59 -08:00
return gCodeFileSwitcher ? . GCodeFile ? . GetLayerIndex ( gCodeFileSwitcher . LineIndex ) ? ? - 1 ;
2016-01-14 10:32:25 -08:00
}
2015-11-28 07:46:57 -08:00
2018-01-07 16:11:44 -08:00
return - 1 ;
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
2018-02-16 14:50:12 -08:00
public bool Disconnecting = > CommunicationState = = CommunicationStates . Disconnecting ;
2015-02-06 08:23:19 -08:00
2020-05-05 09:26:09 -07:00
public double GetFanSpeed0To255 ( int fanIndex )
2015-04-08 15:20:10 -07:00
{
2020-05-05 09:26:09 -07:00
if ( fanIndex > = ExtruderCount )
2015-02-05 07:50:57 -08:00
{
2020-05-05 09:26:09 -07:00
fanIndex = 0 ;
}
return fanSpeed [ fanIndex ] ;
}
public void SetFanSpeed0To255 ( int fanIndex , double value )
{
if ( fanIndex > = ExtruderCount )
{
fanIndex = 0 ;
}
fanSpeed [ fanIndex ] = Math . Max ( 0 , Math . Min ( 255 , value ) ) ;
OnFanSpeedSet ( null ) ;
if ( this . IsConnected )
{
if ( Printer . Settings . GetValue < bool > ( SettingsKey . has_fan_per_extruder ) )
{
QueueLine ( "M106 P{0} S{1}" . FormatWith ( fanIndex , ( int ) ( fanSpeed [ fanIndex ] + . 5 ) ) ) ;
}
else
2015-04-08 15:20:10 -07:00
{
2020-05-05 09:26:09 -07:00
QueueLine ( "M106 S{0}" . FormatWith ( ( int ) ( fanSpeed [ fanIndex ] + . 5 ) ) ) ;
2015-04-08 15:20:10 -07:00
}
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
2019-04-30 15:51:44 -07:00
| | ( CommunicationState = = CommunicationStates . Paused & & PrePauseCommunicationState = = CommunicationStates . PrintingFromSd ) )
2015-04-08 15:20:10 -07:00
{
if ( totalSdBytes > 0 )
{
return currentSdBytes / totalSdBytes * 100 ;
}
return 0 ;
}
2019-02-06 10:34:19 -08:00
if ( PrintIsFinished & & ! Paused )
2015-04-08 15:20:10 -07:00
{
return 100.0 ;
}
else if ( NumberOfLinesInCurrentPrint > 0
2019-03-01 19:38:59 -08:00
& & gCodeFileSwitcher ? . GCodeFile ! = null )
2015-04-08 15:20:10 -07:00
{
2019-03-01 19:38:59 -08:00
return gCodeFileSwitcher . GCodeFile . PercentComplete ( gCodeFileSwitcher . LineIndex ) ;
2015-04-08 15:20:10 -07:00
}
else
{
return 0.0 ;
}
}
}
2018-02-01 14:51:44 -08:00
public bool IsConnected
2015-04-08 15:20:10 -07:00
{
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
}
}
}
2019-02-06 10:34:19 -08:00
public bool Paused = > CommunicationState = = CommunicationStates . Paused ;
2015-04-08 15:20:10 -07:00
2019-02-06 10:34:19 -08:00
public bool Printing
2015-04-08 15:20:10 -07:00
{
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." ) ;
}
}
}
2017-08-30 10:37:44 -07:00
public DetailedPrintingState DetailedPrintingState
2015-04-08 15:20:10 -07:00
{
2019-03-20 23:50:56 -07:00
get = > _detailedPrintingState ;
2015-04-08 15:20:10 -07:00
set
{
2019-03-20 23:50:56 -07:00
if ( _detailedPrintingState ! = value )
2015-04-08 15:20:10 -07:00
{
2019-03-20 23:50:56 -07:00
_detailedPrintingState = value ;
2019-03-20 13:26:15 -07:00
DetailedPrintingStateChanged ? . Invoke ( this , null ) ;
2015-04-08 15:20:10 -07:00
}
}
}
public bool PrintIsActive
{
get
{
switch ( CommunicationState )
{
case CommunicationStates . Disconnected :
case CommunicationStates . Disconnecting :
case CommunicationStates . AttemptingToConnect :
case CommunicationStates . ConnectionLost :
case CommunicationStates . FailedToConnect :
case CommunicationStates . Connected :
case CommunicationStates . FinishedPrint :
return false ;
case CommunicationStates . Printing :
case CommunicationStates . PrintingFromSd :
case CommunicationStates . PreparingToPrint :
case CommunicationStates . Paused :
return true ;
default :
throw new NotImplementedException ( "Make sure every status returns the correct connected state." ) ;
}
}
}
2018-02-16 14:50:12 -08:00
public bool PrintIsFinished = > CommunicationState = = CommunicationStates . FinishedPrint ;
2015-04-08 15:20:10 -07:00
2017-02-01 17:36:33 -08:00
public string PrintJobName { get ; private set ; } = null ;
2015-04-08 15:20:10 -07:00
2021-09-29 18:18:38 -07:00
public bool PrintWasCanceled { get ; private set ; } = false ;
2015-04-08 15:20:10 -07:00
2019-05-19 20:10:28 -07:00
public double RatioIntoCurrentLayerSeconds
2015-04-08 15:20:10 -07:00
{
get
{
2019-05-12 21:00:37 -07:00
if ( gCodeFileSwitcher ? . GCodeFile = = null
| | ! ( gCodeFileSwitcher ? . GCodeFile is GCodeMemoryFile ) )
2017-01-19 10:53:17 -08:00
{
return 0 ;
}
2019-05-19 20:10:28 -07:00
return gCodeFileSwitcher . GCodeFile . Ratio0to1IntoContainedLayerSeconds ( gCodeFileSwitcher . LineIndex ) ;
}
}
public double RatioIntoCurrentLayerInstructions
{
get
{
if ( gCodeFileSwitcher ? . GCodeFile = = null
| | ! ( gCodeFileSwitcher ? . GCodeFile is GCodeMemoryFile ) )
{
return 0 ;
}
return gCodeFileSwitcher . GCodeFile . Ratio0to1IntoContainedLayerInstruction ( gCodeFileSwitcher . LineIndex ) ;
2015-04-08 15:20:10 -07:00
}
}
2019-05-12 21:00:37 -07:00
public int SecondsToEnd
{
get
{
if ( gCodeFileSwitcher ? . GCodeFile = = null )
{
return 0 ;
}
return ( int ) gCodeFileSwitcher . GCodeFile . Instruction ( gCodeFileSwitcher . LineIndex ) . SecondsToEndFromHere ;
}
}
2015-04-08 15:20:10 -07:00
public int SecondsPrinted
{
get
{
2019-02-06 10:34:19 -08:00
if ( Printing | | Paused | | PrintIsFinished )
2015-04-08 15:20:10 -07:00
{
2019-03-22 11:51:45 -07:00
return ( int ) ( timePrinting . ElapsedMilliseconds / 1000 ) ;
2015-04-08 15:20:10 -07:00
}
return 0 ;
}
}
public double TargetBedTemperature
{
2018-02-16 14:50:12 -08:00
get = > _targetBedTemperature ;
2015-04-08 15:20:10 -07:00
set
{
2019-03-19 13:13:14 -07:00
ContinueHoldingTemperature = false ;
2018-01-30 14:48:53 -08:00
if ( _targetBedTemperature ! = value )
2015-04-08 15:20:10 -07:00
{
2018-01-30 14:48:53 -08:00
_targetBedTemperature = value ;
2018-02-01 14:51:44 -08:00
if ( this . IsConnected )
2015-04-08 15:20:10 -07:00
{
2018-01-30 14:48:53 -08:00
QueueLine ( "M140 S{0}" . FormatWith ( _targetBedTemperature ) ) ;
2015-04-08 15:20:10 -07:00
}
2019-04-26 15:53:02 -07:00
2019-03-18 14:12:09 -07:00
BedTargetTemperatureChanged ? . Invoke ( this , null ) ;
2015-04-08 15:20:10 -07:00
}
}
}
2019-03-01 19:38:59 -08:00
public int TotalLayersInPrint = > gCodeFileSwitcher ? . GCodeFile ? . LayerCount ? ? - 1 ;
2018-01-05 11:46:07 -08:00
2019-03-01 19:38:59 -08:00
private int NumberOfLinesInCurrentPrint = > gCodeFileSwitcher ? . GCodeFile ? . LineCount ? ? - 1 ;
2015-04-08 15:20:10 -07:00
public int TotalSecondsInPrint
{
get
{
2019-03-01 19:38:59 -08:00
if ( gCodeFileSwitcher ? . GCodeFile ? . LineCount > 0 )
2015-04-08 15:20:10 -07:00
{
2018-01-06 13:26:28 -08:00
if ( this . FeedRateRatio ! = 0 )
2015-04-08 15:20:10 -07:00
{
2019-03-01 19:38:59 -08:00
return ( int ) ( gCodeFileSwitcher . GCodeFile . TotalSecondsInPrint / this . FeedRateRatio ) ;
2015-04-08 15:20:10 -07:00
}
2019-04-26 15:53:02 -07:00
return ( int ) gCodeFileSwitcher . GCodeFile . TotalSecondsInPrint ;
2015-04-08 15:20:10 -07:00
}
return 0 ;
}
}
2018-12-05 13:48:25 -08:00
public PrinterConfig Printer { get ; }
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
public void ReleaseAndReportFailedConnection ( ConnectionFailure reason )
2017-12-30 13:45:13 -08:00
{
2016-01-05 14:31:17 -08:00
// Shutdown the serial port
2019-05-02 20:41:16 -07:00
if ( serialPort ! = null )
2015-04-08 15:20:10 -07:00
{
// Close and dispose the serial port
2019-05-02 20:41:16 -07:00
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
serialPort = null ;
2015-04-08 15:20:10 -07:00
}
// Notify
2019-04-26 15:53:02 -07:00
OnConnectionFailed ( reason ) ;
2015-04-08 15:20:10 -07:00
}
2018-11-09 08:57:30 -08:00
public void BedTemperatureWasWritenToPrinter ( string line )
2015-04-08 15:20:10 -07:00
{
2018-11-09 08:57:30 -08:00
string [ ] splitOnS = line . Split ( 'S' ) ;
2015-04-08 15:20:10 -07:00
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
2018-01-30 14:48:53 -08:00
_targetBedTemperature = tempBeingSet ;
2019-03-18 14:12:09 -07:00
BedTargetTemperatureChanged ? . Invoke ( this , null ) ;
2015-04-08 15:20:10 -07:00
}
}
2018-11-09 08:57:30 -08:00
catch
2015-04-08 15:20:10 -07:00
{
}
}
}
2018-01-06 12:00:14 -08:00
public void Connect ( )
2015-04-08 15:20:10 -07:00
{
2017-12-13 08:46:11 -08:00
// TODO: Consider adding any conditions that would results in a connection failure to this initial test
// Start the process of requesting permission and exit if permission is not currently granted
2018-01-06 13:26:28 -08:00
if ( ! this . EnableNetworkPrinting
2017-12-13 08:46:11 -08:00
& & ! FrostedSerialPort . EnsureDeviceAccess ( ) )
{
// TODO: Consider calling OnConnectionFailed as we do below to fire events that indicate connection failed
CommunicationState = CommunicationStates . FailedToConnect ;
return ;
}
2015-04-08 15:20:10 -07:00
2017-12-13 08:46:11 -08:00
TerminalLog . Clear ( ) ;
2019-03-27 13:19:58 -07:00
// Attempt connecting to a specific printer
2017-12-13 08:46:11 -08:00
this . FirmwareType = FirmwareTypes . Unknown ;
2016-07-28 19:02:45 -07:00
2017-12-13 08:46:11 -08:00
// On Android, there will never be more than one serial port available for us to connect to. Override the current .ComPort value to account for
// this aspect to ensure the validation logic that verifies port availability/in use status can proceed without additional workarounds for Android
2016-07-28 19:02:45 -07:00
#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
2018-12-05 14:14:08 -08:00
Printer . Settings ? . Helpers . SetComPort ( currentPortName ) ;
2016-07-28 19:02:45 -07:00
}
#endif
2017-12-13 08:46:11 -08:00
if ( SerialPortIsAvailable ( this . ComPort ) )
{
2019-04-26 15:53:02 -07:00
// Create and start connection thread
2017-12-13 08:49:06 -08:00
Task . Run ( ( ) = >
{
2017-12-13 09:04:34 -08:00
Thread . CurrentThread . CurrentCulture = CultureInfo . InvariantCulture ;
// Allow the user to set the appropriate properties.
var portNames = FrostedSerialPort . GetPortNames ( ) ;
2019-04-26 15:53:02 -07:00
// Debug.WriteLine("Open ports: {0}".FormatWith(portNames.Length));
2017-12-13 09:04:34 -08:00
if ( portNames . Length > 0 | | IsNetworkPrinting ( ) )
{
2017-12-13 09:22:30 -08:00
// AttemptToConnect {{
{
string serialPortName = this . ComPort ;
int baudRate = this . BaudRate ;
// make sure we don't have a left over print task
2019-04-26 15:53:02 -07:00
ActivePrintTask = null ;
2017-12-13 09:22:30 -08:00
2018-02-01 14:51:44 -08:00
if ( this . IsConnected )
2017-12-13 09:22:30 -08:00
{
2017-12-30 11:49:17 -08:00
this . OnConnectionFailed ( ConnectionFailure . AlreadyConnected ) ;
return ;
2017-12-13 09:22:30 -08:00
}
var portFactory = FrostedSerialPortFactory . GetAppropriateFactory ( this . DriverType ) ;
2018-12-05 13:48:25 -08:00
bool serialPortIsAvailable = portFactory . SerialPortIsAvailable ( serialPortName , Printer . Settings ) ;
2017-12-13 09:22:30 -08:00
bool serialPortIsAlreadyOpen = this . ComPort ! = "Emulator" & &
portFactory . SerialPortAlreadyOpen ( serialPortName ) ;
if ( serialPortIsAvailable & & ! serialPortIsAlreadyOpen )
{
2018-02-01 14:51:44 -08:00
if ( ! this . IsConnected )
2017-12-13 09:22:30 -08:00
{
try
{
2019-04-05 17:11:05 -07:00
// AttemptingToConnect must come before we open the port, as TcipSerialPort does not return immediately and
// we're actually doing the bulk of the connection time in CreateAndOpen
CommunicationState = CommunicationStates . AttemptingToConnect ;
2019-05-02 20:41:16 -07:00
serialPort = portFactory . CreateAndOpen ( serialPortName , Printer . Settings , baudRate , true ) ;
2017-12-13 09:22:30 -08:00
#if __ANDROID__
2018-12-15 08:53:46 -08:00
ToggleHighLowHigh ( serialPort ) ;
2017-12-13 09:22:30 -08:00
#endif
2017-12-30 07:50:13 -08:00
// TODO: Review and reconsider the cases where this was required
2017-12-13 09:22:30 -08:00
// wait a bit of time to let the firmware start up
2019-04-26 15:53:02 -07:00
// Thread.Sleep(500);
2017-12-30 07:50:13 -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.
2019-04-08 13:38:20 -07:00
foreach ( var line in ProcessWriteRegexStream . ProcessWriteRegEx ( "M105\n" , this . Printer ) )
{
WriteRaw ( line , line ) ;
}
2017-12-13 09:24:00 -08:00
2017-12-30 07:50:13 -08:00
var sb = new StringBuilder ( ) ;
2017-12-13 09:24:00 -08:00
2017-12-30 07:50:13 -08:00
// Read character data until we see a newline or exceed the MAX_INVALID_CONNECTION_CHARS threshold
while ( true )
2017-12-13 09:24:00 -08:00
{
2018-01-04 17:30:48 -08:00
// Plugins required probing to fill read buffer
2019-05-02 20:41:16 -07:00
var na = serialPort . BytesToRead ;
2018-01-04 17:30:48 -08:00
2017-12-30 07:50:13 -08:00
// Read, sanitize, store
2019-05-02 20:41:16 -07:00
string response = serialPort . ReadExisting ( ) . Replace ( "\r\n" , "\n" ) . Replace ( '\r' , '\n' ) ;
2017-12-30 07:50:13 -08:00
sb . Append ( response ) ;
bool hasNewline = response . Contains ( '\n' ) ;
if ( hasNewline | | response . Contains ( '?' ) )
2017-12-13 09:24:00 -08:00
{
2017-12-30 07:50:13 -08:00
int invalidCharactersOnFirstLine = sb . ToString ( ) . Split ( '?' ) . Length - 1 ;
if ( hasNewline
2019-04-26 15:53:02 -07:00
& & invalidCharactersOnFirstLine < = MaxInvalidConnectionChars )
2017-12-30 07:50:13 -08:00
{
2017-12-30 09:31:57 -08:00
// Exit loop, continue with connect
2017-12-30 07:50:13 -08:00
break ;
}
2019-04-26 15:53:02 -07:00
else if ( invalidCharactersOnFirstLine > MaxInvalidConnectionChars )
2017-12-30 07:50:13 -08:00
{
// Abort if we've exceeded the invalid char count
// Force port shutdown and cleanup
2017-12-30 13:45:13 -08:00
ReleaseAndReportFailedConnection ( ConnectionFailure . MaximumErrorsReached ) ;
2017-12-30 07:50:13 -08:00
return ;
}
2017-12-13 09:24:00 -08:00
}
}
2017-12-30 07:50:13 -08:00
// Place all consumed data back in the buffer to be processed by ReadFromPrinter
2017-12-13 09:22:30 -08:00
2018-03-27 09:24:02 -07:00
// Setting connected before calling ReadThread.Start causes the misguided CheckOnPrinter logic to spin up new ReadThreads
/ *
2017-12-30 09:31:57 -08:00
// Switch to connected state when a newline is found and we haven't exceeded the invalid char count
CommunicationState = CommunicationStates . Connected ;
2017-12-30 09:34:09 -08:00
* /
2019-04-25 16:04:24 -07:00
CreateStreamProcessors ( ) ;
2018-01-04 18:29:35 -08:00
2018-03-21 14:20:43 -07:00
TurnOffBedAndExtruders ( TurnOff . Now ) ; // make sure our ui and the printer agree and that the printer is in a known state (not heating).
2017-12-30 09:31:57 -08:00
haveReportedError = false ;
2018-01-06 13:26:28 -08:00
QueueLine ( this . ConnectGCode ) ;
2017-12-30 09:31:57 -08:00
// Call instance event
2018-11-09 13:58:43 -08:00
ConnectionSucceeded ? . Invoke ( this , null ) ;
2017-12-30 09:31:57 -08:00
2022-01-03 18:01:37 -08:00
Console . WriteLine ( "ReadFromPrinter thread created." . Localize ( ) ) ;
2017-12-13 09:22:30 -08:00
ReadThread . Start ( this ) ;
2017-12-30 09:34:09 -08:00
CommunicationState = CommunicationStates . Connected ;
2017-12-13 09:22:30 -08:00
// We do not need to wait for the M105
2018-11-09 08:57:30 -08:00
PrintingCanContinue ( null ) ;
2017-12-13 09:22:30 -08:00
}
2017-12-30 09:31:57 -08:00
catch ( ArgumentOutOfRangeException e )
2017-12-13 09:22:30 -08:00
{
TerminalLog . WriteLine ( "Exception:" + e . Message ) ;
2017-12-30 11:49:17 -08:00
OnConnectionFailed ( ConnectionFailure . UnsupportedBaudRate ) ;
2019-06-18 17:23:15 -07:00
UiThread . RunOnIdle ( ( ) = > {
2022-01-03 18:01:37 -08:00
string message = @"The chosen baud rate is not supported by your operating system. Use a different baud rate, if possible." . Localize ( ) ;
2019-06-18 17:23:15 -07:00
if ( AggContext . OperatingSystem = = OSType . X11 )
{
message + =
@ "
2022-01-03 18:01:37 -08:00
On Linux , MatterControl requires a serial helper library in order to use certain baud rates . It is possible that this component is missing or not installed properly . ".Localize();
2019-06-18 17:23:15 -07:00
}
StyledMessageBox . ShowMessageBox ( message , "Unsupported Baud Rate" . Localize ( ) , useMarkdown : true ) ;
} ) ;
2017-12-13 09:22:30 -08:00
}
2018-12-19 16:43:39 -08:00
catch ( IOException e )
{
TerminalLog . WriteLine ( "Exception:" + e . Message ) ;
OnConnectionFailed ( ConnectionFailure . IOException ) ;
2022-01-03 18:01:37 -08:00
if ( AggContext . OperatingSystem = = OSType . X11 & & e . Message = = "Permission denied" . Localize ( ) )
2018-12-19 16:43:39 -08:00
{
UiThread . RunOnIdle ( ( ) = >
{
2019-06-18 17:23:15 -07:00
string message =
@ "In order for MatterControl to access the serial ports on Linux, you will need to give your user account the appropriate permissions. Run these commands in a terminal to add yourself to the correct group.
2019-04-29 09:13:43 -07:00
2018-12-19 16:43:39 -08:00
Ubuntu / Debian
- - - - - - - - - - - - - -
` ` `
# sudo gpasswd - a $ USER dialout
` ` `
Arch
- - - -
` ` `
# sudo gpasswd - a $ USER uucp
# sudo gpasswd - a $ USER lock
` ` `
2022-01-03 18:01:37 -08:00
You will then need to logout and log back in to the computer for the changes to take effect . ".Localize();
2019-01-03 16:58:05 -08:00
StyledMessageBox . ShowMessageBox ( message , "Permission Denied" . Localize ( ) , useMarkdown : true ) ;
2018-12-19 16:43:39 -08:00
} ) ;
}
2022-01-03 18:01:37 -08:00
else if ( e . Message = = "The semaphore timeout period has expired." . Localize ( ) | | e . Message = = "A device attached to the system is not functioning." . Localize ( ) )
2019-06-18 17:23:15 -07:00
{
UiThread . RunOnIdle ( ( ) = > {
string message =
@ "The operating system has reported that your printer is malfunctioning. MatterControl cannot communicate with it. Contact your printer's manufacturer for assistance.
Details
- - - - - - -
2022-01-03 18:01:37 -08:00
".Localize() + e.Message;
2019-06-18 17:23:15 -07:00
StyledMessageBox . ShowMessageBox ( message , "Hardware Error" . Localize ( ) , useMarkdown : true ) ;
} ) ;
}
else
{
UiThread . RunOnIdle ( ( ) = > {
2021-01-29 17:07:04 -08:00
StyledMessageBox . ShowMessageBox ( e . Message + "\n" + "Attempting to connect again may address the issue." . Localize ( ) , e . GetType ( ) . ToString ( ) ) ;
2019-06-18 17:23:15 -07:00
} ) ;
}
2018-12-19 16:43:39 -08:00
}
2019-04-05 17:12:13 -07:00
catch ( TimeoutException )
{
OnConnectionFailed ( ConnectionFailure . ConnectionTimeout ) ;
2019-06-18 17:23:15 -07:00
UiThread . RunOnIdle ( ( ) = >
{
string message =
@ "MatterControl tried to communicate with your printer, but never received a response.
2022-01-03 18:01:37 -08:00
Make sure that your printer is turned on . Some printers will appear to be connected , even when they are turned off . ".Localize();
2019-06-18 17:23:15 -07:00
StyledMessageBox . ShowMessageBox ( message , "Connection Timeout" . Localize ( ) , useMarkdown : true ) ;
} ) ;
2019-04-05 17:12:13 -07:00
}
2017-12-13 09:22:30 -08:00
catch ( Exception ex )
{
TerminalLog . WriteLine ( "Exception:" + ex . Message ) ;
2017-12-30 11:49:17 -08:00
OnConnectionFailed ( ConnectionFailure . Unknown ) ;
2019-06-18 17:23:15 -07:00
UiThread . RunOnIdle ( ( ) = > {
StyledMessageBox . ShowMessageBox ( ex . Message , ex . GetType ( ) . ToString ( ) ) ;
} ) ;
2017-12-13 09:22:30 -08:00
}
}
}
else
{
2017-12-30 11:49:17 -08:00
if ( serialPortIsAlreadyOpen )
{
OnConnectionFailed ( ConnectionFailure . PortInUse ) ;
2019-06-18 17:23:15 -07:00
UiThread . RunOnIdle ( ( ) = >
{
2022-01-03 18:01:37 -08:00
string message = @"MatterControl cannot connect to your printer because another program on your computer is already connected. Close or disconnect any other 3D printing programs or other programs which access serial ports and try again." . Localize ( ) ;
2019-06-18 17:23:15 -07:00
StyledMessageBox . ShowMessageBox ( message , "Port In Use" . Localize ( ) , useMarkdown : true ) ;
} ) ;
2017-12-30 11:49:17 -08:00
}
else
{
OnConnectionFailed ( ConnectionFailure . PortUnavailable ) ;
}
2017-12-13 09:22:30 -08:00
}
}
// AttemptToConnect }}
2017-12-13 09:04:34 -08:00
if ( CommunicationState = = CommunicationStates . FailedToConnect )
{
2017-12-30 11:49:17 -08:00
OnConnectionFailed ( ConnectionFailure . FailedToConnect ) ;
2017-12-13 09:04:34 -08:00
}
}
else
{
2017-12-30 11:49:17 -08:00
OnConnectionFailed ( ConnectionFailure . PortUnavailable ) ;
2017-12-13 09:04:34 -08:00
}
2017-12-13 08:49:06 -08:00
} ) ;
2017-12-13 08:46:11 -08:00
}
else
{
2019-04-26 15:53:02 -07:00
OnConnectionFailed ( ConnectionFailure . PortUnavailable ) ;
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.
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Register ( "File deleted:" , FileDeleteConfirmed ) ;
2015-04-08 15:20:10 -07:00
// and send the line to delete the file
2018-01-04 17:30:48 -08:00
QueueLine ( "M30 {0}" . FormatWith ( fileName . ToLower ( ) ) ) ;
2015-04-08 15:20:10 -07:00
}
2018-11-16 14:45:22 -08:00
/// <summary>
2018-11-29 13:41:24 -08:00
/// Disable the currently active printer connection and job if it is being actively controlled by MC
2018-11-16 14:45:22 -08:00
/// If we are observing an SD card print, do nothing.
/// </summary>
2015-04-08 15:20:10 -07:00
public void Disable ( )
{
2019-02-22 09:23:45 -08:00
if ( this . CommunicationState = = CommunicationStates . PrintingFromSd
2019-02-06 10:34:19 -08:00
| | ( this . Paused & & this . PrePauseCommunicationState = = CommunicationStates . PrintingFromSd ) )
2018-11-16 14:45:22 -08:00
{
2018-11-29 13:41:24 -08:00
// don't turn off anything if we are printing from sd
2018-11-16 14:45:22 -08:00
return ;
}
2018-02-01 14:51:44 -08:00
if ( this . IsConnected )
2015-04-08 15:20:10 -07:00
{
// Make sure we send this without waiting for the printer to respond. We want to try and turn off the heaters.
// It may be possible in the future to make this go into the printer queue for assured sending but it means
// the program has to be smart about closing an able to wait until the printer has agreed that it shut off
2016-01-05 14:31:17 -08:00
// the motors and heaters (a good idea and something for the future).
2018-01-04 17:30:48 -08:00
forceImmediateWrites = true ;
2015-04-08 15:20:10 -07:00
ReleaseMotors ( ) ;
2018-03-21 14:20:43 -07:00
TurnOffBedAndExtruders ( TurnOff . Now ) ;
2020-05-05 09:26:09 -07:00
2018-01-04 17:30:48 -08:00
forceImmediateWrites = false ;
2015-04-08 15:20:10 -07:00
CommunicationState = CommunicationStates . Disconnecting ;
2019-04-29 09:13:43 -07:00
currentReadThreadIndex + + ;
2021-09-10 17:52:07 -07:00
// protect against multi-threading
var localSerialPort = serialPort ;
if ( localSerialPort ! = null )
2015-04-08 15:20:10 -07:00
{
2021-09-10 17:52:07 -07:00
localSerialPort . Close ( ) ;
localSerialPort . Dispose ( ) ;
2015-04-08 15:20:10 -07:00
}
2019-04-26 15:53:02 -07:00
2019-05-02 20:41:16 -07:00
serialPort = null ;
2015-04-08 15:20:10 -07:00
}
else
{
2019-04-26 15:53:02 -07:00
// Need to reset UI - even if manual disconnect
2018-03-21 14:20:43 -07:00
TurnOffBedAndExtruders ( TurnOff . Now ) ;
2015-04-08 15:20:10 -07:00
}
2019-04-05 11:46:32 -07:00
CommunicationState = CommunicationStates . Disconnected ;
2015-04-08 15:20:10 -07:00
}
2018-11-09 08:57:30 -08:00
public void HotendTemperatureWasWritenToPrinter ( string line )
2015-04-08 15:20:10 -07:00
{
double tempBeingSet = 0 ;
2018-11-09 08:57:30 -08:00
if ( GCodeFile . GetFirstNumberAfter ( "S" , line , ref tempBeingSet ) )
2015-04-08 15:20:10 -07:00
{
2019-03-18 14:12:09 -07:00
int extruderIndex = 0 ;
if ( GCodeFile . GetFirstNumberAfter ( "T" , line , ref extruderIndex ) )
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
2019-04-26 15:53:02 -07:00
int hotendIndex0Based = Math . Min ( extruderIndex , MaxExtruders - 1 ) ;
2017-09-08 10:23:28 -07:00
targetHotendTemperature [ hotendIndex0Based ] = 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
2018-12-04 13:28:38 -08:00
targetHotendTemperature [ ActiveExtruderIndex ] = tempBeingSet ;
2015-04-08 15:20:10 -07:00
}
2019-04-26 15:53:02 -07:00
2019-03-18 14:12:09 -07:00
HotendTargetTemperatureChanged ? . Invoke ( this , extruderIndex ) ;
2015-04-08 15:20:10 -07:00
}
}
2018-11-09 08:57:30 -08:00
public void FanOffWasWritenToPrinter ( string line )
2015-04-08 15:20:10 -07:00
{
2020-05-05 09:26:09 -07:00
fanSpeed [ 0 ] = 0 ;
2015-04-08 15:20:10 -07:00
OnFanSpeedSet ( null ) ;
}
2018-11-09 08:57:30 -08:00
public void FanSpeedWasWritenToPrinter ( string line )
2015-04-08 15:20:10 -07:00
{
2020-05-05 09:26:09 -07:00
var fanIndex = 0.0 ;
2020-05-05 09:40:41 -07:00
GCodeFile . GetFirstNumberAfter ( "P" , line , ref fanIndex ) ;
2018-11-09 08:57:30 -08:00
string [ ] splitOnS = line . Split ( 'S' ) ;
2015-04-08 15:20:10 -07:00
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 ) ;
2020-05-05 09:26:09 -07:00
if ( GetFanSpeed0To255 ( ( int ) fanIndex ) ! = fanSpeedBeingSet )
2015-04-08 15:20:10 -07:00
{
2020-05-05 09:26:09 -07:00
SetFanSpeed0To255 ( ( int ) fanIndex , fanSpeedBeingSet ) ;
2015-04-08 15:20:10 -07:00
OnFanSpeedSet ( null ) ;
}
}
2016-12-29 13:39:16 -08:00
catch ( Exception )
2015-04-08 15:20:10 -07:00
{
}
}
}
2018-11-09 08:57:30 -08:00
public void FoundStart ( string line )
2015-04-08 15:20:10 -07:00
{
}
2017-09-08 10:23:28 -07:00
public double GetActualHotendTemperature ( int hotendIndex0Based )
2015-04-08 15:20:10 -07:00
{
2019-04-26 15:53:02 -07:00
hotendIndex0Based = Math . Min ( hotendIndex0Based , MaxExtruders - 1 ) ;
2017-09-08 10:23:28 -07:00
return actualHotendTemperature [ hotendIndex0Based ] ;
2015-04-08 15:20:10 -07:00
}
2017-09-08 10:23:28 -07:00
public double GetTargetHotendTemperature ( int hotendIndex0Based )
2015-04-08 15:20:10 -07:00
{
2019-04-26 15:53:02 -07:00
hotendIndex0Based = Math . Min ( hotendIndex0Based , MaxExtruders - 1 ) ;
2017-09-08 10:23:28 -07:00
return targetHotendTemperature [ hotendIndex0Based ] ;
2015-04-08 15:20:10 -07:00
}
public void HaltConnectionThread ( )
{
2018-03-27 09:24:02 -07:00
// TODO: stopTryingToConnect is not longer used by anyone. Likely we need to wire up setting CancellationToken from this context
2019-04-26 15:53:02 -07:00
// this.stopTryingToConnect = true;
2015-04-08 15:20:10 -07:00
}
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
{
2020-05-01 07:51:44 -07:00
if ( axis . HasFlag ( Axis . X ) )
2016-05-11 17:04:30 -07:00
{
command + = " X0" ;
}
2019-04-26 15:53:02 -07:00
2020-05-01 07:51:44 -07:00
if ( axis . HasFlag ( Axis . Y ) )
2016-05-11 17:04:30 -07:00
{
command + = " Y0" ;
}
2019-04-26 15:53:02 -07:00
2020-05-01 07:51:44 -07:00
if ( axis . HasFlag ( Axis . Z ) )
2016-05-11 17:04:30 -07:00
{
command + = " Z0" ;
}
2020-05-01 07:51:44 -07:00
if ( axis . HasFlag ( Axis . C ) )
{
command + = " C0" ;
}
2015-04-08 15:20:10 -07:00
}
2018-01-04 17:30:48 -08:00
QueueLine ( command ) ;
2015-04-08 15:20:10 -07:00
}
public void MoveAbsolute ( Axis axis , double axisPositionMm , double feedRateMmPerMinute )
{
SetMovementToAbsolute ( ) ;
2018-01-04 17:30:48 -08:00
QueueLine ( "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 ( ) ;
2018-01-04 17:30:48 -08:00
QueueLine ( "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
2019-05-07 14:47:43 -07:00
bool requiresToolChange = extruderNumber ! = ActiveExtruderIndex ;
2016-01-27 15:02:01 -08:00
2015-04-08 15:20:10 -07:00
SetMovementToRelative ( ) ;
2016-01-27 15:02:01 -08:00
if ( requiresToolChange )
{
2018-12-05 11:48:26 -08:00
var currentExtruderIndex = ActiveExtruderIndex ;
// Set to extrude to use
QueueLine ( $"T{extruderNumber}" ) ;
QueueLine ( $"G1 E{moveAmountMm:0.####} F{feedRateMmPerMinute}" ) ;
// Reset back to previous extruder
QueueLine ( $"T{currentExtruderIndex}" ) ;
2016-01-27 15:02:01 -08:00
}
2018-12-05 11:48:26 -08:00
else
2016-01-27 15:02:01 -08:00
{
2018-12-05 11:48:26 -08:00
QueueLine ( $"G1 E{moveAmountMm:0.####} F{feedRateMmPerMinute}" ) ;
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 ( ) ;
2018-01-04 17:30:48 -08:00
QueueLine ( "G1 {0}{1:0.###} F{2}" . FormatWith ( axis , moveAmountMm , feedRateMmPerMinute ) ) ;
2015-04-08 15:20:10 -07:00
SetMovementToAbsolute ( ) ;
}
}
2019-04-26 15:53:02 -07:00
public void OnConnectionFailed ( ConnectionFailure reason )
2015-04-08 15:20:10 -07:00
{
2017-12-31 14:20:06 -08:00
communicationPossible = false ;
2017-12-30 11:49:17 -08:00
var eventArgs = new ConnectFailedEventArgs ( reason ) ;
2018-11-09 13:50:43 -08:00
ConnectionFailed ? . Invoke ( this , eventArgs ) ;
2015-04-08 15:20:10 -07:00
2017-12-30 13:45:13 -08:00
CommunicationState = CommunicationStates . Disconnected ;
2021-05-18 17:06:37 -07:00
if ( serialPort ! = null )
{
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
}
serialPort = null ;
// make sure we clear out the stream processors
CreateStreamProcessors ( ) ;
2015-04-08 15:20:10 -07:00
}
2018-11-16 16:21:30 -08:00
private void OnIdle ( )
2015-04-08 15:20:10 -07:00
{
2018-02-01 14:51:44 -08:00
if ( this . IsConnected & & ReadThread . NumRunning = = 0 )
2015-04-27 15:42:31 -07:00
{
2017-08-03 15:24:41 -07:00
ReadThread . Start ( this ) ;
2016-04-26 09:20:31 -07:00
}
2015-04-08 15:20:10 -07:00
}
2018-11-09 08:57:30 -08:00
public void PrinterRequestsResend ( string line )
2015-04-08 15:20:10 -07:00
{
2018-11-09 08:57:30 -08:00
if ( ! string . IsNullOrEmpty ( line ) )
2015-04-27 17:05:19 -07:00
{
2016-12-14 15:03:37 -08:00
// 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
{
2018-01-06 13:26:28 -08:00
// asking for the next line don't do anything, continue with sending next instruction
2017-06-07 15:56:02 -07:00
return ;
}
2019-04-26 15:53:02 -07:00
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
2018-11-09 08:57:30 -08:00
PrintingCanContinue ( line ) ;
2016-12-14 15:03:37 -08:00
}
2016-12-02 13:51:58 -08:00
}
2017-06-27 10:14:48 -07:00
if ( currentLineIndexToSend = = allCheckSumLinesSent . Count )
{
2018-01-06 13:26:28 -08:00
// asking for the next line don't do anything, continue with sending next instruction
2017-06-27 10:14:48 -07:00
return ;
}
2017-05-19 14:39:57 -07:00
if ( currentLineIndexToSend > = allCheckSumLinesSent . Count
| | currentLineIndexToSend = = 1 )
2016-12-02 13:51:58 -08:00
{
2018-01-04 17:30:48 -08:00
QueueLine ( "M110 N1" ) ;
2017-05-19 14:39:57 -07:00
allCheckSumLinesSent . SetStartingIndex ( 1 ) ;
waitingForPosition . Reset ( ) ;
2019-02-22 09:23:45 -08:00
PositionReadType = PositionReadType . None ;
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 ;
2018-11-09 08:57:30 -08:00
public void PrinterReportsError ( string line )
2016-01-05 16:48:04 -08:00
{
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
2018-11-09 08:57:30 -08:00
if ( line ! = null )
2016-01-06 12:09:37 -08:00
{
2018-11-09 08:57:30 -08:00
ErrorReported ? . Invoke ( this , line ) ;
2016-01-06 12:09:37 -08:00
}
2018-09-17 14:31:26 -07:00
// pause the printer
2021-03-15 12:27:36 -07:00
this . TerminalLog . WriteLine ( "Pause Due to Error" ) ;
2018-09-17 14:31:26 -07:00
RequestPause ( ) ;
2016-01-05 16:48:04 -08:00
}
}
2018-11-09 08:57:30 -08:00
public void PrinterStatesFirmware ( string line )
2015-04-08 15:20:10 -07:00
{
string firmwareName = "" ;
2018-11-09 08:57:30 -08:00
if ( GCodeFile . GetFirstStringAfter ( "FIRMWARE_NAME:" , line , " " , ref firmwareName ) )
2015-04-08 15:20:10 -07:00
{
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
}
}
2019-04-26 15:53:02 -07:00
2015-04-08 15:20:10 -07:00
string firmwareVersionReported = "" ;
2018-11-09 08:57:30 -08:00
if ( GCodeFile . GetFirstStringAfter ( "MACHINE_TYPE:" , line , " EXTRUDER_COUNT" , ref firmwareVersionReported ) )
2015-04-08 15:20:10 -07:00
{
char splitChar = '^' ;
if ( firmwareVersionReported . Contains ( splitChar ) )
{
string [ ] split = firmwareVersionReported . Split ( splitChar ) ;
2018-01-04 17:30:48 -08:00
if ( split . Length = = 2 )
2015-04-08 15:20:10 -07:00
{
2016-12-29 12:52:12 -08:00
DeviceCode = split [ 0 ] ;
2015-04-08 15:20:10 -07:00
firmwareVersionReported = split [ 1 ] ;
}
}
2019-04-26 15:53:02 -07:00
// 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
2019-04-26 15:53:02 -07:00
// int okCount = 1;
2018-11-09 08:57:30 -08:00
public void PrintingCanContinue ( string line )
2015-04-08 15:20:10 -07:00
{
2019-04-26 15:53:02 -07:00
// if ((okCount++ % 67) != 0)
2015-04-08 15:20:10 -07:00
{
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
2019-05-02 20:41:16 -07:00
if ( serialPort = = null & & this . Printer . Settings ! = null )
2015-04-08 15:20:10 -07:00
{
2018-12-05 13:48:25 -08:00
IFrostedSerialPort resetSerialPort = FrostedSerialPortFactory . GetAppropriateFactory ( this . DriverType ) . Create ( this . ComPort , Printer . Settings ) ;
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
}
}
2017-12-30 07:50:13 -08:00
private string dataLastRead = string . Empty ;
2016-11-04 16:00:54 -07:00
public void ReadFromPrinter ( ReadThread readThreadHolder )
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
2019-05-02 20:41:16 -07:00
| | ( this . IsConnected & & serialPort ! = null & & serialPort . IsOpen & & ! Disconnecting & & readThreadHolder . IsCurrentThread ( ) ) )
2015-04-08 15:20:10 -07:00
{
2018-02-01 14:51:44 -08:00
if ( ( this . IsConnected
2019-04-30 15:51:44 -07:00
| | this . CommunicationState = = CommunicationStates . AttemptingToConnect )
2015-04-08 15:20:10 -07:00
& & CommunicationState ! = CommunicationStates . PrintingFromSd )
{
TryWriteNextLineFromGCodeFile ( ) ;
}
try
{
2019-05-02 20:41:16 -07:00
while ( serialPort ! = null
2022-04-01 11:28:58 -07:00
& & serialPort . IsOpen
2019-05-02 20:41:16 -07:00
& & serialPort . BytesToRead > 0
2015-04-08 15:20:10 -07:00
& & readThreadHolder . IsCurrentThread ( ) )
{
2016-01-14 10:32:25 -08:00
lock ( locker )
{
2019-05-02 20:41:16 -07:00
string allDataRead = serialPort . ReadExisting ( ) ;
2016-10-18 17:29:23 -07:00
allDataRead = allDataRead . Replace ( "\r\n" , "\n" ) ;
allDataRead = allDataRead . Replace ( '\r' , '\n' ) ;
dataLastRead + = allDataRead ;
2018-01-11 13:03:23 -08:00
2015-04-08 15:20:10 -07:00
do
{
int returnPosition = dataLastRead . IndexOf ( '\n' ) ;
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 ( ) ;
}
2019-04-26 15:53:02 -07:00
2015-04-08 15:20:10 -07:00
lastLineRead = dataLastRead . Substring ( 0 , returnPosition ) ;
2019-04-26 15:53:02 -07:00
var ( firstLine , extraLines ) = ProcessReadRegEx ( lastLineRead ) ;
lastLineRead = firstLine ;
dataLastRead + = extraLines ;
2015-04-08 15:20:10 -07:00
dataLastRead = dataLastRead . Substring ( returnPosition + 1 ) ;
// process this command
{
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . ProcessLine ( lastLineRead ) ;
readLineContainsCallBacks . ProcessLine ( lastLineRead ) ;
2016-10-05 14:57:31 -07:00
2018-11-09 11:41:08 -08:00
LineReceived ? . Invoke ( this , lastLineRead ) ;
2015-04-08 15:20:10 -07:00
}
}
2019-04-26 15:53:02 -07:00
}
while ( true ) ;
2015-04-08 15:20:10 -07:00
}
2019-04-26 15:53:02 -07:00
2015-04-08 15:20:10 -07:00
timeSinceLastReadAnything . Restart ( ) ;
}
2019-02-06 10:34:19 -08:00
if ( Printing )
2016-04-06 11:56:48 -07:00
{
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
{
2017-08-03 16:35:22 -07:00
TerminalLog . WriteLine ( "Exception:" + e2 . Message ) ;
2017-12-30 11:49:17 -08:00
OnConnectionFailed ( ConnectionFailure . IOException ) ;
2015-04-08 15:20:10 -07:00
}
catch ( InvalidOperationException ex )
{
2017-08-03 16:35:22 -07:00
TerminalLog . 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.
2017-12-30 11:49:17 -08:00
OnConnectionFailed ( ConnectionFailure . InvalidOperationException ) ;
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
{
2017-08-03 16:35:22 -07:00
TerminalLog . WriteLine ( "Exception:" + e3 . Message ) ;
2017-12-30 11:49:17 -08:00
OnConnectionFailed ( ConnectionFailure . UnauthorizedAccessException ) ;
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
}
2018-12-26 16:56:03 -08:00
2019-04-30 15:51:44 -07:00
Console . WriteLine ( "Exiting ReadFromPrinter method: " + CommunicationState . ToString ( ) ) ;
2022-04-01 16:07:07 -07:00
if ( CommunicationState ! = CommunicationStates . Disconnecting )
2022-04-01 11:28:58 -07:00
{
// we are in an error condition where we have lost the com port
CommunicationState = CommunicationStates . Disconnected ;
}
2015-04-08 15:20:10 -07:00
}
2019-02-22 09:23:45 -08:00
public void ReadPosition ( PositionReadType positionReadType = PositionReadType . Other , bool forceToTopOfQueue = false )
2015-04-08 15:20:10 -07:00
{
2019-04-01 15:51:39 -07:00
var nextIssue = queuedCommandStream . Peek ( ) ;
if ( nextIssue = = null
| | nextIssue ! = "M114" )
2019-04-01 08:46:05 -07:00
{
QueueLine ( "M114" , forceToTopOfQueue ) ;
PositionReadType = positionReadType ;
}
2015-04-08 15:20:10 -07:00
}
2018-11-09 08:57:30 -08:00
public void ReadSdProgress ( string line )
2015-04-08 15:20:10 -07:00
{
2019-02-22 09:23:45 -08:00
if ( line ! = null )
2015-04-08 15:20:10 -07:00
{
2018-11-09 08:57:30 -08:00
string sdProgressString = line . Substring ( "Sd printing byte " . Length ) ;
2015-04-08 15:20:10 -07:00
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 ( ) ;
}
2018-11-09 08:57:30 -08:00
public void ReadTargetPositions ( string line )
2015-04-08 15:20:10 -07:00
{
2018-11-09 08:57:30 -08:00
GCodeFile . GetFirstNumberAfter ( "X:" , line , ref lastReportedPosition . position . X ) ;
GCodeFile . GetFirstNumberAfter ( "Y:" , line , ref lastReportedPosition . position . Y ) ;
GCodeFile . GetFirstNumberAfter ( "Z:" , line , ref lastReportedPosition . position . Z ) ;
GCodeFile . GetFirstNumberAfter ( "E:" , line , ref lastReportedPosition . extrusion ) ;
2015-04-08 15:20:10 -07:00
2018-11-16 14:22:53 -08:00
currentDestination = lastReportedPosition ;
DestinationChanged ? . Invoke ( this , null ) ;
if ( totalGCodeStream ! = null )
2015-04-08 15:20:10 -07:00
{
2018-11-16 14:22:53 -08:00
totalGCodeStream . SetPrinterPosition ( currentDestination ) ;
2016-01-14 10:32:25 -08:00
}
2015-04-08 15:20:10 -07:00
2019-02-22 09:23:45 -08:00
if ( PositionReadType . HasFlag ( PositionReadType . HomeX ) )
{
HomingPosition = new Vector3 ( lastReportedPosition . position . X , HomingPosition . Y , HomingPosition . Z ) ;
}
2019-04-26 15:53:02 -07:00
2019-02-22 09:23:45 -08:00
if ( PositionReadType . HasFlag ( PositionReadType . HomeY ) )
{
HomingPosition = new Vector3 ( HomingPosition . X , lastReportedPosition . position . Y , HomingPosition . Z ) ;
}
2019-04-26 15:53:02 -07:00
2019-02-22 09:23:45 -08:00
if ( PositionReadType . HasFlag ( PositionReadType . HomeZ ) )
{
HomingPosition = new Vector3 ( HomingPosition . X , HomingPosition . Y , lastReportedPosition . position . Z ) ;
}
2015-04-08 15:20:10 -07:00
waitingForPosition . Reset ( ) ;
2019-02-22 09:23:45 -08:00
PositionReadType = PositionReadType . None ;
2015-04-08 15:20:10 -07:00
}
2017-03-21 14:26:54 -07:00
public static void ParseTemperatureString ( string temperatureString ,
2019-04-26 15:53:02 -07:00
double [ ] actualHotendTemperature ,
Action < TemperatureEventArgs > hotendTemperatureChange ,
ref double actualBedTemperature ,
Action < TemperatureEventArgs > bedTemperatureChanged )
2015-04-08 15:20:10 -07:00
{
{
2017-09-08 10:23:28 -07:00
double readHotendTemp = 0 ;
if ( GCodeFile . GetFirstNumberAfter ( "T:" , temperatureString , ref readHotendTemp ) )
2015-04-08 15:20:10 -07:00
{
2017-09-08 10:23:28 -07:00
if ( actualHotendTemperature [ 0 ] ! = readHotendTemp )
2015-04-08 15:20:10 -07:00
{
2017-09-08 10:23:28 -07:00
actualHotendTemperature [ 0 ] = readHotendTemp ;
hotendTemperatureChange ? . Invoke ( new TemperatureEventArgs ( 0 , readHotendTemp ) ) ;
2015-04-08 15:20:10 -07:00
}
}
2019-04-26 15:53:02 -07:00
for ( int hotendIndex = 0 ; hotendIndex < MaxExtruders ; hotendIndex + + )
2015-04-08 15:20:10 -07:00
{
2017-09-08 10:23:28 -07:00
string multiExtruderCheck = "T{0}:" . FormatWith ( hotendIndex ) ;
if ( GCodeFile . GetFirstNumberAfter ( multiExtruderCheck , temperatureString , ref readHotendTemp ) )
2015-04-08 15:20:10 -07:00
{
2017-09-08 10:23:28 -07:00
if ( actualHotendTemperature [ hotendIndex ] ! = readHotendTemp )
2015-04-08 15:20:10 -07:00
{
2017-09-08 10:23:28 -07:00
actualHotendTemperature [ hotendIndex ] = readHotendTemp ;
hotendTemperatureChange ? . Invoke ( new TemperatureEventArgs ( hotendIndex , readHotendTemp ) ) ;
2015-04-08 15:20:10 -07:00
}
}
else
{
2018-11-29 17:45:16 -08:00
continue ;
2015-04-08 15:20:10 -07:00
}
}
}
2019-04-26 15:53:02 -07:00
2015-04-08 15:20:10 -07:00
{
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
}
}
}
}
2018-11-09 08:57:30 -08:00
public void ReadTemperatures ( string line )
2017-03-21 14:26:54 -07:00
{
2018-11-09 08:57:30 -08:00
ParseTemperatureString (
line ,
actualHotendTemperature ,
OnHotendTemperatureRead ,
ref actualBedTemperature ,
OnBedTemperatureRead ) ;
2017-03-21 14:26:54 -07:00
}
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
{
2018-12-05 13:48:25 -08:00
if ( Printer . Settings . PrinterSelected )
2015-06-10 10:19:25 -07:00
{
// first make sure we are not printing if possible (cancel slicing)
2019-05-02 20:41:16 -07:00
if ( serialPort ! = null ) // we still have a serial port
2015-06-10 10:19:25 -07:00
{
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 ;
2019-04-29 09:13:43 -07:00
currentReadThreadIndex + + ;
2019-05-02 20:41:16 -07:00
ToggleHighLowHigh ( serialPort ) ;
if ( serialPort ! = null )
2017-02-07 18:49:06 -08:00
{
2019-05-02 20:41:16 -07:00
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
2017-02-07 18:49:06 -08:00
}
2019-04-26 15:53:02 -07:00
2019-05-02 20:41:16 -07:00
serialPort = null ;
2017-02-09 13:51:16 -08:00
// make sure we clear out the stream processors
2019-04-25 16:04:24 -07:00
CreateStreamProcessors ( ) ;
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-09-18 07:20:06 -07:00
Connect ( ) ;
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
2018-12-05 13:48:25 -08:00
var resetSerialPort = FrostedSerialPortFactory . GetAppropriateFactory ( this . DriverType ) . Create ( this . ComPort , Printer . Settings ) ;
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 ( ) ;
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
}
2017-12-03 14:40:50 -08:00
public void ReleaseMotors ( bool forceRelease = false )
2015-04-08 15:20:10 -07:00
{
2017-12-03 14:40:50 -08:00
if ( forceRelease
2018-01-06 13:26:28 -08:00
| | this . AutoReleaseMotors )
2017-12-03 14:40:50 -08:00
{
2018-01-04 17:30:48 -08:00
QueueLine ( "M84" ) ;
2017-12-03 14:40:50 -08:00
}
2015-04-08 15:20:10 -07:00
}
2015-11-28 07:46:57 -08:00
public void RequestPause ( )
2015-04-08 15:20:10 -07:00
{
2019-02-06 10:34:19 -08:00
if ( Printing )
2015-04-08 15:20:10 -07:00
{
if ( CommunicationState = = CommunicationStates . PrintingFromSd )
{
CommunicationState = CommunicationStates . Paused ;
2018-01-04 17:30:48 -08:00
QueueLine ( "M25" ) ; // : Pause SD print
2015-04-08 15:20:10 -07:00
return ;
}
2019-03-01 19:38:59 -08:00
pauseHandlingStream . 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 ( )
{
2019-02-06 10:34:19 -08:00
if ( Paused )
2015-04-08 15:20:10 -07:00
{
2017-03-07 17:52:44 -08:00
if ( PrePauseCommunicationState = = CommunicationStates . PrintingFromSd )
2015-04-08 15:20:10 -07:00
{
CommunicationState = CommunicationStates . PrintingFromSd ;
2018-01-04 17:30:48 -08:00
QueueLine ( "M24" ) ; // Start/resume SD print
2015-04-08 15:20:10 -07:00
}
else
{
2019-03-01 19:38:59 -08:00
pauseHandlingStream . Resume ( ) ;
2015-04-08 15:20:10 -07:00
CommunicationState = CommunicationStates . Printing ;
}
}
}
2018-01-04 17:30:48 -08:00
public void QueueLine ( 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" ) ;
}
2019-04-26 15:53:02 -07: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 ) ;
2018-06-25 21:45:09 -07:00
for ( int i = 0 ; i < linesToWrite . Length ; i + + )
{
string line = linesToWrite [ i ] . Trim ( ) ;
if ( line . Length > 0 )
{
QueueLine ( line ) ;
}
}
2019-04-26 15:53:02 -07:00
2015-04-08 15:20:10 -07:00
return ;
}
2016-11-04 16:00:54 -07:00
if ( CommunicationState = = CommunicationStates . PrintingFromSd
2018-01-04 17:30:48 -08:00
| | forceImmediateWrites )
2015-04-08 15:20:10 -07:00
{
2016-11-04 16:00:54 -07:00
lineToWrite = lineToWrite . Split ( ';' ) [ 0 ] . Trim ( ) ;
2018-12-20 16:00:27 -08:00
if ( lineToWrite . 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).
2018-01-04 17:30:48 -08:00
WriteRaw ( 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
2019-03-01 19:38:59 -08:00
queuedCommandStream ? . Add ( lineToWrite , forceTopOfQueue ) ;
2015-04-08 15:20:10 -07:00
}
}
}
}
2018-01-11 13:03:23 -08:00
private ( string firstLine , string extraLines ) ProcessReadRegEx ( string lineBeingRead )
2017-06-29 09:47:34 -07:00
{
2017-12-15 16:18:28 -08:00
var addedLines = new List < string > ( ) ;
2018-01-06 16:03:03 -08:00
foreach ( var item in readLineReplacements )
2017-06-29 09:47:34 -07:00
{
2017-12-15 16:18:28 -08:00
var splitReplacement = item . Replacement . Split ( ',' ) ;
if ( splitReplacement . Length > 0 )
{
if ( item . Regex . IsMatch ( lineBeingRead ) )
{
// replace on the first replacement group only
var replacedString = item . Regex . Replace ( lineBeingRead , splitReplacement [ 0 ] ) ;
lineBeingRead = replacedString ;
// add in the other replacement groups
for ( int j = 1 ; j < splitReplacement . Length ; j + + )
{
addedLines . Add ( splitReplacement [ j ] ) ;
}
2019-04-26 15:53:02 -07:00
2017-12-15 16:18:28 -08:00
break ;
}
}
2017-06-29 09:47:34 -07:00
}
2018-01-11 13:03:23 -08:00
string extraLines = "" ;
2019-02-22 09:23:45 -08:00
foreach ( var line in addedLines )
2018-01-11 13:03:23 -08:00
{
extraLines + = line + "\n" ;
}
2017-12-15 16:18:28 -08:00
2018-01-11 13:03:23 -08:00
return ( lineBeingRead , extraLines ) ;
2017-06-29 09:47:34 -07:00
}
2019-03-27 13:19:58 -07:00
// Check is serial port is in the list of available serial ports
2015-04-08 15:20:10 -07:00
public bool SerialPortIsAvailable ( string portName )
{
2017-04-11 10:41:23 -07:00
if ( IsNetworkPrinting ( ) )
2016-07-29 14:48:41 -07:00
{
return true ;
}
2019-03-27 13:19:58 -07:00
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 ( )
{
2018-01-04 17:30:48 -08:00
QueueLine ( "G90" ) ;
2015-04-08 15:20:10 -07:00
}
public void SetMovementToRelative ( )
{
2018-01-04 17:30:48 -08:00
QueueLine ( "G91" ) ;
2015-04-08 15:20:10 -07:00
}
2017-09-08 10:23:28 -07:00
public void SetTargetHotendTemperature ( int hotendIndex0Based , double temperature , bool forceSend = false )
2015-04-08 15:20:10 -07:00
{
2019-04-26 15:53:02 -07:00
hotendIndex0Based = Math . Min ( hotendIndex0Based , MaxExtruders - 1 ) ;
2015-04-08 15:20:10 -07:00
2017-09-08 10:23:28 -07:00
if ( targetHotendTemperature [ hotendIndex0Based ] ! = temperature
2016-07-25 12:29:43 -07:00
| | forceSend )
2015-04-08 15:20:10 -07:00
{
2019-03-19 13:13:14 -07:00
ContinueHoldingTemperature = false ;
2017-09-08 10:23:28 -07:00
targetHotendTemperature [ hotendIndex0Based ] = temperature ;
2018-02-01 14:51:44 -08:00
if ( this . IsConnected )
2015-04-08 15:20:10 -07:00
{
2018-01-04 17:30:48 -08:00
QueueLine ( "M104 T{0} S{1}" . FormatWith ( hotendIndex0Based , targetHotendTemperature [ hotendIndex0Based ] ) ) ;
2015-04-08 15:20:10 -07:00
}
2019-04-26 15:53:02 -07:00
2019-03-18 14:12:09 -07:00
HotendTargetTemperatureChanged ? . Invoke ( this , hotendIndex0Based ) ;
2015-04-08 15:20:10 -07:00
}
}
2021-06-24 10:36:32 -07:00
public PrintingModes PrintingMode { get ; private set ; }
2019-04-26 15:53:02 -07:00
2021-06-24 10:36:32 -07:00
public enum PrintingModes
{
Normal ,
Calibration ,
2021-10-19 10:30:09 -07:00
Autopilot ,
2021-06-24 10:36:32 -07:00
}
public async Task StartPrint ( string gcodeFilename , PrintTask printTaskToUse = null , PrintingModes printingMode = PrintingModes . Normal )
2019-03-23 18:37:53 -07:00
{
var gcodeStream = new StreamReader ( gcodeFilename ) ;
2021-06-24 10:36:32 -07:00
await StartPrint ( gcodeStream . BaseStream , gcodeFilename , printTaskToUse , printingMode ) ;
2019-03-23 18:37:53 -07:00
}
2021-06-24 10:36:32 -07:00
public async Task StartPrint ( Stream gcodeStream , string gcodeFileNameForTask , PrintTask printTaskToUse , PrintingModes printingMode )
2015-04-08 15:20:10 -07:00
{
2019-02-06 10:34:19 -08:00
if ( ! this . IsConnected | | Printing )
2015-04-08 15:20:10 -07:00
{
return ;
}
2021-06-24 10:36:32 -07:00
this . PrintingMode = printingMode ;
2019-04-20 21:56:11 -07:00
2016-11-09 09:22:19 -08:00
haveReportedError = false ;
2017-02-01 17:36:33 -08:00
PrintWasCanceled = false ;
2021-08-25 17:57:22 -07:00
cancelPrintNextWriteLine = false ;
2017-02-01 17:36:33 -08:00
2017-02-02 13:37:03 -08:00
waitingForPosition . Reset ( ) ;
2019-02-22 09:23:45 -08:00
PositionReadType = PositionReadType . None ;
2015-04-08 15:20:10 -07:00
ClearQueuedGCode ( ) ;
2019-04-26 15:53:02 -07:00
ActivePrintTask = printTaskToUse ;
2021-09-15 17:44:24 -07:00
CanceledPrintTask = null ;
2015-04-08 15:20:10 -07:00
2016-04-14 18:01:45 -07:00
await Task . Run ( ( ) = >
{
2018-01-16 08:17:24 -08:00
// LoadGCodeToPrint
2019-04-26 15:53:02 -07:00
CreateStreamProcessors ( gcodeStream ) ;
2016-04-14 18:01:45 -07:00
} ) ;
2018-01-16 08:14:04 -08:00
// DoneLoadingGCodeToPrint
2019-04-30 15:51:44 -07:00
switch ( this . CommunicationState )
2018-01-16 08:14:04 -08:00
{
case CommunicationStates . Connected :
// This can happen if the printer is reset during the slicing of the part.
break ;
case CommunicationStates . PreparingToPrint :
{
2019-03-25 14:23:45 -07:00
if ( gcodeFileNameForTask ! = null )
{
string filePath = this . Printer . Bed . EditContext . SourceFilePath ;
string fileName = Path . GetFileName ( filePath ) ;
2018-12-05 17:07:55 -08:00
2019-03-25 14:23:45 -07:00
var activePrintItem = new PrintItemWrapper ( new PrintItem ( fileName , filePath ) ) ;
2018-12-05 17:07:55 -08:00
2019-03-25 14:23:45 -07:00
if ( activePrintItem . PrintItem . Id = = 0 )
{
activePrintItem . PrintItem . Commit ( ) ;
}
2018-01-16 08:14:04 -08:00
2019-03-25 14:23:45 -07:00
if ( gcodeFileNameForTask ! = null
2019-04-26 15:53:02 -07:00
& & ActivePrintTask = = null
2021-06-24 10:36:32 -07:00
& & PrintingMode ! = PrintingModes . Calibration )
2018-01-16 08:14:04 -08:00
{
2019-03-25 14:23:45 -07:00
// TODO: Fix printerItemID int requirement
2019-04-26 15:53:02 -07:00
ActivePrintTask = new PrintTask
2019-03-25 14:23:45 -07:00
{
PrintStart = DateTime . Now ,
PrinterId = this . Printer . Settings . ID . GetHashCode ( ) ,
PrintName = activePrintItem . PrintItem . Name ,
2022-01-27 16:49:46 -08:00
PrinterName = this . Printer . PrinterName ,
2020-10-23 16:57:26 -07:00
Guid = Guid . NewGuid ( ) . ToString ( ) ,
2019-03-25 14:23:45 -07:00
PrintingGCodeFileName = gcodeFileNameForTask ,
2020-07-11 19:28:30 -07:00
PrintComplete = false ,
QualitySettingsName = this . Printer . Settings . QualityLayer ? . Name ,
MaterialSettingsName = this . Printer . Settings . MaterialLayer ? . Name ,
2020-10-23 16:57:26 -07:00
DeviceToken = this . Printer . Settings . GetValue ( SettingsKey . device_token ) ,
2019-03-25 14:23:45 -07:00
} ;
2018-01-16 08:14:04 -08:00
2021-06-29 11:24:19 -07:00
if ( gCodeFileSwitcher ? . GCodeFile is GCodeMemoryFile memoryFile )
{
ActivePrintTask . VolumeMm3 = memoryFile . GetFilamentCubicMm ( Printer . Settings . GetValue < double > ( SettingsKey . filament_diameter ) ) ;
}
2020-10-23 16:57:26 -07:00
ActivePrintTask . CommitAndPushToServer ( ) ;
2018-01-16 08:42:35 -08:00
2021-09-15 17:44:24 -07:00
Task . Run ( ( ) = > this . SyncProgressToDB ( ) ) ;
2020-07-03 12:05:28 -07:00
PrintStarted ? . Invoke ( this , null ) ;
2019-03-25 14:23:45 -07:00
}
2018-01-16 08:14:04 -08:00
}
}
CommunicationState = CommunicationStates . Printing ;
break ;
default :
#if DEBUG
throw new Exception ( "We are not preparing to print so we should not be starting to print" ) ;
2019-04-26 15:53:02 -07:00
#else
2018-01-16 08:14:04 -08:00
break ;
2019-04-26 15:53:02 -07:00
#endif
2018-01-16 08:14:04 -08:00
}
2015-04-08 15:20:10 -07:00
}
2017-09-23 09:19:32 -07:00
public bool StartSdCardPrint ( string m23FileName )
2015-04-08 15:20:10 -07:00
{
2018-02-01 14:51:44 -08:00
if ( ! this . IsConnected
2019-02-06 10:34:19 -08:00
| | Printing
2017-09-23 09:19:32 -07:00
| | string . IsNullOrEmpty ( m23FileName ) )
2015-04-08 15:20:10 -07:00
{
return false ;
}
currentSdBytes = 0 ;
ClearQueuedGCode ( ) ;
CommunicationState = CommunicationStates . PrintingFromSd ;
2018-01-04 17:30:48 -08:00
QueueLine ( $"M23 {m23FileName.ToLower()}" ) ; // Select SD File
QueueLine ( "M24" ) ; // Start/resume SD print
2015-04-08 15:20:10 -07:00
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Register ( "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-09-16 10:59:23 -07:00
if ( PrePauseCommunicationState = = CommunicationStates . PrintingFromSd )
2015-04-08 15:20:10 -07:00
{
2017-09-16 10:59:23 -07:00
CancelSDCardPrint ( ) ;
CommunicationState = CommunicationStates . Connected ;
}
else
{
CancelPrint ( markPrintCanceled ) ;
// We have to continue printing the end gcode, so we set this to Printing.
CommunicationState = CommunicationStates . Printing ;
2015-04-08 15:20:10 -07:00
}
2019-04-26 15:53:02 -07:00
2015-04-08 15:20:10 -07:00
break ;
case CommunicationStates . AttemptingToConnect :
CommunicationState = CommunicationStates . FailedToConnect ;
2019-04-26 15:53:02 -07:00
// connectThread.Join(JoinThreadTimeoutMs);
2017-12-13 08:49:06 -08:00
2015-04-08 15:20:10 -07:00
CommunicationState = CommunicationStates . Disconnecting ;
2019-04-29 09:13:43 -07:00
currentReadThreadIndex + + ;
2019-05-02 20:41:16 -07:00
if ( serialPort ! = null )
2015-04-08 15:20:10 -07:00
{
2019-05-02 20:41:16 -07:00
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
serialPort = null ;
2015-04-08 15:20:10 -07:00
}
2019-04-26 15:53:02 -07:00
2015-04-08 15:20:10 -07:00
CommunicationState = CommunicationStates . Disconnected ;
break ;
case CommunicationStates . PreparingToPrint :
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
{
2021-09-15 17:44:24 -07:00
TerminalLog . WriteLine ( "Print Canceled" ) ;
// Flag as canceled
this . cancelPrintNextWriteLine = true ;
2018-01-06 13:26:28 -08:00
2021-02-24 16:56:37 -08:00
CancelInProgressStreamProcessors ( ) ;
2015-04-13 12:28:33 -07:00
// get rid of all the gcode we have left to print
ClearQueuedGCode ( ) ;
2018-01-06 13:26:28 -08:00
if ( ! string . IsNullOrEmpty ( this . CancelGCode ) )
2015-04-13 12:28:33 -07:00
{
// add any gcode we want to print while canceling
2018-01-06 13:26:28 -08:00
QueueLine ( this . CancelGCode ) ;
2015-04-13 12:28:33 -07:00
}
2019-04-26 15:53:02 -07:00
2015-12-31 09:40:17 -08:00
// let the process know we canceled not ended normally.
2021-02-09 16:54:31 -08:00
CanceleRequested ? . Invoke ( this , null ) ;
2016-12-01 10:59:03 -08:00
if ( markPrintCanceled
2019-04-26 15:53:02 -07:00
& & ActivePrintTask ! = null )
2016-12-01 10:59:03 -08:00
{
2019-04-26 15:53:02 -07:00
TimeSpan printTimeSpan = DateTime . Now . Subtract ( ActivePrintTask . PrintStart ) ;
2016-12-01 10:59:03 -08:00
2019-04-26 15:53:02 -07:00
ActivePrintTask . PrintEnd = DateTime . Now ;
ActivePrintTask . PrintComplete = false ;
ActivePrintTask . PrintingGCodeFileName = "" ;
2020-07-18 14:31:39 -07:00
ActivePrintTask . PrintCanceled = true ;
2020-10-23 16:57:26 -07:00
ActivePrintTask . CommitAndPushToServer ( ) ;
2016-12-01 10:59:03 -08:00
}
// no matter what we no longer have a print task
2020-10-04 22:21:17 -07:00
CanceledPrintTask = ActivePrintTask ;
2019-04-26 15:53:02 -07:00
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 ;
2018-01-04 17:30:48 -08:00
QueueLine ( "M25" ) ; // : Pause SD print
QueueLine ( "M26" ) ; // : Set SD position
2019-02-22 09:23:45 -08:00
// never leave the extruder and the bed hot
2018-11-09 08:57:30 -08:00
DonePrintingSdFile ( null ) ;
2015-04-13 12:28:33 -07:00
}
}
2018-11-09 08:57:30 -08:00
public void SuppressEcho ( string line )
2015-04-08 15:20:10 -07:00
{
2019-04-26 15:53:02 -07:00
// AllowListenerNotification = false;
2015-04-08 15:20:10 -07:00
}
private void ClearQueuedGCode ( )
{
2019-03-01 19:38:59 -08:00
gCodeFileSwitcher ? . GCodeFile ? . Clear ( ) ;
2015-04-08 15:20:10 -07:00
}
2018-11-09 08:57:30 -08:00
private void DonePrintingSdFile ( string line )
2015-04-08 15:20:10 -07:00
{
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Unregister ( "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
2018-03-21 14:20:43 -07:00
TurnOffBedAndExtruders ( TurnOff . Now ) ;
2015-04-08 15:20:10 -07:00
ReleaseMotors ( ) ;
}
2018-11-09 08:57:30 -08:00
private void FileDeleteConfirmed ( string line )
2015-04-08 15:20:10 -07:00
{
2019-04-26 15:53:02 -07:00
readLineStartCallBacks . Unregister ( "File deleted:" , FileDeleteConfirmed ) ;
2018-11-09 08:57:30 -08:00
PrintingCanContinue ( line ) ;
2015-04-08 15:20:10 -07:00
}
2020-12-19 23:14:33 -08:00
public static bool KeepTrackOfAbsolutePositionAndDestination ( string lineBeingSent , ref PrinterMove currentDestination )
2016-01-14 10:32:25 -08:00
{
if ( lineBeingSent . StartsWith ( "G0 " )
| | lineBeingSent . StartsWith ( "G1 " )
| | lineBeingSent . StartsWith ( "G2 " )
| | lineBeingSent . StartsWith ( "G3 " ) )
{
2016-01-19 15:16:05 -08:00
PrinterMove newDestination = currentDestination ;
2015-11-30 12:26:55 -08:00
2017-10-31 12:51:16 -07: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
2018-11-02 16:14:37 -07:00
if ( currentDestination . position ! = newDestination . position
| | currentDestination . extrusion ! = newDestination . extrusion )
2016-01-14 10:32:25 -08:00
{
currentDestination = newDestination ;
2020-12-19 23:14:33 -08:00
return true ;
2016-01-14 10:32:25 -08:00
}
}
2020-12-19 23:14:33 -08:00
return false ;
2016-01-14 10:32:25 -08:00
}
2015-11-30 12:26:55 -08:00
2019-04-26 15:53:02 -07:00
private void CreateStreamProcessors ( Stream gcodeStream = null )
2015-04-08 15:20:10 -07:00
{
2021-05-18 17:06:37 -07:00
// reset the error detection before each print
RegisterReadlineContainsCallbacks ( ) ;
2020-08-14 18:46:54 -07:00
// reset our assumptions about the flow sensor
FilamentPositionSensorDetected = false ;
2017-11-01 13:57:45 -07:00
secondsSinceUpdateHistory = 0 ;
lineSinceUpdateHistory = 0 ;
2016-01-14 10:32:25 -08:00
totalGCodeStream ? . Dispose ( ) ;
2019-03-01 19:38:59 -08:00
totalGCodeStream = null ;
2019-04-26 15:53:02 -07:00
GCodeStream accumulatedStream ;
2020-12-05 07:32:10 -08:00
var doingPrintRecovery = this . RecoveryIsEnabled & & ActivePrintTask ! = null ;
2019-03-23 18:37:53 -07:00
if ( gcodeStream ! = null )
2016-04-14 18:01:45 -07:00
{
2019-03-23 18:37:53 -07:00
gCodeFileSwitcher = new GCodeSwitcher ( gcodeStream , Printer ) ;
2016-11-03 17:34:36 -07:00
2020-12-05 07:32:10 -08:00
if ( doingPrintRecovery ) // We are resuming a failed print (do lots of interesting stuff).
2016-11-03 17:34:36 -07:00
{
2019-04-26 15:53:02 -07:00
accumulatedStream = new SendProgressStream ( new PrintRecoveryStream ( gCodeFileSwitcher , Printer , ActivePrintTask . PercentDone ) , Printer ) ;
2016-12-14 11:26:53 -08:00
// And increment the recovery count
2019-04-26 15:53:02 -07:00
ActivePrintTask . RecoveryCount + + ;
2020-10-23 16:57:26 -07:00
ActivePrintTask . CommitAndPushToServer ( ) ;
2016-11-03 17:34:36 -07:00
}
else
{
2019-03-01 19:38:59 -08:00
accumulatedStream = new SendProgressStream ( gCodeFileSwitcher , Printer ) ;
2016-11-03 17:34:36 -07:00
}
2016-04-14 18:01:45 -07:00
}
else
{
2019-03-01 19:38:59 -08:00
gCodeFileSwitcher = null ;
accumulatedStream = new NotPrintingStream ( Printer ) ;
2016-04-14 18:01:45 -07:00
}
2016-11-03 17:34:36 -07:00
2019-03-01 19:38:59 -08:00
accumulatedStream = queuedCommandStream = new QueuedCommandsStream ( Printer , accumulatedStream ) ;
2019-04-04 10:37:18 -07:00
// ensure that our read-line replacements are updated at the same time we build our write line replacements
InitializeReadLineReplacements ( ) ;
2019-03-01 19:38:59 -08:00
accumulatedStream = new RelativeToAbsoluteStream ( Printer , accumulatedStream ) ;
2019-02-19 15:26:09 -08:00
if ( ExtruderCount > 1 )
{
2019-05-07 14:47:43 -07:00
accumulatedStream = toolChangeStream = new ToolChangeStream ( Printer , accumulatedStream , queuedCommandStream , gCodeFileSwitcher ) ;
2019-04-09 13:34:16 -07:00
accumulatedStream = new ToolSpeedMultiplierStream ( Printer , accumulatedStream ) ;
2019-02-19 15:26:09 -08:00
}
2019-03-01 19:38:59 -08:00
2022-04-27 11:58:19 -07:00
bool enableLineSplitting = gcodeStream ! = null & & Printer . Settings . GetValue < bool > ( SettingsKey . enable_line_splitting ) ;
accumulatedStream = maxLengthStream = new MaxLengthStream ( Printer , accumulatedStream , enableLineSplitting ? 1 : 2000 ) ;
2020-12-05 07:32:10 -08:00
var doValidateLeveling = Printer . Settings . Helpers . ValidateLevelingWithProbe ;
if ( ! LevelingPlan . NeedsToBeRun ( Printer )
| | doValidateLeveling )
2019-04-25 15:45:03 -07:00
{
2020-12-05 07:32:10 -08:00
if ( ! doingPrintRecovery
& & doValidateLeveling )
2020-10-25 08:48:43 -07:00
{
2020-12-05 07:32:10 -08:00
// make sure we don't validate the leveling while recovering a print
2022-01-24 17:09:24 -08:00
accumulatedStream = validatePrintLevelingStream = new ValidatePrintLevelingStream ( Printer , accumulatedStream ) ;
2020-10-25 08:48:43 -07:00
}
2020-10-27 13:06:12 -07:00
accumulatedStream = printLevelingStream = new PrintLevelingStream ( Printer , accumulatedStream ) ;
2019-04-25 15:45:03 -07:00
}
2021-02-09 15:40:08 -08:00
accumulatedStream = new BabyStepsStream ( Printer , accumulatedStream ) ;
2019-03-01 19:38:59 -08:00
accumulatedStream = waitForTempStream = new WaitForTempStream ( Printer , accumulatedStream ) ;
2020-07-01 21:59:06 -07:00
accumulatedStream = ExtrusionMultiplierStream = new ExtrusionMultiplierStream ( Printer , accumulatedStream ) ;
accumulatedStream = FeedRateMultiplierStream = new FeedRateMultiplierStream ( Printer , accumulatedStream ) ;
2019-03-01 19:38:59 -08:00
accumulatedStream = new RequestTemperaturesStream ( Printer , accumulatedStream ) ;
2019-03-18 15:57:17 -07:00
if ( Printer . Settings . GetValue < bool > ( SettingsKey . emulate_endstops ) )
{
var softwareEndstopsExStream12 = new SoftwareEndstopsStream ( Printer , accumulatedStream ) ;
accumulatedStream = softwareEndstopsExStream12 ;
}
2019-02-19 14:28:24 -08:00
2022-11-27 09:11:49 -08:00
accumulatedStream = pauseHandlingStream = new PauseHandlingStream ( Printer , accumulatedStream ) ;
2020-11-15 17:28:50 -08:00
accumulatedStream = new RunSceneGCodeProcesorsStream ( Printer , accumulatedStream , queuedCommandStream ) ;
2022-11-27 09:11:49 -08:00
accumulatedStream = new RemoveNOPsStream ( Printer , accumulatedStream ) ;
2019-03-31 10:01:52 -07:00
2019-04-09 11:02:34 -07:00
processWriteRegexStream = new ProcessWriteRegexStream ( Printer , accumulatedStream , queuedCommandStream ) ;
accumulatedStream = processWriteRegexStream ;
2019-03-01 19:38:59 -08:00
totalGCodeStream = accumulatedStream ;
2017-02-10 14:44:07 -08:00
2018-01-04 18:29:35 -08:00
// Force a reset of the printer checksum state (but allow it to be write regexed)
2019-04-08 13:38:20 -07:00
var transformedCommand = ProcessWriteRegexStream . ProcessWriteRegEx ( "M110 N1" , this . Printer ) ;
2018-01-04 18:29:35 -08:00
if ( transformedCommand ! = null )
{
foreach ( var line in transformedCommand )
{
WriteChecksumLine ( line ) ;
}
}
2017-02-10 14:44:07 -08:00
// Get the current position of the printer any time we reset our streams
2019-02-22 09:23:45 -08:00
ReadPosition ( PositionReadType . Other ) ;
2016-01-14 10:32:25 -08:00
}
2015-11-28 07:46:57 -08:00
2019-02-27 18:20:27 -08:00
public GCodeStream TotalGCodeStream = > totalGCodeStream ;
2021-09-15 17:44:24 -07:00
private void SyncProgressToDB ( )
2018-01-16 08:42:35 -08:00
{
2021-09-15 17:44:24 -07:00
bool WatingForPrintToFinish ( )
{
var canceled = cancelPrintNextWriteLine | | PrintWasCanceled ;
var stillPrinting = this . CommunicationState ! = CommunicationStates . FinishedPrint & & this . CommunicationState ! = CommunicationStates . Connected ;
return ! canceled & & stillPrinting ;
}
2018-01-16 08:42:35 -08:00
2021-09-15 17:44:24 -07:00
while ( WatingForPrintToFinish ( ) )
2018-01-16 08:42:35 -08:00
{
2019-03-22 11:51:45 -07:00
double secondsSinceStartedPrint = timePrinting . Elapsed . TotalSeconds ;
2018-01-16 08:42:35 -08:00
2019-03-22 11:51:45 -07:00
if ( timePrinting . Elapsed . TotalSeconds > 0
2019-03-01 19:38:59 -08:00
& & gCodeFileSwitcher ! = null
2018-01-16 08:42:35 -08:00
& & ( secondsSinceUpdateHistory > secondsSinceStartedPrint
| | secondsSinceUpdateHistory + 1 < secondsSinceStartedPrint
2019-03-01 19:38:59 -08:00
| | lineSinceUpdateHistory + 20 < gCodeFileSwitcher . LineIndex ) )
2018-01-16 08:42:35 -08:00
{
2019-03-01 19:38:59 -08:00
double currentDone = gCodeFileSwitcher . GCodeFile . PercentComplete ( gCodeFileSwitcher . LineIndex ) ;
2018-01-16 08:42:35 -08:00
// 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.
2019-04-26 15:53:02 -07:00
if ( ActivePrintTask ! = null
& & ActivePrintTask . PercentDone < currentDone )
2018-01-16 08:42:35 -08:00
{
2019-04-26 15:53:02 -07:00
ActivePrintTask . PercentDone = currentDone ;
ActivePrintTask ? . Commit ( ) ;
2018-01-16 08:42:35 -08:00
// Interval looks to be ~10ms
2019-04-26 15:53:02 -07:00
// Console.WriteLine("DB write: {0}ms", timer.ElapsedMilliseconds);
// timer.Restart();
2018-01-16 08:42:35 -08:00
}
2019-04-26 15:53:02 -07:00
2018-01-16 08:42:35 -08:00
secondsSinceUpdateHistory = secondsSinceStartedPrint ;
2019-03-01 19:38:59 -08:00
lineSinceUpdateHistory = gCodeFileSwitcher . LineIndex ;
2018-01-16 08:42:35 -08:00
}
Thread . Sleep ( 5 ) ;
}
// Console.WriteLine("Syncing print to db stopped");
}
2018-11-09 08:57:30 -08:00
private void AtxPowerUpWasWritenToPrinter ( string line )
2015-04-23 20:19:00 -07:00
{
OnAtxPowerStateChanged ( true ) ;
}
2018-11-09 08:57:30 -08:00
private void AtxPowerDownWasWritenToPrinter ( string line )
2015-04-23 20:19:00 -07:00
{
OnAtxPowerStateChanged ( false ) ;
}
2015-04-08 15:20:10 -07:00
private void OnBedTemperatureRead ( EventArgs e )
{
2018-11-09 10:21:40 -08:00
BedTemperatureRead ? . Invoke ( this , e ) ;
2015-04-08 15:20:10 -07:00
}
2017-09-08 10:23:28 -07:00
private void OnHotendTemperatureRead ( EventArgs e )
2015-04-08 15:20:10 -07:00
{
2018-11-09 10:21:40 -08:00
HotendTemperatureRead ? . Invoke ( this , e ) ;
2015-04-08 15:20:10 -07:00
}
private void OnFanSpeedSet ( EventArgs e )
{
2018-11-09 14:31:53 -08:00
FanSpeedSet ? . Invoke ( this , e ) ;
2015-04-08 15:20:10 -07:00
}
private void OnFirmwareVersionRead ( EventArgs e )
{
2018-11-09 14:31:53 -08:00
FirmwareVersionRead ? . Invoke ( this , e ) ;
2015-04-08 15:20:10 -07:00
}
2016-10-07 15:19:32 -07:00
private bool IsNetworkPrinting ( )
{
2018-01-06 13:26:28 -08:00
return this . EnableNetworkPrinting ;
2016-10-07 15:19:32 -07:00
}
2015-04-23 20:19:00 -07:00
private void OnAtxPowerStateChanged ( bool enableAtxPower )
{
atxPowerIsOn = enableAtxPower ;
2018-11-09 14:31:53 -08:00
AtxPowerStateChanged ? . Invoke ( this , null ) ;
2015-04-23 20:19:00 -07:00
}
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
{
2018-11-29 13:41:24 -08:00
// don't time the homing operation
2019-03-22 11:51:45 -07:00
timePrinting . Stop ( ) ;
2017-08-30 10:37:44 -07:00
DetailedPrintingState = DetailedPrintingState . HomingAxis ;
2015-04-08 15:20:10 -07:00
}
2019-03-01 19:38:59 -08:00
else if ( waitForTempStream ? . HeatingBed ? ? false )
2015-04-08 15:20:10 -07:00
{
2018-11-29 13:41:24 -08:00
// don't time the heating bed operation
2019-03-22 11:51:45 -07:00
timePrinting . Stop ( ) ;
2017-08-30 10:37:44 -07:00
DetailedPrintingState = DetailedPrintingState . HeatingBed ;
2015-04-08 15:20:10 -07:00
}
2019-03-14 17:51:19 -07:00
else if ( waitForTempStream ? . HeatingT0 ? ? false )
2015-04-08 15:20:10 -07:00
{
2018-11-29 13:41:24 -08:00
// don't time the heating extruder operation
2019-03-22 11:51:45 -07:00
timePrinting . Stop ( ) ;
2019-03-14 17:51:19 -07:00
DetailedPrintingState = DetailedPrintingState . HeatingT0 ;
}
2019-03-20 23:49:20 -07:00
else if ( waitForTempStream ? . HeatingT1 ? ? false )
2019-03-14 17:51:19 -07:00
{
// don't time the heating extruder operation
2019-03-22 11:51:45 -07:00
timePrinting . Stop ( ) ;
2019-03-14 17:51:19 -07:00
DetailedPrintingState = DetailedPrintingState . HeatingT1 ;
2015-04-08 15:20:10 -07:00
}
else
{
2018-07-16 16:34:21 -07:00
// make sure we time all of the printing that we are doing
2019-02-06 10:34:19 -08:00
if ( this . Printing & & ! this . Paused )
2018-07-16 16:34:21 -07:00
{
2019-03-22 11:51:45 -07:00
timePrinting . Start ( ) ;
2018-07-16 16:34:21 -07:00
}
2019-04-26 15:53:02 -07:00
2017-08-30 10:37:44 -07:00
DetailedPrintingState = DetailedPrintingState . Printing ;
2015-02-21 12:01:59 -08:00
}
}
2017-04-11 10:41:23 -07:00
private string currentSentLine ;
private int ExpectedWaitSeconds ( string lastInstruction )
{
2019-03-11 09:40:29 -07:00
var timeMultiple = noOkResendCount + 1 ;
if ( lastInstruction . StartsWith ( "G0 " )
| | lastInstruction . Contains ( "G1 " ) )
2017-04-11 10:41:23 -07:00
{
// for moves we wait only as much as 2 seconds
2019-03-11 09:40:29 -07:00
return 2 * timeMultiple ;
}
2019-04-26 15:53:02 -07:00
else if ( lastInstruction . StartsWith ( "M109 " )
2019-03-11 09:40:29 -07:00
| | lastInstruction . StartsWith ( "M190 " ) )
{
// heat and wait will allow a long wait time for ok
return 60 ;
2017-04-11 10:41:23 -07:00
}
2019-04-26 15:53:02 -07:00
else if ( lastInstruction . StartsWith ( "G28" ) )
2019-03-11 15:57:20 -07:00
{
return 30 ;
}
2017-04-11 10:41:23 -07:00
2019-03-11 09:40:29 -07:00
// any other move we allow up to 10 seconds for response
return 10 * timeMultiple ;
2017-04-11 10:41:23 -07:00
}
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.
2017-11-30 16:52:52 -08:00
currentLineIndexToSend = Math . Max ( 0 , currentLineIndexToSend - - ) ; // we are going to resend the last command
2019-03-11 09:40:29 -07:00
noOkResendCount + + ;
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 ;
}
}
}
}
2019-03-11 09:40:29 -07:00
else
{
noOkResendCount = 0 ;
}
2016-01-14 10:32:25 -08:00
lock ( locker )
{
2016-12-02 13:51:58 -08:00
if ( currentLineIndexToSend < allCheckSumLinesSent . Count )
2016-01-14 10:32:25 -08:00
{
2018-01-04 17:30:48 -08:00
WriteRaw ( 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
2018-02-01 14:51:44 -08:00
& & this . IsConnected )
2016-01-14 10:32:25 -08:00
{
// we are waiting for a position response don't print more
return ;
}
currentSentLine = totalGCodeStream . ReadLine ( ) ;
if ( currentSentLine ! = null )
{
2018-12-04 13:28:38 -08:00
if ( currentSentLine . EndsWith ( "; NO_PROCESSING" ) )
{
// make sure our processing pipe knows the translated position after a NO_PROCESSING
2019-02-22 09:23:45 -08:00
ReadPosition ( PositionReadType . Other , true ) ;
2018-12-04 13:28:38 -08:00
}
2017-06-29 09:47:34 -07:00
if ( currentSentLine . Contains ( "M114" )
2018-02-01 14:51:44 -08:00
& & this . IsConnected )
2016-01-14 10:32:25 -08:00
{
waitingForPosition . Restart ( ) ;
}
2017-06-29 13:02:36 -07:00
currentSentLine = currentSentLine . Trim ( ) ;
2019-03-31 10:01:52 -07:00
2017-06-29 09:47:34 -07:00
// Check if there is anything in front of the ;.
if ( currentSentLine . Split ( ';' ) [ 0 ] . Trim ( ) . Length > 0 )
2016-01-14 10:32:25 -08:00
{
2017-06-29 09:47:34 -07:00
if ( currentSentLine . Length > 0 )
{
2018-01-04 17:30:48 -08:00
WriteChecksumLine ( currentSentLine ) ;
2016-01-14 10:32:25 -08:00
2017-06-29 09:47:34 -07:00
currentLineIndexToSend + + ;
}
2015-04-08 15:20:10 -07:00
}
2016-01-14 10:32:25 -08:00
}
2021-08-25 17:57:22 -07:00
else if ( this . cancelPrintNextWriteLine )
2016-01-14 10:32:25 -08:00
{
CommunicationState = CommunicationStates . Connected ;
// never leave the extruder and the bed hot
ReleaseMotors ( ) ;
2020-05-05 09:26:09 -07:00
TurnOffPartCoolingFan ( ) ;
2018-03-21 14:20:43 -07:00
TurnOffBedAndExtruders ( TurnOff . AfterDelay ) ;
2021-01-15 17:51:50 -08:00
this . PrintWasCanceled = true ;
2021-08-25 17:57:22 -07:00
this . cancelPrintNextWriteLine = false ;
2019-04-01 16:19:23 -07:00
// and finally notify anyone that wants to know
2021-02-09 16:54:31 -08:00
CancelCompleted ? . Invoke ( this , null ) ;
2016-01-14 10:32:25 -08:00
}
2019-04-30 15:51:44 -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)
2019-04-25 16:04:24 -07:00
CreateStreamProcessors ( ) ;
2017-01-03 10:45:16 -08:00
2016-01-14 10:32:25 -08:00
// never leave the extruder and the bed hot
ReleaseMotors ( ) ;
2019-05-21 16:05:55 -07:00
if ( SecondsPrinted < GCodeMemoryFile . LeaveHeatersOnTime )
2019-03-06 14:55:00 -08:00
{
2020-05-05 09:26:09 -07:00
TurnOffPartCoolingFan ( ) ;
2019-03-06 14:55:00 -08:00
// The user may still be sitting at the machine, leave it heated for a period of time
TurnOffBedAndExtruders ( TurnOff . AfterDelay ) ;
}
else
{
// Turn off the heaters on long prints as the user is less likely to be around and interacting
TurnOffBedAndExtruders ( TurnOff . Now ) ;
}
2015-04-08 15:20:10 -07:00
}
}
2016-01-14 10:32:25 -08:00
}
2015-03-04 17:59:28 -08:00
}
2018-10-16 11:42:40 -07:00
public int TimeToHoldTemperature { get ; set ; } = 600 ;
2018-02-02 09:17:04 -08:00
2018-04-05 12:44:51 -07:00
public bool AnyHeatIsOn
{
get
{
bool anyHeatIsOn = false ;
// check if any temps are set
for ( int i = 0 ; i < this . ExtruderCount ; i + + )
{
if ( GetTargetHotendTemperature ( i ) > 0 )
{
anyHeatIsOn = true ;
break ;
}
}
2019-04-26 15:53:02 -07:00
2018-04-05 12:44:51 -07:00
anyHeatIsOn | = TargetBedTemperature > 0 ;
return anyHeatIsOn ;
}
}
2018-11-02 16:14:37 -07:00
public int NumQueuedCommands
{
get
{
2019-03-01 19:38:59 -08:00
if ( queuedCommandStream ! = null )
2018-11-02 16:14:37 -07:00
{
2019-03-01 19:38:59 -08:00
return queuedCommandStream . Count ;
2018-11-02 16:14:37 -07:00
}
return 0 ;
}
}
2018-12-22 08:30:29 -08:00
public bool AllowLeveling
{
2021-11-05 18:08:58 -07:00
get
{
if ( printLevelingStream ! = null )
{
return printLevelingStream . AllowLeveling ;
}
return false ;
}
2019-04-25 15:45:03 -07:00
set
{
if ( printLevelingStream ! = null )
{
printLevelingStream . AllowLeveling = value ;
}
else if ( value )
{
// we are requesting it turned back on, re-build the leveling stream
CreateStreamProcessors ( ) ;
}
}
2018-12-22 08:30:29 -08:00
}
2018-11-09 12:26:56 -08:00
2019-01-18 15:11:05 -08:00
/// <summary>
2019-04-26 15:53:02 -07:00
/// Gets a value indicating whether the Pause Handling Stream has seen a change in the position sensor.
2019-03-06 13:31:57 -08:00
/// It is important that this is not persisted, it is meant to function correctly if the user
2019-01-18 15:11:05 -08:00
/// plugs in or removes a filament position sensor.
/// </summary>
public bool FilamentPositionSensorDetected { get ; internal set ; }
2019-03-06 13:31:57 -08:00
2019-02-22 09:23:45 -08:00
public Vector3 HomingPosition
{
get = > _homingPosition ;
private set
{
if ( value ! = _homingPosition )
{
_homingPosition = value ;
HomingPositionChanged ? . Invoke ( this , null ) ;
}
}
}
2019-01-18 15:11:05 -08:00
2020-10-04 22:21:17 -07:00
public PrintTask CanceledPrintTask { get ; private set ; }
2020-10-23 16:57:26 -07:00
2019-04-26 15:53:02 -07:00
public PrintTask ActivePrintTask { get ; set ; }
2020-07-01 21:59:06 -07:00
public ExtrusionMultiplierStream ExtrusionMultiplierStream { get ; private set ; }
2020-07-03 12:05:28 -07:00
2020-07-01 21:59:06 -07:00
public FeedRateMultiplierStream FeedRateMultiplierStream { get ; private set ; }
2021-08-13 16:49:23 -07:00
public bool WaitingToPause = > pauseHandlingStream ? . WaitingToPause = = true ;
2020-07-01 21:59:06 -07:00
2020-05-05 09:26:09 -07:00
public void TurnOffPartCoolingFan ( )
{
// turn off all the part cooling fans
if ( Printer . Settings . GetValue < bool > ( SettingsKey . has_fan_per_extruder ) )
{
for ( int i = 0 ; i < this . ExtruderCount ; i + + )
{
SetFanSpeed0To255 ( i , 0 ) ;
}
}
else
{
SetFanSpeed0To255 ( 0 , 0 ) ;
}
}
2019-05-21 07:16:23 -07:00
2018-03-21 14:20:43 -07:00
public void TurnOffBedAndExtruders ( TurnOff turnOffTime )
2015-04-08 15:20:10 -07:00
{
2020-05-05 09:26:09 -07:00
TurnOffPartCoolingFan ( ) ;
2018-03-21 14:20:43 -07:00
if ( turnOffTime = = TurnOff . Now )
2016-01-14 10:32:25 -08:00
{
2018-01-30 14:48:53 -08:00
for ( int i = 0 ; i < this . ExtruderCount ; i + + )
{
SetTargetHotendTemperature ( i , 0 , true ) ;
}
2019-04-26 15:53:02 -07:00
2018-01-30 14:48:53 -08:00
TargetBedTemperature = 0 ;
}
else
{
2019-03-19 13:13:14 -07:00
bool currentlyWaiting = ContinueHoldingTemperature & & TimeHaveBeenHoldingTemperature . IsRunning & & TimeHaveBeenHoldingTemperature . Elapsed . TotalSeconds < TimeToHoldTemperature ;
2018-07-17 10:04:08 -07:00
SecondsToHoldTemperature = TimeToHoldTemperature ;
2019-03-19 13:13:14 -07:00
ContinueHoldingTemperature = true ;
2018-07-17 10:04:08 -07:00
TimeHaveBeenHoldingTemperature = Stopwatch . StartNew ( ) ;
2018-01-31 12:32:25 -08:00
if ( ! currentlyWaiting )
2018-01-30 15:47:12 -08:00
{
2018-11-08 17:16:35 -08:00
TemporarilyHoldingTemp ? . Invoke ( this , null ) ;
2018-01-31 12:32:25 -08:00
// wait secondsToWait and turn off the heaters
Task . Run ( ( ) = >
2018-01-30 15:47:12 -08:00
{
2018-07-17 10:04:08 -07:00
while ( TimeHaveBeenHoldingTemperature . Elapsed . TotalSeconds < TimeToHoldTemperature
2019-03-19 13:13:14 -07:00
& & ContinueHoldingTemperature )
2018-01-31 12:32:25 -08:00
{
2018-04-05 12:44:51 -07:00
if ( CommunicationState = = CommunicationStates . PreparingToPrint
2019-02-06 10:34:19 -08:00
| | Printing )
2018-03-20 18:25:40 -07:00
{
2019-03-19 13:13:14 -07:00
ContinueHoldingTemperature = false ;
2018-03-20 18:25:40 -07:00
}
2018-04-05 12:44:51 -07:00
if ( ! AnyHeatIsOn )
2018-03-20 18:25:40 -07:00
{
2019-03-19 13:13:14 -07:00
ContinueHoldingTemperature = false ;
2018-03-20 18:25:40 -07:00
}
2018-04-05 12:44:51 -07:00
2019-03-19 13:13:14 -07:00
SecondsToHoldTemperature = ContinueHoldingTemperature ? Math . Max ( 0 , TimeToHoldTemperature - TimeHaveBeenHoldingTemperature . Elapsed . TotalSeconds ) : 0 ;
2018-01-31 12:32:25 -08:00
Thread . Sleep ( 100 ) ;
}
2018-01-30 15:47:12 -08:00
2018-02-09 13:37:21 -08:00
// times up turn off heaters
2019-03-19 13:13:14 -07:00
if ( ContinueHoldingTemperature
2019-02-06 10:34:19 -08:00
& & ! Printing
& & ! Paused )
2018-01-30 15:47:12 -08:00
{
2018-01-31 12:32:25 -08:00
UiThread . RunOnIdle ( ( ) = >
2018-01-30 15:47:12 -08:00
{
2018-01-31 12:32:25 -08:00
for ( int i = 0 ; i < this . ExtruderCount ; i + + )
{
SetTargetHotendTemperature ( i , 0 , true ) ;
}
2019-04-26 15:53:02 -07:00
2018-01-31 12:32:25 -08:00
TargetBedTemperature = 0 ;
} ) ;
}
} ) ;
}
2016-01-14 10:32:25 -08:00
}
2015-04-08 15:20:10 -07:00
}
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
2019-04-26 15:53:02 -07:00
// int checkSumCount = 1;
2019-03-19 13:44:07 -07:00
2018-01-04 17:30:48 -08:00
private void WriteChecksumLine ( string lineToWrite )
2016-01-14 10:32:25 -08:00
{
2019-04-26 15:53:02 -07:00
bool sendLineWithChecksum = ! lineToWrite . Contains ( "WRITE_RAW" ) ;
2018-01-11 13:03:23 -08:00
2016-01-14 10:32:25 -08:00
// remove the comment if any
lineToWrite = RemoveCommentIfAny ( lineToWrite ) ;
2020-12-19 23:14:33 -08:00
if ( KeepTrackOfAbsolutePositionAndDestination ( lineToWrite , ref currentDestination ) )
{
DestinationChanged ? . Invoke ( this , null ) ;
}
2016-01-14 10:32:25 -08:00
2018-01-11 13:03:23 -08:00
if ( this . SendWithChecksum & & sendLineWithChecksum )
2016-01-14 10:32:25 -08:00
{
2017-11-30 13:59:14 -08:00
// always send the reset line number without a checksum so that it is accepted
string lineWithCount ;
if ( lineToWrite . StartsWith ( "M110" ) )
2017-05-19 14:39:57 -07:00
{
2017-11-30 13:59:14 -08:00
lineWithCount = $"N1 {lineToWrite}" ;
GCodeFile . GetFirstNumberAfter ( "N" , lineToWrite , ref currentLineIndexToSend ) ;
allCheckSumLinesSent . SetStartingIndex ( currentLineIndexToSend ) ;
2018-01-04 18:29:35 -08:00
currentLineIndexToSend + + ;
2017-11-30 13:59:14 -08:00
}
else
{
lineWithCount = $"N{allCheckSumLinesSent.Count} {lineToWrite}" ;
if ( lineToWrite . StartsWith ( "M999" ) )
{
allCheckSumLinesSent . SetStartingIndex ( 1 ) ;
}
2017-05-19 14:39:57 -07:00
}
2016-12-02 13:51:58 -08:00
2017-11-30 13:59:14 -08:00
string lineWithChecksum = lineWithCount + "*" + GCodeFile . CalculateChecksum ( lineWithCount ) . ToString ( ) ;
2017-04-11 10:41:23 -07:00
2017-11-30 13:59:14 -08:00
allCheckSumLinesSent . Add ( lineWithChecksum ) ;
2016-12-02 13:51:58 -08:00
2019-04-26 15:53:02 -07:00
// if ((checkSumCount++ % 11) == 0)
// lineWithChecksum = lineWithCount + "*" + (GCodeFile.CalculateChecksum(lineWithCount) + checkSumCount).ToString();
2016-12-02 13:51:58 -08:00
2018-01-04 17:30:48 -08:00
WriteRaw ( lineWithChecksum + "\n" , lineToWrite ) ;
2017-11-30 13:59:14 -08:00
}
else
{
2018-01-04 17:30:48 -08:00
WriteRaw ( lineToWrite + "\n" , lineToWrite ) ;
2017-11-30 13:59:14 -08:00
}
2017-09-05 10:33:14 -07:00
SetDetailedPrintingState ( 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 ;
}
2018-01-04 17:30:48 -08:00
private void WriteRaw ( string lineToWrite , string lineWithoutChecksum )
2015-02-04 14:57:56 -08:00
{
2018-02-01 14:51:44 -08:00
if ( this . IsConnected | | CommunicationState = = CommunicationStates . AttemptingToConnect )
2015-02-04 14:57:56 -08:00
{
2019-05-02 20:41:16 -07:00
if ( serialPort ! = null & & serialPort . IsOpen )
2015-04-08 15:20:10 -07:00
{
2019-04-27 13:38:24 -07:00
if ( lineWithoutChecksum . StartsWith ( "G92" ) )
{
// read out the position and store right now
GCodeFile . GetFirstNumberAfter ( "X" , lineWithoutChecksum , ref currentDestination . position . X ) ;
GCodeFile . GetFirstNumberAfter ( "Y" , lineWithoutChecksum , ref currentDestination . position . Y ) ;
GCodeFile . GetFirstNumberAfter ( "Z" , lineWithoutChecksum , ref currentDestination . position . X ) ;
GCodeFile . GetFirstNumberAfter ( "E" , lineWithoutChecksum , ref currentDestination . extrusion ) ;
2019-04-29 11:46:25 -07:00
// The printer position has changed, make sure all the streams know
if ( totalGCodeStream ! = null )
{
totalGCodeStream . SetPrinterPosition ( currentDestination ) ;
}
2019-04-27 13:38:24 -07:00
}
2019-04-29 11:46:25 -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.
2019-02-22 09:23:45 -08:00
if ( lineWithoutChecksum . StartsWith ( "G28" ) // is a home
| | lineWithoutChecksum . StartsWith ( "G29" ) // is a bed level
| | lineWithoutChecksum . StartsWith ( "G30" ) // is a bed level
2016-08-03 16:49:48 -07:00
| | ( 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
{
2019-02-22 09:23:45 -08:00
PositionReadType readType = PositionReadType . Other ;
if ( lineWithoutChecksum . StartsWith ( "G28" ) )
{
if ( lineWithoutChecksum . Contains ( "X" ) )
{
readType | = PositionReadType . HomeX ;
}
2019-04-26 15:53:02 -07:00
2019-02-22 09:23:45 -08:00
if ( lineWithoutChecksum . Contains ( "Y" ) )
{
readType | = PositionReadType . HomeY ;
}
2019-04-26 15:53:02 -07:00
2019-02-22 09:23:45 -08:00
if ( lineWithoutChecksum . Contains ( "Z" ) )
{
readType | = PositionReadType . HomeZ ;
}
2019-04-26 15:53:02 -07:00
2019-02-22 09:23:45 -08:00
if ( lineWithoutChecksum = = "G28" )
{
readType = PositionReadType . HomeAll ;
}
}
2019-04-26 15:53:02 -07:00
2019-02-22 09:23:45 -08:00
ReadPosition ( readType , 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
{
2015-04-08 15:20:10 -07:00
if ( lineWithoutChecksum ! = null )
{
2019-04-26 15:53:02 -07:00
writeLineStartCallBacks . ProcessLine ( lineWithoutChecksum ) ;
writeLineContainsCallBacks . ProcessLine ( lineWithoutChecksum ) ;
2015-04-08 15:20:10 -07:00
2019-01-03 17:51:53 -08:00
LineSent ? . Invoke ( this , lineToWrite ) ;
2015-04-08 15:20:10 -07:00
}
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
{
2017-12-04 15:02:32 -08:00
// only send the line if there is something to send (other than the \n)
if ( lineToWrite . Trim ( ) . Length > 0 )
2015-04-24 18:24:21 -07:00
{
2017-12-04 15:02:32 -08:00
lock ( locker )
{
2019-05-02 20:41:16 -07:00
serialPort . Write ( lineToWrite ) ;
2017-12-04 15:02:32 -08:00
timeSinceLastWrite . Restart ( ) ;
timeHaveBeenWaitingForOK . Restart ( ) ;
}
2015-04-24 18:24:21 -07:00
}
2019-04-26 15:53:02 -07:00
// Debug.Write("w: " + lineToWrite);
2015-04-08 15:20:10 -07:00
}
catch ( IOException ex )
{
2017-08-03 16:35:22 -07:00
TerminalLog . 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
2019-04-26 15:53:02 -07:00
ReleaseAndReportFailedConnection ( ConnectionFailure . ConnectionLost ) ;
2016-12-29 12:52:12 -08:00
}
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.
2017-08-03 16:35:22 -07:00
TerminalLog . 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
{
2017-08-03 16:35:22 -07:00
TerminalLog . WriteLine ( "Exception:" + e3 . Message ) ;
2019-04-26 15:53:02 -07:00
ReleaseAndReportFailedConnection ( ConnectionFailure . UnauthorizedAccessException ) ;
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
{
2017-12-30 11:49:17 -08:00
OnConnectionFailed ( ConnectionFailure . WriteFailed ) ;
2015-04-08 15:20:10 -07:00
}
}
}
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
{
2019-03-01 19:38:59 -08:00
queuedCommandStream ? . Reset ( ) ;
2016-11-04 16:00:54 -07:00
}
2021-02-24 16:56:37 -08:00
public void CancelInProgressStreamProcessors ( )
2017-02-01 17:49:26 -08:00
{
2019-03-01 19:38:59 -08:00
maxLengthStream ? . Cancel ( ) ;
waitForTempStream ? . Cancel ( ) ;
queuedCommandStream ? . Cancel ( ) ;
2022-01-24 17:09:24 -08:00
validatePrintLevelingStream ? . Cancel ( ) ;
2016-11-04 16:00:54 -07:00
}
2018-11-09 13:58:43 -08:00
public void Dispose ( )
{
2019-04-02 15:04:43 -07:00
TerminalLog . Dispose ( ) ;
2018-11-09 13:58:43 -08:00
Disposed ? . Invoke ( this , null ) ;
}
2019-04-26 15:53:02 -07:00
private int currentReadThreadIndex = 0 ;
2019-02-22 09:23:45 -08:00
private Vector3 _homingPosition = Vector3 . NegativeInfinity ;
2019-03-11 09:40:29 -07:00
private int noOkResendCount ;
2019-04-08 13:38:20 -07:00
private ProcessWriteRegexStream processWriteRegexStream ;
2021-08-25 17:57:22 -07:00
private bool cancelPrintNextWriteLine ;
2022-01-24 17:09:24 -08:00
private ValidatePrintLevelingStream validatePrintLevelingStream ;
2018-11-16 16:21:30 -08:00
2022-01-24 17:09:24 -08:00
public class ReadThread
2015-04-08 15:20:10 -07:00
{
2019-04-26 15:53:02 -07:00
private readonly int creationIndex ;
2015-04-08 15:20:10 -07:00
2017-04-11 10:41:23 -07:00
private static int numRunning = 0 ;
2019-04-26 15:53:02 -07:00
private readonly PrinterConnection printerConnection ;
2017-04-11 10:41:23 -07:00
2018-12-26 16:38:54 -08:00
public static int NumRunning = > numRunning ;
2015-04-27 15:42:31 -07:00
2017-08-03 15:24:41 -07:00
private ReadThread ( PrinterConnection printerConnection )
2015-04-08 15:20:10 -07:00
{
2018-11-16 16:21:30 -08:00
this . printerConnection = printerConnection ;
2015-04-27 15:42:31 -07:00
numRunning + + ;
2019-04-29 09:13:43 -07:00
printerConnection . currentReadThreadIndex + + ;
creationIndex = printerConnection . currentReadThreadIndex ;
2015-04-08 15:20:10 -07:00
2015-11-04 17:13:53 -08:00
Task . Run ( ( ) = >
{
try
{
2017-08-03 15:24:41 -07:00
printerConnection . ReadFromPrinter ( this ) ;
2015-11-04 17:13:53 -08:00
}
catch
{
}
2016-01-14 10:32:25 -08:00
2019-04-05 14:00:37 -07:00
printerConnection . TerminalLog . WriteLine ( "Read Thread Has Exited" ) ;
2015-11-04 17:13:53 -08:00
numRunning - - ;
} ) ;
2015-04-27 15:42:31 -07:00
}
2017-08-03 15:24:41 -07:00
internal static void Start ( PrinterConnection printerConnection )
2015-04-08 15:20:10 -07:00
{
2017-08-03 15:24:41 -07:00
new ReadThread ( printerConnection ) ;
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 ( )
{
2019-04-29 09:13:43 -07:00
return printerConnection . 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 ;
2019-04-26 15:53:02 -07:00
private readonly 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
}
}
}
2017-12-30 11:49:17 -08:00
public enum ConnectionFailure
{
Unknown ,
AlreadyConnected ,
MaximumErrorsReached ,
PortNotFound ,
PortInUse ,
WriteFailed ,
UnsupportedBaudRate ,
PortUnavailable ,
Aborted ,
FailedToConnect ,
IOException ,
InvalidOperationException ,
2017-12-30 13:45:13 -08:00
UnauthorizedAccessException ,
2017-12-31 11:36:55 -08:00
ConnectionLost ,
2019-04-05 17:12:13 -07:00
UsbDisconnected ,
ConnectionTimeout
2017-12-30 11:49:17 -08:00
}
2019-05-30 11:41:50 -07:00
}