public override string ReadLine() { string lineToSend = base.ReadLine(); if (lineToSend != null && lineToSend.EndsWith("; NO_PROCESSING")) { return(lineToSend); } if (lineToSend != null && LineIsMovement(lineToSend)) { PrinterMove currentMove = GetPosition(lineToSend, lastDestination); if (currentMove.HaveAnyPosition) { ClampToPrinter(ref currentMove); lineToSend = CreateMovementLine(currentMove, lastDestination); } lastDestination = currentMove; return(lineToSend); } return(lineToSend); }
public override void SetPrinterPosition(PrinterMove outputPosition) { var outputWithLeveling = PrinterMove.Unknown; outputWithLeveling.CopyKnowSettings(outputPosition); if (LevelingActive && outputPosition.PositionFullyKnown) { string expectedOutput = CreateMovementLine(outputPosition); string doubleLeveledOutput = GetLeveledPosition(expectedOutput, outputPosition); PrinterMove doubleLeveledDestination = GetPosition(doubleLeveledOutput, PrinterMove.Unknown); PrinterMove deltaToLeveledPosition = doubleLeveledDestination - outputPosition; this.inputUnleveled = outputPosition - deltaToLeveledPosition; // clean up settings that we don't want to be subtracted this.inputUnleveled.extrusion = outputPosition.extrusion; this.inputUnleveled.feedRate = outputPosition.feedRate; internalStream.SetPrinterPosition(this.inputUnleveled); } else { this.inputUnleveled = outputPosition; internalStream.SetPrinterPosition(this.inputUnleveled); } }
public override void SetPrinterPosition(PrinterMove outputPosition) { outputWithBabyStepping.CopyKnowSettings(outputPosition); // calculate our offset to pass on to internal streams inputNoBabyStepping = outputWithBabyStepping; inputNoBabyStepping.position -= BabbyStepOffset; inputNoBabyStepping.position += extruderOffsets[Math.Min(extruderIndex, 4)]; internalStream.SetPrinterPosition(inputNoBabyStepping); }
public override string ReadLine() { var baseLine = base.ReadLine(); if (baseLine == null) { return(null); } if (baseLine.EndsWith("; NO_PROCESSING")) { return(baseLine); } // if the line has no content don't process it if (baseLine.Length == 0 || baseLine.Trim().Length == 0) { return(baseLine); } var lines = ProcessWriteRegEx(baseLine, printer); for (int i = lines.Count - 1; i >= 1; i--) { queueStream.Add(lines[i], true); } var lineToSend = lines[0]; if (lineToSend != null && LineIsMovement(lineToSend)) { currentMove = GetPosition(lineToSend, currentMove); } // is it a position set? if (lineToSend.StartsWith("G92")) { GCodeFile.GetFirstNumberAfter("X", lineToSend, ref this.currentMove.position.X); GCodeFile.GetFirstNumberAfter("Y", lineToSend, ref this.currentMove.position.Y); GCodeFile.GetFirstNumberAfter("Z", lineToSend, ref this.currentMove.position.Z); GCodeFile.GetFirstNumberAfter("E", lineToSend, ref this.currentMove.extrusion); // tell the stream pipeline what the actual printer position is this.SetPrinterPosition(this.currentMove); } return(lineToSend); }
public override string ReadLine() { if (!wroteLevelingStatus && LevelingActive) { wroteLevelingStatus = true; return("; Software Leveling Applied"); } string lineToSend = base.ReadLine(); if (lineToSend != null && lineToSend.EndsWith("; NO_PROCESSING")) { return(lineToSend); } if (lineToSend == "; Software Leveling Applied") { gcodeAlreadyLeveled = true; } if (lineToSend != null && LevelingActive && !gcodeAlreadyLeveled) { if (LineIsMovement(lineToSend)) { PrinterMove currentUnleveledDestination = GetPosition(lineToSend, inputUnleveled); var leveledLine = GetLeveledPosition(lineToSend, currentUnleveledDestination); // TODO: clamp to 0 - baby stepping - extruder z-offset, so we don't go below the bed (for the active extruder) inputUnleveled = currentUnleveledDestination; return(leveledLine); } else if (lineToSend.StartsWith("G29")) { // remove G29 (machine prob bed) if we are running our own leveling. lineToSend = base.ReadLine(); // get the next line instead } } return(lineToSend); }
public static PrinterMove GetPosition(string lineBeingSent, PrinterMove startPositionPosition) { if (lineBeingSent.StartsWith("G28") || lineBeingSent.StartsWith("G29") || lineBeingSent.StartsWith("G30")) { return(PrinterMove.Unknown); } PrinterMove currentDestination = startPositionPosition; GCodeFile.GetFirstNumberAfter("X", lineBeingSent, ref currentDestination.position.X); GCodeFile.GetFirstNumberAfter("Y", lineBeingSent, ref currentDestination.position.Y); GCodeFile.GetFirstNumberAfter("Z", lineBeingSent, ref currentDestination.position.Z); GCodeFile.GetFirstNumberAfter("E", lineBeingSent, ref currentDestination.extrusion); GCodeFile.GetFirstNumberAfter("F", lineBeingSent, ref currentDestination.feedRate); return(currentDestination); }
public override string ReadLine() { string lineToSend = base.ReadLine(); if (lineToSend != null && lineToSend.EndsWith("; NO_PROCESSING")) { return(lineToSend); } if (lineToSend != null && lineToSend.StartsWith("T")) { int extruder = 0; if (GCodeFile.GetFirstNumberAfter("T", lineToSend, ref extruder)) { extruderIndex = extruder; } } if (lineToSend != null && LineIsMovement(lineToSend)) { inputNoBabyStepping = GetPosition(lineToSend, inputNoBabyStepping); // it is a struct so this is making a new copy we con modify PrinterMove moveToSend = inputNoBabyStepping; moveToSend.position += BabbyStepOffset; moveToSend.position -= extruderOffsets[Math.Min(extruderIndex, 4)]; if (moveToSend.HaveAnyPosition) { lineToSend = CreateMovementLine(moveToSend, outputWithBabyStepping); } outputWithBabyStepping = moveToSend; return(lineToSend); } return(lineToSend); }
public string CreateMovementLine(PrinterMove destination, PrinterMove start) { bool moveHasExtrusion = destination.extrusion != double.PositiveInfinity && destination.extrusion != start.extrusion; string command = (useG0ForMovement && !moveHasExtrusion) ? "G0 " : "G1 "; var sb = new StringBuilder(command); if (destination.position.X != start.position.X) { sb.AppendFormat("X{0:0.##} ", destination.position.X); } if (destination.position.Y != double.PositiveInfinity && destination.position.Y != start.position.Y) { sb.AppendFormat("Y{0:0.##} ", destination.position.Y); } if (destination.position.Z != double.PositiveInfinity && destination.position.Z != start.position.Z) { sb.AppendFormat("Z{0:0.###} ", destination.position.Z); } if (moveHasExtrusion) { sb.AppendFormat("E{0:0.###} ", destination.extrusion); } if (destination.feedRate != double.PositiveInfinity && destination.feedRate != start.feedRate) { if (destination.feedRate > 0) { sb.AppendFormat("F{0:0.##}", destination.feedRate); } } return(sb.ToString().Trim()); }
private string GetLeveledPosition(string lineBeingSent, PrinterMove currentDestination) { PrintLevelingData levelingData = printer.Settings.Helpers.PrintLevelingData; if (levelingData != null && printer.Settings?.GetValue <bool>(SettingsKey.print_leveling_enabled) == true && (lineBeingSent.StartsWith("G0 ") || lineBeingSent.StartsWith("G1 "))) { if (currentLevelingFunctions == null || currentProbeZOffset != printer.Settings.GetValue <Vector3>(SettingsKey.probe_offset) || !levelingData.SamplesAreSame(currentLevelingFunctions.SampledPositions)) { currentProbeZOffset = printer.Settings.GetValue <Vector3>(SettingsKey.probe_offset); currentLevelingFunctions = new LevelingFunctions(printer, levelingData); } lineBeingSent = currentLevelingFunctions.ApplyLeveling(lineBeingSent, currentDestination.position); } return(lineBeingSent); }
private void ClampToPrinter(ref PrinterMove moveToSend) { var bounds = extruderBounds[printer.Connection.ActiveExtruderIndex]; // clamp to each axis for (int i = 0; i < 3; i++) { if (moveToSend.position[i] < bounds.MinXYZ[i]) { moveToSend.position[i] = bounds.MinXYZ[i]; // If we clamp, than do not do any extrusion at all moveToSend.extrusion = lastDestination.extrusion; } else if (moveToSend.position[i] > bounds.MaxXYZ[i]) { moveToSend.position[i] = bounds.MaxXYZ[i]; // If we clamp, than do not do any extrusion at all moveToSend.extrusion = lastDestination.extrusion; } } }
public override string ReadLine() { string lineToSend = internalStream.ReadLine(); if (lineToSend != null && lineToSend.EndsWith("; NO_PROCESSING")) { return(lineToSend); } if (lineToSend != null && LineIsMovement(lineToSend)) { PrinterMove currentMove = GetPosition(lineToSend, this.lastDestination); PrinterMove moveToSend = currentMove; // If we are on T1 if (printer.Connection.ActiveExtruderIndex == 1) { bool extrusionDelta = currentMove.extrusion != this.lastDestination.extrusion; bool xyPositionDelta = currentMove.position.X != this.lastDestination.position.X || currentMove.position.Y != this.lastDestination.position.Y; // and there is both extrusion and position delta if (extrusionDelta && xyPositionDelta) { // modify the speed by the T1 multiplier moveToSend.feedRate *= t0Multiplier; } } if (moveToSend.HaveAnyPosition) { lineToSend = CreateMovementLine(moveToSend, this.lastDestination); } this.lastDestination = currentMove; return(lineToSend); } return(lineToSend); }
public void CopyKnowSettings(PrinterMove copyFrom) { if (copyFrom.position.X != double.PositiveInfinity) { this.position.X = copyFrom.position.X; } if (copyFrom.position.Y != double.PositiveInfinity) { this.position.Y = copyFrom.position.Y; } if (copyFrom.position.Z != double.PositiveInfinity) { this.position.Z = copyFrom.position.Z; } if (copyFrom.extrusion != double.PositiveInfinity) { this.extrusion = copyFrom.extrusion; } if (copyFrom.feedRate != double.PositiveInfinity) { this.feedRate = copyFrom.feedRate; } }
public override void SetPrinterPosition(PrinterMove position) { this.lastDestination.CopyKnowSettings(position); internalStream.SetPrinterPosition(lastDestination); }
public override string ReadLine() { // Send any commands that are queue before moving on to the internal stream. string nextCommand = queuedCommands.ReadLine(); if (nextCommand != null) { lastLine = nextCommand; 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.ExtruderTargetTemperature(0))); if (hasHeatedBed && bedTemp > 0) { // finish heating the bed queuedCommands.Add($"M190 S{bedTemp}"); } RecoveryState = RecoveryState.Raising; lastLine = ""; return(""); // remove it from the part case RecoveryState.Raising: // We don't know where the printer is for sure (it may have been turned off). Disable leveling until we know where it is. printer.Connection.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; lastLine = ""; 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 printer.Connection.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 { lastLine = line; 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 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); } lastLine = 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() { if (queuedCommands.Count > 0) { return(queuedCommands.Dequeue()); } string lineToSend = base.ReadLine(); if (lineToSend == null) { return(null); } if (lineToSend.EndsWith("; NO_PROCESSING")) { return(lineToSend); } var requestedToolForTempChange = -1; // if we see a temp command remember what heat we are setting if (lineToSend.StartsWith("M109") || lineToSend.StartsWith("M104")) { int toolTemp = 0; // get the temp we are setting GCodeFile.GetFirstNumberAfter("S", lineToSend, ref toolTemp); // set it to the tool we will be changing to requestedToolForTempChange = RequestedTool; // check if this command contains a tool specification GCodeFile.GetFirstNumberAfter("T", lineToSend, ref requestedToolForTempChange); if (!lineToSend.Contains("; INACTIVE_COOL_DOWN")) { if (targetTemps[requestedToolForTempChange] != toolTemp) { targetTemps[requestedToolForTempChange] = toolTemp; } } } // check if any of the heaters we will be switching to need to start heating ManageReHeating(lineToSend); if (lineToSend == completedBeforeGCodeString && sendState != SendStates.Normal) { activeTool = RequestedTool; sendState = SendStates.Normal; QueueAfterGCode(); } var lineNoComment = lineToSend.Split(';')[0]; if (lineNoComment == "G28" || lineNoComment == "G28 Z0") { sendState = SendStates.Normal; RequestedTool = activeTool = 0; } // if this command is a temperature change request if (requestedToolForTempChange != -1) { if (requestedToolForTempChange != activeTool) { // For smoothie, switch back to the extrude we were using before the temp change (smoothie switches to the specified extruder, marlin repetier do not) queuedCommands.Enqueue($"T{activeTool}"); var temp = GetNextToolTemp(requestedToolForTempChange); if (temp > 0) { return($"{lineToSend.Substring(0, 4)} T{requestedToolForTempChange} S{temp}"); } else // send the temp as requested { return(lineToSend); } } // if we are waiting to switch to the next tool else if (activeTool != RequestedTool) { // if this command does not include the extruder to switch to, than we need to switch before sending it if (!lineNoComment.Contains("T")) { queuedCommands.Enqueue($"T{RequestedTool}"); } // For smoothie, switch back to the extrude we were using before the temp change (smoothie switches to the specified extruder, marlin repetier do not) queuedCommands.Enqueue($"T{activeTool}"); // then send the heat command return(lineToSend); } } // if this is a tool change request else if (lineToSend.StartsWith("T")) { int changeCommandTool = -1; if (GCodeFile.GetFirstNumberAfter("T", lineToSend, ref changeCommandTool)) { if (changeCommandTool == activeTool) { if (sendState == SendStates.WaitingForMove) { // we have to switch back to our starting tool without a move // change back to normal processing and don't change tools sendState = SendStates.Normal; var lastRequestedTool = RequestedTool; // set the requested tool RequestedTool = changeCommandTool; // don't send the change are we are on the right tool now return($"; switch back without move from T{lastRequestedTool} to T{activeTool}"); } } else // we are switching tools { if (sendState == SendStates.Normal) { sendState = SendStates.WaitingForMove; // set the requested tool RequestedTool = changeCommandTool; // don't queue the tool change until after the before gcode has been sent return($"; waiting for move on T{RequestedTool}"); } } } } // if it is only an extrusion move if (sendState == SendStates.WaitingForMove && activeTool != RequestedTool && // is different than the last extruder set (lineNoComment.StartsWith("G0 ") || lineNoComment.StartsWith("G1 ")) && // is a G1 or G0 lineNoComment.Contains("E") // it is an extrusion move // and have no other position information && !lineNoComment.Contains("X") && !lineNoComment.Contains("Y") && !lineNoComment.Contains("Z")) { double ePosition = 0; if (GCodeFile.GetFirstNumberAfter("E", lineNoComment, ref ePosition)) { // switch extruders queuedCommands.Enqueue($"T{RequestedTool}"); // if we know the current E position before the switch // set the E value to the previous E value. if (lastDestination.extrusion != double.PositiveInfinity) { // On Marlin E position is share between extruders and this code has no utility // On Smoothie E is stored per extruder and this makes it behave the same as Marlin queuedCommands.Enqueue($"G92 E{lastDestination.extrusion}"); } // send the extrusion queuedCommands.Enqueue(lineNoComment + " ; NO_PROCESSING"); // switch back queuedCommands.Enqueue($"T{activeTool}"); lastDestination.extrusion = ePosition; queuedCommands.Enqueue($"G92 E{lastDestination.extrusion}"); return(""); } } if (QueueBeforeIfNeedToSwitchExtruders(lineToSend, lineNoComment)) { return(""); } if (LineIsMovement(lineToSend)) { lastDestination = GetPosition(lineToSend, lastDestination); } return(lineToSend); }
public override string ReadLine() { string lineToSend = null; // lock queue lock (locker) { if (commandQueue.Count > 0) { lineToSend = commandQueue[0]; commandQueue.RemoveAt(0); } } if (lineToSend == null) { if (!printer.Connection.Paused) { lineToSend = base.ReadLine(); if (lineToSend == null) { return(lineToSend); } if (lineToSend.EndsWith("; NO_PROCESSING")) { return(lineToSend); } // We got a line from the gcode we are sending check if we should queue a request for filament runout if (printer.Settings.GetValue <bool>(SettingsKey.filament_runout_sensor)) { // request to read the endstop state if (!timeSinceLastEndstopRead.IsRunning || timeSinceLastEndstopRead.ElapsedMilliseconds > 5000) { printer.Connection.QueueLine("M119"); timeSinceLastEndstopRead.Restart(); } } lastSendTimeMs = UiThread.CurrentTimerMs; } else { lineToSend = ""; // If more than 10 seconds have passed send a movement command so the motors will stay locked if (UiThread.CurrentTimerMs - lastSendTimeMs > 10000) { printer.Connection.MoveRelative(PrinterAxis.X, .1, printer.Settings.Helpers.ManualMovementSpeeds().X); printer.Connection.MoveRelative(PrinterAxis.X, -.1, printer.Settings.Helpers.ManualMovementSpeeds().X); lastSendTimeMs = UiThread.CurrentTimerMs; } } } if (GCodeFile.IsLayerChange(lineToSend)) { int layerNumber = GCodeFile.GetLayerNumber(lineToSend); if (PauseOnLayer(layerNumber)) { this.DoPause( PauseReason.PauseLayerReached, // make the layer 1 based (the internal code is 0 based) layerNumber + 1); } } else if (lineToSend.StartsWith("M226") || lineToSend.StartsWith("@pause")) { DoPause(PauseReason.GCodeRequest); lineToSend = ""; } else if (lineToSend == "MH_PAUSE") { moveLocationAtEndOfPauseCode = LastDestination; if (printer.Connection.Printing) { // remember where we were after we ran the pause gcode printer.Connection.CommunicationState = CommunicationStates.Paused; } lineToSend = ""; } else if (readOutOfFilament) { readOutOfFilament = false; DoPause(PauseReason.FilamentRunout); lineToSend = ""; } // keep track of the position if (lineToSend != null && LineIsMovement(lineToSend)) { lastDestination = GetPosition(lineToSend, lastDestination); } return(lineToSend); }
public override void SetPrinterPosition(PrinterMove position) { this.currentMove.CopyKnowSettings(position); internalStream.SetPrinterPosition(currentMove); }
public override void SetPrinterPosition(PrinterMove position) { }
public string CreateMovementLine(PrinterMove currentDestination) { return(CreateMovementLine(currentDestination, PrinterMove.Unknown)); }
/// <summary> /// Sends the printer position back up the stream pipe. /// </summary> /// <param name="position">The position as seen from down stream. Effectively what this stream will output after computation.</param> public abstract void SetPrinterPosition(PrinterMove position);
public override string ReadLine() { if (movesToSend.Count == 0) { string lineToSend = base.ReadLine(); if (lineToSend != null && lineToSend.EndsWith("; NO_PROCESSING")) { return(lineToSend); } if (lineToSend != null && layerCount < 1 && GCodeFile.IsLayerChange(lineToSend)) { layerCount++; if (layerCount == 1) { MaxSegmentLength = 5; } } if (lineToSend != null && LineIsMovement(lineToSend)) { PrinterMove currentDestination = GetPosition(lineToSend, lastDestination); if (currentDestination.FullyKnown) { PrinterMove deltaToDestination = currentDestination - lastDestination; deltaToDestination.feedRate = 0; // remove the changing of the federate (we'll set it initially) double lengthSquared = Math.Max(deltaToDestination.LengthSquared, deltaToDestination.extrusion * deltaToDestination.extrusion); if (lengthSquared > MaxSegmentLength * MaxSegmentLength) { // create the line segments to send double length = Math.Sqrt(lengthSquared); int numSegmentsToCutInto = (int)Math.Ceiling(length / MaxSegmentLength); // segments = (((mm/min) / (60s/min))mm/s / s/segment)segments*mm / mm double maxSegmentsCanTransmit = 1 / (((currentDestination.feedRate / 60) * maxSecondsPerSegment) / length); int numSegmentsToSend = Math.Max(1, Math.Min(numSegmentsToCutInto, (int)maxSegmentsCanTransmit)); if (numSegmentsToSend > 1) { PrinterMove deltaForSegment = deltaToDestination / numSegmentsToSend; PrinterMove nextPoint = lastDestination + deltaForSegment; nextPoint.feedRate = currentDestination.feedRate; for (int i = 0; i < numSegmentsToSend; i++) { lock (movesToSend) { movesToSend.Add(nextPoint); } nextPoint += deltaForSegment; } // send the first one PrinterMove positionToSend = movesToSend[0]; lock (movesToSend) { movesToSend.RemoveAt(0); } string altredLineToSend = CreateMovementLine(positionToSend, lastDestination); lastDestination = positionToSend; return(altredLineToSend); } } } lastDestination = currentDestination; } return(lineToSend); } else { PrinterMove positionToSend = movesToSend[0]; lock (movesToSend) { movesToSend.RemoveAt(0); } string lineToSend = CreateMovementLine(positionToSend, lastDestination); lastDestination = positionToSend; return(lineToSend); } }
private void QueueAfterGCode() { string afterGcodeToQueue = ""; switch (RequestedTool) { case 0: afterGcodeToQueue = printer.Settings.GetValue(SettingsKey.toolchange_gcode).Replace("\\n", "\n"); break; case 1: afterGcodeToQueue = printer.Settings.GetValue(SettingsKey.toolchange_gcode_1).Replace("\\n", "\n"); break; } PrinterMove newToolMove = GetPosition(postSwitchLine, PrinterMove.Unknown); var newToolPosition = newToolMove.position; var lineNoComment = postSwitchLine.Split(';')[0]; // if there is no extrusion we can move directly to the desired position after the extruder switch. // Otherwise we need to go to the last position to start the extrusion. if (!lineNoComment.Contains("E")) { newToolPosition.X = newToolPosition.X == double.PositiveInfinity ? preSwitchPosition.X : newToolPosition.X; newToolPosition.Y = newToolPosition.Y == double.PositiveInfinity ? preSwitchPosition.Y : newToolPosition.Y; } // no matter what happens with the x and y we want to set our z if we have one before newToolPosition.Z = newToolPosition.Z == double.PositiveInfinity ? preSwitchPosition.Z : newToolPosition.Z; // put together the output we want to send var gcode = new StringBuilder(); // If the printer is heating, make sure we are at temp before switching extruders var nextToolTargetTemp = targetTemps[RequestedTool]; var currentPrinterTargeTemp = printer.Connection.GetTargetHotendTemperature(RequestedTool); if (currentPrinterTargeTemp > 0 && printer.Connection.GetActualHotendTemperature(RequestedTool) < nextToolTargetTemp - 3) { // ensure our next tool is at temp (the one we are switching to) gcode.AppendLine($"M109 T{RequestedTool} S{nextToolTargetTemp}"); } if (afterGcodeToQueue.Trim().Length > 0) { gcode.Append(printer.Settings.ReplaceMacroValues(afterGcodeToQueue)); } // move to selected tool to the last tool position at the travel speed if (newToolPosition.X != double.PositiveInfinity && newToolPosition.Y != double.PositiveInfinity) { gcode.AppendLine($"\n G1 X{newToolPosition.X}Y{newToolPosition.Y}F{printer.Settings.XSpeed()}"); } // move to the z position if (newToolPosition.Z != double.PositiveInfinity) { gcode.AppendLine($"G1 Z{newToolPosition.Z}F{printer.Settings.ZSpeed()}"); } // set the feedrate back to what was before we added any code if (preSwitchFeedRate != double.PositiveInfinity) { gcode.AppendLine($"G1 F{preSwitchFeedRate}"); } // and queue the travel gcode.AppendLine(postSwitchLine); queuedCommandsStream.Add(gcode.ToString()); }