Machsupport Forum

Mach Discussion => Mach4 General Discussion => Topic started by: joeaverage on December 13, 2016, 04:46:22 AM

Title: mcCntlGetGcodeFileName ...Crashes M4
Post by: joeaverage on December 13, 2016, 04:46:22 AM
Hi All,
I'm writing a script that involves file handling and despite my infancy with LUA getting some good results.

This piece of code doesn't work as I expected:

 local code,rc= mc.mcCntlGetGcodeFileName(inst) ;
    if rc ~=0 then;
        wx.wxMessageBox("G code file not loaded");
        error=1;
        return error;
    end;

When this  macro is called either by a running Gcode file or MDI with a file loaded but not running it works well. I had hoped to use the macro as a file processing
utility even when a Gcode file is not loaded. My intention was to use the error trap and at some later stage add a navigation panel to select the file to process.

The problem is that the macro fails immediately on the ...mc.mcCntlGet...function and so never gets to the error trap which I had hoped to use.

Any ideas on how to detect whether a file is loaded or not?

Craig
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: DazTheGas on December 13, 2016, 05:21:43 AM
Your not in a function so where are you returning the error too??

DazTheGas
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: DazTheGas on December 13, 2016, 05:32:29 AM
Something like this should work

Code: [Select]
local inst = mc.mcGetInstance()

local GCode = mc.mcCntlGetGcodeFileName(inst)

if GCode == "" then
    wx.wxMessageBox("No Code Loaded")
else
    wx.wxMessageBox(GCode.." GCode Loaded")
end

DazTheGas
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: joeaverage on December 13, 2016, 12:54:41 PM
Hi DTG,
thanks for that, the piece of code is in a function so it returns to the macro main body code.

Craig
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: joeaverage on December 14, 2016, 02:37:52 AM
Hi DTG,
unfortunately that little code alteration didn't work either. The macro entry and two of the internal function are:

Code: [Select]
function M41()
inst = mc.mcGetInstance();
mc.mcCntlProbeFileClose( inst );-- Close Mach4 ProbeFile
--
-- FUNCTION OpenRPF
-- arguments: inst
-- return data,numdata,pathRPF,error
--
function OpenRPF(inst);
    local error=0;
    local hreg=mc.mcRegGetHandle(inst,"iRegs0/ALfile");
    if hreg==0 or hreg==nil then;
        wx.wxMessageBox("register ALfile not found...Abort");
        error=1;
        return error;
    end;
    local pathRPF=mc.mcRegGetValueString(hreg);
    if pathRPF=="" then;
        wx.wxMessageBox("Filepath not found...Abort");
        error=1;
        return error;
    end;
    local handRPF=assert(io.open(pathRPF,"r"));
    if handRPF==nil then;
        wx.wxMessageBox("File not opened...Abort");
        error=1;
        return error;
    end;
    local data=handRPF:read("*all");
    if data=="" then;
        wx.wxMessageBox("No Data...Abort");
        error=1;
        return error;
    end;
    local i,j,numdata;
    numdata=0;
    i=1;
    j=1;
    while i do;
        i=string.find(data,"\n",j+1);
        if i==nil then break end;
        j=i;
        numdata=numdata+1;
    end;
    return data,numdata,pathRPF,error;
end;
--
-- FUNCTION OpenGcode
-- arguments: inst
-- return: code,error
--
function OpenGcode(inst)
    local error=0
    local code,rc= mc.mcCntlGetGcodeFileName(inst) ;
    if rc ~=0 then;
        wx.wxMessageBox("G code file not loaded");
        error=1;
        return error;
    end;
    local hcode=assert(io.open(code,"r"));
    if hcode==0 or hcode==nil then;
        wx.wxMessageBox("G code file could not be opened");
        error=1;
        return error;
    end;
    code=hcode:read("*all");
    if code=="" then;
        wx.wxMessageBox("G code file empty");
        error=1
        return error;
    end;
    hcode:close();
    return code,error;
end;

As you can see I've tried to detect and report any errors.

This macro, M41 and its partner M40 are intended to be used with Autoleveller, a crafty software utility that generates a Gcode job to probe a circuit
board blank and then apply Z corrections to the PCB-Gcode file to ensure near perfect  accuracy of cut depth when 'etching' circuit boards. I've used it
with M3 and PP and have found it so useful I can't do without it. There are quite a number of M3 users and over time more will migrate to M4 and these
macros may come in use.

As it stands if the M40 and M41 macros are called from the Gcode probe job it works well. I had hoped that if a user tried to run M41 as a stand alone
file processing job that would also be possible. I would need to add navigation windows to get the two files but not insurmountable. Given that there may in
time be a number of people using these macros I've tried to make them as flexible and yet robust as possible. In particular if a file open/read/write op
is going to fail try to detect/report and shut gracefully rather than leaving a user in suspense not knowing if it failed or why.

I may be accused of 'trying to run before I can walk'. All of the other error traps seem to work but for the one trying to get the filename/path of the loaded
probe job in the situation where the job is not loaded or accidently been closed before M41 gets a chance to run.

Must be said that I'm a complete newb with LUA. There was a couple of days there when I was SHOUTING EXTEREMLY LOUDLY the most unprintable
profanities I could imagine. I'm surprised you didn't hear it, after all you're only 14000 naut miles away and I was LOUD!  Have slowly come to some understanding
of syntax. When I think back it was no worse than when I started with VB and is still better than I am with C/C++.

I was of the opinion that Artsoft had made a mistake with LUA. Having suffered the 'hump' I'm beginning to see how powerful and flexible LUA is with such a remarkably
simple instruction set and libraries. I feel that I've just scratched the surface of the flexibility that can be achieved with such a simple language. Same sort of argument
about RISC processors. The upshot is I wont be going back to VB.

I have a couple more bits to write, one extracts the mesh points from a Gcode probe job in one 'dialect' of Autoleveller, and another, a user definable/editable tolerance
applied in the search/replace applied to the numerical values. The tolerance I intend to save in iRegs0 and so can be kept between sessions. If it goes well and live tests
goes as well as my debugging should be able to post in a few more days.

Craig
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: DazTheGas on December 14, 2016, 06:00:35 AM
Firstly take a look at your m code function M41, it is normal practice for all m codes to be declared in lower case as lua is case sensitive and it sets the norm,

After declaring your m function you have also tried to declare "function OpenRPF(inst)" inside of it, all functions must be declared on top level, if you open up the m code in the editor you will see the error of "'end' expected (to close 'function' at line 1) " but saying that I cant see the function being called from anywhere in the script so perhaps just delete that line so the m code becomes the function. There is also a function called "function OpenGcode(inst)" thats not called in anyway and lots of "return error" thats not being returned to anything?

consider an approach something like this

Code: [Select]
hreg, rc = mc.mcRegGetHandle(inst,"iRegs0/ALfile")
if rc ~= 0 then
    wx.wxMessageBox("register ALfile not found...Abort") -- could add the returned rc code here too
    return -- nothing to return just quit (this is only quitting the m code you might need to Stop the gcode??)
else
    --everything was fine so lets get value from Reg
    local pathRPF = mc.mcRegGetValueString(hreg)
    if pathRPF == "" then
        wx.wxMessageBox("register ALfile empty...Abort")
        return
    end
end

-- so now you if you get here do something with the reg value.


Cant test any further than that as dont know whats contained in "mc.mcRegGetHandle(inst,"iRegs0/ALfile")" I can only assume its a file path?

DazTheGas
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: joeaverage on December 14, 2016, 07:18:12 AM
Hi DTG,
I have in fact five or six functions, behaving in the manner of subroutines. After all the functions have been declared then the body of the M41 macro occurs. The
body code it probably only 20-30 lines which really only schedules each function and looks to the error flag to see whether the function called has behaved.

The first function to be called is OpenRPF as listed above. As you rightly surmise the filename/path is stored in iRegs0/ALfile. OpenRPF checks that the register
exists and messages an error if not, then checks to see if the filepath is empty and messages an error if it is, and so on. Each of these errors, in absence of any
recovery code, returns to the main body code, the error flag tested and then it returns presumably to the Gcode calling program.

My intention when going about it this way was to keep the various string manipulation parts separate and reduce confusion, mine particularly.

I found tonight that if I run the macro from the editor the mcCntlGeteGcodeFilname function works OK, that is it returns a null result if there's no file loaded , my simple
test works , messages the error, returns to M41 and it returns to the editor. If I MDI M41 that's when mcCntlGeteGcodeFilname stops it dead without the test
being performed.

I may be getting too fancy for my own good, it works as a macro but not so well as a stand alone process.

Craig
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: DazTheGas on December 14, 2016, 08:40:57 AM
Perhaps post all the code or zip n PM if its sensative or even better use the package profile in the help menu then I might be able to get a better picture of what you are trying to do. I have looked at autoleveller and have a rough gist of what you are trying to do.

Correct me if I am wrong ;-)

Now autoleveller outputs a gcode file, this file has been created from a gcode that you loaded into it, it then inserts some probe routines at the begining of this gcode file then saves it.
The idea is to then load in "mach3" (as it doesnt say its compatible with 4) and it will do the probing and use the params for Z height during the gcode.

How am I doing so far??

DazTheGas
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: joeaverage on December 14, 2016, 01:08:31 PM
Hi DTG,
there are a couple of versions of Autoleveller but all versions apply the general idea that you outlined.

The earliest version takes your original PCB-Gcode file, OGF in the parlance, generated by the circuit board program. It decides on a  number
of probe points throughout the board. It adds some code to the file to probe the board and applies a 2d linear interpolated correction to the
Z values of your OGF which you can then run. It uses # variables in line. As M4 # variables are differently numbered a search and replace edit
is required to get the code to work.

The two later versions take the OGF and decide on a set of probe points, the mesh in the parlance. Autoleveller then produces a new Gcode job
that probes the board and save the results in  file, the RPF. With M3 macros M40 and M41 open and close the digital probe file. The macros I'm
writing are based on M400 and M401 which come with M4 as LUA examples.

M4 and ESS operate slightly differently when probing. My M3/PP machine would report the programed XY position and the Z at the point of probe contact.
M4/ESS reports XYZ measured at the point of probe contact. The subtle difference can render Autoleveller unworkable.
Ther are two reasons, first my machine and hopefully only my machine produces a small random number of extra data triplets than probe events. Thus a RPF
may have 220 lines despite there having been only 210 probe points. I'd hoped this was due to a noisy probe circuit and have tried a number of things to sort
it out but haven't found a solution yet. As it turns out the extras are duplicates. Ergo the M41 macro needs to be able to read the file, detect and delete the
extra entries. I've got working LUA code to do this using LUA standard library string functions.

The second issue is that M4/ESS reports the measured XY not the programed XY and there is a slight difference, on my machine the average error is 0.0225mm.
When Autoleveller uses the RPF to calculate the required Z corrections it can produce wild results if the actual probe points differ from the programed ones.
AL, one variant of Autoleveller accepts errors of 0.02mm without problem but AE the latest variant goes cranky to rounding error in the fourth decimal place.

So extra functionality in M41 is required. Take the Gcode probe job file, strip out the Gcode to get the anticipated XY probe points and then overwrite the measured
XY points in the RPF if within a user specified tolerance. There again I have working code to do both. The two versions use slightly different Gcode generation
techniques and getting code that accommodates both dialects is giving me a little grief at the moment.

The upshot is that what I'm trying to do is automate a data filtering operation. The code is not sensitive or private, its always been my intention to post it for
anyone to use. Once I've got the string manipulation/filtering parts to work smoothly I will post it and a couple of genuine RPFs and the Gcode probe jobs that
generated them. Might be a few days away yet.

Craig
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: joeaverage on December 16, 2016, 10:07:53 PM
Hi All,
have some working code. Concentrating on the two macros M40 and M41. As DTG pointed out the names are case sensitive. AL and AE call the macros
in uppercase ergo I named them uppercase.

Found best combination of reliability/simplicity to use three persistent registers:
iRegs0/"ALcode" for the file/pathname of the G-code probe job,
iRegs0/"AEdata" for the file/pathname of the raw probe file and,
iRegs0/"ALtol" for your choice of permitted tolerance.

These will need to be set up prior to use. The write to the file/path registers occurs in M40 you will note.

While there are a few error traps in the code which will hopefully give you a clue if the code fails there is little/nothing in the way of recovery yet.

Craig
Also had hoped that the macros could be used as standalone processing jobs but have had little luck yet. As it stands they work if they are called
from the AL/AE generated G-code probe job and work from the editor but less successfully if called from the MDI line.
This code is tested by hand editing probe files and am happy that it works but be warned anyone who uses it are my guinea pigs. Please let me
know if you have problems.

Need to point out also that this is my first effort at Lua coding. If there are inconsistencies/mistakes they represent my newbie status.
Have just started looking at the string pattern/capture functions and believe I could at some future date make stronger and more readable code.
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: smurph on January 03, 2017, 08:49:10 PM
An explanation on the lower case M code functions:

When the interpreter reads a line/block of G code, it first converts the whole line to lower case.  It then removes all of the spaces in the block.  So

G00 X1
S2000 M03

becomes

g00x1
s2000m03

So when the M3 macro is called, the core will look for a macro named "m3.mcs" and look for a function named "m3()" within it.  On Windows, the filenames are NOT case sensitive and it will find a file named "M3.mcs" or "M3.MCS" or any other combination of upper and lower case letters.  However, it will still look for a lower case function name!!!  Because that is what is fed to LUA and LUA is case sensitive. 

So the convention is now to use lower case names for both files AND functions to maintain cross platform compatibility. 

Steve
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: joeaverage on January 03, 2017, 10:09:27 PM
Hi smurph,
tried that out and it works exactly as you said it would. The gcode probe job is constructed/written by another program
which calls my macros M40() and M41() and so that's how I named them.

Following your post I renamed them m40() and m41() and the job ran fine or even calling from the MDI line.

Still thinking about filenames. I record the path and filename of the probe job in a register with:
mc.mcRegSetValueString(hreg,pathCode); ie as its not read by the interpreter the string stored retains both
upper and lowercase of the original filename. At the end of the probe job m41() is called which among other things
opens the gcode file with:
   local pathCode=mc.mcRegGetValueString(hreg);
   local hcode=assert(io.open(pathCode,"r")); ie LUA is searching for a file. Would it succeed on a Windows platform if the
filename was correct but all in lowercase say?

I guess I can try it to see!

At the current time I believe M4 only runs on Windows platforms. Is it realistic to believe that it will run on other platforms
in the near future?

Craig
Title: Re: mcCntlGetGcodeFileName ...Crashes M4
Post by: smurph on January 03, 2017, 10:44:50 PM
We have an old build that runs on Linux.  In fact, we demoed Mach 4 at IMTS 6 years ago on a Linux machine.  So yeah, it will run on other platforms.  But Linux is not where the majority of our customers are at the moment.  So we have been concentrating on the Windows platform.  I hope to have a Linux build by the end of the year though.  Once we get that going, we'll keep it in sync with the Windows build from that point on.  However, the Linux build will be more for OEMs and such and run on a dedicated distribution of Linux.  We simply can't get into the world of supporting all of the flavors of Linux.  We will probably choose a CentOS distribution.  We may make it available to end users on a strictly "you are on your own" kind of thing with ZERO support from our ticketing system or phone support (meaning only forum based support from other users).

And from Linux to Mac.  I can't imagine a Mac being used as a dedicated machine controller, but we do get questions asking if we support Macs all of the time.  I have a Mac, so I might just make it run on it just for the fun of it.  :)

As to your case question, I would use the LUA string.lower() function to lcase the string returned into pathCode.  e.g.
Code: [Select]
local pathCode=mc.mcRegGetValueString(hreg);
pathCode = string.lower(pathCode);
...

But only IF you WANT to convert it to lower case.  It will not matter for Windows.  But it will matter for Linux and Mac.  So if you put the filename into the register with the correct case, then I would suggest NOT converting it to lower case in the event you ever run the code on a Linux or Mac machine in the future. 

Steve