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
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/BugList.txt25
-rw-r--r--src/DuetM/TMC22xx.cpp141
-rw-r--r--src/DuetM/TMC22xx.h9
-rw-r--r--src/DuetNG/TMC2660.cpp205
-rw-r--r--src/DuetNG/TMC2660.h36
-rw-r--r--src/GCodes/DriverMode.cpp29
-rw-r--r--src/GCodes/DriverMode.h27
-rw-r--r--src/GCodes/GCodeBuffer.cpp10
-rw-r--r--src/GCodes/GCodeBuffer.h1
-rw-r--r--src/GCodes/GCodes.cpp94
-rw-r--r--src/GCodes/GCodes.h9
-rw-r--r--src/GCodes/GCodes2.cpp94
-rw-r--r--src/Heating/Sensors/TemperatureSensor.cpp2
-rw-r--r--src/Heating/Sensors/Thermistor.cpp17
-rw-r--r--src/Heating/Sensors/Thermistor.h1
-rw-r--r--src/Movement/DDA.cpp24
-rw-r--r--src/Movement/DDA.h3
-rw-r--r--src/Movement/Move.cpp22
-rw-r--r--src/Networking/HttpResponder.cpp319
-rw-r--r--src/Networking/W5500Ethernet/W5500Interface.cpp3
-rw-r--r--src/Platform.cpp59
-rw-r--r--src/Platform.h7
-rw-r--r--src/RepRap.cpp49
-rw-r--r--src/RepRapFirmware.cpp6
-rw-r--r--src/RepRapFirmware.h2
-rw-r--r--src/Version.h4
26 files changed, 736 insertions, 462 deletions
diff --git a/src/BugList.txt b/src/BugList.txt
index 2e6a5753..0640055f 100644
--- a/src/BugList.txt
+++ b/src/BugList.txt
@@ -129,11 +129,32 @@ Remaining:
- [fixed in 2.0b2, test] BUG: G0 command after G1 E command does extrusion
- [believed fixed in 2.0b2] BUG movement system hangs sometimes if using very high microstepping, e.g. janke PSU model and config.g
-- BUG manual probing, see https://github.com/dc42/RepRapFirmware/issues/170#issuecomment-380790290
+Todo in 1.21.1 bugfix release:
+
+- [done in 2.0] BUG: G1 E5 S1 on delta says "Error: G0/G1: attempt to move delta motors to absolute positions"
+- [fixed in 2.0b2, test] BUG M667 S1 echoes the new kinematics
+- [done in 2.0] BUG: if we get a pause due to stalled drivers, the driver numbers won't be listed
+- [done in 2.0, ok] BUG: no call to HttpResponder::CheckSessions
+- [done in 2.0, test] Allow Z jerk down to 0.2mm/sec
+- [done in 2.0, test] BUG: G29 height map is way below bed. Happened on Ormerod. When probing the bed with simple G30 and compensation is applied, correct for the height map offset
+- [believed fixed in 2.0b2] BUG movement system hangs sometimes if using very high microstepping, e.g. janke PSU model and config.g
+- [consider, done in 2.0] Simulation to assume machine starts homed, restore homed status at end
+- [consider, done in 2.0] Update user coordinates after using G10 to change offsets, https://www.duet3d.com/forum/thread.php?pid=44900#p44900
+- [done, test] Support M916 on older Duets
+
+Remaining:
+
+- [done, test] M122 has some duplicate parts of network status on Maestro
+- [done, ok] prevent watchdog reset if MaxReps gets too high
+- [done] BUG manual probing, see https://github.com/dc42/RepRapFirmware/issues/170#issuecomment-380790290
+- [done, ok] BUG strange varying temperature readings if 100K resistor used on an input configured for a PT100
+- [done, ok] BUG if you set an input to be a PT1000 and then set it back to being a thermistor, it still reads like a PT1000
- BUG SCARA continuous rotation doesn't work
- BUG sounds like SCARA only checks that the end point is within limits, but for a G1 move intermediate positions may violate the minimum radius
+- [done, ok] When >1 hot end heater, add T0/T1 prefix to M105 response for compatibility with Marlin etc.
-- When >1 hot end heater, add T0/T1 prefix to M105 response for compatibiity with Marlin etc.
+- PanelDue won't connect if VIN velow minimum for stepper motors [PanelDue firmware needs to recognise status 'O']
+- Add parameter to M116 to specify acceptable temperature difference
- Laser support, see https://forum.duet3d.com/topic/4702/laser-cnc-support-in-rrf-gcode-semantics/4
- support M205 for setting jerk
- support G12 clean tool?
diff --git a/src/DuetM/TMC22xx.cpp b/src/DuetM/TMC22xx.cpp
index b9ab6f4f..47cdd216 100644
--- a/src/DuetM/TMC22xx.cpp
+++ b/src/DuetM/TMC22xx.cpp
@@ -50,7 +50,7 @@ constexpr uint32_t GCONF_MSTEP_REG = 1 << 7; // microstep resolution set by M
constexpr uint32_t GCONF_MULTISTEP_FILT = 1 << 8; // pulse generation optimised for >750Hz full stepping frequency
constexpr uint32_t GCONF_TEST_MODE = 1 << 9; // test mode, do not set this bit for normal operation
-constexpr uint32_t DefaultGConfReg = GCONF_UART | GCONF_MSTEP_REG | GCONF_MULTISTEP_FILT | GCONF_SPREAD_CYCLE; // TODO - do we want spread cycle or not?
+constexpr uint32_t DefaultGConfReg = GCONF_UART | GCONF_MSTEP_REG | GCONF_MULTISTEP_FILT;
// General configuration and status registers
@@ -256,8 +256,13 @@ public:
void Init(uint32_t p_driverNumber, Pin p_pin);
void SetAxisNumber(size_t p_axisNumber);
void WriteAll();
- void SetChopConf(uint32_t newVal);
- void SetMicrostepping(uint32_t shift, bool interpolate);
+ bool SetChopConf(uint32_t newVal);
+ uint32_t GetChopConf() const;
+ void SetCoolStep(uint16_t coolStepConfig);
+ bool SetMicrostepping(uint32_t shift, bool interpolate);
+ unsigned int GetMicrostepping(bool& interpolation) const; // Get microstepping
+ bool SetDriverMode(unsigned int mode);
+ DriverMode GetDriverMode() const;
void SetCurrent(float current);
void Enable(bool en);
void AppendDriverStatus(const StringRef& reply);
@@ -272,7 +277,6 @@ public:
void TransferTimedOut() { ++numTimeouts; }
static void AbortTransfer();
- unsigned int GetMicrostepping(int mode, bool& interpolation) const; // get microstepping or chopper control register
uint32_t ReadLiveStatus() const;
uint32_t ReadAccumulatedStatus(uint32_t bitsToKeep);
@@ -476,15 +480,8 @@ void TmcDriverState::SetStandstillCurrentPercent(float percent)
UpdateCurrent();
}
-// Set the chopper control register to the settings provided by the user
-void TmcDriverState::SetChopConf(uint32_t newVal)
-{
- configuredChopConfReg = (newVal & (CHOPCONF_TBL_MASK | CHOPCONF_HSTRT_MASK | CHOPCONF_HEND_MASK | CHOPCONF_TOFF_MASK)) | CHOPCONF_VSENSE_HIGH;
- UpdateChopConfRegister();
-}
-
// Set the microstepping and microstep interpolation. The desired microstepping is (1 << shift).
-void TmcDriverState::SetMicrostepping(uint32_t shift, bool interpolate)
+bool TmcDriverState::SetMicrostepping(uint32_t shift, bool interpolate)
{
microstepShiftFactor = shift;
configuredChopConfReg = (configuredChopConfReg & ~(CHOPCONF_MRES_MASK | CHOPCONF_INTPOL)) | ((8 - shift) << CHOPCONF_MRES_SHIFT);
@@ -493,6 +490,52 @@ void TmcDriverState::SetMicrostepping(uint32_t shift, bool interpolate)
configuredChopConfReg |= CHOPCONF_INTPOL;
}
UpdateChopConfRegister();
+ return true;
+}
+
+// Get microstepping or chopper control register
+unsigned int TmcDriverState::GetMicrostepping(bool& interpolation) const
+{
+ interpolation = (writeRegisters[WriteChopConf] & CHOPCONF_INTPOL) != 0;
+ return 1u << microstepShiftFactor;
+}
+
+// Set the chopper control register to the settings provided by the user
+bool TmcDriverState::SetChopConf(uint32_t newVal)
+{
+ configuredChopConfReg = (newVal & (CHOPCONF_TBL_MASK | CHOPCONF_HSTRT_MASK | CHOPCONF_HEND_MASK | CHOPCONF_TOFF_MASK)) | CHOPCONF_VSENSE_HIGH;
+ UpdateChopConfRegister();
+ return true;
+}
+
+// Get microstepping or chopper control register
+uint32_t TmcDriverState::GetChopConf() const
+{
+ return configuredChopConfReg;
+}
+
+// Set the driver mode
+bool TmcDriverState::SetDriverMode(unsigned int mode)
+{
+ switch (mode)
+ {
+ case (unsigned int)DriverMode::spreadCycle:
+ UpdateRegister(WriteGConf, writeRegisters[WriteGConf] | GCONF_SPREAD_CYCLE);
+ return true;
+
+ case (unsigned int)DriverMode::stealthChop:
+ UpdateRegister(WriteGConf, writeRegisters[WriteGConf] & ~GCONF_SPREAD_CYCLE);
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+// Get the driver mode
+DriverMode TmcDriverState::GetDriverMode() const
+{
+ return ((writeRegisters[WriteGConf] & GCONF_SPREAD_CYCLE) != 0) ? DriverMode::spreadCycle : DriverMode::stealthChop;
}
// Set the motor current
@@ -574,24 +617,10 @@ void TmcDriverState::AppendDriverStatus(const StringRef& reply)
reply.cat(" ok");
}
- reply.catf(", read errors %u, write errors %u, ifcount %u, reads %u, timoeuts %u", readErrors, writeErrors, lastIfCount, numReads, numTimeouts);
+ reply.catf(", read errors %u, write errors %u, ifcount %u, reads %u, timeouts %u", readErrors, writeErrors, lastIfCount, numReads, numTimeouts);
readErrors = writeErrors = numReads = numTimeouts = 0;
}
-// Get microstepping or chopper control register
-unsigned int TmcDriverState::GetMicrostepping(int mode, bool& interpolation) const
-{
- interpolation = (writeRegisters[WriteChopConf] & CHOPCONF_INTPOL) != 0;
- if (mode == ChopperControlRegisterMode)
- {
- return configuredChopConfReg;
- }
- else
- {
- return 1u << microstepShiftFactor;
- }
-}
-
// This is called by the ISR when the SPI transfer has completed
inline void TmcDriverState::TransferDone()
{
@@ -815,39 +844,51 @@ namespace SmartDrivers
}
// Set microstepping or chopper control register
- bool SetMicrostepping(size_t drive, unsigned int microsteps, int mode)
+ bool SetMicrostepping(size_t drive, unsigned int microsteps, bool interpolate)
{
- if (drive < numTmc22xxDrivers)
+ if (drive < numTmc22xxDrivers && microsteps > 0)
{
- if (mode == ChopperControlRegisterMode && microsteps >= 0)
+ // Set the microstepping. We need to determine how many bits right to shift the desired microstepping to reach 1.
+ unsigned int shift = 0;
+ unsigned int uSteps = (unsigned int)microsteps;
+ while ((uSteps & 1) == 0)
{
- driverStates[drive].SetChopConf((uint32_t)microsteps); // set the chopper control register
- return true;
+ uSteps >>= 1;
+ ++shift;
}
- else if (microsteps > 0 && (mode == 0 || mode == 1))
+ if (uSteps == 1 && shift <= 8)
{
- // Set the microstepping. We need to determine how many bits right to shift the desired microstepping to reach 1.
- unsigned int shift = 0;
- unsigned int uSteps = (unsigned int)microsteps;
- while ((uSteps & 1) == 0)
- {
- uSteps >>= 1;
- ++shift;
- }
- if (uSteps == 1 && shift <= 8)
- {
- driverStates[drive].SetMicrostepping(shift, mode != 0);
- return true;
- }
+ driverStates[drive].SetMicrostepping(shift, interpolate);
+ return true;
}
}
return false;
}
// Get microstepping or chopper control register
- unsigned int GetMicrostepping(size_t drive, int mode, bool& interpolation)
+ unsigned int GetMicrostepping(size_t drive, bool& interpolation)
{
- return (drive < numTmc22xxDrivers) ? driverStates[drive].GetMicrostepping(mode, interpolation) : 1;
+ return (drive < numTmc22xxDrivers) ? driverStates[drive].GetMicrostepping(interpolation) : 1;
+ }
+
+ bool SetDriverMode(size_t driver, unsigned int mode)
+ {
+ return driver < numTmc22xxDrivers && driverStates[driver].SetDriverMode(mode);
+ }
+
+ DriverMode GetDriverMode(size_t driver)
+ {
+ return (driver < numTmc22xxDrivers) ? driverStates[driver].GetDriverMode() : DriverMode::unknown;
+ }
+
+ bool SetChopperControlRegister(size_t driver, uint32_t ccr)
+ {
+ return driver < numTmc22xxDrivers && driverStates[driver].SetChopConf(ccr);
+ }
+
+ uint32_t GetChopperControlRegister(size_t driver)
+ {
+ return (driver < numTmc22xxDrivers) ? driverStates[driver].GetChopConf() : 0;
}
// Flag that the the drivers have been powered up or down and handle any timeouts
@@ -958,7 +999,3 @@ namespace SmartDrivers
}; // end namespace
// End
-
-
-
-
diff --git a/src/DuetM/TMC22xx.h b/src/DuetM/TMC22xx.h
index 69a8f976..4e181fdc 100644
--- a/src/DuetM/TMC22xx.h
+++ b/src/DuetM/TMC22xx.h
@@ -9,6 +9,7 @@
#define TMC2660_H_
#include "RepRapFirmware.h"
+#include "GCodes/DriverMode.h"
#include "Pins.h"
#include "MessageType.h"
#include "Libraries/General/StringRef.h"
@@ -41,8 +42,12 @@ namespace SmartDrivers
void EnableDrive(size_t drive, bool en);
uint32_t GetLiveStatus(size_t drive);
uint32_t GetAccumulatedStatus(size_t drive, uint32_t bitsToKeep);
- bool SetMicrostepping(size_t drive, unsigned int microsteps, int mode);
- unsigned int GetMicrostepping(size_t drive, int mode, bool& interpolation);
+ bool SetMicrostepping(size_t drive, unsigned int microsteps, bool interpolation);
+ unsigned int GetMicrostepping(size_t drive, bool& interpolation);
+ bool SetDriverMode(size_t driver, unsigned int mode);
+ DriverMode GetDriverMode(size_t driver);
+ bool SetChopperControlRegister(size_t driver, uint32_t ccr);
+ uint32_t GetChopperControlRegister(size_t driver);
void Spin(bool powered);
void TurnDriversOff();
void SetCoolStep(size_t drive, uint16_t coolStepConfig);
diff --git a/src/DuetNG/TMC2660.cpp b/src/DuetNG/TMC2660.cpp
index 23c5f098..1972b4ac 100644
--- a/src/DuetNG/TMC2660.cpp
+++ b/src/DuetNG/TMC2660.cpp
@@ -163,21 +163,25 @@ public:
void Init(uint32_t p_axisNumber, uint32_t p_pin);
void SetAxisNumber(size_t p_axisNumber);
void WriteAll();
- void SetChopConf(uint32_t newVal);
- void SetMicrostepping(uint32_t shift, bool interpolate);
+
+ bool SetChopConf(uint32_t newVal);
+ uint32_t GetChopConf() const;
+ void SetCoolStep(uint16_t coolStepConfig);
+ bool SetMicrostepping(uint32_t shift, bool interpolate);
+ unsigned int GetMicrostepping(bool& interpolation) const; // Get microstepping
+ bool SetDriverMode(unsigned int mode);
+ DriverMode GetDriverMode() const;
void SetCurrent(float current);
void Enable(bool en);
void SetStallDetectThreshold(int sgThreshold);
void SetStallDetectFilter(bool sgFilter);
void SetStallMinimumStepsPerSecond(unsigned int stepsPerSecond);
- void SetCoolStep(uint16_t coolStepConfig);
void AppendStallConfig(const StringRef& reply) const;
void AppendDriverStatus(const StringRef& reply);
- void TransferDone() __attribute__ ((hot)); // called by the ISR when the SPI transfer has completed
- void StartTransfer() __attribute__ ((hot)); // called to start a transfer
+ void TransferDone() __attribute__ ((hot)); // called by the ISR when the SPI transfer has completed
+ void StartTransfer() __attribute__ ((hot)); // called to start a transfer
- unsigned int GetMicrostepping(int mode, bool& interpolation) const; // Get microstepping or chopper control register
uint32_t ReadLiveStatus() const;
uint32_t ReadAccumulatedStatus(uint32_t bitsToKeep);
@@ -280,14 +284,48 @@ inline void TmcDriverState::WriteAll()
}
// Set the chopper control register
-void TmcDriverState::SetChopConf(uint32_t newVal)
+bool TmcDriverState::SetChopConf(uint32_t newVal)
{
configuredChopConfReg = (newVal & 0x0001FFFF) | TMC_REG_CHOPCONF; // save the new value
Enable((registers[ChopperControl] & TMC_CHOPCONF_TOFF_MASK) != 0); // send the new value, keeping the current Enable status
+ return true;
+}
+
+// Set the driver mode
+bool TmcDriverState::SetDriverMode(unsigned int mode)
+{
+ switch (mode)
+ {
+ case (unsigned int)DriverMode::constantOffTime:
+ configuredChopConfReg = (configuredChopConfReg & ~TMC_CHOPCONF_RNDTF) | TMC_CHOPCONF_CHM;
+ Enable((registers[ChopperControl] & TMC_CHOPCONF_TOFF_MASK) != 0); // send the new value, keeping the current Enable status
+ return true;
+
+ case (unsigned int)DriverMode::randomOffTime:
+ configuredChopConfReg |= (TMC_CHOPCONF_RNDTF | TMC_CHOPCONF_CHM);
+ Enable((registers[ChopperControl] & TMC_CHOPCONF_TOFF_MASK) != 0); // send the new value, keeping the current Enable status
+ return true;
+
+ case (unsigned int)DriverMode::spreadCycle:
+ configuredChopConfReg &= ~(TMC_CHOPCONF_RNDTF | TMC_CHOPCONF_CHM);
+ Enable((registers[ChopperControl] & TMC_CHOPCONF_TOFF_MASK) != 0); // send the new value, keeping the current Enable status
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+// Get the driver mode
+DriverMode TmcDriverState::GetDriverMode() const
+{
+ return ((configuredChopConfReg & TMC_CHOPCONF_CHM) == 0) ? DriverMode::spreadCycle
+ : ((configuredChopConfReg & TMC_CHOPCONF_RNDTF) == 0) ? DriverMode::constantOffTime
+ : DriverMode::randomOffTime;
}
// Set the microstepping and microstep interpolation. The desired microstepping is (1 << shift).
-void TmcDriverState::SetMicrostepping(uint32_t shift, bool interpolate)
+bool TmcDriverState::SetMicrostepping(uint32_t shift, bool interpolate)
{
microstepShiftFactor = shift;
uint32_t drvCtrlReg = registers[DriveControl] & ~TMC_DRVCTRL_MRES_MASK;
@@ -302,6 +340,7 @@ void TmcDriverState::SetMicrostepping(uint32_t shift, bool interpolate)
}
registers[DriveControl] = drvCtrlReg;
registersToUpdate |= 1u << DriveControl;
+ return true;
}
// Set the motor current
@@ -424,18 +463,17 @@ void TmcDriverState::AppendDriverStatus(const StringRef& reply)
ResetLoadRegisters();
}
-// Get microstepping or chopper control register
-unsigned int TmcDriverState::GetMicrostepping(int mode, bool& interpolation) const
+// Get microstepping
+unsigned int TmcDriverState::GetMicrostepping(bool& interpolation) const
{
interpolation = (registers[DriveControl] & TMC_DRVCTRL_INTPOL) != 0;
- if (mode == ChopperControlRegisterMode)
- {
- return configuredChopConfReg & TMC_DATA_MASK;
- }
- else
- {
- return 1u << microstepShiftFactor;
- }
+ return 1u << microstepShiftFactor;
+}
+
+// Get chopper control register
+uint32_t TmcDriverState::GetChopConf() const
+{
+ return configuredChopConfReg & TMC_DATA_MASK;
}
// This is called by the ISR when the SPI transfer has completed
@@ -568,80 +606,97 @@ namespace SmartDrivers
//delay(10);
driversPowered = false;
- for (size_t drive = 0; drive < numTmc2660Drivers; ++drive)
+ for (size_t driver = 0; driver < numTmc2660Drivers; ++driver)
{
- driverStates[drive].Init(drive, driverSelectPins[drive]); // axes are mapped straight through to drivers initially
+ driverStates[driver].Init(driver, driverSelectPins[driver]); // axes are mapped straight through to drivers initially
}
}
- void SetAxisNumber(size_t drive, uint32_t axisNumber)
+ void SetAxisNumber(size_t driver, uint32_t axisNumber)
{
- if (drive < numTmc2660Drivers)
+ if (driver < numTmc2660Drivers)
{
- driverStates[drive].SetAxisNumber(axisNumber);
+ driverStates[driver].SetAxisNumber(axisNumber);
}
}
- void SetCurrent(size_t drive, float current)
+ void SetCurrent(size_t driver, float current)
{
- if (drive < numTmc2660Drivers)
+ if (driver < numTmc2660Drivers)
{
- driverStates[drive].SetCurrent(current);
+ driverStates[driver].SetCurrent(current);
}
}
- void EnableDrive(size_t drive, bool en)
+ void EnableDrive(size_t driver, bool en)
{
- if (drive < numTmc2660Drivers)
+ if (driver < numTmc2660Drivers)
{
- driverStates[drive].Enable(en);
+ driverStates[driver].Enable(en);
}
}
- uint32_t GetLiveStatus(size_t drive)
+ uint32_t GetLiveStatus(size_t driver)
{
- return (drive < numTmc2660Drivers) ? driverStates[drive].ReadLiveStatus() : 0;
+ return (driver < numTmc2660Drivers) ? driverStates[driver].ReadLiveStatus() : 0;
}
- uint32_t GetAccumulatedStatus(size_t drive, uint32_t bitsToKeep)
+ uint32_t GetAccumulatedStatus(size_t driver, uint32_t bitsToKeep)
{
- return (drive < numTmc2660Drivers) ? driverStates[drive].ReadAccumulatedStatus(bitsToKeep) : 0;
+ return (driver < numTmc2660Drivers) ? driverStates[driver].ReadAccumulatedStatus(bitsToKeep) : 0;
}
- // Set microstepping or chopper control register
- bool SetMicrostepping(size_t drive, unsigned int microsteps, int mode)
+ // Set microstepping and microstep interpolation
+ bool SetMicrostepping(size_t driver, unsigned int microsteps, bool interpolate)
{
- if (drive < numTmc2660Drivers)
+ if (driver < numTmc2660Drivers && microsteps > 0)
{
- if (mode == ChopperControlRegisterMode && microsteps >= 0)
+ // Set the microstepping. We need to determine how many bits right to shift the desired microstepping to reach 1.
+ unsigned int shift = 0;
+ unsigned int uSteps = (unsigned int)microsteps;
+ while ((uSteps & 1) == 0)
{
- driverStates[drive].SetChopConf((uint32_t)microsteps); // set the chopper control register
- return true;
+ uSteps >>= 1;
+ ++shift;
}
- else if (microsteps > 0 && (mode == 0 || mode == 1))
+ if (uSteps == 1 && shift <= 8)
{
- // Set the microstepping. We need to determine how many bits right to shift the desired microstepping to reach 1.
- unsigned int shift = 0;
- unsigned int uSteps = (unsigned int)microsteps;
- while ((uSteps & 1) == 0)
- {
- uSteps >>= 1;
- ++shift;
- }
- if (uSteps == 1 && shift <= 8)
- {
- driverStates[drive].SetMicrostepping(shift, mode != 0);
- return true;
- }
+ driverStates[driver].SetMicrostepping(shift, interpolate);
+ return true;
}
}
return false;
}
- // Get microstepping or chopper control register
- unsigned int GetMicrostepping(size_t drive, int mode, bool& interpolation)
+ // Get microstepping and interpolation
+ unsigned int GetMicrostepping(size_t driver, bool& interpolation)
+ {
+ if (driver < numTmc2660Drivers)
+ {
+ return driverStates[driver].GetMicrostepping(interpolation);
+ }
+ interpolation = false;
+ return 1;
+ }
+
+ bool SetDriverMode(size_t driver, unsigned int mode)
+ {
+ return driver < numTmc2660Drivers && driverStates[driver].SetDriverMode(mode);
+ }
+
+ DriverMode GetDriverMode(size_t driver)
{
- return (drive < numTmc2660Drivers) ? driverStates[drive].GetMicrostepping(mode, interpolation) : 1;
+ return (driver < numTmc2660Drivers) ? driverStates[driver].GetDriverMode() : DriverMode::unknown;
+ }
+
+ bool SetChopperControlRegister(size_t driver, uint32_t ccr)
+ {
+ return driver < numTmc2660Drivers && driverStates[driver].SetChopConf(ccr);
+ }
+
+ uint32_t GetChopperControlRegister(size_t driver)
+ {
+ return (driver < numTmc2660Drivers) ? driverStates[driver].GetChopConf() : 0;
}
// Flag the the drivers have been powered up.
@@ -658,9 +713,9 @@ namespace SmartDrivers
digitalWrite(GlobalTmcEnablePin, LOW);
delayMicroseconds(10);
- for (size_t drive = 0; drive < numTmc2660Drivers; ++drive)
+ for (size_t driver = 0; driver < numTmc2660Drivers; ++driver)
{
- driverStates[drive].WriteAll();
+ driverStates[driver].WriteAll();
}
}
if (currentDriver == nullptr && numTmc2660Drivers != 0)
@@ -683,27 +738,27 @@ namespace SmartDrivers
driversPowered = false;
}
- void SetStallThreshold(size_t drive, int sgThreshold)
+ void SetStallThreshold(size_t driver, int sgThreshold)
{
- if (drive < numTmc2660Drivers)
+ if (driver < numTmc2660Drivers)
{
- driverStates[drive].SetStallDetectThreshold(sgThreshold);
+ driverStates[driver].SetStallDetectThreshold(sgThreshold);
}
}
- void SetStallFilter(size_t drive, bool sgFilter)
+ void SetStallFilter(size_t driver, bool sgFilter)
{
- if (drive < numTmc2660Drivers)
+ if (driver < numTmc2660Drivers)
{
- driverStates[drive].SetStallDetectFilter(sgFilter);
+ driverStates[driver].SetStallDetectFilter(sgFilter);
}
}
- void SetStallMinimumStepsPerSecond(size_t drive, unsigned int stepsPerSecond)
+ void SetStallMinimumStepsPerSecond(size_t driver, unsigned int stepsPerSecond)
{
- if (drive < numTmc2660Drivers)
+ if (driver < numTmc2660Drivers)
{
- driverStates[drive].SetStallMinimumStepsPerSecond(stepsPerSecond);
+ driverStates[driver].SetStallMinimumStepsPerSecond(stepsPerSecond);
}
}
@@ -715,28 +770,28 @@ namespace SmartDrivers
}
}
- void AppendStallConfig(size_t drive, const StringRef& reply)
+ void AppendStallConfig(size_t driver, const StringRef& reply)
{
- if (drive < numTmc2660Drivers)
+ if (driver < numTmc2660Drivers)
{
- driverStates[drive].AppendStallConfig(reply);
+ driverStates[driver].AppendStallConfig(reply);
}
}
- void AppendDriverStatus(size_t drive, const StringRef& reply)
+ void AppendDriverStatus(size_t driver, const StringRef& reply)
{
- if (drive < numTmc2660Drivers)
+ if (driver < numTmc2660Drivers)
{
- driverStates[drive].AppendDriverStatus(reply);
+ driverStates[driver].AppendDriverStatus(reply);
}
}
- float GetStandstillCurrentPercent(size_t drive)
+ float GetStandstillCurrentPercent(size_t driver)
{
return 100.0; // not supported
}
- void SetStandstillCurrentPercent(size_t drive, float percent)
+ void SetStandstillCurrentPercent(size_t driver, float percent)
{
// not supported so nothing to see here
}
diff --git a/src/DuetNG/TMC2660.h b/src/DuetNG/TMC2660.h
index 8e07f75a..c31f6ffe 100644
--- a/src/DuetNG/TMC2660.h
+++ b/src/DuetNG/TMC2660.h
@@ -9,6 +9,7 @@
#define TMC2660_H_
#include "RepRapFirmware.h"
+#include "GCodes/DriverMode.h"
#include "Pins.h"
#include "MessageType.h"
#include "Libraries/General/StringRef.h"
@@ -33,23 +34,28 @@ namespace SmartDrivers
{
void Init(const Pin[DRIVES], size_t numTmcDrivers)
pre(numTmcDrivers <= DRIVES);
- void SetAxisNumber(size_t drive, uint32_t axisNumber);
- void SetCurrent(size_t drive, float current);
- void EnableDrive(size_t drive, bool en);
- uint32_t GetLiveStatus(size_t drive);
- uint32_t GetAccumulatedStatus(size_t drive, uint32_t bitsToKeep);
- bool SetMicrostepping(size_t drive, unsigned int microsteps, int mode);
- unsigned int GetMicrostepping(size_t drive, int mode, bool& interpolation);
void Spin(bool powered);
void TurnDriversOff();
- void SetStallThreshold(size_t drive, int sgThreshold);
- void SetStallFilter(size_t drive, bool sgFilter);
- void SetStallMinimumStepsPerSecond(size_t drive, unsigned int stepsPerSecond);
- void SetCoolStep(size_t drive, uint16_t coolStepConfig);
- void AppendStallConfig(size_t drive, const StringRef& reply);
- void AppendDriverStatus(size_t drive, const StringRef& reply);
- float GetStandstillCurrentPercent(size_t drive);
- void SetStandstillCurrentPercent(size_t drive, float percent);
+
+ void SetAxisNumber(size_t driver, uint32_t axisNumber);
+ void SetCurrent(size_t driver, float current);
+ void EnableDrive(size_t driver, bool en);
+ uint32_t GetLiveStatus(size_t driver);
+ uint32_t GetAccumulatedStatus(size_t drive, uint32_t bitsToKeep);
+ bool SetMicrostepping(size_t drive, unsigned int microsteps, bool interpolation);
+ unsigned int GetMicrostepping(size_t drive, bool& interpolation);
+ bool SetDriverMode(size_t driver, unsigned int mode);
+ DriverMode GetDriverMode(size_t driver);
+ bool SetChopperControlRegister(size_t driver, uint32_t ccr);
+ uint32_t GetChopperControlRegister(size_t driver);
+ void SetStallThreshold(size_t driver, int sgThreshold);
+ void SetStallFilter(size_t driver, bool sgFilter);
+ void SetStallMinimumStepsPerSecond(size_t driver, unsigned int stepsPerSecond);
+ void SetCoolStep(size_t driver, uint16_t coolStepConfig);
+ void AppendStallConfig(size_t driver, const StringRef& reply);
+ void AppendDriverStatus(size_t driver, const StringRef& reply);
+ float GetStandstillCurrentPercent(size_t driver);
+ void SetStandstillCurrentPercent(size_t driver, float percent);
};
#endif /* TMC2660_H_ */
diff --git a/src/GCodes/DriverMode.cpp b/src/GCodes/DriverMode.cpp
new file mode 100644
index 00000000..6450e115
--- /dev/null
+++ b/src/GCodes/DriverMode.cpp
@@ -0,0 +1,29 @@
+/*
+ * DriverMode.cpp
+ *
+ * Created on: 27 Apr 2018
+ * Author: David
+ */
+
+#include "DriverMode.h"
+#include "RepRapFirmware.h"
+
+// This table must be in the same order as enum DriverMode
+static const char * const DriverModeStrings[] =
+{
+ "constant off-time",
+ "random off-time",
+ "spreadCycle",
+ "stealthChop",
+ "unknown"
+};
+
+static_assert(ARRAY_SIZE(DriverModeStrings) == (unsigned int)DriverMode::unknown + 1, "bad driver mode string table");
+
+const char* TranslateDriverMode(unsigned int mode)
+{
+ const unsigned int imode = min<unsigned int>(mode, (unsigned int)DriverMode::unknown);
+ return DriverModeStrings[imode];
+}
+
+// End
diff --git a/src/GCodes/DriverMode.h b/src/GCodes/DriverMode.h
new file mode 100644
index 00000000..594fbcf3
--- /dev/null
+++ b/src/GCodes/DriverMode.h
@@ -0,0 +1,27 @@
+/*
+ * DriverModes.h
+ *
+ * Created on: 27 Apr 2018
+ * Author: David
+ */
+
+#ifndef SRC_GCODES_DRIVERMODE_H_
+#define SRC_GCODES_DRIVERMODE_H_
+
+enum class DriverMode : unsigned int
+{
+ constantOffTime = 0,
+ randomOffTime,
+ spreadCycle,
+ stealthChop, // includes stealthChop2
+ unknown // must be last!
+};
+
+const char* TranslateDriverMode(unsigned int mode);
+
+inline const char* TranslateDriverMode(DriverMode mode)
+{
+ return TranslateDriverMode((unsigned int)mode);
+}
+
+#endif /* SRC_GCODES_DRIVERMODE_H_ */
diff --git a/src/GCodes/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer.cpp
index e3222344..3c190852 100644
--- a/src/GCodes/GCodeBuffer.cpp
+++ b/src/GCodes/GCodeBuffer.cpp
@@ -750,6 +750,16 @@ void GCodeBuffer::TryGetUIValue(char c, uint32_t& val, bool& seen)
}
}
+// If the specified parameter character is found, fetch 'value' as a Boolean and set 'seen'. Otherwise leave val and seen alone.
+void GCodeBuffer::TryGetBValue(char c, bool& val, bool& seen)
+{
+ if (Seen(c))
+ {
+ val = GetIValue() > 0;
+ seen = true;
+ }
+}
+
// Try to get a float array exactly 'numVals' long after parameter letter 'c'.
// If the wrong number of values is provided, generate an error message and return true.
// Else set 'seen' if we saw the letter and value, and return false.
diff --git a/src/GCodes/GCodeBuffer.h b/src/GCodes/GCodeBuffer.h
index 81aefdc9..6675cf2a 100644
--- a/src/GCodes/GCodeBuffer.h
+++ b/src/GCodes/GCodeBuffer.h
@@ -46,6 +46,7 @@ public:
void TryGetFValue(char c, float& val, bool& seen);
void TryGetIValue(char c, int32_t& val, bool& seen);
void TryGetUIValue(char c, uint32_t& val, bool& seen);
+ void TryGetBValue(char c, bool& val, bool& seen);
bool TryGetFloatArray(char c, size_t numVals, float vals[], const StringRef& reply, bool& seen, bool doPad = false);
bool TryGetQuotedString(char c, const StringRef& str, bool& seen);
bool TryGetPossiblyQuotedString(char c, const StringRef& str, bool& seen);
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index 9f3917ae..dae9acf8 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -2330,7 +2330,7 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated)
// Check enough axes have been homed
if (moveBuffer.moveType == 0)
{
- if (CheckEnoughAxesHomed(axesMentioned))
+ if (!doingManualBedProbe && CheckEnoughAxesHomed(axesMentioned))
{
return "G0/G1: insufficient axes homed";
}
@@ -3040,7 +3040,7 @@ void GCodes::GetCurrentCoordinates(const StringRef& s) const
for (size_t axis = 0; axis < numVisibleAxes; ++axis)
{
// Don't put a space after the colon in the response, it confuses Pronterface
- s.catf("%c:%.3f ", axisLetters[axis], (double)currentUserPosition[axis]);
+ s.catf("%c:%.3f ", axisLetters[axis], HideNan(currentUserPosition[axis]));
}
for (size_t i = numTotalAxes; i < DRIVES; i++)
{
@@ -3055,11 +3055,11 @@ void GCodes::GetCurrentCoordinates(const StringRef& s) const
s.catf(" %" PRIi32, reprap.GetMove().GetEndPoint(i));
}
- // Add the user coordinates because they may be different from the machine coordinates under some conditions
+ // Add the machine coordinates because they may be different from the user coordinates under some conditions
s.cat(" Machine");
for (size_t axis = 0; axis < numVisibleAxes; ++axis)
{
- s.catf(" %.3f", (double)liveCoordinates[axis]);
+ s.catf(" %.3f", HideNan(liveCoordinates[axis]));
}
}
@@ -3522,12 +3522,12 @@ void GCodes::DisableDrives()
SetAllAxesNotHomed();
}
-bool GCodes::ChangeMicrostepping(size_t drive, unsigned int microsteps, int mode) const
+bool GCodes::ChangeMicrostepping(size_t drive, unsigned int microsteps, bool interp) const
{
bool dummy;
- const unsigned int oldSteps = platform.GetMicrostepping(drive, mode, dummy);
- const bool success = platform.SetMicrostepping(drive, microsteps, mode);
- if (success && mode <= 1) // modes higher than 1 are used for special functions
+ const unsigned int oldSteps = platform.GetMicrostepping(drive, dummy);
+ const bool success = platform.SetMicrostepping(drive, microsteps, interp);
+ if (success)
{
// We changed the microstepping, so adjust the steps/mm to compensate
platform.SetDriveStepsPerUnit(drive, platform.DriveStepsPerUnit(drive) * (float)microsteps / (float)oldSteps);
@@ -4587,18 +4587,26 @@ GCodeResult GCodes::WriteConfigOverrideFile(GCodeBuffer& gb, const StringRef& re
return GCodeResult::ok;
}
-// Store a standard-format temperature report in 'reply'. This doesn't put a newline character at the end.
-void GCodes::GenerateTemperatureReport(const StringRef& reply) const
+// Report the temperatures of one tool in M105 format
+void GCodes::ReportToolTemperatures(const StringRef& reply, const Tool *tool, bool includeNumber) const
{
- Heat& heat = reprap.GetHeat();
-
- // Pronterface, Repetier etc. expect the temperatures to be reported for T0, T1 etc.
- // So scan the tool list and report the temperature of the heaters associated with each tool.
- // If the user configures tools T0, T1 etc. with 1 heater each, that will return what these programs expect.
- reply.copy("T");
- char sep = ':';
- for (const Tool *tool = reprap.GetFirstTool(); tool != nullptr; tool = tool->Next())
+ if (tool != nullptr && tool->HeaterCount() != 0)
{
+ if (reply.strlen() != 0)
+ {
+ reply.cat(' ');
+ }
+ if (includeNumber)
+ {
+ reply.catf("T%u", tool->Number());
+ }
+ else
+ {
+ reply.cat("T");
+ }
+
+ Heat& heat = reprap.GetHeat();
+ char sep = ':';
for (size_t i = 0; i < tool->HeaterCount(); ++i)
{
const int heater = tool->Heater(i);
@@ -4606,17 +4614,55 @@ void GCodes::GenerateTemperatureReport(const StringRef& reply) const
sep = ' ';
}
}
+}
+
+// Store a standard-format temperature report in 'reply'. This doesn't put a newline character at the end.
+void GCodes::GenerateTemperatureReport(const StringRef& reply) const
+{
+ Heat& heat = reprap.GetHeat();
+
+ // The following is believed to be compatible with Marlin and Octoprint, based on thread https://github.com/foosel/OctoPrint/issues/2590#issuecomment-385023980
+ ReportToolTemperatures(reply, reprap.GetCurrentTool(), false);
+
+ for (const Tool *tool = reprap.GetFirstTool(); tool != nullptr; tool = tool->Next())
+ {
+ ReportToolTemperatures(reply, tool, true);
+ }
- const int bedHeater = (NumBedHeaters > 0) ? heat.GetBedHeater(0) : -1; // default to first heated bed
- if (bedHeater >= 0)
+ for (size_t hn = 0; hn < NumBedHeaters && heat.GetBedHeater(hn) >= 0; ++hn)
{
- reply.catf(" B:%.1f /%.1f", (double)heat.GetTemperature(bedHeater), (double)heat.GetTargetTemperature(bedHeater));
+ if (hn == 0)
+ {
+ if (reply.strlen() != 0)
+ {
+ reply.cat(' ');
+ }
+ reply.cat("B:");
+ }
+ else
+ {
+ reply.catf(" B%u:", hn);
+ }
+ const int8_t heater = heat.GetBedHeater(hn);
+ reply.catf("%.1f /%.1f", (double)heat.GetTemperature(heater), (double)heat.GetTargetTemperature(heater));
}
- const int chamberHeater = (NumChamberHeaters > 0) ? heat.GetChamberHeater(0) : -1; // default to first chamber heater
- if (chamberHeater >= 0)
+ for (size_t hn = 0; hn < NumChamberHeaters && heat.GetChamberHeater(hn) >= 0; ++hn)
{
- reply.catf(" C:%.1f /%.1f", (double)heat.GetTemperature(chamberHeater), (double)heat.GetTargetTemperature(chamberHeater));
+ if (hn == 0)
+ {
+ if (reply.strlen() != 0)
+ {
+ reply.cat(' ');
+ }
+ reply.cat("C:");
+ }
+ else
+ {
+ reply.catf(" C%u:", hn);
+ }
+ const int8_t heater = heat.GetChamberHeater(hn);
+ reply.catf("%.1f /%.1f", (double)heat.GetTemperature(heater), (double)heat.GetTargetTemperature(heater));
}
}
diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h
index a952b92a..c839b481 100644
--- a/src/GCodes/GCodes.h
+++ b/src/GCodes/GCodes.h
@@ -295,6 +295,7 @@ private:
bool ManageTool(GCodeBuffer& gb, const StringRef& reply); // Create a new tool definition, returning true if an error was reported
void SetToolHeaters(Tool *tool, float temperature, bool both); // Set all a tool's heaters to the temperature, for M104/M109
bool ToolHeatersAtSetTemperatures(const Tool *tool, bool waitWhenCooling) const; // Wait for the heaters associated with the specified tool to reach their set temperatures
+ void ReportToolTemperatures(const StringRef& reply, const Tool *tool, bool includeNumber) const;
void GenerateTemperatureReport(const StringRef& reply) const; // Store a standard-format temperature report in reply
OutputBuffer *GenerateJsonStatusResponse(int type, int seq, ResponseSource source) const; // Generate a M408 response
void CheckReportDue(GCodeBuffer& gb, const StringRef& reply) const; // Check whether we need to report temperatures or status
@@ -311,7 +312,7 @@ private:
GCodeResult RetractFilament(GCodeBuffer& gb, bool retract); // Retract or un-retract filaments
GCodeResult LoadFilament(GCodeBuffer& gb, const StringRef& reply); // Load the specified filament into a tool
GCodeResult UnloadFilament(GCodeBuffer& gb, const StringRef& reply); // Unload the current filament from a tool
- bool ChangeMicrostepping(size_t drive, unsigned int microsteps, int mode) const; // Change microstepping on the specified drive
+ bool ChangeMicrostepping(size_t drive, unsigned int microsteps, bool interp) const; // Change microstepping on the specified drive
void ListTriggers(const StringRef& reply, TriggerInputsBitmap mask); // Append a list of trigger inputs to a message
void CheckTriggers(); // Check for and execute triggers
void CheckFilament(); // Check for and respond to filament errors
@@ -342,12 +343,12 @@ private:
GCodeResult ChangeSimulationMode(GCodeBuffer& gb, const StringRef &reply, uint32_t newSimulationMode); // handle M37 to change the simulation mode
GCodeResult WriteConfigOverrideFile(GCodeBuffer& gb, const StringRef& reply) const; // Write the config-override file
- void CopyConfigFinalValues(GCodeBuffer& gb); // Copy the feed rate etc. from the daemon to the input channels
+ void CopyConfigFinalValues(GCodeBuffer& gb); // Copy the feed rate etc. from the daemon to the input channels
void ClearBabyStepping() { currentBabyStepZOffset = 0.0; }
- MessageType GetMessageBoxDevice(GCodeBuffer& gb) const; // Decide which device to display a message box on
- void DoManualProbe(GCodeBuffer& gb); // Do a manual bed probe
+ MessageType GetMessageBoxDevice(GCodeBuffer& gb) const; // Decide which device to display a message box on
+ void DoManualProbe(GCodeBuffer& gb); // Do a manual bed probe
void AppendAxes(const StringRef& reply, AxesBitmap axes) const; // Append a list of axes to a string
diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp
index 7fe9747b..4562cfed 100644
--- a/src/GCodes/GCodes2.cpp
+++ b/src/GCodes/GCodes2.cpp
@@ -30,6 +30,12 @@
# include "FirmwareUpdater.h"
#endif
+#if defined(DUET_NG)
+# include "TMC2660.h"
+#elif defined(DUET_M)
+# include "TMC22xx.h"
+#endif
+
#if SUPPORT_12864_LCD
# include "Display/Display.h"
#endif
@@ -2112,23 +2118,15 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
case 290: // Baby stepping
if (gb.Seen('S') || gb.Seen('Z'))
{
+ const float fval = gb.GetFValue();
if (!LockMovement(gb))
{
return false;
}
- const float fval = constrain<float>(gb.GetFValue(), -1.0, 1.0);
const bool absolute = (gb.Seen('R') && gb.GetIValue() == 0);
- float difference;
- if (absolute)
- {
- difference = fval - currentBabyStepZOffset;
- currentBabyStepZOffset = fval;
- }
- else
- {
- difference = fval;
- currentBabyStepZOffset += fval;
- }
+ float difference = (absolute) ? fval - currentBabyStepZOffset : fval;
+ difference = constrain<float>(difference, -1.0, 1.0);
+ currentBabyStepZOffset += difference;
const float amountPushed = reprap.GetMove().PushBabyStepping(difference);
moveBuffer.initialCoords[Z_AXIS] += amountPushed;
@@ -2357,11 +2355,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
case 350: // Set/report microstepping
{
- // interp is currently an int not a bool, because we use special values of interp to set the chopper control register
- int32_t mode = 0; // this is usually the interpolation requested (0 = off, 1 = on)
- bool dummy;
- gb.TryGetIValue('I', mode, dummy);
-
+ bool interp = (gb.Seen('I') && gb.GetIValue() > 0);
bool seen = false;
for (size_t axis = 0; axis < numTotalAxes; axis++)
{
@@ -2373,13 +2367,13 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
}
seen = true;
const unsigned int microsteps = gb.GetUIValue();
- if (ChangeMicrostepping(axis, microsteps, mode))
+ if (ChangeMicrostepping(axis, microsteps, interp))
{
SetAxisNotHomed(axis);
}
else
{
- reply.printf("Drive %c does not support %ux microstepping%s", axisLetters[axis], microsteps, ((mode) ? " with interpolation" : ""));
+ reply.printf("Drive %c does not support %ux microstepping%s", axisLetters[axis], microsteps, ((interp) ? " with interpolation" : ""));
result = GCodeResult::error;
}
}
@@ -2397,9 +2391,9 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
gb.GetUnsignedArray(eVals, eCount, true);
for (size_t e = 0; e < eCount; e++)
{
- if (!ChangeMicrostepping(numTotalAxes + e, (int)eVals[e], mode))
+ if (!ChangeMicrostepping(numTotalAxes + e, eVals[e], interp))
{
- reply.printf("Drive E%u does not support %ux microstepping%s", e, (unsigned int)eVals[e], ((mode) ? " with interpolation" : ""));
+ reply.printf("Drive E%u does not support %ux microstepping%s", e, (unsigned int)eVals[e], ((interp) ? " with interpolation" : ""));
result = GCodeResult::error;
}
}
@@ -2410,16 +2404,16 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
reply.copy("Microstepping - ");
for (size_t axis = 0; axis < numTotalAxes; ++axis)
{
- bool interp;
- const unsigned int microsteps = platform.GetMicrostepping(axis, mode, interp);
- reply.catf("%c:%u%s, ", axisLetters[axis], microsteps, (interp) ? "(on)" : "");
+ bool actualInterp;
+ const unsigned int microsteps = platform.GetMicrostepping(axis, actualInterp);
+ reply.catf("%c:%u%s, ", axisLetters[axis], microsteps, (actualInterp) ? "(on)" : "");
}
reply.cat("E");
for (size_t extruder = 0; extruder < numExtruders; extruder++)
{
- bool interp;
- const unsigned int microsteps = platform.GetMicrostepping(extruder + numTotalAxes, mode, interp);
- reply.catf(":%u%s", microsteps, (interp) ? "(on)" : "");
+ bool actualInterp;
+ const unsigned int microsteps = platform.GetMicrostepping(extruder + numTotalAxes, actualInterp);
+ reply.catf(":%u%s", microsteps, (actualInterp) ? "(on)" : "");
}
}
}
@@ -3081,8 +3075,8 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
{
return false;
}
- platform.SetDirectionValue(drive, gb.GetIValue() != 0);
seen = true;
+ platform.SetDirectionValue(drive, gb.GetIValue() != 0);
}
if (gb.Seen('R'))
{
@@ -3090,11 +3084,12 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
{
return false;
}
- platform.SetEnableValue(drive, (int8_t)gb.GetIValue());
seen = true;
+ platform.SetEnableValue(drive, (int8_t)gb.GetIValue());
}
if (gb.Seen('T'))
{
+ seen = true;
float timings[4];
size_t numTimings = ARRAY_SIZE(timings);
gb.GetFloatArray(timings, numTimings, true);
@@ -3105,33 +3100,42 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
break;
}
platform.SetDriverStepTiming(drive, timings);
- seen = true;
}
- bool badParameter = false;
- for (size_t axis = 0; axis < numTotalAxes; ++axis)
+
+#if HAS_SMART_DRIVERS
+ if (gb.Seen('D')) // set driver mode
{
- if (gb.Seen(axisLetters[axis]))
+ seen = true;
+ const unsigned int mode = gb.GetUIValue();
+ if (!SmartDrivers::SetDriverMode(drive, mode))
{
- badParameter = true;
+ reply.printf("Driver %u does not support mode '%s'", drive, TranslateDriverMode(mode));
+ result = GCodeResult::error;
+ break;
}
}
- if (gb.Seen(extrudeLetter))
- {
- badParameter = true;
- }
- if (badParameter)
+
+ if (gb.Seen('C')) // set chopper control register
{
- reply.copy("M569 no longer accepts XYZE parameters; use M584 instead");
- result = GCodeResult::error;
+ seen = true;
+ (void)SmartDrivers::SetChopperControlRegister(drive, gb.GetUIValue()); // currently this call never returns failure, so no error handling here
}
- else if (!seen)
+#endif
+ if (!seen)
{
float timings[4];
platform.GetDriverStepTiming(drive, timings);
- reply.printf("Drive %u runs %s, active %s enable, step timing %.1f,%.1f,%.1f,%.1f microseconds",
+ reply.printf("Drive %u runs %s, active %s enable,"
+#if HAS_SMART_DRIVERS
+ " mode %s,"
+#endif
+ " step timing %.1f,%.1f,%.1f,%.1f microseconds",
drive,
(platform.GetDirectionValue(drive)) ? "forwards" : "in reverse",
(platform.GetEnableValue(drive)) ? "high" : "low",
+#if HAS_SMART_DRIVERS
+ TranslateDriverMode(SmartDrivers::GetDriverMode(drive)),
+#endif
(double)timings[0], (double)timings[1], (double)timings[2], (double)timings[3]);
}
}
@@ -3990,7 +3994,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
break;
#if HAS_VOLTAGE_MONITOR
- case 911: // Enable auto save
+ case 911: // Enable auto save on loss of power
if (gb.Seen('S'))
{
const float saveVoltage = gb.GetFValue();
@@ -4087,7 +4091,6 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
break;
#endif
-#if HAS_VOLTAGE_MONITOR
case 916:
if (!platform.GetMassStorage()->FileExists(platform.GetSysDir(), RESUME_AFTER_POWER_FAIL_G))
{
@@ -4104,7 +4107,6 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
DoFileMacro(gb, RESUME_AFTER_POWER_FAIL_G, true);
}
break;
-#endif
// For case 917, see 906
diff --git a/src/Heating/Sensors/TemperatureSensor.cpp b/src/Heating/Sensors/TemperatureSensor.cpp
index 04815119..b5e1600a 100644
--- a/src/Heating/Sensors/TemperatureSensor.cpp
+++ b/src/Heating/Sensors/TemperatureSensor.cpp
@@ -92,7 +92,7 @@ TemperatureSensor *TemperatureSensor::Create(unsigned int channel)
}
else if (FirstPT1000Channel <= channel && channel < FirstPT1000Channel + Heaters)
{
- ts = new Thermistor(channel - FirstPT1000Channel, true);
+ ts = new Thermistor(channel, true);
}
else if (FirstMax31855ThermocoupleChannel <= channel && channel < FirstMax31855ThermocoupleChannel + MaxSpiTempSensors)
{
diff --git a/src/Heating/Sensors/Thermistor.cpp b/src/Heating/Sensors/Thermistor.cpp
index 009a5402..5566c074 100644
--- a/src/Heating/Sensors/Thermistor.cpp
+++ b/src/Heating/Sensors/Thermistor.cpp
@@ -21,21 +21,24 @@
// Create an instance with default values
Thermistor::Thermistor(unsigned int channel, bool p_isPT1000)
- : TemperatureSensor(channel - FirstThermistorChannel, (p_isPT1000) ? "PT1000" : "Thermistor"), isPT1000(p_isPT1000)
+ : TemperatureSensor(channel, (p_isPT1000) ? "PT1000" : "Thermistor"), isPT1000(p_isPT1000)
#if !HAS_VREF_MONITOR
, adcLowOffset(0), adcHighOffset(0)
#endif
{
- r25 = (channel == FirstThermistorChannel) ? BED_R25 : EXT_R25;
- beta = (channel == FirstThermistorChannel) ? BED_BETA : EXT_BETA;
- shC = (channel == FirstThermistorChannel) ? BED_SHC : EXT_SHC;
+ thermistorInputChannel = (isPT1000) ? channel - FirstPT1000Channel : channel - FirstThermistorChannel;
seriesR = THERMISTOR_SERIES_RS;
+
+ // The following only apply to thermistors
+ r25 = (channel == 0) ? BED_R25 : EXT_R25;
+ beta = (channel == 0) ? BED_BETA : EXT_BETA;
+ shC = (channel == 0) ? BED_SHC : EXT_SHC;
CalcDerivedParameters();
}
void Thermistor::Init()
{
- reprap.GetPlatform().GetAdcFilter(GetSensorChannel() - FirstThermistorChannel).Init((1 << AdcBits) - 1);
+ reprap.GetPlatform().GetAdcFilter(thermistorInputChannel).Init((1 << AdcBits) - 1);
}
// Configure the temperature sensor
@@ -99,7 +102,7 @@ GCodeResult Thermistor::Configure(unsigned int mCode, unsigned int heater, GCode
// Get the temperature
TemperatureError Thermistor::GetTemperature(float& t)
{
- const volatile ThermistorAveragingFilter& tempFilter = reprap.GetPlatform().GetAdcFilter(GetSensorChannel() - FirstThermistorChannel);
+ const volatile ThermistorAveragingFilter& tempFilter = reprap.GetPlatform().GetAdcFilter(thermistorInputChannel);
#if HAS_VREF_MONITOR
// Use the actual VSSA and VREF values read by the ADC
@@ -143,7 +146,7 @@ TemperatureError Thermistor::GetTemperature(float& t)
if (isPT1000)
{
// We want 100 * the equivalent PT100 resistance, which is 10 * the actual PT1000 resistance
- uint16_t ohmsx100 = (uint16_t)rintf(resistance * 10);
+ uint16_t ohmsx100 = (uint16_t)rintf(constrain<float>(resistance * 10, 0.0, 65535.0));
#ifdef DUET_NG
// The VSSA PTC fuse on the later Duets has a resistance of a few ohms
ohmsx100 -= 20; // assume 2 ohms and only one PT1000 sensor
diff --git a/src/Heating/Sensors/Thermistor.h b/src/Heating/Sensors/Thermistor.h
index e733417e..f20aecce 100644
--- a/src/Heating/Sensors/Thermistor.h
+++ b/src/Heating/Sensors/Thermistor.h
@@ -33,6 +33,7 @@ private:
void CalcDerivedParameters(); // calculate shA and shB
// The following are configurable parameters
+ unsigned int thermistorInputChannel;
float r25, beta, shC, seriesR; // parameters declared in the M305 command
bool isPT1000; // true if it is a PT1000 sensor, not a thermistor
diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp
index a8cc3515..efe6186a 100644
--- a/src/Movement/DDA.cpp
+++ b/src/Movement/DDA.cpp
@@ -1442,7 +1442,7 @@ pre(state == frozen)
return true; // schedule another interrupt immediately
}
-uint32_t DDA::maxReps = 0; // this holds he maximum ISR loop count
+uint32_t DDA::numHiccups = 0;
uint32_t DDA::lastStepLowTime = 0;
uint32_t DDA::lastDirChangeTime = 0;
@@ -1454,8 +1454,8 @@ bool DDA::Step()
{
Platform& platform = reprap.GetPlatform();
uint32_t lastStepPulseTime = lastStepLowTime;
- bool repeat;
- uint32_t numReps = 0;
+ bool repeat = false;
+ uint32_t isrStartTime;
do
{
// Keep this loop as fast as possible, in the case that there are no endstops to check!
@@ -1471,12 +1471,16 @@ bool DDA::Step()
}
// 2. Determine which drivers are due for stepping, overdue, or will be due very shortly
+ const uint32_t iClocks = Platform::GetInterruptClocks();
+ if (!repeat)
+ {
+ isrStartTime = iClocks; // first time through, so make a note of the ISR start time
+ }
+ const uint32_t elapsedTime = (iClocks - moveStartTime) + MinInterruptInterval;
DriveMovement* dm = firstDM;
- const uint32_t elapsedTime = (Platform::GetInterruptClocks() - moveStartTime) + MinInterruptInterval;
uint32_t driversStepping = 0;
while (dm != nullptr && elapsedTime >= dm->nextStepTime) // if the next step is due
{
- ++numReps;
driversStepping |= platform.GetDriversBitmap(dm->drive);
dm = dm->nextDM;
@@ -1485,7 +1489,7 @@ bool DDA::Step()
//if (t3 < minCalcTime) minCalcTime = t3;
}
- if ((driversStepping & platform.GetSlowDriversBitmap()) == 0) // if not using any external drivers
+ if ((driversStepping & platform.GetSlowDriversBitmap()) == 0) // if not using any external drivers
{
// 3. Step the drivers
Platform::StepDriversHigh(driversStepping); // generate the steps
@@ -1537,14 +1541,10 @@ bool DDA::Step()
}
// 7. Schedule next interrupt, or if it would be too soon, generate more steps immediately
- repeat = platform.ScheduleStepInterrupt(firstDM->nextStepTime + moveStartTime);
+ // If we have already spent too much time in the ISR, delay the interrupt
+ repeat = platform.ScheduleStepInterruptWithLimit(firstDM->nextStepTime + moveStartTime, isrStartTime);
} while (repeat);
- if (numReps > maxReps)
- {
- maxReps = numReps;
- }
-
if (state == completed)
{
// The following finish time is wrong if we aborted the move because of endstop or Z probe checks.
diff --git a/src/Movement/DDA.h b/src/Movement/DDA.h
index 5c340c8a..45f085c4 100644
--- a/src/Movement/DDA.h
+++ b/src/Movement/DDA.h
@@ -119,6 +119,7 @@ public:
static constexpr uint32_t MinCalcIntervalCartesian = (60 * stepClockRate)/1000000; // same as delta for now, but could be lower
static constexpr uint32_t MinInterruptInterval = 4; // about 6us minimum interval between interrupts, in step clocks
#endif
+ static constexpr uint32_t MaxStepInterruptTime = 10 * MinInterruptInterval; // the maximum time we spend looping in the ISR , in step clocks
static void PrintMoves(); // print saved moves for debugging
@@ -128,7 +129,7 @@ public:
static int32_t loggedProbePositions[XYZ_AXES * MaxLoggedProbePositions];
#endif
- static uint32_t maxReps; // maximum number of times that the ISR looped
+ static uint32_t numHiccups; // how many times we delayed an interrupt to avoid using too much CPU time in interrupts
static uint32_t lastStepLowTime; // when we last completed a step pulse to a slow driver
static uint32_t lastDirChangeTime; // when we last change the DIR signal to a slow driver
diff --git a/src/Movement/Move.cpp b/src/Movement/Move.cpp
index 34c952af..0949a043 100644
--- a/src/Movement/Move.cpp
+++ b/src/Movement/Move.cpp
@@ -584,19 +584,13 @@ bool Move::LowPowerPause(RestorePoint& rp)
#endif
-#if 0
-// For debugging
-extern uint32_t sqSum1, sqSum2, sqCount, sqErrors, lastRes1, lastRes2;
-extern uint64_t lastNum;
-#endif
-
void Move::Diagnostics(MessageType mtype)
{
Platform& p = reprap.GetPlatform();
p.Message(mtype, "=== Move ===\n");
- p.MessageF(mtype, "MaxReps: %" PRIu32 ", StepErrors: %u, LaErrors: %u, FreeDm: %d, MinFreeDm %d, MaxWait: %" PRIu32 "ms, Underruns: %u, %u\n",
- DDA::maxReps, stepErrors, numLookaheadErrors, DriveMovement::NumFree(), DriveMovement::MinFree(), longestGcodeWaitInterval, numLookaheadUnderruns, numPrepareUnderruns);
- DDA::maxReps = 0;
+ p.MessageF(mtype, "Hiccups: %" PRIu32 ", StepErrors: %u, LaErrors: %u, FreeDm: %d, MinFreeDm %d, MaxWait: %" PRIu32 "ms, Underruns: %u, %u\n",
+ DDA::numHiccups, stepErrors, numLookaheadErrors, DriveMovement::NumFree(), DriveMovement::MinFree(), longestGcodeWaitInterval, numLookaheadUnderruns, numPrepareUnderruns);
+ DDA::numHiccups = 0;
numLookaheadUnderruns = numPrepareUnderruns = numLookaheadErrors = 0;
longestGcodeWaitInterval = 0;
DriveMovement::ResetMinFree();
@@ -644,16 +638,6 @@ void Move::Diagnostics(MessageType mtype)
}
p.Message(mtype, "\n");
#endif
-
-#if 0
- // For debugging
- if (sqCount != 0)
- {
- p.AppendMessage(GenericMessage, "Average sqrt times %.2f, %.2f, count %u, errors %u, last %" PRIu64 " %u %u\n",
- (float)sqSum1/sqCount, (float)sqSum2/sqCount, sqCount, sqErrors, lastNum, lastRes1, lastRes2);
- sqSum1 = sqSum2 = sqCount = sqErrors = 0;
- }
-#endif
}
// Set the current position to be this
diff --git a/src/Networking/HttpResponder.cpp b/src/Networking/HttpResponder.cpp
index 5095dea1..55d5bbad 100644
--- a/src/Networking/HttpResponder.cpp
+++ b/src/Networking/HttpResponder.cpp
@@ -40,31 +40,23 @@ bool HttpResponder::Accept(Socket *s, NetworkProtocol protocol)
{
if (responderState == ResponderState::free && protocol == HttpProtocol)
{
- // Make sure we can get an output buffer before we accept the connection, or we won't be able to reply
- if (outBuf != nullptr || OutputBuffer::Allocate(outBuf))
- {
- responderState = ResponderState::reading;
- skt = s;
- timer = millis();
+ responderState = ResponderState::reading;
+ skt = s;
+ timer = millis();
+
+ // Reset the parse state variables
+ clientPointer = 0;
+ parseState = HttpParseState::doingCommandWord;
+ numCommandWords = 0;
+ numQualKeys = 0;
+ numHeaderKeys = 0;
+ commandWords[0] = clientMessage;
- // Reset the parse state variables
- clientPointer = 0;
- parseState = HttpParseState::doingCommandWord;
- numCommandWords = 0;
- numQualKeys = 0;
- numHeaderKeys = 0;
- commandWords[0] = clientMessage;
-
- if (reprap.Debug(moduleWebserver))
- {
- debugPrintf("HTTP connection accepted\n");
- }
- return true;
- }
if (reprap.Debug(moduleWebserver))
{
- debugPrintf("HTTP connection refused (no buffers)\n");
+ debugPrintf("HTTP connection accepted\n");
}
+ return true;
}
return false;
}
@@ -509,13 +501,6 @@ bool HttpResponder::GetJsonResponse(const char* request, OutputBuffer *&response
OutputBuffer::Release(response);
response = reprap.GetLegacyStatusResponse(1, 0);
}
-
- if (response->HadOverflow())
- {
- // We ran out of buffers. Release the buffers we have and return false. The caller will retry later.
- OutputBuffer::ReleaseAll(response);
- return false;
- }
}
else if (StringEquals(request, "gcode") && GetKeyValue("gcode") != nullptr)
{
@@ -601,6 +586,13 @@ bool HttpResponder::GetJsonResponse(const char* request, OutputBuffer *&response
RejectMessage("Unknown request", 500);
return false;
}
+
+ if (response->HadOverflow())
+ {
+ // We ran out of buffers. Release the buffers we have and return false. The caller will retry later.
+ OutputBuffer::ReleaseAll(response);
+ return false;
+ }
return true;
}
@@ -905,55 +897,59 @@ void HttpResponder::SendJsonResponse(const char* command)
// Try to process a request for JSON responses
OutputBuffer *jsonResponse;
- if (!OutputBuffer::Allocate(jsonResponse))
+ if (OutputBuffer::Allocate(jsonResponse))
{
- // Reset the connection immediately if we cannot write any data. Should never happen.
- skt->Terminate();
- return;
- }
-
- bool mayKeepOpen;
- const bool gotResponse = GetJsonResponse(command, jsonResponse, mayKeepOpen);
- if (!gotResponse)
- {
- // Either this request was rejected, or it will take longer to process e.g. rr_fileinfo
- OutputBuffer::Release(jsonResponse);
- return;
- }
+ bool mayKeepOpen;
+ const bool gotResponse = GetJsonResponse(command, jsonResponse, mayKeepOpen);
+ if (!gotResponse)
+ {
+ // Either this request was rejected, or it will take longer to process e.g. rr_fileinfo
+ OutputBuffer::Release(jsonResponse);
+ return;
+ }
- // Send the JSON response
- bool keepOpen = false;
- if (mayKeepOpen)
- {
- // Check that the browser wants to persist the connection too
- for (size_t i = 0; i < numHeaderKeys; ++i)
+ // Send the JSON response
+ bool keepOpen = false;
+ if (mayKeepOpen)
{
- if (StringEquals(headers[i].key, "Connection"))
+ // Check that the browser wants to persist the connection too
+ for (size_t i = 0; i < numHeaderKeys; ++i)
{
- // Comment out the following line to disable persistent connections
- keepOpen = StringEquals(headers[i].value, "keep-alive");
- break;
+ if (StringEquals(headers[i].key, "Connection"))
+ {
+ // Comment out the following line to disable persistent connections
+ keepOpen = StringEquals(headers[i].value, "keep-alive");
+ break;
+ }
}
}
- }
- // Note that when using RTOS the following response MUST be small enough to fit in a single buffer.
- // This is because the current task may get suspended e.g. when reading from SD card to build a file list,
- // so other tasks may allocate buffers meanwhile, and the previous mechanism for ensuring that there is sufficient
- // buffer space remaining don't work.
- // This response is currently about 230 bytes long in the worst case.
- outBuf->copy( "HTTP/1.1 200 OK\n"
- "Cache-Control: no-cache, no-store, must-revalidate\n"
- "Pragma: no-cache\n"
- "Expires: 0\n"
- "Access-Control-Allow-Origin: *\n"
- "Content-Type: application/json\n"
- );
- outBuf->catf("Content-Length: %u\n", (jsonResponse != nullptr) ? jsonResponse->Length() : 0);
- outBuf->catf("Connection: %s\n\n", keepOpen ? "keep-alive" : "close");
- outBuf->Append(jsonResponse);
-
- Commit(keepOpen ? ResponderState::reading : ResponderState::free);
+ // Note that when using RTOS the following response MUST be small enough to fit in a single buffer.
+ // This is because the current task may get suspended e.g. when reading from SD card to build a file list,
+ // so other tasks may allocate buffers meanwhile, and the previous mechanism for ensuring that there is sufficient
+ // buffer space remaining don't work.
+ // This response is currently about 230 bytes long in the worst case.
+ outBuf->copy( "HTTP/1.1 200 OK\n"
+ "Cache-Control: no-cache, no-store, must-revalidate\n"
+ "Pragma: no-cache\n"
+ "Expires: 0\n"
+ "Access-Control-Allow-Origin: *\n"
+ "Content-Type: application/json\n"
+ );
+ outBuf->catf("Content-Length: %u\n", (jsonResponse != nullptr) ? jsonResponse->Length() : 0);
+ outBuf->catf("Connection: %s\n\n", keepOpen ? "keep-alive" : "close");
+ outBuf->Append(jsonResponse);
+
+ if (outBuf->HadOverflow())
+ {
+ // We ran out of buffers. Release the buffers we have and return false. The caller will retry later.
+ OutputBuffer::ReleaseAll(outBuf);
+ }
+ else
+ {
+ Commit(keepOpen ? ResponderState::reading : ResponderState::free);
+ }
+ }
}
// Process the message received. We have reached the end of the headers.
@@ -989,123 +985,127 @@ void HttpResponder::ProcessRequest()
return;
}
- if (StringEquals(commandWords[0], "GET"))
+ // Make sure we can get an output buffer before we process the request, or we won't be able to reply
+ if (outBuf != nullptr || OutputBuffer::Allocate(outBuf))
{
- if (StringStartsWith(commandWords[1], KO_START))
+ if (StringEquals(commandWords[0], "GET"))
{
- SendJsonResponse(commandWords[1] + KoFirst);
- }
- else if (commandWords[1][0] == '/' && StringStartsWith(commandWords[1] + 1, KO_START))
- {
- SendJsonResponse(commandWords[1] + 1 + KoFirst);
+ if (StringStartsWith(commandWords[1], KO_START))
+ {
+ SendJsonResponse(commandWords[1] + KoFirst);
+ }
+ else if (commandWords[1][0] == '/' && StringStartsWith(commandWords[1] + 1, KO_START))
+ {
+ SendJsonResponse(commandWords[1] + 1 + KoFirst);
+ }
+ else
+ {
+ SendFile(commandWords[1], true);
+ }
+ return;
}
- else
+
+ if (StringEquals(commandWords[0], "OPTIONS"))
{
- SendFile(commandWords[1], true);
+ outBuf->copy( "HTTP/1.1 200 OK\n"
+ "Allow: OPTIONS, GET, POST\n"
+ "Cache-Control: no-cache, no-store, must-revalidate\n"
+ "Pragma: no-cache\n"
+ "Expires: 0\n"
+ "Access-Control-Allow-Origin: *\n"
+ "Access-Control-Allow-Headers: Content-Type\n"
+ "Content-Length: 0\n"
+ "\n"
+ );
+ Commit();
+ return;
}
- return;
- }
- if (StringEquals(commandWords[0], "OPTIONS"))
- {
- outBuf->copy( "HTTP/1.1 200 OK\n"
- "Allow: OPTIONS, GET, POST\n"
- "Cache-Control: no-cache, no-store, must-revalidate\n"
- "Pragma: no-cache\n"
- "Expires: 0\n"
- "Access-Control-Allow-Origin: *\n"
- "Access-Control-Allow-Headers: Content-Type\n"
- "Content-Length: 0\n"
- "\n"
- );
- Commit();
- return;
- }
-
- if (CheckAuthenticated() && StringEquals(commandWords[0], "POST"))
- {
- const bool isUploadRequest = (StringEquals(commandWords[1], KO_START "upload"))
- || (commandWords[1][0] == '/' && StringEquals(commandWords[1] + 1, KO_START "upload"));
- if (isUploadRequest)
+ if (CheckAuthenticated() && StringEquals(commandWords[0], "POST"))
{
- const char* const filename = GetKeyValue("name");
- if (filename != nullptr)
+ const bool isUploadRequest = (StringEquals(commandWords[1], KO_START "upload"))
+ || (commandWords[1][0] == '/' && StringEquals(commandWords[1] + 1, KO_START "upload"));
+ if (isUploadRequest)
{
- // See how many bytes we expect to read
- bool contentLengthFound = false;
- for (size_t i = 0; i < numHeaderKeys; i++)
+ const char* const filename = GetKeyValue("name");
+ if (filename != nullptr)
{
- if (StringEquals(headers[i].key, "Content-Length"))
+ // See how many bytes we expect to read
+ bool contentLengthFound = false;
+ for (size_t i = 0; i < numHeaderKeys; i++)
{
- postFileLength = atoi(headers[i].value);
- contentLengthFound = true;
- break;
+ if (StringEquals(headers[i].key, "Content-Length"))
+ {
+ postFileLength = atoi(headers[i].value);
+ contentLengthFound = true;
+ break;
+ }
}
- }
- // Start POST file upload
- if (!contentLengthFound)
- {
- RejectMessage("invalid POST upload request");
- return;
- }
+ // Start POST file upload
+ if (!contentLengthFound)
+ {
+ RejectMessage("invalid POST upload request");
+ return;
+ }
- // Start a new file upload
- FileStore *file = GetPlatform().OpenFile(FS_PREFIX, filename, OpenMode::write);
- if (file == nullptr)
- {
- RejectMessage("could not create file");
- return;
+ // Start a new file upload
+ FileStore *file = GetPlatform().OpenFile(FS_PREFIX, filename, OpenMode::write);
+ if (file == nullptr)
+ {
+ RejectMessage("could not create file");
+ return;
- }
- StartUpload(file, filename);
+ }
+ StartUpload(file, filename);
- // Try to get the last modified file date and time
- const char* const lastModifiedString = GetKeyValue("time");
- if (lastModifiedString != nullptr)
- {
- struct tm timeInfo;
- memset(&timeInfo, 0, sizeof(timeInfo));
- if (strptime(lastModifiedString, "%Y-%m-%dT%H:%M:%S", &timeInfo) != nullptr)
+ // Try to get the last modified file date and time
+ const char* const lastModifiedString = GetKeyValue("time");
+ if (lastModifiedString != nullptr)
{
- fileLastModified = mktime(&timeInfo);
+ struct tm timeInfo;
+ memset(&timeInfo, 0, sizeof(timeInfo));
+ if (strptime(lastModifiedString, "%Y-%m-%dT%H:%M:%S", &timeInfo) != nullptr)
+ {
+ fileLastModified = mktime(&timeInfo);
+ }
+ else
+ {
+ fileLastModified = 0;
+ }
}
else
{
fileLastModified = 0;
}
- }
- else
- {
- fileLastModified = 0;
- }
- if (reprap.Debug(moduleWebserver))
- {
- GetPlatform().MessageF(UsbMessage, "Start uploading file %s length %lu\n", filename, postFileLength);
- }
- uploadedBytes = 0;
+ if (reprap.Debug(moduleWebserver))
+ {
+ GetPlatform().MessageF(UsbMessage, "Start uploading file %s length %lu\n", filename, postFileLength);
+ }
+ uploadedBytes = 0;
- // Keep track of the connection that is now uploading
- const uint32_t remoteIP = GetRemoteIP();
- const uint16_t remotePort = skt->GetRemotePort();
- for(size_t i = 0; i < numSessions; i++)
- {
- if (sessions[i].ip == remoteIP)
+ // Keep track of the connection that is now uploading
+ const uint32_t remoteIP = GetRemoteIP();
+ const uint16_t remotePort = skt->GetRemotePort();
+ for(size_t i = 0; i < numSessions; i++)
{
- sessions[i].postPort = remotePort;
- sessions[i].isPostUploading = true;
- break;
+ if (sessions[i].ip == remoteIP)
+ {
+ sessions[i].postPort = remotePort;
+ sessions[i].isPostUploading = true;
+ break;
+ }
}
+ return;
}
- return;
}
+ RejectMessage("only rr_upload is supported for POST requests");
+ }
+ else
+ {
+ RejectMessage("Unknown message type or not authenticated");
}
- RejectMessage("only rr_upload is supported for POST requests");
- }
- else
- {
- RejectMessage("Unknown message type or not authenticated");
}
}
@@ -1132,6 +1132,7 @@ void HttpResponder::DoUpload()
skt->Taken(len);
uploadedBytes += len;
+ (void)CheckAuthenticated(); // uploading may take a long time, so make sure the requester IP is not timed out
if (!fileBeingUploaded.Write(buffer, len))
{
uploadError = true;
diff --git a/src/Networking/W5500Ethernet/W5500Interface.cpp b/src/Networking/W5500Ethernet/W5500Interface.cpp
index 6b946e79..60a254f0 100644
--- a/src/Networking/W5500Ethernet/W5500Interface.cpp
+++ b/src/Networking/W5500Ethernet/W5500Interface.cpp
@@ -380,8 +380,7 @@ void W5500Interface::Spin(bool full)
void W5500Interface::Diagnostics(MessageType mtype)
{
- platform.MessageF(mtype, "=== Network ===\nState: %d\n", (int)state);
- HttpResponder::CommonDiagnostics(mtype);
+ platform.MessageF(mtype, "Interface state: %d\n", (int)state);
}
// Enable or disable the network
diff --git a/src/Platform.cpp b/src/Platform.cpp
index e8031e2c..4542e1a9 100644
--- a/src/Platform.cpp
+++ b/src/Platform.cpp
@@ -3002,7 +3002,7 @@ bool Platform::SetDriverMicrostepping(size_t driver, unsigned int microsteps, in
}
// Set the microstepping, returning true if successful. All drivers for the same axis must use the same microstepping.
-bool Platform::SetMicrostepping(size_t drive, int microsteps, int mode)
+bool Platform::SetMicrostepping(size_t drive, int microsteps, bool interp)
{
// Check that it is a valid microstepping number
const size_t numAxes = reprap.GetGCodes().GetTotalAxes();
@@ -3011,24 +3011,24 @@ bool Platform::SetMicrostepping(size_t drive, int microsteps, int mode)
bool ok = true;
for (size_t i = 0; i < axisDrivers[drive].numDrivers; ++i)
{
- ok = SetDriverMicrostepping(axisDrivers[drive].driverNumbers[i], microsteps, mode) && ok;
+ ok = SetDriverMicrostepping(axisDrivers[drive].driverNumbers[i], microsteps, interp) && ok;
}
return ok;
}
else if (drive < DRIVES)
{
- return SetDriverMicrostepping(extruderDrivers[drive - numAxes], microsteps, mode);
+ return SetDriverMicrostepping(extruderDrivers[drive - numAxes], microsteps, interp);
}
return false;
}
// Get the microstepping for a driver
-unsigned int Platform::GetDriverMicrostepping(size_t driver, int mode, bool& interpolation) const
+unsigned int Platform::GetDriverMicrostepping(size_t driver, bool& interpolation) const
{
#if HAS_SMART_DRIVERS
if (driver < numSmartDrivers)
{
- return SmartDrivers::GetMicrostepping(driver, mode, interpolation);
+ return SmartDrivers::GetMicrostepping(driver, interpolation);
}
// On-board drivers only support x16 microstepping without interpolation
interpolation = false;
@@ -3043,16 +3043,16 @@ unsigned int Platform::GetDriverMicrostepping(size_t driver, int mode, bool& int
}
// Get the microstepping for an axis or extruder
-unsigned int Platform::GetMicrostepping(size_t drive, int mode, bool& interpolation) const
+unsigned int Platform::GetMicrostepping(size_t drive, bool& interpolation) const
{
const size_t numAxes = reprap.GetGCodes().GetTotalAxes();
if (drive < numAxes)
{
- return GetDriverMicrostepping(axisDrivers[drive].driverNumbers[0], mode, interpolation);
+ return GetDriverMicrostepping(axisDrivers[drive].driverNumbers[0], interpolation);
}
else if (drive < DRIVES)
{
- return GetDriverMicrostepping(extruderDrivers[drive - numAxes], mode, interpolation);
+ return GetDriverMicrostepping(extruderDrivers[drive - numAxes], interpolation);
}
else
{
@@ -3348,7 +3348,7 @@ void Platform::RawMessage(MessageType type, const char *message)
}
else if ((type & LcdMessage) != 0)
{
- AppendAuxReply(message, (message[0] == '{') || (type & RawMessageFlag) != 0);
+ AppendAuxReply(message, message[0] == '{' || (type & RawMessageFlag) != 0);
}
if ((type & HttpMessage) != 0)
@@ -4419,18 +4419,51 @@ void STEP_TC_HANDLER()
{
const irqflags_t flags = cpu_irq_save();
const int32_t diff = (int32_t)(tim - GetInterruptClocksInterruptsDisabled()); // see how long we have to go
- if (diff < (int32_t)DDA::MinInterruptInterval) // if less than about 6us or already passed
+ if (diff < (int32_t)DDA::MinInterruptInterval) // if less than about 6us or already passed
{
cpu_irq_restore(flags);
- return true; // tell the caller to simulate an interrupt instead
+ return true; // tell the caller to simulate an interrupt instead
+ }
+
+ STEP_TC->TC_CHANNEL[STEP_TC_CHAN].TC_RA = tim; // set up the compare register
+
+ // We would like to clear any pending step interrupt. To do this, we must read the TC status register.
+ // Unfortunately, this would clear any other pending interrupts from the same TC.
+ // So we don't, and the step ISR must allow for getting called prematurely.
+ STEP_TC->TC_CHANNEL[STEP_TC_CHAN].TC_IER = TC_IER_CPAS; // enable the interrupt
+ cpu_irq_restore(flags);
+
+#ifdef MOVE_DEBUG
+ ++numInterruptsScheduled;
+ nextInterruptTime = tim;
+ nextInterruptScheduledAt = Platform::GetInterruptClocks();
+#endif
+ return false;
+}
+
+// Schedule an interrupt at the specified clock count, or return true if it has passed already
+// This version limits the time we can spend in the ISR
+/*static*/ bool Platform::ScheduleStepInterruptWithLimit(uint32_t tim, uint32_t isrStartTime)
+{
+ const irqflags_t flags = cpu_irq_save();
+ const uint32_t iClocks = GetInterruptClocksInterruptsDisabled();
+ if ((int32_t)(tim - iClocks) < (int32_t)DDA::MinInterruptInterval) // if less than about 6us to go or already passed
+ {
+ if (iClocks - isrStartTime < DDA::MaxStepInterruptTime) // if we haven't already spent too much time looping inside the ISR
+ {
+ cpu_irq_restore(flags);
+ return true; // tell the caller to simulate an interrupt instead
+ }
+ tim = iClocks + DDA::MinInterruptInterval; // delay the interrupt to avoid using all the CPU time
+ ++DDA::numHiccups;
}
- STEP_TC->TC_CHANNEL[STEP_TC_CHAN].TC_RA = tim; // set up the compare register
+ STEP_TC->TC_CHANNEL[STEP_TC_CHAN].TC_RA = tim; // set up the compare register
// We would like to clear any pending step interrupt. To do this, we must read the TC status register.
// Unfortunately, this would clear any other pending interrupts from the same TC.
// So we don't, and the step ISR must allow for getting called prematurely.
- STEP_TC->TC_CHANNEL[STEP_TC_CHAN].TC_IER = TC_IER_CPAS; // enable the interrupt
+ STEP_TC->TC_CHANNEL[STEP_TC_CHAN].TC_IER = TC_IER_CPAS; // enable the interrupt
cpu_irq_restore(flags);
#ifdef MOVE_DEBUG
diff --git a/src/Platform.h b/src/Platform.h
index 9c9477d2..8b623e11 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -333,6 +333,7 @@ public:
static uint32_t GetInterruptClocks() __attribute__ ((hot)); // Get the interrupt clock count
static uint32_t GetInterruptClocksInterruptsDisabled() __attribute__ ((hot)); // Get the interrupt clock count, when we know already that interrupts are disabled
static bool ScheduleStepInterrupt(uint32_t tim) __attribute__ ((hot)); // Schedule an interrupt at the specified clock count, or return true if it has passed already
+ static bool ScheduleStepInterruptWithLimit(uint32_t tim, uint32_t isrStartTime) __attribute__ ((hot)); // Schedule an interrupt at the specified clock count, or return true if it has passed already
static void DisableStepInterrupt(); // Make sure we get no step interrupts
static bool ScheduleSoftTimerInterrupt(uint32_t tim); // Schedule an interrupt at the specified clock count, or return true if it has passed already
static void DisableSoftTimerInterrupt(); // Make sure we get no software timer interrupts
@@ -408,9 +409,9 @@ public:
float GetIdleCurrentFactor() const
{ return idleCurrentFactor; }
bool SetDriverMicrostepping(size_t driver, unsigned int microsteps, int mode);
- unsigned int GetDriverMicrostepping(size_t drive, int mode, bool& interpolation) const;
- bool SetMicrostepping(size_t axisOrExtruder, int microsteps, int mode);
- unsigned int GetMicrostepping(size_t axisOrExtruder, int mode, bool& interpolation) const;
+ unsigned int GetDriverMicrostepping(size_t drive, bool& interpolate) const;
+ bool SetMicrostepping(size_t axisOrExtruder, int microsteps, bool mode);
+ unsigned int GetMicrostepping(size_t axisOrExtruder, bool& interpolation) const;
void SetDriverStepTiming(size_t driver, const float microseconds[4]);
void GetDriverStepTiming(size_t driver, float microseconds[4]) const;
float DriveStepsPerUnit(size_t axisOrExtruder) const;
diff --git a/src/RepRap.cpp b/src/RepRap.cpp
index fa1196fd..469d7e1f 100644
--- a/src/RepRap.cpp
+++ b/src/RepRap.cpp
@@ -727,7 +727,7 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
for (size_t axis = 0; axis < numVisibleAxes; axis++)
{
const float coord = userPos[axis];
- response->catf("%c%.3f", ch, (double)((std::isnan(coord) || std::isinf(coord)) ? 9999.9 : coord));
+ response->catf("%c%.3f", ch, HideNan(coord));
ch = ',';
}
@@ -750,7 +750,7 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
ch = '[';
for (size_t drive = 0; drive < numVisibleAxes; drive++)
{
- response->catf("%c%.3f", ch, (double)liveCoordinates[drive]);
+ response->catf("%c%.3f", ch, HideNan(liveCoordinates[drive]));
ch = ',';
}
@@ -834,16 +834,16 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
ch = '[';
for(size_t i = 0; i < NUM_FANS; i++)
{
- response->catf("%c%.2f", ch, (double)(platform->GetFanValue(i) * 100.0));
+ response->catf("%c%.1f", ch, (double)(platform->GetFanValue(i) * 100.0));
ch = ',';
}
// Speed and Extrusion factors
- response->catf("],\"speedFactor\":%.2f,\"extrFactors\":", (double)(gCodes->GetSpeedFactor() * 100.0));
+ response->catf("],\"speedFactor\":%.1f,\"extrFactors\":", (double)(gCodes->GetSpeedFactor() * 100.0));
ch = '[';
for (size_t extruder = 0; extruder < GetExtrudersInUse(); extruder++)
{
- response->catf("%c%.2f", ch, (double)(gCodes->GetExtrusionFactor(extruder) * 100.0));
+ response->catf("%c%.1f", ch, (double)(gCodes->GetExtrusionFactor(extruder) * 100.0));
ch = ',';
}
response->cat((ch == '[') ? "[]" : "]");
@@ -1050,33 +1050,36 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
#endif
// Spindles
- response->cat(",\"spindles\":[");
- for (size_t i = 0; i < MaxSpindles; i++)
+ if (gCodes->GetMachineType() == MachineType::cnc)
{
- if (i > 0)
+ response->cat(",\"spindles\":[");
+ for (size_t i = 0; i < MaxSpindles; i++)
{
- response->cat(',');
- }
+ if (i > 0)
+ {
+ response->cat(',');
+ }
- const Spindle& spindle = platform->AccessSpindle(i);
- response->catf("{\"current\":%1.f,\"active\":%1.f", (double)spindle.GetCurrentRpm(), (double)spindle.GetRpm());
- if (type == 2)
- {
- response->catf(",\"tool\":%d}", spindle.GetToolNumber());
- }
- else
- {
- response->cat('}');
+ const Spindle& spindle = platform->AccessSpindle(i);
+ response->catf("{\"current\":%.1f,\"active\":%.1f", (double)spindle.GetCurrentRpm(), (double)spindle.GetRpm());
+ if (type == 2)
+ {
+ response->catf(",\"tool\":%d}", spindle.GetToolNumber());
+ }
+ else
+ {
+ response->cat('}');
+ }
}
+ response->cat(']');
}
- response->cat(']');
/* Extended Status Response */
if (type == 2)
{
// Cold Extrude/Retract
- response->catf(",\"coldExtrudeTemp\":%1.f", (double)(heat->ColdExtrude() ? 0.0 : HOT_ENOUGH_TO_EXTRUDE));
- response->catf(",\"coldRetractTemp\":%1.f", (double)(heat->ColdExtrude() ? 0.0 : HOT_ENOUGH_TO_RETRACT));
+ response->catf(",\"coldExtrudeTemp\":%.1f", (double)(heat->ColdExtrude() ? 0.0 : HOT_ENOUGH_TO_EXTRUDE));
+ response->catf(",\"coldRetractTemp\":%.1f", (double)(heat->ColdExtrude() ? 0.0 : HOT_ENOUGH_TO_RETRACT));
// Controllable Fans
FansBitmap controllableFans = 0;
@@ -1090,7 +1093,7 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
response->catf(",\"controllableFans\":%lu", controllableFans);
// Maximum hotend temperature - DWC just wants the highest one
- response->catf(",\"tempLimit\":%1.f", (double)(heat->GetHighestTemperatureLimit()));
+ response->catf(",\"tempLimit\":%.1f", (double)(heat->GetHighestTemperatureLimit()));
// Endstops
uint32_t endstops = 0;
diff --git a/src/RepRapFirmware.cpp b/src/RepRapFirmware.cpp
index d108845b..93827b6f 100644
--- a/src/RepRapFirmware.cpp
+++ b/src/RepRapFirmware.cpp
@@ -300,6 +300,12 @@ void SafeStrncat(char *dst, const char *src, size_t length)
dst[length - 1] = 0;
}
+// Convert a float to double for passing to printf etc. If it is a NaN or infinity, convert it to 9999.9 to avoid getting JSON parse errors.
+double HideNan(float val)
+{
+ return (double)((std::isnan(val) || std::isinf(val)) ? 9999.9 : val);
+}
+
// Append a list of driver numbers to a string, with a space before each one
void ListDrivers(const StringRef& str, DriversBitmap drivers)
{
diff --git a/src/RepRapFirmware.h b/src/RepRapFirmware.h
index 25fe4bf2..fd4eda8d 100644
--- a/src/RepRapFirmware.h
+++ b/src/RepRapFirmware.h
@@ -138,6 +138,8 @@ int StringContains(const char* string, const char* match);
void SafeStrncpy(char *dst, const char *src, size_t length) pre(length != 0);
void SafeStrncat(char *dst, const char *src, size_t length) pre(length != 0);
+double HideNan(float val);
+
void ListDrivers(const StringRef& str, DriversBitmap drivers);
// Macro to assign an array from an initialiser list
diff --git a/src/Version.h b/src/Version.h
index 3397d1cc..22a64fb3 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -15,11 +15,11 @@
#endif
#ifndef VERSION
-# define VERSION "2.0" RTOSVER "beta2"
+# define VERSION "2.0" RTOSVER "beta3"
#endif
#ifndef DATE
-# define DATE "2018-04-19b1"
+# define DATE "2018-04-28b6"
#endif
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman"