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:
authorDavid Crocker <dcrocker@eschertech.com>2018-06-23 13:45:38 +0300
committerDavid Crocker <dcrocker@eschertech.com>2018-06-23 13:45:38 +0300
commit4a525abb1663ab4817b303501d59760f36eb9ea7 (patch)
tree06c3c18608e33483c7aec1bb052cf4b901d42404 /src
parent5db504363ecf7a00c2f1a687cadb29bda47c7f1e (diff)
Version 2.01beta1
Bug fixes: - When using a mixing extruder, the feed rate for extruder-only moves was incorrect - If additional axes were not created in the order UVWABC then incorrect homing files might be run (thanks chrishamm) - On the Duet Maestro, the 7th stepper step/dir pin numbers were swapped - If you paused a print during a G2/G3 arc move, on resuming it the arc centre was at the wrong place. This release defers the pause until the arc move is completed. - If a command that interrogated the network (e.g. M122 on the Duet WiFi) was sent from USB, PanelDue or another non-network channel, the network subsystem could be accessed by multiple tasks concurrently, causing network disconnections or other errors - When using a bltouch, between probe points the pin retracted, deployed and retracted again - M206 with no parameters didn't report the current axis offsets - During heating, the firmware returned M408 S0 responses to the PanelDue port even if the last request was M408 S2 - Fixed VBUS detection (thanks chrishamm) - If the resume threshold in the M911 command was set higher than the supply voltage then the save-on-power-off mechanism never got primed. It will now prime at thwe auto-save threshold plus 0.5V or the resume threshold, whichever is lower. - Fixed "2dtstc2diva=u" in debug printout - Where a G- or M-code command parameter was supposed to accept unsigned values only, if a negative value was supplied then it was accepted and converted to a large unsigned value New features and changed behaviour: - If the firmware gets stuck in a spin loop, the RTOS builds now discard LR and 16 stack dwords in order to get more useful information from the stack trace - Increased M999 delay to 1 second - The report generated by M122 now includes a list of mutexes and their owners - Added SW_ENC pin on CONN_SD to available GPIO ports (thanks chrishamm)
Diffstat (limited to 'src')
-rw-r--r--src/BugList.txt57
-rw-r--r--src/DuetM/Pins_DuetM.h4
-rw-r--r--src/DuetM/TMC22xx.cpp2
-rw-r--r--src/DuetNG/Pins_DuetNG.h3
-rw-r--r--src/FilamentMonitors/FilamentMonitor.cpp2
-rw-r--r--src/GCodes/GCodeInput.cpp2
-rw-r--r--src/GCodes/GCodeMachineState.h6
-rw-r--r--src/GCodes/GCodes.cpp53
-rw-r--r--src/GCodes/GCodes.h3
-rw-r--r--src/GCodes/GCodes2.cpp11
-rw-r--r--src/GCodes/GCodes3.cpp21
-rw-r--r--src/Heating/Sensors/DhtSensor.cpp2
-rw-r--r--src/Libraries/General/SafeStrtod.cpp44
-rw-r--r--src/Libraries/General/SafeStrtod.h11
-rw-r--r--src/Libraries/General/SafeVsnprintf.cpp19
-rw-r--r--src/Libraries/General/StringRef.h17
-rw-r--r--src/Movement/DDA.cpp28
-rw-r--r--src/Movement/Kinematics/Kinematics.cpp12
-rw-r--r--src/Movement/Kinematics/Kinematics.h3
-rw-r--r--src/Networking/ESP8266WiFi/WiFiInterface.cpp14
-rw-r--r--src/Networking/HttpResponder.cpp2
-rw-r--r--src/Networking/LwipEthernet/LwipEthernetInterface.cpp3
-rw-r--r--src/Networking/Network.cpp4
-rw-r--r--src/Networking/NetworkInterface.h2
-rw-r--r--src/Networking/TelnetResponder.cpp2
-rw-r--r--src/Networking/W5500Ethernet/W5500Interface.cpp110
-rw-r--r--src/Networking/W5500Ethernet/W5500Socket.cpp21
-rw-r--r--src/Platform.cpp18
-rw-r--r--src/RTOSIface.cpp8
-rw-r--r--src/RTOSIface.h19
-rw-r--r--src/RepRap.cpp16
-rw-r--r--src/Scanner.cpp20
-rw-r--r--src/Scanner.h2
-rw-r--r--src/Storage/FileInfoParser.cpp2
-rw-r--r--src/Storage/MassStorage.cpp9
-rw-r--r--src/Tasks.cpp30
-rw-r--r--src/Version.h6
37 files changed, 429 insertions, 159 deletions
diff --git a/src/BugList.txt b/src/BugList.txt
index 619a7bcd..e920e51f 100644
--- a/src/BugList.txt
+++ b/src/BugList.txt
@@ -189,17 +189,58 @@ Fixes in release 2.0:
- [done] can't load filaments because DWC doesn't give the option unless a filament is already loaded
- look at wifi disconnect issue, https://forum.duet3d.com/topic/4341/wifi-module-keeps-disconnecting/64
-Planned for 2.01:
+Planned for 2.01/1.21.2:
+
+WiFi:
+- [resolve library incompatibility] New ESP8266 SDK
+- [done] check what's new in Arduino ESP 2.4.1
+
+Bug fixes/investigations:
+- [done, test] sqrt(2) error factor in extrusion-only moves, see Michael's email
+- [done] Homing wrong if axes not labeled sequentially, see Christian's email of 18/6/18
+- [done, test] Fix "2dtstc2diva=u" in debug printout, https://forum.duet3d.com/topic/3139/high-level-of-steperrors-what-can-cause-them/5
+- [done, test] when stuck in spin loop, in RTOS build discard LR and 16 stack dwords, they are within FreeRTOS
+- [done, test] Rotating magnet monitor reports "allowed movement 2147483647% to 160%" in M591 response, see Tony's email (caused by R-1 in M591 command)
+- [done, test] Duet Maestro 7th stepper step/dir pin numbers swapped
+- [done, test] Pausing during an arc move, on resume the arc centre is at the wrong place. Temporarily don't allow pause during an arc move?
+- [done] WiFi needs a mutex on SendCommand because WiFiInterface::Diagnostics and SetHostName can be called from outside the Network task. Similarly for W5500 Ethernet interface.
+- [done, test] bltouch retracts, deploys, retracts between probes. Is the M280 retract command being queued until the end of the movement command?
+- [checked, ok] Check that in M569, T3 is equivalent to T3:3:3:3, see https://forum.duet3d.com/topic/5579/expansion-stepper-breakout-tb6600
+- [done, test] M206 with no parameters to report axis offsets
+- [done] During heating, returns M408 S0 responses to PanelDue port even if the last request was M408 S2, see https://forum.duet3d.com/topic/5761/printer-is-sending-m408-s0-when-heating.
+- [done in CoreNG] Fix VBUS detection in CoreNG, see chrishamm's branch
+- [done] Add SW_ENC pin on CONN_SD to available GPIO ports
+- [done] Increased M999 delay to 1 second
+- [done] If M911 resume threshold is set too high, save-on-power-off never primes itself
+
+- Test gcode file that pauses between parts, https://forum.duet3d.com/topic/5702/printer-keeps-pausing-during-print/15
+- Doesn't find DueX5 after M999 reset? https://forum.duet3d.com/topic/5713/duet2-with-2-0-rtos-looses-duex5-on-reset
+- stuck in spin loop, https://forum.duet3d.com/topic/5674/damned-crash-stuck-in-spin-loop
+- step errors, see https://forum.duet3d.com/topic/3139/high-level-of-steperrors-what-can-cause-them/5
+- Investigate failed .BMP conversion, https://forum.duet3d.com/topic/5623/boot-logo-corruption-in-1-21/2
+- Duet Maestro default to TMC2224 drivers on expansion? How to detect them?
+- M28 and M29 in a macro, https://forum.duet3d.com/topic/5642/filament-load-macro-writing-to-file-in-sys. Move fileBeingWritten to GCodeBuffer, get rid of writingFileDirectory.
+- Is there a kink during auto tuning? https://forum.duet3d.com/topic/5582/hot-end-auto-tuning-failed-due. Could explain oddly low dead times from auto tuning.
+- Does bltouch need a default recovery time to allow it to deploy? (probably not)
+- Should bltouch use digital probe mode? Some users having problems with P25 in G31 command.
+- Test Duet 06/085 DHCP problem again, see https://forum.duet3d.com/topic/5572/it-s-out-reprapfirmware-2-0-and-1-21-1-released/16 for config.g files
+- Retry after SD card error?
+
+Other:
+- @wilriker PR for M106 PWM limit
+- [done, test] display mutex owners in task diagnostics
+
+Planned for 2.02:
+- WiFi continuous auto reconnect, or extra M552 parameter? See https://forum.duet3d.com/topic/5765/wifi-module-auto-reconnect
+- Better dead time measurement during auto tuning. Measure both turn-on and turn-off?
- Bezier speed curves or other S-curve acceleration, e.g. look at https://github.com/MarlinFirmware/Marlin/pull/10373/files
-- Option to send M280 servo commands just a few times instead of continuously, for E3D and BLTouch
+- Option to send M280 servo commands just a few times instead of continuously, for E3D
- Recovery from SD card errors during a print (Dan)
- Danny's modified SCARA kinematics (workpiece is on a plate, extruder is fixed)
- Laser support via G1 S parameter, see https://forum.duet3d.com/topic/4702/laser-cnc-support-in-rrf-gcode-semantics/4
- Look at pushover notification support, https://forum.duet3d.com/topic/169/notification-via-pushover-or-other-service/45
- M3 R parameter so it can restore the spinder/laser after a pause (https://forum.duet3d.com/topic/5418/cnc-laser-m3-unpause-r-parameter)
- M81: don't give low voltage warnings when main power has just been turned off
-- Does bltouch need a default recovery time?
-- Should bltouch use digital probe mode? Some users having problems with P25 in G31 command.
- M584 when assigning a drive, unmap any existing assignment. Also allow an axis to be mapped to driver -1.
- Add S4 option to G1 command, like S1 but no endstop checks (needed for CoreXY, CoreXZ)
- CNC: look at G17/18/19, see https://forum.duet3d.com/topic/4669/ooznest-workbee-screw-driven
@@ -208,8 +249,9 @@ Planned for 2.01:
- Apostrophe in quoted filename: can we make apostrophe special in SSIDs/passwords but not filenames?
- If wifi module gets stuck in starting or changing mode state, reset it again
- If wifi disconnects when in client mode, keep retrying the connection
+- M140 command to set default bed heaters for M140 S commands (e.g. M140 P0:1:2)
-Other (some of these may be in 2.01):
+Other (some of these may be in 2.02):
- Update PanelDue firmware via Duet
- Use Heat task to read DHT sensors?
- Add option R4 to M915 command, to do an emergency stop (useful for Z motor)
@@ -282,16 +324,11 @@ p->ref == 1 in WiFi
Later versions:
-- Multiple bed heaters, https://www.duet3d.com/forum/thread.php?pid=33903#p33903
-- Use M140H1:2:3 to set multiple bed heater numbers
- Check https://www.duet3d.com/forum/thread.php?pid=33951#p33951
- Option to not broadcast SSID?
-- On file read error during SD card print, treat like a temperature fault
- Support faster homing by using interrupts to check homing switch states
- Allow manual bed probing to be aborted
-- Implement G1 S4? (like S2 but always relative)
-- Add work coordinates? https://www.duet3d.com/forum/thread.php?pid=27128#p27128
- Don't do pressure advance during accel/decel of sequences of short segments
- Arc move with same finish and start coordinates to do complete circle
- Add T parameter to M207
diff --git a/src/DuetM/Pins_DuetM.h b/src/DuetM/Pins_DuetM.h
index 50cf453a..3825e32b 100644
--- a/src/DuetM/Pins_DuetM.h
+++ b/src/DuetM/Pins_DuetM.h
@@ -67,8 +67,8 @@ constexpr size_t NUM_SERIAL_CHANNELS = 2; // The number of serial IO channels
// Drivers
constexpr Pin GlobalTmcEnablePin = 1; // The pin that drives ENN of all drivers
constexpr Pin ENABLE_PINS[DRIVES] = { NoPin, NoPin, NoPin, NoPin, NoPin, 63, 61 };
-constexpr Pin STEP_PINS[DRIVES] = { 56, 38, 64, 40, 41, 67, 60 };
-constexpr Pin DIRECTION_PINS[DRIVES] = { 54, 8, 30, 33, 42, 18, 57 };
+constexpr Pin STEP_PINS[DRIVES] = { 56, 38, 64, 40, 41, 67, 57 };
+constexpr Pin DIRECTION_PINS[DRIVES] = { 54, 8, 30, 33, 42, 18, 60 };
constexpr Pin DriverMuxPins[3] = { 50, 52, 53 }; // Pins that control the UART multiplexer, LSB first
// Endstops
diff --git a/src/DuetM/TMC22xx.cpp b/src/DuetM/TMC22xx.cpp
index a02c4ff0..5f373c26 100644
--- a/src/DuetM/TMC22xx.cpp
+++ b/src/DuetM/TMC22xx.cpp
@@ -44,7 +44,7 @@ constexpr uint32_t GCONF_INT_RSENSE = 1 << 1; // use internal sense resistors
constexpr uint32_t GCONF_SPREAD_CYCLE = 1 << 2; // use spread cycle mode (else stealthchop mode)
constexpr uint32_t GCONF_REV_DIR = 1 << 3; // reverse motor direction
constexpr uint32_t GCONF_INDEX_OTPW = 1 << 4; // INDEX output shows over temperature warning (else it shows first microstep position)
-constexpr uint32_t GCONF_INDEX_PULSE = 1 << 5; // INDEX output shows pulses form internal pulse generator, else as set by GCONF_INDEX_OTPW
+constexpr uint32_t GCONF_INDEX_PULSE = 1 << 5; // INDEX output shows pulses from internal pulse generator, else as set by GCONF_INDEX_OTPW
constexpr uint32_t GCONF_UART = 1 << 6; // PDN_UART used for UART interface (else used for power down)
constexpr uint32_t GCONF_MSTEP_REG = 1 << 7; // microstep resolution set by MSTEP register (else by MS1 and MS2 pins)
constexpr uint32_t GCONF_MULTISTEP_FILT = 1 << 8; // pulse generation optimised for >750Hz full stepping frequency
diff --git a/src/DuetNG/Pins_DuetNG.h b/src/DuetNG/Pins_DuetNG.h
index 53624560..3aa83879 100644
--- a/src/DuetNG/Pins_DuetNG.h
+++ b/src/DuetNG/Pins_DuetNG.h
@@ -162,7 +162,8 @@ constexpr Pin ROLAND_RTS_PIN = xx; // Expansion pin 12, PA13_RXD1
// This is the mapping from logical pins 60+ to firmware pin numbers
constexpr Pin SpecialPinMap[] =
{
- 24, 97, 98, 99 // We allow CS5-CS8 to be used because few users need >4 thermocouples or RTDs
+ 24, 97, 98, 99, // We allow CS5-CS8 to be used because few users need >4 thermocouples or RTDs
+ 7 // SW_ENC on CONN_SD
};
constexpr Pin DueX5GpioPinMap[] = { 211, 210, 209, 208 }; // Pins 100-103 map to GPIO 1-4 on DueX5
// We also allow pins 120-135 to be used if there is an additional SX1509B expander
diff --git a/src/FilamentMonitors/FilamentMonitor.cpp b/src/FilamentMonitors/FilamentMonitor.cpp
index 4c5254c2..a9482654 100644
--- a/src/FilamentMonitors/FilamentMonitor.cpp
+++ b/src/FilamentMonitors/FilamentMonitor.cpp
@@ -71,7 +71,7 @@ bool FilamentMonitor::ConfigurePin(GCodeBuffer& gb, const StringRef& reply, Inte
// Static initialisation
/*static*/ void FilamentMonitor::InitStatic()
{
- filamentSensorsMutex.Create();
+ filamentSensorsMutex.Create("FilamentSensors");
}
// Handle M591
diff --git a/src/GCodes/GCodeInput.cpp b/src/GCodes/GCodeInput.cpp
index 35371c26..2e7383db 100644
--- a/src/GCodes/GCodeInput.cpp
+++ b/src/GCodes/GCodeInput.cpp
@@ -201,7 +201,7 @@ void NetworkGCodeInput::Put(MessageType mtype, const char *buf)
NetworkGCodeInput::NetworkGCodeInput() : RegularGCodeInput()
{
- bufMutex.Create();
+ bufMutex.Create("NetworkGCodeInput");
}
// Fill a GCodeBuffer with the last available G-code
diff --git a/src/GCodes/GCodeMachineState.h b/src/GCodes/GCodeMachineState.h
index 88404df0..323ba860 100644
--- a/src/GCodes/GCodeMachineState.h
+++ b/src/GCodes/GCodeMachineState.h
@@ -50,23 +50,25 @@ enum class GCodeState : uint8_t
stopping,
sleeping,
- // These next 7 must be contiguous
+ // These next 9 must be contiguous
gridProbing1,
gridProbing2a,
gridProbing2b,
gridProbing3,
gridProbing4,
+ gridProbing4a,
gridProbing5,
gridProbing6,
gridProbing7,
- // These next 9 must be contiguous
+ // These next 10 must be contiguous
probingAtPoint0,
probingAtPoint1,
probingAtPoint2a,
probingAtPoint2b,
probingAtPoint3,
probingAtPoint4,
+ probingAtPoint4a,
probingAtPoint5,
probingAtPoint6,
probingAtPoint7,
diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp
index 47f7947e..0fd79e68 100644
--- a/src/GCodes/GCodes.cpp
+++ b/src/GCodes/GCodes.cpp
@@ -269,6 +269,19 @@ float GCodes::FractionOfFilePrinted() const
return (float)(fileBeingPrinted.GetPosition() - bytesCached) / (float)len;
}
+// Return the current position of the file being printed in bytes
+FilePosition GCodes::GetFilePosition() const
+{
+ const FileData& fileBeingPrinted = fileGCode->OriginalMachineState().fileState;
+ if (!fileBeingPrinted.IsLive())
+ {
+ return 0;
+ }
+
+ const FilePosition bytesCached = fileGCode->IsDoingFileMacro() ? 0: fileInput->BytesCached();
+ return fileBeingPrinted.GetPosition() - bytesCached;
+}
+
// Start running the config file
// We use triggerCGode as the source to prevent any triggers being executed until we have finished
bool GCodes::RunConfigFile(const char* fileName)
@@ -859,13 +872,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply)
g30zHeightErrorSum += g30zHeightError;
}
- // Move back up to the dive height
- moveBuffer.SetDefaults();
- moveBuffer.coords[Z_AXIS] = platform.GetZProbeStartingHeight();
- moveBuffer.feedRate = platform.GetZProbeTravelSpeed();
- NewMoveAvailable(1);
gb.AdvanceState();
-
if (platform.GetZProbeType() == ZProbeType::blTouch)
{
DoFileMacro(gb, RETRACTPROBE_G, false); // bltouch needs to be retracted when it triggers
@@ -873,6 +880,15 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply)
}
break;
+ case GCodeState::gridProbing4a: // ready to lift the probe after probing the current grid probe point
+ // Move back up to the dive height
+ moveBuffer.SetDefaults();
+ moveBuffer.coords[Z_AXIS] = platform.GetZProbeStartingHeight();
+ moveBuffer.feedRate = platform.GetZProbeTravelSpeed();
+ NewMoveAvailable(1);
+ gb.AdvanceState();
+ break;
+
case GCodeState::gridProbing5: // finished probing a point and moved back to the dive height
if (LockMovementAndWaitForStandstill(gb))
{
@@ -1131,20 +1147,23 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply)
}
}
- // Move back up to the dive height before we change anything, in particular before we adjust leadscrews
- moveBuffer.SetDefaults();
- moveBuffer.coords[Z_AXIS] = platform.GetZProbeStartingHeight();
- moveBuffer.feedRate = platform.GetZProbeTravelSpeed();
- NewMoveAvailable(1);
gb.AdvanceState();
-
if (platform.GetZProbeType() == ZProbeType::blTouch)
{
- DoFileMacro(gb, RETRACTPROBE_G, false); // bltouch needs to be retracted when it triggers
+ DoFileMacro(gb, RETRACTPROBE_G, false); // bltouch needs to be retracted when it triggers
}
}
break;
+ case GCodeState::probingAtPoint4a:
+ // Move back up to the dive height before we change anything, in particular before we adjust leadscrews
+ moveBuffer.SetDefaults();
+ moveBuffer.coords[Z_AXIS] = platform.GetZProbeStartingHeight();
+ moveBuffer.feedRate = platform.GetZProbeTravelSpeed();
+ NewMoveAvailable(1);
+ gb.AdvanceState();
+ break;
+
case GCodeState::probingAtPoint5:
// Here when we have moved the head back up to the dive height
if (LockMovementAndWaitForStandstill(gb))
@@ -2608,7 +2627,7 @@ const char* GCodes::DoArcMove(GCodeBuffer& gb, bool clockwise)
// Adjust the move parameters to account for segmentation and/or part of the move having been done already
void GCodes::FinaliseMove(GCodeBuffer& gb)
{
- moveBuffer.canPauseAfter = (moveBuffer.endStopsToCheck == 0);
+ moveBuffer.canPauseAfter = (moveBuffer.endStopsToCheck == 0) && !doingArcMove; // pausing during an arc move isn't save because the arc centre get recomputed incorrectly when we resume
moveBuffer.filePos = (&gb == fileGCode) ? gb.GetFilePosition(fileInput->BytesCached()) : noFilePosition;
if (totalSegments > 1)
@@ -2663,6 +2682,10 @@ bool GCodes::ReadMove(RawMove& m)
}
}
m.proportionLeft = 0.0;
+ if (doingArcMove)
+ {
+ m.canPauseAfter = true; // we can pause after the final segment of an arc move
+ }
ClearMove();
}
else
@@ -4721,7 +4744,7 @@ void GCodes::CheckReportDue(GCodeBuffer& gb, const StringRef& reply) const
if (lastAuxStatusReportType >= 0)
{
// Send a standard status response for PanelDue
- OutputBuffer * const statusBuf = GenerateJsonStatusResponse(0, -1, ResponseSource::AUX);
+ OutputBuffer * const statusBuf = GenerateJsonStatusResponse(lastAuxStatusReportType, -1, ResponseSource::AUX);
if (statusBuf != nullptr)
{
platform.AppendAuxReply(statusBuf, true);
diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h
index 29190528..0c0de8ce 100644
--- a/src/GCodes/GCodes.h
+++ b/src/GCodes/GCodes.h
@@ -145,6 +145,7 @@ public:
void GetCurrentCoordinates(const StringRef& s) const; // Write where we are into a string
bool DoingFileMacro() const; // Or still busy processing a macro file?
float FractionOfFilePrinted() const; // Get fraction of file printed
+ FilePosition GetFilePosition() const; // Return the current position of the file being printed in bytes
void Diagnostics(MessageType mtype); // Send helpful information out
bool RunConfigFile(const char* fileName); // Start running the config file
@@ -294,7 +295,7 @@ private:
void FinishWrite(GCodeBuffer& gb); // Finish writing to the file and respond
bool SendConfigToLine(); // Deal with M503
- GCodeResult OffsetAxes(GCodeBuffer& gb); // Set offsets
+ GCodeResult OffsetAxes(GCodeBuffer& gb, const StringRef& reply); // Set/report offsets
#if SUPPORT_WORKPLACE_COORDINATES
GCodeResult GetSetWorkplaceCoordinates(GCodeBuffer& gb, const StringRef& reply, bool compute); // Set workspace coordinates
diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp
index af298d35..a87c8d7a 100644
--- a/src/GCodes/GCodes2.cpp
+++ b/src/GCodes/GCodes2.cpp
@@ -1928,7 +1928,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
break;
case 206: // Offset axes
- result = OffsetAxes(gb);
+ result = OffsetAxes(gb, reply);
break;
case 207: // Set firmware retraction details
@@ -2511,7 +2511,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
{
const int type = gb.Seen('S') ? gb.GetIValue() : 0;
const int seq = gb.Seen('R') ? gb.GetIValue() : -1;
- if (&gb == auxGCode)
+ if (&gb == auxGCode && (type == 0 || type == 2))
{
lastAuxStatusReportType = type;
}
@@ -3800,7 +3800,10 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
{
if (reprap.GetScanner().IsEnabled())
{
- result = GetGCodeResultFromFinished(reprap.GetScanner().Register());
+ reprap.GetScanner().Register();
+
+ // The Scanner module will attempt to run a macro via this G-code source so we're not done yet
+ result = GCodeResult::notFinished;
}
else
{
@@ -4163,7 +4166,7 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply)
break;
case 999:
- result = DoDwellTime(gb, 500); // wait half a second to allow the response to be sent back to the web server, otherwise it may retry
+ result = DoDwellTime(gb, 1000); // wait a second to allow the response to be sent back to the web server, otherwise it may retry
if (result != GCodeResult::notFinished)
{
reprap.EmergencyStop(); // this disables heaters and drives - Duet WiFi pre-production boards need drives disabled here
diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp
index 05cd8948..fc33b569 100644
--- a/src/GCodes/GCodes3.cpp
+++ b/src/GCodes/GCodes3.cpp
@@ -173,8 +173,9 @@ GCodeResult GCodes::SetPositions(GCodeBuffer& gb)
// Offset the axes by the X, Y, and Z amounts in the M226 code in gb. The actual movement occurs on the next move command.
// It's not clear from the description in the reprap.org wiki whether offsets are cumulative or not. We now assume they are not.
// Note that M206 offsets are actually negative offsets.
-GCodeResult GCodes::OffsetAxes(GCodeBuffer& gb)
+GCodeResult GCodes::OffsetAxes(GCodeBuffer& gb, const StringRef& reply)
{
+ bool seen = false;
for (size_t axis = 0; axis < numVisibleAxes; axis++)
{
if (gb.Seen(axisLetters[axis]))
@@ -185,6 +186,22 @@ GCodeResult GCodes::OffsetAxes(GCodeBuffer& gb)
axisOffsets[axis]
#endif
= -(gb.GetFValue() * distanceScale);
+ seen = true;
+ }
+ }
+
+ if (!seen)
+ {
+ reply.printf("Axis offsets:");
+ for (size_t axis = 0; axis < numVisibleAxes; axis++)
+ {
+ reply.catf(" %c%.2f", axisLetters[axis],
+#if SUPPORT_WORKPLACE_COORDINATES
+ -(double)(workplaceCoordinates[0][axis]/distanceScale)
+#else
+ -(double)(axisOffsets[axis]/distanceScale)
+#endif
+ );
}
}
@@ -230,7 +247,7 @@ GCodeResult GCodes::GetSetWorkplaceCoordinates(GCodeBuffer& gb, const StringRef&
reply.printf("Origin of workplace %" PRIu32 ":", cs);
for (size_t axis = 0; axis < numVisibleAxes; axis++)
{
- reply.catf(" %c%.2f", axisLetters[axis], (double)workplaceCoordinates[cs - 1][axis]);
+ reply.catf(" %c%.2f", axisLetters[axis], (double)(workplaceCoordinates[cs - 1][axis]/distanceScale));
}
}
return GCodeResult::ok;
diff --git a/src/Heating/Sensors/DhtSensor.cpp b/src/Heating/Sensors/DhtSensor.cpp
index 15da14bb..7340b951 100644
--- a/src/Heating/Sensors/DhtSensor.cpp
+++ b/src/Heating/Sensors/DhtSensor.cpp
@@ -144,7 +144,7 @@ DhtSensorHardwareInterface *DhtSensorHardwareInterface::Create(unsigned int rela
/*static*/ void DhtSensorHardwareInterface::InitStatic()
{
- dhtMutex.Create();
+ dhtMutex.Create("DHT");
}
/*static*/ TemperatureError DhtSensorHardwareInterface::GetTemperatureOrHumidity(unsigned int relativeChannel, float& t, bool wantHumidity)
diff --git a/src/Libraries/General/SafeStrtod.cpp b/src/Libraries/General/SafeStrtod.cpp
index 0701bc72..1c27a01f 100644
--- a/src/Libraries/General/SafeStrtod.cpp
+++ b/src/Libraries/General/SafeStrtod.cpp
@@ -4,18 +4,22 @@
* Created on: 4 Apr 2018
* Author: David
*
- * This is a replacement for strtof() in the C standard library. That version has two problems:
+ * This is a replacement for strtod() and strtof() in the C standard library. Those versions have two problems:
* 1. It is not reentrant. We can make it so by defining configUSE_NEWLIB_REENTRANT in FreeRTOS, but that makes the tasks much bigger.
* 2. It allocates and releases heap memory, which is not nice.
*
* Limitations of this version
* 1. Rounding to nearest double may not always be correct.
- * 2. May not handle overflow for stupidly large numbers correctly.
+ * 2. Does not handle overflow for stupidly large numbers correctly.
*/
#include <cctype>
#include <cmath>
#include <climits>
+#include <cstdlib>
+
+#include "SafeStrtod.h"
+#undef strtoul // Undo the macro definition of strtoul in SafeStrtod.h so that we can call it in this file
double SafeStrtod(const char *s, const char **p)
{
@@ -131,4 +135,40 @@ float SafeStrtof(const char *s, const char **p)
return (float)SafeStrtod(s, p);
}
+unsigned long SafeStrtoul(const char *s, const char **endptr, int base)
+{
+ // strtoul() accepts a leading minus-sign, which we don't want to allow
+ while (*s == ' ' || *s == '\t')
+ {
+ ++s;
+ }
+ if (*s == '-')
+ {
+ if (endptr != nullptr)
+ {
+ *endptr = s;
+ }
+ return 0;
+ }
+ return strtoul(s, const_cast<char**>(endptr), base);
+}
+
+unsigned long SafeStrtoul(char *s, char **endptr, int base)
+{
+ // strtoul() accepts a leading minus-sign, which we don't want to allow
+ while (*s == ' ' || *s == '\t')
+ {
+ ++s;
+ }
+ if (*s == '-')
+ {
+ if (endptr != nullptr)
+ {
+ *endptr = s;
+ }
+ return 0;
+ }
+ return strtoul(s, endptr, base);
+}
+
// End
diff --git a/src/Libraries/General/SafeStrtod.h b/src/Libraries/General/SafeStrtod.h
index ae83228c..d1dc1d5c 100644
--- a/src/Libraries/General/SafeStrtod.h
+++ b/src/Libraries/General/SafeStrtod.h
@@ -16,15 +16,8 @@ inline long SafeStrtol(const char *s, const char **endptr = nullptr, int base =
return strtol(s, const_cast<char**>(endptr), base);
}
-inline unsigned long SafeStrtoul(const char *s, const char **endptr = nullptr, int base = 10)
-{
- return strtoul(s, const_cast<char**>(endptr), base);
-}
-
-inline unsigned long SafeStrtoul(char *s, char **endptr = nullptr, int base = 10)
-{
- return strtoul(s, endptr, base);
-}
+unsigned long SafeStrtoul(const char *s, const char **endptr = nullptr, int base = 10);
+unsigned long SafeStrtoul(char *s, char **endptr = nullptr, int base = 10);
#define strtod(s, p) Do_not_use_strtod_use_SafeStrtod_instead
#define strtof(s, p) Do_not_use_strtof_use_SafeStrtof_instead
diff --git a/src/Libraries/General/SafeVsnprintf.cpp b/src/Libraries/General/SafeVsnprintf.cpp
index 0952c243..9b171ce0 100644
--- a/src/Libraries/General/SafeVsnprintf.cpp
+++ b/src/Libraries/General/SafeVsnprintf.cpp
@@ -15,7 +15,7 @@
Changes for the FreeRTOS ports:
- The dot in "%-8.8s"
- - The specifiers 'l' (long) and 'L' (long long)
+ - The specifiers 'l' (long) and 'll' (long long)
- The specifier 'u' for unsigned
- Dot notation for IP addresses:
sprintf("IP = %xip\n", 0xC0A80164);
@@ -546,14 +546,15 @@ static void tiny_print(SStringBuf& apBuf, const char *format, va_list args)
if (ch == 'l')
{
ch = *format++;
- apBuf.flags.long32 = 1;
- // Makes no difference as u32 == long
- }
- if (ch == 'L')
- {
- ch = *format++;
- apBuf.flags.long64 = 1;
- // Does make a difference
+ if (ch == 'l')
+ {
+ ch = *format++;
+ apBuf.flags.long64 = 1;
+ }
+ else
+ {
+ apBuf.flags.long32 = 1;
+ }
}
if (ch == 'f' || ch == 'e' || ch == 'F' || ch == 'E')
diff --git a/src/Libraries/General/StringRef.h b/src/Libraries/General/StringRef.h
index d6d84a31..74a52ddd 100644
--- a/src/Libraries/General/StringRef.h
+++ b/src/Libraries/General/StringRef.h
@@ -54,7 +54,7 @@ public:
const char *c_str() const { return storage; }
size_t strlen() const { return Strnlen(storage, Len); }
bool IsEmpty() const { return storage[0] == 0; }
-// char *Pointer() { return storage; }
+ bool IsFull() const { return strlen() == Len; }
char& operator[](size_t index) { return storage[index]; }
char operator[](size_t index) const { return storage[index]; }
constexpr size_t Capacity() const { return Len; }
@@ -74,6 +74,7 @@ public:
bool ConstantTimeEquals(String<Len> other) const;
void Truncate(size_t len);
+ void Erase(size_t pos, size_t count = 1);
private:
char storage[Len + 1];
@@ -133,6 +134,20 @@ template<size_t Len> void String<Len>::Truncate(size_t len)
}
}
+template<size_t Len> void String<Len>::Erase(size_t pos, size_t count)
+{
+ const size_t len = strlen();
+ if (pos < len)
+ {
+ while (pos + count < len)
+ {
+ storage[pos] = storage[pos + count];
+ ++pos;
+ }
+ storage[pos] = 0;
+ }
+}
+
template<size_t Len> bool String<Len>::EndsWith(char c) const
{
const size_t len = strlen();
diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp
index a969c6dc..dfa7ae75 100644
--- a/src/Movement/DDA.cpp
+++ b/src/Movement/DDA.cpp
@@ -266,6 +266,7 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping)
}
xyMoving = false;
+ bool axesMoving = false;
bool extruding = false; // we set this true if extrusion was commanded, even if it is too small to do
bool realMove = false;
float accelerations[DRIVES];
@@ -345,6 +346,10 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping)
}
}
}
+ else
+ {
+ axesMoving = true;
+ }
}
}
@@ -413,18 +418,25 @@ bool DDA::Init(GCodes::RawMove &nextMove, bool doMotorMapping)
// This means that the user gets the feed rate that he asked for. It also makes the delta calculations simpler.
// First do the bed tilt compensation for deltas.
directionVector[Z_AXIS] += (directionVector[X_AXIS] * k.GetTiltCorrection(X_AXIS)) + (directionVector[Y_AXIS] * k.GetTiltCorrection(Y_AXIS));
-
totalDistance = NormaliseXYZ();
}
+ else if (axesMoving)
+ {
+ // Some axes are moving, but not axes that X or Y are mapped to. Normalise the movement to the vector sum of the axes that are moving.
+ totalDistance = Normalise(directionVector, DRIVES, numAxes);
+ }
else
{
- // Extruder-only movement, or movement of additional axes, or a combination.
- // Currently we normalise vector sum of all drive movement to unit length.
- // Alternatives would be:
- // 1. Normalise the largest one to unit length. This means that when retracting multiple filaments, they all get the requested retract speed.
- // 2. Normalise the sum to unit length. This means that when we use mixing, we get the requested extrusion rate at the nozzle.
- // 3. Normalise the sum to the sum of the mixing coefficients (which we would have to include in the move details).
- totalDistance = Normalise(directionVector, DRIVES, DRIVES);
+ // Extruder-only movement. Normalise so that the magnitude is the total absolute movement. This gives the correct feed rate for mixing extruders.
+ totalDistance = 0.0;
+ for (size_t d = 0; d < DRIVES; d++)
+ {
+ totalDistance += fabs(directionVector[d]);
+ }
+ if (totalDistance > 0.0) // should always be true
+ {
+ Scale(directionVector, 1.0/totalDistance, DRIVES);
+ }
}
// 5. Compute the maximum acceleration available
diff --git a/src/Movement/Kinematics/Kinematics.cpp b/src/Movement/Kinematics/Kinematics.cpp
index 50c1409e..51c4d1fe 100644
--- a/src/Movement/Kinematics/Kinematics.cpp
+++ b/src/Movement/Kinematics/Kinematics.cpp
@@ -18,6 +18,7 @@
#include "RepRap.h"
#include "Platform.h"
#include "GCodes/GCodeBuffer.h"
+#include "GCodes/GCodes.h"
const char * const Kinematics::HomeAllFileName = "homeall.g";
const char * const Kinematics::StandardHomingFileNames[] = AXES_("homex.g", "homey.g", "homez.g", "homeu.g", "homev.g", "homew.g", "homea.g", "homeb.g", "homec.g");
@@ -115,11 +116,20 @@ const char* Kinematics::GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alrea
const AxesBitmap homeFirst = AxesToHomeBeforeProbing();
// Return the homing file for the lowest axis that we have been asked to home
+ const char * const axisNames = reprap.GetGCodes().GetAxisLetters();
+ const char lettersToTry[] = "XYZUVWABC";
+ static_assert(ARRAY_SIZE(lettersToTry) >= MaxAxes, "lettersToTry too short");
for (size_t axis = 0; axis < numVisibleAxes; ++axis)
{
if (IsBitSet(toBeHomed, axis) && (axis != Z_AXIS || !homeZLast || (alreadyHomed & homeFirst) == homeFirst))
{
- return StandardHomingFileNames[axis];
+ for (size_t actualAxis = 0; actualAxis < MaxAxes; actualAxis++)
+ {
+ if (axisNames[axis] == lettersToTry[actualAxis])
+ {
+ return StandardHomingFileNames[actualAxis];
+ }
+ }
}
}
diff --git a/src/Movement/Kinematics/Kinematics.h b/src/Movement/Kinematics/Kinematics.h
index 5c386f68..531d0a45 100644
--- a/src/Movement/Kinematics/Kinematics.h
+++ b/src/Movement/Kinematics/Kinematics.h
@@ -17,7 +17,7 @@ inline floatc_t fcsquare(floatc_t a)
}
// Different types of kinematics we support. Each of these has a class to represent it.
-// These must have the same numeric assignments as the K parameter of the M669 command, as documented in ???
+// These must have the same numeric assignments as the K parameter of the M669 command, as documented in the GCodes wiki page
enum class KinematicsType : uint8_t
{
cartesian = 0,
@@ -29,6 +29,7 @@ enum class KinematicsType : uint8_t
hangprinter,
polar,
coreXYUV,
+// linearDeltaPlusZ, // reserved for @sga, see https://forum.duet3d.com/topic/5775/aditional-carterian-z-axis-on-delta-printer
unknown // this one must be last!
};
diff --git a/src/Networking/ESP8266WiFi/WiFiInterface.cpp b/src/Networking/ESP8266WiFi/WiFiInterface.cpp
index 2f4e8b18..394db873 100644
--- a/src/Networking/ESP8266WiFi/WiFiInterface.cpp
+++ b/src/Networking/ESP8266WiFi/WiFiInterface.cpp
@@ -158,6 +158,8 @@ WiFiInterface::WiFiInterface(Platform& p) : platform(p), uploader(nullptr), ftpD
void WiFiInterface::Init()
{
+ interfaceMutex.Create("WiFi");
+
// Make sure the ESP8266 is held in the reset state
ResetWiFi();
lastTickMillis = millis();
@@ -182,6 +184,8 @@ GCodeResult WiFiInterface::EnableProtocol(NetworkProtocol protocol, int port, in
else if (protocol < NumProtocols)
{
const Port portToUse = (port < 0) ? DefaultPortNumbers[protocol] : port;
+ MutexLocker lock(interfaceMutex);
+
if (portToUse != portNumbers[protocol] && state == NetworkState::active)
{
// We need to shut down and restart the protocol if it is active because the port number has changed
@@ -210,6 +214,8 @@ GCodeResult WiFiInterface::DisableProtocol(NetworkProtocol protocol, const Strin
{
if (protocol < NumProtocols)
{
+ MutexLocker lock(interfaceMutex);
+
if (state == NetworkState::active)
{
ShutdownProtocol(protocol);
@@ -225,6 +231,8 @@ GCodeResult WiFiInterface::DisableProtocol(NetworkProtocol protocol, const Strin
void WiFiInterface::StartProtocol(NetworkProtocol protocol)
{
+ MutexLocker lock(interfaceMutex);
+
switch(protocol)
{
case HttpProtocol:
@@ -246,6 +254,8 @@ void WiFiInterface::StartProtocol(NetworkProtocol protocol)
void WiFiInterface::ShutdownProtocol(NetworkProtocol protocol)
{
+ MutexLocker lock(interfaceMutex);
+
switch(protocol)
{
case HttpProtocol:
@@ -432,6 +442,8 @@ void WiFiInterface::Stop()
{
if (state != NetworkState::disabled)
{
+ MutexLocker lock(interfaceMutex);
+
digitalWrite(SamTfrReadyPin, LOW); // tell the ESP we can't receive
digitalWrite(EspResetPin, LOW); // put the ESP back into reset
DisableEspInterrupt(); // ignore IRQs from the transfer request pin
@@ -1535,6 +1547,8 @@ int32_t WiFiInterface::SendCommand(NetworkCommand cmd, SocketNumber socketNum, u
return ResponseNetworkDisabled;
}
+ MutexLocker lock(interfaceMutex);
+
if (transferPending)
{
if (reprap.Debug(moduleNetwork))
diff --git a/src/Networking/HttpResponder.cpp b/src/Networking/HttpResponder.cpp
index b96fcac2..edad5413 100644
--- a/src/Networking/HttpResponder.cpp
+++ b/src/Networking/HttpResponder.cpp
@@ -1296,7 +1296,7 @@ void HttpResponder::Diagnostics(MessageType mt) const
/*static*/ void HttpResponder::InitStatic()
{
- gcodeReplyMutex.Create();
+ gcodeReplyMutex.Create("HttpGCodeReply");
}
// This is called from the GCodes task to store a response, which is picked up by the Network task
diff --git a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
index c203cf28..27e44fe7 100644
--- a/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
+++ b/src/Networking/LwipEthernet/LwipEthernetInterface.cpp
@@ -140,6 +140,9 @@ LwipEthernetInterface::LwipEthernetInterface(Platform& p) : platform(p), closeDa
void LwipEthernetInterface::Init()
{
+ interfaceMutex.Create("Lwip");
+ //TODO we don't yet use this mutex anywhere!
+
// Clear the PCBs
for (size_t i = 0; i < NumTcpPorts; ++i)
{
diff --git a/src/Networking/Network.cpp b/src/Networking/Network.cpp
index ddfc9099..40a9d742 100644
--- a/src/Networking/Network.cpp
+++ b/src/Networking/Network.cpp
@@ -59,8 +59,8 @@ Network::Network(Platform& p) : platform(p), responders(nullptr), nextResponderT
// Note that Platform::Init() must be called before this to that Platform::IsDuetWiFi() returns the correct value
void Network::Init()
{
- httpMutex.Create();
- telnetMutex.Create();
+ httpMutex.Create("HTTP");
+ telnetMutex.Create("Telnet");
#if defined(DUET_NG)
interfaces[0] = (platform.IsDuetWiFi()) ? static_cast<NetworkInterface*>(new WiFiInterface(platform)) : static_cast<NetworkInterface*>(new W5500Interface(platform));
diff --git a/src/Networking/NetworkInterface.h b/src/Networking/NetworkInterface.h
index 6e10ea4f..4c807971 100644
--- a/src/Networking/NetworkInterface.h
+++ b/src/Networking/NetworkInterface.h
@@ -41,6 +41,8 @@ public:
virtual void OpenDataPort(Port port) = 0;
virtual void TerminateDataPort() = 0;
+ Mutex interfaceMutex; // mutex to protect against multiple tasks using the same interface concurrently. Public so that sockets can lock it.
+
protected:
Port portNumbers[NumProtocols]; // port number used for each protocol
bool protocolEnabled[NumProtocols]; // whether each protocol is enabled
diff --git a/src/Networking/TelnetResponder.cpp b/src/Networking/TelnetResponder.cpp
index 41cbe749..f2caf8a5 100644
--- a/src/Networking/TelnetResponder.cpp
+++ b/src/Networking/TelnetResponder.cpp
@@ -291,7 +291,7 @@ void TelnetResponder::ProcessLine()
/*static*/ void TelnetResponder::InitStatic()
{
- gcodeReplyMutex.Create();
+ gcodeReplyMutex.Create("TelnetGCodeReply");
}
/*static*/ void TelnetResponder::HandleGCodeReply(const char *reply)
diff --git a/src/Networking/W5500Ethernet/W5500Interface.cpp b/src/Networking/W5500Ethernet/W5500Interface.cpp
index 60a254f0..8d5a885a 100644
--- a/src/Networking/W5500Ethernet/W5500Interface.cpp
+++ b/src/Networking/W5500Ethernet/W5500Interface.cpp
@@ -35,6 +35,8 @@ W5500Interface::W5500Interface(Platform& p)
void W5500Interface::Init()
{
+ interfaceMutex.Create("W5500");
+
// Ensure that the W5500 chip is in the reset state
pinMode(W5500ResetPin, OUTPUT_LOW);
lastTickMillis = millis();
@@ -53,6 +55,8 @@ GCodeResult W5500Interface::EnableProtocol(NetworkProtocol protocol, int port, i
if (protocol < NumProtocols)
{
+ MutexLocker lock(interfaceMutex);
+
const Port portToUse = (port < 0) ? DefaultPortNumbers[protocol] : port;
if (portToUse != portNumbers[protocol] && state == NetworkState::active)
{
@@ -87,6 +91,8 @@ GCodeResult W5500Interface::DisableProtocol(NetworkProtocol protocol, const Stri
{
if (protocol < NumProtocols)
{
+ MutexLocker lock(interfaceMutex);
+
if (state == NetworkState::active)
{
ShutdownProtocol(protocol);
@@ -102,6 +108,8 @@ GCodeResult W5500Interface::DisableProtocol(NetworkProtocol protocol, const Stri
void W5500Interface::StartProtocol(NetworkProtocol protocol)
{
+ MutexLocker lock(interfaceMutex);
+
switch(protocol)
{
case HttpProtocol:
@@ -126,6 +134,8 @@ void W5500Interface::StartProtocol(NetworkProtocol protocol)
void W5500Interface::ShutdownProtocol(NetworkProtocol protocol)
{
+ MutexLocker lock(interfaceMutex);
+
switch(protocol)
{
case HttpProtocol:
@@ -222,6 +232,8 @@ void W5500Interface::SetMacAddress(const uint8_t mac[])
// Start up the network
void W5500Interface::Start()
{
+ MutexLocker lock(interfaceMutex);
+
SetIPAddress(platform.GetIPAddress(), platform.NetMask(), platform.GateWay());
pinMode(W5500ResetPin, OUTPUT_LOW);
delayMicroseconds(550); // W550 reset pulse must be at least 500us long
@@ -252,6 +264,8 @@ void W5500Interface::Stop()
{
if (state != NetworkState::disabled)
{
+ MutexLocker lock(interfaceMutex);
+
if (usingDhcp)
{
DHCP_stop();
@@ -273,21 +287,25 @@ void W5500Interface::Spin(bool full)
break;
case NetworkState::establishingLink:
- if (full && wizphy_getphylink() == PHY_LINK_ON)
{
- usingDhcp = (ipAddress[0] == 0 && ipAddress[1] == 0 && ipAddress[2] == 0 && ipAddress[3] == 0);
- if (usingDhcp)
- {
- // IP address is all zeros, so use DHCP
-// debugPrintf("Link established, getting IP address\n");
- DHCP_init(DhcpSocketNumber, platform.Random(), reprap.GetNetwork().GetHostname());
- lastTickMillis = millis();
- state = NetworkState::obtainingIP;
- }
- else
+ MutexLocker lock(interfaceMutex);
+
+ if (full && wizphy_getphylink() == PHY_LINK_ON)
{
-// debugPrintf("Link established, network running\n");
- state = NetworkState::connected;
+ usingDhcp = (ipAddress[0] == 0 && ipAddress[1] == 0 && ipAddress[2] == 0 && ipAddress[3] == 0);
+ if (usingDhcp)
+ {
+ // IP address is all zeros, so use DHCP
+// debugPrintf("Link established, getting IP address\n");
+ DHCP_init(DhcpSocketNumber, platform.Random(), reprap.GetNetwork().GetHostname());
+ lastTickMillis = millis();
+ state = NetworkState::obtainingIP;
+ }
+ else
+ {
+// debugPrintf("Link established, network running\n");
+ state = NetworkState::connected;
+ }
}
}
break;
@@ -295,6 +313,8 @@ void W5500Interface::Spin(bool full)
case NetworkState::obtainingIP:
if (full)
{
+ MutexLocker lock(interfaceMutex);
+
if (wizphy_getphylink() == PHY_LINK_ON)
{
const uint32_t now = millis();
@@ -334,45 +354,49 @@ void W5500Interface::Spin(bool full)
break;
case NetworkState::active:
- // Check that the link is still up
- if (wizphy_getphylink() == PHY_LINK_ON)
{
- // Maintain DHCP
- if (full && usingDhcp)
+ MutexLocker lock(interfaceMutex);
+
+ // Check that the link is still up
+ if (wizphy_getphylink() == PHY_LINK_ON)
{
- const uint32_t now = millis();
- if (now - lastTickMillis >= 1000)
- {
- lastTickMillis += 1000;
- DHCP_time_handler();
- }
- const DhcpRunResult ret = DHCP_run();
- if (ret == DhcpRunResult::DHCP_IP_CHANGED || ret == DhcpRunResult::DHCP_IP_ASSIGN)
+ // Maintain DHCP
+ if (full && usingDhcp)
{
-// debugPrintf("IP address changed\n");
- getSIPR(ipAddress);
+ const uint32_t now = millis();
+ if (now - lastTickMillis >= 1000)
+ {
+ lastTickMillis += 1000;
+ DHCP_time_handler();
+ }
+ const DhcpRunResult ret = DHCP_run();
+ if (ret == DhcpRunResult::DHCP_IP_CHANGED || ret == DhcpRunResult::DHCP_IP_ASSIGN)
+ {
+// debugPrintf("IP address changed\n");
+ getSIPR(ipAddress);
+ }
}
- }
- // Poll the next TCP socket
- sockets[nextSocketToPoll]->Poll(full);
+ // Poll the next TCP socket
+ sockets[nextSocketToPoll]->Poll(full);
- // Move on to the next TCP socket for next time
- ++nextSocketToPoll;
- if (nextSocketToPoll == NumW5500TcpSockets)
- {
- nextSocketToPoll = 0;
+ // Move on to the next TCP socket for next time
+ ++nextSocketToPoll;
+ if (nextSocketToPoll == NumW5500TcpSockets)
+ {
+ nextSocketToPoll = 0;
+ }
}
- }
- else if (full)
- {
-// debugPrintf("Lost phy link\n");
- if (usingDhcp)
+ else if (full)
{
- DHCP_stop();
+// debugPrintf("Lost phy link\n");
+ if (usingDhcp)
+ {
+ DHCP_stop();
+ }
+ TerminateSockets();
+ state = NetworkState::establishingLink;
}
- TerminateSockets();
- state = NetworkState::establishingLink;
}
break;
}
diff --git a/src/Networking/W5500Ethernet/W5500Socket.cpp b/src/Networking/W5500Ethernet/W5500Socket.cpp
index 8e200352..f6bacc2b 100644
--- a/src/Networking/W5500Ethernet/W5500Socket.cpp
+++ b/src/Networking/W5500Ethernet/W5500Socket.cpp
@@ -7,6 +7,7 @@
#include "W5500Socket.h"
#include "Network.h"
+#include "NetworkInterface.h"
#include "Wiznet/Ethernet/socketlib.h"
#include "NetworkBuffer.h"
#include "RepRap.h"
@@ -32,12 +33,16 @@ void W5500Socket::Init(SocketNumber skt, Port serverPort, NetworkProtocol p)
void W5500Socket::TerminateAndDisable()
{
+ MutexLocker lock(interface->interfaceMutex);
+
Terminate();
state = SocketState::disabled;
}
void W5500Socket::ReInit()
{
+ MutexLocker lock(interface->interfaceMutex);
+
// Discard any received data
while (receivedData != nullptr)
{
@@ -56,6 +61,8 @@ void W5500Socket::ReInit()
// Close a connection when the last packet has been sent
void W5500Socket::Close()
{
+ MutexLocker lock(interface->interfaceMutex);
+
if (state != SocketState::disabled && state != SocketState::inactive)
{
ExecCommand(socketNum, Sn_CR_DISCON);
@@ -71,6 +78,8 @@ void W5500Socket::Close()
// Terminate a connection immediately
void W5500Socket::Terminate()
{
+ MutexLocker lock(interface->interfaceMutex);
+
if (state != SocketState::disabled)
{
disconnectNoWait(socketNum);
@@ -97,6 +106,8 @@ bool W5500Socket::ReadChar(char& c)
{
if (receivedData != nullptr)
{
+ MutexLocker lock(interface->interfaceMutex);
+
const bool ret = receivedData->ReadChar(c);
if (receivedData->IsEmpty())
{
@@ -140,6 +151,8 @@ void W5500Socket::Poll(bool full)
{
if (state != SocketState::disabled)
{
+ MutexLocker lock(interface->interfaceMutex);
+
switch(getSn_SR(socketNum))
{
case SOCK_INIT:
@@ -206,7 +219,7 @@ void W5500Socket::Poll(bool full)
}
}
-// Try to receive more incoming data from the socket
+// Try to receive more incoming data from the socket. The mutex is alrady owned.
void W5500Socket::ReceiveData()
{
const uint16_t len = getSn_RX_RSR(socketNum);
@@ -245,7 +258,7 @@ void W5500Socket::ReceiveData()
}
}
-// Discard any received data for this transaction
+// Discard any received data for this transaction. The mutex is already owned.
void W5500Socket::DiscardReceivedData()
{
while (receivedData != nullptr)
@@ -257,6 +270,8 @@ void W5500Socket::DiscardReceivedData()
// Send the data, returning the length buffered
size_t W5500Socket::Send(const uint8_t *data, size_t length)
{
+ MutexLocker lock(interface->interfaceMutex);
+
if (CanSend() && length != 0 && getSn_SR(socketNum) == SOCK_ESTABLISHED)
{
// Check for previous send complete
@@ -311,6 +326,8 @@ size_t W5500Socket::Send(const uint8_t *data, size_t length)
// Tell the interface to send the outstanding data
void W5500Socket::Send()
{
+ MutexLocker lock(interface->interfaceMutex);
+
if (CanSend() && sendOutstanding)
{
setSn_TX_WR(socketNum, wizTxBufferPtr);
diff --git a/src/Platform.cpp b/src/Platform.cpp
index 64000fe1..2e74416e 100644
--- a/src/Platform.cpp
+++ b/src/Platform.cpp
@@ -57,6 +57,8 @@
#include <climits>
+extern uint32_t _estack; // defined in the linker script
+
#if !defined(HAS_LWIP_NETWORKING) || !defined(HAS_WIFI_NETWORKING) || !defined(HAS_CPU_TEMP_SENSOR) || !defined(HAS_HIGH_SPEED_SD) \
|| !defined(HAS_SMART_DRIVERS) || !defined(HAS_STALL_DETECT) || !defined(HAS_VOLTAGE_MONITOR) || !defined(HAS_VREF_MONITOR) || !defined(ACTIVE_LOW_HEAT_ON) \
|| !defined(SUPPORT_NONLINEAR_EXTRUSION)
@@ -215,8 +217,8 @@ void Platform::Init()
commsParams[2] = 0;
#endif
- usbMutex.Create();
- auxMutex.Create();
+ usbMutex.Create("USB");
+ auxMutex.Create("Aux");
auxDetected = false;
auxSeq = 0;
@@ -224,7 +226,7 @@ void Platform::Init()
SERIAL_AUX_DEVICE.begin(baudRates[1]); // this can't be done in the constructor because the Arduino port initialisation isn't complete at that point
#ifdef SERIAL_AUX2_DEVICE
SERIAL_AUX2_DEVICE.begin(baudRates[2]);
- aux2Mutex.Create();
+ aux2Mutex.Create("Aux2");
#endif
compatibility = Compatibility::marlin; // default to Marlin because the common host programs expect the "OK" response to commands
@@ -1074,7 +1076,7 @@ void Platform::UpdateFirmware()
}
#if defined(DUET_NG) || defined(DUET_M)
- IoPort::WriteDigital(Z_PROBE_MOD_PIN, false); // turn the DIAG LED off
+ IoPort::WriteDigital(DiagPin, false); // turn the DIAG LED off
#endif
wdt_restart(WDT); // kick the watchdog one last time
@@ -1381,7 +1383,7 @@ void Platform::Spin()
{
if ((stalledDrivers & mask) == 0)
{
- // This stall is new and we are printing, so check whether we need to perform some action in response to the stall
+ // This stall is new so check whether we need to perform some action in response to the stall
if ((rehomeOnStallDrivers & mask) != 0)
{
stalledDriversToRehome |= mask;
@@ -1551,7 +1553,8 @@ void Platform::Spin()
switch (autoSaveState)
{
case AutoSaveState::starting:
- if (currentVin >= autoResumeReading)
+ // Some users set the auto resume threshold high to disable auto resume, so prime auto save at the auto save threshold plus half a volt
+ if (currentVin >= autoResumeReading || currentVin > autoPauseReading + PowerVoltageToAdcReading(0.5))
{
autoSaveState = AutoSaveState::normal;
}
@@ -1794,7 +1797,8 @@ void Platform::SoftwareReset(uint16_t reason, const uint32_t *stk)
srdBuf[slot].sp = reinterpret_cast<uint32_t>(stk);
for (size_t i = 0; i < ARRAY_SIZE(srdBuf[slot].stack); ++i)
{
- srdBuf[slot].stack[i] = stk[i];
+ srdBuf[slot].stack[i] = (stk < &_estack) ? *stk : 0xFFFFFFFF;
+ ++stk;
}
}
diff --git a/src/RTOSIface.cpp b/src/RTOSIface.cpp
index ee9650bc..c185a454 100644
--- a/src/RTOSIface.cpp
+++ b/src/RTOSIface.cpp
@@ -15,11 +15,14 @@
static_assert(Mutex::TimeoutUnlimited == portMAX_DELAY, "Bad value for TimeoutUnlimited");
-void Mutex::Create()
+void Mutex::Create(const char *pName)
{
if (handle == nullptr)
{
handle = xSemaphoreCreateRecursiveMutexStatic(&storage);
+ name = pName;
+ next = mutexList;
+ mutexList = this;
}
}
@@ -39,10 +42,11 @@ TaskHandle Mutex::GetHolder() const
}
TaskBase *TaskBase::taskList = nullptr;
+Mutex *Mutex::mutexList = nullptr;
#else
-void Mutex::Create()
+void Mutex::Create(const char *pName)
{
}
diff --git a/src/RTOSIface.h b/src/RTOSIface.h
index a1964b66..151f3204 100644
--- a/src/RTOSIface.h
+++ b/src/RTOSIface.h
@@ -28,21 +28,34 @@ class Mutex
public:
Mutex() { handle = nullptr; }
- void Create();
+ void Create(const char *pName);
bool Take(uint32_t timeout = TimeoutUnlimited) const;
bool Release() const;
TaskHandle GetHolder() const;
- static constexpr uint32_t TimeoutUnlimited = 0xFFFFFFFF;
+#ifdef RTOS
+ const Mutex *GetNext() const { return next; }
+ const char *GetName() const { return name; }
+#endif
Mutex(const Mutex&) = delete;
Mutex& operator=(const Mutex&) = delete;
+ static constexpr uint32_t TimeoutUnlimited = 0xFFFFFFFF;
+
+#ifdef RTOS
+ static const Mutex *GetMutexList() { return mutexList; }
+#endif
+
private:
#ifdef RTOS
SemaphoreHandle_t handle;
+ Mutex *next;
+ const char *name;
StaticSemaphore_t storage;
+
+ static Mutex *mutexList;
#else
void *handle;
#endif
@@ -60,7 +73,7 @@ public:
void Suspend() const { vTaskSuspend(handle); }
const TaskBase *GetNext() const { return next; }
- TaskBase(const TaskBase&) = delete; // it's not save to copy these
+ TaskBase(const TaskBase&) = delete; // it's not safe to copy these
TaskBase& operator=(const TaskBase&) = delete; // it's not safe to assign these
// Ideally we would declare the destructor as deleted too, because it's unsafe to delete these because they are linked together via the 'next' field.
// But that prevents us from declaring static instances of tasks.
diff --git a/src/RepRap.cpp b/src/RepRap.cpp
index 914b860a..e83bd6e7 100644
--- a/src/RepRap.cpp
+++ b/src/RepRap.cpp
@@ -154,8 +154,8 @@ RepRap::RepRap() : toolList(nullptr), currentTool(nullptr), lastWarningMillis(0)
void RepRap::Init()
{
- toolListMutex.Create();
- messageBoxMutex.Create();
+ toolListMutex.Create("ToolList");
+ messageBoxMutex.Create("MessageBox");
platform->Init();
network->Init();
@@ -687,7 +687,14 @@ void RepRap::Tick()
// We now save the stack when we get stuck in a spin loop
register const uint32_t * stackPtr asm ("sp");
- platform->SoftwareReset((uint16_t)SoftwareResetReason::stuckInSpin, stackPtr + 5);
+
+ platform->SoftwareReset((uint16_t)SoftwareResetReason::stuckInSpin,
+#ifdef RTOS
+ stackPtr + 5 + 15 // discard the stack used by the FreeRTOS stack handler and our tick handler
+#else
+ stackPtr + 5 // discard the stack used by our tick handler
+#endif
+ );
}
}
}
@@ -1320,6 +1327,9 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source)
// Fraction of file printed
response->catf("],\"fractionPrinted\":%.1f", (double)((printMonitor->IsPrinting()) ? (gCodes->FractionOfFilePrinted() * 100.0) : 0.0));
+ // Byte position of the file being printed
+ response->catf(",\"filePosition\":%lu", gCodes->GetFilePosition());
+
// First Layer Duration
response->catf(",\"firstLayerDuration\":%.1f", (double)(printMonitor->GetFirstLayerDuration()));
diff --git a/src/Scanner.cpp b/src/Scanner.cpp
index 64ab3a62..6e762bd7 100644
--- a/src/Scanner.cpp
+++ b/src/Scanner.cpp
@@ -13,6 +13,8 @@
#include "Platform.h"
+const char* const SCANNER_ON_G = "scanner_on.g";
+const char* const SCANNER_OFF_G = "scanner_off.g";
const char* const ALIGN_ON_G = "align_on.g";
const char* const ALIGN_OFF_G = "align_off.g";
const char* const SCAN_PRE_G = "scan_pre.g";
@@ -104,7 +106,8 @@ void Scanner::Spin()
}
SetState(ScannerState::Disconnected);
- // Cannot do anything else...
+ // Run a macro to perform custom actions when the scanner is removed
+ DoFileMacro(SCANNER_OFF_G);
return;
}
@@ -389,18 +392,15 @@ bool Scanner::Enable()
}
// Register a scanner device
-bool Scanner::Register()
+void Scanner::Register()
{
- if (IsRegistered())
+ if (!IsRegistered())
{
- // Don't do anything if a device is already registered
- return true;
- }
-
- platform.Message(MessageType::BlockingUsbMessage, "OK\n");
- SetState(ScannerState::Idle);
+ platform.Message(MessageType::BlockingUsbMessage, "OK\n");
+ SetState(ScannerState::Idle);
- return true;
+ DoFileMacro(SCANNER_ON_G);
+ }
}
// Initiate a new scan
diff --git a/src/Scanner.h b/src/Scanner.h
index db50c5d1..0c5c279d 100644
--- a/src/Scanner.h
+++ b/src/Scanner.h
@@ -53,7 +53,7 @@ public:
bool Enable(); // Enable 3D scanner extension. Returns true when done
bool IsRegistered() const; // Is the 3D scanner registered and ready to use?
- bool Register(); // Register a 3D scanner. Returns true when done
+ void Register(); // Register a 3D scanner instance
// External scanners are automatically unregistered when the main port (USB) is closed
// Start a new 3D scan. Returns true when the scan has been initiated
diff --git a/src/Storage/FileInfoParser.cpp b/src/Storage/FileInfoParser.cpp
index 4dfc90cf..0e2d4173 100644
--- a/src/Storage/FileInfoParser.cpp
+++ b/src/Storage/FileInfoParser.cpp
@@ -32,7 +32,7 @@ FileInfoParser::FileInfoParser()
: parseState(notParsing), fileBeingParsed(nullptr), accumulatedParseTime(0), accumulatedReadTime(0), accumulatedSeekTime(0), fileOverlapLength(0)
{
parsedFileInfo.Init();
- parserMutex.Create();
+ parserMutex.Create("FileInfoParser");
}
bool FileInfoParser::GetFileInfo(const char *directory, const char *fileName, GCodeFileInfo& info, bool quitEarly)
diff --git a/src/Storage/MassStorage.cpp b/src/Storage/MassStorage.cpp
index e06946a1..c13bb8ef 100644
--- a/src/Storage/MassStorage.cpp
+++ b/src/Storage/MassStorage.cpp
@@ -63,9 +63,12 @@ MassStorage::MassStorage(Platform* p) : freeWriteBuffers(nullptr)
void MassStorage::Init()
{
+ static const char * const VolMutexNames[] = { "SD0", "SD1" };
+ static_assert(ARRAY_SIZE(VolMutexNames) >= NumSdCards, "Incorrect VolMutexNames array");
+
// Create the mutexes
- fsMutex.Create();
- dirMutex.Create();
+ fsMutex.Create("FileSystem");
+ dirMutex.Create("DirSearch");
for (size_t i = 0; i < NumFileWriteBuffers; ++i)
{
@@ -79,7 +82,7 @@ void MassStorage::Init()
inf.mounting = inf.isMounted = false;
inf.cdPin = SdCardDetectPins[card];
inf.cardState = (inf.cdPin == NoPin) ? CardDetectState::present : CardDetectState::notPresent;
- inf.volMutex.Create();
+ inf.volMutex.Create(VolMutexNames[card]);
}
sd_mmc_init(SdWriteProtectPins, SdSpiCSPins); // initialize SD MMC stack
diff --git a/src/Tasks.cpp b/src/Tasks.cpp
index dc9169d6..a3a4c782 100644
--- a/src/Tasks.cpp
+++ b/src/Tasks.cpp
@@ -91,8 +91,8 @@ extern "C" void AppMain()
extern "C" void MainTask(void *pvParameters)
{
- mallocMutex.Create();
- spiMutex.Create();
+ mallocMutex.Create("Malloc");
+ spiMutex.Create("SPI");
#endif
reprap.Init();
for (;;)
@@ -188,6 +188,7 @@ namespace Tasks
}
#ifdef RTOS
+ p.Message(mtype, "Tasks:");
for (const TaskBase *t = TaskBase::GetTaskList(); t != nullptr; t = t->GetNext())
{
TaskStatus_t taskDetails;
@@ -197,9 +198,28 @@ namespace Tasks
: (taskDetails.eCurrentState == eBlocked) ? "blocked"
: (taskDetails.eCurrentState == eSuspended) ? "suspended"
: "invalid";
- p.MessageF(mtype, "Task %s %s, free stack %u\n",
+ p.MessageF(mtype, " %s(%s,%u)",
taskDetails.pcTaskName, stateText, (unsigned int)(taskDetails.usStackHighWaterMark * sizeof(StackType_t)));
}
+ p.Message(mtype, "\nMutexes:");
+
+ for (const Mutex *m = Mutex::GetMutexList(); m != nullptr; m = m->GetNext())
+ {
+ const TaskHandle holder = m->GetHolder();
+ TaskStatus_t taskDetails;
+ const char *holderText;
+ if (holder == nullptr)
+ {
+ holderText = "null";
+ }
+ else
+ {
+ vTaskGetInfo(holder, &taskDetails, pdTRUE, eInvalid);
+ holderText = taskDetails.pcTaskName;
+ }
+ p.MessageF(mtype, " %s(%s)", m->GetName(), holderText);
+ }
+ p.MessageF(mtype, "\n");
#endif
}
@@ -216,7 +236,7 @@ namespace Tasks
#ifdef RTOS
static StaticTask_t xIdleTaskTCB;
-static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
+static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE];
extern "C" void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
@@ -233,7 +253,7 @@ extern "C" void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuff
}
static StaticTask_t xTimerTaskTCB;
-static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
+static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH];
extern "C" void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
diff --git a/src/Version.h b/src/Version.h
index 6c5ebe24..b2e0b33c 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -12,9 +12,9 @@
#ifndef VERSION
#ifdef RTOS
# define RTOSVER "(RTOS)"
-# define MAIN_VERSION "2.0"
+# define MAIN_VERSION "2.01beta1"
#else
-# define MAIN_VERSION "1.21.1"
+# define MAIN_VERSION "1.21.2beta1"
# define RTOSVER
#endif
@@ -22,7 +22,7 @@
#endif
#ifndef DATE
-# define DATE "2018-06-05b3"
+# define DATE "2018-06-23b1"
#endif
#define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman"