diff options
author | David Crocker <dcrocker@eschertech.com> | 2018-03-16 17:49:58 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2018-03-16 17:50:20 +0300 |
commit | df7c0f0a4a20a5f8f908424e9570ffe38566c890 (patch) | |
tree | fec1f61d35f7421a95a98d724388fe4c0a7589b9 /src | |
parent | 875c2d29d4436da34ac01b6292ef658660ee948e (diff) |
Version 1.21RC5
New features:
- New M569 T parameter options to specify step pulse width, step pulse
interval, direction setup and direction hold times
- M665 now sets the M208 limits (except Z min) to match the machine
limits, so that Duet Web Control reports the correct values
Bug fixes:
- M116 commands were sometimes executed out-of-order relative to
previous G10 commands if movement commands were in progress
- G10 L20 now computes the workplace coordinate origin correctly
- G53 is only active until the end of the current line of GCode
- The default coordinate system is the one selected by G54
- G54..G59 update the user coordinates immediately
- Fixed "Error: Pop(): stack underflow!" when a file or macro is
terminated due to an illegal move command
- A short delay is inserted when M558 is used to change the Z probe
type, to allow the averaging filters to accumulate the new data
- M291 messages which are non-blocking (i.e. mode < 2) are now
synchronised to queued moves, like M117 messages
Other changes:
- Duet Web Control and PanelDue now report the coordinates relative to
the origin of the current workplace
- Rewrote dhcp_rec function on Duet06/085 to avoid goto statements
(possible fix for startup problem when using DHCP)
Diffstat (limited to 'src')
-rw-r--r-- | src/BugList.txt | 30 | ||||
-rw-r--r-- | src/Duet/Lwip/lwip/src/core/dhcp.c | 44 | ||||
-rw-r--r-- | src/DuetNG/SX1509.h | 2 | ||||
-rw-r--r-- | src/Fan.cpp | 6 | ||||
-rw-r--r-- | src/Fan.h | 4 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer.cpp | 7 | ||||
-rw-r--r-- | src/GCodes/GCodeMachineState.cpp | 3 | ||||
-rw-r--r-- | src/GCodes/GCodeMachineState.h | 1 | ||||
-rw-r--r-- | src/GCodes/GCodeQueue.cpp | 8 | ||||
-rw-r--r-- | src/GCodes/GCodes.cpp | 24 | ||||
-rw-r--r-- | src/GCodes/GCodes.h | 46 | ||||
-rw-r--r-- | src/GCodes/GCodes2.cpp | 83 | ||||
-rw-r--r-- | src/GCodes/GCodes3.cpp | 11 | ||||
-rw-r--r-- | src/Movement/DDA.cpp | 31 | ||||
-rw-r--r-- | src/Movement/DDA.h | 4 | ||||
-rw-r--r-- | src/Movement/Kinematics/LinearDeltaKinematics.cpp | 11 | ||||
-rw-r--r-- | src/Networking/W5500Ethernet/Wiznet/Internet/DHCP/dhcp.cpp | 1 | ||||
-rw-r--r-- | src/Pins.h | 4 | ||||
-rw-r--r-- | src/Platform.cpp | 79 | ||||
-rw-r--r-- | src/Platform.h | 17 | ||||
-rw-r--r-- | src/RepRap.cpp | 95 | ||||
-rw-r--r-- | src/RepRap.h | 1 | ||||
-rw-r--r-- | src/Version.h | 4 |
23 files changed, 346 insertions, 170 deletions
diff --git a/src/BugList.txt b/src/BugList.txt index 0afe7b67..5916a9b5 100644 --- a/src/BugList.txt +++ b/src/BugList.txt @@ -60,31 +60,45 @@ Done in 1.21RC2: - [done, should be better] https://www.duet3d.com/forum/thread.php?pid=40183#p40183, https://www.duet3d.com/forum/thread.php?pid=39509#p39509 (not starting up correctly in access point mode) - [done] Attempted movements outside limits or when not homed cause current print file to be aborted -Remaining: +Done in 1.21RC4: - [done] for CoreXZ require just X and Y to be homed before probing (so that G30 can be used to home Z axis) -- [done, test] Check min. 8 character password in M589, see https://www.duet3d.com/forum/thread.php?pid=40914#p40914 - [done] G10 L2 - [done] G10 L20 - [done, test] Suppress heater fault detection when heaters are suspended - [done] DuetWiFiServer: new SDK version - [problem gone away with latest DuetWiFiServer] Duet WiFi (Kossel): disconnects every time after I upload file xyzCalibration_cube s3d.gcode due to incomplete json reply, but can reconnect afterwards -- [done] Ethernet: set W5500 to auto negotiate +- [done, ok] Ethernet: set W5500 to auto negotiate +- [done, test] Check min. 8 character password in M589, see https://www.duet3d.com/forum/thread.php?pid=40914#p40914 - [done, test] I parameter on M452, M453 and M573 didn't work - [done, test] M564 H0 to allow axis movement before homing on Cartesian/CoreXY printers - [done, test] Filament length comment generated by Cura, see https://www.duet3d.com/forum/thread.php?pid=40913#p40913 - [done, test] Doesn't cancel homeall.g if there is an illegal Z move at the start, https://www.duet3d.com/forum/thread.php?pid=41082#p41082 +- [done] Corrected Z probe input pin in RADDS build +- [done, test] in M589 check password is empty or at least 8 characters +- [done] Multi tap on G30 +- [done, didn't help] Possible fix to Duet 06/085 failure to start when using DHCP +- [ok] Test smart effector sensitivity programming +Remaining: +- [done] M116 fix, see https://www.duet3d.com/forum/thread.php?pid=41954#p41954. Also M109, M190, M191 +- [done] queue M291 non-blocking messages +- [done, networking seems OK inc. DHCP] Duet 06/085 DHCP issue; rewrite dhcp_recv without goto? https://www.duet3d.com/forum/thread.php?pid=34605#p34605 and https://www.duet3d.com/forum/thread.php?pid=41923#p41923 +- [done, hard to test] Error: Pop(): stack underflow! https://www.duet3d.com/forum/thread.php?pid=41967#p41967 +- [done, test] Short delay after M558, https://www.duet3d.com/forum/thread.php?pid=41967#p41967 +- [done, test] G10 L20 sign error, https://www.duet3d.com/forum/thread.php?pid=42044#p42044 +- [done, test] When G54 etc. are sent, update user coordinates immediately +- [done, test] G54 is the default coordinate system; G53 only lasts until end of line +- [done, test] DWC and PD report user coordinates, nt machine coordinates +- [done] new step pulse timing for slow drivers +- check out G30 H parameter, https://www.duet3d.com/forum/thread.php?pid=42322#p42322 + +- Error message if you attempt movement with VIN < minimum - How should we lift X on a CoreXZ printer before homing? -- Multi tap on G30? - - if a homing command in an SD print file is aborted due to e.g. G1 Z5 in the homing file, error message should be written to both DWC and PanelDue -- M116 issue -- [made a change, but try to reproduce it] Duet 0.8/0.8.5 DHCP issue, https://www.duet3d.com/forum/thread.php?pid=34605#p34605 - stall detect on Z axis - Files generated by Cura doesn't detect layer changes, see https://www.duet3d.com/forum/thread.php?pid=40865#p40865 - [re-test using new DuetWiFiServer] "Failed to change mode" messages after M552 S2/S0/S1 cycle - [can't reproduce] "Attempt to seek on a non-open file", https://www.duet3d.com/forum/thread.php?pid=41175#p41175 -- Test smart effector sensitivity programming - min/max RSSI display? diff --git a/src/Duet/Lwip/lwip/src/core/dhcp.c b/src/Duet/Lwip/lwip/src/core/dhcp.c index 3b9dea30..f5483bc7 100644 --- a/src/Duet/Lwip/lwip/src/core/dhcp.c +++ b/src/Duet/Lwip/lwip/src/core/dhcp.c @@ -1568,12 +1568,24 @@ dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t if (p->len < DHCP_MIN_REPLY_LEN) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n")); +#if 1 //dc42 + dhcp->msg_in = NULL; + pbuf_free(p); + return; +#else goto free_pbuf_and_return; +#endif } if (reply_msg->op != DHCP_BOOTREPLY) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op)); +#if 1 //dc42 + dhcp->msg_in = NULL; + pbuf_free(p); + return; +#else goto free_pbuf_and_return; +#endif } /* iterate through hardware address and match against DHCP message */ #if 1 //dc42 from lwip2 @@ -1585,27 +1597,51 @@ dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n", (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i])); +#if 1 //dc42 + dhcp->msg_in = NULL; + pbuf_free(p); + return; +#else goto free_pbuf_and_return; +#endif } } /* match transaction ID against what we expected */ if (ntohl(reply_msg->xid) != dhcp->xid) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid)); +#if 1 //dc42 + dhcp->msg_in = NULL; + pbuf_free(p); + return; +#else goto free_pbuf_and_return; +#endif } /* option fields could be unfold? */ if (dhcp_parse_reply(dhcp, p) != ERR_OK) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("problem unfolding DHCP message - too short on memory?\n")); +#if 1 //dc42 + dhcp->msg_in = NULL; + pbuf_free(p); + return; +#else goto free_pbuf_and_return; +#endif } LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); /* obtain pointer to DHCP message type */ if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); +#if 1 //dc42 + dhcp->msg_in = NULL; + pbuf_free(p); + return; +#else goto free_pbuf_and_return; +#endif } /* read DHCP message type */ @@ -1653,14 +1689,10 @@ dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t /* remember offered lease */ dhcp_handle_offer(netif); } +#if 0 //dc42 free_pbuf_and_return: -#if 1 //dc42 from lwpi2 -if (dhcp != NULL) { - dhcp->msg_in = NULL; -} -#else - dhcp->msg_in = NULL; #endif + dhcp->msg_in = NULL; pbuf_free(p); } diff --git a/src/DuetNG/SX1509.h b/src/DuetNG/SX1509.h index 76a3a92a..96a6a59b 100644 --- a/src/DuetNG/SX1509.h +++ b/src/DuetNG/SX1509.h @@ -27,7 +27,7 @@ Distributed as-is; no warranty is given. #include "Core.h" const int ReceiveTimeout = 1000; // Timeout for I2C receive -const uint8_t DefaultOscDivider = 5; // a clock divider of 2 ^ (5 - 1) = 16 gives a PSWM frequency of 2MHz / (16 * 255) = 488Hz +const uint8_t DefaultOscDivider = 5; // a clock divider of 2 ^ (5 - 1) = 16 gives a PWM frequency of 2MHz / (16 * 255) = 488Hz class SX1509 { diff --git a/src/Fan.cpp b/src/Fan.cpp index 0a3deb9f..367433b0 100644 --- a/src/Fan.cpp +++ b/src/Fan.cpp @@ -116,7 +116,7 @@ bool Fan::Configure(unsigned int mcode, int fanNum, GCodeBuffer& gb, const Strin } if (heatersMonitored != 0) { - SetValue(1.0); // default the fan speed to full for safety + SetPwm(1.0); // default the fan speed to full for safety } } @@ -124,7 +124,7 @@ bool Fan::Configure(unsigned int mcode, int fanNum, GCodeBuffer& gb, const Strin if (seen && gb.Seen('S')) // Set new fan value - process this after processing 'H' or it may not be acted on { const float f = constrain<float>(gb.GetFValue(), 0.0, 255.0); - SetValue(f); + SetPwm(f); } if (seen) @@ -158,7 +158,7 @@ bool Fan::Configure(unsigned int mcode, int fanNum, GCodeBuffer& gb, const Strin return seen; } -void Fan::SetValue(float speed) +void Fan::SetPwm(float speed) { if (speed > 1.0) { @@ -25,10 +25,10 @@ public: bool Configure(unsigned int mcode, int fanNum, GCodeBuffer& gb, const StringRef& reply, bool& error); bool IsEnabled() const { return pin != NoPin; } - float GetValue() const { return val; } + float GetConfiguredPwm() const { return val; } // returns the configured PWM. Actual PWM may be different, e.g. due to blipping or for thermostatic fans. void Init(Pin p_pin, bool hwInverted); - void SetValue(float speed); + void SetPwm(float speed); void SetHeatersMonitored(HeatersMonitoredBitmap h); bool Check(); // update the fan PWM returning true if it is a thermostatic fan that is on void Disable(); diff --git a/src/GCodes/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer.cpp index ccb20d82..a3bc359b 100644 --- a/src/GCodes/GCodeBuffer.cpp +++ b/src/GCodes/GCodeBuffer.cpp @@ -390,6 +390,7 @@ void GCodeBuffer::SetFinished(bool f) } else { + machineState->useMachineCoordinates = false; // G53 does not persist beyond the current line Init(); } } @@ -445,13 +446,14 @@ float GCodeBuffer::GetFValue() } // Get a colon-separated list of floats after a key letter +// If doPad is true then we allow just one element to be given, in which case we fill all elements with that value const void GCodeBuffer::GetFloatArray(float arr[], size_t& returnedLength, bool doPad) { if (readPointer >= 0) { size_t length = 0; bool inList = true; - while(inList) + while (inList) { if (length >= returnedLength) // array limit has been set in here { @@ -475,7 +477,7 @@ const void GCodeBuffer::GetFloatArray(float arr[], size_t& returnedLength, bool // Special case if there is one entry and returnedLength requests several. Fill the array with the first entry. if (doPad && length == 1 && returnedLength > 1) { - for(size_t i = 1; i < returnedLength; i++) + for (size_t i = 1; i < returnedLength; i++) { arr[i] = arr[0]; } @@ -930,6 +932,7 @@ bool GCodeBuffer::PushState() ms->runningM501 = machineState->runningM501; ms->runningM502 = machineState->runningM502; ms->volumetricExtrusion = false; + ms->useMachineCoordinates = false; ms->messageAcknowledged = false; ms->waitingForAcknowledgement = false; machineState = ms; diff --git a/src/GCodes/GCodeMachineState.cpp b/src/GCodes/GCodeMachineState.cpp index dc396a3d..696d8f07 100644 --- a/src/GCodes/GCodeMachineState.cpp +++ b/src/GCodes/GCodeMachineState.cpp @@ -13,7 +13,8 @@ unsigned int GCodeMachineState::numAllocated = 0; // Create a default initialised GCodeMachineState GCodeMachineState::GCodeMachineState() : previous(nullptr), feedrate(DefaultFeedrate * SecondsToMinutes), fileState(), lockedResources(0), errorMessage(nullptr), state(GCodeState::normal), - drivesRelative(false), axesRelative(false), doingFileMacro(false), runningM501(false), runningM502(false), volumetricExtrusion(false), waitingForAcknowledgement(false), messageAcknowledged(false) + drivesRelative(false), axesRelative(false), doingFileMacro(false), runningM501(false), runningM502(false), + volumetricExtrusion(false), useMachineCoordinates(false), waitingForAcknowledgement(false), messageAcknowledged(false) { } diff --git a/src/GCodes/GCodeMachineState.h b/src/GCodes/GCodeMachineState.h index 9ac29a64..d1455986 100644 --- a/src/GCodes/GCodeMachineState.h +++ b/src/GCodes/GCodeMachineState.h @@ -104,6 +104,7 @@ public: runningM501 : 1, runningM502 : 1, volumetricExtrusion : 1, + useMachineCoordinates : 1, // true if seen G53 on this line of GCode // Caution: these next 3 will be modified out-of-process when we use RTOS, so they will need to be individual bool variables waitingForAcknowledgement : 1, messageAcknowledged : 1, diff --git a/src/GCodes/GCodeQueue.cpp b/src/GCodes/GCodeQueue.cpp index 0aa44556..207bfd17 100644 --- a/src/GCodes/GCodeQueue.cpp +++ b/src/GCodes/GCodeQueue.cpp @@ -60,6 +60,14 @@ GCodeQueue::GCodeQueue() : freeItems(nullptr), queuedItems(nullptr) case 420: // set RGB colour return true; + case 291: + { + bool seen = false; + int32_t sParam = 1; + gb.TryGetIValue('S', sParam, seen); + return sParam < 2; // queue non-blocking messages only + } + default: break; } diff --git a/src/GCodes/GCodes.cpp b/src/GCodes/GCodes.cpp index ac9d9c0c..6062b9e8 100644 --- a/src/GCodes/GCodes.cpp +++ b/src/GCodes/GCodes.cpp @@ -160,7 +160,7 @@ void GCodes::Reset() { axisScaleFactors[i] = 1.0; #if SUPPORT_WORKPLACE_COORDINATES - for (size_t j = 0; j < 10; ++j) + for (size_t j = 0; j < NumCoordinateSystems; ++j) { workplaceCoordinates[j][i] = 0.0; } @@ -320,7 +320,7 @@ void GCodes::Spin() if (gb.MachineState().messageAcknowledged) { const bool wasCancelled = gb.MachineState().messageCancelled; - Pop(gb); + gb.PopState(); // this could fail if the current macro has already been aborted if (wasCancelled) { @@ -527,7 +527,7 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) if (LockMovementAndWaitForStandstill(gb)) // wait for tpre.g to finish executing { reprap.SelectTool(gb.MachineState().newToolNumber, simulationMode != 0); - GetCurrentUserPosition(); // get the actual position of the new tool + UpdateCurrentUserPosition(); // get the actual position of the new tool gb.AdvanceState(); if (AllAxesAreHomed()) @@ -2347,6 +2347,12 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated) { currentUserPosition[axis] += moveArg; } +#if SUPPORT_WORKPLACE_COORDINATES + else if (gb.MachineState().useMachineCoordinates) + { + currentUserPosition[axis] = moveArg - workplaceCoordinates[currentCoordinateSystem][axis]; + } +#endif else { currentUserPosition[axis] = moveArg; @@ -2475,6 +2481,13 @@ const char* GCodes::DoArcMove(GCodeBuffer& gb, bool clockwise) currentUserPosition[X_AXIS] += xParam; currentUserPosition[Y_AXIS] += yParam; } +#if SUPPORT_WORKPLACE_COORDINATES + else if (gb.MachineState().useMachineCoordinates) + { + currentUserPosition[X_AXIS] = xParam - workplaceCoordinates[currentCoordinateSystem][X_AXIS]; + currentUserPosition[Y_AXIS] = yParam - workplaceCoordinates[currentCoordinateSystem][Y_AXIS]; + } +#endif else { currentUserPosition[X_AXIS] = xParam; @@ -4231,7 +4244,7 @@ void GCodes::SetMachinePosition(const float positionNow[DRIVES], bool doBedCompe } // Get the current position from the Move class -void GCodes::GetCurrentUserPosition() +void GCodes::UpdateCurrentUserPosition() { reprap.GetMove().GetCurrentUserPosition(moveBuffer.coords, 0, reprap.GetCurrentXAxes(), reprap.GetCurrentYAxes()); ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); @@ -4271,7 +4284,8 @@ void GCodes::RestorePosition(const RestorePoint& rp, GCodeBuffer *gb) } // Convert user coordinates to head reference point coordinates, optionally allowing for X axis mapping -// If the X axis is mapped to some other axes not including X, then the X coordinate of coordsOut will be left unchanged. So make sure it is suitably initialised before calling this. +// If the X axis is mapped to some other axes not including X, then the X coordinate of coordsOut will be left unchanged. +// So make sure it is suitably initialised before calling this. void GCodes::ToolOffsetTransform(const float coordsIn[MaxAxes], float coordsOut[MaxAxes], AxesBitmap explicitAxes) { const Tool * const currentTool = reprap.GetCurrentTool(); diff --git a/src/GCodes/GCodes.h b/src/GCodes/GCodes.h index ba312f2c..cf9ab462 100644 --- a/src/GCodes/GCodes.h +++ b/src/GCodes/GCodes.h @@ -160,6 +160,7 @@ public: float GetRawExtruderTotalByDrive(size_t extruder) const; // Get the total extrusion since start of print, for one drive float GetTotalRawExtrusion() const { return rawExtruderTotal; } // Get the total extrusion since start of print, all drives float GetBabyStepOffset() const { return currentBabyStepZOffset; } // Get the current baby stepping Z offset + const float *GetUserPosition() const { return currentUserPosition; } // Return the current user position RegularGCodeInput *GetHTTPInput() const { return httpInput; } RegularGCodeInput *GetTelnetInput() const { return telnetInput; } @@ -292,42 +293,42 @@ private: bool ToolHeatersAtSetTemperatures(const Tool *tool, bool waitWhenCooling) const; // Wait for the heaters associated with the specified tool to reach their set temperatures 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 + void CheckReportDue(GCodeBuffer& gb, const StringRef& reply) const; // Check whether we need to report temperatures or status - void SavePosition(RestorePoint& rp, const GCodeBuffer& gb) const; // Save position to a restore point - void RestorePosition(const RestorePoint& rp, GCodeBuffer *gb); // Restore user position from a restore point + void SavePosition(RestorePoint& rp, const GCodeBuffer& gb) const; // Save position to a restore point + void RestorePosition(const RestorePoint& rp, GCodeBuffer *gb); // Restore user position from a restore point - void SetAllAxesNotHomed(); // Flag all axes as not homed + void SetAllAxesNotHomed(); // Flag all axes as not homed void SetMachinePosition(const float positionNow[DRIVES], bool doBedCompensation = true); // Set the current position to be this - void GetCurrentUserPosition(); // Get the current position form the Move class + void UpdateCurrentUserPosition(); // Get the current position from the Move class void ToolOffsetTransform(const float coordsIn[MaxAxes], float coordsOut[MaxAxes], AxesBitmap explicitAxes = 0); // Convert user coordinates to head reference point coordinates void ToolOffsetInverseTransform(const float coordsIn[MaxAxes], float coordsOut[MaxAxes]); // Convert head reference point coordinates to user coordinates - const char *TranslateEndStopResult(EndStopHit es); // Translate end stop result to text - 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 + const char *TranslateEndStopResult(EndStopHit es); // Translate end stop result to text + 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 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 - void CheckHeaterFault(); // Check for and respond to a heater fault, returning true if we should exit - void DoEmergencyStop(); // Execute an emergency stop + void CheckTriggers(); // Check for and execute triggers + void CheckFilament(); // Check for and respond to filament errors + void CheckHeaterFault(); // Check for and respond to a heater fault, returning true if we should exit + void DoEmergencyStop(); // Execute an emergency stop - void DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg) // Pause the print + void DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg) // Pause the print pre(resourceOwners[movementResource] = &gb); #if HAS_VOLTAGE_MONITOR || HAS_SMART_DRIVERS - bool DoEmergencyPause(); // Do an emergency pause following loss of power or a motor stall + bool DoEmergencyPause(); // Do an emergency pause following loss of power or a motor stall #endif - void SetMappedFanSpeed(); // Set the speeds of fans mapped for the current tool - void SaveFanSpeeds(); // Save the speeds of all fans + void SetMappedFanSpeed(); // Set the speeds of fans mapped for the current tool + void SaveFanSpeeds(); // Save the speeds of all fans - GCodeResult SetOrReportZProbe(GCodeBuffer& gb, const StringRef &reply); // Handle M558 + GCodeResult SetOrReportZProbe(GCodeBuffer& gb, const StringRef &reply); // Handle M558 GCodeResult DefineGrid(GCodeBuffer& gb, const StringRef &reply); // Define the probing grid, returning true if error - bool LoadHeightMap(GCodeBuffer& gb, const StringRef& reply) const; // Load the height map from file - bool SaveHeightMap(GCodeBuffer& gb, const StringRef& reply) const; // Save the height map to file - GCodeResult ProbeGrid(GCodeBuffer& gb, const StringRef& reply); // Start probing the grid, returning true if we didn't because of an error + bool LoadHeightMap(GCodeBuffer& gb, const StringRef& reply) const; // Load the height map from file + bool SaveHeightMap(GCodeBuffer& gb, const StringRef& reply) const; // Save the height map to file + GCodeResult ProbeGrid(GCodeBuffer& gb, const StringRef& reply); // Start probing the grid, returning true if we didn't because of an error GCodeResult CheckOrConfigureTrigger(GCodeBuffer& gb, const StringRef& reply, int code); // Handle M581 and M582 GCodeResult UpdateFirmware(GCodeBuffer& gb, const StringRef &reply); // Handle M997 GCodeResult SendI2c(GCodeBuffer& gb, const StringRef &reply); // Handle M260 @@ -431,8 +432,9 @@ private: float arcSegmentLength; // Length of segments that we split arc moves into #if SUPPORT_WORKPLACE_COORDINATES + static const size_t NumCoordinateSystems = 9; unsigned int currentCoordinateSystem; - float workplaceCoordinates[10][MaxAxes]; // Workplace coordinate offsets + float workplaceCoordinates[NumCoordinateSystems][MaxAxes]; // Workplace coordinate offsets #else float axisOffsets[MaxAxes]; // M206 axis offsets #endif diff --git a/src/GCodes/GCodes2.cpp b/src/GCodes/GCodes2.cpp index dea916c1..3be09f1f 100644 --- a/src/GCodes/GCodes2.cpp +++ b/src/GCodes/GCodes2.cpp @@ -89,13 +89,13 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) { GCodeResult result = GCodeResult::ok; const int code = gb.GetCommandNumber(); - if (simulationMode != 0 && code > 4 && code != 10 && code != 11 && code != 20 && code != 21 && code != 90 && code != 91 && code != 92) + if (simulationMode != 0 && code > 4 && code != 10 && code != 11 && code != 20 && code != 21 && (code < 53 || code > 59) && (code < 90 || code > 92)) { - return true; // we only simulate some gcodes + return true; // we only simulate some gcodes } if (gb.MachineState().runningM502 && code != 31) { - return true; // when running M502 the only gcode we execute is G31 + return true; // when running M502 the only gcode we execute is G31 } switch (code) @@ -272,26 +272,35 @@ bool GCodes::HandleGcode(GCodeBuffer& gb, const StringRef& reply) break; #if SUPPORT_WORKPLACE_COORDINATES - case 53: // Switch to coordinate system 0 + case 53: // Temporarily use machine coordinates + gb.MachineState().useMachineCoordinates = true; + break; + case 54: // Switch to coordinate system 1 case 55: // Switch to coordinate system 2 case 56: // Switch to coordinate system 3 case 57: // Switch to coordinate system 4 case 58: // Switch to coordinate system 5 case 59: // Switch to coordinate system 6,7,8,9 + if (!LockMovementAndWaitForStandstill(gb)) { - unsigned int cs = code - 53; + return false; + } + { + unsigned int cs = code - 54; if (code == 59) { const int8_t fraction = gb.GetCommandFraction(); if (fraction >= 0) { - cs += (unsigned int) fraction; + cs += (unsigned int)fraction; } } - if (cs < ARRAY_SIZE(workplaceCoordinates)) + if (cs < NumCoordinateSystems) { - currentCoordinateSystem = cs; + currentCoordinateSystem = cs; // this is the zero-base coordinate system number + gb.MachineState().useMachineCoordinates = false; + ToolOffsetInverseTransform(moveBuffer.coords, currentUserPosition); // update user coordinates } else { @@ -1239,8 +1248,15 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) } break; - case 104: case 109: // Deprecated in RRF, but widely generated by slicers + if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished + || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution + ) + { + return false; + } + // no break + case 104: // New behaviour from 1.20beta12: // M109 Snnn // - If no tools are active, set Tool 0 to active @@ -1388,6 +1404,13 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) break; case 116: // Wait for set temperatures + if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished + || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution + ) + { + return false; + } + if (!cancelWait) { bool seen = false; @@ -1694,12 +1717,18 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) case 190: // Set bed temperature and wait case 191: // Set chamber temperature and wait + if ( !LockMovementAndWaitForStandstill(gb) // wait until movement has finished + || !IsCodeQueueIdle() // also wait until deferred command queue has caught up to avoid out-of-order execution + ) + { + return false; + } { // Check if the heater index is passed - int index = gb.Seen('P') ? gb.GetIValue() : 0; - if (index < 0 || index >= (int)((code == 190) ? NumBedHeaters : NumChamberHeaters)) + const uint32_t index = gb.Seen('P') ? gb.GetUIValue() : 0; + if (index >= ((code == 190) ? NumBedHeaters : NumChamberHeaters)) { - reply.printf("Invalid heater index '%d'", index); + reply.printf("Invalid heater index '%" PRIu32 "'", index); result = GCodeResult::error; break; } @@ -2139,6 +2168,11 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) break; } + if (sParam >= 2 && !LockMovementAndWaitForStandstill(gb)) + { + return false; // if it's a blocking message, wait for movement to stop before displaying it + } + float tParam; if (sParam == 0 || sParam == 1) { @@ -3046,7 +3080,16 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) } if (gb.Seen('T')) { - platform.SetDriverStepTiming(drive, gb.GetFValue()); + float timings[4]; + size_t numTimings = ARRAY_SIZE(timings); + gb.GetFloatArray(timings, numTimings, true); + if (numTimings != ARRAY_SIZE(timings)) + { + reply.copy("bad timing parameter"); + result = GCodeResult::error; + break; + } + platform.SetDriverStepTiming(drive, timings); seen = true; } bool badParameter = false; @@ -3063,14 +3106,18 @@ bool GCodes::HandleMcode(GCodeBuffer& gb, const StringRef& reply) } if (badParameter) { - platform.Message(ErrorMessage, "M569 no longer accepts XYZE parameters; use M584 instead\n"); + reply.copy("M569 no longer accepts XYZE parameters; use M584 instead"); + result = GCodeResult::error; } else if (!seen) { - reply.printf("A %d sends drive %u forwards, a %d enables it, and the minimum pulse width is %.1f microseconds", - (int)platform.GetDirectionValue(drive), drive, - (int)platform.GetEnableValue(drive), - (double)platform.GetDriverStepTiming(drive)); + float timings[4]; + platform.GetDriverStepTiming(drive, timings); + reply.printf("Drive %u runs %s, active %s enable, step timing %.1f,%.1f,%.1f,%.1f microseconds", + drive, + (platform.GetDirectionValue(drive)) ? "forwards" : "in reverse", + (platform.GetEnableValue(drive)) ? "high" : "low", + (double)timings[0], (double)timings[1], (double)timings[2], (double)timings[3]); } } } diff --git a/src/GCodes/GCodes3.cpp b/src/GCodes/GCodes3.cpp index 9ab7291b..1d0e20f6 100644 --- a/src/GCodes/GCodes3.cpp +++ b/src/GCodes/GCodes3.cpp @@ -198,7 +198,7 @@ GCodeResult GCodes::GetSetWorkplaceCoordinates(GCodeBuffer& gb, const StringRef& if (gb.Seen('P')) { const uint32_t cs = gb.GetIValue(); - if (cs < ARRAY_SIZE(workplaceCoordinates)) + if (cs > 0 && cs <= NumCoordinateSystems) { bool seen = false; for (size_t axis = 0; axis < numVisibleAxes; axis++) @@ -214,8 +214,8 @@ GCodeResult GCodes::GetSetWorkplaceCoordinates(GCodeBuffer& gb, const StringRef& } seen = true; } - workplaceCoordinates[cs][axis] = (compute) - ? coord - currentUserPosition[axis] + workplaceCoordinates[currentCoordinateSystem][axis] + workplaceCoordinates[cs - 1][axis] = (compute) + ? currentUserPosition[axis] - coord + workplaceCoordinates[currentCoordinateSystem][axis] : coord; } } @@ -226,10 +226,10 @@ GCodeResult GCodes::GetSetWorkplaceCoordinates(GCodeBuffer& gb, const StringRef& } else { - reply.printf("Coordinates of workplace %" PRIu32 ":", cs); + reply.printf("Origin of workplace %" PRIu32 ":", cs); for (size_t axis = 0; axis < numVisibleAxes; axis++) { - reply.catf(" %c%.2f", axisLetters[axis], (double)workplaceCoordinates[cs][axis]); + reply.catf(" %c%.2f", axisLetters[axis], (double)workplaceCoordinates[cs - 1][axis]); } } return GCodeResult::ok; @@ -345,6 +345,7 @@ GCodeResult GCodes::SetOrReportZProbe(GCodeBuffer& gb, const StringRef &reply) { platform.SetZProbeType(gb.GetIValue()); seenType = true; + DoDwellTime(gb, 100); // delay a little to allow the averaging filters to accumulate data from the new source } ZProbe params = platform.GetCurrentZProbeParameters(); diff --git a/src/Movement/DDA.cpp b/src/Movement/DDA.cpp index a0bf5aab..45250ae9 100644 --- a/src/Movement/DDA.cpp +++ b/src/Movement/DDA.cpp @@ -1440,7 +1440,9 @@ pre(state == frozen) return true; // schedule another interrupt immediately } -uint32_t DDA::maxReps = 0; // this holds he maximum ISR loop count +uint32_t DDA::maxReps = 0; // this holds he maximum ISR loop count +uint32_t DDA::lastStepLowTime = 0; +uint32_t DDA::lastDirChangeTime = 0; // This is called by the interrupt service routine to execute steps. // It returns true if it needs to be called again on the DDA of the new current move, otherwise false. @@ -1449,7 +1451,7 @@ uint32_t DDA::maxReps = 0; // this holds he maximum ISR loop count bool DDA::Step() { Platform& platform = reprap.GetPlatform(); - uint32_t lastStepPulseTime = platform.GetInterruptClocks(); + uint32_t lastStepPulseTime = lastStepLowTime; bool repeat; uint32_t numReps = 0; do @@ -1481,7 +1483,7 @@ bool DDA::Step() //if (t3 < minCalcTime) minCalcTime = t3; } - if ((driversStepping & platform.GetSlowDrivers()) == 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 @@ -1489,22 +1491,27 @@ bool DDA::Step() else { // 3. Step the drivers - while (Platform::GetInterruptClocks() - lastStepPulseTime < platform.GetSlowDriverClocks()) {} + uint32_t now; + do + { + now = Platform::GetInterruptClocks(); + } + while (now - lastStepPulseTime < platform.GetSlowDriverStepLowClocks() || now - lastDirChangeTime < platform.GetSlowDriverDirSetupClocks()); Platform::StepDriversHigh(driversStepping); // generate the steps lastStepPulseTime = Platform::GetInterruptClocks(); // 3a. Reset all step pins low. Do this now because some external drivers don't like the direction pins being changed before the end of the step pulse. - while (Platform::GetInterruptClocks() - lastStepPulseTime < platform.GetSlowDriverClocks()) {} + while (Platform::GetInterruptClocks() - lastStepPulseTime < platform.GetSlowDriverStepHighClocks()) {} Platform::StepDriversLow(); // set all step pins low - lastStepPulseTime = Platform::GetInterruptClocks(); + lastStepLowTime = lastStepPulseTime = Platform::GetInterruptClocks(); } // 4. Remove those drives from the list, calculate the next step times, update the direction pins where necessary, // and re-insert them so as to keep the list in step-time order. // Note that the call to CalcNextStepTime may change the state of Direction pin. - DriveMovement *dmToInsert = firstDM; // head of the chain we need to re-insert - firstDM = dm; // remove the chain from the list - while (dmToInsert != dm) // note that both of these may be nullptr + DriveMovement *dmToInsert = firstDM; // head of the chain we need to re-insert + firstDM = dm; // remove the chain from the list + while (dmToInsert != dm) // note that both of these may be nullptr { const bool hasMoreSteps = (isDeltaMovement && dmToInsert->drive < DELTA_AXES) ? dmToInsert->CalcNextStepTimeDelta(*this, true) @@ -1518,7 +1525,7 @@ bool DDA::Step() } // 5. Reset all step pins low. We already did this if we are using any external drivers, but doing it again does no harm. - Platform::StepDriversLow(); // set all step pins low + Platform::StepDriversLow(); // set all step pins low // 6. Check for move completed if (firstDM == nullptr) @@ -1542,8 +1549,8 @@ bool DDA::Step() // However, following a move that checks endstops or the Z probe, we always wait for the move to complete before we schedule another, so this doesn't matter. const uint32_t finishTime = moveStartTime + clocksNeeded; // calculate how long this move should take Move& move = reprap.GetMove(); - move.CurrentMoveCompleted(); // tell Move that the current move is complete - return move.TryStartNextMove(finishTime); // schedule the next move + move.CurrentMoveCompleted(); // tell Move that the current move is complete + return move.TryStartNextMove(finishTime); // schedule the next move } return false; } diff --git a/src/Movement/DDA.h b/src/Movement/DDA.h index 5de52e3f..72124b30 100644 --- a/src/Movement/DDA.h +++ b/src/Movement/DDA.h @@ -127,7 +127,9 @@ public: static int32_t loggedProbePositions[XYZ_AXES * MaxLoggedProbePositions]; #endif - static uint32_t maxReps; + static uint32_t maxReps; // maximum number of times that the ISR looped + 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 private: DriveMovement *FindDM(size_t drive) const; diff --git a/src/Movement/Kinematics/LinearDeltaKinematics.cpp b/src/Movement/Kinematics/LinearDeltaKinematics.cpp index 4704b191..7029deee 100644 --- a/src/Movement/Kinematics/LinearDeltaKinematics.cpp +++ b/src/Movement/Kinematics/LinearDeltaKinematics.cpp @@ -593,6 +593,12 @@ bool LinearDeltaKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const if (gb.Seen('B')) { printRadius = gb.GetFValue(); + // Set the axis limits so that DWC reports them correctly (they are not otherwise used for deltas, except Z min) + Platform& p = reprap.GetPlatform(); + p.SetAxisMinimum(X_AXIS, -printRadius, false); + p.SetAxisMinimum(Y_AXIS, -printRadius, false); + p.SetAxisMaximum(X_AXIS, printRadius, false); + p.SetAxisMaximum(Y_AXIS, printRadius, false); seen = true; } if (gb.Seen('X')) @@ -609,15 +615,16 @@ bool LinearDeltaKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const } if (gb.Seen('Z')) { - // Y tower position correction + // Z tower position correction angleCorrections[DELTA_C_AXIS] = gb.GetFValue(); seen = true; } - // The homed height must be done last, because it gets recalculated when some of the other factors are changed if (gb.Seen('H')) { homedHeight = gb.GetFValue(); + // Set the Z axis maximum so that DWC reports it correctly (it is not otherwise used for deltas) + reprap.GetPlatform().SetAxisMaximum(Z_AXIS, homedHeight, false); seen = true; } diff --git a/src/Networking/W5500Ethernet/Wiznet/Internet/DHCP/dhcp.cpp b/src/Networking/W5500Ethernet/Wiznet/Internet/DHCP/dhcp.cpp index 5b325645..2ecd0af3 100644 --- a/src/Networking/W5500Ethernet/Wiznet/Internet/DHCP/dhcp.cpp +++ b/src/Networking/W5500Ethernet/Wiznet/Internet/DHCP/dhcp.cpp @@ -938,7 +938,6 @@ void check_DHCP_leasedIP(void) // IP conflict detection : ARP request - ARP reply // Broadcasting ARP Request for check the IP conflict using UDP sendto() function - // TODO the following takes 620ms to time out - hanging for this long isn't very nice sendto(DHCP_SOCKET, (const uint8_t *)"CHECK_IP_CONFLICT", 17, DHCP_allocated_ip, 5000); // RCR value restore @@ -44,4 +44,8 @@ # define SUPPORT_12864_LCD 0 #endif +#ifndef USE_CACHE +# define USE_CACHE 0 +#endif + #endif // PINS_H__ diff --git a/src/Platform.cpp b/src/Platform.cpp index aee8b7c6..43dcb2c2 100644 --- a/src/Platform.cpp +++ b/src/Platform.cpp @@ -66,7 +66,7 @@ extern "C" char *sbrk(int i); # error Missing feature definition #endif -#if SAM4E && USE_CACHE +#if USE_CACHE #include "sam/drivers/cmcc/cmcc.h" @@ -114,7 +114,7 @@ const uint32_t fanMaxInterruptCount = 32; // number of fan interrupts that we static volatile uint32_t fanLastResetTime = 0; // time (microseconds) at which we last reset the interrupt count, accessed inside and outside ISR static volatile uint32_t fanInterval = 0; // written by ISR, read outside the ISR -const float minStepPulseTiming = 0.2; // we assume that we always generate step high and low times at least this wide without special action +const float MinStepPulseTiming = 0.2; // we assume that we always generate step high and low times at least this wide without special action const LogicalPin Heater0LogicalPin = 0; const LogicalPin Fan0LogicalPin = 20; @@ -197,7 +197,7 @@ void setup() #endif RSTC->RSTC_MR = RSTC_MR_KEY_PASSWD | RSTC_MR_URSTEN; // ignore any signal on the NRST pin for now so that the reset reason will show as Software -#if SAM4E && USE_CACHE +#if USE_CACHE // Enable the cache struct cmcc_config g_cmcc_cfg; cmcc_get_config_defaults(&g_cmcc_cfg); @@ -518,8 +518,11 @@ void Platform::Init() #endif } - slowDriverStepPulseClocks = 0; // no extended driver timing configured yet - slowDrivers = 0; // assume no drivers need extended step pulse timing + for (uint32_t& entry : slowDriverStepTimingClocks) + { + entry = 0; // reset all to zero as we have no known slow drivers yet + } + slowDriversBitmap = 0; // assume no drivers need extended step pulse timing for (size_t extr = 0; extr < MaxExtruders; ++extr) { @@ -2110,7 +2113,7 @@ void Platform::PrintUniqueId(MessageType mtype) // Return diagnostic information void Platform::Diagnostics(MessageType mtype) { -#if SAM4E && USE_CACHE +#if USE_CACHE // Get the cache statistics before we start messing around with the cache const uint32_t cacheCount = cmcc_get_monitor_cnt(CMCC); #endif @@ -2308,8 +2311,7 @@ void Platform::Diagnostics(MessageType mtype) Message(mtype, "not set\n"); } -#if SAM4E && USE_CACHE - // Get the cache statistics before we start messing around with the cache +#if USE_CACHE MessageF(mtype, "Cache data hit count %" PRIu32 "\n", cacheCount); #endif @@ -2491,7 +2493,8 @@ bool Platform::DiagnosticTest(GCodeBuffer& gb, const StringRef& reply, int d) case (int)DiagnosticTestType::UnalignedMemoryAccess: // do an unaligned memory access to test exception handling deliberateError = true; SCB->CCR |= SCB_CCR_UNALIGN_TRP_Msk; // by default, unaligned memory accesses are allowed, so change that - (void)RepRap::ReadDword(reinterpret_cast<const char*>(dummy) + 1); // call function in another module so it can't be optimised away + __DMB(); // make sure that instruction completes, don't allow prefetch + (void)*(reinterpret_cast<const volatile char*>(dummy) + 1); break; case (int)DiagnosticTestType::BusFault: @@ -2502,9 +2505,9 @@ bool Platform::DiagnosticTest(GCodeBuffer& gb, const StringRef& reply, int d) // I guess this can wait until we have the RTOS working though. Message(WarningMessage, "There is no abort area on the SAME70"); #elif SAM4E || SAM4S - (void)RepRap::ReadDword(reinterpret_cast<const char*>(0x20800000)); + (void)*(reinterpret_cast<const volatile char*>(0x20800000)); #elif SAM3XA - (void)RepRap::ReadDword(reinterpret_cast<const char*>(0x20200000)); + (void)*(reinterpret_cast<const volatile char*>(0x20200000)); #else # error #endif @@ -2846,6 +2849,11 @@ bool Platform::WriteAxisLimits(FileStore *f, AxesBitmap axesProbed, const float // If drive >= DRIVES then we are setting an individual motor direction void Platform::SetDirection(size_t drive, bool direction) { + const bool isSlowDriver = (GetDriversBitmap(drive) & GetSlowDriversBitmap()) != 0; + if (isSlowDriver) + { + while (GetInterruptClocks() - DDA::lastStepLowTime < GetSlowDriverDirHoldClocks()) { } + } const size_t numAxes = reprap.GetGCodes().GetTotalAxes(); if (drive < numAxes) { @@ -2862,6 +2870,10 @@ void Platform::SetDirection(size_t drive, bool direction) { SetDriverDirection(drive - DRIVES, direction); } + if (isSlowDriver) + { + DDA::lastDirChangeTime = GetInterruptClocks(); + } } // Enable a driver. Must not be called from an ISR, or with interrupts disabled. @@ -3248,28 +3260,41 @@ void Platform::SetExtruderDriver(size_t extruder, uint8_t driver) driveDriverBits[extruder + reprap.GetGCodes().GetTotalAxes()] = CalcDriverBitmap(driver); } -void Platform::SetDriverStepTiming(size_t driver, float microseconds) +void Platform::SetDriverStepTiming(size_t driver, const float microseconds[4]) { - if (microseconds < minStepPulseTiming) + const uint32_t bitmap = CalcDriverBitmap(driver); + slowDriversBitmap &= ~bitmap; // start by assuming this drive does not need extended timing + if (slowDriversBitmap == 0) { - slowDrivers &= ~CalcDriverBitmap(driver); // this drive does not need extended timing + for (uint32_t& entry : slowDriverStepTimingClocks) + { + entry = 0; // reset all to zero if we have no known slow drivers + } } - else + + for (size_t i = 0; i < ARRAY_SIZE(slowDriverStepTimingClocks); ++i) { - const uint32_t clocks = (uint32_t)(((float)DDA::stepClockRate * microseconds * 0.000001) + 0.99); // convert microseconds to step clocks, rounding up - if (clocks > slowDriverStepPulseClocks) + if (microseconds[i] > MinStepPulseTiming) { - slowDriverStepPulseClocks = clocks; + slowDriversBitmap |= CalcDriverBitmap(driver); // this drive does need extended timing + const uint32_t clocks = (uint32_t)(((float)DDA::stepClockRate * microseconds[i] * 0.000001) + 0.99); // convert microseconds to step clocks, rounding up + if (clocks > slowDriverStepTimingClocks[i]) + { + slowDriverStepTimingClocks[i] = clocks; + } } - slowDrivers |= CalcDriverBitmap(driver); // this drive does need extended timing } } -float Platform::GetDriverStepTiming(size_t driver) const +void Platform::GetDriverStepTiming(size_t driver, float microseconds[4]) const { - return ((slowDrivers & CalcDriverBitmap(driver)) != 0) - ? (float)slowDriverStepPulseClocks * 1000000.0/(float)DDA::stepClockRate - : 0.0; + const bool isSlowDriver = ((slowDriversBitmap & CalcDriverBitmap(driver)) != 0); + for (size_t i = 0; i < 4; ++i) + { + microseconds[i] = (isSlowDriver) + ? (float)slowDriverStepTimingClocks[i] * 1000000.0/(float)DDA::stepClockRate + : 0.0; + } } // Set or report the parameters for the specified fan @@ -3292,7 +3317,7 @@ bool Platform::ConfigureFan(unsigned int mcode, int fanNum, GCodeBuffer& gb, con // Get current cooling fan speed on a scale between 0 and 1 float Platform::GetFanValue(size_t fan) const { - return (fan < NUM_FANS) ? fans[fan].GetValue() : -1; + return (fan < NUM_FANS) ? fans[fan].GetConfiguredPwm() : -1; } // This is a bit of a compromise - old RepRaps used fan speeds in the range @@ -3304,7 +3329,7 @@ void Platform::SetFanValue(size_t fan, float speed) { if (fan < NUM_FANS) { - fans[fan].SetValue(speed); + fans[fan].SetPwm(speed); } } @@ -3354,7 +3379,7 @@ void Platform::InitFans() { #if defined(DUET_06_085) // Fan 1 on the Duet 0.8.5 shares its control pin with heater 6. Set it full on to make sure the heater (if present) is off. - fans[1].SetValue(1.0); // set it full on + fans[1].SetPwm(1.0); // set it full on #else // Set fan 1 to be thermostatic by default, monitoring all heaters except the default bed and chamber heaters Fan::HeatersMonitoredBitmap bedAndChamberHeaterMask = 0; @@ -3373,7 +3398,7 @@ void Platform::InitFans() } } fans[1].SetHeatersMonitored(LowestNBits<Fan::HeatersMonitoredBitmap>(Heaters) & ~bedAndChamberHeaterMask); - fans[1].SetValue(1.0); // set it full on + fans[1].SetPwm(1.0); // set it full on #endif } diff --git a/src/Platform.h b/src/Platform.h index 5977b2fa..253b66ec 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -406,8 +406,8 @@ public: unsigned int GetDriverMicrostepping(size_t drive, int mode, bool& interpolation) const; bool SetMicrostepping(size_t drive, int microsteps, int mode); unsigned int GetMicrostepping(size_t drive, int mode, bool& interpolation) const; - void SetDriverStepTiming(size_t driver, float microseconds); - float GetDriverStepTiming(size_t driver) const; + void SetDriverStepTiming(size_t driver, const float microseconds[4]); + void GetDriverStepTiming(size_t driver, float microseconds[4]) const; float DriveStepsPerUnit(size_t drive) const; const float *GetDriveStepsPerUnit() const { return driveStepsPerUnit; } @@ -455,8 +455,11 @@ public: { return driveDriverBits[drive]; } static void StepDriversLow(); // set all step pins low static void StepDriversHigh(uint32_t driverMap); // set the specified step pins high - uint32_t GetSlowDrivers() const { return slowDrivers; } - uint32_t GetSlowDriverClocks() const { return slowDriverStepPulseClocks; } + uint32_t GetSlowDriversBitmap() const { return slowDriversBitmap; } + uint32_t GetSlowDriverStepHighClocks() const { return slowDriverStepTimingClocks[0]; } + uint32_t GetSlowDriverStepLowClocks() const { return slowDriverStepTimingClocks[1]; } + uint32_t GetSlowDriverDirSetupClocks() const { return slowDriverStepTimingClocks[2]; } + uint32_t GetSlowDriverDirHoldClocks() const { return slowDriverStepTimingClocks[3]; } #if SUPPORT_NONLINEAR_EXTRUSION bool GetExtrusionCoefficients(size_t extruder, float& a, float& b, float& limit) const; @@ -739,8 +742,8 @@ private: AxisDriversConfig axisDrivers[MaxAxes]; // the driver numbers assigned to each axis uint8_t extruderDrivers[MaxExtruders]; // the driver number assigned to each extruder uint32_t driveDriverBits[2 * DRIVES]; // the bitmap of driver port bits for each axis or extruder, followed by the raw versions - uint32_t slowDriverStepPulseClocks; // minimum high and low step pulse widths, in processor clocks - uint32_t slowDrivers; // bitmap of driver port bits that need extended step pulse timing + uint32_t slowDriverStepTimingClocks[4]; // minimum step high, step low, dir setup and dir hold timing for slow drivers + uint32_t slowDriversBitmap; // bitmap of driver port bits that need extended step pulse timing float idleCurrentFactor; #if HAS_SMART_DRIVERS @@ -1131,7 +1134,7 @@ inline float Platform::GetPressureAdvance(size_t extruder) const return rslt; } -// Function GetInterruptClocks() is quite long for these processors, so it is moved to Platform.cpp and no longer inlined +// Function GetInterruptClocksInterruptsDisabled() is quite long for these processors, so it is moved to Platform.cpp and no longer inlined #else // TCs are 32-bit diff --git a/src/RepRap.cpp b/src/RepRap.cpp index 5a486c2c..6d7e8008 100644 --- a/src/RepRap.cpp +++ b/src/RepRap.cpp @@ -607,6 +607,32 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) // Coordinates const size_t numVisibleAxes = gCodes->GetVisibleAxes(); + // Homed axes + response->cat("\"axesHomed\":"); + ch = '['; + for (size_t axis = 0; axis < numVisibleAxes; ++axis) + { + response->catf("%c%d", ch, (gCodes->GetAxisIsHomed(axis)) ? 1 : 0); + ch = ','; + } + + // XYZ positions + // Coordinates may be NaNs or infinities, for example when delta or SCARA homing fails. We must replace any NaNs or infinities to avoid JSON parsing errors. + // Ideally we would report "unknown" or similar for axis positions that are not known because we haven't homed them, but that requires changes to both DWC and PanelDue. + // So we report 9999.9 instead. + + // First the user coordinates + response->cat("],\"xyz\":"); + const float * const userPos = gCodes->GetUserPosition(); + ch = '['; + 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)); + ch = ','; + } + + // Now the machine coordinates and the extruder coordinates { float liveCoordinates[DRIVES]; #if SUPPORT_ROLAND @@ -620,47 +646,27 @@ OutputBuffer *RepRap::GetStatusResponse(uint8_t type, ResponseSource source) move->LiveCoordinates(liveCoordinates, GetCurrentXAxes(), GetCurrentYAxes()); } - if (currentTool != nullptr) - { - for (size_t i = 0; i < numVisibleAxes; ++i) - { - liveCoordinates[i] += currentTool->GetOffset(i); - } - } - - // Homed axes - response->cat("\"axesHomed\":"); + // Machine coordinates + response->catf("],\"machine\":"); // announce the machine position ch = '['; - for (size_t axis = 0; axis < numVisibleAxes; ++axis) + for (size_t drive = 0; drive < numVisibleAxes; drive++) { - response->catf("%c%d", ch, (gCodes->GetAxisIsHomed(axis)) ? 1 : 0); + response->catf("%c%.3f", ch, (double)liveCoordinates[drive]); ch = ','; } // Actual and theoretical extruder positions since power up, last G92 or last M23 - response->catf("],\"extr\":"); // announce actual extruder positions + response->catf("],\"extr\":"); // announce actual extruder positions ch = '['; for (size_t extruder = 0; extruder < GetExtrudersInUse(); extruder++) { response->catf("%c%.1f", ch, (double)liveCoordinates[gCodes->GetTotalAxes() + extruder]); ch = ','; } - if (ch == '[') + if (ch == '[') // we may have no extruders { response->cat(ch); } - - // XYZ positions - // TODO ideally we would report "unknown" or similar for axis positions that are not known because we haven't homed them, but that requires changes to both DWC and PanelDue. - response->cat("],\"xyz\":"); - ch = '['; - for (size_t axis = 0; axis < numVisibleAxes; axis++) - { - // Coordinates may be NaNs, for example when delta or SCARA homing fails. Replace any NaNs or infinities by 9999.9 to prevent JSON parsing errors. - const float coord = liveCoordinates[axis]; - response->catf("%c%.3f", ch, (double)((std::isnan(coord) || std::isinf(coord)) ? 9999.9 : coord)); - ch = ','; - } } // Current tool number @@ -1341,19 +1347,26 @@ OutputBuffer *RepRap::GetLegacyStatusResponse(uint8_t type, int seq) response->cat("]"); // Send XYZ positions - const size_t numAxes = gCodes->GetVisibleAxes(); - float liveCoordinates[DRIVES]; - move->LiveCoordinates(liveCoordinates, GetCurrentXAxes(), GetCurrentYAxes()); - if (currentTool != nullptr) + const size_t numVisibleAxes = gCodes->GetVisibleAxes(); + + // First the user coordinates + response->catf(",\"pos\":"); // announce the user position + const float * const userPos = gCodes->GetUserPosition(); + ch = '['; + for (size_t axis = 0; axis < numVisibleAxes; axis++) { - for (size_t i = 0; i < numAxes; ++i) - { - liveCoordinates[i] += currentTool->GetOffset(i); - } + // Coordinates may be NaNs, for example when delta or SCARA homing fails. Replace any NaNs or infinities by 9999.9 to prevent JSON parsing errors. + const float coord = userPos[axis]; + response->catf("%c%.3f", ch, (double)((std::isnan(coord) || std::isinf(coord)) ? 9999.9 : coord)); + ch = ','; } - response->catf(",\"pos\":"); // announce the XYZ position + + // Now the machine coordinates + float liveCoordinates[DRIVES]; + move->LiveCoordinates(liveCoordinates, GetCurrentXAxes(), GetCurrentYAxes()); + response->catf("],\"machine\":"); // announce the machine position ch = '['; - for (size_t drive = 0; drive < numAxes; drive++) + for (size_t drive = 0; drive < numVisibleAxes; drive++) { response->catf("%c%.3f", ch, (double)liveCoordinates[drive]); ch = ','; @@ -1406,7 +1419,7 @@ OutputBuffer *RepRap::GetLegacyStatusResponse(uint8_t type, int seq) // Send the home state. To keep the messages short, we send 1 for homed and 0 for not homed, instead of true and false. response->cat(",\"homed\":"); ch = '['; - for (size_t axis = 0; axis < numAxes; ++axis) + for (size_t axis = 0; axis < numVisibleAxes; ++axis) { response->catf("%c%d", ch, (gCodes->GetAxisIsHomed(axis)) ? 1 : 0); ch = ','; @@ -1459,7 +1472,7 @@ OutputBuffer *RepRap::GetLegacyStatusResponse(uint8_t type, int seq) { // Add the static fields response->catf(",\"geometry\":\"%s\",\"axes\":%u,\"axisNames\":\"%s\",\"volumes\":%u,\"numTools\":%u,\"myName\":", - move->GetGeometryString(), numAxes, gCodes->GetAxisLetters(), NumSdCards, GetNumberOfContiguousTools()); + move->GetGeometryString(), numVisibleAxes, gCodes->GetAxisLetters(), NumSdCards, GetNumberOfContiguousTools()); response->EncodeString(myName.c_str(), myName.MaxLength(), false); response->cat(",\"firmwareName\":"); response->EncodeString(FIRMWARE_NAME, strlen(FIRMWARE_NAME), false); @@ -1862,12 +1875,6 @@ bool RepRap::WriteToolParameters(FileStore *f) const return a/b; } -// Helper function for diagnostic tests in Platform.cpp, to cause a deliberate unaligned memory read -/*static*/ uint32_t RepRap::ReadDword(const char* p) -{ - return *reinterpret_cast<const uint32_t*>(p); -} - // Report an internal error void RepRap::ReportInternalError(const char *file, const char *func, int line) const { diff --git a/src/RepRap.h b/src/RepRap.h index 0a8daa2f..145d23e5 100644 --- a/src/RepRap.h +++ b/src/RepRap.h @@ -114,7 +114,6 @@ public: void ReportInternalError(const char *file, const char *func, int line) const; // Report an internal error static uint32_t DoDivide(uint32_t a, uint32_t b); // helper function for diagnostic tests - static uint32_t ReadDword(const char* p); // helper function for diagnostic tests private: static void EncodeString(StringRef& response, const char* src, size_t spaceToLeave, bool allowControlChars = false, char prefix = 0); diff --git a/src/Version.h b/src/Version.h index d90862b8..13abf823 100644 --- a/src/Version.h +++ b/src/Version.h @@ -9,11 +9,11 @@ #define SRC_VERSION_H_ #ifndef VERSION -# define VERSION "1.21RC4" +# define VERSION "1.21RC5" #endif #ifndef DATE -# define DATE "2018-03-11 build 1" +# define DATE "2018-03-16 build 1" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman" |