diff options
author | David Crocker <dcrocker@eschertech.com> | 2020-01-13 15:15:19 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2020-01-13 15:15:19 +0300 |
commit | 36a72fd1cbc274a6f932294f184133e08d681858 (patch) | |
tree | b6a8c1dd2f05d3f54710de9e20960c3a16932e5b | |
parent | 13084f6566c536df08430cce6c584f5e5c06b5a8 (diff) |
More work on object model
Changed all object model names to use camelCase
Added # operator to return the number of elements in an array or the
length of a string
Replaced M408 P1 by M409 and added flags parameter
Added rr_model to do the same as M409 directly via http
Removed default fan and Z probe assignments in Duet 2 builds
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" |