M28 doesn't allow tabs to be written to file.
-
Now that we have conditional G code, it looks like some revision to M28 might be required.
It seems that the default behavior is the trim leading spaces (and probably trailing) from the code as it writes it to the new file.
That would have been logical in the past, but....
This makes dynamically creating a job file that uses condition gcode impossible.
I tried using /t and #9 as an escape character to no avail.
Whilst the use cases for this might be low, I'll expand on what I was trying to achieve (a bit long winded).During upgrading to RRF3.3b3, I noticed some really erratic temperature readings.
I couldn't find a loose connection, so I ran a new PID tune and the problem seemed to go away.
That bugged me as there were no notes about changes to the heater routines, so I decided to do a macro that would run very fast random moves so I could watch the graph to see if the shaking gave any erratic heater values.
I thought I'd use the status of my LED strip as a way to cancel out of the loop, but found that when run as a macro, it didn't work (possibly too many queued moves).
I found if I ran it as a print job, I could indeed cancel out using my LED status.Then I decided "why not let the macro create the job file?"
It was then I found the "bug" in M28Here's my macro
;random-moves.g ; macro to do high speed moves to random positions. a small amount of filament will be extruded to sop it burning ; note if run as a macro, it can't be interupted, so a print job is created. if job.file.fileName!=null echo "A print is running - macro cancelled" M99 if !exists(global.minX) global minX = 80 ; minimum X position if !exists(global.maxX) global maxX = 120 ; maximum X position if !exists(global.minY) global minY = 80 ; minimum Y position if !exists(global.maxY) global maxY = 120 ; maximum Y position if !exists(global.minSpeed) global minSpeed = 9000 ; minimum travel speed if !exists(global.maxSpeed) global maxSpeed = 24000 ; max travel speed this will be scaled based on the part fan speed, so it can be controlled/reduced during the test if !exists(global.outputIO) global outputIO = 5 ; tied to an output (LED) so we cabn interupt the "print" without a reset M566 X600.00 Y600.00 Z120.00 E6000.00 ; set maximum instantaneous speed changes (mm/min) M203 X36000.00 Y36000.00 Z900.00 E24000.00 ; set maximum speeds (mm/min) M201 X6000.00 Y6000.00 Z800.00 E6000.00 ; set accelerations (mm/s^2) M83 ; set relative extruder moves if fans[0].actualValue = 0 M106 P0 S1 ; make sure fan is on if !move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed G28 if result != 0 abort "Homing failed" G1 X{global.minX + ((global.maxX-global.minX)/2)} Y{global.minY + ((global.maxY-global.minY)/2)} Z50 F3000 ; move to the centre of the range and 50mm above bed T0 ; select tool echo "waiting for heaters" G10 T0 S240 R180 ; set extruder temp M116 ; wait for temps M291 P"Ready to start?" R"Ready" S3 M28 "0:/gcodes/random-moves-test.g" while state.gpOut[{global.outputIO}].pwm = 1 G1 X{max(random(global.maxX),global.minX)} Y{max(random(global.maxY),global.minY)} E0.05 F{max(random(global.maxSpeed),global.minSpeed)*fans[0].actualValue}; if result !=0 abort "Could not execute move" M400 G4 P1 echo "LED is off - moves cancelled" M98 P"0:/sys/set_max_speeds.g" ; reset speeds M29 M32 "0:/gcodes/random-moves-test.g" M99 ; probably not needed
and here is the output.
while state.gpOut[{global.outputIO}].pwm = 1 G1 X{max(random(global.maxX),global.minX)} Y{max(random(global.maxY),global.minY)} E0.05 F{max(random(global.maxSpeed),global.minSpeed)*fans[0].actualValue} if result !=0 abort "Could not execute move" M400 G4 P10 echo "LED is off - moves cancelled" M98 P"0:/sys/set_max_speeds.g"
-
@owend, thanks for reporting this. I have added it to my list of things to look at.
-
@owend Have you tried M560? Just make sure to include the P parameter or I heard it can nuke your config.g! But the reason I suggest it is I've found that M560 will write comments, where M28 won't. So maybe it treats tabs differently as well. I don't know.
Where with M28 you'd do this:
M28 "<filespec>"
. . .
M29With M560 you do this:
M560 P"<filespec>"
. . .
<!-- EoF --> -
@donstauffer
My Understanding is that M559/M560 upload previously written files whereas M28 actually creates the file.
Therefore unless I create the file externally, it doesn't help as the "problem" , small though it is, is that M28 won't allow tab characters to be written to the file. -
@owend I routinely create files with M560. In fact, if I want to create a macro which creates a macro, I nest them:
Create a macro named "Maker", containing:
M560 P"/macros/Outer"
M28 "/macros/Inner"
M98 P"/macros/Another"
M29<!-- EoF -->
Now, if you run "Maker", it creates a file "Outer", which contains:
M28 "/macros/Inner"
M98 P"/macros/Another"
M29And then, if your run "Outer", it creates a file "Inner", which contains:
M98 P"/macros/Another"
Then, if you run "Inner", it will make a call to macro "Another".
-
@owend The forum is doing something strange - it removed the asterisks from that termination (EoF) string, so if you copy and paste that it won't work. The string actually should have a pair of asterisks immediately preceding and after "EoF".
-
@owend I just tested the example I gave, with tabs. Both M28 and M560 preserved the tabs in the files they wrote. I put a pair of tabs directly after "M28" and "M98", and they did appear in Outer, and the M98 pair of tabs did appear in Inner, which was written by M28.
-
@donstauffer
I'm not seeing where your examples are creating macros with indented conditional code like the examples I posted. -
@owend I tried it with an "if" and an indented "set", and M560 handled it but M28 didn't. Possibly M28 eats the tabs but only at the beginning or end of a line.
-
There is an inconsequential error in this example. it should be "set var.X = 5", but since it will never execute it doesn't matter.
-
@owend The limitation on M28 actually presents a problem on a project I'm currently working on, because the project has macros which do nested writes, which can only be achieved using both M560 and M28, and the nested write does include a conditional. I haven't thought of how to deal with that yet.
I'm wondering if there's a character meta commands consider to be indents but M28 doesn't consider space to be removed. A no-break space (C2 A0) didn't work. Neither did a character code 255.