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>2020-03-26 17:45:22 +0300
committerDavid Crocker <dcrocker@eschertech.com>2020-03-26 17:45:22 +0300
commitee519544acbee712ff1b9acf94a4bff83114aa85 (patch)
tree5ef60a2369903f2d0235b838c77c624fd05c8aef /src/GCodes/ObjectTracker.cpp
parentd2d3da87b8c0c495bb23e935391a8373bbed9128 (diff)
Partially implemented object cancellation
M486 implemented, but parsing object names in comments not done yet
Diffstat (limited to 'src/GCodes/ObjectTracker.cpp')
-rw-r--r--src/GCodes/ObjectTracker.cpp324
1 files changed, 324 insertions, 0 deletions
diff --git a/src/GCodes/ObjectTracker.cpp b/src/GCodes/ObjectTracker.cpp
new file mode 100644
index 00000000..17cb588c
--- /dev/null
+++ b/src/GCodes/ObjectTracker.cpp
@@ -0,0 +1,324 @@
+/*
+ * ObjectCancellation.cpp
+ *
+ * Created on: 24 Mar 2020
+ * Author: David
+ */
+
+#include "ObjectTracker.h"
+#include <GCodes/GCodeBuffer/GCodeBuffer.h>
+#include <RepRap.h>
+#include "GCodes.h"
+
+#if TRACK_OBJECT_NAMES && SUPPORT_OBJECT_MODEL
+
+// Object model tables and functions for class ObjectDirectoryEntry
+// Note: if using GCC version 7.3.1 20180622 and lambda functions are used in this table, you must compile this file with option -std=gnu++17.
+// Otherwise the table will be allocate in RAM instead of flash, which wastes too much RAM.
+
+// Macro to build a standard lambda function that includes the necessary type conversions
+#define OBJECT_MODEL_FUNC_ODE(...) OBJECT_MODEL_FUNC_BODY(ObjectDirectoryEntry, __VA_ARGS__)
+#define OBJECT_MODEL_FUNC_ODE_IF(_condition,...) OBJECT_MODEL_FUNC_IF_BODY(ObjectDirectoryEntry, _condition,__VA_ARGS__)
+
+constexpr ObjectModelArrayDescriptor ObjectDirectoryEntry::xArrayDescriptor =
+{
+ nullptr,
+ [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return 2; },
+ [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(((const ObjectDirectoryEntry*)self)->x[context.GetLastIndex()]); }
+};
+
+constexpr ObjectModelArrayDescriptor ObjectDirectoryEntry::yArrayDescriptor =
+{
+ nullptr,
+ [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return 2; },
+ [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(((const ObjectDirectoryEntry*)self)->y[context.GetLastIndex()]); }
+};
+
+constexpr ObjectModelTableEntry ObjectDirectoryEntry::objectModelTable[] =
+{
+ // Within each group, these entries must be in alphabetical order
+ // 0. ObjectDirectoryEntry root
+ { "name", OBJECT_MODEL_FUNC_ODE(self->name), ObjectModelEntryFlags::live },
+ { "x", OBJECT_MODEL_FUNC_NOSELF(&xArrayDescriptor), ObjectModelEntryFlags::live },
+ { "y", OBJECT_MODEL_FUNC_NOSELF(&yArrayDescriptor), ObjectModelEntryFlags::live },
+};
+
+constexpr uint8_t ObjectDirectoryEntry::objectModelTableDescriptor[] =
+{
+ 1, // number of sub-tables
+ 3
+};
+
+DEFINE_GET_OBJECT_MODEL_TABLE(ObjectDirectoryEntry)
+
+// Object model tables and functions for class ObjectTracker
+
+// Macro to build a standard lambda function that includes the necessary type conversions
+#define OBJECT_MODEL_FUNC_OT(...) OBJECT_MODEL_FUNC_BODY(ObjectTracker, __VA_ARGS__)
+#define OBJECT_MODEL_FUNC_OT_IF(_condition,...) OBJECT_MODEL_FUNC_IF_BODY(ObjectTracker, _condition,__VA_ARGS__)
+
+constexpr ObjectModelArrayDescriptor ObjectTracker::objectsArrayDescriptor =
+{
+ nullptr,
+ [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return ((const ObjectTracker*)self)->numObjects; },
+ [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept
+ -> ExpressionValue { return ExpressionValue(&(((const ObjectTracker*)self)->objectDirectory[context.GetLastIndex()]), 0); }
+};
+
+constexpr ObjectModelTableEntry ObjectTracker::objectModelTable[] =
+{
+ // Within each group, these entries must be in alphabetical order
+ // 0. BuildObjects root
+ { "m486Names", OBJECT_MODEL_FUNC_OT(self->usingM486Naming), ObjectModelEntryFlags::live },
+ { "m486Numbers", OBJECT_MODEL_FUNC_OT(self->usingM486Labelling), ObjectModelEntryFlags::live },
+ { "objects", OBJECT_MODEL_FUNC_NOSELF(&objectsArrayDescriptor), ObjectModelEntryFlags::live },
+};
+
+constexpr uint8_t ObjectTracker::objectModelTableDescriptor[] =
+{
+ 1, // number of sub-tables
+ 3
+};
+
+DEFINE_GET_OBJECT_MODEL_TABLE(ObjectTracker)
+
+#endif
+
+void ObjectTracker::Init() noexcept
+{
+ objectsCancelled.Clear();
+ currentObjectNumber = -1;
+ numObjects = 0;
+ currentObjectCancelled = printingJustResumed = usingM486Labelling = false;
+#if TRACK_OBJECT_NAMES
+ // Clear out all object names in case of late object model requests
+ for (size_t i = 0; i < MaxTrackedObjects; ++i)
+ {
+ objectDirectory[i].Init("");
+ }
+ objectNames.Reset();
+ usingM486Naming = false;
+#endif
+}
+
+void ObjectTracker::ChangeToObject(GCodeBuffer& gb, int i) noexcept
+{
+ currentObjectNumber = i;
+ if (currentObjectNumber >= (int)numObjects)
+ {
+ numObjects = currentObjectNumber + 1;
+ }
+ const bool cancelCurrentObject = currentObjectNumber >= 0 && currentObjectNumber < (int)objectsCancelled.MaxBits() && objectsCancelled.IsBitSet(currentObjectNumber);
+ if (cancelCurrentObject && !currentObjectCancelled)
+ {
+ StopPrinting(gb);
+ }
+ else if (!cancelCurrentObject && currentObjectCancelled)
+ {
+ ResumePrinting(gb);
+ }
+}
+
+GCodeResult ObjectTracker::HandleM486(GCodeBuffer &gb, const StringRef &reply) THROWS(GCodeException)
+{
+ if (gb.Seen('T'))
+ {
+ // Specify how many objects. May be useful for a user interface.
+ numObjects = gb.GetUIValue();
+ objectsCancelled.Clear(); // assume this command is only used at the start of a print
+ }
+
+ if (gb.Seen('S'))
+ {
+ // Specify which object we are about to print
+ usingM486Labelling = true;
+ const int num = gb.GetIValue();
+#if TRACK_OBJECT_NAMES
+ if (num >= 0 && num < (int)MaxTrackedObjects && gb.Seen('A'))
+ {
+ String<StringLength50> objectName;
+ gb.GetQuotedString(objectName.GetRef());
+ usingM486Naming = true;
+
+ if (num >= (int)numObjects) // if this is a new object
+ {
+ CreateObject(num, objectName.c_str());
+ }
+ else if (strcmp(objectName.c_str(), objectDirectory[num].name) != 0)
+ {
+ objectNames.FinishedUsing(objectDirectory[num].name);
+ SetObjectName(num, objectName.c_str());
+ }
+ }
+#endif
+ ChangeToObject(gb, num);
+ }
+
+ if (gb.Seen('P'))
+ {
+ // Cancel an object
+ const int objectToCancel = gb.GetIValue();
+ if (objectToCancel >= 0 && objectToCancel < (int)objectsCancelled.MaxBits())
+ {
+ objectsCancelled.SetBit(objectToCancel);
+ if (objectToCancel == currentObjectNumber && !currentObjectCancelled)
+ {
+ StopPrinting(gb);
+ }
+ }
+ }
+ if (gb.Seen('U'))
+ {
+ // Resume an object
+ const int objectToResume = gb.GetIValue();
+ if (objectToResume >= 0 && objectToResume < (int)objectsCancelled.MaxBits())
+ {
+ objectsCancelled.ClearBit(objectToResume);
+ if (objectToResume == currentObjectNumber && currentObjectCancelled)
+ {
+ ResumePrinting(gb);
+ }
+ }
+ }
+ if (gb.Seen('C') && currentObjectNumber >= 0 && currentObjectNumber < (int)objectsCancelled.MaxBits())
+ {
+ // Cancel current object
+ objectsCancelled.SetBit(currentObjectNumber);
+ if (!currentObjectCancelled)
+ {
+ StopPrinting(gb);
+ }
+ }
+ return GCodeResult::ok;
+}
+
+// We are currently printing, but we must now stop because the current object is cancelled
+void ObjectTracker::StopPrinting(GCodeBuffer& gb) noexcept
+{
+ currentObjectCancelled = true;
+ virtualToolNumber = reprap.GetCurrentToolNumber();
+}
+
+// We are currently not printing because the current object was cancelled, but now we need to print again
+void ObjectTracker::ResumePrinting(GCodeBuffer& gb) noexcept
+{
+ currentObjectCancelled = false;
+ printingJustResumed = true;
+ reprap.GetGCodes().SavePosition(rp, gb); // save the position we should be at for the start of the next move
+ if (reprap.GetCurrentToolNumber() != virtualToolNumber) // if the wrong tool is loaded
+ {
+ reprap.GetGCodes().StartToolChange(gb, virtualToolNumber, DefaultToolChangeParam);
+ }
+}
+
+#if TRACK_OBJECT_NAMES
+
+// Create a new entry in the object directory
+void ObjectDirectoryEntry::Init(const char *label) noexcept
+{
+ name = label;
+ x[0] = std::numeric_limits<float>::quiet_NaN();
+}
+
+// Update the min and max object coordinates to include the coordinates passed
+void ObjectDirectoryEntry::UpdateObjectCoordinates(const float coords[]) noexcept
+{
+ if (isnan(x[0]))
+ {
+ x[0] = x[1] = coords[X_AXIS];
+ y[0] = y[1] = coords[Y_AXIS];
+ }
+ else
+ {
+ if (coords[X_AXIS] < x[0])
+ {
+ x[0] = coords[X_AXIS];
+ }
+ else if (coords[X_AXIS] > x[1])
+ {
+ x[1] = coords[X_AXIS];
+ }
+
+ if (coords[Y_AXIS] < y[0])
+ {
+ y[0] = coords[Y_AXIS];
+ }
+ else if (coords[Y_AXIS] > y[1])
+ {
+ y[1] = coords[Y_AXIS];
+ }
+ }
+}
+
+// Update the min and max object coordinates to include the coordinates passed
+// We could pass both the start and end coordinates of the printing move, however it is simpler just to pass the end coordinates.
+// This is OK because it is very unlikely that there won't be a subsequent extruding move that ends close to the original one.
+void ObjectTracker::UpdateObjectCoordinates(const float coords[]) noexcept
+{
+ if (currentObjectNumber >= 0 && currentObjectNumber < (int)numObjects)
+ {
+ objectDirectory[currentObjectNumber].UpdateObjectCoordinates(coords);
+ }
+}
+
+void ObjectTracker::SetObjectName(unsigned int number, const char *label) noexcept
+{
+ bool err = objectNames.GetRef().copy(label);
+ const char * const name = objectNames.LatestCStr();
+ err = err || objectNames.Fix();
+ objectDirectory[number].name = ((err) ? "" : name);
+}
+
+// This is called when we need to create a new named object
+void ObjectTracker::CreateObject(unsigned int number, const char *label) noexcept
+{
+ if (number < MaxTrackedObjects)
+ {
+ while (numObjects <= number)
+ {
+ objectDirectory[numObjects].Init("");
+ ++numObjects;
+ }
+ SetObjectName(number, label);
+ }
+}
+
+// This is called when we have found an object label in a comment
+void ObjectTracker::StartObject(GCodeBuffer& gb, const char *label) noexcept
+{
+ if (!usingM486Naming)
+ {
+ for (size_t i = 0; i < numObjects; ++i)
+ {
+ if (strcmp(objectDirectory[i].name, label) == 0)
+ {
+ ChangeToObject(gb, i);
+ break;
+ }
+ }
+
+ // The object was not found, so add it
+ if (numObjects < MaxTrackedObjects)
+ {
+ const int newObjectNumber = numObjects;
+ CreateObject(newObjectNumber, label);
+ ChangeToObject(gb, newObjectNumber);
+ }
+
+ // Here if the new object won't fit in the directory
+ ChangeToObject(gb, -1);
+ }
+}
+
+// This is called when we have found a "stop printing object" comment
+void ObjectTracker::StopObject(GCodeBuffer& gb) noexcept
+{
+ if (!usingM486Naming)
+ {
+ ChangeToObject(gb, -1);
+ }
+}
+
+#endif
+
+// End