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-22 23:46:13 +0300
committerDavid Crocker <dcrocker@eschertech.com>2020-01-22 23:46:13 +0300
commitf11710c9cb9f16901437f39b5e07326f3d1ad6bf (patch)
tree27b6c95c661a56e3a5c3d24b85e934616697cf6b
parentee1ccb5074a1824175c29e3e28fc47d888c15091 (diff)
Bug fix and more Object Model fields
Fixed bad JSON in M408 reports when no fans are configured Added more object model fields: kinematics, machine coordinates Refactored code that generates M408 responses
-rw-r--r--src/Configuration.h2
-rw-r--r--src/GCodes/GCodes.cpp12
-rw-r--r--src/GCodes/GCodes.h28
-rw-r--r--src/GCodes/GCodes3.cpp15
-rw-r--r--src/Movement/DDARing.cpp16
-rw-r--r--src/Movement/DDARing.h6
-rw-r--r--src/Movement/Kinematics/CoreKinematics.cpp54
-rw-r--r--src/Movement/Kinematics/CoreKinematics.h7
-rw-r--r--src/Movement/Kinematics/FiveBarScaraKinematics.cpp22
-rw-r--r--src/Movement/Kinematics/FiveBarScaraKinematics.h3
-rw-r--r--src/Movement/Kinematics/HangprinterKinematics.cpp22
-rw-r--r--src/Movement/Kinematics/HangprinterKinematics.h3
-rw-r--r--src/Movement/Kinematics/Kinematics.h9
-rw-r--r--src/Movement/Kinematics/LinearDeltaKinematics.cpp41
-rw-r--r--src/Movement/Kinematics/LinearDeltaKinematics.h4
-rw-r--r--src/Movement/Kinematics/PolarKinematics.cpp22
-rw-r--r--src/Movement/Kinematics/PolarKinematics.h3
-rw-r--r--src/Movement/Kinematics/RotaryDeltaKinematics.cpp22
-rw-r--r--src/Movement/Kinematics/RotaryDeltaKinematics.h3
-rw-r--r--src/Movement/Kinematics/ScaraKinematics.cpp22
-rw-r--r--src/Movement/Kinematics/ScaraKinematics.h3
-rw-r--r--src/Movement/Move.cpp19
-rw-r--r--src/Movement/Move.h21
-rw-r--r--src/ObjectModel/ObjectModel.cpp17
-rw-r--r--src/ObjectModel/ObjectModel.h6
-rw-r--r--src/Platform.cpp16
-rw-r--r--src/Platform.h1
-rw-r--r--src/RepRap.cpp424
-rw-r--r--src/RepRap.h4
-rw-r--r--src/RepRapFirmware.cpp8
-rw-r--r--src/RepRapFirmware.h7
-rw-r--r--src/Version.h2
32 files changed, 484 insertions, 360 deletions
diff --git a/src/Configuration.h b/src/Configuration.h
index 47c56bcd..c022fc94 100644
--- a/src/Configuration.h
+++ b/src/Configuration.h
@@ -243,7 +243,7 @@ constexpr size_t SHORT_GCODE_LENGTH = 61; // maximum length of a GCode that w
// for the HTTP responder to return a status response. Otherwise DWC never gets to know that it needs to make a rr_reply call and the system deadlocks.
#if SAME70
constexpr size_t OUTPUT_BUFFER_SIZE = 256; // How many bytes does each OutputBuffer hold?
-constexpr size_t OUTPUT_BUFFER_COUNT = 32; // How many OutputBuffer instances do we have?
+constexpr size_t OUTPUT_BUFFER_COUNT = 40; // How many OutputBuffer instances do we have?
constexpr size_t RESERVED_OUTPUT_BUFFERS = 4; // Number of reserved output buffers after long responses, enough to hold a status response
#elif SAM4E || SAM4S
constexpr size_t OUTPUT_BUFFER_SIZE = 256; // How many bytes does each OutputBuffer hold?
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index e6c2abcf..1dbe5564 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -218,19 +218,13 @@ void GCodes::Reset() noexcept
for (size_t i = 0; i < MaxAxes; ++i)
{
axisScaleFactors[i] = 1.0;
-#if SUPPORT_WORKPLACE_COORDINATES
for (size_t j = 0; j < NumCoordinateSystems; ++j)
{
workplaceCoordinates[j][i] = 0.0;
}
-#else
- axisOffsets[i] = 0.0;
-#endif
}
-#if SUPPORT_WORKPLACE_COORDINATES
currentCoordinateSystem = 0;
-#endif
for (float& f : moveBuffer.coords)
{
@@ -2787,14 +2781,10 @@ void GCodes::GetCurrentCoordinates(const StringRef& s) const noexcept
// Now the virtual extruder position, for Octoprint
s.catf("E:%.3f ", (double)virtualExtruderPosition);
- // Get the live machine coordinates, we'll need them later
- float liveCoordinates[MaxAxesPlusExtruders];
- reprap.GetMove().LiveCoordinates(liveCoordinates, reprap.GetCurrentTool());
-
// Now the extruder coordinates
for (size_t i = 0; i < numExtruders; i++)
{
- s.catf("E%u:%.1f ", i, (double)liveCoordinates[ExtruderToLogicalDrive(i)]);
+ s.catf("E%u:%.1f ", i, (double)reprap.GetMove().LiveCoordinate(ExtruderToLogicalDrive(i), reprap.GetCurrentTool()));
}
// Print the axis stepper motor positions as Marlin does, as an aid to debugging.
diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h
index df2e78ec..3df21230 100644
--- a/src/GCodes/GCodes.h
+++ b/src/GCodes/GCodes.h
@@ -195,8 +195,19 @@ public:
GCodeResult StartSDTiming(GCodeBuffer& gb, const StringRef& reply) noexcept; // Start timing SD card file writing
#endif
-#if SUPPORT_WORKPLACE_COORDINATES
unsigned int GetWorkplaceCoordinateSystemNumber() const noexcept { return currentCoordinateSystem + 1; }
+
+ // This function is called by other functions to account correctly for workplace coordinates
+ inline float GetWorkplaceOffset(size_t axis) const noexcept
+ {
+ return workplaceCoordinates[currentCoordinateSystem][axis];
+ }
+
+#if SUPPORT_OBJECT_MODEL
+ inline float GetWorkplaceOffset(size_t axis, size_t workplaceNumber) const noexcept
+ {
+ return workplaceCoordinates[workplaceNumber][axis];
+ }
#endif
private:
@@ -368,16 +379,6 @@ private:
#endif
Pwm_t ConvertLaserPwm(float reqVal) const noexcept;
- // This function is called by other functions to account correctly for workplace coordinates, depending on whether the build configuration supports them.
- inline float GetWorkplaceOffset(size_t axis) const noexcept
- {
-#if SUPPORT_WORKPLACE_COORDINATES
- return workplaceCoordinates[currentCoordinateSystem][axis];
-#else
- return axisOffsets[axis];
-#endif
- }
-
#ifdef SERIAL_AUX_DEVICE
static bool emergencyStopCommanded;
static void CommandEmergencyStop(UARTClass *p);
@@ -469,13 +470,8 @@ private:
float rawExtruderTotalByDrive[MaxExtruders]; // Extrusion amount in the last G1 command with an E parameter when in absolute extrusion mode
float rawExtruderTotal; // Total extrusion amount fed to Move class since starting print, before applying extrusion factor, summed over all drives
-#if SUPPORT_WORKPLACE_COORDINATES
- static const size_t NumCoordinateSystems = 9;
unsigned int currentCoordinateSystem; // This is zero-based, where as the P parameter in the G10 command is 1-based
float workplaceCoordinates[NumCoordinateSystems][MaxAxes]; // Workplace coordinate offsets
-#else
- float axisOffsets[MaxAxes]; // M206 axis offsets
-#endif
#if HAS_MASS_STORAGE
FileData fileToPrint; // The next file to print
diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp
index cb7ffda6..5e6dad81 100644
--- a/src/GCodes/GCodes3.cpp
+++ b/src/GCodes/GCodes3.cpp
@@ -126,12 +126,7 @@ GCodeResult GCodes::OffsetAxes(GCodeBuffer& gb, const StringRef& reply)
{
if (gb.Seen(axisLetters[axis]))
{
-#if SUPPORT_WORKPLACE_COORDINATES
- workplaceCoordinates[currentCoordinateSystem][axis]
-#else
- axisOffsets[axis]
-#endif
- = -gb.GetDistance();
+ workplaceCoordinates[currentCoordinateSystem][axis] = -gb.GetDistance();
seen = true;
}
}
@@ -141,13 +136,7 @@ GCodeResult GCodes::OffsetAxes(GCodeBuffer& gb, const StringRef& reply)
reply.printf("Axis offsets:");
for (size_t axis = 0; axis < numVisibleAxes; axis++)
{
- reply.catf(" %c%.2f", axisLetters[axis],
-#if SUPPORT_WORKPLACE_COORDINATES
- -(double)(gb.InverseConvertDistance(workplaceCoordinates[0][axis]))
-#else
- -(double)(gb.InverseConvertDistance(axisOffsets[axis]))
-#endif
- );
+ reply.catf(" %c%.2f", axisLetters[axis], -(double)(gb.InverseConvertDistance(workplaceCoordinates[0][axis])));
}
}
diff --git a/src/Movement/DDARing.cpp b/src/Movement/DDARing.cpp
index 6be3bcd0..292a4526 100644
--- a/src/Movement/DDARing.cpp
+++ b/src/Movement/DDARing.cpp
@@ -408,6 +408,7 @@ void DDARing::CurrentMoveCompleted() noexcept
{
// Save the current motor coordinates, and the machine Cartesian coordinates if known
liveCoordinatesValid = currentDda->FetchEndPosition(const_cast<int32_t*>(liveEndPoints), const_cast<float *>(liveCoordinates));
+ liveCoordinatesChanged = true;
const size_t numExtruders = reprap.GetGCodes().GetNumExtruders();
for (size_t extruder = 0; extruder < numExtruders; ++extruder)
{
@@ -479,12 +480,18 @@ void DDARing::AdjustMotorPositions(const float adjustment[], size_t numMotors) n
}
liveCoordinatesValid = false; // force the live XYZ position to be recalculated
+ liveCoordinatesChanged = true;
}
-// Return the current live XYZ and extruder coordinates
+// Fetch the current live XYZ and extruder coordinates if they have changed since this was lass called
// Interrupts are assumed enabled on entry
-void DDARing::LiveCoordinates(float m[MaxAxesPlusExtruders]) noexcept
+bool DDARing::LiveCoordinates(float m[MaxAxesPlusExtruders]) noexcept
{
+ if (!liveCoordinatesChanged)
+ {
+ return false;
+ }
+
// The live coordinates and live endpoints are modified by the ISR, so be careful to get a self-consistent set of them
const size_t numVisibleAxes = reprap.GetGCodes().GetVisibleAxes(); // do this before we disable interrupts
const size_t numTotalAxes = reprap.GetGCodes().GetTotalAxes(); // do this before we disable interrupts
@@ -493,6 +500,7 @@ void DDARing::LiveCoordinates(float m[MaxAxesPlusExtruders]) noexcept
{
// All coordinates are valid, so copy them across
memcpy(m, const_cast<const float *>(liveCoordinates), sizeof(m[0]) * MaxAxesPlusExtruders);
+ liveCoordinatesChanged = false;
cpu_irq_enable();
}
else
@@ -511,9 +519,11 @@ void DDARing::LiveCoordinates(float m[MaxAxesPlusExtruders]) noexcept
{
memcpy(const_cast<float *>(liveCoordinates), m, sizeof(m[0]) * numVisibleAxes);
liveCoordinatesValid = true;
+ liveCoordinatesChanged = false;
}
cpu_irq_enable();
}
+ return true;
}
// These are the actual numbers that we want to be the coordinates, so don't transform them.
@@ -525,6 +535,7 @@ void DDARing::SetLiveCoordinates(const float coords[MaxAxesPlusExtruders]) noexc
liveCoordinates[drive] = coords[drive];
}
liveCoordinatesValid = true;
+ liveCoordinatesChanged = true;
reprap.GetMove().EndPointToMachine(coords, const_cast<int32_t *>(liveEndPoints), reprap.GetGCodes().GetVisibleAxes());
}
@@ -536,6 +547,7 @@ void DDARing::ResetExtruderPositions() noexcept
liveCoordinates[eDrive] = 0.0;
}
cpu_irq_enable();
+ liveCoordinatesChanged = true;
}
float DDARing::GetRequestedSpeed() const noexcept
diff --git a/src/Movement/DDARing.h b/src/Movement/DDARing.h
index f5456145..b4e2a668 100644
--- a/src/Movement/DDARing.h
+++ b/src/Movement/DDARing.h
@@ -66,7 +66,7 @@ public:
void GetCurrentMachinePosition(float m[MaxAxes], bool disableMotorMapping) const noexcept; // Get the current position in untransformed coords
void SetPositions(const float move[MaxAxesPlusExtruders]) noexcept; // Force the machine coordinates to be these
void AdjustMotorPositions(const float adjustment[], size_t numMotors) noexcept; // Perform motor endpoint adjustment
- void LiveCoordinates(float m[MaxAxesPlusExtruders]) noexcept; // Gives the last point at the end of the last complete DDA transformed to user coords
+ bool LiveCoordinates(float m[MaxAxesPlusExtruders]) noexcept; // Fetch the last point at the end of the last completed DDA if it has changed since we last called this
void SetLiveCoordinates(const float coords[MaxAxesPlusExtruders]) noexcept; // Force the live coordinates (see above) to be these
void ResetExtruderPositions() noexcept; // Resets the extrusion amounts of the live coordinates
@@ -96,7 +96,6 @@ private:
StepTimer timer; // Timer object to control getting step interrupts
volatile float liveCoordinates[MaxAxesPlusExtruders]; // The endpoint that the machine moved to in the last completed move
- volatile bool liveCoordinatesValid; // True if the XYZ live coordinates are reliable (the extruder ones always are)
volatile int32_t liveEndPoints[MaxAxesPlusExtruders]; // The XYZ endpoints of the last completed move in motor coordinates
unsigned int numDdasInRing;
@@ -114,7 +113,10 @@ private:
float extrusionPending[MaxExtruders]; // Extrusion not done due to rounding to nearest step
volatile int32_t extrusionAccumulators[MaxExtruders]; // Accumulated extruder motor steps
volatile uint32_t extrudersPrintingSince; // The milliseconds clock time when extrudersPrinting was set to true
+
volatile bool extrudersPrinting; // Set whenever an extruder starts a printing move, cleared by a non-printing extruder move
+ volatile bool liveCoordinatesValid; // True if the XYZ live coordinates in liveCoordinates are reliable (the extruder ones always are)
+ volatile bool liveCoordinatesChanged; // True if the live coordinates have changed since LiveCoordinates was last called
};
// Start the next move. Return true if laser or IO bits need to be active
diff --git a/src/Movement/Kinematics/CoreKinematics.cpp b/src/Movement/Kinematics/CoreKinematics.cpp
index 23b4c3d2..91b63794 100644
--- a/src/Movement/Kinematics/CoreKinematics.cpp
+++ b/src/Movement/Kinematics/CoreKinematics.cpp
@@ -12,6 +12,60 @@
#include "GCodes/GCodeBuffer/GCodeBuffer.h"
#include "Movement/DDA.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(CoreKinematics, __VA_ARGS__)
+
+constexpr ObjectModelArrayDescriptor CoreKinematics::forwardMatrixElementArrayDescriptor =
+{
+ nullptr, // no lock needed
+ [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return reprap.GetGCodes().GetTotalAxes(); },
+ [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue
+ { return ExpressionValue(((const CoreKinematics*)self)->forwardMatrix(context.GetIndex(1), context.GetIndex(0)), 3); }
+};
+
+constexpr ObjectModelArrayDescriptor CoreKinematics::inverseMatrixElementArrayDescriptor =
+{
+ nullptr, // no lock needed
+ [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return reprap.GetGCodes().GetVisibleAxes(); },
+ [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue
+ { return ExpressionValue(((const CoreKinematics*)self)->forwardMatrix(context.GetIndex(1), context.GetIndex(0)), 3); }
+};
+
+constexpr ObjectModelArrayDescriptor CoreKinematics::forwardMatrixArrayDescriptor =
+{
+ nullptr, // no lock needed
+ [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return reprap.GetGCodes().GetVisibleAxes(); },
+ [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(&forwardMatrixElementArrayDescriptor); }
+};
+
+constexpr ObjectModelArrayDescriptor CoreKinematics::inverseMatrixArrayDescriptor =
+{
+ nullptr, // no lock needed
+ [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return reprap.GetGCodes().GetTotalAxes(); },
+ [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(&inverseMatrixElementArrayDescriptor); }
+};
+
+constexpr ObjectModelTableEntry CoreKinematics::objectModelTable[] =
+{
+ // Within each group, these entries must be in alphabetical order
+ // 0. kinematics members
+ { "forwardMatrix", OBJECT_MODEL_FUNC_NOSELF(&forwardMatrixArrayDescriptor), ObjectModelEntryFlags::none },
+ { "inverseMatrix", OBJECT_MODEL_FUNC_NOSELF(&inverseMatrixArrayDescriptor), ObjectModelEntryFlags::none },
+ { "name", OBJECT_MODEL_FUNC(self->GetName(false)), ObjectModelEntryFlags::none },
+};
+
+constexpr uint8_t CoreKinematics::objectModelTableDescriptor[] = { 1, 3 };
+
+DEFINE_GET_OBJECT_MODEL_TABLE(CoreKinematics)
+
+#endif
+
// Recalculate internal variables following a configuration change
void CoreKinematics::Recalc() noexcept
{
diff --git a/src/Movement/Kinematics/CoreKinematics.h b/src/Movement/Kinematics/CoreKinematics.h
index a44dde09..27bcc5b4 100644
--- a/src/Movement/Kinematics/CoreKinematics.h
+++ b/src/Movement/Kinematics/CoreKinematics.h
@@ -28,6 +28,13 @@ public:
AxesBitmap GetConnectedAxes(size_t axis) const noexcept override;
AxesBitmap GetLinearAxes() const noexcept override;
+protected:
+ DECLARE_OBJECT_MODEL
+ OBJECT_MODEL_ARRAY(forwardMatrix)
+ OBJECT_MODEL_ARRAY(forwardMatrixElement)
+ OBJECT_MODEL_ARRAY(inverseMatrix)
+ OBJECT_MODEL_ARRAY(inverseMatrixElement)
+
private:
void Recalc() noexcept; // recalculate internal variables following a configuration change
bool HasSharedMotor(size_t axis) const noexcept; // return true if the axis doesn't have a single dedicated motor
diff --git a/src/Movement/Kinematics/FiveBarScaraKinematics.cpp b/src/Movement/Kinematics/FiveBarScaraKinematics.cpp
index b35fd3b3..735b88e8 100644
--- a/src/Movement/Kinematics/FiveBarScaraKinematics.cpp
+++ b/src/Movement/Kinematics/FiveBarScaraKinematics.cpp
@@ -18,6 +18,28 @@
//#define debugPrintf if(0) debugPrintf
+#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(FiveBarScaraKinematics, __VA_ARGS__)
+
+constexpr ObjectModelTableEntry FiveBarScaraKinematics::objectModelTable[] =
+{
+ // Within each group, these entries must be in alphabetical order
+ // 0. kinematics members
+ { "name", OBJECT_MODEL_FUNC(self->GetName(false)), ObjectModelEntryFlags::none },
+};
+
+constexpr uint8_t FiveBarScaraKinematics::objectModelTableDescriptor[] = { 1, 1 };
+
+DEFINE_GET_OBJECT_MODEL_TABLE(FiveBarScaraKinematics)
+
+#endif
+
FiveBarScaraKinematics::FiveBarScaraKinematics() noexcept
: ZLeadscrewKinematics(KinematicsType::scara, DefaultSegmentsPerSecond, DefaultMinSegmentSize, true)
{
diff --git a/src/Movement/Kinematics/FiveBarScaraKinematics.h b/src/Movement/Kinematics/FiveBarScaraKinematics.h
index 337e0bcb..a88b419b 100644
--- a/src/Movement/Kinematics/FiveBarScaraKinematics.h
+++ b/src/Movement/Kinematics/FiveBarScaraKinematics.h
@@ -45,6 +45,9 @@ public:
AxesBitmap GetLinearAxes() const noexcept;
AxesBitmap GetConnectedAxes(size_t axis) const noexcept;
+protected:
+ DECLARE_OBJECT_MODEL
+
private:
static constexpr float DefaultSegmentsPerSecond = 100.0;
static constexpr float DefaultMinSegmentSize = 0.2;
diff --git a/src/Movement/Kinematics/HangprinterKinematics.cpp b/src/Movement/Kinematics/HangprinterKinematics.cpp
index 717888e3..fadff2bf 100644
--- a/src/Movement/Kinematics/HangprinterKinematics.cpp
+++ b/src/Movement/Kinematics/HangprinterKinematics.cpp
@@ -20,6 +20,28 @@ constexpr float DefaultAnchorC[3] = {-2000.0, 1000.0, -100.0};
constexpr float DefaultAnchorDz = 3000.0;
constexpr float DefaultPrintRadius = 1500.0;
+#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(HangprinterKinematics, __VA_ARGS__)
+
+constexpr ObjectModelTableEntry HangprinterKinematics::objectModelTable[] =
+{
+ // Within each group, these entries must be in alphabetical order
+ // 0. kinematics members
+ { "name", OBJECT_MODEL_FUNC(self->GetName(false)), ObjectModelEntryFlags::none },
+};
+
+constexpr uint8_t HangprinterKinematics::objectModelTableDescriptor[] = { 1, 1 };
+
+DEFINE_GET_OBJECT_MODEL_TABLE(HangprinterKinematics)
+
+#endif
+
// Constructor
HangprinterKinematics::HangprinterKinematics() noexcept
: Kinematics(KinematicsType::scara, DefaultSegmentsPerSecond, DefaultMinSegmentSize, true)
diff --git a/src/Movement/Kinematics/HangprinterKinematics.h b/src/Movement/Kinematics/HangprinterKinematics.h
index 4c585eac..7dc00de5 100644
--- a/src/Movement/Kinematics/HangprinterKinematics.h
+++ b/src/Movement/Kinematics/HangprinterKinematics.h
@@ -44,6 +44,9 @@ public:
void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const noexcept override;
AxesBitmap GetLinearAxes() const noexcept override;
+protected:
+ DECLARE_OBJECT_MODEL
+
private:
static constexpr float DefaultSegmentsPerSecond = 100.0;
static constexpr float DefaultMinSegmentSize = 0.2;
diff --git a/src/Movement/Kinematics/Kinematics.h b/src/Movement/Kinematics/Kinematics.h
index 79a3d65b..0ecdc062 100644
--- a/src/Movement/Kinematics/Kinematics.h
+++ b/src/Movement/Kinematics/Kinematics.h
@@ -8,8 +8,9 @@
#ifndef SRC_MOVEMENT_KINEMATICS_H_
#define SRC_MOVEMENT_KINEMATICS_H_
-#include "RepRapFirmware.h"
-#include "Math/Matrix.h"
+#include <RepRapFirmware.h>
+#include <Math/Matrix.h>
+#include <ObjectModel/ObjectModel.h>
inline floatc_t fcsquare(floatc_t a)
{
@@ -61,7 +62,7 @@ enum class LimitPositionResult : uint8_t
adjustedAndIntermediateUnreachable // we adjusted the final position to make it reachable, but intermediate positions are still urreachable
};
-class Kinematics
+class Kinematics INHERIT_OBJECT_MODEL
{
public:
// Functions that must be defined in each derived class that implements a kinematics
@@ -208,6 +209,8 @@ public:
float GetMinSegmentLength() const noexcept pre(UseSegmentation()) { return minSegmentLength; }
protected:
+ DECLARE_OBJECT_MODEL_VIRTUAL
+
// Constructor. Pass segsPerSecond <= 0.0 to get non-segmented motion.
Kinematics(KinematicsType t, float segsPerSecond, float minSegLength, bool doUseRawG0) noexcept;
diff --git a/src/Movement/Kinematics/LinearDeltaKinematics.cpp b/src/Movement/Kinematics/LinearDeltaKinematics.cpp
index a284be8e..8e27dec5 100644
--- a/src/Movement/Kinematics/LinearDeltaKinematics.cpp
+++ b/src/Movement/Kinematics/LinearDeltaKinematics.cpp
@@ -13,6 +13,47 @@
#include "GCodes/GCodeBuffer/GCodeBuffer.h"
#include <Math/Deviation.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(LinearDeltaKinematics, __VA_ARGS__)
+
+constexpr ObjectModelArrayDescriptor LinearDeltaKinematics::towersArrayDescriptor =
+{
+ nullptr, // no lock needed
+ [] (const ObjectModel *self, const ObjectExplorationContext&) noexcept -> size_t { return ((const LinearDeltaKinematics*)self)->numTowers; },
+ [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue { return ExpressionValue(self, 2); }
+};
+
+constexpr ObjectModelTableEntry LinearDeltaKinematics::objectModelTable[] =
+{
+ // Within each group, these entries must be in alphabetical order
+ // 0. kinematics members
+ { "deltaRadius", OBJECT_MODEL_FUNC(self->radius, 3), ObjectModelEntryFlags::none },
+ { "homedHeight", OBJECT_MODEL_FUNC(self->homedHeight, 3), ObjectModelEntryFlags::none },
+ { "name", OBJECT_MODEL_FUNC(self->GetName(false)), ObjectModelEntryFlags::none },
+ { "printRadius", OBJECT_MODEL_FUNC(self->printRadius, 1), ObjectModelEntryFlags::none },
+ { "towers", OBJECT_MODEL_FUNC_NOSELF(&towersArrayDescriptor), ObjectModelEntryFlags::none },
+ { "xTilt", OBJECT_MODEL_FUNC(self->xTilt, 3), ObjectModelEntryFlags::none },
+ { "yTilt", OBJECT_MODEL_FUNC(self->yTilt, 3), ObjectModelEntryFlags::none },
+
+ // 1. tower members
+ { "diagonal", OBJECT_MODEL_FUNC(self->diagonals[context.GetLastIndex()], 3), ObjectModelEntryFlags::none },
+ { "endstopAdjustment", OBJECT_MODEL_FUNC(self->endstopAdjustments[context.GetLastIndex()], 3), ObjectModelEntryFlags::none },
+ { "xPos", OBJECT_MODEL_FUNC(self->towerX[context.GetLastIndex()], 3), ObjectModelEntryFlags::none },
+ { "yPos", OBJECT_MODEL_FUNC(self->towerY[context.GetLastIndex()], 3), ObjectModelEntryFlags::none },
+};
+
+constexpr uint8_t LinearDeltaKinematics::objectModelTableDescriptor[] = { 2, 7, 4 };
+
+DEFINE_GET_OBJECT_MODEL_TABLE(LinearDeltaKinematics)
+
+#endif
+
LinearDeltaKinematics::LinearDeltaKinematics() noexcept : Kinematics(KinematicsType::linearDelta, -1.0, 0.0, true), numTowers(UsualNumTowers)
{
Init();
diff --git a/src/Movement/Kinematics/LinearDeltaKinematics.h b/src/Movement/Kinematics/LinearDeltaKinematics.h
index 9765a0e2..40203863 100644
--- a/src/Movement/Kinematics/LinearDeltaKinematics.h
+++ b/src/Movement/Kinematics/LinearDeltaKinematics.h
@@ -57,6 +57,10 @@ public:
float GetTowerX(size_t axis) const noexcept { return towerX[axis]; }
float GetTowerY(size_t axis) const noexcept { return towerY[axis]; }
+protected:
+ DECLARE_OBJECT_MODEL
+ OBJECT_MODEL_ARRAY(towers)
+
private:
void Init() noexcept;
void Recalc() noexcept;
diff --git a/src/Movement/Kinematics/PolarKinematics.cpp b/src/Movement/Kinematics/PolarKinematics.cpp
index 578d37df..b8dffce6 100644
--- a/src/Movement/Kinematics/PolarKinematics.cpp
+++ b/src/Movement/Kinematics/PolarKinematics.cpp
@@ -13,6 +13,28 @@
#include "GCodes/GCodeBuffer/GCodeBuffer.h"
#include "Movement/DDA.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(PolarKinematics, __VA_ARGS__)
+
+constexpr ObjectModelTableEntry PolarKinematics::objectModelTable[] =
+{
+ // Within each group, these entries must be in alphabetical order
+ // 0. kinematics members
+ { "name", OBJECT_MODEL_FUNC(self->GetName(false)), ObjectModelEntryFlags::none },
+};
+
+constexpr uint8_t PolarKinematics::objectModelTableDescriptor[] = { 1, 1 };
+
+DEFINE_GET_OBJECT_MODEL_TABLE(PolarKinematics)
+
+#endif
+
// Constructor
PolarKinematics::PolarKinematics() noexcept
: Kinematics(KinematicsType::polar, DefaultSegmentsPerSecond, DefaultMinSegmentSize, true),
diff --git a/src/Movement/Kinematics/PolarKinematics.h b/src/Movement/Kinematics/PolarKinematics.h
index 811f2789..cbbac0a8 100644
--- a/src/Movement/Kinematics/PolarKinematics.h
+++ b/src/Movement/Kinematics/PolarKinematics.h
@@ -34,6 +34,9 @@ public:
bool IsContinuousRotationAxis(size_t axis) const noexcept override;
AxesBitmap GetLinearAxes() const noexcept override;
+protected:
+ DECLARE_OBJECT_MODEL
+
private:
static constexpr float DefaultSegmentsPerSecond = 100.0;
static constexpr float DefaultMinSegmentSize = 0.2;
diff --git a/src/Movement/Kinematics/RotaryDeltaKinematics.cpp b/src/Movement/Kinematics/RotaryDeltaKinematics.cpp
index 3f58c7c1..e6a1da3c 100644
--- a/src/Movement/Kinematics/RotaryDeltaKinematics.cpp
+++ b/src/Movement/Kinematics/RotaryDeltaKinematics.cpp
@@ -13,6 +13,28 @@
const float RotaryDeltaKinematics::NormalTowerAngles[DELTA_AXES] = { -150.0, -30.0, 90.0 };
+#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(RotaryDeltaKinematics, __VA_ARGS__)
+
+constexpr ObjectModelTableEntry RotaryDeltaKinematics::objectModelTable[] =
+{
+ // Within each group, these entries must be in alphabetical order
+ // 0. kinematics members
+ { "name", OBJECT_MODEL_FUNC(self->GetName(false)), ObjectModelEntryFlags::none },
+};
+
+constexpr uint8_t RotaryDeltaKinematics::objectModelTableDescriptor[] = { 1, 1 };
+
+DEFINE_GET_OBJECT_MODEL_TABLE(RotaryDeltaKinematics)
+
+#endif
+
// Constructor
RotaryDeltaKinematics::RotaryDeltaKinematics() noexcept : Kinematics(KinematicsType::rotaryDelta, DefaultSegmentsPerSecond, DefaultMinSegmentSize, false)
{
diff --git a/src/Movement/Kinematics/RotaryDeltaKinematics.h b/src/Movement/Kinematics/RotaryDeltaKinematics.h
index e2e80f38..8283c9c9 100644
--- a/src/Movement/Kinematics/RotaryDeltaKinematics.h
+++ b/src/Movement/Kinematics/RotaryDeltaKinematics.h
@@ -44,6 +44,9 @@ public:
void LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector, size_t numVisibleAxes, bool continuousRotationShortcut) const noexcept override;
AxesBitmap GetLinearAxes() const noexcept override;
+protected:
+ DECLARE_OBJECT_MODEL
+
private:
void Init() noexcept;
void Recalc() noexcept;
diff --git a/src/Movement/Kinematics/ScaraKinematics.cpp b/src/Movement/Kinematics/ScaraKinematics.cpp
index 156ecd1f..21deab11 100644
--- a/src/Movement/Kinematics/ScaraKinematics.cpp
+++ b/src/Movement/Kinematics/ScaraKinematics.cpp
@@ -14,6 +14,28 @@
#include <limits>
+#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(ScaraKinematics, __VA_ARGS__)
+
+constexpr ObjectModelTableEntry ScaraKinematics::objectModelTable[] =
+{
+ // Within each group, these entries must be in alphabetical order
+ // 0. kinematics members
+ { "name", OBJECT_MODEL_FUNC(self->GetName(false)), ObjectModelEntryFlags::none },
+};
+
+constexpr uint8_t ScaraKinematics::objectModelTableDescriptor[] = { 1, 1 };
+
+DEFINE_GET_OBJECT_MODEL_TABLE(ScaraKinematics)
+
+#endif
+
ScaraKinematics::ScaraKinematics() noexcept
: ZLeadscrewKinematics(KinematicsType::scara, DefaultSegmentsPerSecond, DefaultMinSegmentSize, true),
proximalArmLength(DefaultProximalArmLength), distalArmLength(DefaultDistalArmLength), xOffset(0.0), yOffset(0.0)
diff --git a/src/Movement/Kinematics/ScaraKinematics.h b/src/Movement/Kinematics/ScaraKinematics.h
index 9cba53f6..0bdbd644 100644
--- a/src/Movement/Kinematics/ScaraKinematics.h
+++ b/src/Movement/Kinematics/ScaraKinematics.h
@@ -45,6 +45,9 @@ public:
bool IsContinuousRotationAxis(size_t axis) const noexcept override;
AxesBitmap GetLinearAxes() const noexcept override;
+protected:
+ DECLARE_OBJECT_MODEL
+
private:
static constexpr float DefaultSegmentsPerSecond = 100.0;
static constexpr float DefaultMinSegmentSize = 0.2;
diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp
index 14600eff..3cc7ad00 100644
--- a/src/Movement/Move.cpp
+++ b/src/Movement/Move.cpp
@@ -79,10 +79,12 @@ constexpr ObjectModelTableEntry Move::objectModelTable[] =
{ "extruders", OBJECT_MODEL_FUNC_NOSELF(&extrudersArrayDescriptor), ObjectModelEntryFlags::none },
{ "idle", OBJECT_MODEL_FUNC(self, 2), ObjectModelEntryFlags::none },
{ "initialDeviation", OBJECT_MODEL_FUNC(self, 5), ObjectModelEntryFlags::none },
+ { "kinematics", OBJECT_MODEL_FUNC(self->kinematics), ObjectModelEntryFlags::none },
{ "meshDeviation", OBJECT_MODEL_FUNC(self, 6), ObjectModelEntryFlags::none },
{ "printingAcceleration", OBJECT_MODEL_FUNC(self->maxPrintingAcceleration, 1), ObjectModelEntryFlags::none },
{ "speedFactor", OBJECT_MODEL_FUNC_NOSELF(reprap.GetGCodes().GetSpeedFactor(), 1), ObjectModelEntryFlags::live },
{ "travelAcceleration", OBJECT_MODEL_FUNC(self->maxTravelAcceleration, 1), ObjectModelEntryFlags::none },
+ { "workspaceNumber", OBJECT_MODEL_FUNC_NOSELF((int32_t)reprap.GetGCodes().GetWorkplaceCoordinateSystemNumber()), ObjectModelEntryFlags::none },
// 1. Move.Daa members
{ "enabled", OBJECT_MODEL_FUNC(self->drcEnabled), ObjectModelEntryFlags::none },
@@ -112,7 +114,7 @@ constexpr ObjectModelTableEntry Move::objectModelTable[] =
{ "mean", OBJECT_MODEL_FUNC(self->latestMeshDeviation.GetMean(), 3), ObjectModelEntryFlags::none },
};
-constexpr uint8_t Move::objectModelTableDescriptor[] = { 7, 11, 3, 2, 4, 2, 2, 2 };
+constexpr uint8_t Move::objectModelTableDescriptor[] = { 7, 13, 3, 2, 4, 2, 2, 2 };
DEFINE_GET_OBJECT_MODEL_TABLE(Move)
@@ -160,7 +162,7 @@ void Move::Init() noexcept
simulationMode = 0;
longestGcodeWaitInterval = 0;
- bedLevellingMoveAvailable = false;
+ bedLevellingMoveAvailable = liveCoordinatesUpToDate = false;
active = true;
}
@@ -991,6 +993,19 @@ GCodeResult Move::ConfigureDynamicAcceleration(GCodeBuffer& gb, const StringRef&
return GCodeResult::ok;
}
+// Return the current live XYZ and extruder coordinates
+// Interrupts are assumed enabled on entry
+float Move::LiveCoordinate(unsigned int axisOrExtruder, const Tool *tool) noexcept
+{
+ if (!liveCoordinatesUpToDate)
+ {
+ mainDDARing.LiveCoordinates(latestLiveCoordinates);
+ InverseAxisAndBedTransform(latestLiveCoordinates, tool);
+ liveCoordinatesUpToDate = true;
+ }
+ return latestLiveCoordinates[axisOrExtruder];
+}
+
#if SUPPORT_LASER || SUPPORT_IOBITS
// Laser and IOBits support
diff --git a/src/Movement/Move.h b/src/Movement/Move.h
index de59f43d..0bcf1639 100644
--- a/src/Movement/Move.h
+++ b/src/Movement/Move.h
@@ -62,7 +62,7 @@ public:
void GetCurrentUserPosition(float m[MaxAxes], uint8_t moveType, const Tool *tool) const noexcept;
// Return the position (after all queued moves have been executed) in transformed coords
int32_t GetEndPoint(size_t drive) const noexcept; // Get the current position of a motor
- void LiveCoordinates(float m[MaxAxesPlusExtruders], const Tool *tool) noexcept; // Gives the last point at the end of the last complete DDA transformed to user coords
+ float LiveCoordinate(unsigned int axisOrExtruder, const Tool *tool) noexcept; // Gives the last point at the end of the last complete DDA
bool AllMovesAreFinished() noexcept; // Is the look-ahead ring empty? Stops more moves being added as well.
void DoLookAhead() noexcept __attribute__ ((hot)); // Run the look-ahead procedure
void SetNewPosition(const float positionNow[MaxAxesPlusExtruders], bool doBedCompensation) noexcept; // Set the current position to be this
@@ -252,18 +252,21 @@ private:
Deviation initialCalibrationDeviation;
Deviation latestMeshDeviation;
- bool usingMesh; // True if we are using the height map, false if we are using the random probe point set
- bool useTaper; // True to taper off the compensation
-
uint32_t idleTimeout; // How long we wait with no activity before we reduce motor currents to idle, in milliseconds
uint32_t lastStateChangeTime; // The approximate time at which the state last changed, except we don't record timing->idle
Kinematics *kinematics; // What kinematics we are using
+ StraightProbeSettings straightProbeSettings; // G38 straight probe settings
+
+ float latestLiveCoordinates[MaxAxesPlusExtruders];
float specialMoveCoords[MaxDriversPerAxis]; // Amounts by which to move individual Z motors (leadscrew adjustment move)
+
bool bedLevellingMoveAvailable; // True if a leadscrew adjustment move is pending
+ bool liveCoordinatesUpToDate;
+ bool usingMesh; // True if we are using the height map, false if we are using the random probe point set
+ bool useTaper; // True to taper off the compensation
- StraightProbeSettings straightProbeSettings; // G38 straight probe settings
#if SUPPORT_LASER || SUPPORT_IOBITS
static constexpr size_t LaserTaskStackWords = 100; // stack size in dwords for the laser and IOBits task
@@ -292,14 +295,6 @@ inline void Move::AdjustMotorPositions(const float adjustment[], size_t numMotor
mainDDARing.AdjustMotorPositions(adjustment, numMotors);
}
-// Return the current live XYZ and extruder coordinates
-// Interrupts are assumed enabled on entry
-inline void Move::LiveCoordinates(float m[MaxAxesPlusExtruders], const Tool *tool) noexcept
-{
- mainDDARing.LiveCoordinates(m);
- InverseAxisAndBedTransform(m, tool);
-}
-
// These are the actual numbers that we want to be the coordinates, so don't transform them.
// The caller must make sure that no moves are in progress or pending when calling this
inline void Move::SetLiveCoordinates(const float coords[MaxAxesPlusExtruders]) noexcept
diff --git a/src/ObjectModel/ObjectModel.cpp b/src/ObjectModel/ObjectModel.cpp
index 7cd35a93..fc9a096a 100644
--- a/src/ObjectModel/ObjectModel.cpp
+++ b/src/ObjectModel/ObjectModel.cpp
@@ -14,14 +14,6 @@
#include <cstring>
#include <General/SafeStrtod.h>
-// Get the format string to use assuming this is a floating point number
-const char *ExpressionValue::GetFloatFormatString() const noexcept
-{
- static constexpr const char *FormatStrings[] = { "%.7f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f", "%.6f", "%.7f" };
- static_assert(ARRAY_SIZE(FormatStrings) == MaxFloatDigitsDisplayedAfterPoint + 1);
- return FormatStrings[min<unsigned int>(param, MaxFloatDigitsDisplayedAfterPoint)];
-}
-
void ObjectExplorationContext::AddIndex(int32_t index)
{
if (numIndicesCounted == MaxIndices)
@@ -244,7 +236,14 @@ void ObjectModel::ReportItemAsJson(OutputBuffer *buf, ObjectExplorationContext&
break;
case TYPE_OF(float):
- buf->catf(val.GetFloatFormatString(), (double)val.fVal);
+ if (val.fVal == 0.0)
+ {
+ buf->cat('0'); // replace 0.000... in JSON by 0. This is mostly to save space when writing workplace coordinates.
+ }
+ else
+ {
+ buf->catf(val.GetFloatFormatString(), (double)val.fVal);
+ }
break;
case TYPE_OF(uint32_t):
diff --git a/src/ObjectModel/ObjectModel.h b/src/ObjectModel/ObjectModel.h
index 3d73d7d9..ad404be4 100644
--- a/src/ObjectModel/ObjectModel.h
+++ b/src/ObjectModel/ObjectModel.h
@@ -109,7 +109,7 @@ struct ExpressionValue
uint64_t Get56BitValue() const noexcept { return ((uint64_t)param << 32) | uVal; }
// Get the format string to use assuming this is a floating point number
- const char *GetFloatFormatString() const noexcept;
+ const char *GetFloatFormatString() const noexcept { return ::GetFloatFormatString(param); }
};
// Flags field of a table entry
@@ -263,6 +263,9 @@ public:
static const ObjectModelTableEntry objectModelTable[]; \
static const uint8_t objectModelTableDescriptor[];
+#define DECLARE_OBJECT_MODEL_VIRTUAL \
+ virtual const ObjectModelTableEntry *GetObjectModelTable(const uint8_t*& descriptor) const noexcept override = 0;
+
#define DESCRIPTOR_OK(_class) (ARRAY_SIZE(_class::objectModelTableDescriptor) == _class::objectModelTableDescriptor[0] + 1)
#define OMT_SIZE_OK(_class) (ARRAY_SIZE(_class::objectModelTable) == ArraySum(_class::objectModelTableDescriptor + 1, ARRAY_SIZE(_class::objectModelTableDescriptor) - 1))
#define OMT_ORDERING_OK(_class) (ObjectModelTableEntry::IsOrdered(_class::objectModelTableDescriptor, _class::objectModelTable))
@@ -288,6 +291,7 @@ public:
#define INHERIT_OBJECT_MODEL // nothing
#define DECLARE_OBJECT_MODEL // nothing
+#define DECLARE_OBJECT_MODEL_VIRTUAL // nothing
#define DEFINE_GET_OBJECT_MODEL_TABLE // nothing
#define OBJECT_MODEL_ARRAY(_name) // nothing
diff --git a/src/Platform.cpp b/src/Platform.cpp
index 7be8d693..eee1e2c6 100644
--- a/src/Platform.cpp
+++ b/src/Platform.cpp
@@ -202,6 +202,14 @@ constexpr ObjectModelArrayDescriptor Platform::axisDriversArrayDescriptor =
{ return ExpressionValue(((const Platform*)self)->axisDrivers[context.GetIndex(1)].driverNumbers[context.GetLastIndex()]); }
};
+constexpr ObjectModelArrayDescriptor Platform::workplaceOffsetsArrayDescriptor =
+{
+ nullptr, // no lock needed
+ [] (const ObjectModel *self, const ObjectExplorationContext& context) noexcept -> size_t { return NumCoordinateSystems; },
+ [] (const ObjectModel *self, ObjectExplorationContext& context) noexcept -> ExpressionValue
+ { return ExpressionValue(reprap.GetGCodes().GetWorkplaceOffset(context.GetIndex(1), context.GetIndex(0)), 3); }
+};
+
constexpr ObjectModelTableEntry Platform::objectModelTable[] =
{
// 0. boards[] members
@@ -242,11 +250,13 @@ constexpr ObjectModelTableEntry Platform::objectModelTable[] =
{ "homed", OBJECT_MODEL_FUNC_NOSELF(reprap.GetGCodes().IsAxisHomed(context.GetLastIndex())), ObjectModelEntryFlags::live },
{ "jerk", OBJECT_MODEL_FUNC(MinutesToSeconds * self->GetInstantDv(context.GetLastIndex()), 1), ObjectModelEntryFlags::none },
{ "letter", OBJECT_MODEL_FUNC_NOSELF(reprap.GetGCodes().GetAxisLetters()[context.GetLastIndex()]), ObjectModelEntryFlags::none },
+ { "machinePosition", OBJECT_MODEL_FUNC_NOSELF(reprap.GetMove().LiveCoordinate(context.GetLastIndex(), reprap.GetCurrentTool()), 3), ObjectModelEntryFlags::live },
{ "max", OBJECT_MODEL_FUNC(self->AxisMaximum(context.GetLastIndex()), 1), ObjectModelEntryFlags::none },
{ "min", OBJECT_MODEL_FUNC(self->AxisMinimum(context.GetLastIndex()), 1), ObjectModelEntryFlags::none },
{ "speed", OBJECT_MODEL_FUNC(MinutesToSeconds * self->MaxFeedrate(context.GetLastIndex()), 1), 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 },
+ { "workplaceOffsets", OBJECT_MODEL_FUNC_NOSELF(&workplaceOffsetsArrayDescriptor), ObjectModelEntryFlags::none },
// 4. move.extruders[] members
{ "driver", OBJECT_MODEL_FUNC(self->extruderDrivers[context.GetLastIndex()]), ObjectModelEntryFlags::none },
@@ -274,7 +284,7 @@ constexpr uint8_t Platform::objectModelTableDescriptor[] =
9 + HAS_LINUX_INTERFACE + HAS_12V_MONITOR, // section 0: boards[]
3, // section 1: mcuTemp
3, // section 2: vIn
- 10, // section 3: move.axes[]
+ 12, // section 3: move.axes[]
4, // section 4: move.extruders[]
3, // section 5: move.extruders[].nonlinear
#if HAS_12V_MONITOR
@@ -1236,9 +1246,7 @@ void Platform::Spin() noexcept
String<StringLength100> scratchString;
ListDrivers(scratchString.GetRef(), stalledDriversToLog);
stalledDriversToLog.Clear();
- float liveCoordinates[MaxAxesPlusExtruders];
- reprap.GetMove().LiveCoordinates(liveCoordinates, reprap.GetCurrentTool());
- MessageF(WarningMessage, "Driver(s)%s stalled at Z height %.2f", scratchString.c_str(), (double)liveCoordinates[Z_AXIS]);
+ MessageF(WarningMessage, "Driver(s)%s stalled at Z height %.2f", scratchString.c_str(), (double)reprap.GetMove().LiveCoordinate(Z_AXIS, reprap.GetCurrentTool()));
reported = true;
}
#endif
diff --git a/src/Platform.h b/src/Platform.h
index 7f387070..220ddd28 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -558,6 +558,7 @@ public:
protected:
DECLARE_OBJECT_MODEL
OBJECT_MODEL_ARRAY(axisDrivers)
+ OBJECT_MODEL_ARRAY(workplaceOffsets)
private:
const char* InternalGetSysDir() const noexcept; // where the system files are - not thread-safe!
diff --git a/src/RepRap.cpp b/src/RepRap.cpp
index fb8c34fb..a4f3240f 100644
--- a/src/RepRap.cpp
+++ b/src/RepRap.cpp
@@ -1006,19 +1006,11 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
}
// Machine status
- char ch = GetStatusCharacter();
- response->printf("{\"status\":\"%c\",\"coords\":{", ch);
+ response->printf("{\"status\":\"%c\",\"coords\":{", GetStatusCharacter());
- // Coordinates
- const size_t numVisibleAxes = gCodes->GetVisibleAxes();
// Homed axes
- response->cat("\"axesHomed\":");
- ch = '[';
- for (size_t axis = 0; axis < numVisibleAxes; ++axis)
- {
- response->catf("%c%d", ch, (gCodes->IsAxisHomed(axis)) ? 1 : 0);
- ch = ',';
- }
+ const size_t numVisibleAxes = gCodes->GetVisibleAxes();
+ AppendIntArray(response, "axesHomed", numVisibleAxes, [this](size_t axis) noexcept { return (gCodes->IsAxisHomed(axis)) ? 1 : 0; });
// XYZ positions
// Coordinates may be NaNs or infinities, for example when delta or SCARA homing fails. We must replace any NaNs or infinities to avoid JSON parsing errors.
@@ -1027,57 +1019,23 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
// First the user coordinates
#if SUPPORT_WORKPLACE_COORDINATES
- response->catf("],\"wpl\":%u,\"xyz\":", gCodes->GetWorkplaceCoordinateSystemNumber());
+ response->catf(",\"wpl\":%u,", gCodes->GetWorkplaceCoordinateSystemNumber());
#else
- response->cat("],\"xyz\":");
+ response->cat(',');
#endif
- ch = '[';
- for (size_t axis = 0; axis < numVisibleAxes; axis++)
- {
- response->catf("%c%.3f", ch, HideNan(gCodes->GetUserCoordinate(axis)));
- ch = ',';
- }
- // Now the machine coordinates and the extruder coordinates
- {
- float liveCoordinates[MaxAxesPlusExtruders];
-#if SUPPORT_ROLAND
- if (roland->Active())
- {
- roland->GetCurrentRolandPosition(liveCoordinates);
- }
- else
-#endif
- {
- move->LiveCoordinates(liveCoordinates, currentTool);
- }
+ AppendFloatArray(response, "xyz", numVisibleAxes, [this](size_t axis) noexcept { return gCodes->GetUserCoordinate(axis); }, 3);
- // Machine coordinates
- response->catf("],\"machine\":"); // announce the machine position
- ch = '[';
- for (size_t drive = 0; drive < numVisibleAxes; drive++)
- {
- response->catf("%c%.3f", ch, HideNan(liveCoordinates[drive]));
- ch = ',';
- }
+ // Machine coordinates
+ response->cat(',');
+ AppendFloatArray(response, "machine", numVisibleAxes, [this](size_t axis) noexcept { return move->LiveCoordinate(axis, currentTool); }, 3);
- // Actual and theoretical extruder positions since power up, last G92 or last M23
- response->catf("],\"extr\":"); // announce actual extruder positions
- ch = '[';
- for (size_t extruder = 0; extruder < GetExtrudersInUse(); extruder++)
- {
- response->catf("%c%.1f", ch, HideNan(liveCoordinates[ExtruderToLogicalDrive(extruder)]));
- ch = ',';
- }
- if (ch == '[') // we may have no extruders
- {
- response->cat(ch);
- }
- }
+ // Actual extruder positions since power up, last G92 or last M23
+ response->cat(',');
+ AppendFloatArray(response, "extr", GetExtrudersInUse(), [this](size_t extruder) noexcept { return move->LiveCoordinate(ExtruderToLogicalDrive(extruder), currentTool); }, 1);
// Current speeds
- response->catf("]},\"speeds\":{\"requested\":%.1f,\"top\":%.1f}",
- (double)move->GetRequestedSpeed(), (double)move->GetTopSpeed());
+ response->catf("},\"speeds\":{\"requested\":%.1f,\"top\":%.1f}", (double)move->GetRequestedSpeed(), (double)move->GetTopSpeed());
// Current tool number
response->catf(",\"currentTool\":%d", GetCurrentToolNumber());
@@ -1141,42 +1099,27 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
// Parameters
{
// Cooling fan values
+ response->cat(',');
const size_t numFans = fansManager->GetNumFansToReport();
- response->cat(",\"fanPercent\":");
- ch = '[';
- for (size_t i = 0; i < numFans; i++)
- {
- const float fanValue = fansManager->GetFanValue(i);
- response->catf("%c%d", ch, (fanValue < 0.0) ? -1 : (int)lrintf(fanValue * 100.0));
- ch = ',';
- }
- response->cat((ch == '[') ? "[]" : "]");
+ AppendIntArray(response, "fanPercent", numFans,
+ [this](size_t fan) noexcept
+ {
+ const float fanValue = fansManager->GetFanValue(fan);
+ return (fanValue < 0.0) ? -1 : (int)lrintf(fanValue * 100.0);
+ });
// Cooling fan names
if (type == 2)
{
- response->cat(",\"fanNames\":");
- ch = '[';
- for (size_t fan = 0; fan < numFans; fan++)
- {
- response->cat(ch);
- ch = ',';
-
- const char *fanName = fansManager->GetFanName(fan);
- response->EncodeString(fanName, true);
- }
- response->cat((ch == '[') ? "[]" : "]");
+ response->cat(',');
+ AppendStringArray(response, "fanNames", numFans, [this](size_t fan) noexcept { return fansManager->GetFanName(fan); });
}
// Speed and Extrusion factors in %
- response->catf(",\"speedFactor\":%.1f,\"extrFactors\":", (double)(gCodes->GetSpeedFactor()));
- ch = '[';
- for (size_t extruder = 0; extruder < GetExtrudersInUse(); extruder++)
- {
- response->catf("%c%.1f", ch, (double)(gCodes->GetExtrusionFactor(extruder)));
- ch = ',';
- }
- response->cat((ch == '[') ? "[]" : "]");
+ response->catf(",\"speedFactor\":%.1f,", (double)(gCodes->GetSpeedFactor()));
+ AppendFloatArray(response, "extrFactors", GetExtrudersInUse(), [this](size_t extruder) noexcept { return gCodes->GetExtrusionFactor(extruder); }, 1);
+
+ // Z babystepping
response->catf(",\"babystep\":%.3f}", (double)gCodes->GetTotalBabyStepOffset(Z_AXIS));
// G-code reply sequence for webserver (sequence number for AUX is handled later)
@@ -1195,22 +1138,16 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
switch (zp->GetSecondaryValues(v1))
{
case 1:
- response->catf("\"probeValue\":%d,\"probeSecondary\":[%d]", v0, v1);
+ response->catf("\"probeValue\":%d,\"probeSecondary\":[%d],", v0, v1);
break;
default:
- response->catf("\"probeValue\":%d", v0);
+ response->catf("\"probeValue\":%d,", v0);
break;
}
// Send fan RPM value(s)
- response->cat(",\"fanRPM\":");
- char ch = '[';
- for (size_t i = 0; i < numFans; ++i)
- {
- response->catf("%c%" PRIi32, ch, fansManager->GetFanRPM(i));
- ch = ',';
- }
- response->cat("]}"); // end fan RPMs and sensors
+ AppendIntArray(response, "fanRPM", numFans, [this](size_t fan) noexcept { return (int)fansManager->GetFanRPM(fan); });
+ response->cat('}');
}
/* Temperatures */
@@ -1247,39 +1184,19 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
/* Heaters */
// Current temperatures
- response->cat("\"current\":");
- ch = '[';
{
const size_t numHeaters = heat->GetNumHeatersToReport();
- for (size_t heater = 0; heater < numHeaters; heater++)
- {
- response->catf("%c%.1f", ch, (double)heat->GetHeaterTemperature(heater));
- ch = ',';
- }
- response->cat((ch == '[') ? "[]" : "]");
+ AppendFloatArray(response, "current", numHeaters, [this](size_t heater) noexcept { return heat->GetHeaterTemperature(heater); }, 1);
// Current states
- response->cat(",\"state\":");
- ch = '[';
- for (size_t heater = 0; heater < numHeaters; heater++)
- {
- response->catf("%c%u", ch, heat->GetStatus(heater).ToBaseType());
- ch = ',';
- }
- response->cat((ch == '[') ? "[]" : "]");
+ response->cat(',');
+ AppendIntArray(response, "state", numHeaters, [this](size_t heater) noexcept { return (int)heat->GetStatus(heater).ToBaseType(); });
// Names of the sensors use to control heaters
if (type == 2)
{
- response->cat(",\"names\":");
- ch = '[';
- for (size_t heater = 0; heater < numHeaters; heater++)
- {
- response->cat(ch);
- ch = ',';
- response->EncodeString(GetHeat().GetHeaterSensorName(heater), true);
- }
- response->cat((ch == '[') ? "[]" : "]");
+ response->cat(',');
+ AppendStringArray(response, "names", numHeaters, [this](size_t heater) noexcept { return heat->GetHeaterSensorName(heater); });
}
}
@@ -1289,14 +1206,7 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
ReadLocker lock(toolListLock);
for (const Tool *tool = toolList; tool != nullptr; tool = tool->Next())
{
- ch = '[';
- for (size_t heater = 0; heater < tool->heaterCount; heater++)
- {
- response->catf("%c%.1f", ch, (double)tool->activeTemperatures[heater]);
- ch = ',';
- }
- response->cat((ch == '[') ? "[]" : "]");
-
+ AppendFloatArray(response, nullptr, tool->heaterCount, [tool](unsigned int n) noexcept { return tool->activeTemperatures[n]; }, 1);
if (tool->Next() != nullptr)
{
response->cat(',');
@@ -1306,14 +1216,7 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
response->cat("],\"standby\":[");
for (const Tool *tool = toolList; tool != nullptr; tool = tool->Next())
{
- ch = '[';
- for (size_t heater = 0; heater < tool->heaterCount; heater++)
- {
- response->catf("%c%.1f", ch, (double)tool->standbyTemperatures[heater]);
- ch = ',';
- }
- response->cat((ch == '[') ? "[]" : "]");
-
+ AppendFloatArray(response, nullptr, tool->heaterCount, [tool](unsigned int n) noexcept { return tool->standbyTemperatures[n]; }, 1);
if (tool->Next() != nullptr)
{
response->cat(',');
@@ -1368,21 +1271,18 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
// Spindles
if (gCodes->GetMachineType() == MachineType::cnc || type == 2)
{
- int lastConfiguredSpindle = -1;
- for (size_t spindle = 0; spindle < MaxSpindles; spindle++)
+ size_t numSpindles = MaxSpindles;
+ while (numSpindles != 0 && platform->AccessSpindle(numSpindles - 1).GetToolNumber() == -1)
{
- if (platform->AccessSpindle(spindle).GetToolNumber() != -1)
- {
- lastConfiguredSpindle = spindle;
- }
+ --numSpindles;
}
- if (lastConfiguredSpindle != -1)
+ if (numSpindles != 0)
{
response->cat(",\"spindles\":[");
- for (int i = 0; i <= lastConfiguredSpindle; i++)
+ for (size_t i = 0; i < numSpindles; i++)
{
- if (i > 0)
+ if (i != 0)
{
response->cat(',');
}
@@ -1497,40 +1397,26 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
for (Tool *tool = toolList; tool != nullptr; tool = tool->Next())
{
// Number
- response->catf("{\"number\":%d", tool->Number());
+ response->catf("{\"number\":%d,", tool->Number());
// Name
const char *toolName = tool->GetName();
if (toolName[0] != 0)
{
- response->cat(",\"name\":");
+ response->cat("\"name\":");
response->EncodeString(toolName, false);
+ response->cat(',');
}
// Heaters
- response->cat(",\"heaters\":[");
- for (size_t heater = 0; heater < tool->HeaterCount(); heater++)
- {
- response->catf("%d", tool->Heater(heater));
- if (heater + 1 < tool->HeaterCount())
- {
- response->cat(',');
- }
- }
+ AppendIntArray(response, "heaters", tool->HeaterCount(), [tool](size_t heater) noexcept { return tool->Heater(heater); });
// Extruder drives
- response->cat("],\"drives\":[");
- for (size_t drive = 0; drive < tool->DriveCount(); drive++)
- {
- response->catf("%d", tool->Drive(drive));
- if (drive + 1 < tool->DriveCount())
- {
- response->cat(',');
- }
- }
+ response->cat(',');
+ AppendIntArray(response, "drives", tool->DriveCount(), [tool](size_t drive) noexcept { return tool->Drive(drive); });
// Axis mapping
- response->cat("],\"axisMap\":[[");
+ response->cat(",\"axisMap\":[[");
tool->GetXAxisMap().Iterate
([&response](unsigned int xi, bool first) noexcept
{
@@ -1567,14 +1453,11 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
}
// Offsets
- response->cat(",\"offsets\":[");
- for (size_t i = 0; i < numVisibleAxes; i++)
- {
- response->catf((i == 0) ? "%.2f" : ",%.2f", (double)tool->GetOffset(i));
- }
+ response->cat(',');
+ AppendFloatArray(response, "offsets", numVisibleAxes, [tool](size_t axis) noexcept { return tool->GetOffset(axis); }, 2);
// Do we have any more tools?
- response->cat((tool->Next() != nullptr) ? "]}," : "]}");
+ response->cat((tool->Next() != nullptr) ? "}," : "}");
}
response->cat(']');
}
@@ -1609,23 +1492,13 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
response->catf(",\"currentLayer\":%d", printMonitor->GetCurrentLayer());
// Current Layer Time
- response->catf(",\"currentLayerTime\":%.1f", (double)(printMonitor->GetCurrentLayerTime()));
+ response->catf(",\"currentLayerTime\":%.1f,", (double)(printMonitor->GetCurrentLayerTime()));
// Raw Extruder Positions
- response->cat(",\"extrRaw\":");
- ch = '[';
- for (size_t extruder = 0; extruder < GetExtrudersInUse(); extruder++) // loop through extruders
- {
- response->catf("%c%.1f", ch, (double)(gCodes->GetRawExtruderTotalByDrive(extruder)));
- ch = ',';
- }
- if (ch == '[')
- {
- response->cat(ch); // no extruders
- }
+ AppendFloatArray(response, "extrRaw", GetExtrudersInUse(), [this](size_t extruder) noexcept { return gCodes->GetRawExtruderTotalByDrive(extruder); }, 1);
// Fraction of file printed
- response->catf("],\"fractionPrinted\":%.1f", (double)((printMonitor->IsPrinting()) ? (printMonitor->FractionOfFilePrinted() * 100.0) : 0.0));
+ response->catf(",\"fractionPrinted\":%.1f", (double)((printMonitor->IsPrinting()) ? (printMonitor->FractionOfFilePrinted() * 100.0) : 0.0));
// Byte position of the file being printed
response->catf(",\"filePosition\":%lu", gCodes->GetFilePosition());
@@ -1646,13 +1519,10 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) noe
/* Print Time Estimations */
{
// Based on file progress
- response->catf(",\"timesLeft\":{\"file\":%.1f", (double)(printMonitor->EstimateTimeLeft(fileBased)));
-
- // Based on filament usage
- response->catf(",\"filament\":%.1f", (double)(printMonitor->EstimateTimeLeft(filamentBased)));
-
- // Based on layers
- response->catf(",\"layer\":%.1f}", (double)(printMonitor->EstimateTimeLeft(layerBased)));
+ response->catf(",\"timesLeft\":{\"file\":%.1f,\"filament\":%.1f,\"layer\":%.1f}",
+ (double)(printMonitor->EstimateTimeLeft(fileBased)),
+ (double)(printMonitor->EstimateTimeLeft(filamentBased)),
+ (double)(printMonitor->EstimateTimeLeft(layerBased)));
}
}
@@ -1690,43 +1560,23 @@ OutputBuffer *RepRap::GetConfigResponse() noexcept
const size_t numAxes = gCodes->GetVisibleAxes();
// Axis minima
- response->copy("{\"axisMins\":");
- char ch = '[';
- for (size_t axis = 0; axis < numAxes; axis++)
- {
- response->catf("%c%.2f", ch, (double)(platform->AxisMinimum(axis)));
- ch = ',';
- }
+ response->copy('{');
+ AppendFloatArray(response, "axisMins", numAxes, [this](size_t axis) noexcept { return platform->AxisMinimum(axis); }, 2);
// Axis maxima
- response->cat("],\"axisMaxes\":");
- ch = '[';
- for (size_t axis = 0; axis < numAxes; axis++)
- {
- response->catf("%c%.2f", ch, (double)(platform->AxisMaximum(axis)));
- ch = ',';
- }
+ response->cat(',');
+ AppendFloatArray(response, "axisMaxes", numAxes, [this](size_t axis) noexcept { return platform->AxisMaximum(axis); }, 2);
// Accelerations
- response->cat("],\"accelerations\":");
- ch = '[';
- for (size_t drive = 0; drive < MaxAxesPlusExtruders; drive++)
- {
- response->catf("%c%.2f", ch, (double)(platform->Acceleration(drive)));
- ch = ',';
- }
+ response->cat(',');
+ AppendFloatArray(response, "accelerations", MaxAxesPlusExtruders, [this](size_t drive) noexcept { return platform->Acceleration(drive); }, 2);
// Motor currents
- response->cat("],\"currents\":");
- ch = '[';
- for (size_t drive = 0; drive < MaxAxesPlusExtruders; drive++)
- {
- response->catf("%c%d", ch, (int)platform->GetMotorCurrent(drive, 906));
- ch = ',';
- }
+ response->cat(',');
+ AppendIntArray(response, "currents", MaxAxesPlusExtruders, [this](size_t drive) noexcept { return (int)platform->GetMotorCurrent(drive, 906); });
// Firmware details
- response->catf("],\"firmwareElectronics\":\"%s", platform->GetElectronicsString());
+ response->catf(",\"firmwareElectronics\":\"%s", platform->GetElectronicsString());
#ifdef DUET_NG
const char* expansionName = DuetExpansion::GetExpansionBoardName();
if (expansionName != nullptr)
@@ -1774,28 +1624,17 @@ OutputBuffer *RepRap::GetConfigResponse() noexcept
// Motor idle parameters
response->catf(",\"idleCurrentFactor\":%.1f", (double)(platform->GetIdleCurrentFactor() * 100.0));
- response->catf(",\"idleTimeout\":%.1f", (double)(move->IdleTimeout()));
+ response->catf(",\"idleTimeout\":%.1f,", (double)(move->IdleTimeout()));
// Minimum feedrates
- response->cat(",\"minFeedrates\":");
- ch = '[';
- for (size_t drive = 0; drive < MaxAxesPlusExtruders; drive++)
- {
- response->catf("%c%.2f", ch, (double)(platform->GetInstantDv(drive)));
- ch = ',';
- }
+ AppendFloatArray(response, "minFeedrates", MaxAxesPlusExtruders, [this](size_t drive) noexcept { return platform->GetInstantDv(drive); }, 2);
// Maximum feedrates
- response->cat("],\"maxFeedrates\":");
- ch = '[';
- for (size_t drive = 0; drive < MaxAxesPlusExtruders; drive++)
- {
- response->catf("%c%.2f", ch, (double)(platform->MaxFeedrate(drive)));
- ch = ',';
- }
+ response->cat(',');
+ AppendFloatArray(response, "maxFeedrates", MaxAxesPlusExtruders, [this](size_t drive) noexcept { return platform->MaxFeedrate(drive); }, 2);
// Config file is no longer included, because we can use rr_configfile or M503 instead
- response->cat("]}");
+ response->cat('}');
return response;
}
@@ -1861,41 +1700,19 @@ OutputBuffer *RepRap::GetLegacyStatusResponse(uint8_t type, int seq) noexcept
{
response->catf(",%u", heat->GetStatus(heater).ToBaseType());
}
- response->cat(']');
+ response->cat("],");
- // Send XYZ positions
+ // User coordinates
const size_t numVisibleAxes = gCodes->GetVisibleAxes();
+ AppendFloatArray(response, "pos", numVisibleAxes, [this](size_t axis) noexcept { return gCodes->GetUserCoordinate(axis); }, 3);
- // First the user coordinates
- response->catf(",\"pos\":"); // announce the user position
- ch = '[';
- for (size_t axis = 0; axis < numVisibleAxes; axis++)
- {
- // Coordinates may be NaNs, for example when delta or SCARA homing fails. Replace any NaNs or infinities by 9999.9 to prevent JSON parsing errors.
- response->catf("%c%.3f", ch, HideNan(gCodes->GetUserCoordinate(axis)));
- ch = ',';
- }
-
- // Now the machine coordinates
- float liveCoordinates[MaxAxesPlusExtruders];
- move->LiveCoordinates(liveCoordinates, currentTool);
- response->catf("],\"machine\":"); // announce the machine position
- ch = '[';
- for (size_t drive = 0; drive < numVisibleAxes; drive++)
- {
- response->catf("%c%.3f", ch, HideNan(liveCoordinates[drive]));
- ch = ',';
- }
+ // Machine coordinates
+ response->cat(',');
+ AppendFloatArray(response, "machine", numVisibleAxes, [this](size_t axis) noexcept { return move->LiveCoordinate(axis, currentTool); }, 3);
// Send the speed and extruder override factors
- response->catf("],\"sfactor\":%.2f,\"efactor\":", (double)(gCodes->GetSpeedFactor()));
- ch = '[';
- for (size_t i = 0; i < GetExtrudersInUse(); ++i)
- {
- response->catf("%c%.2f", ch, (double)(gCodes->GetExtrusionFactor(i)));
- ch = ',';
- }
- response->cat((ch == '[') ? "[]" : "]");
+ response->catf(",\"sfactor\":%.2f,", (double)(gCodes->GetSpeedFactor()));
+ AppendFloatArray(response, "efactor", GetExtrudersInUse(), [this](size_t extruder) noexcept { return gCodes->GetExtrusionFactor(extruder); }, 2);
// Send the baby stepping offset
response->catf(",\"babystep\":%.03f", (double)(gCodes->GetTotalBabyStepOffset(Z_AXIS)));
@@ -1925,27 +1742,14 @@ OutputBuffer *RepRap::GetLegacyStatusResponse(uint8_t type, int seq) noexcept
const float fanValue = fansManager->GetFanValue(i);
response->catf(",%d", (fanValue < 0.0) ? -1 : (int)lrintf(fanValue * 100.0));
}
- response->cat(']');
+ response->cat("],");
// Send fan RPM value(s)
- response->cat(",\"fanRPM\":");
- ch = '[';
- for (size_t i = 0; i < MaxFans; ++i)
- {
- response->catf("%c%" PRIi32, ch, fansManager->GetFanRPM(i));
- ch = ',';
- }
- response->cat(']');
+ AppendIntArray(response, "fanRPM", fansManager->GetNumFansToReport(), [this](size_t fan) { return (int)fansManager->GetFanRPM(fan);});
// Send the home state. To keep the messages short, we send 1 for homed and 0 for not homed, instead of true and false.
- response->cat(",\"homed\":");
- ch = '[';
- for (size_t axis = 0; axis < numVisibleAxes; ++axis)
- {
- response->catf("%c%d", ch, (gCodes->IsAxisHomed(axis)) ? 1 : 0);
- ch = ',';
- }
- response->cat(']');
+ response->cat(',');
+ AppendIntArray(response, "homed", numVisibleAxes, [this](size_t axis) noexcept { return (gCodes->IsAxisHomed(axis)) ? 1 : 0; });
if (printMonitor->IsPrinting())
{
@@ -2276,6 +2080,62 @@ bool RepRap::GetFileInfoResponse(const char *filename, OutputBuffer *&response,
return true;
}
+// Helper functions to write JSON arrays
+// Append float array using 1 decimal place
+void RepRap::AppendFloatArray(OutputBuffer *buf, const char *name, size_t numValues, std::function<float(size_t)> func, unsigned int numDecimalDigits)
+{
+ if (name != nullptr)
+ {
+ buf->catf("\"%s\":", name);
+ }
+ buf->cat('[');
+ for (size_t i = 0; i < numValues; ++i)
+ {
+ if (i != 0)
+ {
+ buf->cat(',');
+ }
+ buf->catf(GetFloatFormatString(numDecimalDigits), HideNan(func(i)));
+ }
+ buf->cat(']');
+}
+
+void RepRap::AppendIntArray(OutputBuffer *buf, const char *name, size_t numValues, std::function<int(size_t)> func)
+{
+ if (name != nullptr)
+ {
+ buf->catf("\"%s\":", name);
+ }
+ buf->cat('[');
+ for (size_t i = 0; i < numValues; ++i)
+ {
+ if (i != 0)
+ {
+ buf->cat(',');
+ }
+ buf->catf("%d", func(i));
+ }
+ buf->cat(']');
+}
+
+void RepRap::AppendStringArray(OutputBuffer *buf, const char *name, size_t numValues, std::function<const char *(size_t)> func)
+{
+ if (name != nullptr)
+ {
+ buf->catf("\"%s\":", name);
+ }
+ buf->cat('[');
+ for (size_t i = 0; i < numValues; ++i)
+ {
+ if (i != 0)
+ {
+ buf->cat(',');
+ }
+ buf->EncodeString(func(i), true);
+ }
+ buf->cat(']');
+}
+
#if SUPPORT_OBJECT_MODEL
// Return a query into the object model, or return nullptr if no buffer available
diff --git a/src/RepRap.h b/src/RepRap.h
index 6993bd2f..a4c15066 100644
--- a/src/RepRap.h
+++ b/src/RepRap.h
@@ -29,6 +29,7 @@ Licence: GPL
#include "Fans/FansManager.h"
#include "Tools/Tool.h"
#include "SoftwareReset.h"
+#include <functional>
enum class ResponseSource
{
@@ -175,6 +176,9 @@ protected:
private:
static void EncodeString(StringRef& response, const char* src, size_t spaceToLeave, bool allowControlChars = false, char prefix = 0) noexcept;
+ static void AppendFloatArray(OutputBuffer *buf, const char *name, size_t numValues, std::function<float(size_t)> func, unsigned int numDecimalDigits);
+ static void AppendIntArray(OutputBuffer *buf, const char *name, size_t numValues, std::function<int(size_t)> func);
+ static void AppendStringArray(OutputBuffer *buf, const char *name, size_t numValues, std::function<const char *(size_t)> func);
size_t GetStatusIndex() const noexcept;
char GetStatusCharacter() const noexcept;
diff --git a/src/RepRapFirmware.cpp b/src/RepRapFirmware.cpp
index c01fea1f..3e17f4f0 100644
--- a/src/RepRapFirmware.cpp
+++ b/src/RepRapFirmware.cpp
@@ -172,6 +172,14 @@ Licence: GPL
RepRap reprap;
+// Get the format string to use for printing a floating point number to the specified number of decimal digits. Zero means the maximum sensible number.
+const char *GetFloatFormatString(unsigned int numDigitsAfterPoint) noexcept
+{
+ static constexpr const char *FormatStrings[] = { "%.7f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f", "%.6f", "%.7f" };
+ static_assert(ARRAY_SIZE(FormatStrings) == MaxFloatDigitsDisplayedAfterPoint + 1);
+ return FormatStrings[min<unsigned int>(numDigitsAfterPoint, MaxFloatDigitsDisplayedAfterPoint)];
+}
+
static const char * const moduleName[] =
{
"Platform",
diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h
index 5fab76eb..6bf9e952 100644
--- a/src/RepRapFirmware.h
+++ b/src/RepRapFirmware.h
@@ -439,6 +439,13 @@ constexpr float DegreesToRadians = 3.141592653589793/180.0;
constexpr float RadiansToDegrees = 180.0/3.141592653589793;
constexpr unsigned int MaxFloatDigitsDisplayedAfterPoint = 7;
+const char *GetFloatFormatString(unsigned int numDigitsAfterPoint) noexcept;
+
+#if SUPPORT_WORKPLACE_COORDINATES
+constexpr size_t NumCoordinateSystems = 9; // G54 up to G59.3
+#else
+constexpr size_t NumCoordinateSystems = 1;
+#endif
#define DEGREE_SYMBOL "\xC2\xB0" // degree-symbol encoding in UTF8
diff --git a/src/Version.h b/src/Version.h
index e545e367..3ac41602 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -20,7 +20,7 @@
#endif
#ifndef DATE
-# define DATE "2020-01-20b1"
+# define DATE "2020-01-22b2"
#endif
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman, printm3d"