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 .
* /
2017-06-13 17:32:38 -07:00
using System ;
2017-06-29 09:47:34 -07:00
using System.Collections.Generic ;
2017-06-13 17:32:38 -07:00
using System.Diagnostics ;
using System.Globalization ;
using System.IO ;
using System.Linq ;
2017-12-30 07:50:13 -08:00
using System.Text ;
2017-06-29 09:47:34 -07:00
using System.Text.RegularExpressions ;
2017-06-13 17:32:38 -07:00
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 ;
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
{
2018-03-21 14:20:43 -07:00
public enum TurnOff { Now , AfterDelay }
2019-02-22 09:23:45 -08:00
[Flags]
public enum PositionReadType
{
None = 0 ,
HomeX = 1 < < 1 ,
HomeY = 1 < < 2 ,
HomeZ = 1 < < 3 ,
Other = 1 < < 4 ,
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-03-14 17:51:19 -07:00
public enum DetailedPrintingState { HomingAxis , HeatingBed , HeatingT0 , HeatingT1 , Printing } ;
2017-06-13 17:32:38 -07:00
public enum FirmwareTypes { Unknown , Repetier , Marlin , Sprinter } ;
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 ;
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
2018-11-09 14:02:11 -08:00
public event EventHandler EnableChanged ;
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 ;
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
}
2019-01-18 09:49:38 -08:00
public event EventHandler < PrintFinishedEventArgs > PrintFinished ;
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
2018-11-09 14:31:53 -08:00
public EventHandler AtxPowerStateChanged ;
2015-04-23 20:19:00 -07:00
private bool atxPowerIsOn = false ;
2016-04-18 11:31:31 -07:00
internal const int MAX_EXTRUDERS = 16 ;
2015-04-08 15:20:10 -07:00
private const int MAX_INVALID_CONNECTION_CHARS = 3 ;
2017-04-11 10:41:23 -07:00
private object locker = new object ( ) ;
2016-01-07 16:45:16 -08:00
2018-03-14 13:49:57 -07:00
public PrintTask activePrintTask ;
2015-04-08 15:20:10 -07:00
private double actualBedTemperature ;
2018-12-04 13:28:38 -08:00
public int ActiveExtruderIndex { get ; private set ; }
2016-07-25 12:29:43 -07:00
2017-09-08 10:23:28 -07:00
private double [ ] actualHotendTemperature = new double [ MAX_EXTRUDERS ] ;
2015-04-08 15:20:10 -07:00
private CheckSumLines allCheckSumLinesSent = new CheckSumLines ( ) ;
private CommunicationStates communicationState = CommunicationStates . Disconnected ;
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
2017-11-02 12:26:14 -07:00
private double fanSpeed ;
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 ;
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
2018-11-09 11:17:11 -08:00
private ContainsStringLineActions ReadLineContainsCallBacks = new ContainsStringLineActions ( ) ;
2015-04-08 15:20:10 -07:00
2018-11-09 11:17:11 -08:00
private StartsWithLineActions ReadLineStartCallBacks = new StartsWithLineActions ( ) ;
2015-04-08 15:20:10 -07:00
// we start out by setting it to a nothing file
private IFrostedSerialPort serialPort ;
2018-01-30 14:48:53 -08:00
private double _targetBedTemperature ;
2015-04-08 15:20:10 -07:00
2017-09-08 10:23:28 -07:00
private double [ ] targetHotendTemperature = new double [ MAX_EXTRUDERS ] ;
2015-04-08 15:20:10 -07:00
private Stopwatch timeHaveBeenWaitingForOK = new Stopwatch ( ) ;
private Stopwatch timeSinceLastReadAnything = new Stopwatch ( ) ;
private Stopwatch timeSinceLastWrite = new Stopwatch ( ) ;
2016-04-06 11:56:48 -07:00
private Stopwatch timeSinceRecievedOk = new Stopwatch ( ) ;
2019-03-22 11:51:45 -07:00
private Stopwatch timePrinting = new Stopwatch ( ) ;
2015-04-08 15:20:10 -07:00
private Stopwatch timeWaitingForSdProgress = new Stopwatch ( ) ;
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
private Stopwatch waitingForPosition = new Stopwatch ( ) ;
2018-11-09 11:17:11 -08:00
private ContainsStringLineActions WriteLineContainsCallBacks = new ContainsStringLineActions ( ) ;
2015-04-08 15:20:10 -07:00
2018-11-09 11:17:11 -08:00
private 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
2018-11-09 11:05:25 -08:00
ReadLineStartCallBacks . Register ( "start" , FoundStart ) ;
ReadLineStartCallBacks . Register ( "start" , PrintingCanContinue ) ;
2015-01-19 18:26:09 -08:00
2018-11-09 11:05:25 -08:00
ReadLineStartCallBacks . Register ( "ok" , SuppressEcho ) ;
ReadLineStartCallBacks . Register ( "wait" , SuppressEcho ) ;
ReadLineStartCallBacks . Register ( "T:" , SuppressEcho ) ; // repetier
2015-04-08 15:20:10 -07:00
2018-11-09 11:05:25 -08:00
ReadLineStartCallBacks . Register ( "ok" , PrintingCanContinue ) ;
ReadLineStartCallBacks . Register ( "Done saving file" , PrintingCanContinue ) ;
2015-04-08 15:20:10 -07:00
2018-11-09 11:05:25 -08:00
ReadLineStartCallBacks . Register ( "B:" , ReadTemperatures ) ; // smoothie
ReadLineContainsCallBacks . Register ( "T0:" , ReadTemperatures ) ; // marlin
ReadLineContainsCallBacks . Register ( "T:" , ReadTemperatures ) ; // repetier
2015-04-08 15:20:10 -07:00
2018-11-09 11:05:25 -08:00
ReadLineStartCallBacks . Register ( "SD printing byte" , ReadSdProgress ) ; // repetier
2015-04-08 15:20:10 -07:00
2018-11-09 11:05:25 -08: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
2018-11-09 11:05:25 -08:00
ReadLineStartCallBacks . Register ( "rs " , PrinterRequestsResend ) ; // smoothie is lower case and no :
ReadLineStartCallBacks . Register ( "RS:" , PrinterRequestsResend ) ;
ReadLineContainsCallBacks . Register ( "Resend:" , PrinterRequestsResend ) ;
2015-04-08 15:20:10 -07:00
2018-11-09 11:05:25 -08:00
ReadLineContainsCallBacks . Register ( "FIRMWARE_NAME:" , PrinterStatesFirmware ) ;
2015-04-08 15:20:10 -07:00
2016-01-05 17:31:11 -08:00
#region hardware failure callbacks
2017-04-11 10:41:23 -07:00
2016-01-05 17:31:11 -08:00
// smoothie temperature failures
2018-11-09 11:05:25 -08:00
ReadLineContainsCallBacks . Register ( "T:inf" , PrinterReportsError ) ;
ReadLineContainsCallBacks . Register ( "B:inf" , PrinterReportsError ) ;
2016-01-06 12:09:37 -08:00
2016-01-05 17:31:11 -08:00
// marlin temperature failures
2018-11-09 11:05:25 -08:00
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:Heating failed" , PrinterReportsError ) ;
ReadLineStartCallBacks . Register ( "temp sensor defect" , PrinterReportsError ) ;
ReadLineStartCallBacks . Register ( "Error:Printer halted" , PrinterReportsError ) ;
2016-01-06 12:09:37 -08:00
2016-09-22 17:26:27 -07:00
// repetier temperature failures
2018-11-09 11:05:25 -08:00
ReadLineContainsCallBacks . Register ( "dry run mode" , PrinterReportsError ) ;
ReadLineStartCallBacks . Register ( "accelerometer send i2c error" , PrinterReportsError ) ;
ReadLineStartCallBacks . Register ( "accelerometer i2c recv error" , PrinterReportsError ) ;
2016-12-12 16:37:09 -08:00
// s3g temperature failures
2018-11-09 11:05:25 -08:00
ReadLineContainsCallBacks . Register ( "Bot is Shutdown due to Overheat" , PrinterReportsError ) ;
2017-04-11 10:41:23 -07:00
#endregion hardware failure callbacks
2016-01-05 16:48:04 -08:00
2018-11-09 11:05:25 -08: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 ) ;
WriteLineStartCallBacks . Register ( "T" , ExtruderIndexSet ) ;
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 ;
case SettingsKey . temperature1 :
extruder = 1 ;
break ;
case SettingsKey . temperature2 :
extruder = 2 ;
break ;
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
}
}
}
if ( stringEvent . Data = = SettingsKey . bed_temperature )
{
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 )
{
var newGoal = printer . Settings . GetValue < double > ( SettingsKey . bed_temperature ) ;
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
}
2019-03-05 17:55:44 -08:00
/// <summary>
/// seconds until the next tool change while printing
/// </summary>
/// <returns></returns>
2019-03-06 10:19:35 -08:00
public ( int toolIndex , double time ) NextToolChange ( int toolToLookFor = - 1 )
2019-03-05 17:55:44 -08:00
{
2019-03-06 13:44:33 -08:00
if ( gCodeFileSwitcher ! = null
& & gCodeFileSwitcher . GCodeFile is GCodeMemoryFile gCodeMemoryFile )
2019-03-05 17:55:44 -08:00
{
2019-03-08 13:48:00 -08:00
var timeToTool = gCodeMemoryFile . NextToolChange ( gCodeFileSwitcher . LineIndex , - 1 , toolToLookFor ) ;
return timeToTool ;
2019-03-05 17:55:44 -08:00
}
2019-03-06 13:44:33 -08:00
return ( - 1 , 0 ) ;
2019-03-05 17:55:44 -08:00
}
2018-11-09 08:57:30 -08:00
private void ExtruderIndexSet ( string line )
2016-07-25 12:29:43 -07:00
{
double extruderBeingSet = 0 ;
2018-11-09 08:57:30 -08:00
if ( GCodeFile . GetFirstNumberAfter ( "T" , line , ref extruderBeingSet ) )
2016-07-25 12:29:43 -07:00
{
2018-12-04 13:28:38 -08:00
ActiveExtruderIndex = ( int ) extruderBeingSet ;
2016-07-25 12:29:43 -07:00
}
2015-04-08 15:20:10 -07:00
}
2016-01-14 10:32:25 -08:00
[Flags]
2015-04-08 15:20:10 -07:00
public enum Axis { X = 1 , Y = 2 , Z = 4 , E = 8 , XYZ = ( X | Y | Z ) }
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
{
if ( ! string . IsNullOrEmpty ( Printer . Settings . GetValue ( SettingsKey . baud_rate ) ) )
{
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 ) ;
2018-11-14 16:54:23 -08:00
public string LastPrintedItemName { get ; private set ; } = "" ;
public string PrintingItemName { get ; set ; } = "" ;
2018-01-06 13:26:28 -08:00
2018-01-06 16:03:03 -08:00
private List < ( Regex Regex , string Replacement ) > readLineReplacements = new List < ( Regex Regex , string Replacement ) > ( ) ;
private string _readLineReplacementString = "" ;
public string ReadLineReplacementString
{
2019-03-25 17:55:52 -07:00
get
2018-01-06 16:03:03 -08:00
{
2019-03-25 17:55:52 -07:00
var readRegEx = Printer . Settings . GetValue ( SettingsKey . read_regex ) ;
if ( readRegEx ! = _readLineReplacementString )
2018-01-06 16:03:03 -08:00
{
2019-03-25 17:55:52 -07:00
_readLineReplacementString = readRegEx ;
2018-01-06 16:03:03 -08:00
// Clear and rebuild the replacement list
readLineReplacements . Clear ( ) ;
foreach ( string regExLine in _readLineReplacementString . Split ( new string [ ] { "\\n" } , StringSplitOptions . RemoveEmptyEntries ) )
{
var matches = getQuotedParts . Matches ( regExLine ) ;
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 ) ) ;
}
}
}
2019-03-25 17:55:52 -07:00
return _readLineReplacementString ;
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
{
get
{
return communicationState ;
}
2014-01-29 19:09:30 -08:00
2015-04-08 15:20:10 -07:00
set
{
2015-03-13 12:25:33 -07:00
switch ( value )
{
case CommunicationStates . AttemptingToConnect :
2018-11-14 16:54:23 -08:00
PrintingItemName = "" ;
2016-01-14 10:32:25 -08:00
#if DEBUG
2015-03-13 12:25:33 -07:00
if ( serialPort = = null )
{
throw new Exception ( "The serial port should be constructed prior to setting this or we can fail our connection on a write before it has a chance to be created." ) ;
}
2016-01-14 10:32:25 -08:00
#endif
2015-03-13 12:25:33 -07:00
break ;
2015-04-27 15:42:31 -07:00
case CommunicationStates . Connected :
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 ) ;
2017-12-31 14:20:06 -08:00
for ( int hotendIndex = 0 ; hotendIndex < MAX_EXTRUDERS ; hotendIndex + + )
{
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
}
2015-04-08 15:20:10 -07:00
if ( communicationState ! = value )
{
2019-03-25 17:55:52 -07:00
LineSent ? . Invoke ( this , string . Format ( "Communication State: {0}" , value ) ) ;
2015-04-27 15:42:31 -07:00
2015-04-08 15:20:10 -07:00
switch ( communicationState )
{
// if it was printing
2015-04-07 10:19:49 -07:00
case CommunicationStates . PrintingFromSd :
2015-04-08 15:20:10 -07:00
case CommunicationStates . Printing :
{
// and is changing to paused
if ( value = = CommunicationStates . Paused )
{
if ( communicationState = = CommunicationStates . Printing )
2015-04-07 10:19:49 -07:00
{
2017-03-07 17:52:44 -08:00
PrePauseCommunicationState = CommunicationStates . Printing ;
2015-04-07 10:19:49 -07:00
}
else
{
2017-03-07 17:52:44 -08:00
PrePauseCommunicationState = CommunicationStates . PrintingFromSd ;
2015-04-07 10:19:49 -07:00
}
2019-03-22 11:51:45 -07:00
timePrinting . Stop ( ) ;
2015-04-08 15:20:10 -07:00
}
else if ( value = = CommunicationStates . FinishedPrint )
{
if ( activePrintTask ! = null )
{
activePrintTask . PrintEnd = DateTime . Now ;
2016-04-14 10:34:47 -07:00
activePrintTask . PercentDone = 100 ;
2015-04-08 15:20:10 -07:00
activePrintTask . PrintComplete = true ;
activePrintTask . Commit ( ) ;
}
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.
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 )
{
PrintFinished ? . Invoke ( this , new PrintFinishedEventArgs ( Printer . Bed . EditContext . SourceItem . Name ) ) ;
}
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
}
}
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
}
}
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
}
break ;
2015-04-08 15:20:10 -07:00
}
2015-02-05 07:50:57 -08:00
2015-04-08 15:20:10 -07:00
communicationState = value ;
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 ;
}
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
2017-11-02 12:26:14 -07:00
public double FanSpeed0To255
2015-04-08 15:20:10 -07:00
{
2018-02-16 14:50:12 -08:00
get = > fanSpeed ;
2015-04-08 15:20:10 -07:00
set
2015-02-05 07:50:57 -08:00
{
2015-04-08 15:20:10 -07:00
fanSpeed = Math . Max ( 0 , Math . Min ( 255 , value ) ) ;
OnFanSpeedSet ( null ) ;
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 ( "M106 S{0}" . FormatWith ( ( int ) ( fanSpeed + . 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
2017-03-07 17:52:44 -08:00
| | ( communicationState = = CommunicationStates . Paused & & PrePauseCommunicationState = = CommunicationStates . PrintingFromSd ) )
2015-04-08 15:20:10 -07:00
{
if ( totalSdBytes > 0 )
{
return currentSdBytes / totalSdBytes * 100 ;
}
return 0 ;
}
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
2017-02-01 17:36:33 -08:00
public bool PrintWasCanceled { get ; set ; } = false ;
2015-04-08 15:20:10 -07:00
public double RatioIntoCurrentLayer
{
get
{
2019-03-01 19:38:59 -08:00
if ( gCodeFileSwitcher ? . GCodeFile = = null )
2017-01-19 10:53:17 -08:00
{
return 0 ;
}
2019-03-01 19:38:59 -08:00
return gCodeFileSwitcher . GCodeFile . Ratio0to1IntoContainedLayer ( gCodeFileSwitcher . LineIndex ) ;
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-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-03-01 19:38:59 -08: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
2017-12-31 11:36:55 -08:00
public void ReleaseAndReportFailedConnection ( ConnectionFailure reason , string details = null )
2017-12-30 13:45:13 -08:00
{
2016-01-05 14:31:17 -08:00
// Shutdown the serial port
2015-04-08 15:20:10 -07:00
if ( serialPort ! = null )
{
// Close and dispose the serial port
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
serialPort = null ;
}
// Notify
2017-12-30 13:45:13 -08:00
OnConnectionFailed ( reason , details ) ;
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 ) )
{
//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 ( ) ;
//Debug.WriteLine("Open ports: {0}".FormatWith(portNames.Length));
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
activePrintTask = null ;
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
{
2018-12-05 13:48:25 -08: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
2017-12-30 07:50:13 -08:00
//Thread.Sleep(500);
2017-12-13 09:22:30 -08:00
CommunicationState = CommunicationStates . AttemptingToConnect ;
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.
2018-01-04 17:30:48 -08:00
serialPort . Write ( "M105\n" ) ;
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
var na = serialPort . BytesToRead ;
2017-12-30 07:50:13 -08:00
// Read, sanitize, store
string response = serialPort . ReadExisting ( ) . Replace ( "\r\n" , "\n" ) . Replace ( '\r' , '\n' ) ;
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
& & invalidCharactersOnFirstLine < = MAX_INVALID_CONNECTION_CHARS )
{
2017-12-30 09:31:57 -08:00
// Exit loop, continue with connect
2017-12-30 07:50:13 -08:00
break ;
}
else if ( invalidCharactersOnFirstLine > MAX_INVALID_CONNECTION_CHARS )
{
// 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
* /
2018-01-04 18:29:35 -08:00
CreateStreamProcessors ( null , false ) ;
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
2017-12-13 09:22:30 -08:00
Console . WriteLine ( "ReadFromPrinter thread created." ) ;
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-31 14:20:06 -08:00
2017-12-30 11:49:17 -08:00
OnConnectionFailed ( ConnectionFailure . UnsupportedBaudRate ) ;
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 ) ;
if ( AggContext . OperatingSystem = = OSType . X11 & & e . Message = = "Permission denied" )
{
UiThread . RunOnIdle ( ( ) = >
{
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.
Ubuntu / Debian
- - - - - - - - - - - - - -
` ` `
# sudo gpasswd - a $ USER dialout
` ` `
Arch
- - - -
` ` `
# sudo gpasswd - a $ USER uucp
# sudo gpasswd - a $ USER lock
` ` `
You will then need to logout and log back in to the computer for the changes to take effect . ";
2019-01-03 16:58:05 -08:00
StyledMessageBox . ShowMessageBox ( message , "Permission Denied" . Localize ( ) , useMarkdown : true ) ;
2018-12-19 16:43:39 -08: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 ) ;
2017-12-13 09:22:30 -08:00
}
}
}
else
{
2017-12-30 11:49:17 -08:00
if ( serialPortIsAlreadyOpen )
{
OnConnectionFailed ( ConnectionFailure . PortInUse ) ;
}
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
{
2017-12-30 11:49:17 -08:00
OnConnectionFailed (
ConnectionFailure . PortUnavailable ,
$"{this.ComPort} is not available" ) ;
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.
2018-11-09 11:05:25 -08: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 ) ;
2015-04-08 15:20:10 -07:00
FanSpeed0To255 = 0 ;
2018-01-04 17:30:48 -08:00
forceImmediateWrites = false ;
2015-04-08 15:20:10 -07:00
CommunicationState = CommunicationStates . Disconnecting ;
2018-11-16 16:21:30 -08:00
currentReadThreadIndex + + ;
2015-04-08 15:20:10 -07:00
if ( serialPort ! = null )
{
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
}
serialPort = null ;
CommunicationState = CommunicationStates . Disconnected ;
}
else
{
//Need to reset UI - even if manual disconnect
2018-03-21 14:20:43 -07:00
TurnOffBedAndExtruders ( TurnOff . Now ) ;
2015-04-08 15:20:10 -07:00
FanSpeed0To255 = 0 ;
}
OnEnabledChanged ( null ) ;
}
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-03-18 14:12:09 -07:00
int hotendIndex0Based = Math . Min ( extruderIndex , MAX_EXTRUDERS - 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-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
{
fanSpeed = 0 ;
OnFanSpeedSet ( null ) ;
}
2018-11-09 08:57:30 -08:00
public void FanSpeedWasWritenToPrinter ( 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 )
{
// when there is no explicit S value the assumption is 255
splitOnS = "M106 S255" . Split ( 'S' ) ;
}
if ( splitOnS . Length = = 2 )
{
string fanSpeedString = splitOnS [ 1 ] ;
try
{
int fanSpeedBeingSet = int . Parse ( fanSpeedString ) ;
if ( FanSpeed0To255 ! = fanSpeedBeingSet )
{
fanSpeed = fanSpeedBeingSet ;
OnFanSpeedSet ( null ) ;
}
}
2016-12-29 13:39:16 -08:00
catch ( Exception )
2015-04-08 15:20:10 -07:00
{
}
}
}
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
{
2017-09-08 10:23:28 -07:00
hotendIndex0Based = Math . Min ( hotendIndex0Based , MAX_EXTRUDERS - 1 ) ;
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
{
2017-09-08 10:23:28 -07:00
hotendIndex0Based = Math . Min ( hotendIndex0Based , MAX_EXTRUDERS - 1 ) ;
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
//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
{
2016-05-11 17:04:30 -07:00
if ( ( axis & Axis . X ) = = Axis . X )
{
command + = " X0" ;
}
if ( ( axis & Axis . Y ) = = Axis . Y )
{
command + = " Y0" ;
}
if ( ( axis & Axis . Z ) = = Axis . Z )
{
command + = " Z0" ;
}
2015-04-08 15:20:10 -07:00
}
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
2018-12-05 11:48:26 -08: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 ( ) ;
}
}
2017-12-30 11:49:17 -08:00
public void OnConnectionFailed ( ConnectionFailure reason , string failureDetails = null )
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 ;
2017-12-30 11:49:17 -08:00
OnEnabledChanged ( eventArgs ) ;
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 ;
}
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
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
}
}
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 ] ;
}
}
//Firmware version was detected and is different
2016-12-28 13:10:39 -08:00
if ( firmwareVersionReported ! = "" & & FirmwareVersion ! = firmwareVersionReported )
2015-04-08 15:20:10 -07:00
{
2016-12-28 13:10:39 -08:00
FirmwareVersion = firmwareVersionReported ;
2015-04-08 15:20:10 -07:00
OnFirmwareVersionRead ( null ) ;
}
}
}
// this is to make it misbehave
//int okCount = 1;
2018-11-09 08:57:30 -08:00
public void PrintingCanContinue ( string line )
2015-04-08 15:20:10 -07:00
{
//if ((okCount++ % 67) != 0)
{
timeHaveBeenWaitingForOK . Stop ( ) ;
}
}
2015-06-05 15:28:37 -07:00
public void ArduinoDtrReset ( )
2015-04-08 15:20:10 -07:00
{
2015-06-05 15:28:37 -07:00
// TODO: Ideally we would shutdown the printer connection when this method is called and we're connected. The
2017-04-11 10:41:23 -07:00
// current approach results in unpredictable behavior if the caller fails to close the connection
2018-12-05 13:48:25 -08: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
2018-02-01 14:51:44 -08: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
2016-11-29 14:58:24 -08:00
| | this . communicationState = = CommunicationStates . AttemptingToConnect )
2015-04-08 15:20:10 -07:00
& & CommunicationState ! = CommunicationStates . PrintingFromSd )
{
TryWriteNextLineFromGCodeFile ( ) ;
}
try
{
while ( serialPort ! = null
& & serialPort . BytesToRead > 0
& & readThreadHolder . IsCurrentThread ( ) )
{
2016-01-14 10:32:25 -08:00
lock ( locker )
{
2018-01-11 13:03:23 -08: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 ( ) ;
}
2015-04-08 15:20:10 -07:00
lastLineRead = dataLastRead . Substring ( 0 , returnPosition ) ;
2018-01-11 13:03:23 -08:00
var processingData = ProcessReadRegEx ( lastLineRead ) ;
lastLineRead = processingData . firstLine ;
dataLastRead + = processingData . extraLines ;
2015-04-08 15:20:10 -07:00
dataLastRead = dataLastRead . Substring ( returnPosition + 1 ) ;
// process this command
{
2018-11-09 11:41:08 -08: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
}
}
} while ( true ) ;
}
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
Console . WriteLine ( "Exiting ReadFromPrinter method: " + communicationState . ToString ( ) ) ;
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 08:46:05 -07:00
var lastAddd = queuedCommandStream . LastAdd ( ) ;
if ( lastAddd = = null
| | lastAddd ! = "M114" )
{
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 ) ;
}
if ( PositionReadType . HasFlag ( PositionReadType . HomeY ) )
{
HomingPosition = new Vector3 ( HomingPosition . X , lastReportedPosition . position . Y , HomingPosition . Z ) ;
}
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 ,
2017-09-08 10:23:28 -07:00
double [ ] actualHotendTemperature , Action < TemperatureEventArgs > hotendTemperatureChange ,
2017-03-21 14:26:54 -07:00
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
}
}
2017-09-08 10:23:28 -07:00
for ( int hotendIndex = 0 ; hotendIndex < MAX_EXTRUDERS ; 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
}
}
}
{
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)
if ( serialPort ! = null ) // we still have a serial port
{
2017-02-07 18:49:06 -08:00
Stop ( false ) ;
2015-06-10 10:19:25 -07:00
ClearQueuedGCode ( ) ;
2015-04-08 15:20:10 -07:00
2017-02-07 18:49:06 -08:00
CommunicationState = CommunicationStates . Disconnecting ;
2018-11-16 16:21:30 -08:00
currentReadThreadIndex + + ;
2017-03-02 09:47:24 -08:00
ToggleHighLowHigh ( serialPort ) ;
2017-02-07 18:49:06 -08:00
if ( serialPort ! = null )
{
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
}
serialPort = null ;
2017-02-09 13:51:16 -08:00
// make sure we clear out the stream processors
CreateStreamProcessors ( null , false ) ;
2017-02-07 18:49:06 -08:00
CommunicationState = CommunicationStates . Disconnected ;
2017-02-08 10:02:39 -08:00
// We were connected to a printer so try to reconnect
2017-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 ( ) ;
2015-12-31 09:40:17 -08:00
// let the process know we canceled not ended normally.
2015-06-10 10:19:25 -07:00
CommunicationState = CommunicationStates . Disconnected ;
}
2015-04-08 15:20:10 -07:00
}
}
2016-12-29 13:39:16 -08:00
catch ( Exception )
2015-06-10 10:19:25 -07:00
{
}
}
2017-03-02 09:47:24 -08:00
private void ToggleHighLowHigh ( IFrostedSerialPort serialPort )
2015-06-10 10:19:25 -07:00
{
serialPort . RtsEnable = true ;
serialPort . DtrEnable = true ;
Thread . Sleep ( 100 ) ;
serialPort . RtsEnable = false ;
serialPort . DtrEnable = false ;
Thread . Sleep ( 100 ) ;
serialPort . RtsEnable = true ;
serialPort . DtrEnable = true ;
2015-04-08 15:20:10 -07:00
}
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" ) ;
}
2015-12-31 09:40:17 -08:00
//Check line for line breaks, split and process separate if necessary
2015-04-08 15:20:10 -07:00
if ( lineToWrite . Contains ( "\n" ) )
{
string [ ] linesToWrite = lineToWrite . Split ( new string [ ] { "\n" } , StringSplitOptions . None ) ;
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 ) ;
}
}
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
}
}
}
}
2017-06-29 09:47:34 -07:00
#region ProcessRead
2018-01-06 16:03:03 -08:00
private static Regex getQuotedParts = new Regex ( @"([""'])(\\?.)*?\1" , RegexOptions . Compiled ) ;
2017-06-29 09:47:34 -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 ] ) ;
}
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-12-15 16:18:28 -08:00
2017-06-29 09:47:34 -07:00
}
#endregion // ProcessRead
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
{
2017-09-08 10:23:28 -07:00
hotendIndex0Based = Math . Min ( hotendIndex0Based , MAX_EXTRUDERS - 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-03-18 14:12:09 -07:00
HotendTargetTemperatureChanged ? . Invoke ( this , hotendIndex0Based ) ;
2015-04-08 15:20:10 -07:00
}
}
2018-01-16 08:42:35 -08:00
private CancellationTokenSource printingCancellation ;
2019-03-14 11:46:50 -07:00
public async Task StartPrint ( string gcodeFilename , PrintTask printTaskToUse = null , bool allowRecovery = true )
2019-03-23 18:37:53 -07:00
{
var gcodeStream = new StreamReader ( gcodeFilename ) ;
await StartPrint ( gcodeStream . BaseStream , gcodeFilename , printTaskToUse , allowRecovery ) ;
}
public async Task StartPrint ( Stream gcodeStream , string gcodeFileNameForTask = null , PrintTask printTaskToUse = null , bool allowRecovery = true )
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 ;
}
2018-01-16 08:42:35 -08:00
printingCancellation = new CancellationTokenSource ( ) ;
2016-11-09 09:22:19 -08:00
haveReportedError = false ;
2017-02-01 17:36:33 -08:00
PrintWasCanceled = false ;
2017-02-02 13:37:03 -08:00
waitingForPosition . Reset ( ) ;
2019-02-22 09:23:45 -08:00
PositionReadType = PositionReadType . None ;
2015-04-08 15:20:10 -07:00
ClearQueuedGCode ( ) ;
2016-04-14 18:01:45 -07:00
activePrintTask = printTaskToUse ;
2015-04-08 15:20:10 -07:00
2016-04-14 18:01:45 -07:00
await Task . Run ( ( ) = >
{
2018-01-16 08:17:24 -08:00
// LoadGCodeToPrint
2019-03-23 18:37:53 -07:00
CreateStreamProcessors ( gcodeStream , this . RecoveryIsEnabled ) ;
2016-04-14 18:01:45 -07:00
} ) ;
2018-01-16 08:14:04 -08:00
// DoneLoadingGCodeToPrint
switch ( communicationState )
{
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
& & activePrintTask = = null
& & allowRecovery )
2018-01-16 08:14:04 -08:00
{
2019-03-25 14:23:45 -07:00
// TODO: Fix printerItemID int requirement
activePrintTask = new PrintTask
{
PrintStart = DateTime . Now ,
PrinterId = this . Printer . Settings . ID . GetHashCode ( ) ,
PrintName = activePrintItem . PrintItem . Name ,
PrintItemId = activePrintItem . PrintItem . Id ,
PrintingGCodeFileName = gcodeFileNameForTask ,
PrintComplete = false
} ;
2018-01-16 08:14:04 -08:00
2019-03-25 14:23:45 -07:00
activePrintTask . Commit ( ) ;
2018-01-16 08:42:35 -08:00
2019-03-25 14:23:45 -07:00
Task . Run ( ( ) = > this . SyncProgressToDB ( printingCancellation . Token ) ) . ConfigureAwait ( false ) ;
}
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" ) ;
#endif
break ;
}
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
2018-11-09 11:05:25 -08: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
}
break ;
case CommunicationStates . AttemptingToConnect :
CommunicationState = CommunicationStates . FailedToConnect ;
2017-12-13 08:49:06 -08:00
//connectThread.Join(JoinThreadTimeoutMs);
2015-04-08 15:20:10 -07:00
CommunicationState = CommunicationStates . Disconnecting ;
2018-11-16 16:21:30 -08:00
currentReadThreadIndex + + ;
2015-04-08 15:20:10 -07:00
if ( serialPort ! = null )
{
serialPort . Close ( ) ;
serialPort . Dispose ( ) ;
serialPort = null ;
}
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
{
2018-01-16 08:42:35 -08:00
// Flag as canceled, wait briefly for listening threads to catch up
printingCancellation . Cancel ( ) ;
Thread . Sleep ( 15 ) ;
2018-01-06 13:26:28 -08:00
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
}
2015-12-31 09:40:17 -08:00
// let the process know we canceled not ended normally.
2017-02-01 17:36:33 -08:00
this . PrintWasCanceled = true ;
2016-12-01 10:59:03 -08:00
if ( markPrintCanceled
& & activePrintTask ! = null )
{
TimeSpan printTimeSpan = DateTime . Now . Subtract ( activePrintTask . PrintStart ) ;
activePrintTask . PrintEnd = DateTime . Now ;
activePrintTask . PrintComplete = false ;
activePrintTask . PrintingGCodeFileName = "" ;
activePrintTask . Commit ( ) ;
}
// no matter what we no longer have a print task
activePrintTask = null ;
2015-04-13 12:28:33 -07:00
}
}
private void CancelSDCardPrint ( )
{
2016-01-14 10:32:25 -08:00
lock ( locker )
2015-04-13 12:28:33 -07:00
{
// get rid of all the gcode we have left to print
ClearQueuedGCode ( ) ;
2015-12-31 09:40:17 -08:00
// let the process know we canceled not ended normally.
2015-04-13 12:28:33 -07:00
CommunicationState = CommunicationStates . Connected ;
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
{
2018-11-09 08:57:30 -08: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
{
2018-11-09 11:05:25 -08: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
{
2018-11-09 11:05:25 -08:00
ReadLineStartCallBacks . Unregister ( "File deleted:" , FileDeleteConfirmed ) ;
2018-11-09 08:57:30 -08:00
PrintingCanContinue ( line ) ;
2015-04-08 15:20:10 -07:00
}
2018-04-04 15:58:57 -07:00
private void KeepTrackOfAbsolutePositionAndDestination ( string lineBeingSent )
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 ;
2018-11-09 13:50:43 -08:00
DestinationChanged ? . Invoke ( this , null ) ;
2016-01-14 10:32:25 -08:00
}
}
}
2015-11-30 12:26:55 -08:00
2019-03-23 18:37:53 -07:00
private void CreateStreamProcessors ( Stream gcodeStream , bool recoveryEnabled )
2015-04-08 15:20:10 -07:00
{
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 ;
GCodeStream accumulatedStream = null ;
2015-12-01 14:49:50 -08:00
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
2018-01-06 13:26:28 -08:00
if ( this . RecoveryIsEnabled
2016-11-03 17:34:36 -07:00
& & activePrintTask ! = null ) // We are resuming a failed print (do lots of interesting stuff).
{
2019-03-01 19:38:59 -08:00
accumulatedStream = new SendProgressStream ( new PrintRecoveryStream ( gCodeFileSwitcher , Printer , activePrintTask . PercentDone ) , Printer ) ;
2016-12-14 11:26:53 -08:00
// And increment the recovery count
activePrintTask . RecoveryCount + + ;
activePrintTask . Commit ( ) ;
2016-11-03 17:34:36 -07:00
}
else
{
2019-03-01 19:38:59 -08:00
accumulatedStream = new SendProgressStream ( gCodeFileSwitcher , Printer ) ;
2016-11-03 17:34:36 -07:00
}
2019-03-01 19:38:59 -08:00
accumulatedStream = pauseHandlingStream = new PauseHandlingStream ( Printer , accumulatedStream ) ;
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 ) ;
var processWriteRegexStream = new ProcessWriteRegexStream ( Printer , accumulatedStream , queuedCommandStream ) ;
accumulatedStream = processWriteRegexStream ;
accumulatedStream = new RelativeToAbsoluteStream ( Printer , accumulatedStream ) ;
2019-02-19 15:26:09 -08:00
if ( ExtruderCount > 1 )
{
2019-03-01 19:38:59 -08:00
accumulatedStream = new ToolChangeStream ( Printer , accumulatedStream , queuedCommandStream ) ;
2019-02-19 15:26:09 -08:00
}
2019-03-01 19:38:59 -08:00
accumulatedStream = new BabyStepsStream ( Printer , accumulatedStream ) ;
2019-03-23 18:37:53 -07:00
bool enableLineSpliting = gcodeStream ! = null & & Printer . Settings . GetValue < bool > ( SettingsKey . enable_line_splitting ) ;
2019-03-01 19:38:59 -08:00
accumulatedStream = maxLengthStream = new MaxLengthStream ( Printer , accumulatedStream , enableLineSpliting ? 1 : 2000 ) ;
accumulatedStream = printLevelingStream = new PrintLevelingStream ( Printer , accumulatedStream , true ) ;
accumulatedStream = waitForTempStream = new WaitForTempStream ( Printer , accumulatedStream ) ;
accumulatedStream = new ExtrusionMultiplyerStream ( Printer , accumulatedStream ) ;
accumulatedStream = new FeedRateMultiplyerStream ( Printer , accumulatedStream ) ;
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
2019-03-31 10:01:52 -07:00
accumulatedStream = new RemoveNOPsStream ( Printer , accumulatedStream ) ;
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-03-01 19:38:59 -08:00
var transformedCommand = processWriteRegexStream . ProcessWriteRegEx ( "M110 N1" ) ;
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 ;
2018-01-16 08:42:35 -08:00
private void SyncProgressToDB ( CancellationToken cancellationToken )
{
//var timer = Stopwatch.StartNew();
while ( ! cancellationToken . IsCancellationRequested
& & this . CommunicationState ! = CommunicationStates . FinishedPrint
& & this . communicationState ! = CommunicationStates . Connected )
{
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.
if ( activePrintTask ! = null
& & activePrintTask . PercentDone < currentDone )
{
activePrintTask . PercentDone = currentDone ;
activePrintTask ? . Commit ( ) ;
// Interval looks to be ~10ms
//Console.WriteLine("DB write: {0}ms", timer.ElapsedMilliseconds);
//timer.Restart();
}
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
}
private void OnEnabledChanged ( EventArgs e )
{
2018-11-09 14:02:11 -08:00
EnableChanged ? . 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
}
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 string previousSentLine ;
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 ;
}
else if ( lastInstruction . StartsWith ( "M109 " )
| | 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-03-11 15:57:20 -07:00
else if ( lastInstruction . StartsWith ( "G28" ) )
{
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 ;
}
previousSentLine = this . currentSentLine ;
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
}
2017-02-01 17:36:33 -08:00
else if ( this . PrintWasCanceled )
2016-01-14 10:32:25 -08:00
{
CommunicationState = CommunicationStates . Connected ;
// never leave the extruder and the bed hot
ReleaseMotors ( ) ;
2018-03-21 14:20:43 -07:00
TurnOffBedAndExtruders ( TurnOff . AfterDelay ) ;
2017-02-01 17:36:33 -08:00
this . PrintWasCanceled = false ;
2016-01-14 10:32:25 -08:00
}
2017-04-11 10:41:23 -07:00
else if ( communicationState = = CommunicationStates . Printing ) // we finished printing normally
2016-01-14 10:32:25 -08:00
{
CommunicationState = CommunicationStates . FinishedPrint ;
2017-02-01 17:36:33 -08:00
this . PrintJobName = null ;
2016-01-14 10:32:25 -08:00
2017-01-03 10:45:16 -08:00
// get us back to the no printing setting (this will clear the queued commands)
CreateStreamProcessors ( null , false ) ;
2016-01-14 10:32:25 -08:00
// never leave the extruder and the bed hot
ReleaseMotors ( ) ;
2019-03-06 14:55:00 -08:00
if ( SecondsPrinted < 60 * 10 )
{
// 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 ;
}
}
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
{
2019-03-01 19:38:59 -08:00
get = > printLevelingStream . AllowLeveling ;
set = > printLevelingStream . AllowLeveling = value ;
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>
/// This gets set by the Pause Handling Stream when a change in the position sensor is seen.
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
2018-03-21 14:20:43 -07:00
public void TurnOffBedAndExtruders ( TurnOff turnOffTime )
2015-04-08 15:20:10 -07:00
{
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 ) ;
}
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 ) ;
}
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
2017-01-11 17:18:42 -08: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
{
2018-01-11 13:03:23 -08:00
bool sendLineWithChecksum = true ;
sendLineWithChecksum = ! lineToWrite . Contains ( "WRITE_RAW" ) ;
2016-01-14 10:32:25 -08:00
// remove the comment if any
lineToWrite = RemoveCommentIfAny ( lineToWrite ) ;
2018-04-04 15:58:57 -07:00
KeepTrackOfAbsolutePositionAndDestination ( lineToWrite ) ;
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
2017-11-30 13:59:14 -08: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
{
2015-04-08 15:20:10 -07:00
if ( serialPort ! = null & & serialPort . IsOpen )
{
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
| | lineWithoutChecksum . StartsWith ( "G92" ) // is a reset of printer position
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 ;
}
if ( lineWithoutChecksum . Contains ( "Y" ) )
{
readType | = PositionReadType . HomeY ;
}
if ( lineWithoutChecksum . Contains ( "Z" ) )
{
readType | = PositionReadType . HomeZ ;
}
if ( lineWithoutChecksum = = "G28" )
{
readType = PositionReadType . HomeAll ;
}
}
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 )
{
2018-11-09 11:41:08 -08: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 )
{
serialPort . Write ( lineToWrite ) ;
timeSinceLastWrite . Restart ( ) ;
timeHaveBeenWaitingForOK . Restart ( ) ;
}
2015-04-24 18:24:21 -07:00
}
2015-04-08 15:20:10 -07:00
//Debug.Write("w: " + lineToWrite);
}
catch ( IOException ex )
{
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
2017-12-30 13:45:13 -08:00
ReleaseAndReportFailedConnection ( ConnectionFailure . ConnectionLost , ex . Message ) ;
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 ) ;
2017-12-30 13:45:13 -08:00
ReleaseAndReportFailedConnection ( ConnectionFailure . UnauthorizedAccessException , e3 . Message ) ;
2015-04-08 15:20:10 -07:00
}
2016-12-29 13:39:16 -08:00
catch ( Exception )
2015-04-24 18:24:21 -07:00
{
}
2015-04-08 15:20:10 -07:00
}
else
{
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
}
2017-02-01 17:49:26 -08:00
public void MacroCancel ( )
{
2019-03-01 19:38:59 -08:00
maxLengthStream ? . Cancel ( ) ;
waitForTempStream ? . Cancel ( ) ;
queuedCommandStream ? . Cancel ( ) ;
2016-11-04 16:00:54 -07:00
}
2018-11-09 13:58:43 -08:00
public void Dispose ( )
{
Disposed ? . Invoke ( this , null ) ;
}
2018-11-16 16:21:30 -08:00
internal 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 ;
2018-11-16 16:21:30 -08:00
2015-11-04 17:13:53 -08:00
public class ReadThread
2015-04-08 15:20:10 -07:00
{
private int creationIndex ;
2017-04-11 10:41:23 -07:00
private static int numRunning = 0 ;
2018-11-16 16:21:30 -08:00
private 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 + + ;
2018-11-16 16:21:30 -08: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
2018-11-09 12:26:56 -08:00
// TODO: Consider if passing non-printer messages through LineSent is acceptable or if a dedicated event would add clarity
printerConnection ? . LineSent ? . Invoke ( this , "Read Thread Has Exited.\n" ) ;
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 ( )
{
2018-11-16 16:21:30 -08: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 ;
private string [ ] ringBuffer = new string [ RingBufferCount ] ;
2014-11-10 20:15:59 -08:00
2015-04-08 15:20:10 -07:00
public int Count { get { return addedCount ; } }
public string this [ int index ]
{
get
{
return ringBuffer [ index % RingBufferCount ] ;
}
set
{
ringBuffer [ index % RingBufferCount ] = value ;
}
}
internal void Add ( string lineWithChecksum )
{
this [ addedCount + + ] = lineWithChecksum ;
}
2016-12-02 13:51:58 -08:00
internal void SetStartingIndex ( int startingIndex )
2015-04-08 15:20:10 -07:00
{
2016-12-02 13:51:58 -08:00
addedCount = startingIndex ;
2015-04-08 15:20:10 -07:00
}
}
}
2017-12-30 11:49:17 -08:00
public class ConnectFailedEventArgs : EventArgs
{
public ConnectionFailure Reason { get ; }
public ConnectFailedEventArgs ( ConnectionFailure reason )
{
this . Reason = reason ;
}
}
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 ,
UsbDisconnected
2017-12-30 11:49:17 -08:00
}
2019-01-18 09:49:38 -08:00
public class PrintFinishedEventArgs : EventArgs
2015-04-08 15:20:10 -07:00
{
2019-01-18 09:49:38 -08:00
public PrintFinishedEventArgs ( string name )
2015-04-08 15:20:10 -07:00
{
2017-11-14 14:02:56 -08:00
this . ItemName = name ;
2015-04-08 15:20:10 -07:00
}
2017-11-14 14:02:56 -08:00
public string ItemName { get ; }
2015-04-08 15:20:10 -07:00
}
2019-01-18 09:49:38 -08:00
public class PrintPauseEventArgs : EventArgs
{
public PrintPauseEventArgs ( string name , bool filamentRunout , int layerNumber )
{
this . ItemName = name ;
this . filamentRunout = filamentRunout ;
this . layerNumber = layerNumber ;
}
public string ItemName { get ; }
public bool filamentRunout { get ; }
public int layerNumber { get ; }
}
2015-04-08 15:20:10 -07:00
/// <summary>
/// This is a class to pass temperatures to callbacks that expect them.
/// </summary>
public class TemperatureEventArgs : EventArgs
{
public TemperatureEventArgs ( int index0Based , double temperature )
{
2017-01-23 14:03:04 -08:00
this . Index0Based = index0Based ;
this . Temperature = temperature ;
2015-04-08 15:20:10 -07:00
}
2017-01-23 14:03:04 -08:00
public int Index0Based { get ; }
public double Temperature { get ; }
2015-04-08 15:20:10 -07:00
}
2018-03-14 13:49:57 -07:00
}