diff options
author | David Crocker <dcrocker@eschertech.com> | 2016-12-12 18:27:06 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2016-12-12 18:27:39 +0300 |
commit | cd5af6c7b13656a555cdc5ffbb8e37624ce9af67 (patch) | |
tree | ceed8ac57fda8910ff28194e1a7460beb0b6afac /src | |
parent | 4896bba4e81a38792f3c72ff31363d7ed68132df (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.h | 4 | ||||
-rw-r--r-- | src/Duet/Webserver.cpp | 2 | ||||
-rw-r--r-- | src/DuetNG/Webserver.cpp | 2 | ||||
-rw-r--r-- | src/GCodes/GCodeMachineState.cpp | 2 | ||||
-rw-r--r-- | src/GCodes/GCodeMachineState.h | 5 | ||||
-rw-r--r-- | src/GCodes/GCodes.cpp | 366 | ||||
-rw-r--r-- | src/GCodes/GCodes.h | 18 | ||||
-rw-r--r-- | src/GCodes/GCodes2.cpp | 142 | ||||
-rw-r--r-- | src/Heating/FOPDT.cpp | 53 | ||||
-rw-r--r-- | src/Heating/FOPDT.h | 29 | ||||
-rw-r--r-- | src/Heating/Heat.cpp | 51 | ||||
-rw-r--r-- | src/Heating/Heat.h | 24 | ||||
-rw-r--r-- | src/Heating/Pid.cpp | 49 | ||||
-rw-r--r-- | src/Heating/Pid.h | 10 | ||||
-rw-r--r-- | src/Libraries/Fatfs/fattime_rtc.cpp (renamed from src/Libraries/Fatfs/fattime_rtc.c) | 31 | ||||
-rw-r--r-- | src/Movement/DeltaParameters.cpp | 28 | ||||
-rw-r--r-- | src/Movement/DeltaParameters.h | 1 | ||||
-rw-r--r-- | src/Movement/Grid.cpp | 92 | ||||
-rw-r--r-- | src/Movement/Grid.h | 20 | ||||
-rw-r--r-- | src/Movement/Move.cpp | 43 | ||||
-rw-r--r-- | src/Movement/Move.h | 10 | ||||
-rw-r--r-- | src/Platform.cpp | 362 | ||||
-rw-r--r-- | src/Platform.h | 172 | ||||
-rw-r--r-- | src/RADDS/Pins_radds.h | 42 | ||||
-rw-r--r-- | src/Reprap.cpp | 21 | ||||
-rw-r--r-- | src/Storage/MassStorage.cpp | 12 | ||||
-rw-r--r-- | src/Storage/MassStorage.h | 2 |
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]; } |