public override string ReadLine() { // Send any commands that are queue before moving on to the internal stream. string nextCommand = queuedCommands.ReadLine(); if (nextCommand != null) { return(nextCommand); } switch (RecoveryState) { // heat the extrude to remove it from the part case RecoveryState.RemoveHeating: // TODO: make sure we heat up all the extruders that we need to (all that are used) queuedCommands.Add("G21; set units to millimeters"); queuedCommands.Add("M107; fan off"); queuedCommands.Add("T0; set the active extruder to 0"); queuedCommands.Add("G90; use absolute coordinates"); queuedCommands.Add("G92 E0; reset the expected extruder position"); queuedCommands.Add("M82; use absolute distance for extrusion"); bool hasHeatedBed = printer.Settings.GetValue <bool>(SettingsKey.has_heated_bed); double bedTemp = printer.Settings.GetValue <double>(SettingsKey.bed_temperature); if (hasHeatedBed && bedTemp > 0) { // start heating the bed queuedCommands.Add($"M140 S{bedTemp}"); } // heat up the extruder queuedCommands.Add("M109 S{0}".FormatWith(printer.Settings.Helpers.ExtruderTemperature(0))); if (hasHeatedBed && bedTemp > 0) { // finish heating the bed queuedCommands.Add($"M190 S{bedTemp}"); } RecoveryState = RecoveryState.Raising; return(""); // remove it from the part case RecoveryState.Raising: // We don't know where the printer is for sure (it make have been turned off). Disable leveling until we know where it is. PrintLevelingStream.AllowLeveling = false; queuedCommands.Add("M114 ; get current position"); queuedCommands.Add("G91 ; move relative"); queuedCommands.Add("G1 Z10 F{0}".FormatWith(printer.Settings.ZSpeed())); queuedCommands.Add("G90 ; move absolute"); RecoveryState = RecoveryState.Homing; return(""); // if top homing, home the extruder case RecoveryState.Homing: if (printer.Settings.GetValue <bool>(SettingsKey.z_homes_to_max)) { queuedCommands.Add("G28"); } else { // home x queuedCommands.Add("G28 X0"); // home y queuedCommands.Add("G28 Y0"); // move to the place we can home z from Vector2 recoveryPositionXy = printer.Settings.GetValue <Vector2>(SettingsKey.recover_position_before_z_home); queuedCommands.Add("G1 X{0:0.###}Y{1:0.###}F{2}".FormatWith(recoveryPositionXy.X, recoveryPositionXy.Y, printer.Settings.XSpeed())); // home z queuedCommands.Add("G28 Z0"); } // We now know where the printer is re-enable print leveling PrintLevelingStream.AllowLeveling = true; RecoveryState = RecoveryState.FindingRecoveryLayer; return(""); // This is to recover printing if an out a filament occurs. // Help the user move the extruder down to just touching the part case RecoveryState.FindingRecoveryLayer: if (false) // help the user get the head to the right position { // move to above the completed print // move over a know good part of the model at the current top layer (extrude vertex from gcode) // let the user move down until they like the height // calculate that position and continue } else // we are resuming because of disconnect or reset, skip this { RecoveryState = RecoveryState.SkippingGCode; goto case RecoveryState.SkippingGCode; } case RecoveryState.SkippingGCode: // run through the gcode that the device expected looking for things like temp // and skip everything else until we get to the point we left off last time int commandCount = 0; boundsOfSkippedLayers = RectangleDouble.ZeroIntersection; while (internalStream.GCodeFile.PercentComplete(internalStream.LineIndex) < percentDone) { string line = internalStream.ReadLine(); if (line == null) { break; } commandCount++; // make sure we don't parse comments if (line.Contains(";")) { line = line.Split(';')[0]; } lastDestination = GetPosition(line, lastDestination); if (commandCount > 100) { boundsOfSkippedLayers.ExpandToInclude(lastDestination.position.Xy); } // check if the line is something we want to send to the printer (like a temp) if (line.StartsWith("M109") || // heat and wait extruder line.StartsWith("M104") || // heat extruder line.StartsWith("M190") || // heat and wait bed line.StartsWith("M140") || // heat bed line.StartsWith("T") || // switch extruder line.StartsWith("M106") || // fan on line.StartsWith("M107") || // fan off line.StartsWith("G92")) // set position { return(line); } } RecoveryState = RecoveryState.PrimingAndMovingToStart; // make sure we always- pick up the last movement boundsOfSkippedLayers.ExpandToInclude(lastDestination.position.Xy); return(""); case RecoveryState.PrimingAndMovingToStart: { if (printer.Settings.GetValue("z_homes_to_max") == "0") // we are homed to the bed { // move to the height we can recover printing from Vector2 recoverPositionXy = printer.Settings.GetValue <Vector2>(SettingsKey.recover_position_before_z_home); queuedCommands.Add(CreateMovementLine(new PrinterMove(new VectorMath.Vector3(recoverPositionXy.X, recoverPositionXy.Y, lastDestination.position.Z), 0, printer.Settings.ZSpeed()))); } double extruderWidth = printer.Settings.GetValue <double>(SettingsKey.nozzle_diameter); // move to a position outside the printed bounds queuedCommands.Add(CreateMovementLine(new PrinterMove( new Vector3(boundsOfSkippedLayers.Left - extruderWidth * 2, boundsOfSkippedLayers.Bottom + boundsOfSkippedLayers.Height / 2, lastDestination.position.Z), 0, printer.Settings.XSpeed()))); // let's prime the extruder queuedCommands.Add("G1 E10 F{0}".FormatWith(printer.Settings.EFeedRate(0))); // extrude 10 queuedCommands.Add("G1 E9"); // and retract a bit // move to the actual print position queuedCommands.Add(CreateMovementLine(new PrinterMove(lastDestination.position, 0, printer.Settings.XSpeed()))); /// reset the printer to know where the filament should be queuedCommands.Add("G92 E{0}".FormatWith(lastDestination.extrusion)); RecoveryState = RecoveryState.PrintingSlow; } return(""); case RecoveryState.PrintingSlow: { string lineToSend = internalStream.ReadLine(); if (lineToSend == null) { return(null); } if (!GCodeFile.IsLayerChange(lineToSend)) { // have not seen the end of this layer so keep printing slow if (LineIsMovement(lineToSend)) { PrinterMove currentMove = GetPosition(lineToSend, lastDestination); PrinterMove moveToSend = currentMove; moveToSend.feedRate = recoverFeedRate; lineToSend = CreateMovementLine(moveToSend, lastDestination); lastDestination = currentMove; return(lineToSend); } return(lineToSend); } } // we only fall through to here after seeing the next "; Layer:" RecoveryState = RecoveryState.PrintingToEnd; return(""); case RecoveryState.PrintingToEnd: return(internalStream.ReadLine()); } return(null); }
public override string ReadLine() { string nextCommand = queuedCommands.ReadLine(); if (nextCommand != null) { return(nextCommand); } switch (resumeState) { // heat the extrude to remove it from the part case ResumeState.RemoveHeating: // TODO: make sure we heat up all the extruders that we need to (all that are used) queuedCommands.Add("G21; set units to millimeters"); queuedCommands.Add("M107; fan off"); queuedCommands.Add("T0; set the active extruder to 0"); queuedCommands.Add("G90; use absolute coordinates"); queuedCommands.Add("G92 E0; reset the expected extruder position"); queuedCommands.Add("M82; use absolute distance for extrusion"); queuedCommands.Add("M109 S{0}".FormatWith(ActiveSliceSettings.Instance.ExtruderTemperature(0))); resumeState = ResumeState.Raising; return(""); // remove it from the part case ResumeState.Raising: queuedCommands.Add("M114 ; get current position"); queuedCommands.Add("G91 ; move relative"); queuedCommands.Add("G1 Z10 F{0}".FormatWith(MovementControls.ZSpeed)); queuedCommands.Add("G90 ; move absolute"); resumeState = ResumeState.Homing; return(""); // if top homing, home the extruder case ResumeState.Homing: if (ActiveSliceSettings.Instance.ActiveValue("z_homes_to_max") == "1") { queuedCommands.Add("G28"); } else { // home x queuedCommands.Add("G28 X0"); // home y queuedCommands.Add("G28 Y0"); // move to the place we can home z from Vector2 resumePositionXy = ActiveSliceSettings.Instance.ActiveVector2("resume_position_before_z_home"); queuedCommands.Add("G1 X{0:0.000}Y{1:0.000}F{2}".FormatWith(resumePositionXy.x, resumePositionXy.y, MovementControls.XSpeed)); // home z queuedCommands.Add("G28 Z0"); } resumeState = ResumeState.FindingResumeLayer; return(""); // This is to resume printing if an out a filament occurs. // Help the user move the extruder down to just touching the part case ResumeState.FindingResumeLayer: if (false) // help the user get the head to the right position { // move to above the completed print // move over a know good part of the model at the current top layer (extrude vertex from gcode) // let the user move down until they like the height // calculate that position and continue } else // we are resuming because of disconnect or reset, skip this { resumeState = ResumeState.SkippingGCode; goto case ResumeState.SkippingGCode; } case ResumeState.SkippingGCode: // run through the gcode that the device expected looking for things like temp // and skip everything else until we get to the point we left off last time while (internalStream.FileStreaming.PercentComplete(internalStream.LineIndex) < percentDone) { string line = internalStream.ReadLine(); lastDestination = GetPosition(line, lastDestination); // check if the line is something we want to send to the printer (like a temp) if (line.StartsWith("M109") || line.StartsWith("M104") || line.StartsWith("T") || line.StartsWith("M106") || line.StartsWith("M107")) { return(line); } } resumeState = ResumeState.PrimingAndMovingToStart; return(""); case ResumeState.PrimingAndMovingToStart: { // let's prime the extruder, move to a good position over the part, then start printing queuedCommands.Add("G1 E5"); queuedCommands.Add("G1 E4"); if (ActiveSliceSettings.Instance.ActiveValue("z_homes_to_max") == "0") // we are homed to the bed { // move to the height we can resume printing from Vector2 resumePositionXy = ActiveSliceSettings.Instance.ActiveVector2("resume_position_before_z_home"); queuedCommands.Add(CreateMovementLine(new PrinterMove(new VectorMath.Vector3(resumePositionXy.x, resumePositionXy.y, lastDestination.position.z + 5), 0, MovementControls.ZSpeed))); // move just above the actual print position queuedCommands.Add(CreateMovementLine(new PrinterMove(lastDestination.position + new VectorMath.Vector3(0, 0, 5), 0, MovementControls.XSpeed))); // move down to part queuedCommands.Add(CreateMovementLine(new PrinterMove(lastDestination.position, 0, MovementControls.ZSpeed))); } else { // move to the actual print position queuedCommands.Add(CreateMovementLine(new PrinterMove(lastDestination.position, 0, MovementControls.ZSpeed))); } // extrude back to our filament start queuedCommands.Add("G1 E5"); /// reset the printer to know where the filament should be queuedCommands.Add("G92 E{0}".FormatWith(lastDestination.extrusion)); resumeState = ResumeState.PrintingSlow; } return(""); case ResumeState.PrintingSlow: { string lineToSend = internalStream.ReadLine(); if (lineToSend != null && lineToSend.StartsWith("; LAYER:")) { if (lineToSend != null && LineIsMovement(lineToSend)) { PrinterMove currentMove = GetPosition(lineToSend, lastDestination); PrinterMove moveToSend = currentMove; double feedRate; string firstLayerSpeed = ActiveSliceSettings.Instance.ActiveValue("resume_first_layer_speed"); if (!double.TryParse(firstLayerSpeed, out feedRate)) { feedRate = 10; } feedRate *= 60; moveToSend.feedRate = feedRate; lineToSend = CreateMovementLine(moveToSend, lastDestination); lastDestination = currentMove; return(lineToSend); } return(lineToSend); } } resumeState = ResumeState.PrintingToEnd; return(""); case ResumeState.PrintingToEnd: return(internalStream.ReadLine()); } return(null); }