Maths in GCode for RepRap: New M930 & M931, & #Px# values

In my fork (this link) off of Dave's work for the RepRap firmware, I added two new M commands for inGCode arithmetic and mathematical calculations. I also added a general GCode parsing feature to enable it using the result of the realtime arithmetic calculation:
I took a liberty to use an apparently empty bracket in M command numbers and created these two M commands to the firmware: M930 and M931
.
M930
M930 performs a maths expression between curly brackets ({}) and saves the results in one on the 10 memory slots called P0 to P9. If memory slots aren’t set, their default value will be 0 (zero)Example 1:
M930 { 2 * (2+1)} P0sets P0 to 6. The expression that is between the curly brackets is 2*(2+1) that is 2*(3) = 6. The result is 6 which will be saved in memory slot 0 because of P0 parameter given in the M930 command line
Using X or Y or Z in the expression copies the current position in the expression and uses the position as if it was a number.
Example 2:
Assume X is at 5mm (or whatever unit you are running on)M930 {2*X} P1
sets P1 to 10. Because X will be interpreted as 5.000 and the result of the expression 2*5.00 equals 10. This result is then saved in P1 memory slot to be used later.
Example 3:
M930 {X} P2 ;simply sets P2 to current X position 5 (assuming X is at 5, P2 value will be 5.000)
Px (such as P0, P1, … P9) values are accessible to other G or M commands using #Px# format (such as #P0#, #P1#, … #P9#)
Example 4:
G0 X#P0# ;Remember in Example 1 P0 was set to 6. This line will be translated as G0 X6. That is value of 6 replaced the variable name P0
Example 5:
M930 {(X * #P0#)+2} P0 ;remember in Example 1 P0 was set to 6, it is now set to be (X*6)+2. For example if X is at 5, P0 would be 32
If Px is not set, it’ll auto initialises to 0
Example 6:
G1 X#P1# Y#P2# F#P8#Assume before this line of GCode, P1 is set to be 76.23, P2 is 36.17, P8 is 400. The output of this line will be as if it was:
G1 X76.23 Y36.17 F400;If you need to make any calculation to be passed to any G command you will need to do it before that G command in a separate M930 command line.
Example 7:
M930 {X*2} P1 ; doubles the value of the current position of X axis
G1 X#P1# ; moves X axis to our newly calculated P1. Now the current X position is the changed to be P1
Assume X is at 5. The first M930 line above sets P1 to 10. The second line will be G1 X10. Therefore now the current position of X is 10 (as opposed to be 5). So the next time you do this P1 will be 20 (as opposed to 10)Similarly you can use this format #Px# (for P0 to P9) in any other G or M commands to pass your calculation results to other commands.
Example 8:
M930 {25} P0 ; #P0# is 25
M930 {100} P0 ; #P0# is now overwritten with 100 without any warningThe second M930 overwrites P0 value to 100, without giving any warning.
.
M931
M931 saves or loads all variables (P0 to P9) on SD Card in a file named: “arithmeticsmemoryslots.g” that can be found under “sys” directory (/folder)
This can be useful to inspect the values, or to load them again for a later useM931 has a single parameter Pxx. P0 saves variables, P1 loads them from the file
Example 1:
M931 P0 ; this saves all P0 to P9 values into “arithmeticsmemoryslots.g”Example 2:
M931 P1 ; this loads all values back to P0 to P9 when running your GCode programme.
M930 Capabilities
M930 takes advantage of the ExprTk library that has the following capabilities:
Mathematical operators (+, , *, /, %, ^)

Trigonometry (sin, cos, tan, acos, asin, atan, atan2, cosh, cot, csc, sec, sinh, tanh, d2r, r2d, d2g, g2d, hyp)

Equalities & Inequalities (=, ==, <>, !=, <, <=, >, >=)

Assignment (:=, +=, =, *=, /=, %=)

Logical operators (and, nand, nor, not, or, xor, xnor, mand, mor)

Functions (min, max, avg, sum, abs, ceil, floor, round, roundn, exp, log, log10, logn, pow, root, sqrt, clamp, inrange, swap)

And more …
I hope a few people find this useful for their projects as it is for mine. Please comment if you have any thoughts to improve this.
At this stage I only did this for my own use and obviously cannot be held responsible for whatever damages that could come out of this.
I will be pulling a request for this on GitHub to hopefully be added to an official release. I have a hard time compiling this correctly for RepRap so I hope Dave (or others) come to rescue


To whoever interested:
These 6 files are modified for this addition:(Under src/GCodes)
 GCodes.h
 GCodes.cpp
 GCodeBuffer.h
 GCodeBuffer.cpp
 GCodes2.cpp
 GCodes3.cpp
This file (and toolkit folder) added:
 src/toolkit/exprtk,hpp

Looks like you've gone to a lot of trouble.
Kudos for that.
Can you give some more detail about why you felt it necessary or how it might be used that isn't currentlly possible?Initially I thought it was largely redundant as we already have the ability to carry out mathematical equations and now that we have variables, the scope is opened even more.
I can see a use for it as a method of using psuedo arrays which may be handy.
Especially as these can be persistent.We already have min(n,n,n,n) etc, but no method of creating an array other than a series of variables.

@OwenD Thank you for your comment
I mainly did this for the ability to create even smarter ‘Macros’. Another one is the ability to generate formula driven paths using GCode only.
As a use case example:
Creating a macro to automatically set/fine tune /readjust axis steps per unit (using M92)Let’s say we need to fine tune steps per mm on X and Y (or automate it for every morning. For example to compensate for the room temperature changes)
We got a cuboid probe. The exact dimensions on each side are measured and know (L x W x H)  Let’s put the exact measurements in P0, P1, P2
We know our current step per unit in each axis from our config.g file (say X400 for the X drive and 400 steps per mm for the Y drive. Set in P3 and P4.
Now, in our macro, we probe a corner (say bottomleft) and set them in P5 and P5. Like:
M930 {X} P5
M930 {Y} P6The macro then moves to probe the opposite corner. We now have
M930 {X} P7
M930 {Y} P8
The motor/firmware ‘thinks’ that the tool has moved L mm (that is saved in P0), however, the probe shows that to reach the opposite corner we moved L+0.1 mm (+0.1 is an example error we got). So:
Actual (Measured) Movement Distance = L + 0.1 = P7  P5
Desired Movement Distance = L = P0
Therefore 400 steps (= P3) took us 0.1 short of L
Now the macro does this and fine tunes the steps per mm for us automatically:
M930 {#P0# * #P3# / (#P7#  #P5#)} P9
M92 X#P9#
Here, M930 on the above line calculates the correct and super accurate steps needed for L mm and holds it in P9
The next M92 line sets the Steps per mm to the super accurate valueWe do similar thing for Y axis:
M930 {#P1# * #P4# / (#P8#  #P6#)} P9
M92 Y#P9#
The M92 line above sets the steps per mm for the Y axis automaticallyThis is just one example to show a use case in a macro. I hope I was able to make my use case example easy to follow

@OwenD
In the above example we can have the probe known dimensions (P0, P1, P2) and or config,g steps (P4 and P5) saved in the file and load them at the beginning of the example macro with M931 P1, and the whole fine tuning steps can happen really quickly and accurately