diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/BugList.txt | 25 | ||||
-rw-r--r-- | src/DuetM/TMC22xx.cpp | 141 | ||||
-rw-r--r-- | src/DuetM/TMC22xx.h | 9 | ||||
-rw-r--r-- | src/DuetNG/TMC2660.cpp | 205 | ||||
-rw-r--r-- | src/DuetNG/TMC2660.h | 36 | ||||
-rw-r--r-- | src/GCodes/DriverMode.cpp | 29 | ||||
-rw-r--r-- | src/GCodes/DriverMode.h | 27 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer.cpp | 10 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer.h | 1 | ||||
-rw-r--r-- | src/GCodes/GCodes.cpp | 94 | ||||
-rw-r--r-- | src/GCodes/GCodes.h | 9 | ||||
-rw-r--r-- | src/GCodes/GCodes2.cpp | 94 | ||||
-rw-r--r-- | src/Heating/Sensors/TemperatureSensor.cpp | 2 | ||||
-rw-r--r-- | src/Heating/Sensors/Thermistor.cpp | 17 | ||||
-rw-r--r-- | src/Heating/Sensors/Thermistor.h | 1 | ||||
-rw-r--r-- | src/Movement/DDA.cpp | 24 | ||||
-rw-r--r-- | src/Movement/DDA.h | 3 | ||||
-rw-r--r-- | src/Movement/Move.cpp | 22 | ||||
-rw-r--r-- | src/Networking/HttpResponder.cpp | 319 | ||||
-rw-r--r-- | src/Networking/W5500Ethernet/W5500Interface.cpp | 3 | ||||
-rw-r--r-- | src/Platform.cpp | 59 | ||||
-rw-r--r-- | src/Platform.h | 7 | ||||
-rw-r--r-- | src/RepRap.cpp | 49 | ||||
-rw-r--r-- | src/RepRapFirmware.cpp | 6 | ||||
-rw-r--r-- | src/RepRapFirmware.h | 2 | ||||
-rw-r--r-- | src/Version.h | 4 |
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" |