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

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore9
-rw-r--r--src/BugList.txt20
-rw-r--r--src/GCodes/GCodeBuffer.cpp128
-rw-r--r--src/GCodes/GCodeBuffer.h14
-rw-r--r--src/GCodes/GCodes.cpp1
-rw-r--r--src/GCodes/GCodes3.cpp91
-rw-r--r--src/Movement/BedProbing/Grid.cpp1
-rw-r--r--src/Movement/BedProbing/RandomProbePointSet.cpp3
-rw-r--r--src/Movement/DDA.cpp7
-rw-r--r--src/Movement/Move.cpp12
-rw-r--r--src/Networking/ESP8266WiFi/WiFiInterface.cpp5
-rw-r--r--src/Networking/LwipEthernet/LwipEthernetInterface.cpp5
-rw-r--r--src/Networking/Network.cpp1
-rw-r--r--src/Networking/Network.h2
-rw-r--r--src/Networking/W5500Ethernet/W5500Interface.cpp5
-rw-r--r--src/ObjectModel/ObjectModel.cpp88
-rw-r--r--src/ObjectModel/ObjectModel.h28
-rw-r--r--src/Platform.cpp17
-rw-r--r--src/RepRap.cpp2
-rw-r--r--src/Version.h2
20 files changed, 290 insertions, 151 deletions
diff --git a/.gitignore b/.gitignore
index 09bdd33b..6b93fb33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,16 @@
*.d
*.o
+*.s
+*.map
!Release/*.bin
!Release/*/*.bin
!Release/*/*/*.bin
*~
*orig
+/Alligator/
+/Duet085/
+/Duet2_RTOS/
+/DuetM_RTOS/
+/RADDS_RTOS/
+/SAME70_RTOS/
+.settings/language.settings.xml
diff --git a/src/BugList.txt b/src/BugList.txt
index 67fd3ec5..fdd00c6c 100644
--- a/src/BugList.txt
+++ b/src/BugList.txt
@@ -110,26 +110,31 @@ Open investigations:
- check DAA working as intended, results are inconsistent. Problem when used with segmented kinematics because the acceleration is in multiple segments.
To be fixed in 2.02 release:
-- [done, test] G30 H parameters don't work if deployprobe.g or retractprobe.g file present
-- [done, test] Execute residual babystepping immediately
-- [done, test] Warning message if trying to move motors on internal drivers but VIN too low or too high
- [done, ok] Send mapped fan speed at the start of the fan speed list in the M408 response for PanelDue
- [done, ok] PanelDue emergency stop interrupt from UART driver
- [done, ok] M408 P1 F"gcodes" returns an empty gcodes object
- [done, ok] Variable substitution in GCode commands
+- [done, ok] In object model, "interface"->"interfaces" to look better in JSON response
- [done, ok in DWC and PanelDue, test on 12864] Object model returned wrong value for speed factor
-- [done, ok] support string-valued object model values in JSON report
+- [done, ok] Support string-valued object model values in JSON report
+- [done, ok] Array indices in variable substitution
+- [done, ok] Support conversion from numeric or boolean to string in variable substitution
+- [done, test] G30 H parameters don't work if deployprobe.g or retractprobe.g file present
+- [done, test] Execute residual babystepping immediately
+- [done, test] Warning message if trying to move motors on internal drivers but VIN too low or too high
- [done, test] increase min fullsteps for motor open detection from 4 to 20
-- [done] Bring RADDS build up to date and use RTOS
+- [done, test] I2C addresses can be specified in hex format e.g. "0x71" or "x71"
+- [done, test] M584 can now use dummy (high) driver numbers to assign an axis or extruder to no driver
+- [done, test] M122 to tell you if the drivers are enabled, or disabled and waiting for the correct voltage
+- [done] Special support for coast-to-end in RecalculateMove
+- [done] Bring RADDS build up to date and use RTOS (not tested)
Future:
- Allow jerk between printing and non-printing moves, so that coast-to-end works?
- M408 P1 S"gcodes" returns an empty gcodes object, so does m408p1 f"gcodes.speedFactor"
- Error handling in [variable] parser in GCodeBuffer class
-- In object model, "interface"->"interfaces" to look better in JSON response
- WiFi auto reconnect should not log all unsuccessful connection attempts, just the first one
- Option to send M280 servo commands just a few times instead of continuously, for E3D
-- M122 to tell you if the drivers are enabled, or disabled and waiting for the correct voltage
- M3 R parameter so it can restore the spinder/laser after a pause (https://forum.duet3d.com/topic/5418/cnc-laser-m3-unpause-r-parameter)
- Adjust laser power during acceleration/deceleration
- First layer segmentation, to help with baby stepping? Or another way to implement live babystepping?
@@ -139,7 +144,6 @@ Future:
- CNC shutdown when movement outside limits attempted not working well, https://forum.duet3d.com/topic/6186/stable-firmware-2-01-duet-2-and-1-22-duet-06-085-released/55
- Better dead time measurement during auto tuning. Measure both turn-on and turn-off?
- Bezier speed curves or other S-curve acceleration, e.g. look at https://github.com/MarlinFirmware/Marlin/pull/10373/files
-- M584 allow an axis to be mapped to driver -1
- If wifi module gets stuck in starting or changing mode state, reset it again
- Workplace offsets are supposed to be persistant (check NIST), https://www.duet3d.com/forum/thread.php?pid=43755#p43755
- At the end of a simulation, restore the original workplace coordinate selection
diff --git a/src/GCodes/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer.cpp
index 1c300d53..90246266 100644
--- a/src/GCodes/GCodeBuffer.cpp
+++ b/src/GCodes/GCodeBuffer.cpp
@@ -12,6 +12,7 @@
#include "GCodeInput.h"
#include "Platform.h"
#include "RepRap.h"
+#include "General/IP4String.h"
static constexpr char eofString[] = EOF_STRING; // What's at the end of an HTML file?
@@ -611,7 +612,19 @@ bool GCodeBuffer::GetQuotedString(const StringRef& str)
if (readPointer >= 0)
{
++readPointer; // skip the character that introduced the string
- return gcodeBuffer[readPointer] == '"' && InternalGetQuotedString(str);
+ switch (gcodeBuffer[readPointer])
+ {
+ case '"':
+ return InternalGetQuotedString(str);
+
+#if SUPPORT_OBJECT_MODEL
+ case '[':
+ return GetStringExpression(str);
+#endif
+
+ default:
+ return false;
+ }
}
INTERNAL_ERROR;
@@ -621,6 +634,7 @@ bool GCodeBuffer::GetQuotedString(const StringRef& str)
// Given that the current character is double-quote, fetch the quoted string
bool GCodeBuffer::InternalGetQuotedString(const StringRef& str)
{
+ str.Clear();
++readPointer;
for (;;)
{
@@ -655,6 +669,7 @@ bool GCodeBuffer::InternalGetQuotedString(const StringRef& str)
}
// 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 GCodeBuffer::GetPossiblyQuotedString(const StringRef& str)
{
if (readPointer >= 0)
@@ -667,7 +682,7 @@ bool GCodeBuffer::GetPossiblyQuotedString(const StringRef& str)
return false;
}
-// Get and copy a string which may or may not be quoted, starting at readPointer
+// Get and copy a string which may or may not be quoted, starting at readPointer. Return true if successful.
bool GCodeBuffer::InternalGetPossiblyQuotedString(const StringRef& str)
{
str.Clear();
@@ -675,10 +690,13 @@ bool GCodeBuffer::InternalGetPossiblyQuotedString(const StringRef& str)
{
return InternalGetQuotedString(str);
}
+
+#if SUPPORT_OBJECT_MODEL
if (gcodeBuffer[readPointer] == '[')
{
return GetStringExpression(str);
}
+#endif
commandEnd = gcodeLineEnd; // the string is the remainder of the line of gcode
for (;;)
@@ -738,6 +756,45 @@ uint32_t GCodeBuffer::GetUIValue()
return 0;
}
+// Get an uint32 after a G Code letter, interpreting quoted numbers starting with x or X or 0x or 0X as hex
+uint32_t GCodeBuffer::GetUIValueMaybeHex()
+{
+ if (readPointer >= 0)
+ {
+ int base = 10;
+ size_t skip = 1;
+
+ // Allow "0xNNNN" or "xNNNN" where NNNN are hex digits
+ if (gcodeBuffer[readPointer + 1] == '"')
+ {
+ switch (gcodeBuffer[readPointer + 2])
+ {
+ case 'x':
+ case 'X':
+ base = 16;
+ skip = 3;
+ break;
+
+ case '0':
+ if (gcodeBuffer[readPointer + 3] == 'x' || gcodeBuffer[readPointer + 3] == 'X')
+ {
+ base = 16;
+ skip = 4;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ const uint32_t result = SafeStrtoul(&gcodeBuffer[readPointer + skip], nullptr, base);
+ readPointer = -1;
+ return result;
+ }
+ INTERNAL_ERROR;
+ return 0;
+}
+
// If the specified parameter character is found, fetch 'value' and set 'seen'. Otherwise leave val and seen alone.
bool GCodeBuffer::TryGetFValue(char c, float& val, bool& seen)
{
@@ -1266,30 +1323,54 @@ int32_t GCodeBuffer::ReadIValue(const char *p, const char **endptr)
return SafeStrtol(p, endptr);
}
+#if SUPPORT_OBJECT_MODEL
+
// Get a string expression. The current character is '['.
bool GCodeBuffer::GetStringExpression(const StringRef& str)
{
- ++readPointer;
- for (;;)
+ ExpressionValue val;
+ switch (EvaluateExpression(gcodeBuffer + readPointer, nullptr, val))
{
- const char c = gcodeBuffer[readPointer];
- if (c == 0)
- {
- return false;
- }
- ++readPointer;
- // For now we don't process the characters between { } and just return a standard string
- if (c == ']')
- {
- str.copy("string_variables_not_implemented");
- break;
- }
+ case TYPE_OF(const char*):
+ str.copy(val.sVal);
+ break;
+
+ case TYPE_OF(float):
+ str.printf("%.1f", (double)val.fVal);
+ break;
+
+ case TYPE_OF(Float2):
+ str.printf("%.2f", (double)val.fVal);
+ break;
+
+ case TYPE_OF(Float3):
+ str.printf("%.3f", (double)val.fVal);
+ break;
+
+ case TYPE_OF(uint32_t):
+ str.printf("%" PRIu32, val.uVal); // convert unsigned integer to string
+ break;
+
+ case TYPE_OF(int32_t):
+ str.printf("%" PRIi32, val.uVal); // convert signed integer to string
+ break;
+
+ case TYPE_OF(bool):
+ str.copy((val.bVal) ? "true" : "false"); // convert bool to string
+ break;
+
+ case TYPE_OF(IPAddress):
+ str.copy(IP4String(val.uVal).c_str());
+ break;
+
+ default:
+ //TODO report error
+ return false;
}
+
return true;
}
-#if SUPPORT_OBJECT_MODEL
-
// Evaluate an expression. the current character is '['.
TypeCode GCodeBuffer::EvaluateExpression(const char *p, const char **endptr, ExpressionValue& rslt)
{
@@ -1298,8 +1379,17 @@ TypeCode GCodeBuffer::EvaluateExpression(const char *p, const char **endptr, Exp
if (isalpha(*p)) // if it's a variable name
{
const char * const start = p;
- while (isalpha(*p) || isdigit(*p) || *p == '_' || *p == '.')
+ unsigned int numBrackets = 0;
+ while (isalpha(*p) || isdigit(*p) || *p == '_' || *p == '.' || *p == '[' || (*p == ']' && numBrackets != 0))
{
+ if (*p == '[')
+ {
+ ++numBrackets;
+ }
+ else if (*p == ']')
+ {
+ -- numBrackets;
+ }
++p;
}
String<MaxVariableNameLength> varName;
diff --git a/src/GCodes/GCodeBuffer.h b/src/GCodes/GCodeBuffer.h
index 73227c6d..073e69b0 100644
--- a/src/GCodes/GCodeBuffer.h
+++ b/src/GCodes/GCodeBuffer.h
@@ -36,11 +36,12 @@ public:
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 MAX address sextet after a key letter
+ uint32_t GetUIValueMaybeHex(); // Get an unsigned integer value that might be written in hex format
+ 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
- const void GetFloatArray(float arr[], size_t& length, bool doPad) __attribute__((hot)); // Get a :-separated list of floats after a key letter
+ const void GetFloatArray(float arr[], size_t& length, bool doPad) __attribute__((hot)); // Get a colon-separated list of floats after a key letter
const void GetIntArray(int32_t arr[], size_t& length, bool doPad); // Get a :-separated list of ints after a key letter
const void GetUnsignedArray(uint32_t arr[], size_t& length, bool doPad); // Get a :-separated list of unsigned ints after a key letter
@@ -50,7 +51,7 @@ public:
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 TryGetQuotedString(char c, const StringRef& str, bool& seen);
bool TryGetPossiblyQuotedString(char c, const StringRef& str, bool& seen);
const char* Buffer() const;
@@ -122,11 +123,12 @@ private:
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);
- bool GetStringExpression(const StringRef& str)
- pre (readPointer >= 0; gcodeBuffer[readPointer] == '{'; str.IsEmpty());
#if SUPPORT_OBJECT_MODEL
- TypeCode EvaluateExpression(const char *p, const char **endptr, ExpressionValue& rslt);
+ bool GetStringExpression(const StringRef& str)
+ pre (readPointer >= 0; gcodeBuffer[readPointer] == '['; str.IsEmpty());
+ TypeCode EvaluateExpression(const char *p, const char **endptr, ExpressionValue& rslt)
+ pre (readPointer >= 0; gcodeBuffer[readPointer] == '[');
#endif
GCodeMachineState *machineState; // Machine state for this gcode source
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index 83462029..e012884b 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -70,6 +70,7 @@ void GCodes::RawMove::SetDefaults()
const ObjectModelTableEntry GCodes::objectModelTable[] =
{
+ // These entries must be in alphabetical order
{ "speedFactor", OBJECT_MODEL_FUNC(&(self->speedFactor)), TYPE_OF(float), ObjectModelTableEntry::none }
};
diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp
index 5c3b96b9..c9b56c2b 100644
--- a/src/GCodes/GCodes3.cpp
+++ b/src/GCodes/GCodes3.cpp
@@ -679,7 +679,7 @@ GCodeResult GCodes::DoDriveMapping(GCodeBuffer& gb, const StringRef& reply)
return GCodeResult::notFinished;
}
- bool seen = false, badDrive = false;
+ bool seen = false;
const char *lettersToTry = "XYZUVWABC";
char c;
while ((c = *lettersToTry) != 0)
@@ -697,19 +697,7 @@ GCodeResult GCodes::DoDriveMapping(GCodeBuffer& gb, const StringRef& reply)
config.numDrivers = numValues;
for (size_t i = 0; i < numValues; ++i)
{
- if (drivers[i] >= MaxTotalDrivers)
- {
- badDrive = true;
- }
- else
- {
- config.driverNumbers[i] = (uint8_t)drivers[i];
- }
- }
-
- if (badDrive)
- {
- break;
+ config.driverNumbers[i] = (uint8_t)min<uint32_t>(drivers[i], 255);
}
// Find the drive number allocated to this axis, or allocate a new one if necessary
@@ -748,62 +736,47 @@ GCodeResult GCodes::DoDriveMapping(GCodeBuffer& gb, const StringRef& reply)
numExtruders = numValues;
for (size_t i = 0; i < numValues; ++i)
{
- if (drivers[i] >= MaxTotalDrivers)
- {
- badDrive = true;
- }
- else
- {
- platform.SetExtruderDriver(i, (uint8_t)drivers[i]);
- }
+ platform.SetExtruderDriver(i, (uint8_t)min<uint32_t>(drivers[i], 255));
}
}
- if (badDrive)
- {
- reply.copy("Invalid driver number");
- return GCodeResult::error;
- }
- else
+ if (gb.Seen('P'))
{
- if (gb.Seen('P'))
+ seen = true;
+ const int nva = gb.GetIValue();
+ if (nva >= (int)MinAxes && (unsigned int)nva <= numTotalAxes)
{
- seen = true;
- const int nva = gb.GetIValue();
- if (nva >= (int)MinAxes && (unsigned int)nva <= numTotalAxes)
- {
- numVisibleAxes = (size_t)nva;
- }
- else
- {
- reply.copy("Invalid number of visible axes");
- return GCodeResult::error;
- }
+ numVisibleAxes = (size_t)nva;
+ }
+ else
+ {
+ reply.copy("Invalid number of visible axes");
+ return GCodeResult::error;
}
+ }
- if (!seen)
+ if (!seen)
+ {
+ reply.copy("Driver assignments:");
+ for (size_t drive = 0; drive < numTotalAxes; ++ drive)
{
- reply.copy("Driver assignments:");
- for (size_t drive = 0; drive < numTotalAxes; ++ drive)
- {
- reply.cat(' ');
- const AxisDriversConfig& axisConfig = platform.GetAxisDriversConfig(drive);
- char c = axisLetters[drive];
- for (size_t i = 0; i < axisConfig.numDrivers; ++i)
- {
- reply.catf("%c%u", c, axisConfig.driverNumbers[i]);
- c = ':';
- }
- }
reply.cat(' ');
- char c = extrudeLetter;
- for (size_t extruder = 0; extruder < numExtruders; ++extruder)
+ const AxisDriversConfig& axisConfig = platform.GetAxisDriversConfig(drive);
+ char c = axisLetters[drive];
+ for (size_t i = 0; i < axisConfig.numDrivers; ++i)
{
- reply.catf("%c%u", c, platform.GetExtruderDriver(extruder));
+ reply.catf("%c%u", c, axisConfig.driverNumbers[i]);
c = ':';
}
- reply.catf(", %u axes visible", numVisibleAxes);
}
+ reply.cat(' ');
+ char c = extrudeLetter;
+ for (size_t extruder = 0; extruder < numExtruders; ++extruder)
+ {
+ reply.catf("%c%u", c, platform.GetExtruderDriver(extruder));
+ c = ':';
+ }
+ reply.catf(", %u axes visible", numVisibleAxes);
}
return GCodeResult::ok;
@@ -1025,7 +998,7 @@ GCodeResult GCodes::SendI2c(GCodeBuffer& gb, const StringRef &reply)
#if defined(I2C_IFACE)
if (gb.Seen('A'))
{
- const uint32_t address = gb.GetUIValue();
+ const uint32_t address = gb.GetUIValueMaybeHex();
if (gb.Seen('B'))
{
int32_t values[MaxI2cBytes];
@@ -1064,7 +1037,7 @@ GCodeResult GCodes::ReceiveI2c(GCodeBuffer& gb, const StringRef &reply)
#if defined(I2C_IFACE)
if (gb.Seen('A'))
{
- const uint32_t address = gb.GetUIValue();
+ const uint32_t address = gb.GetUIValueMaybeHex();
if (gb.Seen('B'))
{
uint32_t numBytes = gb.GetUIValue();
diff --git a/src/Movement/BedProbing/Grid.cpp b/src/Movement/BedProbing/Grid.cpp
index 79c1031a..9e96f400 100644
--- a/src/Movement/BedProbing/Grid.cpp
+++ b/src/Movement/BedProbing/Grid.cpp
@@ -28,6 +28,7 @@ const char * const GridDefinition::HeightMapLabelLines[] =
const ObjectModelTableEntry GridDefinition::objectModelTable[] =
{
+ // These entries must be in alphabetical order
{ "radius", OBJECT_MODEL_FUNC(&(self->radius)), TYPE_OF(float), ObjectModelTableEntry::none }
};
diff --git a/src/Movement/BedProbing/RandomProbePointSet.cpp b/src/Movement/BedProbing/RandomProbePointSet.cpp
index 4b49e5c4..e64da0b8 100644
--- a/src/Movement/BedProbing/RandomProbePointSet.cpp
+++ b/src/Movement/BedProbing/RandomProbePointSet.cpp
@@ -20,7 +20,8 @@
const ObjectModelTableEntry RandomProbePointSet::objectModelTable[] =
{
- { "numBedCompensationPoints", OBJECT_MODEL_FUNC(&(self->numBedCompensationPoints)), TYPE_OF(uint32_t), ObjectModelTableEntry::none }
+ // These entries must be in alphabetical order
+ { "numPointsProbed", OBJECT_MODEL_FUNC(&(self->numBedCompensationPoints)), TYPE_OF(uint32_t), ObjectModelTableEntry::none }
};
DEFINE_GET_OBJECT_MODEL_TABLE(RandomProbePointSet)
diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp
index 51068b79..50a35d14 100644
--- a/src/Movement/DDA.cpp
+++ b/src/Movement/DDA.cpp
@@ -678,7 +678,12 @@ pre(state == provisional)
)
{
// This is a deceleration-only move, so we may have to adjust the previous move as well to get optimum behaviour
- if (laDDA->prev->state == provisional && laDDA->prev->isPrintingMove == laDDA->isPrintingMove && laDDA->prev->xyMoving == laDDA->xyMoving)
+ if ( laDDA->prev->state == provisional
+ && laDDA->prev->xyMoving == laDDA->xyMoving
+ && ( laDDA->prev->isPrintingMove == laDDA->isPrintingMove
+ || (laDDA->prev->isPrintingMove && laDDA->prev->requestedSpeed == laDDA->requestedSpeed) // special case to support coast-to-end
+ )
+ )
{
laDDA->MatchSpeeds();
const float maxStartSpeed = sqrtf(fsquare(laDDA->targetNextSpeed) + (2 * laDDA->deceleration * laDDA->totalDistance));
diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp
index 9840f93c..bd81d352 100644
--- a/src/Movement/Move.cpp
+++ b/src/Movement/Move.cpp
@@ -57,11 +57,12 @@ constexpr uint32_t AbsoluteMinimumPreparedTime = StepTimer::StepClockRate/20; /
const ObjectModelTableEntry Move::objectModelTable[] =
{
+ // These entries must be in alphabetical order
+ { "drcEnabled", OBJECT_MODEL_FUNC(&(self->drcEnabled)), TYPE_OF(bool), ObjectModelTableEntry::none },
+ { "drcMinimumAcceleration", OBJECT_MODEL_FUNC(&(self->drcMinimumAcceleration)), TYPE_OF(float), ObjectModelTableEntry::none },
+ { "drcPeriod", OBJECT_MODEL_FUNC(&(self->drcPeriod)), TYPE_OF(float), ObjectModelTableEntry::none },
{ "maxPrintingAcceleration", OBJECT_MODEL_FUNC(&(self->maxPrintingAcceleration)), TYPE_OF(float), ObjectModelTableEntry::none },
{ "maxTravelAcceleration", OBJECT_MODEL_FUNC(&(self->maxTravelAcceleration)), TYPE_OF(float), ObjectModelTableEntry::none },
- { "drcPeriod", OBJECT_MODEL_FUNC(&(self->drcPeriod)), TYPE_OF(float), ObjectModelTableEntry::none },
- { "drcMinimumAcceleration", OBJECT_MODEL_FUNC(&(self->drcMinimumAcceleration)), TYPE_OF(float), ObjectModelTableEntry::none },
- { "drcEnabled", OBJECT_MODEL_FUNC(&(self->drcEnabled)), TYPE_OF(bool), ObjectModelTableEntry::none },
};
DEFINE_GET_OBJECT_MODEL_TABLE(Move)
@@ -1307,7 +1308,10 @@ void Move::AdjustLeadscrews(const floatc_t corrections[])
const AxisDriversConfig& config = reprap.GetPlatform().GetAxisDriversConfig(Z_AXIS);
for (size_t i = 0; i < config.numDrivers; ++i)
{
- specialMoveCoords[config.driverNumbers[i]] = corrections[i];
+ if (config.driverNumbers[i] < MaxTotalDrivers)
+ {
+ specialMoveCoords[config.driverNumbers[i]] = corrections[i];
+ }
}
specialMoveAvailable = true;
}
diff --git a/src/Networking/ESP8266WiFi/WiFiInterface.cpp b/src/Networking/ESP8266WiFi/WiFiInterface.cpp
index bd71e507..ad288202 100644
--- a/src/Networking/ESP8266WiFi/WiFiInterface.cpp
+++ b/src/Networking/ESP8266WiFi/WiFiInterface.cpp
@@ -167,10 +167,11 @@ WiFiInterface::WiFiInterface(Platform& p) : platform(p), uploader(nullptr), ftpD
const ObjectModelTableEntry WiFiInterface::objectModelTable[] =
{
- { "name", OBJECT_MODEL_FUNC_NOSELF("wifi"), TYPE_OF(const char *), ObjectModelTableEntry::none },
+ // These entries must be in alphabetical order
+ { "gateway", OBJECT_MODEL_FUNC(&(self->gateway)), TYPE_OF(IPAddress), ObjectModelTableEntry::none },
{ "ip", OBJECT_MODEL_FUNC(&(self->ipAddress)), TYPE_OF(IPAddress), ObjectModelTableEntry::none },
+ { "name", OBJECT_MODEL_FUNC_NOSELF("wifi"), TYPE_OF(const char *), ObjectModelTableEntry::none },
{ "netmask", OBJECT_MODEL_FUNC(&(self->netmask)), TYPE_OF(IPAddress), ObjectModelTableEntry::none },
- { "gateway", OBJECT_MODEL_FUNC(&(self->gateway)), TYPE_OF(IPAddress), ObjectModelTableEntry::none }
};
DEFINE_GET_OBJECT_MODEL_TABLE(WiFiInterface)
diff --git a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
index dc8dd614..ed89f892 100644
--- a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
+++ b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
@@ -149,10 +149,11 @@ LwipEthernetInterface::LwipEthernetInterface(Platform& p) : platform(p), closeDa
const ObjectModelTableEntry LwipEthernetInterface::objectModelTable[] =
{
- { "name", OBJECT_MODEL_FUNC_NOSELF("ethernet"), TYPE_OF(const char *), ObjectModelTableEntry::none },
+ // These entries must be in alphabetical order
+ { "gateway", OBJECT_MODEL_FUNC(&(self->gateway)), TYPE_OF(IPAddress), ObjectModelTableEntry::none },
{ "ip", OBJECT_MODEL_FUNC(&(self->ipAddress)), TYPE_OF(IPAddress), ObjectModelTableEntry::none },
+ { "name", OBJECT_MODEL_FUNC_NOSELF("ethernet"), TYPE_OF(const char *), ObjectModelTableEntry::none },
{ "netmask", OBJECT_MODEL_FUNC(&(self->netmask)), TYPE_OF(IPAddress), ObjectModelTableEntry::none },
- { "gateway", OBJECT_MODEL_FUNC(&(self->gateway)), TYPE_OF(IPAddress), ObjectModelTableEntry::none }
};
DEFINE_GET_OBJECT_MODEL_TABLE(LwipEthernetInterface)
diff --git a/src/Networking/Network.cpp b/src/Networking/Network.cpp
index 179d3a57..424043a5 100644
--- a/src/Networking/Network.cpp
+++ b/src/Networking/Network.cpp
@@ -70,6 +70,7 @@ static const ObjectModelArrayDescriptor interfaceArrayDescriptor =
const ObjectModelTableEntry Network::objectModelTable[] =
{
+ // These entries must be in alphabetical order
{ "interfaces", OBJECT_MODEL_FUNC_NOSELF(&interfaceArrayDescriptor), TYPE_OF(ObjectModel) | IsArray, ObjectModelTableEntry::none }
};
diff --git a/src/Networking/Network.h b/src/Networking/Network.h
index 6e86a1b0..41f4c148 100644
--- a/src/Networking/Network.h
+++ b/src/Networking/Network.h
@@ -80,7 +80,7 @@ public:
uint32_t GetHttpReplySeq();
#if SUPPORT_OBJECT_MODEL
- void *GetInterface(size_t n) { return interfaces[n]; }
+ NetworkInterface *GetInterface(size_t n) const { return interfaces[n]; }
#endif
protected:
diff --git a/src/Networking/W5500Ethernet/W5500Interface.cpp b/src/Networking/W5500Ethernet/W5500Interface.cpp
index 18f008d0..3d401ff8 100644
--- a/src/Networking/W5500Ethernet/W5500Interface.cpp
+++ b/src/Networking/W5500Ethernet/W5500Interface.cpp
@@ -44,10 +44,11 @@ W5500Interface::W5500Interface(Platform& p)
const ObjectModelTableEntry W5500Interface::objectModelTable[] =
{
- { "name", OBJECT_MODEL_FUNC_NOSELF("ethernet"), TYPE_OF(const char *), ObjectModelTableEntry::none },
+ // These entries must be in alphabetical order
+ { "gateway", OBJECT_MODEL_FUNC(&(self->gateway)), TYPE_OF(IPAddress), ObjectModelTableEntry::none },
{ "ip", OBJECT_MODEL_FUNC(&(self->ipAddress)), TYPE_OF(IPAddress), ObjectModelTableEntry::none },
+ { "name", OBJECT_MODEL_FUNC_NOSELF("ethernet"), TYPE_OF(const char *), ObjectModelTableEntry::none },
{ "netmask", OBJECT_MODEL_FUNC(&(self->netmask)), TYPE_OF(IPAddress), ObjectModelTableEntry::none },
- { "gateway", OBJECT_MODEL_FUNC(&(self->gateway)), TYPE_OF(IPAddress), ObjectModelTableEntry::none }
};
DEFINE_GET_OBJECT_MODEL_TABLE(W5500Interface)
diff --git a/src/ObjectModel/ObjectModel.cpp b/src/ObjectModel/ObjectModel.cpp
index 581c16c8..44c579b1 100644
--- a/src/ObjectModel/ObjectModel.cpp
+++ b/src/ObjectModel/ObjectModel.cpp
@@ -11,6 +11,7 @@
#include "OutputMemory.h"
#include <cstring>
+#include <General/SafeStrtod.h>
// Constructor
ObjectModel::ObjectModel()
@@ -96,7 +97,15 @@ void ObjectModelTableEntry::ReportItemAsJson(OutputBuffer *buf, const char *filt
break;
case TYPE_OF(float):
- buf->catf("%.1f", (double)*(const float *)nParam); //TODO different parameters need different number of decimal places
+ buf->catf("%.1f", (double)*(const float *)nParam);
+ break;
+
+ case TYPE_OF(Float2):
+ buf->catf("%.2f", (double)*(const float *)nParam);
+ break;
+
+ case TYPE_OF(Float3):
+ buf->catf("%.3f", (double)*(const float *)nParam);
break;
case TYPE_OF(uint32_t):
@@ -118,8 +127,15 @@ void ObjectModelTableEntry::ReportItemAsJson(OutputBuffer *buf, const char *filt
}
else
{
+ uint32_t v = *(const uint32_t *)nParam;
buf->cat('[');
- // TODO list the bits that are set
+ buf->cat((v & 1) ? '1' : '0');
+ for (unsigned int i = 1; i < 32; ++i)
+ {
+ v >>= 1;
+ buf->cat(',');
+ buf->cat((v & 1) ? '1' : '0');
+ }
buf->cat(']');
}
break;
@@ -145,7 +161,7 @@ void ObjectModelTableEntry::ReportItemAsJson(OutputBuffer *buf, const char *filt
}
else
{
- buf->cat((bVal) ? "yes" : "no");
+ buf->cat((bVal) ? "\"yes\"" : "\"no\"");
}
}
break;
@@ -212,16 +228,6 @@ int ObjectModelTableEntry::IdCompare(const char *id) const
: -1;
}
-// Check the type is correct, call the function if necessary and return the pointer
-void* ObjectModelTableEntry::GetValuePointer(ObjectModel *self, TypeCode t) const
-{
- if (t != type)
- {
- return nullptr;
- }
- return param(self);
-}
-
// Get the value of an object when we don't know what its type is
TypeCode ObjectModel::GetObjectValue(ExpressionValue& val, const char *idString)
{
@@ -231,39 +237,73 @@ TypeCode ObjectModel::GetObjectValue(ExpressionValue& val, const char *idString)
return NoType;
}
- if ((e->type & IsArray) != 0)
+ idString = GetNextElement(idString);
+ void * param = e->param(this);
+ TypeCode tc = e->type;
+ if ((tc & IsArray) != 0)
{
- //TODO handle arrays
- return NoType;
+ if (*idString != '[')
+ {
+ return NoType; // no array index is provided, and we don't currently allow an entire array to be returned
+ }
+ const char *endptr;
+ const unsigned long val = SafeStrtoul(idString + 1, &endptr);
+ if (endptr == idString + 1 || *endptr != ']')
+ {
+ return NoType; // invalid syntax
+ }
+ const ObjectModelArrayDescriptor *arr = (const ObjectModelArrayDescriptor*)param;
+ if (val >= arr->GetNumElements(this))
+ {
+ return NoType; // array index out of range
+ }
+
+ idString = endptr + 1; // skip past the ']'
+ if (*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
}
- switch (e->type)
+ switch (tc)
{
case TYPE_OF(ObjectModel):
- return ((ObjectModel*)e->param(this))->GetObjectValue(val, GetNextElement(idString));
+ return ((ObjectModel*)param)->GetObjectValue(val, idString);
case TYPE_OF(float):
- val.fVal = *((const float*)e->param(this));
+ case TYPE_OF(Float2):
+ case TYPE_OF(Float3):
+ val.fVal = *((const float*)param);
break;
case TYPE_OF(uint32_t):
case TYPE_OF(Bitmap32):
case TYPE_OF(Enum32):
- val.uVal = *((const uint32_t*)e->param(this));
+ val.uVal = *((const uint32_t*)param);
break;
case TYPE_OF(int32_t):
- val.iVal = *((const int32_t*)e->param(this));
+ val.iVal = *((const int32_t*)param);
break;
case TYPE_OF(const char*):
- val.sVal = *((const char* const *)e->param(this));
+ val.sVal = (const char*)param;
break;
- default:
+ case TYPE_OF(bool):
+ val.bVal = *((const bool*)param);
+ break;
+
+ case TYPE_OF(IPAddress):
+ val.uVal = ((const IPAddress *)param)->GetV4LittleEndian();
break;
+
+ default:
+ return NoType;
}
- return e->type;
+ return tc;
}
// Template specialisations
diff --git a/src/ObjectModel/ObjectModel.h b/src/ObjectModel/ObjectModel.h
index e0e69f4c..a3ad2d17 100644
--- a/src/ObjectModel/ObjectModel.h
+++ b/src/ObjectModel/ObjectModel.h
@@ -24,6 +24,7 @@ class ObjectModel;
union ExpressionValue
{
+ bool bVal;
float fVal;
int32_t iVal;
uint32_t uVal;
@@ -32,8 +33,10 @@ union ExpressionValue
};
// Dummy types, used to define type codes
-class Bitmap32 { };
-class Enum32 { };
+class Bitmap32;
+class Enum32;
+class Float2; // float printed to 2 decimal places instead of 1
+class Float3; // float printed to 3 decimal places instead of 1
class ObjectModel
{
@@ -87,11 +90,13 @@ template<> constexpr TypeCode TypeOf<bool> () { return 1; }
template<> constexpr TypeCode TypeOf<uint32_t> () { return 2; }
template<> constexpr TypeCode TypeOf<int32_t>() { return 3; }
template<> constexpr TypeCode TypeOf<float>() { return 4; }
-template<> constexpr TypeCode TypeOf<Bitmap32>() { return 5; }
-template<> constexpr TypeCode TypeOf<Enum32>() { return 6; }
-template<> constexpr TypeCode TypeOf<ObjectModel>() { return 7; }
-template<> constexpr TypeCode TypeOf<const char *>() { return 8; }
-template<> constexpr TypeCode TypeOf<IPAddress>() { return 9; }
+template<> constexpr TypeCode TypeOf<Float2>() { return 5; }
+template<> constexpr TypeCode TypeOf<Float3>() { return 6; }
+template<> constexpr TypeCode TypeOf<Bitmap32>() { return 7; }
+template<> constexpr TypeCode TypeOf<Enum32>() { return 8; }
+template<> constexpr TypeCode TypeOf<ObjectModel>() { return 9; }
+template<> constexpr TypeCode TypeOf<const char *>() { return 10; }
+template<> constexpr TypeCode TypeOf<IPAddress>() { return 11; }
#define TYPE_OF(_t) (TypeOf<_t>())
@@ -141,15 +146,6 @@ public:
// Compare the name of this field with the filter string that we are trying to match
int IdCompare(const char *id) const;
- // Return true if this field is an object, not a primitive type
- bool IsObject() const { return type == TYPE_OF(ObjectModel); }
-
- // Follow the path specified by the ifString until we reach the end of it
- const ObjectModelTableEntry *FindLeafEntry(ObjectModel *self, const char *idString) const;
-
- // Check the type is correct, call the function and return the pointer
- void* GetValuePointer(ObjectModel *self, TypeCode t) const;
-
// Private function to report a value of primitive type
static void ReportItemAsJson(OutputBuffer *buf, const char *filter, ObjectModel::ReportFlags flags, void *nParam, TypeCode type);
};
diff --git a/src/Platform.cpp b/src/Platform.cpp
index 4bbb2274..b4104610 100644
--- a/src/Platform.cpp
+++ b/src/Platform.cpp
@@ -2294,9 +2294,10 @@ void Platform::Diagnostics(MessageType mtype)
#if HAS_VOLTAGE_MONITOR
// Show the supply voltage
- MessageF(mtype, "Supply voltage: min %.1f, current %.1f, max %.1f, under voltage events: %" PRIu32 ", over voltage events: %" PRIu32 "\n",
+ MessageF(mtype, "Supply voltage: min %.1f, current %.1f, max %.1f, under voltage events: %" PRIu32 ", over voltage events: %" PRIu32 ", power good: %s\n",
(double)AdcReadingToPowerVoltage(lowestVin), (double)AdcReadingToPowerVoltage(currentVin), (double)AdcReadingToPowerVoltage(highestVin),
- numUnderVoltageEvents, numOverVoltageEvents);
+ numUnderVoltageEvents, numOverVoltageEvents,
+ (driversPowered) ? "yes" : "no");
lowestVin = highestVin = currentVin;
#endif
@@ -4436,7 +4437,11 @@ GCodeResult Platform::ConfigureStallDetection(GCodeBuffer& gb, const StringRef&
{
for (size_t j = 0; j < axisDrivers[i].numDrivers; ++j)
{
- SetBit(drivers, axisDrivers[i].driverNumbers[j]);
+ const uint8_t driver = axisDrivers[i].driverNumbers[j];
+ if (driver < numSmartDrivers)
+ {
+ SetBit(drivers, driver);
+ }
}
}
}
@@ -4451,7 +4456,11 @@ GCodeResult Platform::ConfigureStallDetection(GCodeBuffer& gb, const StringRef&
{
if (extruderNumbers[i] < MaxExtruders)
{
- SetBit(drivers, GetExtruderDriver(extruderNumbers[i]));
+ const uint8_t driver = GetExtruderDriver(extruderNumbers[i]);
+ if (driver < numSmartDrivers)
+ {
+ SetBit(drivers, driver);
+ }
}
}
}
diff --git a/src/RepRap.cpp b/src/RepRap.cpp
index 422fc826..c0b12870 100644
--- a/src/RepRap.cpp
+++ b/src/RepRap.cpp
@@ -162,9 +162,9 @@ const ObjectModelTableEntry RepRap::objectModelTable[] =
// These entries are temporary pending design of the object model
//TODO design the object model
{ "gcodes", OBJECT_MODEL_FUNC(&(self->GetGCodes())), TYPE_OF(ObjectModel), ObjectModelTableEntry::none },
+ { "meshProbe", OBJECT_MODEL_FUNC(&(self->GetMove().GetGrid())), TYPE_OF(ObjectModel), ObjectModelTableEntry::none },
{ "move", OBJECT_MODEL_FUNC(&(self->GetMove())), TYPE_OF(ObjectModel), ObjectModelTableEntry::none },
{ "network", OBJECT_MODEL_FUNC(&(self->GetNetwork())), TYPE_OF(ObjectModel), ObjectModelTableEntry::none },
- { "meshProbe", OBJECT_MODEL_FUNC(&(self->GetMove().GetGrid())), TYPE_OF(ObjectModel), ObjectModelTableEntry::none },
{ "randomProbe", OBJECT_MODEL_FUNC(&(self->GetMove().GetProbePoints())), TYPE_OF(ObjectModel), ObjectModelTableEntry::none },
};
diff --git a/src/Version.h b/src/Version.h
index 7a7f96c5..ca8c11e2 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -22,7 +22,7 @@
#endif
#ifndef DATE
-# define DATE "2018-10-28b2"
+# define DATE "2018-10-29b1"
#endif
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman, printm3d"