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:
authorDavid Crocker <dcrocker@eschertech.com>2020-01-09 21:10:49 +0300
committerDavid Crocker <dcrocker@eschertech.com>2020-01-09 21:10:49 +0300
commit651f821e18bbb2a53f0c951babe50b481be30cd9 (patch)
treedd73fda5339cd3f7dbf1ac20c8b7f10554feeca6
parent0e047b2d7e5ebc59441a6796d62059b7bf9da368 (diff)
More work on object model
Added facility to acquire a read lock around access to an array Partially implemented Heaters and Sensors in the model
-rw-r--r--src/GCodes/GCodes2.cpp2
-rw-r--r--src/Heating/Heat.cpp61
-rw-r--r--src/Heating/Heat.h8
-rw-r--r--src/Heating/Heater.cpp30
-rw-r--r--src/Heating/Heater.h8
-rw-r--r--src/Heating/Sensors/TemperatureSensor.cpp24
-rw-r--r--src/Heating/Sensors/TemperatureSensor.h5
-rw-r--r--src/Movement/Move.cpp1
-rw-r--r--src/Networking/Network.cpp1
-rw-r--r--src/ObjectModel/ObjectModel.cpp35
-rw-r--r--src/ObjectModel/ObjectModel.h6
-rw-r--r--src/RepRap.cpp8
-rw-r--r--src/Version.h2
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"