diff options
Diffstat (limited to 'src/GCodes')
-rw-r--r-- | src/GCodes/GCodeBuffer/BinaryParser.cpp | 198 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/BinaryParser.h | 17 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/ExpressionParser.cpp | 99 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/ExpressionParser.h | 11 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/GCodeBuffer.cpp | 101 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/GCodeBuffer.h | 18 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/StringParser.cpp | 137 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/StringParser.h | 21 | ||||
-rw-r--r-- | src/GCodes/GCodeMachineState.cpp | 2 | ||||
-rw-r--r-- | src/GCodes/GCodeQueue.cpp | 10 | ||||
-rw-r--r-- | src/GCodes/GCodes.cpp | 60 | ||||
-rw-r--r-- | src/GCodes/GCodes2.cpp | 96 | ||||
-rw-r--r-- | src/GCodes/GCodes3.cpp | 16 | ||||
-rw-r--r-- | src/GCodes/GCodes4.cpp | 24 | ||||
-rw-r--r-- | src/GCodes/RestorePoint.cpp | 4 |
15 files changed, 475 insertions, 339 deletions
diff --git a/src/GCodes/GCodeBuffer/BinaryParser.cpp b/src/GCodes/GCodeBuffer/BinaryParser.cpp index de4b7b02..1b6d3398 100644 --- a/src/GCodes/GCodeBuffer/BinaryParser.cpp +++ b/src/GCodes/GCodeBuffer/BinaryParser.cpp @@ -88,6 +88,25 @@ 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' && bm.IsBitSet(paramLetter - 'A')) + { + return true; + } + } + } + return false; +} + char BinaryParser::GetCommandLetter() const noexcept { return (bufferLength != 0) ? header->letter : 'Q'; @@ -455,19 +474,58 @@ void BinaryParser::GetPossiblyQuotedString(const StringRef& str, bool allowEmpty } } -void BinaryParser::GetFloatArray(float arr[], size_t& length, bool doPad) THROWS(GCodeException) +void BinaryParser::GetFloatArray(float arr[], size_t& length) THROWS(GCodeException) { - GetArray(arr, length, doPad, DataType::Float); + if (seenParameter == nullptr) + { + THROW_INTERNAL_ERROR; + } + + if (seenParameter->type == DataType::Expression) + { + ExpressionParser parser(gb, seenParameterValue, seenParameterValue + seenParameter->intValue, -1); + parser.ParseFloatArray(arr, length); + } + else + { + GetArray(arr, length); + } } -void BinaryParser::GetIntArray(int32_t arr[], size_t& length, bool doPad) THROWS(GCodeException) +void BinaryParser::GetIntArray(int32_t arr[], size_t& length) THROWS(GCodeException) { - GetArray(arr, length, doPad, DataType::Int); + if (seenParameter == nullptr) + { + THROW_INTERNAL_ERROR; + } + + if (seenParameter->type == DataType::Expression) + { + ExpressionParser parser(gb, seenParameterValue, seenParameterValue + seenParameter->intValue, -1); + parser.ParseIntArray(arr, length); + } + else + { + GetArray(arr, length); + } } -void BinaryParser::GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad) THROWS(GCodeException) +void BinaryParser::GetUnsignedArray(uint32_t arr[], size_t& length) THROWS(GCodeException) { - GetArray(arr, length, doPad, DataType::UInt); + if (seenParameter == nullptr) + { + THROW_INTERNAL_ERROR; + } + + if (seenParameter->type == DataType::Expression) + { + ExpressionParser parser(gb, seenParameterValue, seenParameterValue + seenParameter->intValue, -1); + parser.ParseUnsignedArray(arr, length); + } + else + { + GetArray(arr, length); + } } // Get a :-separated list of drivers after a key letter @@ -499,15 +557,12 @@ void BinaryParser::GetDriverIdArray(DriverId arr[], size_t& length) THROWS(GCode break; case DataType::Expression: - { - float temp[seenParameter->intValue]; - GetArray(temp, length, false, DataType::Float); - for (int i = 0; i < seenParameter->intValue; i++) { - SetDriverIdFromBinary(arr[i], temp[i]); + ExpressionParser parser(gb, seenParameterValue, seenParameterValue + seenParameter->intValue, -1); + parser.ParseDriverIdArray(arr, length); + parser.CheckForExtraCharacters(); } break; - } default: length = 0; @@ -573,13 +628,8 @@ void BinaryParser::AppendFullCommand(const StringRef &s) const noexcept } } -template<typename T> void BinaryParser::GetArray(T arr[], size_t& length, bool doPad, DataType type) THROWS(GCodeException) +template<typename T> void BinaryParser::GetArray(T arr[], size_t& length) THROWS(GCodeException) { - if (seenParameter == nullptr) - { - THROW_INTERNAL_ERROR; - } - int lastIndex = -1; switch (seenParameter->type) { @@ -627,122 +677,12 @@ template<typename T> void BinaryParser::GetArray(T arr[], size_t& length, bool d lastIndex = seenParameter->intValue - 1; break; - case DataType::Expression: - { - const char *pos = seenParameterValue, *endPos = seenParameterValue + seenParameter->intValue; - - // Check if the whole expression is encapsulated in curly braces and remove them if necessary - if (*pos == '{' && pos != endPos) - { - bool isEncapsulated = true, inQuotes = false; - size_t numBraces = 1; - for (const char *str = pos + 1; str < endPos; str++) - { - if (inQuotes) - { - inQuotes = (*str != '"'); - } - else if (*str == '"') - { - inQuotes = true; - } - else if (*str == '{') - { - numBraces++; - } - else if (*str == '}') - { - numBraces--; - if (numBraces == 0) - { - const char *curPos = str; - while (str != endPos && strchr("\t ", *++str) != nullptr) { } - if (str == endPos) - { - endPos = curPos + 1; - } - else - { - isEncapsulated = false; - } - break; - } - } - } - - if (isEncapsulated) - { - pos++; - endPos--; - } - } - - // Read array expression - for (;;) - { - if (lastIndex >= (int)length) - { - throw ConstructParseException("array too long, max length = %u", (uint32_t)length); - } - - // Read the next expression value - ExpressionParser parser(gb, pos, endPos, -1); - switch (type) - { - case DataType::Int: - arr[++lastIndex] = (T)parser.ParseInteger(); - break; - - case DataType::UInt: - arr[++lastIndex] = (T)parser.ParseUnsigned(); - break; - - case DataType::Float: - arr[++lastIndex] = (T)parser.ParseFloat(); - break; - - default: - throw ConstructParseException("Unsupported array data type"); - } - parser.CheckForExtraCharacters(true); - pos = parser.GetEndptr(); - - if (pos++ >= endPos) - { - break; - } - } - - if (doPad && lastIndex == 0) - { - for (size_t i = 1; i < length; i++) - { - arr[i] = arr[0]; - } - } - else - { - length = lastIndex + 1; - } - break; - } - default: length = 0; return; } - if (doPad && lastIndex == 0) - { - for (size_t i = 1; i < length; i++) - { - arr[i] = arr[0]; - } - } - else - { - length = lastIndex + 1; - } + length = lastIndex + 1; } void BinaryParser::CheckArrayLength(size_t maxLength) THROWS(GCodeException) diff --git a/src/GCodes/GCodeBuffer/BinaryParser.h b/src/GCodes/GCodeBuffer/BinaryParser.h index 3495d9c8..adb2286b 100644 --- a/src/GCodes/GCodeBuffer/BinaryParser.h +++ b/src/GCodes/GCodeBuffer/BinaryParser.h @@ -24,10 +24,11 @@ class BinaryParser { public: BinaryParser(GCodeBuffer& gcodeBuffer) noexcept; - void Init() noexcept; // Set it up to parse another G-code - 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? + void Init() noexcept; // Set it up to parse another G-code + 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 char GetCommandLetter() const noexcept; bool HasCommandNumber() const noexcept; @@ -45,9 +46,9 @@ public: void GetCompleteParameters(const StringRef& str) THROWS(GCodeException); // Get the complete parameter string void GetQuotedString(const StringRef& str, bool allowEmpty) THROWS(GCodeException); // Get and copy a quoted string void GetPossiblyQuotedString(const StringRef& str, bool allowEmpty) THROWS(GCodeException); // Get and copy a string which may or may not be quoted - void GetFloatArray(float arr[], size_t& length, bool doPad) THROWS(GCodeException) SPEED_CRITICAL; // Get a colon-separated list of floats after a key letter - void GetIntArray(int32_t arr[], size_t& length, bool doPad) THROWS(GCodeException); // Get a :-separated list of ints after a key letter - void GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad) THROWS(GCodeException); // Get a :-separated list of unsigned ints after a key letter + void GetFloatArray(float arr[], size_t& length) THROWS(GCodeException) SPEED_CRITICAL; // Get a colon-separated list of floats after a key letter + void GetIntArray(int32_t arr[], size_t& length) THROWS(GCodeException); // Get a :-separated list of ints after a key letter + void GetUnsignedArray(uint32_t arr[], size_t& length) THROWS(GCodeException); // Get a :-separated list of unsigned ints after a key letter void GetDriverIdArray(DriverId arr[], size_t& length) THROWS(GCodeException); // Get a :-separated list of drivers after a key letter void SetFinished() noexcept; // Set the G Code finished @@ -72,7 +73,7 @@ private: GCodeException ConstructParseException(const char *str, uint32_t param) const noexcept; size_t AddPadding(size_t bytesRead) const noexcept { return (bytesRead + 3u) & (~3u); } - template<typename T> void GetArray(T arr[], size_t& length, bool doPad, DataType type) THROWS(GCodeException) SPEED_CRITICAL; + template<typename T> void GetArray(T arr[], size_t& length) THROWS(GCodeException) SPEED_CRITICAL; void WriteParameters(const StringRef& s, bool quoteStrings) const noexcept; size_t bufferLength; diff --git a/src/GCodes/GCodeBuffer/ExpressionParser.cpp b/src/GCodes/GCodeBuffer/ExpressionParser.cpp index 0e3ac432..0c65a39c 100644 --- a/src/GCodes/GCodeBuffer/ExpressionParser.cpp +++ b/src/GCodes/GCodeBuffer/ExpressionParser.cpp @@ -560,6 +560,60 @@ uint32_t ExpressionParser::ParseUnsigned() THROWS(GCodeException) } } +DriverId ExpressionParser::ParseDriverId() THROWS(GCodeException) +{ + ExpressionValue val = Parse(); + ConvertToDriverId(val, true); + return val.GetDriverIdValue(); +} + +void ExpressionParser::ParseArray(size_t& length, function_ref<void(size_t index)> processElement) THROWS(GCodeException) +{ + size_t numElements = 0; + AdvancePointer(); // skip the '{' + while (numElements < length) + { + processElement(numElements); + ++numElements; + if (CurrentCharacter() != ',') + { + break; + } + if (numElements == length) + { + ThrowParseException("Array too long"); + } + AdvancePointer(); // skip the '{' + } + if (CurrentCharacter() != '}') + { + ThrowParseException("Expected '}'"); + } + AdvancePointer(); // skip the '{' + length = numElements; +} + +// This is called when we expect a non-empty float array parameter and we have encountered (but not skipped) '{' +void ExpressionParser::ParseFloatArray(float arr[], size_t& length) THROWS(GCodeException) +{ + ParseArray(length, [this, &arr](size_t index) { arr[index] = ParseFloat(); }); +} + +void ExpressionParser::ParseIntArray(int32_t arr[], size_t& length) THROWS(GCodeException) +{ + ParseArray(length, [this, &arr](size_t index) { arr[index] = ParseInteger(); }); +} + +void ExpressionParser::ParseUnsignedArray(uint32_t arr[], size_t& length) THROWS(GCodeException) +{ + ParseArray(length, [this, &arr](size_t index) { arr[index] = ParseUnsigned(); }); +} + +void ExpressionParser::ParseDriverIdArray(DriverId arr[], size_t& length) THROWS(GCodeException) +{ + ParseArray(length, [this, &arr](size_t index) { arr[index] = ParseDriverId(); }); +} + void ExpressionParser::BalanceNumericTypes(ExpressionValue& val1, ExpressionValue& val2, bool evaluate) const THROWS(GCodeException) { // First convert any Uint64 or Uint32 operands to float @@ -704,6 +758,51 @@ void ExpressionParser::ConvertToString(ExpressionValue& val, bool evaluate) noex } } +void ExpressionParser::ConvertToDriverId(ExpressionValue& val, bool evaluate) const THROWS(GCodeException) +{ + switch (val.GetType()) + { + case TypeCode::DriverId: + break; + + case TypeCode::Int32: +#if SUPPORT_CAN_EXPANSION + val.Set(DriverId(0, val.uVal)); +#else + val.Set(DriverId(val.uVal)); +#endif + break; + + case TypeCode::Float: + { + const float f10val = 10.0 * val.fVal; + const int32_t ival = lrintf(f10val); +#if SUPPORT_CAN_EXPANSION + if (ival >= 0 && fabsf(f10val - (float)ival) <= 0.002) + { + val.Set(ival/10, ival % 10); + } +#else + if (ival >= 0 && ival < 10 && fabsf(f10val - (float)ival) <= 0.002) + { + val.Set(0, ival % 10); + } +#endif + else + { + ThrowParseException("invalid driver ID"); + } + } + break; + + default: + if (evaluate) + { + ThrowParseException("expected driver ID"); + } + } +} + void ExpressionParser::SkipWhiteSpace() noexcept { char c; diff --git a/src/GCodes/GCodeBuffer/ExpressionParser.h b/src/GCodes/GCodeBuffer/ExpressionParser.h index bfd4de4e..adfff7c7 100644 --- a/src/GCodes/GCodeBuffer/ExpressionParser.h +++ b/src/GCodes/GCodeBuffer/ExpressionParser.h @@ -24,6 +24,13 @@ public: float ParseFloat() THROWS(GCodeException); int32_t ParseInteger() THROWS(GCodeException); uint32_t ParseUnsigned() THROWS(GCodeException); + DriverId ParseDriverId() THROWS(GCodeException); + + // These 4 functions may be removed when we support array-valued expressions more generally + void ParseFloatArray(float arr[], size_t& length) THROWS(GCodeException); + void ParseIntArray(int32_t arr[], size_t& length) THROWS(GCodeException); + void ParseUnsignedArray(uint32_t arr[], size_t& length) THROWS(GCodeException); + void ParseDriverIdArray(DriverId arr[], size_t& length) THROWS(GCodeException); void SkipWhiteSpace() noexcept; void CheckForExtraCharacters(bool isArrayExpression = false) THROWS(GCodeException); @@ -41,11 +48,15 @@ private: void __attribute__((noinline)) ParseIdentifierExpression(ExpressionValue& rslt, bool evaluate, bool applyLengthOperator, bool applyExists) THROWS(GCodeException) pre(readPointer >= 0; isalpha(gb.buffer[readPointer])); void __attribute__((noinline)) ParseQuotedString(ExpressionValue& rslt) THROWS(GCodeException); + + void ParseArray(size_t& length, function_ref<void(size_t index)> processElement) THROWS(GCodeException); + void GetVariableValue(ExpressionValue& rslt, const VariableSet *vars, const char *name, bool parameter, bool wantExists) THROWS(GCodeException); void ConvertToFloat(ExpressionValue& val, bool evaluate) const THROWS(GCodeException); void ConvertToBool(ExpressionValue& val, bool evaluate) const THROWS(GCodeException); void ConvertToString(ExpressionValue& val, bool evaluate) noexcept; + void ConvertToDriverId(ExpressionValue& val, bool evaluate) const THROWS(GCodeException); void CheckStack(uint32_t calledFunctionStackUsage) const THROWS(GCodeException); diff --git a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp index 37e616c2..bc607448 100644 --- a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp +++ b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp @@ -19,6 +19,7 @@ #include <GCodes/GCodeException.h> #include <Platform/RepRap.h> #include <Platform/Platform.h> +#include <Movement/StepTimer.h> // Macros to reduce the amount of explicit conditional compilation in this file #if HAS_LINUX_INTERFACE @@ -49,17 +50,17 @@ constexpr ObjectModelTableEntry GCodeBuffer::objectModelTable[] = { // Within each group, these entries must be in alphabetical order // 0. inputs[] root - { "axesRelative", OBJECT_MODEL_FUNC((bool)self->machineState->axesRelative), ObjectModelEntryFlags::none }, - { "compatibility", OBJECT_MODEL_FUNC(self->machineState->compatibility.ToString()), ObjectModelEntryFlags::none }, - { "distanceUnit", OBJECT_MODEL_FUNC((self->machineState->usingInches) ? "inch" : "mm"), ObjectModelEntryFlags::none }, - { "drivesRelative", OBJECT_MODEL_FUNC((bool)self->machineState->drivesRelative), ObjectModelEntryFlags::none }, - { "feedRate", OBJECT_MODEL_FUNC(self->machineState->feedRate, 1), ObjectModelEntryFlags::live }, - { "inMacro", OBJECT_MODEL_FUNC((bool)self->machineState->doingFileMacro), ObjectModelEntryFlags::none }, - { "lineNumber", OBJECT_MODEL_FUNC((int32_t)self->GetLineNumber()), ObjectModelEntryFlags::live }, - { "name", OBJECT_MODEL_FUNC(self->codeChannel.ToString()), ObjectModelEntryFlags::none }, - { "stackDepth", OBJECT_MODEL_FUNC((int32_t)self->GetStackDepth()), ObjectModelEntryFlags::none }, - { "state", OBJECT_MODEL_FUNC(self->GetStateText()), ObjectModelEntryFlags::live }, - { "volumetric", OBJECT_MODEL_FUNC((bool)self->machineState->volumetricExtrusion), ObjectModelEntryFlags::none }, + { "axesRelative", OBJECT_MODEL_FUNC((bool)self->machineState->axesRelative), ObjectModelEntryFlags::none }, + { "compatibility", OBJECT_MODEL_FUNC(self->machineState->compatibility.ToString()), ObjectModelEntryFlags::none }, + { "distanceUnit", OBJECT_MODEL_FUNC(self->GetDistanceUnits()), ObjectModelEntryFlags::none }, + { "drivesRelative", OBJECT_MODEL_FUNC((bool)self->machineState->drivesRelative), ObjectModelEntryFlags::none }, + { "feedRate", OBJECT_MODEL_FUNC(InverseConvertSpeedToMmPerSec(self->machineState->feedRate), 1), ObjectModelEntryFlags::live }, + { "inMacro", OBJECT_MODEL_FUNC((bool)self->machineState->doingFileMacro), ObjectModelEntryFlags::none }, + { "lineNumber", OBJECT_MODEL_FUNC((int32_t)self->GetLineNumber()), ObjectModelEntryFlags::live }, + { "name", OBJECT_MODEL_FUNC(self->codeChannel.ToString()), ObjectModelEntryFlags::none }, + { "stackDepth", OBJECT_MODEL_FUNC((int32_t)self->GetStackDepth()), ObjectModelEntryFlags::none }, + { "state", OBJECT_MODEL_FUNC(self->GetStateText()), ObjectModelEntryFlags::live }, + { "volumetric", OBJECT_MODEL_FUNC((bool)self->machineState->volumetricExtrusion), ObjectModelEntryFlags::none }, }; constexpr uint8_t GCodeBuffer::objectModelTableDescriptor[] = { 1, 11 }; @@ -344,6 +345,12 @@ 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 +{ + return PARSER_OPERATION(SeenAny(bm)); +} + // Test for character present, throw error if not void GCodeBuffer::MustSee(char c) THROWS(GCodeException) { @@ -388,6 +395,24 @@ float GCodeBuffer::GetDistance() THROWS(GCodeException) return ConvertDistance(GetFValue()); } +// Get a speed in mm/min or inches/min and convert it to mm/step_clock +float GCodeBuffer::GetSpeed() THROWS(GCodeException) +{ + return ConvertSpeed(GetFValue()); +} + +// Get a speed in mm/min mm/sec and convert it to mm/step_clock +float GCodeBuffer::GetSpeedFromMm(bool useSeconds) THROWS(GCodeException) +{ + return ConvertSpeedFromMm(GetFValue(), useSeconds); +} + +// Get an acceleration in mm/sec^2 and convert it to mm/step_clock^2 +float GCodeBuffer::GetAcceleration() THROWS(GCodeException) +{ + return ConvertAcceleration(GetFValue()); +} + // Get an integer after a key letter int32_t GCodeBuffer::GetIValue() THROWS(GCodeException) { @@ -482,19 +507,46 @@ void GCodeBuffer::GetReducedString(const StringRef& str) THROWS(GCodeException) // Get a colon-separated list of floats after a key letter void GCodeBuffer::GetFloatArray(float arr[], size_t& length, bool doPad) THROWS(GCodeException) { - PARSER_OPERATION(GetFloatArray(arr, length, doPad)); + const size_t maxLength = length; + PARSER_OPERATION(GetFloatArray(arr, length)); + // If there is one entry and doPad is true, fill the rest of the array with the first entry. + if (doPad && length == 1) + { + while (length < maxLength) + { + arr[length++] = arr[0]; + } + } } // Get a :-separated list of ints after a key letter void GCodeBuffer::GetIntArray(int32_t arr[], size_t& length, bool doPad) THROWS(GCodeException) { - PARSER_OPERATION(GetIntArray(arr, length, doPad)); + const size_t maxLength = length; + PARSER_OPERATION(GetIntArray(arr, length)); + // If there is one entry and doPad is true, fill the rest of the array with the first entry. + if (doPad && length == 1) + { + while (length < maxLength) + { + arr[length++] = arr[0]; + } + } } // Get a :-separated list of unsigned ints after a key letter void GCodeBuffer::GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad) THROWS(GCodeException) { - PARSER_OPERATION(GetUnsignedArray(arr, length, doPad)); + const size_t maxLength = length; + PARSER_OPERATION(GetUnsignedArray(arr, length)); + // If there is one entry and doPad is true, fill the rest of the array with the first entry. + if (doPad && length == 1) + { + while (length < maxLength) + { + arr[length++] = arr[0]; + } + } } // Get a :-separated list of drivers after a key letter @@ -727,13 +779,30 @@ GCodeMachineState& GCodeBuffer::CurrentFileMachineState() const noexcept // Convert from inches to mm if necessary float GCodeBuffer::ConvertDistance(float distance) const noexcept { - return (machineState->usingInches) ? distance * InchToMm : distance; + return (UsingInches()) ? distance * InchToMm : distance; } // Convert from mm to inches if necessary float GCodeBuffer::InverseConvertDistance(float distance) const noexcept { - return (machineState->usingInches) ? distance/InchToMm : distance; + return (UsingInches()) ? distance/InchToMm : distance; +} + +// Convert speed from mm/min or inches/min to mm per step clock +float GCodeBuffer::ConvertSpeed(float speed) const noexcept +{ + return speed * ((UsingInches()) ? InchToMm/(StepClockRate * iMinutesToSeconds) : 1.0/(StepClockRate * iMinutesToSeconds)); +} + +// Convert speed to mm/min or inches/min +float GCodeBuffer::InverseConvertSpeed(float speed) const noexcept +{ + return speed * ((UsingInches()) ? (StepClockRate * iMinutesToSeconds)/InchToMm : (float)(StepClockRate * iMinutesToSeconds)); +} + +const char *GCodeBuffer::GetDistanceUnits() const noexcept +{ + return (UsingInches()) ? "in" : "mm"; } // Return the current stack depth diff --git a/src/GCodes/GCodeBuffer/GCodeBuffer.h b/src/GCodes/GCodeBuffer/GCodeBuffer.h index fb1f7a3f..b6cec720 100644 --- a/src/GCodes/GCodeBuffer/GCodeBuffer.h +++ b/src/GCodes/GCodeBuffer/GCodeBuffer.h @@ -72,9 +72,13 @@ 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))); } float GetFValue() THROWS(GCodeException) SPEED_CRITICAL; // Get a float after a key letter float GetDistance() THROWS(GCodeException); // Get a distance or coordinate and convert it from inches to mm if necessary + float GetSpeed() THROWS(GCodeException); // Get a speed in mm/min or inches/min and convert it to mm/step_clock + float GetSpeedFromMm(bool useSeconds) THROWS(GCodeException); // Get a speed in mm/min or optionally /sec and convert it to mm/step_clock + float GetAcceleration() THROWS(GCodeException); // Get an acceleration in mm/sec^2 or inches/sec^2 and convert it to mm/step_clock^2 int32_t GetIValue() THROWS(GCodeException) SPEED_CRITICAL; // Get an integer after a key letter int32_t GetLimitedIValue(char c, int32_t minValue, int32_t maxValue) THROWS(GCodeException) pre(minvalue <= maxValue) @@ -127,8 +131,13 @@ public: GCodeMachineState::BlockState& GetBlockState() const noexcept { return CurrentFileMachineState().CurrentBlockState(); } uint16_t GetBlockIndent() const noexcept { return GetBlockState().GetIndent(); } + void UseInches(bool inchesNotMm) noexcept { machineState->usingInches = inchesNotMm; } + bool UsingInches() const noexcept { return machineState->usingInches; } float ConvertDistance(float distance) const noexcept; float InverseConvertDistance(float distance) const noexcept; + float ConvertSpeed(float speed) const noexcept; + float InverseConvertSpeed(float speed) const noexcept; + const char *GetDistanceUnits() const noexcept; unsigned int GetStackDepth() const noexcept; bool PushState(bool withinSameFile) noexcept; // Push state returning true if successful (i.e. stack not overflowed) bool PopState(bool withinSameFile) noexcept; // Pop state returning true if successful (i.e. no stack underrun) @@ -235,6 +244,15 @@ 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 + { + return (*s == 0) ? 0 + : (*s >= 'A' && *s <= 'Z') ? ((uint32_t)1 << (*s - 'A')) | ParametersToBitmap(s + 1) + : ParametersToBitmap(s + 1); + } #if SUPPORT_OBJECT_MODEL const char *GetStateText() const noexcept; diff --git a/src/GCodes/GCodeBuffer/StringParser.cpp b/src/GCodes/GCodeBuffer/StringParser.cpp index 9247c577..4876f3d6 100644 --- a/src/GCodes/GCodeBuffer/StringParser.cpp +++ b/src/GCodes/GCodeBuffer/StringParser.cpp @@ -1059,6 +1059,12 @@ 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) { @@ -1074,35 +1080,32 @@ float StringParser::GetFValue() THROWS(GCodeException) // Get a colon-separated list of floats after a key letter // If doPad is true then we allow just one element to be given, in which case we fill all elements with that value -void StringParser::GetFloatArray(float arr[], size_t& returnedLength, bool doPad) THROWS(GCodeException) +void StringParser::GetFloatArray(float arr[], size_t& returnedLength) THROWS(GCodeException) { if (readPointer <= 0) { THROW_INTERNAL_ERROR; } - size_t length = 0; - for (;;) + if (gb.buffer[readPointer] == '{') { - CheckArrayLength(length, returnedLength); - arr[length++] = ReadFloatValue(); - if (gb.buffer[readPointer] != EXPRESSION_LIST_SEPARATOR && gb.buffer[readPointer] != LIST_SEPARATOR) - { - break; - } - ++readPointer; + ExpressionParser parser(gb, gb.buffer + readPointer, gb.buffer + ARRAY_SIZE(gb.buffer), commandIndent + readPointer); + parser.ParseFloatArray(arr, returnedLength); } - - // Special case if there is one entry and returnedLength requests several. Fill the array with the first entry. - if (doPad && length == 1 && returnedLength > 1) + else { - for (size_t i = 1; i < returnedLength; i++) + size_t length = 0; + for (;;) { - arr[i] = arr[0]; + CheckArrayLength(length, returnedLength); + arr[length++] = ReadFloatValue(); + if (gb.buffer[readPointer] != LIST_SEPARATOR) + { + break; + } + ++readPointer; } - } - else - { + returnedLength = length; } @@ -1110,72 +1113,67 @@ void StringParser::GetFloatArray(float arr[], size_t& returnedLength, bool doPad } // Get a :-separated list of ints after a key letter -void StringParser::GetIntArray(int32_t arr[], size_t& returnedLength, bool doPad) THROWS(GCodeException) +void StringParser::GetIntArray(int32_t arr[], size_t& returnedLength) THROWS(GCodeException) { if (readPointer <= 0) { THROW_INTERNAL_ERROR; } - size_t length = 0; - for (;;) + if (gb.buffer[readPointer] == '{') { - CheckArrayLength(length, returnedLength); - arr[length] = ReadIValue(); - length++; - if (gb.buffer[readPointer] != EXPRESSION_LIST_SEPARATOR && gb.buffer[readPointer] != LIST_SEPARATOR) - { - break; - } - ++readPointer; + ExpressionParser parser(gb, gb.buffer + readPointer, gb.buffer + ARRAY_SIZE(gb.buffer), commandIndent + readPointer); + parser.ParseIntArray(arr, returnedLength); } - - // Special case if there is one entry and returnedLength requests several. Fill the array with the first entry. - if (doPad && length == 1 && returnedLength > 1) + else { - for (size_t i = 1; i < returnedLength; i++) + size_t length = 0; + for (;;) { - arr[i] = arr[0]; + CheckArrayLength(length, returnedLength); + arr[length] = ReadIValue(); + length++; + if (gb.buffer[readPointer] != LIST_SEPARATOR) + { + break; + } + ++readPointer; } - } - else - { + returnedLength = length; } + readPointer = -1; } // Get a :-separated list of unsigned ints after a key letter -void StringParser::GetUnsignedArray(uint32_t arr[], size_t& returnedLength, bool doPad) THROWS(GCodeException) +void StringParser::GetUnsignedArray(uint32_t arr[], size_t& returnedLength) THROWS(GCodeException) { if (readPointer <= 0) { THROW_INTERNAL_ERROR; } - size_t length = 0; - for (;;) + if (gb.buffer[readPointer] == '{') { - CheckArrayLength(length, returnedLength); - arr[length] = ReadUIValue(); - length++; - if (gb.buffer[readPointer] != EXPRESSION_LIST_SEPARATOR && gb.buffer[readPointer] != LIST_SEPARATOR) - { - break; - } - ++readPointer; + ExpressionParser parser(gb, gb.buffer + readPointer, gb.buffer + ARRAY_SIZE(gb.buffer), commandIndent + readPointer); + parser.ParseUnsignedArray(arr, returnedLength); } - - // Special case if there is one entry and returnedLength requests several. Fill the array with the first entry. - if (doPad && length == 1 && returnedLength > 1) + else { - for (size_t i = 1; i < returnedLength; i++) + size_t length = 0; + for (;;) { - arr[i] = arr[0]; + CheckArrayLength(length, returnedLength); + arr[length] = ReadUIValue(); + length++; + if (gb.buffer[readPointer] != LIST_SEPARATOR) + { + break; + } + ++readPointer; } - } - else - { + returnedLength = length; } @@ -1190,20 +1188,29 @@ void StringParser::GetDriverIdArray(DriverId arr[], size_t& returnedLength) THRO THROW_INTERNAL_ERROR; } - size_t length = 0; - for (;;) + if (gb.buffer[readPointer] == '{') + { + ExpressionParser parser(gb, gb.buffer + readPointer, gb.buffer + ARRAY_SIZE(gb.buffer), commandIndent + readPointer); + parser.ParseDriverIdArray(arr, returnedLength); + } + else { - CheckArrayLength(length, returnedLength); - arr[length] = ReadDriverIdValue(); - length++; - if (gb.buffer[readPointer] != EXPRESSION_LIST_SEPARATOR && gb.buffer[readPointer] != LIST_SEPARATOR) + size_t length = 0; + for (;;) { - break; + CheckArrayLength(length, returnedLength); + arr[length] = ReadDriverIdValue(); + length++; + if (gb.buffer[readPointer] != LIST_SEPARATOR) + { + break; + } + ++readPointer; } - ++readPointer; + + returnedLength = length; } - returnedLength = length; readPointer = -1; } diff --git a/src/GCodes/GCodeBuffer/StringParser.h b/src/GCodes/GCodeBuffer/StringParser.h index 3e7c515b..b56aa9f9 100644 --- a/src/GCodes/GCodeBuffer/StringParser.h +++ b/src/GCodes/GCodeBuffer/StringParser.h @@ -43,22 +43,23 @@ public: bool IsLastCommand() const noexcept; bool ContainsExpression() const noexcept { return seenExpression; } - bool Seen(char c) noexcept SPEED_CRITICAL; // Is a character present? - 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 + 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 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 + 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 void GetPossiblyQuotedString(const StringRef& str, bool allowEmpty) THROWS(GCodeException); // Get and copy a string which may or may not be quoted - void GetFloatArray(float arr[], size_t& length, bool doPad) THROWS(GCodeException) SPEED_CRITICAL; // Get a colon-separated list of floats after a key letter - void GetIntArray(int32_t arr[], size_t& length, bool doPad) THROWS(GCodeException); // Get a :-separated list of ints after a key letter - void GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad) THROWS(GCodeException); // Get a :-separated list of unsigned ints after a key letter - void GetDriverIdArray(DriverId arr[], size_t& length) THROWS(GCodeException); // Get a :-separated list of drivers after a key letter + void GetFloatArray(float arr[], size_t& length) THROWS(GCodeException) SPEED_CRITICAL; // Get a colon-separated list of floats after a key letter + void GetIntArray(int32_t arr[], size_t& length) THROWS(GCodeException); // Get a :-separated list of ints after a key letter + void GetUnsignedArray(uint32_t arr[], size_t& length) THROWS(GCodeException); // Get a :-separated list of unsigned ints after a key letter + void GetDriverIdArray(DriverId arr[], size_t& length) THROWS(GCodeException); // Get a :-separated list of drivers after a key letter void SetFinished() noexcept; // Set the G Code finished void SetCommsProperties(uint32_t arg) noexcept { checksumRequired = (arg & 1); } diff --git a/src/GCodes/GCodeMachineState.cpp b/src/GCodes/GCodeMachineState.cpp index 1af502d1..1e6e6dda 100644 --- a/src/GCodes/GCodeMachineState.cpp +++ b/src/GCodes/GCodeMachineState.cpp @@ -12,7 +12,7 @@ // Create a default initialised GCodeMachineState GCodeMachineState::GCodeMachineState() noexcept - : feedRate(DefaultFeedRate * SecondsToMinutes), + : feedRate(ConvertSpeedFromMmPerMin(DefaultFeedRate)), #if HAS_LINUX_INTERFACE fileId(NoFileId), #endif diff --git a/src/GCodes/GCodeQueue.cpp b/src/GCodes/GCodeQueue.cpp index 9412e735..a87a1f9b 100644 --- a/src/GCodes/GCodeQueue.cpp +++ b/src/GCodes/GCodeQueue.cpp @@ -220,14 +220,15 @@ void GCodeQueue::Clear() noexcept void GCodeQueue::Diagnostics(MessageType mtype) noexcept { - reprap.GetPlatform().MessageF(mtype, "Code queue is %s\n", (queuedItems == nullptr) ? "empty." : "not empty:"); - if (queuedItems != nullptr) + if (queuedItems == nullptr) + { + reprap.GetPlatform().Message(mtype, "Code queue is empty\n"); + } + else { const QueuedCode *item = queuedItems; - size_t queueLength = 0; do { - queueLength++; #if HAS_LINUX_INTERFACE // The following may output binary gibberish if this code is stored in binary. // We could restore this message by using GCodeBuffer::AppendFullCommand but there is probably no need to @@ -237,7 +238,6 @@ void GCodeQueue::Diagnostics(MessageType mtype) noexcept reprap.GetPlatform().MessageF(mtype, "Queued '%.*s' for move %" PRIu32 "\n", item->dataLength, item->data, item->executeAtMove); } } while ((item = item->Next()) != nullptr); - reprap.GetPlatform().MessageF(mtype, "%d of %d codes have been queued.\n", queueLength, maxQueuedCodes); } } diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index 9c716f3b..85e88c33 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -451,6 +451,7 @@ void GCodes::Spin() noexcept ) // if autoPause is active { (void)SpinGCodeBuffer(*autoPauseGCode); + (void)SpinGCodeBuffer(*queuedGCode); // autopause sometimes to wait for queued GCodes to complete, so spin queuedGCodes too to avoid lockup } else { @@ -646,9 +647,7 @@ bool GCodes::DoFilePrint(GCodeBuffer& gb, const StringRef& reply) noexcept // We never get here if the file ends in M0 because CancelPrint gets called directly in that case. // Don't close the file until all moves have been completed, in case the print gets paused. // Also, this keeps the state as 'Printing' until the print really has finished. - if ( LockMovementAndWaitForStandstill(gb) // wait until movement has finished - && IsCodeQueueIdle() // must also wait until deferred command queue has caught up - ) + if (LockMovementAndWaitForStandstill(gb)) // wait until movement has finished and deferred command queue has caught up { StopPrint(StopPrintReason::normalCompletion); } @@ -784,9 +783,7 @@ bool GCodes::DoFilePrint(GCodeBuffer& gb, const StringRef& reply) noexcept // We never get here if the file ends in M0 because CancelPrint gets called directly in that case. // Don't close the file until all moves have been completed, in case the print gets paused. // Also, this keeps the state as 'Printing' until the print really has finished. - if ( LockMovementAndWaitForStandstill(gb) // wait until movement has finished - && IsCodeQueueIdle() // must also wait until deferred command queue has caught up - ) + if (LockMovementAndWaitForStandstill(gb)) // wait until movement has finished and deferred command queue has caught up { StopPrint(StopPrintReason::normalCompletion); } @@ -1495,7 +1492,7 @@ void GCodes::SaveResumeInfo(bool wasPowerFailure) noexcept buf.catf("\nG0 F6000 Z%.3f\n", (double)pauseRestorePoint.moveCoords[Z_AXIS]); // Set the feed rate - buf.catf("G1 F%.1f", (double)(pauseRestorePoint.feedRate * MinutesToSeconds)); + buf.catf("G1 F%.1f", (double)InverseConvertSpeedToMmPerMin(pauseRestorePoint.feedRate)); #if SUPPORT_LASER if (machineType == MachineType::laser) { @@ -1577,7 +1574,12 @@ bool GCodes::LockMovementAndWaitForStandstill(GCodeBuffer& gb) noexcept return false; } - gb.MotionStopped(); // must do this after we have finished waiting, so that we don't stop waiting when executing G4 + if (&gb != queuedGCode && !IsCodeQueueIdle()) // wait for deferred command queue to catch up + { + return false; + } + + gb.MotionStopped(); // must do this after we have finished waiting, so that we don't stop waiting when executing G4 if (RTOSIface::GetCurrentTask() == Tasks::GetMainTask()) { @@ -1628,7 +1630,7 @@ const char * GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, bool isP moveBuffer.applyM220M221 = (moveBuffer.moveType == 0 && isPrintingMove && !gb.IsDoingFileMacro()); if (gb.Seen(feedrateLetter)) { - gb.LatestMachineState().feedRate = gb.GetDistance() * SecondsToMinutes; // update requested speed, not allowing for speed factor + gb.LatestMachineState().feedRate = gb.GetSpeed(); // update requested speed, not allowing for speed factor } moveBuffer.feedRate = (moveBuffer.applyM220M221) ? speedFactor * gb.LatestMachineState().feedRate @@ -1638,7 +1640,7 @@ const char * GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, bool isP else { moveBuffer.applyM220M221 = false; - moveBuffer.feedRate = DefaultG0FeedRate; // use maximum feed rate, the M203 parameters will limit it + moveBuffer.feedRate = ConvertSpeedFromMmPerMin(DefaultG0FeedRate); // use maximum feed rate, the M203 parameters will limit it moveBuffer.usingStandardFeedrate = false; } @@ -1648,11 +1650,11 @@ const char * GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, bool isP moveBuffer.coords[drive] = 0.0; } moveBuffer.hasPositiveExtrusion = false; - moveBuffer.virtualExtruderPosition = virtualExtruderPosition; // save this before we update it + moveBuffer.virtualExtruderPosition = virtualExtruderPosition; // save this before we update it ExtrudersBitmap extrudersMoving; // Check if we are extruding - if (gb.Seen(extrudeLetter)) // DC 2018-08-07: at E3D's request, extrusion is now recognised even on uncoordinated moves + if (gb.Seen(extrudeLetter)) // DC 2018-08-07: at E3D's request, extrusion is now recognised even on uncoordinated moves { // Check that we have a tool to extrude with Tool* const tool = reprap.GetCurrentTool(); @@ -2116,7 +2118,7 @@ bool GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated, const char *& e moveLengthSquared += fsquare(currentUserPosition[Z_AXIS] - initialUserPosition[Z_AXIS]); } const float moveLength = fastSqrtf(moveLengthSquared); - const float moveTime = moveLength/moveBuffer.feedRate; // this is a best-case time, often the move will take longer + const float moveTime = moveLength/(moveBuffer.feedRate * StepClockRate); // this is a best-case time, often the move will take longer moveBuffer.totalSegments = (unsigned int)max<long>(1, lrintf(min<float>(moveLength * kin.GetReciprocalMinSegmentLength(), moveTime * kin.GetSegmentsPerSecond()))); } else @@ -2466,7 +2468,7 @@ bool GCodes::DoArcMove(GCodeBuffer& gb, bool clockwise, const char *& err) // We leave out the square term because it is very small // In CNC applications even very small deviations can be visible, so we use a smaller segment length at low speeds const float arcSegmentLength = constrain<float> - ( min<float>(fastSqrtf(8 * moveBuffer.arcRadius * MaxArcDeviation), moveBuffer.feedRate * (1.0/MinArcSegmentsPerSec)), + ( min<float>(fastSqrtf(8 * moveBuffer.arcRadius * MaxArcDeviation), moveBuffer.feedRate * StepClockRate * (1.0/MinArcSegmentsPerSec)), MinArcSegmentLength, MaxArcSegmentLength ); @@ -2814,10 +2816,32 @@ bool GCodes::DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissi #if HAS_LINUX_INTERFACE || HAS_MASS_STORAGE gb.LatestMachineState().doingFileMacro = true; - gb.LatestMachineState().runningM501 = (codeRunning == 501); - gb.LatestMachineState().runningM502 = (codeRunning == 502); - gb.LatestMachineState().runningSystemMacro = (codeRunning == SystemHelperMacroCode || codeRunning == AsyncSystemMacroCode || codeRunning == 29 || codeRunning == 32); - // running a system macro e.g. homing, so don't use workplace coordinates + + // The following three flags need to be inherited in the case that a system macro calls another macro, e.g.homeall.g calls homez.g. The Push call copied them over already. + switch (codeRunning) + { + case 501: + gb.LatestMachineState().runningM501 = true; + gb.LatestMachineState().runningSystemMacro = true; // running a system macro e.g. homing, so don't use workplace coordinates + break; + + case 502: + gb.LatestMachineState().runningM502 = true; + gb.LatestMachineState().runningSystemMacro = true; // running a system macro e.g. homing, so don't use workplace coordinates + break; + + case SystemHelperMacroCode: + case AsyncSystemMacroCode: + case ToolChangeMacroCode: + case 29: + case 32: + gb.LatestMachineState().runningSystemMacro = true; // running a system macro e.g. homing, so don't use workplace coordinates + break; + + default: + break; + } + gb.SetState(GCodeState::normal); gb.Init(); diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index d5dc4af4..ee50c201 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -267,12 +267,12 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx break; case 20: // Inches (which century are we living in, here?) - gb.LatestMachineState().usingInches = true; + gb.UseInches(true); reprap.InputsUpdated(); break; case 21: // mm - gb.LatestMachineState().usingInches = false; + gb.UseInches(false); reprap.InputsUpdated(); break; @@ -515,9 +515,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx reply.copy("Pause the print before attempting to cancel it"); result = GCodeResult::error; } - else if ( !LockMovementAndWaitForStandstill(gb) // wait until everything has stopped - || !IsCodeQueueIdle() // must also wait until deferred command queue has caught up - ) + else if (!LockMovementAndWaitForStandstill(gb)) // wait until everything has stopped and deferred command queue has caught up { return false; } @@ -1464,9 +1462,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx case 109: // Deprecated in RRF, but widely generated by slicers { const bool movementWasLocked = gb.LatestMachineState().lockedResources.IsBitSet(MoveResource); - if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished - || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution - ) + if (!LockMovementAndWaitForStandstill(gb)) // wait until movement has finished and deferred command queue has caught up to avoid out-of-order execution { return false; } @@ -1677,9 +1673,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx break; case 116: // Wait for set temperatures - if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished - || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution - ) + if (!LockMovementAndWaitForStandstill(gb)) // wait until movement has finished and deferred command queue has caught up to avoid out-of-order execution { return false; } @@ -2021,9 +2015,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx case 190: // Set bed temperature and wait case 191: // Set chamber temperature and wait - if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished - || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution - ) + if (!LockMovementAndWaitForStandstill(gb)) // wait until movement has finished and deferred command queue has caught up to avoid out-of-order execution { return false; } @@ -2109,7 +2101,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx { if (gb.Seen(axisLetters[axis])) { - platform.SetAcceleration(axis, gb.GetDistance()); + platform.SetAcceleration(axis, gb.GetAcceleration()); seen = true; } } @@ -2122,7 +2114,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx gb.GetFloatArray(eVals, eCount, true); for (size_t e = 0; e < eCount; e++) { - platform.SetAcceleration(ExtruderToLogicalDrive(e), gb.ConvertDistance(eVals[e])); + platform.SetAcceleration(ExtruderToLogicalDrive(e), ConvertAcceleration(eVals[e])); } } @@ -2132,16 +2124,16 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx } else { - reply.printf("Accelerations (mm/sec^2): "); + reply.copy("Accelerations (mm/sec^2): "); for (size_t axis = 0; axis < numTotalAxes; ++axis) { - reply.catf("%c: %.1f, ", axisLetters[axis], (double)platform.Acceleration(axis)); + reply.catf("%c: %.1f, ", axisLetters[axis], (double)InverseConvertAcceleration(platform.Acceleration(axis))); } reply.cat("E:"); char sep = ' '; for (size_t extruder = 0; extruder < numExtruders; extruder++) { - reply.catf("%c%.1f", sep, (double)platform.Acceleration(ExtruderToLogicalDrive(extruder))); + reply.catf("%c%.1f", sep, (double)InverseConvertAcceleration(platform.Acceleration(ExtruderToLogicalDrive(extruder)))); sep = ':'; } } @@ -2152,14 +2144,13 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx { // Units are mm/sec if S1 is given, else mm/min const bool usingMmPerSec = (gb.Seen('S') && gb.GetIValue() == 1); - const float settingMultiplier = (usingMmPerSec) ? 1.0 : SecondsToMinutes; bool seen = false; // Do the minimum first, because we constrain the maximum rates to be no lower than it if (gb.Seen('I')) { seen = true; - platform.SetMinMovementSpeed(gb.GetDistance() * settingMultiplier); + platform.SetMinMovementSpeed(gb.GetSpeedFromMm(usingMmPerSec)); } for (size_t axis = 0; axis < numTotalAxes; ++axis) @@ -2167,7 +2158,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx if (gb.Seen(axisLetters[axis])) { seen = true; - platform.SetMaxFeedrate(axis, gb.GetDistance() * settingMultiplier); + platform.SetMaxFeedrate(axis, gb.GetSpeedFromMm(usingMmPerSec)); } } @@ -2179,7 +2170,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx gb.GetFloatArray(eVals, eCount, true); for (size_t e = 0; e < eCount; e++) { - platform.SetMaxFeedrate(ExtruderToLogicalDrive(e), gb.ConvertDistance(eVals[e]) * settingMultiplier); + platform.SetMaxFeedrate(ExtruderToLogicalDrive(e), ConvertSpeedFromMm(eVals[e], usingMmPerSec)); } } @@ -2189,20 +2180,19 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx } else { - const float reportingMultiplier = (usingMmPerSec) ? 1.0 : MinutesToSeconds; - reply.printf("Max speeds (mm/%s): ", (usingMmPerSec) ? "sec" : "min"); + reply.printf("Max speeds (%s)): ", (usingMmPerSec) ? "mm/sec" : "mm/min"); for (size_t axis = 0; axis < numTotalAxes; ++axis) { - reply.catf("%c: %.1f, ", axisLetters[axis], (double)(platform.MaxFeedrate(axis) * reportingMultiplier)); + reply.catf("%c: %.1f, ", axisLetters[axis], (double)InverseConvertSpeedToMm(platform.MaxFeedrate(axis), usingMmPerSec)); } reply.cat("E:"); char sep = ' '; for (size_t extruder = 0; extruder < numExtruders; extruder++) { - reply.catf("%c%.1f", sep, (double)(platform.MaxFeedrate(ExtruderToLogicalDrive(extruder)) * reportingMultiplier)); + reply.catf("%c%.1f", sep, (double)InverseConvertSpeedToMm(platform.MaxFeedrate(ExtruderToLogicalDrive(extruder)), usingMmPerSec)); sep = ':'; } - reply.catf(", min. speed %.2f", (double)(platform.MinMovementSpeed() * reportingMultiplier)); + reply.catf(", min. speed %.2f", (double)InverseConvertSpeedToMm(platform.MinMovementSpeed(), usingMmPerSec)); } } break; @@ -2287,7 +2277,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx if (!seen) { - reply.copy("Axis limit"); + reply.copy("Axis limits (mm)"); char sep = 's'; for (size_t axis = 0; axis < numTotalAxes; axis++) { @@ -2456,7 +2446,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx { // The pipeline is empty, so execute the babystepping move immediately SetMoveBufferDefaults(); - moveBuffer.feedRate = DefaultFeedRate; + moveBuffer.feedRate = ConvertSpeedFromMmPerMin(DefaultFeedRate); moveBuffer.tool = reprap.GetCurrentTool(); NewMoveAvailable(1); } @@ -3320,13 +3310,13 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx case 205: // Set/print maximum jerk speeds in mm/sec case 566: // Set/print maximum jerk speeds in mm/min { - const float multiplier1 = (code == 566) ? SecondsToMinutes : 1.0; + const bool useMmPerSec = (code == 205); bool seenAxis = false, seenExtruder = false; for (size_t axis = 0; axis < numTotalAxes; axis++) { if (gb.Seen(axisLetters[axis])) { - platform.SetInstantDv(axis, gb.GetDistance() * multiplier1); + platform.SetInstantDv(axis, gb.GetSpeedFromMm(useMmPerSec)); seenAxis = true; } } @@ -3339,7 +3329,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx gb.GetFloatArray(eVals, eCount, true); for (size_t e = 0; e < eCount; e++) { - platform.SetInstantDv(ExtruderToLogicalDrive(e), eVals[e] * multiplier1); + platform.SetInstantDv(ExtruderToLogicalDrive(e), ConvertSpeedFromMm(eVals[e], useMmPerSec)); } } @@ -3355,17 +3345,16 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx } else if (!seenExtruder) { - const float multiplier2 = (code == 566) ? MinutesToSeconds : 1.0; - reply.printf("Maximum jerk rates (mm/%s): ", (code == 566) ? "min" : "sec"); + reply.printf("Maximum jerk rates (%s): ", (useMmPerSec) ? "mm/sec" : "mm/min"); for (size_t axis = 0; axis < numTotalAxes; ++axis) { - reply.catf("%c: %.1f, ", axisLetters[axis], (double)(platform.GetInstantDv(axis) * multiplier2)); + reply.catf("%c: %.1f, ", axisLetters[axis], (double)InverseConvertSpeedToMm(platform.GetInstantDv(axis), useMmPerSec)); } reply.cat("E:"); char sep = ' '; for (size_t extruder = 0; extruder < numExtruders; extruder++) { - reply.catf("%c%.1f", sep, (double)(platform.GetInstantDv(ExtruderToLogicalDrive(extruder)) * multiplier2)); + reply.catf("%c%.1f", sep, (double)InverseConvertSpeedToMm(platform.GetInstantDv(ExtruderToLogicalDrive(extruder)), useMmPerSec)); sep = ':'; } if (code == 566) @@ -3459,25 +3448,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx break; case 572: // Set/report pressure advance - if (gb.Seen('S')) - { - const float advance = gb.GetFValue(); - if (!LockMovementAndWaitForStandstill(gb)) - { - return false; - } - result = platform.SetPressureAdvance(advance, gb, reply); - } - else - { - reply.copy("Extruder pressure advance"); - char c = ':'; - for (size_t i = 0; i < numExtruders; ++i) - { - reply.catf("%c %.3f", c, (double)platform.GetPressureAdvance(i)); - c = ','; - } - } + result = reprap.GetMove().ConfigurePressureAdvance(gb, reply); break; case 573: // Report heater average PWM @@ -3735,11 +3706,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx #endif case 593: // Configure dynamic ringing cancellation - if (!LockMovementAndWaitForStandstill(gb)) - { - return false; - } - result = reprap.GetMove().GetShaper().Configure(gb, reply); + result = reprap.GetMove().GetAxisShaper().Configure(gb, reply); break; #if SUPPORT_ASYNC_MOVES @@ -4022,8 +3989,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx // Get the feedrate (if any) and kick off a new move if (gb.Seen(feedrateLetter)) { - const float rate = gb.ConvertDistance(gb.GetFValue()); - gb.LatestMachineState().feedRate = rate * SecondsToMinutes; // don't apply the speed factor + gb.LatestMachineState().feedRate = gb.GetSpeed(); // don't apply the speed factor } moveBuffer.feedRate = gb.LatestMachineState().feedRate; moveBuffer.usingStandardFeedrate = true; @@ -4660,7 +4626,7 @@ bool GCodes::HandleTcode(GCodeBuffer& gb, const StringRef& reply) } else if (gb.Seen('T')) { - // We handle "T{expression}" as if it's "T "{expression}, also DSF may pass a T{expression} command in this way + // We handle "T T{expression}" as if it's "T "{expression}, also DSF may pass a T{expression} command in this way seen = true; toolNum = gb.GetIValue(); } @@ -4682,7 +4648,7 @@ bool GCodes::HandleTcode(GCodeBuffer& gb, const StringRef& reply) if (seen) { - if (!LockMovementAndWaitForStandstill(gb) || !IsCodeQueueIdle()) + if (!LockMovementAndWaitForStandstill(gb)) { return false; } diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp index 5bed126e..42388844 100644 --- a/src/GCodes/GCodes3.cpp +++ b/src/GCodes/GCodes3.cpp @@ -909,7 +909,7 @@ GCodeResult GCodes::ProbeTool(GCodeBuffer& gb, const StringRef& reply) THROWS(GC // Get the feed rate and axis gb.MustSee(feedrateLetter); - m585Settings.feedRate = gb.LatestMachineState().feedRate = gb.GetDistance() * SecondsToMinutes; // don't apply the speed factor to homing and other special moves + m585Settings.feedRate = gb.LatestMachineState().feedRate = gb.GetSpeed(); // don't apply the speed factor to homing and other special moves m585Settings.axisNumber = FindAxisLetter(gb); m585Settings.offset = gb.GetDistance(); @@ -1000,7 +1000,7 @@ GCodeResult GCodes::FindCenterOfCavity(GCodeBuffer& gb, const StringRef& reply) // Get the feed rate, backoff distance, and axis gb.MustSee(feedrateLetter); - m675Settings.feedRate = gb.LatestMachineState().feedRate = gb.GetDistance() * SecondsToMinutes; // don't apply the speed factor to homing and other special moves + m675Settings.feedRate = gb.LatestMachineState().feedRate = gb.GetSpeed(); // don't apply the speed factor to homing and other special moves m675Settings.backoffDistance = gb.Seen('R') ? gb.GetDistance() : 5.0; m675Settings.axisNumber = FindAxisLetter(gb); @@ -1378,22 +1378,22 @@ GCodeResult GCodes::ConfigureLocalDriver(GCodeBuffer& gb, const StringRef& reply { if (drive < platform.GetNumActualDirectDrivers()) { - bool seen = false; - if (gb.Seen('S')) + if (gb.SeenAny("RS")) { if (!LockMovementAndWaitForStandstill(gb)) { return GCodeResult::notFinished; } + } + + bool seen = false; + if (gb.Seen('S')) + { seen = true; platform.SetDirectionValue(drive, gb.GetIValue() != 0); } if (gb.Seen('R')) { - if (!LockMovementAndWaitForStandstill(gb)) - { - return GCodeResult::notFinished; - } seen = true; platform.SetEnableValue(drive, (int8_t)gb.GetIValue()); } diff --git a/src/GCodes/GCodes4.cpp b/src/GCodes/GCodes4.cpp index 34a28473..ac0961cc 100644 --- a/src/GCodes/GCodes4.cpp +++ b/src/GCodes/GCodes4.cpp @@ -384,7 +384,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept if (currentTool != nullptr) { const float newZPos = (moveBuffer.coords[Z_AXIS] - currentTool->GetOffset(Z_AXIS)); - if(newZPos > platform.AxisMaximum(Z_AXIS) || newZPos < platform.AxisMinimum(Z_AXIS)) + if (newZPos > platform.AxisMaximum(Z_AXIS) || newZPos < platform.AxisMinimum(Z_AXIS)) { gb.LatestMachineState().feedRate = toolChangeRestorePoint.feedRate; doingToolChange = false; @@ -394,13 +394,13 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept break; } } + // Restore the original Z axis user position, so that different tool Z offsets work even if the first move after the tool change doesn't have a Z coordinate - // Only do this if we are running as an FDM printer, because it's not appropriate for CNC machines. SetMoveBufferDefaults(); currentUserPosition[Z_AXIS] = toolChangeRestorePoint.moveCoords[Z_AXIS]; ToolOffsetTransform(currentUserPosition, moveBuffer.coords); - moveBuffer.feedRate = DefaultFeedRate * SecondsToMinutes; // ask for a good feed rate, we may have paused during a slow move - moveBuffer.tool = reprap.GetCurrentTool(); // needed so that bed compensation is applied correctly + moveBuffer.feedRate = ConvertSpeedFromMmPerMin(DefaultFeedRate); // ask for a good feed rate, we may have paused during a slow move + moveBuffer.tool = reprap.GetCurrentTool(); // needed so that bed compensation is applied correctly NewMoveAvailable(1); gb.AdvanceState(); } @@ -408,7 +408,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept case GCodeState::toolChangeComplete: case GCodeState::m109ToolChangeComplete: - if (LockMovementAndWaitForStandstill(gb)) // wait for tpost.g to finish executing or the move to height to finish + if (LockMovementAndWaitForStandstill(gb)) // wait for the move to height to finish { gb.LatestMachineState().feedRate = toolChangeRestorePoint.feedRate; // We don't restore the default fan speed in case the user wants to use a different one for the new tool @@ -511,8 +511,8 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept } SetMoveBufferDefaults(); ToolOffsetTransform(currentUserPosition, moveBuffer.coords); - moveBuffer.feedRate = DefaultFeedRate * SecondsToMinutes; // ask for a good feed rate, we may have paused during a slow move - moveBuffer.tool = reprap.GetCurrentTool(); // needed so that bed compensation is applied correctly + moveBuffer.feedRate = ConvertSpeedFromMmPerMin(DefaultFeedRate); // ask for a good feed rate, we may have paused during a slow move + moveBuffer.tool = reprap.GetCurrentTool(); // needed so that bed compensation is applied correctly if (gb.GetState() == GCodeState::resuming1 && currentZ > pauseRestorePoint.moveCoords[Z_AXIS]) { // First move the head to the correct XY point, then move it down in a separate move @@ -640,14 +640,14 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept axes.SetBit(axis0Num); axes.SetBit(axis1Num); float axesCoords[MaxAxes]; - axesCoords[axis0Num] = axis0Coord; - axesCoords[axis1Num] = axis1Coord; + const auto zp = platform.GetZProbeOrDefault(currentZProbeNumber); + axesCoords[axis0Num] = axis0Coord - zp->GetOffset(axis0Num); + axesCoords[axis1Num] = axis1Coord - zp->GetOffset(axis1Num); if (move.IsAccessibleProbePoint(axesCoords, axes)) { SetMoveBufferDefaults(); - const auto zp = platform.GetZProbeOrDefault(currentZProbeNumber); - moveBuffer.coords[axis0Num] = axis0Coord - zp->GetOffset(axis0Num); - moveBuffer.coords[axis1Num] = axis1Coord - zp->GetOffset(axis1Num); + moveBuffer.coords[axis0Num] = axesCoords[axis0Num]; + moveBuffer.coords[axis1Num] = axesCoords[axis1Num]; moveBuffer.coords[Z_AXIS] = zp->GetStartingHeight(); moveBuffer.feedRate = zp->GetTravelSpeed(); NewMoveAvailable(1); diff --git a/src/GCodes/RestorePoint.cpp b/src/GCodes/RestorePoint.cpp index edbfbf71..f197b25d 100644 --- a/src/GCodes/RestorePoint.cpp +++ b/src/GCodes/RestorePoint.cpp @@ -34,7 +34,7 @@ constexpr ObjectModelTableEntry RestorePoint::objectModelTable[] = { "coords", OBJECT_MODEL_FUNC_NOSELF(&coordinatesArrayDescriptor), ObjectModelEntryFlags::none }, { "extruderPos", OBJECT_MODEL_FUNC(self->virtualExtruderPosition, 1), ObjectModelEntryFlags::none }, { "fanPwm", OBJECT_MODEL_FUNC(self->fanSpeed, 2), ObjectModelEntryFlags::none }, - { "feedRate", OBJECT_MODEL_FUNC(self->feedRate, 1), ObjectModelEntryFlags::none }, + { "feedRate", OBJECT_MODEL_FUNC(InverseConvertSpeedToMmPerSec(self->feedRate), 1), ObjectModelEntryFlags::none }, #if SUPPORT_IOBITS { "ioBits", OBJECT_MODEL_FUNC_IF(reprap.GetGCodes().GetMachineType() != MachineType::laser, (int32_t)self->laserPwmOrIoBits.ioBits), ObjectModelEntryFlags::none }, @@ -64,7 +64,7 @@ void RestorePoint::Init() noexcept moveCoords[i] = 0.0; } - feedRate = DefaultFeedRate * SecondsToMinutes; + feedRate = ConvertSpeedFromMmPerMin(DefaultFeedRate); virtualExtruderPosition = 0.0; filePos = noFilePosition; proportionDone = 0.0; |