Skip to content

Commit d7f8763

Browse files
committed
Towards version 2.02beta1
(note: dynamic acceleration control is probably not working correctly yet) New features and changed behaviour: - When switched into Laser mode (M452), the S parameter on G0 and G1 commands sets the laser power - The primary parameter letter used to control the type of a G0 or G1 move has been changed from S to H. This is because S is the standard parameter to control laser power on a laser cutter or engraver. However, unless you use M452 to put the firmware into Laser mode, you can continue to use S to set the move type. - If you set the motor idle current percentage to 0 in the M906 command, all drives will now be disabled when all motors have been idle for the idle timeout and all axes will be flagged as not homed. - The M569 accepts a new F parameter for the off-time. Valid values are 1 to 15. - Attempts to use M569 to set disallowed combinations of TOFF and TBL in the chopper control register of TMC2660 or TMC22xx drivers are rejected - The M106 command supports a new A parameter to map the fan to a different fan output or a heater output, or to re-enable a disabled fan - On Duet Ethernet and Duet Maestro the physical link speed and half/full duplex status is included in the Network section of the M122 report - The total number of axes is now passed to DWC and PanelDue as well as the number of visible axes - Added M703 support (thanks chrishamm) Bug fixes: - Lock the scheduler during M260 and M261 commabnds - The E parameter was ignored in G0 commands - Fixed bad JSON response when the 'first' parameter of a rr_filelist HTML command was non-zero - M106 Snn commands with no P parameter failed if fan 0 had been disabled but the print cooling fan was mapped to another fan in the current tool definition - If config.g invoked a macro then final values were copied to GCode sources too early and a subsequent M501 command wasn't acted on (thanks chrishamm) - If an emergency stop occurred during execution of a macro, an internal seek error message was sometimes generated. Emergency stop now closes any active print files and macro files.
1 parent 92bb016 commit d7f8763

30 files changed

+562
-447
lines changed

src/BugList.txt

Lines changed: 36 additions & 259 deletions
Large diffs are not rendered by default.

src/DuetNG/Pins_DuetNG.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,9 @@ constexpr size_t NumFirmwareUpdateModules = 4; // 3 modules, plus one for manua
2525
#define SUPPORT_INKJET 0 // set nonzero to support inkjet control
2626
#define SUPPORT_ROLAND 0 // set nonzero to support Roland mill
2727
#define SUPPORT_SCANNER 1 // set zero to disable support for FreeLSS scanners
28+
#define SUPPORT_LASER 1 // support laser cutters and engravers using G1 S parameter
2829
#define SUPPORT_IOBITS 1 // set to support P parameter in G0/G1 commands
29-
#ifdef RTOS
30-
# define SUPPORT_DHT_SENSOR 1 // set nonzero to support DHT temperature/humidity sensors
31-
#else
32-
# define SUPPORT_DHT_SENSOR 0 // DHT sensors are only supported in RTOS builds
33-
#endif
30+
#define SUPPORT_DHT_SENSOR 1 // set nonzero to support DHT temperature/humidity sensors
3431
#define SUPPORT_WORKPLACE_COORDINATES 1 // set nonzero to support G10 L2 and G53..59
3532

3633
#define USE_CACHE 0 // set nonzero to enable the cache. Disabled this at 1.21RC1 because of doubts about its safety.

src/Fans/Fan.cpp

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include "GCodes/GCodeBuffer.h"
1212
#include "Heating/Heat.h"
1313

14-
void Fan::Init(Pin p_pin, bool hwInverted, PwmFrequency p_freq)
14+
void Fan::Init(Pin p_pin, LogicalPin lp, bool hwInverted, PwmFrequency p_freq)
1515
{
1616
isConfigured = false;
1717
val = lastVal = 0.0;
@@ -20,6 +20,7 @@ void Fan::Init(Pin p_pin, bool hwInverted, PwmFrequency p_freq)
2020
blipTime = 100; // 100ms fan blip
2121
freq = p_freq;
2222
pin = p_pin;
23+
logicalPin = lp;
2324
hardwareInverted = hwInverted;
2425
inverted = blipping = false;
2526
heatersMonitored = 0;
@@ -38,16 +39,36 @@ void Fan::Init(Pin p_pin, bool hwInverted, PwmFrequency p_freq)
3839
// 2. Don't process the R parameter, but if it is present don't print the existing configuration.
3940
bool Fan::Configure(unsigned int mcode, int fanNum, GCodeBuffer& gb, const StringRef& reply, bool& error)
4041
{
41-
if (!IsEnabled())
42-
{
43-
reply.printf("Fan %d is disabled", fanNum);
44-
error = true;
45-
return true; // say we have processed it
46-
}
47-
4842
bool seen = false;
4943
if (mcode == 106)
5044
{
45+
// We allow a disabled fan to be re-enabled using the A parameter to specify the logical pin number
46+
if (gb.Seen('A'))
47+
{
48+
seen = true;
49+
const LogicalPin lp = gb.GetUIValue();
50+
if (reprap.GetPlatform().TranslateFanPin(lp, pin, hardwareInverted))
51+
{
52+
logicalPin = lp;
53+
}
54+
else
55+
{
56+
reply.copy("Logical pin ");
57+
reprap.GetPlatform().AppendPinName(lp, reply);
58+
reply.catf(" is not available to use for fan %d", fanNum);
59+
error = true;
60+
return true;
61+
}
62+
}
63+
64+
// The remaining parameters are not available if the fan has been disabled
65+
if (!IsEnabled())
66+
{
67+
reply.printf("Fan %d is disabled", fanNum);
68+
error = true;
69+
return true; // say we have processed it
70+
}
71+
5172
if (gb.Seen('I')) // Invert cooling
5273
{
5374
seen = true;
@@ -153,15 +174,20 @@ bool Fan::Configure(unsigned int mcode, int fanNum, GCodeBuffer& gb, const Strin
153174
else if (!gb.Seen('R') && !gb.Seen('S'))
154175
{
155176
// Report the configuration of the specified fan
156-
reply.printf("Fan%i frequency: %uHz, speed: %d%%, min: %d%%, max: %d%%, blip: %.2f, inverted: %s, name: %s",
157-
fanNum,
158-
(unsigned int)freq,
159-
(int)(val * 100.0),
160-
(int)(minVal * 100.0),
161-
(int)(maxVal * 100.0),
162-
(double)(blipTime * MillisToSeconds),
163-
(inverted) ? "yes" : "no",
164-
name.c_str());
177+
reply.printf("Fan %i", fanNum);
178+
if (name.strlen() != 0)
179+
{
180+
reply.catf(" (%s)", name.c_str());
181+
}
182+
reply.cat(" pin: ");
183+
reprap.GetPlatform().AppendPinName(logicalPin, reply);
184+
reply.catf(", frequency: %uHz, speed: %d%%, min: %d%%, max: %d%%, blip: %.2f, inverted: %s",
185+
(unsigned int)freq,
186+
(int)(val * 100.0),
187+
(int)(minVal * 100.0),
188+
(int)(maxVal * 100.0),
189+
(double)(blipTime * MillisToSeconds),
190+
(inverted) ? "yes" : "no");
165191
if (heatersMonitored != 0)
166192
{
167193
reply.catf(", temperature: %.1f:%.1fC, heaters:", (double)triggerTemperatures[0], (double)triggerTemperatures[1]);
@@ -264,10 +290,10 @@ void Fan::Refresh()
264290
// We already know that ht < triggerTemperatures[1], therefore unless we have NaNs it is safe to divide by (triggerTemperatures[1] - triggerTemperatures[0])
265291
reqVal = max<float>(reqVal, (ht - triggerTemperatures[0])/(triggerTemperatures[1] - triggerTemperatures[0]));
266292
}
267-
else if (lastVal != 0.0 && ht + ThermostatHysteresis > triggerTemperatures[0])
293+
else if (lastVal != 0.0 && ht + ThermostatHysteresis > triggerTemperatures[0]) // if the fan is on, add a hysteresis before turning it off
268294
{
269-
// If the fan is on, add a hysteresis before turning it off
270-
reqVal = min<float>(max<float>(reqVal, (bangBangMode) ? max<float>(0.5, val) : minVal), maxVal);
295+
const float minFanSpeed = (bangBangMode) ? max<float>(0.5, val) : minVal;
296+
reqVal = constrain<float>(reqVal, minFanSpeed, maxVal);
271297
}
272298
#if HAS_SMART_DRIVERS
273299
const unsigned int channel = reprap.GetHeat().GetHeaterChannel(heaterHumber);
@@ -283,16 +309,7 @@ void Fan::Refresh()
283309

284310
if (reqVal > 0.0)
285311
{
286-
if (reqVal < minVal)
287-
{
288-
reqVal = minVal;
289-
}
290-
291-
if (reqVal > maxVal)
292-
{
293-
reqVal = maxVal;
294-
}
295-
312+
reqVal = constrain<float>(reqVal, minVal, maxVal);
296313
if (lastVal == 0.0)
297314
{
298315
// We are turning this fan on
@@ -345,6 +362,7 @@ void Fan::Disable()
345362
SetHardwarePwm(0.0);
346363
}
347364
pin = NoPin;
365+
logicalPin = NoLogicalPin;
348366
}
349367

350368
// Save the settings of this fan if it isn't thermostatic

src/Fans/Fan.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ class Fan
2828

2929
bool IsEnabled() const { return pin != NoPin; }
3030
float GetConfiguredPwm() const { return val; } // returns the configured PWM. Actual PWM may be different, e.g. due to blipping or for thermostatic fans.
31+
LogicalPin GetLogicalPin() const { return logicalPin; }
3132

32-
void Init(Pin p_pin, bool hwInverted, PwmFrequency p_freq);
33+
void Init(Pin p_pin, LogicalPin lp, bool hwInverted, PwmFrequency p_freq);
3334
void SetPwm(float speed);
3435
bool HasMonitoredHeaters() const { return heatersMonitored != 0; }
3536
void SetHeatersMonitored(HeatersMonitoredBitmap h);
@@ -51,6 +52,7 @@ class Fan
5152
uint32_t blipStartTime;
5253
HeatersMonitoredBitmap heatersMonitored;
5354
PwmFrequency freq;
55+
LogicalPin logicalPin;
5456
Pin pin;
5557
String<MaxFanNameLength> name;
5658
bool isConfigured;

src/GCodes/GCodes.cpp

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,8 @@ void GCodes::Reset()
219219
moveBuffer.yAxes = DefaultYAxisMapping;
220220
moveBuffer.virtualExtruderPosition = 0.0;
221221

222-
#if SUPPORT_IOBITS
223-
moveBuffer.ioBits = 0;
222+
#if SUPPORT_LASER || SUPPORT_IOBITS
223+
moveBuffer.laserPwmOrIoBits.Clear();
224224
#endif
225225

226226
reprap.GetMove().GetKinematics().GetAssumedInitialPosition(numVisibleAxes, moveBuffer.coords);
@@ -1514,7 +1514,7 @@ void GCodes::DoFilePrint(GCodeBuffer& gb, const StringRef& reply)
15141514
// Finished a macro or finished processing config.g
15151515
fileInput->Reset(fd);
15161516
fd.Close();
1517-
if (runningConfigFile)
1517+
if (runningConfigFile && gb.MachineState().previous->previous == nullptr)
15181518
{
15191519
CopyConfigFinalValues(gb);
15201520
runningConfigFile = false;
@@ -1678,8 +1678,8 @@ void GCodes::DoPause(GCodeBuffer& gb, PauseReason reason, const char *msg)
16781678
// TODO: when using RTOS there is a possible race condition in the following,
16791679
// because we might try to pause when a waiting move has just been added but before the gcode buffer has been re-initialised ready for the next command
16801680
pauseRestorePoint.filePos = fileGCode->GetFilePosition(fileInput->BytesCached());
1681-
#if SUPPORT_IOBITS
1682-
pauseRestorePoint.ioBits = moveBuffer.ioBits;
1681+
#if SUPPORT_LASER || SUPPORT_IOBITS
1682+
pauseRestorePoint.laserPwmOrIoBits = moveBuffer.laserPwmOrIoBits;
16831683
#endif
16841684
}
16851685

@@ -1813,8 +1813,8 @@ bool GCodes::DoEmergencyPause()
18131813
pauseRestorePoint.virtualExtruderPosition = moveBuffer.virtualExtruderPosition;
18141814
pauseRestorePoint.filePos = moveBuffer.filePos;
18151815
pauseRestorePoint.proportionDone = (float)(totalSegments - segmentsLeft)/(float)totalSegments;
1816-
#if SUPPORT_IOBITS
1817-
pauseRestorePoint.ioBits = moveBuffer.ioBits;
1816+
#if SUPPORT_LASER || SUPPORT_IOBITS
1817+
pauseRestorePoint.laserPwmOrIoBits = moveBuffer.laserPwmOrIoBits;
18181818
#endif
18191819
ClearMove();
18201820
}
@@ -1828,8 +1828,8 @@ bool GCodes::DoEmergencyPause()
18281828
// because we might try to pause when a waiting move has just been added but before the gcode buffer has been re-initialised ready for the next command
18291829
pauseRestorePoint.filePos = fileGCode->GetFilePosition(fileInput->BytesCached());
18301830
pauseRestorePoint.proportionDone = 0.0;
1831-
#if SUPPORT_IOBITS
1832-
pauseRestorePoint.ioBits = moveBuffer.ioBits;
1831+
#if SUPPORT_LASER || SUPPORT_IOBITS
1832+
pauseRestorePoint.laserPwmOrIoBits = moveBuffer.laserPwmOrIoBits;
18331833
#endif
18341834
}
18351835

@@ -2061,8 +2061,19 @@ void GCodes::SaveResumeInfo(bool wasPowerFailure)
20612061

20622062
// Set the feed rate
20632063
buf.catf("G1 F%.1f", (double)(pauseRestorePoint.feedRate * MinutesToSeconds));
2064+
#if SUPPORT_LASER
2065+
if (machineType == MachineType::laser)
2066+
{
2067+
buf.catf(" S%u", (unsigned int)pauseRestorePoint.laserPwmOrIoBits.laserPwm);
2068+
}
2069+
else
2070+
{
2071+
#endif
20642072
#if SUPPORT_IOBITS
2065-
buf.catf(" P%u", (unsigned int)pauseRestorePoint.ioBits);
2073+
buf.catf(" P%u", (unsigned int)pauseRestorePoint.laserPwmOrIoBits.ioBits);
2074+
#endif
2075+
#if SUPPORT_LASER
2076+
}
20662077
#endif
20672078
buf.cat("\nM24\n");
20682079
ok = f->Write(buf.c_str()); // restore feed rate and output bits
@@ -2185,7 +2196,7 @@ bool GCodes::LoadExtrusionAndFeedrateFromGCode(GCodeBuffer& gb)
21852196
moveBuffer.virtualExtruderPosition = virtualExtruderPosition; // save this before we update it
21862197

21872198
// Check if we are extruding
2188-
if (moveBuffer.isCoordinated && gb.Seen(extrudeLetter))
2199+
if (gb.Seen(extrudeLetter)) // DC 2018-08-07: at E3D's request, extrusion is now recognised even on uncoordinated moves
21892200
{
21902201
// Check that we have a tool to extrude with
21912202
Tool* const tool = reprap.GetCurrentTool();
@@ -2305,7 +2316,7 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated)
23052316

23062317
// Check to see if the move is a 'homing' move that endstops are checked on.
23072318
// We handle S1 parameters affecting extrusion elsewhere.
2308-
if (gb.Seen('S'))
2319+
if (gb.Seen('H') || (machineType != MachineType::laser && gb.Seen('S')))
23092320
{
23102321
const int ival = gb.GetIValue();
23112322
if (ival == 1 || ival == 2 || ival == 3)
@@ -2335,20 +2346,34 @@ const char* GCodes::DoStraightMove(GCodeBuffer& gb, bool isCoordinated)
23352346
}
23362347
}
23372348

2338-
#if SUPPORT_IOBITS
2339-
// Update the iobits parameter
2349+
// Check for laser power setting or IOBITS
2350+
#if SUPPORT_LASER || SUPPORT_IOBITS
23402351
if (rp != nullptr)
23412352
{
2342-
moveBuffer.ioBits = rp->ioBits;
2353+
moveBuffer.laserPwmOrIoBits = rp->laserPwmOrIoBits;
23432354
}
2344-
else if (gb.Seen('P'))
2355+
#if SUPPORT_LASER
2356+
else if (machineType == MachineType::laser)
23452357
{
2346-
moveBuffer.ioBits = (IoBits_t)gb.GetIValue();
2358+
moveBuffer.laserPwmOrIoBits.laserPwm = (moveBuffer.moveType == 0 && isCoordinated && gb.Seen('S'))
2359+
? ConvertLaserPwm(gb.GetFValue())
2360+
: 0;
23472361
}
2362+
#endif
2363+
#if SUPPORT_IOBITS
23482364
else
23492365
{
2350-
// Leave moveBuffer.ioBits alone so that we keep the previous value
2366+
// Update the iobits parameter
2367+
if (gb.Seen('P'))
2368+
{
2369+
moveBuffer.laserPwmOrIoBits.ioBits = (IoBits_t)gb.GetIValue();
2370+
}
2371+
else
2372+
{
2373+
// Leave moveBuffer.ioBits alone so that we keep the previous value
2374+
}
23512375
}
2376+
#endif
23522377
#endif
23532378

23542379
if (moveBuffer.moveType != 0)
@@ -2820,6 +2845,18 @@ void GCodes::AbortPrint(GCodeBuffer& gb)
28202845
}
28212846
}
28222847

2848+
// Cancel everything
2849+
void GCodes::EmergencyStop()
2850+
{
2851+
for (GCodeBuffer *gbp : gcodeSources)
2852+
{
2853+
if (gbp != nullptr)
2854+
{
2855+
AbortPrint(*gbp);
2856+
}
2857+
}
2858+
}
2859+
28232860
// Run a file macro. Prior to calling this, 'state' must be set to the state we want to enter when the macro has been completed.
28242861
// Return true if the file was found or it wasn't and we were asked to report that fact.
28252862
// 'codeRunning' is the M command we are running, as follows;
@@ -4298,8 +4335,8 @@ void GCodes::SavePosition(RestorePoint& rp, const GCodeBuffer& gb) const
42984335
rp.feedRate = gb.MachineState().feedRate;
42994336
rp.virtualExtruderPosition = virtualExtruderPosition;
43004337

4301-
#if SUPPORT_IOBITS
4302-
rp.ioBits = moveBuffer.ioBits;
4338+
#if SUPPORT_LASER || SUPPORT_IOBITS
4339+
rp.laserPwmOrIoBits = moveBuffer.laserPwmOrIoBits;
43034340
#endif
43044341
}
43054342

@@ -4310,13 +4347,14 @@ void GCodes::RestorePosition(const RestorePoint& rp, GCodeBuffer *gb)
43104347
{
43114348
currentUserPosition[axis] = rp.moveCoords[axis];
43124349
}
4350+
43134351
if (gb != nullptr)
43144352
{
43154353
gb->MachineState().feedRate = rp.feedRate;
43164354
}
43174355

4318-
#if SUPPORT_IOBITS
4319-
moveBuffer.ioBits = rp.ioBits;
4356+
#if SUPPORT_LASER || SUPPORT_IOBITS
4357+
moveBuffer.laserPwmOrIoBits = rp.laserPwmOrIoBits;
43204358
#endif
43214359
}
43224360

@@ -4530,11 +4568,6 @@ bool GCodes::AllAxesAreHomed() const
45304568
return (axesHomed & allAxes) == allAxes;
45314569
}
45324570

4533-
void GCodes::SetAllAxesNotHomed()
4534-
{
4535-
axesHomed = 0;
4536-
}
4537-
45384571
// Write the config-override file returning true if an error occurred
45394572
GCodeResult GCodes::WriteConfigOverrideFile(GCodeBuffer& gb, const StringRef& reply) const
45404573
{
@@ -4935,6 +4968,11 @@ void GCodes::SetExtrusionFactor(size_t extruder, float factor)
49354968
}
49364969
}
49374970

4971+
Pwm_t GCodes::ConvertLaserPwm(float reqVal) const
4972+
{
4973+
return (uint16_t)constrain<long>(lrintf((reqVal * 65535)/laserMaxPower), 0, 65535);
4974+
}
4975+
49384976
#if SUPPORT_12864_LCD
49394977

49404978
// Process a GCode command from the 12864 LCD returning true if the command was accepted

0 commit comments

Comments
 (0)