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
path: root/src
diff options
context:
space:
mode:
authorDavid Crocker <dcrocker@eschertech.com>2019-12-23 22:37:31 +0300
committerDavid Crocker <dcrocker@eschertech.com>2019-12-23 22:37:31 +0300
commitecbc545743695c73791ed8420bb4ad97266bec28 (patch)
tree4c33bb0c9efcd92e5bf8d219c447f6cfde894ae8 /src
parent7cf6080c42246a0bfea1e807325d312a457e13d3 (diff)
Handle command parsing errors using exceptions
Diffstat (limited to 'src')
-rw-r--r--src/CAN/CanMessageGenericConstructor.cpp18
-rw-r--r--src/DuetM/Pins_DuetM.h1
-rw-r--r--src/Endstops/SwitchEndstop.cpp7
-rw-r--r--src/Fans/Fan.cpp3
-rw-r--r--src/Fans/FansManager.cpp6
-rw-r--r--src/GCodes/GCodeBuffer/BinaryParser.cpp114
-rw-r--r--src/GCodes/GCodeBuffer/BinaryParser.h34
-rw-r--r--src/GCodes/GCodeBuffer/GCodeBuffer.cpp88
-rw-r--r--src/GCodes/GCodeBuffer/GCodeBuffer.h56
-rw-r--r--src/GCodes/GCodeBuffer/ParseException.cpp23
-rw-r--r--src/GCodes/GCodeBuffer/ParseException.h48
-rw-r--r--src/GCodes/GCodeBuffer/StringParser.cpp493
-rw-r--r--src/GCodes/GCodeBuffer/StringParser.h90
-rw-r--r--src/GCodes/GCodes.cpp23
-rw-r--r--src/GCodes/GCodes2.cpp5926
-rw-r--r--src/Hardware/IoPorts.cpp7
-rw-r--r--src/Heating/Heat.cpp24
-rw-r--r--src/Heating/Sensors/AdditionalOutputSensor.cpp6
-rw-r--r--src/Linux/DataTransfer.cpp2
-rw-r--r--src/Linux/LinuxInterface.cpp4
-rw-r--r--src/Networking/ESP8266WiFi/WiFiInterface.cpp146
-rw-r--r--src/Networking/ESP8266WiFi/WiFiInterface.h2
-rw-r--r--src/ObjectModel/ObjectModel.cpp33
-rw-r--r--src/ObjectModel/ObjectModel.h21
-rw-r--r--src/Pccb/Pins_Pccb.h2
-rw-r--r--src/Platform.cpp12
-rw-r--r--src/RADDS/Pins_RADDS.h37
-rw-r--r--src/RepRap.cpp6
-rw-r--r--src/RepRap.h4
-rw-r--r--src/RepRapFirmware.h5
-rw-r--r--src/Storage/FileStore.cpp16
31 files changed, 3652 insertions, 3605 deletions
diff --git a/src/CAN/CanMessageGenericConstructor.cpp b/src/CAN/CanMessageGenericConstructor.cpp
index 3a270c57..c13307c2 100644
--- a/src/CAN/CanMessageGenericConstructor.cpp
+++ b/src/CAN/CanMessageGenericConstructor.cpp
@@ -117,11 +117,7 @@ bool CanMessageGenericConstructor::PopulateFromCommand(GCodeBuffer& gb, const St
case ParamDescriptor::char_p:
{
String<StringLength20> str;
- if (!gb.GetQuotedString(str.GetRef()))
- {
- reply.printf("expected quoted string after '%c'", d->letter);
- return false;
- }
+ gb.GetQuotedString(str.GetRef());
if (str.strlen() != 1)
{
reply.printf("expected single-character quoted string after '%c'", d->letter);
@@ -135,11 +131,7 @@ bool CanMessageGenericConstructor::PopulateFromCommand(GCodeBuffer& gb, const St
case ParamDescriptor::string:
{
String<StringLength20> str;
- if (!gb.GetQuotedString(str.GetRef()))
- {
- reply.printf("expected quoted string after '%c'", d->letter);
- return false;
- }
+ gb.GetQuotedString(str.GetRef());
overflowed = StoreValue(str.c_str(), str.strlen() + 1);
}
break;
@@ -147,11 +139,7 @@ bool CanMessageGenericConstructor::PopulateFromCommand(GCodeBuffer& gb, const St
case ParamDescriptor::reducedString:
{
String<StringLength20> str;
- if (!gb.GetReducedString(str.GetRef()))
- {
- reply.printf("expected quoted string after '%c'", d->letter);
- return false;
- }
+ gb.GetReducedString(str.GetRef());
// We don't want port names sent to expansion boards to include the board number, so remove the board number.
// We also use the reducedString type for sensor names, but they should't start with digits followed by '.'.
(void)IoPort::RemoveBoardAddress(str.GetRef());
diff --git a/src/DuetM/Pins_DuetM.h b/src/DuetM/Pins_DuetM.h
index e6bd13ea..4208a797 100644
--- a/src/DuetM/Pins_DuetM.h
+++ b/src/DuetM/Pins_DuetM.h
@@ -40,7 +40,6 @@ constexpr uint32_t IAP_IMAGE_END = 0x0047FFFF; // we allow a full 64K on
#define HAS_VOLTAGE_MONITOR 1
#define ENFORCE_MAX_VIN 0
#define HAS_VREF_MONITOR 1
-#define ACTIVE_LOW_HEAT_ON 1
#define SUPPORT_INKJET 0 // set nonzero to support inkjet control
#define SUPPORT_ROLAND 0 // set nonzero to support Roland mill
diff --git a/src/Endstops/SwitchEndstop.cpp b/src/Endstops/SwitchEndstop.cpp
index 00e0e2dd..4b000710 100644
--- a/src/Endstops/SwitchEndstop.cpp
+++ b/src/Endstops/SwitchEndstop.cpp
@@ -56,12 +56,7 @@ void SwitchEndstop::ReleasePorts()
GCodeResult SwitchEndstop::Configure(GCodeBuffer& gb, const StringRef& reply)
{
String<StringLength50> portNames;
- if (!gb.GetReducedString(portNames.GetRef()))
- {
- reply.copy("Missing port name string");
- return GCodeResult::error;
- }
-
+ gb.GetReducedString(portNames.GetRef());
return Configure(portNames.c_str(), reply);
}
diff --git a/src/Fans/Fan.cpp b/src/Fans/Fan.cpp
index c45f602c..d9453398 100644
--- a/src/Fans/Fan.cpp
+++ b/src/Fans/Fan.cpp
@@ -107,9 +107,10 @@ bool Fan::Configure(unsigned int mcode, size_t fanNum, GCodeBuffer& gb, const St
}
}
- if (gb.Seen('C') && gb.GetQuotedString(name.GetRef()))
+ if (gb.Seen('C'))
{
seen = true;
+ gb.GetQuotedString(name.GetRef());
}
if (seen)
diff --git a/src/Fans/FansManager.cpp b/src/Fans/FansManager.cpp
index 7aa484b3..721c4260 100644
--- a/src/Fans/FansManager.cpp
+++ b/src/Fans/FansManager.cpp
@@ -96,11 +96,7 @@ GCodeResult FansManager::ConfigureFanPort(uint32_t fanNum, GCodeBuffer& gb, cons
if (seenPin)
{
String<StringLength50> pinName;
- if (!gb.GetReducedString(pinName.GetRef()))
- {
- reply.copy("Missing pin name");
- return GCodeResult::error;
- }
+ gb.GetReducedString(pinName.GetRef());
WriteLocker lock(fansLock);
diff --git a/src/GCodes/GCodeBuffer/BinaryParser.cpp b/src/GCodes/GCodeBuffer/BinaryParser.cpp
index 870e1673..91f1a6d3 100644
--- a/src/GCodes/GCodeBuffer/BinaryParser.cpp
+++ b/src/GCodes/GCodeBuffer/BinaryParser.cpp
@@ -115,8 +115,7 @@ float BinaryParser::GetFValue()
return value;
}
- INTERNAL_ERROR;
- return 0.0f;
+ THROW_INTERNAL_ERROR;
}
int32_t BinaryParser::GetIValue()
@@ -144,8 +143,7 @@ int32_t BinaryParser::GetIValue()
return value;
}
- INTERNAL_ERROR;
- return 0;
+ THROW_INTERNAL_ERROR;
}
uint32_t BinaryParser::GetUIValue()
@@ -173,8 +171,7 @@ uint32_t BinaryParser::GetUIValue()
return value;
}
- INTERNAL_ERROR;
- return 0;
+ THROW_INTERNAL_ERROR;
}
// Get a driver ID
@@ -200,24 +197,19 @@ DriverId BinaryParser::GetDriverId()
return value;
}
- INTERNAL_ERROR;
- value.Clear();
- return value;
+ THROW_INTERNAL_ERROR;
}
-bool BinaryParser::GetIPAddress(IPAddress& returnedIp)
+void BinaryParser::GetIPAddress(IPAddress& returnedIp)
{
if (seenParameter == nullptr)
{
- INTERNAL_ERROR;
- return false;
+ THROW_INTERNAL_ERROR;
}
if (seenParameter->type != DataType::String)
{
- seenParameter = nullptr;
- seenParameterValue = nullptr;
- return false;
+ throw ConstructParseException("IP address string expected");
}
const char* p = seenParameterValue;
@@ -229,9 +221,7 @@ bool BinaryParser::GetIPAddress(IPAddress& returnedIp)
const unsigned long v = SafeStrtoul(p, &pp);
if (pp == p || pp > seenParameterValue + seenParameter->intValue || v > 255)
{
- seenParameter = nullptr;
- seenParameterValue = nullptr;
- return false;
+ throw ConstructParseException("invalid IP address");
}
ip[n] = (uint8_t)v;
++n;
@@ -242,36 +232,30 @@ bool BinaryParser::GetIPAddress(IPAddress& returnedIp)
}
if (n == 4)
{
- seenParameter = nullptr;
- seenParameterValue = nullptr;
- return false;
+ throw ConstructParseException("invalid IP address");
}
++p;
}
seenParameter = nullptr;
seenParameterValue = nullptr;
- if (n == 4)
+ if (n != 4)
{
- returnedIp.SetV4(ip);
- return true;
+ throw ConstructParseException("invalid IP address");
}
- returnedIp.SetNull();
- return false;
+
+ returnedIp.SetV4(ip);
}
-bool BinaryParser::GetMacAddress(uint8_t mac[6])
+void BinaryParser::GetMacAddress(uint8_t mac[6])
{
if (seenParameter == nullptr)
{
- INTERNAL_ERROR;
- return false;
+ THROW_INTERNAL_ERROR;
}
if (seenParameter->type != DataType::String)
{
- seenParameter = nullptr;
- seenParameterValue = nullptr;
- return false;
+ throw ConstructParseException("MAC address string expected");
}
const char* p = seenParameterValue;
@@ -282,9 +266,7 @@ bool BinaryParser::GetMacAddress(uint8_t mac[6])
const unsigned long v = SafeStrtoul(p, &pp, 16);
if (pp == p || pp > seenParameterValue + seenParameter->intValue || v > 255)
{
- seenParameter = nullptr;
- seenParameterValue = nullptr;
- return false;
+ throw ConstructParseException("invalid MAC address");
}
mac[n] = (uint8_t)v;
++n;
@@ -295,30 +277,36 @@ bool BinaryParser::GetMacAddress(uint8_t mac[6])
}
if (n == 6)
{
- seenParameter = nullptr;
- seenParameterValue = nullptr;
- return false;
+ throw ConstructParseException("invalid MAC address");
}
++p;
}
+
+ if (n != 6)
+ {
+ throw ConstructParseException("invalid MAC address");
+ }
+
seenParameter = nullptr;
seenParameterValue = nullptr;
- return n == 6;
}
-bool BinaryParser::GetUnprecedentedString(const StringRef& str)
+void BinaryParser::GetUnprecedentedString(const StringRef& str, bool allowEmpty)
{
str.Clear();
WriteParameters(str, false);
- return !str.IsEmpty();
+ if (!allowEmpty && str.IsEmpty())
+ {
+ throw ConstructParseException("non-empty string expected");
+ }
}
-bool BinaryParser::GetQuotedString(const StringRef& str)
+void BinaryParser::GetQuotedString(const StringRef& str)
{
- return GetPossiblyQuotedString(str);
+ GetPossiblyQuotedString(str);
}
-bool BinaryParser::GetPossiblyQuotedString(const StringRef& str)
+void BinaryParser::GetPossiblyQuotedString(const StringRef& str)
{
if (seenParameter != nullptr && (seenParameter->type == DataType::String || seenParameter->type == DataType::Expression))
{
@@ -330,10 +318,13 @@ bool BinaryParser::GetPossiblyQuotedString(const StringRef& str)
}
seenParameter = nullptr;
seenParameterValue = nullptr;
- return !str.IsEmpty();
+ if (str.IsEmpty())
+ {
+ throw ConstructParseException("non-empty string expected");
+ }
}
-bool BinaryParser::GetReducedString(const StringRef& str)
+void BinaryParser::GetReducedString(const StringRef& str)
{
str.Clear();
if (seenParameterValue != nullptr && (seenParameter->type == DataType::String || seenParameter->type == DataType::Expression))
@@ -353,7 +344,7 @@ bool BinaryParser::GetReducedString(const StringRef& str)
{
seenParameter = nullptr;
seenParameterValue = nullptr;
- return false;
+ throw ConstructParseException("control character in string");
}
str.cat(tolower(c));
break;
@@ -363,7 +354,10 @@ bool BinaryParser::GetReducedString(const StringRef& str)
seenParameter = nullptr;
seenParameterValue = nullptr;
- return !str.IsEmpty();
+ if (str.IsEmpty())
+ {
+ throw ConstructParseException("non-empty string expected");
+ }
}
void BinaryParser::GetFloatArray(float arr[], size_t& length, bool doPad)
@@ -386,9 +380,7 @@ void BinaryParser::GetDriverIdArray(DriverId arr[], size_t& length)
{
if (seenParameter == nullptr)
{
- INTERNAL_ERROR;
- length = 0;
- return;
+ THROW_INTERNAL_ERROR;
}
switch (seenParameter->type)
@@ -484,9 +476,7 @@ template<typename T> void BinaryParser::GetArray(T arr[], size_t& length, bool d
{
if (seenParameter == nullptr)
{
- INTERNAL_ERROR;
- length = 0;
- return;
+ THROW_INTERNAL_ERROR;
}
int lastIndex = -1;
@@ -648,3 +638,19 @@ void BinaryParser::WriteParameters(const StringRef& s, bool quoteStrings) const
}
}
+ParseException BinaryParser::ConstructParseException(const char *str) const
+{
+ return ParseException(-1, str);
+}
+
+ParseException BinaryParser::ConstructParseException(const char *str, const char *param) const
+{
+ return ParseException(-1, str, param);
+}
+
+ParseException BinaryParser::ConstructParseException(const char *str, uint32_t param) const
+{
+ return ParseException(-1, str, param);
+}
+
+// End
diff --git a/src/GCodes/GCodeBuffer/BinaryParser.h b/src/GCodes/GCodeBuffer/BinaryParser.h
index cfd412a7..ebfb85fb 100644
--- a/src/GCodes/GCodeBuffer/BinaryParser.h
+++ b/src/GCodes/GCodeBuffer/BinaryParser.h
@@ -11,6 +11,7 @@
#include "Linux/MessageFormats.h"
#include "MessageType.h"
#include "RepRapFirmware.h"
+#include "ParseException.h"
class GCodeBuffer;
class IPAddress;
@@ -28,20 +29,20 @@ public:
int GetCommandNumber() const;
int8_t GetCommandFraction() const;
- float GetFValue() __attribute__((hot)); // Get a float after a key letter
- int32_t GetIValue() __attribute__((hot)); // Get an integer after a key letter
- uint32_t GetUIValue(); // Get an unsigned integer value
- DriverId GetDriverId(); // Get a driver ID
- bool GetIPAddress(IPAddress& returnedIp); // Get an IP address quad after a key letter
- bool GetMacAddress(uint8_t mac[6]); // Get a MAC address sextet after a key letter
- bool GetUnprecedentedString(const StringRef& str); // Get a string with no preceding key letter
- bool GetQuotedString(const StringRef& str); // Get and copy a quoted string
- bool GetPossiblyQuotedString(const StringRef& str); // Get and copy a string which may or may not be quoted
- bool GetReducedString(const StringRef& str); // Get and copy a quoted string, removing certain characters
- void GetFloatArray(float arr[], size_t& length, bool doPad) __attribute__((hot)); // Get a colon-separated list of floats after a key letter
- void GetIntArray(int32_t arr[], size_t& length, bool doPad); // Get a :-separated list of ints after a key letter
- void GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad); // Get a :-separated list of unsigned ints after a key letter
- void GetDriverIdArray(DriverId arr[], size_t& length); // Get a :-separated list of drivers after a key letter
+ float GetFValue() THROWS_PARSE_ERROR __attribute__((hot)); // Get a float after a key letter
+ int32_t GetIValue() THROWS_PARSE_ERROR __attribute__((hot)); // Get an integer after a key letter
+ uint32_t GetUIValue() THROWS_PARSE_ERROR; // Get an unsigned integer value
+ DriverId GetDriverId() THROWS_PARSE_ERROR; // Get a driver ID
+ void GetIPAddress(IPAddress& returnedIp) THROWS_PARSE_ERROR; // Get an IP address quad after a key letter
+ void GetMacAddress(uint8_t mac[6]) THROWS_PARSE_ERROR; // Get a MAC address sextet after a key letter
+ void GetUnprecedentedString(const StringRef& str, bool allowEmpty) THROWS_PARSE_ERROR; // Get a string with no preceding key letter
+ void GetQuotedString(const StringRef& str) THROWS_PARSE_ERROR; // Get and copy a quoted string
+ void GetPossiblyQuotedString(const StringRef& str) THROWS_PARSE_ERROR; // Get and copy a string which may or may not be quoted
+ void GetReducedString(const StringRef& str) THROWS_PARSE_ERROR; // Get and copy a quoted string, removing certain characters
+ void GetFloatArray(float arr[], size_t& length, bool doPad) THROWS_PARSE_ERROR __attribute__((hot)); // Get a colon-separated list of floats after a key letter
+ void GetIntArray(int32_t arr[], size_t& length, bool doPad) THROWS_PARSE_ERROR; // Get a :-separated list of ints after a key letter
+ void GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad) THROWS_PARSE_ERROR; // Get a :-separated list of unsigned ints after a key letter
+ void GetDriverIdArray(DriverId arr[], size_t& length) THROWS_PARSE_ERROR; // Get a :-separated list of drivers after a key letter
void SetFinished(); // Set the G Code finished
@@ -54,9 +55,12 @@ public:
void AppendFullCommand(const StringRef &s) const;
private:
-
GCodeBuffer& gb;
+ ParseException ConstructParseException(const char *str) const;
+ ParseException ConstructParseException(const char *str, const char *param) const;
+ ParseException ConstructParseException(const char *str, uint32_t param) const;
+
size_t AddPadding(size_t bytesRead) const;
template<typename T> void GetArray(T arr[], size_t& length, bool doPad) __attribute__((hot));
void WriteParameters(const StringRef& s, bool quoteStrings) const;
diff --git a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp
index 158783d3..62b43164 100644
--- a/src/GCodes/GCodeBuffer/GCodeBuffer.cpp
+++ b/src/GCodes/GCodeBuffer/GCodeBuffer.cpp
@@ -13,6 +13,7 @@
#endif
#include "BinaryParser.h"
#include "StringParser.h"
+#include "ParseException.h"
#include "RepRap.h"
#include "Platform.h"
@@ -181,6 +182,15 @@ bool GCodeBuffer::Seen(char c)
return isBinaryBuffer ? binaryParser.Seen(c) : stringParser.Seen(c);
}
+// Test for character present, throw error if not
+void GCodeBuffer::MustSee(char c)
+{
+ if (!Seen(c))
+ {
+ throw ParseException(-1, "missing parameter '%c'", (uint32_t)c);
+ }
+}
+
// Get a float after a key letter
float GCodeBuffer::GetFValue()
{
@@ -206,38 +216,80 @@ uint32_t GCodeBuffer::GetUIValue()
}
// Get an IP address quad after a key letter
-bool GCodeBuffer::GetIPAddress(IPAddress& returnedIp)
+void GCodeBuffer::GetIPAddress(IPAddress& returnedIp)
{
- return isBinaryBuffer ? binaryParser.GetIPAddress(returnedIp) : stringParser.GetIPAddress(returnedIp);
+ if (isBinaryBuffer)
+ {
+ binaryParser.GetIPAddress(returnedIp);
+ }
+ else
+ {
+ stringParser.GetIPAddress(returnedIp);
+ }
}
// Get a MAC address sextet after a key letter
-bool GCodeBuffer::GetMacAddress(uint8_t mac[6])
+void GCodeBuffer::GetMacAddress(uint8_t mac[6])
{
- return isBinaryBuffer ? binaryParser.GetMacAddress(mac) : stringParser.GetMacAddress(mac);
+ if (isBinaryBuffer)
+ {
+ binaryParser.GetMacAddress(mac);
+ }
+ else
+ {
+ stringParser.GetMacAddress(mac);
+ }
}
// Get a string with no preceding key letter
-bool GCodeBuffer::GetUnprecedentedString(const StringRef& str)
+void GCodeBuffer::GetUnprecedentedString(const StringRef& str, bool allowEmpty)
{
- return isBinaryBuffer ? binaryParser.GetUnprecedentedString(str) : stringParser.GetUnprecedentedString(str);
+ if (isBinaryBuffer)
+ {
+ binaryParser.GetUnprecedentedString(str, allowEmpty);
+ }
+ else
+ {
+ stringParser.GetUnprecedentedString(str, allowEmpty);
+ }
}
// Get and copy a quoted string
-bool GCodeBuffer::GetQuotedString(const StringRef& str)
+void GCodeBuffer::GetQuotedString(const StringRef& str)
{
- return isBinaryBuffer ? binaryParser.GetQuotedString(str) : stringParser.GetQuotedString(str);
+ if (isBinaryBuffer)
+ {
+ binaryParser.GetQuotedString(str);
+ }
+ else
+ {
+ stringParser.GetQuotedString(str);
+ }
}
// Get and copy a string which may or may not be quoted
-bool GCodeBuffer::GetPossiblyQuotedString(const StringRef& str)
+void GCodeBuffer::GetPossiblyQuotedString(const StringRef& str)
{
- return isBinaryBuffer ? binaryParser.GetPossiblyQuotedString(str) : stringParser.GetPossiblyQuotedString(str);
+ if (isBinaryBuffer)
+ {
+ binaryParser.GetPossiblyQuotedString(str);
+ }
+ else
+ {
+ stringParser.GetPossiblyQuotedString(str);
+ }
}
-bool GCodeBuffer::GetReducedString(const StringRef& str)
+void GCodeBuffer::GetReducedString(const StringRef& str)
{
- return isBinaryBuffer ? binaryParser.GetReducedString(str) : stringParser.GetReducedString(str);
+ if (isBinaryBuffer)
+ {
+ binaryParser.GetReducedString(str);
+ }
+ else
+ {
+ stringParser.GetReducedString(str);
+ }
}
// Get a colon-separated list of floats after a key letter
@@ -388,9 +440,10 @@ bool GCodeBuffer::TryGetFloatArray(char c, size_t numVals, float vals[], const S
// If we found it then set 'seen' true and return true, else leave 'seen' alone and return false
bool GCodeBuffer::TryGetQuotedString(char c, const StringRef& str, bool& seen)
{
- if (Seen(c) && GetQuotedString(str))
+ if (Seen(c))
{
seen = true;
+ GetQuotedString(str);
return true;
}
return false;
@@ -400,9 +453,10 @@ bool GCodeBuffer::TryGetQuotedString(char c, const StringRef& str, bool& seen)
// If we found it then set 'seen' true and return true, else leave 'seen' alone and return false
bool GCodeBuffer::TryGetPossiblyQuotedString(char c, const StringRef& str, bool& seen)
{
- if (Seen(c) && GetPossiblyQuotedString(str))
+ if (Seen(c))
{
seen = true;
+ GetPossiblyQuotedString(str);
return true;
}
return false;
@@ -813,10 +867,4 @@ void GCodeBuffer::AppendFullCommand(const StringRef &s) const
}
}
-// Report a program error
-void GCodeBuffer::ReportProgramError(const char *str)
-{
- reprap.GetPlatform().MessageF(AddError(GetResponseMessageType()), "%s\n", str);
-}
-
// End
diff --git a/src/GCodes/GCodeBuffer/GCodeBuffer.h b/src/GCodes/GCodeBuffer/GCodeBuffer.h
index 50aaa2fc..0e79c6bd 100644
--- a/src/GCodes/GCodeBuffer/GCodeBuffer.h
+++ b/src/GCodes/GCodeBuffer/GCodeBuffer.h
@@ -59,32 +59,34 @@ public:
int8_t GetCommandFraction() const;
bool Seen(char c) __attribute__((hot)); // Is a character present?
- float GetFValue() __attribute__((hot)); // Get a float after a key letter
- float GetDistance(); // Get a distance or coordinate and convert it from inches to mm if necessary
- int32_t GetIValue() __attribute__((hot)); // Get an integer after a key letter
- uint32_t GetUIValue(); // Get an unsigned integer value
- bool GetIPAddress(IPAddress& returnedIp); // Get an IP address quad after a key letter
- bool GetMacAddress(uint8_t mac[6]); // Get a MAC address sextet after a key letter
- PwmFrequency GetPwmFrequency(); // Get a PWM frequency
- float GetPwmValue(); // Get a PWM value
- DriverId GetDriverId(); // Get a driver ID
- bool GetUnprecedentedString(const StringRef& str); // Get a string with no preceding key letter
- bool GetQuotedString(const StringRef& str); // Get and copy a quoted string
- bool GetPossiblyQuotedString(const StringRef& str); // Get and copy a string which may or may not be quoted
- bool GetReducedString(const StringRef& str); // Get and copy a quoted string, removing certain characters
- void GetFloatArray(float arr[], size_t& length, bool doPad) __attribute__((hot)); // Get a colon-separated list of floats after a key letter
- void GetIntArray(int32_t arr[], size_t& length, bool doPad); // Get a :-separated list of ints after a key letter
- void GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad); // Get a :-separated list of unsigned ints after a key letter
- void GetDriverIdArray(DriverId arr[], size_t& length); // Get a :-separated list of drivers after a key letter
-
- bool TryGetFValue(char c, float& val, bool& seen);
- bool TryGetIValue(char c, int32_t& val, bool& seen);
- bool TryGetUIValue(char c, uint32_t& val, bool& seen);
- bool TryGetBValue(char c, bool& val, bool& seen);
- bool TryGetFloatArray(char c, size_t numVals, float vals[], const StringRef& reply, bool& seen, bool doPad = false);
- bool TryGetUIArray(char c, size_t numVals, uint32_t vals[], const StringRef& reply, bool& seen, bool doPad = false);
- bool TryGetQuotedString(char c, const StringRef& str, bool& seen);
- bool TryGetPossiblyQuotedString(char c, const StringRef& str, bool& seen);
+ void MustSee(char c); // Test for character present, throw error if not
+
+ float GetFValue() THROWS_PARSE_ERROR __attribute__((hot)); // Get a float after a key letter
+ float GetDistance() THROWS_PARSE_ERROR; // Get a distance or coordinate and convert it from inches to mm if necessary
+ int32_t GetIValue() THROWS_PARSE_ERROR __attribute__((hot)); // Get an integer after a key letter
+ uint32_t GetUIValue() THROWS_PARSE_ERROR; // Get an unsigned integer value
+ void GetIPAddress(IPAddress& returnedIp) THROWS_PARSE_ERROR; // Get an IP address quad after a key letter
+ void GetMacAddress(uint8_t mac[6]) THROWS_PARSE_ERROR; // Get a MAC address sextet after a key letter
+ PwmFrequency GetPwmFrequency() THROWS_PARSE_ERROR; // Get a PWM frequency
+ float GetPwmValue() THROWS_PARSE_ERROR; // Get a PWM value
+ DriverId GetDriverId() THROWS_PARSE_ERROR; // Get a driver ID
+ void GetUnprecedentedString(const StringRef& str, bool allowEmpty = false) THROWS_PARSE_ERROR; // Get a string with no preceding key letter
+ void GetQuotedString(const StringRef& str) THROWS_PARSE_ERROR; // Get and copy a quoted string
+ void GetPossiblyQuotedString(const StringRef& str) THROWS_PARSE_ERROR; // Get and copy a string which may or may not be quoted
+ void GetReducedString(const StringRef& str) THROWS_PARSE_ERROR; // Get and copy a quoted string, removing certain characters
+ void GetFloatArray(float arr[], size_t& length, bool doPad) THROWS_PARSE_ERROR __attribute__((hot)); // Get a colon-separated list of floats after a key letter
+ void GetIntArray(int32_t arr[], size_t& length, bool doPad) THROWS_PARSE_ERROR; // Get a :-separated list of ints after a key letter
+ void GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad) THROWS_PARSE_ERROR; // Get a :-separated list of unsigned ints after a key letter
+ void GetDriverIdArray(DriverId arr[], size_t& length) THROWS_PARSE_ERROR; // Get a :-separated list of drivers after a key letter
+
+ bool TryGetFValue(char c, float& val, bool& seen) THROWS_PARSE_ERROR;
+ bool TryGetIValue(char c, int32_t& val, bool& seen) THROWS_PARSE_ERROR;
+ bool TryGetUIValue(char c, uint32_t& val, bool& seen) THROWS_PARSE_ERROR;
+ bool TryGetBValue(char c, bool& val, bool& seen) THROWS_PARSE_ERROR;
+ bool TryGetFloatArray(char c, size_t numVals, float vals[], const StringRef& reply, bool& seen, bool doPad = false) THROWS_PARSE_ERROR;
+ bool TryGetUIArray(char c, size_t numVals, uint32_t vals[], const StringRef& reply, bool& seen, bool doPad = false) THROWS_PARSE_ERROR;
+ bool TryGetQuotedString(char c, const StringRef& str, bool& seen) THROWS_PARSE_ERROR;
+ bool TryGetPossiblyQuotedString(char c, const StringRef& str, bool& seen) THROWS_PARSE_ERROR;
bool IsIdle() const;
bool IsCompletelyIdle() const;
@@ -169,8 +171,6 @@ public:
GCodeInput *GetNormalInput() const { return normalInput; } //TEMPORARY!
private:
- void ReportProgramError(const char *str);
-
const GCodeChannel codeChannel; // Channel number of this instance
GCodeInput *normalInput; // Our normal input stream, or nullptr if there isn't one
diff --git a/src/GCodes/GCodeBuffer/ParseException.cpp b/src/GCodes/GCodeBuffer/ParseException.cpp
new file mode 100644
index 00000000..add55b55
--- /dev/null
+++ b/src/GCodes/GCodeBuffer/ParseException.cpp
@@ -0,0 +1,23 @@
+/*
+ * ParseException.cpp
+ *
+ * Created on: 21 Dec 2019
+ * Author: David
+ */
+
+#include "ParseException.h"
+
+#include <General/StringRef.h>
+
+void ParseException::GetMessage(const StringRef &reply) const
+{
+ reply.copy("Parsing error");
+ if (column >= 0)
+ {
+ reply.catf(" at column %d", column + 1);
+ }
+ reply.cat(": ");
+ reply.printf(message, param.u);
+}
+
+// End
diff --git a/src/GCodes/GCodeBuffer/ParseException.h b/src/GCodes/GCodeBuffer/ParseException.h
new file mode 100644
index 00000000..66939224
--- /dev/null
+++ b/src/GCodes/GCodeBuffer/ParseException.h
@@ -0,0 +1,48 @@
+/*
+ * ParseException.h
+ *
+ * Created on: 21 Dec 2019
+ * Author: David
+ */
+
+#ifndef SRC_GCODES_PARSEEXCEPTION_H_
+#define SRC_GCODES_PARSEEXCEPTION_H_
+
+#include <cstdint>
+
+class StringRef;
+
+class ParseException
+{
+public:
+ ParseException(int col, const char *msg) : column(col), message(msg) { }
+
+ ParseException(int col, const char *msg, const char *sparam) : column(col), message(msg)
+ {
+ param.s = sparam;
+ }
+
+ ParseException(int col, const char *msg, uint32_t uparam) : column(col), message(msg)
+ {
+ param.u = uparam;
+ }
+
+ ParseException(unsigned int col, const char *msg, int32_t iparam) : column(col), message(msg)
+ {
+ param.i = iparam;
+ }
+
+ void GetMessage(const StringRef& reply) const;
+
+private:
+ int column;
+ const char *message;
+ union
+ {
+ int32_t i;
+ uint32_t u;
+ const char *s;
+ } param;
+};
+
+#endif /* SRC_GCODES_PARSEEXCEPTION_H_ */
diff --git a/src/GCodes/GCodeBuffer/StringParser.cpp b/src/GCodes/GCodeBuffer/StringParser.cpp
index ee05cc30..d8600322 100644
--- a/src/GCodes/GCodeBuffer/StringParser.cpp
+++ b/src/GCodes/GCodeBuffer/StringParser.cpp
@@ -19,14 +19,14 @@
static constexpr char eofString[] = EOF_STRING; // What's at the end of an HTML file?
#endif
-StringParser::StringParser(GCodeBuffer& gcodeBuffer)
+StringParser::StringParser(GCodeBuffer& gcodeBuffer) noexcept
: gb(gcodeBuffer), fileBeingWritten(nullptr), writingFileSize(0), eofStringCounter(0), indentToSkipTo(NoIndentSkip),
hasCommandNumber(false), commandLetter('Q'), checksumRequired(false), binaryWriting(false)
{
Init();
}
-void StringParser::Init()
+void StringParser::Init() noexcept
{
gcodeLineEnd = 0;
commandLength = 0;
@@ -37,7 +37,7 @@ void StringParser::Init()
commandIndent = 0;
}
-inline void StringParser::AddToChecksum(char c)
+inline void StringParser::AddToChecksum(char c) noexcept
{
computedChecksum ^= (uint8_t)c;
}
@@ -410,8 +410,7 @@ void StringParser::ProcessElseCommand(bool skippedIfFalse)
}
else
{
- gb.ReportProgramError("'else' did not follow 'if");
- indentToSkipTo = gb.machineState->indentLevel; // skip forwards to the end of the block
+ throw ConstructParseException("'else' did not follow 'if");
}
}
@@ -433,7 +432,7 @@ void StringParser::ProcessBreakCommand()
{
if (gb.machineState->indentLevel == 0)
{
- gb.ReportProgramError("'break' was not inside a loop");
+ throw ConstructParseException("'break' was not inside a loop");
return;
}
gb.machineState->EndBlock();
@@ -443,15 +442,13 @@ void StringParser::ProcessBreakCommand()
void StringParser::ProcessVarCommand()
{
- gb.ReportProgramError("'var' not implemented yet");
+ throw ConstructParseException("'var' not implemented yet");
}
// Evaluate the condition that should follow 'if' or 'while'
-// If we fail, report an error and return false
bool StringParser::EvaluateCondition(const char* keyword)
{
- reprap.GetPlatform().MessageF(AddError(gb.GetResponseMessageType()), "Failed to evaluate condition after '%s'\n", keyword);
- return false;
+ throw ConstructParseException("Failed to evaluate condition after '%s'", keyword);
}
// Decode this command and find the start of the next one on the same line.
@@ -587,7 +584,7 @@ void StringParser::SetFinished()
}
// Get the file position at the start of the current command
-FilePosition StringParser::GetFilePosition() const
+FilePosition StringParser::GetFilePosition() const noexcept
{
#if HAS_MASS_STORAGE
if (gb.machineState->DoingFile())
@@ -598,19 +595,19 @@ FilePosition StringParser::GetFilePosition() const
return noFilePosition;
}
-const char* StringParser::DataStart() const
+const char* StringParser::DataStart() const noexcept
{
return gb.buffer + commandStart;
}
-size_t StringParser::DataLength() const
+size_t StringParser::DataLength() const noexcept
{
return commandEnd - commandStart;
}
// Is 'c' in the G Code string? 'c' must be uppercase.
-// Leave the pointer there for a subsequent read.
-bool StringParser::Seen(char c)
+// Leave the pointer one after it for a subsequent read.
+bool StringParser::Seen(char c) noexcept
{
bool inQuotes = false;
unsigned int inBrackets = 0;
@@ -625,13 +622,14 @@ bool StringParser::Seen(char c)
{
if (inBrackets == 0 && toupper(b) == c && (c != 'E' || (unsigned int)readPointer == parameterStart || !isdigit(gb.buffer[readPointer - 1])))
{
+ ++readPointer;
return true;
}
- if (b == '[')
+ if (b == '{')
{
++inBrackets;
}
- else if (b == ']' && inBrackets != 0)
+ else if (b == '}' && inBrackets != 0)
{
--inBrackets;
}
@@ -644,42 +642,35 @@ bool StringParser::Seen(char c)
// Get a float after a G Code letter found by a call to Seen()
float StringParser::GetFValue()
{
- if (readPointer >= 0)
+ if (readPointer > 0)
{
- const float result = ReadFloatValue(&gb.buffer[readPointer + 1], nullptr);
+ const float result = ReadFloatValue();
readPointer = -1;
return result;
}
- INTERNAL_ERROR;
- return 0.0;
+ THROW_INTERNAL_ERROR;
}
// Get a colon-separated list of floats after a key letter
// If doPad is true then we allow just one element to be given, in which case we fill all elements with that value
void StringParser::GetFloatArray(float arr[], size_t& returnedLength, bool doPad)
{
- if (readPointer >= 0)
+ if (readPointer > 0)
{
size_t length = 0;
- const char *p = gb.buffer + readPointer + 1;
for (;;)
{
if (length >= returnedLength) // array limit has been set in here
{
- reprap.GetPlatform().MessageF(ErrorMessage, "GCodes: Attempt to read a GCode float array that is too long: %s\n", gb.buffer);
- readPointer = -1;
- returnedLength = 0;
- return;
+ throw ConstructParseException("array too long, max length = %u", (uint32_t)returnedLength);
}
- const char *q;
- arr[length] = ReadFloatValue(p, &q);
- length++;
- if (*q != LIST_SEPARATOR)
+ arr[length++] = ReadFloatValue();
+ if (gb.buffer[readPointer] != LIST_SEPARATOR)
{
break;
}
- p = q + 1;
+ ++readPointer;
}
// Special case if there is one entry and returnedLength requests several. Fill the array with the first entry.
@@ -699,35 +690,29 @@ void StringParser::GetFloatArray(float arr[], size_t& returnedLength, bool doPad
}
else
{
- INTERNAL_ERROR;
- returnedLength = 0;
+ THROW_INTERNAL_ERROR;
}
}
// Get a :-separated list of ints after a key letter
void StringParser::GetIntArray(int32_t arr[], size_t& returnedLength, bool doPad)
{
- if (readPointer >= 0)
+ if (readPointer > 0)
{
size_t length = 0;
- const char *p = gb.buffer + readPointer + 1;
for (;;)
{
if (length >= returnedLength) // Array limit has been set in here
{
- reprap.GetPlatform().MessageF(ErrorMessage, "GCodes: Attempt to read a GCode int array that is too long: %s\n", gb.buffer);
- readPointer = -1;
- returnedLength = 0;
- return;
+ throw ConstructParseException("array too long, max length = %u", (uint32_t)returnedLength);
}
- const char *q;
- arr[length] = ReadIValue(p, &q);
+ arr[length] = ReadIValue();
length++;
- if (*q != LIST_SEPARATOR)
+ if (gb.buffer[readPointer] != LIST_SEPARATOR)
{
break;
}
- p = q + 1;
+ ++readPointer;
}
// Special case if there is one entry and returnedLength requests several. Fill the array with the first entry.
@@ -746,35 +731,29 @@ void StringParser::GetIntArray(int32_t arr[], size_t& returnedLength, bool doPad
}
else
{
- INTERNAL_ERROR;
- returnedLength = 0;
+ THROW_INTERNAL_ERROR;
}
}
// Get a :-separated list of unsigned ints after a key letter
void StringParser::GetUnsignedArray(uint32_t arr[], size_t& returnedLength, bool doPad)
{
- if (readPointer >= 0)
+ if (readPointer > 0)
{
size_t length = 0;
- const char *p = gb.buffer + readPointer + 1;
for (;;)
{
if (length >= returnedLength) // Array limit has been set in here
{
- reprap.GetPlatform().MessageF(ErrorMessage, "GCodes: Attempt to read a GCode unsigned array that is too long: %s\n", gb.buffer);
- readPointer = -1;
- returnedLength = 0;
- return;
+ throw ConstructParseException("array too long, max length = %u", (uint32_t)returnedLength);
}
- const char *q;
- arr[length] = ReadUIValue(p, &q);
+ arr[length] = ReadUIValue();
length++;
- if (*q != LIST_SEPARATOR)
+ if (gb.buffer[readPointer] != LIST_SEPARATOR)
{
break;
}
- p = q + 1;
+ ++readPointer;
}
// Special case if there is one entry and returnedLength requests several. Fill the array with the first entry.
@@ -794,35 +773,29 @@ void StringParser::GetUnsignedArray(uint32_t arr[], size_t& returnedLength, bool
}
else
{
- INTERNAL_ERROR;
- returnedLength = 0;
+ THROW_INTERNAL_ERROR;
}
}
// Get a :-separated list of drivers after a key letter
void StringParser::GetDriverIdArray(DriverId arr[], size_t& returnedLength)
{
- if (readPointer >= 0)
+ if (readPointer > 0)
{
size_t length = 0;
- const char *p = gb.buffer + readPointer + 1;
for (;;)
{
if (length >= returnedLength) // Array limit has been set in here
{
- reprap.GetPlatform().MessageF(ErrorMessage, "GCodes: Attempt to read a GCode driverID array that is too long: %s\n", gb.buffer);
- readPointer = -1;
- returnedLength = 0;
- return;
+ throw ConstructParseException("array too long, max length = %u", (uint32_t)returnedLength);
}
- const char *q;
- arr[length] = ReadDriverIdValue(p, &q);
+ arr[length] = ReadDriverIdValue();
length++;
- if (*q != LIST_SEPARATOR)
+ if (gb.buffer[readPointer] != LIST_SEPARATOR)
{
break;
}
- p = q + 1;
+ ++readPointer;
}
returnedLength = length;
@@ -830,39 +803,36 @@ void StringParser::GetDriverIdArray(DriverId arr[], size_t& returnedLength)
}
else
{
- INTERNAL_ERROR;
- returnedLength = 0;
+ THROW_INTERNAL_ERROR;
}
}
// Get and copy a quoted string returning true if successful
-bool StringParser::GetQuotedString(const StringRef& str)
+void StringParser::GetQuotedString(const StringRef& str)
{
str.Clear();
- if (readPointer >= 0)
+ if (readPointer > 0)
{
- ++readPointer; // skip the character that introduced the string
switch (gb.buffer[readPointer])
{
case '"':
- return InternalGetQuotedString(str);
+ InternalGetQuotedString(str);
+ return;
-#if SUPPORT_OBJECT_MODEL
- case '[':
- return GetStringExpression(str);
-#endif
+ case '{':
+ GetStringExpression(str);
+ return;
default:
- return false;
+ throw ConstructParseException("expected string expression");
}
}
- INTERNAL_ERROR;
- return false;
+ THROW_INTERNAL_ERROR;
}
// Given that the current character is double-quote, fetch the quoted string
-bool StringParser::InternalGetQuotedString(const StringRef& str)
+void StringParser::InternalGetQuotedString(const StringRef& str)
{
str.Clear();
++readPointer;
@@ -871,13 +841,13 @@ bool StringParser::InternalGetQuotedString(const StringRef& str)
char c = gb.buffer[readPointer++];
if (c < ' ')
{
- return false;
+ throw ConstructParseException("control character in string");
}
if (c == '"')
{
if (gb.buffer[readPointer++] != '"')
{
- return true;
+ return;
}
}
else if (c == '\'')
@@ -895,38 +865,32 @@ bool StringParser::InternalGetQuotedString(const StringRef& str)
}
str.cat(c);
}
- return false;
}
// Get and copy a string which may or may not be quoted. If it is not quoted, it ends at the first space or control character.
-// Return true if successful.
-bool StringParser::GetPossiblyQuotedString(const StringRef& str)
+void StringParser::GetPossiblyQuotedString(const StringRef& str)
{
- if (readPointer >= 0)
+ if (readPointer > 0)
{
- ++readPointer;
- return InternalGetPossiblyQuotedString(str);
+ InternalGetPossiblyQuotedString(str, false);
}
- INTERNAL_ERROR;
- return false;
+ THROW_INTERNAL_ERROR;
}
// Get and copy a string which may or may not be quoted, starting at readPointer. Return true if successful.
-bool StringParser::InternalGetPossiblyQuotedString(const StringRef& str)
+void StringParser::InternalGetPossiblyQuotedString(const StringRef& str, bool allowEmpty)
{
str.Clear();
if (gb.buffer[readPointer] == '"')
{
- return InternalGetQuotedString(str);
+ InternalGetQuotedString(str);
}
-#if SUPPORT_OBJECT_MODEL
- if (gb.buffer[readPointer] == '[')
+ if (gb.buffer[readPointer] == '{')
{
- return GetStringExpression(str);
+ GetStringExpression(str);
}
-#endif
commandEnd = gcodeLineEnd; // the string is the remainder of the line of gcode
for (;;)
@@ -939,19 +903,21 @@ bool StringParser::InternalGetPossiblyQuotedString(const StringRef& str)
str.cat(c);
}
str.StripTrailingSpaces();
- return !str.IsEmpty();
+ if (!allowEmpty && str.IsEmpty())
+ {
+ throw ConstructParseException("non-empty string expected");
+ }
}
-bool StringParser::GetReducedString(const StringRef& str)
+void StringParser::GetReducedString(const StringRef& str)
{
str.Clear();
- if (readPointer >= 0)
+ if (readPointer > 0)
{
// Reduced strings must start with a double-quote
- ++readPointer;
if (gb.buffer[readPointer] != '"')
{
- return false;
+ throw ConstructParseException("string expected");
}
++readPointer;
@@ -963,7 +929,7 @@ bool StringParser::GetReducedString(const StringRef& str)
case '"':
if (gb.buffer[readPointer++] != '"')
{
- return true;
+ return;
}
str.cat(c);
break;
@@ -976,7 +942,7 @@ bool StringParser::GetReducedString(const StringRef& str)
default:
if (c < ' ')
{
- return false;
+ throw ConstructParseException("control characer in string");
}
str.cat(tolower(c));
break;
@@ -984,8 +950,7 @@ bool StringParser::GetReducedString(const StringRef& str)
}
}
- INTERNAL_ERROR;
- return false;
+ THROW_INTERNAL_ERROR;
}
// This returns a string comprising the rest of the line, excluding any comment
@@ -993,7 +958,7 @@ bool StringParser::GetReducedString(const StringRef& str)
// command that sets the name of a file to be printed. In
// preference use GetString() which requires the string to have
// been preceded by a tag letter.
-bool StringParser::GetUnprecedentedString(const StringRef& str)
+void StringParser::GetUnprecedentedString(const StringRef& str, bool allowEmpty)
{
readPointer = parameterStart;
char c;
@@ -1001,63 +966,58 @@ bool StringParser::GetUnprecedentedString(const StringRef& str)
{
++readPointer; // skip leading spaces
}
- return InternalGetPossiblyQuotedString(str);
+ InternalGetPossiblyQuotedString(str, allowEmpty);
}
// Get an int32 after a G Code letter
int32_t StringParser::GetIValue()
{
- if (readPointer >= 0)
+ if (readPointer > 0)
{
- const int32_t result = ReadIValue(&gb.buffer[readPointer + 1], nullptr);
+ const int32_t result = ReadIValue();
readPointer = -1;
return result;
}
- INTERNAL_ERROR;
- return 0;
+ THROW_INTERNAL_ERROR;
}
// Get an uint32 after a G Code letter
uint32_t StringParser::GetUIValue()
{
- if (readPointer >= 0)
+ if (readPointer > 0)
{
- const uint32_t result = ReadUIValue(&gb.buffer[readPointer + 1], nullptr);
+ const uint32_t result = ReadUIValue();
readPointer = -1;
return result;
}
- INTERNAL_ERROR;
- return 0;
+ THROW_INTERNAL_ERROR;
}
// Get a driver ID
DriverId StringParser::GetDriverId()
{
DriverId result;
- if (readPointer >= 0)
+ if (readPointer > 0)
{
- result = ReadDriverIdValue(&gb.buffer[readPointer + 1], nullptr);
+ result = ReadDriverIdValue();
readPointer = -1;
return result;
}
- INTERNAL_ERROR;
- result.SetLocal(0);
- return result;
+ THROW_INTERNAL_ERROR;
}
// Get an IP address quad after a key letter
-bool StringParser::GetIPAddress(IPAddress& returnedIp)
+void StringParser::GetIPAddress(IPAddress& returnedIp)
{
- if (readPointer < 0)
+ if (readPointer <= 0)
{
- INTERNAL_ERROR;
- return false;
+ THROW_INTERNAL_ERROR;
}
- const char* p = &gb.buffer[readPointer + 1];
+ const char* p = gb.buffer + readPointer;
uint8_t ip[4];
unsigned int n = 0;
for (;;)
@@ -1067,7 +1027,7 @@ bool StringParser::GetIPAddress(IPAddress& returnedIp)
if (pp == p || v > 255)
{
readPointer = -1;
- return false;
+ throw ConstructParseException("invalid IP address");
}
ip[n] = (uint8_t)v;
++n;
@@ -1079,30 +1039,27 @@ bool StringParser::GetIPAddress(IPAddress& returnedIp)
if (n == 4)
{
readPointer = -1;
- return false;
+ throw ConstructParseException("invalid IP address");
}
++p;
}
readPointer = -1;
- if (n == 4)
+ if (n != 4)
{
- returnedIp.SetV4(ip);
- return true;
+ throw ConstructParseException("invalid IP address");
}
- returnedIp.SetNull();
- return false;
+ returnedIp.SetV4(ip);
}
// Get a MAX address sextet after a key letter
-bool StringParser::GetMacAddress(uint8_t mac[6])
+void StringParser::GetMacAddress(uint8_t mac[6])
{
- if (readPointer < 0)
+ if (readPointer <= 0)
{
- INTERNAL_ERROR;
- return false;
+ THROW_INTERNAL_ERROR;
}
- const char* p = gb.buffer + readPointer + 1;
+ const char* p = gb.buffer + readPointer;
unsigned int n = 0;
for (;;)
{
@@ -1111,7 +1068,7 @@ bool StringParser::GetMacAddress(uint8_t mac[6])
if (pp == p || v > 255)
{
readPointer = -1;
- return false;
+ throw ConstructParseException("invalid MAC address");
}
mac[n] = (uint8_t)v;
++n;
@@ -1123,16 +1080,19 @@ bool StringParser::GetMacAddress(uint8_t mac[6])
if (n == 6)
{
readPointer = -1;
- return false;
+ throw ConstructParseException("invalid MAC address");
}
++p;
}
readPointer = -1;
- return n == 6;
+ if (n != 6)
+ {
+ throw ConstructParseException("invalid MAC address");
+ }
}
// Write the command to a string
-void StringParser::PrintCommand(const StringRef& s) const
+void StringParser::PrintCommand(const StringRef& s) const noexcept
{
s.printf("%c%d", commandLetter, commandNumber);
if (commandFraction >= 0)
@@ -1142,7 +1102,7 @@ void StringParser::PrintCommand(const StringRef& s) const
}
// Append the full command content to a string
-void StringParser::AppendFullCommand(const StringRef &s) const
+void StringParser::AppendFullCommand(const StringRef &s) const noexcept
{
s.cat(gb.buffer);
}
@@ -1285,13 +1245,14 @@ void StringParser::FileEnded()
#endif
// Functions to read values from lines of GCode, allowing for expressions and variable substitution
-float StringParser::ReadFloatValue(const char *p, const char **endptr)
+float StringParser::ReadFloatValue()
{
-#if SUPPORT_OBJECT_MODEL
- if (*p == '{')
+ ++readPointer;
+ if (gb.buffer[readPointer] == '{')
{
- ExpressionValue val;
- switch (EvaluateExpression(p, endptr, val))
+ ++readPointer;
+ const ExpressionValue val = EvaluateExpression();
+ switch (val.type)
{
case TYPE_OF(float):
return val.fVal;
@@ -1303,22 +1264,19 @@ float StringParser::ReadFloatValue(const char *p, const char **endptr)
return (float)val.uVal;
default:
- //TODO report error
- return 1.0;
+ throw ConstructParseException("expected float value");
}
}
-#endif
- return SafeStrtof(p, endptr);
+ return SafeStrtof(gb.buffer + readPointer, nullptr);
}
-uint32_t StringParser::ReadUIValue(const char *p, const char **endptr)
+uint32_t StringParser::ReadUIValue()
{
-#if SUPPORT_OBJECT_MODEL
- if (*p == '{')
+ if (gb.buffer[readPointer] == '{')
{
- ExpressionValue val;
- switch (EvaluateExpression(p, endptr, val))
+ const ExpressionValue val = EvaluateExpression();
+ switch (val.type)
{
case TYPE_OF(uint32_t):
return val.uVal;
@@ -1328,37 +1286,34 @@ uint32_t StringParser::ReadUIValue(const char *p, const char **endptr)
{
return (uint32_t)val.iVal;
}
- //TODO report error
- return 0;
+ throw ConstructParseException("value must be non-negative");
default:
- //TODO report error
- return 0;
+ throw ConstructParseException("expected non-negative integer value");
}
}
-#endif
int base = 10;
size_t skipTrailingQuote = 0;
// Allow "0xNNNN" or "xNNNN" where NNNN are hex digits
- if (*p == '"')
+ if (gb.buffer[readPointer] == '"')
{
- ++p;
+ ++readPointer;
skipTrailingQuote = 1;
- switch (*p)
+ switch (gb.buffer[readPointer])
{
case 'x':
case 'X':
base = 16;
- ++p;
+ ++readPointer;
break;
case '0':
- if (*(p + 1) == 'x' || *(p + 1) == 'X')
+ if (gb.buffer[readPointer + 1] == 'x' || gb.buffer[readPointer + 1] == 'X')
{
base = 16;
- p += 2;
+ readPointer += 2;
}
break;
@@ -1366,18 +1321,19 @@ uint32_t StringParser::ReadUIValue(const char *p, const char **endptr)
break;
}
}
- const uint32_t result = SafeStrtoul(p, endptr, base);
- endptr += skipTrailingQuote;
+
+ const char *endptr;
+ const uint32_t result = SafeStrtoul(gb.buffer + readPointer, &endptr, base);
+ readPointer = endptr - gb.buffer + skipTrailingQuote;
return result;
}
-int32_t StringParser::ReadIValue(const char *p, const char **endptr)
+int32_t StringParser::ReadIValue()
{
-#if SUPPORT_OBJECT_MODEL
- if (*p == '{')
+ if (gb.buffer[readPointer] == '{')
{
- ExpressionValue val;
- switch (EvaluateExpression(p, endptr, val))
+ ExpressionValue val = EvaluateExpression();
+ switch (val.type)
{
case TYPE_OF(int32_t):
return val.iVal;
@@ -1386,24 +1342,25 @@ int32_t StringParser::ReadIValue(const char *p, const char **endptr)
return (int32_t)val.uVal;
default:
- //TODO report error
- return 0;
+ throw ConstructParseException("expected integer value");
}
}
-#endif
- return SafeStrtol(p, endptr);
+ const char *endptr;
+ const int32_t val = SafeStrtol(gb.buffer + readPointer, &endptr);
+ readPointer = endptr - gb.buffer;
+ return val;
}
-DriverId StringParser::ReadDriverIdValue(const char *p, const char **endptr)
+DriverId StringParser::ReadDriverIdValue()
{
DriverId result;
- const char *endp;
- const uint32_t v1 = ReadUIValue(p, &endp);
+ const uint32_t v1 = ReadUIValue();
#if SUPPORT_CAN_EXPANSION
- if (*endp == '.')
+ if (gb.buffer[readPointer] == '.')
{
- const uint32_t v2 = ReadUIValue(endp + 1, &endp);
+ ++readPointer;
+ const uint32_t v2 = ReadUIValue();
result.localDriver = v2;
result.boardAddress = v1;
}
@@ -1415,20 +1372,14 @@ DriverId StringParser::ReadDriverIdValue(const char *p, const char **endptr)
#else
result.localDriver = v1;
#endif
- if (endptr != nullptr)
- {
- *endptr = endp;
- }
return result;
}
-#if SUPPORT_OBJECT_MODEL
-
-// Get a string expression. The current character is '['.
-bool StringParser::GetStringExpression(const StringRef& str)
+// Get a string expression. The current character is '{'.
+void StringParser::GetStringExpression(const StringRef& str)
{
- ExpressionValue val;
- switch (EvaluateExpression(gb.buffer + readPointer, nullptr, val))
+ const ExpressionValue val = EvaluateExpression();
+ switch (val.type)
{
case TYPE_OF(const char*):
str.copy(val.sVal);
@@ -1463,55 +1414,161 @@ bool StringParser::GetStringExpression(const StringRef& str)
break;
default:
- //TODO report error
- return false;
+ throw ConstructParseException("string value expected");
}
-
- return true;
}
// Evaluate an expression. the current character is '{'.
-TypeCode StringParser::EvaluateExpression(const char *p, const char **endptr, ExpressionValue& rslt)
+ExpressionValue StringParser::EvaluateExpression()
{
- ++p; // skip the '{'
+ ++readPointer; // skip the '{'
// For now the only form of expression we handle is {variable-name}
- if (isalpha(*p)) // if it's a variable name
+ if (isalpha(gb.buffer[readPointer])) // if it's a variable name
{
- const char * const start = p;
+ unsigned int start = readPointer;
unsigned int numBrackets = 0;
- while (isalpha(*p) || isdigit(*p) || *p == '_' || *p == '.' || *p == '[' || (*p == ']' && numBrackets != 0))
+ char c;
+ while (isalpha((c = gb.buffer[readPointer])) || isdigit(c) || c == '_' || c == '.' || c == '(' || (c == ')' && numBrackets != 0))
{
- if (*p == '[')
+ if (c == '(')
{
++numBrackets;
}
- else if (*p == ']')
+ else if (c == ')')
{
--numBrackets;
}
- ++p;
+ ++readPointer;
}
String<MaxVariableNameLength> varName;
- if (varName.copy(start, p - start))
+ if (varName.copy(gb.buffer + start, readPointer - start))
{
- // variable name is too long
- //TODO error handling
- return NoType;
+ throw ConstructParseException("variable name too long");;
}
//TODO consider supporting standard CNC functions here
- const TypeCode tc = reprap.GetObjectValue(rslt, varName.c_str());
- if (tc != NoType && (tc & IsArray) == 0 && *p == '}')
+ const ExpressionValue val = reprap.GetObjectValue(*this, varName.c_str());
+ if (c != '}')
+ {
+ throw ConstructParseException("expected '}'");
+ }
+ ++readPointer;
+ return val;
+ }
+
+ throw ConstructParseException("expected variable name");
+}
+
+// Parse a number. the initial character of the string is a decimal digit.
+ExpressionValue StringParser::ParseNumber()
+{
+ // 2. Read digits before decimal point, E or e
+ unsigned long valueBeforePoint = 0;
+ char c;
+ while (isdigit((c = gb.buffer[readPointer])))
+ {
+ const unsigned int digit = c - '0';
+ if (valueBeforePoint > ULONG_MAX/10 || (valueBeforePoint *= 10, valueBeforePoint > ULONG_MAX - digit))
+ {
+ throw ConstructParseException("too many digits");
+ }
+ valueBeforePoint += digit;
+ ++readPointer;
+ }
+
+ // 3. Check for decimal point before E or e
+ unsigned long valueAfterPoint = 0;
+ long digitsAfterPoint = 0;
+ bool isFloat = (c == '.');
+ if (isFloat)
+ {
+ ++readPointer;
+
+ // 3b. Read the digits (if any) after the decimal point
+ while (isdigit((c = gb.buffer[readPointer])))
{
- if (endptr != nullptr)
+ const unsigned int digit = c - '0';
+ if (valueAfterPoint > ULONG_MAX/10 || (valueAfterPoint *= 10, valueAfterPoint > ULONG_MAX - digit))
{
- *endptr = p + 1;
+ throw ConstructParseException("too many decimal digits");
}
- return tc;
+ valueAfterPoint += digit;
+ ++digitsAfterPoint;
+ ++readPointer;
+ }
+ }
+
+ // 5. Check for exponent part
+ long exponent = 0;
+ if (toupper(c) == 'E')
+ {
+ isFloat = true;
+ ++readPointer;
+ c = gb.buffer[readPointer];
+
+ // 5a. Check for signed exponent
+ const bool expNegative = (c == '-');
+ if (expNegative || c == '+')
+ {
+ ++readPointer;
+ }
+
+ // 5b. Read exponent digits
+ while (isdigit((c = gb.buffer[readPointer])))
+ {
+ exponent = (10 * exponent) + (c - '0'); // could overflow, but anyone using such large numbers is being very silly
+ ++readPointer;
+ }
+
+ if (expNegative)
+ {
+ exponent = -exponent;
}
}
- return NoType;
+
+ // 6. Compute the composite value
+ ExpressionValue retvalue;
+
+ if (isFloat)
+ {
+ retvalue.type = TypeOf<float>();
+ if (valueAfterPoint != 0)
+ {
+ if (valueBeforePoint == 0)
+ {
+ retvalue.fVal = (float)((double)valueAfterPoint * pow(10, exponent - digitsAfterPoint));
+ }
+ else
+ {
+ retvalue.fVal = (float)(((double)valueAfterPoint/pow(10, digitsAfterPoint) + valueBeforePoint) * pow(10, exponent));
+ }
+ }
+ else
+ {
+ retvalue.fVal = (float)(valueBeforePoint * pow(10, exponent));
+ }
+ }
+ else
+ {
+ retvalue.type = TypeOf<uint32_t>();
+ retvalue.uVal = valueBeforePoint;
+ }
+
+ return retvalue;
}
-#endif
+ParseException StringParser::ConstructParseException(const char *str) const
+{
+ return ParseException(readPointer, str);
+}
+
+ParseException StringParser::ConstructParseException(const char *str, const char *param) const
+{
+ return ParseException(readPointer, str, param);
+}
+
+ParseException StringParser::ConstructParseException(const char *str, uint32_t param) const
+{
+ return ParseException(readPointer, str, param);
+}
// End
diff --git a/src/GCodes/GCodeBuffer/StringParser.h b/src/GCodes/GCodeBuffer/StringParser.h
index 815b4d47..e0d10117 100644
--- a/src/GCodes/GCodeBuffer/StringParser.h
+++ b/src/GCodes/GCodeBuffer/StringParser.h
@@ -12,6 +12,7 @@
#include "GCodes/GCodeInput.h"
#include "MessageType.h"
#include "ObjectModel/ObjectModel.h"
+#include "ParseException.h"
class GCodeBuffer;
class IPAddress;
@@ -19,35 +20,35 @@ class IPAddress;
class StringParser
{
public:
- StringParser(GCodeBuffer& gcodeBuffer);
- void Init(); // Set it up to parse another G-code
- void Diagnostics(MessageType mtype); // Write some debug info
+ StringParser(GCodeBuffer& gcodeBuffer) noexcept;
+ void Init() noexcept; // Set it up to parse another G-code
+ void Diagnostics(MessageType mtype) noexcept; // Write some debug info
bool Put(char c) __attribute__((hot)); // Add a character to the end
void Put(const char *str, size_t len); // Add an entire string, overwriting any existing content
void Put(const char *str); // Add a null-terminated string, overwriting any existing content
void FileEnded(); // Called when we reach the end of the file we are reading from
- bool Seen(char c) __attribute__((hot)); // Is a character present?
-
- char GetCommandLetter() const { return commandLetter; }
- bool HasCommandNumber() const { return hasCommandNumber; }
- int GetCommandNumber() const { return commandNumber; }
- int8_t GetCommandFraction() const { return commandFraction; }
-
- float GetFValue() __attribute__((hot)); // Get a float after a key letter
- float GetDistance(); // Get a distance or coordinate and convert it from inches to mm if necessary
- int32_t GetIValue() __attribute__((hot)); // Get an integer after a key letter
- uint32_t GetUIValue(); // Get an unsigned integer value
- DriverId GetDriverId(); // Get a driver ID
- bool GetIPAddress(IPAddress& returnedIp); // Get an IP address quad after a key letter
- bool GetMacAddress(uint8_t mac[6]); // Get a MAC address sextet after a key letter
- bool GetUnprecedentedString(const StringRef& str); // Get a string with no preceding key letter
- bool GetQuotedString(const StringRef& str); // Get and copy a quoted string
- bool GetPossiblyQuotedString(const StringRef& str); // Get and copy a string which may or may not be quoted
- bool GetReducedString(const StringRef& str); // Get and copy a quoted string, removing certain characters
- void GetFloatArray(float arr[], size_t& length, bool doPad) __attribute__((hot)); // Get a colon-separated list of floats after a key letter
- void GetIntArray(int32_t arr[], size_t& length, bool doPad); // Get a :-separated list of ints after a key letter
- void GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad); // Get a :-separated list of unsigned ints after a key letter
- void GetDriverIdArray(DriverId arr[], size_t& length); // Get a :-separated list of drivers after a key letter
+ bool Seen(char c) noexcept __attribute__((hot)); // Is a character present?
+
+ char GetCommandLetter() const noexcept { return commandLetter; }
+ bool HasCommandNumber() const noexcept { return hasCommandNumber; }
+ int GetCommandNumber() const noexcept { return commandNumber; }
+ int8_t GetCommandFraction() const noexcept { return commandFraction; }
+
+ float GetFValue() THROWS_PARSE_ERROR __attribute__((hot)); // Get a float after a key letter
+ float GetDistance() THROWS_PARSE_ERROR; // Get a distance or coordinate and convert it from inches to mm if necessary
+ int32_t GetIValue() THROWS_PARSE_ERROR __attribute__((hot)); // Get an integer after a key letter
+ uint32_t GetUIValue() THROWS_PARSE_ERROR; // Get an unsigned integer value
+ DriverId GetDriverId() THROWS_PARSE_ERROR; // Get a driver ID
+ void GetIPAddress(IPAddress& returnedIp) THROWS_PARSE_ERROR; // Get an IP address quad after a key letter
+ void GetMacAddress(uint8_t mac[6]) THROWS_PARSE_ERROR; // Get a MAC address sextet after a key letter
+ void GetUnprecedentedString(const StringRef& str, bool allowEmpty) THROWS_PARSE_ERROR; // Get a string with no preceding key letter
+ void GetQuotedString(const StringRef& str) THROWS_PARSE_ERROR; // Get and copy a quoted string
+ void GetPossiblyQuotedString(const StringRef& str) THROWS_PARSE_ERROR; // Get and copy a string which may or may not be quoted
+ void GetReducedString(const StringRef& str) THROWS_PARSE_ERROR; // Get and copy a quoted string, removing certain characters
+ void GetFloatArray(float arr[], size_t& length, bool doPad) THROWS_PARSE_ERROR __attribute__((hot)); // Get a colon-separated list of floats after a key letter
+ void GetIntArray(int32_t arr[], size_t& length, bool doPad) THROWS_PARSE_ERROR; // Get a :-separated list of ints after a key letter
+ void GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad) THROWS_PARSE_ERROR; // Get a :-separated list of unsigned ints after a key letter
+ void GetDriverIdArray(DriverId arr[], size_t& length) THROWS_PARSE_ERROR; // Get a :-separated list of drivers after a key letter
void SetFinished(); // Set the G Code finished
void SetCommsProperties(uint32_t arg) { checksumRequired = (arg & 1); }
@@ -62,30 +63,33 @@ public:
void FinishWritingBinary();
#endif
- FilePosition GetFilePosition() const; // Get the file position at the start of the current command
+ FilePosition GetFilePosition() const noexcept; // Get the file position at the start of the current command
- const char* DataStart() const; // Get the start of the current command
- size_t DataLength() const; // Get the length of the current command
+ const char* DataStart() const noexcept; // Get the start of the current command
+ size_t DataLength() const noexcept; // Get the length of the current command
- void PrintCommand(const StringRef& s) const;
- void AppendFullCommand(const StringRef &s) const;
+ void PrintCommand(const StringRef& s) const noexcept;
+ void AppendFullCommand(const StringRef &s) const noexcept;
-private:
+ ParseException ConstructParseException(const char *str) const;
+ ParseException ConstructParseException(const char *str, const char *param) const;
+ ParseException ConstructParseException(const char *str, uint32_t param) const;
+private:
GCodeBuffer& gb;
- void AddToChecksum(char c);
+ void AddToChecksum(char c) noexcept;
void StoreAndAddToChecksum(char c);
bool LineFinished(); // Deal with receiving end-of-line and return true if we have a command
void DecodeCommand();
- bool InternalGetQuotedString(const StringRef& str)
+ void InternalGetQuotedString(const StringRef& str) THROWS_PARSE_ERROR
pre (readPointer >= 0; gb.buffer[readPointer] == '"'; str.IsEmpty());
- bool InternalGetPossiblyQuotedString(const StringRef& str)
+ void InternalGetPossiblyQuotedString(const StringRef& str, bool allowEmpty) THROWS_PARSE_ERROR
pre (readPointer >= 0);
- float ReadFloatValue(const char *p, const char **endptr);
- uint32_t ReadUIValue(const char *p, const char **endptr);
- int32_t ReadIValue(const char *p, const char **endptr);
- DriverId ReadDriverIdValue(const char *p, const char **endptr);
+ float ReadFloatValue() THROWS_PARSE_ERROR;
+ uint32_t ReadUIValue() THROWS_PARSE_ERROR;
+ int32_t ReadIValue() THROWS_PARSE_ERROR;
+ DriverId ReadDriverIdValue() THROWS_PARSE_ERROR;
bool ProcessConditionalGCode(bool skippedIfFalse); // Check for and process a conditional GCode language command returning true if we found one
void CreateBlocks(); // Create new code blocks
@@ -95,14 +99,14 @@ private:
void ProcessWhileCommand();
void ProcessBreakCommand();
void ProcessVarCommand();
- bool EvaluateCondition(const char* keyword);
+ bool EvaluateCondition(const char* keyword) THROWS_PARSE_ERROR;
-#if SUPPORT_OBJECT_MODEL
- bool GetStringExpression(const StringRef& str)
+ void GetStringExpression(const StringRef& str) THROWS_PARSE_ERROR
pre (readPointer >= 0; gb.buffer[readPointer] == '{'; str.IsEmpty());
- TypeCode EvaluateExpression(const char *p, const char **endptr, ExpressionValue& rslt)
+ ExpressionValue EvaluateExpression() THROWS_PARSE_ERROR
pre (readPointer >= 0; gb.buffer[readPointer] == '{');
-#endif
+ ExpressionValue ParseNumber() THROWS_PARSE_ERROR
+ pre(isdigit(*s));
unsigned int commandStart; // Index in the buffer of the command letter of this command
unsigned int parameterStart;
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index 7188e1e0..33295463 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -2692,15 +2692,8 @@ GCodeResult GCodes::SaveHeightMap(GCodeBuffer& gb, const StringRef& reply) const
if (gb.Seen('P'))
{
String<MaxFilenameLength> heightMapFileName;
- if (gb.GetQuotedString(heightMapFileName.GetRef()))
- {
- return GetGCodeResultFromError(TrySaveHeightMap(heightMapFileName.c_str(), reply));
- }
- else
- {
- reply.copy("Missing height map file name");
- return GCodeResult::error;
- }
+ gb.GetQuotedString(heightMapFileName.GetRef());
+ return GetGCodeResultFromError(TrySaveHeightMap(heightMapFileName.c_str(), reply));
}
return GetGCodeResultFromError(TrySaveHeightMap(DefaultHeightMapFile, reply));
}
@@ -2991,11 +2984,7 @@ GCodeResult GCodes::ManageTool(GCodeBuffer& gb, const StringRef& reply)
String<ToolNameLength> name;
if (gb.Seen('S'))
{
- if (!gb.GetQuotedString(name.GetRef()))
- {
- reply.copy("Invalid tool name");
- return GCodeResult::error;
- }
+ gb.GetQuotedString(name.GetRef());
seen = true;
}
@@ -3487,11 +3476,7 @@ GCodeResult GCodes::LoadFilament(GCodeBuffer& gb, const StringRef& reply)
if (gb.Seen('S'))
{
String<FilamentNameLength> filamentName;
- if (!gb.GetQuotedString(filamentName.GetRef()) || filamentName.IsEmpty())
- {
- reply.copy("Invalid filament name");
- return GCodeResult::error;
- }
+ gb.GetQuotedString(filamentName.GetRef());
if (StringContains(filamentName.c_str(), ",") >= 0)
{
diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp
index ca2f95e4..a56db99f 100644
--- a/src/GCodes/GCodes2.cpp
+++ b/src/GCodes/GCodes2.cpp
@@ -10,6 +10,7 @@
#include "GCodes.h"
#include "GCodeBuffer/GCodeBuffer.h"
+#include "GCodeBuffer/ParseException.h"
#include "GCodeQueue.h"
#include "Heating/Heat.h"
#include "Movement/Move.h"
@@ -69,29 +70,39 @@ bool GCodes::ActOnCode(GCodeBuffer& gb, const StringRef& reply)
return false; // we should queue this code but we can't, so wait until we can either execute it or queue it
}
- switch (gb.GetCommandLetter())
+ try
{
- case 'G':
- if (gb.HasCommandNumber())
+ switch (gb.GetCommandLetter())
{
- return HandleGcode(gb, reply);
- }
- break;
+ case 'G':
+ if (gb.HasCommandNumber())
+ {
+ return HandleGcode(gb, reply);
+ }
+ break;
- case 'M':
- if (gb.HasCommandNumber())
- {
- return HandleMcode(gb, reply);
- }
- break;
+ case 'M':
+ if (gb.HasCommandNumber())
+ {
+ return HandleMcode(gb, reply);
+ }
+ break;
- case 'T':
- return HandleTcode(gb, reply);
+ case 'T':
+ return HandleTcode(gb, reply);
- default:
- break;
+ default:
+ break;
+ }
+ }
+ catch (const ParseException& e)
+ {
+ e.GetMessage(reply);
+ HandleReply(gb, GCodeResult::error, reply.c_str());
+ return true;
}
+ // if we get here then we didn't see a command that was worth parsing
reply.printf("Bad command: ");
gb.AppendFullCommand(reply);
HandleReply(gb, GCodeResult::error, reply.c_str());
@@ -387,9 +398,6 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply)
bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
{
- GCodeResult result = GCodeResult::ok;
- OutputBuffer *outBuf = nullptr;
-
const int code = gb.GetCommandNumber();
if ( simulationMode != 0
&& (code < 20 || code > 37)
@@ -399,351 +407,355 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
return true; // we don't simulate most M codes
}
- switch (code)
+ OutputBuffer *outBuf = nullptr;
+
+ try
{
- case 0: // Stop
- case 1: // Sleep
- // Don't allow M0 or M1 to stop a print, unless the print is paused or the command comes from the file being printed itself.
- if (reprap.GetPrintMonitor().IsPrinting() && &gb != fileGCode && !IsPaused())
- {
- reply.copy("Pause the print before attempting to cancel it");
- result = GCodeResult::error;
- }
- else if ( !LockMovementAndWaitForStandstill(gb) // wait until everything has stopped
- || !IsCodeQueueIdle() // must also wait until deferred command queue has caught up
- )
+ GCodeResult result = GCodeResult::ok;
+ switch (code)
{
- return false;
- }
- else
- {
- const bool wasPaused = isPaused; // isPaused gets cleared by CancelPrint
- const bool wasSimulating = IsSimulating(); // simulationMode may get cleared by CancelPrint
- isWaiting = cancelWait = false; // we may have been waiting for temperatures to be reached
- StopPrint((&gb == fileGCode) ? StopPrintReason::normalCompletion : StopPrintReason::userCancelled);
-
- if (!wasSimulating) // don't run any macro files or turn heaters off etc. if we were simulating before we stopped the print
+ case 0: // Stop
+ case 1: // Sleep
+ // Don't allow M0 or M1 to stop a print, unless the print is paused or the command comes from the file being printed itself.
+ if (reprap.GetPrintMonitor().IsPrinting() && &gb != fileGCode && !IsPaused())
{
- // 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 (wasPaused && code == 0 && AllAxesAreHomed() && DoFileMacro(gb, CANCEL_G, false, 0))
+ reply.copy("Pause the print before attempting to cancel it");
+ result = GCodeResult::error;
+ }
+ else if ( !LockMovementAndWaitForStandstill(gb) // wait until everything has stopped
+ || !IsCodeQueueIdle() // must also wait until deferred command queue has caught up
+ )
+ {
+ return false;
+ }
+ else
+ {
+ const bool wasPaused = isPaused; // isPaused gets cleared by CancelPrint
+ const bool wasSimulating = IsSimulating(); // simulationMode may get cleared by CancelPrint
+ isWaiting = cancelWait = false; // we may have been waiting for temperatures to be reached
+ StopPrint((&gb == fileGCode) ? StopPrintReason::normalCompletion : StopPrintReason::userCancelled);
+
+ if (!wasSimulating) // don't run any macro files or turn heaters off etc. if we were simulating before we stopped the print
{
- break;
- }
+ // 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 (wasPaused && code == 0 && AllAxesAreHomed() && DoFileMacro(gb, CANCEL_G, false, 0))
+ {
+ 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);
+ 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);
+ }
}
- }
- break;
+ break;
- case 3: // Spin spindle clockwise
- {
- const uint32_t slot = gb.Seen('P') ? gb.GetUIValue() : 0;
- if (slot >= MaxSpindles && machineType == MachineType::cnc)
- {
- reply.copy("Invalid spindle index");
- result = GCodeResult::error;
- }
- else if (gb.Seen('S'))
+ case 3: // Spin spindle clockwise
{
- switch (machineType)
+ const uint32_t slot = gb.Seen('P') ? gb.GetUIValue() : 0;
+ if (slot >= MaxSpindles && machineType == MachineType::cnc)
{
- case MachineType::cnc:
- platform.AccessSpindle(slot).SetRpm(gb.GetFValue());
- break;
+ reply.copy("Invalid spindle index");
+ result = GCodeResult::error;
+ }
+ else if (gb.Seen('S'))
+ {
+ switch (machineType)
+ {
+ case MachineType::cnc:
+ platform.AccessSpindle(slot).SetRpm(gb.GetFValue());
+ break;
#if SUPPORT_LASER
- case MachineType::laser:
- moveBuffer.laserPwmOrIoBits.laserPwm = ConvertLaserPwm(gb.GetFValue());
- break;
+ case MachineType::laser:
+ moveBuffer.laserPwmOrIoBits.laserPwm = ConvertLaserPwm(gb.GetFValue());
+ break;
#endif
- default:
+ default:
#if SUPPORT_ROLAND
- if (reprap.GetRoland()->Active())
+ if (reprap.GetRoland()->Active())
+ {
+ result = reprap.GetRoland()->ProcessSpindle(gb.GetFValue());
+ }
+ else
+#endif
+ {
+ result = GCodeResult::notSupportedInCurrentMode;
+ }
+ break;
+ }
+ }
+ else if (machineType == MachineType::cnc && gb.Seen('R'))
+ {
+ const unsigned int rpNumber = gb.GetUIValue();
+ if (rpNumber >= NumRestorePoints)
{
- result = reprap.GetRoland()->ProcessSpindle(gb.GetFValue());
+ reply.copy("Invalid restore point number");
+ result = GCodeResult::error;
}
else
-#endif
{
- result = GCodeResult::notSupportedInCurrentMode;
+ platform.AccessSpindle(slot).SetRpm(numberedRestorePoints[rpNumber].spindleSpeeds[slot]);
}
- break;
}
}
- else if (machineType == MachineType::cnc && gb.Seen('R'))
+ break;
+
+ case 4: // Spin spindle counter clockwise
+ if (gb.Seen('S'))
{
- const unsigned int rpNumber = gb.GetUIValue();
- if (rpNumber >= NumRestorePoints)
+ if (machineType == MachineType::cnc)
{
- reply.copy("Invalid restore point number");
- result = GCodeResult::error;
+ const float rpm = gb.GetFValue();
+ const uint32_t slot = gb.Seen('P') ? gb.GetUIValue() : 0;
+ if (slot >= MaxSpindles)
+ {
+ reply.copy("Invalid spindle index");
+ result = GCodeResult::error;
+ }
+ else
+ {
+ platform.AccessSpindle(slot).SetRpm(-rpm);
+ }
}
else
{
- platform.AccessSpindle(slot).SetRpm(numberedRestorePoints[rpNumber].spindleSpeeds[slot]);
+ result = GCodeResult::notSupportedInCurrentMode;
}
}
- }
- break;
+ break;
- case 4: // Spin spindle counter clockwise
- if (gb.Seen('S'))
- {
- if (machineType == MachineType::cnc)
+ case 5: // Spindle motor off
+ switch (machineType)
{
- const float rpm = gb.GetFValue();
- const uint32_t slot = gb.Seen('P') ? gb.GetUIValue() : 0;
- if (slot >= MaxSpindles)
+ case MachineType::cnc:
+ if (gb.Seen('P'))
{
- reply.copy("Invalid spindle index");
- result = GCodeResult::error;
+ // Turn off specific spindle
+ const uint32_t slot = gb.GetUIValue();
+ if (slot >= MaxSpindles)
+ {
+ reply.copy("Invalid spindle index");
+ result = GCodeResult::error;
+ }
+ else
+ {
+ platform.AccessSpindle(slot).TurnOff();
+ }
}
else
{
- platform.AccessSpindle(slot).SetRpm(-rpm);
+ // Turn off every spindle if no 'P' parameter is present
+ for (size_t i = 0; i < MaxSpindles; i++)
+ {
+ platform.AccessSpindle(i).TurnOff();
+ }
}
- }
- else
- {
- result = GCodeResult::notSupportedInCurrentMode;
- }
- }
- break;
+ break;
- case 5: // Spindle motor off
- switch (machineType)
- {
- case MachineType::cnc:
- if (gb.Seen('P'))
- {
- // Turn off specific spindle
- const uint32_t slot = gb.GetUIValue();
- if (slot >= MaxSpindles)
+ #if SUPPORT_LASER
+ case MachineType::laser:
+ moveBuffer.laserPwmOrIoBits.Clear();
+ break;
+#endif
+
+ default:
+#if SUPPORT_ROLAND
+ if (reprap.GetRoland()->Active())
{
- reply.copy("Invalid spindle index");
- result = GCodeResult::error;
+ result = reprap.GetRoland()->ProcessSpindle(0.0);
}
else
+#endif
{
- platform.AccessSpindle(slot).TurnOff();
- }
- }
- else
- {
- // Turn off every spindle if no 'P' parameter is present
- for (size_t i = 0; i < MaxSpindles; i++)
- {
- platform.AccessSpindle(i).TurnOff();
+ result = GCodeResult::notSupportedInCurrentMode;
}
+ break;
}
break;
-#if SUPPORT_LASER
- case MachineType::laser:
- moveBuffer.laserPwmOrIoBits.Clear();
- break;
-#endif
-
- default:
-#if SUPPORT_ROLAND
- if (reprap.GetRoland()->Active())
+ case 18: // Motors off
+ case 84:
+ if (!LockMovementAndWaitForStandstill(gb))
{
- result = reprap.GetRoland()->ProcessSpindle(0.0);
+ return false;
}
- else
-#endif
{
- result = GCodeResult::notSupportedInCurrentMode;
- }
- break;
- }
- break;
+ bool seen = false;
+ for (size_t axis = 0; axis < numTotalAxes; axis++)
+ {
+ if (gb.Seen(axisLetters[axis]))
+ {
+ SetAxisNotHomed(axis);
+ platform.DisableDrivers(axis);
+ seen = true;
+ }
+ }
- case 18: // Motors off
- case 84:
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- {
- bool seen = false;
- for (size_t axis = 0; axis < numTotalAxes; axis++)
- {
- if (gb.Seen(axisLetters[axis]))
+ if (gb.Seen(extrudeLetter))
{
- SetAxisNotHomed(axis);
- platform.DisableDrivers(axis);
- seen = true;
+ uint32_t eDrive[MaxExtruders];
+ size_t eCount = numExtruders;
+ gb.GetUnsignedArray(eDrive, eCount, false);
+ for (size_t i = 0; i < eCount; i++)
+ {
+ seen = true;
+ if (eDrive[i] >= numExtruders)
+ {
+ reply.printf("Invalid extruder number specified: %" PRIu32, eDrive[i]);
+ result = GCodeResult::error;
+ break;
+ }
+ platform.DisableDrivers(ExtruderToLogicalDrive(eDrive[i]));
+ }
}
- }
- if (gb.Seen(extrudeLetter))
- {
- uint32_t eDrive[MaxExtruders];
- size_t eCount = numExtruders;
- gb.GetUnsignedArray(eDrive, eCount, false);
- for (size_t i = 0; i < eCount; i++)
+ if (gb.Seen('S'))
{
seen = true;
- if (eDrive[i] >= numExtruders)
+
+ const float idleTimeout = gb.GetFValue();
+ if (idleTimeout < 0.0)
{
- reply.printf("Invalid extruder number specified: %" PRIu32, eDrive[i]);
+ reply.copy("Idle timeouts cannot be negative");
result = GCodeResult::error;
- break;
}
- platform.DisableDrivers(ExtruderToLogicalDrive(eDrive[i]));
+ else
+ {
+ reprap.GetMove().SetIdleTimeout(idleTimeout);
+ }
}
- }
-
- if (gb.Seen('S'))
- {
- seen = true;
- const float idleTimeout = gb.GetFValue();
- if (idleTimeout < 0.0)
- {
- reply.copy("Idle timeouts cannot be negative");
- result = GCodeResult::error;
- }
- else
+ if (!seen)
{
- reprap.GetMove().SetIdleTimeout(idleTimeout);
+ DisableDrives();
}
}
-
- if (!seen)
- {
- DisableDrives();
- }
- }
- break;
+ break;
#if HAS_MASS_STORAGE
- case 20: // List files on SD card
- if (!LockFileSystem(gb)) // don't allow more than one at a time to avoid contention on output buffers
- {
- return false;
- }
- {
- const int sparam = (gb.Seen('S')) ? gb.GetIValue() : 0;
- const unsigned int rparam = (gb.Seen('R')) ? gb.GetUIValue() : 0;
- String<MaxFilenameLength> dir;
- if (gb.Seen('P'))
- {
- gb.GetPossiblyQuotedString(dir.GetRef());
- }
- else
+ case 20: // List files on SD card
+ if (!LockFileSystem(gb)) // don't allow more than one at a time to avoid contention on output buffers
{
- dir.copy(platform.GetGCodeDir());
+ return false;
}
-
- if (sparam == 2)
{
- outBuf = reprap.GetFilesResponse(dir.c_str(), rparam, true); // send the file list in JSON format
- if (outBuf == nullptr)
+ const int sparam = (gb.Seen('S')) ? gb.GetIValue() : 0;
+ const unsigned int rparam = (gb.Seen('R')) ? gb.GetUIValue() : 0;
+ String<MaxFilenameLength> dir;
+ if (gb.Seen('P'))
{
- return false;
+ gb.GetPossiblyQuotedString(dir.GetRef());
}
- outBuf->cat('\n');
- }
- else if (sparam == 3)
- {
- outBuf = reprap.GetFilelistResponse(dir.c_str(), rparam);
- if (outBuf == nullptr)
+ else
{
- return false;
+ dir.copy(platform.GetGCodeDir());
}
- outBuf->cat('\n');
- }
- else
- {
- if (!OutputBuffer::Allocate(outBuf))
+
+ if (sparam == 2)
{
- return false; // cannot allocate an output buffer, try again later
+ outBuf = reprap.GetFilesResponse(dir.c_str(), rparam, true); // send the file list in JSON format
+ if (outBuf == nullptr)
+ {
+ return false;
+ }
+ outBuf->cat('\n');
}
-
- // To mimic the behaviour of the official RepRapPro firmware:
- // 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::me || gb.MachineState().compatibility == Compatibility::reprapFirmware)
+ else if (sparam == 3)
{
- outBuf->copy("GCode files:\n");
+ outBuf = reprap.GetFilelistResponse(dir.c_str(), rparam);
+ if (outBuf == nullptr)
+ {
+ return false;
+ }
+ outBuf->cat('\n');
}
-
- bool encapsulateList = gb.MachineState().compatibility != Compatibility::marlin;
- FileInfo fileInfo;
- if (MassStorage::FindFirst(dir.c_str(), fileInfo))
+ else
{
- // iterate through all entries and append each file name
- do {
+ if (!OutputBuffer::Allocate(outBuf))
+ {
+ return false; // cannot allocate an output buffer, try again later
+ }
+
+ // To mimic the behaviour of the official RepRapPro firmware:
+ // 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::me || gb.MachineState().compatibility == Compatibility::reprapFirmware)
+ {
+ outBuf->copy("GCode files:\n");
+ }
+
+ bool encapsulateList = gb.MachineState().compatibility != Compatibility::marlin;
+ FileInfo fileInfo;
+ if (MassStorage::FindFirst(dir.c_str(), fileInfo))
+ {
+ // iterate through all entries and append each file name
+ do {
+ if (encapsulateList)
+ {
+ outBuf->catf("%c%s%c%c", FILE_LIST_BRACKET, fileInfo.fileName.c_str(), FILE_LIST_BRACKET, FILE_LIST_SEPARATOR);
+ }
+ else
+ {
+ outBuf->catf("%s\n", fileInfo.fileName.c_str());
+ }
+ } while (MassStorage::FindNext(fileInfo));
+
if (encapsulateList)
{
- outBuf->catf("%c%s%c%c", FILE_LIST_BRACKET, fileInfo.fileName.c_str(), FILE_LIST_BRACKET, FILE_LIST_SEPARATOR);
+ // remove the last separator
+ (*outBuf)[outBuf->Length() - 1] = 0;
}
- else
- {
- outBuf->catf("%s\n", fileInfo.fileName.c_str());
- }
- } while (MassStorage::FindNext(fileInfo));
-
- if (encapsulateList)
+ }
+ else
{
- // remove the last separator
- (*outBuf)[outBuf->Length() - 1] = 0;
+ outBuf->cat("NONE\n");
}
}
- else
- {
- outBuf->cat("NONE\n");
- }
}
- }
- break;
-
- case 21: // Initialise SD card
- if (!LockFileSystem(gb)) // don't allow more than one at a time to avoid contention on output buffers
- {
- return false;
- }
- {
- const size_t card = (gb.Seen('P')) ? gb.GetIValue() : 0;
- result = MassStorage::Mount(card, reply, true);
- }
- break;
+ break;
- case 22: // Release SD card
- if (!LockFileSystem(gb)) // don't allow more than one at a time to avoid contention on output buffers
- {
- return false;
- }
- {
- const size_t card = (gb.Seen('P')) ? gb.GetIValue() : 0;
- result = MassStorage::Unmount(card, reply);
- }
- break;
+ case 21: // Initialise SD card
+ if (!LockFileSystem(gb)) // don't allow more than one at a time to avoid contention on output buffers
+ {
+ return false;
+ }
+ {
+ const size_t card = (gb.Seen('P')) ? gb.GetIValue() : 0;
+ result = MassStorage::Mount(card, reply, true);
+ }
+ break;
- case 23: // Set file to print
- case 32: // Select file and start SD print
- // We now allow a file that is being printed to chain to another file. This is required for the resume-after-power-fail functionality.
- if (fileGCode->IsDoingFile() && (&gb) != fileGCode)
- {
- reply.copy("Cannot set file to print, because a file is already being printed");
- result = GCodeResult::error;
+ case 22: // Release SD card
+ if (!LockFileSystem(gb)) // don't allow more than one at a time to avoid contention on output buffers
+ {
+ return false;
+ }
+ {
+ const size_t card = (gb.Seen('P')) ? gb.GetIValue() : 0;
+ result = MassStorage::Unmount(card, reply);
+ }
break;
- }
- if (code == 32 && !LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- {
- String<MaxFilenameLength> filename;
- if (gb.GetUnprecedentedString(filename.GetRef()))
+ case 23: // Set file to print
+ case 32: // Select file and start SD print
+ // We now allow a file that is being printed to chain to another file. This is required for the resume-after-power-fail functionality.
+ if (fileGCode->IsDoingFile() && (&gb) != fileGCode)
{
+ reply.copy("Cannot set file to print, because a file is already being printed");
+ result = GCodeResult::error;
+ break;
+ }
+
+ if (code == 32 && !LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ {
+ String<MaxFilenameLength> filename;
+ gb.GetUnprecedentedString(filename.GetRef());
if (QueueFileToPrint(filename.c_str(), reply))
{
reprap.GetPrintMonitor().StartingPrint(filename.c_str());
@@ -767,169 +779,162 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
result = GCodeResult::error;
}
}
- else
- {
- reply.copy("Filename expected");
- result = GCodeResult::error;
- }
- }
- break;
+ break;
#endif
- case 24: // Print/resume-printing the selected file
- if (IsPausing() || IsResuming())
- {
- // ignore the resume request
- }
- else
- {
- if (!LockMovementAndWaitForStandstill(gb))
+ case 24: // Print/resume-printing the selected file
+ if (IsPausing() || IsResuming())
{
- return false;
+ // ignore the resume request
}
-
- if (IsPaused())
+ else
{
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+
+ if (IsPaused())
+ {
#if HAS_VOLTAGE_MONITOR
- if (!platform.IsPowerOk())
+ if (!platform.IsPowerOk())
+ {
+ reply.copy("Cannot resume while power voltage is low");
+ result = GCodeResult::error;
+ }
+ else
+#endif
+ {
+ gb.SetState(GCodeState::resuming1);
+ if (AllAxesAreHomed())
+ {
+ DoFileMacro(gb, RESUME_G, true, 24);
+ }
+ }
+ }
+#if HAS_MASS_STORAGE
+ else if (!fileToPrint.IsLive())
{
- reply.copy("Cannot resume while power voltage is low");
+ reply.copy("Cannot print, because no file is selected!");
result = GCodeResult::error;
}
else
-#endif
{
- gb.SetState(GCodeState::resuming1);
- if (AllAxesAreHomed())
+# if HAS_VOLTAGE_MONITOR
+ if (!platform.IsPowerOk())
{
- DoFileMacro(gb, RESUME_G, true, 24);
+ reply.copy("Cannot start a print while power voltage is low");
+ result = GCodeResult::error;
+ }
+ else
+# endif
+ {
+ bool fromStart = (fileOffsetToPrint == 0);
+ if (!fromStart)
+ {
+ // 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());
+ fileToPrint.Seek(fileOffsetToPrint);
+ moveFractionToSkip = restartMoveFractionDone;
+ }
+ StartPrinting(fromStart);
}
}
+#endif
}
-#if HAS_MASS_STORAGE
- else if (!fileToPrint.IsLive())
+ break;
+
+ case 226: // Synchronous pause, normally initiated from within the file being printed
+ if (!isPaused && !IsPausing())
{
- reply.copy("Cannot print, because no file is selected!");
- result = GCodeResult::error;
+ if (gb.IsDoingFileMacro())
+ {
+ pausePending = true;
+ }
+ else
+ {
+ if (!LockMovementAndWaitForStandstill(gb)) // lock movement before calling DoPause, also wait for movement to complete
+ {
+ return false;
+ }
+ DoPause(gb, PauseReason::gcode, nullptr);
+ }
}
- else
+ break;
+
+ case 600: // Filament change pause, synchronous
+ if (!isPaused && !IsPausing())
{
-# if HAS_VOLTAGE_MONITOR
- if (!platform.IsPowerOk())
+ if (gb.IsDoingFileMacro())
{
- reply.copy("Cannot start a print while power voltage is low");
- result = GCodeResult::error;
+ filamentChangePausePending = true;
}
else
-# endif
{
- bool fromStart = (fileOffsetToPrint == 0);
- if (!fromStart)
+ if (!LockMovementAndWaitForStandstill(gb)) // lock movement before calling DoPause, also wait for movement to complete
{
- // 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());
- fileToPrint.Seek(fileOffsetToPrint);
- moveFractionToSkip = restartMoveFractionDone;
+ return false;
}
- StartPrinting(fromStart);
+ DoPause(gb, PauseReason::filamentChange, nullptr);
}
}
-#endif
- }
- break;
+ break;
- case 226: // Synchronous pause, normally initiated from within the file being printed
- if (!isPaused && !IsPausing())
- {
- if (gb.IsDoingFileMacro())
+ case 25: // Pause the print
+ if (isPaused)
{
- pausePending = true;
+ reply.copy("Printing is already paused!!");
+ result = GCodeResult::error;
}
- else
+ else if (!reprap.GetPrintMonitor().IsPrinting())
{
- if (!LockMovementAndWaitForStandstill(gb)) // lock movement before calling DoPause, also wait for movement to complete
- {
- return false;
- }
- DoPause(gb, PauseReason::gcode, nullptr);
+ reply.copy("Cannot pause print, because no file is being printed!");
+ result = GCodeResult::error;
}
- }
- break;
-
- case 600: // Filament change pause, synchronous
- if (!isPaused && !IsPausing())
- {
- if (gb.IsDoingFileMacro())
+ else if (fileGCode->IsDoingFileMacro())
{
- filamentChangePausePending = true;
+ pausePending = true;
}
else
{
- if (!LockMovementAndWaitForStandstill(gb)) // lock movement before calling DoPause, also wait for movement to complete
+ if (!LockMovement(gb)) // lock movement before calling DoPause
{
return false;
}
- DoPause(gb, PauseReason::filamentChange, nullptr);
+ DoPause(gb, PauseReason::user, nullptr);
}
- }
- break;
+ break;
- case 25: // Pause the print
- if (isPaused)
- {
- reply.copy("Printing is already paused!!");
- result = GCodeResult::error;
- }
- else if (!reprap.GetPrintMonitor().IsPrinting())
- {
- reply.copy("Cannot pause print, because no file is being printed!");
- result = GCodeResult::error;
- }
- else if (fileGCode->IsDoingFileMacro())
- {
- pausePending = true;
- }
- else
- {
- if (!LockMovement(gb)) // lock movement before calling DoPause
+#if HAS_MASS_STORAGE
+ case 26: // Set SD position
+ // This is used between executing M23 to set up the file to print, and M25 to print it
+ if (gb.Seen('S'))
{
- return false;
+ fileOffsetToPrint = (FilePosition)gb.GetUIValue();
+ restartMoveFractionDone = (gb.Seen('P')) ? constrain<float>(gb.GetFValue(), 0.0, 1.0) : 0.0;
+ restartInitialUserX = (gb.Seen('X')) ? gb.GetFValue() : 0.0;
+ restartInitialUserY = (gb.Seen('Y')) ? gb.GetFValue() : 0.0;
}
- DoPause(gb, PauseReason::user, nullptr);
- }
- break;
-
-#if HAS_MASS_STORAGE
- case 26: // Set SD position
- // This is used between executing M23 to set up the file to print, and M25 to print it
- if (gb.Seen('S'))
- {
- fileOffsetToPrint = (FilePosition)gb.GetUIValue();
- restartMoveFractionDone = (gb.Seen('P')) ? constrain<float>(gb.GetFValue(), 0.0, 1.0) : 0.0;
- restartInitialUserX = (gb.Seen('X')) ? gb.GetFValue() : 0.0;
- restartInitialUserY = (gb.Seen('Y')) ? gb.GetFValue() : 0.0;
- }
- break;
+ break;
- case 27: // Report print status - Deprecated
- if (reprap.GetPrintMonitor().IsPrinting())
- {
- // Pronterface keeps sending M27 commands if "Monitor status" is checked, and it specifically expects the following response syntax
- FileData& fileBeingPrinted = fileGCode->OriginalMachineState().fileState;
- reply.printf("SD printing byte %lu/%lu", GetFilePosition(), fileBeingPrinted.Length());
- }
- else
- {
- reply.copy("Not SD printing.");
- }
- break;
+ case 27: // Report print status - Deprecated
+ if (reprap.GetPrintMonitor().IsPrinting())
+ {
+ // Pronterface keeps sending M27 commands if "Monitor status" is checked, and it specifically expects the following response syntax
+ FileData& fileBeingPrinted = fileGCode->OriginalMachineState().fileState;
+ reply.printf("SD printing byte %lu/%lu", GetFilePosition(), fileBeingPrinted.Length());
+ }
+ else
+ {
+ reply.copy("Not SD printing.");
+ }
+ break;
- case 28: // Write to file
- {
- String<MaxFilenameLength> filename;
- if (gb.GetUnprecedentedString(filename.GetRef()))
+ case 28: // Write to file
{
+ String<MaxFilenameLength> filename;
+ gb.GetUnprecedentedString(filename.GetRef());
const bool ok = gb.OpenFileToWrite(platform.GetGCodeDir(), filename.c_str(), 0, false, 0);
if (ok)
{
@@ -941,113 +946,99 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
result = GCodeResult::error;
}
}
- else
- {
- reply.copy("Filename expected");
- result = GCodeResult::error;
- }
- }
- break;
+ break;
- case 29: // End of file being written; should be intercepted before getting here
- reply.copy("GCode end-of-file being interpreted.");
- break;
+ case 29: // End of file being written; should be intercepted before getting here
+ reply.copy("GCode end-of-file being interpreted.");
+ break;
- case 30: // Delete file
- {
- String<MaxFilenameLength> filename;
- if (gb.GetUnprecedentedString(filename.GetRef()))
+ case 30: // Delete file
{
+ String<MaxFilenameLength> filename;
+ gb.GetUnprecedentedString(filename.GetRef());
platform.Delete(platform.GetGCodeDir(), filename.c_str());
}
- else
- {
- reply.copy("Filename expected");
- result = GCodeResult::error;
- }
- }
- break;
+ break;
#endif
// For case 32, see case 23
#if HAS_MASS_STORAGE || HAS_LINUX_INTERFACE
- case 36: // Return file information
+ case 36: // Return file information
# if HAS_LINUX_INTERFACE
- if (reprap.UsingLinuxInterface())
- {
- reprap.GetFileInfoResponse(nullptr, outBuf, true);
- }
- else
-# endif
- {
-# if HAS_MASS_STORAGE
- if (!LockFileSystem(gb)) // getting file info takes several calls and isn't reentrant
- {
- return false;
- }
-
- String<MaxFilenameLength> filename;
- const bool gotFilename = gb.GetUnprecedentedString(filename.GetRef());
- const bool done = reprap.GetFileInfoResponse((gotFilename) ? filename.c_str() : nullptr, outBuf, false);
- if (outBuf != nullptr)
+ if (reprap.UsingLinuxInterface())
{
- outBuf->cat('\n');
+ reprap.GetFileInfoResponse(nullptr, outBuf, true);
}
- result = (done) ? GCodeResult::ok : GCodeResult::notFinished;
+ else
# endif
- }
- break;
+ {
+# if HAS_MASS_STORAGE
+ if (!LockFileSystem(gb)) // getting file info takes several calls and isn't reentrant
+ {
+ return false;
+ }
- case 37: // Simulation mode on/off, or simulate a whole file
-# if HAS_LINUX_INTERFACE
- if (reprap.UsingLinuxInterface() && !gb.IsBinary())
- {
- reply.copy("M37 can be only started from the Linux interface");
- result = GCodeResult::error;
- }
- else
+ String<MaxFilenameLength> filename;
+ gb.GetUnprecedentedString(filename.GetRef(), true);
+ const bool done = reprap.GetFileInfoResponse((filename.IsEmpty()) ? nullptr : filename.c_str(), outBuf, false);
+ if (outBuf != nullptr)
+ {
+ outBuf->cat('\n');
+ }
+ result = (done) ? GCodeResult::ok : GCodeResult::notFinished;
# endif
- {
- bool seen = false;
- String<MaxFilenameLength> simFileName;
+ }
+ break;
- gb.TryGetPossiblyQuotedString('P', simFileName.GetRef(), seen);
- if (seen)
+ case 37: // Simulation mode on/off, or simulate a whole file
+# if HAS_LINUX_INTERFACE
+ if (reprap.UsingLinuxInterface() && !gb.IsBinary())
{
- const bool updateFile = !gb.Seen('F') || gb.GetUIValue() == 1;
- result = SimulateFile(gb, reply, simFileName.GetRef(), updateFile);
+ reply.copy("M37 can be only started from the Linux interface");
+ result = GCodeResult::error;
}
else
+# endif
{
- uint32_t newSimulationMode;
- gb.TryGetUIValue('S', newSimulationMode, seen);
+ bool seen = false;
+ String<MaxFilenameLength> simFileName;
+
+ gb.TryGetPossiblyQuotedString('P', simFileName.GetRef(), seen);
if (seen)
{
- result = ChangeSimulationMode(gb, reply, newSimulationMode);
+ const bool updateFile = !gb.Seen('F') || gb.GetUIValue() == 1;
+ result = SimulateFile(gb, reply, simFileName.GetRef(), updateFile);
}
else
{
- reply.printf("Simulation mode: %s, move time: %.1f sec, other time: %.1f sec",
- (simulationMode != 0) ? "on" : "off", (double)reprap.GetMove().GetSimulationTime(), (double)simulationTime);
+ uint32_t newSimulationMode;
+ gb.TryGetUIValue('S', newSimulationMode, seen);
+ if (seen)
+ {
+ result = ChangeSimulationMode(gb, reply, newSimulationMode);
+ }
+ else
+ {
+ reply.printf("Simulation mode: %s, move time: %.1f sec, other time: %.1f sec",
+ (simulationMode != 0) ? "on" : "off", (double)reprap.GetMove().GetSimulationTime(), (double)simulationTime);
+ }
}
}
- }
- break;
+ break;
#endif
#if HAS_MASS_STORAGE
- case 38: // Report SHA1 of file
- if (!LockFileSystem(gb)) // getting file hash takes several calls and isn't reentrant
- {
- return false;
- }
- if (fileBeingHashed == nullptr)
- {
- // See if we can open the file and start hashing
- String<MaxFilenameLength> filename;
- if (gb.GetUnprecedentedString(filename.GetRef()))
+ case 38: // Report SHA1 of file
+ if (!LockFileSystem(gb)) // getting file hash takes several calls and isn't reentrant
{
+ return false;
+ }
+ if (fileBeingHashed == nullptr)
+ {
+ // See if we can open the file and start hashing
+ String<MaxFilenameLength> filename;
+ gb.GetUnprecedentedString(filename.GetRef());
if (StartHash(filename.c_str()))
{
// Hashing is now in progress...
@@ -1061,2710 +1052,2704 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
}
else
{
- reply.copy("Filename expected");
- result = GCodeResult::error;
+ // This can take some time. All the actual heavy lifting is in dedicated methods
+ result = AdvanceHash(reply);
}
- }
- else
- {
- // This can take some time. All the actual heavy lifting is in dedicated methods
- result = AdvanceHash(reply);
- }
- break;
+ break;
- case 39: // Return SD card info
- {
- uint32_t slot = 0;
- bool dummy;
- gb.TryGetUIValue('P', slot, dummy);
- int32_t format = 0;
- gb.TryGetIValue('S', format, dummy);
- uint64_t capacity, freeSpace;
- uint32_t speed;
- uint32_t clSize;
- const MassStorage::InfoResult res = MassStorage::GetCardInfo(slot, capacity, freeSpace, speed, clSize);
- if (format == 2)
- {
- reply.printf("{\"SDinfo\":{\"slot\":%" PRIu32 ",\"present\":", slot);
- if (res == MassStorage::InfoResult::ok)
- {
- reply.catf("1,\"capacity\":%" PRIu64 ",\"free\":%" PRIu64 ",\"speed\":%" PRIu32 ",\"clsize\":%" PRIu32 "}}", capacity, freeSpace, speed, clSize);
- }
- else
- {
- reply.cat("0}}");
- }
- }
- else
+ case 39: // Return SD card info
{
- switch(res)
- {
- case MassStorage::InfoResult::badSlot:
- default:
- reply.printf("Bad SD slot number: %" PRIu32, slot);
- result = GCodeResult::error;
- break;
-
- case MassStorage::InfoResult::noCard:
- reply.printf("No SD card mounted in slot %" PRIu32, slot);
- result = GCodeResult::error;
- break;
-
- case MassStorage::InfoResult::ok:
- reply.printf("SD card in slot %" PRIu32 ": capacity %.2fGb, free space %.2fGb, speed %.2fMBytes/sec, cluster size ",
- slot, (double)capacity/(1000*1000*1000), (double)freeSpace/(1000*1000*1000), (double)speed/(1000*1000));
- if (clSize < 1024)
+ uint32_t slot = 0;
+ bool dummy;
+ gb.TryGetUIValue('P', slot, dummy);
+ int32_t format = 0;
+ gb.TryGetIValue('S', format, dummy);
+ uint64_t capacity, freeSpace;
+ uint32_t speed;
+ uint32_t clSize;
+ const MassStorage::InfoResult res = MassStorage::GetCardInfo(slot, capacity, freeSpace, speed, clSize);
+ if (format == 2)
+ {
+ reply.printf("{\"SDinfo\":{\"slot\":%" PRIu32 ",\"present\":", slot);
+ if (res == MassStorage::InfoResult::ok)
{
- reply.catf("%" PRIu32 " bytes", clSize);
+ reply.catf("1,\"capacity\":%" PRIu64 ",\"free\":%" PRIu64 ",\"speed\":%" PRIu32 ",\"clsize\":%" PRIu32 "}}", capacity, freeSpace, speed, clSize);
}
else
{
- reply.catf("%" PRIu32 "kb", clSize/1024);
+ reply.cat("0}}");
+ }
+ }
+ else
+ {
+ switch(res)
+ {
+ case MassStorage::InfoResult::badSlot:
+ default:
+ reply.printf("Bad SD slot number: %" PRIu32, slot);
+ result = GCodeResult::error;
+ break;
+
+ case MassStorage::InfoResult::noCard:
+ reply.printf("No SD card mounted in slot %" PRIu32, slot);
+ result = GCodeResult::error;
+ break;
+
+ case MassStorage::InfoResult::ok:
+ reply.printf("SD card in slot %" PRIu32 ": capacity %.2fGb, free space %.2fGb, speed %.2fMBytes/sec, cluster size ",
+ slot, (double)capacity/(1000*1000*1000), (double)freeSpace/(1000*1000*1000), (double)speed/(1000*1000));
+ if (clSize < 1024)
+ {
+ reply.catf("%" PRIu32 " bytes", clSize);
+ }
+ else
+ {
+ reply.catf("%" PRIu32 "kb", clSize/1024);
+ }
+ break;
}
- break;
}
}
- }
- break;
+ break;
#endif
- case 42: // Turn an output pin on or off
- if (gb.Seen('P'))
- {
- const uint32_t gpioPortNumber = gb.GetUIValue();
- if (gpioPortNumber < MaxGpioPorts)
+ case 42: // Turn an output pin on or off
+ if (gb.Seen('P'))
{
- if (gb.Seen('S'))
+ const uint32_t gpioPortNumber = gb.GetUIValue();
+ if (gpioPortNumber < MaxGpioPorts)
{
- const float val = gb.GetPwmValue();
- const GpOutputPort& gpPort = platform.GetGpioPort(gpioPortNumber);
-#if SUPPORT_CAN_EXPANSION
- if (gpPort.boardAddress != CanId::MasterAddress)
+ if (gb.Seen('S'))
{
- result = CanInterface::WriteGpio(gpPort.boardAddress, gpioPortNumber, val, false, reply);
- break;
- }
+ const float val = gb.GetPwmValue();
+ const GpOutputPort& gpPort = platform.GetGpioPort(gpioPortNumber);
+#if SUPPORT_CAN_EXPANSION
+ if (gpPort.boardAddress != CanId::MasterAddress)
+ {
+ result = CanInterface::WriteGpio(gpPort.boardAddress, gpioPortNumber, val, false, reply);
+ break;
+ }
#endif
- gpPort.port.WriteAnalog(val);
+ gpPort.port.WriteAnalog(val);
+ }
+ }
+ else
+ {
+ reply.printf("Invalid gpio port %" PRIu32, gpioPortNumber);
+ result = GCodeResult::error;
}
}
- else
+ break;
+
+ case 80: // ATX power on
+ atxPowerControlled = true;
+ platform.AtxPowerOn();
+ break;
+
+ case 81: // ATX power off
+ atxPowerControlled = true;
+ if (!LockMovementAndWaitForStandstill(gb))
{
- reply.printf("Invalid gpio port %" PRIu32, gpioPortNumber);
- result = GCodeResult::error;
+ return false;
}
- }
- break;
-
- case 80: // ATX power on
- atxPowerControlled = true;
- platform.AtxPowerOn();
- break;
+ platform.AtxPowerOff(gb.Seen('S') && gb.GetUIValue() != 0);
+ break;
- case 81: // ATX power off
- atxPowerControlled = true;
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- platform.AtxPowerOff(gb.Seen('S') && gb.GetUIValue() != 0);
- break;
+ case 82: // Use absolute extruder positioning
+ gb.MachineState().drivesRelative = false;
+ break;
- case 82: // Use absolute extruder positioning
- gb.MachineState().drivesRelative = false;
- break;
+ case 83: // Use relative extruder positioning
+ gb.MachineState().drivesRelative = true;
+ break;
- case 83: // Use relative extruder positioning
- gb.MachineState().drivesRelative = true;
- break;
+ // For case 84, see case 18
- // For case 84, see case 18
+ case 85: // Set inactive time
+ break;
- case 85: // Set inactive time
- break;
+ case 92: // Set/report steps/mm for some axes
+ {
+ bool seenUstepMultiplier = false;
+ uint32_t ustepMultiplier = 0;
+ gb.TryGetUIValue('S', ustepMultiplier, seenUstepMultiplier);
- case 92: // Set/report steps/mm for some axes
- {
- bool seenUstepMultiplier = false;
- uint32_t ustepMultiplier = 0;
- gb.TryGetUIValue('S', ustepMultiplier, seenUstepMultiplier);
+ bool seen = false;
+ for (size_t axis = 0; axis < numTotalAxes; axis++)
+ {
+ if (gb.Seen(axisLetters[axis]))
+ {
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ platform.SetDriveStepsPerUnit(axis, gb.GetFValue(), ustepMultiplier);
+ seen = true;
+ }
+ }
- bool seen = false;
- for (size_t axis = 0; axis < numTotalAxes; axis++)
- {
- if (gb.Seen(axisLetters[axis]))
+ if (gb.Seen(extrudeLetter))
{
if (!LockMovementAndWaitForStandstill(gb))
{
return false;
}
- platform.SetDriveStepsPerUnit(axis, gb.GetFValue(), ustepMultiplier);
seen = true;
+ float eVals[MaxExtruders];
+ size_t eCount = numExtruders;
+ gb.GetFloatArray(eVals, eCount, true);
+
+ // The user may not have as many extruders as we allow for, so just set the ones for which a value is provided
+ for (size_t e = 0; e < eCount; e++)
+ {
+ platform.SetDriveStepsPerUnit(ExtruderToLogicalDrive(e), eVals[e], ustepMultiplier);
+ }
}
- }
- if (gb.Seen(extrudeLetter))
- {
- if (!LockMovementAndWaitForStandstill(gb))
+ if (seen)
{
- return false;
+ // On a delta, if we change the drive steps/mm then we need to recalculate the motor positions
+ reprap.GetMove().SetNewPosition(moveBuffer.coords, true);
}
- seen = true;
- float eVals[MaxExtruders];
- size_t eCount = numExtruders;
- gb.GetFloatArray(eVals, eCount, true);
-
- // The user may not have as many extruders as we allow for, so just set the ones for which a value is provided
- for (size_t e = 0; e < eCount; e++)
+ else
{
- platform.SetDriveStepsPerUnit(ExtruderToLogicalDrive(e), eVals[e], ustepMultiplier);
+ reply.copy("Steps/mm: ");
+ for (size_t axis = 0; axis < numTotalAxes; ++axis)
+ {
+ reply.catf("%c: %.3f, ", axisLetters[axis], (double)platform.DriveStepsPerUnit(axis));
+ }
+ reply.catf("E:");
+ char sep = ' ';
+ for (size_t extruder = 0; extruder < numExtruders; extruder++)
+ {
+ reply.catf("%c%.3f", sep, (double)platform.DriveStepsPerUnit(ExtruderToLogicalDrive(extruder)));
+ sep = ':';
+ }
}
}
+ break;
- if (seen)
- {
- // On a delta, if we change the drive steps/mm then we need to recalculate the motor positions
- reprap.GetMove().SetNewPosition(moveBuffer.coords, true);
- }
- else
+ case 98: // Call Macro/Subprogram
+ if (gb.Seen('P'))
{
- reply.copy("Steps/mm: ");
- for (size_t axis = 0; axis < numTotalAxes; ++axis)
- {
- reply.catf("%c: %.3f, ", axisLetters[axis], (double)platform.DriveStepsPerUnit(axis));
- }
- reply.catf("E:");
- char sep = ' ';
- for (size_t extruder = 0; extruder < numExtruders; extruder++)
+#if HAS_LINUX_INTERFACE
+ if (reprap.UsingLinuxInterface())
{
- reply.catf("%c%.3f", sep, (double)platform.DriveStepsPerUnit(ExtruderToLogicalDrive(extruder)));
- sep = ':';
+ gb.SetState(GCodeState::doingUserMacro);
}
- }
- }
- break;
-
- case 98: // Call Macro/Subprogram
- if (gb.Seen('P'))
- {
-#if HAS_LINUX_INTERFACE
- if (reprap.UsingLinuxInterface())
- {
- gb.SetState(GCodeState::doingUserMacro);
- }
#endif
- String<MaxFilenameLength> filename;
- gb.GetPossiblyQuotedString(filename.GetRef());
- DoFileMacro(gb, filename.c_str(), true, code);
- }
- break;
-
- case 99: // Return from Macro/Subprogram
- FileMacroCyclesReturn(gb);
- break;
+ String<MaxFilenameLength> filename;
+ gb.GetPossiblyQuotedString(filename.GetRef());
+ DoFileMacro(gb, filename.c_str(), true, code);
+ }
+ break;
- case 101: // Un-retract, generated by S3D if "Include M101/101/103" is enabled
- result = RetractFilament(gb, false);
- break;
+ case 99: // Return from Macro/Subprogram
+ FileMacroCyclesReturn(gb);
+ break;
- case 102:
- // S3D generates this command just before each explicit retraction command if both explicit retraction and "Include M101/101/103" are enabled.
- // Old versions of S3D also generate it once at the start of each print file if "Include M101/101/103" is enabled.
- // It's not documented, so we just ignore it rather than generate an error message.
- break;
+ case 101: // Un-retract, generated by S3D if "Include M101/101/103" is enabled
+ result = RetractFilament(gb, false);
+ break;
- case 103: // Retract, generated by S3D if "Include M101/101/103" is enabled
- result = RetractFilament(gb, true);
- break;
+ case 102:
+ // S3D generates this command just before each explicit retraction command if both explicit retraction and "Include M101/101/103" are enabled.
+ // Old versions of S3D also generate it once at the start of each print file if "Include M101/101/103" is enabled.
+ // It's not documented, so we just ignore it rather than generate an error message.
+ break;
- // For case 104, see 109
+ case 103: // Retract, generated by S3D if "Include M101/101/103" is enabled
+ result = RetractFilament(gb, true);
+ break;
- case 105: // Get temperatures
- GenerateTemperatureReport(reply);
- break;
+ // For case 104, see 109
- case 106: // Set/report fan values
- {
- bool seenFanNum = false;
- uint32_t fanNum;
- gb.TryGetUIValue('P', fanNum, seenFanNum);
- bool processed;
+ case 105: // Get temperatures
+ GenerateTemperatureReport(reply);
+ break;
- // 2018-08-09: only configure the fan if a fan number was given.
- // This avoids M106 Snn failing if we have disabled Fan 0 and mapped the print cooling fan to a different fan.
- if (seenFanNum)
+ case 106: // Set/report fan values
{
- bool error = false;
- processed = reprap.GetFansManager().ConfigureFan(code, fanNum, gb, reply, error);
- result = GetGCodeResultFromError(error);
- }
- else
- {
- processed = false;
- }
+ bool seenFanNum = false;
+ uint32_t fanNum;
+ gb.TryGetUIValue('P', fanNum, seenFanNum);
+ bool processed;
- // ConfigureFan only processes S parameters if there were other parameters to process
- if (!processed && gb.Seen('S'))
- {
- // Convert the parameter to an interval in 0.0..1.0 here so that we save the correct value in lastDefaultFanSpeed
- const float f = gb.GetPwmValue();
+ // 2018-08-09: only configure the fan if a fan number was given.
+ // This avoids M106 Snn failing if we have disabled Fan 0 and mapped the print cooling fan to a different fan.
if (seenFanNum)
{
- result = reprap.GetFansManager().SetFanValue(fanNum, f, reply);
- if (IsMappedFan(fanNum))
- {
- lastDefaultFanSpeed = f;
- }
+ bool error = false;
+ processed = reprap.GetFansManager().ConfigureFan(code, fanNum, gb, reply, error);
+ result = GetGCodeResultFromError(error);
}
else
{
- // We are processing an M106 S### command with no other recognised parameters and we have a tool selected.
- // Apply the fan speed setting to the fans in the fan mapping for the current tool.
- SetMappedFanSpeed(f);
+ processed = false;
}
- }
- // ConfigureFan doesn't process R parameters
- if (gb.Seen('R'))
- {
- // Restore fan speed to value when print was paused
- if (seenFanNum)
+ // ConfigureFan only processes S parameters if there were other parameters to process
+ if (!processed && gb.Seen('S'))
{
- result = reprap.GetFansManager().SetFanValue(fanNum, pausedFanSpeeds[fanNum], reply);
+ // Convert the parameter to an interval in 0.0..1.0 here so that we save the correct value in lastDefaultFanSpeed
+ const float f = gb.GetPwmValue();
+ if (seenFanNum)
+ {
+ result = reprap.GetFansManager().SetFanValue(fanNum, f, reply);
+ if (IsMappedFan(fanNum))
+ {
+ lastDefaultFanSpeed = f;
+ }
+ }
+ else
+ {
+ // We are processing an M106 S### command with no other recognised parameters and we have a tool selected.
+ // Apply the fan speed setting to the fans in the fan mapping for the current tool.
+ SetMappedFanSpeed(f);
+ }
}
- else
+
+ // ConfigureFan doesn't process R parameters
+ if (gb.Seen('R'))
{
- SetMappedFanSpeed(pausedDefaultFanSpeed);
+ // Restore fan speed to value when print was paused
+ if (seenFanNum)
+ {
+ result = reprap.GetFansManager().SetFanValue(fanNum, pausedFanSpeeds[fanNum], reply);
+ }
+ else
+ {
+ SetMappedFanSpeed(pausedDefaultFanSpeed);
+ }
}
}
- }
- break;
-
- case 107: // Fan off - deprecated
- SetMappedFanSpeed(0.0);
- break;
-
- case 108: // Cancel waiting for temperature
- if (isWaiting)
- {
- cancelWait = true;
- }
- break;
-
- case 109: // Deprecated in RRF, but widely generated by slicers
- if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished
- || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution
- )
- {
- return false;
- }
- UnlockMovement(gb); // allow babystepping and pausing while heating
-
- // no break
- case 104:
- // New behaviour from 1.20beta12:
- // M109 Snnn
- // - If no tools are active, set Tool 0 to active
- // - Set active tool's active and standby temperatures to Snnn
- //
- // M109 Tnnn Snnn
- // - If no tools are active, set Tnnn to active
- // - If another tool is active but Tnnn is off, set Tnnn to standby
- // - Set Tnnn's active and standby temperatures to Snnn
- // M104 does the same but doesn't ever select a tool
- {
- // Get the temperature to set
- float temperature;
- if (gb.Seen('R'))
- {
- gb.MachineState().waitWhileCooling = true;
- temperature = gb.GetFValue();
- }
- else if (gb.Seen('S'))
- {
- gb.MachineState().waitWhileCooling = false;
- temperature = gb.GetFValue();
- }
- else
- {
- break; // no target temperature given
- }
+ break;
- // Find the tool that the command applies to.
- // This is the tool specified in the T parameter, else the current tool if there is one, else the default tool
- Tool *applicableTool;
- if (gb.Seen('T'))
- {
- int toolNumber = gb.GetIValue();
- toolNumber += gb.GetToolNumberAdjust();
- applicableTool = reprap.GetTool(toolNumber);
- }
- else
- {
- applicableTool = reprap.GetCurrentOrDefaultTool();
- }
+ case 107: // Fan off - deprecated
+ SetMappedFanSpeed(0.0);
+ break;
- // Check that we have a tool
- if (applicableTool == nullptr)
+ case 108: // Cancel waiting for temperature
+ if (isWaiting)
{
- reply.copy("Invalid tool number");
- result = GCodeResult::error;
- break;
+ cancelWait = true;
}
+ break;
- // Set the heater temperatures for that tool. We set the standby temperatures as well as the active ones,
- // because any slicer that uses M109 doesn't understand that there are separate active and standby temperatures.
- if (simulationMode == 0)
+ case 109: // Deprecated in RRF, but widely generated by slicers
+ if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished
+ || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution
+ )
{
- SetToolHeaters(applicableTool, temperature, true);
+ return false;
}
-
- Tool * const currentTool = reprap.GetCurrentTool();
- if (code == 109 && currentTool == nullptr)
- {
- // Switch to the tool
- if (!LockMovementAndWaitForStandstill(gb))
+ UnlockMovement(gb); // allow babystepping and pausing while heating
+
+ // no break
+ case 104:
+ // New behaviour from 1.20beta12:
+ // M109 Snnn
+ // - If no tools are active, set Tool 0 to active
+ // - Set active tool's active and standby temperatures to Snnn
+ //
+ // M109 Tnnn Snnn
+ // - If no tools are active, set Tnnn to active
+ // - If another tool is active but Tnnn is off, set Tnnn to standby
+ // - Set Tnnn's active and standby temperatures to Snnn
+ // M104 does the same but doesn't ever select a tool
+ {
+ // Get the temperature to set
+ float temperature;
+ if (gb.Seen('R'))
{
- return false;
+ gb.MachineState().waitWhileCooling = true;
+ temperature = gb.GetFValue();
+ }
+ else if (gb.Seen('S'))
+ {
+ gb.MachineState().waitWhileCooling = false;
+ temperature = gb.GetFValue();
+ }
+ else
+ {
+ break; // no target temperature given
}
- gb.MachineState().newToolNumber = applicableTool->Number();
- gb.MachineState().toolChangeParam = (simulationMode != 0) ? 0 : DefaultToolChangeParam;
- gb.SetState(GCodeState::m109ToolChange0);
- result = GCodeResult::ok;
- }
- else
- {
- if (applicableTool == currentTool)
+ // Find the tool that the command applies to.
+ // This is the tool specified in the T parameter, else the current tool if there is one, else the default tool
+ Tool *applicableTool;
+ if (gb.Seen('T'))
{
- // Even though the tool is selected, we may have turned it off e.g. when upgrading the WiFi firmware or following a heater fault that has been cleared.
- // So make sure the tool heaters are on.
- reprap.SelectTool(applicableTool->Number(), simulationMode != 0);
+ int toolNumber = gb.GetIValue();
+ toolNumber += gb.GetToolNumberAdjust();
+ applicableTool = reprap.GetTool(toolNumber);
}
else
{
- // If we already have an active tool and we are setting temperatures for a different tool, set that tool's heaters to standby in case it is off
- reprap.StandbyTool(applicableTool->Number(), simulationMode != 0);
+ applicableTool = reprap.GetCurrentOrDefaultTool();
+ }
+
+ // Check that we have a tool
+ if (applicableTool == nullptr)
+ {
+ reply.copy("Invalid tool number");
+ result = GCodeResult::error;
+ break;
+ }
+
+ // Set the heater temperatures for that tool. We set the standby temperatures as well as the active ones,
+ // because any slicer that uses M109 doesn't understand that there are separate active and standby temperatures.
+ if (simulationMode == 0)
+ {
+ SetToolHeaters(applicableTool, temperature, true);
}
- if (code == 109 && simulationMode == 0)
+ Tool * const currentTool = reprap.GetCurrentTool();
+ if (code == 109 && currentTool == nullptr)
{
- gb.SetState(GCodeState::m109WaitForTemperature);
+ // Switch to the tool
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+
+ gb.MachineState().newToolNumber = applicableTool->Number();
+ gb.MachineState().toolChangeParam = (simulationMode != 0) ? 0 : DefaultToolChangeParam;
+ gb.SetState(GCodeState::m109ToolChange0);
result = GCodeResult::ok;
}
+ else
+ {
+ if (applicableTool == currentTool)
+ {
+ // Even though the tool is selected, we may have turned it off e.g. when upgrading the WiFi firmware or following a heater fault that has been cleared.
+ // So make sure the tool heaters are on.
+ reprap.SelectTool(applicableTool->Number(), simulationMode != 0);
+ }
+ else
+ {
+ // If we already have an active tool and we are setting temperatures for a different tool, set that tool's heaters to standby in case it is off
+ reprap.StandbyTool(applicableTool->Number(), simulationMode != 0);
+ }
+
+ if (code == 109 && simulationMode == 0)
+ {
+ gb.SetState(GCodeState::m109WaitForTemperature);
+ result = GCodeResult::ok;
+ }
+ }
}
- }
- break;
+ break;
- case 110: // Set line numbers - line numbers are dealt with in the GCodeBuffer class
- break;
+ case 110: // Set line numbers - line numbers are dealt with in the GCodeBuffer class
+ break;
- case 111: // Debug level
- if (gb.Seen('S'))
- {
- const bool dbv = (gb.GetIValue() != 0);
- if (gb.Seen('P'))
- {
- reprap.SetDebug(static_cast<Module>(gb.GetIValue()), dbv);
- reprap.PrintDebug(gb.GetResponseMessageType());
- return true;
- }
- if (dbv)
+ case 111: // Debug level
+ if (gb.Seen('S'))
{
- // Repetier Host sends M111 with various S parameters to enable echo and similar features, which used to turn on all out debugging.
- // But it's not useful to enable all debugging anyway. So we no longer allow debugging to be enabled without a P parameter.
- reply.copy("Use P parameter to specify which module to debug");
+ const bool dbv = (gb.GetIValue() != 0);
+ if (gb.Seen('P'))
+ {
+ reprap.SetDebug(static_cast<Module>(gb.GetIValue()), dbv);
+ reprap.PrintDebug(gb.GetResponseMessageType());
+ return true;
+ }
+ if (dbv)
+ {
+ // Repetier Host sends M111 with various S parameters to enable echo and similar features, which used to turn on all out debugging.
+ // But it's not useful to enable all debugging anyway. So we no longer allow debugging to be enabled without a P parameter.
+ reply.copy("Use P parameter to specify which module to debug");
+ }
+ else
+ {
+ // M111 S0 still clears all debugging
+ reprap.ClearDebug();
+ }
}
else
{
- // M111 S0 still clears all debugging
- reprap.ClearDebug();
+ reprap.PrintDebug(gb.GetResponseMessageType());
+ return true;
}
- }
- else
- {
- reprap.PrintDebug(gb.GetResponseMessageType());
- return true;
- }
- break;
+ break;
- case 112: // Emergency stop - acted upon in Webserver, but also here in case it comes from USB etc.
- DoEmergencyStop();
- break;
+ case 112: // Emergency stop - acted upon in Webserver, but also here in case it comes from USB etc.
+ DoEmergencyStop();
+ break;
- case 114:
- GetCurrentCoordinates(reply);
- break;
+ case 114:
+ GetCurrentCoordinates(reply);
+ break;
- case 115: // Print firmware version or set hardware type
+ case 115: // Print firmware version or set hardware type
#if defined(DUET_NG) || defined(DUET_06_85)
- if (gb.Seen('P'))
- {
- if (runningConfigFile)
+ if (gb.Seen('P'))
{
- platform.SetBoardType((BoardType)gb.GetIValue());
+ if (runningConfigFile)
+ {
+ platform.SetBoardType((BoardType)gb.GetIValue());
+ }
+ else
+ {
+ reply.copy("Board type can only be set within config.g");
+ result = GCodeResult::error;
+ }
}
else
- {
- reply.copy("Board type can only be set within config.g");
- result = GCodeResult::error;
- }
- }
- else
#endif
- {
-#if SUPPORT_CAN_EXPANSION
- if (gb.Seen('B'))
{
- const uint32_t board = gb.GetUIValue();
- if (board != CanId::MasterAddress)
+#if SUPPORT_CAN_EXPANSION
+ if (gb.Seen('B'))
{
- result = CanInterface::GetRemoteFirmwareDetails(board, gb, reply);
- break;
+ const uint32_t board = gb.GetUIValue();
+ if (board != CanId::MasterAddress)
+ {
+ result = CanInterface::GetRemoteFirmwareDetails(board, gb, reply);
+ break;
+ }
}
- }
#endif
- reply.printf("FIRMWARE_NAME: %s FIRMWARE_VERSION: %s ELECTRONICS: %s", FIRMWARE_NAME, VERSION, platform.GetElectronicsString());
+ reply.printf("FIRMWARE_NAME: %s FIRMWARE_VERSION: %s ELECTRONICS: %s", FIRMWARE_NAME, VERSION, platform.GetElectronicsString());
#ifdef DUET_NG
- const char* const expansionName = DuetExpansion::GetExpansionBoardName();
- if (expansionName != nullptr)
- {
- reply.catf(" + %s", expansionName);
- }
- const char* const additionalExpansionName = DuetExpansion::GetAdditionalExpansionBoardName();
- if (additionalExpansionName != nullptr)
- {
- reply.catf(" + %s", additionalExpansionName);
- }
-#endif
- reply.catf(" FIRMWARE_DATE: %s", DATE);
- }
- break;
-
- case 116: // Wait for set temperatures
- if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished
- || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution
- )
- {
- return false;
- }
-
- if (!cancelWait)
- {
- const float tolerance = (gb.Seen('S')) ? max<float>(gb.GetFValue(), 0.1) : TEMPERATURE_CLOSE_ENOUGH;
- bool seen = false;
- if (gb.Seen('P'))
- {
- // Wait for the heaters associated with the specified tool to be ready
- int toolNumber = gb.GetIValue();
- toolNumber += gb.GetToolNumberAdjust();
- if (!ToolHeatersAtSetTemperatures(reprap.GetTool(toolNumber), true, tolerance))
+ const char* const expansionName = DuetExpansion::GetExpansionBoardName();
+ if (expansionName != nullptr)
{
- CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
- isWaiting = true;
- return false;
+ reply.catf(" + %s", expansionName);
+ }
+ const char* const additionalExpansionName = DuetExpansion::GetAdditionalExpansionBoardName();
+ if (additionalExpansionName != nullptr)
+ {
+ reply.catf(" + %s", additionalExpansionName);
}
- seen = true;
+#endif
+ reply.catf(" FIRMWARE_DATE: %s", DATE);
}
+ break;
- if (gb.Seen('H'))
+ case 116: // Wait for set temperatures
+ if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished
+ || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution
+ )
{
- // Wait for specified heaters to be ready
- uint32_t heaters[MaxHeaters];
- size_t heaterCount = MaxHeaters;
- gb.GetUnsignedArray(heaters, heaterCount, false);
+ return false;
+ }
- for (size_t i = 0; i < heaterCount; i++)
+ if (!cancelWait)
+ {
+ const float tolerance = (gb.Seen('S')) ? max<float>(gb.GetFValue(), 0.1) : TEMPERATURE_CLOSE_ENOUGH;
+ bool seen = false;
+ if (gb.Seen('P'))
{
- if (!reprap.GetHeat().HeaterAtSetTemperature(heaters[i], true, tolerance))
+ // Wait for the heaters associated with the specified tool to be ready
+ int toolNumber = gb.GetIValue();
+ toolNumber += gb.GetToolNumberAdjust();
+ if (!ToolHeatersAtSetTemperatures(reprap.GetTool(toolNumber), true, tolerance))
{
- CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
+ CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
isWaiting = true;
return false;
}
+ seen = true;
}
- seen = true;
- }
- if (gb.Seen('C'))
- {
- // Wait for specified chamber(s) to be ready
- uint32_t chamberIndices[MaxChamberHeaters];
- size_t chamberCount = MaxChamberHeaters;
- gb.GetUnsignedArray(chamberIndices, chamberCount, false);
-
- if (chamberCount == 0)
+ if (gb.Seen('H'))
{
- // If no values are specified, wait for all chamber heaters
- for (size_t i = 0; i < MaxChamberHeaters; i++)
+ // Wait for specified heaters to be ready
+ uint32_t heaters[MaxHeaters];
+ size_t heaterCount = MaxHeaters;
+ gb.GetUnsignedArray(heaters, heaterCount, false);
+
+ for (size_t i = 0; i < heaterCount; i++)
{
- const int8_t heater = reprap.GetHeat().GetChamberHeater(i);
- if (heater >= 0 && !reprap.GetHeat().HeaterAtSetTemperature(heater, true, tolerance))
+ if (!reprap.GetHeat().HeaterAtSetTemperature(heaters[i], true, tolerance))
{
- CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
+ CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
isWaiting = true;
return false;
}
}
+ seen = true;
}
- else
+
+ if (gb.Seen('C'))
{
- // Otherwise wait only for the specified chamber heaters
- for (size_t i = 0; i < chamberCount; i++)
+ // Wait for specified chamber(s) to be ready
+ uint32_t chamberIndices[MaxChamberHeaters];
+ size_t chamberCount = MaxChamberHeaters;
+ gb.GetUnsignedArray(chamberIndices, chamberCount, false);
+
+ if (chamberCount == 0)
{
- if (chamberIndices[i] >= 0 && chamberIndices[i] < MaxChamberHeaters)
+ // If no values are specified, wait for all chamber heaters
+ for (size_t i = 0; i < MaxChamberHeaters; i++)
{
- const int8_t heater = reprap.GetHeat().GetChamberHeater(chamberIndices[i]);
+ const int8_t heater = reprap.GetHeat().GetChamberHeater(i);
if (heater >= 0 && !reprap.GetHeat().HeaterAtSetTemperature(heater, true, tolerance))
{
- CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
+ CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
isWaiting = true;
return false;
}
}
}
+ else
+ {
+ // Otherwise wait only for the specified chamber heaters
+ for (size_t i = 0; i < chamberCount; i++)
+ {
+ if (chamberIndices[i] >= 0 && chamberIndices[i] < MaxChamberHeaters)
+ {
+ const int8_t heater = reprap.GetHeat().GetChamberHeater(chamberIndices[i]);
+ if (heater >= 0 && !reprap.GetHeat().HeaterAtSetTemperature(heater, true, tolerance))
+ {
+ CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
+ isWaiting = true;
+ return false;
+ }
+ }
+ }
+ }
+ seen = true;
}
- seen = true;
- }
- // Wait for all heaters except chamber(s) to be ready
- if (!seen && !reprap.GetHeat().AllHeatersAtSetTemperatures(true, tolerance))
- {
- CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
- isWaiting = true;
- return false;
+ // Wait for all heaters except chamber(s) to be ready
+ if (!seen && !reprap.GetHeat().AllHeatersAtSetTemperatures(true, tolerance))
+ {
+ CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
+ isWaiting = true;
+ return false;
+ }
}
- }
-
- // If we get here, there is nothing more to wait for
- cancelWait = isWaiting = false;
- break;
- case 117: // Display message
- {
- String<MediumStringLength> msg;
- gb.GetUnprecedentedString(msg.GetRef());
- reprap.SetMessage(msg.c_str());
- }
- break;
+ // If we get here, there is nothing more to wait for
+ cancelWait = isWaiting = false;
+ break;
- case 118: // Echo message on host
- {
- MessageType type = GenericMessage;
- if (gb.Seen('P'))
+ case 117: // Display message
{
- const int32_t param = gb.GetIValue();
- switch (param)
- {
- case 0: // Generic (default)
- // no need to set it twice
- break;
- case 1: // USB
- type = UsbMessage;
- break;
- case 2: // UART port
- type = DirectAuxMessage;
- break;
- case 3: // HTTP
- type = HttpMessage;
- break;
- case 4: // Telnet
- type = TelnetMessage;
- break;
- default:
- reply.printf("Invalid message type: %" PRIi32, param);
- result = GCodeResult::error;
- break;
- }
+ String<MediumStringLength> msg;
+ gb.GetUnprecedentedString(msg.GetRef());
+ reprap.SetMessage(msg.c_str());
}
+ break;
- if (result != GCodeResult::error && gb.Seen(('S')))
+ case 118: // Echo message on host
{
- String<GCODE_LENGTH> message;
- gb.GetQuotedString(message.GetRef());
- if (type != HttpMessage)
+ MessageType type = GenericMessage;
+ if (gb.Seen('P'))
{
- platform.Message((MessageType)(type | PushFlag), message.c_str());
- platform.Message(type, "\n");
+ const int32_t param = gb.GetIValue();
+ switch (param)
+ {
+ case 0: // Generic (default)
+ // no need to set it twice
+ break;
+ case 1: // USB
+ type = UsbMessage;
+ break;
+ case 2: // UART port
+ type = DirectAuxMessage;
+ break;
+ case 3: // HTTP
+ type = HttpMessage;
+ break;
+ case 4: // Telnet
+ type = TelnetMessage;
+ break;
+ default:
+ reply.printf("Invalid message type: %" PRIi32, param);
+ result = GCodeResult::error;
+ break;
+ }
}
- else
+
+ if (result != GCodeResult::error && gb.Seen(('S')))
{
- platform.Message(type, message.c_str());
+ String<GCODE_LENGTH> message;
+ gb.GetQuotedString(message.GetRef());
+ if (type != HttpMessage)
+ {
+ platform.Message((MessageType)(type | PushFlag), message.c_str());
+ platform.Message(type, "\n");
+ }
+ else
+ {
+ platform.Message(type, message.c_str());
+ }
}
}
- }
- break;
+ break;
- case 119:
- platform.GetEndstops().GetM119report(reply);
- break;
+ case 119:
+ platform.GetEndstops().GetM119report(reply);
+ break;
- case 120:
- Push(gb, true);
- break;
+ case 120:
+ Push(gb, true);
+ break;
- case 121:
- Pop(gb, true);
- break;
+ case 121:
+ Pop(gb, true);
+ break;
- case 122:
- {
- const unsigned int type = (gb.Seen('P')) ? gb.GetIValue() : 0;
- const MessageType mt = (MessageType)(gb.GetResponseMessageType() | PushFlag);
-#if SUPPORT_CAN_EXPANSION
- const uint32_t board = (gb.Seen('B')) ? gb.GetUIValue() : 0;
- if (board != CanId::MasterAddress)
+ case 122:
{
- result = CanInterface::RemoteDiagnostics(mt, board, type, gb, reply);
- break;
- }
+ const unsigned int type = (gb.Seen('P')) ? gb.GetIValue() : 0;
+ const MessageType mt = (MessageType)(gb.GetResponseMessageType() | PushFlag);
+#if SUPPORT_CAN_EXPANSION
+ const uint32_t board = (gb.Seen('B')) ? gb.GetUIValue() : 0;
+ if (board != CanId::MasterAddress)
+ {
+ result = CanInterface::RemoteDiagnostics(mt, board, type, gb, reply);
+ break;
+ }
#endif
- if (type == 0)
- {
- // Set the Push flag to combine multiple messages into a single OutputBuffer chain
- reprap.Diagnostics(mt);
- }
- else
- {
- result = platform.DiagnosticTest(gb, reply, type);
+ if (type == 0)
+ {
+ // Set the Push flag to combine multiple messages into a single OutputBuffer chain
+ reprap.Diagnostics(mt);
+ }
+ else
+ {
+ result = platform.DiagnosticTest(gb, reply, type);
+ }
}
- }
- break;
-
- // M135 (set PID sample interval) is no longer supported
+ break;
- case 140: // Bed temperature
- case 141: // Chamber temperature
- {
- Heat& heat = reprap.GetHeat();
- bool seen = false;
+ // M135 (set PID sample interval) is no longer supported
- // Check if the heater index is passed
- int index = gb.Seen('P') ? gb.GetIValue() : 0;
- if (index < 0 || index >= (int)((code == 140) ? MaxBedHeaters : MaxChamberHeaters))
+ case 140: // Bed temperature
+ case 141: // Chamber temperature
{
- reply.printf("Invalid heater index '%d'", index);
- result = GCodeResult::error;
- break;
- }
+ Heat& heat = reprap.GetHeat();
+ bool seen = false;
- // See if the heater number is being set
- if (gb.Seen('H'))
- {
- seen = true;
- int heater = gb.GetIValue();
- if (heater < 0)
+ // Check if the heater index is passed
+ int index = gb.Seen('P') ? gb.GetIValue() : 0;
+ if (index < 0 || index >= (int)((code == 140) ? MaxBedHeaters : MaxChamberHeaters))
{
- heater = -1;
- }
- else if (heater >= (int)MaxHeaters)
- {
- reply.printf("Invalid heater number '%d'", heater);
+ reply.printf("Invalid heater index '%d'", index);
result = GCodeResult::error;
break;
}
- if (code == 141)
+ // See if the heater number is being set
+ if (gb.Seen('H'))
{
- heat.SetChamberHeater(index, heater);
+ seen = true;
+ int heater = gb.GetIValue();
+ if (heater < 0)
+ {
+ heater = -1;
+ }
+ else if (heater >= (int)MaxHeaters)
+ {
+ reply.printf("Invalid heater number '%d'", heater);
+ result = GCodeResult::error;
+ break;
+ }
+
+ if (code == 141)
+ {
+ heat.SetChamberHeater(index, heater);
+ }
+ else
+ {
+ heat.SetBedHeater(index, heater);
+ }
+ platform.UpdateConfiguredHeaters();
}
- else
+
+ const int8_t currentHeater = (code == 141) ? heat.GetChamberHeater(index) : heat.GetBedHeater(index);
+ const char* const heaterName = (code == 141) ? "chamber" : "bed";
+
+ // Active temperature
+ if (gb.Seen('S'))
{
- heat.SetBedHeater(index, heater);
+ seen = true;
+ const float temperature = gb.GetFValue();
+ if (currentHeater < 0)
+ {
+ if (temperature > 0.0) // turning off a non-existent bed or chamber heater is not an error
+ {
+ reply.printf("No %s heater has been configured for slot %d", heaterName, index);
+ result = GCodeResult::error;
+ }
+ }
+ else
+ {
+ if (temperature < NEARLY_ABS_ZERO)
+ {
+ heat.SwitchOff(currentHeater);
+ }
+ else
+ {
+ heat.SetActiveTemperature(currentHeater, temperature);
+ result = heat.Activate(currentHeater, reply);
+ }
+ }
}
- platform.UpdateConfiguredHeaters();
- }
-
- const int8_t currentHeater = (code == 141) ? heat.GetChamberHeater(index) : heat.GetBedHeater(index);
- const char* const heaterName = (code == 141) ? "chamber" : "bed";
- // Active temperature
- if (gb.Seen('S'))
- {
- seen = true;
- const float temperature = gb.GetFValue();
- if (currentHeater < 0)
+ // Standby temperature
+ if (gb.Seen('R'))
{
- if (temperature > 0.0) // turning off a non-existent bed or chamber heater is not an error
+ seen = true;
+ if (currentHeater < 0)
{
reply.printf("No %s heater has been configured for slot %d", heaterName, index);
result = GCodeResult::error;
}
+ else
+ {
+ heat.SetStandbyTemperature(currentHeater, gb.GetFValue());
+ }
}
- else
+
+ if (!seen)
{
- if (temperature < NEARLY_ABS_ZERO)
+ if (currentHeater < 0)
{
- heat.SwitchOff(currentHeater);
+ reply.printf("No %s heater has been configured for slot %d", heaterName, index);
}
else
{
- heat.SetActiveTemperature(currentHeater, temperature);
- result = heat.Activate(currentHeater, reply);
+ reply.printf("%c%s heater %d (slot %d) is currently at %.1f" DEGREE_SYMBOL "C",
+ toupper(heaterName[0]), heaterName + 1, currentHeater, index, (double)reprap.GetHeat().GetHeaterTemperature(currentHeater));
}
}
}
+ break;
- // Standby temperature
- if (gb.Seen('R'))
+ case 143: // Configure heater protection
+ result = reprap.GetHeat().SetHeaterProtection(gb, reply);
+ break;
+
+ case 144: // Set bed to standby, or to active if S1 parameter given
{
- seen = true;
- if (currentHeater < 0)
+ const unsigned int index = gb.Seen('P') ? gb.GetUIValue() : 0;
+ if (index >= MaxBedHeaters)
{
- reply.printf("No %s heater has been configured for slot %d", heaterName, index);
+ reply.printf("Invalid bed heater index '%u'", index);
result = GCodeResult::error;
+ break;
}
- else
- {
- heat.SetStandbyTemperature(currentHeater, gb.GetFValue());
- }
- }
- if (!seen)
- {
- if (currentHeater < 0)
- {
- reply.printf("No %s heater has been configured for slot %d", heaterName, index);
- }
- else
+ const int8_t bedHeater = reprap.GetHeat().GetBedHeater(index);
+ if (bedHeater >= 0)
{
- reply.printf("%c%s heater %d (slot %d) is currently at %.1f" DEGREE_SYMBOL "C",
- toupper(heaterName[0]), heaterName + 1, currentHeater, index, (double)reprap.GetHeat().GetHeaterTemperature(currentHeater));
+ if (gb.Seen('S') && gb.GetIValue() == 1)
+ {
+ result = reprap.GetHeat().Activate(bedHeater, reply);
+ }
+ else
+ {
+ reprap.GetHeat().Standby(bedHeater, nullptr);
+ }
}
}
- }
- break;
+ break;
- case 143: // Configure heater protection
- result = reprap.GetHeat().SetHeaterProtection(gb, reply);
- break;
+#if SUPPORT_DOTSTAR_LED
+ case 150:
+ result = DotStarLed::SetColours(gb, reply);
+ break;
+#endif
- case 144: // Set bed to standby, or to active if S1 parameter given
- {
- const unsigned int index = gb.Seen('P') ? gb.GetUIValue() : 0;
- if (index >= MaxBedHeaters)
+ case 190: // Set bed temperature and wait
+ case 191: // Set chamber temperature and wait
+ if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished
+ || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution
+ )
{
- reply.printf("Invalid bed heater index '%u'", index);
- result = GCodeResult::error;
- break;
+ return false;
}
- const int8_t bedHeater = reprap.GetHeat().GetBedHeater(index);
- if (bedHeater >= 0)
+ UnlockMovement(gb); // allow babystepping and pausing while heating
{
- if (gb.Seen('S') && gb.GetIValue() == 1)
+ // Check if the heater index is passed
+ const uint32_t index = gb.Seen('P') ? gb.GetUIValue() : 0;
+ if (index >= ((code == 190) ? MaxBedHeaters : MaxChamberHeaters))
{
- result = reprap.GetHeat().Activate(bedHeater, reply);
- }
- else
- {
- reprap.GetHeat().Standby(bedHeater, nullptr);
+ reply.printf("Invalid heater index '%" PRIu32 "'", index);
+ result = GCodeResult::error;
+ break;
}
- }
- }
- break;
-#if SUPPORT_DOTSTAR_LED
- case 150:
- result = DotStarLed::SetColours(gb, reply);
- break;
-#endif
+ const int8_t heater = (code == 191) ? reprap.GetHeat().GetChamberHeater(index) : reprap.GetHeat().GetBedHeater(index);
+ if (heater >= 0)
+ {
+ float temperature;
+ bool waitWhenCooling;
+ if (gb.Seen('R'))
+ {
+ waitWhenCooling = true;
+ temperature = gb.GetFValue();
+ }
+ else if (gb.Seen('S'))
+ {
+ waitWhenCooling = false;
+ temperature = gb.GetFValue();
+ }
+ else
+ {
+ break; // no target temperature given
+ }
- case 190: // Set bed temperature and wait
- case 191: // Set chamber temperature and wait
- if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished
- || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution
- )
- {
- return false;
- }
+ reprap.GetHeat().SetActiveTemperature(heater, temperature);
+ result = reprap.GetHeat().Activate(heater, reply);
+ if (cancelWait || reprap.GetHeat().HeaterAtSetTemperature(heater, waitWhenCooling, TEMPERATURE_CLOSE_ENOUGH))
+ {
+ cancelWait = isWaiting = false;
+ break;
+ }
- UnlockMovement(gb); // allow babystepping and pausing while heating
- {
- // Check if the heater index is passed
- const uint32_t index = gb.Seen('P') ? gb.GetUIValue() : 0;
- if (index >= ((code == 190) ? MaxBedHeaters : MaxChamberHeaters))
- {
- reply.printf("Invalid heater index '%" PRIu32 "'", index);
- result = GCodeResult::error;
- break;
+ CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
+ isWaiting = true;
+ return false;
+ }
}
+ break;
- const int8_t heater = (code == 191) ? reprap.GetHeat().GetChamberHeater(index) : reprap.GetHeat().GetBedHeater(index);
- if (heater >= 0)
+ case 200: // Set filament diameter for volumetric extrusion and enable/disable volumetric extrusion
+ if (gb.Seen('D'))
{
- float temperature;
- bool waitWhenCooling;
- if (gb.Seen('R'))
+ float diameters[MaxExtruders];
+ size_t len = MaxExtruders;
+ gb.GetFloatArray(diameters, len, true);
+ for (size_t i = 0; i < len; ++i)
{
- waitWhenCooling = true;
- temperature = gb.GetFValue();
+ const float d = diameters[i];
+ volumetricExtrusionFactors[i] = (d <= 0.0) ? 1.0 : 4.0/(fsquare(d) * Pi);
}
- else if (gb.Seen('S'))
- {
- waitWhenCooling = false;
- temperature = gb.GetFValue();
- }
- else
- {
- break; // no target temperature given
- }
-
- reprap.GetHeat().SetActiveTemperature(heater, temperature);
- result = reprap.GetHeat().Activate(heater, reply);
- if (cancelWait || reprap.GetHeat().HeaterAtSetTemperature(heater, waitWhenCooling, TEMPERATURE_CLOSE_ENOUGH))
- {
- cancelWait = isWaiting = false;
- break;
- }
-
- CheckReportDue(gb, reply); // check whether we need to send a temperature or status report
- isWaiting = true;
- return false;
+ gb.MachineState().volumetricExtrusion = (diameters[0] > 0.0);
}
- }
- break;
-
- case 200: // Set filament diameter for volumetric extrusion and enable/disable volumetric extrusion
- if (gb.Seen('D'))
- {
- float diameters[MaxExtruders];
- size_t len = MaxExtruders;
- gb.GetFloatArray(diameters, len, true);
- for (size_t i = 0; i < len; ++i)
+ else if (!gb.MachineState().volumetricExtrusion)
{
- const float d = diameters[i];
- volumetricExtrusionFactors[i] = (d <= 0.0) ? 1.0 : 4.0/(fsquare(d) * Pi);
+ reply.copy("Volumetric extrusion is disabled for this input source");
}
- gb.MachineState().volumetricExtrusion = (diameters[0] > 0.0);
- }
- else if (!gb.MachineState().volumetricExtrusion)
- {
- reply.copy("Volumetric extrusion is disabled for this input source");
- }
- else
- {
- reply.copy("Filament diameters for volumetric extrusion:");
- for (size_t i = 0; i < numExtruders; ++i)
+ else
{
- const float vef = volumetricExtrusionFactors[i];
- if (vef == 1.0)
- {
- reply.cat(" n/a");
- }
- else
+ reply.copy("Filament diameters for volumetric extrusion:");
+ for (size_t i = 0; i < numExtruders; ++i)
{
- reply.catf(" %.03f", (double)(2.0/sqrtf(vef * Pi)));
+ const float vef = volumetricExtrusionFactors[i];
+ if (vef == 1.0)
+ {
+ reply.cat(" n/a");
+ }
+ else
+ {
+ reply.catf(" %.03f", (double)(2.0/sqrtf(vef * Pi)));
+ }
}
}
- }
- break;
+ break;
- case 201: // Set/print axis accelerations
- {
- bool seen = false;
- for (size_t axis = 0; axis < numTotalAxes; axis++)
+ case 201: // Set/print axis accelerations
{
- if (gb.Seen(axisLetters[axis]))
+ bool seen = false;
+ for (size_t axis = 0; axis < numTotalAxes; axis++)
{
- platform.SetAcceleration(axis, gb.GetDistance());
- seen = true;
+ if (gb.Seen(axisLetters[axis]))
+ {
+ platform.SetAcceleration(axis, gb.GetDistance());
+ seen = true;
+ }
}
- }
- if (gb.Seen(extrudeLetter))
- {
- seen = true;
- float eVals[MaxExtruders];
- size_t eCount = numExtruders;
- gb.GetFloatArray(eVals, eCount, true);
- for (size_t e = 0; e < eCount; e++)
+ if (gb.Seen(extrudeLetter))
{
- platform.SetAcceleration(ExtruderToLogicalDrive(e), gb.ConvertDistance(eVals[e]));
+ seen = true;
+ float eVals[MaxExtruders];
+ size_t eCount = numExtruders;
+ gb.GetFloatArray(eVals, eCount, true);
+ for (size_t e = 0; e < eCount; e++)
+ {
+ platform.SetAcceleration(ExtruderToLogicalDrive(e), gb.ConvertDistance(eVals[e]));
+ }
}
- }
- if (!seen)
- {
- reply.printf("Accelerations (mm/sec^2): ");
- for (size_t axis = 0; axis < numTotalAxes; ++axis)
- {
- reply.catf("%c: %.1f, ", axisLetters[axis], (double)platform.Acceleration(axis));
- }
- reply.cat("E:");
- char sep = ' ';
- for (size_t extruder = 0; extruder < numExtruders; extruder++)
+ if (!seen)
{
- reply.catf("%c%.1f", sep, (double)platform.Acceleration(ExtruderToLogicalDrive(extruder)));
- sep = ':';
+ reply.printf("Accelerations (mm/sec^2): ");
+ for (size_t axis = 0; axis < numTotalAxes; ++axis)
+ {
+ reply.catf("%c: %.1f, ", axisLetters[axis], (double)platform.Acceleration(axis));
+ }
+ reply.cat("E:");
+ char sep = ' ';
+ for (size_t extruder = 0; extruder < numExtruders; extruder++)
+ {
+ reply.catf("%c%.1f", sep, (double)platform.Acceleration(ExtruderToLogicalDrive(extruder)));
+ sep = ':';
+ }
}
}
- }
- break;
-
- case 203: // Set/print minimum/maximum feedrates
- {
- bool seen = false;
+ break;
- // Do the minimum first, because we constrain the maximum rates to be no lower than it
- if (gb.Seen('I'))
+ case 203: // Set/print minimum/maximum feedrates
{
- seen = true;
- platform.SetMinMovementSpeed(gb.GetDistance() * SecondsToMinutes);
- }
+ bool seen = false;
- for (size_t axis = 0; axis < numTotalAxes; ++axis)
- {
- if (gb.Seen(axisLetters[axis]))
+ // Do the minimum first, because we constrain the maximum rates to be no lower than it
+ if (gb.Seen('I'))
{
seen = true;
- platform.SetMaxFeedrate(axis, gb.GetDistance() * SecondsToMinutes);
+ platform.SetMinMovementSpeed(gb.GetDistance() * SecondsToMinutes);
}
- }
- if (gb.Seen(extrudeLetter))
- {
- seen = true;
- float eVals[MaxExtruders];
- size_t eCount = numExtruders;
- gb.GetFloatArray(eVals, eCount, true);
- for (size_t e = 0; e < eCount; e++)
+ for (size_t axis = 0; axis < numTotalAxes; ++axis)
{
- platform.SetMaxFeedrate(ExtruderToLogicalDrive(e), gb.ConvertDistance(eVals[e]) * SecondsToMinutes);
+ if (gb.Seen(axisLetters[axis]))
+ {
+ seen = true;
+ platform.SetMaxFeedrate(axis, gb.GetDistance() * SecondsToMinutes);
+ }
}
- }
- if (!seen)
- {
- reply.copy("Max speeds (mm/sec): ");
- for (size_t axis = 0; axis < numTotalAxes; ++axis)
+ if (gb.Seen(extrudeLetter))
{
- reply.catf("%c: %.1f, ", axisLetters[axis], (double)platform.MaxFeedrate(axis));
+ seen = true;
+ float eVals[MaxExtruders];
+ size_t eCount = numExtruders;
+ gb.GetFloatArray(eVals, eCount, true);
+ for (size_t e = 0; e < eCount; e++)
+ {
+ platform.SetMaxFeedrate(ExtruderToLogicalDrive(e), gb.ConvertDistance(eVals[e]) * SecondsToMinutes);
+ }
}
- reply.cat("E:");
- char sep = ' ';
- for (size_t extruder = 0; extruder < numExtruders; extruder++)
+
+ if (!seen)
{
- reply.catf("%c%.1f", sep, (double)platform.MaxFeedrate(ExtruderToLogicalDrive(extruder)));
- sep = ':';
+ reply.copy("Max speeds (mm/sec): ");
+ for (size_t axis = 0; axis < numTotalAxes; ++axis)
+ {
+ reply.catf("%c: %.1f, ", axisLetters[axis], (double)platform.MaxFeedrate(axis));
+ }
+ reply.cat("E:");
+ char sep = ' ';
+ for (size_t extruder = 0; extruder < numExtruders; extruder++)
+ {
+ reply.catf("%c%.1f", sep, (double)platform.MaxFeedrate(ExtruderToLogicalDrive(extruder)));
+ sep = ':';
+ }
+ reply.catf(", min. speed %.2f", (double)platform.MinMovementSpeed());
}
- reply.catf(", min. speed %.2f", (double)platform.MinMovementSpeed());
}
- }
- break;
+ break;
- case 204: // Set max travel and printing accelerations
- result = reprap.GetMove().ConfigureAccelerations(gb, reply);
- break;
+ case 204: // Set max travel and printing accelerations
+ result = reprap.GetMove().ConfigureAccelerations(gb, reply);
+ break;
- // For case 205 see case 566
+ // For case 205 see case 566
- case 206: // Offset axes
- result = OffsetAxes(gb, reply);
- break;
+ case 206: // Offset axes
+ result = OffsetAxes(gb, reply);
+ break;
- case 207: // Set firmware retraction details
- {
- bool seen = false;
- if (gb.Seen('S'))
- {
- retractLength = max<float>(gb.GetFValue(), 0.0);
- seen = true;
- }
- if (gb.Seen('R')) // must do this one after 'S'
+ case 207: // Set firmware retraction details
{
- retractExtra = max<float>(gb.GetFValue(), -retractLength);
- seen = true;
- }
- if (gb.Seen('F'))
- {
- unRetractSpeed = retractSpeed = max<float>(gb.GetFValue(), 60.0) * SecondsToMinutes;
- seen = true;
- }
- if (gb.Seen('T')) // must do this one after 'F'
- {
- unRetractSpeed = max<float>(gb.GetFValue(), 60.0) * SecondsToMinutes;
- seen = true;
- }
- if (gb.Seen('Z'))
- {
- retractHop = max<float>(gb.GetFValue(), 0.0);
- seen = true;
- }
- if (!seen)
- {
- reply.printf("Retraction/un-retraction settings: length %.2f/%.2fmm, speed %d/%dmm/min, Z hop %.2fmm",
- (double)retractLength, (double)(retractLength + retractExtra), (int)(retractSpeed * MinutesToSeconds), (int)(unRetractSpeed * MinutesToSeconds), (double)retractHop);
+ bool seen = false;
+ if (gb.Seen('S'))
+ {
+ retractLength = max<float>(gb.GetFValue(), 0.0);
+ seen = true;
+ }
+ if (gb.Seen('R')) // must do this one after 'S'
+ {
+ retractExtra = max<float>(gb.GetFValue(), -retractLength);
+ seen = true;
+ }
+ if (gb.Seen('F'))
+ {
+ unRetractSpeed = retractSpeed = max<float>(gb.GetFValue(), 60.0) * SecondsToMinutes;
+ seen = true;
+ }
+ if (gb.Seen('T')) // must do this one after 'F'
+ {
+ unRetractSpeed = max<float>(gb.GetFValue(), 60.0) * SecondsToMinutes;
+ seen = true;
+ }
+ if (gb.Seen('Z'))
+ {
+ retractHop = max<float>(gb.GetFValue(), 0.0);
+ seen = true;
+ }
+ if (!seen)
+ {
+ reply.printf("Retraction/un-retraction settings: length %.2f/%.2fmm, speed %d/%dmm/min, Z hop %.2fmm",
+ (double)retractLength, (double)(retractLength + retractExtra), (int)(retractSpeed * MinutesToSeconds), (int)(unRetractSpeed * MinutesToSeconds), (double)retractHop);
+ }
}
- }
- break;
+ break;
- case 208: // Set/print maximum axis lengths. If there is an S parameter with value 1 then we set the min value, else we set the max value.
- {
- bool setMin = (gb.Seen('S') ? (gb.GetIValue() == 1) : false);
- bool seen = false;
- for (size_t axis = 0; axis < numTotalAxes; axis++)
+ case 208: // Set/print maximum axis lengths. If there is an S parameter with value 1 then we set the min value, else we set the max value.
{
- if (gb.Seen(axisLetters[axis]))
+ bool setMin = (gb.Seen('S') ? (gb.GetIValue() == 1) : false);
+ bool seen = false;
+ for (size_t axis = 0; axis < numTotalAxes; axis++)
{
- seen = true;
- float values[2];
- size_t numValues = 2;
- gb.GetFloatArray(values, numValues, false);
- bool ok;
- if (numValues == 2)
- {
- ok = values[1] > values[0];
- if (ok)
+ if (gb.Seen(axisLetters[axis]))
+ {
+ seen = true;
+ float values[2];
+ size_t numValues = 2;
+ gb.GetFloatArray(values, numValues, false);
+ bool ok;
+ if (numValues == 2)
{
- platform.SetAxisMinimum(axis, values[0], gb.MachineState().runningM501);
- platform.SetAxisMaximum(axis, values[1], gb.MachineState().runningM501);
+ ok = values[1] > values[0];
+ if (ok)
+ {
+ platform.SetAxisMinimum(axis, values[0], gb.MachineState().runningM501);
+ platform.SetAxisMaximum(axis, values[1], gb.MachineState().runningM501);
+ }
}
- }
- else if (setMin)
- {
- ok = platform.AxisMaximum(axis) > values[0];
- if (ok)
+ else if (setMin)
{
- platform.SetAxisMinimum(axis, values[0], gb.MachineState().runningM501);
+ ok = platform.AxisMaximum(axis) > values[0];
+ if (ok)
+ {
+ platform.SetAxisMinimum(axis, values[0], gb.MachineState().runningM501);
+ }
}
- }
- else
- {
- ok = values[0] > platform.AxisMinimum(axis);
- if (ok)
+ else
{
- platform.SetAxisMaximum(axis, values[0], gb.MachineState().runningM501);
+ ok = values[0] > platform.AxisMinimum(axis);
+ if (ok)
+ {
+ platform.SetAxisMaximum(axis, values[0], gb.MachineState().runningM501);
+ }
}
- }
- if (!ok)
- {
- reply.printf("%c axis maximum must be greater than minimum", axisLetters[axis]);
- result = GCodeResult::error;
+ if (!ok)
+ {
+ reply.printf("%c axis maximum must be greater than minimum", axisLetters[axis]);
+ result = GCodeResult::error;
+ }
}
}
- }
- if (!seen)
- {
- reply.copy("Axis limit");
- char sep = 's';
- for (size_t axis = 0; axis < numTotalAxes; axis++)
+ if (!seen)
{
- reply.catf("%c %c%.1f:%.1f", sep, axisLetters[axis], (double)platform.AxisMinimum(axis), (double)platform.AxisMaximum(axis));
- sep = ',';
+ reply.copy("Axis limit");
+ char sep = 's';
+ for (size_t axis = 0; axis < numTotalAxes; axis++)
+ {
+ reply.catf("%c %c%.1f:%.1f", sep, axisLetters[axis], (double)platform.AxisMinimum(axis), (double)platform.AxisMaximum(axis));
+ sep = ',';
+ }
}
}
- }
- break;
+ break;
- case 210: // Set/print homing feed rates
- // This is no longer used, but for backwards compatibility we don't report an error
- break;
+ case 210: // Set/print homing feed rates
+ // This is no longer used, but for backwards compatibility we don't report an error
+ break;
- case 220: // Set/report speed factor override percentage
- if (gb.Seen('S'))
- {
- float newSpeedFactor = gb.GetFValue();
- if (newSpeedFactor >= 1.0)
+ case 220: // Set/report speed factor override percentage
+ if (gb.Seen('S'))
{
- // Update the feed rate for ALL input sources, and all feed rates on the stack
- const float speedFactorRatio = newSpeedFactor / speedFactor;
- for (GCodeBuffer *gb2 : gcodeSources)
+ float newSpeedFactor = gb.GetFValue();
+ if (newSpeedFactor >= 1.0)
{
- if (gb2 != nullptr)
+ // Update the feed rate for ALL input sources, and all feed rates on the stack
+ const float speedFactorRatio = newSpeedFactor / speedFactor;
+ for (GCodeBuffer *gb2 : gcodeSources)
{
- GCodeMachineState *ms = &gb2->MachineState();
- while (ms != nullptr)
+ if (gb2 != nullptr)
{
- ms->feedRate *= speedFactorRatio;
- ms = ms->previous;
+ GCodeMachineState *ms = &gb2->MachineState();
+ while (ms != nullptr)
+ {
+ ms->feedRate *= speedFactorRatio;
+ ms = ms->previous;
+ }
}
}
+ // If the last move hasn't gone yet, update its feed rate too if it is not a firmware retraction
+ if (segmentsLeft != 0 && !moveBuffer.isFirmwareRetraction)
+ {
+ moveBuffer.feedRate *= speedFactorRatio;
+ }
+ speedFactor = newSpeedFactor;
}
- // If the last move hasn't gone yet, update its feed rate too if it is not a firmware retraction
- if (segmentsLeft != 0 && !moveBuffer.isFirmwareRetraction)
+ else
{
- moveBuffer.feedRate *= speedFactorRatio;
+ reply.copy("Invalid speed factor");
+ result = GCodeResult::error;
}
- speedFactor = newSpeedFactor;
}
else
{
- reply.copy("Invalid speed factor");
- result = GCodeResult::error;
+ reply.printf("Speed factor override: %.1f%%", (double)speedFactor);
}
- }
- else
- {
- reply.printf("Speed factor override: %.1f%%", (double)speedFactor);
- }
- break;
-
- case 221: // Set/report extrusion factor override percentage
- {
- uint32_t extruder;
- bool seenD = false;
- gb.TryGetUIValue('D', extruder, seenD);
+ break;
- const Tool * const ct = reprap.GetCurrentTool();
- if (!seenD && ct == nullptr)
+ case 221: // Set/report extrusion factor override percentage
{
- reply.copy("No tool selected");
- result = GCodeResult::error;
- }
- else if (gb.Seen('S')) // S parameter sets the override percentage
- {
- const float extrusionFactor = gb.GetFValue() / 100.0;
- if (extrusionFactor >= 0.0)
+ uint32_t extruder;
+ bool seenD = false;
+ gb.TryGetUIValue('D', extruder, seenD);
+
+ const Tool * const ct = reprap.GetCurrentTool();
+ if (!seenD && ct == nullptr)
+ {
+ reply.copy("No tool selected");
+ result = GCodeResult::error;
+ }
+ else if (gb.Seen('S')) // S parameter sets the override percentage
{
- if (seenD)
+ const float extrusionFactor = gb.GetFValue() / 100.0;
+ if (extrusionFactor >= 0.0)
{
- if (extruder < numExtruders)
+ if (seenD)
{
- ChangeExtrusionFactor(extruder, extrusionFactor);
+ if (extruder < numExtruders)
+ {
+ ChangeExtrusionFactor(extruder, extrusionFactor);
+ }
+ }
+ else
+ {
+ ct->IterateExtruders([this, extrusionFactor](unsigned int extruder) { ChangeExtrusionFactor(extruder, extrusionFactor); });
}
- }
- else
- {
- ct->IterateExtruders([this, extrusionFactor](unsigned int extruder) { ChangeExtrusionFactor(extruder, extrusionFactor); });
}
}
+ else if (seenD)
+ {
+ reply.printf("Extrusion factor override for extruder %" PRIu32 ": %.1f%%", extruder, (double)(extrusionFactors[extruder] * 100.0));
+ }
+ else
+ {
+ reply.copy("Extrusion factor(s) for current tool:");
+ ct->IterateExtruders([reply, this](unsigned int extruder) { reply.catf(" %.1f%%", (double)(extrusionFactors[extruder] * 100.0)); });
+ }
}
- else if (seenD)
- {
- reply.printf("Extrusion factor override for extruder %" PRIu32 ": %.1f%%", extruder, (double)(extrusionFactors[extruder] * 100.0));
- }
- else
- {
- reply.copy("Extrusion factor(s) for current tool:");
- ct->IterateExtruders([reply, this](unsigned int extruder) { reply.catf(" %.1f%%", (double)(extrusionFactors[extruder] * 100.0)); });
- }
- }
- break;
+ break;
- // For case 226, see case 25
+ // For case 226, see case 25
- case 260: // I2C send
- result = SendI2c(gb, reply);
- break;
+ case 260: // I2C send
+ result = SendI2c(gb, reply);
+ break;
- case 261: // I2C send
- result = ReceiveI2c(gb, reply);
- break;
+ case 261: // I2C send
+ result = ReceiveI2c(gb, reply);
+ break;
- case 280: // Servos
- if (gb.Seen('P'))
- {
- const uint32_t gpioPortNumber = gb.GetUIValue();
- if (gpioPortNumber < MaxGpioPorts)
+ case 280: // Servos
+ if (gb.Seen('P'))
{
- if (gb.Seen('S'))
+ const uint32_t gpioPortNumber = gb.GetUIValue();
+ if (gpioPortNumber < MaxGpioPorts)
{
- float angleOrWidth = gb.GetFValue();
- if (angleOrWidth < 0.0)
+ if (gb.Seen('S'))
{
- // Disable the servo by setting the pulse width to zero
- angleOrWidth = 0.0;
- }
- else if (angleOrWidth < MinServoPulseWidth)
- {
- // User gave an angle so convert it to a pulse width in microseconds
- angleOrWidth = (min<float>(angleOrWidth, 180.0) * ((MaxServoPulseWidth - MinServoPulseWidth) / 180.0)) + MinServoPulseWidth;
- }
- else if (angleOrWidth > MaxServoPulseWidth)
- {
- angleOrWidth = MaxServoPulseWidth;
- }
+ float angleOrWidth = gb.GetFValue();
+ if (angleOrWidth < 0.0)
+ {
+ // Disable the servo by setting the pulse width to zero
+ angleOrWidth = 0.0;
+ }
+ else if (angleOrWidth < MinServoPulseWidth)
+ {
+ // User gave an angle so convert it to a pulse width in microseconds
+ angleOrWidth = (min<float>(angleOrWidth, 180.0) * ((MaxServoPulseWidth - MinServoPulseWidth) / 180.0)) + MinServoPulseWidth;
+ }
+ else if (angleOrWidth > MaxServoPulseWidth)
+ {
+ angleOrWidth = MaxServoPulseWidth;
+ }
- const GpOutputPort& gpPort = platform.GetGpioPort(gpioPortNumber);
- const float pwm = angleOrWidth * (ServoRefreshFrequency/1e6);
+ const GpOutputPort& gpPort = platform.GetGpioPort(gpioPortNumber);
+ const float pwm = angleOrWidth * (ServoRefreshFrequency/1e6);
#if SUPPORT_CAN_EXPANSION
- if (gpPort.boardAddress != CanId::MasterAddress)
- {
- result = CanInterface::WriteGpio(gpPort.boardAddress, gpioPortNumber, pwm, true, reply);
- break;
- }
+ if (gpPort.boardAddress != CanId::MasterAddress)
+ {
+ result = CanInterface::WriteGpio(gpPort.boardAddress, gpioPortNumber, pwm, true, reply);
+ break;
+ }
#endif
- gpPort.port.WriteAnalog(pwm);
+ gpPort.port.WriteAnalog(pwm);
+ }
+ // We don't currently allow the servo position to be read back
+ }
+ else
+ {
+ reply.printf("Invalid gpio port %" PRIu32, gpioPortNumber);
+ result = GCodeResult::error;
}
- // We don't currently allow the servo position to be read back
- }
- else
- {
- reply.printf("Invalid gpio port %" PRIu32, gpioPortNumber);
- result = GCodeResult::error;
}
- }
- break;
+ break;
- case 290: // Baby stepping
- {
- const bool absolute = (gb.Seen('R') && gb.GetIValue() == 0);
- bool seen = false;
- float differences[MaxAxes];
- for (size_t axis = 0; axis < numVisibleAxes; ++axis)
+ case 290: // Baby stepping
{
- if (gb.Seen(axisLetters[axis]) || (axis == 2 && gb.Seen('S'))) // S is a synonym for Z
+ const bool absolute = (gb.Seen('R') && gb.GetIValue() == 0);
+ bool seen = false;
+ float differences[MaxAxes];
+ for (size_t axis = 0; axis < numVisibleAxes; ++axis)
{
- seen = true;
- const float fval = gb.GetFValue();
- if (absolute)
+ if (gb.Seen(axisLetters[axis]) || (axis == 2 && gb.Seen('S'))) // S is a synonym for Z
{
- differences[axis] = fval - GetTotalBabyStepOffset(axis);
+ seen = true;
+ const float fval = gb.GetFValue();
+ if (absolute)
+ {
+ differences[axis] = fval - GetTotalBabyStepOffset(axis);
+ }
+ else
+ {
+ differences[axis] = constrain<float>(fval, -1.0, 1.0);
+ }
}
else
{
- differences[axis] = constrain<float>(fval, -1.0, 1.0);
+ differences[axis] = 0.0;
}
}
- else
- {
- differences[axis] = 0.0;
- }
- }
- if (seen)
- {
- if (!LockMovement(gb))
- {
- return false;
- }
-
- // Perform babystepping synchronously with moves
- bool haveResidual = false;
- for (size_t axis = 0; axis < numVisibleAxes; ++axis)
+ if (seen)
{
- currentBabyStepOffsets[axis] += differences[axis];
- const float amountPushed = reprap.GetMove().PushBabyStepping(axis, differences[axis]);
- moveBuffer.initialCoords[axis] += amountPushed;
+ if (!LockMovement(gb))
+ {
+ return false;
+ }
- // The following causes all the remaining baby stepping that we didn't manage to push to be added to the [remainder of the] currently-executing move, if there is one.
- // This could result in an abrupt Z movement, however the move will be processed as normal so the jerk limit will be honoured.
- moveBuffer.coords[axis] += differences[axis];
- if (amountPushed != differences[axis])
+ // Perform babystepping synchronously with moves
+ bool haveResidual = false;
+ for (size_t axis = 0; axis < numVisibleAxes; ++axis)
{
- haveResidual = true;
+ currentBabyStepOffsets[axis] += differences[axis];
+ const float amountPushed = reprap.GetMove().PushBabyStepping(axis, differences[axis]);
+ moveBuffer.initialCoords[axis] += amountPushed;
+
+ // The following causes all the remaining baby stepping that we didn't manage to push to be added to the [remainder of the] currently-executing move, if there is one.
+ // This could result in an abrupt Z movement, however the move will be processed as normal so the jerk limit will be honoured.
+ moveBuffer.coords[axis] += differences[axis];
+ if (amountPushed != differences[axis])
+ {
+ haveResidual = true;
+ }
}
- }
- if (haveResidual && segmentsLeft == 0 && reprap.GetMove().AllMovesAreFinished())
- {
- // The pipeline is empty, so execute the babystepping move immediately
- SetMoveBufferDefaults();
- moveBuffer.feedRate = DefaultFeedRate;
- NewMoveAvailable(1);
+ if (haveResidual && segmentsLeft == 0 && reprap.GetMove().AllMovesAreFinished())
+ {
+ // The pipeline is empty, so execute the babystepping move immediately
+ SetMoveBufferDefaults();
+ moveBuffer.feedRate = DefaultFeedRate;
+ NewMoveAvailable(1);
+ }
}
- }
- else
- {
- reply.printf("Baby stepping offsets (mm):");
- for (size_t axis = 0; axis < numVisibleAxes; ++axis)
+ else
{
- reply.catf(" %c:%.3f", axisLetters[axis], (double)GetTotalBabyStepOffset(axis));
+ reply.printf("Baby stepping offsets (mm):");
+ for (size_t axis = 0; axis < numVisibleAxes; ++axis)
+ {
+ reply.catf(" %c:%.3f", axisLetters[axis], (double)GetTotalBabyStepOffset(axis));
+ }
}
}
- }
- break;
+ break;
- case 291: // Display message, optionally wait for acknowledgement
- {
- bool seen = false;
- String<MaxMessageLength> title;
- gb.TryGetQuotedString('R', title.GetRef(), seen);
+ case 291: // Display message, optionally wait for acknowledgement
+ {
+ bool seen = false;
+ String<MaxMessageLength> title;
+ gb.TryGetQuotedString('R', title.GetRef(), seen);
- String<MaxMessageLength> message;
- gb.TryGetQuotedString('P', message.GetRef(), seen);
+ String<MaxMessageLength> message;
+ gb.TryGetQuotedString('P', message.GetRef(), seen);
- if (seen)
- {
- int32_t sParam = 1;
- gb.TryGetIValue('S', sParam, seen);
- if (sParam < 0 || sParam > 3)
+ if (seen)
{
- reply.copy("Invalid message box mode");
- result = GCodeResult::error;
- break;
- }
+ int32_t sParam = 1;
+ gb.TryGetIValue('S', sParam, seen);
+ if (sParam < 0 || sParam > 3)
+ {
+ reply.copy("Invalid message box mode");
+ result = GCodeResult::error;
+ break;
+ }
- float tParam;
- if (sParam == 0 || sParam == 1)
- {
- tParam = DefaultMessageTimeout;
- gb.TryGetFValue('T', tParam, seen);
- }
- else
- {
- tParam = 0.0;
- }
+ float tParam;
+ if (sParam == 0 || sParam == 1)
+ {
+ tParam = DefaultMessageTimeout;
+ gb.TryGetFValue('T', tParam, seen);
+ }
+ else
+ {
+ tParam = 0.0;
+ }
- if (sParam == 0 && tParam <= 0.0)
- {
- reply.copy("Attempt to create a message box that cannot be dismissed");
- result = GCodeResult::error;
- break;
- }
+ if (sParam == 0 && tParam <= 0.0)
+ {
+ reply.copy("Attempt to create a message box that cannot be dismissed");
+ result = GCodeResult::error;
+ break;
+ }
- AxesBitmap axisControls = 0;
- for (size_t axis = 0; axis < numTotalAxes; axis++)
- {
- if (gb.Seen(axisLetters[axis]) && gb.GetIValue() > 0)
+ AxesBitmap axisControls = 0;
+ for (size_t axis = 0; axis < numTotalAxes; axis++)
{
- SetBit(axisControls, axis);
+ if (gb.Seen(axisLetters[axis]) && gb.GetIValue() > 0)
+ {
+ SetBit(axisControls, axis);
+ }
}
- }
- // Don't lock the movement system, because if we do then only the channel that issues the M291 can move the axes
+ // Don't lock the movement system, because if we do then only the channel that issues the M291 can move the axes
- // If we need to wait for an acknowledgement, save the state and set waiting
- if ((sParam == 2 || sParam == 3) && Push(gb, true)) // stack the machine state including the file position
- {
- UnlockMovement(gb); // allow movement so that e.g. an SD card print can call M291 and then DWC or PanelDue can be used to jog axes
- gb.MachineState().CloseFile(); // stop reading from file
- gb.MachineState().waitingForAcknowledgement = true; // flag that we are waiting for acknowledgement
- }
+ // If we need to wait for an acknowledgement, save the state and set waiting
+ if ((sParam == 2 || sParam == 3) && Push(gb, true)) // stack the machine state including the file position
+ {
+ UnlockMovement(gb); // allow movement so that e.g. an SD card print can call M291 and then DWC or PanelDue can be used to jog axes
+ gb.MachineState().CloseFile(); // stop reading from file
+ gb.MachineState().waitingForAcknowledgement = true; // flag that we are waiting for acknowledgement
+ }
- // Display the message box on all relevant devices. Acknowledging any one of them clears them all.
- const MessageType mt = GetMessageBoxDevice(gb); // get the display device
- platform.SendAlert(mt, message.c_str(), title.c_str(), (int)sParam, tParam, axisControls);
+ // Display the message box on all relevant devices. Acknowledging any one of them clears them all.
+ const MessageType mt = GetMessageBoxDevice(gb); // get the display device
+ platform.SendAlert(mt, message.c_str(), title.c_str(), (int)sParam, tParam, axisControls);
+ }
}
- }
- break;
-
- case 292: // Acknowledge message
- {
- reprap.ClearAlert();
+ break;
- const bool cancelled = (gb.Seen('P') && gb.GetIValue() == 1);
- for (GCodeBuffer* targetGb : gcodeSources)
+ case 292: // Acknowledge message
{
- if (targetGb != nullptr)
+ reprap.ClearAlert();
+
+ const bool cancelled = (gb.Seen('P') && gb.GetIValue() == 1);
+ for (GCodeBuffer* targetGb : gcodeSources)
{
- targetGb->MessageAcknowledged(cancelled);
+ if (targetGb != nullptr)
+ {
+ targetGb->MessageAcknowledged(cancelled);
+ }
}
}
- }
- break;
-
- case 300: // Beep
- {
- const unsigned int ms = (gb.Seen('P')) ? gb.GetUIValue() : 1000; // time in milliseconds
- const unsigned int freq = (gb.Seen('S')) ? gb.GetUIValue() : 4600; // 4600Hz produces the loudest sound on a PanelDue
- reprap.Beep(freq, ms);
- }
- break;
-
- case 301: // Set/report hot end PID values
- result = reprap.GetHeat().SetPidParameters(1, gb, reply);
- break;
+ break;
- case 302: // Allow, deny or report cold extrudes and configure minimum extrusion/retraction temps
- {
- bool seen = false;
- if (gb.Seen('P'))
+ case 300: // Beep
{
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- seen = true;
- reprap.GetHeat().AllowColdExtrude(gb.GetIValue() > 0);
+ const unsigned int ms = (gb.Seen('P')) ? gb.GetUIValue() : 1000; // time in milliseconds
+ const unsigned int freq = (gb.Seen('S')) ? gb.GetUIValue() : 4600; // 4600Hz produces the loudest sound on a PanelDue
+ reprap.Beep(freq, ms);
}
- if (gb.Seen('S'))
+ break;
+
+ case 301: // Set/report hot end PID values
+ result = reprap.GetHeat().SetPidParameters(1, gb, reply);
+ break;
+
+ case 302: // Allow, deny or report cold extrudes and configure minimum extrusion/retraction temps
{
- if (!LockMovementAndWaitForStandstill(gb))
+ bool seen = false;
+ if (gb.Seen('P'))
{
- return false;
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ seen = true;
+ reprap.GetHeat().AllowColdExtrude(gb.GetIValue() > 0);
}
- seen = true;
- reprap.GetHeat().SetExtrusionMinTemp(gb.GetFValue());
- }
- if (gb.Seen('R'))
- {
- if (!LockMovementAndWaitForStandstill(gb))
+ if (gb.Seen('S'))
{
- return false;
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ seen = true;
+ reprap.GetHeat().SetExtrusionMinTemp(gb.GetFValue());
}
- seen = true;
- reprap.GetHeat().SetRetractionMinTemp(gb.GetFValue());
- }
- if (!seen)
- {
- if (reprap.GetHeat().ColdExtrude())
+ if (gb.Seen('R'))
{
- reply.copy("Cold extrusion is allowed (use M302 P0 to forbid it)");
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ seen = true;
+ reprap.GetHeat().SetRetractionMinTemp(gb.GetFValue());
}
- else
+ if (!seen)
{
- reply.printf("Cold extrusion is forbidden (use M302 P1 to allow it), min. extrusion temperature %.1fC, min. retraction temperature %.1fC",
- (double)reprap.GetHeat().GetExtrusionMinTemp(), (double)reprap.GetHeat().GetRetractionMinTemp());
+ if (reprap.GetHeat().ColdExtrude())
+ {
+ reply.copy("Cold extrusion is allowed (use M302 P0 to forbid it)");
+ }
+ else
+ {
+ reply.printf("Cold extrusion is forbidden (use M302 P1 to allow it), min. extrusion temperature %.1fC, min. retraction temperature %.1fC",
+ (double)reprap.GetHeat().GetExtrusionMinTemp(), (double)reprap.GetHeat().GetRetractionMinTemp());
+ }
}
}
- }
- break;
+ break;
- case 303: // Run PID tuning
- result = reprap.GetHeat().TuneHeater(gb, reply);
- break;
+ case 303: // Run PID tuning
+ result = reprap.GetHeat().TuneHeater(gb, reply);
+ break;
- case 304: // Set/report heated bed PID values
- result = reprap.GetHeat().SetPidParameters(0, gb, reply);
- break;
+ case 304: // Set/report heated bed PID values
+ result = reprap.GetHeat().SetPidParameters(0, gb, reply);
+ break;
- case 305: // Set/report specific heater parameters
- reply.copy("M305 has been replaced by M308 and M950 in RepRapFirmware 3");
- result = GCodeResult::error;
- break;
+ case 305: // Set/report specific heater parameters
+ reply.copy("M305 has been replaced by M308 and M950 in RepRapFirmware 3");
+ result = GCodeResult::error;
+ break;
- case 307: // Set heater process model parameters
- result = reprap.GetHeat().SetOrReportHeaterModel(gb, reply);
- break;
+ case 307: // Set heater process model parameters
+ result = reprap.GetHeat().SetOrReportHeaterModel(gb, reply);
+ break;
- case 308:
- result = reprap.GetHeat().ConfigureSensor(gb, reply);
- break;
+ case 308:
+ result = reprap.GetHeat().ConfigureSensor(gb, reply);
+ break;
- case 350: // Set/report microstepping
- {
- bool interp = (gb.Seen('I') && gb.GetIValue() > 0);
- bool seen = false;
- for (size_t axis = 0; axis < numTotalAxes; axis++)
+ case 350: // Set/report microstepping
{
- if (gb.Seen(axisLetters[axis]))
+ bool interp = (gb.Seen('I') && gb.GetIValue() > 0);
+ bool seen = false;
+ for (size_t axis = 0; axis < numTotalAxes; axis++)
+ {
+ if (gb.Seen(axisLetters[axis]))
+ {
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ seen = true;
+ const unsigned int microsteps = gb.GetUIValue();
+ if (ChangeMicrostepping(axis, microsteps, interp, reply))
+ {
+ SetAxisNotHomed(axis);
+ }
+ else
+ {
+ result = GCodeResult::error;
+ }
+ }
+ }
+
+ if (gb.Seen(extrudeLetter))
{
if (!LockMovementAndWaitForStandstill(gb))
{
return false;
}
seen = true;
- const unsigned int microsteps = gb.GetUIValue();
- if (ChangeMicrostepping(axis, microsteps, interp, reply))
- {
- SetAxisNotHomed(axis);
- }
- else
+ uint32_t eVals[MaxExtruders];
+ size_t eCount = numExtruders;
+ gb.GetUnsignedArray(eVals, eCount, true);
+ for (size_t e = 0; e < eCount; e++)
{
- result = GCodeResult::error;
+ if (!ChangeMicrostepping(ExtruderToLogicalDrive(e), eVals[e], interp, reply))
+ {
+ result = GCodeResult::error;
+ }
}
}
- }
- if (gb.Seen(extrudeLetter))
- {
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- seen = true;
- uint32_t eVals[MaxExtruders];
- size_t eCount = numExtruders;
- gb.GetUnsignedArray(eVals, eCount, true);
- for (size_t e = 0; e < eCount; e++)
+ if (!seen)
{
- if (!ChangeMicrostepping(ExtruderToLogicalDrive(e), eVals[e], interp, reply))
+ reply.copy("Microstepping - ");
+ for (size_t axis = 0; axis < numTotalAxes; ++axis)
{
- result = GCodeResult::error;
+ bool actualInterp;
+ const unsigned int microsteps = platform.GetMicrostepping(axis, actualInterp);
+ reply.catf("%c:%u%s, ", axisLetters[axis], microsteps, (actualInterp) ? "(on)" : "");
+ }
+ reply.cat("E");
+ for (size_t extruder = 0; extruder < numExtruders; extruder++)
+ {
+ bool actualInterp;
+ const unsigned int microsteps = platform.GetMicrostepping(ExtruderToLogicalDrive(extruder), actualInterp);
+ reply.catf(":%u%s", microsteps, (actualInterp) ? "(on)" : "");
}
}
}
+ break;
+
+#if HAS_MASS_STORAGE
+ case 374: // Save grid and height map to file
+ result = SaveHeightMap(gb, reply);
+ break;
+
+ case 375: // Load grid and height map from file and enable compensation
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ result = LoadHeightMap(gb, reply);
+ break;
+#endif
- if (!seen)
+ case 376: // Set taper height
{
- reply.copy("Microstepping - ");
- for (size_t axis = 0; axis < numTotalAxes; ++axis)
+ Move& move = reprap.GetMove();
+ if (gb.Seen('H'))
+ {
+ move.SetTaperHeight(gb.GetFValue());
+ }
+ else if (move.GetTaperHeight() > 0.0)
{
- bool actualInterp;
- const unsigned int microsteps = platform.GetMicrostepping(axis, actualInterp);
- reply.catf("%c:%u%s, ", axisLetters[axis], microsteps, (actualInterp) ? "(on)" : "");
+ reply.printf("Bed compensation taper height is %.1fmm", (double)move.GetTaperHeight());
}
- reply.cat("E");
- for (size_t extruder = 0; extruder < numExtruders; extruder++)
+ else
{
- bool actualInterp;
- const unsigned int microsteps = platform.GetMicrostepping(ExtruderToLogicalDrive(extruder), actualInterp);
- reply.catf(":%u%s", microsteps, (actualInterp) ? "(on)" : "");
+ reply.copy("Bed compensation is not tapered");
}
}
- }
- break;
-
-#if HAS_MASS_STORAGE
- case 374: // Save grid and height map to file
- result = SaveHeightMap(gb, reply);
- break;
-
- case 375: // Load grid and height map from file and enable compensation
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- result = LoadHeightMap(gb, reply);
- break;
-#endif
+ break;
- case 376: // Set taper height
- {
- Move& move = reprap.GetMove();
- if (gb.Seen('H'))
+ case 400: // Wait for current moves to finish
+ if (!LockMovementAndWaitForStandstill(gb))
{
- move.SetTaperHeight(gb.GetFValue());
+ return false;
}
- else if (move.GetTaperHeight() > 0.0)
+ break;
+
+ case 401: // Deploy Z probe
+ if (platform.GetCurrentZProbeType() != ZProbeType::none)
{
- reply.printf("Bed compensation taper height is %.1fmm", (double)move.GetTaperHeight());
+ probeIsDeployed = true;
+ DoFileMacro(gb, DEPLOYPROBE_G, false, 401);
}
- else
+ break;
+
+ case 402: // Retract Z probe
+ if (platform.GetCurrentZProbeType() != ZProbeType::none)
{
- reply.copy("Bed compensation is not tapered");
+ probeIsDeployed = false;
+ DoFileMacro(gb, RETRACTPROBE_G, false, 402);
}
- }
- break;
-
- case 400: // Wait for current moves to finish
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- break;
-
- case 401: // Deploy Z probe
- if (platform.GetCurrentZProbeType() != ZProbeType::none)
- {
- probeIsDeployed = true;
- DoFileMacro(gb, DEPLOYPROBE_G, false, 401);
- }
- break;
+ break;
- case 402: // Retract Z probe
- if (platform.GetCurrentZProbeType() != ZProbeType::none)
- {
- probeIsDeployed = false;
- DoFileMacro(gb, RETRACTPROBE_G, false, 402);
- }
- break;
+ case 404: // Filament width and nozzle diameter
+ {
+ bool seen = false;
- case 404: // Filament width and nozzle diameter
- {
- bool seen = false;
+ if (gb.Seen('N'))
+ {
+ platform.SetFilamentWidth(gb.GetFValue());
+ seen = true;
+ }
+ if (gb.Seen('D'))
+ {
+ platform.SetNozzleDiameter(gb.GetFValue());
+ seen = true;
+ }
- if (gb.Seen('N'))
- {
- platform.SetFilamentWidth(gb.GetFValue());
- seen = true;
- }
- if (gb.Seen('D'))
- {
- platform.SetNozzleDiameter(gb.GetFValue());
- seen = true;
+ if (!seen)
+ {
+ reply.printf("Filament width: %.2fmm, nozzle diameter: %.2fmm", (double)platform.GetFilamentWidth(), (double)platform.GetNozzleDiameter());
+ }
}
+ break;
- if (!seen)
+ case 408: // Get status in JSON format
{
- reply.printf("Filament width: %.2fmm, nozzle diameter: %.2fmm", (double)platform.GetFilamentWidth(), (double)platform.GetNozzleDiameter());
- }
- }
- break;
-
- case 408: // Get status in JSON format
- {
- const unsigned int form = (gb.Seen('P')) ? gb.GetUIValue() : 0;
- const unsigned int type = gb.Seen('S') ? gb.GetUIValue() : 0;
+ const unsigned int form = (gb.Seen('P')) ? gb.GetUIValue() : 0;
+ const unsigned int type = gb.Seen('S') ? gb.GetUIValue() : 0;
#if SUPPORT_CAN_EXPANSION
- const uint32_t board = (gb.Seen('B')) ? gb.GetUIValue() : 0;
- if (board != 0)
- {
- result = CanInterface::RemoteM408(board, form, type, gb, reply);
- break;
- }
+ const uint32_t board = (gb.Seen('B')) ? gb.GetUIValue() : 0;
+ if (board != 0)
+ {
+ result = CanInterface::RemoteM408(board, form, type, gb, reply);
+ break;
+ }
#endif
- switch (form)
- {
- case 0:
+ switch (form)
{
- const int seq = gb.Seen('R') ? gb.GetIValue() : -1;
- if (&gb == auxGCode && (type == 0 || type == 2))
+ case 0:
{
- lastAuxStatusReportType = type;
- }
+ const int seq = gb.Seen('R') ? gb.GetIValue() : -1;
+ if (&gb == auxGCode && (type == 0 || type == 2))
+ {
+ lastAuxStatusReportType = type;
+ }
- outBuf = GenerateJsonStatusResponse(type, seq, (&gb == auxGCode) ? ResponseSource::AUX : ResponseSource::Generic);
- if (outBuf == nullptr)
- {
- result = GCodeResult::notFinished; // we ran out of buffers, so try again later
+ outBuf = GenerateJsonStatusResponse(type, seq, (&gb == auxGCode) ? ResponseSource::AUX : ResponseSource::Generic);
+ if (outBuf == nullptr)
+ {
+ result = GCodeResult::notFinished; // we ran out of buffers, so try again later
+ }
}
- }
- break;
+ break;
#if SUPPORT_OBJECT_MODEL
- case 1:
- {
- String<MediumStringLength> filter;
- bool dummy;
- gb.TryGetQuotedString('F', filter.GetRef(), dummy);
- if (!OutputBuffer::Allocate(outBuf))
- {
- result = GCodeResult::notFinished;
- }
- else
+ case 1:
{
- reprap.ReportAsJson(outBuf, filter.c_str(), ObjectModel::flagsNone);
+ String<MediumStringLength> filter;
+ bool dummy;
+ gb.TryGetQuotedString('F', filter.GetRef(), dummy);
+ if (!OutputBuffer::Allocate(outBuf))
+ {
+ result = GCodeResult::notFinished;
+ }
+ else
+ {
+ reprap.ReportAsJson(outBuf, filter.c_str(), ObjectModel::flagsNone);
+ }
}
- }
- break;
+ break;
#endif
- default:
- break;
+ default:
+ break;
+ }
}
- }
- break;
-
- case 450: // Report printer mode
- reply.printf("PrinterMode:%s", GetMachineModeString());
- break;
-
- case 451: // Select FFF printer mode
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- machineType = MachineType::fff;
- break;
-
-#if SUPPORT_LASER
- case 452: // Select laser mode
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
+ break;
- machineType = MachineType::laser;
- Move::CreateLaserTask();
+ case 450: // Report printer mode
+ reply.printf("PrinterMode:%s", GetMachineModeString());
+ break;
- if (gb.Seen('C'))
- {
- if (platform.AssignLaserPin(gb, reply))
- {
- reply.copy("Laser mode selected");
- }
- else
- {
- result = GCodeResult::error;
- }
- }
- if (gb.Seen('F'))
- {
- platform.SetLaserPwmFrequency(gb.GetPwmFrequency());
- }
- if (result == GCodeResult::ok)
- {
- if (gb.Seen('S'))
- {
- laserPowerSticky = (gb.GetUIValue() == 1);
- }
- if (gb.Seen('R'))
+ case 451: // Select FFF printer mode
+ if (!LockMovementAndWaitForStandstill(gb))
{
- laserMaxPower = max<float>(1.0, gb.GetFValue());
+ return false;
}
- }
- break;
-#endif
+ machineType = MachineType::fff;
+ break;
- case 453: // Select CNC mode
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- {
- const MachineType oldMachineType = machineType;
- machineType = MachineType::cnc; // switch to CNC mode even if the spindle parameter is bad
- const uint32_t slot = gb.Seen('S') ? gb.GetUIValue() : 0;
- if (slot >= MaxSpindles)
+#if SUPPORT_LASER
+ case 452: // Select laser mode
+ if (!LockMovementAndWaitForStandstill(gb))
{
- reply.copy("Invalid spindle index");
- result = GCodeResult::error;
- break;
+ return false;
}
- Spindle& spindle = platform.AccessSpindle(slot);
+ machineType = MachineType::laser;
+ Move::CreateLaserTask();
+
if (gb.Seen('C'))
{
- if (!spindle.AllocatePins(gb, reply))
+ if (platform.AssignLaserPin(gb, reply))
+ {
+ reply.copy("Laser mode selected");
+ }
+ else
{
result = GCodeResult::error;
- break;
}
}
if (gb.Seen('F'))
{
- spindle.SetFrequency(gb.GetPwmFrequency());
+ platform.SetLaserPwmFrequency(gb.GetPwmFrequency());
}
- if (gb.Seen('R'))
+ if (result == GCodeResult::ok)
{
- spindle.SetMaxRpm(max<float>(1.0, gb.GetFValue()));
+ if (gb.Seen('S'))
+ {
+ laserPowerSticky = (gb.GetUIValue() == 1);
+ }
+ if (gb.Seen('R'))
+ {
+ laserMaxPower = max<float>(1.0, gb.GetFValue());
+ }
}
- if (gb.Seen('T'))
+ break;
+#endif
+
+ case 453: // Select CNC mode
+ if (!LockMovementAndWaitForStandstill(gb))
{
- spindle.SetToolNumber(gb.GetIValue());
+ return false;
}
-
- // M453 may be repeated to set up multiple spindles, so only print the message on the initial switch
- if (oldMachineType != MachineType::cnc)
{
- reply.copy("CNC mode selected");
+ const MachineType oldMachineType = machineType;
+ machineType = MachineType::cnc; // switch to CNC mode even if the spindle parameter is bad
+ const uint32_t slot = gb.Seen('S') ? gb.GetUIValue() : 0;
+ if (slot >= MaxSpindles)
+ {
+ reply.copy("Invalid spindle index");
+ result = GCodeResult::error;
+ break;
+ }
+
+ Spindle& spindle = platform.AccessSpindle(slot);
+ if (gb.Seen('C'))
+ {
+ if (!spindle.AllocatePins(gb, reply))
+ {
+ result = GCodeResult::error;
+ break;
+ }
+ }
+ if (gb.Seen('F'))
+ {
+ spindle.SetFrequency(gb.GetPwmFrequency());
+ }
+ if (gb.Seen('R'))
+ {
+ spindle.SetMaxRpm(max<float>(1.0, gb.GetFValue()));
+ }
+ if (gb.Seen('T'))
+ {
+ spindle.SetToolNumber(gb.GetIValue());
+ }
+
+ // M453 may be repeated to set up multiple spindles, so only print the message on the initial switch
+ if (oldMachineType != MachineType::cnc)
+ {
+ reply.copy("CNC mode selected");
+ }
}
- }
- break;
+ break;
#if HAS_MASS_STORAGE
- case 470: // mkdir
- {
- String<MaxFilenameLength> dirName;
- if (!gb.Seen('P') || !gb.GetQuotedString(dirName.GetRef()))
+ case 470: // mkdir
{
- reply.copy("Bad or missing P parameter");
- result = GCodeResult::error;
- break;
+ gb.MustSee('P');
+ String<MaxFilenameLength> dirName;
+ gb.GetQuotedString(dirName.GetRef());
+ MassStorage::MakeDirectory(dirName.c_str());
}
- MassStorage::MakeDirectory(dirName.c_str());
- }
- break;
+ break;
- case 471: // move/rename file/directory
- {
- String<MaxFilenameLength> oldVal;
- if (!gb.Seen('S') || !gb.GetQuotedString(oldVal.GetRef()))
+ case 471: // move/rename file/directory
{
- reply.copy("Bad or missing S parameter");
- result = GCodeResult::error;
- break;
- }
- String<MaxFilenameLength> newVal;
- if (!gb.Seen('T') || !gb.GetQuotedString(newVal.GetRef()))
- {
- reply.copy("Bad or missing T parameter");
- result = GCodeResult::error;
- break;
- }
- if (gb.Seen('D') && gb.GetUIValue() == 1 && MassStorage::FileExists(oldVal.c_str()) && MassStorage::FileExists(newVal.c_str()))
- {
- MassStorage::Delete(newVal.c_str());
+ gb.MustSee('S');
+ String<MaxFilenameLength> oldVal;
+ gb.GetQuotedString(oldVal.GetRef());
+ String<MaxFilenameLength> newVal;
+ gb.MustSee('T');
+ gb.GetQuotedString(newVal.GetRef());
+ if (gb.Seen('D') && gb.GetUIValue() == 1 && MassStorage::FileExists(oldVal.c_str()) && MassStorage::FileExists(newVal.c_str()))
+ {
+ MassStorage::Delete(newVal.c_str());
+ }
+ MassStorage::Rename(oldVal.c_str(), newVal.c_str());
}
- MassStorage::Rename(oldVal.c_str(), newVal.c_str());
- }
- break;
+ break;
- case 500: // Store parameters in config-override.g
- result = WriteConfigOverrideFile(gb, reply);
- break;
+ case 500: // Store parameters in config-override.g
+ result = WriteConfigOverrideFile(gb, reply);
+ break;
#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 (runningConfigFile)
+ case 501: // Load parameters from config-override.g
+ if (!gb.MachineState().runningM502 && !gb.MachineState().runningM501) // when running M502 we ignore config-override.g
{
- m501SeenInConfigFile = true;
+ if (runningConfigFile)
+ {
+ m501SeenInConfigFile = true;
+ }
+ DoFileMacro(gb, CONFIG_OVERRIDE_G, true, code);
}
- DoFileMacro(gb, CONFIG_OVERRIDE_G, true, code);
- }
- break;
+ break;
- case 502: // Revert to default "factory settings" ignoring values in config-override.g
- if (!gb.MachineState().runningM502) // avoid recursion
- {
- if (!LockMovementAndWaitForStandstill(gb))
+ case 502: // Revert to default "factory settings" ignoring values in config-override.g
+ if (!gb.MachineState().runningM502) // avoid recursion
{
- return false;
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ reprap.GetHeat().SwitchOffAll(true); // turn heaters off before changing the models
+ reprap.GetHeat().ResetHeaterModels(); // in case some heaters have no M307 commands in config.g
+ reprap.GetMove().GetKinematics().SetCalibrationDefaults(); // in case M665/M666/M667/M669 in config.g don't define all the parameters
+ platform.GetEndstops().SetZProbeDefaults();
+ DoFileMacro(gb, CONFIG_FILE, true, code);
}
- reprap.GetHeat().SwitchOffAll(true); // turn heaters off before changing the models
- reprap.GetHeat().ResetHeaterModels(); // in case some heaters have no M307 commands in config.g
- reprap.GetMove().GetKinematics().SetCalibrationDefaults(); // in case M665/M666/M667/M669 in config.g don't define all the parameters
- platform.GetEndstops().SetZProbeDefaults();
- DoFileMacro(gb, CONFIG_FILE, true, code);
- }
- break;
+ break;
#if HAS_MASS_STORAGE
- case 503: // List variable settings
- {
- if (!LockFileSystem(gb))
+ case 503: // List variable settings
{
- return false;
- }
+ if (!LockFileSystem(gb))
+ {
+ return false;
+ }
- // Need a valid output buffer to continue
- if (!OutputBuffer::Allocate(outBuf))
- {
- // No buffer available, try again later
- return false;
- }
+ // Need a valid output buffer to continue
+ if (!OutputBuffer::Allocate(outBuf))
+ {
+ // No buffer available, try again later
+ return false;
+ }
- // Read the entire file
- FileStore * const f = platform.OpenSysFile(platform.GetConfigFile(), OpenMode::read);
- if (f == nullptr)
- {
- reply.copy("Configuration file not found");
- result = GCodeResult::error;
- }
- else
- {
- char fileBuffer[FILE_BUFFER_SIZE];
- size_t bytesRead,
- bytesLeftForWriting = OutputBuffer::GetBytesLeft(outBuf);
- while ((bytesRead = f->Read(fileBuffer, FILE_BUFFER_SIZE)) > 0 && bytesLeftForWriting > 0)
+ // Read the entire file
+ FileStore * const f = platform.OpenSysFile(platform.GetConfigFile(), OpenMode::read);
+ if (f == nullptr)
{
- // Don't write more data than we can process
- if (bytesRead < bytesLeftForWriting)
- {
- bytesLeftForWriting -= bytesRead;
- }
- else
+ reply.copy("Configuration file not found");
+ result = GCodeResult::error;
+ }
+ else
+ {
+ char fileBuffer[FILE_BUFFER_SIZE];
+ size_t bytesRead,
+ bytesLeftForWriting = OutputBuffer::GetBytesLeft(outBuf);
+ while ((bytesRead = f->Read(fileBuffer, FILE_BUFFER_SIZE)) > 0 && bytesLeftForWriting > 0)
{
- bytesRead = bytesLeftForWriting;
- bytesLeftForWriting = 0;
- }
+ // Don't write more data than we can process
+ if (bytesRead < bytesLeftForWriting)
+ {
+ bytesLeftForWriting -= bytesRead;
+ }
+ else
+ {
+ bytesRead = bytesLeftForWriting;
+ bytesLeftForWriting = 0;
+ }
- // Write it
- outBuf->cat(fileBuffer, bytesRead);
+ // Write it
+ outBuf->cat(fileBuffer, bytesRead);
+ }
+ f->Close();
}
- f->Close();
}
- }
- break;
+ break;
- case 505: // set sys folder
- if (gb.Seen('P'))
- {
- // Lock movement to try to prevent other threads opening system files while we change the system path
- if (!LockMovementAndWaitForStandstill(gb))
+ case 505: // set sys folder
+ if (gb.Seen('P'))
{
- return false;
+ // Lock movement to try to prevent other threads opening system files while we change the system path
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ String<MaxFilenameLength> path;
+ gb.GetQuotedString(path.GetRef());
+ result = platform.SetSysDir(path.c_str(), reply);
}
- String<MaxFilenameLength> path;
- gb.GetQuotedString(path.GetRef());
- result = platform.SetSysDir(path.c_str(), reply);
- }
- else
- {
- String<MaxFilenameLength> path;
- platform.GetSysDir(path.GetRef());
- reply.printf("Sys file path is %s", path.c_str());
- }
- break;
+ else
+ {
+ String<MaxFilenameLength> path;
+ platform.GetSysDir(path.GetRef());
+ reply.printf("Sys file path is %s", path.c_str());
+ }
+ break;
#endif
- case 540: // Set/report MAC address
- if (!gb.MachineState().runningM502) // when running M502 we don't execute network-related commands
- {
- const unsigned int interface = (gb.Seen('I') ? gb.GetUIValue() : 0);
- if (gb.Seen('P'))
+ case 540: // Set/report MAC address
+ if (!gb.MachineState().runningM502) // when running M502 we don't execute network-related commands
{
- uint8_t mac[6];
- if (gb.GetMacAddress(mac))
+ const unsigned int interface = (gb.Seen('I') ? gb.GetUIValue() : 0);
+ if (gb.Seen('P'))
{
+ uint8_t mac[6];
+ gb.GetMacAddress(mac);
reprap.GetNetwork().SetMacAddress(interface, mac);
}
else
{
- reply.copy("Bad MAC address");
- result = GCodeResult::error;
+ const uint8_t * const mac = reprap.GetNetwork().GetMacAddress(interface);
+ reply.printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
}
- else
- {
- const uint8_t * const mac = reprap.GetNetwork().GetMacAddress(interface);
- reply.printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- }
- }
- break;
+ break;
- case 550: // Set/report machine name
+ case 550: // Set/report machine name
#if HAS_LINUX_INTERFACE
- if (reprap.UsingLinuxInterface() && !gb.IsBinary())
- {
- result = GCodeResult::errorNotSupported;
- }
- else
-#endif
- {
- String<MachineNameLength> name;
- bool seen = false;
- gb.TryGetPossiblyQuotedString('P', name.GetRef(), seen);
- if (seen)
+ if (reprap.UsingLinuxInterface() && !gb.IsBinary())
{
- reprap.SetName(name.c_str());
+ result = GCodeResult::errorNotSupported;
}
else
+#endif
{
- reply.printf("RepRap name: %s", reprap.GetName());
+ String<MachineNameLength> name;
+ bool seen = false;
+ gb.TryGetPossiblyQuotedString('P', name.GetRef(), seen);
+ if (seen)
+ {
+ reprap.SetName(name.c_str());
+ }
+ else
+ {
+ reply.printf("RepRap name: %s", reprap.GetName());
+ }
}
- }
- break;
+ break;
- case 551: // Set password (no option to report it)
- {
- String<RepRapPasswordLength> password;
- bool seen = false;
- gb.TryGetPossiblyQuotedString('P', password.GetRef(), seen);
- if (seen)
+ case 551: // Set password (no option to report it)
{
- reprap.SetPassword(password.c_str());
+ String<RepRapPasswordLength> password;
+ bool seen = false;
+ gb.TryGetPossiblyQuotedString('P', password.GetRef(), seen);
+ if (seen)
+ {
+ reprap.SetPassword(password.c_str());
+ }
}
- }
- break;
-
- case 552: // Enable/Disable network and/or Set/Get IP address
- if (!gb.MachineState().runningM502) // when running M502 we don't execute network-related commands
- {
- bool seen = false;
- const unsigned int interface = (gb.Seen('I') ? gb.GetUIValue() : 0);
+ break;
- String<SsidBufferLength> ssid;
- if (reprap.GetNetwork().IsWiFiInterface(interface))
+ case 552: // Enable/Disable network and/or Set/Get IP address
+ if (!gb.MachineState().runningM502) // when running M502 we don't execute network-related commands
{
- if (gb.Seen('S')) // Has the user turned the network on or off?
- {
- const int enableValue = gb.GetIValue();
- seen = true;
+ bool seen = false;
+ const unsigned int interface = (gb.Seen('I') ? gb.GetUIValue() : 0);
- if (gb.Seen('P') && !gb.GetQuotedString(ssid.GetRef()))
- {
- reply.copy("Bad or missing SSID");
- result = GCodeResult::error;
- }
- else
+ String<SsidBufferLength> ssid;
+ if (reprap.GetNetwork().IsWiFiInterface(interface))
+ {
+ if (gb.Seen('S')) // Has the user turned the network on or off?
{
+ const int enableValue = gb.GetIValue();
+ seen = true;
+
+ gb.MustSee('P');
+ gb.GetQuotedString(ssid.GetRef());
result = reprap.GetNetwork().EnableInterface(interface, enableValue, ssid.GetRef(), reply);
}
}
- }
- else
- {
- if (gb.Seen('P'))
+ else
{
- seen = true;
- IPAddress eth;
- if (gb.GetIPAddress(eth))
+ if (gb.Seen('P'))
{
+ seen = true;
+ IPAddress eth;
+ gb.GetIPAddress(eth);
platform.SetIPAddress(eth);
}
- else
+
+ // Process this one last in case the IP address is changed and the network enabled in the same command
+ if (gb.Seen('S')) // Has the user turned the network on or off?
{
- reply.copy("Bad IP address");
- result = GCodeResult::error;
- break;
+ seen = true;
+ result = reprap.GetNetwork().EnableInterface(interface, gb.GetIValue(), ssid.GetRef(), reply);
}
}
- // Process this one last in case the IP address is changed and the network enabled in the same command
- if (gb.Seen('S')) // Has the user turned the network on or off?
+ if (!seen)
{
- seen = true;
- result = reprap.GetNetwork().EnableInterface(interface, gb.GetIValue(), ssid.GetRef(), reply);
+ result = reprap.GetNetwork().GetNetworkState(interface, reply);
}
}
+ break;
- if (!seen)
- {
- result = reprap.GetNetwork().GetNetworkState(interface, reply);
- }
- }
- break;
-
- case 553: // Set/Get netmask
- if (!gb.MachineState().runningM502) // when running M502 we don't execute network-related commands
- {
- if (gb.Seen('P'))
+ case 553: // Set/Get netmask
+ if (!gb.MachineState().runningM502) // when running M502 we don't execute network-related commands
{
- IPAddress eth;
- if (gb.GetIPAddress(eth))
+ if (gb.Seen('P'))
{
+ IPAddress eth;
+ gb.GetIPAddress(eth);
platform.SetNetMask(eth);
}
else
{
- reply.copy("Bad IP address");
- result = GCodeResult::error;
+ const IPAddress nm = platform.NetMask();
+ reply.printf("Net mask: %d.%d.%d.%d ", nm.GetQuad(0), nm.GetQuad(1), nm.GetQuad(2), nm.GetQuad(3));
}
}
- else
- {
- const IPAddress nm = platform.NetMask();
- reply.printf("Net mask: %d.%d.%d.%d ", nm.GetQuad(0), nm.GetQuad(1), nm.GetQuad(2), nm.GetQuad(3));
- }
- }
- break;
+ break;
- case 554: // Set/Get gateway
- if (!gb.MachineState().runningM502) // when running M502 we don't execute network-related commands
- {
- if (gb.Seen('P'))
+ case 554: // Set/Get gateway
+ if (!gb.MachineState().runningM502) // when running M502 we don't execute network-related commands
{
- IPAddress eth;
- if (gb.GetIPAddress(eth))
+ if (gb.Seen('P'))
{
+ IPAddress eth;
+ gb.GetIPAddress(eth);
platform.SetGateWay(eth);
}
else
{
- reply.copy("Bad IP address");
- result = GCodeResult::error;
+ const IPAddress gw = platform.GateWay();
+ reply.printf("Gateway: %d.%d.%d.%d ", gw.GetQuad(0), gw.GetQuad(1), gw.GetQuad(2), gw.GetQuad(3));
}
}
- else
+ break;
+
+ case 555: // Set/report firmware type to emulate
+ if (gb.Seen('P'))
{
- const IPAddress gw = platform.GateWay();
- reply.printf("Gateway: %d.%d.%d.%d ", gw.GetQuad(0), gw.GetQuad(1), gw.GetQuad(2), gw.GetQuad(3));
+ gb.MachineState().compatibility = (Compatibility)gb.GetIValue();
}
- }
- break;
-
- case 555: // Set/report firmware type to emulate
- if (gb.Seen('P'))
- {
- gb.MachineState().compatibility = (Compatibility)gb.GetIValue();
- }
- else
- {
- reply.copy("Emulating ");
- switch (gb.MachineState().compatibility)
+ else
{
- case Compatibility::me:
- case Compatibility::reprapFirmware:
- reply.cat("RepRapFirmware (i.e. in native mode)");
- break;
+ reply.copy("Emulating ");
+ switch (gb.MachineState().compatibility)
+ {
+ case Compatibility::me:
+ case Compatibility::reprapFirmware:
+ reply.cat("RepRapFirmware (i.e. in native mode)");
+ break;
- case Compatibility::marlin:
- reply.cat("Marlin");
- break;
+ case Compatibility::marlin:
+ reply.cat("Marlin");
+ break;
- case Compatibility::teacup:
- reply.cat("Teacup");
- break;
+ case Compatibility::teacup:
+ reply.cat("Teacup");
+ break;
- case Compatibility::sprinter:
- reply.cat("Sprinter");
- break;
+ case Compatibility::sprinter:
+ reply.cat("Sprinter");
+ break;
- case Compatibility::repetier:
- reply.cat("Repetier");
- break;
+ case Compatibility::repetier:
+ reply.cat("Repetier");
+ break;
- case Compatibility::nanoDLP:
- reply.cat("nanoDLP");
- break;
+ case Compatibility::nanoDLP:
+ reply.cat("nanoDLP");
+ break;
- default:
- reply.catf("Unknown: (%u)", (unsigned int)gb.MachineState().compatibility);
+ default:
+ reply.catf("Unknown: (%u)", (unsigned int)gb.MachineState().compatibility);
+ }
}
- }
- break;
+ break;
- case 556: // Axis compensation (we support only X, Y, Z)
- if (gb.Seen('S'))
- {
- const float value = gb.GetFValue();
- if (value >= 10.0) // avoid divide by zero and silly results
+ case 556: // Axis compensation (we support only X, Y, Z)
+ if (gb.Seen('S'))
{
- for (size_t axis = 0; axis <= Z_AXIS; axis++)
+ const float value = gb.GetFValue();
+ if (value >= 10.0) // avoid divide by zero and silly results
{
- if (gb.Seen(axisLetters[axis]))
+ for (size_t axis = 0; axis <= Z_AXIS; axis++)
{
- reprap.GetMove().SetAxisCompensation(axis, gb.GetFValue() / value);
+ if (gb.Seen(axisLetters[axis]))
+ {
+ reprap.GetMove().SetAxisCompensation(axis, gb.GetFValue() / value);
+ }
}
}
}
- }
- else
- {
- reply.printf("Axis compensations - XY: %.5f, YZ: %.5f, ZX: %.5f",
- (double)reprap.GetMove().AxisCompensation(X_AXIS), (double)reprap.GetMove().AxisCompensation(Y_AXIS), (double)reprap.GetMove().AxisCompensation(Z_AXIS));
- }
- break;
-
- case 557: // Set/report Z probe point coordinates
- result = DefineGrid(gb, reply);
- break;
-
- case 558: // Set or report Z probe type and for which axes it is used
- result = platform.GetEndstops().HandleM558(gb, reply);
- break;
-
-#if HAS_MASS_STORAGE
- case 559:
- case 560: // Binary writing
- {
- String<MaxFilenameLength> sysDir;
- const char* defaultFile;
- const char *folder;
- if (code == 560)
- {
- folder = platform.GetWebDir();
- defaultFile = INDEX_PAGE_FILE;
- }
else
{
- platform.GetSysDir(sysDir.GetRef());
- folder = sysDir.c_str();
- defaultFile = platform.GetConfigFile();
+ reply.printf("Axis compensations - XY: %.5f, YZ: %.5f, ZX: %.5f",
+ (double)reprap.GetMove().AxisCompensation(X_AXIS), (double)reprap.GetMove().AxisCompensation(Y_AXIS), (double)reprap.GetMove().AxisCompensation(Z_AXIS));
}
- String<MaxFilenameLength> filename;
- if (gb.Seen('P'))
- {
- gb.GetPossiblyQuotedString(filename.GetRef());
- }
- else
- {
- filename.copy(defaultFile);
- }
- const FilePosition size = (gb.Seen('S') ? (FilePosition)gb.GetIValue() : 0);
- const uint32_t crc32 = (gb.Seen('C') ? gb.GetUIValue() : 0);
- const bool ok = gb.OpenFileToWrite(folder, filename.c_str(), size, true, crc32);
- if (ok)
- {
- reply.printf("Writing to file: %s", filename.c_str());
- }
- else
- {
- reply.printf("Can't open file %s for writing.", filename.c_str());
- result = GCodeResult::error;
- }
- }
- break;
-#endif
-
- case 561: // Set identity transform and disable height map
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- ClearBedMapping();
- break;
+ break;
- case 562: // Reset temperature fault - use with great caution
- if (gb.Seen('P'))
- {
- const unsigned int heater = gb.GetUIValue();
- if (heater < MaxHeaters)
- {
- result = reprap.ClearTemperatureFault(heater, reply);
- }
- else
- {
- reply.printf("Invalid heater number '%d'", heater);
- result = GCodeResult::error;
- }
- }
- else
- {
- // Clear all heater faults
- for (unsigned int heater = 0; heater < MaxHeaters; ++heater)
- {
- result = max<GCodeResult>(result, reprap.ClearTemperatureFault(heater, reply));
- }
- }
- heaterFaultState = HeaterFaultState::noFault;
- break;
+ case 557: // Set/report Z probe point coordinates
+ result = DefineGrid(gb, reply);
+ break;
- case 563: // Define tool
- result = ManageTool(gb, reply);
- break;
+ case 558: // Set or report Z probe type and for which axes it is used
+ result = platform.GetEndstops().HandleM558(gb, reply);
+ break;
- case 564: // Think outside the box?
- {
- bool seen = false;
- if (gb.Seen('S'))
- {
- seen = true;
- limitAxes = (gb.GetIValue() > 0);
- }
- if (gb.Seen('H'))
+#if HAS_MASS_STORAGE
+ case 559:
+ case 560: // Binary writing
{
- seen = true;
- noMovesBeforeHoming = (gb.GetIValue() > 0);
+ String<MaxFilenameLength> sysDir;
+ const char* defaultFile;
+ const char *folder;
+ if (code == 560)
+ {
+ folder = platform.GetWebDir();
+ defaultFile = INDEX_PAGE_FILE;
+ }
+ else
+ {
+ platform.GetSysDir(sysDir.GetRef());
+ folder = sysDir.c_str();
+ defaultFile = platform.GetConfigFile();
+ }
+ String<MaxFilenameLength> filename;
+ if (gb.Seen('P'))
+ {
+ gb.GetPossiblyQuotedString(filename.GetRef());
+ }
+ else
+ {
+ filename.copy(defaultFile);
+ }
+ const FilePosition size = (gb.Seen('S') ? (FilePosition)gb.GetIValue() : 0);
+ const uint32_t crc32 = (gb.Seen('C') ? gb.GetUIValue() : 0);
+ const bool ok = gb.OpenFileToWrite(folder, filename.c_str(), size, true, crc32);
+ if (ok)
+ {
+ reply.printf("Writing to file: %s", filename.c_str());
+ }
+ else
+ {
+ reply.printf("Can't open file %s for writing.", filename.c_str());
+ result = GCodeResult::error;
+ }
}
- if (!seen)
+ break;
+#endif
+
+ case 561: // Set identity transform and disable height map
+ if (!LockMovementAndWaitForStandstill(gb))
{
- reply.printf("Movement outside the bed is %spermitted, movement before homing is %spermitted", (limitAxes) ? "not " : "", (noMovesBeforeHoming) ? "not " : "");
+ return false;
}
- }
- break;
+ ClearBedMapping();
+ break;
- case 205: // Set/print maximum jerk speeds in mm/sec
- case 566: // Set/print maximum jerk speeds in mm/min
- {
- const float multiplier1 = (code == 566) ? SecondsToMinutes : 1.0;
- bool seen = false;
- for (size_t axis = 0; axis < numTotalAxes; axis++)
+ case 562: // Reset temperature fault - use with great caution
+ if (gb.Seen('P'))
{
- if (gb.Seen(axisLetters[axis]))
+ const unsigned int heater = gb.GetUIValue();
+ if (heater < MaxHeaters)
{
- platform.SetInstantDv(axis, gb.GetDistance() * multiplier1);
- seen = true;
+ result = reprap.ClearTemperatureFault(heater, reply);
+ }
+ else
+ {
+ reply.printf("Invalid heater number '%d'", heater);
+ result = GCodeResult::error;
}
}
-
- if (gb.Seen(extrudeLetter))
+ else
{
- seen = true;
- float eVals[MaxExtruders];
- size_t eCount = numExtruders;
- gb.GetFloatArray(eVals, eCount, true);
- for (size_t e = 0; e < eCount; e++)
+ // Clear all heater faults
+ for (unsigned int heater = 0; heater < MaxHeaters; ++heater)
{
- platform.SetInstantDv(ExtruderToLogicalDrive(e), eVals[e] * multiplier1);
+ result = max<GCodeResult>(result, reprap.ClearTemperatureFault(heater, reply));
}
}
+ heaterFaultState = HeaterFaultState::noFault;
+ break;
- if (code == 566 && gb.Seen('P'))
- {
- seen = true;
- reprap.GetMove().SetJerkPolicy(gb.GetUIValue());
- }
+ case 563: // Define tool
+ result = ManageTool(gb, reply);
+ break;
- if (!seen)
+ case 564: // Think outside the box?
{
- const float multiplier2 = (code == 566) ? MinutesToSeconds : 1.0;
- reply.printf("Maximum jerk rates (mm/%s): ", (code == 566) ? "min" : "sec");
- for (size_t axis = 0; axis < numTotalAxes; ++axis)
+ bool seen = false;
+ if (gb.Seen('S'))
{
- reply.catf("%c: %.1f, ", axisLetters[axis], (double)(platform.GetInstantDv(axis) * multiplier2));
+ seen = true;
+ limitAxes = (gb.GetIValue() > 0);
}
- reply.cat("E:");
- char sep = ' ';
- for (size_t extruder = 0; extruder < numExtruders; extruder++)
+ if (gb.Seen('H'))
{
- reply.catf("%c%.1f", sep, (double)(platform.GetInstantDv(ExtruderToLogicalDrive(extruder)) * multiplier2));
- sep = ':';
+ seen = true;
+ noMovesBeforeHoming = (gb.GetIValue() > 0);
}
- if (code == 566)
+ if (!seen)
{
- reply.catf(", jerk policy: %u", reprap.GetMove().GetJerkPolicy());
+ reply.printf("Movement outside the bed is %spermitted, movement before homing is %spermitted", (limitAxes) ? "not " : "", (noMovesBeforeHoming) ? "not " : "");
}
}
- }
- break;
+ break;
- case 567: // Set/report tool mix ratios
- if (gb.Seen('P'))
- {
- const int8_t tNumber = gb.GetIValue();
- Tool* const tool = reprap.GetTool(tNumber);
- if (tool != nullptr)
+ case 205: // Set/print maximum jerk speeds in mm/sec
+ case 566: // Set/print maximum jerk speeds in mm/min
{
- if (gb.Seen(extrudeLetter))
+ const float multiplier1 = (code == 566) ? SecondsToMinutes : 1.0;
+ bool seen = false;
+ for (size_t axis = 0; axis < numTotalAxes; axis++)
{
- float eVals[MaxExtruders];
- size_t eCount = tool->DriveCount();
- gb.GetFloatArray(eVals, eCount, false);
- if (eCount != tool->DriveCount())
+ if (gb.Seen(axisLetters[axis]))
{
- reply.copy("Setting mix ratios - wrong number of E drives: ");
- gb.AppendFullCommand(reply);
+ platform.SetInstantDv(axis, gb.GetDistance() * multiplier1);
+ seen = true;
}
- else
+ }
+
+ if (gb.Seen(extrudeLetter))
+ {
+ seen = true;
+ float eVals[MaxExtruders];
+ size_t eCount = numExtruders;
+ gb.GetFloatArray(eVals, eCount, true);
+ for (size_t e = 0; e < eCount; e++)
{
- tool->DefineMix(eVals);
+ platform.SetInstantDv(ExtruderToLogicalDrive(e), eVals[e] * multiplier1);
}
}
- else
+
+ if (code == 566 && gb.Seen('P'))
{
- reply.printf("Tool %d mix ratios:", tNumber);
+ seen = true;
+ reprap.GetMove().SetJerkPolicy(gb.GetUIValue());
+ }
+
+ if (!seen)
+ {
+ const float multiplier2 = (code == 566) ? MinutesToSeconds : 1.0;
+ reply.printf("Maximum jerk rates (mm/%s): ", (code == 566) ? "min" : "sec");
+ for (size_t axis = 0; axis < numTotalAxes; ++axis)
+ {
+ reply.catf("%c: %.1f, ", axisLetters[axis], (double)(platform.GetInstantDv(axis) * multiplier2));
+ }
+ reply.cat("E:");
char sep = ' ';
- for (size_t drive = 0; drive < tool->DriveCount(); drive++)
+ for (size_t extruder = 0; extruder < numExtruders; extruder++)
{
- reply.catf("%c%.3f", sep, (double)tool->GetMix()[drive]);
+ reply.catf("%c%.1f", sep, (double)(platform.GetInstantDv(ExtruderToLogicalDrive(extruder)) * multiplier2));
sep = ':';
}
+ if (code == 566)
+ {
+ reply.catf(", jerk policy: %u", reprap.GetMove().GetJerkPolicy());
+ }
}
}
- }
- break;
-
- case 568: // Turn on/off automatic tool mixing
- reply.copy("The M568 command is no longer needed");
- break;
-
- case 569: // Set/report axis direction
- result = ConfigureDriver(gb, reply);
- break;
+ break;
- case 570: // Set/report heater monitoring
- {
- bool seen = false;
- if (gb.Seen('S'))
- {
- seen = true;
- heaterFaultTimeout = gb.GetUIValue() * (60 * 1000);
- }
- if (gb.Seen('H'))
+ case 567: // Set/report tool mix ratios
+ if (gb.Seen('P'))
{
- seen = true;
- result = reprap.GetHeat().ConfigureHeaterMonitoring(gb.GetUIValue(), gb, reply);
+ const int8_t tNumber = gb.GetIValue();
+ Tool* const tool = reprap.GetTool(tNumber);
+ if (tool != nullptr)
+ {
+ if (gb.Seen(extrudeLetter))
+ {
+ float eVals[MaxExtruders];
+ size_t eCount = tool->DriveCount();
+ gb.GetFloatArray(eVals, eCount, false);
+ if (eCount != tool->DriveCount())
+ {
+ reply.copy("Setting mix ratios - wrong number of E drives: ");
+ gb.AppendFullCommand(reply);
+ }
+ else
+ {
+ tool->DefineMix(eVals);
+ }
+ }
+ else
+ {
+ reply.printf("Tool %d mix ratios:", tNumber);
+ char sep = ' ';
+ for (size_t drive = 0; drive < tool->DriveCount(); drive++)
+ {
+ reply.catf("%c%.3f", sep, (double)tool->GetMix()[drive]);
+ sep = ':';
+ }
+ }
+ }
}
- if (!seen)
+ break;
+
+ case 568: // Turn on/off automatic tool mixing
+ reply.copy("The M568 command is no longer needed");
+ break;
+
+ case 569: // Set/report axis direction
+ result = ConfigureDriver(gb, reply);
+ break;
+
+ case 570: // Set/report heater monitoring
{
- reply.printf("Print will be terminated if a heater fault is not reset within %" PRIu32 " minutes", heaterFaultTimeout/(60 * 1000));
+ bool seen = false;
+ if (gb.Seen('S'))
+ {
+ seen = true;
+ heaterFaultTimeout = gb.GetUIValue() * (60 * 1000);
+ }
+ if (gb.Seen('H'))
+ {
+ seen = true;
+ result = reprap.GetHeat().ConfigureHeaterMonitoring(gb.GetUIValue(), gb, reply);
+ }
+ if (!seen)
+ {
+ reply.printf("Print will be terminated if a heater fault is not reset within %" PRIu32 " minutes", heaterFaultTimeout/(60 * 1000));
+ }
}
- }
- break;
+ break;
- case 571: // Set output on extrude
- result = platform.GetSetAncillaryPwm(gb, reply);
- break;
+ case 571: // Set output on extrude
+ result = platform.GetSetAncillaryPwm(gb, reply);
+ break;
- case 572: // Set/report pressure advance
- if (gb.Seen('S'))
- {
- const float advance = gb.GetFValue();
- if (!LockMovementAndWaitForStandstill(gb))
+ case 572: // Set/report pressure advance
+ if (gb.Seen('S'))
{
- return false;
+ const float advance = gb.GetFValue();
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ result = platform.SetPressureAdvance(advance, gb, reply);
}
- result = platform.SetPressureAdvance(advance, gb, reply);
- }
- else
- {
- reply.copy("Extruder pressure advance");
- char c = ':';
- for (size_t i = 0; i < numExtruders; ++i)
+ else
{
- reply.catf("%c %.3f", c, (double)platform.GetPressureAdvance(i));
- c = ',';
+ reply.copy("Extruder pressure advance");
+ char c = ':';
+ for (size_t i = 0; i < numExtruders; ++i)
+ {
+ reply.catf("%c %.3f", c, (double)platform.GetPressureAdvance(i));
+ c = ',';
+ }
}
- }
- break;
+ break;
- case 573: // Report heater average PWM
- if (gb.Seen('P'))
- {
- const unsigned int heater = gb.GetUIValue();
- if (heater < MaxHeaters)
+ case 573: // Report heater average PWM
+ if (gb.Seen('P'))
{
- reply.printf("Average heater %u PWM: %.3f", heater, (double)reprap.GetHeat().GetAveragePWM(heater));
+ const unsigned int heater = gb.GetUIValue();
+ if (heater < MaxHeaters)
+ {
+ reply.printf("Average heater %u PWM: %.3f", heater, (double)reprap.GetHeat().GetAveragePWM(heater));
+ }
}
- }
- break;
+ break;
- case 574: // Set endstop configuration
- // We may be about to delete endstops, so make sure we are not executing a move that uses them
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- result = platform.GetEndstops().HandleM574(gb, reply, outBuf);
- break;
+ case 574: // Set endstop configuration
+ // We may be about to delete endstops, so make sure we are not executing a move that uses them
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
+ }
+ result = platform.GetEndstops().HandleM574(gb, reply, outBuf);
+ break;
- case 575: // Set communications parameters
- if (gb.Seen('P'))
- {
- size_t chan = gb.GetIValue();
- if (chan < NUM_SERIAL_CHANNELS)
+ case 575: // Set communications parameters
{
- bool seen = false;
- if (gb.Seen('B'))
- {
- platform.SetBaudRate(chan, gb.GetIValue());
- seen = true;
- }
- if (gb.Seen('S'))
+ gb.MustSee('P');
+ size_t chan = gb.GetIValue();
+ if (chan < NUM_SERIAL_CHANNELS)
{
- uint32_t val = gb.GetIValue();
- platform.SetCommsProperties(chan, val);
- switch (chan)
+ bool seen = false;
+ if (gb.Seen('B'))
{
- case 0:
- usbGCode->SetCommsProperties(val);
- break;
- case 1:
- if (auxGCode != nullptr)
+ platform.SetBaudRate(chan, gb.GetIValue());
+ seen = true;
+ }
+ if (gb.Seen('S'))
+ {
+ uint32_t val = gb.GetIValue();
+ platform.SetCommsProperties(chan, val);
+ switch (chan)
{
- auxGCode->SetCommsProperties(val);
- platform.SetAuxDetected();
+ case 0:
+ usbGCode->SetCommsProperties(val);
+ break;
+ case 1:
+ if (auxGCode != nullptr)
+ {
+ auxGCode->SetCommsProperties(val);
+ platform.SetAuxDetected();
+ }
+ break;
+ default:
+ break;
}
- break;
- default:
- break;
+ seen = true;
+ }
+ if (!seen)
+ {
+ uint32_t cp = platform.GetCommsProperties(chan);
+ reply.printf("Channel %d: baud rate %" PRIu32 ", %s checksum", chan, platform.GetBaudRate(chan), (cp & 1) ? "requires" : "does not require");
}
- seen = true;
- }
- if (!seen)
- {
- uint32_t cp = platform.GetCommsProperties(chan);
- reply.printf("Channel %d: baud rate %" PRIu32 ", %s checksum", chan, platform.GetBaudRate(chan), (cp & 1) ? "requires" : "does not require");
}
}
- }
- break;
+ break;
- case 577: // Wait until endstop input is triggered
- result = WaitForPin(gb, reply);
- break;
+ case 577: // Wait until endstop input is triggered
+ result = WaitForPin(gb, reply);
+ break;
#if SUPPORT_INKJET
- case 578: // Fire Inkjet bits
- if (!LockMovementAndWaitForStandstill())
- {
- return false;
- }
-
- if (gb.Seen('S')) // Need to handle the 'P' parameter too; see http://reprap.org/wiki/G-code#M578:_Fire_inkjet_bits
- {
- platform.Inkjet(gb.GetIValue());
- }
- break;
-#endif
+ case 578: // Fire Inkjet bits
+ if (!LockMovementAndWaitForStandstill())
+ {
+ return false;
+ }
- case 579: // Scale Cartesian axes (mostly for Delta configurations)
- {
- bool seen = false;
- for (size_t axis = 0; axis < numVisibleAxes; axis++)
+ if (gb.Seen('S')) // Need to handle the 'P' parameter too; see http://reprap.org/wiki/G-code#M578:_Fire_inkjet_bits
{
- gb.TryGetFValue(axisLetters[axis], axisScaleFactors[axis], seen);
+ platform.Inkjet(gb.GetIValue());
}
+ break;
+#endif
- if (!seen)
+ case 579: // Scale Cartesian axes (mostly for Delta configurations)
{
- char sep = ':';
- reply.copy("Axis scale factors");
- for(size_t axis = 0; axis < numVisibleAxes; axis++)
+ bool seen = false;
+ for (size_t axis = 0; axis < numVisibleAxes; axis++)
{
- reply.catf("%c %c: %.3f", sep, axisLetters[axis], (double)axisScaleFactors[axis]);
- sep = ',';
+ gb.TryGetFValue(axisLetters[axis], axisScaleFactors[axis], seen);
+ }
+
+ if (!seen)
+ {
+ char sep = ':';
+ reply.copy("Axis scale factors");
+ for(size_t axis = 0; axis < numVisibleAxes; axis++)
+ {
+ reply.catf("%c %c: %.3f", sep, axisLetters[axis], (double)axisScaleFactors[axis]);
+ sep = ',';
+ }
}
}
- }
- break;
+ break;
#if SUPPORT_ROLAND
- case 580: // (De)Select Roland mill
- if (gb.Seen('R'))
- {
- if (gb.GetIValue())
+ case 580: // (De)Select Roland mill
+ if (gb.Seen('R'))
{
- reprap.GetRoland()->Activate();
- if (gb.Seen('P'))
+ if (gb.GetIValue())
+ {
+ reprap.GetRoland()->Activate();
+ if (gb.Seen('P'))
+ {
+ result = reprap.GetRoland()->RawWrite(gb.GetString());
+ }
+ }
+ else
{
- result = reprap.GetRoland()->RawWrite(gb.GetString());
+ result = reprap.GetRoland()->Deactivate();
}
}
else
{
- result = reprap.GetRoland()->Deactivate();
+ reply.printf("Roland is %s.", reprap.GetRoland()->Active() ? "active" : "inactive");
}
- }
- else
- {
- reply.printf("Roland is %s.", reprap.GetRoland()->Active() ? "active" : "inactive");
- }
- break;
+ break;
#endif
- case 581: // Configure external trigger
- result = ConfigureTrigger(gb, reply, code);
- break;
-
- case 582: // Check external trigger
- result = CheckTrigger(gb, reply, code);
- break;
+ case 581: // Configure external trigger
+ result = ConfigureTrigger(gb, reply, code);
+ break;
- case 584: // Set axis/extruder to stepper driver(s) mapping
- result = DoDriveMapping(gb, reply);
- break;
+ case 582: // Check external trigger
+ result = CheckTrigger(gb, reply, code);
+ break;
- case 585: // Probe Tool
- result = ProbeTool(gb, reply);
- break;
+ case 584: // Set axis/extruder to stepper driver(s) mapping
+ result = DoDriveMapping(gb, reply);
+ break;
- case 586: // Configure network protocols
- {
- const unsigned int interface = (gb.Seen('I') ? gb.GetUIValue() : 0);
+ case 585: // Probe Tool
+ result = ProbeTool(gb, reply);
+ break;
- if (gb.Seen('P'))
+ case 586: // Configure network protocols
{
- const unsigned int protocol = gb.GetUIValue();
- if (gb.Seen('S'))
+ const unsigned int interface = (gb.Seen('I') ? gb.GetUIValue() : 0);
+
+ if (gb.Seen('P'))
{
- const bool enable = (gb.GetIValue() == 1);
- if (enable)
+ const unsigned int protocol = gb.GetUIValue();
+ if (gb.Seen('S'))
{
- const int port = (gb.Seen('R')) ? gb.GetIValue() : -1;
- const int secure = (gb.Seen('T')) ? gb.GetIValue() : -1;
- result = reprap.GetNetwork().EnableProtocol(interface, protocol, port, secure, reply);
- }
- else
- {
- result = reprap.GetNetwork().DisableProtocol(interface, protocol, reply);
+ const bool enable = (gb.GetIValue() == 1);
+ if (enable)
+ {
+ const int port = (gb.Seen('R')) ? gb.GetIValue() : -1;
+ const int secure = (gb.Seen('T')) ? gb.GetIValue() : -1;
+ result = reprap.GetNetwork().EnableProtocol(interface, protocol, port, secure, reply);
+ }
+ else
+ {
+ result = reprap.GetNetwork().DisableProtocol(interface, protocol, reply);
+ }
}
}
+ else
+ {
+ // Default to reporting current protocols if P or S parameter missing
+ result = reprap.GetNetwork().ReportProtocols(interface, reply);
+ }
}
- else
- {
- // Default to reporting current protocols if P or S parameter missing
- result = reprap.GetNetwork().ReportProtocols(interface, reply);
- }
- }
- break;
+ break;
#if HAS_WIFI_NETWORKING
- case 587: // Add WiFi network or list remembered networks
- case 588: // Forget WiFi network
- case 589: // Configure access point
- if (!gb.MachineState().runningM502) // when running M502 we don't execute network-related commands
- {
- result = reprap.GetNetwork().HandleWiFiCode(code, gb, reply, outBuf);
- }
- break;
+ case 587: // Add WiFi network or list remembered networks
+ case 588: // Forget WiFi network
+ case 589: // Configure access point
+ if (!gb.MachineState().runningM502) // when running M502 we don't execute network-related commands
+ {
+ result = reprap.GetNetwork().HandleWiFiCode(code, gb, reply, outBuf);
+ }
+ break;
#endif
- case 591: // Configure filament sensor
- if (gb.Seen('D'))
- {
- const unsigned int extruder = gb.GetUIValue();
- if (extruder < numExtruders)
+ case 591: // Configure filament sensor
{
- result = FilamentMonitor::Configure(gb, reply, extruder);
+ gb.MustSee('D');
+ const unsigned int extruder = gb.GetUIValue();
+ if (extruder < numExtruders)
+ {
+ result = FilamentMonitor::Configure(gb, reply, extruder);
+ }
}
- }
- break;
+ break;
#if SUPPORT_NONLINEAR_EXTRUSION
- case 592: // Configure nonlinear extrusion
- if (gb.Seen('D'))
- {
- const unsigned int extruder = gb.GetUIValue();
- bool seen = false;
- float a = 0.0, b = 0.0, limit = DefaultNonlinearExtrusionLimit;
- gb.TryGetFValue('A', a, seen);
- gb.TryGetFValue('B', b, seen);
- gb.TryGetFValue('L', limit, seen);
- if (seen)
+ case 592: // Configure nonlinear extrusion
{
- platform.SetNonlinearExtrusion(extruder, a, b, limit);
- }
- else
- {
- platform.GetExtrusionCoefficients(extruder, a, b, limit);
- reply.printf("Drive %u nonlinear extrusion coefficients: A=%.3f, B=%.4f, limit=%.2f", extruder, (double)a, (double)b, (double)limit);
+ gb.MustSee('D');
+ const unsigned int extruder = gb.GetUIValue();
+ bool seen = false;
+ float a = 0.0, b = 0.0, limit = DefaultNonlinearExtrusionLimit;
+ gb.TryGetFValue('A', a, seen);
+ gb.TryGetFValue('B', b, seen);
+ gb.TryGetFValue('L', limit, seen);
+ if (seen)
+ {
+ platform.SetNonlinearExtrusion(extruder, a, b, limit);
+ }
+ else
+ {
+ platform.GetExtrusionCoefficients(extruder, a, b, limit);
+ reply.printf("Drive %u nonlinear extrusion coefficients: A=%.3f, B=%.4f, limit=%.2f", extruder, (double)a, (double)b, (double)limit);
+ }
}
- }
- break;
+ break;
#endif
- case 593: // Configure dynamic ringing cancellation
- result = reprap.GetMove().ConfigureDynamicAcceleration(gb, reply);
- break;
+ case 593: // Configure dynamic ringing cancellation
+ result = reprap.GetMove().ConfigureDynamicAcceleration(gb, reply);
+ break;
#if SUPPORT_ASYNC_MOVES
- case 594: // Enter or leave height following mode
- result = reprap.GetMove().StartHeightFollowing(gb, reply);
- break;
+ case 594: // Enter or leave height following mode
+ result = reprap.GetMove().StartHeightFollowing(gb, reply);
+ break;
#endif
- // For case 600, see 226
+ // For case 600, see 226
- // M650 (set peel move parameters) and M651 (execute peel move) are no longer handled specially. Use macros to specify what they should do.
+ // M650 (set peel move parameters) and M651 (execute peel move) are no longer handled specially. Use macros to specify what they should do.
- case 665: // Set delta configuration
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- {
- Move& move = reprap.GetMove();
-
- bool changedMode = false;
- if ((gb.Seen('L') || gb.Seen('D')) && move.GetKinematics().GetKinematicsType() != KinematicsType::linearDelta)
+ case 665: // Set delta configuration
+ if (!LockMovementAndWaitForStandstill(gb))
{
- // Not in delta mode, so switch to it
- changedMode = true;
- move.SetKinematics(KinematicsType::linearDelta);
+ return false;
}
- bool error = false;
- const bool changed = move.GetKinematics().Configure(code, gb, reply, error);
- if (changedMode)
{
- move.GetKinematics().GetAssumedInitialPosition(numVisibleAxes, moveBuffer.coords);
- ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition);
+ Move& move = reprap.GetMove();
+
+ bool changedMode = false;
+ if ((gb.Seen('L') || gb.Seen('D')) && move.GetKinematics().GetKinematicsType() != KinematicsType::linearDelta)
+ {
+ // Not in delta mode, so switch to it
+ changedMode = true;
+ move.SetKinematics(KinematicsType::linearDelta);
+ }
+ bool error = false;
+ const bool changed = move.GetKinematics().Configure(code, gb, reply, error);
+ if (changedMode)
+ {
+ move.GetKinematics().GetAssumedInitialPosition(numVisibleAxes, moveBuffer.coords);
+ ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition);
+ }
+ if (changed || changedMode)
+ {
+ if (reprap.GetMove().GetKinematics().LimitPosition(moveBuffer.coords, nullptr, numVisibleAxes, axesHomed, false, false) != LimitPositionResult::ok)
+ {
+ ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); // make sure the limits are reflected in the user position
+ }
+ reprap.GetMove().SetNewPosition(moveBuffer.coords, true);
+ SetAllAxesNotHomed();
+ }
+ result = GetGCodeResultFromError(error);
+ }
+ break;
+
+ case 666: // Set delta endstop adjustments
+ if (!LockMovementAndWaitForStandstill(gb))
+ {
+ return false;
}
- if (changed || changedMode)
{
- if (reprap.GetMove().GetKinematics().LimitPosition(moveBuffer.coords, nullptr, numVisibleAxes, axesHomed, false, false) != LimitPositionResult::ok)
+ bool error = false;
+ const bool changed = reprap.GetMove().GetKinematics().Configure(code, gb, reply, error);
+ if (changed)
{
- ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); // make sure the limits are reflected in the user position
+ SetAllAxesNotHomed();
}
- reprap.GetMove().SetNewPosition(moveBuffer.coords, true);
- SetAllAxesNotHomed();
+ result = GetGCodeResultFromError(error);
}
- result = GetGCodeResultFromError(error);
- }
- break;
+ break;
- case 666: // Set delta endstop adjustments
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- {
- bool error = false;
- const bool changed = reprap.GetMove().GetKinematics().Configure(code, gb, reply, error);
- if (changed)
+ case 667: // Set CoreXY mode
+ if (!LockMovementAndWaitForStandstill(gb))
{
- SetAllAxesNotHomed();
+ return false;
}
- result = GetGCodeResultFromError(error);
- }
- break;
-
- case 667: // Set CoreXY mode
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- {
- Move& move = reprap.GetMove();
- const KinematicsType oldK = move.GetKinematics().GetKinematicsType(); // get the current kinematics type so we can tell whether it changed
-
- bool seen = false;
- if (gb.Seen('S'))
{
- // Switch to the correct CoreXY mode
- const int mode = gb.GetIValue();
- switch (mode)
+ Move& move = reprap.GetMove();
+ const KinematicsType oldK = move.GetKinematics().GetKinematicsType(); // get the current kinematics type so we can tell whether it changed
+
+ bool seen = false;
+ if (gb.Seen('S'))
{
- case 0:
- move.SetKinematics(KinematicsType::cartesian);
- break;
+ // Switch to the correct CoreXY mode
+ const int mode = gb.GetIValue();
+ switch (mode)
+ {
+ case 0:
+ move.SetKinematics(KinematicsType::cartesian);
+ break;
- case 1:
- move.SetKinematics(KinematicsType::coreXY);
- break;
+ case 1:
+ move.SetKinematics(KinematicsType::coreXY);
+ break;
- case 2:
- move.SetKinematics(KinematicsType::coreXZ);
- break;
+ case 2:
+ move.SetKinematics(KinematicsType::coreXZ);
+ break;
- default:
- reply.printf("Mode %d is not valid", mode);
- result = GCodeResult::error;
- break;
+ default:
+ reply.printf("Mode %d is not valid", mode);
+ result = GCodeResult::error;
+ break;
+ }
+ seen = true;
+ }
+
+ if (result == GCodeResult::ok)
+ {
+ if (gb.Seen('X') || gb.Seen('Y') || gb.Seen('Z'))
+ {
+ reply.copy("M667 XYZ parameters are no longer supported, use M669 matrix parameters instead");
+ result = GCodeResult::error;
+ }
+
+ if (seen)
+ {
+ // We changed something, so reset the positions and set all axes not homed
+ if (move.GetKinematics().GetKinematicsType() != oldK)
+ {
+ move.GetKinematics().GetAssumedInitialPosition(numVisibleAxes, moveBuffer.coords);
+ ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition);
+ }
+ if (reprap.GetMove().GetKinematics().LimitPosition(moveBuffer.coords, nullptr, numVisibleAxes, axesHomed, false, false) != LimitPositionResult::ok)
+ {
+ ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); // make sure the limits are reflected in the user position
+ }
+ reprap.GetMove().SetNewPosition(moveBuffer.coords, true);
+ SetAllAxesNotHomed();
+ }
}
- seen = true;
}
+ break;
- if (result == GCodeResult::ok)
+ case 669: // Set kinematics and parameters for SCARA and other kinematics that don't use M665, M666 or M667
+ if (!LockMovementAndWaitForStandstill(gb))
{
- if (gb.Seen('X') || gb.Seen('Y') || gb.Seen('Z'))
+ return false;
+ }
+ {
+ Move& move = reprap.GetMove();
+ const KinematicsType oldK = move.GetKinematics().GetKinematicsType(); // get the current kinematics type so we can tell whether it changed
+
+ bool seen = false;
+ if (gb.Seen('K'))
{
- reply.copy("M667 XYZ parameters are no longer supported, use M669 matrix parameters instead");
- result = GCodeResult::error;
+ const int nk = gb.GetIValue();
+ if (nk < 0 || nk >= (int)KinematicsType::unknown || !move.SetKinematics(static_cast<KinematicsType>(nk)))
+ {
+ reply.printf("Unknown kinematics type %d", nk);
+ result = GCodeResult::error;
+ break;
+ }
+ seen = true;
}
+ bool error = false;
+ if (move.GetKinematics().Configure(code, gb, reply, error))
+ {
+ seen = true;
+ }
+ result = GetGCodeResultFromError(error);
if (seen)
{
- // We changed something, so reset the positions and set all axes not homed
+ // We changed something significant, so reset the positions and set all axes not homed
if (move.GetKinematics().GetKinematicsType() != oldK)
{
move.GetKinematics().GetAssumedInitialPosition(numVisibleAxes, moveBuffer.coords);
@@ -3778,272 +3763,224 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
SetAllAxesNotHomed();
}
}
- }
- break;
+ break;
- case 669: // Set kinematics and parameters for SCARA and other kinematics that don't use M665, M666 or M667
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- {
- Move& move = reprap.GetMove();
- const KinematicsType oldK = move.GetKinematics().GetKinematicsType(); // get the current kinematics type so we can tell whether it changed
+#if SUPPORT_IOBITS
+ case 670:
+ Move::CreateLaserTask();
+ result = GetGCodeResultFromError(reprap.GetPortControl().Configure(gb, reply));
+ break;
+#endif
- bool seen = false;
- if (gb.Seen('K'))
+ case 671: // Set Z leadscrew positions
+ if (!LockMovementAndWaitForStandstill(gb))
{
- const int nk = gb.GetIValue();
- if (nk < 0 || nk >= (int)KinematicsType::unknown || !move.SetKinematics(static_cast<KinematicsType>(nk)))
- {
- reply.printf("Unknown kinematics type %d", nk);
- result = GCodeResult::error;
- break;
- }
- seen = true;
+ return false;
}
- bool error = false;
- if (move.GetKinematics().Configure(code, gb, reply, error))
{
- seen = true;
+ bool error = false;
+ (void)reprap.GetMove().GetKinematics().Configure(code, gb, reply, error);
+ result = GetGCodeResultFromError(error);
}
- result = GetGCodeResultFromError(error);
+ break;
+
+ case 672: // Program Z probe
+ result = platform.GetEndstops().ProgramZProbe(gb, reply);
+ break;
- if (seen)
+ case 673: // Align plane on rotary axis
+ if (numTotalAxes < U_AXIS)
{
- // We changed something significant, so reset the positions and set all axes not homed
- if (move.GetKinematics().GetKinematicsType() != oldK)
+ reply.copy("Insufficient axes configured");
+ result = GCodeResult::error;
+ }
+ else if (LockMovementAndWaitForStandstill(gb))
+ {
+ if (reprap.GetMove().GetNumProbedProbePoints() < 2)
{
- move.GetKinematics().GetAssumedInitialPosition(numVisibleAxes, moveBuffer.coords);
- ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition);
+ reply.copy("Insufficient probe points");
+ result = GCodeResult::error;
}
- if (reprap.GetMove().GetKinematics().LimitPosition(moveBuffer.coords, nullptr, numVisibleAxes, axesHomed, false, false) != LimitPositionResult::ok)
+ else if (!AllAxesAreHomed())
{
- ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); // make sure the limits are reflected in the user position
+ reply.copy("Home the axes first");
+ result = GCodeResult::error;
}
- reprap.GetMove().SetNewPosition(moveBuffer.coords, true);
- SetAllAxesNotHomed();
- }
- }
- break;
-
-#if SUPPORT_IOBITS
- case 670:
- Move::CreateLaserTask();
- result = GetGCodeResultFromError(reprap.GetPortControl().Configure(gb, reply));
- break;
-#endif
+ else
+ {
+ // See which rotary axis needs to be compensated (if any)
+ size_t axisToUse = 0;
+ for (size_t axis = U_AXIS; axis < numVisibleAxes; axis++)
+ {
+ if (gb.Seen(axisLetters[axis]))
+ {
+ axisToUse = axis;
+ break;
+ }
+ }
- case 671: // Set Z leadscrew positions
- if (!LockMovementAndWaitForStandstill(gb))
- {
- return false;
- }
- {
- bool error = false;
- (void)reprap.GetMove().GetKinematics().Configure(code, gb, reply, error);
- result = GetGCodeResultFromError(error);
- }
- break;
+ // Get the coordinates of the first two G30 points and calculate how far off the axis is
+ float x1, y1, x2, y2;
+ const float z1 = reprap.GetMove().GetProbeCoordinates(0, x1, y1, true);
+ const float z2 = reprap.GetMove().GetProbeCoordinates(1, x2, y2, true);
+ const float a1 = (x1 == x2) ? y1 : x1;
+ const float a2 = (x1 == x2) ? y2 : x2;
- case 672: // Program Z probe
- result = platform.GetEndstops().ProgramZProbe(gb, reply);
- break;
+ // See what kind of compensation we need to perform
+ SetMoveBufferDefaults();
+ if (axisToUse != 0)
+ {
+ // An axis letter is given, so try to level the given axis
+ const float correctionAngle = atanf((z2 - z1) / (a2 - a1)) * 180.0 / M_PI;
+ const float correctionFactor = gb.Seen('S') ? gb.GetFValue() : 1.0;
+ moveBuffer.coords[axisToUse] += correctionAngle * correctionFactor;
- case 673: // Align plane on rotary axis
- if (numTotalAxes < U_AXIS)
- {
- reply.copy("Insufficient axes configured");
- result = GCodeResult::error;
- }
- else if (LockMovementAndWaitForStandstill(gb))
- {
- if (reprap.GetMove().GetNumProbedProbePoints() < 2)
- {
- reply.copy("Insufficient probe points");
- result = GCodeResult::error;
- }
- else if (!AllAxesAreHomed())
- {
- reply.copy("Home the axes first");
- result = GCodeResult::error;
- }
- else
- {
- // See which rotary axis needs to be compensated (if any)
- size_t axisToUse = 0;
- for (size_t axis = U_AXIS; axis < numVisibleAxes; axis++)
- {
- if (gb.Seen(axisLetters[axis]))
+ reply.printf("%c axis is off by %.2f deg", axisLetters[axisToUse], (double)correctionAngle);
+ HandleReply(gb, GCodeResult::notFinished, reply.c_str());
+ }
+ else if (reprap.GetMove().GetNumProbedProbePoints() >= 4)
{
- axisToUse = axis;
+ // At least four G30 points are given. This lets us figure out how far off the centre of the axis is
+ const float z3 = reprap.GetMove().GetProbeCoordinates(2, x1, y1, true);
+ const float z4 = reprap.GetMove().GetProbeCoordinates(3, x2, y2, true);
+ const float a3 = (x1 == x2) ? y1 : x1;
+ const float a4 = (x1 == x2) ? y2 : x2;
+
+ // Calculate intersection points in [XY] and Z directions
+ const float aS = ((a4 - a3) * (a2 * z1 - a1 * z2) - (a2 - a1) * (a4 * z3 - a3 * z4)) /
+ ((z4 - z3) * (a2 - a1) - (z2 - z1) * (a4 - a3));
+ const float zS = ((z1 - z2) * (a4 * z3 - a3 * z4) - (z3 - z4) * (a2 * z1 - a1 * z2)) /
+ ((z4 - z3) * (a2 - a1) - (z2 - z1) * (a4 - a3));
+ moveBuffer.coords[(x1 == x2) ? Y_AXIS : X_AXIS] += aS;
+ moveBuffer.coords[Z_AXIS] += zS;
+
+ reply.printf("%c is offset by %.2fmm, Z is offset by %.2fmm", (x2 == x1) ? 'Y' : 'X', (double)aS, (double)zS);
+ HandleReply(gb, GCodeResult::notFinished, reply.c_str());
+ }
+ else
+ {
+ reply.copy("No rotary axis letter and/or not enough probe points for rotary axis alignment");
+ result = GCodeResult::error;
break;
}
- }
-
- // Get the coordinates of the first two G30 points and calculate how far off the axis is
- float x1, y1, x2, y2;
- const float z1 = reprap.GetMove().GetProbeCoordinates(0, x1, y1, true);
- const float z2 = reprap.GetMove().GetProbeCoordinates(1, x2, y2, true);
- const float a1 = (x1 == x2) ? y1 : x1;
- const float a2 = (x1 == x2) ? y2 : x2;
- // See what kind of compensation we need to perform
- SetMoveBufferDefaults();
- if (axisToUse != 0)
- {
- // An axis letter is given, so try to level the given axis
- const float correctionAngle = atanf((z2 - z1) / (a2 - a1)) * 180.0 / M_PI;
- const float correctionFactor = gb.Seen('S') ? gb.GetFValue() : 1.0;
- moveBuffer.coords[axisToUse] += correctionAngle * correctionFactor;
+ // Get the feedrate (if any) and kick off a new move
+ if (gb.Seen(feedrateLetter))
+ {
+ const float rate = gb.ConvertDistance(gb.GetFValue());
+ gb.MachineState().feedRate = rate * SecondsToMinutes; // don't apply the speed factor
+ }
+ moveBuffer.feedRate = gb.MachineState().feedRate;
+ moveBuffer.usingStandardFeedrate = true;
+ NewMoveAvailable(1);
- reply.printf("%c axis is off by %.2f deg", axisLetters[axisToUse], (double)correctionAngle);
- HandleReply(gb, GCodeResult::notFinished, reply.c_str());
+ gb.SetState(GCodeState::waitingForSpecialMoveToComplete);
}
- else if (reprap.GetMove().GetNumProbedProbePoints() >= 4)
- {
- // At least four G30 points are given. This lets us figure out how far off the centre of the axis is
- const float z3 = reprap.GetMove().GetProbeCoordinates(2, x1, y1, true);
- const float z4 = reprap.GetMove().GetProbeCoordinates(3, x2, y2, true);
- const float a3 = (x1 == x2) ? y1 : x1;
- const float a4 = (x1 == x2) ? y2 : x2;
-
- // Calculate intersection points in [XY] and Z directions
- const float aS = ((a4 - a3) * (a2 * z1 - a1 * z2) - (a2 - a1) * (a4 * z3 - a3 * z4)) /
- ((z4 - z3) * (a2 - a1) - (z2 - z1) * (a4 - a3));
- const float zS = ((z1 - z2) * (a4 * z3 - a3 * z4) - (z3 - z4) * (a2 * z1 - a1 * z2)) /
- ((z4 - z3) * (a2 - a1) - (z2 - z1) * (a4 - a3));
- moveBuffer.coords[(x1 == x2) ? Y_AXIS : X_AXIS] += aS;
- moveBuffer.coords[Z_AXIS] += zS;
+ }
+ else
+ {
+ result = GCodeResult::notFinished;
+ }
+ break;
- reply.printf("%c is offset by %.2fmm, Z is offset by %.2fmm", (x2 == x1) ? 'Y' : 'X', (double)aS, (double)zS);
- HandleReply(gb, GCodeResult::notFinished, reply.c_str());
- }
- else
+#if false
+ // This code is not finished yet
+ case 674: // Set Z to center point
+ if (LockMovementAndWaitForStandstill(gb))
+ {
+ if (reprap.GetMove().GetNumProbedProbePoints() < 2)
{
- reply.copy("No rotary axis letter and/or not enough probe points for rotary axis alignment");
+ reply.copy("Insufficient probe points");
result = GCodeResult::error;
- break;
}
-
- // Get the feedrate (if any) and kick off a new move
- if (gb.Seen(feedrateLetter))
+ else if (!AllAxesAreHomed())
{
- const float rate = gb.ConvertDistance(gb.GetFValue());
- gb.MachineState().feedRate = rate * SecondsToMinutes; // don't apply the speed factor
+ reply.copy("Home the axes first");
+ result = GCodeResult::error;
}
- moveBuffer.feedRate = gb.MachineState().feedRate;
- moveBuffer.usingStandardFeedrate = true;
- NewMoveAvailable(1);
-
- gb.SetState(GCodeState::waitingForSpecialMoveToComplete);
- }
- }
- else
- {
- result = GCodeResult::notFinished;
- }
- break;
+ else
+ {
+ float x, y;
+ const float z1 = reprap.GetMove().GetProbeCoordinates(0, x, y, true);
+ const float z2 = reprap.GetMove().GetProbeCoordinates(1, x, y, true);
+ const float offset = gb.Seen('P') ? gb.GetFValue() : 0.0;
+ currentUserPosition[Z_AXIS] -= (z1 + z2) / 2.0 + offset;
-#if false
- // This code is not finished yet
- case 674: // Set Z to center point
- if (LockMovementAndWaitForStandstill(gb))
- {
- if (reprap.GetMove().GetNumProbedProbePoints() < 2)
- {
- reply.copy("Insufficient probe points");
- result = GCodeResult::error;
- }
- else if (!AllAxesAreHomed())
- {
- reply.copy("Home the axes first");
- result = GCodeResult::error;
- }
- else
- {
- float x, y;
- const float z1 = reprap.GetMove().GetProbeCoordinates(0, x, y, true);
- const float z2 = reprap.GetMove().GetProbeCoordinates(1, x, y, true);
- const float offset = gb.Seen('P') ? gb.GetFValue() : 0.0;
- currentUserPosition[Z_AXIS] -= (z1 + z2) / 2.0 + offset;
+ ToolOffsetTransform(currentUserPosition, moveBuffer.coords);
+ if (reprap.GetMove().GetKinematics().LimitPosition(moveBuffer.coords, numVisibleAxes, LowestNBits<AxesBitmap>(numVisibleAxes), false)) // pretend that all axes are homed
+ {
+ ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); // make sure the limits are reflected in the user position
+ }
+ reprap.GetMove().SetNewPosition(moveBuffer.coords, true);
+ axesHomed |= reprap.GetMove().GetKinematics().AxesAssumedHomed(MakeBitmap<AxesBitmap>(Z_AXIS));
- ToolOffsetTransform(currentUserPosition, moveBuffer.coords);
- if (reprap.GetMove().GetKinematics().LimitPosition(moveBuffer.coords, numVisibleAxes, LowestNBits<AxesBitmap>(numVisibleAxes), false)) // pretend that all axes are homed
- {
- ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); // make sure the limits are reflected in the user position
+ reply.printf("Probe points at %.2f %.2f, setting new Z to %.2f", (double)z1, (double)z2, (double)currentUserPosition[Z_AXIS]);
}
- reprap.GetMove().SetNewPosition(moveBuffer.coords, true);
- axesHomed |= reprap.GetMove().GetKinematics().AxesAssumedHomed(MakeBitmap<AxesBitmap>(Z_AXIS));
-
- reply.printf("Probe points at %.2f %.2f, setting new Z to %.2f", (double)z1, (double)z2, (double)currentUserPosition[Z_AXIS]);
}
- }
- break;
+ break;
#endif
- case 675: // Find center of cavity
- result = FindCenterOfCavity(gb, reply);
- break;
+ case 675: // Find center of cavity
+ result = FindCenterOfCavity(gb, reply);
+ break;
- case 701: // Load filament
- result = LoadFilament(gb, reply);
- break;
+ case 701: // Load filament
+ result = LoadFilament(gb, reply);
+ break;
- case 702: // Unload filament
- result = UnloadFilament(gb, reply);
- break;
+ case 702: // Unload filament
+ result = UnloadFilament(gb, reply);
+ break;
- case 703: // Configure Filament
- if (reprap.GetCurrentTool() != nullptr)
- {
- const Filament *filament = reprap.GetCurrentTool()->GetFilament();
- if (filament != nullptr && filament->IsLoaded())
+ case 703: // Configure Filament
+ if (reprap.GetCurrentTool() != nullptr)
{
- String<ScratchStringLength> scratchString;
- scratchString.printf("%s%s/%s", FILAMENTS_DIRECTORY, filament->GetName(), CONFIG_FILAMENT_G);
- DoFileMacro(gb, scratchString.c_str(), false, 703);
+ const Filament *filament = reprap.GetCurrentTool()->GetFilament();
+ if (filament != nullptr && filament->IsLoaded())
+ {
+ String<ScratchStringLength> scratchString;
+ scratchString.printf("%s%s/%s", FILAMENTS_DIRECTORY, filament->GetName(), CONFIG_FILAMENT_G);
+ DoFileMacro(gb, scratchString.c_str(), false, 703);
+ }
}
- }
- else
- {
- result = GCodeResult::error;
- reply.copy("No tool selected");
- }
- break;
+ else
+ {
+ result = GCodeResult::error;
+ reply.copy("No tool selected");
+ }
+ break;
#if SUPPORT_SCANNER
- case 750: // Enable 3D scanner extension
- reprap.GetScanner().Enable();
- break;
+ case 750: // Enable 3D scanner extension
+ reprap.GetScanner().Enable();
+ break;
- case 751: // Register 3D scanner extension over USB
- if (&gb == usbGCode)
- {
- if (reprap.GetScanner().IsEnabled())
+ case 751: // Register 3D scanner extension over USB
+ if (&gb == usbGCode)
{
- reprap.GetScanner().Register();
+ if (reprap.GetScanner().IsEnabled())
+ {
+ reprap.GetScanner().Register();
+ }
+ else
+ {
+ reply.copy("Scanner extension is not enabled");
+ result = GCodeResult::error;
+ }
}
else
{
- reply.copy("Scanner extension is not enabled");
+ reply.copy("Invalid source");
result = GCodeResult::error;
}
- }
- else
- {
- reply.copy("Invalid source");
- result = GCodeResult::error;
- }
- break;
+ break;
- case 752: // Start 3D scan
- if (gb.Seen('P'))
- {
- String<MaxFilenameLength> file;
- gb.GetPossiblyQuotedString(file.GetRef());
- if (gb.Seen('S'))
+ case 752: // Start 3D scan
{
+ gb.MustSee('P');
+ String<MaxFilenameLength> file;
+ gb.GetPossiblyQuotedString(file.GetRef());
+ gb.MustSee('S');
const int range = gb.GetIValue();
if (reprap.GetScanner().IsEnabled())
{
@@ -4065,402 +4002,397 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
result = GCodeResult::error;
}
}
- else
- {
- reply.copy("Missing length/degree parameter");
- result = GCodeResult::error;
- }
- }
- else
- {
- reply.copy("Missing filename");
- result = GCodeResult::error;
- }
- break;
+ break;
- case 753: // Cancel current 3D scanner action
- if (reprap.GetScanner().IsEnabled())
- {
- if (reprap.GetScanner().IsRegistered())
+ case 753: // Cancel current 3D scanner action
+ if (reprap.GetScanner().IsEnabled())
{
- result = GetGCodeResultFromFinished(reprap.GetScanner().Cancel());
+ if (reprap.GetScanner().IsRegistered())
+ {
+ result = GetGCodeResultFromFinished(reprap.GetScanner().Cancel());
+ }
+ else
+ {
+ reply.copy("Scanner is not registered");
+ result = GCodeResult::error;
+ }
}
else
{
- reply.copy("Scanner is not registered");
+ reply.copy("Scanner extension is not enabled");
result = GCodeResult::error;
}
- }
- else
- {
- reply.copy("Scanner extension is not enabled");
- result = GCodeResult::error;
- }
- break;
+ break;
- case 754: // Calibrate scanner
- if (reprap.GetScanner().IsEnabled())
- {
- if (reprap.GetScanner().IsRegistered())
+ case 754: // Calibrate scanner
+ if (reprap.GetScanner().IsEnabled())
{
- const int mode = gb.Seen('N') ? gb.GetIValue() : 0;
- result = GetGCodeResultFromFinished(reprap.GetScanner().Calibrate(mode));
+ if (reprap.GetScanner().IsRegistered())
+ {
+ const int mode = gb.Seen('N') ? gb.GetIValue() : 0;
+ result = GetGCodeResultFromFinished(reprap.GetScanner().Calibrate(mode));
+ }
+ else
+ {
+ reply.copy("Scanner is not registered");
+ result = GCodeResult::error;
+ }
}
else
{
- reply.copy("Scanner is not registered");
+ reply.copy("Scanner extension is not enabled");
result = GCodeResult::error;
}
- }
- else
- {
- reply.copy("Scanner extension is not enabled");
- result = GCodeResult::error;
- }
- break;
+ break;
- case 755: // Set alignment mode for 3D scanner
- if (reprap.GetScanner().IsEnabled())
- {
- if (reprap.GetScanner().IsRegistered())
+ case 755: // Set alignment mode for 3D scanner
+ if (reprap.GetScanner().IsEnabled())
{
- const bool on = (gb.Seen('P') && gb.GetIValue() > 0);
- result = GetGCodeResultFromFinished(reprap.GetScanner().SetAlignment(on));
+ if (reprap.GetScanner().IsRegistered())
+ {
+ const bool on = (gb.Seen('P') && gb.GetIValue() > 0);
+ result = GetGCodeResultFromFinished(reprap.GetScanner().SetAlignment(on));
+ }
+ else
+ {
+ reply.copy("Scanner is not registered");
+ result = GCodeResult::error;
+ }
}
else
{
- reply.copy("Scanner is not registered");
+ reply.copy("Scanner extension is not enabled");
result = GCodeResult::error;
}
- }
- else
- {
- reply.copy("Scanner extension is not enabled");
- result = GCodeResult::error;
- }
- break;
+ break;
- case 756: // Shutdown 3D scanner
- if (reprap.GetScanner().IsEnabled())
- {
- if (reprap.GetScanner().IsRegistered())
+ case 756: // Shutdown 3D scanner
+ if (reprap.GetScanner().IsEnabled())
{
- result = GetGCodeResultFromFinished(reprap.GetScanner().Shutdown());
+ if (reprap.GetScanner().IsRegistered())
+ {
+ result = GetGCodeResultFromFinished(reprap.GetScanner().Shutdown());
+ }
+ else
+ {
+ reply.copy("Scanner is not registered");
+ result = GCodeResult::error;
+ }
}
else
{
- reply.copy("Scanner is not registered");
+ reply.copy("Scanner extension is not enabled");
result = GCodeResult::error;
}
- }
- else
- {
- reply.copy("Scanner extension is not enabled");
- result = GCodeResult::error;
- }
- break;
+ break;
#else
- case 750:
- case 751:
- case 752:
- case 753:
- case 754:
- case 755:
- case 756:
- reply.copy("Scanner support not built-in");
- result = GCodeResult::error;
- break;
+ case 750:
+ case 751:
+ case 752:
+ case 753:
+ case 754:
+ case 755:
+ case 756:
+ reply.copy("Scanner support not built-in");
+ result = GCodeResult::error;
+ break;
#endif
- case 851: // Set Z probe offset, only for Marlin compatibility
- {
- ZProbe& zp = platform.GetCurrentZProbe();
- if (gb.Seen('Z'))
- {
- zp.SetTriggerHeight(-gb.GetFValue());
- zp.SetSaveToConfigOverride();
- }
- else
+ case 851: // Set Z probe offset, only for Marlin compatibility
{
- reply.printf("Z probe offset is %.2fmm", (double)(-zp.GetConfiguredTriggerHeight()));
+ ZProbe& zp = platform.GetCurrentZProbe();
+ if (gb.Seen('Z'))
+ {
+ zp.SetTriggerHeight(-gb.GetFValue());
+ zp.SetSaveToConfigOverride();
+ }
+ else
+ {
+ reply.printf("Z probe offset is %.2fmm", (double)(-zp.GetConfiguredTriggerHeight()));
+ }
}
- }
- break;
+ break;
- case 905: // Set current RTC date and time
- result = SetDateTime(gb, reply);
- break;
+ case 905: // Set current RTC date and time
+ result = SetDateTime(gb, reply);
+ break;
- case 906: // Set/report Motor currents
- case 913: // Set/report motor current percent
+ case 906: // Set/report Motor currents
+ case 913: // Set/report motor current percent
#if HAS_SMART_DRIVERS
- case 917: // Set/report standstill motor current percentage
+ case 917: // Set/report standstill motor current percentage
#endif
- // Note that we no longer wait for movement to stop. This is so that we can use these commands (in particular, M913) in the M911 power fail script.
- {
- bool seen = false;
- for (size_t axis = 0; axis < numTotalAxes; axis++)
+ // Note that we no longer wait for movement to stop. This is so that we can use these commands (in particular, M913) in the M911 power fail script.
{
- if (gb.Seen(axisLetters[axis]))
+ bool seen = false;
+ for (size_t axis = 0; axis < numTotalAxes; axis++)
{
- if (!platform.SetMotorCurrent(axis, gb.GetFValue(), code, reply))
+ if (gb.Seen(axisLetters[axis]))
{
- result = GCodeResult::error;
+ if (!platform.SetMotorCurrent(axis, gb.GetFValue(), code, reply))
+ {
+ result = GCodeResult::error;
+ }
+ seen = true;
}
- seen = true;
}
- }
- if (gb.Seen(extrudeLetter))
- {
- seen = true;
- float eVals[MaxExtruders];
- size_t eCount = numExtruders;
- gb.GetFloatArray(eVals, eCount, true);
- for (size_t e = 0; e < eCount; e++)
+ if (gb.Seen(extrudeLetter))
{
- if (!platform.SetMotorCurrent(ExtruderToLogicalDrive(e), eVals[e], code, reply))
+ seen = true;
+ float eVals[MaxExtruders];
+ size_t eCount = numExtruders;
+ gb.GetFloatArray(eVals, eCount, true);
+ for (size_t e = 0; e < eCount; e++)
{
- result = GCodeResult::error;
+ if (!platform.SetMotorCurrent(ExtruderToLogicalDrive(e), eVals[e], code, reply))
+ {
+ result = GCodeResult::error;
+ }
}
}
- }
- if (code == 906 && gb.Seen('I'))
- {
- seen = true;
- platform.SetIdleCurrentFactor(gb.GetFValue()/100.0);
- }
+ if (code == 906 && gb.Seen('I'))
+ {
+ seen = true;
+ platform.SetIdleCurrentFactor(gb.GetFValue()/100.0);
+ }
- if (!seen)
- {
- reply.copy( (code == 913) ? "Motor current % of normal - "
+ if (!seen)
+ {
+ reply.copy( (code == 913) ? "Motor current % of normal - "
#if HAS_SMART_DRIVERS
: (code == 917) ? "Motor standstill current % of normal - "
#endif
- : "Motor current (mA) - "
- );
- for (size_t axis = 0; axis < numTotalAxes; ++axis)
- {
- reply.catf("%c:%d, ", axisLetters[axis], (int)platform.GetMotorCurrent(axis, code));
- }
- reply.cat("E");
- for (size_t extruder = 0; extruder < numExtruders; extruder++)
- {
- reply.catf(":%d", (int)platform.GetMotorCurrent(ExtruderToLogicalDrive(extruder), code));
- }
- if (code == 906)
- {
- reply.catf(", idle factor %d%%", (int)(platform.GetIdleCurrentFactor() * 100.0));
+ : "Motor current (mA) - "
+ );
+ for (size_t axis = 0; axis < numTotalAxes; ++axis)
+ {
+ reply.catf("%c:%d, ", axisLetters[axis], (int)platform.GetMotorCurrent(axis, code));
+ }
+ reply.cat("E");
+ for (size_t extruder = 0; extruder < numExtruders; extruder++)
+ {
+ reply.catf(":%d", (int)platform.GetMotorCurrent(ExtruderToLogicalDrive(extruder), code));
+ }
+ if (code == 906)
+ {
+ reply.catf(", idle factor %d%%", (int)(platform.GetIdleCurrentFactor() * 100.0));
+ }
}
}
- }
- break;
+ break;
#if HAS_VOLTAGE_MONITOR
- case 911: // Enable auto save on loss of power
- if (gb.Seen('S'))
- {
- const float saveVoltage = gb.GetFValue();
- if (saveVoltage < 10.0)
+ case 911: // Enable auto save on loss of power
+ if (gb.Seen('S'))
{
- platform.DisableAutoSave();
+ const float saveVoltage = gb.GetFValue();
+ if (saveVoltage < 10.0)
+ {
+ platform.DisableAutoSave();
+ }
+ else
+ {
+ float resumeVoltage = saveVoltage + 1.0; // set up default resume voltage
+ bool dummy;
+ gb.TryGetFValue('R', resumeVoltage, dummy);
+
+ String<80> powerFailString;
+ bool seenCommandString = false;
+ gb.TryGetQuotedString('P', powerFailString.GetRef(), seenCommandString);
+ if (seenCommandString)
+ {
+ // Replace the power fail script atomically
+ char *newPowerFailScript = new char[powerFailString.strlen() + 1];
+ strcpy(newPowerFailScript, powerFailString.c_str());
+ std::swap(newPowerFailScript, powerFailScript);
+ delete[] newPowerFailScript;
+ }
+ else if (powerFailScript == nullptr)
+ {
+ reply.copy("No power fail script provided");
+ result = GCodeResult::error;
+ break;
+ }
+ platform.EnableAutoSave(saveVoltage, resumeVoltage);
+ }
}
else
{
- float resumeVoltage = saveVoltage + 1.0; // set up default resume voltage
- bool dummy;
- gb.TryGetFValue('R', resumeVoltage, dummy);
-
- String<80> powerFailString;
- bool seenCommandString = false;
- gb.TryGetQuotedString('P', powerFailString.GetRef(), seenCommandString);
- if (seenCommandString)
+ float saveVoltage, resumeVoltage;
+ if (platform.GetAutoSaveSettings(saveVoltage, resumeVoltage))
{
- // Replace the power fail script atomically
- char *newPowerFailScript = new char[powerFailString.strlen() + 1];
- strcpy(newPowerFailScript, powerFailString.c_str());
- std::swap(newPowerFailScript, powerFailScript);
- delete[] newPowerFailScript;
+ reply.printf("Auto save voltage %.1fV, resume %.1fV, script \"%s\"", (double)saveVoltage, (double)resumeVoltage, (powerFailScript == nullptr) ? "" : powerFailScript);
}
- else if (powerFailScript == nullptr)
+ else
{
- reply.copy("No power fail script provided");
- result = GCodeResult::error;
- break;
+ reply.copy("Auto save is disabled");
}
- platform.EnableAutoSave(saveVoltage, resumeVoltage);
}
- }
- else
- {
- float saveVoltage, resumeVoltage;
- if (platform.GetAutoSaveSettings(saveVoltage, resumeVoltage))
+ break;
+#endif
+
+#if HAS_CPU_TEMP_SENSOR
+ case 912: // Set electronics temperature monitor adjustment
+ // Currently we ignore the P parameter (i.e. temperature measurement channel)
+ if (gb.Seen('S'))
{
- reply.printf("Auto save voltage %.1fV, resume %.1fV, script \"%s\"", (double)saveVoltage, (double)resumeVoltage, (powerFailScript == nullptr) ? "" : powerFailScript);
+ platform.SetMcuTemperatureAdjust(gb.GetFValue());
}
else
{
- reply.copy("Auto save is disabled");
+ reply.printf("MCU temperature calibration adjustment is %.1f" DEGREE_SYMBOL "C", (double)platform.GetMcuTemperatureAdjust());
}
- }
- break;
-#endif
-
-#if HAS_CPU_TEMP_SENSOR
- case 912: // Set electronics temperature monitor adjustment
- // Currently we ignore the P parameter (i.e. temperature measurement channel)
- if (gb.Seen('S'))
- {
- platform.SetMcuTemperatureAdjust(gb.GetFValue());
- }
- else
- {
- reply.printf("MCU temperature calibration adjustment is %.1f" DEGREE_SYMBOL "C", (double)platform.GetMcuTemperatureAdjust());
- }
- break;
+ break;
#endif
// For case 913, see 906
#if defined(__ALLIGATOR__)
- case 914: // Set/Get J14 Expansion Voltage Level Translator on Port J5, 5.5V or 3.3V
- // Get Piggy module presence status
- if (gb.Seen('S'))
- {
- const int voltageValue = gb.GetIValue();
- if (voltageValue != 5 && voltageValue != 3 )
+ case 914: // Set/Get J14 Expansion Voltage Level Translator on Port J5, 5.5V or 3.3V
+ // Get Piggy module presence status
+ if (gb.Seen('S'))
{
- reply.printf("The Expansion Voltage Translator does not support %dV. \n Only 5V or 3V are supported.",voltageValue);
+ const int voltageValue = gb.GetIValue();
+ if (voltageValue != 5 && voltageValue != 3 )
+ {
+ reply.printf("The Expansion Voltage Translator does not support %dV. \n Only 5V or 3V are supported.",voltageValue);
+ }
+ else
+ {
+ // Change Voltage translator level
+ digitalWrite(ExpansionVoltageLevelPin, voltageValue == 5);
+ }
}
else
{
- // Change Voltage translator level
- digitalWrite(ExpansionVoltageLevelPin, voltageValue == 5);
+ // Change Voltage translator level Status
+ reply.printf("The Voltage of Expansion Translator is %dV \nPiggy module %s",
+ digitalRead(ExpansionVoltageLevelPin) ? 5 : 3 ,
+ digitalRead(ExpansionPiggyDetectPin) ? "not detected" : "detected");
}
- }
- else
- {
- // Change Voltage translator level Status
- reply.printf("The Voltage of Expansion Translator is %dV \nPiggy module %s",
- digitalRead(ExpansionVoltageLevelPin) ? 5 : 3 ,
- digitalRead(ExpansionPiggyDetectPin) ? "not detected" : "detected");
- }
- break;
+ break;
#endif
#if HAS_STALL_DETECT
- case 915:
- result = platform.ConfigureStallDetection(gb, reply, outBuf);
- break;
+ case 915:
+ result = platform.ConfigureStallDetection(gb, reply, outBuf);
+ break;
#endif
#if HAS_MASS_STORAGE
- case 916:
- if (!platform.SysFileExists(RESUME_AFTER_POWER_FAIL_G))
- {
- reply.copy("No resume file found");
- result = GCodeResult::error;
- }
- else if (!platform.SysFileExists(RESUME_PROLOGUE_G))
- {
- reply.printf("Resume prologue file '%s' not found", RESUME_PROLOGUE_G);
- result = GCodeResult::error;
- }
- else
- {
- DoFileMacro(gb, RESUME_AFTER_POWER_FAIL_G, true, 916);
- }
- break;
+ case 916:
+ if (!platform.SysFileExists(RESUME_AFTER_POWER_FAIL_G))
+ {
+ reply.copy("No resume file found");
+ result = GCodeResult::error;
+ }
+ else if (!platform.SysFileExists(RESUME_PROLOGUE_G))
+ {
+ reply.printf("Resume prologue file '%s' not found", RESUME_PROLOGUE_G);
+ result = GCodeResult::error;
+ }
+ else
+ {
+ DoFileMacro(gb, RESUME_AFTER_POWER_FAIL_G, true, 916);
+ }
+ break;
#endif
// For case 917, see 906
#if SUPPORT_12864_LCD
- case 918: // Configure direct-connect display
- result = reprap.GetDisplay().Configure(gb, reply);
- break;
+ case 918: // Configure direct-connect display
+ result = reprap.GetDisplay().Configure(gb, reply);
+ break;
#endif
- case 929: // Start/stop event logging
+ case 929: // Start/stop event logging
#if HAS_MASS_STORAGE
- result = platform.ConfigureLogging(gb, reply);
+ result = platform.ConfigureLogging(gb, reply);
#else
- result = GCodeResult::warningNotSupported;
+ result = GCodeResult::warningNotSupported;
#endif
- break;
+ break;
- case 950: // configure I/O pins
- result = platform.ConfigurePort(gb, reply);
- break;
+ case 950: // configure I/O pins
+ result = platform.ConfigurePort(gb, reply);
+ break;
#if SUPPORT_ASYNC_MOVES
- case 951: // configure height control
- result = reprap.GetMove().ConfigureHeightFollowing(gb, reply);
- break;
+ case 951: // configure height control
+ result = reprap.GetMove().ConfigureHeightFollowing(gb, reply);
+ break;
#endif
- case 997: // Perform firmware update
- result = UpdateFirmware(gb, reply);
- break;
+ case 997: // Perform firmware update
+ result = UpdateFirmware(gb, reply);
+ break;
- case 998:
- // The input handling code replaces the gcode by this when it detects a checksum error.
- // Since we have no way of asking for the line to be re-sent, just report an error.
- if (gb.Seen('P'))
- {
- const int val = gb.GetIValue();
- if (val != 0)
+ case 998:
+ // The input handling code replaces the gcode by this when it detects a checksum error.
+ // Since we have no way of asking for the line to be re-sent, just report an error.
+ if (gb.Seen('P'))
{
- reply.printf("Checksum error on line %d", val);
+ const int val = gb.GetIValue();
+ if (val != 0)
+ {
+ reply.printf("Checksum error on line %d", val);
+ }
}
- }
- break;
+ break;
- case 999:
- if (!gb.DoDwellTime(1000)) // wait a second to allow the response to be sent back to the web server, otherwise it may retry
- {
- return false;
- }
+ case 999:
+ if (!gb.DoDwellTime(1000)) // wait a second to allow the response to be sent back to the web server, otherwise it may retry
+ {
+ return false;
+ }
- reprap.EmergencyStop(); // this disables heaters and drives - Duet WiFi pre-production boards need drives disabled here
- {
- uint16_t reason = (uint16_t)SoftwareResetReason::user;
- if (gb.Seen('P'))
+ reprap.EmergencyStop(); // this disables heaters and drives - Duet WiFi pre-production boards need drives disabled here
{
- String<StringLength20> eraseString;
- gb.GetQuotedString(eraseString.GetRef());
- if (strcmp(eraseString.c_str(), "ERASE") == 0)
+ uint16_t reason = (uint16_t)SoftwareResetReason::user;
+ if (gb.Seen('P'))
{
- reason = (uint16_t)SoftwareResetReason::erase;
+ String<StringLength20> eraseString;
+ gb.GetQuotedString(eraseString.GetRef());
+ if (strcmp(eraseString.c_str(), "ERASE") == 0)
+ {
+ reason = (uint16_t)SoftwareResetReason::erase;
+ }
}
+ platform.SoftwareReset(reason); // doesn't return
}
- platform.SoftwareReset(reason); // doesn't return
- }
- break;
+ break;
- default:
- // See if there is a file in /sys named Mxx.g
- if (code >= 0 && code < 10000)
- {
-#if HAS_LINUX_INTERFACE
- if (reprap.UsingLinuxInterface())
+ default:
+ // See if there is a file in /sys named Mxx.g
+ if (code >= 0 && code < 10000)
{
- gb.SetState(GCodeState::doingUnsupportedCode);
- }
+#if HAS_LINUX_INTERFACE
+ if (reprap.UsingLinuxInterface())
+ {
+ gb.SetState(GCodeState::doingUnsupportedCode);
+ }
#endif
- String<StringLength20> macroName;
- macroName.printf("M%d.g", code);
- if (DoFileMacro(gb, macroName.c_str(), false, code))
- {
- break;
+ String<StringLength20> macroName;
+ macroName.printf("M%d.g", code);
+ if (DoFileMacro(gb, macroName.c_str(), false, code))
+ {
+ break;
+ }
}
+ result = GCodeResult::warningNotSupported;
+ break;
}
- result = GCodeResult::warningNotSupported;
- break;
- }
- return HandleResult(gb, result, reply, outBuf);
+ return HandleResult(gb, result, reply, outBuf);
+ }
+ catch (const ParseException& e)
+ {
+ OutputBuffer::ReleaseAll(outBuf);
+ throw;
+ }
}
bool GCodes::HandleTcode(GCodeBuffer& gb, const StringRef& reply)
diff --git a/src/Hardware/IoPorts.cpp b/src/Hardware/IoPorts.cpp
index 96838934..4f7bf15a 100644
--- a/src/Hardware/IoPorts.cpp
+++ b/src/Hardware/IoPorts.cpp
@@ -25,12 +25,7 @@
{
// Get the full port names string
String<StringLength50> portNames;
- if (!gb.GetReducedString(portNames.GetRef()))
- {
- reply.copy("Missing port name string");
- return 0;
- }
-
+ gb.GetReducedString(portNames.GetRef());
return AssignPorts(portNames.c_str(), reply, neededFor, numPorts, ports, access);
}
diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp
index 8d7fb36f..baaf07e0 100644
--- a/src/Heating/Heat.cpp
+++ b/src/Heating/Heat.cpp
@@ -518,11 +518,7 @@ GCodeResult Heat::ConfigureHeater(size_t heater, GCodeBuffer& gb, const StringRe
if (gb.Seen('C'))
{
String<StringLength50> pinName;
- if (!gb.GetReducedString(pinName.GetRef()))
- {
- reply.copy("Missing pin name");
- return GCodeResult::error;
- }
+ gb.GetReducedString(pinName.GetRef());
if (StringEqualsIgnoreCase(pinName.c_str(), NoPinName))
{
@@ -963,9 +959,15 @@ GCodeResult Heat::ConfigureSensor(GCodeBuffer& gb, const StringRef& reply) noexc
// Set boardAddress to the board number that the port is on, or NoAddress if the port was not given
CanAddress boardAddress;
String<StringLength20> portName;
- boardAddress = (gb.Seen('P') && gb.GetReducedString(portName.GetRef()))
- ? IoPort::RemoveBoardAddress(portName.GetRef())
- : CanId::NoAddress;
+ if (gb.Seen('P'))
+ {
+ gb.GetReducedString(portName.GetRef());
+ boardAddress = IoPort::RemoveBoardAddress(portName.GetRef());
+ }
+ else
+ {
+ boardAddress = CanId::NoAddress;
+ }
#endif
bool newSensor = gb.Seen('Y');
if (newSensor)
@@ -975,11 +977,7 @@ GCodeResult Heat::ConfigureSensor(GCodeBuffer& gb, const StringRef& reply) noexc
DeleteSensor(sensorNum);
String<StringLength20> typeName;
- if (!gb.GetReducedString(typeName.GetRef()))
- {
- reply.copy("Missing sensor type name");
- return GCodeResult::error;
- }
+ gb.GetReducedString(typeName.GetRef());
#if SUPPORT_CAN_EXPANSION
if (boardAddress == CanId::NoAddress)
diff --git a/src/Heating/Sensors/AdditionalOutputSensor.cpp b/src/Heating/Sensors/AdditionalOutputSensor.cpp
index 496386bf..0b6cd84b 100644
--- a/src/Heating/Sensors/AdditionalOutputSensor.cpp
+++ b/src/Heating/Sensors/AdditionalOutputSensor.cpp
@@ -27,11 +27,7 @@ GCodeResult AdditionalOutputSensor::Configure(GCodeBuffer& gb, const StringRef&
{
seen = true;
String<StringLength20> pParam;
- if (!gb.GetQuotedString(pParam.GetRef()))
- {
- reply.copy("Missing parent sensor and output number");
- return GCodeResult::error;
- }
+ gb.GetQuotedString(pParam.GetRef());
const char *pn = pParam.c_str();
if (*pn != 'S' && *pn != 's')
diff --git a/src/Linux/DataTransfer.cpp b/src/Linux/DataTransfer.cpp
index 2604202d..2d2acc35 100644
--- a/src/Linux/DataTransfer.cpp
+++ b/src/Linux/DataTransfer.cpp
@@ -533,7 +533,7 @@ bool DataTransfer::IsReady()
default:
// Should never get here. If we do, this probably means that StartNextTransfer has not been called
ExchangeHeader();
- INTERNAL_ERROR;
+ REPORT_INTERNAL_ERROR;
break;
}
}
diff --git a/src/Linux/LinuxInterface.cpp b/src/Linux/LinuxInterface.cpp
index 3535b60c..2fd40510 100644
--- a/src/Linux/LinuxInterface.cpp
+++ b/src/Linux/LinuxInterface.cpp
@@ -50,7 +50,7 @@ void LinuxInterface::Spin()
if (packet->request >= (uint16_t)LinuxRequest::InvalidRequest)
{
- INTERNAL_ERROR;
+ REPORT_INTERNAL_ERROR;
return;
}
const LinuxRequest request = (LinuxRequest)packet->request;
@@ -314,7 +314,7 @@ void LinuxInterface::Spin()
// Invalid request
default:
- INTERNAL_ERROR;
+ REPORT_INTERNAL_ERROR;
break;
}
}
diff --git a/src/Networking/ESP8266WiFi/WiFiInterface.cpp b/src/Networking/ESP8266WiFi/WiFiInterface.cpp
index a63f70d0..04ffe795 100644
--- a/src/Networking/ESP8266WiFi/WiFiInterface.cpp
+++ b/src/Networking/ESP8266WiFi/WiFiInterface.cpp
@@ -899,55 +899,38 @@ GCodeResult WiFiInterface::HandleWiFiCode(int mcode, GCodeBuffer &gb, const Stri
WirelessConfigurationData config;
memset(&config, 0, sizeof(config));
String<ARRAY_SIZE(config.ssid)> ssid;
- bool ok = gb.GetQuotedString(ssid.GetRef());
- if (ok)
- {
- SafeStrncpy(config.ssid, ssid.c_str(), ARRAY_SIZE(config.ssid));
- String<ARRAY_SIZE(config.password)> password;
- ok = gb.Seen('P') && gb.GetQuotedString(password.GetRef());
- if (ok)
- {
- if (password.strlen() < 8 && password.strlen() != 0) // WPA2 passwords must be at least 8 characters
- {
- reply.copy("WiFi password must be at least 8 characters");
- return GCodeResult::error;
- }
- SafeStrncpy(config.password, password.c_str(), ARRAY_SIZE(config.password));
- }
- }
- if (ok && gb.Seen('I'))
+ gb.GetQuotedString(ssid.GetRef());
+ SafeStrncpy(config.ssid, ssid.c_str(), ARRAY_SIZE(config.ssid));
+ String<ARRAY_SIZE(config.password)> password;
+ gb.MustSee('P');
+ gb.GetQuotedString(password.GetRef());
+ if (gb.Seen('I'))
{
IPAddress temp;
gb.GetIPAddress(temp);
config.ip = temp.GetV4LittleEndian();
}
- if (ok && gb.Seen('J'))
+ if (gb.Seen('J'))
{
IPAddress temp;
- ok = gb.GetIPAddress(temp);
+ gb.GetIPAddress(temp);
config.gateway = temp.GetV4LittleEndian();
}
- if (ok && gb.Seen('K'))
+ if (gb.Seen('K'))
{
IPAddress temp;
- ok = gb.GetIPAddress(temp);
+ gb.GetIPAddress(temp);
config.netmask = temp.GetV4LittleEndian();
}
- if (ok)
+
+ const int32_t rslt = SendCommand(NetworkCommand::networkAddSsid, 0, 0, &config, sizeof(config), nullptr, 0);
+ if (rslt == ResponseEmpty)
{
- const int32_t rslt = SendCommand(NetworkCommand::networkAddSsid, 0, 0, &config, sizeof(config), nullptr, 0);
- if (rslt == ResponseEmpty)
- {
- return GCodeResult::ok;
- }
- else
- {
- reply.copy("Failed to add SSID to remembered list");
- }
+ return GCodeResult::ok;
}
else
{
- reply.copy("Bad or missing parameter");
+ reply.copy("Failed to add SSID to remembered list");
}
}
else
@@ -993,31 +976,29 @@ GCodeResult WiFiInterface::HandleWiFiCode(int mcode, GCodeBuffer &gb, const Stri
if (gb.Seen('S'))
{
String<SsidLength> ssidText;
- if (gb.GetQuotedString(ssidText.GetRef()))
+ gb.GetQuotedString(ssidText.GetRef());
+ if (strcmp(ssidText.c_str(), "*") == 0)
{
- if (strcmp(ssidText.c_str(), "*") == 0)
- {
- const int32_t rslt = SendCommand(NetworkCommand::networkFactoryReset, 0, 0, nullptr, 0, nullptr, 0);
- if (rslt == ResponseEmpty)
- {
- return GCodeResult::ok;
- }
-
- reply.copy("Failed to reset the WiFi module to factory settings");
- return GCodeResult::error;
- }
-
- uint32_t ssid32[NumDwords(SsidLength)]; // need a dword-aligned buffer for SendCommand
- memcpy(ssid32, ssidText.c_str(), SsidLength);
- const int32_t rslt = SendCommand(NetworkCommand::networkDeleteSsid, 0, 0, ssid32, SsidLength, nullptr, 0);
+ const int32_t rslt = SendCommand(NetworkCommand::networkFactoryReset, 0, 0, nullptr, 0, nullptr, 0);
if (rslt == ResponseEmpty)
{
return GCodeResult::ok;
}
- reply.copy("Failed to remove SSID from remembered list");
+ reply.copy("Failed to reset the WiFi module to factory settings");
return GCodeResult::error;
}
+
+ uint32_t ssid32[NumDwords(SsidLength)]; // need a dword-aligned buffer for SendCommand
+ memcpy(ssid32, ssidText.c_str(), SsidLength);
+ const int32_t rslt = SendCommand(NetworkCommand::networkDeleteSsid, 0, 0, ssid32, SsidLength, nullptr, 0);
+ if (rslt == ResponseEmpty)
+ {
+ return GCodeResult::ok;
+ }
+
+ reply.copy("Failed to remove SSID from remembered list");
+ return GCodeResult::error;
}
reply.copy("Bad or missing parameter");
@@ -1030,56 +1011,39 @@ GCodeResult WiFiInterface::HandleWiFiCode(int mcode, GCodeBuffer &gb, const Stri
WirelessConfigurationData config;
memset(&config, 0, sizeof(config));
String<SsidLength> ssid;
- bool ok = gb.GetQuotedString(ssid.GetRef());
- if (ok)
+ gb.GetQuotedString(ssid.GetRef());
+ if (strcmp(ssid.c_str(), "*") == 0)
{
- if (strcmp(ssid.c_str(), "*") == 0)
- {
- // Delete the access point details
- memset(&config, 0xFF, sizeof(config));
- }
- else
- {
- SafeStrncpy(config.ssid, ssid.c_str(), ARRAY_SIZE(config.ssid));
- String<ARRAY_SIZE(config.password)> password;
- ok = gb.Seen('P') && gb.GetQuotedString(password.GetRef());
- if (ok)
- {
- SafeStrncpy(config.password, password.c_str(), ARRAY_SIZE(config.password));
- if (password.strlen() < 8 && password.strlen() != 0) // WPA2 passwords must be at least 8 characters
- {
- reply.copy("WiFi password must be at least 8 characters");
- return GCodeResult::error;
- }
- SafeStrncpy(config.password, password.c_str(), ARRAY_SIZE(config.password));
- if (gb.Seen('I'))
- {
- IPAddress temp;
- ok = gb.GetIPAddress(temp);
- config.ip = temp.GetV4LittleEndian();
- config.channel = (gb.Seen('C')) ? gb.GetIValue() : 0;
- }
- else
- {
- ok = false;
- }
- }
- }
+ // Delete the access point details
+ memset(&config, 0xFF, sizeof(config));
}
- if (ok)
+ else
{
- const int32_t rslt = SendCommand(NetworkCommand::networkConfigureAccessPoint, 0, 0, &config, sizeof(config), nullptr, 0);
- if (rslt == ResponseEmpty)
+ SafeStrncpy(config.ssid, ssid.c_str(), ARRAY_SIZE(config.ssid));
+ String<ARRAY_SIZE(config.password)> password;
+ gb.MustSee('P');
+ gb.GetQuotedString(password.GetRef());
+ SafeStrncpy(config.password, password.c_str(), ARRAY_SIZE(config.password));
+ if (password.strlen() < 8 && password.strlen() != 0) // WPA2 passwords must be at least 8 characters
{
- return GCodeResult::ok;
+ reply.copy("WiFi password must be at least 8 characters");
+ return GCodeResult::error;
}
-
- reply.copy("Failed to configure access point parameters");
+ SafeStrncpy(config.password, password.c_str(), ARRAY_SIZE(config.password));
+ gb.MustSee('I');
+ IPAddress temp;
+ gb.GetIPAddress(temp);
+ config.ip = temp.GetV4LittleEndian();
+ config.channel = (gb.Seen('C')) ? gb.GetIValue() : 0;
}
- else
+
+ const int32_t rslt = SendCommand(NetworkCommand::networkConfigureAccessPoint, 0, 0, &config, sizeof(config), nullptr, 0);
+ if (rslt == ResponseEmpty)
{
- reply.copy("Bad or missing parameter");
+ return GCodeResult::ok;
}
+
+ reply.copy("Failed to configure access point parameters");
}
else
{
diff --git a/src/Networking/ESP8266WiFi/WiFiInterface.h b/src/Networking/ESP8266WiFi/WiFiInterface.h
index 4e090f8b..13f154b7 100644
--- a/src/Networking/ESP8266WiFi/WiFiInterface.h
+++ b/src/Networking/ESP8266WiFi/WiFiInterface.h
@@ -67,7 +67,7 @@ public:
void TerminateDataPort() noexcept override;
// The remaining functions are specific to the WiFi version
- GCodeResult HandleWiFiCode(int mcode, GCodeBuffer &gb, const StringRef& reply, OutputBuffer*& longReply);
+ GCodeResult HandleWiFiCode(int mcode, GCodeBuffer &gb, const StringRef& reply, OutputBuffer*& longReply) THROWS_PARSE_ERROR;
WifiFirmwareUploader *GetWifiUploader() const noexcept { return uploader; }
void StartWiFi() noexcept;
void ResetWiFi() noexcept;
diff --git a/src/ObjectModel/ObjectModel.cpp b/src/ObjectModel/ObjectModel.cpp
index c1d487ec..39620eff 100644
--- a/src/ObjectModel/ObjectModel.cpp
+++ b/src/ObjectModel/ObjectModel.cpp
@@ -10,6 +10,7 @@
#if SUPPORT_OBJECT_MODEL
#include "OutputMemory.h"
+#include <GCodes/GCodeBuffer/StringParser.h>
#include <cstring>
#include <General/SafeStrtod.h>
@@ -256,33 +257,35 @@ int ObjectModelTableEntry::IdCompare(const char *id) const
}
// Get the value of an object when we don't know what its type is
-TypeCode ObjectModel::GetObjectValue(ExpressionValue& val, const char *idString)
+ExpressionValue ObjectModel::GetObjectValue(const StringParser& sp, const char *idString)
{
+ ExpressionValue val;
+
const ObjectModelTableEntry *e = FindObjectModelTableEntry(idString);
if (e == nullptr)
{
- return NoType;
+ throw sp.ConstructParseException("unknown variable %s", idString);
}
idString = GetNextElement(idString);
void * param = e->param(this);
- TypeCode tc = e->type;
- if ((tc & IsArray) != 0)
+ val.type = e->type;
+ if ((val.type & IsArray) != 0)
{
if (*idString != '[')
{
- return NoType; // no array index is provided, and we don't currently allow an entire array to be returned
+ throw sp.ConstructParseException("can't use whole array");
}
const char *endptr;
- const unsigned long val = SafeStrtoul(idString + 1, &endptr);
+ const unsigned long index = SafeStrtoul(idString + 1, &endptr);
if (endptr == idString + 1 || *endptr != ']')
{
- return NoType; // invalid syntax
+ throw sp.ConstructParseException("expected ']'");
}
const ObjectModelArrayDescriptor *arr = (const ObjectModelArrayDescriptor*)param;
- if (val >= arr->GetNumElements(this))
+ if (index >= arr->GetNumElements(this))
{
- return NoType; // array index out of range
+ throw sp.ConstructParseException("array index out of bounds");
}
idString = endptr + 1; // skip past the ']'
@@ -290,14 +293,14 @@ TypeCode ObjectModel::GetObjectValue(ExpressionValue& val, const char *idString)
{
++idString; // skip any '.' after it because it could be an array of objects
}
- tc &= ~IsArray; // clear the array flag
- param = arr->GetElement(this, val); // fetch the pointer to the array element
+ val.type &= ~IsArray; // clear the array flag
+ param = arr->GetElement(this, index); // fetch the pointer to the array element
}
- switch (tc)
+ switch (val.type)
{
case TYPE_OF(ObjectModel):
- return ((ObjectModel*)param)->GetObjectValue(val, idString);
+ return ((ObjectModel*)param)->GetObjectValue(sp, idString);
case TYPE_OF(float):
case TYPE_OF(Float2):
@@ -328,9 +331,9 @@ TypeCode ObjectModel::GetObjectValue(ExpressionValue& val, const char *idString)
break;
default:
- return NoType;
+ throw sp.ConstructParseException("unknown type");
}
- return tc;
+ return val;
}
// Template specialisations
diff --git a/src/ObjectModel/ObjectModel.h b/src/ObjectModel/ObjectModel.h
index e1226dd7..5c5e7ea7 100644
--- a/src/ObjectModel/ObjectModel.h
+++ b/src/ObjectModel/ObjectModel.h
@@ -23,15 +23,20 @@ constexpr TypeCode NoType = 0; // code for an invalid or unknown type
// Forward declarations
class ObjectModelTableEntry;
class ObjectModel;
+class StringParser;
-union ExpressionValue
+struct ExpressionValue
{
- bool bVal;
- float fVal;
- int32_t iVal;
- uint32_t uVal;
- const char *sVal;
- const ObjectModel *omVal;
+ TypeCode type;
+ union
+ {
+ bool bVal;
+ float fVal;
+ int32_t iVal;
+ uint32_t uVal;
+ const char *sVal;
+ const ObjectModel *omVal;
+ };
};
// Dummy types, used to define type codes
@@ -58,7 +63,7 @@ public:
TypeCode GetObjectType(const char *idString);
// Get the value of an object when we don't know what its type is
- TypeCode GetObjectValue(ExpressionValue& val, const char *idString);
+ ExpressionValue GetObjectValue(const StringParser& sp, const char *idString);
// Specialisation of above for float, allowing conversion from integer to float
bool GetObjectValue(float& val, const char *idString);
diff --git a/src/Pccb/Pins_Pccb.h b/src/Pccb/Pins_Pccb.h
index e9d3719b..20607b62 100644
--- a/src/Pccb/Pins_Pccb.h
+++ b/src/Pccb/Pins_Pccb.h
@@ -55,7 +55,6 @@ constexpr uint32_t IAP_IMAGE_END = 0x0047FFFF; // we allow a full 64K on the SA
#define HAS_VOLTAGE_MONITOR 1
#define ENFORCE_MAX_VIN 1
#define HAS_VREF_MONITOR 1
-#define ACTIVE_LOW_HEAT_ON 0 // although we have no heaters, this matters because we treat the LEDs as heaters
#define SUPPORT_INKJET 0 // set nonzero to support inkjet control
#define SUPPORT_ROLAND 0 // set nonzero to support Roland mill
@@ -63,6 +62,7 @@ constexpr uint32_t IAP_IMAGE_END = 0x0047FFFF; // we allow a full 64K on the SA
#define SUPPORT_IOBITS 0 // set to support P parameter in G0/G1 commands
#define SUPPORT_DHT_SENSOR 0 // set nonzero to support DHT temperature/humidity sensors (requires RTOS)
#define SUPPORT_WORKPLACE_COORDINATES 1 // set nonzero to support G10 L2 and G53..59
+#define SUPPORT_OBJECT_MODEL 1
#define SUPPORT_12864_LCD 0 // set nonzero to support 12864 LCD and rotary encoder
#define SUPPORT_DOTSTAR_LED 1 // set nonzero to support DotStar LED strips
#define ALLOCATE_DEFAULT_PORTS 1
diff --git a/src/Platform.cpp b/src/Platform.cpp
index 8b1dba6a..0edf770e 100644
--- a/src/Platform.cpp
+++ b/src/Platform.cpp
@@ -3254,11 +3254,7 @@ GCodeResult Platform::ConfigureLogging(GCodeBuffer& gb, const StringRef& reply)
StringRef filename(buf, ARRAY_SIZE(buf));
if (gb.Seen('P'))
{
- if (!gb.GetQuotedString(filename))
- {
- reply.copy("Missing filename in M929 command");
- return GCodeResult::error;
- }
+ gb.GetQuotedString(filename);
}
else
{
@@ -4158,11 +4154,7 @@ GCodeResult Platform::ConfigureGpioOrServo(uint32_t gpioNumber, bool isServo, GC
if (gb.Seen('C'))
{
String<StringLength50> pinName;
- if (!gb.GetReducedString(pinName.GetRef()))
- {
- reply.copy("Missing pin name");
- return GCodeResult::error;
- }
+ gb.GetReducedString(pinName.GetRef());
// Remove any existing assignment
#if SUPPORT_CAN_EXPANSION
diff --git a/src/RADDS/Pins_RADDS.h b/src/RADDS/Pins_RADDS.h
index 5ffc7dae..64a32bcc 100644
--- a/src/RADDS/Pins_RADDS.h
+++ b/src/RADDS/Pins_RADDS.h
@@ -10,31 +10,42 @@
#define HAS_HIGH_SPEED_SD 0
#define HAS_VOLTAGE_MONITOR 0
#define HAS_VREF_MONITOR 0
-#define ACTIVE_LOW_HEAT_ON 0
const size_t NumFirmwareUpdateModules = 1;
-#define IAP_UPDATE_FILE "iapradds.bin"
#define IAP_FIRMWARE_FILE "RepRapFirmware-RADDS.bin"
+#define IAP_IN_RAM 0
+
+#if IAP_IN_RAM
+
+# define IAP_UPDATE_FILE "RaddsIAP.bin"
+constexpr uint32_t IAP_IMAGE_START = 0x20008000u;
+
+#else
+
+# define IAP_UPDATE_FILE "iapradds.bin"
+constexpr uint32_t IAP_IMAGE_START = 0x000F0000;
+constexpr uint32_t IAP_IMAGE_END = 0x000FFBFF; // don't touch the last 1KB, it's used for NvData
+
+#endif
+
// Default board type
#define DEFAULT_BOARD_TYPE BoardType::RADDS_15
#define ELECTRONICS "RADDS"
-#define SUPPORT_INKJET 0 // set nonzero to support inkjet control
-#define SUPPORT_ROLAND 0 // set nonzero to support Roland mill
-#define SUPPORT_SCANNER 0 // set nonzero to support FreeLSS scanners
-#define SUPPORT_IOBITS 0 // set to support P parameter in G0/G1 commands
-#define SUPPORT_DHT_SENSOR 0 // set nonzero to support DHT temperature/humidity sensors
-
-#define NO_EXTRUDER_ENDSTOPS 1 // Temporary!!!
+#define SUPPORT_INKJET 0 // set nonzero to support inkjet control
+#define SUPPORT_ROLAND 0 // set nonzero to support Roland mill
+#define SUPPORT_SCANNER 0 // set nonzero to support FreeLSS scanners
+#define SUPPORT_IOBITS 0 // set to support P parameter in G0/G1 commands
+#define SUPPORT_DHT_SENSOR 0 // set nonzero to support DHT temperature/humidity sensors
+#define SUPPORT_OBJECT_MODEL 1
// The physical capabilities of the machine
// The number of drives in the machine, including X, Y, and Z plus extruder drives
constexpr size_t NumDirectDrivers = 9;
-constexpr size_t MaxSensorsInSystem = 32;
-typedef uint32_t SensorsBitmap;
+constexpr size_t MaxSensors = 32;
constexpr size_t MaxHeaters = 3;
constexpr size_t MaxExtraHeaterProtections = 4; // The number of extra heater protection instances
@@ -238,10 +249,6 @@ constexpr PwmFrequency DefaultFanPwmFrequencies[] = { DefaultFanPwmFreq };
// Function to look up a pin name pass back the corresponding index into the pin table
bool LookupPinName(const char *pn, LogicalPin& lpin, bool& hardwareInverted);
-// SAM3X Flash locations (may be expanded in the future)
-constexpr uint32_t IAP_FLASH_START = 0x000F0000;
-constexpr uint32_t IAP_FLASH_END = 0x000FFBFF; // don't touch the last 1KB, it's used for NvData
-
// Timer allocation
#define NETWORK_TC (TC1)
#define NETWORK_TC_CHAN (1)
diff --git a/src/RepRap.cpp b/src/RepRap.cpp
index 53e2c73c..399b0403 100644
--- a/src/RepRap.cpp
+++ b/src/RepRap.cpp
@@ -2481,7 +2481,7 @@ void RepRap::UpdateFirmware() noexcept
# else // SAM3X code
- for (uint32_t flashAddr = IAP_FLASH_START; flashAddr < IAP_FLASH_END; flashAddr += IFLASH_PAGE_SIZE)
+ for (uint32_t flashAddr = IAP_IMAGE_START; flashAddr < IAP_IMAGE_END; flashAddr += IFLASH_PAGE_SIZE)
{
const int bytesRead = iapFile->Read(data, IFLASH_PAGE_SIZE);
@@ -2513,13 +2513,13 @@ void RepRap::UpdateFirmware() noexcept
if (rc != FLASH_RC_OK)
{
- MessageF(FirmwareUpdateErrorMessage, "flash %s failed, code=%" PRIu32 ", address=0x%08" PRIx32 "\n", op, rc, flashAddr);
+ platform->MessageF(FirmwareUpdateErrorMessage, "flash %s failed, code=%" PRIu32 ", address=0x%08" PRIx32 "\n", op, rc, flashAddr);
return;
}
// Verify written data
if (memcmp(reinterpret_cast<void *>(flashAddr), data, bytesRead) != 0)
{
- MessageF(FirmwareUpdateErrorMessage, "verify during flash write failed, address=0x%08" PRIx32 "\n", flashAddr);
+ platform->MessageF(FirmwareUpdateErrorMessage, "verify during flash write failed, address=0x%08" PRIx32 "\n", flashAddr);
return;
}
}
diff --git a/src/RepRap.h b/src/RepRap.h
index 651f1dd3..1f5b75b6 100644
--- a/src/RepRap.h
+++ b/src/RepRap.h
@@ -243,9 +243,7 @@ inline uint16_t RepRap::GetExtrudersInUse() const noexcept { return activeExtrud
inline uint16_t RepRap::GetToolHeatersInUse() const noexcept { return activeToolHeaters; }
inline bool RepRap::IsStopped() const noexcept { return stopped; }
-#define STRINGIZE(s) #s
-#define INTERNAL_ERROR do { reprap.ReportInternalError((__FILE__), (__func__), (__LINE__)); } while(0)
-#define INTERNAL_ERROR_MESSAGE "Internal error at " __FILE__ "(" STRINGIZE(__LINE__) ")"
+#define REPORT_INTERNAL_ERROR do { reprap.ReportInternalError((__FILE__), (__func__), (__LINE__)); } while(0)
#endif
diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h
index e2d020ac..3da8bcd3 100644
--- a/src/RepRapFirmware.h
+++ b/src/RepRapFirmware.h
@@ -89,7 +89,7 @@ enum class PinUsedBy : uint8_t
static_assert(NumNamedPins <= 255 || sizeof(LogicalPin) > 1, "Need 16-bit logical pin numbers");
#if SUPPORT_CAN_EXPANSION
-# include "CanId.h" // for type CanAddress
+# include "CanId.h" // for type CanAddress
#endif
#include "General/StringRef.h"
@@ -98,6 +98,9 @@ static_assert(NumNamedPins <= 255 || sizeof(LogicalPin) > 1, "Need 16-bit logica
#include "General/SafeStrtod.h"
#include "General/SafeVsnprintf.h"
+#define THROWS_PARSE_ERROR // we tag this on to function declarations to indicate that they may throw parse errors, which must be caught
+#define THROW_INTERNAL_ERROR throw ConstructParseException("internal error at file " __FILE__ "(%d)", __LINE__)
+
// Type of a driver identifier
struct DriverId
{
diff --git a/src/Storage/FileStore.cpp b/src/Storage/FileStore.cpp
index adf704d8..d92e5c41 100644
--- a/src/Storage/FileStore.cpp
+++ b/src/Storage/FileStore.cpp
@@ -140,7 +140,7 @@ void FileStore::Duplicate()
switch (usageMode)
{
case FileUseMode::free:
- INTERNAL_ERROR;
+ REPORT_INTERNAL_ERROR;
break;
case FileUseMode::readOnly:
@@ -166,7 +166,7 @@ bool FileStore::Close()
case FileUseMode::free:
if (!inInterrupt())
{
- INTERNAL_ERROR;
+ REPORT_INTERNAL_ERROR;
}
return false;
@@ -237,7 +237,7 @@ bool FileStore::Seek(FilePosition pos)
switch (usageMode)
{
case FileUseMode::free:
- INTERNAL_ERROR;
+ REPORT_INTERNAL_ERROR;
return false;
case FileUseMode::readOnly:
@@ -272,7 +272,7 @@ FilePosition FileStore::Length() const
switch (usageMode)
{
case FileUseMode::free:
- INTERNAL_ERROR;
+ REPORT_INTERNAL_ERROR;
return 0;
case FileUseMode::readOnly:
@@ -299,7 +299,7 @@ int FileStore::Read(char* extBuf, size_t nBytes)
switch (usageMode)
{
case FileUseMode::free:
- INTERNAL_ERROR;
+ REPORT_INTERNAL_ERROR;
return -1;
case FileUseMode::readOnly:
@@ -387,7 +387,7 @@ bool FileStore::Write(const char *s, size_t len)
switch (usageMode)
{
case FileUseMode::free:
- INTERNAL_ERROR;
+ REPORT_INTERNAL_ERROR;
return false;
case FileUseMode::readOnly:
@@ -441,7 +441,7 @@ bool FileStore::Flush()
switch (usageMode)
{
case FileUseMode::free:
- INTERNAL_ERROR;
+ REPORT_INTERNAL_ERROR;
return false;
case FileUseMode::readOnly:
@@ -479,7 +479,7 @@ bool FileStore::Truncate()
{
case FileUseMode::free:
case FileUseMode::readOnly:
- INTERNAL_ERROR;
+ REPORT_INTERNAL_ERROR;
return false;
case FileUseMode::readWrite: