diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/BugList.txt | 20 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer.cpp | 128 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer.h | 14 | ||||
-rw-r--r-- | src/GCodes/GCodes.cpp | 1 | ||||
-rw-r--r-- | src/GCodes/GCodes3.cpp | 91 | ||||
-rw-r--r-- | src/Movement/BedProbing/Grid.cpp | 1 | ||||
-rw-r--r-- | src/Movement/BedProbing/RandomProbePointSet.cpp | 3 | ||||
-rw-r--r-- | src/Movement/DDA.cpp | 7 | ||||
-rw-r--r-- | src/Movement/Move.cpp | 12 | ||||
-rw-r--r-- | src/Networking/ESP8266WiFi/WiFiInterface.cpp | 5 | ||||
-rw-r--r-- | src/Networking/LwipEthernet/LwipEthernetInterface.cpp | 5 | ||||
-rw-r--r-- | src/Networking/Network.cpp | 1 | ||||
-rw-r--r-- | src/Networking/Network.h | 2 | ||||
-rw-r--r-- | src/Networking/W5500Ethernet/W5500Interface.cpp | 5 | ||||
-rw-r--r-- | src/ObjectModel/ObjectModel.cpp | 88 | ||||
-rw-r--r-- | src/ObjectModel/ObjectModel.h | 28 | ||||
-rw-r--r-- | src/Platform.cpp | 17 | ||||
-rw-r--r-- | src/RepRap.cpp | 2 | ||||
-rw-r--r-- | src/Version.h | 2 |
19 files changed, 281 insertions, 151 deletions
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" |