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>2022-10-24 11:48:46 +0300
committerDavid Crocker <dcrocker@eschertech.com>2022-10-24 11:48:46 +0300
commitd4bea3d3c623da8ae91484ab3a87d006e078cabb (patch)
treed6650b8cf3d9667a34cd211f4fd5f47a6b6a3492
parent6a89f63937679797e572807108e9b29245ced400 (diff)
We no longer allow axis letters greater than lowercase 'f'
-rw-r--r--src/CAN/CanInterface.cpp6
-rw-r--r--src/GCodes/GCodeBuffer/BinaryParser.cpp44
-rw-r--r--src/GCodes/GCodeBuffer/BinaryParser.h3
-rw-r--r--src/GCodes/GCodeBuffer/GCodeBuffer.cpp7
-rw-r--r--src/GCodes/GCodeBuffer/GCodeBuffer.h8
-rw-r--r--src/GCodes/GCodeBuffer/StringParser.cpp8
-rw-r--r--src/GCodes/GCodeBuffer/StringParser.h20
-rw-r--r--src/GCodes/GCodes.cpp35
-rw-r--r--src/GCodes/GCodes.h7
-rw-r--r--src/GCodes/GCodes3.cpp3
-rw-r--r--src/Movement/RawMove.h1
-rw-r--r--src/RepRapFirmware.h27
12 files changed, 101 insertions, 68 deletions
diff --git a/src/CAN/CanInterface.cpp b/src/CAN/CanInterface.cpp
index 7e2f6a33..d692c7c7 100644
--- a/src/CAN/CanInterface.cpp
+++ b/src/CAN/CanInterface.cpp
@@ -919,7 +919,7 @@ extern "C" [[noreturn]] void CanReceiverLoop(void *) noexcept
// This one is used by ATE
GCodeResult CanInterface::EnableRemoteDrivers(const CanDriversList& drivers, const StringRef& reply) noexcept
{
- return SetRemoteDriverStates(drivers, reply, DriverStateControl(DriverStateControl::driverActive));
+ return SetRemoteDriverStates(drivers, reply, DriverStateControl(DriverStateControl::driverActive, reprap.GetGCodes().GetMotorBrakeOffDelay()));
}
// This one is used by Prepare and by M17
@@ -932,7 +932,7 @@ void CanInterface::EnableRemoteDrivers(const CanDriversList& drivers) noexcept
// This one is used by ATE
GCodeResult CanInterface::DisableRemoteDrivers(const CanDriversList& drivers, const StringRef& reply) noexcept
{
- return SetRemoteDriverStates(drivers, reply, DriverStateControl(DriverStateControl::driverDisabled));
+ return SetRemoteDriverStates(drivers, reply, DriverStateControl(DriverStateControl::driverDisabled, reprap.GetGCodes().GetMotorBrakeOnDelay()));
}
// This one is used by Prepare
@@ -945,7 +945,7 @@ void CanInterface::DisableRemoteDrivers(const CanDriversList& drivers) noexcept
void CanInterface::SetRemoteDriversIdle(const CanDriversList& drivers, float idleCurrentFactor) noexcept
{
String<1> dummy;
- (void)SetRemoteDriverStates(drivers, dummy.GetRef(), DriverStateControl(DriverStateControl::driverIdle, lrintf(idleCurrentFactor * 100)));
+ (void)SetRemoteDriverStates(drivers, dummy.GetRef(), DriverStateControl(DriverStateControl::driverIdle, (uint16_t)lrintf(idleCurrentFactor * 100) << 4));
}
GCodeResult CanInterface::SetRemoteStandstillCurrentPercent(const CanDriversData<float>& data, const StringRef& reply) noexcept
diff --git a/src/GCodes/GCodeBuffer/BinaryParser.cpp b/src/GCodes/GCodeBuffer/BinaryParser.cpp
index b4508158..fbe0ec4c 100644
--- a/src/GCodes/GCodeBuffer/BinaryParser.cpp
+++ b/src/GCodes/GCodeBuffer/BinaryParser.cpp
@@ -26,6 +26,24 @@ void BinaryParser::Init() noexcept
gb.bufferState = GCodeBufferState::parseNotStarted;
seenParameter = nullptr;
seenParameterValue = nullptr;
+ parametersPresent.Clear();
+ if (bufferLength != 0 && header->numParameters != 0)
+ {
+ const char *parameterStart = reinterpret_cast<const char*>(gb.buffer) + sizeof(CodeHeader);
+ for (size_t i = 0; i < header->numParameters; i++)
+ {
+ const CodeParameter *param = reinterpret_cast<const CodeParameter*>(parameterStart + i * sizeof(CodeParameter));
+ const char paramLetter = param->letter;
+ if (paramLetter >= 'A' && paramLetter <= 'Z')
+ {
+ parametersPresent.SetBit(paramLetter - 'A');
+ }
+ else if (paramLetter >= 'a' && paramLetter <= 'f')
+ {
+ parametersPresent.SetBit(paramLetter - ('a' - 26));
+ }
+ }
+ }
}
// Add an entire binary G-Code, overwriting any existing content
@@ -88,32 +106,6 @@ bool BinaryParser::Seen(char c) noexcept
return false;
}
-// Return true if any of the parameter letters in the bitmap were seen
-bool BinaryParser::SeenAny(Bitmap<uint32_t> bm) const noexcept
-{
- if (bufferLength != 0 && header->numParameters != 0)
- {
- const char *parameterStart = reinterpret_cast<const char*>(gb.buffer) + sizeof(CodeHeader);
- for (size_t i = 0; i < header->numParameters; i++)
- {
- const CodeParameter *param = reinterpret_cast<const CodeParameter*>(parameterStart + i * sizeof(CodeParameter));
- const char paramLetter = param->letter;
- if (paramLetter >= 'A' && paramLetter <= 'Z')
- {
- if (bm.IsBitSet(paramLetter - 'A'))
- {
- return true;
- }
- }
- else if (paramLetter >= 'a' && paramLetter <= 'f' && bm.IsBitSet(paramLetter - ('a' - 26)))
- {
- return true;
- }
- }
- }
- return false;
-}
-
char BinaryParser::GetCommandLetter() const noexcept
{
return (bufferLength != 0) ? header->letter : 'Q';
diff --git a/src/GCodes/GCodeBuffer/BinaryParser.h b/src/GCodes/GCodeBuffer/BinaryParser.h
index 199d1901..76ab98cf 100644
--- a/src/GCodes/GCodeBuffer/BinaryParser.h
+++ b/src/GCodes/GCodeBuffer/BinaryParser.h
@@ -28,7 +28,7 @@ public:
void Put(const uint32_t *data, size_t len) noexcept; // Add an entire binary code, overwriting any existing content
void DecodeCommand() noexcept; // Print the buffer content in debug mode and prepare for execution
bool Seen(char c) noexcept SPEED_CRITICAL; // Is a character present?
- bool SeenAny(Bitmap<uint32_t> bm) const noexcept; // Return true if any of the parameter letters in the bitmap were seen
+ ParameterLettersBitmap AllParameters() const noexcept { return parametersPresent; } // Return the bitmap of all parameters seen
char GetCommandLetter() const noexcept;
bool HasCommandNumber() const noexcept;
@@ -81,6 +81,7 @@ private:
const CodeHeader *header;
int reducedBytesRead;
+ ParameterLettersBitmap parametersPresent;
const CodeParameter *seenParameter;
const char *seenParameterValue;
};
diff --git a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp
index 91a7369c..62b64e19 100644
--- a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp
+++ b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp
@@ -381,7 +381,7 @@ bool GCodeBuffer::IsLaterThan(const GCodeBuffer& other) const noexcept
// If the command was or called a macro then there will be no command in the buffer, so we must return true for this case also.
bool GCodeBuffer::IsLastCommand() const noexcept
{
- return IS_BINARY_OR((bufferState != GCodeBufferState::ready && bufferState != GCodeBufferState::executing) || stringParser.IsLastCommand());
+ return IS_BINARY_OR((bufferState != GCodeBufferState::ready && bufferState != GCodeBufferState::executing) || stringParser.IsLastCommand());
}
bool GCodeBuffer::ContainsExpression() const noexcept
@@ -395,10 +395,9 @@ bool GCodeBuffer::Seen(char c) noexcept
return PARSER_OPERATION(Seen(c));
}
-// Return true if any of the parameter letters in the bitmap were seen
-bool GCodeBuffer::SeenAny(Bitmap<uint32_t> bm) const noexcept
+ParameterLettersBitmap GCodeBuffer::AllParameters() const noexcept
{
- return PARSER_OPERATION(SeenAny(bm));
+ return PARSER_OPERATION(AllParameters());
}
// Test for character present, throw error if not
diff --git a/src/GCodes/GCodeBuffer/GCodeBuffer.h b/src/GCodes/GCodeBuffer/GCodeBuffer.h
index 4fc40cbc..1d653a63 100644
--- a/src/GCodes/GCodeBuffer/GCodeBuffer.h
+++ b/src/GCodes/GCodeBuffer/GCodeBuffer.h
@@ -76,7 +76,11 @@ public:
bool Seen(char c) noexcept SPEED_CRITICAL; // Is a character present?
void MustSee(char c) THROWS(GCodeException); // Test for character present, throw error if not
char MustSee(char c1, char c2) THROWS(GCodeException); // Test for one of two characters present, throw error if not
- inline bool SeenAny(const char *s) const noexcept { return SeenAny(Bitmap<uint32_t>(ParametersToBitmap(s))); }
+ ParameterLettersBitmap AllParameters() const noexcept; // Return a bitmap of all parameters in the command
+ bool SeenAny(ParameterLettersBitmap bm) const noexcept // Return true if any of the parameter letters in the bitmap were seen
+ { return AllParameters().Intersects(bm); }
+ bool SeenAny(const char *s) const noexcept // Return true if any of the parameter letters in the string were seen
+ { return SeenAny(ParameterLettersBitmap(ParametersToBitmap(s))); }
float GetFValue() THROWS(GCodeException) SPEED_CRITICAL; // Get a float after a key letter
float GetPositiveFValue() THROWS(GCodeException) SPEED_CRITICAL; // Get a float after a key letter and check that it is greater than zero
@@ -298,8 +302,6 @@ protected:
DECLARE_OBJECT_MODEL
private:
- bool SeenAny(Bitmap<uint32_t> bm) const noexcept; // Return true if any of the parameter letters in the bitmap were seen
-
// Convert a string of uppercase parameter letters to a bit map
static inline constexpr uint32_t ParametersToBitmap(const char *s) noexcept
{
diff --git a/src/GCodes/GCodeBuffer/StringParser.cpp b/src/GCodes/GCodeBuffer/StringParser.cpp
index f51ae716..35f555fa 100644
--- a/src/GCodes/GCodeBuffer/StringParser.cpp
+++ b/src/GCodes/GCodeBuffer/StringParser.cpp
@@ -1140,7 +1140,7 @@ bool StringParser::Seen(char c) noexcept
{
bit = c - 'A';
}
- if (bit > 31 || !parametersPresent.IsBitSet(c - 'A'))
+ if (bit >= ParameterLettersBitmap::MaxBits() || !parametersPresent.IsBitSet(c - 'A'))
{
return false;
}
@@ -1188,12 +1188,6 @@ bool StringParser::Seen(char c) noexcept
return false;
}
-// Return true if any of the parameter letters in the bitmap were seen
-bool StringParser::SeenAny(Bitmap<uint32_t> bm) const noexcept
-{
- return parametersPresent.Intersects(bm);
-}
-
// Get a float after a G Code letter found by a call to Seen()
float StringParser::GetFValue() THROWS(GCodeException)
{
diff --git a/src/GCodes/GCodeBuffer/StringParser.h b/src/GCodes/GCodeBuffer/StringParser.h
index 5c9953f8..e3686506 100644
--- a/src/GCodes/GCodeBuffer/StringParser.h
+++ b/src/GCodes/GCodeBuffer/StringParser.h
@@ -44,15 +44,15 @@ public:
bool IsLastCommand() const noexcept;
bool ContainsExpression() const noexcept { return seenExpression; }
- bool Seen(char c) noexcept SPEED_CRITICAL; // Is a character present?
- bool SeenAny(Bitmap<uint32_t> bm) const noexcept; // Return true if any of the parameter letters in the bitmap were seen
- float GetFValue() THROWS(GCodeException) SPEED_CRITICAL; // Get a float after a key letter
- float GetDistance() THROWS(GCodeException) SPEED_CRITICAL; // Get a distance or coordinate and convert it from inches to mm if necessary
- int32_t GetIValue() THROWS(GCodeException) SPEED_CRITICAL; // Get an integer after a key letter
- uint32_t GetUIValue() THROWS(GCodeException); // Get an unsigned integer value
- DriverId GetDriverId() THROWS(GCodeException); // Get a driver ID
- void GetIPAddress(IPAddress& returnedIp) THROWS(GCodeException); // Get an IP address quad after a key letter
- void GetMacAddress(MacAddress& mac) THROWS(GCodeException); // Get a MAC address sextet after a key letter
+ bool Seen(char c) noexcept SPEED_CRITICAL; // Is a character present?
+ ParameterLettersBitmap AllParameters() const noexcept { return parametersPresent; } // Return the bitmap of all parameters seen
+ float GetFValue() THROWS(GCodeException) SPEED_CRITICAL; // Get a float after a key letter
+ float GetDistance() THROWS(GCodeException) SPEED_CRITICAL; // Get a distance or coordinate and convert it from inches to mm if necessary
+ int32_t GetIValue() THROWS(GCodeException) SPEED_CRITICAL; // Get an integer after a key letter
+ uint32_t GetUIValue() THROWS(GCodeException); // Get an unsigned integer value
+ DriverId GetDriverId() THROWS(GCodeException); // Get a driver ID
+ void GetIPAddress(IPAddress& returnedIp) THROWS(GCodeException); // Get an IP address quad after a key letter
+ void GetMacAddress(MacAddress& mac) THROWS(GCodeException); // Get a MAC address sextet after a key letter
void GetUnprecedentedString(const StringRef& str, bool allowEmpty) THROWS(GCodeException); // Get a string with no preceding key letter
void GetCompleteParameters(const StringRef& str) const noexcept; // Get the complete parameter string
void GetQuotedString(const StringRef& str, bool allowEmpty) THROWS(GCodeException); // Get and copy a quoted string
@@ -135,7 +135,7 @@ private:
unsigned int commandLength; // Number of characters we read to build this command including the final \r or \n
unsigned int braceCount; // how many nested { } we are inside
unsigned int gcodeLineEnd; // Number of characters in the entire line of gcode
- Bitmap<uint32_t> parametersPresent; // which parameters are present in this command
+ ParameterLettersBitmap parametersPresent; // which parameters are present in this command
int readPointer; // Where in the buffer to read next, or -1
FileStore *fileBeingWritten; // If we are copying GCodes to a file, which file it is
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index e3902540..6d5d58e0 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -174,6 +174,9 @@ void GCodes::Init() noexcept
axisLetters[0] = 'X';
axisLetters[1] = 'Y';
axisLetters[2] = 'Z';
+#if SUPPORT_ASYNC_MOVES
+ allAxisLetters = ParameterLettersBitmap((1u << ('X'-'A')) | (1u << ('Y'-'A')) | (1u << ('Z'-'A')));
+#endif
numExtruders = 0;
@@ -1603,6 +1606,7 @@ bool GCodes::LockMovementSystemAndWaitForStandstill(GCodeBuffer& gb, unsigned in
// Release the axes and extruders that this movement system owns
axesAndExtrudersMoved.ClearBits(ownedAxes);
moveStates[msNumber].axesAndExtrudersOwned.Clear();
+ ms.ownedAxisLetters.Clear();
#else
UpdateCurrentUserPosition(gb);
#endif
@@ -1833,6 +1837,18 @@ bool GCodes::CheckEnoughAxesHomed(AxesBitmap axesToMove) noexcept
bool GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated) THROWS(GCodeException)
{
MovementState& ms = GetMovementState(gb);
+
+#if SUPPORT_ASYNC_MOVES
+ // We need to check for moving unowned axes right at the start in case we need to fetch axis positions before processing the command
+ ParameterLettersBitmap axisLettersMentioned = gb.AllParameters() & allAxisLetters;
+ axisLettersMentioned.ClearBits(ms.ownedAxisLetters);
+ if (axisLettersMentioned.IsNonEmpty())
+ {
+ //TODO problem! this ignores axis mapping and coordinate rotation!!!
+ AllocateAxisLetters(gb, ms, axisLettersMentioned);
+ }
+#endif
+
if (ms.moveFractionToSkip > 0.0)
{
ms.initialUserC0 = ms.restartInitialUserC0;
@@ -4910,7 +4926,7 @@ const MovementState& GCodes::GetCurrentMovementState(const ObjectExplorationCont
return GetConstMovementState(*gb);
}
-// Allocate an axis to a movement state returning true if successful, false if another movement state owns it already
+// Allocate additional axes and/or extruders to a movement state returning true if successful, false if another movement state owns it already
// This relies on cooperative scheduling between different GCodeBuffer objects
void GCodes::AllocateAxes(const GCodeBuffer& gb, MovementState& ms, AxesBitmap axes) THROWS(GCodeException)
{
@@ -4922,6 +4938,23 @@ void GCodes::AllocateAxes(const GCodeBuffer& gb, MovementState& ms, AxesBitmap a
ms.axesAndExtrudersOwned |= axes;
}
+// Allocate additional axes by letter
+void GCodes::AllocateAxisLetters(const GCodeBuffer& gb, MovementState& ms, ParameterLettersBitmap axLetters) THROWS(GCodeException)
+{
+ AxesBitmap newAxes;
+ for (size_t axis = 0; axis < numVisibleAxes; ++axis)
+ {
+ const char c = axisLetters[axis];
+ const unsigned int axisLetterBit = (c >= 'a') ? c - ('a' - 26) : c - 'A';
+ if (axLetters.IsBitSet(axisLetterBit))
+ {
+ newAxes.SetBit(axis);
+ }
+ }
+ AllocateAxes(gb, ms, newAxes);
+ ms.ownedAxisLetters |= axLetters;
+}
+
// Synchronise motion systems and update user coordinates.
// Return true if synced, false if we need to wait longer.
bool GCodes::SyncWith(GCodeBuffer& thisGb, const GCodeBuffer& otherGb) noexcept
diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h
index 1b37f38c..c5118440 100644
--- a/src/GCodes/GCodes.h
+++ b/src/GCodes/GCodes.h
@@ -190,6 +190,8 @@ public:
bool LockMovementSystemAndWaitForStandstill(GCodeBuffer& gb, unsigned int msNumber) noexcept; // Lock a movement system and wait for pending moves to finish
bool LockCurrentMovementSystemAndWaitForStandstill(GCodeBuffer& gb) noexcept; // Lock movement and wait for pending moves to finish
bool LockAllMovementSystemsAndWaitForStandstill(GCodeBuffer& gb) noexcept; // Lock movement and wait for all motion systems to reach standstill
+ uint16_t GetMotorBrakeOnDelay() const noexcept { return 200; } // Get the delay between brake on and motors off, in milliseconds TODO make this configurable
+ uint16_t GetMotorBrakeOffDelay() const noexcept { return 25; } // Get the delay between motors on and brake off, in milliseconds
#if SUPPORT_DIRECT_LCD
void SetPrimarySpeedFactor(float factor) noexcept; // Set the speed factor
@@ -553,6 +555,8 @@ private:
GCodeResult SyncMovementSystems(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException); // Handle M598
GCodeResult ExecuteM400(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeException); // Handle M400
void AllocateAxes(const GCodeBuffer& gb, MovementState& ms, AxesBitmap axes) THROWS(GCodeException); // allocate axes to a movement state
+ void AllocateAxisLetters(const GCodeBuffer& gb, MovementState& ms, ParameterLettersBitmap axLetters) THROWS(GCodeException);
+ // allocate axes by letter
bool DoSync(GCodeBuffer& gb) noexcept; // sync with the other stream returning true if done, false if we need to wait for it
bool SyncWith(GCodeBuffer& thisGb, const GCodeBuffer& otherGb) noexcept; // synchronise motion systems
void UpdateAllCoordinates(GCodeBuffer& gb) noexcept;
@@ -647,6 +651,9 @@ private:
FileData fileToPrint; // The next file to print
#endif
+#if SUPPORT_ASYNC_MOVES
+ ParameterLettersBitmap allAxisLetters; // Which axis letters are in use
+#endif
char axisLetters[MaxAxes + 1]; // The names of the axes, with a null terminator
bool limitAxes; // Don't think outside the box
bool noMovesBeforeHoming; // Don't allow movement prior to homing the associates axes
diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp
index d91df708..779043fb 100644
--- a/src/GCodes/GCodes3.cpp
+++ b/src/GCodes/GCodes3.cpp
@@ -477,6 +477,9 @@ GCodeResult GCodes::DoDriveMapping(GCodeBuffer& gb, const StringRef& reply) THRO
{
// We are creating a new axis
axisLetters[drive] = c; // assign the drive to this drive letter
+#if SUPPORT_ASYNC_MOVES
+ allAxisLetters.SetBit((c >= 'a') ? c - ('a' - 26) : c - 'A'); // update the map of all parameters that can be axis letters
+#endif
const AxisWrapType wrapType = (newAxesType != AxisWrapType::undefined) ? newAxesType
: (c >= 'A' && c <= 'D') ? AxisWrapType::wrapAt360 // default A thru D to rotational but not continuous
: AxisWrapType::noWrap; // default other axes to linear
diff --git a/src/Movement/RawMove.h b/src/Movement/RawMove.h
index adec7b08..99b11d1b 100644
--- a/src/Movement/RawMove.h
+++ b/src/Movement/RawMove.h
@@ -80,6 +80,7 @@ struct MovementState : public RawMove
{
Tool *currentTool; // the current tool of this movement system
AxesBitmap axesAndExtrudersOwned; // axes and extruders that this movement system has moved since the last sync
+ ParameterLettersBitmap ownedAxisLetters; // letters denoting axes that this movement system owns
// The current user position now holds the requested user position after applying workplace coordinate offsets.
// So we must subtract the workplace coordinate offsets when we want to display them.
diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h
index c2845247..a994f734 100644
--- a/src/RepRapFirmware.h
+++ b/src/RepRapFirmware.h
@@ -318,25 +318,26 @@ class ExpansionManager;
// Define floating point type to use for calculations where we would like high precision in matrix calculations
#if SAME70
-typedef double floatc_t; // type of matrix element used for calibration
+typedef double floatc_t; // type of matrix element used for calibration
#else
-// We are more memory-constrained on the other processors and they don't support double precision
-typedef float floatc_t; // type of matrix element used for calibration
+// We are more memory-constrained on the other processors and they don't support double precision in hardware
+typedef float floatc_t; // type of matrix element used for calibration
#endif
#if defined(DUET3) || defined(DUET3MINI)
-typedef Bitmap<uint32_t> AxesBitmap; // Type of a bitmap representing a set of axes, and sometimes extruders too
+typedef Bitmap<uint32_t> AxesBitmap; // Type of a bitmap representing a set of axes, and sometimes extruders too
#else
-typedef Bitmap<uint16_t> AxesBitmap; // Type of a bitmap representing a set of axes, and sometimes extruders too
+typedef Bitmap<uint16_t> AxesBitmap; // Type of a bitmap representing a set of axes, and sometimes extruders too
#endif
-typedef Bitmap<uint32_t> ExtrudersBitmap; // Type of a bitmap representing a set of extruder drive numbers
-typedef Bitmap<uint32_t> DriversBitmap; // Type of a bitmap representing a set of local driver numbers
-typedef Bitmap<uint32_t> FansBitmap; // Type of a bitmap representing a set of fan numbers
-typedef Bitmap<uint32_t> HeatersBitmap; // Type of a bitmap representing a set of heater numbers
-typedef Bitmap<uint16_t> DriverChannelsBitmap; // Type of a bitmap representing a set of drivers that typically have a common cooling fan
-typedef Bitmap<uint32_t> InputPortsBitmap; // Type of a bitmap representing a set of input ports
-typedef Bitmap<uint32_t> TriggerNumbersBitmap; // Type of a bitmap representing a set of trigger numbers
-typedef Bitmap<uint64_t> ToolNumbersBitmap; // Type of a bitmap representing a set of tool numbers
+typedef Bitmap<uint32_t> ExtrudersBitmap; // Type of a bitmap representing a set of extruder drive numbers
+typedef Bitmap<uint32_t> DriversBitmap; // Type of a bitmap representing a set of local driver numbers
+typedef Bitmap<uint32_t> FansBitmap; // Type of a bitmap representing a set of fan numbers
+typedef Bitmap<uint32_t> HeatersBitmap; // Type of a bitmap representing a set of heater numbers
+typedef Bitmap<uint16_t> DriverChannelsBitmap; // Type of a bitmap representing a set of drivers that typically have a common cooling fan
+typedef Bitmap<uint32_t> InputPortsBitmap; // Type of a bitmap representing a set of input ports
+typedef Bitmap<uint32_t> TriggerNumbersBitmap; // Type of a bitmap representing a set of trigger numbers
+typedef Bitmap<uint64_t> ToolNumbersBitmap; // Type of a bitmap representing a set of tool numbers
+typedef Bitmap<uint32_t> ParameterLettersBitmap; // Type of a bitmap representing a set of parameter letters in A..Z and a..f
#if defined(DUET3) || defined(DUET3MINI)
typedef Bitmap<uint64_t> SensorsBitmap;