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--src/CAN/CanInterface.cpp2
-rw-r--r--src/CAN/CanInterface.h2
-rw-r--r--src/DuetM/Pins_DuetM.h8
-rw-r--r--src/DuetNG/Pins_DuetNG.h6
-rw-r--r--src/GCodes/GCodeBuffer/StringParser.cpp35
-rw-r--r--src/GCodes/GCodeBuffer/StringParser.h2
-rw-r--r--src/GCodes/GCodes2.cpp64
-rw-r--r--src/Heating/Heat.cpp10
-rw-r--r--src/Heating/Heater.cpp6
-rw-r--r--src/Heating/Sensors/CpuTemperatureSensor.cpp5
-rw-r--r--src/Heating/Sensors/TemperatureSensor.cpp6
-rw-r--r--src/Movement/Move.cpp47
-rw-r--r--src/Networking/ESP8266WiFi/WiFiInterface.cpp10
-rw-r--r--src/Networking/HttpResponder.cpp9
-rw-r--r--src/Networking/LwipEthernet/LwipEthernetInterface.cpp10
-rw-r--r--src/Networking/Network.cpp2
-rw-r--r--src/Networking/W5500Ethernet/W5500Interface.cpp10
-rw-r--r--src/ObjectModel/ObjectModel.cpp293
-rw-r--r--src/ObjectModel/ObjectModel.h32
-rw-r--r--src/Pccb/Pins_Pccb.h6
-rw-r--r--src/Platform.cpp86
-rw-r--r--src/Platform.h6
-rw-r--r--src/PrintMonitor.cpp34
-rw-r--r--src/RepRap.cpp65
-rw-r--r--src/RepRap.h4
-rw-r--r--src/RepRapFirmware.h8
-rw-r--r--src/Version.h2
27 files changed, 464 insertions, 306 deletions
diff --git a/src/CAN/CanInterface.cpp b/src/CAN/CanInterface.cpp
index bec9eb33..c05feee5 100644
--- a/src/CAN/CanInterface.cpp
+++ b/src/CAN/CanInterface.cpp
@@ -844,7 +844,7 @@ GCodeResult CanInterface::RemoteDiagnostics(MessageType mt, uint32_t boardAddres
return res;
}
-GCodeResult CanInterface::RemoteM408(uint32_t boardAddress, unsigned int form, unsigned int type, GCodeBuffer& gb, const StringRef& reply) noexcept
+GCodeResult CanInterface::RemoteM408(uint32_t boardAddress, unsigned int type, GCodeBuffer& gb, const StringRef& reply) noexcept
{
return GetRemoteInfo(CanMessageReturnInfo::typeM408, boardAddress, type, gb, reply, nullptr);
}
diff --git a/src/CAN/CanInterface.h b/src/CAN/CanInterface.h
index 9fb964e9..1230993f 100644
--- a/src/CAN/CanInterface.h
+++ b/src/CAN/CanInterface.h
@@ -73,7 +73,7 @@ namespace CanInterface
// Info functions
GCodeResult GetRemoteFirmwareDetails(uint32_t boardAddress, GCodeBuffer& gb, const StringRef& reply) noexcept;
GCodeResult RemoteDiagnostics(MessageType mt, uint32_t boardAddress, unsigned int type, GCodeBuffer& gb, const StringRef& reply) noexcept;
- GCodeResult RemoteM408(uint32_t boardAddress, unsigned int form, unsigned int type, GCodeBuffer& gb, const StringRef& reply) noexcept;
+ GCodeResult RemoteM408(uint32_t boardAddress, unsigned int type, GCodeBuffer& gb, const StringRef& reply) noexcept;
// Firmware update functions
GCodeResult UpdateRemoteFirmware(uint32_t boardAddress, GCodeBuffer& gb, const StringRef& reply) noexcept;
diff --git a/src/DuetM/Pins_DuetM.h b/src/DuetM/Pins_DuetM.h
index f96bb74a..68c10949 100644
--- a/src/DuetM/Pins_DuetM.h
+++ b/src/DuetM/Pins_DuetM.h
@@ -55,7 +55,7 @@ constexpr uint32_t IAP_IMAGE_END = 0x0047FFFF; // we allow a full 64K on
#define SUPPORT_FTP 1
#define SUPPORT_TELNET 1
#define SUPPORT_ASYNC_MOVES 1
-#define ALLOCATE_DEFAULT_PORTS 1
+#define ALLOCATE_DEFAULT_PORTS 0
// The physical capabilities of the machine
@@ -265,15 +265,19 @@ constexpr PinEntry PinTable[] =
constexpr unsigned int NumNamedPins = ARRAY_SIZE(PinTable);
-// Function to look up a pin name pass back the corresponding index into the pin table
+// Function to look up a pin name and pass back the corresponding index into the pin table
bool LookupPinName(const char *pn, LogicalPin& lpin, bool& hardwareInverted) noexcept;
+#if ALLOCATE_DEFAULT_PORTS
+
// Default pin allocations
constexpr const char *DefaultEndstopPinNames[] = { "xstop", "ystop", "zstop" };
constexpr const char *DefaultZProbePinNames = "^zprobe.in+zprobe.mod";
constexpr const char *DefaultFanPinNames[] = { "fan0", "fan1", "fan2" };
constexpr PwmFrequency DefaultFanPwmFrequencies[] = { DefaultFanPwmFreq };
+#endif
+
// Duet pin numbers to control the W5500 interface
constexpr Pin W5500ResetPin = PortCPin(13); // Low on this in holds the W5500 in reset
constexpr Pin W5500SsPin = PortAPin(11); // SPI NPCS pin to W5500
diff --git a/src/DuetNG/Pins_DuetNG.h b/src/DuetNG/Pins_DuetNG.h
index 14c46244..8db247e6 100644
--- a/src/DuetNG/Pins_DuetNG.h
+++ b/src/DuetNG/Pins_DuetNG.h
@@ -54,7 +54,7 @@ constexpr size_t NumFirmwareUpdateModules = 4; // 3 modules, plus one for manua
#define SUPPORT_FTP 1
#define SUPPORT_TELNET 1
#define SUPPORT_ASYNC_MOVES 1
-#define ALLOCATE_DEFAULT_PORTS 1
+#define ALLOCATE_DEFAULT_PORTS 0
#define USE_CACHE 1 // set nonzero to enable the cache
#define USE_MPU 0 // set nonzero to enable the memory protection unit
@@ -326,12 +326,16 @@ constexpr unsigned int NumNamedPins = ARRAY_SIZE(PinTable);
// 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) noexcept;
+#if ALLOCATE_DEFAULT_PORTS
+
// Default pin allocations
constexpr const char *DefaultEndstopPinNames[] = { "xstop", "ystop", "zstop" };
constexpr const char *DefaultZProbePinNames = "^zprobe.in+zprobe.mod";
constexpr const char *DefaultFanPinNames[] = { "fan0", "fan1", "fan2" };
constexpr PwmFrequency DefaultFanPwmFrequencies[] = { DefaultFanPwmFreq };
+#endif
+
// Duet pin numbers to control the WiFi interface on the Duet WiFi
constexpr Pin EspResetPin = PortEPin(4); // Low on this in holds the WiFi module in reset (ESP_RESET)
constexpr Pin EspEnablePin = PortEPin(5); // High to enable the WiFi module, low to power it down (ESP_CH_PD)
diff --git a/src/GCodes/GCodeBuffer/StringParser.cpp b/src/GCodes/GCodeBuffer/StringParser.cpp
index cefaab89..4f4b8d7c 100644
--- a/src/GCodes/GCodeBuffer/StringParser.cpp
+++ b/src/GCodes/GCodeBuffer/StringParser.cpp
@@ -1657,7 +1657,7 @@ ExpressionValue StringParser::ParseExpression(StringBuffer& stringBuffer, uint8_
constexpr uint8_t UnaryPriority = 10; // must be higher than any binary operator priority
static_assert(ARRAY_SIZE(priorities) == strlen(operators));
- // Start by parsing a unary expression
+ // Start by looking for a unary operator or opening bracket
SkipWhiteSpace();
const char c = gb.buffer[readPointer];
ExpressionValue val;
@@ -1688,7 +1688,7 @@ ExpressionValue StringParser::ParseExpression(StringBuffer& stringBuffer, uint8_
case '+':
++readPointer;
- val = ParseExpression(stringBuffer, UnaryPriority, true);
+ val = ParseExpression(stringBuffer, UnaryPriority, evaluate);
switch (val.type)
{
case TYPE_OF(uint32_t):
@@ -1706,6 +1706,31 @@ ExpressionValue StringParser::ParseExpression(StringBuffer& stringBuffer, uint8_
}
break;
+ case '#':
+ ++readPointer;
+ SkipWhiteSpace();
+ if (isalpha(gb.buffer[readPointer]))
+ {
+ // Probably applying # to an object model array, so optimise by asking the OM for just the length
+ val = ParseIdentifierExpression(stringBuffer, true, evaluate);
+ }
+ else
+ {
+ val = ParseExpression(stringBuffer, UnaryPriority, evaluate);
+ if (val.type == TYPE_OF(const char*))
+ {
+ const char* s = val.sVal;
+ val.Set((int32_t)strlen(s));
+ stringBuffer.FinishedUsing(s);
+ val.type = TYPE_OF(int32_t);
+ }
+ else
+ {
+ throw ConstructParseException("expected object model value or string after '#");
+ }
+ }
+ break;
+
case '{':
++readPointer;
val = ParseBracketedExpression(stringBuffer, '}', evaluate);
@@ -1730,7 +1755,7 @@ ExpressionValue StringParser::ParseExpression(StringBuffer& stringBuffer, uint8_
}
else if (isalpha(c)) // looks like a variable name
{
- val = ParseIdentifierExpression(stringBuffer, evaluate);
+ val = ParseIdentifierExpression(stringBuffer, evaluate, false);
}
else
{
@@ -2212,7 +2237,7 @@ ExpressionValue StringParser::ParseNumber()
}
// Parse an identifier expression
-ExpressionValue StringParser::ParseIdentifierExpression(StringBuffer& stringBuffer, bool evaluate)
+ExpressionValue StringParser::ParseIdentifierExpression(StringBuffer& stringBuffer, bool applyLengthOperator, bool evaluate)
{
if (!isalpha(gb.buffer[readPointer]))
{
@@ -2220,7 +2245,7 @@ ExpressionValue StringParser::ParseIdentifierExpression(StringBuffer& stringBuff
}
String<MaxVariableNameLength> id;
- ObjectExplorationContext context(ObjectModelReportFlags::none, ObjectModelEntryFlags::none);
+ ObjectExplorationContext context("v", applyLengthOperator);
// Loop parsing identifiers and index expressions
// When we come across an index expression, evaluate it, add it to the context, and place a marker in the identifier string.
diff --git a/src/GCodes/GCodeBuffer/StringParser.h b/src/GCodes/GCodeBuffer/StringParser.h
index c767baba..0d688661 100644
--- a/src/GCodes/GCodeBuffer/StringParser.h
+++ b/src/GCodes/GCodeBuffer/StringParser.h
@@ -119,7 +119,7 @@ private:
pre (readPointer >= 0);
ExpressionValue ParseNumber() THROWS_GCODE_EXCEPTION
pre(readPointer >= 0; isdigit(gb.buffer[readPointer]));
- ExpressionValue ParseIdentifierExpression(StringBuffer& stringBuffer, bool evaluate) THROWS_GCODE_EXCEPTION
+ ExpressionValue ParseIdentifierExpression(StringBuffer& stringBuffer, bool applyLengthOperator, bool evaluate) THROWS_GCODE_EXCEPTION
pre(readPointer >= 0; isalpha(gb.buffer[readPointer]));
void BalanceNumericTypes(ExpressionValue& val1, ExpressionValue& val2, bool evaluate) THROWS_GCODE_EXCEPTION;
diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp
index a6bf1531..55c0a19c 100644
--- a/src/GCodes/GCodes2.cpp
+++ b/src/GCodes/GCodes2.cpp
@@ -2655,61 +2655,45 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
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;
#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);
+ result = CanInterface::RemoteM408(board, type, gb, reply);
break;
}
#endif
- switch (form)
+ const int seq = gb.Seen('R') ? gb.GetIValue() : -1;
+ if (&gb == auxGCode && (type == 0 || type == 2))
{
- case 0:
- {
- const int seq = gb.Seen('R') ? gb.GetIValue() : -1;
- if (&gb == auxGCode && (type == 0 || type == 2))
- {
- lastAuxStatusReportType = type;
- }
+ 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
- }
- }
- break;
+ 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;
#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
- {
- outBuf->printf("{\"key\":");
- outBuf->EncodeString(filter.c_str(), false);
- outBuf->cat(",\"value\":");
- reprap.ReportAsJson(outBuf, filter.c_str(), ObjectModelReportFlags::shortForm, ObjectModelEntryFlags::none);
- outBuf->cat('}');
- }
- }
- break;
-#endif
-
- default:
- break;
+ case 409: // Get status in JSON format
+ {
+ String<StringLength100> key;
+ String<StringLength20> flags;
+ bool dummy;
+ gb.TryGetQuotedString('K', key.GetRef(), dummy);
+ gb.TryGetQuotedString('F', flags.GetRef(), dummy);
+ outBuf = reprap.GetModelResponse(key.c_str(), flags.c_str());
+ if (outBuf == nullptr)
+ {
+ result = GCodeResult::notFinished; // we ran out of buffers, so try again later
}
}
break;
+#endif
case 450: // Report printer mode
reply.printf("PrinterMode:%s", GetMachineModeString());
diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp
index b14bf4ec..0cf9f211 100644
--- a/src/Heating/Heat.cpp
+++ b/src/Heating/Heat.cpp
@@ -81,13 +81,13 @@ constexpr ObjectModelTableEntry Heat::objectModelTable[] =
{
// These entries must be in alphabetical order
// 0. Heat class
- { "ColdExtrudeTemperature", OBJECT_MODEL_FUNC(self->extrusionMinTemp), ObjectModelEntryFlags::none},
- { "ColdRetractTemperature", OBJECT_MODEL_FUNC(self->retractionMinTemp), ObjectModelEntryFlags::none},
- { "Heaters", OBJECT_MODEL_FUNC_NOSELF(&heatersArrayDescriptor), ObjectModelEntryFlags::none },
- { "Sensors", OBJECT_MODEL_FUNC_NOSELF(&sensorsArrayDescriptor), ObjectModelEntryFlags::none },
+ { "coldExtrudeTemperature", OBJECT_MODEL_FUNC(self->extrusionMinTemp), ObjectModelEntryFlags::none},
+ { "coldRetractTemperature", OBJECT_MODEL_FUNC(self->retractionMinTemp), ObjectModelEntryFlags::none},
+ { "heaters", OBJECT_MODEL_FUNC_NOSELF(&heatersArrayDescriptor), ObjectModelEntryFlags::live },
+ { "sensors", OBJECT_MODEL_FUNC_NOSELF(&sensorsArrayDescriptor), ObjectModelEntryFlags::live },
};
-constexpr uint8_t Heat::objectModelTableDescriptor[] = { 3, 4, 0, 0 };
+constexpr uint8_t Heat::objectModelTableDescriptor[] = { 1, 4 };
DEFINE_GET_OBJECT_MODEL_TABLE(Heat)
diff --git a/src/Heating/Heater.cpp b/src/Heating/Heater.cpp
index 7dc201bb..d71dc68c 100644
--- a/src/Heating/Heater.cpp
+++ b/src/Heating/Heater.cpp
@@ -25,9 +25,9 @@ constexpr ObjectModelTableEntry Heater::objectModelTable[] =
{
// Within each group, these entries must be in alphabetical order
// 0. Heater members
- { "Current", OBJECT_MODEL_FUNC(self->GetTemperature()), ObjectModelEntryFlags::none },
- { "Sensor", OBJECT_MODEL_FUNC((int32_t)self->GetSensorNumber()), ObjectModelEntryFlags::none },
- { "State", OBJECT_MODEL_FUNC(self->GetStateName()), ObjectModelEntryFlags::none },
+ { "current", OBJECT_MODEL_FUNC(self->GetTemperature()), ObjectModelEntryFlags::live },
+ { "sensor", OBJECT_MODEL_FUNC((int32_t)self->GetSensorNumber()), ObjectModelEntryFlags::none },
+ { "state", OBJECT_MODEL_FUNC(self->GetStateName()), ObjectModelEntryFlags::live },
};
constexpr uint8_t Heater::objectModelTableDescriptor[] = { 1, 3 };
diff --git a/src/Heating/Sensors/CpuTemperatureSensor.cpp b/src/Heating/Sensors/CpuTemperatureSensor.cpp
index abcac784..983f8832 100644
--- a/src/Heating/Sensors/CpuTemperatureSensor.cpp
+++ b/src/Heating/Sensors/CpuTemperatureSensor.cpp
@@ -17,9 +17,8 @@ CpuTemperatureSensor::CpuTemperatureSensor(unsigned int sensorNum) noexcept : Te
void CpuTemperatureSensor::Poll() noexcept
{
- float minT, currentT, maxT;
- reprap.GetPlatform().GetMcuTemperatures(minT, currentT, maxT);
- SetResult(currentT, TemperatureError::success);
+ const MinMaxCurrent temperatures = reprap.GetPlatform().GetMcuTemperatures();
+ SetResult(temperatures.current, TemperatureError::success);
}
#endif
diff --git a/src/Heating/Sensors/TemperatureSensor.cpp b/src/Heating/Sensors/TemperatureSensor.cpp
index 9b82e6be..63954e99 100644
--- a/src/Heating/Sensors/TemperatureSensor.cpp
+++ b/src/Heating/Sensors/TemperatureSensor.cpp
@@ -37,9 +37,9 @@ constexpr ObjectModelTableEntry TemperatureSensor::objectModelTable[] =
{
// Within each group, these entries must be in alphabetical order
// 0. TemperatureSensor members
- { "LastReading", OBJECT_MODEL_FUNC(self->lastTemperature), ObjectModelEntryFlags::none },
- { "Name", OBJECT_MODEL_FUNC(self->sensorName), ObjectModelEntryFlags::none },
- { "Type", OBJECT_MODEL_FUNC(self->sensorType), ObjectModelEntryFlags::none },
+ { "lastReading", OBJECT_MODEL_FUNC(self->lastTemperature), ObjectModelEntryFlags::live },
+ { "name", OBJECT_MODEL_FUNC(self->sensorName), ObjectModelEntryFlags::none },
+ { "type", OBJECT_MODEL_FUNC(self->sensorType), ObjectModelEntryFlags::none },
};
constexpr uint8_t TemperatureSensor::objectModelTableDescriptor[] = { 1, 3 };
diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp
index cf0b2160..f871f32e 100644
--- a/src/Movement/Move.cpp
+++ b/src/Movement/Move.cpp
@@ -65,35 +65,40 @@ constexpr ObjectModelTableEntry Move::objectModelTable[] =
{
// Within each group, these entries must be in alphabetical order
// 0. Move members
- { "Axes", OBJECT_MODEL_FUNC_NOSELF(&axesArrayDescriptor), ObjectModelEntryFlags::none },
- { "CalibrationDeviation", OBJECT_MODEL_FUNC(self->lastCalibrationDeviation, 3), ObjectModelEntryFlags::none },
- { "Daa", OBJECT_MODEL_FUNC(self, 1), ObjectModelEntryFlags::none },
- { "Idle", OBJECT_MODEL_FUNC(self, 2), ObjectModelEntryFlags::none },
- { "MeshDeviation", OBJECT_MODEL_FUNC(self->lastMeshDeviation, 3), ObjectModelEntryFlags::none },
- { "PreviousDeviation", OBJECT_MODEL_FUNC(self->previousCalibrationDeviation, 3), ObjectModelEntryFlags::none },
- { "PrintingAcceleration", OBJECT_MODEL_FUNC(self->maxPrintingAcceleration), ObjectModelEntryFlags::none },
- { "TravelAcceleration", OBJECT_MODEL_FUNC(self->maxTravelAcceleration), ObjectModelEntryFlags::none },
- { "SpeedFactor", OBJECT_MODEL_FUNC_NOSELF(reprap.GetGCodes().GetSpeedFactor()), ObjectModelEntryFlags::none },
+ { "axes", OBJECT_MODEL_FUNC_NOSELF(&axesArrayDescriptor), ObjectModelEntryFlags::live },
+ { "calibrationDeviation", OBJECT_MODEL_FUNC(self->lastCalibrationDeviation, 3), ObjectModelEntryFlags::none },
+ { "currentMove", OBJECT_MODEL_FUNC(self, 4), ObjectModelEntryFlags::live },
+ { "daa", OBJECT_MODEL_FUNC(self, 1), ObjectModelEntryFlags::none },
+ { "idle", OBJECT_MODEL_FUNC(self, 2), ObjectModelEntryFlags::none },
+ { "meshDeviation", OBJECT_MODEL_FUNC(self->lastMeshDeviation, 3), ObjectModelEntryFlags::none },
+ { "previousDeviation", OBJECT_MODEL_FUNC(self->previousCalibrationDeviation, 3), ObjectModelEntryFlags::none },
+ { "printingAcceleration", OBJECT_MODEL_FUNC(self->maxPrintingAcceleration), ObjectModelEntryFlags::none },
+ { "travelAcceleration", OBJECT_MODEL_FUNC(self->maxTravelAcceleration), ObjectModelEntryFlags::none },
+ { "speedFactor", OBJECT_MODEL_FUNC_NOSELF(reprap.GetGCodes().GetSpeedFactor()), ObjectModelEntryFlags::live },
// 1. Move.Daa members
- { "Enabled", OBJECT_MODEL_FUNC(self->drcEnabled), ObjectModelEntryFlags::none },
- { "MinimumAcceleration", OBJECT_MODEL_FUNC(self->drcMinimumAcceleration), ObjectModelEntryFlags::none },
- { "Period", OBJECT_MODEL_FUNC(self->drcPeriod), ObjectModelEntryFlags::none },
+ { "enabled", OBJECT_MODEL_FUNC(self->drcEnabled), ObjectModelEntryFlags::none },
+ { "minimumAcceleration", OBJECT_MODEL_FUNC(self->drcMinimumAcceleration), ObjectModelEntryFlags::none },
+ { "period", OBJECT_MODEL_FUNC(self->drcPeriod), ObjectModelEntryFlags::none },
// 2. Move.Idle members
- { "Factor", OBJECT_MODEL_FUNC_NOSELF(reprap.GetPlatform().GetIdleCurrentFactor()), ObjectModelEntryFlags::none },
- { "Timeout", OBJECT_MODEL_FUNC((int32_t)self->idleTimeout), ObjectModelEntryFlags::none },
+ { "factor", OBJECT_MODEL_FUNC_NOSELF(reprap.GetPlatform().GetIdleCurrentFactor()), ObjectModelEntryFlags::none },
+ { "timeout", OBJECT_MODEL_FUNC((int32_t)self->idleTimeout), ObjectModelEntryFlags::none },
// 3. Move.Axis[] members
- { "Homed", OBJECT_MODEL_FUNC_NOSELF(reprap.GetGCodes().IsAxisHomed(context.GetLastIndex())), ObjectModelEntryFlags::none },
- { "Letter", OBJECT_MODEL_FUNC_NOSELF(reprap.GetGCodes().GetAxisLetters()[context.GetLastIndex()]), ObjectModelEntryFlags::none },
- { "Max", OBJECT_MODEL_FUNC_NOSELF(reprap.GetPlatform().AxisMaximum(context.GetLastIndex())), ObjectModelEntryFlags::none },
- { "Min", OBJECT_MODEL_FUNC_NOSELF(reprap.GetPlatform().AxisMinimum(context.GetLastIndex())), ObjectModelEntryFlags::none },
- { "UserPosition", OBJECT_MODEL_FUNC_NOSELF(reprap.GetGCodes().GetUserCoordinate(context.GetLastIndex()), 3), ObjectModelEntryFlags::none },
- { "Visible", OBJECT_MODEL_FUNC_NOSELF(context.GetLastIndex() < (int32_t)reprap.GetGCodes().GetVisibleAxes()), ObjectModelEntryFlags::none },
+ { "homed", OBJECT_MODEL_FUNC_NOSELF(reprap.GetGCodes().IsAxisHomed(context.GetLastIndex())), ObjectModelEntryFlags::live },
+ { "letter", OBJECT_MODEL_FUNC_NOSELF(reprap.GetGCodes().GetAxisLetters()[context.GetLastIndex()]), ObjectModelEntryFlags::none },
+ { "max", OBJECT_MODEL_FUNC_NOSELF(reprap.GetPlatform().AxisMaximum(context.GetLastIndex())), ObjectModelEntryFlags::none },
+ { "min", OBJECT_MODEL_FUNC_NOSELF(reprap.GetPlatform().AxisMinimum(context.GetLastIndex())), ObjectModelEntryFlags::none },
+ { "userPosition", OBJECT_MODEL_FUNC_NOSELF(reprap.GetGCodes().GetUserCoordinate(context.GetLastIndex()), 3), ObjectModelEntryFlags::live },
+ { "visible", OBJECT_MODEL_FUNC_NOSELF(context.GetLastIndex() < (int32_t)reprap.GetGCodes().GetVisibleAxes()), ObjectModelEntryFlags::none },
+
+ // 4. move.currentMove members
+ { "requestedSpeed", OBJECT_MODEL_FUNC(self->GetRequestedSpeed()), ObjectModelEntryFlags::live },
+ { "topSpeed", OBJECT_MODEL_FUNC(self->GetTopSpeed()), ObjectModelEntryFlags::live },
};
-constexpr uint8_t Move::objectModelTableDescriptor[] = { 4, 9, 3, 2, 6 };
+constexpr uint8_t Move::objectModelTableDescriptor[] = { 5, 10, 3, 2, 6, 2 };
DEFINE_GET_OBJECT_MODEL_TABLE(Move)
diff --git a/src/Networking/ESP8266WiFi/WiFiInterface.cpp b/src/Networking/ESP8266WiFi/WiFiInterface.cpp
index 6c2cd6a3..da341686 100644
--- a/src/Networking/ESP8266WiFi/WiFiInterface.cpp
+++ b/src/Networking/ESP8266WiFi/WiFiInterface.cpp
@@ -175,11 +175,11 @@ WiFiInterface::WiFiInterface(Platform& p) noexcept : platform(p), uploader(nullp
constexpr ObjectModelTableEntry WiFiInterface::objectModelTable[] =
{
// These entries must be in alphabetical order
- { "ActualIP", OBJECT_MODEL_FUNC(self->ipAddress), ObjectModelEntryFlags::none },
- { "FirmwareVersion", OBJECT_MODEL_FUNC_NOSELF(nullptr), ObjectModelEntryFlags::none },
- { "Gateway", OBJECT_MODEL_FUNC(self->gateway), ObjectModelEntryFlags::none },
- { "Subnet", OBJECT_MODEL_FUNC(self->netmask), ObjectModelEntryFlags::none },
- { "Type", OBJECT_MODEL_FUNC_NOSELF("wifi"), ObjectModelEntryFlags::none },
+ { "actualIP", OBJECT_MODEL_FUNC(self->ipAddress), ObjectModelEntryFlags::none },
+ { "firmwareVersion", OBJECT_MODEL_FUNC_NOSELF(nullptr), ObjectModelEntryFlags::none },
+ { "gateway", OBJECT_MODEL_FUNC(self->gateway), ObjectModelEntryFlags::none },
+ { "subnet", OBJECT_MODEL_FUNC(self->netmask), ObjectModelEntryFlags::none },
+ { "type", OBJECT_MODEL_FUNC_NOSELF("wifi"), ObjectModelEntryFlags::none },
};
constexpr uint8_t WiFiInterface::objectModelTableDescriptor[] = { 1, 5 };
diff --git a/src/Networking/HttpResponder.cpp b/src/Networking/HttpResponder.cpp
index 8e0b994b..2fe28e34 100644
--- a/src/Networking/HttpResponder.cpp
+++ b/src/Networking/HttpResponder.cpp
@@ -608,6 +608,15 @@ bool HttpResponder::GetJsonResponse(const char* request, OutputBuffer *&response
responderState = ResponderState::gettingFileInfo;
return false;
}
+#if SUPPORT_OBJECT_MODEL
+ else if (StringEqualsIgnoreCase(request, "model"))
+ {
+ OutputBuffer::Release(response);
+ const char *const filterVal = GetKeyValue("key");
+ const char *const flagsVal = GetKeyValue("flags");
+ response = reprap.GetModelResponse(filterVal, flagsVal);
+ }
+#endif
else if (StringEqualsIgnoreCase(request, "config"))
{
OutputBuffer::Release(response);
diff --git a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
index 16ad4a6c..4fa2dd36 100644
--- a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
+++ b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
@@ -111,11 +111,11 @@ LwipEthernetInterface::LwipEthernetInterface(Platform& p) noexcept : platform(p)
constexpr ObjectModelTableEntry LwipEthernetInterface::objectModelTable[] =
{
// These entries must be in alphabetical order
- { "ActualIP", OBJECT_MODEL_FUNC(self->ipAddress), ObjectModelEntryFlags::none },
- { "FirmwareVersion", OBJECT_MODEL_FUNC_NOSELF(nullptr), ObjectModelEntryFlags::none },
- { "Gateway", OBJECT_MODEL_FUNC(self->gateway), ObjectModelEntryFlags::none },
- { "Subnet", OBJECT_MODEL_FUNC(self->netmask), ObjectModelEntryFlags::none },
- { "Type", OBJECT_MODEL_FUNC_NOSELF("ethernet"), ObjectModelEntryFlags::none },
+ { "actualIP", OBJECT_MODEL_FUNC(self->ipAddress), ObjectModelEntryFlags::none },
+ { "firmwareVersion", OBJECT_MODEL_FUNC_NOSELF(nullptr), ObjectModelEntryFlags::none },
+ { "gateway", OBJECT_MODEL_FUNC(self->gateway), ObjectModelEntryFlags::none },
+ { "subnet", OBJECT_MODEL_FUNC(self->netmask), ObjectModelEntryFlags::none },
+ { "type", OBJECT_MODEL_FUNC_NOSELF("ethernet"), ObjectModelEntryFlags::none },
};
constexpr uint8_t LwipEthernetInterface::objectModelTableDescriptor[] = { 1, 5 };
diff --git a/src/Networking/Network.cpp b/src/Networking/Network.cpp
index 441f90ea..69e9465b 100644
--- a/src/Networking/Network.cpp
+++ b/src/Networking/Network.cpp
@@ -86,7 +86,7 @@ static const ObjectModelArrayDescriptor interfaceArrayDescriptor =
constexpr ObjectModelTableEntry Network::objectModelTable[] =
{
// These entries must be in alphabetical order
- { "Interfaces", OBJECT_MODEL_FUNC_NOSELF(&interfaceArrayDescriptor), ObjectModelEntryFlags::none }
+ { "interfaces", OBJECT_MODEL_FUNC_NOSELF(&interfaceArrayDescriptor), ObjectModelEntryFlags::none }
};
constexpr uint8_t Network::objectModelTableDescriptor[] = { 1, 1 };
diff --git a/src/Networking/W5500Ethernet/W5500Interface.cpp b/src/Networking/W5500Ethernet/W5500Interface.cpp
index c3a78cb4..47ec6f95 100644
--- a/src/Networking/W5500Ethernet/W5500Interface.cpp
+++ b/src/Networking/W5500Ethernet/W5500Interface.cpp
@@ -49,11 +49,11 @@ W5500Interface::W5500Interface(Platform& p) noexcept
const ObjectModelTableEntry W5500Interface::objectModelTable[] =
{
// These entries must be in alphabetical order
- { "ActualIP", OBJECT_MODEL_FUNC(self->ipAddress), ObjectModelEntryFlags::none },
- { "FirmwareVersion", OBJECT_MODEL_FUNC_NOSELF(nullptr), ObjectModelEntryFlags::none },
- { "Gateway", OBJECT_MODEL_FUNC(self->gateway), ObjectModelEntryFlags::none },
- { "Subnet", OBJECT_MODEL_FUNC(self->netmask), ObjectModelEntryFlags::none },
- { "Type", OBJECT_MODEL_FUNC_NOSELF("ethernet"), ObjectModelEntryFlags::none },
+ { "actualIP", OBJECT_MODEL_FUNC(self->ipAddress), ObjectModelEntryFlags::none },
+ { "firmwareVersion", OBJECT_MODEL_FUNC_NOSELF(nullptr), ObjectModelEntryFlags::none },
+ { "gateway", OBJECT_MODEL_FUNC(self->gateway), ObjectModelEntryFlags::none },
+ { "subnet", OBJECT_MODEL_FUNC(self->netmask), ObjectModelEntryFlags::none },
+ { "type", OBJECT_MODEL_FUNC_NOSELF("ethernet"), ObjectModelEntryFlags::none },
};
constexpr uint8_t W5500Interface::objectModelTableDescriptor[] = { 1, 5 };
diff --git a/src/ObjectModel/ObjectModel.cpp b/src/ObjectModel/ObjectModel.cpp
index 824e6f4a..e45eb644 100644
--- a/src/ObjectModel/ObjectModel.cpp
+++ b/src/ObjectModel/ObjectModel.cpp
@@ -57,6 +57,33 @@ ObjectModel::ObjectModel() noexcept
{
}
+// ObjectExplorationContext members
+
+ObjectExplorationContext::ObjectExplorationContext(const char *reportFlags, bool wal) noexcept
+ : numIndicesProvided(0), numIndicesCounted(0), shortForm(false), onlyLive(false), includeVerbose(false), wantArrayLength(wal)
+{
+ while (true)
+ {
+ switch(*reportFlags)
+ {
+ case '\0':
+ return;
+ case 'v':
+ includeVerbose = true;
+ break;
+ case 's':
+ shortForm = true;
+ break;
+ case 'f':
+ onlyLive = true;
+ break;
+ default:
+ break;
+ }
+ ++reportFlags;
+ }
+}
+
int32_t ObjectExplorationContext::GetIndex(size_t n) const
{
if (n < numIndicesCounted)
@@ -75,6 +102,12 @@ int32_t ObjectExplorationContext::GetLastIndex() const
THROW_INTERNAL_ERROR;
}
+bool ObjectExplorationContext::ShouldReport(const ObjectModelEntryFlags f) const noexcept
+{
+ return (!onlyLive || ((uint8_t)f & (uint8_t)ObjectModelEntryFlags::live) != 0)
+ && (includeVerbose || ((uint8_t)f & (uint8_t)ObjectModelEntryFlags::verbose) == 0);
+}
+
// Report this object
void ObjectModel::ReportAsJson(OutputBuffer* buf, ObjectExplorationContext& context, uint8_t tableNumber, const char* filter) const
{
@@ -96,7 +129,7 @@ void ObjectModel::ReportAsJson(OutputBuffer* buf, ObjectExplorationContext& cont
{
if (!added)
{
- if (*filter == 0 || context.ReportFullPath())
+ if (*filter == 0)
{
buf->cat('{');
}
@@ -111,7 +144,7 @@ void ObjectModel::ReportAsJson(OutputBuffer* buf, ObjectExplorationContext& cont
--numEntries;
++tbl;
}
- if (added && (*filter == 0 || context.ReportFullPath()))
+ if (added && *filter == 0)
{
buf->cat('}');
}
@@ -123,157 +156,172 @@ void ObjectModel::ReportAsJson(OutputBuffer* buf, ObjectExplorationContext& cont
}
// Construct a JSON representation of those parts of the object model requested by the user. This version is called on the root of the tree.
-void ObjectModel::ReportAsJson(OutputBuffer *buf, const char *filter, ObjectModelReportFlags rf, ObjectModelEntryFlags ff) const
+void ObjectModel::ReportAsJson(OutputBuffer *buf, const char *filter, const char *reportFlags, bool wantArrayLength) const
{
- ObjectExplorationContext context(rf, ff);
+ ObjectExplorationContext context(reportFlags, wantArrayLength);
ReportAsJson(buf, context, 0, filter);
}
// Function to report a value or object as JSON
void ObjectModel::ReportItemAsJson(OutputBuffer *buf, ObjectExplorationContext& context, ExpressionValue val, const char *filter) const
{
- switch (val.type)
+ if (context.WantArrayLength() && *filter == 0)
+ {
+ // We have been asked for the length of an array and we have reached the end of the filter, so the value should be an array
+ if (val.type == TYPE_OF(const ObjectModelArrayDescriptor*))
+ {
+ buf->catf("%u", val.omadVal->GetNumElements(this, context));
+ }
+ else
+ {
+ buf->cat("null");
+ }
+ }
+ else
{
- case TYPE_OF(const ObjectModelArrayDescriptor*):
- if (*filter == '[')
+ switch (val.type)
{
- ++filter;
- if (*filter == ']') // if reporting on [parts of] all elements in the array
+ case TYPE_OF(const ObjectModelArrayDescriptor*):
+ if (*filter == '[')
{
- return ReportArrayAsJson(buf, context, val.omadVal, filter + 1);
- }
+ ++filter;
+ if (*filter == ']') // if reporting on [parts of] all elements in the array
+ {
+ return ReportArrayAsJson(buf, context, val.omadVal, filter + 1);
+ }
- const char *endptr;
- const long index = SafeStrtol(filter, &endptr);
- if (endptr == filter || *endptr != ']' || index < 0 || (size_t)index >= val.omadVal->GetNumElements(this, context))
- {
- buf->cat("null"); // avoid returning badly-formed JSON
- break; // invalid syntax, or index out of range
- }
- if (*filter == 0 || context.ReportFullPath())
- {
- buf->cat('[');
- }
- context.AddIndex(index);
- {
- ReadLocker lock(val.omadVal->lockPointer);
- ReportItemAsJson(buf, context, val.omadVal->GetElement(this, context), endptr + 1);
+ const char *endptr;
+ const long index = SafeStrtol(filter, &endptr);
+ if (endptr == filter || *endptr != ']' || index < 0 || (size_t)index >= val.omadVal->GetNumElements(this, context))
+ {
+ buf->cat("null"); // avoid returning badly-formed JSON
+ break; // invalid syntax, or index out of range
+ }
+ if (*filter == 0)
+ {
+ buf->cat('[');
+ }
+ context.AddIndex(index);
+ {
+ ReadLocker lock(val.omadVal->lockPointer);
+ ReportItemAsJson(buf, context, val.omadVal->GetElement(this, context), endptr + 1);
+ }
+ context.RemoveIndex();
+ if (*filter == 0)
+ {
+ buf->cat(']');
+ }
}
- context.RemoveIndex();
- if (*filter == 0 || context.ReportFullPath())
+ else if (*filter == 0) // else reporting on all subparts of all elements in the array, or just the length
{
- buf->cat(']');
+ ReportArrayAsJson(buf, context, val.omadVal, filter);
}
- }
- else if (*filter == 0) // else reporting on all subparts of all elements in the array
- {
- ReportArrayAsJson(buf, context, val.omadVal, filter);
- }
- break;;
+ break;
- case TYPE_OF(const ObjectModel*):
- if (val.omVal != nullptr)
- {
- if (*filter == '.')
+ case TYPE_OF(const ObjectModel*):
+ if (val.omVal != nullptr)
{
- ++filter;
+ if (*filter == '.')
+ {
+ ++filter;
+ }
+ return val.omVal->ReportAsJson(buf, context, val.param, filter);
}
- return val.omVal->ReportAsJson(buf, context, val.param, filter);
- }
- buf->cat("null");
- break;
+ buf->cat("null");
+ break;
- case TYPE_OF(float):
- buf->catf((val.param == 3) ? "%.3f" : (val.param == 2) ? "%.2f" : "%.1f", (double)val.fVal);
- break;
+ case TYPE_OF(float):
+ buf->catf((val.param == 3) ? "%.3f" : (val.param == 2) ? "%.2f" : "%.1f", (double)val.fVal);
+ break;
- case TYPE_OF(uint32_t):
- buf->catf("%" PRIu32, val.uVal);
- break;
+ case TYPE_OF(uint32_t):
+ buf->catf("%" PRIu32, val.uVal);
+ break;
- case TYPE_OF(int32_t):
- buf->catf("%" PRIi32, val.iVal);
- break;
+ case TYPE_OF(int32_t):
+ buf->catf("%" PRIi32, val.iVal);
+ break;
- case TYPE_OF(const char*):
- buf->EncodeString(val.sVal, true);
- break;
+ case TYPE_OF(const char*):
+ buf->EncodeString(val.sVal, true);
+ break;
- case TYPE_OF(Bitmap32):
- if (context.ShortFormReport())
- {
- buf->catf("%" PRIu32, val.uVal);
- }
- else
- {
- uint32_t v = val.uVal;
- buf->cat('[');
- buf->cat((v & 1) ? '1' : '0');
- for (unsigned int i = 1; i < 32; ++i)
+ case TYPE_OF(Bitmap32):
+ if (context.ShortFormReport())
+ {
+ buf->catf("%" PRIu32, val.uVal);
+ }
+ else
{
- v >>= 1;
- buf->cat(',');
+ uint32_t v = val.uVal;
+ buf->cat('[');
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(']');
}
- buf->cat(']');
- }
- break;
-
- case TYPE_OF(Enum32):
- if (context.ShortFormReport())
- {
- buf->catf("%" PRIu32, val.uVal);
- }
- else
- {
- buf->cat("\"unimplemented\"");
- // TODO append the real name
- }
- break;
-
- case TYPE_OF(bool):
- buf->cat((val.bVal) ? "true" : "false");
- break;
-
- case TYPE_OF(char):
- buf->cat('"');
- buf->EncodeChar(val.cVal);
- buf->cat('"');
- break;
+ break;
- case TYPE_OF(IPAddress):
- {
- const IPAddress ipVal(val.uVal);
- char sep = '"';
- for (unsigned int q = 0; q < 4; ++q)
+ case TYPE_OF(Enum32):
+ if (context.ShortFormReport())
+ {
+ buf->catf("%" PRIu32, val.uVal);
+ }
+ else
{
- buf->catf("%c%u", sep, ipVal.GetQuad(q));
- sep = '.';
+ buf->cat("\"unimplemented\"");
+ // TODO append the real name
}
+ break;
+
+ case TYPE_OF(bool):
+ buf->cat((val.bVal) ? "true" : "false");
+ break;
+
+ case TYPE_OF(char):
buf->cat('"');
- }
- break;
+ buf->EncodeChar(val.cVal);
+ buf->cat('"');
+ break;
- case TYPE_OF(DateTime):
- {
- const time_t time = val.Get40BitValue();
- if (time == 0)
+ case TYPE_OF(IPAddress):
{
- buf->cat("null");
+ const IPAddress ipVal(val.uVal);
+ char sep = '"';
+ for (unsigned int q = 0; q < 4; ++q)
+ {
+ buf->catf("%c%u", sep, ipVal.GetQuad(q));
+ sep = '.';
+ }
+ buf->cat('"');
}
- else
+ break;
+
+ case TYPE_OF(DateTime):
{
- tm timeInfo;
- gmtime_r(&time, &timeInfo);
- buf->catf("\"%04u-%02u-%02uT%02u:%02u:%02u\"",
- timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday, timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec);
+ const time_t time = val.Get40BitValue();
+ if (time == 0)
+ {
+ buf->cat("null");
+ }
+ else
+ {
+ tm timeInfo;
+ gmtime_r(&time, &timeInfo);
+ buf->catf("\"%04u-%02u-%02uT%02u:%02u:%02u\"",
+ timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday, timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec);
+ }
}
- }
- break;
+ break;
- case NoType:
- buf->cat("null");
- break;
+ case NoType:
+ buf->cat("null");
+ break;
+ }
}
}
@@ -346,13 +394,13 @@ const ObjectModelTableEntry* ObjectModel::FindObjectModelTableEntry(uint8_t tabl
bool ObjectModelTableEntry::Matches(const char* filterString, const ObjectExplorationContext& context) const noexcept
{
- return IdCompare(filterString) == 0 && ((uint8_t)flags & (uint8_t)context.GetFilterFlags()) == (uint8_t)context.GetFilterFlags();
+ return IdCompare(filterString) == 0 && context.ShouldReport(flags);
}
// Add the value of this element to the buffer, returning true if it matched and we did
void ObjectModelTableEntry::ReportAsJson(OutputBuffer* buf, ObjectExplorationContext& context, const ObjectModel *self, const char* filter) const noexcept
{
- if (*filter == 0 || context.ReportFullPath())
+ if (*filter == 0)
{
buf->cat('"');
buf->cat(name);
@@ -403,6 +451,11 @@ ExpressionValue ObjectModel::GetObjectValue(const StringParser& sp, ObjectExplor
{
if (val.type == TYPE_OF(const ObjectModelArrayDescriptor*))
{
+ if (*idString == 0 && context.WantArrayLength())
+ {
+ ReadLocker lock(val.omadVal->lockPointer);
+ return ExpressionValue((int32_t)val.omadVal->GetNumElements(this, context));
+ }
if (*idString != '^')
{
throw sp.ConstructParseException("missing array index");
diff --git a/src/ObjectModel/ObjectModel.h b/src/ObjectModel/ObjectModel.h
index cb671e14..9700c9a3 100644
--- a/src/ObjectModel/ObjectModel.h
+++ b/src/ObjectModel/ObjectModel.h
@@ -106,27 +106,24 @@ struct ExpressionValue
uint64_t Get40BitValue() const noexcept { return ((uint64_t)param << 32) | uVal; }
};
-enum class ObjectModelReportFlags : uint16_t
-{
- none = 0,
- shortForm = 1,
- fullPath = 2
-};
-
// Flags field of a table entry
enum class ObjectModelEntryFlags : uint8_t
{
+ // none, live and verbose are alternatives occupying the bottom 2 bits
none = 0, // nothing special
live = 1, // fast changing data, included in common status response
- canAlter = 2, // we can alter this value
+ verbose = 2, // omit reporting this value by default
+
+ // canAlter can be or'ed in
+ canAlter = 4, // we can alter this value
+ liveCanAlter = 5, // we can alter this value
};
// Context passed to object model functions
class ObjectExplorationContext
{
public:
- ObjectExplorationContext(ObjectModelReportFlags rf, ObjectModelEntryFlags ff) noexcept
- : numIndicesProvided(0), numIndicesCounted(0), reportFlags(rf), filterFlags(ff) { }
+ ObjectExplorationContext(const char *reportFlags, bool wal) noexcept;
void AddIndex(int32_t index) THROWS_GCODE_EXCEPTION;
void AddIndex() THROWS_GCODE_EXCEPTION;
@@ -135,10 +132,9 @@ public:
int32_t GetIndex(size_t n) const THROWS_GCODE_EXCEPTION;
int32_t GetLastIndex() const THROWS_GCODE_EXCEPTION;
size_t GetNumIndicesCounted() const noexcept { return numIndicesCounted; }
- ObjectModelReportFlags GetReportFlags() const noexcept { return reportFlags; }
- ObjectModelEntryFlags GetFilterFlags() const noexcept { return filterFlags; }
- bool ShortFormReport() const noexcept { return ((uint16_t)reportFlags & (uint16_t)ObjectModelReportFlags::shortForm) != 0; }
- bool ReportFullPath() const noexcept { return ((uint16_t)reportFlags & (uint16_t)ObjectModelReportFlags::fullPath) != 0; }
+ bool ShortFormReport() const noexcept { return shortForm; }
+ bool ShouldReport(const ObjectModelEntryFlags f) const noexcept;
+ bool WantArrayLength() const noexcept { return wantArrayLength; }
private:
static constexpr size_t MaxIndices = 4; // max depth of array nesting
@@ -146,8 +142,10 @@ private:
size_t numIndicesProvided; // the number of indices provided, when we are doing a value lookup
size_t numIndicesCounted; // the number of indices passed in the search string
int32_t indices[MaxIndices];
- ObjectModelReportFlags reportFlags;
- ObjectModelEntryFlags filterFlags;
+ bool shortForm;
+ bool onlyLive;
+ bool includeVerbose;
+ bool wantArrayLength;
};
// Entry to describe an array of objects or values. These must be brace-initializable into flash memory.
@@ -166,7 +164,7 @@ public:
ObjectModel() noexcept;
// Construct a JSON representation of those parts of the object model requested by the user. This version is called on the root of the tree.
- void ReportAsJson(OutputBuffer *buf, const char *filter, ObjectModelReportFlags rf, ObjectModelEntryFlags ff) const THROWS_GCODE_EXCEPTION;
+ void ReportAsJson(OutputBuffer *buf, const char *filter, const char *reportFlags, bool wantArrayLength) const THROWS_GCODE_EXCEPTION;
// Get the value of an object via the table
ExpressionValue GetObjectValue(const StringParser& sp, ObjectExplorationContext& context, const char *idString, uint8_t tableNumber = 0) const THROWS_GCODE_EXCEPTION;
diff --git a/src/Pccb/Pins_Pccb.h b/src/Pccb/Pins_Pccb.h
index 5afe4a1d..4c9f32e2 100644
--- a/src/Pccb/Pins_Pccb.h
+++ b/src/Pccb/Pins_Pccb.h
@@ -69,8 +69,6 @@ constexpr uint32_t IAP_IMAGE_END = 0x0047FFFF; // we allow a full 64K on the SA
#define SUPPORT_DOTSTAR_LED 1 // set nonzero to support DotStar LED strips
#define ALLOCATE_DEFAULT_PORTS 1
-#define NO_EXTRUDER_ENDSTOPS 1 // Temporary!!!
-
// The physical capabilities of the machine
#if defined(PCCB_10)
@@ -343,6 +341,8 @@ constexpr unsigned int NumNamedPins = ARRAY_SIZE(PinTable);
// 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) noexcept;
+#if ALLOCATE_DEFAULT_PORTS
+
// Default pin allocations
constexpr const char *DefaultEndstopPinNames[] = { "stop1", "nil", "stop0" }; // stop0 is the default Z endstop, stop1 is the X endstop
constexpr const char *DefaultZProbePinNames = "nil";
@@ -357,6 +357,8 @@ constexpr const char *DefaultFanPinNames[] = { "fan0", "fan1", "fan2", "!fan3+fa
constexpr PwmFrequency DefaultFanPwmFrequencies[] = { DefaultFanPwmFreq, DefaultFanPwmFreq, DefaultFanPwmFreq, 25000 };
#endif
+#endif
+
// Timer allocation
// TC0 channel 0 is used for step pulse generation and software timers (lower 16 bits)
// TC0 channel 1 is currently unused
diff --git a/src/Platform.cpp b/src/Platform.cpp
index 58ff4f83..a3e24381 100644
--- a/src/Platform.cpp
+++ b/src/Platform.cpp
@@ -196,29 +196,55 @@ DriversBitmap AxisDriversConfig::GetDriversBitmap() const noexcept
constexpr ObjectModelTableEntry Platform::objectModelTable[] =
{
- // Table entries for object Boards[]
- { "FirmwareFileName", OBJECT_MODEL_FUNC_NOSELF(IAP_FIRMWARE_FILE), ObjectModelEntryFlags::none },
+ // 0. boards[] members
+ { "firmwareFileName", OBJECT_MODEL_FUNC_NOSELF(IAP_FIRMWARE_FILE), ObjectModelEntryFlags::none },
#if HAS_LINUX_INTERFACE
- { "IAPFileNameSBC", OBJECT_MODEL_FUNC_NOSELF(IAP_UPDATE_FILE_SBC), ObjectModelEntryFlags::none },
+ { "iapFileNameSBC", OBJECT_MODEL_FUNC_NOSELF(IAP_UPDATE_FILE_SBC), ObjectModelEntryFlags::none },
#endif
- { "IAPFileNameSD", OBJECT_MODEL_FUNC_NOSELF(IAP_UPDATE_FILE), ObjectModelEntryFlags::none },
- { "MaxHeaters", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxHeaters), ObjectModelEntryFlags::none },
- { "MaxMotors", OBJECT_MODEL_FUNC_NOSELF((int32_t)NumDirectDrivers), ObjectModelEntryFlags::none },
+ { "iapFileNameSD", OBJECT_MODEL_FUNC_NOSELF(IAP_UPDATE_FILE), ObjectModelEntryFlags::none },
+ { "maxHeaters", OBJECT_MODEL_FUNC_NOSELF((int32_t)MaxHeaters), ObjectModelEntryFlags::verbose },
+ { "maxMotors", OBJECT_MODEL_FUNC_NOSELF((int32_t)NumDirectDrivers), ObjectModelEntryFlags::verbose },
+ { "mcuTemp", OBJECT_MODEL_FUNC(self, 1), ObjectModelEntryFlags::live },
# ifdef DUET_NG
- { "Name", OBJECT_MODEL_FUNC(self->GetBoardName()), ObjectModelEntryFlags::none },
- { "ShortName", OBJECT_MODEL_FUNC(self->GetBoardShortName()), ObjectModelEntryFlags::none },
+ { "name", OBJECT_MODEL_FUNC(self->GetBoardName()), ObjectModelEntryFlags::none },
+ { "shortName", OBJECT_MODEL_FUNC(self->GetBoardShortName()), ObjectModelEntryFlags::none },
# else
- { "Name", OBJECT_MODEL_FUNC_NOSELF(BOARD_NAME), ObjectModelEntryFlags::none },
- { "ShortName", OBJECT_MODEL_FUNC_NOSELF(BOARD_SHORT_NAME), ObjectModelEntryFlags::none },
+ { "name", OBJECT_MODEL_FUNC_NOSELF(BOARD_NAME), ObjectModelEntryFlags::none },
+ { "shortName", OBJECT_MODEL_FUNC_NOSELF(BOARD_SHORT_NAME), ObjectModelEntryFlags::none },
# endif
+#if HAS_12V_MONITOR
+ { "v12", OBJECT_MODEL_FUNC(self, 3), ObjectModelEntryFlags::live },
+#endif
+ { "vIn", OBJECT_MODEL_FUNC(self, 2), ObjectModelEntryFlags::live },
+
+ // 1. mcuTemp members
+ { "current", OBJECT_MODEL_FUNC(self->GetMcuTemperatures().current), ObjectModelEntryFlags::live },
+ { "max", OBJECT_MODEL_FUNC(self->GetMcuTemperatures().max), ObjectModelEntryFlags::none },
+ { "min", OBJECT_MODEL_FUNC(self->GetMcuTemperatures().min), ObjectModelEntryFlags::none },
+
+ // 2. vIn members
+ { "current", OBJECT_MODEL_FUNC(self->GetCurrentPowerVoltage()), ObjectModelEntryFlags::live },
+ { "max", OBJECT_MODEL_FUNC(self->GetPowerVoltages().max), ObjectModelEntryFlags::none },
+ { "min", OBJECT_MODEL_FUNC(self->GetPowerVoltages().min), ObjectModelEntryFlags::none },
+
+#if HAS_12V_MONITOR
+ // 3. v12 members
+ { "current", OBJECT_MODEL_FUNC(self->GetV12Voltages().current), ObjectModelEntryFlags::live },
+ { "max", OBJECT_MODEL_FUNC(self->GetV12Voltages().max), ObjectModelEntryFlags::none },
+ { "min", OBJECT_MODEL_FUNC(self->GetV12Voltages().min), ObjectModelEntryFlags::none },
+#endif
};
constexpr uint8_t Platform::objectModelTableDescriptor[] =
-#if HAS_LINUX_INTERFACE
- { 1, 7 };
-#else
- { 1, 6 };
+{
+ 3 + HAS_12V_MONITOR,
+ 8 + HAS_LINUX_INTERFACE + HAS_12V_MONITOR,
+ 3,
+ 3,
+#if HAS_12V_MONITOR
+ 3
#endif
+};
DEFINE_GET_OBJECT_MODEL_TABLE(Platform)
@@ -3804,23 +3830,29 @@ bool Platform::Inkjet(int bitPattern) noexcept
#endif
#if HAS_CPU_TEMP_SENSOR
+
// CPU temperature
-void Platform::GetMcuTemperatures(float& minT, float& currT, float& maxT) const noexcept
+MinMaxCurrent Platform::GetMcuTemperatures() const noexcept
{
- minT = AdcReadingToCpuTemperature(lowestMcuTemperature);
- currT = AdcReadingToCpuTemperature(adcFilters[CpuTempFilterIndex].GetSum());
- maxT = AdcReadingToCpuTemperature(highestMcuTemperature);
+ MinMaxCurrent result;
+ result.min = AdcReadingToCpuTemperature(lowestMcuTemperature);
+ result.current = AdcReadingToCpuTemperature(adcFilters[CpuTempFilterIndex].GetSum());
+ result.max = AdcReadingToCpuTemperature(highestMcuTemperature);
+ return result;
}
+
#endif
#if HAS_VOLTAGE_MONITOR
// Power in voltage
-void Platform::GetPowerVoltages(float& minV, float& currV, float& maxV) const noexcept
+MinMaxCurrent Platform::GetPowerVoltages() const noexcept
{
- minV = AdcReadingToPowerVoltage(lowestVin);
- currV = AdcReadingToPowerVoltage(currentVin);
- maxV = AdcReadingToPowerVoltage(highestVin);
+ MinMaxCurrent result;
+ result.min = AdcReadingToPowerVoltage(lowestVin);
+ result.current = AdcReadingToPowerVoltage(currentVin);
+ result.max = AdcReadingToPowerVoltage(highestVin);
+ return result;
}
float Platform::GetCurrentPowerVoltage() const noexcept
@@ -3832,11 +3864,13 @@ float Platform::GetCurrentPowerVoltage() const noexcept
#if HAS_12V_MONITOR
-void Platform::GetV12Voltages(float& minV, float& currV, float& maxV) const noexcept
+MinMaxCurrent Platform::GetV12Voltages() const noexcept
{
- minV = AdcReadingToPowerVoltage(lowestV12);
- currV = AdcReadingToPowerVoltage(currentV12);
- maxV = AdcReadingToPowerVoltage(highestV12);
+ MinMaxCurrent result;
+ result.min = AdcReadingToPowerVoltage(lowestV12);
+ result.current = AdcReadingToPowerVoltage(currentV12);
+ result.max = AdcReadingToPowerVoltage(highestV12);
+ return result;
}
#endif
diff --git a/src/Platform.h b/src/Platform.h
index 0c7c086a..47ba31d3 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -489,14 +489,14 @@ public:
// MCU temperature
#if HAS_CPU_TEMP_SENSOR
- void GetMcuTemperatures(float& minT, float& currT, float& maxT) const noexcept;
+ MinMaxCurrent GetMcuTemperatures() const noexcept;
void SetMcuTemperatureAdjust(float v) noexcept { mcuTemperatureAdjust = v; }
float GetMcuTemperatureAdjust() const noexcept { return mcuTemperatureAdjust; }
#endif
#if HAS_VOLTAGE_MONITOR
// Power in voltage
- void GetPowerVoltages(float& minV, float& currV, float& maxV) const noexcept;
+ MinMaxCurrent GetPowerVoltages() const noexcept;
float GetCurrentPowerVoltage() const noexcept;
bool IsPowerOk() const noexcept;
void DisableAutoSave() noexcept;
@@ -506,7 +506,7 @@ public:
#if HAS_12V_MONITOR
// 12V rail voltage
- void GetV12Voltages(float& minV, float& currV, float& maxV) const noexcept;
+ MinMaxCurrent GetV12Voltages() const noexcept;
#endif
#if HAS_SMART_DRIVERS
diff --git a/src/PrintMonitor.cpp b/src/PrintMonitor.cpp
index 8d7deead..381f8244 100644
--- a/src/PrintMonitor.cpp
+++ b/src/PrintMonitor.cpp
@@ -47,27 +47,27 @@ constexpr ObjectModelTableEntry PrintMonitor::objectModelTable[] =
{
// Within each group, these entries must be in alphabetical order
// 0. PrintMonitor members
- { "File", OBJECT_MODEL_FUNC(self, 1), ObjectModelEntryFlags::none },
- { "LastFileName", OBJECT_MODEL_FUNC(self->filenameBeingPrinted.c_str()), ObjectModelEntryFlags::none },
- { "Layer", OBJECT_MODEL_FUNC((int32_t)self->currentLayer), ObjectModelEntryFlags::none },
- { "TimesLeft", OBJECT_MODEL_FUNC(self, 2), ObjectModelEntryFlags::none },
+ { "file", OBJECT_MODEL_FUNC(self, 1), ObjectModelEntryFlags::none },
+ { "lastFileName", OBJECT_MODEL_FUNC(self->filenameBeingPrinted.c_str()), ObjectModelEntryFlags::none },
+ { "layer", OBJECT_MODEL_FUNC((int32_t)self->currentLayer), ObjectModelEntryFlags::none },
+ { "timesLeft", OBJECT_MODEL_FUNC(self, 2), ObjectModelEntryFlags::none },
// 1. ParsedFileInfo members
- { "Filament", OBJECT_MODEL_FUNC_NOSELF(&filamentArrayDescriptor), ObjectModelEntryFlags::none },
- { "FirstLayerHeight", OBJECT_MODEL_FUNC(self->printingFileInfo.firstLayerHeight), ObjectModelEntryFlags::none },
- { "GeneratedBy", OBJECT_MODEL_FUNC(self->printingFileInfo.generatedBy.c_str()), ObjectModelEntryFlags::none },
- { "Height", OBJECT_MODEL_FUNC(self->printingFileInfo.objectHeight), ObjectModelEntryFlags::none },
- { "LastModified", OBJECT_MODEL_FUNC(DateTime(self->printingFileInfo.lastModifiedTime)), ObjectModelEntryFlags::none },
- { "LayerHeight", OBJECT_MODEL_FUNC(self->printingFileInfo.layerHeight), ObjectModelEntryFlags::none },
- { "NumLayers", OBJECT_MODEL_FUNC((int32_t)self->printingFileInfo.GetNumLayers()), ObjectModelEntryFlags::none },
- { "PrintTime", OBJECT_MODEL_FUNC((int32_t)self->printingFileInfo.printTime), ObjectModelEntryFlags::none },
- { "SimulatedTime", OBJECT_MODEL_FUNC((int32_t)self->printingFileInfo.simulatedTime), ObjectModelEntryFlags::none },
- { "Size", OBJECT_MODEL_FUNC((int32_t)self->printingFileInfo.fileSize), ObjectModelEntryFlags::none }, // note, using int32_t limits us to 2Gb
+ { "filament", OBJECT_MODEL_FUNC_NOSELF(&filamentArrayDescriptor), ObjectModelEntryFlags::none },
+ { "firstLayerHeight", OBJECT_MODEL_FUNC(self->printingFileInfo.firstLayerHeight), ObjectModelEntryFlags::none },
+ { "generatedBy", OBJECT_MODEL_FUNC(self->printingFileInfo.generatedBy.c_str()), ObjectModelEntryFlags::none },
+ { "height", OBJECT_MODEL_FUNC(self->printingFileInfo.objectHeight), ObjectModelEntryFlags::none },
+ { "lastModified", OBJECT_MODEL_FUNC(DateTime(self->printingFileInfo.lastModifiedTime)), ObjectModelEntryFlags::none },
+ { "layerHeight", OBJECT_MODEL_FUNC(self->printingFileInfo.layerHeight), ObjectModelEntryFlags::none },
+ { "numLayers", OBJECT_MODEL_FUNC((int32_t)self->printingFileInfo.GetNumLayers()), ObjectModelEntryFlags::none },
+ { "printTime", OBJECT_MODEL_FUNC((int32_t)self->printingFileInfo.printTime), ObjectModelEntryFlags::none },
+ { "simulatedTime", OBJECT_MODEL_FUNC((int32_t)self->printingFileInfo.simulatedTime), ObjectModelEntryFlags::none },
+ { "size", OBJECT_MODEL_FUNC((int32_t)self->printingFileInfo.fileSize), ObjectModelEntryFlags::none }, // note, using int32_t limits us to 2Gb
// 2. TimesLeft members
- { "Filament", OBJECT_MODEL_FUNC(self->EstimateTimeLeft(filamentBased)), ObjectModelEntryFlags::none },
- { "File", OBJECT_MODEL_FUNC(self->EstimateTimeLeft(fileBased)), ObjectModelEntryFlags::none },
- { "Layer", OBJECT_MODEL_FUNC(self->EstimateTimeLeft(layerBased)), ObjectModelEntryFlags::none },
+ { "filament", OBJECT_MODEL_FUNC(self->EstimateTimeLeft(filamentBased)), ObjectModelEntryFlags::none },
+ { "file", OBJECT_MODEL_FUNC(self->EstimateTimeLeft(fileBased)), ObjectModelEntryFlags::none },
+ { "layer", OBJECT_MODEL_FUNC(self->EstimateTimeLeft(layerBased)), ObjectModelEntryFlags::none },
};
constexpr uint8_t PrintMonitor::objectModelTableDescriptor[] = { 3, 4, 10, 3 };
diff --git a/src/RepRap.cpp b/src/RepRap.cpp
index d40e9561..bbe4b539 100644
--- a/src/RepRap.cpp
+++ b/src/RepRap.cpp
@@ -136,17 +136,17 @@ constexpr ObjectModelTableEntry RepRap::objectModelTable[] =
{
// Within each group, these entries must be in alphabetical order
// 0. MachineModel root
- { "Boards", OBJECT_MODEL_FUNC_NOSELF(&boardsArrayDescriptor), ObjectModelEntryFlags::none },
- { "Heat", OBJECT_MODEL_FUNC(self->heat), ObjectModelEntryFlags::none },
- { "Job", OBJECT_MODEL_FUNC(self->printMonitor), ObjectModelEntryFlags::none },
- { "Move", OBJECT_MODEL_FUNC(self->move), ObjectModelEntryFlags::none },
- { "Network", OBJECT_MODEL_FUNC(self->network), ObjectModelEntryFlags::none },
- { "State", OBJECT_MODEL_FUNC(self, 1), ObjectModelEntryFlags::none },
+ { "boards", OBJECT_MODEL_FUNC_NOSELF(&boardsArrayDescriptor), ObjectModelEntryFlags::live },
+ { "heat", OBJECT_MODEL_FUNC(self->heat), ObjectModelEntryFlags::live },
+ { "job", OBJECT_MODEL_FUNC(self->printMonitor), ObjectModelEntryFlags::live },
+ { "move", OBJECT_MODEL_FUNC(self->move), ObjectModelEntryFlags::live },
+ { "network", OBJECT_MODEL_FUNC(self->network), ObjectModelEntryFlags::none },
+ { "state", OBJECT_MODEL_FUNC(self, 1), ObjectModelEntryFlags::live },
// 1. MachineModel.State
- { "CurrentTool", OBJECT_MODEL_FUNC((int32_t)self->GetCurrentToolNumber()), ObjectModelEntryFlags::none },
- { "MachineMode", OBJECT_MODEL_FUNC(self->gCodes->GetMachineModeString()), ObjectModelEntryFlags::none },
- { "Status", OBJECT_MODEL_FUNC(self->GetStatusString()), ObjectModelEntryFlags::none },
+ { "currentTool", OBJECT_MODEL_FUNC((int32_t)self->GetCurrentToolNumber()), ObjectModelEntryFlags::live },
+ { "machineMode", OBJECT_MODEL_FUNC(self->gCodes->GetMachineModeString()), ObjectModelEntryFlags::none },
+ { "status", OBJECT_MODEL_FUNC(self->GetStatusString()), ObjectModelEntryFlags::live },
};
constexpr uint8_t RepRap::objectModelTableDescriptor[] = { 2, 6, 3 };
@@ -1521,27 +1521,24 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
// MCU temperatures
#if HAS_CPU_TEMP_SENSOR
{
- float minT, currT, maxT;
- platform->GetMcuTemperatures(minT, currT, maxT);
- response->catf(",\"mcutemp\":{\"min\":%.1f,\"cur\":%.1f,\"max\":%.1f}", (double)minT, (double)currT, (double)maxT);
+ const MinMaxCurrent temps = platform->GetMcuTemperatures();
+ response->catf(",\"mcutemp\":{\"min\":%.1f,\"cur\":%.1f,\"max\":%.1f}", (double)temps.min, (double)temps.current, (double)temps.max);
}
#endif
#if HAS_VOLTAGE_MONITOR
// Power in voltages
{
- float minV, currV, maxV;
- platform->GetPowerVoltages(minV, currV, maxV);
- response->catf(",\"vin\":{\"min\":%.1f,\"cur\":%.1f,\"max\":%.1f}", (double)minV, (double)currV, (double)maxV);
+ const MinMaxCurrent voltages = platform->GetPowerVoltages();
+ response->catf(",\"vin\":{\"min\":%.1f,\"cur\":%.1f,\"max\":%.1f}", (double)voltages.min, (double)voltages.current, (double)voltages.max);
}
#endif
#if HAS_12V_MONITOR
// Power in voltages
{
- float minV, currV, maxV;
- platform->GetV12Voltages(minV, currV, maxV);
- response->catf(",\"v12\":{\"min\":%.1f,\"cur\":%.1f,\"max\":%.1f}", (double)minV, (double)currV, (double)maxV);
+ const MinMaxCurrent voltages = platform->GetV12Voltages();
+ response->catf(",\"v12\":{\"min\":%.1f,\"cur\":%.1f,\"max\":%.1f}", (double)voltages.min, (double)voltages.current, (double)voltages.max);
}
#endif
}
@@ -2220,6 +2217,38 @@ bool RepRap::GetFileInfoResponse(const char *filename, OutputBuffer *&response,
return true;
}
+#if SUPPORT_OBJECT_MODEL
+
+// Return a query into the object model, or return nullptr if no buffer available
+OutputBuffer *RepRap::GetModelResponse(const char *key, const char *flags)
+{
+ OutputBuffer *outBuf;
+ if (OutputBuffer::Allocate(outBuf))
+ {
+ if (key == nullptr) { key = ""; }
+ if (flags == nullptr) { flags = ""; }
+
+ outBuf->printf("{\"key\":");
+ outBuf->EncodeString(key, false);
+ outBuf->catf("{\"flags\":");
+ outBuf->EncodeString(flags, false);
+
+ const bool wantArrayLength = (*key == '#');
+ if (wantArrayLength)
+ {
+ ++key;
+ }
+
+ outBuf->cat(",\"result\":");
+ reprap.ReportAsJson(outBuf, key, flags, wantArrayLength);
+ outBuf->cat('}');
+ }
+
+ return outBuf;
+}
+
+#endif
+
// Send a beep. We send it to both PanelDue and the web interface.
void RepRap::Beep(unsigned int freq, unsigned int ms) noexcept
{
diff --git a/src/RepRap.h b/src/RepRap.h
index 1eabfb45..fc699f9e 100644
--- a/src/RepRap.h
+++ b/src/RepRap.h
@@ -137,6 +137,10 @@ public:
bool GetFileInfoResponse(const char *filename, OutputBuffer *&response, bool quitEarly) noexcept;
+#if SUPPORT_OBJECT_MODEL
+ OutputBuffer *GetModelResponse(const char *key, const char *flags);
+#endif
+
void Beep(unsigned int freq, unsigned int ms) noexcept;
void SetMessage(const char *msg) noexcept;
void SetAlert(const char *msg, const char *title, int mode, float timeout, AxesBitmap controls) noexcept;
diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h
index eda1cc0f..7682fda5 100644
--- a/src/RepRapFirmware.h
+++ b/src/RepRapFirmware.h
@@ -104,6 +104,14 @@ static_assert(NumNamedPins <= 255 || sizeof(LogicalPin) > 1, "Need 16-bit logica
#define THROWS_GCODE_EXCEPTION // we tag this on to function declarations to indicate that they may throw a GCodeException, which must be caught
#define THROW_INTERNAL_ERROR throw GCodeException(-1, -1, "internal error at file " __FILE__ "(%d)", (int32_t)__LINE__)
+// Struct to hold min, max and current values
+struct MinMaxCurrent
+{
+ float min;
+ float max;
+ float current;
+};
+
// Type of a driver identifier
struct DriverId
{
diff --git a/src/Version.h b/src/Version.h
index 0e8c0874..4043f9dc 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -20,7 +20,7 @@
#endif
#ifndef DATE
-# define DATE "2020-01-12b3"
+# define DATE "2020-01-13b1"
#endif
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman, printm3d"