Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Hammacher <bmasterc@gmail.com>2021-09-27 13:10:10 +0300
committerChristian Hammacher <bmasterc@gmail.com>2021-09-27 13:10:10 +0300
commite84003ab69f398dbe84beb6c98e69c527e045852 (patch)
tree8c14d8234833e7e28a021e901668d663755d1be2
parent130708fda5628013cbf83d33d031345ed1b90a37 (diff)
parente76c1a56191fdc5213a372f983f702be14529090 (diff)
Merge remote-tracking branch 'origin/3.4-dev' into v3-chrishamm3.4.0beta4
-rw-r--r--src/CAN/CanMotion.cpp11
-rw-r--r--src/CAN/CanMotion.h2
-rw-r--r--src/GCodes/GCodes.cpp30
-rw-r--r--src/GCodes/GCodes.h14
-rw-r--r--src/GCodes/GCodes2.cpp24
-rw-r--r--src/GCodes/GCodes3.cpp18
-rw-r--r--src/GCodes/GCodes4.cpp6
-rw-r--r--src/Movement/DDA.cpp64
-rw-r--r--src/Movement/DDA.h3
-rw-r--r--src/Movement/DDARing.cpp26
-rw-r--r--src/Movement/DDARing.h4
-rw-r--r--src/Movement/DriveMovement.cpp152
-rw-r--r--src/Movement/DriveMovement.h5
-rw-r--r--src/Movement/Move.cpp10
-rw-r--r--src/Movement/Move.h6
-rw-r--r--src/Version.h2
16 files changed, 268 insertions, 109 deletions
diff --git a/src/CAN/CanMotion.cpp b/src/CAN/CanMotion.cpp
index 09ea0ff7..6d311d41 100644
--- a/src/CAN/CanMotion.cpp
+++ b/src/CAN/CanMotion.cpp
@@ -178,7 +178,7 @@ void CanMotion::AddExtruderMovement(const PrepParams& params, DriverId canDriver
#endif
// This is called by DDA::Prepare when all DMs for CAN drives have been processed. Return the calculated move time in steps, or 0 if there are no CAN moves
-uint32_t CanMotion::FinishMovement(uint32_t moveStartTime) noexcept
+uint32_t CanMotion::FinishMovement(uint32_t moveStartTime, bool simulating) noexcept
{
boardsActiveInLastMove.ClearAll();
CanMessageBuffer *buf = movementBufferList;
@@ -207,7 +207,14 @@ uint32_t CanMotion::FinishMovement(uint32_t moveStartTime) noexcept
buf->dataLength = buf->msg.moveLinear.GetActualDataLength();
#endif
CanMessageBuffer * const nextBuffer = buf->next; // must get this before sending the buffer, because sending the buffer releases it
- CanInterface::SendMotion(buf); // queues the buffer for sending and frees it when done
+ if (simulating)
+ {
+ CanMessageBuffer::Free(buf);
+ }
+ else
+ {
+ CanInterface::SendMotion(buf); // queues the buffer for sending and frees it when done
+ }
#if 0
++numMotionMessagesSentLast;
#endif
diff --git a/src/CAN/CanMotion.h b/src/CAN/CanMotion.h
index e14aadcf..7b6b0d32 100644
--- a/src/CAN/CanMotion.h
+++ b/src/CAN/CanMotion.h
@@ -24,7 +24,7 @@ namespace CanMotion
#else
void AddMovement(const PrepParams& params, DriverId canDriver, int32_t steps, bool usePressureAdvance = false) noexcept;
#endif
- uint32_t FinishMovement(uint32_t moveStartTime) noexcept;
+ uint32_t FinishMovement(uint32_t moveStartTime, bool simulating) noexcept;
bool CanPrepareMove() noexcept;
CanMessageBuffer *GetUrgentMessage() noexcept;
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index ee42846e..c98779ec 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -276,7 +276,7 @@ void GCodes::Reset() noexcept
}
triggersPending.Clear();
- simulationMode = 0;
+ simulationMode = SimulationMode::off;
exitSimulationWhenFileComplete = updateFileWhenSimulationComplete = false;
simulationTime = 0.0;
lastDuration = 0;
@@ -990,7 +990,7 @@ void GCodes::DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg, uint1
pauseRestorePoint.fanSpeed = lastDefaultFanSpeed;
#if HAS_MASS_STORAGE || HAS_LINUX_INTERFACE
- if (simulationMode == 0)
+ if (!IsSimulating())
{
SaveResumeInfo(false); // create the resume file so that we can resume after power down
}
@@ -1190,7 +1190,7 @@ bool GCodes::DoEmergencyPause() noexcept
// Try to pause the current SD card print, returning true if successful, false if needs to be called again
bool GCodes::LowVoltagePause() noexcept
{
- if (simulationMode != 0)
+ if (IsSimulating())
{
return true; // ignore the low voltage indication
}
@@ -2099,7 +2099,7 @@ bool GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated, const char *& e
// As soon as we set segmentsLeft nonzero, the Move process will assume that the move is ready to take, so this must be the last thing we do.
const Kinematics& kin = reprap.GetMove().GetKinematics();
const SegmentationType st = kin.GetSegmentationType();
- if (st.useSegmentation && simulationMode != 1 && (moveState.hasPositiveExtrusion || moveState.isCoordinated || st.useG0Segmentation))
+ if (st.useSegmentation && simulationMode != SimulationMode::normal && (moveState.hasPositiveExtrusion || moveState.isCoordinated || st.useG0Segmentation))
{
// This kinematics approximates linear motion by means of segmentation
float moveLengthSquared = fsquare(moveState.currentUserPosition[X_AXIS] - initialUserPosition[X_AXIS]) + fsquare(moveState.currentUserPosition[Y_AXIS] - initialUserPosition[Y_AXIS]);
@@ -3294,7 +3294,7 @@ void GCodes::StartPrinting(bool fromStart) noexcept
lastFilamentError = FilamentSensorStatus::ok;
reprap.GetPrintMonitor().StartedPrint();
platform.MessageF(LogWarn,
- (simulationMode == 0) ? "Started printing file %s\n" : "Started simulating printing file %s\n",
+ (IsSimulating()) ? "Started simulating printing file %s\n" : "Started printing file %s\n",
reprap.GetPrintMonitor().GetPrintingFilename());
if (fromStart)
{
@@ -3338,7 +3338,7 @@ GCodeResult GCodes::DoDwell(GCodeBuffer& gb) THROWS(GCodeException)
}
#endif
- if ( simulationMode != 0 // if we are simulating then simulate the G4...
+ if ( IsSimulating() // if we are simulating then simulate the G4...
&& &gb != daemonGCode // ...unless it comes from the daemon...
&& &gb != triggerGCode // ...or a trigger...
&& (&gb == fileGCode || !exitSimulationWhenFileComplete) // ...or we are simulating a file and this command doesn't come from the file
@@ -3410,7 +3410,7 @@ GCodeResult GCodes::SetOrReportOffsets(GCodeBuffer &gb, const StringRef& reply,
if (gb.Seen('R'))
{
settingTemps = true;
- if (simulationMode == 0)
+ if (!IsSimulating())
{
float standby[MaxHeaters];
gb.GetFloatArray(standby, hCount, true);
@@ -3423,7 +3423,7 @@ GCodeResult GCodes::SetOrReportOffsets(GCodeBuffer &gb, const StringRef& reply,
if (gb.Seen('S'))
{
settingTemps = true;
- if (simulationMode == 0)
+ if (!IsSimulating())
{
float activeTemps[MaxHeaters];
gb.GetFloatArray(activeTemps, hCount, true);
@@ -3444,7 +3444,7 @@ GCodeResult GCodes::SetOrReportOffsets(GCodeBuffer &gb, const StringRef& reply,
if (gb.Seen('F'))
{
settingOther = true;
- if (simulationMode == 0)
+ if (!IsSimulating())
{
tool->SetSpindleRpm(gb.GetUIValue());
}
@@ -4163,7 +4163,7 @@ void GCodes::StopPrint(StopPrintReason reason) noexcept
#endif
exitSimulationWhenFileComplete = false;
- simulationMode = 0; // do this after we append the simulation info to the file so that DWC doesn't try to reload the file info too soon
+ simulationMode = SimulationMode::off; // do this after we append the simulation info to the file so that DWC doesn't try to reload the file info too soon
reprap.GetMove().Simulate(simulationMode);
EndSimulation(nullptr);
@@ -4225,7 +4225,7 @@ void GCodes::StopPrint(StopPrintReason reason) noexcept
(reason == StopPrintReason::normalCompletion) ? "Finished" : "Cancelled",
printingFilename, printMinutes/60u, printMinutes % 60u);
#if HAS_MASS_STORAGE || HAS_LINUX_INTERFACE
- if (reason == StopPrintReason::normalCompletion && simulationMode == 0)
+ if (reason == StopPrintReason::normalCompletion && !IsSimulating())
{
platform.DeleteSysFile(RESUME_AFTER_POWER_FAIL_G);
}
@@ -4458,7 +4458,7 @@ bool GCodes::AllAxesAreHomed() const noexcept
// Tell us that the axis is now homed
void GCodes::SetAxisIsHomed(unsigned int axis) noexcept
{
- if (simulationMode == 0)
+ if (!IsSimulating())
{
axesHomed.SetBit(axis);
axesVirtuallyHomed = axesHomed;
@@ -4469,7 +4469,7 @@ void GCodes::SetAxisIsHomed(unsigned int axis) noexcept
// Tell us that the axis is not homed
void GCodes::SetAxisNotHomed(unsigned int axis) noexcept
{
- if (simulationMode == 0)
+ if (!IsSimulating())
{
axesHomed.ClearBit(axis);
axesVirtuallyHomed = axesHomed;
@@ -4484,7 +4484,7 @@ void GCodes::SetAxisNotHomed(unsigned int axis) noexcept
// Flag all axes as not homed
void GCodes::SetAllAxesNotHomed() noexcept
{
- if (simulationMode == 0)
+ if (!IsSimulating())
{
axesHomed.Clear();
axesVirtuallyHomed = axesHomed;
@@ -4724,7 +4724,7 @@ OutputBuffer *GCodes::GenerateJsonStatusResponse(int type, int seq, ResponseSour
void GCodes::StartToolChange(GCodeBuffer& gb, int toolNum, uint8_t param) noexcept
{
newToolNumber = toolNum;
- toolChangeParam = (simulationMode != 0) ? 0 : param;
+ toolChangeParam = (IsSimulating()) ? 0 : param;
gb.SetState(GCodeState::toolChange0);
}
diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h
index dd3144a7..21796b31 100644
--- a/src/GCodes/GCodes.h
+++ b/src/GCodes/GCodes.h
@@ -102,6 +102,14 @@ struct M675Settings
float minDistance; // the position we reached when probing towards minimum
};
+enum class SimulationMode : uint8_t
+{ off = 0, // not simulating
+ debug, // simulating step generation
+ normal, // not generating steps, just timing
+ partial, // generating DDAs but doing nothing with them
+ highest = partial
+};
+
class LinuxInterface;
// The GCode interpreter
@@ -162,7 +170,7 @@ public:
bool IsReallyPrinting() const noexcept; // Return true if we are printing from SD card and not pausing, paused or resuming
bool IsReallyPrintingOrResuming() const noexcept;
- bool IsSimulating() const noexcept { return simulationMode != 0; }
+ bool IsSimulating() const noexcept { return simulationMode != SimulationMode::off; }
bool IsDoingToolChange() const noexcept { return doingToolChange; }
bool IsHeatingUp() const noexcept; // Return true if the SD card print is waiting for a heater to reach temperature
bool IsRunningConfigFile() const noexcept { return runningConfigFile; }
@@ -466,7 +474,7 @@ private:
GCodeResult ReceiveI2c(GCodeBuffer& gb, const StringRef &reply) THROWS(GCodeException); // Handle M261
#if HAS_MASS_STORAGE || HAS_LINUX_INTERFACE || HAS_EMBEDDED_FILES
GCodeResult SimulateFile(GCodeBuffer& gb, const StringRef &reply, const StringRef& file, bool updateFile) THROWS(GCodeException); // Handle M37 to simulate a whole file
- GCodeResult ChangeSimulationMode(GCodeBuffer& gb, const StringRef &reply, uint32_t newSimulationMode) THROWS(GCodeException); // Handle M37 to change the simulation mode
+ GCodeResult ChangeSimulationMode(GCodeBuffer& gb, const StringRef &reply, SimulationMode newSimMode) THROWS(GCodeException); // Handle M37 to change the simulation mode
#endif
GCodeResult WaitForPin(GCodeBuffer& gb, const StringRef &reply) THROWS(GCodeException); // Handle M577
@@ -639,7 +647,7 @@ private:
// Simulation and print time
float simulationTime; // Accumulated simulation time
uint32_t lastDuration; // Time or simulated time of the last successful print or simulation, in seconds
- uint8_t simulationMode; // 0 = not simulating, 1 = simulating, >1 are simulation modes for debugging
+ SimulationMode simulationMode; // see description of enum SimulationMode
bool exitSimulationWhenFileComplete; // true if simulating a file
bool updateFileWhenSimulationComplete; // true if simulated time should be appended to the file
diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp
index 59b14e66..7a376fff 100644
--- a/src/GCodes/GCodes2.cpp
+++ b/src/GCodes/GCodes2.cpp
@@ -131,7 +131,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx
{
GCodeResult result = GCodeResult::ok;
const int code = gb.GetCommandNumber();
- if (simulationMode != 0 && code > 4 && code != 10 && code != 11 && code != 20 && code != 21 && (code < 53 || code > 59) && (code < 90 || code > 92))
+ if (IsSimulating() && code > 4 && code != 10 && code != 11 && code != 20 && code != 21 && (code < 53 || code > 59) && (code < 90 || code > 92))
{
HandleReply(gb, result, "");
return true; // we only simulate some gcodes
@@ -236,7 +236,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx
if (modifyingTool)
{
- if (simulationMode != 0)
+ if (IsSimulating())
{
break;
}
@@ -452,7 +452,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx
{
const int code = gb.GetCommandNumber();
- if ( simulationMode != 0
+ if ( IsSimulating()
&& (code < 20 || code > 37)
&& code != 0 && code != 1 && code != 82 && code != 83 && code != 105 && code != 109 && code != 111 && code != 112 && code != 122
&& code != 200 && code != 204 && code != 207 && code != 408 && code != 409 && code != 486 && code != 999)
@@ -1155,15 +1155,15 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx
else
{
uint32_t newSimulationMode;
- gb.TryGetUIValue('S', newSimulationMode, seen);
+ gb.TryGetLimitedUIValue('S', newSimulationMode, seen, (uint32_t)SimulationMode::highest + 1);
if (seen)
{
- result = ChangeSimulationMode(gb, reply, newSimulationMode);
+ result = ChangeSimulationMode(gb, reply, (SimulationMode)newSimulationMode);
}
else
{
reply.printf("Simulation mode: %s, move time: %.1f sec, other time: %.1f sec",
- (simulationMode != 0) ? "on" : "off", (double)reprap.GetMove().GetSimulationTime(), (double)simulationTime);
+ (IsSimulating()) ? "on" : "off", (double)reprap.GetMove().GetSimulationTime(), (double)simulationTime);
}
}
}
@@ -1541,7 +1541,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx
// Set the heater temperatures for that tool. We set the standby temperatures as well as the active ones,
// because any slicer that uses M109 doesn't understand that there are separate active and standby temperatures.
- if (simulationMode == 0)
+ if (!IsSimulating())
{
SetToolHeaters(applicableTool.Ptr(), temperature, true); // this may throw
}
@@ -1556,7 +1556,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx
}
newToolNumber = applicableTool->Number();
- toolChangeParam = (simulationMode != 0) ? 0 : DefaultToolChangeParam;
+ toolChangeParam = (IsSimulating()) ? 0 : DefaultToolChangeParam;
gb.SetState(GCodeState::m109ToolChange0);
result = GCodeResult::ok;
}
@@ -1566,15 +1566,15 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx
{
// Even though the tool is selected, we may have turned it off e.g. when upgrading the WiFi firmware or following a heater fault that has been cleared.
// So make sure the tool heaters are on.
- reprap.SelectTool(applicableTool->Number(), simulationMode != 0);
+ reprap.SelectTool(applicableTool->Number(), IsSimulating());
}
else
{
// If we already have an active tool and we are setting temperatures for a different tool, set that tool's heaters to standby in case it is off
- reprap.StandbyTool(applicableTool->Number(), simulationMode != 0);
+ reprap.StandbyTool(applicableTool->Number(), IsSimulating());
}
- if (code == 109 && simulationMode == 0)
+ if (code == 109 && !IsSimulating())
{
gb.SetState(GCodeState::m109WaitForTemperature);
result = GCodeResult::ok;
@@ -4689,7 +4689,7 @@ bool GCodes::HandleTcode(GCodeBuffer& gb, const StringRef& reply)
{
// Even though the tool is selected, we may have turned it off e.g. when upgrading the WiFi firmware or following a heater fault that has been cleared.
// So make sure the tool heaters are on.
- reprap.SelectTool(toolNum, simulationMode != 0);
+ reprap.SelectTool(toolNum, IsSimulating());
}
}
}
diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp
index 528a77dc..ba7843f6 100644
--- a/src/GCodes/GCodes3.cpp
+++ b/src/GCodes/GCodes3.cpp
@@ -95,7 +95,7 @@ GCodeResult GCodes::SetPositions(GCodeBuffer& gb) THROWS(GCodeException)
ToolOffsetInverseTransform(moveState.coords, moveState.currentUserPosition); // make sure the limits are reflected in the user position
}
reprap.GetMove().SetNewPosition(moveState.coords, true);
- if (simulationMode == 0)
+ if (!IsSimulating())
{
axesHomed |= reprap.GetMove().GetKinematics().AxesAssumedHomed(axesIncluded);
axesVirtuallyHomed = axesHomed;
@@ -424,7 +424,7 @@ GCodeResult GCodes::SimulateFile(GCodeBuffer& gb, const StringRef &reply, const
QueueFileToPrint(file.c_str(), reply))
# endif
{
- if (simulationMode == 0)
+ if (!IsSimulating())
{
axesVirtuallyHomed = AxesBitmap::MakeLowestNBits(numVisibleAxes); // pretend all axes are homed
SavePosition(simulationRestorePoint, gb);
@@ -437,7 +437,7 @@ GCodeResult GCodes::SimulateFile(GCodeBuffer& gb, const StringRef &reply, const
# else
updateFileWhenSimulationComplete = updateFile;
# endif
- simulationMode = 1;
+ simulationMode = SimulationMode::normal;
reprap.GetMove().Simulate(simulationMode);
reprap.GetPrintMonitor().StartingPrint(file.c_str());
StartPrinting(true);
@@ -449,22 +449,22 @@ GCodeResult GCodes::SimulateFile(GCodeBuffer& gb, const StringRef &reply, const
}
// Handle M37 to change the simulation mode
-GCodeResult GCodes::ChangeSimulationMode(GCodeBuffer& gb, const StringRef &reply, uint32_t newSimulationMode)
+GCodeResult GCodes::ChangeSimulationMode(GCodeBuffer& gb, const StringRef &reply, SimulationMode newSimMode) THROWS(GCodeException)
{
- if (newSimulationMode != simulationMode)
+ if (newSimMode != simulationMode)
{
if (!LockMovementAndWaitForStandstill(gb))
{
return GCodeResult::notFinished;
}
- if (newSimulationMode == 0)
+ if (newSimMode == SimulationMode::off)
{
EndSimulation(&gb);
}
else
{
- if (simulationMode == 0)
+ if (!IsSimulating())
{
// Starting a new simulation, so save the current position
axesVirtuallyHomed = AxesBitmap::MakeLowestNBits(numVisibleAxes); // pretend all axes are homed
@@ -473,8 +473,8 @@ GCodeResult GCodes::ChangeSimulationMode(GCodeBuffer& gb, const StringRef &reply
simulationTime = 0.0;
}
exitSimulationWhenFileComplete = updateFileWhenSimulationComplete = false;
- simulationMode = (uint8_t)newSimulationMode;
- reprap.GetMove().Simulate(simulationMode);
+ simulationMode = newSimMode;
+ reprap.GetMove().Simulate(newSimMode);
}
return GCodeResult::ok;
}
diff --git a/src/GCodes/GCodes4.cpp b/src/GCodes/GCodes4.cpp
index 65ebe0cc..ab8c3689 100644
--- a/src/GCodes/GCodes4.cpp
+++ b/src/GCodes/GCodes4.cpp
@@ -345,7 +345,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept
const Tool * const oldTool = reprap.GetCurrentTool();
if (oldTool != nullptr)
{
- reprap.StandbyTool(oldTool->Number(), simulationMode != 0);
+ reprap.StandbyTool(oldTool->Number(), IsSimulating());
UpdateCurrentUserPosition(); // the tool offset may have changed, so get the current position
}
gb.AdvanceState();
@@ -362,7 +362,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept
case GCodeState::m109ToolChange2: // select the new tool if it exists and run tpost
if (LockMovementAndWaitForStandstill(gb)) // wait for tpre.g to finish executing
{
- reprap.SelectTool(newToolNumber, simulationMode != 0);
+ reprap.SelectTool(newToolNumber, IsSimulating());
UpdateCurrentUserPosition(); // get the actual position of the new tool
gb.AdvanceState();
@@ -432,7 +432,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept
break;
case GCodeState::m109WaitForTemperature:
- if (cancelWait || simulationMode != 0 || ToolHeatersAtSetTemperatures(reprap.GetCurrentTool(), gb.LatestMachineState().waitWhileCooling, TEMPERATURE_CLOSE_ENOUGH))
+ if (cancelWait || IsSimulating() || ToolHeatersAtSetTemperatures(reprap.GetCurrentTool(), gb.LatestMachineState().waitWhileCooling, TEMPERATURE_CLOSE_ENOUGH))
{
cancelWait = isWaiting = false;
gb.SetState(GCodeState::normal);
diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp
index e743de84..96e05715 100644
--- a/src/Movement/DDA.cpp
+++ b/src/Movement/DDA.cpp
@@ -1279,7 +1279,7 @@ void DDA::EnsureUnshapedSegments(const PrepParams& params) noexcept
// Prepare this DDA for execution.
// This must not be called with interrupts disabled, because it calls Platform::EnableDrive.
-void DDA::Prepare(uint8_t simMode) noexcept
+void DDA::Prepare(SimulationMode simMode) noexcept
{
flags.wasAccelOnlyMove = IsAccelerationMove(); // save this for the next move to look at
@@ -1311,7 +1311,7 @@ void DDA::Prepare(uint8_t simMode) noexcept
acceleration = params.unshaped.acceleration;
deceleration = params.unshaped.deceleration;
- if (simMode == 0)
+ if (simMode < SimulationMode::normal)
{
if (flags.isDeltaMovement)
{
@@ -1611,7 +1611,7 @@ void DDA::Prepare(uint8_t simMode) noexcept
}
#if SUPPORT_CAN_EXPANSION
- const uint32_t canClocksNeeded = CanMotion::FinishMovement(afterPrepare.moveStartTime);
+ const uint32_t canClocksNeeded = CanMotion::FinishMovement(afterPrepare.moveStartTime, simMode != SimulationMode::off);
if (canClocksNeeded > clocksNeeded)
{
// Due to rounding error in the calculations, we quite often calculate the CAN move as being longer than our previously-calculated value, normally by just one clock.
@@ -2116,6 +2116,64 @@ void DDA::StepDrivers(Platform& p, uint32_t now) noexcept
}
}
+// Simulate stepping the drivers, for debugging.
+// This is basically a copy of DDA::SetDrivers except that instead of being called from the timer ISR and generating steps,
+// it is called from the Move task and outputs info on the step timings. It ignores endstops.
+void DDA::SimulateSteppingDrivers(Platform& p) noexcept
+{
+ static uint32_t lastStepTime;
+ static bool checkTiming = false;
+
+ DriveMovement* dm = activeDMs;
+ if (dm != nullptr)
+ {
+ const uint32_t dueTime = dm->nextStepTime;
+ while (dm != nullptr && dueTime >= dm->nextStepTime) // if the next step is due
+ {
+ const uint32_t timeDiff = dm->nextStepTime - lastStepTime;
+ const bool badTiming = checkTiming && (timeDiff < 10 || timeDiff > 100000000);
+ debugPrintf("%10" PRIu32 " D%u %c%s", dm->nextStepTime, dm->drive, (dm->direction) ? 'F' : 'B', (badTiming) ? " *\n" : "\n");
+ dm = dm->nextDM;
+ }
+ lastStepTime = dueTime;
+ checkTiming = true;
+
+ for (DriveMovement *dm2 = activeDMs; dm2 != dm; dm2 = dm2->nextDM)
+ {
+ (void)dm2->CalcNextStepTime(*this); // calculate next step times
+ }
+
+ // Remove those drives from the list, update the direction pins where necessary, and re-insert them so as to keep the list in step-time order.
+ DriveMovement *dmToInsert = activeDMs; // head of the chain we need to re-insert
+ activeDMs = dm; // remove the chain from the list
+ while (dmToInsert != dm) // note that both of these may be nullptr
+ {
+ DriveMovement * const nextToInsert = dmToInsert->nextDM;
+ if (dmToInsert->state >= DMState::firstMotionState)
+ {
+ InsertDM(dmToInsert);
+ if (dmToInsert->directionChanged)
+ {
+ dmToInsert->directionChanged = false;
+ }
+ }
+ else
+ {
+ dmToInsert->nextDM = completedDMs;
+ completedDMs = dmToInsert;
+ }
+ dmToInsert = nextToInsert;
+ }
+ }
+
+ // If there are no more steps to do and the time for the move has nearly expired, flag the move as complete
+ if (activeDMs == nullptr)
+ {
+ checkTiming = false; // don't check the timing of the first step in the next move
+ state = completed;
+ }
+}
+
// Stop a drive and re-calculate the corresponding endpoint.
// For extruder drivers, we need to be able to calculate how much of the extrusion was completed after calling this.
void DDA::StopDrive(size_t drive) noexcept
diff --git a/src/Movement/DDA.h b/src/Movement/DDA.h
index 66019a35..2c693d98 100644
--- a/src/Movement/DDA.h
+++ b/src/Movement/DDA.h
@@ -98,13 +98,14 @@ public:
void Start(Platform& p, uint32_t tim) noexcept SPEED_CRITICAL; // Start executing the DDA, i.e. move the move.
void StepDrivers(Platform& p, uint32_t now) noexcept SPEED_CRITICAL; // Take one step of the DDA, called by timer interrupt.
+ void SimulateSteppingDrivers(Platform& p) noexcept; // For debugging use
bool ScheduleNextStepInterrupt(StepTimer& timer) const noexcept SPEED_CRITICAL; // Schedule the next interrupt, returning true if we can't because it is already due
void SetNext(DDA *n) noexcept { next = n; }
void SetPrevious(DDA *p) noexcept { prev = p; }
void Complete() noexcept { state = completed; }
bool Free() noexcept;
- void Prepare(uint8_t simMode) noexcept SPEED_CRITICAL; // Calculate all the values and freeze this DDA
+ void Prepare(SimulationMode simMode) noexcept SPEED_CRITICAL; // Calculate all the values and freeze this DDA
bool HasStepError() const noexcept;
bool CanPauseAfter() const noexcept;
bool IsPrintingMove() const noexcept { return flags.isPrintingMove; } // Return true if this involves both XY movement and extrusion
diff --git a/src/Movement/DDARing.cpp b/src/Movement/DDARing.cpp
index e8de24e4..cc8af5b0 100644
--- a/src/Movement/DDARing.cpp
+++ b/src/Movement/DDARing.cpp
@@ -262,16 +262,26 @@ bool DDARing::AddAsyncMove(const AsyncMove& nextMove) noexcept
// Try to process moves in the ring. Called by the Move task.
// Return the maximum time in milliseconds that should elapse before we prepare further unprepared moves that are already in the ring, or TaskBase::TimeoutUnlimited if there are no unprepared moves left.
-uint32_t DDARing::Spin(uint8_t simulationMode, bool waitingForSpace, bool shouldStartMove) noexcept
+uint32_t DDARing::Spin(SimulationMode simulationMode, bool waitingForSpace, bool shouldStartMove) noexcept
{
DDA *cdda = currentDda; // capture volatile variable
// If we are simulating, simulate completion of the current move.
// Do this here rather than at the end, so that when simulating, currentDda is non-null for most of the time and IsExtruding() returns the correct value
- if (simulationMode != 0 && cdda != nullptr)
+ if (simulationMode != SimulationMode::off && cdda != nullptr)
{
simulationTime += (float)cdda->GetClocksNeeded() * (1.0/StepClockRate);
- cdda->Complete();
+ if (simulationMode == SimulationMode::debug && reprap.Debug(moduleDda))
+ {
+ do
+ {
+ cdda->SimulateSteppingDrivers(reprap.GetPlatform());
+ } while (cdda->GetState() != DDA::completed);
+ }
+ else
+ {
+ cdda->Complete();
+ }
CurrentMoveCompleted(); // this sets currentDda to nullptr and advances getPointer
DDA * const gp = getPointer; // capture volatile variable
if (gp->GetState() == DDA::frozen)
@@ -300,14 +310,14 @@ uint32_t DDARing::Spin(uint8_t simulationMode, bool waitingForSpace, bool should
cdda = cdda->GetNext();
if (cdda == addPointer)
{
- return (simulationMode == 0)
+ return (simulationMode == SimulationMode::off)
? TaskBase::TimeoutUnlimited // all the moves we have are already prepared, so nothing to do until new moves arrive
: 0;
}
}
uint32_t ret = PrepareMoves(cdda, preparedTime, preparedCount, simulationMode);
- if (simulationMode != 0)
+ if (simulationMode >= SimulationMode::normal)
{
return 0;
}
@@ -345,7 +355,7 @@ uint32_t DDARing::Spin(uint8_t simulationMode, bool waitingForSpace, bool should
}
else if (dda->GetState() == DDA::frozen)
{
- if (simulationMode != 0)
+ if (simulationMode != SimulationMode::off)
{
currentDda = dda; // pretend we are executing this move
return 0; // we don't want any delay because we want Spin() to be called again soon to complete this move
@@ -392,7 +402,7 @@ uint32_t DDARing::Spin(uint8_t simulationMode, bool waitingForSpace, bool should
// Prepare some moves. moveTimeLeft is the total length remaining of moves that are already executing or prepared.
// Return the maximum time in milliseconds that should elapse before we prepare further unprepared moves that are already in the ring, or TaskBase::TimeoutUnlimited if there are no unprepared moves left.
-uint32_t DDARing::PrepareMoves(DDA *firstUnpreparedMove, int32_t moveTimeLeft, unsigned int alreadyPrepared, uint8_t simulationMode) noexcept
+uint32_t DDARing::PrepareMoves(DDA *firstUnpreparedMove, int32_t moveTimeLeft, unsigned int alreadyPrepared, SimulationMode simulationMode) noexcept
{
// If the number of prepared moves will execute in less than the minimum time, prepare another move.
// Try to avoid preparing deceleration-only moves too early
@@ -415,7 +425,7 @@ uint32_t DDARing::PrepareMoves(DDA *firstUnpreparedMove, int32_t moveTimeLeft, u
if (firstUnpreparedMove->GetState() == DDA::provisional)
{
// There are more moves waiting to be prepared, so ask to be woken up early
- if (simulationMode != 0)
+ if (simulationMode != SimulationMode::off)
{
return 1;
}
diff --git a/src/Movement/DDARing.h b/src/Movement/DDARing.h
index 9183db40..1bae00c8 100644
--- a/src/Movement/DDARing.h
+++ b/src/Movement/DDARing.h
@@ -29,7 +29,7 @@ public:
bool AddAsyncMove(const AsyncMove& nextMove) noexcept;
#endif
- uint32_t Spin(uint8_t simulationMode, bool waitingForSpace, bool shouldStartMove) noexcept SPEED_CRITICAL; // Try to process moves in the ring
+ uint32_t Spin(SimulationMode simulationMode, bool waitingForSpace, bool shouldStartMove) noexcept SPEED_CRITICAL; // Try to process moves in the ring
bool IsIdle() const noexcept; // Return true if this DDA ring is idle
uint32_t GetGracePeriod() const noexcept { return gracePeriod; } // Return the minimum idle time, before we should start a move. Better to have a few moves in the queue so that we can do lookahead
@@ -99,7 +99,7 @@ protected:
private:
bool StartNextMove(Platform& p, uint32_t startTime) noexcept SPEED_CRITICAL; // Start the next move, returning true if laser or IObits need to be controlled
- uint32_t PrepareMoves(DDA *firstUnpreparedMove, int32_t moveTimeLeft, unsigned int alreadyPrepared, uint8_t simulationMode) noexcept;
+ uint32_t PrepareMoves(DDA *firstUnpreparedMove, int32_t moveTimeLeft, unsigned int alreadyPrepared, SimulationMode simulationMode) noexcept;
static void TimerCallback(CallbackParameter p) noexcept;
diff --git a/src/Movement/DriveMovement.cpp b/src/Movement/DriveMovement.cpp
index f00c1624..3ae424b2 100644
--- a/src/Movement/DriveMovement.cpp
+++ b/src/Movement/DriveMovement.cpp
@@ -197,40 +197,59 @@ bool DriveMovement::NewDeltaSegment(const DDA& dda) noexcept
pB = currentSegment->CalcNonlinearB(timeSoFar);
}
- const float startDistance = distanceSoFar;
distanceSoFar += currentSegment->GetSegmentLength();
timeSoFar += currentSegment->GetSegmentTime();
- // Work out whether we reverse in this segment and the movement limit in steps
- const float sDx = distanceSoFar * dda.directionVector[0];
- const float sDy = distanceSoFar * dda.directionVector[1];
- const int32_t netStepsAtEnd = (int32_t)(fastSqrtf(mp.delta.fDSquaredMinusAsquaredMinusBsquaredTimesSsquared - fsquare(stepsPerMm) * (sDx * (sDx + mp.delta.fTwoA) + sDy * (sDy + mp.delta.fTwoB)))
- + (distanceSoFar * dda.directionVector[2] - mp.delta.h0MinusZ0) * stepsPerMm);
-
- if (mp.delta.reverseStartDistance <= startDistance)
+ // Work out whether we reverse in this segment and the movement limit in steps.
+ // First check whether the first step in this segment is the previously-calculated reverse start step, and if so then do the reversal.
+ if (nextStep == reverseStartStep)
{
- // This segment is purely downwards motion and we want the greater of the two quadratic solutions. There may have been upwards motion earlier in the move.
- if (direction)
- {
- direction = false;
- directionChanged = true;
- }
- state = DMState::deltaReverse;
- phaseStepLimit = (currentSegment->GetNext() == nullptr) ? totalSteps + 1
- : (reverseStartStep <= totalSteps) ? (uint32_t)((int32_t)(2 * reverseStartStep) - netStepsAtEnd)
- : 1 - netStepsAtEnd;
+ direction = false; // we must have been going up, so now we are going down
+ directionChanged = true;
}
- else if (distanceSoFar <= mp.delta.reverseStartDistance)
+
+ if (currentSegment->GetNext() == nullptr)
{
- // This segment is purely upwards motion of the tower and we want the lower quadratic solution
- state = DMState::deltaForwardsNoReverse;
- phaseStepLimit = (currentSegment->GetNext() == nullptr) ? totalSteps + 1 : (uint32_t)(netStepsAtEnd + 1);
+ // This is the last segment, so the phase step limit is the number of total steps, and we can avoid some calculation
+ phaseStepLimit = totalSteps + 1;
+ state = (reverseStartStep <= totalSteps && nextStep < reverseStartStep) ? DMState::deltaForwardsReversing : DMState::deltaNormal;
}
else
{
- // This segment ends with reverse motion. We want the lower quadratic solution initially.
- phaseStepLimit = (currentSegment->GetNext() == nullptr) ? totalSteps + 1 : (uint32_t)((int32_t)(2 * reverseStartStep) - netStepsAtEnd);
- state = DMState::deltaForwardsReversing;
+ // Work out how many whole steps we have moved up or down at the end of this segment
+ const float sDx = distanceSoFar * dda.directionVector[0];
+ const float sDy = distanceSoFar * dda.directionVector[1];
+ int32_t netStepsAtEnd = (int32_t)floorf(fastSqrtf(mp.delta.fDSquaredMinusAsquaredMinusBsquaredTimesSsquared - fsquare(stepsPerMm) * (sDx * (sDx + mp.delta.fTwoA) + sDy * (sDy + mp.delta.fTwoB)))
+ + (distanceSoFar * dda.directionVector[2] - mp.delta.h0MinusZ0) * stepsPerMm);
+
+ // If there is a reversal then we only ever move up by (reverseStartStep - 1) steps, so netStepsAtEnd should be less than reverseStartStep.
+ // However, because of rounding error, it might possibly be equal.
+ // If there is no reversal then reverseStartStep is set to totalSteps + 1, so netStepsAtEnd must again be less than reverseStartStep.
+ if (netStepsAtEnd >= (int32_t)reverseStartStep)
+ {
+ netStepsAtEnd = (int32_t)(reverseStartStep - 1); // correct the rounding error - we know that reverseStartStep cannot be 0 so subtracting 1 is safe
+ }
+
+ if (!direction)
+ {
+ // We are going down so any reversal has already happened
+ state = DMState::deltaNormal;
+ phaseStepLimit = (nextStep >= reverseStartStep)
+ ? (uint32_t)((int32_t)(2 * reverseStartStep) - netStepsAtEnd) // we went up (reverseStartStep-1) steps, now we are going down to netStepsAtEnd
+ : (uint32_t)(-netStepsAtEnd); // we are just going down to netStepsAtEnd
+ }
+ else if (distanceSoFar <= mp.delta.reverseStartDistance)
+ {
+ // This segment is purely upwards motion of the tower
+ state = DMState::deltaNormal;
+ phaseStepLimit = (uint32_t)(netStepsAtEnd + 1);
+ }
+ else
+ {
+ // This segment ends with reverse motion
+ phaseStepLimit = (uint32_t)((int32_t)(2 * reverseStartStep) - netStepsAtEnd);
+ state = DMState::deltaForwardsReversing;
+ }
}
#else
iC = currentSegment->GetC()/stepsPerMm; //TODO store the reciprocal to avoid the division? Use a scaling factor for C
@@ -306,7 +325,6 @@ bool DriveMovement::NewExtruderSegment() noexcept
const float startDistance = distanceSoFar;
const float startTime = timeSoFar;
- // Work out the movement limit in steps
distanceSoFar += currentSegment->GetSegmentLength();
timeSoFar += currentSegment->GetSegmentTime();
@@ -331,10 +349,11 @@ bool DriveMovement::NewExtruderSegment() noexcept
else
{
// This is the single decelerating segment. If it includes pressure advance then it may include reversal.
- state = DMState::cartDecelForwardsReversing; // assume that it may reverse
+ state = (reverseStartStep <= totalSteps) ? DMState::cartDecelForwardsReversing : DMState::cartDecelNoReverse;
}
}
+ // Work out the movement limit in steps
phaseStepLimit = ((currentSegment->GetNext() == nullptr) ? totalSteps : (uint32_t)(distanceSoFar * mp.cart.effectiveStepsPerMm)) + 1;
#else
const uint32_t startDistance = iDistanceSoFar;
@@ -439,7 +458,7 @@ bool DriveMovement::PrepareDeltaAxis(const DDA& dda, const PrepParams& params) n
// Calculate the distance at which we need to reverse direction.
if (params.a2plusb2 <= 0.0)
{
- // Pure Z movement. We can't use the main calculation because it divides by a2plusb2.
+ // Pure Z movement. We can't use the main calculation because it divides by params.a2plusb2.
direction = (dda.directionVector[Z_AXIS] >= 0.0);
mp.delta.reverseStartDistance = (direction) ? dda.totalDistance + 1.0 : -1.0; // so that we never reverse and NewDeltaSegment knows which way we are going
reverseStartStep = totalSteps + 1;
@@ -451,18 +470,34 @@ bool DriveMovement::PrepareDeltaAxis(const DDA& dda, const PrepParams& params) n
const float drev = ((dda.directionVector[Z_AXIS] * fastSqrtf(params.a2plusb2 * params.dparams->GetDiagonalSquared(drive) - fsquare(A * dda.directionVector[Y_AXIS] - B * dda.directionVector[X_AXIS])))
- aAplusbB)/params.a2plusb2;
mp.delta.reverseStartDistance = drev;
- if (drev > 0.0 && drev < dda.totalDistance) // if the reversal point is within range
+ if (drev > 0.0 && drev < dda.totalDistance) // if the reversal point is within range
{
// Calculate how many steps we need to move up before reversing
const float hrev = dda.directionVector[Z_AXIS] * drev + fastSqrtf(dSquaredMinusAsquaredMinusBsquared - 2 * drev * aAplusbB - params.a2plusb2 * fsquare(drev));
const int32_t numStepsUp = (int32_t)((hrev - mp.delta.h0MinusZ0) * stepsPerMm);
- // We may be almost at the peak height already, in which case we don't really have a reversal.
+ // We may be going down but almost at the peak height already, in which case we don't really have a reversal.
+ // However, we could be going up by a whole step due to rounding, so we need to check the direction
if (numStepsUp < 1)
{
- mp.delta.reverseStartDistance = -1.0; // so that we know we have reversed already
+ if (direction)
+ {
+ mp.delta.reverseStartDistance = dda.totalDistance + 1.0; // indicate that there is no reversal
+ }
+ else
+ {
+ mp.delta.reverseStartDistance = -1.0; // so that we know we have reversed already
+ reverseStartStep = totalSteps + 1;
+ }
+ }
+ else if (direction && (uint32_t)numStepsUp <= totalSteps)
+ {
+ // If numStepsUp == totalSteps then the reverse segment is too small to do.
+ // If numStepsUp < totalSteps then there has been a rounding error, because we are supposed to move up more than the calculated number of steps we move up.
+ // This can happen if the calculated reversal is very close to the end of the move, because we round the final step positions to the nearest step, which may be up.
+ // Either way, don't do a reverse segment.
reverseStartStep = totalSteps + 1;
- direction = false;
+ mp.delta.reverseStartDistance = dda.totalDistance + 1.0;
}
else
{
@@ -472,13 +507,13 @@ bool DriveMovement::PrepareDeltaAxis(const DDA& dda, const PrepParams& params) n
if (direction)
{
// Net movement is up, so we will go up first and then down by a lesser amount
- totalSteps = (2 * numStepsUp) - totalSteps;
+ totalSteps = (2 * (uint32_t)numStepsUp) - totalSteps;
}
else
{
// Net movement is down, so we will go up first and then down by a greater amount
direction = true;
- totalSteps = (2 * numStepsUp) + totalSteps;
+ totalSteps = (2 * (uint32_t)numStepsUp) + totalSteps;
}
}
}
@@ -601,6 +636,47 @@ bool DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params) no
mp.cart.extraExtrusionDistance = mp.cart.pressureAdvanceK * (dda.topSpeed - dda.startSpeed);
forwardDistance += mp.cart.extraExtrusionDistance;
+# if 0 //SHAPE_EXTRUSION
+ forwardDistance += params.shaped.decelStartDistance;
+ reverseDistance = 0.0;
+
+ // Find the deceleration segments
+ const MoveSegment *decelSeg = dda.unshapedSegments;
+ while (decelSeg != nullptr && (decelSeg->IsLinear() || decelSeg->IsAccelerating()))
+ {
+ decelSeg = decelSeg->GetNext();
+ }
+
+ float lastUncorrectedSpeed = dda.topSpeed;
+ float lastDistance = forwardDistance;
+ while (decelSeg != nullptr)
+ {
+ const float initialDecelSpeed = lastUncorrectedSpeed - mp.cart.pressureAdvanceK * decelSeg->deceleration;
+ if (initialDecelSpeed <= 0.0)
+ {
+ // This entire deceleration segment is in reverse
+ reverseDistance += ((0.5 * params.unshaped.deceleration * params.unshaped.decelClocks) - initialDecelSpeed) * params.unshaped.decelClocks;
+ }
+ else
+ {
+ const float timeToReverse = initialDecelSpeed * ((-0.5) * decelSeg->GetC()); // 'c' is -2/deceleration, so -0.5*c is 1/deceleration
+ if (timeToReverse < params.unshaped.decelClocks)
+ {
+ // There is a reversal, although it could be tiny
+ const float distanceToReverse = fsquare(initialDecelSpeed) * decelSeg->GetC() * (-0.25); // because (v^2-u^2) = 2as, so if v=0 then s=-u^2/2a = u^2/2d = -0.25*u^2*c
+ forwardDistance += params.unshaped.decelStartDistance + distanceToReverse;
+ reverseDistance = 0.5 * params.unshaped.deceleration * fsquare(params.unshaped.decelClocks - timeToReverse); // because s = 0.5*a*t^2
+ }
+ else
+ {
+ // No reversal
+ forwardDistance += dda.totalDistance - (mp.cart.pressureAdvanceK * params.unshaped.deceleration * params.unshaped.decelClocks);
+ reverseDistance = 0.0;
+ }
+ }
+
+ }
+# else
// Check if there is a reversal in the deceleration segment
// There is at most one deceleration segment in the unshaped segments
const MoveSegment *decelSeg = dda.unshapedSegments;
@@ -641,6 +717,7 @@ bool DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params) no
}
}
}
+# endif
}
else
{
@@ -786,7 +863,7 @@ bool DriveMovement::PrepareExtruder(const DDA& dda, const PrepParams& params) no
#if MS_USE_FPU
-// Version of fastSqrtf that allows for slightly negative operands cause dby rounding error
+// Version of fastSqrtf that allows for slightly negative operands caused by rounding error
static inline float fastLimSqrtf(float f) noexcept
{
return (f > 0.0) ? fastSqrtf(f) : 0.0;
@@ -914,11 +991,10 @@ pre(nextStep <= totalSteps; stepsTillRecalc == 0)
{
direction = false;
directionChanged = true;
- state = DMState::deltaReverse;
+ state = DMState::deltaNormal;
}
// no break
- case DMState::deltaForwardsNoReverse:
- case DMState::deltaReverse: // reversing on this and subsequent steps
+ case DMState::deltaNormal:
// Calculate d*s where d = distance the head has travelled, s = steps/mm for this drive
{
#if MS_USE_FPU
diff --git a/src/Movement/DriveMovement.h b/src/Movement/DriveMovement.h
index 8b24ecc1..5e4084ba 100644
--- a/src/Movement/DriveMovement.h
+++ b/src/Movement/DriveMovement.h
@@ -31,9 +31,8 @@ enum class DMState : uint8_t
cartDecelForwardsReversing, // linear decelerating motion, expect reversal
cartDecelReverse, // linear decelerating motion, reversed
- deltaForwardsNoReverse, // moving forwards, no reversal in this segment
- deltaForwardsReversing, // moving forwards but reversing in this segment
- deltaReverse, // moving in reverse
+ deltaNormal, // moving forwards without reversing in this segment, or in reverse
+ deltaForwardsReversing, // moving forwards to start with, reversing before the end of this segment
};
// This class describes a single movement of one drive
diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp
index d034b61e..72ef43fa 100644
--- a/src/Movement/Move.cpp
+++ b/src/Movement/Move.cpp
@@ -200,7 +200,7 @@ void Move::Init() noexcept
moveState = MoveState::idle;
whenLastMoveAdded = whenIdleTimerStarted = millis();
- simulationMode = 0;
+ simulationMode = SimulationMode::off;
longestGcodeWaitInterval = 0;
bedLevellingMoveAvailable = false;
@@ -240,7 +240,7 @@ void Move::Exit() noexcept
if (bedLevellingMoveAvailable)
{
moveRead = true;
- if (simulationMode < 2)
+ if (simulationMode < SimulationMode::partial)
{
if (mainDDARing.AddSpecialMove(reprap.GetPlatform().MaxFeedrate(Z_AXIS), specialMoveCoords))
{
@@ -263,7 +263,7 @@ void Move::Exit() noexcept
if (reprap.GetGCodes().ReadMove(nextMove)) // if we have a new move
{
moveRead = true;
- if (simulationMode < 2) // in simulation mode 2 and higher, we don't process incoming moves beyond this point
+ if (simulationMode < SimulationMode::partial) // in simulation mode partial, we don't process incoming moves beyond this point
{
if (nextMove.moveType == 0)
{
@@ -916,10 +916,10 @@ float Move::GetProbeCoordinates(int count, float& x, float& y, bool wantNozzlePo
}
// Enter or leave simulation mode
-void Move::Simulate(uint8_t simMode) noexcept
+void Move::Simulate(SimulationMode simMode) noexcept
{
simulationMode = simMode;
- if (simMode != 0)
+ if (simMode != SimulationMode::off)
{
mainDDARing.ResetSimulationTime();
}
diff --git a/src/Movement/Move.h b/src/Movement/Move.h
index b5583bb0..6eee76f2 100644
--- a/src/Movement/Move.h
+++ b/src/Movement/Move.h
@@ -129,7 +129,7 @@ public:
float IdleTimeout() const noexcept; // Returns the idle timeout in seconds
void SetIdleTimeout(float timeout) noexcept; // Set the idle timeout in seconds
- void Simulate(uint8_t simMode) noexcept; // Enter or leave simulation mode
+ void Simulate(SimulationMode simMode) noexcept; // Enter or leave simulation mode
float GetSimulationTime() const noexcept { return mainDDARing.GetSimulationTime(); } // Get the accumulated simulation time
bool PausePrint(RestorePoint& rp) noexcept; // Pause the print as soon as we can, returning true if we were able to
@@ -257,7 +257,7 @@ private:
DDARing& mainDDARing = rings[0]; // The DDA ring used for regular moves
- uint8_t simulationMode; // Are we simulating, or really printing?
+ SimulationMode simulationMode; // Are we simulating, or really printing?
MoveState moveState; // whether the idle timer is active
float maxPrintingAcceleration;
@@ -345,7 +345,7 @@ inline float Move::GetPressureAdvanceClocks(size_t extruder) const noexcept
// This is called from the stepper drivers SPI interface ISR
inline __attribute__((always_inline)) uint32_t Move::GetStepInterval(size_t axis, uint32_t microstepShift) const noexcept
{
- return (simulationMode == 0) ? mainDDARing.GetStepInterval(axis, microstepShift) : 0;
+ return (simulationMode == SimulationMode::off) ? mainDDARing.GetStepInterval(axis, microstepShift) : 0;
}
#endif
diff --git a/src/Version.h b/src/Version.h
index 8896bea8..f3a62e55 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -10,7 +10,7 @@
#ifndef VERSION
// Note: the complete VERSION string must be in standard version number format and must not contain spaces! This is so that DWC can parse it.
-# define MAIN_VERSION "3.4.0beta3+1"
+# define MAIN_VERSION "3.4.0beta4"
# ifdef USE_CAN0
# define VERSION_SUFFIX "(CAN0)"
# else