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
path: root/src
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2016-12-12 18:27:06 +0300
committerDavid Crocker <dcrocker@eschertech.com>2016-12-12 18:27:39 +0300
commitcd5af6c7b13656a555cdc5ffbb8e37624ce9af67 (patch)
treeceed8ac57fda8910ff28194e1a7460beb0b6afac /src
parent4896bba4e81a38792f3c72ff31363d7ed68132df (diff)
Version 1.17rc1
- Added support for M374 (save height map) and M375 (load height map) - Added M376 (set bed compensation taper height) - Added T parameter to G31 command - M500, M501 and M502 now use config_override.g instead of flash memory. The parameters saved and restored are: -- M307 auto tune results -- PID parameters, if you used M301 to override the auto tune PID settings -- Delta printer M665 and M666 settings -- G31 trigger height, trigger value and X and Y offsets - The M501 auto save option has been removed - Removed S and T parameters from M301 command. Use M307 command instead. - M301 with negative P parameter no longer sets bang-bang mode. Use M307 instead. - Added P parameter to the G31 command to specify Z probe type. This allows you to view the parameters for the Z probe(s) and to set parameters for a particular Z probe type without selecting that type. G31 P or G31 P0 prints the parameters of the currently-selected Z probe. - Z probe offsets are now applied during G30 probing with specified XY coordinates, including during delta auto calibration - Z probe recovery time is now applied from the end of the travel move just before probing - Fixed bad dive height when using G29 with a large trigger height - Fixed bad JSON message during printing when there were no active extruders - Added exception handlers and store a software reset code when an exception occurs - Fixed reset reason text because on the Duet WiFi a watchdog reset can look like an external reset - G30 S-1 how printes the stopped height - Implemented M401 and M402
Diffstat (limited to 'src')
-rw-r--r--src/Configuration.h4
-rw-r--r--src/Duet/Webserver.cpp2
-rw-r--r--src/DuetNG/Webserver.cpp2
-rw-r--r--src/GCodes/GCodeMachineState.cpp2
-rw-r--r--src/GCodes/GCodeMachineState.h5
-rw-r--r--src/GCodes/GCodes.cpp366
-rw-r--r--src/GCodes/GCodes.h18
-rw-r--r--src/GCodes/GCodes2.cpp142
-rw-r--r--src/Heating/FOPDT.cpp53
-rw-r--r--src/Heating/FOPDT.h29
-rw-r--r--src/Heating/Heat.cpp51
-rw-r--r--src/Heating/Heat.h24
-rw-r--r--src/Heating/Pid.cpp49
-rw-r--r--src/Heating/Pid.h10
-rw-r--r--src/Libraries/Fatfs/fattime_rtc.cpp (renamed from src/Libraries/Fatfs/fattime_rtc.c)31
-rw-r--r--src/Movement/DeltaParameters.cpp28
-rw-r--r--src/Movement/DeltaParameters.h1
-rw-r--r--src/Movement/Grid.cpp92
-rw-r--r--src/Movement/Grid.h20
-rw-r--r--src/Movement/Move.cpp43
-rw-r--r--src/Movement/Move.h10
-rw-r--r--src/Platform.cpp362
-rw-r--r--src/Platform.h172
-rw-r--r--src/RADDS/Pins_radds.h42
-rw-r--r--src/Reprap.cpp21
-rw-r--r--src/Storage/MassStorage.cpp12
-rw-r--r--src/Storage/MassStorage.h2
27 files changed, 871 insertions, 722 deletions
diff --git a/src/Configuration.h b/src/Configuration.h
index 728a1156..e739ac96 100644
--- a/src/Configuration.h
+++ b/src/Configuration.h
@@ -28,11 +28,11 @@ Licence: GPL
// Firmware name is now defined in the Pins file
#ifndef VERSION
-# define VERSION "1.17dev8"
+# define VERSION "1.17RC1"
#endif
#ifndef DATE
-# define DATE "2016-12-09"
+# define DATE "2016-12-12"
#endif
#define AUTHORS "reprappro, dc42, zpl, t3p3, dnewman"
diff --git a/src/Duet/Webserver.cpp b/src/Duet/Webserver.cpp
index 8db33a5e..69807ace 100644
--- a/src/Duet/Webserver.cpp
+++ b/src/Duet/Webserver.cpp
@@ -690,7 +690,7 @@ void Webserver::HttpInterpreter::DoFastUpload()
// Update the file timestamp if it was specified before
if (fileLastModified != 0)
{
- (void)platform->GetMassStorage()->SetLastModifiedTime(filename, fileLastModified);
+ (void)platform->GetMassStorage()->SetLastModifiedTime(nullptr, filename, fileLastModified);
}
// Eventually send the JSON response
diff --git a/src/DuetNG/Webserver.cpp b/src/DuetNG/Webserver.cpp
index 5f67e9f2..2a2a94f4 100644
--- a/src/DuetNG/Webserver.cpp
+++ b/src/DuetNG/Webserver.cpp
@@ -229,7 +229,7 @@ void Webserver::FinishUpload(HttpSession& session)
else if (session.fileLastModified != 0)
{
// Upload OK, update the file timestamp if it was specified before
- (void)platform->GetMassStorage()->SetLastModifiedTime(session.filenameBeingUploaded, session.fileLastModified);
+ (void)platform->GetMassStorage()->SetLastModifiedTime(nullptr, session.filenameBeingUploaded, session.fileLastModified);
}
}
diff --git a/src/GCodes/GCodeMachineState.cpp b/src/GCodes/GCodeMachineState.cpp
index 98dac7e6..55475680 100644
--- a/src/GCodes/GCodeMachineState.cpp
+++ b/src/GCodes/GCodeMachineState.cpp
@@ -13,7 +13,7 @@ unsigned int GCodeMachineState::numAllocated = 0;
// Create a default initialised GCodeMachineState
GCodeMachineState::GCodeMachineState()
: previous(nullptr), feedrate(DEFAULT_FEEDRATE/minutesToSeconds), fileState(), lockedResources(0), state(GCodeState::normal),
- drivesRelative(false), axesRelative(false), doingFileMacro(false)
+ drivesRelative(false), axesRelative(false), doingFileMacro(false), runningM502(false)
{
}
diff --git a/src/GCodes/GCodeMachineState.h b/src/GCodes/GCodeMachineState.h
index 1d05d2fa..74d41965 100644
--- a/src/GCodes/GCodeMachineState.h
+++ b/src/GCodes/GCodeMachineState.h
@@ -43,8 +43,10 @@ enum class GCodeState : uint8_t
flashing2,
stopping,
sleeping,
+ // These next 5 must be contiguous
gridProbing1,
gridProbing2,
+ gridProbing2a,
gridProbing3,
gridProbing4
};
@@ -64,7 +66,8 @@ public:
drivesRelative : 1,
axesRelative : 1,
doingFileMacro : 1,
- waitWhileCooling : 1;
+ waitWhileCooling : 1,
+ runningM502 : 1;
static GCodeMachineState *Allocate()
post(!result.IsLive(); result.state == GCodeState::normal);
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index 3fb29110..81f59e43 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -84,7 +84,6 @@ void GCodes::Init()
eofStringCounter = 0;
eofStringLength = strlen(eofString);
offSetSet = false;
- zProbesSet = false;
active = true;
longWait = platform->Time();
dwellTime = longWait;
@@ -158,8 +157,6 @@ void GCodes::Reset()
{
resourceOwners[i] = nullptr;
}
-
- lastProbedTime = millis();
}
float GCodes::FractionOfFilePrinted() const
@@ -175,8 +172,8 @@ bool GCodes::RunConfigFile(const char* fileName)
return DoFileMacro(*daemonGCode, fileName, false);
}
-// Are we still running the config file?
-bool GCodes::IsRunningConfigFile() const
+// Return true if the daemon is busy running config.g or a trigger file
+bool GCodes::IsDaemonBusy() const
{
return daemonGCode->MachineState().fileState.IsLive();
}
@@ -229,7 +226,7 @@ void GCodes::Spin()
if ((toBeHomed & (1u << axis)) != 0 && (axis != Z_AXIS || toBeHomed == (1u << Z_AXIS)))
{
toBeHomed &= ~(1u << axis);
- DoFileMacro(gb, HomingFileNames[axis]);
+ DoFileMacro(gb, HomingFileNames[axis], true);
break;
}
}
@@ -250,7 +247,6 @@ void GCodes::Spin()
probeCount++;
if (probeCount >= numProbePoints)
{
- zProbesSet = true;
reprap.GetMove()->FinishedBedProbing(0, reply);
gb.SetState(GCodeState::normal);
}
@@ -304,7 +300,7 @@ void GCodes::Spin()
if (LockMovementAndWaitForStandstill(gb))
{
gb.SetState(GCodeState::pausing2);
- DoFileMacro(gb, PAUSE_G);
+ DoFileMacro(gb, PAUSE_G, true);
}
break;
@@ -445,13 +441,13 @@ void GCodes::Spin()
moveBuffer.endStopsToCheck = 0;
moveBuffer.usePressureAdvance = false;
moveBuffer.filePos = noFilePosition;
- moveBuffer.coords[X_AXIS] = x - platform->GetZProbeParameters().xOffset;
- moveBuffer.coords[Y_AXIS] = y - platform->GetZProbeParameters().yOffset;
- moveBuffer.coords[Z_AXIS] = platform->GetZProbeDiveHeight();
+ moveBuffer.coords[X_AXIS] = x - platform->GetCurrentZProbeParameters().xOffset;
+ moveBuffer.coords[Y_AXIS] = y - platform->GetCurrentZProbeParameters().yOffset;
+ moveBuffer.coords[Z_AXIS] = platform->GetZProbeStartingHeight();
moveBuffer.feedRate = platform->GetZProbeTravelSpeed();
moveBuffer.xAxes = 0;
segmentsLeft = 1;
- gb.SetState(GCodeState::gridProbing2);
+ gb.AdvanceState();
}
else
{
@@ -461,9 +457,15 @@ void GCodes::Spin()
break;
case GCodeState::gridProbing2: // ready to probe the current grid probe point
- if (LockMovementAndWaitForStandstill(gb)
- && millis() - lastProbedTime >= (uint32_t)(reprap.GetPlatform()->GetZProbeParameters().recoveryTime * SecondsToMillis)
- )
+ if (LockMovementAndWaitForStandstill(gb))
+ {
+ lastProbedTime = millis();
+ gb.AdvanceState();
+ }
+ break;
+
+ case GCodeState::gridProbing2a: // ready to probe the current grid probe point
+ if (millis() - lastProbedTime >= (uint32_t)(reprap.GetPlatform()->GetCurrentZProbeParameters().recoveryTime * SecondsToMillis))
{
// Probe the bed at the current XY coordinates
// Check for probe already triggered at start
@@ -481,7 +483,7 @@ void GCodes::Spin()
moveBuffer.usePressureAdvance = false;
moveBuffer.filePos = noFilePosition;
moveBuffer.coords[Z_AXIS] = -platform->GetZProbeDiveHeight();
- moveBuffer.feedRate = platform->GetZProbeParameters().probeSpeed;
+ moveBuffer.feedRate = platform->GetCurrentZProbeParameters().probeSpeed;
moveBuffer.xAxes = 0;
segmentsLeft = 1;
gb.SetState(GCodeState::gridProbing3);
@@ -499,19 +501,15 @@ void GCodes::Spin()
break;
}
- lastProbedTime = millis();
const float heightError = moveBuffer.coords[Z_AXIS] - platform->ZProbeStopHeight();
reprap.GetMove()->AccessBedProbeGrid().SetGridHeight(gridXindex, gridYindex, heightError);
- ++numPointsProbed;
- heightSum += (double)heightError;
- heightSquaredSum += (double)heightError * (double)heightError;
// Move back up to the dive height
moveBuffer.moveType = 0;
moveBuffer.endStopsToCheck = 0;
moveBuffer.usePressureAdvance = false;
moveBuffer.filePos = noFilePosition;
- moveBuffer.coords[Z_AXIS] = platform->GetZProbeDiveHeight();
+ moveBuffer.coords[Z_AXIS] = platform->GetZProbeStartingHeight();
moveBuffer.feedRate = platform->GetZProbeTravelSpeed();
moveBuffer.xAxes = 0;
segmentsLeft = 1;
@@ -550,13 +548,13 @@ void GCodes::Spin()
if (gridYindex == grid.NumYpoints())
{
// Finished probing the grid
+ float mean, deviation;
+ const uint32_t numPointsProbed = reprap.GetMove()->AccessBedProbeGrid().GetStatistics(mean, deviation);
if (numPointsProbed >= 4)
{
- error = SaveHeightMapToFile(reply);
- const double mean = heightSum/numPointsProbed;
- const double deviation = sqrt(((heightSquaredSum * numPointsProbed) - (heightSum * heightSum)))/numPointsProbed;
- reply.catf(" - %u points probed, mean error %.2f, deviation %.2f", numPointsProbed, mean, deviation);
- reprap.GetMove()->UseHeightMap(true);
+ reply.printf("%u points probed, mean error %.2f, deviation %.2f\n", numPointsProbed, mean, deviation);
+ error = SaveHeightMap(gb, reply);
+ reprap.GetMove()->AccessBedProbeGrid().UseHeightMap(true);
}
else
{
@@ -783,7 +781,7 @@ void GCodes::CheckTriggers()
DoEmergencyStop();
}
else if (lowestTriggerPending < MaxTriggers // if a trigger is pending
- && !daemonGCode->MachineState().fileState.IsLive()
+ && !IsDaemonBusy()
&& daemonGCode->GetState() == GCodeState::normal // and we are not already executing a trigger or config.g
)
{
@@ -1061,9 +1059,10 @@ unsigned int GCodes::LoadMoveBufferFromGCode(GCodeBuffer& gb, int moveType)
{
mappedMoveArg -= currentTool->GetOffset()[mappedAxis]; // adjust requested position to compensate for tool offset
}
- if (reprap.GetMove()->UsingHeightMap())
+ const HeightMap& heightMap = reprap.GetMove()->AccessBedProbeGrid();
+ if (heightMap.UsingHeightMap())
{
- const unsigned int minSegments = reprap.GetMove()->AccessBedProbeGrid().GetMinimumSegments(fabs(mappedMoveArg - moveBuffer.coords[mappedAxis]));
+ const unsigned int minSegments = heightMap.GetMinimumSegments(fabs(mappedMoveArg - moveBuffer.coords[mappedAxis]));
if (minSegments > numSegments)
{
numSegments = minSegments;
@@ -1084,12 +1083,16 @@ unsigned int GCodes::LoadMoveBufferFromGCode(GCodeBuffer& gb, int moveType)
moveArg -= currentTool->GetOffset()[axis]; // adjust requested position to compensate for tool offset
}
- if (axis < Z_AXIS && moveType == 0 && reprap.GetMove()->UsingHeightMap())
+ if (axis < Z_AXIS && moveType == 0)
{
- const unsigned int minSegments = reprap.GetMove()->AccessBedProbeGrid().GetMinimumSegments(fabs(moveArg - moveBuffer.coords[axis]));
- if (minSegments > numSegments)
+ const HeightMap& heightMap = reprap.GetMove()->AccessBedProbeGrid();
+ if (heightMap.UsingHeightMap())
{
- numSegments = minSegments;
+ const unsigned int minSegments = reprap.GetMove()->AccessBedProbeGrid().GetMinimumSegments(fabs(moveArg - moveBuffer.coords[axis]));
+ if (minSegments > numSegments)
+ {
+ numSegments = minSegments;
+ }
}
}
moveBuffer.coords[axis] = moveArg;
@@ -1296,7 +1299,7 @@ void GCodes::ClearMove()
// Run a file macro. Prior to calling this, 'state' must be set to the state we want to enter when the macro has been completed.
// Return true if the file was found or it wasn't and we were asked to report that fact.
-bool GCodes::DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissing)
+bool GCodes::DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissing, bool runningM502)
{
FileStore * const f = platform->GetFileStore(platform->GetSysDir(), fileName, false);
if (f == nullptr)
@@ -1316,6 +1319,7 @@ bool GCodes::DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissi
}
gb.MachineState().fileState.Set(f);
gb.MachineState().doingFileMacro = true;
+ gb.MachineState().runningM502 = runningM502;
gb.SetState(GCodeState::normal);
gb.Init();
return true;
@@ -1524,7 +1528,7 @@ bool GCodes::DoHome(GCodeBuffer& gb, StringRef& reply, bool& error)
if (reprap.GetMove()->IsDeltaMode())
{
SetAllAxesNotHomed();
- DoFileMacro(gb, HOME_DELTA_G);
+ DoFileMacro(gb, HOME_DELTA_G, true);
}
else
{
@@ -1542,7 +1546,7 @@ bool GCodes::DoHome(GCodeBuffer& gb, StringRef& reply, bool& error)
{
// Homing everything
SetAllAxesNotHomed();
- DoFileMacro(gb, HOME_ALL_G);
+ DoFileMacro(gb, HOME_ALL_G, true);
}
else if ( platform->MustHomeXYBeforeZ()
&& ((toBeHomed & (1u << Z_AXIS)) != 0)
@@ -1577,7 +1581,7 @@ bool GCodes::DoSingleZProbeAtPoint(GCodeBuffer& gb, int probePointIndex, float h
switch (cannedCycleMoveCount)
{
case 0: // Move Z to the dive height. This only does anything on the first move; on all the others Z is already there
- cannedMoveCoords[Z_AXIS] = platform->GetZProbeDiveHeight() + max<float>(platform->ZProbeStopHeight(), 0.0);
+ cannedMoveCoords[Z_AXIS] = platform->GetZProbeStartingHeight();
cannedMoveType[Z_AXIS] = CannedMoveType::absolute;
cannedFeedRate = platform->GetZProbeTravelSpeed();
if (DoCannedCycleMove(gb, 0))
@@ -1587,19 +1591,20 @@ bool GCodes::DoSingleZProbeAtPoint(GCodeBuffer& gb, int probePointIndex, float h
return false;
case 1: // Move to the correct XY coordinates
- GetProbeCoordinates(probePointIndex, cannedMoveCoords[X_AXIS], cannedMoveCoords[Y_AXIS], cannedMoveCoords[Z_AXIS]);
+ (void)reprap.GetMove()->GetProbeCoordinates(probePointIndex, cannedMoveCoords[X_AXIS], cannedMoveCoords[Y_AXIS], true);
cannedMoveType[X_AXIS] = CannedMoveType::absolute;
cannedMoveType[Y_AXIS] = CannedMoveType::absolute;
// NB - we don't use the Z value
cannedFeedRate = platform->GetZProbeTravelSpeed();
if (DoCannedCycleMove(gb, 0))
{
+ lastProbedTime = millis();
cannedCycleMoveCount++;
}
return false;
case 2: // Probe the bed
- if (millis() - lastProbedTime >= (uint32_t)(platform->GetZProbeParameters().recoveryTime * SecondsToMillis))
+ if (millis() - lastProbedTime >= (uint32_t)(platform->GetCurrentZProbeParameters().recoveryTime * SecondsToMillis))
{
const float height = (GetAxisIsHomed(Z_AXIS))
? 2 * platform->GetZProbeDiveHeight() // Z axis has been homed, so no point in going very far
@@ -1622,7 +1627,6 @@ bool GCodes::DoSingleZProbeAtPoint(GCodeBuffer& gb, int probePointIndex, float h
case 2:
// Successful probing
- lastProbedTime = millis();
if (GetAxisIsHomed(Z_AXIS))
{
lastProbedZ = moveBuffer.coords[Z_AXIS] - (platform->ZProbeStopHeight() + heightAdjust);
@@ -1646,7 +1650,7 @@ bool GCodes::DoSingleZProbeAtPoint(GCodeBuffer& gb, int probePointIndex, float h
return false;
case 3: // Raise the head back up to the dive height
- cannedMoveCoords[Z_AXIS] = platform->GetZProbeDiveHeight() + max<float>(platform->ZProbeStopHeight(), 0.0);
+ cannedMoveCoords[Z_AXIS] = platform->GetZProbeStartingHeight();
cannedMoveType[Z_AXIS] = CannedMoveType::absolute;
cannedFeedRate = platform->GetZProbeTravelSpeed();
if (DoCannedCycleMove(gb, 0))
@@ -1664,7 +1668,7 @@ bool GCodes::DoSingleZProbeAtPoint(GCodeBuffer& gb, int probePointIndex, float h
// This simply moves down till the Z probe/switch is triggered. Call it repeatedly until it returns true.
// Called when we do a G30 with no P parameter.
-bool GCodes::DoSingleZProbe(GCodeBuffer& gb, bool reportOnly, float heightAdjust)
+bool GCodes::DoSingleZProbe(GCodeBuffer& gb, StringRef& reply, bool reportOnly, float heightAdjust)
{
switch (DoZProbe(gb, 1.1 * platform->AxisTotalLength(Z_AXIS)))
{
@@ -1677,7 +1681,13 @@ bool GCodes::DoSingleZProbe(GCodeBuffer& gb, bool reportOnly, float heightAdjust
return true;
case 2: // success
- if (!reportOnly)
+ if (reportOnly)
+ {
+ float m[DRIVES];
+ reprap.GetMove()->GetCurrentMachinePosition(m, false);
+ reply.printf("Stopped at height %.3f mm", m[Z_AXIS]);
+ }
+ else
{
moveBuffer.coords[Z_AXIS] = platform->ZProbeStopHeight() + heightAdjust;
SetPositions(moveBuffer.coords);
@@ -1700,7 +1710,7 @@ int GCodes::DoZProbe(GCodeBuffer& gb, float distance)
{
if (platform->GetZProbeType() == ZProbeTypeDelta)
{
- const ZProbeParameters& params = platform->GetZProbeParameters();
+ const ZProbeParameters& params = platform->GetCurrentZProbeParameters();
return reprap.GetMove()->DoDeltaProbe(params.extraParam, 1.0, params.probeSpeed, distance); //TODO second parameter
}
else
@@ -1723,7 +1733,7 @@ int GCodes::DoZProbe(GCodeBuffer& gb, float distance)
cannedMoveCoords[Z_AXIS] = -distance;
cannedMoveType[Z_AXIS] = CannedMoveType::relative;
- cannedFeedRate = platform->GetZProbeParameters().probeSpeed;
+ cannedFeedRate = platform->GetCurrentZProbeParameters().probeSpeed;
if (DoCannedCycleMove(gb, ZProbeActive))
{
@@ -1756,24 +1766,20 @@ bool GCodes::SetSingleZProbeAtAPosition(GCodeBuffer& gb, StringRef& reply)
if (!gb.Seen('P'))
{
- bool reportOnly = false;
- if (gb.Seen('S') && gb.GetIValue() < 0)
- {
- reportOnly = true;
- }
- return DoSingleZProbe(gb, reportOnly, heightAdjust);
+ const bool reportOnly = (gb.Seen('S') && gb.GetIValue() < 0);
+ return DoSingleZProbe(gb, reply, reportOnly, heightAdjust);
}
- int probePointIndex = gb.GetIValue();
+ const int probePointIndex = gb.GetIValue();
if (probePointIndex < 0 || (unsigned int)probePointIndex >= MaxProbePoints)
{
reprap.GetPlatform()->Message(GENERIC_MESSAGE, "Z probe point index out of range.\n");
return true;
}
- float x = (gb.Seen(axisLetters[X_AXIS])) ? gb.GetFValue() : moveBuffer.coords[X_AXIS];
- float y = (gb.Seen(axisLetters[Y_AXIS])) ? gb.GetFValue() : moveBuffer.coords[Y_AXIS];
- float z = (gb.Seen(axisLetters[Z_AXIS])) ? gb.GetFValue() : moveBuffer.coords[Z_AXIS];
+ const float x = (gb.Seen(axisLetters[X_AXIS])) ? gb.GetFValue() : moveBuffer.coords[X_AXIS];
+ const float y = (gb.Seen(axisLetters[Y_AXIS])) ? gb.GetFValue() : moveBuffer.coords[Y_AXIS];
+ const float z = (gb.Seen(axisLetters[Z_AXIS])) ? gb.GetFValue() : moveBuffer.coords[Z_AXIS];
reprap.GetMove()->SetXBedProbePoint(probePointIndex, x);
reprap.GetMove()->SetYBedProbePoint(probePointIndex, y);
@@ -1783,7 +1789,6 @@ bool GCodes::SetSingleZProbeAtAPosition(GCodeBuffer& gb, StringRef& reply)
reprap.GetMove()->SetZBedProbePoint(probePointIndex, z, false, false);
if (gb.Seen('S'))
{
- zProbesSet = true;
reprap.GetMove()->FinishedBedProbing(gb.GetIValue(), reply);
}
return true;
@@ -1794,8 +1799,7 @@ bool GCodes::SetSingleZProbeAtAPosition(GCodeBuffer& gb, StringRef& reply)
{
if (gb.Seen('S'))
{
- zProbesSet = true;
- int sParam = gb.GetIValue();
+ const int sParam = gb.GetIValue();
if (sParam == 1)
{
// G30 with a silly Z value and S=1 is equivalent to G30 with no parameters in that it sets the current Z height
@@ -1816,20 +1820,18 @@ bool GCodes::SetSingleZProbeAtAPosition(GCodeBuffer& gb, StringRef& reply)
return false;
}
-// This returns the (X, Y) points to probe the bed at probe point count. When probing, it returns false.
-// If called after probing has ended it returns true, and the Z coordinate probed is also returned.
-bool GCodes::GetProbeCoordinates(int count, float& x, float& y, float& z) const
-{
- const ZProbeParameters& rp = platform->GetZProbeParameters();
- x = reprap.GetMove()->XBedProbePoint(count) - rp.xOffset;
- y = reprap.GetMove()->YBedProbePoint(count) - rp.yOffset;
- z = reprap.GetMove()->ZBedProbePoint(count);
- return zProbesSet;
-}
-
+// Set or print the Z probe. Called by G31.
+// Note that G31 P or G31 P0 prints the parameters of the currently-selected Z probe.
bool GCodes::SetPrintZProbe(GCodeBuffer& gb, StringRef& reply)
{
- ZProbeParameters params = platform->GetZProbeParameters();
+ int32_t zProbeType = 0;
+ bool seenT = false;
+ gb.TryGetIValue('T',zProbeType, seenT);
+ if (zProbeType == 0)
+ {
+ zProbeType = platform->GetZProbeType();
+ }
+ ZProbeParameters params = platform->GetZProbeParameters(zProbeType);
bool seen = false;
gb.TryGetFValue(axisLetters[X_AXIS], params.xOffset, seen);
gb.TryGetFValue(axisLetters[Y_AXIS], params.yOffset, seen);
@@ -1853,11 +1855,20 @@ bool GCodes::SetPrintZProbe(GCodeBuffer& gb, StringRef& reply)
if (seen)
{
- platform->SetZProbeParameters(params);
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ platform->SetZProbeParameters(zProbeType, params);
+ }
+ else if (seenT)
+ {
+ // Don't bother printing temperature coefficient and calibration temperature because we will probably remove them soon
+ reply.printf("Threshold %d, trigger height %.2f, offsets X%.1f Y%.1f", params.adcValue, params.height, params.xOffset, params.yOffset);
}
else
{
- const int v0 = platform->ZProbe();
+ const int v0 = platform->GetZProbeReading();
int v1, v2;
switch (platform->GetZProbeSecondaryValues(v1, v2))
{
@@ -1879,8 +1890,6 @@ bool GCodes::SetPrintZProbe(GCodeBuffer& gb, StringRef& reply)
// Called when we see an M557 command with no P parameter
bool GCodes::DefineGrid(GCodeBuffer& gb, StringRef &reply)
{
- reprap.GetMove()->UseHeightMap(false);
-
bool seenX = false, seenY = false, seenR = false, seenS = false;
float xValues[2];
float yValues[2];
@@ -1963,7 +1972,7 @@ bool GCodes::DefineGrid(GCodeBuffer& gb, StringRef &reply)
return true;
}
}
- GridDefinition newGrid(xValues, yValues, radius, spacing); // create a new grid
+ GridDefinition newGrid(xValues, yValues, radius, spacing); // create a new grid
if (newGrid.IsValid())
{
reprap.GetMove()->AccessBedProbeGrid().SetGrid(newGrid);
@@ -1981,100 +1990,90 @@ bool GCodes::DefineGrid(GCodeBuffer& gb, StringRef &reply)
// Prior to calling this the movement system must be locked.
bool GCodes::ProbeGrid(GCodeBuffer& gb, StringRef& reply)
{
- int32_t sParam = 0;
- bool dummy;
- gb.TryGetIValue('S', sParam, dummy);
+ Move * const move = reprap.GetMove();
+ if (!move->AccessBedProbeGrid().GetGrid().IsValid())
+ {
+ reply.copy("No valid grid defined for G29 bed probing");
+ return true;
+ }
+
+ if (!AllAxesAreHomed())
+ {
+ reply.copy("Must home printer before G29 bed probing");
+ return true;
+ }
+ gridXindex = gridYindex = 0;
+
+ HeightMap& heightMap = move->AccessBedProbeGrid();
+ heightMap.UseHeightMap(false);
+ heightMap.ClearGridHeights();
+ move->SetIdentityTransform();
+ gb.SetState(GCodeState::gridProbing1);
+ return false;
+}
+
+bool GCodes::LoadHeightMap(GCodeBuffer& gb, StringRef& reply) const
+{
+ const char* heightMapFileName;
if (gb.Seen('P'))
{
- heightMapFile = gb.GetString();
+ heightMapFileName = gb.GetString();
}
else
{
- heightMapFile = DefaultHeightMapFile;
+ heightMapFileName = DefaultHeightMapFile;
}
+ FileStore * const f = platform->GetFileStore(platform->GetSysDir(), heightMapFileName, false);
- Move * const move = reprap.GetMove();
- switch(sParam)
+ if (f == nullptr)
{
- case 0: // Probe the bed and save to file
- if (!move->AccessBedProbeGrid().GetGrid().IsValid())
- {
- reply.copy("No valid grid defined for G29 bed probing");
- return true;
- }
-
- if (!AllAxesAreHomed())
- {
- reply.copy("Must home printer before G29 bed probing");
- return true;
- }
+ reply.printf("Height map file %s not found", heightMapFileName);
+ return true;
+ }
- gridXindex = gridYindex = 0;
- numPointsProbed = 0;
- heightSum = heightSquaredSum = 0.0;
+ reply.printf("Failed to load height map from file %s: ", heightMapFileName); // set up error message to append to
+ HeightMap& heightMap = reprap.GetMove()->AccessBedProbeGrid();
+ const bool err = heightMap.LoadFromFile(f, reply);
+ f->Close();
+ if (err)
+ {
+ heightMap.ClearGridHeights(); // make sure we don't end up with a partial height map
+ }
+ else
+ {
+ reply.Clear(); // wipe the error message
+ }
- move->AccessBedProbeGrid().ClearGridHeights();
- move->UseHeightMap(false);
- move->SetIdentityTransform();
- gb.SetState(GCodeState::gridProbing1);
- return false;
+ heightMap.UseHeightMap(!err);
+ return err;
+}
- case 1: // Load height map from file
+// Save the height map and append the success or error message to 'reply', returning true if an error occurred
+// Called by G29 and M374. Both use the P parameter to provide the filename.
+bool GCodes::SaveHeightMap(GCodeBuffer& gb, StringRef& reply) const
+{
+ const char* heightMapFileName;
+ if (gb.Seen('P'))
+ {
+ heightMapFileName = gb.GetString();
+ if (heightMapFileName[0] == 0)
{
- const char* locHeightMapFileName;
- if (gb.Seen('P'))
- {
- locHeightMapFileName = gb.GetString();
- }
- else
- {
- locHeightMapFileName = DefaultHeightMapFile;
- }
- FileStore * const f = platform->GetFileStore(platform->GetSysDir(), locHeightMapFileName, false);
-
- if (f == nullptr)
- {
- reply.printf("Height map file %s not found", locHeightMapFileName);
- return true;
- }
-
- reply.printf("Failed to load height map from file %s: ", heightMapFile); // set up error message to append to
- const bool err = move->AccessBedProbeGrid().LoadFromFile(f, reply);
- f->Close();
- if (err)
- {
- move->AccessBedProbeGrid().ClearGridHeights(); // make sure we don't end up with a partial height map
- }
- else
- {
- reply.Clear(); // wipe the error message
- }
-
- move->UseHeightMap(!err);
- return err;
+ reply.cat("No height map file name provided");
+ return false; // no file name provided, which is legitimate for G29
}
-
- case 2: // Clear height map
- move->AccessBedProbeGrid().ClearGridHeights();
- move->UseHeightMap(false);
- return false;
-
- default:
- reply.copy("Invalid S parameter in G29 command");
- return true;
}
-}
+ else
+ {
+ heightMapFileName = DefaultHeightMapFile;
+ }
-// Save the height map and write the success or error message to 'reply', returning true if an error occurred
-bool GCodes::SaveHeightMapToFile(StringRef& reply) const
-{
- Platform *platform = reprap.GetPlatform();
- FileStore * const f = platform->GetFileStore(platform->GetSysDir(), heightMapFile, true);
+ Platform * const platform = reprap.GetPlatform();
+ FileStore * const f = platform->GetFileStore(platform->GetSysDir(), heightMapFileName, true);
bool err;
if (f == nullptr)
{
- reply.printf("Failed to create height map file %s", heightMapFile);
+ reply.catf("Failed to create height map file %s", heightMapFileName);
err = true;
}
else
@@ -2083,17 +2082,25 @@ bool GCodes::SaveHeightMapToFile(StringRef& reply) const
f->Close();
if (err)
{
- platform->GetMassStorage()->Delete(platform->GetSysDir(), heightMapFile);
- reply.printf("Failed to save height map to file %s", heightMapFile);
+ platform->GetMassStorage()->Delete(platform->GetSysDir(), heightMapFileName);
+ reply.catf("Failed to save height map to file %s", heightMapFileName);
}
else
{
- reply.printf("Height map saved to file %s", heightMapFile);
+ reply.catf("Height map saved to file %s", heightMapFileName);
}
}
return err;
}
+// Clear the height map
+void GCodes::ClearHeightMap() const
+{
+ HeightMap& heightMap = reprap.GetMove()->AccessBedProbeGrid();
+ heightMap.ClearGridHeights();
+ heightMap.UseHeightMap(false);
+}
+
// Return the current coordinates as a printable string.
// Coordinates are updated at the end of each movement, so this won't tell you where you are mid-movement.
void GCodes::GetCurrentCoordinates(StringRef& s) const
@@ -2868,22 +2875,28 @@ void GCodes::SetPidParameters(GCodeBuffer& gb, int heater, StringRef& reply)
if (heater >= 0 && heater < HEATERS)
{
- PidParameters pp = platform->GetPidParameters(heater);
+ const FopDt& model = reprap.GetHeat()->GetHeaterModel(heater);
+ M301PidParameters pp = model.GetM301PidParameters(false);
bool seen = false;
gb.TryGetFValue('P', pp.kP, seen);
gb.TryGetFValue('I', pp.kI, seen);
gb.TryGetFValue('D', pp.kD, seen);
- gb.TryGetFValue('T', pp.kT, seen);
- gb.TryGetFValue('S', pp.kS, seen);
if (seen)
{
- platform->SetPidParameters(heater, pp);
- reprap.GetHeat()->UseModel(heater, false);
+ reprap.GetHeat()->SetM301PidParameters(heater, pp);
+ }
+ else if (!model.UsePid())
+ {
+ reply.printf("Heater %d is in bang-bang mode", heater);
+ }
+ else if (model.ArePidParametersOverridden())
+ {
+ reply.printf("Heater %d P:%.1f I:%.3f D:%.1f", heater, pp.kP, pp.kI, pp.kD);
}
else
{
- reply.printf("Heater %d P:%.2f I:%.3f D:%.2f T:%.2f S:%.2f", heater, pp.kP, pp.kI, pp.kD, pp.kT, pp.kS);
+ reply.printf("Heater %d uses model-derived PID parameters. Use M307 H%d to view them", heater, heater);
}
}
}
@@ -3217,6 +3230,41 @@ void GCodes::SetAllAxesNotHomed()
axesHomed = 0;
}
+// Write the config-override file returning true if an error occurred
+bool GCodes::WriteConfigOverrideFile(StringRef& reply, const char *fileName) const
+{
+ FileStore * const f = platform->GetFileStore(platform->GetSysDir(), fileName, true);
+ if (f == nullptr)
+ {
+ reply.printf("Failed to create file %s", fileName);
+ return true;
+ }
+
+ bool ok = f->Write("; This is a system-generated file - do not edit\n");
+ if (ok)
+ {
+ ok = reprap.GetMove()->GetDeltaParams().WriteParameters(f);
+ }
+ if (ok)
+ {
+ ok = reprap.GetHeat()->WriteModelParameters(f);
+ }
+ if (ok)
+ {
+ ok = platform->WriteZProbeParameters(f);
+ }
+ if (!f->Close())
+ {
+ ok = false;
+ }
+ if (!ok)
+ {
+ reply.printf("Failed to write file %s", fileName);
+ platform->GetMassStorage()->Delete(platform->GetSysDir(), fileName);
+ }
+ return !ok;
+}
+
// Resource locking/unlocking
// Lock the resource, returning true if success.
diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h
index 4c677382..04a8aeb3 100644
--- a/src/GCodes/GCodes.h
+++ b/src/GCodes/GCodes.h
@@ -83,14 +83,13 @@ public:
void ClearMove();
void QueueFileToPrint(const char* fileName); // Open a file of G Codes to run
void DeleteFile(const char* fileName); // Does what it says
- bool GetProbeCoordinates(int count, float& x, float& y, float& z) const; // Get pre-recorded probe coordinates
void GetCurrentCoordinates(StringRef& s) const; // Write where we are into a string
bool DoingFileMacro() const; // Or still busy processing a macro file?
float FractionOfFilePrinted() const; // Get fraction of file printed
void Diagnostics(MessageType mtype); // Send helpful information out
bool RunConfigFile(const char* fileName); // Start running the config file
- bool IsRunningConfigFile() const; // Are we still running the config file?
+ bool IsDaemonBusy() const; // Return true if the daemon is busy running config.g or a trigger file
bool GetAxisIsHomed(unsigned int axis) const // Has the axis been homed?
{ return (axesHomed & (1 << axis)) != 0; }
@@ -155,7 +154,8 @@ private:
void StartNextGCode(GCodeBuffer& gb, StringRef& reply); // Fetch a new or old GCode and process it
void DoFilePrint(GCodeBuffer& gb, StringRef& reply); // Get G Codes from a file and print them
- bool DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissing = true); // Run a GCode macro in a file, optionally report error if not found
+ bool DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissing, bool runningM502 = false);
+ // Run a GCode macro file, optionally report error if not found
bool DoCannedCycleMove(GCodeBuffer& gb, EndstopChecks ce); // Do a move from an internally programmed canned cycle
void FileMacroCyclesReturn(GCodeBuffer& gb); // End a macro
bool ActOnCode(GCodeBuffer& gb, StringRef& reply); // Do a G, M or T Code
@@ -167,7 +167,7 @@ private:
bool DoDwellTime(float dwell); // Really wait for a bit
bool DoHome(GCodeBuffer& gb, StringRef& reply, bool& error); // Home some axes
bool DoSingleZProbeAtPoint(GCodeBuffer& gb, int probePointIndex, float heightAdjust); // Probe at a given point
- bool DoSingleZProbe(GCodeBuffer& gb, bool reportOnly, float heightAdjust); // Probe where we are
+ bool DoSingleZProbe(GCodeBuffer& gb, StringRef& reply, bool reportOnly, float heightAdjust); // Probe where we are
int DoZProbe(GCodeBuffer& gb, float distance); // Do a Z probe cycle up to the maximum specified distance
bool SetSingleZProbeAtAPosition(GCodeBuffer& gb, StringRef& reply); // Probes at a given position - see the comment at the head of the function itself
void SetBedEquationWithProbe(int sParam, StringRef& reply); // Probes a series of points and sets the bed equation
@@ -211,7 +211,11 @@ private:
bool DefineGrid(GCodeBuffer& gb, StringRef &reply); // Define the probing grid, returning true if error
bool ProbeGrid(GCodeBuffer& gb, StringRef& reply); // Start probing the grid, returning true if we didn't because of an error
- bool SaveHeightMapToFile(StringRef& reply) const; // Save the height map to file
+ bool LoadHeightMap(GCodeBuffer& gb, StringRef& reply) const; // Load the height map from file
+ bool SaveHeightMap(GCodeBuffer& gb, StringRef& reply) const; // Save the height map to file
+ void ClearHeightMap() const; // Clear the height map
+
+ bool WriteConfigOverrideFile(StringRef& reply, const char *fileName) const; // Write the config-override file
static uint32_t LongArrayToBitMap(const long *arr, size_t numEntries); // Convert an array of longs to a bit map
@@ -272,12 +276,8 @@ private:
// Z probe
float lastProbedZ; // the last height at which the Z probe stopped
uint32_t lastProbedTime; // time in milliseconds that the probe was last triggered
- bool zProbesSet; // True if all Z probing is done and we can set the bed equation
volatile bool zProbeTriggered; // Set by the step ISR when a move is aborted because the Z probe is triggered
size_t gridXindex, gridYindex; // Which grid probe point is next
- size_t numPointsProbed;
- double heightSum, heightSquaredSum;
- const char *heightMapFile;
float simulationTime; // Accumulated simulation time
uint8_t simulationMode; // 0 = not simulating, 1 = simulating, >1 are simulation modes for debugging
diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp
index 3dd0c2d4..02a52294 100644
--- a/src/GCodes/GCodes2.cpp
+++ b/src/GCodes/GCodes2.cpp
@@ -18,6 +18,9 @@ const char* RESUME_G = "resume.g";
const char* CANCEL_G = "cancel.g";
const char* STOP_G = "stop.g";
const char* SLEEP_G = "sleep.g";
+const char* CONFIG_OVERRIDE_G = "config-override.g";
+const char* DEPLOYPROBE_G = "deployprobe.g";
+const char* RETRACTPROBE_G = "retractprobe.g";
const float MinServoPulseWidth = 544.0, MaxServoPulseWidth = 2400.0;
const uint16_t ServoRefreshFrequency = 50;
@@ -66,6 +69,10 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, StringRef& reply)
{
return true; // we only simulate some gcodes
}
+ if (gb.MachineState().runningM502 && code != 31)
+ {
+ return true; // when running M502 the only gcode we execute is G31
+ }
switch (code)
{
@@ -162,7 +169,23 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, StringRef& reply)
{
return false;
}
- error = ProbeGrid(gb, reply);
+ {
+ const int sparam = (gb.Seen('S')) ? gb.GetIValue() : 0;
+ switch(sparam)
+ {
+ case 0: // probe and save height map
+ error = ProbeGrid(gb, reply);
+ break;
+
+ case 1: // load height map file
+ error = LoadHeightMap(gb, reply);
+ break;
+
+ default: // clear height map
+ reprap.GetMove()->AccessBedProbeGrid().ClearGridHeights();
+ break;
+ }
+ }
break;
case 30: // Z probe/manually set at a position and set that as point P
@@ -182,10 +205,6 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, StringRef& reply)
break;
case 31: // Return the probe value, or set probe variables
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
result = SetPrintZProbe(gb, reply);
break;
@@ -247,6 +266,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
{
return true; // we don't yet simulate most M codes
}
+ if (gb.MachineState().runningM502 && code != 301 && code != 307 && code != 558 && code != 665 && code != 666)
+ {
+ return true; // when running M502 the only mcodes we execute are 301, 307, 558, 665 and 666
+ }
switch (code)
{
@@ -489,7 +512,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
if (isPaused)
{
gb.SetState(GCodeState::resuming1);
- DoFileMacro(gb, RESUME_G);
+ DoFileMacro(gb, RESUME_G, true);
}
else if (!fileToPrint.IsLive())
{
@@ -843,7 +866,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
case 98: // Call Macro/Subprogram
if (gb.Seen('P'))
{
- DoFileMacro(gb, gb.GetString());
+ DoFileMacro(gb, gb.GetString(), true);
}
break;
@@ -1557,10 +1580,6 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
}
break;
- case 205: //M205 advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk
- // This is superseded in this firmware by M codes for the separate types (e.g. M566).
- break;
-
case 206: // Offset axes - Deprecated
result = OffsetAxes(gb);
break;
@@ -1826,11 +1845,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
if (seen)
{
- if (reprap.GetHeat()->SetHeaterModel(heater, gain, tc, td, maxPwm, dontUsePid == 0))
- {
- reprap.GetHeat()->UseModel(heater, true);
- }
- else
+ if (!reprap.GetHeat()->SetHeaterModel(heater, gain, tc, td, maxPwm, dontUsePid == 0))
{
reply.copy("Error: bad model parameters");
}
@@ -1841,21 +1856,18 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
}
else
{
- reply.printf("Heater %u model: gain %.1f, time constant %.1f, dead time %.1f, max PWM %.2f, in use: %s, mode: %s",
- heater, model.GetGain(), model.GetTimeConstant(), model.GetDeadTime(), model.GetMaxPwm(),
- (reprap.GetHeat()->IsModelUsed(heater)) ? "yes" : "no",
- (model.UsePid()) ? "PID" : "bang-bang");
+ const char* mode = (!model.UsePid()) ? "bang-bang"
+ : (model.ArePidParametersOverridden()) ? "custom PID"
+ : "PID";
+ reply.printf("Heater %u model: gain %.1f, time constant %.1f, dead time %.1f, max PWM %.2f, mode: %s",
+ heater, model.GetGain(), model.GetTimeConstant(), model.GetDeadTime(), model.GetMaxPwm(), mode);
if (model.UsePid())
{
// When reporting the PID parameters, we scale them by 255 for compatibility with older firmware and other firmware
- const PidParams& spParams = model.GetPidParameters(false);
- const float scaledSpKp = 255.0 * spParams.kP;
- reply.catf("\nSetpoint change: P%.1f, I%.2f, D%.1f",
- scaledSpKp, scaledSpKp * spParams.recipTi, scaledSpKp * spParams.tD);
- const PidParams& ldParams = model.GetPidParameters(true);
- const float scaledLoadKp = 255.0 * ldParams.kP;
- reply.catf("\nLoad change: P%.1f, I%.2f, D%.1f",
- scaledLoadKp, scaledLoadKp * ldParams.recipTi, scaledLoadKp * ldParams.tD);
+ M301PidParameters params = model.GetM301PidParameters(false);
+ reply.catf("\nSetpoint change: P%.1f, I%.3f, D%.1f", params.kP, params.kI, params.kD);
+ params = model.GetM301PidParameters(true);
+ reply.catf("\nLoad change: P%.1f, I%.3f, D%.1f", params.kP, params.kI, params.kD);
}
}
}
@@ -1932,6 +1944,36 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
}
break;
+ case 374: // Save grid and height map to file
+ error = SaveHeightMap(gb, reply);
+ break;
+
+ case 375: // Load grid and height map from file and enable compensation
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ error = LoadHeightMap(gb, reply);
+ break;
+
+ case 376: // Set taper height
+ {
+ HeightMap& heightMap = reprap.GetMove()->AccessBedProbeGrid();
+ if (gb.Seen('H'))
+ {
+ heightMap.SetTaperHeight(gb.GetFValue());
+ }
+ else if (heightMap.GetTaperHeight() > 0.0)
+ {
+ reply.printf("Bed compensation taper height is %.1fmm", heightMap.GetTaperHeight());
+ }
+ else
+ {
+ reply.copy("Bed compensation is not tapered");
+ }
+ }
+ break;
+
case 400: // Wait for current moves to finish
if (!LockMovementAndWaitForStandstill(gb))
{
@@ -1939,6 +1981,14 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
}
break;
+ case 401: // Deploy Z probe
+ DoFileMacro(gb, DEPLOYPROBE_G, false);
+ break;
+
+ case 402: // Retract Z probe
+ DoFileMacro(gb, RETRACTPROBE_G, false);
+ break;
+
case 404: // Filament width and nozzle diameter
{
bool seen = false;
@@ -1996,19 +2046,18 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
break;
case 500: // Store parameters in EEPROM
- reprap.GetPlatform()->WriteNvData();
+ error = WriteConfigOverrideFile(reply, CONFIG_OVERRIDE_G);
break;
case 501: // Load parameters from EEPROM
- reprap.GetPlatform()->ReadNvData();
- if (gb.Seen('S'))
- {
- reprap.GetPlatform()->SetAutoSave(gb.GetIValue() > 0);
- }
+ DoFileMacro(gb, "config-override.g", true);
break;
case 502: // Revert to default "factory settings"
- reprap.GetPlatform()->ResetNvData();
+ reprap.GetHeat()->ResetHeaterModels(); // in case some heaters have no M307 commands in config.g
+ reprap.GetMove()->AccessDeltaParams().Init(); // in case M665 and M666 in config.g don't define all the parameters
+ platform->SetZProbeDefaults();
+ DoFileMacro(gb, "config.g", true, true);
break;
case 503: // List variable settings
@@ -2281,7 +2330,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
seenType = true;
}
- ZProbeParameters params = platform->GetZProbeParameters();
+ ZProbeParameters params = platform->GetCurrentZProbeParameters();
gb.TryGetFValue('H', params.diveHeight, seenParam); // dive height
if (gb.Seen('F')) // feed rate i.e. probing speed
@@ -2307,7 +2356,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
if (seenParam)
{
- platform->SetZProbeParameters(params);
+ platform->SetZProbeParameters(platform->GetZProbeType(), params);
}
if (!(seenAxes || seenType || seenParam))
@@ -2363,7 +2412,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
}
break;
- case 561:
+ case 561: // Set identity transform (also clears bed probe grid)
reprap.GetMove()->SetIdentityTransform();
break;
@@ -3040,17 +3089,17 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
if (gb.Seen('L'))
{
- params.SetDiagonal(gb.GetFValue() * distanceScale);
+ params.SetDiagonal(gb.GetFValue());
seen = true;
}
if (gb.Seen('R'))
{
- params.SetRadius(gb.GetFValue() * distanceScale);
+ params.SetRadius(gb.GetFValue());
seen = true;
}
if (gb.Seen('B'))
{
- params.SetPrintRadius(gb.GetFValue() * distanceScale);
+ params.SetPrintRadius(gb.GetFValue());
seen = true;
}
if (gb.Seen('X'))
@@ -3075,7 +3124,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
// The homed height must be done last, because it gets recalculated when some of the other factors are changed
if (gb.Seen('H'))
{
- params.SetHomedHeight(gb.GetFValue() * distanceScale);
+ params.SetHomedHeight(gb.GetFValue());
seen = true;
}
@@ -3097,8 +3146,8 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
{
reply.printf("Diagonal %.3f, delta radius %.3f, homed height %.3f, bed radius %.1f"
", X %.3f" DEGREE_SYMBOL ", Y %.3f" DEGREE_SYMBOL ", Z %.3f" DEGREE_SYMBOL,
- params.GetDiagonal() / distanceScale, params.GetRadius() / distanceScale,
- params.GetHomedHeight() / distanceScale, params.GetPrintRadius() / distanceScale,
+ params.GetDiagonal(), params.GetRadius(),
+ params.GetHomedHeight(), params.GetPrintRadius(),
params.GetXCorrection(), params.GetYCorrection(), params.GetZCorrection());
}
else
@@ -3450,6 +3499,11 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, StringRef& reply)
bool GCodes::HandleTcode(GCodeBuffer& gb, StringRef& reply)
{
+ if (gb.MachineState().runningM502)
+ {
+ return true; // when running M502 we don't execute T commands
+ }
+
if (!LockMovementAndWaitForStandstill(gb))
{
return false;
diff --git a/src/Heating/FOPDT.cpp b/src/Heating/FOPDT.cpp
index f68b4639..e3bc22c6 100644
--- a/src/Heating/FOPDT.cpp
+++ b/src/Heating/FOPDT.cpp
@@ -8,17 +8,17 @@
#include "FOPDT.h"
#include "Core.h"
#include "Configuration.h"
+#include "Storage/FileStore.h"
+#include "Libraries/General/StringRef.h"
+extern StringRef scratchString;
+
+// Heater 6 on the Duet 0.8.5 is disabled by default at startup so that we can use fan 2.
+// Set up sensible defaults here in case the user enables the heater without specifying values for all the parameters.
FopDt::FopDt()
+ : gain(DefaultHotEndHeaterGain), timeConstant(DefaultHotEndHeaterTimeConstant), deadTime(DefaultHotEndHeaterDeadTime), maxPwm(1.0),
+ enabled(false), usePid(true), pidParametersOverridden(false)
{
- // Heater 6 on the Duet 0.8.5 is disabled by default at startup so that we can use fan 2.
- // Set up sensible defaults in case the user enables the heater without specifying values for all the parameters.
- enabled = false;
- gain = DefaultHotEndHeaterGain;
- timeConstant = DefaultHotEndHeaterTimeConstant;
- deadTime = DefaultHotEndHeaterDeadTime;
- maxPwm = 1.0;
- usePid = true;
}
// Check the model parameters are sensible, if they are then save them and return true.
@@ -45,6 +45,41 @@ bool FopDt::SetParameters(float pg, float ptc, float pdt, float pMaxPwm, bool pU
return false;
}
+// Get the PID parameters as reported by M301
+M301PidParameters FopDt::GetM301PidParameters(bool forLoadChange) const
+{
+ M301PidParameters rslt;
+ const PidParameters& pp = GetPidParameters(forLoadChange);
+ const float reportedKp = pp.kP * 255.0;
+ rslt.kP = reportedKp;
+ rslt.kI = pp.recipTi * reportedKp;
+ rslt.kD = pp.tD * reportedKp;
+ return rslt;
+}
+
+// Override the PID parameters. We set both sets to the same parameters.
+void FopDt::SetM301PidParameters(const M301PidParameters& pp)
+{
+ loadChangeParams.kP = setpointChangeParams.kP = pp.kP * (1.0/255.0);
+ loadChangeParams.recipTi = setpointChangeParams.recipTi = pp.kI/pp.kP;
+ loadChangeParams.tD = setpointChangeParams.tD = pp.kD/pp.kP;
+ pidParametersOverridden = true;
+}
+
+// Write the model parameters to file returning true if no error
+bool FopDt::WriteParameters(FileStore *f, size_t heater) const
+{
+ scratchString.printf("M307 H%u A%.1f C%.1f D%.1f S%.2f B%d\n", heater, gain, timeConstant, deadTime, maxPwm, (usePid) ? 0 : 1);
+ bool ok = f->Write(scratchString.Pointer());
+ if (ok && pidParametersOverridden)
+ {
+ const M301PidParameters pp = GetM301PidParameters(false);
+ scratchString.printf("M301 H%u P%.1f I%.3f D%.1f\n", heater, pp.kP, pp.kI, pp.kD);
+ ok = f->Write(scratchString.Pointer());
+ }
+ return ok;
+}
+
/* Re-calculate the PID parameters.
* For some possible formulas, see "Comparison of some well-known PID tuning formulas", Computers and Chemical Engineering 30 (2006) 1416–1423,
* available at http://www.ece.ualberta.ca/~marquez/journal_publications_files/papers/tan_cce_06.pdf
@@ -86,6 +121,8 @@ void FopDt::CalcPidConstants()
setpointChangeParams.kP = 0.7/(gain * timeFrac);
setpointChangeParams.recipTi = 1.0/timeConstant; // Ti = time constant
setpointChangeParams.tD = deadTime * 0.7;
+
+ pidParametersOverridden = false;
}
// End
diff --git a/src/Heating/FOPDT.h b/src/Heating/FOPDT.h
index 55757331..4f703039 100644
--- a/src/Heating/FOPDT.h
+++ b/src/Heating/FOPDT.h
@@ -10,13 +10,26 @@
#ifndef SRC_HEATING_FOPDT_H_
#define SRC_HEATING_FOPDT_H_
-struct PidParams
+#include <cstddef>
+
+// This is how PID parameters are stored internally
+struct PidParameters
{
float kP; // controller (not model) gain
float recipTi; // reciprocal of controller integral time
float tD; // controller differential time
};
+// This is how PID parameters are given in M301 commands
+struct M301PidParameters
+{
+ float kP;
+ float kI;
+ float kD;
+};
+
+class FileStore;
+
class FopDt
{
public:
@@ -30,12 +43,17 @@ public:
float GetMaxPwm() const { return maxPwm; }
bool UsePid() const { return usePid; }
bool IsEnabled() const { return enabled; }
+ bool ArePidParametersOverridden() const { return pidParametersOverridden; }
+ M301PidParameters GetM301PidParameters(bool forLoadChange) const;
+ void SetM301PidParameters(const M301PidParameters& params);
- const PidParams& GetPidParameters(bool forLoadChange) const
+ const PidParameters& GetPidParameters(bool forLoadChange) const
{
return (forLoadChange) ? loadChangeParams : setpointChangeParams;
}
+ bool WriteParameters(FileStore *f, size_t heater) const; // Write the model parameters to file returning true if no error
+
private:
void CalcPidConstants();
@@ -43,11 +61,12 @@ private:
float timeConstant;
float deadTime;
float maxPwm;
- bool usePid;
bool enabled;
+ bool usePid;
+ bool pidParametersOverridden;
- PidParams setpointChangeParams; // parameters for handling changes in the setpoint
- PidParams loadChangeParams; // parameters for handling changes in the load
+ PidParameters setpointChangeParams; // parameters for handling changes in the setpoint
+ PidParameters loadChangeParams; // parameters for handling changes in the load
};
#endif /* SRC_HEATING_FOPDT_H_ */
diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp
index aad8b75b..57df8e95 100644
--- a/src/Heating/Heat.cpp
+++ b/src/Heating/Heat.cpp
@@ -30,15 +30,35 @@ Heat::Heat(Platform* p)
}
}
+// Reset all heater models to defaults. Called when running M502.
+void Heat::ResetHeaterModels()
+{
+ for (int heater = 0; heater < HEATERS; heater++)
+ {
+ if (pids[heater]->IsHeaterEnabled())
+ {
+ if (heater == DefaultBedHeater)
+ {
+ pids[heater]->SetModel(DefaultBedHeaterGain, DefaultBedHeaterTimeConstant, DefaultBedHeaterDeadTime, 1.0, false);
+ }
+ else
+ {
+ pids[heater]->SetModel(DefaultHotEndHeaterGain, DefaultHotEndHeaterTimeConstant, DefaultHotEndHeaterDeadTime, 1.0, true);
+ }
+ }
+ }
+}
+
void Heat::Init()
{
for (int heater = 0; heater < HEATERS; heater++)
{
- if (heater == bedHeater || heater == chamberHeater)
+ if (heater == DefaultBedHeater)
{
- pids[heater]->Init(DefaultBedHeaterGain, DefaultBedHeaterTimeConstant, DefaultBedHeaterDeadTime, DefaultBedTemperatureLimit, false);
+ pids[heater]->Init(DefaultBedHeaterGain, DefaultBedHeaterTimeConstant, DefaultBedHeaterDeadTime,
+ DefaultBedTemperatureLimit, false);
}
-#ifndef DUET_NG
+#if !defined(DUET_NG) && !defined(__RADDS__)
else if (heater == HEATERS - 1)
{
// Heater 6 pin is shared with fan 1. By default we support fan 1, so disable heater 6.
@@ -47,9 +67,11 @@ void Heat::Init()
#endif
else
{
- pids[heater]->Init(DefaultHotEndHeaterGain, DefaultHotEndHeaterTimeConstant, DefaultHotEndHeaterDeadTime, DefaultExtruderTemperatureLimit, true);
+ pids[heater]->Init(DefaultHotEndHeaterGain, DefaultHotEndHeaterTimeConstant, DefaultHotEndHeaterDeadTime,
+ DefaultExtruderTemperatureLimit, true);
}
}
+
lastTime = millis() - platform->HeatSampleInterval(); // flag the PIDS as due for spinning
longWait = platform->Time();
coldExtrude = false;
@@ -295,4 +317,25 @@ float Heat::GetHighestTemperatureLimit() const
return limit;
}
+// Override the model-generated PID parameters
+void Heat::SetM301PidParameters(size_t heater, const M301PidParameters& params)
+{
+ pids[heater]->SetM301PidParameters(params);
+}
+
+// Write heater model parameters to file returning true if no error
+bool Heat::WriteModelParameters(FileStore *f) const
+{
+ bool ok = f->Write("; Heater model parameters\n");
+ for (size_t h = 0; ok && h < HEATERS; ++h)
+ {
+ const FopDt& model = pids[h]->GetModel();
+ if (model.IsEnabled())
+ {
+ ok = model.WriteParameters(f, h);
+ }
+ }
+ return ok;
+}
+
// End
diff --git a/src/Heating/Heat.h b/src/Heating/Heat.h
index ab74e6a9..e6395a27 100644
--- a/src/Heating/Heat.h
+++ b/src/Heating/Heat.h
@@ -37,6 +37,7 @@ public:
void Spin(); // Called in a tight loop to keep everything going
void Init(); // Set everything up
void Exit(); // Shut everything down
+ void ResetHeaterModels(); // Reset all active heater models to defaults
bool ColdExtrude() const; // Is cold extrusion allowed?
void AllowColdExtrude(bool b); // Allow or deny cold extrusion
@@ -92,12 +93,6 @@ public:
bool SetHeaterModel(size_t heater, float gain, float tc, float td, float maxPwm, bool usePid) // Set the heater process model
pre(heater < HEATERS);
- bool IsModelUsed(size_t heater) const // Is the heater using the PID parameters calculated form the model?
- pre(heater < HEATERS);
-
- void UseModel(size_t heater, bool b) // Use or don't use the model to provide the PID parameters
- pre(heater < HEATERS);
-
void GetHeaterProtection(size_t heater, float& maxTempExcursion, float& maxFaultTime) const
pre(heater < HEATERS);
@@ -109,6 +104,11 @@ public:
float GetHighestTemperatureLimit() const; // Get the highest temperature limit of any heater
+ void SetM301PidParameters(size_t heater, const M301PidParameters& params)
+ pre(heater < HEATERS);
+
+ bool WriteModelParameters(FileStore *f) const; // Write heater model parameters to file returning true if no error
+
private:
Platform* platform; // The instance of the RepRap hardware class
PID* pids[HEATERS]; // A PID controller for each heater
@@ -168,18 +168,6 @@ inline bool Heat::SetHeaterModel(size_t heater, float gain, float tc, float td,
return pids[heater]->SetModel(gain, tc, td, maxPwm, usePid);
}
-// Is the heater using the PID parameters calculated form the model?
-inline bool Heat::IsModelUsed(size_t heater) const
-{
- return pids[heater]->IsModelUsed();
-}
-
-// Use or don't use the model to provide the PID parameters
-inline void Heat::UseModel(size_t heater, bool b)
-{
- pids[heater]->UseModel(b);
-}
-
// Is the heater enabled?
inline bool Heat::IsHeaterEnabled(size_t heater) const
{
diff --git a/src/Heating/Pid.cpp b/src/Heating/Pid.cpp
index 1cab2a77..039729a6 100644
--- a/src/Heating/Pid.cpp
+++ b/src/Heating/Pid.cpp
@@ -60,7 +60,6 @@ void PID::Reset()
badTemperatureCount = 0;
active = false; // default to standby temperature
tuned = false;
- useModel = true; // by default we use the model in this first release
averagePWM = lastPwm = 0.0;
heatingFaultCount = 0;
temperature = BAD_ERROR_TEMPERATURE;
@@ -180,7 +179,6 @@ void PID::Spin()
{
// Read the temperature
const TemperatureError err = ReadTemperature();
- const PidParameters& pp = platform->GetPidParameters(heater);
// Handle any temperature reading error and calculate the temperature rate of change, if possible
if (err != TemperatureError::success)
@@ -314,38 +312,19 @@ void PID::Spin()
else if (mode < HeaterMode::tuning0)
{
// Performing normal temperature control
- bool usingPid = (useModel) ? model.UsePid() : pp.UsePID();
- float maxPwm = (useModel) ? model.GetMaxPwm() : pp.kS;
- if (usingPid)
+ if (model.UsePid())
{
// Using PID mode. Determine the PID parameters to use.
- float kP, recipTi, tD, gain;
- bool inLoadMode;
- if (useModel)
- {
- inLoadMode = (mode == HeaterMode::stable); // use standard PID when maintaining temperature
- const PidParams& params = model.GetPidParameters(inLoadMode);
- kP = params.kP;
- recipTi = params.recipTi;
- tD = params.tD;
- gain = model.GetGain();
- }
- else
- {
- inLoadMode = true; // use standard PID always
- kP = (pp.kP * pp.kS) * (1.0/255.0);
- recipTi = pp.kI/pp.kP;
- tD = pp.kD/pp.kP;
- gain = 255.0/pp.kT;
- }
+ const bool inLoadMode = (mode == HeaterMode::stable); // use standard PID when maintaining temperature
+ const PidParameters& params = model.GetPidParameters(inLoadMode);
// If the P and D terms together demand that the heater is full on or full off, disregard the I term
- const float errorMinusDterm = error - (tD * derivative);
- const float pPlusD = kP * errorMinusDterm;
- const float expectedPwm = constrain<float>((temperature - NormalAmbientTemperature)/gain, 0.0, maxPwm);
- if (pPlusD + expectedPwm > maxPwm)
+ const float errorMinusDterm = error - (params.tD * derivative);
+ const float pPlusD = params.kP * errorMinusDterm;
+ const float expectedPwm = constrain<float>((temperature - NormalAmbientTemperature)/model.GetGain(), 0.0, model.GetMaxPwm());
+ if (pPlusD + expectedPwm > model.GetMaxPwm())
{
- lastPwm = maxPwm;
+ lastPwm = model.GetMaxPwm();
// If we are heating up, preset the I term to the expected PWM at this temperature, ready for the switch over to PID
if (mode == HeaterMode::heating && error > 0.0 && derivative > 0.0)
{
@@ -361,16 +340,17 @@ void PID::Spin()
// In the following we use a modified PID when the temperature is a long way off target.
// During initial heating or cooling, the D term represents expected overshoot, which we don't want to add to the I accumulator.
// When we are in load mode, the I term is much larger and the D term doesn't represent overshoot, so use normal PID.
- const float errorToUse = (inLoadMode) ? error : errorMinusDterm;
- iAccumulator = constrain<float>(iAccumulator + (errorToUse * kP * recipTi * platform->HeatSampleInterval() * MillisToSeconds),
- 0.0, maxPwm);
- lastPwm = constrain<float>(pPlusD + iAccumulator, 0.0, maxPwm);
+ const float errorToUse = (inLoadMode || model.ArePidParametersOverridden()) ? error : errorMinusDterm;
+ iAccumulator = constrain<float>
+ (iAccumulator + (errorToUse * params.kP * params.recipTi * platform->HeatSampleInterval() * MillisToSeconds),
+ 0.0, model.GetMaxPwm());
+ lastPwm = constrain<float>(pPlusD + iAccumulator, 0.0, model.GetMaxPwm());
}
}
else
{
// Using bang-bang mode
- lastPwm = (error > 0.0) ? maxPwm : 0.0;
+ lastPwm = (error > 0.0) ? model.GetMaxPwm() : 0.0;
}
}
else
@@ -772,7 +752,6 @@ void PID::FitCurve()
tuned = SetModel(gain, tc, td, model.GetMaxPwm(), true);
if (tuned)
{
- useModel = true;
platform->MessageF(GENERIC_MESSAGE,
"Auto tune heater %d with PWM=%.2f completed in %u sec, maximum temperature reached %.1fC\n"
"Use M307 H%d to see the result\n",
diff --git a/src/Heating/Pid.h b/src/Heating/Pid.h
index 17002877..b5ecb8cb 100644
--- a/src/Heating/Pid.h
+++ b/src/Heating/Pid.h
@@ -65,12 +65,6 @@ public:
bool SetModel(float gain, float tc, float td, float maxPwm, bool usePid); // Set the process model
- bool IsModelUsed() const // Is the model being used to determine the PID parameters?
- { return useModel; }
-
- void UseModel(bool b) // Use or don't use the model to provide the PID parameters
- { useModel = b; }
-
bool IsHeaterEnabled() const // Is this heater enabled?
{ return model.IsEnabled(); }
@@ -80,6 +74,9 @@ public:
void SetHeaterProtection(float pMaxTempExcursion, float pMaxFaultTime)
{ maxTempExcursion = pMaxTempExcursion; maxHeatingFaultTime = pMaxFaultTime; }
+ void SetM301PidParameters(const M301PidParameters& params)
+ { model.SetM301PidParameters(params); }
+
private:
void SwitchOn(); // Turn the heater on and set the mode
@@ -116,7 +113,6 @@ private:
HeaterMode mode; // Current state of the heater
bool active; // Are we active or standby?
bool tuned; // True if tuning was successful
- bool useModel; // Use the model to calculate the PID parameters
uint8_t badTemperatureCount; // Count of sequential dud readings
static_assert(sizeof(previousTemperaturesGood) * 8 >= NumPreviousTemperatures, "too few bits in previousTemperaturesGood");
diff --git a/src/Libraries/Fatfs/fattime_rtc.c b/src/Libraries/Fatfs/fattime_rtc.cpp
index 392e6373..9c416759 100644
--- a/src/Libraries/Fatfs/fattime_rtc.c
+++ b/src/Libraries/Fatfs/fattime_rtc.cpp
@@ -40,11 +40,8 @@
* \asf_license_stop
*
*/
-#include "compiler.h"
-#include "rtc.h"
+#include "RepRapFirmware.h"
-
-uint32_t get_fattime(void);
/**
* \brief Current time returned is packed into a DWORD value.
*
@@ -64,28 +61,26 @@ uint32_t get_fattime(void);
*
* \return Current time.
*/
-uint32_t get_fattime(void)
+extern "C" uint32_t get_fattime()
{
- if (rtc_get_valid_entry(RTC) != 0)
+ Platform *platform = reprap.GetPlatform();
+ if (!platform->IsDateTimeSet())
{
// Date and time have not been set, return default timestamp instead
return 0x210001;
}
// Retrieve current date and time from RTC
- uint32_t ul_time;
- uint32_t ul_hour, ul_minute, ul_second;
- uint32_t ul_year, ul_month, ul_day, ul_week;
- rtc_get_time(RTC, &ul_hour, &ul_minute, &ul_second);
- rtc_get_date(RTC, &ul_year, &ul_month, &ul_day, &ul_week);
-
- ul_time = ((ul_year - 1980) << 25)
- | (ul_month << 21)
- | (ul_day << 16)
- | (ul_hour << 11)
- | (ul_minute << 5)
- | (ul_second >> 1);
+ time_t timeNow = platform->GetDateTime();
+ struct tm timeInfo;
+ gmtime_r(&timeNow, &timeInfo);
+ uint32_t ul_time = ((timeInfo.tm_year + 1900 - 1980) << 25)
+ | ((timeInfo.tm_mon + 1) << 21)
+ | (timeInfo.tm_mday << 16)
+ | (timeInfo.tm_hour << 11)
+ | (timeInfo.tm_min << 5)
+ | (timeInfo.tm_sec >> 1);
return ul_time;
}
diff --git a/src/Movement/DeltaParameters.cpp b/src/Movement/DeltaParameters.cpp
index 34f3a1c6..4594ae6c 100644
--- a/src/Movement/DeltaParameters.cpp
+++ b/src/Movement/DeltaParameters.cpp
@@ -237,7 +237,7 @@ void DeltaParameters::Adjust(size_t numFactors, const floatc_t v[])
homedCarriageHeight -= heightError;
// Note: if we adjusted the X and Y tilts, and there are any endstop adjustments, then the homed position won't be exactly in the centre
- // and changing the tilt will therefore affect the homed height. We ignore this for now. If it is ever significant, a second sutocalibration
+ // and changing the tilt will therefore affect the homed height. We ignore this for now. If it is ever significant, a second autocalibration
// run will correct it.
}
@@ -248,6 +248,32 @@ void DeltaParameters::PrintParameters(StringRef& reply) const
xCorrection, yCorrection, zCorrection, xTilt * 100.0, yTilt * 100.0);
}
+// Write parameters to file if in delta mode, returning true if no error
+// Values are written in mm
+bool DeltaParameters::WriteParameters(FileStore *f) const
+{
+ if (!IsDeltaMode())
+ {
+ return true;
+ }
+
+ bool ok = f->Write("; Delta parameters\n");
+ if (ok)
+ {
+ scratchString.printf("M665 L%.3f R%.3f H%.3f B%.1f X%.3f Y%.3f Z%.3f\n",
+ GetDiagonal(), GetRadius(), GetHomedHeight(), GetPrintRadius(), GetXCorrection(), GetYCorrection(), GetZCorrection());
+ ok = f->Write(scratchString.Pointer());
+ }
+ if (ok)
+ {
+ scratchString.printf("M666 X%.3f Y%.3f Z%.3f A%.2f B%.2f\n",
+ GetEndstopAdjustment(X_AXIS), GetEndstopAdjustment(Y_AXIS), GetEndstopAdjustment(Z_AXIS),
+ GetXTilt() * 100.0, GetYTilt() * 100.0);
+ ok = f->Write(scratchString.Pointer());
+ }
+ return ok;
+}
+
// End
diff --git a/src/Movement/DeltaParameters.h b/src/Movement/DeltaParameters.h
index 331e0752..b4d677ff 100644
--- a/src/Movement/DeltaParameters.h
+++ b/src/Movement/DeltaParameters.h
@@ -48,6 +48,7 @@ public:
floatc_t ComputeDerivative(unsigned int deriv, float ha, float hb, float hc); // Compute the derivative of height with respect to a parameter at a set of motor endpoints
void Adjust(size_t numFactors, const floatc_t v[]); // Perform 3-, 4-, 6- or 7-factor adjustment
void PrintParameters(StringRef& reply) const; // Print all the parameters for debugging
+ bool WriteParameters(FileStore *f) const; // Write parameters to file if in delta mode, returning true if no error
private:
void Recalc();
diff --git a/src/Movement/Grid.cpp b/src/Movement/Grid.cpp
index 3cd91e49..4aa21f7d 100644
--- a/src/Movement/Grid.cpp
+++ b/src/Movement/Grid.cpp
@@ -109,10 +109,11 @@ void GridDefinition::PrintError(StringRef& r) const
// Increase the version number in the following string whenever we change the format of the height map file.
const char *HeightMap::HeightMapComment = "RepRapFirmware height map file v1";
-HeightMap::HeightMap(float *heightStorage) : gridHeights(heightStorage) { }
+HeightMap::HeightMap(float *heightStorage) : gridHeights(heightStorage), useMap(false), useTaper(false) { }
void HeightMap::SetGrid(const GridDefinition& gd)
{
+ useMap = false;
def = gd;
ClearGridHeights();
}
@@ -157,7 +158,9 @@ bool HeightMap::SaveToFile(FileStore *f) const
buf.catf(" generated at %04u-%02u-%02u %02u:%02u",
timeInfo->tm_year + 1900, timeInfo->tm_mon, timeInfo->tm_mday, timeInfo->tm_hour, timeInfo->tm_min);
}
- buf.cat('\n');
+ float mean, deviation;
+ (void)GetStatistics(mean, deviation);
+ buf.catf(", mean error %.2f, deviation %.2f\n", mean, deviation);
if (!f->Write(buf.Pointer()))
{
return true;
@@ -170,7 +173,7 @@ bool HeightMap::SaveToFile(FileStore *f) const
return true;
}
- // Write the grid heights
+ // Write the grid heights. We use a fixed field with of 6 characters to make is easier to view.
uint32_t index = 0;
for (uint32_t i = 0; i < def.numY; ++i)
{
@@ -183,11 +186,11 @@ bool HeightMap::SaveToFile(FileStore *f) const
}
if (IsHeightSet(index))
{
- buf.catf("%.3f%", gridHeights[index]);
+ buf.catf("%7.3f%", gridHeights[index]);
}
else
{
- buf.cat("0"); // write 0 with no decimal point where we didn't probe, so we can tell when we reload it
+ buf.cat(" 0"); // write 0 with no decimal point where we didn't probe, so we can tell when we reload it
}
++index;
}
@@ -281,9 +284,86 @@ bool HeightMap::LoadFromFile(FileStore *f, StringRef& r)
return true; // an error occurred
}
+// Return number of points probed, mean and RMS deviation
+unsigned int HeightMap::GetStatistics(float& mean, float& deviation) const
+{
+ double heightSum = 0.0, heightSquaredSum = 0.0;
+ unsigned int numProbed = 0;
+ for (uint32_t i = 0; i < def.NumPoints(); ++i)
+ {
+ if (IsHeightSet(i))
+ {
+ ++numProbed;
+ const double heightError = (double)gridHeights[i];
+ heightSum += heightError;
+ heightSquaredSum += heightError * heightError;
+ }
+ }
+ if (numProbed == 0)
+ {
+ mean = deviation = 0.0;
+ }
+ else
+ {
+ mean = (float)(heightSum/numProbed);
+ deviation = (float)sqrt(((heightSquaredSum * numProbed) - (heightSum * heightSum)))/numProbed;
+ }
+ return numProbed;
+}
+
+void HeightMap::UseHeightMap(bool b)
+{
+ useMap = b && def.IsValid();
+}
+
+void HeightMap::SetTaperHeight(float h)
+{
+ useTaper = (h > 1.0);
+ if (useTaper)
+ {
+ taperHeight = h;
+ recipTaperHeight = 1.0/h;
+ }
+}
+
+// Compute the height error at the specified point i.e. value that needs to be added to the Z coordinate
+float HeightMap::ComputeHeightError(float x, float y, float z) const
+{
+ if (!useMap || (useTaper && z >= taperHeight))
+ {
+ return 0.0;
+ }
+
+ const float rawError = GetInterpolatedHeightError(x, y);
+ return (useTaper) ? (taperHeight - z) * recipTaperHeight * rawError : rawError;
+}
+
+// Compute the inverse height error at the specified point i.e. value that needs to be subtracted form the Z coordinate
+float HeightMap::ComputeInverseHeightError(float x, float y, float z) const
+{
+ if (!useMap)
+ {
+ return 0.0;
+ }
+
+ const float rawError = GetInterpolatedHeightError(x, y);
+ if (!useTaper || rawError > taperHeight) // need check on rawError to avoid possible divide by zero
+ {
+ return rawError;
+ }
+
+ const float zreq = (z - rawError)/(1.0 - (rawError * recipTaperHeight));
+ return (zreq >= taperHeight) ? 0.0 : z - zreq;
+}
+
// Compute the height error at the specified point
-float HeightMap::ComputeHeightError(float x, float y) const
+float HeightMap::GetInterpolatedHeightError(float x, float y) const
{
+ if (!useMap)
+ {
+ return 0.0;
+ }
+
const float xf = (x - def.xMin) * def.recipSpacing;
const float xFloor = floor(xf);
const int32_t xIndex = (int32_t)xFloor;
diff --git a/src/Movement/Grid.h b/src/Movement/Grid.h
index cb73b21f..89f332fa 100644
--- a/src/Movement/Grid.h
+++ b/src/Movement/Grid.h
@@ -68,9 +68,8 @@ public:
const GridDefinition& GetGrid() const { return def; }
void SetGrid(const GridDefinition& gd);
- float ComputeHeightError(float x, float y) const // Compute the height error at the specified point
- pre(IsValid(); gridHeights != nullptr; gridHeights.upb >= NumPoints());
-
+ float ComputeHeightError(float x, float y, float z) const; // Compute the height error at the specified point
+ float ComputeInverseHeightError(float x, float y, float z) const; // Compute the inverse height error at the specified point
void ClearGridHeights(); // Clear all grid height corrections
void SetGridHeight(size_t xIndex, size_t yIndex, float height); // Set the height of a grid point
@@ -81,15 +80,30 @@ public:
unsigned int GetMinimumSegments(float distance) const; // Return the minimum number of segments for a move by this X or Y amount
+ void UseHeightMap(bool b);
+ bool UsingHeightMap() const { return useMap; }
+ float GetTaperHeight() const { return (useTaper) ? taperHeight : 0.0; }
+ void SetTaperHeight(float h);
+
+ unsigned int GetStatistics(float& mean, float& deviation) const; // Return number of points probed, mean and RMS deviation
+
private:
static const char *HeightMapComment; // The start of the comment we write at the start of the height map file
GridDefinition def;
float *gridHeights; // The map of grid heights, must have at least MaxGridProbePoints entries
uint32_t gridHeightSet[MaxGridProbePoints/32]; // Bitmap of which heights are set
+ float taperHeight; // Height over which we taper
+ float recipTaperHeight; // Reciprocal of the taper height
+ bool useMap; // True to do bed compensation
+ bool useTaper; // True to taper off the compensation
uint32_t GetMapIndex(uint32_t xIndex, uint32_t yIndex) const { return (yIndex * def.NumXpoints()) + xIndex; }
bool IsHeightSet(uint32_t index) const { return (gridHeightSet[index/32] & (1 << (index & 31))) != 0; }
+
+ float GetInterpolatedHeightError(float x, float y) const // Compute the interpolated height error at the specified point
+ pre(useMap);
+
float GetHeightError(uint32_t xIndex, uint32_t yIndex) const;
float InterpolateX(uint32_t xIndex, uint32_t yIndex, float xFrac) const;
float InterpolateY(uint32_t xIndex, uint32_t yIndex, float yFrac) const;
diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp
index 278ecc8d..e32bcecf 100644
--- a/src/Movement/Move.cpp
+++ b/src/Movement/Move.cpp
@@ -98,7 +98,6 @@ void Move::Init()
simulationTime = 0.0;
longestGcodeWaitInterval = 0;
waitingForMove = false;
- useGridHeights = false;
active = true;
}
@@ -656,10 +655,7 @@ void Move::BedTransform(float xyzPoint[MAX_AXES], uint32_t xAxes) const
switch(numBedCompensationPoints)
{
case 0:
- if (useGridHeights)
- {
- zCorrection += grid.ComputeHeightError(xCoord, xyzPoint[Y_AXIS]);
- }
+ zCorrection += grid.ComputeHeightError(xCoord, xyzPoint[Y_AXIS], xyzPoint[Z_AXIS]);
break;
case 3:
@@ -704,10 +700,7 @@ void Move::InverseBedTransform(float xyzPoint[MAX_AXES], uint32_t xAxes) const
switch(numBedCompensationPoints)
{
case 0:
- if (useGridHeights)
- {
- zCorrection += grid.ComputeHeightError(xCoord, xyzPoint[Y_AXIS]);
- }
+ zCorrection += grid.ComputeInverseHeightError(xCoord, xyzPoint[Y_AXIS], xyzPoint[Z_AXIS]);
break;
case 3:
@@ -738,6 +731,7 @@ void Move::InverseBedTransform(float xyzPoint[MAX_AXES], uint32_t xAxes) const
void Move::SetIdentityTransform()
{
numBedCompensationPoints = 0;
+ grid.ClearGridHeights();
}
float Move::AxisCompensation(int8_t axis) const
@@ -1038,23 +1032,14 @@ void Move::DoDeltaCalibration(size_t numFactors, StringRef& reply)
{
corrections[i] = 0.0;
float machinePos[DELTA_AXES];
- float xp = xBedProbePoints[i], yp = yBedProbePoints[i];
- if (probePointSet[i] & xyCorrected)
- {
- // The point was probed with the sensor at the specified XY coordinates, so subtract the sensor offset to get the head position
- const ZProbeParameters& zparams = reprap.GetPlatform()->GetZProbeParameters();
- xp -= zparams.xOffset;
- yp -= zparams.yOffset;
- }
- machinePos[X_AXIS] = xp;
- machinePos[Y_AXIS] = yp;
+ float zp = GetProbeCoordinates(i, machinePos[X_AXIS], machinePos[Y_AXIS], (probePointSet[i] & xyCorrected) != 0);
machinePos[Z_AXIS] = 0.0;
probeMotorPositions(i, A_AXIS) = deltaParams.Transform(machinePos, A_AXIS);
probeMotorPositions(i, B_AXIS) = deltaParams.Transform(machinePos, B_AXIS);
probeMotorPositions(i, C_AXIS) = deltaParams.Transform(machinePos, C_AXIS);
- initialSumOfSquares += fsquare(zBedProbePoints[i]);
+ initialSumOfSquares += fsquare(zp);
}
// Do 1 or more Newton-Raphson iterations
@@ -1446,7 +1431,7 @@ void Move::SetZBedProbePoint(size_t index, float z, bool wasXyCorrected, bool wa
}
else
{
- useGridHeights = false;
+ grid.UseHeightMap(false);
zBedProbePoints[index] = z;
probePointSet[index] |= zSet;
if (wasXyCorrected)
@@ -1493,6 +1478,22 @@ bool Move::XYProbeCoordinatesSet(int index) const
return (probePointSet[index] & xSet) && (probePointSet[index] & ySet);
}
+// This returns the (X, Y) points to probe the bed at probe point count. When probing, it returns false.
+// If called after probing has ended it returns true, and the Z coordinate probed is also returned.
+// If 'wantNozzlePosition is true then we return the nozzle position when the point is probed, else we return the probe point itself
+float Move::GetProbeCoordinates(int count, float& x, float& y, bool wantNozzlePosition) const
+{
+ x = xBedProbePoints[count];
+ y = yBedProbePoints[count];
+ if (wantNozzlePosition)
+ {
+ const ZProbeParameters& rp = reprap.GetPlatform()->GetCurrentZProbeParameters();
+ x -= rp.xOffset;
+ y -= rp.yOffset;
+ }
+ return zBedProbePoints[count];
+}
+
size_t Move::NumberOfProbePoints() const
{
for(size_t i = 0; i < MaxProbePoints; i++)
diff --git a/src/Movement/Move.h b/src/Movement/Move.h
index ad946261..de92f0ad 100644
--- a/src/Movement/Move.h
+++ b/src/Movement/Move.h
@@ -45,7 +45,9 @@ public:
void Init(); // Start me up
void Spin(); // Called in a tight loop to keep the class going
void Exit(); // Shut down
- void GetCurrentUserPosition(float m[DRIVES], uint8_t moveType, uint32_t xAxes) const; // Return the position (after all queued moves have been executed) in transformed coords
+
+ void GetCurrentMachinePosition(float m[DRIVES], bool disableMotorMapping) const; // Get the current position in untransformed coords
+ void GetCurrentUserPosition(float m[DRIVES], uint8_t moveType, uint32_t xAxes) const; // Return the position (after all queued moves have been executed) in transformed coords
int32_t GetEndPoint(size_t drive) const { return liveEndPoints[drive]; } // Get the current position of a motor
void LiveCoordinates(float m[DRIVES], uint32_t xAxes); // Gives the last point at the end of the last complete DDA transformed to user coords
void Interrupt(); // The hardware's (i.e. platform's) interrupt should call this.
@@ -69,6 +71,7 @@ public:
size_t NumberOfXYProbePoints() const; // How many XY coordinates of probe points have been set (Zs may not have been probed yet)
bool AllProbeCoordinatesSet(int index) const; // XY, and Z all set for this one?
bool XYProbeCoordinatesSet(int index) const; // Just XY set for this one?
+ float GetProbeCoordinates(int count, float& x, float& y, bool wantNozzlePosition) const; // Get pre-recorded probe coordinates
void FinishedBedProbing(int sParam, StringRef& reply); // Calibrate or set the bed equation after probing
float SecondDegreeTransformZ(float x, float y) const; // Used for second degree bed equation
void SetAxisCompensation(int8_t axis, float tangent); // Set an axis-pair compensation angle
@@ -76,6 +79,7 @@ public:
void SetIdentityTransform(); // Cancel the bed equation; does not reset axis angle compensation
void Transform(float move[], uint32_t xAxes) const; // Take a position and apply the bed and the axis-angle compensations
void InverseTransform(float move[], uint32_t xAxes) const; // Go from a transformed point back to user coordinates
+
void Diagnostics(MessageType mtype); // Report useful stuff
const DeltaParameters& GetDeltaParams() const { return deltaParams; }
@@ -115,8 +119,6 @@ public:
HeightMap& AccessBedProbeGrid() { return grid; } // Access the bed probing grid
- void UseHeightMap(bool b) { useGridHeights = b; } // Start or stop using the height map
- bool UsingHeightMap() const { return useGridHeights; } // Are we doing grid bed compensation?
void Babystep(float zMovement); // Request babystepping
private:
@@ -127,7 +129,6 @@ private:
void SetProbedBedEquation(size_t numPoints, StringRef& reply); // When we have a full set of probed points, work out the bed's equation
void DoDeltaCalibration(size_t numPoints, StringRef& reply);
void BedTransform(float move[MAX_AXES], uint32_t xAxes) const; // Take a position and apply the bed compensations
- void GetCurrentMachinePosition(float m[DRIVES], bool disableMotorMapping) const; // Get the current position in untransformed coords
void InverseBedTransform(float move[MAX_AXES], uint32_t xAxes) const; // Go from a bed-transformed point back to user coordinates
void AxisTransform(float move[MAX_AXES]) const; // Take a position and apply the axis-angle compensations
void InverseAxisTransform(float move[MAX_AXES]) const; // Go from an axis transformed point back to user coordinates
@@ -179,7 +180,6 @@ private:
float xRectangle, yRectangle; // The side lengths of the rectangle used for second-degree bed compensation
HeightMap grid; // Grid definition and height map for G29 bed probing. The probe heights are stored in zBedProbePoints, see above.
- bool useGridHeights; // True if the zBedProbePoints came from valid bed probing and relate to the current grid
float idleTimeout; // How long we wait with no activity before we reduce motor currents to idle
float lastMoveTime; // The approximate time at which the last move was completed, or 0
diff --git a/src/Platform.cpp b/src/Platform.cpp
index 95ca1edf..dbcb6f22 100644
--- a/src/Platform.cpp
+++ b/src/Platform.cpp
@@ -20,17 +20,13 @@
****************************************************************************************************/
#include "RepRapFirmware.h"
-#include "DueFlashStorage.h"
#include "sam/drivers/tc/tc.h"
#include "sam/drivers/hsmci/hsmci.h"
#include "sd_mmc.h"
-#if defined(DUET_NG)
-# include "TMC2660.h"
-#endif
-
#ifdef DUET_NG
+# include "TMC2660.h"
# include "FirmwareUpdater.h"
#endif
@@ -69,6 +65,8 @@ uint32_t nextInterruptScheduledAt = 0;
uint32_t lastInterruptTime = 0;
#endif
+// Global functions
+
// Urgent initialisation function
// This is called before general init has been done, and before constructors for C++ static data have been called.
// Therefore, be very careful what you do here!
@@ -115,26 +113,51 @@ extern "C"
reprap.Tick();
return 0;
}
+
+ void NMI_Handler () { reprap.GetPlatform()->SoftwareReset((uint16_t)SoftwareResetReason::NMI); }
+ void HardFault_Handler () { reprap.GetPlatform()->SoftwareReset((uint16_t)SoftwareResetReason::hardFault); }
+ void MemManage_Handler () { reprap.GetPlatform()->SoftwareReset((uint16_t)SoftwareResetReason::memManage); }
+ void BusFault_Handler () { reprap.GetPlatform()->SoftwareReset((uint16_t)SoftwareResetReason::busFault); }
+ void UsageFault_Handler () { reprap.GetPlatform()->SoftwareReset((uint16_t)SoftwareResetReason::usageFault); }
+ void SVC_Handler () { reprap.GetPlatform()->SoftwareReset((uint16_t)SoftwareResetReason::otherFault); }
+ void DebugMon_Handler () { reprap.GetPlatform()->SoftwareReset((uint16_t)SoftwareResetReason::otherFault); }
+ void PendSV_Handler () { reprap.GetPlatform()->SoftwareReset((uint16_t)SoftwareResetReason::otherFault); }
}
-//*************************************************************************************************
-// PidParameters class
-bool PidParameters::UsePID() const
+
+// ZProbeParameters class
+
+void ZProbeParameters::Init(float h)
+{
+ adcValue = Z_PROBE_AD_VALUE;
+ xOffset = yOffset = 0.0;
+ height = h;
+ calibTemperature = 20.0;
+ temperatureCoefficient = 0.0; // no default temperature correction
+ diveHeight = DEFAULT_Z_DIVE;
+ probeSpeed = DEFAULT_PROBE_SPEED;
+ travelSpeed = DEFAULT_TRAVEL_SPEED;
+ recoveryTime = extraParam = 0.0;
+ invertReading = false;
+}
+
+float ZProbeParameters::GetStopHeight(float temperature) const
{
- return kP >= 0;
+ return ((temperature - calibTemperature) * temperatureCoefficient) + height;
}
-bool PidParameters::operator==(const PidParameters& other) const
+bool ZProbeParameters::WriteParameters(FileStore *f, unsigned int probeType) const
{
- return kI == other.kI && kD == other.kD && kP == other.kP && kT == other.kT && kS == other.kS;
+ scratchString.printf("G31 T%u P%d X%.1f Y%.1f Z%.2f\n", probeType, adcValue, xOffset, yOffset, height);
+ return f->Write(scratchString.Pointer());
}
//*************************************************************************************************
// Platform class
Platform::Platform() :
- autoSaveEnabled(false), board(DEFAULT_BOARD_TYPE), active(false), errorCodeBits(0),
+ board(DEFAULT_BOARD_TYPE), active(false), errorCodeBits(0),
auxGCodeReply(nullptr), fileStructureInitialised(false), tickState(0), debugCode(0)
{
// Output
@@ -165,7 +188,6 @@ void Platform::Init()
realTime = 0;
// Comms
-
baudRates[0] = MAIN_BAUD_RATE;
baudRates[1] = AUX_BAUD_RATE;
#if NUM_SERIAL_CHANNELS >= 2
@@ -186,9 +208,20 @@ void Platform::Init()
SERIAL_AUX2_DEVICE.begin(baudRates[2]);
#endif
- static_assert(sizeof(FlashData) + sizeof(SoftwareResetData) <= FLASH_DATA_LENGTH, "NVData too large");
+ compatibility = marlin; // default to Marlin because the common host programs expect the "OK" response to commands
+ ARRAY_INIT(ipAddress, IP_ADDRESS);
+ ARRAY_INIT(netMask, NET_MASK);
+ ARRAY_INIT(gateWay, GATE_WAY);
+
+#ifdef DUET_NG
+ memset(macAddress, 0xFF, sizeof(macAddress));
+#else
+ ARRAY_INIT(macAddress, MAC_ADDRESS);
+#endif
- ResetNvData();
+ zProbeType = 0; // Default is to use no Z probe switch
+ zProbeAxes = Z_PROBE_AXES;
+ SetZProbeDefaults();
// We need to initialise at least some of the time stuff before we call MassStorage::Init()
addToTime = 0.0;
@@ -218,7 +251,7 @@ void Platform::Init()
ARRAY_INIT(driveStepsPerUnit, DRIVE_STEPS_PER_UNIT);
ARRAY_INIT(instantDvs, INSTANT_DVS);
-#if !defined(DUET_NG) && !defined(RADDS)
+#if !defined(DUET_NG) && !defined(__RADDS__)
// Motor current setting on Duet 0.6 and 0.8.5
ARRAY_INIT(potWipes, POT_WIPES);
senseResistor = SENSE_RESISTOR;
@@ -403,12 +436,14 @@ void Platform::Init()
#endif
// MCU temperature and power monitoring
+#ifndef __RADDS__
temperatureAdcChannel = GetTemperatureAdcChannel();
AnalogInEnableChannel(temperatureAdcChannel, true);
currentMcuTemperature = highestMcuTemperature = 0;
lowestMcuTemperature = 4095;
- mcuTemperatureAdjust = 0.0;
mcuAlarmTemperature = 80.0; // need to set the quite high here because the sensor is not be calibrated yet
+#endif
+ mcuTemperatureAdjust = 0.0;
#ifdef DUET_NG
vInMonitorAdcChannel = PinToAdcChannel(PowerMonitorVinDetectPin);
@@ -471,6 +506,13 @@ int Platform::GetThermistorNumber(size_t heater) const
return heaterTempChannels[heater];
}
+void Platform::SetZProbeDefaults()
+{
+ switchZProbeParameters.Init(0.0);
+ irZProbeParameters.Init(Z_PROBE_STOP_HEIGHT);
+ alternateZProbeParameters.Init(Z_PROBE_STOP_HEIGHT);
+}
+
void Platform::InitZProbe()
{
zProbeOnFilter.Init(0);
@@ -482,7 +524,7 @@ void Platform::InitZProbe()
zProbeModulationPin = (board == BoardType::Duet_07 || board == BoardType::Duet_085) ? Z_PROBE_MOD_PIN07 : Z_PROBE_MOD_PIN;
#endif
- switch (nvData.zProbeType)
+ switch (zProbeType)
{
case 1:
case 2:
@@ -524,12 +566,12 @@ void Platform::InitZProbe()
// Return the Z probe data.
// The ADC readings are 12 bits, so we convert them to 10-bit readings for compatibility with the old firmware.
-int Platform::ZProbe() const
+int Platform::GetZProbeReading() const
{
int zProbeVal = 0; // initialised to avoid spurious compiler warning
if (zProbeOnFilter.IsValid() && zProbeOffFilter.IsValid())
{
- switch (nvData.zProbeType)
+ switch (zProbeType)
{
case 1: // Simple or intelligent IR sensor
case 3: // Alternate sensor
@@ -554,7 +596,7 @@ int Platform::ZProbe() const
}
}
- return (GetZProbeParameters().invertReading) ? 1000 - zProbeVal : zProbeVal;
+ return (GetCurrentZProbeParameters().invertReading) ? 1000 - zProbeVal : zProbeVal;
}
// Return the Z probe secondary values.
@@ -562,7 +604,7 @@ int Platform::GetZProbeSecondaryValues(int& v1, int& v2)
{
if (zProbeOnFilter.IsValid() && zProbeOffFilter.IsValid())
{
- switch (nvData.zProbeType)
+ switch (zProbeType)
{
case 2: // modulated IR sensor
v1 = (int) (zProbeOnFilter.GetSum() / (4 * Z_PROBE_AVERAGE_READINGS)); // pass back the reading with IR turned on
@@ -574,18 +616,9 @@ int Platform::GetZProbeSecondaryValues(int& v1, int& v2)
return 0;
}
-int Platform::GetZProbeType() const
-{
- return nvData.zProbeType;
-}
-
void Platform::SetZProbeAxes(uint32_t axes)
{
- nvData.zProbeAxes = axes;
- if (autoSaveEnabled)
- {
- WriteNvData();
- }
+ zProbeAxes = axes;
}
// Get our best estimate of the Z probe temperature
@@ -606,87 +639,77 @@ float Platform::GetZProbeTemperature()
float Platform::ZProbeStopHeight()
{
- return GetZProbeParameters().GetStopHeight(GetZProbeTemperature());
+ return GetCurrentZProbeParameters().GetStopHeight(GetZProbeTemperature());
}
float Platform::GetZProbeDiveHeight() const
{
- return GetZProbeParameters().diveHeight;
+ return GetCurrentZProbeParameters().diveHeight;
+}
+
+float Platform::GetZProbeStartingHeight()
+{
+ const ZProbeParameters& params = GetCurrentZProbeParameters();
+ return params.diveHeight + max<float>(params.GetStopHeight(GetZProbeTemperature()), 0.0);
}
float Platform::GetZProbeTravelSpeed() const
{
- return GetZProbeParameters().travelSpeed;
+ return GetCurrentZProbeParameters().travelSpeed;
}
void Platform::SetZProbeType(int pt)
{
- int newZProbeType = (pt >= 0 && pt <= 7) ? pt : 0;
- if (newZProbeType != nvData.zProbeType)
- {
- nvData.zProbeType = newZProbeType;
- if (autoSaveEnabled)
- {
- WriteNvData();
- }
- }
+ zProbeType = (pt >= 0 && pt <= 7) ? pt : 0;
InitZProbe();
}
-const ZProbeParameters& Platform::GetZProbeParameters() const
+const ZProbeParameters& Platform::GetZProbeParameters(int32_t probeType) const
{
- switch (nvData.zProbeType)
+ switch (probeType)
{
case 1:
case 2:
- return nvData.irZProbeParameters;
+ case 5:
+ return irZProbeParameters;
case 3:
case 7:
- return nvData.alternateZProbeParameters;
+ return alternateZProbeParameters;
case 4:
- case 5:
case 6:
default:
- return nvData.switchZProbeParameters;
+ return switchZProbeParameters;
}
}
-void Platform::SetZProbeParameters(const ZProbeParameters& params)
+void Platform::SetZProbeParameters(int32_t probeType, const ZProbeParameters& params)
{
- if (GetZProbeParameters() != params)
+ switch (probeType)
{
- switch (nvData.zProbeType)
- {
- case 1:
- case 2:
- nvData.irZProbeParameters = params;
- break;
-
- case 3:
- case 7:
- nvData.alternateZProbeParameters = params;
- break;
+ case 1:
+ case 2:
+ case 5:
+ irZProbeParameters = params;
+ break;
- case 4:
- case 5:
- case 6:
- default:
- nvData.switchZProbeParameters = params;
- break;
- }
+ case 3:
+ case 7:
+ alternateZProbeParameters = params;
+ break;
- if (autoSaveEnabled)
- {
- WriteNvData();
- }
+ case 4:
+ case 6:
+ default:
+ switchZProbeParameters = params;
+ break;
}
}
// Return true if the specified point is accessible to the Z probe
bool Platform::IsAccessibleProbePoint(float x, float y) const
{
- x -= GetZProbeParameters().xOffset;
- y -= GetZProbeParameters().yOffset;
+ x -= GetCurrentZProbeParameters().xOffset;
+ y -= GetCurrentZProbeParameters().yOffset;
return (reprap.GetMove()->IsDeltaMode())
? x * x + y * y < reprap.GetMove()->GetDeltaParams().GetPrintRadiusSquared()
: x >= axisMinima[X_AXIS] && y >= axisMinima[Y_AXIS] && x <= axisMaxima[X_AXIS] && y <= axisMaxima[Y_AXIS];
@@ -695,75 +718,7 @@ bool Platform::IsAccessibleProbePoint(float x, float y) const
// Return true if we must home X and Y before we home Z (i.e. we are using a bed probe)
bool Platform::MustHomeXYBeforeZ() const
{
- return (nvData.zProbeType != 0) && ((nvData.zProbeAxes & (1 << Z_AXIS)) != 0);
-}
-
-void Platform::ResetNvData()
-{
- nvData.compatibility = marlin; // default to Marlin because the common host programs expect the "OK" response to commands
- ARRAY_INIT(nvData.ipAddress, IP_ADDRESS);
- ARRAY_INIT(nvData.netMask, NET_MASK);
- ARRAY_INIT(nvData.gateWay, GATE_WAY);
-
-#ifdef DUET_NG
- memset(nvData.macAddress, 0xFF, sizeof(nvData.macAddress));
-#else
- ARRAY_INIT(nvData.macAddress, MAC_ADDRESS);
-#endif
-
- nvData.zProbeType = 0; // Default is to use no Z probe switch
- nvData.zProbeAxes = Z_PROBE_AXES;
- nvData.switchZProbeParameters.Init(0.0);
- nvData.irZProbeParameters.Init(Z_PROBE_STOP_HEIGHT);
- nvData.alternateZProbeParameters.Init(Z_PROBE_STOP_HEIGHT);
-
- for (size_t i = 0; i < HEATERS; ++i)
- {
- PidParameters& pp = nvData.pidParams[i];
- pp.kI = defaultPidKis[i];
- pp.kD = defaultPidKds[i];
- pp.kP = defaultPidKps[i];
- pp.kT = defaultPidKts[i];
- pp.kS = defaultPidKss[i];
- }
-
-#if FLASH_SAVE_ENABLED
- nvData.magic = FlashData::magicValue;
- nvData.version = FlashData::versionValue;
-#endif
-}
-
-void Platform::ReadNvData()
-{
-#if FLASH_SAVE_ENABLED
- DueFlashStorage::read(FlashData::nvAddress, &nvData, sizeof(nvData));
- if (nvData.magic != FlashData::magicValue || nvData.version != FlashData::versionValue)
- {
- // Nonvolatile data has not been initialized since the firmware was last written, so set up default values
- ResetNvData();
- // No point in writing it back here
- }
-#else
- Message(BOTH_ERROR_MESSAGE, "Cannot load non-volatile data, because Flash support has been disabled!\n");
-#endif
-}
-
-void Platform::WriteNvData()
-{
-#if FLASH_SAVE_ENABLED
- DueFlashStorage::write(FlashData::nvAddress, &nvData, sizeof(nvData));
-#else
- Message(BOTH_ERROR_MESSAGE, "Cannot write non-volatile data, because Flash support has been disabled!\n");
-#endif
-}
-
-void Platform::SetAutoSave(bool enabled)
-{
-#if FLASH_SAVE_ENABLED
- autoSaveEnabled = enabled;
-#else
- Message(BOTH_ERROR_MESSAGE, "Cannot enable auto-save, because Flash support has been disabled!\n");
-#endif
+ return (zProbeType != 0) && ((zProbeAxes & (1 << Z_AXIS)) != 0);
}
// Check the prerequisites for updating the main firmware. Return True if satisfied, else print as message and return false.
@@ -1011,7 +966,7 @@ void Platform::Exit()
Compatibility Platform::Emulating() const
{
- return (nvData.compatibility == reprapFirmware) ? me : nvData.compatibility;
+ return (compatibility == reprapFirmware) ? me : compatibility;
}
void Platform::SetEmulating(Compatibility c)
@@ -1025,46 +980,30 @@ void Platform::SetEmulating(Compatibility c)
{
c = me;
}
- if (c != nvData.compatibility)
- {
- nvData.compatibility = c;
- if (autoSaveEnabled)
- {
- WriteNvData();
- }
- }
+ compatibility = c;
}
void Platform::UpdateNetworkAddress(byte dst[4], const byte src[4])
{
- bool changed = false;
for (uint8_t i = 0; i < 4; i++)
{
- if (dst[i] != src[i])
- {
- dst[i] = src[i];
- changed = true;
- }
- }
- if (changed && autoSaveEnabled)
- {
- WriteNvData();
+ dst[i] = src[i];
}
}
void Platform::SetIPAddress(byte ip[])
{
- UpdateNetworkAddress(nvData.ipAddress, ip);
+ UpdateNetworkAddress(ipAddress, ip);
}
void Platform::SetGateWay(byte gw[])
{
- UpdateNetworkAddress(nvData.gateWay, gw);
+ UpdateNetworkAddress(gateWay, gw);
}
void Platform::SetNetMask(byte nm[])
{
- UpdateNetworkAddress(nvData.netMask, nm);
+ UpdateNetworkAddress(netMask, nm);
}
// Flush messages to USB and aux, returning true if there is more to send
@@ -1165,6 +1104,7 @@ void Platform::Spin()
}
// Check the MCU max and min temperatures
+#ifndef __RADDS__
if (currentMcuTemperature > highestMcuTemperature)
{
highestMcuTemperature= currentMcuTemperature;
@@ -1173,6 +1113,7 @@ void Platform::Spin()
{
lowestMcuTemperature = currentMcuTemperature;
}
+#endif
// Diagnostics test
if (debugCode == (int)DiagnosticTestType::TestSpinLockup)
@@ -1218,6 +1159,7 @@ void Platform::Spin()
void Platform::SoftwareReset(uint16_t reason)
{
+ wdt_restart(WDT); // kick the watchdog
if (reason == (uint16_t)SoftwareResetReason::erase)
{
EraseAndReset();
@@ -1403,13 +1345,19 @@ void Platform::Diagnostics(MessageType mtype)
// Show the up time and reason for the last reset
const uint32_t now = (uint32_t)Time(); // get up time in seconds
- const char* resetReasons[8] = { "power up", "backup", "watchdog", "software", "reset button", "?", "?", "?" };
+ const char* resetReasons[8] = { "power up", "backup", "watchdog", "software",
+#ifdef DUET_NG
+ // On the SAM4E a watchdog reset may be reported as a user reset because of the capacitor on the NRST pin
+ "reset button or watchdog",
+#else
+ "reset button",
+#endif
+ "?", "?", "?" };
MessageF(mtype, "Last reset %02d:%02d:%02d ago, cause: %s\n",
(unsigned int)(now/3600), (unsigned int)((now % 3600)/60), (unsigned int)(now % 60),
resetReasons[(REG_RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos]);
// Show the reset code stored at the last software reset
- Message(mtype, "Last software reset code & available RAM: ");
{
SoftwareResetData srdBuf[SoftwareResetData::numberOfSlots];
memset(srdBuf, 0, sizeof(srdBuf));
@@ -1429,9 +1377,10 @@ void Platform::Diagnostics(MessageType mtype)
}
}
+ Message(mtype, "Last software reset code: ");
if (slot >= 0 && srdBuf[slot].magic == SoftwareResetData::magicValue)
{
- MessageF(mtype, "0x%04x, %u (slot %d)\n", srdBuf[slot].resetReason, srdBuf[slot].neverUsedRam, slot);
+ MessageF(mtype, "0x%04x, available RAM %u bytes (slot %d)\n", srdBuf[slot].resetReason, srdBuf[slot].neverUsedRam, slot);
MessageF(mtype, "Spinning module during software reset: %s\n", moduleName[srdBuf[slot].resetReason & 0x0F]);
}
else
@@ -1455,15 +1404,21 @@ void Platform::Diagnostics(MessageType mtype)
MessageF(mtype, "Free file entries: %u\n", numFreeFiles);
// Show the HSMCI CD pin and speed
+#ifdef __RADDS__
+ MessageF(mtype, "SD card 0 %s\n", (sd_mmc_card_detected(0) ? "detected" : "not detected"));
+#else
MessageF(mtype, "SD card 0 %s, interface speed: %.1fMBytes/sec\n", (sd_mmc_card_detected(0) ? "detected" : "not detected"), (float)hsmci_get_speed()/1000000.0);
+#endif
// Show the longest SD card write time
MessageF(mtype, "SD card longest block write time: %.1fms\n", FileStore::GetAndClearLongestWriteTime());
+#ifndef __RADDS__
// Show the MCU temperatures
MessageF(mtype, "MCU temperature: min %.1f, current %.1f, max %.1f\n",
AdcReadingToCpuTemperature(lowestMcuTemperature), AdcReadingToCpuTemperature(currentMcuTemperature), AdcReadingToCpuTemperature(highestMcuTemperature));
lowestMcuTemperature = highestMcuTemperature = currentMcuTemperature;
+#endif
#ifdef DUET_NG
// Show the supply voltage
@@ -1683,25 +1638,7 @@ bool Platform::AnyHeaterHot(uint16_t heaters, float t)
return false;
}
-// Update the heater PID parameters or thermistor resistance etc.
-void Platform::SetPidParameters(size_t heater, const PidParameters& params)
-{
- if (heater < HEATERS && params != nvData.pidParams[heater])
- {
- nvData.pidParams[heater] = params;
- if (autoSaveEnabled)
- {
- WriteNvData();
- }
- }
-}
-const PidParameters& Platform::GetPidParameters(size_t heater) const
-{
- return nvData.pidParams[heater];
-}
-
-// power is a fraction in [0,1]
-
+// Power is a fraction in [0,1]
void Platform::SetHeater(size_t heater, float power)
{
if (heatOnPins[heater] != NoPin)
@@ -1755,7 +1692,7 @@ EndStopHit Platform::Stopped(size_t drive) const
else if (endStopType[drive] == EndStopType::noEndStop)
{
// No homing switch is configured for this axis, so see if we should use the Z probe
- if (nvData.zProbeType > 0 && drive < reprap.GetGCodes()->GetNumAxes() && (nvData.zProbeAxes & (1 << drive)) != 0)
+ if (zProbeType > 0 && drive < reprap.GetGCodes()->GetNumAxes() && (zProbeAxes & (1 << drive)) != 0)
{
return GetZProbeResult(); // using the Z probe as a low homing stop for this axis, so just get its result
}
@@ -1786,13 +1723,32 @@ uint32_t Platform::GetAllEndstopStates() const
// Return the Z probe result. We assume that if the Z probe is used as an endstop, it is used as the low stop.
EndStopHit Platform::GetZProbeResult() const
{
- const int zProbeVal = ZProbe();
- const int zProbeADValue = GetZProbeParameters().adcValue;
+ const int zProbeVal = GetZProbeReading();
+ const int zProbeADValue = GetCurrentZProbeParameters().adcValue;
return (zProbeVal >= zProbeADValue) ? EndStopHit::lowHit
: (zProbeVal * 10 >= zProbeADValue * 9) ? EndStopHit::lowNear // if we are at/above 90% of the target value
: EndStopHit::noStop;
}
+// Write the Z probe parameters to file
+bool Platform::WriteZProbeParameters(FileStore *f) const
+{
+ bool ok = f->Write("; Z probe parameters\n");
+ if (ok)
+ {
+ ok = irZProbeParameters.WriteParameters(f, 1);
+ }
+ if (ok)
+ {
+ ok = alternateZProbeParameters.WriteParameters(f, 3);
+ }
+ if (ok)
+ {
+ ok = switchZProbeParameters.WriteParameters(f, 4);
+ }
+ return ok;
+}
+
// This is called from the step ISR as well as other places, so keep it fast
void Platform::SetDirection(size_t drive, bool direction)
{
@@ -2230,18 +2186,9 @@ void Platform::InitFans()
void Platform::SetMACAddress(uint8_t mac[])
{
- bool changed = false;
for (size_t i = 0; i < 6; i++)
{
- if (nvData.macAddress[i] != mac[i])
- {
- nvData.macAddress[i] = mac[i];
- changed = true;
- }
- }
- if (changed && autoSaveEnabled)
- {
- WriteNvData();
+ macAddress[i] = mac[i];
}
}
@@ -2654,9 +2601,6 @@ const char* Platform::GetBoardString() const
// User I/O and servo support
bool Platform::GetFirmwarePin(int logicalPin, PinAccess access, Pin& firmwarePin, bool& invert)
{
-#ifdef __RADDS__
-# error This needs to be modified for RADDS
-#endif
firmwarePin = NoPin; // assume failure
invert = false; // this is the common case
if (logicalPin < 0 || logicalPin > HighestLogicalPin)
@@ -2832,6 +2776,7 @@ char Platform::ReadFromSource(const SerialSource source)
return 0;
}
+#ifndef __RADDS__
// CPU temperature
void Platform::GetMcuTemperatures(float& minT, float& currT, float& maxT) const
{
@@ -2839,6 +2784,7 @@ void Platform::GetMcuTemperatures(float& minT, float& currT, float& maxT) const
currT = AdcReadingToCpuTemperature(currentMcuTemperature);
maxT = AdcReadingToCpuTemperature(highestMcuTemperature);
}
+#endif
#ifdef DUET_NG
// Power in voltage
@@ -3035,13 +2981,15 @@ void Platform::Tick()
case 2: // last conversion started was the Z probe, with IR LED on
const_cast<ZProbeAveragingFilter&>(zProbeOnFilter).ProcessReading(GetRawZProbeReading());
- if (nvData.zProbeType == 2) // if using a modulated IR sensor
+ if (zProbeType == 2) // if using a modulated IR sensor
{
digitalWrite(zProbeModulationPin, LOW); // turn off the IR emitter
}
// Read the MCU temperature as well (no need to do it in every state)
+#ifndef __RADDS__
currentMcuTemperature = AnalogInReadChannel(temperatureAdcChannel);
+#endif
++tickState;
break;
@@ -3051,7 +2999,7 @@ void Platform::Tick()
// no break
case 0: // this is the state after initialisation, no conversion has been started
default:
- if (nvData.zProbeType == 2) // if using a modulated IR sensor
+ if (zProbeType == 2) // if using a modulated IR sensor
{
digitalWrite(zProbeModulationPin, HIGH); // turn on the IR emitter
}
diff --git a/src/Platform.h b/src/Platform.h
index 86668c7a..e82f99bd 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -46,6 +46,7 @@ Licence: GPL
// Platform-specific includes
#include "Core.h"
+#include "DueFlashStorage.h"
#include "Heating/TemperatureSensor.h"
#include "Heating/Thermistor.h"
#include "Heating/TemperatureError.h"
@@ -54,7 +55,7 @@ Licence: GPL
#if defined(DUET_NG)
# include "DueXn.h"
-#else
+#elif !defined(__RADDS__)
# include "Libraries/MCP4461/MCP4461.h"
#endif
@@ -125,20 +126,6 @@ const uint32_t Z_PROBE_AXES = (1 << X_AXIS) | (1 << Z_AXIS); // Axes for which t
// HEATERS - The bed is assumed to be the at index 0
-// The thermistors used in the R3epRapPro Ormerod are:
-// Bed thermistor: http://uk.farnell.com/epcos/b57863s103f040/sensor-miniature-ntc-10k/dp/1299930?Ntt=129-9930
-// Hot end thermistor: http://www.digikey.co.uk/product-search/en?x=20&y=11&KeyWords=480-3137-ND
-
-// Note: a negative P, I or D value means do not use PID for this heater, use bang-bang control instead.
-// This allows us to switch between PID and bang-bang using the M301 and M304 commands.
-
-// We use method 2 (see above)
-const float defaultPidKis[HEATERS] = HEATERS_(5.0, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2); // Integral PID constants
-const float defaultPidKds[HEATERS] = HEATERS_(500.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0); // Derivative PID constants
-const float defaultPidKps[HEATERS] = HEATERS_(-1.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0); // Proportional PID constants, negative values indicate use bang-bang instead of PID
-const float defaultPidKts[HEATERS] = HEATERS_(2.7, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4); // approximate PWM value needed to maintain temperature, per degC above room temperature
-const float defaultPidKss[HEATERS] = HEATERS_(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0); // PWM scaling factor, to allow for variation in heater power and supply voltage
-
// Define the number of temperature readings we average for each thermistor. This should be a power of 2 and at least 4 ** AD_OVERSAMPLE_BITS.
// Keep THERMISTOR_AVERAGE_READINGS * NUM_HEATERS * 2ms no greater than HEAT_SAMPLE_TIME or the PIDs won't work well.
const unsigned int ThermistorAverageReadings = 32;
@@ -190,11 +177,17 @@ enum class EndStopType
/***************************************************************************************************/
// Enumeration describing the reasons for a software reset.
-// The spin state gets or'ed into this, so keep the lower ~4 bits unused.
+// The spin state gets or'ed into this, so keep the lower 4 bits unused.
enum class SoftwareResetReason : uint16_t
{
user = 0, // M999 command
- erase = 55, // special M999 command to erase firmware and reset
+ erase = 0x10, // special M999 command to erase firmware and reset
+ NMI = 0x20,
+ hardFault = 0x30,
+ memManage = 0x40,
+ busFault = 0x50,
+ usageFault = 0x60,
+ otherFault = 0x70,
inAuxOutput = 0x0800, // this bit is or'ed in if we were in aux output at the time
stuckInSpin = 0x1000, // we got stuck in a Spin() function for too long
inLwipSpin = 0x2000, // we got stuck in a call to LWIP for too long
@@ -240,64 +233,13 @@ struct ZProbeParameters
float extraParam; // extra parameters used by some types of probe e.g. Delta probe
bool invertReading; // true if we need to invert the reading
- void Init(float h)
- {
- adcValue = Z_PROBE_AD_VALUE;
- xOffset = yOffset = 0.0;
- height = h;
- calibTemperature = 20.0;
- temperatureCoefficient = 0.0; // no default temperature correction
- diveHeight = DEFAULT_Z_DIVE;
- probeSpeed = DEFAULT_PROBE_SPEED;
- travelSpeed = DEFAULT_TRAVEL_SPEED;
- recoveryTime = extraParam = 0.0;
- invertReading = false;
- }
-
- float GetStopHeight(float temperature) const
- {
- return ((temperature - calibTemperature) * temperatureCoefficient) + height;
- }
-
- bool operator==(const ZProbeParameters& other) const
- {
- return adcValue == other.adcValue
- && height == other.height
- && xOffset == other.xOffset
- && yOffset == other.yOffset
- && calibTemperature == other.calibTemperature
- && temperatureCoefficient == other.temperatureCoefficient
- && diveHeight == other.diveHeight
- && probeSpeed == other.probeSpeed
- && travelSpeed == other.travelSpeed
- && recoveryTime == other.recoveryTime
- && extraParam == other.extraParam
- && invertReading == other.invertReading;
- }
-
- bool operator!=(const ZProbeParameters& other) const
- {
- return !operator==(other);
- }
-};
-
-class PidParameters
-{
- // If you add any more variables to this class, don't forget to change the definition of operator== in Platform.cpp!
-public:
- float kI, kD, kP, kT, kS;
-
- bool UsePID() const;
- bool operator==(const PidParameters& other) const;
- bool operator!=(const PidParameters& other) const
- {
- return !operator==(other);
- }
+ void Init(float h);
+ float GetStopHeight(float temperature) const;
+ bool WriteParameters(FileStore *f, unsigned int probeType) const;
};
// Class to perform averaging of values read from the ADC
// numAveraged should be a power of 2 for best efficiency
-
template<size_t numAveraged> class AveragingFilter
{
public:
@@ -547,19 +489,25 @@ public:
// Z probe
+ void SetZProbeDefaults();
float ZProbeStopHeight();
float GetZProbeDiveHeight() const;
+ float GetZProbeStartingHeight();
float GetZProbeTravelSpeed() const;
- int ZProbe() const;
+ int GetZProbeReading() const;
EndStopHit GetZProbeResult() const;
int GetZProbeSecondaryValues(int& v1, int& v2);
void SetZProbeType(int iZ);
- int GetZProbeType() const;
+ int GetZProbeType() const { return zProbeType; }
void SetZProbeAxes(uint32_t axes);
- uint32_t GetZProbeAxes() const { return nvData.zProbeAxes; }
- const ZProbeParameters& GetZProbeParameters() const;
- void SetZProbeParameters(const struct ZProbeParameters& params);
+ uint32_t GetZProbeAxes() const { return zProbeAxes; }
+ const ZProbeParameters& GetZProbeParameters(int32_t probeType) const;
+ const ZProbeParameters& GetCurrentZProbeParameters() const { return GetZProbeParameters(zProbeType); }
+ void SetZProbeParameters(int32_t probeType, const struct ZProbeParameters& params);
bool MustHomeXYBeforeZ() const;
+ bool WriteZProbeParameters(FileStore *f) const;
+
+ // Ancilliary PWM
void SetExtrusionAncilliaryPwmValue(float v);
float GetExtrusionAncilliaryPwmValue() const;
@@ -573,23 +521,19 @@ public:
// Heat and temperature
float GetTemperature(size_t heater, TemperatureError& err) // Result is in degrees Celsius
- pre (heater < HEATERS);
+ pre(heater < HEATERS);
float GetZProbeTemperature(); // Get our best estimate of the Z probe temperature
void SetHeater(size_t heater, float power) // power is a fraction in [0,1]
- pre (heater < HEATERS);
+ pre(heater < HEATERS);
uint32_t HeatSampleInterval() const;
void SetHeatSampleTime(float st);
float GetHeatSampleTime() const;
- void SetPidParameters(size_t heater, const PidParameters& params);
-
- const PidParameters& GetPidParameters(size_t heater) const
- pre (heater < HEATERS);
Thermistor& GetThermistor(size_t heater)
- pre (heater < HEATERS)
+ pre(heater < HEATERS)
{
return thermistors[heater];
}
@@ -598,7 +542,7 @@ public:
pre(heater < HEATERS; thermistor < HEATERS);
int GetThermistorNumber(size_t heater) const
- pre (heater < HEATERS);
+ pre(heater < HEATERS);
bool IsThermistorChannel(uint8_t heater) const
pre(heater < HEATERS);
@@ -627,11 +571,6 @@ public:
float GetFanRPM();
// Flash operations
- void ResetNvData();
- void ReadNvData();
- void WriteNvData();
- void SetAutoSave(bool enabled);
-
void UpdateFirmware();
bool CheckFirmwareUpdatePrerequisites();
@@ -651,7 +590,9 @@ public:
bool Inkjet(int bitPattern);
// MCU temperature
+#ifndef __RADDS
void GetMcuTemperatures(float& minT, float& currT, float& maxT) const;
+#endif
void SetMcuTemperatureAdjust(float v) { mcuTemperatureAdjust = v; }
float GetMcuTemperatureAdjust() const { return mcuTemperatureAdjust; }
@@ -706,35 +647,22 @@ private:
}
};
+#ifdef DUET_NG
static_assert(SoftwareResetData::numberOfSlots * sizeof(SoftwareResetData) <= 512, "Can't fit software reset data in SAM4E user signature area");
+#else
+ static_assert(SoftwareResetData::numberOfSlots * sizeof(SoftwareResetData) <= FLASH_DATA_LENGTH, "NVData too large");
+#endif
- // The following struct is due to be replaced by the config-override.g file.
- struct FlashData
- {
- static const uint16_t magicValue = 0xE6C4; // value we use to recognise that the flash data has been written
- static const uint16_t versionValue = 5; // increment this whenever this struct changes
- static const uint32_t nvAddress = SoftwareResetData::nvAddress + (SoftwareResetData::numberOfSlots * sizeof(SoftwareResetData));
-
- uint16_t magic;
- uint16_t version;
-
- // The remaining data could alternatively be saved to SD card.
- // Note however that if we save them as G codes, we need to provide a way of saving IR and ultrasonic G31 parameters separately.
- ZProbeParameters switchZProbeParameters; // Z probe values for the switch Z-probe
- ZProbeParameters irZProbeParameters; // Z probe values for the IR sensor
- ZProbeParameters alternateZProbeParameters; // Z probe values for the alternate sensor
- int zProbeType; // the type of Z probe we are currently using
- uint32_t zProbeAxes; // Z probe is used for these axes (bitmap)
- PidParameters pidParams[HEATERS];
- byte ipAddress[4];
- byte netMask[4];
- byte gateWay[4];
- uint8_t macAddress[6];
- Compatibility compatibility;
- };
-
- FlashData nvData;
- bool autoSaveEnabled;
+ ZProbeParameters switchZProbeParameters; // Z probe values for the switch Z-probe
+ ZProbeParameters irZProbeParameters; // Z probe values for the IR sensor
+ ZProbeParameters alternateZProbeParameters; // Z probe values for the alternate sensor
+ int zProbeType; // the type of Z probe we are currently using
+ uint32_t zProbeAxes; // Z probe is used for these axes (bitmap)
+ byte ipAddress[4];
+ byte netMask[4];
+ byte gateWay[4];
+ uint8_t macAddress[6];
+ Compatibility compatibility;
BoardType board;
#ifdef DUET_NG
@@ -896,9 +824,11 @@ private:
float nozzleDiameter;
// Temperature and power monitoring
+#ifndef __RADDS__ // reading temperature on the RADDS messes up one of the heater pins, so don't do it
AnalogChannelNumber temperatureAdcChannel;
uint16_t currentMcuTemperature, highestMcuTemperature, lowestMcuTemperature;
uint16_t mcuAlarmTemperature;
+#endif
float mcuTemperatureAdjust;
#ifdef DUET_NG
@@ -1208,22 +1138,22 @@ inline bool Platform::IsRtdChannel(uint8_t heater) const
inline const uint8_t* Platform::IPAddress() const
{
- return nvData.ipAddress;
+ return ipAddress;
}
inline const uint8_t* Platform::NetMask() const
{
- return nvData.netMask;
+ return netMask;
}
inline const uint8_t* Platform::GateWay() const
{
- return nvData.gateWay;
+ return gateWay;
}
inline const uint8_t* Platform::MACAddress() const
{
- return nvData.macAddress;
+ return macAddress;
}
inline float Platform::GetPressureAdvance(size_t extruder) const
@@ -1252,7 +1182,7 @@ inline void Platform::GetEndStopConfiguration(size_t axis, EndStopType& esType,
// This is called by the tick ISR to get the raw Z probe reading to feed to the filter
inline uint16_t Platform::GetRawZProbeReading() const
{
- switch (nvData.zProbeType)
+ switch (zProbeType)
{
case 4:
{
diff --git a/src/RADDS/Pins_radds.h b/src/RADDS/Pins_radds.h
index 09beff9c..51f1f363 100644
--- a/src/RADDS/Pins_radds.h
+++ b/src/RADDS/Pins_radds.h
@@ -86,8 +86,10 @@ const Pin HEAT_ON_PINS[HEATERS] = HEATERS_(7, 13, 12, 11, e, f, g, h); // bed, h
// Default thermistor betas
const float BED_R25 = 10000.0;
const float BED_BETA = 4066.0;
+const float BED_SHC = 0.0;
const float EXT_R25 = 100000.0;
const float EXT_BETA = 4066.0;
+const float EXT_SHC = 0.0;
// Thermistor series resistor value in Ohms
const float THERMISTOR_SERIES_RS = 4700.0;
@@ -106,14 +108,8 @@ const Pin ATX_POWER_PIN = 40;
const Pin Z_PROBE_PIN = 5; // RADDS "ADC" pin
// Digital pin number to turn the IR LED on (high) or off (low)
-// channel 1: Z_PROBE_MOD_PIN07
-// channel 0: Z_PROBE_MOD_PIN
-// Make channel 0 == channel 1 for RADDS. Difference in channels
-// is an artifact of difference in different versions of Duet electronics
-//
// D34 -- unused X-max on RADDS
const Pin Z_PROBE_MOD_PIN = 34;
-const Pin Z_PROBE_MOD_PIN07 = 34;
// Use a PWM capable pin
// Firmware uses SamNonDue so feel free to use a non-Arduino pin
@@ -128,12 +124,11 @@ const Pin COOLING_FAN_RPM_PIN = 25;
// SD cards
const size_t NumSdCards = 1;
-const Pin SdCardDetectPins[NumSdCards] = {NoPin};
+const Pin SdCardDetectPins[NumSdCards] = { 14 };
const Pin SdWriteProtectPins[NumSdCards] = { NoPin};
-const Pin SdSpiCSPins[1] = {zz}; //FIXME
+const Pin SdSpiCSPins[1] = { 77 };
// Definition of which pins we allow to be controlled using M42
-//
// Spare pins on the Arduino Due are
//
// D5 / TIOA6 / C.25
@@ -150,20 +145,16 @@ const Pin SdSpiCSPins[1] = {zz}; //FIXME
// D72 / RX LED / C.30
// D73 / TX LED / A.21
-const size_t NUM_PINS_ALLOWED = 80;
-#define PINS_ALLOWED { \
- /* pins 00-07 */ 0b01100000, \
- /* pins 08-15 */ 0, \
- /* pins 16-23 */ 0, \
- /* pins 24-31 */ 0, \
- /* pins 32-39 */ 0b00000000, \
- /* pins 40-47 */ 0, \
- /* pins 48-55 */ 0, \
- /* pins 56-63 */ 0b00001100, \
- /* pins 64-71 */ 0b11111100, \
- /* pins 72-79 */ 0b00000011 \
-}
+// M42 and M208 commands now use logical pin numbers, not firmware pin numbers.
+// This is the mapping from logical pins 60+ to firmware pin numbers
+const Pin SpecialPinMap[] =
+{
+ 5, 6, 58, 59,
+ 66, 67, 68, 69, 70, 71, 73, 73
+};
+// This next definition defines the highest one.
+const int HighestLogicalPin = 60 + ARRAY_SIZE(SpecialPinMap) - 1; // highest logical pin number on this electronics
// SAM3X Flash locations (may be expanded in the future)
const uint32_t IAP_FLASH_START = 0x000F0000;
@@ -180,13 +171,6 @@ const uint32_t IAP_FLASH_END = 0x000FFBFF; // don't touch the last 1KB, it's us
#define STEP_TC_IRQN TC3_IRQn
#define STEP_TC_HANDLER TC3_Handler
-// Hardware SPI support for SD cards
-
-// SD select
-#define SD_SS 4
-#define SD_DETECT_PIN 14 // card detect switch; needs pullup asserted
-#define SD_DETECT_VAL 0 // detect switch active low
-#define SD_DETECT_PIO_ID ID_PIOD
#ifdef LCD_UI
diff --git a/src/Reprap.cpp b/src/Reprap.cpp
index aa372a27..02b0f178 100644
--- a/src/Reprap.cpp
+++ b/src/Reprap.cpp
@@ -61,7 +61,7 @@ void RepRap::Init()
if (gCodes->RunConfigFile(configFile))
{
- while (gCodes->IsRunningConfigFile())
+ while (gCodes->IsDaemonBusy())
{
// GCodes::Spin will read the macro and ensure DoingFileMacro returns false when it's done
Spin();
@@ -647,7 +647,7 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
response->cat(",\"sensors\":{");
// Probe
- const int v0 = platform->ZProbe();
+ const int v0 = platform->GetZProbeReading();
int v1, v2;
switch (platform->GetZProbeSecondaryValues(v1, v2))
{
@@ -759,11 +759,8 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
}
response->catf(",\"endstops\":%d", endstops);
- // Delta configuration and number of axes
- response->catf(",\"geometry\":\"%s\",\"axes\":%u", move->GetGeometryString(), numAxes);
-
- // Firmware name, for PanelDue
- response->catf(",\"firmwareName\":\"%s\"", NAME);
+ // Firmware name, machine geometry and number of axes
+ response->catf(",\"firmwareName\":\"%s\",\"geometry\":\"%s\",\"axes\":%u", NAME, move->GetGeometryString(), numAxes);
// Total and mounted volumes
size_t mountedCards = 0;
@@ -782,7 +779,7 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
/* Probe */
{
- const ZProbeParameters probeParams = platform->GetZProbeParameters();
+ const ZProbeParameters probeParams = platform->GetCurrentZProbeParameters();
// Trigger threshold
response->catf(",\"probe\":{\"threshold\":%d", probeParams.adcValue);
@@ -854,11 +851,13 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
}
// MCU temperatures
+#ifndef __RADDS__
{
float minT, currT, maxT;
platform->GetMcuTemperatures(minT, currT, maxT);
response->catf(",\"mcutemp\":{\"min\":%.1f,\"cur\":%.1f,\"max\":%.1f}", minT, currT, maxT);
}
+#endif
#ifdef DUET_NG
// Power in voltages
@@ -887,7 +886,7 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
}
if (ch == '[')
{
- response->cat("]");
+ response->cat(ch); // no extruders
}
// Fraction of file printed
@@ -1173,7 +1172,7 @@ OutputBuffer *RepRap::GetLegacyStatusResponse(uint8_t type, int seq)
response->catf(",\"tool\":%d", toolNumber);
// Send the Z probe value
- const int v0 = platform->ZProbe();
+ const int v0 = platform->GetZProbeReading();
int v1, v2;
switch (platform->GetZProbeSecondaryValues(v1, v2))
{
@@ -1236,6 +1235,8 @@ OutputBuffer *RepRap::GetLegacyStatusResponse(uint8_t type, int seq)
response->catf(",\"geometry\":\"%s\",\"axes\":%u,\"volumes\":%u,\"numTools\":%u,\"myName\":",
move->GetGeometryString(), numAxes, NumSdCards, GetNumberOfContiguousTools());
response->EncodeString(myName, ARRAY_SIZE(myName), false);
+ response->cat(",\"firmwareName\":");
+ response->EncodeString(NAME, strlen(NAME), false);
}
const int auxSeq = (int)platform->GetAuxSeq();
diff --git a/src/Storage/MassStorage.cpp b/src/Storage/MassStorage.cpp
index 06b38627..b296329d 100644
--- a/src/Storage/MassStorage.cpp
+++ b/src/Storage/MassStorage.cpp
@@ -301,17 +301,19 @@ time_t MassStorage::GetLastModifiedTime(const char* directory, const char *fileN
return 0;
}
-bool MassStorage::SetLastModifiedTime(const char *file, time_t time)
+bool MassStorage::SetLastModifiedTime(const char* directory, const char *fileName, time_t time)
{
- FILINFO fno;
+ const char *location = (directory != nullptr)
+ ? platform->GetMassStorage()->CombineName(directory, fileName)
+ : fileName;
const struct tm * const timeInfo = gmtime(&time);
-
+ FILINFO fno;
fno.fdate = (WORD)(((timeInfo->tm_year - 80) * 512U) | (timeInfo->tm_mon + 1) * 32U | timeInfo->tm_mday);
fno.ftime = (WORD)(timeInfo->tm_hour * 2048U | timeInfo->tm_min * 32U | timeInfo->tm_sec / 2U);
- const bool ok = (f_utime(file, &fno) == FR_OK);
+ const bool ok = (f_utime(location, &fno) == FR_OK);
if (!ok)
{
- reprap.GetPlatform()->MessageF(HTTP_MESSAGE, "SetLastModifiedTime didn't work for file '%s'\n", file);
+ reprap.GetPlatform()->MessageF(HTTP_MESSAGE, "SetLastModifiedTime didn't work for file '%s'\n", location);
}
return ok;
}
diff --git a/src/Storage/MassStorage.h b/src/Storage/MassStorage.h
index 3ccf973d..ee355796 100644
--- a/src/Storage/MassStorage.h
+++ b/src/Storage/MassStorage.h
@@ -31,7 +31,7 @@ public:
bool DirectoryExists(const char *path) const;
bool DirectoryExists(const char* directory, const char* subDirectory);
time_t GetLastModifiedTime(const char* directory, const char *fileName) const;
- bool SetLastModifiedTime(const char *file, time_t time);
+ bool SetLastModifiedTime(const char* directory, const char *file, time_t time);
bool Mount(size_t card, StringRef& reply, bool reportSuccess);
bool Unmount(size_t card, StringRef& reply);
bool IsDriveMounted(size_t drive) const { return drive < NumSdCards && isMounted[drive]; }