diff options
author | Manuel Coenen <manuel@duet3d.com> | 2021-03-10 12:38:04 +0300 |
---|---|---|
committer | Manuel Coenen <manuel@duet3d.com> | 2021-03-10 12:38:04 +0300 |
commit | 68cfaacc16424ff08e53a2c52c51a76ecc7f98ba (patch) | |
tree | 8a8f70c8e81600fe4170a485edfd6fdb4d54d722 /src/GCodes | |
parent | bb201b96deaf1226d4ec3a0eb2c72f9dc2d7229c (diff) | |
parent | 8b89aab7455a870574fed653738af5566e82beb3 (diff) |
Merge remote-tracking branch 'origin/3.3-dev' into wil-extend-m111
Conflicts:
src/GCodes/GCodeBuffer/StringParser.cpp
Diffstat (limited to 'src/GCodes')
-rw-r--r-- | src/GCodes/GCodeBuffer/BinaryParser.cpp | 81 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/BinaryParser.h | 2 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/ExpressionParser.cpp | 131 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/ExpressionParser.h | 10 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/GCodeBuffer.cpp | 51 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/GCodeBuffer.h | 13 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/StringParser.cpp | 268 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer/StringParser.h | 6 | ||||
-rw-r--r-- | src/GCodes/GCodeMachineState.cpp | 15 | ||||
-rw-r--r-- | src/GCodes/GCodeMachineState.h | 11 | ||||
-rw-r--r-- | src/GCodes/GCodes.cpp | 169 | ||||
-rw-r--r-- | src/GCodes/GCodes.h | 9 | ||||
-rw-r--r-- | src/GCodes/GCodes2.cpp | 82 | ||||
-rw-r--r-- | src/GCodes/GCodes3.cpp | 22 | ||||
-rw-r--r-- | src/GCodes/GCodes4.cpp | 104 | ||||
-rw-r--r-- | src/GCodes/ObjectTracker.cpp | 32 | ||||
-rw-r--r-- | src/GCodes/ObjectTracker.h | 13 | ||||
-rw-r--r-- | src/GCodes/Variable.cpp | 83 | ||||
-rw-r--r-- | src/GCodes/Variable.h | 56 |
19 files changed, 775 insertions, 383 deletions
diff --git a/src/GCodes/GCodeBuffer/BinaryParser.cpp b/src/GCodes/GCodeBuffer/BinaryParser.cpp index e3f2fdf0..47f696ad 100644 --- a/src/GCodes/GCodeBuffer/BinaryParser.cpp +++ b/src/GCodes/GCodeBuffer/BinaryParser.cpp @@ -13,6 +13,7 @@ #include "ExpressionParser.h" #include <Platform/Platform.h> #include <Platform/RepRap.h> +#include <GCodes/Variable.h> #include <Networking/NetworkDefs.h> BinaryParser::BinaryParser(GCodeBuffer& gcodeBuffer) noexcept : gb(gcodeBuffer) @@ -34,8 +35,8 @@ void BinaryParser::Put(const uint32_t *data, size_t len) noexcept memcpyu32(reinterpret_cast<uint32_t *>(gb.buffer), data, len); bufferLength = len * sizeof(uint32_t); gb.bufferState = GCodeBufferState::parsingGCode; - gb.machineState->g53Active = (header->flags & CodeFlags::EnforceAbsolutePosition) != 0; - gb.machineState->lineNumber = header->lineNumber; + gb.LatestMachineState().g53Active = (header->flags & CodeFlags::EnforceAbsolutePosition) != 0; + gb.CurrentFileMachineState().lineNumber = header->lineNumber; } void BinaryParser::DecodeCommand() noexcept @@ -70,6 +71,7 @@ bool BinaryParser::Seen(char c) noexcept return true; } + // Skip to the next parameter if (param->type == DataType::IntArray || param->type == DataType::UIntArray || param->type == DataType::FloatArray || @@ -469,7 +471,7 @@ void BinaryParser::GetDriverIdArray(DriverId arr[], size_t& length) THROWS(GCode void BinaryParser::SetFinished() noexcept { - gb.machineState->g53Active = false; // G53 does not persist beyond the current command + gb.LatestMachineState().g53Active = false; // G53 does not persist beyond the current command Init(); } @@ -752,6 +754,79 @@ void BinaryParser::WriteParameters(const StringRef& s, bool quoteStrings) const } } +void BinaryParser::SetParameters(VariableSet& vs, int codeRunning) noexcept +{ + if (bufferLength != 0 && header->numParameters != 0) + { + const char *parameterStart = reinterpret_cast<const char*>(gb.buffer) + sizeof(CodeHeader); + reducedBytesRead = 0; + seenParameter = nullptr; + seenParameterValue = parameterStart + header->numParameters * sizeof(CodeParameter); + + for (size_t i = 0; i < header->numParameters; i++) + { + const CodeParameter *param = reinterpret_cast<const CodeParameter*>(parameterStart + i * sizeof(CodeParameter)); + if (param->letter != 'P' || codeRunning != 98) + { + ExpressionValue ev; + switch (param->type) + { + case DataType::String: + { + StringHandle sh(seenParameterValue, seenParameter->intValue); + ev.Set(sh); + } + break; + + case DataType::Expression: + try + { + ExpressionParser parser(gb, seenParameterValue, seenParameterValue + seenParameter->intValue, -1); + ev.Set(parser.ParseFloat()); + } + catch (const GCodeException&) { } + break; + + case DataType::Float: + ev.Set(seenParameter->floatValue); + break; + + case DataType::Int: + ev.Set(seenParameter->intValue); + break; + + case DataType::UInt: + ev.Set((int32_t)seenParameter->uintValue); + break; + + default: + break; + } + + if (ev.GetType() != TypeCode::None) + { + char paramName[2] = { param->letter, 0 }; + vs.Insert(new Variable(paramName, ev, -1)); + } + } + + // Skip to the next parameter + if (param->type == DataType::IntArray || + param->type == DataType::UIntArray || + param->type == DataType::FloatArray || + param->type == DataType::DriverIdArray) + { + seenParameterValue += param->intValue * sizeof(uint32_t); + } + else if (param->type == DataType::String || param->type == DataType::Expression) + { + seenParameterValue += AddPadding(param->intValue); + } + } + } + //TODO +} + GCodeException BinaryParser::ConstructParseException(const char *str) const noexcept { return GCodeException(header->lineNumber, -1, str); diff --git a/src/GCodes/GCodeBuffer/BinaryParser.h b/src/GCodes/GCodeBuffer/BinaryParser.h index a20b516b..d2e81c06 100644 --- a/src/GCodes/GCodeBuffer/BinaryParser.h +++ b/src/GCodes/GCodeBuffer/BinaryParser.h @@ -15,6 +15,7 @@ #include <Linux/LinuxMessageFormats.h> #include <Platform/MessageType.h> #include <GCodes/GCodeException.h> +#include <GCodes/GCodeMachineState.h> class GCodeBuffer; class IPAddress; @@ -59,6 +60,7 @@ public: void PrintCommand(const StringRef& s) const noexcept; void AppendFullCommand(const StringRef &s) const noexcept; + void SetParameters(VariableSet& vs, int codeRunning) noexcept; private: GCodeBuffer& gb; diff --git a/src/GCodes/GCodeBuffer/ExpressionParser.cpp b/src/GCodes/GCodeBuffer/ExpressionParser.cpp index 13e18652..17e2ff0f 100644 --- a/src/GCodes/GCodeBuffer/ExpressionParser.cpp +++ b/src/GCodes/GCodeBuffer/ExpressionParser.cpp @@ -15,12 +15,14 @@ #include <limits> +constexpr size_t MaxStringExpressionLength = StringLength100; + // These can't be declared locally inside ParseIdentifierExpression because NamedEnum includes static data NamedEnum(NamedConstant, unsigned int, _false, iterations, line, _null, pi, _result, _true); NamedEnum(Function, unsigned int, abs, acos, asin, atan, atan2, cos, degrees, floor, isnan, max, min, mod, radians, random, sin, sqrt, tan); ExpressionParser::ExpressionParser(const GCodeBuffer& p_gb, const char *text, const char *textLimit, int p_column) noexcept - : currentp(text), startp(text), endp(textLimit), gb(p_gb), column(p_column), stringBuffer(stringBufferStorage, ARRAY_SIZE(stringBufferStorage)) + : currentp(text), startp(text), endp(textLimit), gb(p_gb), column(p_column) { } @@ -48,6 +50,25 @@ ExpressionValue ExpressionParser::Parse(bool evaluate) THROWS(GCodeException) return result; } +// Evaluate an expression that must either be a numeric or string literal or enclosed in { } +ExpressionValue ExpressionParser::ParseSimple() THROWS(GCodeException) +{ + const char c = CurrentCharacter(); + if (c == '{') + { + return ParseExpectKet(true, '}'); + } + if (c == '"') + { + return ParseQuotedString(); + } + if (isDigit(c)) + { + return ParseNumber(); + } + throw ConstructParseException("expected simple expression"); +} + // Evaluate an expression internally, stopping before any binary operators with priority 'priority' or lower ExpressionValue ExpressionParser::ParseInternal(bool evaluate, uint8_t priority) THROWS(GCodeException) { @@ -64,8 +85,7 @@ ExpressionValue ExpressionParser::ParseInternal(bool evaluate, uint8_t priority) switch (c) { case '"': - ParseQuotedString(stringBuffer.GetRef()); - val.Set(GetAndFix()); + val = ParseQuotedString(); break; case '-': @@ -119,10 +139,11 @@ ExpressionValue ExpressionParser::ParseInternal(bool evaluate, uint8_t priority) val = ParseInternal(evaluate, UnaryPriority); if (val.GetType() == TypeCode::CString) { - const char* s = val.sVal; - val.Set((int32_t)strlen(s)); - stringBuffer.FinishedUsing(s); - val.SetType(TypeCode::Int32); + val.Set((int32_t)strlen(val.sVal)); + } + else if (val.GetType() == TypeCode::HeapString) + { + val.Set((int32_t)val.shVal.GetLength()); } else { @@ -435,7 +456,11 @@ ExpressionValue ExpressionParser::ParseInternal(bool evaluate, uint8_t priority) break; case TypeCode::CString: - val.bVal = (strcmp(val.sVal, val2.sVal) == 0); + val.bVal = (strcmp(val.sVal, (val2.GetType() == TypeCode::HeapString) ? val2.shVal.Get().Ptr() : val2.sVal) == 0); + break; + + case TypeCode::HeapString: + val.bVal = (strcmp(val.shVal.Get().Ptr(), (val2.GetType() == TypeCode::HeapString) ? val2.shVal.Get().Ptr() : val2.sVal) == 0); break; default: @@ -450,14 +475,14 @@ ExpressionValue ExpressionParser::ParseInternal(bool evaluate, uint8_t priority) break; case '^': - ConvertToString(val, evaluate); - ConvertToString(val2, evaluate); - // We could skip evaluation if evaluate is false, but there is no real need to - if (stringBuffer.Concat(val.sVal, val2.sVal)) { - throw ConstructParseException("too many strings"); + String<MaxStringExpressionLength> str; + val.AppendAsString(str.GetRef()); + val2.AppendAsString(str.GetRef()); + StringHandle sh(str.c_str()); + val.Set(sh); + val2.Release(); } - val.sVal = GetAndFix(); break; } } @@ -548,7 +573,7 @@ void ExpressionParser::BalanceNumericTypes(ExpressionValue& val1, ExpressionValu // Balance types for a comparison operator void ExpressionParser::BalanceTypes(ExpressionValue& val1, ExpressionValue& val2, bool evaluate) THROWS(GCodeException) { - if (val1.GetType() == val2.GetType()) // handle the common case first + if ((val1.GetType() == val2.GetType()) || (val1.IsStringType() && val2.IsStringType())) // handle the common case first { // nothing to do } @@ -560,11 +585,11 @@ void ExpressionParser::BalanceTypes(ExpressionValue& val1, ExpressionValue& val2 { ConvertToFloat(val1, evaluate); } - else if (val2.GetType() == TypeCode::CString && TypeHasNoLiterals(val1.GetType())) + else if (val2.IsStringType() && TypeHasNoLiterals(val1.GetType())) { ConvertToString(val1, evaluate); } - else if (val1.GetType() == TypeCode::CString && TypeHasNoLiterals(val2.GetType())) + else if (val1.IsStringType() && TypeHasNoLiterals(val2.GetType())) { ConvertToString(val2, evaluate); } @@ -637,13 +662,14 @@ void ExpressionParser::ConvertToBool(ExpressionValue& val, bool evaluate) const void ExpressionParser::ConvertToString(ExpressionValue& val, bool evaluate) THROWS(GCodeException) { - if (val.GetType() != TypeCode::CString) + if (!val.IsStringType()) { if (evaluate) { - stringBuffer.ClearLatest(); - val.AppendAsString(stringBuffer.GetRef()); - val.Set(GetAndFix()); + String<MaxStringExpressionLength> str; + val.AppendAsString(str.GetRef()); + StringHandle sh(str.c_str()); + val.Set(sh); } else { @@ -652,17 +678,6 @@ void ExpressionParser::ConvertToString(ExpressionValue& val, bool evaluate) THRO } } -// Get a C-style pointer to the latest string in the buffer, and start a new one -const char *ExpressionParser::GetAndFix() -{ - const char *const rslt = stringBuffer.LatestCStr(); - if (stringBuffer.Fix()) - { - throw ConstructParseException("too many strings"); - } - return rslt; -} - void ExpressionParser::SkipWhiteSpace() noexcept { char c; @@ -702,7 +717,7 @@ ExpressionValue ExpressionParser::ParseIdentifierExpression(bool evaluate, bool } String<MaxVariableNameLength> id; - ObjectExplorationContext context(applyLengthOperator, gb.MachineState().lineNumber, GetColumn()); + ObjectExplorationContext context(applyLengthOperator, gb.GetLineNumber(), GetColumn()); // Loop parsing identifiers and index expressions // When we come across an index expression, evaluate it, add it to the context, and place a marker in the identifier string. @@ -751,7 +766,7 @@ ExpressionValue ExpressionParser::ParseIdentifierExpression(bool evaluate, bool case NamedConstant::iterations: { - const int32_t v = gb.MachineState().GetIterations(); + const int32_t v = gb.CurrentFileMachineState().GetIterations(); if (v < 0) { throw ConstructParseException("'iterations' used when not inside a loop"); @@ -781,7 +796,7 @@ ExpressionValue ExpressionParser::ParseIdentifierExpression(bool evaluate, bool } case NamedConstant::line: - return ExpressionValue((int32_t)gb.MachineState().lineNumber); + return ExpressionValue((int32_t)gb.GetLineNumber()); default: THROW_INTERNAL_ERROR; @@ -1016,6 +1031,23 @@ ExpressionValue ExpressionParser::ParseIdentifierExpression(bool evaluate, bool // If we are not evaluating then the object expression doesn't have to exist, so don't retrieve it because that might throw an error if (evaluate) { + // Check for a parameter, local or global variable + if (StringStartsWith(id.c_str(), "param.")) + { + return GetVariableValue(gb.GetVariables(), id.c_str() + strlen("param."), true); + } + + if (StringStartsWith(id.c_str(), "global.")) + { + return GetVariableValue(reprap.globalVariables, id.c_str() + strlen("global."), false); + } + + if (StringStartsWith(id.c_str(), "var.")) + { + return GetVariableValue(gb.GetVariables(), id.c_str() + strlen("var."), false); + } + + // Else assume an object model value ExpressionValue value = reprap.GetObjectValue(context, nullptr, id.c_str()); if (context.ObsoleteFieldQueried() && obsoleteField.IsEmpty()) { @@ -1026,13 +1058,25 @@ ExpressionValue ExpressionParser::ParseIdentifierExpression(bool evaluate, bool return ExpressionValue(nullptr); } +// Get the value of a variable +ExpressionValue ExpressionParser::GetVariableValue(VariableSet& vars, const char *name, bool parameter) THROWS(GCodeException) +{ + const Variable* var = vars.Lookup(name); + if (var != nullptr && (!parameter || var->GetScope() < 0)) + { + return var->GetValue(); + } + + throw ConstructParseException((parameter) ? "unknown parameter '%s'" : "unknown variable '%s'", name); +} + // Parse a quoted string, given that the current character is double-quote // This is almost a copy of InternalGetQuotedString in class StringParser -void ExpressionParser::ParseQuotedString(const StringRef& str) THROWS(GCodeException) +ExpressionValue ExpressionParser::ParseQuotedString() THROWS(GCodeException) { - str.Clear(); + String<MaxStringExpressionLength> str; AdvancePointer(); - for (;;) + while (true) { char c = CurrentCharacter(); AdvancePointer(); @@ -1044,7 +1088,8 @@ void ExpressionParser::ParseQuotedString(const StringRef& str) THROWS(GCodeExcep { if (CurrentCharacter() != c) { - return; + StringHandle sh(str.c_str()); + return ExpressionValue(sh); } AdvancePointer(); } @@ -1058,7 +1103,7 @@ void ExpressionParser::ParseQuotedString(const StringRef& str) THROWS(GCodeExcep } else if (CurrentCharacter() == c) { - // Two backslashes are used to represent one + // Two quotes are used to represent one AdvancePointer(); } } @@ -1082,17 +1127,17 @@ int ExpressionParser::GetColumn() const noexcept GCodeException ExpressionParser::ConstructParseException(const char *str) const noexcept { - return GCodeException(gb.MachineState().lineNumber, GetColumn(), str); + return GCodeException(gb.GetLineNumber(), GetColumn(), str); } GCodeException ExpressionParser::ConstructParseException(const char *str, const char *param) const noexcept { - return GCodeException(gb.MachineState().lineNumber, GetColumn(), str, param); + return GCodeException(gb.GetLineNumber(), GetColumn(), str, param); } GCodeException ExpressionParser::ConstructParseException(const char *str, uint32_t param) const noexcept { - return GCodeException(gb.MachineState().lineNumber, GetColumn(), str, param); + return GCodeException(gb.GetLineNumber(), GetColumn(), str, param); } // End diff --git a/src/GCodes/GCodeBuffer/ExpressionParser.h b/src/GCodes/GCodeBuffer/ExpressionParser.h index 4c70393a..c965b605 100644 --- a/src/GCodes/GCodeBuffer/ExpressionParser.h +++ b/src/GCodes/GCodeBuffer/ExpressionParser.h @@ -9,16 +9,18 @@ #define SRC_GCODES_GCODEBUFFER_EXPRESSIONPARSER_H_ #include <RepRapFirmware.h> -#include <General/StringBuffer.h> #include <ObjectModel/ObjectModel.h> #include <GCodes/GCodeException.h> +class VariableSet; + class ExpressionParser { public: ExpressionParser(const GCodeBuffer& p_gb, const char *text, const char *textLimit, int p_column = -1) noexcept; ExpressionValue Parse(bool evaluate = true) THROWS(GCodeException); + ExpressionValue ParseSimple() THROWS(GCodeException); bool ParseBoolean() THROWS(GCodeException); float ParseFloat() THROWS(GCodeException); int32_t ParseInteger() THROWS(GCodeException); @@ -39,7 +41,8 @@ private: pre(readPointer >= 0; isdigit(gb.buffer[readPointer])); ExpressionValue ParseIdentifierExpression(bool evaluate, bool applyLengthOperator) THROWS(GCodeException) pre(readPointer >= 0; isalpha(gb.buffer[readPointer])); - void ParseQuotedString(const StringRef& str) THROWS(GCodeException); + ExpressionValue ParseQuotedString() THROWS(GCodeException); + ExpressionValue GetVariableValue(VariableSet& vars, const char *name, bool parameter) THROWS(GCodeException); void ConvertToFloat(ExpressionValue& val, bool evaluate) const THROWS(GCodeException); void ConvertToBool(ExpressionValue& val, bool evaluate) const THROWS(GCodeException); @@ -50,7 +53,6 @@ private: void EnsureNumeric(ExpressionValue& val, bool evaluate) const THROWS(GCodeException); static bool TypeHasNoLiterals(TypeCode t) noexcept; - const char *GetAndFix() THROWS(GCodeException); int GetColumn() const noexcept; char CurrentCharacter() const noexcept; void AdvancePointer() noexcept { ++currentp; } // could check that we havebn't reached endp but we should stop before that happens @@ -60,8 +62,6 @@ private: const char * const endp; const GCodeBuffer& gb; int column; - char stringBufferStorage[StringBufferLength]; - StringBuffer stringBuffer; String<MaxVariableNameLength> obsoleteField; }; diff --git a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp index f957a23f..43d2e26a 100644 --- a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp +++ b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp @@ -55,7 +55,7 @@ constexpr ObjectModelTableEntry GCodeBuffer::objectModelTable[] = { "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->machineState->lineNumber), ObjectModelEntryFlags::live }, + { "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 }, @@ -349,7 +349,7 @@ void GCodeBuffer::MustSee(char c) THROWS(GCodeException) { if (!Seen(c)) { - throw GCodeException(machineState->lineNumber, -1, "missing parameter '%c'", (uint32_t)c); + throw GCodeException(GetLineNumber(), -1, "missing parameter '%c'", (uint32_t)c); } } @@ -365,11 +365,11 @@ float GCodeBuffer::GetLimitedFValue(char c, float minValue, float maxValue) THRO const float ret = GetFValue(); if (ret < minValue) { - throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too low", (uint32_t)c); + throw GCodeException(GetLineNumber(), -1, "parameter '%c' too low", (uint32_t)c); } if (ret > maxValue) { - throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too high", (uint32_t)c); + throw GCodeException(GetLineNumber(), -1, "parameter '%c' too high", (uint32_t)c); } return ret; } @@ -393,11 +393,11 @@ int32_t GCodeBuffer::GetLimitedIValue(char c, int32_t minValue, int32_t maxValue const int32_t ret = GetIValue(); if (ret < minValue) { - throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too low", (uint32_t)c); + throw GCodeException(GetLineNumber(), -1, "parameter '%c' too low", (uint32_t)c); } if (ret > maxValue) { - throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too high", (uint32_t)c); + throw GCodeException(GetLineNumber(), -1, "parameter '%c' too high", (uint32_t)c); } return ret; } @@ -415,11 +415,11 @@ uint32_t GCodeBuffer::GetLimitedUIValue(char c, uint32_t minValue, uint32_t maxV const uint32_t ret = GetUIValue(); if (ret < minValue) { - throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too low", (uint32_t)c); + throw GCodeException(GetLineNumber(), -1, "parameter '%c' too low", (uint32_t)c); } if (ret >= maxValuePlusOne) { - throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too high", (uint32_t)c); + throw GCodeException(GetLineNumber(), -1, "parameter '%c' too high", (uint32_t)c); } return ret; } @@ -527,11 +527,11 @@ bool GCodeBuffer::TryGetLimitedIValue(char c, int32_t& val, bool& seen, int32_t { if (val < minValue) { - throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too low", (uint32_t)c); + throw GCodeException(GetLineNumber(), -1, "parameter '%c' too low", (uint32_t)c); } if (val > maxValue) { - throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too high", (uint32_t)c); + throw GCodeException(GetLineNumber(), -1, "parameter '%c' too high", (uint32_t)c); } } return b; @@ -555,7 +555,7 @@ bool GCodeBuffer::TryGetLimitedUIValue(char c, uint32_t& val, bool& seen, uint32 const bool b = TryGetUIValue(c, val, seen); if (b && val >= maxValuePlusOne) { - throw GCodeException(machineState->lineNumber, -1, "parameter '%c' too high", (uint32_t)c); + throw GCodeException(GetLineNumber(), -1, "parameter '%c' too high", (uint32_t)c); } return b; } @@ -706,6 +706,16 @@ GCodeMachineState& GCodeBuffer::OriginalMachineState() const noexcept return *ms; } +GCodeMachineState& GCodeBuffer::CurrentFileMachineState() const noexcept +{ + GCodeMachineState *ms = machineState; + while (ms->localPush && ms->GetPrevious() != nullptr) + { + ms = ms->GetPrevious(); + } + return *ms; +} + // Convert from inches to mm if necessary float GCodeBuffer::ConvertDistance(float distance) const noexcept { @@ -754,10 +764,6 @@ bool GCodeBuffer::PopState(bool withinSameFile) noexcept } machineState = ms->GetPrevious(); - if (withinSameFile) - { - machineState->lineNumber = ms->lineNumber; - } delete ms; return true; @@ -1011,4 +1017,19 @@ void GCodeBuffer::AppendFullCommand(const StringRef &s) const noexcept PARSER_OPERATION(AppendFullCommand(s)); } +void GCodeBuffer::SetParameters(int codeRunning) noexcept +{ + PARSER_OPERATION(SetParameters(GetVariables(), codeRunning)); +} + +VariableSet& GCodeBuffer::GetVariables() const noexcept +{ + GCodeMachineState *mc = machineState; + while (mc->localPush && mc->GetPrevious() != nullptr) + { + mc = mc->GetPrevious(); + } + return mc->variables; +} + // End diff --git a/src/GCodes/GCodeBuffer/GCodeBuffer.h b/src/GCodes/GCodeBuffer/GCodeBuffer.h index b4e721f4..e6f479fd 100644 --- a/src/GCodes/GCodeBuffer/GCodeBuffer.h +++ b/src/GCodes/GCodeBuffer/GCodeBuffer.h @@ -49,7 +49,7 @@ public: void Init() noexcept; // Set it up to parse another G-code void Diagnostics(MessageType mtype) noexcept; // Write some debug info - bool Put(char c) noexcept SPEED_CRITICAL; // Add a character to the end + bool Put(char c) noexcept SPEED_CRITICAL; // Add a character to the end #if HAS_LINUX_INTERFACE void PutBinary(const uint32_t *data, size_t len) noexcept; // Add an entire binary G-Code, overwriting any existing content #endif @@ -66,7 +66,7 @@ public: int8_t GetCommandFraction() const noexcept; // Return the command fraction, or -1 if none given bool ContainsExpression() const noexcept; void GetCompleteParameters(const StringRef& str) THROWS(GCodeException); // Get all of the line following the command. Currently called only for the Q0 command. - int32_t GetLineNumber() const noexcept { return machineState->lineNumber; } + int32_t GetLineNumber() const noexcept { return CurrentFileMachineState().lineNumber; } bool IsLastCommand() const noexcept; GCodeResult GetLastResult() const noexcept { return lastResult; } void SetLastResult(GCodeResult r) noexcept { lastResult = r; } @@ -122,8 +122,12 @@ public: void SetCommsProperties(uint32_t arg) noexcept; - GCodeMachineState& MachineState() const noexcept { return *machineState; } + GCodeMachineState& LatestMachineState() const noexcept { return *machineState; } + GCodeMachineState& CurrentFileMachineState() const noexcept; GCodeMachineState& OriginalMachineState() const noexcept; + GCodeMachineState::BlockState& GetBlockState() const noexcept { return CurrentFileMachineState().CurrentBlockState(); } + uint16_t GetBlockIndent() const noexcept { return GetBlockState().GetIndent(); } + float ConvertDistance(float distance) const noexcept; float InverseConvertDistance(float distance) const noexcept; unsigned int GetStackDepth() const noexcept; @@ -223,6 +227,9 @@ public: void MotionStopped() noexcept { motionCommanded = false; } bool WasMotionCommanded() const noexcept { return motionCommanded; } + void SetParameters(int codeRunning) noexcept; + VariableSet& GetVariables() const noexcept; + Mutex mutex; protected: diff --git a/src/GCodes/GCodeBuffer/StringParser.cpp b/src/GCodes/GCodeBuffer/StringParser.cpp index 5e9b139a..dad4f3e6 100644 --- a/src/GCodes/GCodeBuffer/StringParser.cpp +++ b/src/GCodes/GCodeBuffer/StringParser.cpp @@ -14,7 +14,6 @@ #include <GCodes/GCodes.h> #include <Platform/Platform.h> #include <Platform/RepRap.h> -#include <General/StringBuffer.h> #include <Networking/NetworkDefs.h> // Replace the default definition of THROW_INTERNAL_ERROR by one that gives line information @@ -271,11 +270,11 @@ bool StringParser::LineFinished() { if (hadLineNumber) { - gb.machineState->lineNumber = receivedLineNumber; + gb.CurrentFileMachineState().lineNumber = receivedLineNumber; } else { - ++gb.machineState->lineNumber; + ++gb.CurrentFileMachineState().lineNumber; } if (gcodeLineEnd == 0) @@ -290,7 +289,7 @@ bool StringParser::LineFinished() if (gb.bufferState != GCodeBufferState::parsingComment) // we don't checksum comment lines { const bool badChecksum = (hadChecksum && computedChecksum != declaredChecksum); - const bool missingChecksum = (checksumRequired && !hadChecksum && gb.machineState->GetPrevious() == nullptr); + const bool missingChecksum = (checksumRequired && !hadChecksum && gb.LatestMachineState().GetPrevious() == nullptr); if (reprap.GetDebugFlags(moduleGcodes).IsBitSet(gb.GetChannel().ToBaseType()) && fileBeingWritten == nullptr) { debugPrintf("%s%s: %s\n", gb.GetChannel().ToString(), ((badChecksum) ? "(bad-csum)" : (missingChecksum) ? "(no-csum)" : ""), gb.buffer); @@ -307,7 +306,7 @@ bool StringParser::CheckMetaCommand(const StringRef& reply) THROWS(GCodeExceptio { if (overflowed) { - throw GCodeException(gb.MachineState().lineNumber, ARRAY_SIZE(gb.buffer) - 1, "GCode command too long"); + throw GCodeException(gb.GetLineNumber(), ARRAY_SIZE(gb.buffer) - 1, "GCode command too long"); } const bool doingFile = gb.IsDoingFile(); @@ -337,30 +336,30 @@ bool StringParser::CheckMetaCommand(const StringRef& reply) THROWS(GCodeExceptio // Finished skipping the nested block if (indentToSkipTo == commandIndent) { - skippedBlockType = gb.machineState->CurrentBlockState().GetType(); // save the type of the block we skipped in case the command is 'else' or 'elif' - gb.machineState->CurrentBlockState().SetPlainBlock(); // we've ended the loop or if-block + skippedBlockType = gb.GetBlockState().GetType(); // save the type of the block we skipped in case the command is 'else' or 'elif' + gb.GetBlockState().SetPlainBlock(); // we've ended the loop or if-block } indentToSkipTo = NoIndentSkip; // no longer skipping } } - while (commandIndent < gb.machineState->CurrentBlockIndent()) + while (commandIndent < gb.GetBlockIndent()) { - gb.machineState->EndBlock(); - if (gb.machineState->CurrentBlockState().GetType() == BlockType::loop) + gb.CurrentFileMachineState().EndBlock(); + if (gb.GetBlockState().GetType() == BlockType::loop) { // Go back to the start of the loop and re-evaluate the while-part - gb.machineState->lineNumber = gb.machineState->CurrentBlockState().GetLineNumber(); - gb.RestartFrom(gb.machineState->CurrentBlockState().GetFilePosition()); + gb.CurrentFileMachineState().lineNumber = gb.GetBlockState().GetLineNumber(); + gb.RestartFrom(gb.GetBlockState().GetFilePosition()); Init(); return true; } } - if (commandIndent > gb.machineState->CurrentBlockIndent()) + if (commandIndent > gb.GetBlockIndent()) { // Indentation has increased so start new block(s) - if (!gb.machineState->CreateBlock(commandIndent)) + if (!gb.CurrentFileMachineState().CreateBlock(commandIndent)) { throw ConstructParseException("blocks nested too deeply"); } @@ -393,7 +392,7 @@ void StringParser::CheckForMixedSpacesAndTabs() noexcept if (seenMetaCommand && !warnedAboutMixedSpacesAndTabs && seenLeadingSpace && seenLeadingTab) { reprap.GetPlatform().MessageF(AddWarning(gb.GetResponseMessageType()), - "both space and tab characters used to indent blocks by line %" PRIu32, gb.MachineState().lineNumber); + "both space and tab characters used to indent blocks by line %" PRIu32, gb.GetLineNumber()); warnedAboutMixedSpacesAndTabs = true; } } @@ -428,18 +427,15 @@ bool StringParser::ProcessConditionalGCode(const StringRef& reply, BlockType ski break; case 3: - if (doingFile) + if (doingFile && StringStartsWith(command, "var")) { - if (StringStartsWith(command, "var")) - { - ProcessVarCommand(); - return true; - } - if (StringStartsWith(command, "set")) - { - ProcessSetCommand(); - return true; - } + ProcessVarOrGlobalCommand(false); + return true; + } + if (StringStartsWith(command, "set")) + { + ProcessSetCommand(); + return true; } break; @@ -489,6 +485,14 @@ bool StringParser::ProcessConditionalGCode(const StringRef& reply, BlockType ski } break; + case 6: + if (StringStartsWith(command, "global")) + { + ProcessVarOrGlobalCommand(true); + return true; + } + break; + case 8: if (doingFile && StringStartsWith(command, "continue")) { @@ -506,29 +510,29 @@ bool StringParser::ProcessConditionalGCode(const StringRef& reply, BlockType ski return false; } -void StringParser::ProcessIfCommand() +void StringParser::ProcessIfCommand() THROWS(GCodeException) { if (EvaluateCondition()) { - gb.machineState->CurrentBlockState().SetIfTrueBlock(); + gb.GetBlockState().SetIfTrueBlock(); } else { - gb.machineState->CurrentBlockState().SetIfFalseNoneTrueBlock(); - indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the block + gb.GetBlockState().SetIfFalseNoneTrueBlock(); + indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the block } } -void StringParser::ProcessElseCommand(BlockType skippedBlockType) +void StringParser::ProcessElseCommand(BlockType skippedBlockType) THROWS(GCodeException) { if (skippedBlockType == BlockType::ifFalseNoneTrue) { - gb.machineState->CurrentBlockState().SetPlainBlock(); // execute the else-block, treating it like a plain block + gb.GetBlockState().SetPlainBlock(); // execute the else-block, treating it like a plain block } - else if (skippedBlockType == BlockType::ifFalseHadTrue || gb.machineState->CurrentBlockState().GetType() == BlockType::ifTrue) + else if (skippedBlockType == BlockType::ifFalseHadTrue || gb.GetBlockState().GetType() == BlockType::ifTrue) { - indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the if-block - gb.machineState->CurrentBlockState().SetPlainBlock(); // so that we get an error if there is another 'else' part + indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the if-block + gb.GetBlockState().SetPlainBlock(); // so that we get an error if there is another 'else' part } else { @@ -536,24 +540,24 @@ void StringParser::ProcessElseCommand(BlockType skippedBlockType) } } -void StringParser::ProcessElifCommand(BlockType skippedBlockType) +void StringParser::ProcessElifCommand(BlockType skippedBlockType) THROWS(GCodeException) { if (skippedBlockType == BlockType::ifFalseNoneTrue) { if (EvaluateCondition()) { - gb.machineState->CurrentBlockState().SetIfTrueBlock(); + gb.GetBlockState().SetIfTrueBlock(); } else { - indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the elif-block - gb.machineState->CurrentBlockState().SetIfFalseNoneTrueBlock(); + indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the elif-block + gb.GetBlockState().SetIfFalseNoneTrueBlock(); } } - else if (skippedBlockType == BlockType::ifFalseHadTrue || gb.machineState->CurrentBlockState().GetType() == BlockType::ifTrue) + else if (skippedBlockType == BlockType::ifFalseHadTrue || gb.GetBlockState().GetType() == BlockType::ifTrue) { - indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the if-block - gb.machineState->CurrentBlockState().SetIfFalseHadTrueBlock(); + indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the if-block + gb.GetBlockState().SetIfFalseHadTrueBlock(); } else { @@ -561,69 +565,138 @@ void StringParser::ProcessElifCommand(BlockType skippedBlockType) } } -void StringParser::ProcessWhileCommand() +void StringParser::ProcessWhileCommand() THROWS(GCodeException) { // Set the current block as a loop block first so that we may use 'iterations' in the condition - if (gb.machineState->CurrentBlockState().GetType() == BlockType::loop) + if (gb.GetBlockState().GetType() == BlockType::loop) { - gb.machineState->CurrentBlockState().IncrementIterations(); // starting another iteration + gb.GetBlockState().IncrementIterations(); // starting another iteration } else { - gb.machineState->CurrentBlockState().SetLoopBlock(GetFilePosition(), gb.machineState->lineNumber); + gb.GetBlockState().SetLoopBlock(GetFilePosition(), gb.GetLineNumber()); } if (!EvaluateCondition()) { - gb.machineState->CurrentBlockState().SetPlainBlock(); - indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the block + gb.GetBlockState().SetPlainBlock(); + indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the block } } -void StringParser::ProcessBreakCommand() +void StringParser::ProcessBreakCommand() THROWS(GCodeException) { do { - if (gb.machineState->CurrentBlockIndent() == 0) + if (gb.GetBlockIndent() == 0) { throw ConstructParseException("'break' was not inside a loop"); } - gb.machineState->EndBlock(); - } while (gb.machineState->CurrentBlockState().GetType() != BlockType::loop); - gb.machineState->CurrentBlockState().SetPlainBlock(); - indentToSkipTo = gb.machineState->CurrentBlockIndent(); // skip forwards to the end of the loop + gb.CurrentFileMachineState().EndBlock(); + } while (gb.GetBlockState().GetType() != BlockType::loop); + gb.GetBlockState().SetPlainBlock(); + indentToSkipTo = gb.GetBlockIndent(); // skip forwards to the end of the loop } -void StringParser::ProcessContinueCommand() +void StringParser::ProcessContinueCommand() THROWS(GCodeException) { do { - if (gb.machineState->CurrentBlockIndent() == 0) + if (gb.GetBlockIndent() == 0) { throw ConstructParseException("'continue' was not inside a loop"); } - gb.machineState->EndBlock(); - } while (gb.machineState->CurrentBlockState().GetType() != BlockType::loop); + gb.CurrentFileMachineState().EndBlock(); + } while (gb.GetBlockState().GetType() != BlockType::loop); // Go back to the start of the loop and re-evaluate the while-part - gb.machineState->lineNumber = gb.machineState->CurrentBlockState().GetLineNumber(); - gb.RestartFrom(gb.machineState->CurrentBlockState().GetFilePosition()); + gb.CurrentFileMachineState().lineNumber = gb.GetBlockState().GetLineNumber(); + gb.RestartFrom(gb.GetBlockState().GetFilePosition()); } -void StringParser::ProcessVarCommand() +void StringParser::ProcessVarOrGlobalCommand(bool isGlobal) THROWS(GCodeException) { -#if 0 SkipWhiteSpace(); + + // Get the identifier + char c = gb.buffer[readPointer]; + if (!isalpha(c)) + { + throw ConstructParseException("expected a new variable name"); + } String<MaxVariableNameLength> varName; - ParseIdentifier(varName.GetRef()); - qq; -#endif - throw ConstructParseException("'var' not implemented"); + do + { + varName.cat(c); + ++readPointer; + c = gb.buffer[readPointer]; + } while (isalpha(c) || isdigit(c) || c == '_' ); + + // Expect '=' + SkipWhiteSpace(); + if (gb.buffer[readPointer] != '=') + { + throw ConstructParseException("expected '='"); + } + ++readPointer; + + // Check whether the identifier already exists + VariableSet& vset = (isGlobal) ? reprap.globalVariables : gb.GetVariables(); + Variable * const v = vset.Lookup(varName.c_str()); + if (v != nullptr) + { + // For now we don't allow an existing variable to be reassigned using a 'var' or 'global' statement. We may need to allow it for 'global' statements. + throw ConstructParseException("variable '%s' already exists", varName.c_str()); + } + + SkipWhiteSpace(); + ExpressionParser parser(gb, gb.buffer + readPointer, gb.buffer + ARRAY_SIZE(gb.buffer), commandIndent + readPointer); + ExpressionValue ev = parser.Parse(); + vset.Insert(new Variable(varName.c_str(), ev, (isGlobal) ? 0 : gb.CurrentFileMachineState().GetBlockNesting())); } -void StringParser::ProcessSetCommand() +void StringParser::ProcessSetCommand() THROWS(GCodeException) { - throw ConstructParseException("'set' not implemented"); + // Skip the "var." or "global." prefix + SkipWhiteSpace(); + VariableSet& vset = (StringStartsWith(gb.buffer + readPointer, "global.")) ? (readPointer += strlen("global."), reprap.globalVariables) + : (StringStartsWith(gb.buffer + readPointer, "var.")) ? (readPointer += strlen("var."), gb.GetVariables()) + : throw ConstructParseException("expected a global or local variable"); + + // Get the identifier + char c = gb.buffer[readPointer]; + if (!isalpha(c)) + { + throw ConstructParseException("expected a new variable name"); + } + + String<MaxVariableNameLength> varName; + do + { + varName.cat(c); + ++readPointer; + c = gb.buffer[readPointer]; + } while (isalpha(c) || isdigit(c) || c == '_' ); + + // Expect '=' + SkipWhiteSpace(); + if (gb.buffer[readPointer] != '=') + { + throw ConstructParseException("expected '='"); + } + ++readPointer; + + // Look up the identifier + Variable * const var = vset.Lookup(varName.c_str()); + if (var == nullptr) + { + throw ConstructParseException("unknown variable '%s'", varName.c_str()); + } + + SkipWhiteSpace(); + ExpressionParser parser(gb, gb.buffer + readPointer, gb.buffer + ARRAY_SIZE(gb.buffer), commandIndent + readPointer); + ExpressionValue ev = parser.Parse(); + var->Assign(ev); } void StringParser::ProcessAbortCommand(const StringRef& reply) noexcept @@ -752,6 +825,7 @@ void StringParser::DecodeCommand() noexcept // Find where the end of the command is. We assume that a G or M not inside quotes or { } and not preceded by ' is the start of a new command. bool inQuotes = false; unsigned int localBraceCount = 0; + parametersPresent.Clear(); for (commandEnd = parameterStart; commandEnd < gcodeLineEnd; ++commandEnd) { const char c = gb.buffer[commandEnd]; @@ -774,11 +848,15 @@ void StringParser::DecodeCommand() noexcept } else { - char c2; - if (((c2 = toupper(c)) == 'G' || c2 == 'M') && gb.buffer[commandEnd - 1] != '\'') + const char c2 = toupper(c); + if ((c2 == 'G' || c2 == 'M') && gb.buffer[commandEnd - 1] != '\'') { break; } + if (c2 >= 'A' && c2 <= 'Z' && (c2 != 'E' || commandEnd == parameterStart || !isdigit(gb.buffer[commandEnd - 1]))) + { + parametersPresent.SetBit(c2 - 'A'); + } } } } @@ -866,7 +944,7 @@ void StringParser::SetFinished() noexcept } else { - gb.machineState->g53Active = false; // G53 does not persist beyond the current line + gb.LatestMachineState().g53Active = false; // G53 does not persist beyond the current line Init(); } } @@ -875,13 +953,13 @@ void StringParser::SetFinished() noexcept FilePosition StringParser::GetFilePosition() const noexcept { #if HAS_MASS_STORAGE - if (gb.machineState->DoingFile() + if (gb.LatestMachineState().DoingFile() # if HAS_LINUX_INTERFACE && !reprap.UsingLinuxInterface() # endif ) { - return gb.machineState->fileState.GetPosition() - gb.fileInput->BytesCached() - commandLength + commandStart; + return gb.LatestMachineState().fileState.GetPosition() - gb.fileInput->BytesCached() - commandLength + commandStart; } #endif return noFilePosition; @@ -903,18 +981,22 @@ bool StringParser::IsLastCommand() const noexcept return commandEnd >= gcodeLineEnd; // using >= here also covers the case where the buffer is empty and gcodeLineEnd has been set to zero } -// Is 'c' in the G Code string? 'c' must be uppercase. +// Is 'c' in the G Code string? // Leave the pointer one after it for a subsequent read. bool StringParser::Seen(char c) noexcept { - bool inQuotes = false; - bool escaped = false; bool wantLowerCase = (c >= 'a'); if (wantLowerCase) { c = toupper(c); } + else if (!parametersPresent.IsBitSet(c - 'A')) + { + return false; + } + bool inQuotes = false; + bool escaped = false; unsigned int inBrackets = 0; for (readPointer = parameterStart; (unsigned int)readPointer < commandEnd; ++readPointer) { @@ -1431,7 +1513,7 @@ void StringParser::WriteToFile() noexcept fileBeingWritten->Close(); fileBeingWritten = nullptr; Init(); - const char* const r = (gb.MachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : ""; + const char* const r = (gb.LatestMachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : ""; reprap.GetGCodes().HandleReply(gb, GCodeResult::ok, r); return; } @@ -1494,7 +1576,7 @@ void StringParser::FinishWritingBinary() noexcept binaryWriting = false; if (crcOk) { - const char* const r = (gb.MachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : ""; + const char* const r = (gb.LatestMachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : ""; reprap.GetGCodes().HandleReply(gb, GCodeResult::ok, r); } else @@ -1541,12 +1623,12 @@ bool StringParser::FileEnded() noexcept fileBeingWritten->Close(); fileBeingWritten = nullptr; SetFinished(); - const char* const r = (gb.MachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : ""; + const char* const r = (gb.LatestMachineState().compatibility == Compatibility::Marlin) ? "Done saving file." : ""; reprap.GetGCodes().HandleReply(gb, GCodeResult::ok, r); return false; } - if (!commandCompleted && gb.MachineState().GetIterations() >= 0) + if (!commandCompleted && gb.CurrentFileMachineState().GetIterations() >= 0) { // We reached the end of the file while inside a loop. Insert a dummy 'skip' command to allow the loop processing to complete. Init(); @@ -1662,19 +1744,39 @@ void StringParser::SkipWhiteSpace() noexcept } } +void StringParser::SetParameters(VariableSet& vs, int codeRunning) noexcept +{ + parametersPresent.Iterate([this, &vs, codeRunning](unsigned int bit, unsigned int count) + { + const char letter = 'A' + bit; + if ((letter != 'P' || codeRunning != 98) && Seen(letter)) + { + ExpressionParser parser(gb, &gb.buffer[readPointer], &gb.buffer[commandEnd]); + try + { + ExpressionValue ev = parser.Parse(); + char paramName[2] = { letter, 0 }; + vs.Insert(new Variable(paramName, ev, -1)); + } + catch (const GCodeException&) { } + } + } + ); +} + GCodeException StringParser::ConstructParseException(const char *str) const noexcept { - return GCodeException(gb.machineState->lineNumber, readPointer + commandIndent, str); + return GCodeException(gb.GetLineNumber(), readPointer + commandIndent, str); } GCodeException StringParser::ConstructParseException(const char *str, const char *param) const noexcept { - return GCodeException(gb.machineState->lineNumber, readPointer + commandIndent, str, param); + return GCodeException(gb.GetLineNumber(), readPointer + commandIndent, str, param); } GCodeException StringParser::ConstructParseException(const char *str, uint32_t param) const noexcept { - return GCodeException(gb.machineState->lineNumber, readPointer + commandIndent, str, param); + return GCodeException(gb.GetLineNumber(), readPointer + commandIndent, str, param); } // End diff --git a/src/GCodes/GCodeBuffer/StringParser.h b/src/GCodes/GCodeBuffer/StringParser.h index e30de69a..6ac3279f 100644 --- a/src/GCodes/GCodeBuffer/StringParser.h +++ b/src/GCodes/GCodeBuffer/StringParser.h @@ -19,7 +19,7 @@ class GCodeBuffer; class IPAddress; class MacAddress; -class StringBuffer; +class VariableSet; class StringParser { @@ -82,6 +82,7 @@ public: void PrintCommand(const StringRef& s) const noexcept; void AppendFullCommand(const StringRef &s) const noexcept; + void SetParameters(VariableSet& vs, int codeRunning) noexcept; GCodeException ConstructParseException(const char *str) const noexcept; GCodeException ConstructParseException(const char *str, const char *param) const noexcept; @@ -113,7 +114,7 @@ private: void ProcessWhileCommand() THROWS(GCodeException); void ProcessBreakCommand() THROWS(GCodeException); void ProcessContinueCommand() THROWS(GCodeException); - void ProcessVarCommand() THROWS(GCodeException); + void ProcessVarOrGlobalCommand(bool isGlobal) THROWS(GCodeException); void ProcessSetCommand() THROWS(GCodeException); void ProcessAbortCommand(const StringRef& reply) noexcept; void ProcessEchoCommand(const StringRef& reply) THROWS(GCodeException); @@ -128,6 +129,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 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/GCodeMachineState.cpp b/src/GCodes/GCodeMachineState.cpp index e0868f08..b3fc004a 100644 --- a/src/GCodes/GCodeMachineState.cpp +++ b/src/GCodes/GCodeMachineState.cpp @@ -20,13 +20,13 @@ GCodeMachineState::GCodeMachineState() noexcept selectedPlane(0), drivesRelative(false), axesRelative(false), doingFileMacro(false), waitWhileCooling(false), runningM501(false), runningM502(false), volumetricExtrusion(false), g53Active(false), runningSystemMacro(false), usingInches(false), - waitingForAcknowledgement(false), messageAcknowledged(false), + waitingForAcknowledgement(false), messageAcknowledged(false), localPush(false), #if HAS_LINUX_INTERFACE lastCodeFromSbc(false), macroStartedByCode(false), fileFinished(false), #endif - compatibility(Compatibility::RepRapFirmware), blockNesting(0), + compatibility(Compatibility::RepRapFirmware), previous(nullptr), errorMessage(nullptr), - state(GCodeState::normal), stateMachineResult(GCodeResult::ok) + blockNesting(0), state(GCodeState::normal), stateMachineResult(GCodeResult::ok) { blockStates[0].SetPlainBlock(0); } @@ -41,17 +41,17 @@ GCodeMachineState::GCodeMachineState(GCodeMachineState& prev, bool withinSameFil fileId(prev.fileId), #endif lockedResources(prev.lockedResources), - lineNumber((withinSameFile) ? prev.lineNumber : 0), + lineNumber(0), selectedPlane(prev.selectedPlane), drivesRelative(prev.drivesRelative), axesRelative(prev.axesRelative), doingFileMacro(prev.doingFileMacro), waitWhileCooling(prev.waitWhileCooling), runningM501(prev.runningM501), runningM502(prev.runningM502), volumetricExtrusion(false), g53Active(false), runningSystemMacro(prev.runningSystemMacro), usingInches(prev.usingInches), - waitingForAcknowledgement(false), messageAcknowledged(false), + waitingForAcknowledgement(false), messageAcknowledged(false), localPush(withinSameFile), #if HAS_LINUX_INTERFACE lastCodeFromSbc(prev.lastCodeFromSbc), macroStartedByCode(prev.macroStartedByCode), fileFinished(prev.fileFinished), #endif - compatibility(prev.compatibility), blockNesting((withinSameFile) ? prev.blockNesting : 0), + compatibility(prev.compatibility), previous(&prev), errorMessage(nullptr), - state(GCodeState::normal), stateMachineResult(GCodeResult::ok) + blockNesting((withinSameFile) ? prev.blockNesting : 0), state(GCodeState::normal), stateMachineResult(GCodeResult::ok) { if (withinSameFile) { @@ -245,6 +245,7 @@ void GCodeMachineState::EndBlock() noexcept if (blockNesting != 0) { --blockNesting; + variables.EndScope(blockNesting); } } diff --git a/src/GCodes/GCodeMachineState.h b/src/GCodes/GCodeMachineState.h index 96b17d5c..2ddc96d6 100644 --- a/src/GCodes/GCodeMachineState.h +++ b/src/GCodes/GCodeMachineState.h @@ -13,6 +13,7 @@ #include <General/FreelistManager.h> #include <General/NamedEnum.h> #include <GCodes/GCodeResult.h> +#include <GCodes/Variable.h> // Enumeration to list all the possible states that the Gcode processing machine may be in enum class GCodeState : uint8_t @@ -183,13 +184,15 @@ public: inline void AdvanceState() noexcept { state = static_cast<GCodeState>(static_cast<uint8_t>(state) + 1); } GCodeMachineState *GetPrevious() const noexcept { return previous; } + uint8_t GetBlockNesting() const noexcept { return blockNesting; } + VariableSet variables; // local variables and parameters float feedRate; #if HAS_MASS_STORAGE FileData fileState; #endif #if HAS_LINUX_INTERFACE - FileId fileId; // virtual ID to distinguish files in different stack levels (only unique per GB) + FileId fileId; // virtual ID to distinguish files in different stack levels (only unique per GB) #endif ResourceBitmap lockedResources; BlockState blockStates[MaxBlockIndent]; @@ -209,7 +212,8 @@ public: usingInches : 1, // true if units are inches not mm waitingForAcknowledgement : 1, messageAcknowledged : 1, - messageCancelled : 1 + messageCancelled : 1, + localPush : 1 // true if this stack frame was created by M120, so we use the parent variables #if HAS_LINUX_INTERFACE , lastCodeFromSbc : 1, macroStartedByCode : 1, @@ -218,7 +222,6 @@ public: ; Compatibility compatibility; - uint8_t blockNesting; uint16_t stateParameter; // a parameter, the meaning of which depends on what state we are in bool DoingFile() const noexcept; @@ -244,7 +247,6 @@ public: BlockState& CurrentBlockState() noexcept; const BlockState& CurrentBlockState() const noexcept; int32_t GetIterations() const noexcept; - uint16_t CurrentBlockIndent() const noexcept { return CurrentBlockState().GetIndent(); } bool CreateBlock(uint16_t indentLevel) noexcept; void EndBlock() noexcept; @@ -252,6 +254,7 @@ public: private: GCodeMachineState *previous; const char *errorMessage; + uint8_t blockNesting; GCodeState state; GCodeResult stateMachineResult; // the worst status (ok, warning or error) that we encountered while running the state machine }; diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index 8989d149..67e5b4e6 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -330,7 +330,7 @@ bool GCodes::WaitingForAcknowledgement() const noexcept { for (const GCodeBuffer *gbp : gcodeSources) { - if (gbp != nullptr && gbp->MachineState().waitingForAcknowledgement) + if (gbp != nullptr && gbp->LatestMachineState().waitingForAcknowledgement) { return true; } @@ -375,7 +375,7 @@ FilePosition GCodes::GetFilePosition() const noexcept // Start running the config file bool GCodes::RunConfigFile(const char* fileName) noexcept { - runningConfigFile = DoFileMacro(*triggerGCode, fileName, false); + runningConfigFile = DoFileMacro(*triggerGCode, fileName, false, SystemMacroCode); return runningConfigFile; } @@ -390,14 +390,14 @@ void GCodes::CheckFinishedRunningConfigFile(GCodeBuffer& gb) noexcept { if (runningConfigFile) { - gb.MachineState().GetPrevious()->CopyStateFrom(gb.MachineState()); // so that M83 etc. in nested file don't get forgotten - if (gb.MachineState().GetPrevious()->GetPrevious() == nullptr) + gb.LatestMachineState().GetPrevious()->CopyStateFrom(gb.LatestMachineState()); // so that M83 etc. in nested file don't get forgotten + if (gb.LatestMachineState().GetPrevious()->GetPrevious() == nullptr) { for (GCodeBuffer *gb2 : gcodeSources) { if (gb2 != nullptr && gb2 != &gb) { - gb2->MachineState().CopyStateFrom(gb.MachineState()); + gb2->LatestMachineState().CopyStateFrom(gb.LatestMachineState()); } } runningConfigFile = false; @@ -444,7 +444,7 @@ void GCodes::Spin() noexcept GCodeBuffer *gbp = autoPauseGCode; if (!autoPauseGCode->IsCompletelyIdle() #if HAS_MASS_STORAGE || HAS_LINUX_INTERFACE - || autoPauseGCode->MachineState().DoingFile() + || autoPauseGCode->LatestMachineState().DoingFile() #endif ) // if autoPause is active { @@ -513,14 +513,14 @@ bool GCodes::SpinGCodeBuffer(GCodeBuffer& gb) noexcept MutexLocker gbLock(gb.mutex); if (gb.GetState() == GCodeState::normal) { - if (gb.MachineState().messageAcknowledged) + if (gb.LatestMachineState().messageAcknowledged) { - const bool wasCancelled = gb.MachineState().messageCancelled; + const bool wasCancelled = gb.LatestMachineState().messageCancelled; gb.PopState(false); // this could fail if the current macro has already been aborted if (wasCancelled) { - if (gb.MachineState().GetPrevious() == nullptr) + if (gb.LatestMachineState().GetPrevious() == nullptr) { StopPrint(StopPrintReason::userCancelled); } @@ -579,7 +579,7 @@ bool GCodes::StartNextGCode(GCodeBuffer& gb, const StringRef& reply) noexcept && gb.DoDwellTime(1000) ) { - return DoFileMacro(gb, DAEMON_G, false, -1); + return DoFileMacro(gb, DAEMON_G, false, SystemMacroCode); } } else @@ -633,7 +633,7 @@ bool GCodes::DoFilePrint(GCodeBuffer& gb, const StringRef& reply) noexcept if (gb.IsFileFinished()) { - if (gb.MachineState().GetPrevious() == nullptr) + if (gb.LatestMachineState().GetPrevious() == nullptr) { // Finished printing SD card file. // We never get here if the file ends in M0 because CancelPrint gets called directly in that case. @@ -662,7 +662,7 @@ bool GCodes::DoFilePrint(GCodeBuffer& gb, const StringRef& reply) noexcept if (gb.GetState() == GCodeState::normal) { UnlockAll(gb); - if (!gb.MachineState().lastCodeFromSbc || gb.MachineState().macroStartedByCode) + if (!gb.LatestMachineState().lastCodeFromSbc || gb.LatestMachineState().macroStartedByCode) { HandleReply(gb, GCodeResult::ok, ""); } @@ -675,7 +675,7 @@ bool GCodes::DoFilePrint(GCodeBuffer& gb, const StringRef& reply) noexcept else { bool gotCommand = false; - if (gb.MachineState().waitingForAcknowledgement && gb.GetNormalInput() != nullptr) + if (gb.LatestMachineState().waitingForAcknowledgement && gb.GetNormalInput() != nullptr) { gotCommand = gb.GetNormalInput()->FillBuffer(&gb); if (gotCommand) @@ -694,7 +694,7 @@ bool GCodes::DoFilePrint(GCodeBuffer& gb, const StringRef& reply) noexcept #endif { #if HAS_MASS_STORAGE - FileData& fd = gb.MachineState().fileState; + FileData& fd = gb.LatestMachineState().fileState; // Do we have more data to process? switch (gb.GetFileInput()->ReadFromFile(fd)) @@ -771,7 +771,7 @@ bool GCodes::DoFilePrint(GCodeBuffer& gb, const StringRef& reply) noexcept gb.Init(); // mark buffer as empty - if (gb.MachineState().GetPrevious() == nullptr) + if (gb.LatestMachineState().GetPrevious() == nullptr) { // Finished printing SD card file. // We never get here if the file ends in M0 because CancelPrint gets called directly in that case. @@ -855,7 +855,7 @@ void GCodes::CheckTriggers() noexcept triggersPending.ClearBit(lowestTriggerPending); // clear the trigger String<StringLength20> filename; filename.printf("trigger%u.g", lowestTriggerPending); - DoFileMacro(*triggerGCode, filename.c_str(), true); + DoFileMacro(*triggerGCode, filename.c_str(), true, SystemMacroCode); } } } @@ -908,7 +908,7 @@ void GCodes::DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg, uint1 else { // Pausing a file print via another input source or for some other reason - pauseRestorePoint.feedRate = fileGCode->MachineState().feedRate; // set up the default + pauseRestorePoint.feedRate = fileGCode->LatestMachineState().feedRate; // set up the default const bool movesSkipped = reprap.GetMove().PausePrint(pauseRestorePoint); // tell Move we wish to pause the current print if (movesSkipped) @@ -932,7 +932,7 @@ void GCodes::DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg, uint1 else { // We were not able to skip any moves, and there is no move waiting - pauseRestorePoint.feedRate = fileGCode->MachineState().feedRate; + pauseRestorePoint.feedRate = fileGCode->LatestMachineState().feedRate; pauseRestorePoint.virtualExtruderPosition = virtualExtruderPosition; pauseRestorePoint.proportionDone = 0.0; @@ -964,7 +964,7 @@ void GCodes::DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg, uint1 // The following could be delayed until we resume the print if (pauseRestorePoint.filePos != noFilePosition) { - FileData& fdata = fileGCode->MachineState().fileState; + FileData& fdata = fileGCode->LatestMachineState().fileState; if (fdata.IsLive()) { fileGCode->RestartFrom(pauseRestorePoint.filePos); // TODO we ought to restore the line number too, but currently we don't save it @@ -1145,7 +1145,7 @@ bool GCodes::DoEmergencyPause() noexcept else { // We were not able to skip any moves, and if there is a move waiting then we can't skip that one either - pauseRestorePoint.feedRate = fileGCode->MachineState().feedRate; + pauseRestorePoint.feedRate = fileGCode->LatestMachineState().feedRate; pauseRestorePoint.virtualExtruderPosition = virtualExtruderPosition; pauseRestorePoint.filePos = fileGCode->GetFilePosition(); @@ -1300,9 +1300,9 @@ bool GCodes::ReHomeOnStall(DriversBitmap stalledDrivers) noexcept // Now pass the machine axes to the rehome.g file // TODO - autoPauseGCode->SetState(GCodeState::resuming1); // set up to resume after rehoming + autoPauseGCode->SetState(GCodeState::resuming1); // set up to resume after rehoming pauseState = PauseState::resuming; - DoFileMacro(*autoPauseGCode, REHOME_G, true); // run the SD card rehome-and-resume script + DoFileMacro(*autoPauseGCode, REHOME_G, true, SystemMacroCode); // run the SD card rehome-and-resume script return true; } @@ -1607,11 +1607,11 @@ const char * GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, bool isP moveBuffer.applyM220M221 = (moveBuffer.moveType == 0 && isPrintingMove && !gb.IsDoingFileMacro()); if (gb.Seen(feedrateLetter)) { - gb.MachineState().feedRate = gb.GetDistance() * SecondsToMinutes; // update requested speed, not allowing for speed factor + gb.LatestMachineState().feedRate = gb.GetDistance() * SecondsToMinutes; // update requested speed, not allowing for speed factor } moveBuffer.feedRate = (moveBuffer.applyM220M221) - ? speedFactor * gb.MachineState().feedRate - : gb.MachineState().feedRate; + ? speedFactor * gb.LatestMachineState().feedRate + : gb.LatestMachineState().feedRate; moveBuffer.usingStandardFeedrate = true; } else @@ -1654,7 +1654,7 @@ const char * GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, bool isP // There may be multiple extruders present but only one value has been specified, so use mixing const float moveArg = gb.ConvertDistance(eMovement[0]); float requestedExtrusionAmount; - if (gb.MachineState().drivesRelative) + if (gb.LatestMachineState().drivesRelative) { requestedExtrusionAmount = moveArg; } @@ -1687,7 +1687,7 @@ const char * GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, bool isP totalMix += thisMix; const int extruder = tool->Drive(eDrive); float extrusionAmount = requestedExtrusionAmount * thisMix; - if (gb.MachineState().volumetricExtrusion) + if (gb.LatestMachineState().volumetricExtrusion) { extrusionAmount *= volumetricExtrusionFactors[extruder]; } @@ -1712,7 +1712,7 @@ const char * GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, bool isP { // Individual extrusion amounts have been provided. This is supported in relative extrusion mode only. // Note, if this is an extruder-only movement then the feed rate will apply to the total of all active extruders - if (gb.MachineState().drivesRelative) + if (gb.LatestMachineState().drivesRelative) { for (size_t eDrive = 0; eDrive < eMoveCount; eDrive++) { @@ -1725,7 +1725,7 @@ const char * GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb, bool isP moveBuffer.hasPositiveExtrusion = true; } - if (gb.MachineState().volumetricExtrusion) + if (gb.LatestMachineState().volumetricExtrusion) { extrusionAmount *= volumetricExtrusionFactors[extruder]; } @@ -1781,7 +1781,7 @@ bool GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated, const char *& e } else { - const unsigned int selectedPlane = gb.MachineState().selectedPlane; + const unsigned int selectedPlane = gb.LatestMachineState().selectedPlane; moveBuffer.initialUserC0 = currentUserPosition[(selectedPlane == 2) ? Y_AXIS : X_AXIS]; moveBuffer.initialUserC1 = currentUserPosition[(selectedPlane == 0) ? Y_AXIS : Z_AXIS]; } @@ -1896,7 +1896,7 @@ bool GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated, const char *& e if (gb.Seen(axisLetters[axis])) { // If it is a special move on a delta, movement must be relative. - if (moveBuffer.moveType != 0 && !gb.MachineState().axesRelative && reprap.GetMove().GetKinematics().GetKinematicsType() == KinematicsType::linearDelta) + if (moveBuffer.moveType != 0 && !gb.LatestMachineState().axesRelative && reprap.GetMove().GetKinematics().GetKinematicsType() == KinematicsType::linearDelta) { err = "G0/G1: attempt to move individual motors of a delta machine to absolute positions"; return true; @@ -1907,7 +1907,7 @@ bool GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated, const char *& e if (moveBuffer.moveType != 0) { // Special moves update the move buffer directly, bypassing the user coordinates - if (gb.MachineState().axesRelative) + if (gb.LatestMachineState().axesRelative) { moveBuffer.coords[axis] += moveArg * (1.0 - moveFractionToSkip); } @@ -1923,15 +1923,15 @@ bool GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated, const char *& e // But that causes issues for tool change on IDEX machines because we end up restoring the U axis when we shouldn't. // So we no longer do that, and the user must mention any axes that he wants restored e.g. G1 R2 X0 Y0. } - else if (gb.MachineState().axesRelative) + else if (gb.LatestMachineState().axesRelative) { currentUserPosition[axis] += moveArg * (1.0 - moveFractionToSkip); } - else if (gb.MachineState().g53Active) + else if (gb.LatestMachineState().g53Active) { currentUserPosition[axis] = moveArg + GetCurrentToolOffset(axis); // g53 ignores tool offsets as well as workplace coordinates } - else if (gb.MachineState().runningSystemMacro) + else if (gb.LatestMachineState().runningSystemMacro) { currentUserPosition[axis] = moveArg; // don't apply workplace offsets to commands in system macros } @@ -2068,7 +2068,7 @@ bool GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated, const char *& e } // If we are emulating Marlin for nanoDLP then we need to set a special end state - if (gb.MachineState().compatibility == Compatibility::NanoDLP && !DoingFileMacro()) + if (gb.LatestMachineState().compatibility == Compatibility::NanoDLP && !DoingFileMacro()) { gb.SetState(GCodeState::waitingForSpecialMoveToComplete); } @@ -2130,7 +2130,7 @@ bool GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated, const char *& e // If an error occurs, return true with 'err' assigned bool GCodes::DoArcMove(GCodeBuffer& gb, bool clockwise, const char *& err) { - const unsigned int selectedPlane = gb.MachineState().selectedPlane; + const unsigned int selectedPlane = gb.LatestMachineState().selectedPlane; const unsigned int axis0 = (selectedPlane == 2) ? Y_AXIS : X_AXIS; const unsigned int axis1 = (selectedPlane == 0) ? Y_AXIS : Z_AXIS; @@ -2150,15 +2150,15 @@ bool GCodes::DoArcMove(GCodeBuffer& gb, bool clockwise, const char *& err) if (gb.Seen(axisLetters[axis0])) { newAxis0Pos = gb.GetDistance(); - if (gb.MachineState().axesRelative) + if (gb.LatestMachineState().axesRelative) { newAxis0Pos += moveBuffer.initialUserC0; } - else if (gb.MachineState().g53Active) + else if (gb.LatestMachineState().g53Active) { newAxis0Pos += GetCurrentToolOffset(axis0); } - else if (!gb.MachineState().runningSystemMacro) + else if (!gb.LatestMachineState().runningSystemMacro) { newAxis0Pos += GetWorkplaceOffset(axis0); } @@ -2171,15 +2171,15 @@ bool GCodes::DoArcMove(GCodeBuffer& gb, bool clockwise, const char *& err) if (gb.Seen(axisLetters[axis1])) { newAxis1Pos = gb.GetDistance(); - if (gb.MachineState().axesRelative) + if (gb.LatestMachineState().axesRelative) { newAxis1Pos += moveBuffer.initialUserC1; } - else if (gb.MachineState().g53Active) + else if (gb.LatestMachineState().g53Active) { newAxis1Pos += GetCurrentToolOffset(axis1); } - else if (!gb.MachineState().runningSystemMacro) + else if (!gb.LatestMachineState().runningSystemMacro) { newAxis1Pos += GetWorkplaceOffset(axis1); } @@ -2287,15 +2287,15 @@ bool GCodes::DoArcMove(GCodeBuffer& gb, bool clockwise, const char *& err) if (axis != axis0 && axis != axis1 && gb.Seen(axisLetters[axis])) { const float moveArg = gb.GetDistance(); - if (gb.MachineState().axesRelative) + if (gb.LatestMachineState().axesRelative) { currentUserPosition[axis] += moveArg * (1.0 - moveFractionToSkip); } - else if (gb.MachineState().g53Active) + else if (gb.LatestMachineState().g53Active) { currentUserPosition[axis] = moveArg + GetCurrentToolOffset(axis); // g53 ignores tool offsets as well as workplace coordinates } - else if (gb.MachineState().runningSystemMacro) + else if (gb.LatestMachineState().runningSystemMacro) { currentUserPosition[axis] = moveArg; // don't apply workplace offsets to commands in system macros } @@ -2688,7 +2688,7 @@ void GCodes::EmergencyStop() noexcept // 501 = running M501 // 502 = running M502 // 98 = running a macro explicitly via M98 -// otherwise it is either the G- or M-code being executed, or 0 for a tool change file, or -1 for another system file +// otherwise it is either the G- or M-code being executed, or ToolChangeMacroCode for a tool change file, or SystemMacroCode for another system file bool GCodes::DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissing, int codeRunning) noexcept { #if HAS_LINUX_INTERFACE @@ -2698,7 +2698,7 @@ bool GCodes::DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissi { if (reportMissing) { - MessageType mt = (gb.IsBinary() && codeRunning >= 0) + MessageType mt = (gb.IsBinary() && codeRunning != SystemMacroCode) ? (MessageType)(gb.GetResponseMessageType() | WarningMessageFlag | PushFlag) : WarningMessage; platform.MessageF(mt, "Macro file %s not found\n", fileName); @@ -2739,9 +2739,13 @@ bool GCodes::DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissi f->Close(); return true; } - gb.MachineState().fileState.Set(f); + if (codeRunning >= 0) + { + gb.SetParameters(codeRunning); + } + gb.LatestMachineState().fileState.Set(f); gb.StartNewFile(); - gb.GetFileInput()->Reset(gb.MachineState().fileState); + gb.GetFileInput()->Reset(gb.LatestMachineState().fileState); #else if (reportMissing) { @@ -2752,13 +2756,10 @@ bool GCodes::DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissi } #if HAS_LINUX_INTERFACE || HAS_MASS_STORAGE - gb.MachineState().doingFileMacro = true; - gb.MachineState().runningM501 = (codeRunning == 501); - gb.MachineState().runningM502 = (codeRunning == 502); - if (codeRunning != 98) - { - gb.MachineState().runningSystemMacro = true; // running a system macro e.g. homing or tool change, so don't use workplace coordinates - } + gb.LatestMachineState().doingFileMacro = true; + gb.LatestMachineState().runningM501 = (codeRunning == 501); + gb.LatestMachineState().runningM502 = (codeRunning == 502); + gb.LatestMachineState().runningSystemMacro = (codeRunning == SystemMacroCode || codeRunning == 29 || codeRunning == 32); // running a system macro e.g. homing or tool change, so don't use workplace coordinates gb.SetState(GCodeState::normal); gb.Init(); return true; @@ -2778,7 +2779,7 @@ void GCodes::FileMacroCyclesReturn(GCodeBuffer& gb) noexcept #endif { #if HAS_MASS_STORAGE - FileData &file = gb.MachineState().fileState; + FileData &file = gb.LatestMachineState().fileState; gb.GetFileInput()->Reset(file); file.Close(); @@ -2892,7 +2893,7 @@ GCodeResult GCodes::ExecuteG30(GCodeBuffer& gb, const StringRef& reply) gb.SetState(GCodeState::probingAtPoint0); if (zp->GetProbeType() != ZProbeType::blTouch) { - DeployZProbe(gb, 30); + DeployZProbe(gb); } } } @@ -2906,7 +2907,7 @@ GCodeResult GCodes::ExecuteG30(GCodeBuffer& gb, const StringRef& reply) gb.SetState(GCodeState::probingAtPoint2a); if (zp->GetProbeType() != ZProbeType::blTouch) { - DeployZProbe(gb, 30); + DeployZProbe(gb); } } return GCodeResult::ok; @@ -2982,7 +2983,7 @@ GCodeResult GCodes::ProbeGrid(GCodeBuffer& gb, const StringRef& reply) gb.SetState(GCodeState::gridProbing1); if (zp->GetProbeType() != ZProbeType::blTouch) { - DeployZProbe(gb, 29); + DeployZProbe(gb); } return GCodeResult::ok; } @@ -3174,7 +3175,7 @@ void GCodes::StartPrinting(bool fromStart) noexcept if (fromStart) // if not resurrecting a print { - fileGCode->MachineState().volumetricExtrusion = false; // default to non-volumetric extrusion + fileGCode->LatestMachineState().volumetricExtrusion = false; // default to non-volumetric extrusion virtualExtruderPosition = 0.0; } @@ -3208,7 +3209,7 @@ void GCodes::StartPrinting(bool fromStart) noexcept if (fromStart) { // Get the fileGCode to execute the start macro so that any M82/M83 codes will be executed in the correct context - DoFileMacro(*fileGCode, START_G, false); + DoFileMacro(*fileGCode, START_G, false, SystemMacroCode); } } @@ -3284,7 +3285,7 @@ GCodeResult GCodes::SetOrReportOffsets(GCodeBuffer &gb, const StringRef& reply, return GCodeResult::notFinished; } settingOffset = true; - tool->SetOffset(axis, gb.GetFValue(), gb.MachineState().runningM501); + tool->SetOffset(axis, gb.GetFValue(), gb.LatestMachineState().runningM501); } } @@ -3592,11 +3593,11 @@ void GCodes::HandleReplyPreserveResult(GCodeBuffer& gb, GCodeResult rslt, const { #if HAS_LINUX_INTERFACE // Deal with replies to the Linux interface - if (gb.MachineState().lastCodeFromSbc) + if (gb.LatestMachineState().lastCodeFromSbc) { MessageType type = gb.GetResponseMessageType(); if (rslt == GCodeResult::notFinished || gb.HasJustStartedMacro() || - (gb.MachineState().waitingForAcknowledgement && gb.IsMessagePromptPending())) + (gb.LatestMachineState().waitingForAcknowledgement && gb.IsMessagePromptPending())) { if (reply[0] == 0) { @@ -3632,7 +3633,7 @@ void GCodes::HandleReplyPreserveResult(GCodeBuffer& gb, GCodeResult rslt, const : (rslt == GCodeResult::warning) ? AddWarning(initialMt) : initialMt; - switch (gb.MachineState().compatibility.RawValue()) + switch (gb.LatestMachineState().compatibility.RawValue()) { case Compatibility::Default: case Compatibility::RepRapFirmware: @@ -3678,7 +3679,7 @@ void GCodes::HandleReplyPreserveResult(GCodeBuffer& gb, GCodeResult rslt, const case Compatibility::Sprinter: case Compatibility::Repetier: default: - platform.MessageF(mt, "Emulation of %s is not yet supported.\n", gb.MachineState().compatibility.ToString()); + platform.MessageF(mt, "Emulation of %s is not yet supported.\n", gb.LatestMachineState().compatibility.ToString()); break; } } @@ -3715,7 +3716,7 @@ void GCodes::HandleReply(GCodeBuffer& gb, OutputBuffer *reply) noexcept const MessageType type = gb.GetResponseMessageType(); const char* const response = (gb.GetCommandLetter() == 'M' && gb.GetCommandNumber() == 998) ? "rs " : "ok"; - switch (gb.MachineState().compatibility.RawValue()) + switch (gb.LatestMachineState().compatibility.RawValue()) { case Compatibility::Default: case Compatibility::RepRapFirmware: @@ -3766,7 +3767,7 @@ void GCodes::HandleReply(GCodeBuffer& gb, OutputBuffer *reply) noexcept case Compatibility::Sprinter: case Compatibility::Repetier: default: - platform.MessageF(type, "Emulation of %s is not yet supported.\n", gb.MachineState().compatibility.ToString()); + platform.MessageF(type, "Emulation of %s is not yet supported.\n", gb.LatestMachineState().compatibility.ToString()); break; } @@ -3919,7 +3920,7 @@ GCodeResult GCodes::LoadFilament(GCodeBuffer& gb, const StringRef& reply) String<StringLength256> scratchString; scratchString.printf("%s%s/%s", FILAMENTS_DIRECTORY, filamentName.c_str(), LOAD_FILAMENT_G); - DoFileMacro(gb, scratchString.c_str(), true, 701); + DoFileMacro(gb, scratchString.c_str(), true, SystemMacroCode); } else if (tool->GetFilament()->IsLoaded()) { @@ -3953,7 +3954,7 @@ GCodeResult GCodes::UnloadFilament(GCodeBuffer& gb, const StringRef& reply) gb.SetState(GCodeState::unloadingFilament); String<StringLength256> scratchString; scratchString.printf("%s%s/%s", FILAMENTS_DIRECTORY, tool->GetFilament()->GetName(), UNLOAD_FILAMENT_G); - DoFileMacro(gb, scratchString.c_str(), true, 702); + DoFileMacro(gb, scratchString.c_str(), true, SystemMacroCode); } return GCodeResult::ok; } @@ -3981,7 +3982,7 @@ void GCodes::StopPrint(StopPrintReason reason) noexcept if (reprap.UsingLinuxInterface()) { lastFilePosition = noFilePosition; - fileGCode->MachineState().CloseFile(); + fileGCode->LatestMachineState().CloseFile(); fileGCode->Init(); } else @@ -4076,12 +4077,12 @@ void GCodes::StopPrint(StopPrintReason reason) noexcept } // Pronterface expects a "Done printing" message - if (usbGCode->MachineState().compatibility == Compatibility::Marlin) + if (usbGCode->LatestMachineState().compatibility == Compatibility::Marlin) { platform.Message(UsbMessage, "Done printing file\n"); } #if SUPPORT_TELNET - if (telnetGCode->MachineState().compatibility == Compatibility::Marlin) + if (telnetGCode->LatestMachineState().compatibility == Compatibility::Marlin) { platform.Message(TelnetMessage, "Done printing file\n"); } @@ -4142,7 +4143,7 @@ void GCodes::SavePosition(RestorePoint& rp, const GCodeBuffer& gb) const noexcep rp.moveCoords[axis] = currentUserPosition[axis]; } - rp.feedRate = gb.MachineState().feedRate; + rp.feedRate = gb.LatestMachineState().feedRate; rp.virtualExtruderPosition = virtualExtruderPosition; rp.filePos = gb.GetFilePosition(); @@ -4161,7 +4162,7 @@ void GCodes::RestorePosition(const RestorePoint& rp, GCodeBuffer *gb) noexcept if (gb != nullptr) { - gb->MachineState().feedRate = rp.feedRate; + gb->LatestMachineState().feedRate = rp.feedRate; } moveBuffer.initialUserC0 = rp.initialUserC0; @@ -4526,7 +4527,7 @@ void GCodes::CheckReportDue(GCodeBuffer& gb, const StringRef& reply) const { if (&gb == usbGCode) { - if (gb.MachineState().compatibility == Compatibility::Marlin && gb.IsReportDue()) + if (gb.LatestMachineState().compatibility == Compatibility::Marlin && gb.IsReportDue()) { // In Marlin emulation mode we should return a standard temperature report every second GenerateTemperatureReport(reply); @@ -4624,7 +4625,7 @@ bool GCodes::LockResource(const GCodeBuffer& gb, Resource r) noexcept if (resourceOwners[r] == nullptr) { resourceOwners[r] = &gb; - gb.MachineState().lockedResources.SetBit(r); + gb.LatestMachineState().lockedResources.SetBit(r); return true; } return false; @@ -4639,7 +4640,7 @@ void GCodes::GrabResource(const GCodeBuffer& gb, Resource r) noexcept { if (resourceOwners[r] != nullptr) { - GCodeMachineState *m = &(resourceOwners[r]->MachineState()); + GCodeMachineState *m = &(resourceOwners[r]->LatestMachineState()); do { m->lockedResources.ClearBit(r); @@ -4682,7 +4683,7 @@ void GCodes::UnlockResource(const GCodeBuffer& gb, Resource r) noexcept if (resourceOwners[r] == &gb) { - GCodeMachineState * mc = &gb.MachineState(); + GCodeMachineState * mc = &gb.LatestMachineState(); do { mc->lockedResources.ClearBit(r); @@ -4697,7 +4698,7 @@ void GCodes::UnlockAll(const GCodeBuffer& gb) noexcept { TaskCriticalSectionLocker lock; - const GCodeMachineState * const mc = gb.MachineState().GetPrevious(); + const GCodeMachineState * const mc = gb.LatestMachineState().GetPrevious(); const GCodeMachineState::ResourceBitmap resourcesToKeep = (mc == nullptr) ? GCodeMachineState::ResourceBitmap() : mc->lockedResources; for (size_t i = 0; i < NumResources; ++i) { @@ -4709,7 +4710,7 @@ void GCodes::UnlockAll(const GCodeBuffer& gb) noexcept toBeHomed.Clear(); } resourceOwners[i] = nullptr; - gb.MachineState().lockedResources.ClearBit(i); + gb.LatestMachineState().lockedResources.ClearBit(i); } } } @@ -4852,7 +4853,7 @@ void GCodes::ActivateHeightmap(bool activate) noexcept // On entry, 'reply' is empty and 'result' is GCodeResult::ok bool GCodes::CheckNetworkCommandAllowed(GCodeBuffer& gb, const StringRef& reply, GCodeResult& result) noexcept { - if (gb.MachineState().runningM502) // when running M502 we don't execute network-related commands + if (gb.LatestMachineState().runningM502) // when running M502 we don't execute network-related commands { return false; // just ignore the command but report success } diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h index 63d74171..4114ec2a 100644 --- a/src/GCodes/GCodes.h +++ b/src/GCodes/GCodes.h @@ -306,6 +306,9 @@ private: static_assert(NumResources <= sizeof(Resource) * CHAR_BIT, "Too many resources to keep a bitmap of them in class GCodeMachineState"); + static constexpr int ToolChangeMacroCode = -1; + static constexpr int SystemMacroCode = -2; + bool LockResource(const GCodeBuffer& gb, Resource r) noexcept; // Lock the resource, returning true if success bool LockFileSystem(const GCodeBuffer& gb) noexcept; // Lock the unshareable parts of the file system bool LockMovement(const GCodeBuffer& gb) noexcept; // Lock movement @@ -323,7 +326,7 @@ private: void StopPrint(StopPrintReason reason) noexcept; // Stop the current print bool DoFilePrint(GCodeBuffer& gb, const StringRef& reply) noexcept; // Get G Codes from a file and print them - bool DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissing, int codeRunning = -1) noexcept; + bool DoFileMacro(GCodeBuffer& gb, const char* fileName, bool reportMissing, int codeRunning) noexcept; // Run a GCode macro file, optionally report error if not found void FileMacroCyclesReturn(GCodeBuffer& gb) noexcept; // End a macro @@ -445,8 +448,8 @@ private: MessageType GetMessageBoxDevice(GCodeBuffer& gb) const; // Decide which device to display a message box on void DoManualProbe(GCodeBuffer&, const char *message, const char *title, const AxesBitmap); // Do manual probe in arbitrary direction void DoManualBedProbe(GCodeBuffer& gb); // Do a manual bed probe - void DeployZProbe(GCodeBuffer& gb, int code) noexcept; - void RetractZProbe(GCodeBuffer& gb, int code) noexcept; + void DeployZProbe(GCodeBuffer& gb) noexcept; + void RetractZProbe(GCodeBuffer& gb) noexcept; void AppendAxes(const StringRef& reply, AxesBitmap axes) const noexcept; // Append a list of axes to a string diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index 3c6dfdd1..04b489a5 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -157,7 +157,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx if (err != nullptr) { gb.SetState(GCodeState::abortWhenMovementFinished); // empty the queue before ending simulation, and force the user position to be restored - gb.MachineState().SetError(err); // must do this *after* calling SetState + gb.LatestMachineState().SetError(err); // must do this *after* calling SetState } } break; @@ -182,7 +182,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx if (err != nullptr) { gb.SetState(GCodeState::abortWhenMovementFinished); // empty the queue before ending simulation, and force the user position to be restored - gb.MachineState().SetError(err); // must do this *after* calling SetState + gb.LatestMachineState().SetError(err); // must do this *after* calling SetState } } break; @@ -253,15 +253,15 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx return false; } - gb.MachineState().selectedPlane = code - 17; + gb.LatestMachineState().selectedPlane = code - 17; break; case 20: // Inches (which century are we living in, here?) - gb.MachineState().usingInches = true; + gb.LatestMachineState().usingInches = true; break; case 21: // mm - gb.MachineState().usingInches = false; + gb.LatestMachineState().usingInches = false; break; case 28: // Home @@ -376,7 +376,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx break; case 53: // Temporarily use machine coordinates - gb.MachineState().g53Active = true; + gb.LatestMachineState().g53Active = true; break; #if SUPPORT_WORKPLACE_COORDINATES @@ -400,7 +400,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx { currentCoordinateSystem = cs; // this is the zero-base coordinate system number reprap.MoveUpdated(); - gb.MachineState().g53Active = false; // cancel any active G53 + gb.LatestMachineState().g53Active = false; // cancel any active G53 } else { @@ -415,11 +415,11 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx break; case 90: // Absolute coordinates - gb.MachineState().axesRelative = false; + gb.LatestMachineState().axesRelative = false; break; case 91: // Relative coordinates - gb.MachineState().axesRelative = true; // Axis movements (i.e. X, Y and Z) + gb.LatestMachineState().axesRelative = true; // Axis movements (i.e. X, Y and Z) break; case 92: // Set position @@ -516,14 +516,14 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx if (!wasSimulating) // don't run any macro files or turn heaters off etc. if we were simulating before we stopped the print { // If we are cancelling a paused print with M0 and we are homed and cancel.g exists then run it and do nothing else - if (oldPauseState != PauseState::notPaused && code == 0 && AllAxesAreHomed() && DoFileMacro(gb, CANCEL_G, false, 0)) + if (oldPauseState != PauseState::notPaused && code == 0 && AllAxesAreHomed() && DoFileMacro(gb, CANCEL_G, false, SystemMacroCode)) { break; } const bool leaveHeatersOn = (gb.Seen('H') && gb.GetIValue() > 0); gb.SetState((leaveHeatersOn) ? GCodeState::stoppingWithHeatersOn : GCodeState::stoppingWithHeatersOff); - (void)DoFileMacro(gb, (code == 0) ? STOP_G : SLEEP_G, false, code); + (void)DoFileMacro(gb, (code == 0) ? STOP_G : SLEEP_G, false, SystemMacroCode); } } break; @@ -820,12 +820,12 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx // If we are emulating RepRap then we print "GCode files:\n" at the start, otherwise we don't. // If we are emulating Marlin and the code came via the serial/USB interface, then we don't put quotes around the names and we separate them with newline; // otherwise we put quotes around them and separate them with comma. - if (gb.MachineState().compatibility == Compatibility::Default || gb.MachineState().compatibility == Compatibility::RepRapFirmware) + if (gb.LatestMachineState().compatibility == Compatibility::Default || gb.LatestMachineState().compatibility == Compatibility::RepRapFirmware) { outBuf->copy("GCode files:\n"); } - const bool encapsulateList = gb.MachineState().compatibility != Compatibility::Marlin; + const bool encapsulateList = gb.LatestMachineState().compatibility != Compatibility::Marlin; FileInfo fileInfo; if (MassStorage::FindFirst(dir.c_str(), fileInfo)) { @@ -894,7 +894,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx if (QueueFileToPrint(filename.c_str(), reply)) { reprap.GetPrintMonitor().StartingPrint(filename.c_str()); - if (gb.MachineState().compatibility == Compatibility::Marlin) + if (gb.LatestMachineState().compatibility == Compatibility::Marlin) { reply.copy("File opened\nFile selected"); } @@ -944,7 +944,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx gb.SetState(GCodeState::resuming1); if (AllAxesAreHomed()) { - DoFileMacro(gb, RESUME_G, true, 24); + DoFileMacro(gb, RESUME_G, true, SystemMacroCode); } } } @@ -970,7 +970,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx { // We executed M26 to set the file offset, which normally means that we are executing resurrect.g. // We need to copy the absolute/relative and volumetric extrusion flags over - fileGCode->OriginalMachineState().CopyStateFrom(gb.MachineState()); + fileGCode->OriginalMachineState().CopyStateFrom(gb.LatestMachineState()); fileToPrint.Seek(fileOffsetToPrint); moveFractionToSkip = restartMoveFractionDone; } @@ -1058,7 +1058,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx fileOffsetToPrint = (FilePosition)gb.GetUIValue(); restartMoveFractionDone = (gb.Seen('P')) ? constrain<float>(gb.GetFValue(), 0.0, 1.0) : 0.0; { - const unsigned int selectedPlane = gb.MachineState().selectedPlane; + const unsigned int selectedPlane = gb.LatestMachineState().selectedPlane; const char c0 = (selectedPlane == 2) ? 'Y' : 'X'; const char c1 = (selectedPlane == 0) ? 'Y' : 'Z'; restartInitialUserC0 = (gb.Seen(c0)) ? gb.GetFValue() : 0.0; @@ -1285,11 +1285,11 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx break; case 82: // Use absolute extruder positioning - gb.MachineState().drivesRelative = false; + gb.LatestMachineState().drivesRelative = false; break; case 83: // Use relative extruder positioning - gb.MachineState().drivesRelative = true; + gb.LatestMachineState().drivesRelative = true; break; // For case 84, see case 18 @@ -1474,7 +1474,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.MachineState().lockedResources.IsBitSet(MoveResource); + 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 ) @@ -1506,12 +1506,12 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx float temperature; if (gb.Seen('R')) { - gb.MachineState().waitWhileCooling = true; + gb.LatestMachineState().waitWhileCooling = true; temperature = gb.GetFValue(); } else if (gb.Seen('S')) { - gb.MachineState().waitWhileCooling = false; + gb.LatestMachineState().waitWhileCooling = false; temperature = gb.GetFValue(); } else @@ -2088,9 +2088,9 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx const float d = diameters[i]; volumetricExtrusionFactors[i] = (d <= 0.0) ? 1.0 : 4.0/(fsquare(d) * Pi); } - gb.MachineState().volumetricExtrusion = (diameters[0] > 0.0); + gb.LatestMachineState().volumetricExtrusion = (diameters[0] > 0.0); } - else if (!gb.MachineState().volumetricExtrusion) + else if (!gb.LatestMachineState().volumetricExtrusion) { reply.copy("Volumetric extrusion is disabled for this input source"); } @@ -2266,8 +2266,8 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx ok = values[1] > values[0]; if (ok) { - platform.SetAxisMinimum(axis, values[0], gb.MachineState().runningM501); - platform.SetAxisMaximum(axis, values[1], gb.MachineState().runningM501); + platform.SetAxisMinimum(axis, values[0], gb.LatestMachineState().runningM501); + platform.SetAxisMaximum(axis, values[1], gb.LatestMachineState().runningM501); } } else if (setMin) @@ -2275,7 +2275,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx ok = platform.AxisMaximum(axis) > values[0]; if (ok) { - platform.SetAxisMinimum(axis, values[0], gb.MachineState().runningM501); + platform.SetAxisMinimum(axis, values[0], gb.LatestMachineState().runningM501); } } else @@ -2283,7 +2283,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx ok = values[0] > platform.AxisMinimum(axis); if (ok) { - platform.SetAxisMaximum(axis, values[0], gb.MachineState().runningM501); + platform.SetAxisMaximum(axis, values[0], gb.LatestMachineState().runningM501); } } @@ -2770,7 +2770,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx if (zp.IsNotNull() && zp->GetProbeType() != ZProbeType::none) { zp->SetDeployedByUser(false); // pretend that the probe isn't deployed, to make sure we deploy it unconditionally - DeployZProbe(gb, 401); + DeployZProbe(gb); zp->SetDeployedByUser(true); // probe is now deployed } } @@ -2783,7 +2783,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx if (zp.IsNotNull() && zp->GetProbeType() != ZProbeType::none) { zp->SetDeployedByUser(false); // do this first, otherwise the probe won't be retracted - RetractZProbe(gb, 402); + RetractZProbe(gb); } } break; @@ -2971,7 +2971,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx #endif case 501: // Load parameters from config-override.g - if (!gb.MachineState().runningM502 && !gb.MachineState().runningM501) // when running M502 we ignore config-override.g + if (!gb.LatestMachineState().runningM502 && !gb.LatestMachineState().runningM501) // when running M502 we ignore config-override.g { if (runningConfigFile) { @@ -2982,7 +2982,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx break; case 502: // Revert to default "factory settings" ignoring values in config-override.g - if (!gb.MachineState().runningM502) // avoid recursion + if (!gb.LatestMachineState().runningM502) // avoid recursion { if (!LockMovementAndWaitForStandstill(gb)) { @@ -3201,11 +3201,11 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx case 555: // Set/report firmware type to emulate if (gb.Seen('P')) { - gb.MachineState().compatibility.Assign(gb.GetIValue()); + gb.LatestMachineState().compatibility.Assign(gb.GetIValue()); } else { - reply.printf("Output mode: %s", gb.MachineState().compatibility.ToString()); + reply.printf("Output mode: %s", gb.LatestMachineState().compatibility.ToString()); } break; @@ -3541,7 +3541,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx platform.SetAuxRaw(chan - 1, rawMode); if (rawMode && !platform.IsAuxEnabled(chan - 1)) // if enabling aux for the first time and in raw mode, set Marlin compatibility { - gbp->MachineState().compatibility = Compatibility::Marlin; + gbp->LatestMachineState().compatibility = Compatibility::Marlin; } } } @@ -4047,9 +4047,9 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx if (gb.Seen(feedrateLetter)) { const float rate = gb.ConvertDistance(gb.GetFValue()); - gb.MachineState().feedRate = rate * SecondsToMinutes; // don't apply the speed factor + gb.LatestMachineState().feedRate = rate * SecondsToMinutes; // don't apply the speed factor } - moveBuffer.feedRate = gb.MachineState().feedRate; + moveBuffer.feedRate = gb.LatestMachineState().feedRate; moveBuffer.usingStandardFeedrate = true; moveBuffer.tool = reprap.GetCurrentTool(); NewMoveAvailable(1); @@ -4120,7 +4120,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx { String<StringLength256> scratchString; scratchString.printf("%s%s/%s", FILAMENTS_DIRECTORY, filament->GetName(), CONFIG_FILAMENT_G); - DoFileMacro(gb, scratchString.c_str(), false, 703); + DoFileMacro(gb, scratchString.c_str(), false, SystemMacroCode); } } else @@ -4479,7 +4479,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx } else { - DoFileMacro(gb, RESUME_AFTER_POWER_FAIL_G, true, 916); + DoFileMacro(gb, RESUME_AFTER_POWER_FAIL_G, true, SystemMacroCode); } break; #endif @@ -4646,7 +4646,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) THROWS(GCodeEx bool GCodes::HandleTcode(GCodeBuffer& gb, const StringRef& reply) { - if (gb.MachineState().runningM502) + if (gb.LatestMachineState().runningM502) { return true; // when running M502 we don't execute T commands } @@ -4820,7 +4820,7 @@ bool GCodes::HandleResult(GCodeBuffer& gb, GCodeResult rslt, const StringRef& re break; } - if (gb.MachineState().GetState() == GCodeState::normal) + if (gb.LatestMachineState().GetState() == GCodeState::normal) { gb.StopTimer(); UnlockAll(gb); diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp index 79836356..e7f09715 100644 --- a/src/GCodes/GCodes3.cpp +++ b/src/GCodes/GCodes3.cpp @@ -424,7 +424,7 @@ GCodeResult GCodes::SimulateFile(GCodeBuffer& gb, const StringRef &reply, const { axesVirtuallyHomed = AxesBitmap::MakeLowestNBits(numVisibleAxes); // pretend all axes are homed SavePosition(simulationRestorePoint, gb); - simulationRestorePoint.feedRate = gb.MachineState().feedRate; + simulationRestorePoint.feedRate = gb.LatestMachineState().feedRate; } simulationTime = 0.0; exitSimulationWhenFileComplete = true; @@ -836,7 +836,7 @@ GCodeResult GCodes::StraightProbe(GCodeBuffer& gb, const StringRef& reply) THROW // - If prefixed by G53 add the ToolOffset that will be subtracted below in ToolOffsetTransform as we ignore any offsets when G53 is active // - otherwise add current workplace offsets so we go where the user expects to go // comparable to hoe DoStraightMove/DoArcMove does it - const float axisTarget = gb.GetDistance() + (gb.MachineState().g53Active ? GetCurrentToolOffset(axis) : GetWorkplaceOffset(axis)); + const float axisTarget = gb.GetDistance() + (gb.LatestMachineState().g53Active ? GetCurrentToolOffset(axis) : GetWorkplaceOffset(axis)); if (axisTarget != userPositionTarget[axis]) { doesMove = true; @@ -942,9 +942,9 @@ GCodeResult GCodes::ProbeTool(GCodeBuffer& gb, const StringRef& reply) THROWS(GC if (gb.Seen(feedrateLetter)) { const float rate = gb.GetDistance(); - gb.MachineState().feedRate = rate * SecondsToMinutes; // don't apply the speed factor to homing and other special moves + gb.LatestMachineState().feedRate = rate * SecondsToMinutes; // don't apply the speed factor to homing and other special moves } - moveBuffer.feedRate = gb.MachineState().feedRate; + moveBuffer.feedRate = gb.LatestMachineState().feedRate; const bool probeOk = (useProbe) ? platform.GetEndstops().EnableZProbe(probeNumberToUse) @@ -1008,7 +1008,7 @@ GCodeResult GCodes::FindCenterOfCavity(GCodeBuffer& gb, const StringRef& reply, // Deal with feed rate gb.MustSee(feedrateLetter); const float rate = gb.GetDistance(); - moveBuffer.feedRate = gb.MachineState().feedRate = rate * SecondsToMinutes; // don't apply the speed factor to homing and other special moves + moveBuffer.feedRate = gb.LatestMachineState().feedRate = rate * SecondsToMinutes; // don't apply the speed factor to homing and other special moves const bool probeOk = (useProbe) ? platform.GetEndstops().EnableZProbe(probeNumberToUse) @@ -1566,32 +1566,32 @@ void GCodes::ChangeExtrusionFactor(unsigned int extruder, float factor) noexcept // Deploy the Z probe unless it has already been deployed explicitly // The required next state must be set up (e.g. by gb.SetState()) before calling this -void GCodes::DeployZProbe(GCodeBuffer& gb, int code) noexcept +void GCodes::DeployZProbe(GCodeBuffer& gb) noexcept { auto zp = reprap.GetPlatform().GetEndstops().GetZProbe(currentZProbeNumber); if (zp.IsNotNull() && zp->GetProbeType() != ZProbeType::none && !zp->IsDeployedByUser()) { String<StringLength20> fileName; fileName.printf(DEPLOYPROBE "%u.g", currentZProbeNumber); - if (!DoFileMacro(gb, fileName.c_str(), false, code)) + if (!DoFileMacro(gb, fileName.c_str(), false, SystemMacroCode)) { - DoFileMacro(gb, DEPLOYPROBE ".g", false, code); + DoFileMacro(gb, DEPLOYPROBE ".g", false, SystemMacroCode); } } } // Retract the Z probe unless it was deployed explicitly (in which case, wait for the user to retract it explicitly) // The required next state must be set up (e.g. by gb.SetState()) before calling this -void GCodes::RetractZProbe(GCodeBuffer& gb, int code) noexcept +void GCodes::RetractZProbe(GCodeBuffer& gb) noexcept { auto zp = reprap.GetPlatform().GetEndstops().GetZProbe(currentZProbeNumber); if (zp.IsNotNull() && zp->GetProbeType() != ZProbeType::none && !zp->IsDeployedByUser()) { String<StringLength20> fileName; fileName.printf(RETRACTPROBE "%u.g", currentZProbeNumber); - if (!DoFileMacro(gb, fileName.c_str(), false, code)) + if (!DoFileMacro(gb, fileName.c_str(), false, SystemMacroCode)) { - DoFileMacro(gb, RETRACTPROBE ".g", false, code); + DoFileMacro(gb, RETRACTPROBE ".g", false, SystemMacroCode); } } } diff --git a/src/GCodes/GCodes4.cpp b/src/GCodes/GCodes4.cpp index 6098b97b..0d335899 100644 --- a/src/GCodes/GCodes4.cpp +++ b/src/GCodes/GCodes4.cpp @@ -53,7 +53,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept } } - if (gb.MachineState().compatibility == Compatibility::NanoDLP && !DoingFileMacro()) + if (gb.LatestMachineState().compatibility == Compatibility::NanoDLP && !DoingFileMacro()) { reply.copy("Z_move_comp"); } @@ -79,7 +79,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { break; } - gb.MachineState().SetError("G1/G2/G3: intermediate position outside machine limits"); + gb.LatestMachineState().SetError("G1/G2/G3: intermediate position outside machine limits"); gb.SetState(GCodeState::normal); if (machineType != MachineType::fff) { @@ -249,7 +249,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { String<StringLength20> scratchString; scratchString.printf("tfree%d.g", oldTool->Number()); - DoFileMacro(gb, scratchString.c_str(), false, 0); // don't pass the T code here because it may be negative + DoFileMacro(gb, scratchString.c_str(), false, ToolChangeMacroCode); // don't pass the T code here because it may be negative } } break; @@ -269,7 +269,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { String<StringLength20> scratchString; scratchString.printf("tpre%d.g", newToolNumber); - DoFileMacro(gb, scratchString.c_str(), false, 0); + DoFileMacro(gb, scratchString.c_str(), false, ToolChangeMacroCode); } } break; @@ -291,7 +291,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { String<StringLength20> scratchString; scratchString.printf("tpost%d.g", newToolNumber); - DoFileMacro(gb, scratchString.c_str(), false, 0); + DoFileMacro(gb, scratchString.c_str(), false, ToolChangeMacroCode); } } break; @@ -307,9 +307,9 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept const float newZPos = (moveBuffer.coords[Z_AXIS] - currentTool->GetOffset(Z_AXIS)); if(newZPos > platform.AxisMaximum(Z_AXIS) || newZPos < platform.AxisMinimum(Z_AXIS)) { - gb.MachineState().feedRate = toolChangeRestorePoint.feedRate; + gb.LatestMachineState().feedRate = toolChangeRestorePoint.feedRate; doingToolChange = false; - gb.MachineState().SetError("New tool too close to Z axis limit. Aborting tool change"); + gb.LatestMachineState().SetError("New tool too close to Z axis limit. Aborting tool change"); AbortPrint(gb); gb.SetState(GCodeState::checkError); break; @@ -331,7 +331,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept case GCodeState::m109ToolChangeComplete: if (LockMovementAndWaitForStandstill(gb)) // wait for tpost.g to finish executing or the move to height to finish { - gb.MachineState().feedRate = toolChangeRestorePoint.feedRate; + 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 doingToolChange = false; @@ -348,7 +348,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept break; case GCodeState::m109WaitForTemperature: - if (cancelWait || simulationMode != 0 || ToolHeatersAtSetTemperatures(reprap.GetCurrentTool(), gb.MachineState().waitWhileCooling, TEMPERATURE_CLOSE_ENOUGH)) + if (cancelWait || simulationMode != 0 || ToolHeatersAtSetTemperatures(reprap.GetCurrentTool(), gb.LatestMachineState().waitWhileCooling, TEMPERATURE_CLOSE_ENOUGH)) { cancelWait = isWaiting = false; gb.SetState(GCodeState::normal); @@ -365,7 +365,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept gb.AdvanceState(); if (AllAxesAreHomed()) { - DoFileMacro(gb, PAUSE_G, true, 25); + DoFileMacro(gb, PAUSE_G, true, SystemMacroCode); } } break; @@ -376,9 +376,9 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept gb.AdvanceState(); if (AllAxesAreHomed()) { - if (!DoFileMacro(gb, FILAMENT_CHANGE_G, false, -1)) + if (!DoFileMacro(gb, FILAMENT_CHANGE_G, false, SystemMacroCode)) { - DoFileMacro(gb, PAUSE_G, true, -1); + DoFileMacro(gb, PAUSE_G, true, SystemMacroCode); } } } @@ -391,12 +391,12 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept if (AllAxesAreHomed()) { String<StringLength20> macroName; - macroName.printf(FILAMENT_ERROR "%u.g", gb.MachineState().stateParameter); - if (!DoFileMacro(gb, macroName.c_str(), false, -1)) + macroName.printf(FILAMENT_ERROR "%u.g", gb.LatestMachineState().stateParameter); + if (!DoFileMacro(gb, macroName.c_str(), false, SystemMacroCode)) { - if (!DoFileMacro(gb, FILAMENT_ERROR ".g", false, -1)) + if (!DoFileMacro(gb, FILAMENT_ERROR ".g", false, SystemMacroCode)) { - DoFileMacro(gb, PAUSE_G, true, -1); + DoFileMacro(gb, PAUSE_G, true, SystemMacroCode); } } } @@ -458,7 +458,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept } virtualExtruderPosition = pauseRestorePoint.virtualExtruderPosition; // reset the extruder position in case we are receiving absolute extruder moves moveBuffer.virtualExtruderPosition = pauseRestorePoint.virtualExtruderPosition; - fileGCode->MachineState().feedRate = pauseRestorePoint.feedRate; + fileGCode->LatestMachineState().feedRate = pauseRestorePoint.feedRate; moveFractionToSkip = pauseRestorePoint.proportionDone; restartInitialUserC0 = pauseRestorePoint.initialUserC0; restartInitialUserC1 = pauseRestorePoint.initialUserC1; @@ -588,7 +588,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept gb.AdvanceState(); if (platform.GetZProbeOrDefault(currentZProbeNumber)->GetProbeType() == ZProbeType::blTouch) { - DeployZProbe(gb, 29); + DeployZProbe(gb); } } break; @@ -625,9 +625,9 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { reprap.GetMove().heightMapLock.ReleaseWriter(); reprap.GetHeat().SuspendHeaters(false); - gb.MachineState().SetError("Z probe already triggered before probing move started"); + gb.LatestMachineState().SetError("Z probe already triggered before probing move started"); gb.SetState(GCodeState::checkError); - RetractZProbe(gb, 29); + RetractZProbe(gb); break; } else @@ -637,9 +637,9 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept if (!platform.GetEndstops().EnableZProbe(currentZProbeNumber) || !zp->SetProbing(true)) { reprap.GetMove().heightMapLock.ReleaseWriter(); - gb.MachineState().SetError("Failed to enable Z probe"); + gb.LatestMachineState().SetError("Failed to enable Z probe"); gb.SetState(GCodeState::checkError); - RetractZProbe(gb, 29); + RetractZProbe(gb); break; } moveBuffer.checkEndstops = true; @@ -671,9 +671,9 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept if (!zProbeTriggered) { reprap.GetMove().heightMapLock.ReleaseWriter(); - gb.MachineState().SetError("Z probe was not triggered during probing move"); + gb.LatestMachineState().SetError("Z probe was not triggered during probing move"); gb.SetState(GCodeState::checkError); - RetractZProbe(gb, 29); + RetractZProbe(gb); break; } @@ -685,7 +685,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept gb.AdvanceState(); if (zp->GetProbeType() == ZProbeType::blTouch) // bltouch needs to be retracted when it triggers { - RetractZProbe(gb, 29); + RetractZProbe(gb); } } break; @@ -745,9 +745,9 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept else { reprap.GetMove().heightMapLock.ReleaseWriter(); - gb.MachineState().SetError("Z probe readings not consistent"); + gb.LatestMachineState().SetError("Z probe readings not consistent"); gb.SetState(GCodeState::checkError); - RetractZProbe(gb, 29); + RetractZProbe(gb); } } break; @@ -784,7 +784,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { // Done all the points gb.AdvanceState(); - RetractZProbe(gb, 29); + RetractZProbe(gb); } else { @@ -825,7 +825,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept } else { - gb.MachineState().SetError("Too few points probed"); + gb.LatestMachineState().SetError("Too few points probed"); } reprap.GetMove().heightMapLock.ReleaseWriter(); } @@ -874,7 +874,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept gb.AdvanceState(); if (platform.GetZProbeOrDefault(currentZProbeNumber)->GetProbeType() == ZProbeType::blTouch) // bltouch needs to be redeployed prior to each probe point { - DeployZProbe(gb, 30); + DeployZProbe(gb); } } break; @@ -912,13 +912,13 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { // Z probe is already triggered at the start of the move, so abandon the probe and record an error reprap.GetHeat().SuspendHeaters(false); - gb.MachineState().SetError("Z probe already triggered at start of probing move"); + gb.LatestMachineState().SetError("Z probe already triggered at start of probing move"); if (g30ProbePointIndex >= 0) { reprap.GetMove().SetZBedProbePoint(g30ProbePointIndex, zp->GetDiveHeight(), true, true); } gb.SetState(GCodeState::checkError); // no point in doing anything else - RetractZProbe(gb, 30); + RetractZProbe(gb); } else { @@ -926,9 +926,9 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept SetMoveBufferDefaults(); if (!platform.GetEndstops().EnableZProbe(currentZProbeNumber) || !zp->SetProbing(true)) { - gb.MachineState().SetError("Failed to enable Z probe"); + gb.LatestMachineState().SetError("Failed to enable Z probe"); gb.SetState(GCodeState::checkError); - RetractZProbe(gb, 30); + RetractZProbe(gb); break; } @@ -966,7 +966,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept zp->SetProbing(false); if (!zProbeTriggered) { - gb.MachineState().SetError("Z probe was not triggered during probing move"); + gb.LatestMachineState().SetError("Z probe was not triggered during probing move"); g30zHeightErrorSum = g30zHeightError = 0.0; hadProbingError = true; } @@ -992,7 +992,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { // G30 S-1 command taps once and reports the height, S-2 sets the tool offset to the negative of the current height, S-3 sets the Z probe trigger height gb.SetState(GCodeState::probingAtPoint7); // special state for reporting the stopped height at the end - RetractZProbe(gb, 30); // retract the probe before moving to the new state + RetractZProbe(gb); // retract the probe before moving to the new state break; } @@ -1019,7 +1019,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept gb.AdvanceState(); if (zp->GetProbeType() == ZProbeType::blTouch) // bltouch needs to be retracted when it triggers { - RetractZProbe(gb, 30); + RetractZProbe(gb); } } break; @@ -1072,7 +1072,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept g30zHeightError = g30zHeightErrorSum/tapsDone; if (zp->GetTolerance() > 0.0) // zero or negative tolerance means always average all readings, so no warning message { - gb.MachineState().SetError("Z probe readings not consistent"); + gb.LatestMachineState().SetError("Z probe readings not consistent"); } } @@ -1097,7 +1097,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept gb.AdvanceState(); if (zp->GetProbeType() != ZProbeType::blTouch) // if it's a BLTouch then we have already retracted it { - RetractZProbe(gb, 30); + RetractZProbe(gb); } } break; @@ -1144,7 +1144,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept Tool * const tool = reprap.GetCurrentTool(); if (tool == nullptr) { - gb.MachineState().SetError("Tool was deselected during G30 S-2 command"); + gb.LatestMachineState().SetError("Tool was deselected during G30 S-2 command"); } else { @@ -1165,7 +1165,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { gb.AdvanceState(); currentZProbeNumber = reprap.GetMove().GetStraightProbeSettings().GetZProbeToUse(); - DeployZProbe(gb, 38); + DeployZProbe(gb); } break; @@ -1208,10 +1208,10 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept reprap.GetHeat().SuspendHeaters(false); if (sps.SignalError()) { - gb.MachineState().SetError((probingAway) ? "Probe not triggered at start of probing move" : "Probe already triggered at start of probing move"); + gb.LatestMachineState().SetError((probingAway) ? "Probe not triggered at start of probing move" : "Probe already triggered at start of probing move"); } gb.SetState(GCodeState::checkError); // no point in doing anything else - RetractZProbe(gb, 38); + RetractZProbe(gb); } else { @@ -1219,9 +1219,9 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept SetMoveBufferDefaults(); if (!platform.GetEndstops().EnableZProbe(sps.GetZProbeToUse(), probingAway) || !zp->SetProbing(true)) { - gb.MachineState().SetError("Failed to enable Z probe"); + gb.LatestMachineState().SetError("Failed to enable Z probe"); gb.SetState(GCodeState::checkError); - RetractZProbe(gb, 38); + RetractZProbe(gb); break; } @@ -1251,12 +1251,12 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept zp->SetProbing(false); if (!zProbeTriggered && sps.SignalError()) { - gb.MachineState().SetError((probingAway) ? "Z probe did not lose contact during probing move" : "Z probe was not triggered during probing move"); + gb.LatestMachineState().SetError((probingAway) ? "Z probe did not lose contact during probing move" : "Z probe was not triggered during probing move"); } } gb.SetState(GCodeState::checkError); - RetractZProbe(gb, 38); // retract the probe before moving to the new state + RetractZProbe(gb); // retract the probe before moving to the new state } break; @@ -1364,7 +1364,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept if (sdTimingFile == nullptr) { platform.Delete(platform.GetGCodeDir(), TimingFileName); - gb.MachineState().SetError("Failed to re-open timing file"); + gb.LatestMachineState().SetError("Failed to re-open timing file"); gb.SetState(GCodeState::normal); break; } @@ -1381,7 +1381,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { sdTimingFile->Close(); platform.Delete(platform.GetGCodeDir(), TimingFileName); - gb.MachineState().SetError("Failed to write to timing file"); + gb.LatestMachineState().SetError("Failed to write to timing file"); gb.SetState(GCodeState::normal); break; } @@ -1410,7 +1410,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { sdTimingFile->Close(); platform.Delete(platform.GetGCodeDir(), TimingFileName); - gb.MachineState().SetError("Failed to read from timing file"); + gb.LatestMachineState().SetError("Failed to read from timing file"); gb.SetState(GCodeState::normal); break; } @@ -1428,7 +1428,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept break; default: // should not happen - gb.MachineState().SetError("Undefined GCodeState"); + gb.LatestMachineState().SetError("Undefined GCodeState"); gb.SetState(GCodeState::normal); break; } @@ -1438,7 +1438,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept // We completed a command, so unlock resources and tell the host about it gb.StopTimer(); UnlockAll(gb); - gb.MachineState().RetrieveStateMachineResult(stateMachineResult, reply); + gb.LatestMachineState().RetrieveStateMachineResult(stateMachineResult, reply); HandleReply(gb, stateMachineResult, reply.c_str()); CheckForDeferredPause(gb); } diff --git a/src/GCodes/ObjectTracker.cpp b/src/GCodes/ObjectTracker.cpp index 69a25f3f..b3597d0a 100644 --- a/src/GCodes/ObjectTracker.cpp +++ b/src/GCodes/ObjectTracker.cpp @@ -47,10 +47,11 @@ constexpr ObjectModelTableEntry ObjectTracker::objectModelTable[] = { "m486Names", OBJECT_MODEL_FUNC(self->usingM486Naming), ObjectModelEntryFlags::none }, { "m486Numbers", OBJECT_MODEL_FUNC(self->usingM486Labelling), ObjectModelEntryFlags::none }, { "objects", OBJECT_MODEL_FUNC_NOSELF(&objectsArrayDescriptor), ObjectModelEntryFlags::none }, + #if TRACK_OBJECT_NAMES // 1. ObjectDirectoryEntry root { "cancelled", OBJECT_MODEL_FUNC(self->IsCancelled(context.GetLastIndex())), ObjectModelEntryFlags::none }, - { "name", OBJECT_MODEL_FUNC(self->objectDirectory[context.GetLastIndex()].name), ObjectModelEntryFlags::none }, + { "name", OBJECT_MODEL_FUNC(self->objectDirectory[context.GetLastIndex()].name.IncreaseRefCount()), ObjectModelEntryFlags::none }, { "x", OBJECT_MODEL_FUNC_NOSELF(&xArrayDescriptor), ObjectModelEntryFlags::none }, { "y", OBJECT_MODEL_FUNC_NOSELF(&yArrayDescriptor), ObjectModelEntryFlags::none }, #endif @@ -81,7 +82,6 @@ void ObjectTracker::Init() noexcept { objectDirectory[i].Init(""); } - objectNames.Reset(); usingM486Naming = false; #endif } @@ -137,10 +137,9 @@ GCodeResult ObjectTracker::HandleM486(GCodeBuffer &gb, const StringRef &reply, O { CreateObject(num, objectName.c_str()); } - else if (strcmp(objectName.c_str(), objectDirectory[num].name) != 0) + else if (strcmp(objectName.c_str(), objectDirectory[num].name.Get().Ptr()) != 0) { - objectNames.FinishedUsing(objectDirectory[num].name); - SetObjectName(num, objectName.c_str()); + objectDirectory[num].SetName(objectName.c_str()); reprap.JobUpdated(); } } @@ -225,7 +224,7 @@ GCodeResult ObjectTracker::HandleM486(GCodeBuffer &gb, const StringRef &reply, O (objectsCancelled.IsBitSet(i) ? " (cancelled)" : ""), (int)obj.x[0], (int)obj.x[1], (int)obj.y[0], (int)obj.y[1], - obj.name); + obj.name.Get().Ptr()); } if (numObjects > MaxTrackedObjects) { @@ -278,7 +277,7 @@ bool ObjectTracker::WriteObjectDirectory(FileStore *f) const noexcept for (size_t i = 0; ok && i < min<unsigned int>(numObjects, MaxTrackedObjects); ++i) { String<StringLength100> buf; - buf.printf("M486 S%u A\"%s\"\n", i, objectDirectory[i].name); + buf.printf("M486 S%u A\"%s\"\n", i, objectDirectory[i].name.Get().Ptr()); ok = f->Write(buf.c_str()); } #else @@ -318,7 +317,7 @@ bool ObjectTracker::WriteObjectDirectory(FileStore *f) const noexcept // Create a new entry in the object directory void ObjectDirectoryEntry::Init(const char *label) noexcept { - name = label; + name.Assign(label); x[0] = x[1] = y[0] = y[1] = std::numeric_limits<int16_t>::min(); } @@ -369,6 +368,11 @@ bool ObjectDirectoryEntry::UpdateObjectCoordinates(const float coords[], AxesBit return updated; } +void ObjectDirectoryEntry::SetName(const char *label) noexcept +{ + name.Assign(label); +} + // 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. @@ -383,14 +387,6 @@ void ObjectTracker::UpdateObjectCoordinates(const float coords[], AxesBitmap axe } } -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 { @@ -401,7 +397,7 @@ void ObjectTracker::CreateObject(unsigned int number, const char *label) noexcep objectDirectory[numObjects].Init(""); ++numObjects; } - SetObjectName(number, label); + objectDirectory[number].SetName(label); reprap.JobUpdated(); } } @@ -413,7 +409,7 @@ void ObjectTracker::StartObject(GCodeBuffer& gb, const char *label) noexcept { for (size_t i = 0; i < numObjects; ++i) { - if (strcmp(objectDirectory[i].name, label) == 0) + if (strcmp(objectDirectory[i].name.Get().Ptr(), label) == 0) { ChangeToObject(gb, i); return; diff --git a/src/GCodes/ObjectTracker.h b/src/GCodes/ObjectTracker.h index 0b0e253b..efcf4eac 100644 --- a/src/GCodes/ObjectTracker.h +++ b/src/GCodes/ObjectTracker.h @@ -12,17 +12,18 @@ #include "GCodeResult.h" #include "RestorePoint.h" #include <ObjectModel/ObjectModel.h> -#include <General/StringBuffer.h> +#include <Platform/Heap.h> #if TRACK_OBJECT_NAMES struct ObjectDirectoryEntry { - const char *name; // pointer to the object name within the string buffer - int16_t x[2], y[2]; // lowest and highest extrusion coordinates + AutoStringHandle name; // pointer to the object name within the string buffer + int16_t x[2], y[2]; // lowest and highest extrusion coordinates void Init(const char *label) noexcept; bool UpdateObjectCoordinates(const float coords[], AxesBitmap axes) noexcept; + void SetName(const char *label) noexcept; }; #endif @@ -35,9 +36,6 @@ class ObjectTracker public: ObjectTracker() noexcept : numObjects(0) -#if TRACK_OBJECT_NAMES - , objectNames(stringBufferStorage, ARRAY_SIZE(stringBufferStorage)) -#endif { } void Init() noexcept; @@ -82,7 +80,6 @@ private: #if TRACK_OBJECT_NAMES void CreateObject(unsigned int number, const char *label) noexcept; - void SetObjectName(unsigned int number, const char *label) noexcept; ExpressionValue GetXCoordinate(const ObjectExplorationContext& context) const noexcept; ExpressionValue GetYCoordinate(const ObjectExplorationContext& context) const noexcept; #endif @@ -95,8 +92,6 @@ private: #if TRACK_OBJECT_NAMES ObjectDirectoryEntry objectDirectory[MaxTrackedObjects]; - StringBuffer objectNames; - char stringBufferStorage[ObjectNamesStringSpace]; bool usingM486Naming; #endif diff --git a/src/GCodes/Variable.cpp b/src/GCodes/Variable.cpp new file mode 100644 index 00000000..b62f30ff --- /dev/null +++ b/src/GCodes/Variable.cpp @@ -0,0 +1,83 @@ +/* + * Variable.cpp + * + * Created on: 6 Mar 2021 + * Author: David + */ + +#include "Variable.h" + +Variable::Variable(const char *str, ExpressionValue pVal, int8_t pScope) noexcept : name(str), val(pVal), scope(pScope) +{ +} + +Variable::~Variable() +{ + name.Delete(); + val.Release(); +} + +Variable* VariableSet::Lookup(const char *str) noexcept +{ + Variable *v; + for (v = root; v != nullptr; v = v->next) + { + auto vname = v->name.Get(); + if (strcmp(vname.Ptr(), str) == 0) + { + break; + } + } + return v; +} + +void VariableSet::Insert(Variable *toInsert) noexcept +{ + toInsert->next = root; + root = toInsert; +} + +// Remove all variables with a scope greater than the parameter +void VariableSet::EndScope(uint8_t blockNesting) noexcept +{ + Variable *prev = nullptr; + for (Variable *v = root; v != nullptr; ) + { + if (v->scope > blockNesting) + { + Variable *temp = v; + v = v->next; + if (prev == nullptr) + { + root = v; + } + else + { + prev->next = v; + } + delete temp; + } + else + { + prev = v; + v = v->next; + } + } +} + +void VariableSet::Clear() noexcept +{ + while (root != nullptr) + { + Variable *v = root; + root = v->next; + delete v; + } +} + +VariableSet::~VariableSet() +{ + Clear(); +} + +// End diff --git a/src/GCodes/Variable.h b/src/GCodes/Variable.h new file mode 100644 index 00000000..fa936e4e --- /dev/null +++ b/src/GCodes/Variable.h @@ -0,0 +1,56 @@ +/* + * Variable.h + * + * Created on: 6 Mar 2021 + * Author: David + */ + +#ifndef SRC_GCODES_VARIABLE_H_ +#define SRC_GCODES_VARIABLE_H_ + +#include <RepRapFirmware.h> +#include <General/FreelistManager.h> +#include <Platform/Heap.h> +#include <ObjectModel/ObjectModel.h> + +// Class to represent a variable having a name and a value +class Variable +{ +public: + friend class VariableSet; + + void* operator new(size_t sz) noexcept { return FreelistManager::Allocate<Variable>(); } + void operator delete(void* p) noexcept { FreelistManager::Release<Variable>(p); } + + Variable(const char *str, ExpressionValue pVal, int8_t pScope) noexcept; + ~Variable(); + + ExpressionValue GetValue() const noexcept { return val; } + int8_t GetScope() const noexcept { return scope; } + void Assign(ExpressionValue ev) noexcept { val = ev; } + +private: + Variable *next; + StringHandle name; + ExpressionValue val; + int8_t scope; // -1 for a parameter, else the block nesting level when it was created +}; + +// Class to represent a collection of variables. +// For now this is just a linked list, but it could be changed to a hash table for faster lookup and insertion. +class VariableSet +{ +public: + VariableSet() noexcept : root(nullptr) { } + ~VariableSet(); + + Variable *Lookup(const char *str) noexcept; + void Insert(Variable *toInsert) noexcept; + void EndScope(uint8_t blockNesting) noexcept; + void Clear() noexcept; + +private: + Variable *root; +}; + +#endif /* SRC_GCODES_VARIABLE_H_ */ |