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

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2019-04-23 01:11:52 +0300
committerDavid Crocker <dcrocker@eschertech.com>2019-04-23 01:11:52 +0300
commitcb0a782b673773037185ff73e53230251c2dff51 (patch)
treed8485db2ff5799a34fa0474f9264945ba70e4442 /src/Endstops/EndstopsManager.cpp
parent6814c342969a471fa3b32c5e859f66b528de1131 (diff)
Duet 3 initial working build
Only the Duet_NG configuration builds at present. New features: - Pins are named instead of numbered - Support multiple endstops per axis - Support multiple Z probes - Support M950 for heater and fan mapping - GPIO pins now need to be allocated before they can be used by M42 or M280 - Laser power velocity ramping - New codes for 12864 display - Added LinearAnalogSensor - Height following mode is mostly implemented Bug fixes: - M109 didn't run the tool change files if no tool was selected initially - The M290 command written to resurrect.g didn't use absolute babystepping - The M32 command written to resurrect.g didn't quote the filename - M291 no longer locks the movement system, it stopped the jog buttons working - M302 now waits for standstill
Diffstat (limited to 'src/Endstops/EndstopsManager.cpp')
-rw-r--r--src/Endstops/EndstopsManager.cpp424
1 files changed, 424 insertions, 0 deletions
diff --git a/src/Endstops/EndstopsManager.cpp b/src/Endstops/EndstopsManager.cpp
new file mode 100644
index 00000000..171e24a3
--- /dev/null
+++ b/src/Endstops/EndstopsManager.cpp
@@ -0,0 +1,424 @@
+/*
+ * Endstop.cpp
+ *
+ * Created on: 3 Apr 2019
+ * Author: David
+ */
+
+#include "EndstopsManager.h"
+#include "Endstop.h"
+#include "ZProbe.h"
+#include "RepRap.h"
+#include "GCodes/GCodeBuffer.h"
+#include "GCodes/GCodes.h"
+#include "Movement/Move.h"
+
+EndstopsManager::EndstopsManager() : activeEndstops(nullptr)
+{
+ for (Endstop *& es : axisEndstops)
+ {
+ es = nullptr;
+ }
+ for (ZProbe *& zp : zProbes)
+ {
+ zp = nullptr;
+ }
+}
+
+void EndstopsManager::Init()
+{
+ activeEndstops = nullptr;
+ String<1> dummy;
+
+ // Configure default endstops
+ for (size_t axis = 0; axis < NumDefaultEndstops; ++axis)
+ {
+ SwitchEndstop * const sw = new SwitchEndstop(axis, EndStopPosition::lowEndStop);
+ sw->Configure(DefaultEndstopPinNames[axis], dummy.GetRef(), EndStopInputType::activeHigh);
+ axisEndstops[axis] = sw;
+ }
+
+ // Z PROBE
+ reprap.GetPlatform().InitZProbeFilters();
+
+ ZProbe * const zp = new ZProbe();
+ zp->AssignPorts(DefaultZProbePinNames, dummy.GetRef());
+ zProbes[0] = zp;
+ currentZProbeNumber = 0;
+
+}
+
+// Add an endstop to the active list
+void EndstopsManager::AddToActive(EndstopOrZProbe& e)
+{
+ e.SetNext(activeEndstops);
+ activeEndstops = &e;
+}
+
+// Set up the active endstop list according to the axes commanded to move in a G0/G1 S1/S3 command
+void EndstopsManager::EnableAxisEndstops(AxesBitmap axes)
+{
+ activeEndstops = nullptr;
+ const Kinematics& kin = reprap.GetMove().GetKinematics();
+ for (size_t axis = 0; axis < reprap.GetGCodes().GetVisibleAxes(); ++axis)
+ {
+ if (IsBitSet(axes, axis) && axisEndstops[axis] != nullptr)
+ {
+ axisEndstops[axis]->Prime(kin, reprap.GetPlatform().GetAxisDriversConfig(axis));
+ AddToActive(*axisEndstops[axis]);
+ }
+ }
+}
+
+// Set up the active endstops for Z probing
+void EndstopsManager::EnableZProbe(size_t probeNumber)
+{
+ activeEndstops = nullptr;
+ if (probeNumber < MaxZProbes && zProbes[probeNumber] != nullptr)
+ {
+ AddToActive(*zProbes[probeNumber]);
+ }
+}
+
+// Check the endstops.
+// If an endstop has triggered, remove it from the active list, return its action, and return a pointer to it via 'es'.
+EndstopHitDetails EndstopsManager::CheckEndstops(bool goingSlow)
+{
+ EndstopHitDetails ret; // the default constructor will clear all fields
+ EndstopOrZProbe *actioned = nullptr;
+ for (EndstopOrZProbe *esp = activeEndstops; esp != nullptr; esp = esp->GetNext())
+ {
+ const EndstopHitDetails hd = esp->CheckTriggered(goingSlow);
+ if (hd.GetAction() == EndstopHitAction::stopAll)
+ {
+ activeEndstops = nullptr; // no need to do anything else
+ return hd;
+ }
+ if (hd.GetAction() > ret.GetAction())
+ {
+ ret = hd;
+ actioned = esp;
+ }
+ }
+ if (ret.GetAction() > EndstopHitAction::reduceSpeed)
+ {
+ if (actioned->Acknowledge(ret))
+ {
+ // The actioned endstop has completed so remove it from the active list
+ EndstopOrZProbe *prev = nullptr;
+ for (EndstopOrZProbe *es = activeEndstops; es != nullptr; )
+ {
+ if (es == actioned)
+ {
+ if (prev == nullptr)
+ {
+ activeEndstops = es->GetNext();
+ }
+ else
+ {
+ prev->SetNext(es->GetNext());
+ }
+ break;
+ }
+ prev = es;
+ es = es->GetNext();
+ }
+ }
+ }
+ return ret;
+}
+
+// Configure the endstops in response to M574
+GCodeResult EndstopsManager::HandleM574(GCodeBuffer& gb, const StringRef& reply)
+{
+ // First count how many axes we are configuring, and lock movement if necessary
+ unsigned int axesSeen = 0;
+ size_t lastAxisSeen = 0; // dummy initialisation to avoid compiler warnings
+ EndStopPosition lastPosSeen = EndStopPosition::noEndStop; // dummy initialisation to avoid compiler warnings
+ for (size_t axis = 0; axis < reprap.GetGCodes().GetTotalAxes(); ++axis)
+ {
+ if (gb.Seen(reprap.GetGCodes().GetAxisLetters()[axis]))
+ {
+ lastPosSeen = (EndStopPosition)gb.GetUIValue();
+ if (lastPosSeen >= EndStopPosition::numPositions)
+ {
+ reply.copy("Invalid endstop position");
+ return GCodeResult::error;
+ }
+ lastAxisSeen = axis;
+ ++axesSeen;
+ }
+ }
+
+ if (axesSeen == 0)
+ {
+ reply.copy("Endstop configuration");
+ char sep = ':';
+ for (size_t axis = 0; axis < reprap.GetGCodes().GetTotalAxes(); ++axis)
+ {
+ const char c = reprap.GetGCodes().GetAxisLetters()[axis];
+ if (axisEndstops[axis] == nullptr)
+ {
+ reply.catf("%c %c: none", sep, c);
+ }
+ else
+ {
+ EndStopInputType inputType = axisEndstops[axis]->GetEndstopType();
+ reply.catf("%c %c: %s %s",
+ sep, c,
+ (axisEndstops[axis]->GetAtHighEnd()) ? "high end" : "low end",
+ (inputType == EndStopInputType::activeHigh) ? "active high switch"
+ : (inputType == EndStopInputType::activeLow) ? "active low switch"
+ : (inputType == EndStopInputType::zProbeAsEndstop) ? "Z probe"
+ : (inputType == EndStopInputType::motorStall) ? "motor stall"
+ : "unknown type"
+ );
+ axisEndstops[axis]->AppendPinNames(reply);
+ }
+ sep = ',';
+ }
+ return GCodeResult::ok;
+ }
+
+ // If we get here then axes were specified so we are setting endstop parameters
+ if (!reprap.GetGCodes().LockMovementAndWaitForStandstill(gb))
+ {
+ return GCodeResult::notFinished;
+ }
+
+ activeEndstops = nullptr; // we may be about to remove endstops, so make sure they are not in the active list
+
+ const EndStopInputType inputType = (gb.Seen('S')) ? (EndStopInputType)gb.GetUIValue() : EndStopInputType::activeHigh;
+ if (inputType >= EndStopInputType::numInputTypes)
+ {
+ reply.copy("invalid input type");
+ return GCodeResult::error;
+ }
+
+ if (gb.Seen('C'))
+ {
+ // Setting the port number(s), so there must be just one axis and we must be using switch-type endstops
+ if (axesSeen > 1 || (inputType != EndStopInputType::activeLow && inputType != EndStopInputType::activeHigh))
+ {
+ reply.copy("Invalid use of P parameter");
+ return GCodeResult::error;
+ }
+
+ delete axisEndstops[lastAxisSeen];
+ axisEndstops[lastAxisSeen] = nullptr;
+ SwitchEndstop * const sw = new SwitchEndstop(lastAxisSeen, lastPosSeen);
+ const bool ok = sw->Configure(gb, reply, inputType);
+ axisEndstops[lastAxisSeen] = sw;
+ if (!ok)
+ {
+ return GCodeResult::error;
+ }
+ }
+ else
+ {
+ // No C parameter, so there may be multiple axes
+ for (size_t axis = 0; axis < reprap.GetGCodes().GetTotalAxes(); ++axis)
+ {
+ const char c = reprap.GetGCodes().GetAxisLetters()[axis];
+ if (gb.Seen(c))
+ {
+ const EndStopPosition pos = (EndStopPosition)gb.GetUIValue(); // we range-checked this earlier
+ if (pos == EndStopPosition::noEndStop)
+ {
+ delete axisEndstops[axis];
+ axisEndstops[axis] = nullptr;
+ }
+ else
+ {
+ switch (inputType)
+ {
+ case EndStopInputType::motorStall:
+ // Asking for stall detection endstop, so we can delete any existing endstop(s) and create new ones
+ delete axisEndstops[axis];
+ axisEndstops[axis] = new StallDetectionEndstop(axis, pos);
+ break;
+
+ case EndStopInputType::zProbeAsEndstop:
+ // Asking for a ZProbe or stall detection endstop, so we can delete any existing endstop(s) and create new ones
+ delete axisEndstops[axis];
+ axisEndstops[axis] = new ZProbeEndstop(axis, pos);
+ break;
+
+ case EndStopInputType::activeHigh:
+ case EndStopInputType::activeLow:
+ if ( axisEndstops[axis] == nullptr
+ || (axisEndstops[axis]->GetEndstopType() != EndStopInputType::activeHigh && axisEndstops[axis]->GetEndstopType() != EndStopInputType::activeLow)
+ )
+ {
+ // Asking for a switch endstop but we don't already have one, so we don't know what pin number(s) it should use
+ reply.printf("Logical pin number needed for witch-type endstop on %c axis", c);
+ return GCodeResult::error;
+ }
+ else
+ {
+ ((SwitchEndstop *)axisEndstops[axis])->Reconfigure(pos, inputType);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return GCodeResult::ok;
+}
+
+EndStopPosition EndstopsManager::GetEndStopPosition(size_t axis) const pre(axis < MaxAxes)
+{
+ return (axisEndstops[axis] == nullptr) ? EndStopPosition::noEndStop
+ : (axisEndstops[axis]->GetAtHighEnd()) ? EndStopPosition::highEndStop
+ : EndStopPosition::lowEndStop;
+}
+
+// Return true if we are using a bed probe to home Z
+bool EndstopsManager::HomingZWithProbe() const
+{
+ return axisEndstops[Z_AXIS] == nullptr || axisEndstops[Z_AXIS]->GetEndstopType() == EndStopInputType::zProbeAsEndstop;
+}
+
+EndStopHit EndstopsManager::Stopped(size_t axis) const
+{
+ return axisEndstops[axis]->Stopped();
+}
+
+void EndstopsManager::GetM119report(const StringRef& reply)
+{
+ reply.copy("Endstops - ");
+ for (size_t axis = 0; axis < reprap.GetGCodes().GetTotalAxes(); ++axis)
+ {
+ reply.catf("%c: %s, ", reprap.GetGCodes().GetAxisLetters()[axis], TranslateEndStopResult(Stopped(axis), axisEndstops[axis]->GetAtHighEnd()));
+ }
+ reply.catf("Z probe: %s", TranslateEndStopResult(GetCurrentZProbe().Stopped(), false));
+}
+
+const char *EndstopsManager::TranslateEndStopResult(EndStopHit es, bool atHighEnd)
+{
+ switch (es)
+ {
+ case EndStopHit::atStop:
+ return (atHighEnd) ? "at max stop" : "at min stop";
+
+ case EndStopHit::nearStop:
+ return "near stop";
+
+ case EndStopHit::noStop:
+ default:
+ return "not stopped";
+ }
+}
+
+// Allocate ports to the specified Z probe returning true if successful
+bool EndstopsManager::AssignZProbePorts(GCodeBuffer& gb, const StringRef& reply, size_t probeNumber)
+{
+ if (probeNumber < MaxZProbes)
+ {
+ if (zProbes[probeNumber] == nullptr)
+ {
+ zProbes[probeNumber] = new ZProbe();
+ }
+ return zProbes[probeNumber]->AssignPorts(gb, reply);
+ }
+ reply.copy("Z probe number out of range");
+ return false;
+}
+
+ZProbe *EndstopsManager::GetZProbe(size_t num) const
+{
+ return (num < ARRAY_SIZE(zProbes)) ? zProbes[num] : nullptr;
+}
+
+void EndstopsManager::SetZProbeDefaults()
+{
+ zProbes[0]->SetDefaults();
+ for (size_t i = 0; i < MaxZProbes; ++i)
+ {
+ delete zProbes[i];
+ }
+}
+
+// Program the Z probe
+GCodeResult EndstopsManager::ProgramZProbe(GCodeBuffer& gb, const StringRef& reply)
+{
+ if (gb.Seen('S'))
+ {
+ uint32_t zProbeProgram[MaxZProbeProgramBytes];
+ size_t len = MaxZProbeProgramBytes;
+ gb.GetUnsignedArray(zProbeProgram, len, false);
+ if (len != 0)
+ {
+ for (size_t i = 0; i < len; ++i)
+ {
+ if (zProbeProgram[i] > 255)
+ {
+ reply.copy("Out of range value in program bytes");
+ return GCodeResult::error;
+ }
+ }
+ zProbeProg.SendProgram(zProbeProgram, len);
+ return GCodeResult::ok;
+ }
+ }
+ reply.copy("No program bytes provided");
+ return GCodeResult::error;
+}
+
+bool EndstopsManager::WriteZProbeParameters(FileStore *f, bool includingG31) const
+{
+ bool ok = true;
+ bool written = false;
+ for (size_t i = 0; i < MaxZProbes; ++i)
+ {
+ if (zProbes[i] != nullptr && (includingG31 || zProbes[i]->GetSaveToConfigOverride()))
+ {
+ if (!written)
+ {
+ ok = f->Write("; Z probe parameters\n");
+ written = true;
+ }
+ if (ok)
+ {
+ ok = zProbes[i]->WriteParameters(f, i);
+ }
+ }
+ }
+ return ok;
+}
+
+// Handle M558
+GCodeResult EndstopsManager::HandleM558(GCodeBuffer& gb, const StringRef &reply)
+{
+ const unsigned int probeNumber = (gb.Seen('K')) ? gb.GetUIValue() : currentZProbeNumber;
+ if (probeNumber >= MaxZProbes || zProbes[probeNumber] == nullptr)
+ {
+ reply.copy("Invalid Z probe index");
+ return GCodeResult::error;
+ }
+
+ return zProbes[probeNumber]->HandleM558(gb, reply, probeNumber);
+}
+
+// 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.
+GCodeResult EndstopsManager::HandleG31(GCodeBuffer& gb, const StringRef& reply)
+{
+ uint32_t probeNumber = currentZProbeNumber;
+ bool seenK = false;
+ gb.TryGetUIValue('K', probeNumber, seenK);
+ if (probeNumber >= MaxZProbes || zProbes[probeNumber] == nullptr)
+ {
+ reply.copy("Invalid Z probe index");
+ return GCodeResult::error;
+ }
+
+ return zProbes[probeNumber]->HandleG31(gb, reply, seenK);
+}
+
+// End