lua Error Handling Macro

 

This is an example of how to write a lua macro that will perform error checking, abort if something goes wrong and report what goes wrong.

There are a lot of mc.mcCntlLog(...) calls in this example, that you wouldn't want in a real macro (i.e. Function location 1, 2, 3... or the Alpha, Beta, Delta, ...), but they help to show you in the log file what areas were called and in which order.  The functionality performed in here is useful at times, but doesn't perform anything terribly useful in total for this macro, other than error processing and debugging.

Here is a YouTube video that will explain what is happening, but you should still be able to get a decent idea of what is happening by reading through the notes after the code and the pictures of the log files.

 

First we need to understand some functions that will report messages to the user.

All of these functions may be found in your "C:\Mach4Hobby\Docs\Mach4CoreAPI.chm" file.   

The first two functions only post messages and don not affect the control state of Mach4:

mc.mcCntlLog()

number: rc = mc.mcCntlLog(number: inst, string: message, string file, number: line)

  • rc is the return code, and will be mc.MERROR_NOERROR or 0 if nothing went wrong or a negative number if it did.
  • inst is Instance, or the specific function instance that is calling this function: local inst = mc.mcGetInstance('info '). This only needs to be defined once per function or once per lua file.
  • message is the message you want sent to the log file.
  • fileA string buffer specifying the source file name. I almost always have it set to ""
  • line An integer specifying the source line number. Leave it set to -1 unless you are using the file.

This will send information to the Menu -> Diagnostics -> Logging..., that you can open and press start (the play icon) in order to start logging.  This is a great place to display lots of detailed information from your scripts.

 

mc.mcCntlSetLastError()

number: rc = mc.mcCntlSetLastError(number: inst, string: message)

  • rc is the return code, and will be mc.MERROR_NOERROR or 0 if nothing went wrong or a negative number if it did
  • inst is Instance, or the specific function instance that is calling this function: local inst = mc.mcGetInstance('info '). This only needs to be defined once per function or once per lua file.
  • message is a string that will be sent to the History line or Error line visible at the bottom of the screen set

While this is called an error, it is more aptly called a history or informational message, since there are many messages sent there that are not errors.

 

These next two functions are very helpful inside lua macros (scripts) since they will stop the machine if an error condition occurs (provided you check for and handle that error condition). Either of these functions will stop the execution of the GCode after the macro ends, but will not halt the execution of the macro itself. You will need to put "return" statements in after the calling of these functions, in order to halt the macro itself.

mcCntlMacroAlarm(...)

number: rc = mc.mcCntlMacroAlarm(number: inst, number: error_number, string: error_message)

  • rc is the return code, and will be mc.MERROR_NOERROR or 0 if nothing went wrong or a negative number if it did
  • inst is Instance, or the specific function instance that is calling this function: local inst = mc.mcGetInstance('info '). This only needs to be defined once per function or once per lua file.
  • error_number is the specific number you want displayed before the error message (this may aid in locating the source of the error)
  • error_message is a string that you may define yourself or may be filled with the error report's message string

This lua API call:

mc.mcCntlMacroAlarm(inst, 16, 'Error 16 condition')

Does the same thing as this GCode call

#3000 = 16 (Error 16 condition)

This will result in:

  • A Cycle Stop, halting GCode execution (not an EStop)
  • The status history showing "Error 16 condition"
  • Control is set to the ALARM state by raising the OSIG_ALARM signal. This alarm can only be canceled by pressing the screen set's Reset button. OSIG_ALARM can be used to drive a yellow beacon light or similar that is commonly found on production CNC machines.

 

mcCntlMacroStop(...)

number: rc = mc.mcCntlMacroStop(number: inst, number: error_number, string: error_message)

  • rc is the return code, and will be mc.MERROR_NOERROR or 0 if nothing went wrong or a negative number if it did
  • inst is Instance, or the specific function instance that is calling this function: local inst = mc.mcGetInstance('info '). This only needs to be defined once per function or once per lua file.
  • error_number is the specific number you want displayed before the error message (this may aid in locating the source of the error)
  • error_message is a string that you may define yourself or may be filled with the error report's message string

This lua API call:

mc.mcCntlMacroStop(inst, 12, 'Error 12 condition')

Does the same thing as this GCode call

#3006 = 12 (Error 12 condition)

This will result in:

  • A Cycle Stop, halting GCode execution (not an EStop)
  • The status history showing "Error 12 condition"
  • Control is set to the IDLE state. No alarm signal will generated. This does not need to be canceled by pressing the screen set's Reset button. This is basically the same as pressing the Cycle Stop button.

 

 

Example Macro

The lua return codes may be found here.

This will demonstrate an example macro m2345.mcs . Please keep in mind that this is just demonstrating so things you can do in a macro, but not a truly useful macro in its entirety.

 

-------START OF MACRO CODE-------

--This if statement is here to allow the debugging from the lua editor, and will be the first code that the editor calls

if (mc.mcInEditor() == 1) then

local inst = mc.mcGetInstance('Fn m2345 InEditor ') -- Pass in the script number, so we can see the commands called by this script in the log

mc.mcCntlLog(inst, "~~~~Function location Alpha" , "", -1) -- This will send a message to the log window NOT NEEDED IN REAL CODE

m2345()

mc.mcCntlLog(inst, "~~~~Function location Gamma" , "", -1) -- This will send a message to the log window NOT NEEDED IN REAL CODE

end

 

--This is the function that Mach4 will call from GCode

function m2345()

--This will call your macro and allow for a report of what went wrong if something does go wrong

local inst = mc.mcGetInstance('Fn m2345 ') -- Pass in the script number, so we can see the commands called by this script in the log

mc.mcCntlLog(inst, "~~~~Function location Beta" , "", -1) -- This will send a message to the log windowNOT NEEDED IN REAL CODE

xpcall(m2345Core, m2345ErrorOut)

mc.mcCntlLog(inst, "~~~~Function location Delta" , "", -1) -- This will send a message to the log windowNOT NEEDED IN REAL CODE

end

 

--This function will handle any errors generated by the core macro code

local function m2345ErrorOut(msg)

--This will report something bad happening

local inst = mc.mcGetInstance('Fn m2345ErrorOut ') -- Pass in the script number, so we can see the commands called by this script in the log

mc.mcCntlLog(inst, "~~~~Function location 6" , "", -1) -- This will send a message to the log window

mc.mcCntlMacroAlarm(inst, 6, msg) -- You may want to replace this with mcCntlMacroStop instead of mcCntlMacroAlarm

mc.mcCntlLog(inst, "~~~~Function location 7" , "", -1) -- This will send a message to the log window

end

 

local zSafe = 1.2345 --This is local to contain it in this example code, but should exist in your screen load script or be declared globally somewhere else

function m2345Core()

local inst = mc.mcGetInstance('Fn m2345Core ') -- Pass in the script number, so we can see the commands called by this script in the log

mc.mcCntlLog(inst, "~~~~Function location 1" , "", -1) -- This will send a message to the log window

 

local rc = 0

local msg

rc = mc.mcSpindleSetDirection(inst,0)

if (rc ~= 0) then

--A non zero return code was bad...

msg = mc.mcCntrlGetErrorString(inst,0)

error(msg,1) --This will report the error

return --This will get us out of the macro without running the rest of it.

end

 

mc.mcCntlLog(inst, "~~~~Function location 2" , "", -1) -- This will send a message to the log window

rc = mc.mcCntlGcodeExecuteWait(inst, string.format("G0 G53 Z%0.4f\n",zSafe)) --Rapid to zSafe, this will fail if debugging

if (rc ~= mc.MERROR_NOERROR) then

--A non zero return code was bad...

--msg = mc.mcCntrlGetErrorString(inst,0)

error("GCode Aborted!",1) --This will report the error

return --This will get us out of the macro without running the rest of it.

end

 

local hGoodBuildVer

local StrGoodBuildVer

local hBadBuildVer

local StrBadBuildVer

mc.mcCntlLog(inst, "~~~~Function location 3" , "", -1) -- This will send a message to the log window

 

hGoodBuildVer, rc = mc.mcRegGetHandle(inst, string.format("ESS/Build_Version"))

if (rc ~= mc.MERROR_NOERROR) then

--A non zero return code was bad...

msg = mc.mcCntrlGetErrorString(inst,0)

error(msg,1) --This will report the error

return --This will get us out of the macro without running the rest of it.

end

 

StrGoodBuildVer, rc = mc.mcRegGetValueString(hGoodBuildVer)

if (rc ~= mc.MERROR_NOERROR) then

--A non zero return code was bad...

msg = mc.mcCntrlGetErrorString(inst,0)

error(msg,1) --This will report the error

return --This will get us out of the macro without running the rest of it.

end

 

mc.mcCntlLog(inst, "ESS Build Ver " .. StrGoodBuildVer, "", -1) -- This will send a message to the log window

 

mc.mcCntlLog(inst, "~~~~Function location 4" , "", -1) -- This will send a message to the log window

 

--START OF This section will fail

hBadBuildVer, rc = mc.mcRegGetHandle(inst, string.format("ESS/Build_VersionBADPath"))

if (rc ~= mc.MERROR_NOERROR) then

--A non zero return code was bad...

msg = mc.mcCntrlGetErrorString(inst,0)

error(msg,1) --This will report the error

return --This will get us out of the macro without running the rest of it.

end

--END OF This section will fail

 

StrBadBuildVer, rc = mc.mcRegGetValueString(hBadBuildVer)

if (rc ~= mc.MERROR_NOERROR) then

--A non zero return code was bad...

msg = mc.mcCntrlGetErrorString(inst,0)

error(msg,1) --This will report the error

return --This will get us out of the macro without running the rest of it.

end

 

mc.mcCntlLog(inst, "ESS Build Ver " .. StrBadBuildVer, "", -1) -- This will send a message to the log window

 

mc.mcCntlLog(inst, "~~~~Function location 5" , "", -1) -- This will send a message to the log window

 

local hInputSignal9

local InputSignal9

hInputSignal9,rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT9)

InputSignal9, rc = mc.mcSignalGetState(hInputSignal9)

 

 

--Do more stuff in your macro after here....

end --End of your macro

-------END OF MACRO CODE-------

 

Testing the Macro

Here is the output I received on the first run:

So I commented out the code associated around that mcGcodeExecuteWait (I wasn't running GCode, so that is why it could not do it now...)

Here is the second run:

So I removed the code around "ESS/Build_VersionBADPath", so we could get by that part.

And finally it ran all the way through the end

 

 

 

 

 

Top of Page