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

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManuel Coenen <manuel@duet3d.com>2021-03-10 12:38:04 +0300
committerManuel Coenen <manuel@duet3d.com>2021-03-10 12:38:04 +0300
commit68cfaacc16424ff08e53a2c52c51a76ecc7f98ba (patch)
tree8a8f70c8e81600fe4170a485edfd6fdb4d54d722 /src/GCodes
parentbb201b96deaf1226d4ec3a0eb2c72f9dc2d7229c (diff)
parent8b89aab7455a870574fed653738af5566e82beb3 (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.cpp81
-rw-r--r--src/GCodes/GCodeBuffer/BinaryParser.h2
-rw-r--r--src/GCodes/GCodeBuffer/ExpressionParser.cpp131
-rw-r--r--src/GCodes/GCodeBuffer/ExpressionParser.h10
-rw-r--r--src/GCodes/GCodeBuffer/GCodeBuffer.cpp51
-rw-r--r--src/GCodes/GCodeBuffer/GCodeBuffer.h13
-rw-r--r--src/GCodes/GCodeBuffer/StringParser.cpp268
-rw-r--r--src/GCodes/GCodeBuffer/StringParser.h6
-rw-r--r--src/GCodes/GCodeMachineState.cpp15
-rw-r--r--src/GCodes/GCodeMachineState.h11
-rw-r--r--src/GCodes/GCodes.cpp169
-rw-r--r--src/GCodes/GCodes.h9
-rw-r--r--src/GCodes/GCodes2.cpp82
-rw-r--r--src/GCodes/GCodes3.cpp22
-rw-r--r--src/GCodes/GCodes4.cpp104
-rw-r--r--src/GCodes/ObjectTracker.cpp32
-rw-r--r--src/GCodes/ObjectTracker.h13
-rw-r--r--src/GCodes/Variable.cpp83
-rw-r--r--src/GCodes/Variable.h56
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_ */