diff options
-rw-r--r-- | src/GCodes/GCodes2.cpp | 2 | ||||
-rw-r--r-- | src/Heating/Heat.cpp | 61 | ||||
-rw-r--r-- | src/Heating/Heat.h | 8 | ||||
-rw-r--r-- | src/Heating/Heater.cpp | 30 | ||||
-rw-r--r-- | src/Heating/Heater.h | 8 | ||||
-rw-r--r-- | src/Heating/Sensors/TemperatureSensor.cpp | 24 | ||||
-rw-r--r-- | src/Heating/Sensors/TemperatureSensor.h | 5 | ||||
-rw-r--r-- | src/Movement/Move.cpp | 1 | ||||
-rw-r--r-- | src/Networking/Network.cpp | 1 | ||||
-rw-r--r-- | src/ObjectModel/ObjectModel.cpp | 35 | ||||
-rw-r--r-- | src/ObjectModel/ObjectModel.h | 6 | ||||
-rw-r--r-- | src/RepRap.cpp | 8 | ||||
-rw-r--r-- | src/Version.h | 2 |
13 files changed, 157 insertions, 34 deletions
diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index 7b8623ba..df1ec9df 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -115,6 +115,7 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) const int code = gb.GetCommandNumber(); if (simulationMode != 0 && code > 4 && code != 10 && code != 11 && code != 20 && code != 21 && (code < 53 || code > 59) && (code < 90 || code > 92)) { + HandleReply(gb, GCodeResult::ok, ""); return true; // we only simulate some gcodes } @@ -404,6 +405,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) && code != 0 && code != 1 && code != 82 && code != 83 && code != 105 && code != 109 && code != 111 && code != 112 && code != 122 && code != 200 && code != 204 && code != 207 && code != 408 && code != 999) { + HandleReply(gb, GCodeResult::ok, ""); return true; // we don't simulate most M codes } diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp index 8a25d832..cc214ae2 100644 --- a/src/Heating/Heat.cpp +++ b/src/Heating/Heat.cpp @@ -60,13 +60,19 @@ extern "C" [[noreturn]] void SensorsTaskStart(void * pvParameters) noexcept // Note: if using GCC version 7.3.1 20180622 and lambda functions are used in this table, you must compile this file with option -std=gnu++17. // Otherwise the table will be allocated in RAM instead of flash, which wastes too much RAM. -#if 0 // need to extend object model functions to handle read-locked pointers before we can use this -static const ObjectModelArrayDescriptor heatersArrayDescriptor = +const ObjectModelArrayDescriptor Heat::heatersArrayDescriptor = { - [] (ObjectModel *self) -> size_t { return MaxHeaters; }, - [] (ObjectModel *self, size_t n) -> void* { return (void *)(((Heat*)self)->FindHeater(n)); } + &heatersLock, + [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return ((const Heat*)self)->GetNumHeatersToReport(); }, + [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(((const Heat*)self)->heaters[context.GetIndex(0)]); } +}; + +const ObjectModelArrayDescriptor Heat::sensorsArrayDescriptor = +{ + &sensorsLock, + [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return ((const Heat*)self)->GetNumSensorsToReport(); }, + [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(((const Heat*)self)->FindSensor(context.GetIndex(0)).Ptr()); } }; -#endif // Macro to build a standard lambda function that includes the necessary type conversions #define OBJECT_MODEL_FUNC(...) OBJECT_MODEL_FUNC_BODY(Heat, __VA_ARGS__) @@ -74,14 +80,14 @@ static const ObjectModelArrayDescriptor heatersArrayDescriptor = 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}, -#if 0 - { "Heaters", OBJECT_MODEL_FUNC_NOSELF(&heatersArrayDescriptor), ObjectModelEntryFlags::none } -#endif + { "Heaters", OBJECT_MODEL_FUNC_NOSELF(&heatersArrayDescriptor), ObjectModelEntryFlags::none }, + { "Sensors", OBJECT_MODEL_FUNC_NOSELF(&sensorsArrayDescriptor), ObjectModelEntryFlags::none }, }; -constexpr uint8_t Heat::objectModelTableDescriptor[] = { 1, 2 }; +constexpr uint8_t Heat::objectModelTableDescriptor[] = { 3, 4, 0, 0 }; DEFINE_GET_OBJECT_MODEL_TABLE(Heat) @@ -254,6 +260,10 @@ ReadLockedPointer<TemperatureSensor> Heat::FindSensor(int sn) const noexcept { return ReadLockedPointer<TemperatureSensor>(locker, sensor); } + if ((int)sensor->GetSensorNumber() > sn) + { + break; + } } return ReadLockedPointer<TemperatureSensor>(locker, nullptr); } @@ -1210,15 +1220,34 @@ float Heat::GetSensorTemperature(int sensorNum, TemperatureError& err) const noe return BadErrorTemperature; } -// Return the highest used heater number. Used by RepRap.cpp to shorten responses by omitting unused trailing heater numbers. If no heaters are configured, return 0. -size_t Heat::GetHighestUsedHeaterNumber() const noexcept +// Return the highest used heater number plus one. Used by RepRap.cpp to shorten responses by omitting unused trailing heater numbers. +size_t Heat::GetNumHeatersToReport() const noexcept +{ + size_t ret = ARRAY_SIZE(heaters); + while (ret != 0 && heaters[ret] == nullptr) + { + --ret; + } + return ret; +} + +// Return the highest used sensor number plus one +size_t Heat::GetNumSensorsToReport() const noexcept { - size_t highestHeater = ARRAY_SIZE(heaters); - do + ReadLocker lock(sensorsLock); + + const TemperatureSensor *s = sensorsRoot; + if (s == nullptr) { - --highestHeater; - } while (heaters[highestHeater] == nullptr && highestHeater != 0); - return highestHeater; + return 0; + } + + // Find the last sensor in the list + while (s->GetNext() != nullptr) + { + s = s->GetNext(); + } + return s->GetSensorNumber() + 1; } // Get the temperature of a heater diff --git a/src/Heating/Heat.h b/src/Heating/Heat.h index 22c011a1..a369d23c 100644 --- a/src/Heating/Heat.h +++ b/src/Heating/Heat.h @@ -92,7 +92,8 @@ public: float GetSensorTemperature(int sensorNum, TemperatureError& err) const noexcept; // Result is in degrees Celsius float GetHighestTemperatureLimit() const noexcept; // Get the highest temperature limit of any heater - size_t GetHighestUsedHeaterNumber() const noexcept; + size_t GetNumHeatersToReport() const noexcept; + size_t GetNumSensorsToReport() const noexcept; void Diagnostics(MessageType mtype) noexcept; // Output useful information @@ -145,6 +146,11 @@ public: protected: DECLARE_OBJECT_MODEL +#if SUPPORT_OBJECT_MODEL + static const ObjectModelArrayDescriptor heatersArrayDescriptor; + static const ObjectModelArrayDescriptor sensorsArrayDescriptor; +#endif + private: Heat(const Heat&) = delete; // Private copy constructor to prevent copying diff --git a/src/Heating/Heater.cpp b/src/Heating/Heater.cpp index 87b7b57c..7dc201bb 100644 --- a/src/Heating/Heater.cpp +++ b/src/Heating/Heater.cpp @@ -12,6 +12,30 @@ #include "HeaterProtection.h" #include "Sensors/TemperatureSensor.h" +#if SUPPORT_OBJECT_MODEL + +// Object model table and functions +// Note: if using GCC version 7.3.1 20180622 and lambda functions are used in this table, you must compile this file with option -std=gnu++17. +// Otherwise the table will be allocated in RAM instead of flash, which wastes too much RAM. + +// Macro to build a standard lambda function that includes the necessary type conversions +#define OBJECT_MODEL_FUNC(...) OBJECT_MODEL_FUNC_BODY(Heater, __VA_ARGS__) + +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 }, +}; + +constexpr uint8_t Heater::objectModelTableDescriptor[] = { 1, 3 }; + +DEFINE_GET_OBJECT_MODEL_TABLE(Heater) + +#endif + Heater::Heater(unsigned int num) noexcept : heaterNumber(num), sensorNumber(-1), activeTemperature(0.0), standbyTemperature(0.0), maxTempExcursion(DefaultMaxTempExcursion), maxHeatingFaultTime(DefaultMaxHeatingFaultTime), @@ -75,6 +99,12 @@ HeaterStatus Heater::GetStatus() const noexcept : HeaterStatus::standby; } +const char *Heater::GetStateName() const noexcept +{ + static const char * const StateNames[] = { "Off", "Standby", "Active", "Tuning", "Offline" }; + return StateNames[(uint8_t)GetStatus()]; +} + const char* Heater::GetSensorName() const noexcept { const auto sensor = reprap.GetHeat().FindSensor(sensorNumber); diff --git a/src/Heating/Heater.h b/src/Heating/Heater.h index f8bbb33d..7a26e441 100644 --- a/src/Heating/Heater.h +++ b/src/Heating/Heater.h @@ -11,6 +11,7 @@ #include "RepRapFirmware.h" #include "FOPDT.h" #include "GCodes/GCodeResult.h" +#include <ObjectModel/ObjectModel.h> #if SUPPORT_CAN_EXPANSION # include "CanId.h" @@ -22,7 +23,7 @@ struct CanHeaterReport; // Enumeration to describe the status of a heater. Note that the web interface returns the numerical values, so don't change them. enum class HeaterStatus { off = 0, standby = 1, active = 2, fault = 3, tuning = 4, offline = 5 }; -class Heater +class Heater INHERIT_OBJECT_MODEL { public: Heater(unsigned int num) noexcept; @@ -79,6 +80,8 @@ public: bool CheckGood() const noexcept; protected: + DECLARE_OBJECT_MODEL + enum class HeaterMode : uint8_t { // The order of these is important because we test "mode > HeatingMode::suspended" to determine whether the heater is active @@ -114,7 +117,8 @@ protected: FopDt model; private: - bool CheckProtection() const noexcept; // Check heater protection elements and return true if everything is good + bool CheckProtection() const noexcept; // Check heater protection elements and return true if everything is good + const char *GetStateName() const noexcept; unsigned int heaterNumber; int sensorNumber; // the sensor number used by this heater diff --git a/src/Heating/Sensors/TemperatureSensor.cpp b/src/Heating/Sensors/TemperatureSensor.cpp index a8d7a2cc..9b82e6be 100644 --- a/src/Heating/Sensors/TemperatureSensor.cpp +++ b/src/Heating/Sensors/TemperatureSensor.cpp @@ -24,6 +24,30 @@ # include "CAN/CanInterface.h" #endif +#if SUPPORT_OBJECT_MODEL + +// Object model table and functions +// Note: if using GCC version 7.3.1 20180622 and lambda functions are used in this table, you must compile this file with option -std=gnu++17. +// Otherwise the table will be allocated in RAM instead of flash, which wastes too much RAM. + +// Macro to build a standard lambda function that includes the necessary type conversions +#define OBJECT_MODEL_FUNC(...) OBJECT_MODEL_FUNC_BODY(TemperatureSensor, __VA_ARGS__) + +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 }, +}; + +constexpr uint8_t TemperatureSensor::objectModelTableDescriptor[] = { 1, 3 }; + +DEFINE_GET_OBJECT_MODEL_TABLE(TemperatureSensor) + +#endif + // Constructor TemperatureSensor::TemperatureSensor(unsigned int sensorNum, const char *t) noexcept : next(nullptr), sensorNumber(sensorNum), sensorType(t), sensorName(nullptr), diff --git a/src/Heating/Sensors/TemperatureSensor.h b/src/Heating/Sensors/TemperatureSensor.h index d4b50a6d..fc522974 100644 --- a/src/Heating/Sensors/TemperatureSensor.h +++ b/src/Heating/Sensors/TemperatureSensor.h @@ -5,11 +5,12 @@ #include "Heating/TemperatureError.h" // for result codes #include "Hardware/IoPorts.h" #include "GCodes/GCodeResult.h" +#include <ObjectModel/ObjectModel.h> class GCodeBuffer; struct CanSensorReport; -class TemperatureSensor +class TemperatureSensor INHERIT_OBJECT_MODEL { public: TemperatureSensor(unsigned int sensorNum, const char *type) noexcept; @@ -80,6 +81,8 @@ public: virtual bool PollInTask() noexcept { return false; }; // Classes implementing this method need to also call Heat::EnsureSensorsTask() after succesful configuration protected: + DECLARE_OBJECT_MODEL + void SetResult(float t, TemperatureError rslt) noexcept; void SetResult(TemperatureError rslt) noexcept; diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp index c656b29b..3614b08c 100644 --- a/src/Movement/Move.cpp +++ b/src/Movement/Move.cpp @@ -56,6 +56,7 @@ static const ObjectModelArrayDescriptor axesArrayDescriptor = { + nullptr, [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return reprap.GetGCodes().GetVisibleAxes(); }, [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(self, 3); } }; diff --git a/src/Networking/Network.cpp b/src/Networking/Network.cpp index f5b1a6a4..dd70d29d 100644 --- a/src/Networking/Network.cpp +++ b/src/Networking/Network.cpp @@ -71,6 +71,7 @@ Network::Network(Platform& p) noexcept : platform(p), responders(nullptr), nextR static const ObjectModelArrayDescriptor interfaceArrayDescriptor = { + nullptr, [] (const ObjectModel *self, const ObjectExplorationContext& context) noexcept -> size_t { return NumNetworkInterfaces; }, [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(((Network*)self)->GetInterface(context.GetIndex(0))); } }; diff --git a/src/ObjectModel/ObjectModel.cpp b/src/ObjectModel/ObjectModel.cpp index 36375ec5..3221a532 100644 --- a/src/ObjectModel/ObjectModel.cpp +++ b/src/ObjectModel/ObjectModel.cpp @@ -112,7 +112,11 @@ bool ObjectModel::ReportItemAsJson(OutputBuffer *buf, ObjectExplorationContext& } buf->cat('['); context.AddIndex(index); - const bool ret = ReportItemAsJson(buf, context, val.omadVal->GetElement(this, context), endptr + 1); + bool ret; + { + ReadLocker lock(val.omadVal->lockPointer); + ret = ReportItemAsJson(buf, context, val.omadVal->GetElement(this, context), endptr + 1); + } context.RemoveIndex(); buf->cat(']'); return ret; @@ -124,11 +128,15 @@ bool ObjectModel::ReportItemAsJson(OutputBuffer *buf, ObjectExplorationContext& return false; case TYPE_OF(const ObjectModel*): - if (*filter == '.') + 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; case TYPE_OF(float): @@ -212,6 +220,8 @@ bool ObjectModel::ReportItemAsJson(OutputBuffer *buf, ObjectExplorationContext& // Report an entire array as JSON bool ObjectModel::ReportArrayAsJson(OutputBuffer *buf, ObjectExplorationContext& context, const ObjectModelArrayDescriptor *omad, const char *filter) const { + ReadLocker lock(omad->lockPointer); + buf->cat('['); bool ret = true; const size_t count = omad->GetNumElements(this, context); @@ -322,7 +332,7 @@ ExpressionValue ObjectModel::GetObjectValue(const StringParser& sp, const char * // Get the value of an object ExpressionValue ObjectModel::GetObjectValue(const StringParser& sp, ObjectExplorationContext& context, uint8_t tableNumber, const char *idString) const { - const ObjectModelTableEntry *e = FindObjectModelTableEntry(tableNumber, idString); + const ObjectModelTableEntry *const e = FindObjectModelTableEntry(tableNumber, idString); if (e == nullptr) { throw sp.ConstructParseException("unknown value %s", idString); @@ -330,7 +340,12 @@ ExpressionValue ObjectModel::GetObjectValue(const StringParser& sp, ObjectExplor idString = GetNextElement(idString); ExpressionValue val = e->func(this, context); - while (val.type == TYPE_OF(const ObjectModelArrayDescriptor*)) + return GetObjectValue(sp, context, val, idString); +} + +ExpressionValue ObjectModel::GetObjectValue(const StringParser& sp, ObjectExplorationContext& context, ExpressionValue val, const char *idString) const +{ + if (val.type == TYPE_OF(const ObjectModelArrayDescriptor*)) { if (*idString != '[') { @@ -342,15 +357,19 @@ ExpressionValue ObjectModel::GetObjectValue(const StringParser& sp, ObjectExplor { throw sp.ConstructParseException("expected ']'"); } + + ReadLocker lock(val.omadVal->lockPointer); + if (index < 0 || (size_t)index >= val.omadVal->GetNumElements(this, context)) { throw sp.ConstructParseException("array index out of bounds"); } - idString = endptr + 1; // skip past the ']' + idString = endptr + 1; // skip past the ']' context.AddIndex(index); - val = val.omadVal->GetElement(this, context); // fetch the array element + val = GetObjectValue(sp, context, val.omadVal->GetElement(this, context), idString); context.RemoveIndex(); + return val; } if (val.type == TYPE_OF(const ObjectModel*)) diff --git a/src/ObjectModel/ObjectModel.h b/src/ObjectModel/ObjectModel.h index bde3eabd..75d3a723 100644 --- a/src/ObjectModel/ObjectModel.h +++ b/src/ObjectModel/ObjectModel.h @@ -133,6 +133,7 @@ private: class ObjectModelArrayDescriptor { public: + ReadWriteLock *lockPointer; size_t (*GetNumElements)(const ObjectModel*, const ObjectExplorationContext&) noexcept; ExpressionValue (*GetElement)(const ObjectModel*, ObjectExplorationContext&) noexcept; }; @@ -159,9 +160,12 @@ protected: // Report an entire array as JSON bool ReportArrayAsJson(OutputBuffer *buf, ObjectExplorationContext& context, const ObjectModelArrayDescriptor *omad, const char *filter) const THROWS_GCODE_EXCEPTION; - // Get the value of an object + // Get the value of an object via the table ExpressionValue GetObjectValue(const StringParser& sp, ObjectExplorationContext& context, uint8_t tableNumber, const char *idString) const THROWS_GCODE_EXCEPTION; + // Get the value of an object that we hold + ExpressionValue GetObjectValue(const StringParser& sp, ObjectExplorationContext& context, ExpressionValue val, const char *idString) const THROWS_GCODE_EXCEPTION; + // Get the object model table entry for the current level object in the query const ObjectModelTableEntry *FindObjectModelTableEntry(uint8_t tableNumber, const char *idString) const noexcept; diff --git a/src/RepRap.cpp b/src/RepRap.cpp index 3539c594..63a74da8 100644 --- a/src/RepRap.cpp +++ b/src/RepRap.cpp @@ -1151,8 +1151,8 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe response->cat("\"current\":"); ch = '['; { - const size_t highestHeater = heat->GetHighestUsedHeaterNumber(); - for (size_t heater = 0; heater <= highestHeater; heater++) + const size_t numHeaters = heat->GetNumHeatersToReport(); + for (size_t heater = 0; heater < numHeaters; heater++) { response->catf("%c%.1f", ch, (double)heat->GetHeaterTemperature(heater)); ch = ','; @@ -1162,7 +1162,7 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe // Current states response->cat(",\"state\":"); ch = '['; - for (size_t heater = 0; heater <= highestHeater; heater++) + for (size_t heater = 0; heater < numHeaters; heater++) { response->catf("%c%d", ch, (int)heat->GetStatus(heater)); ch = ','; @@ -1174,7 +1174,7 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe { response->cat(",\"names\":"); ch = '['; - for (size_t heater = 0; heater <= highestHeater; heater++) + for (size_t heater = 0; heater < numHeaters; heater++) { response->cat(ch); ch = ','; diff --git a/src/Version.h b/src/Version.h index a156cd0b..1bcc9d29 100644 --- a/src/Version.h +++ b/src/Version.h @@ -20,7 +20,7 @@ #endif #ifndef DATE -# define DATE "2020-01-07b3" +# define DATE "2020-01-08b1" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman, printm3d" |