Hello Guest it is April 28, 2024, 08:40:25 PM

Author Topic: Proper way to error out of a lua function if an API call fails  (Read 293 times)

0 Members and 1 Guest are viewing this topic.

Proper way to error out of a lua function if an API call fails
« on: February 07, 2024, 07:27:23 AM »
OK.

So every

Code: [Select]
variable = mc.mcGetSomething(inst)

call that we see in macros like m6() etc are actually a

Code: [Select]
variable, rc = mc.mcGetSomething(inst)

call, where "rc" is the return code that indicates API success or failure.

For some reason, all the scripts people write handwave this away and blithely assume that API calls always work.

That might very well be true in 99.999% of the cases, but it is poor programming practice to not check error codes.

That means that functions like m6() need an error-checking function within them, like this:

Code: [Select]
function m6()
     
     function wc(rc)          -- wc stands for "welfare check"

          if (not(rc == mc.MERROR_NOERROR))
               -- Do something reasonable to abort m6()
          end
     end

     -- Do tool change stuff here
     local inst, rc = mc.mcGetInstance()
     wc(rc) -- make sure we got our instance

     -- etc..
end

I'm talking to some lua experts elsewhere to see if there is a way to do something like

Code: [Select]

 local inst, wc(rc) = mc.mcGetInstance()


so as to make the syntax a little cleaner, and is seems that lua does not have a case or switch statement, so parsing all the various possible error codes is likely to be a bitch.

But it is worth discussing this: if an API call fails in a gCode replacement call like m6(), what should the function do to gracefully report the error to the user and stop the machine?

There has to be a best practice here.

Ideally there would be a global wc(rc) lua function that was written to do just that and came with Mach - maybe there is?

Offline Tweakie.CNC

*
  • *
  •  9,200 9,200
  • Super Kitty
    • View Profile
Re: Proper way to error out of a lua function if an API call fails
« Reply #1 on: February 08, 2024, 12:56:44 AM »
I think that once you have all this sorted you will become the forums, resident, Lua expert.

Keep up the good work - I am following with great interest.

Tweakie.
PEACE
Re: Proper way to error out of a lua function if an API call fails
« Reply #2 on: February 08, 2024, 11:55:36 AM »
> I think that once you have all this sorted you will become the forums, resident, Lua expert.

Don't you put that evil on me, Ricky Bobby!

But this is less a lua issue than it is a process issue:

If I call a GCode linked to a lua script, and in that script an API call fails, we want to report the error and do something reasonable with the machine - which, in order of increasing drastic, is probably "FEED HOLD", "STOP", or "ESTOP".

Putting the error code into a text box is easy. Giving that error code some useful context so the operator can source and fix the problem is a little more challenging, but doable. How do I stop the machine if the API failed?

Re: Proper way to error out of a lua function if an API call fails
« Reply #3 on: February 08, 2024, 03:32:44 PM »
Hi, check out this post

https://www.machsupport.com/forum/index.php?topic=41630.msg272402#msg272402

You can also use mcCntlMacroStop in place of mcCntlMacroAlarm as used in the example
Re: Proper way to error out of a lua function if an API call fails
« Reply #4 on: February 08, 2024, 09:37:43 PM »
OK so this code:

Code: [Select]
if (rc ~= 0) then
   msg = mc.mcCntlGetErrorString(inst, rc) --Get the returned error string
   errorOut(msg)
   return --Exit the function
end

local function errorOut(msg)
   local inst = mc.mcGetInstance()
   mc.mcSpindleSetDirection(inst, mc.MC_SPINDLE_OFF)   
   mc.mcCntlMacroAlarm(inst, 3, msg)
end


Can be simplified to this:

Code: [Select]
value, rc = mc.mcGetSomeValueFromAPI
if (not (rc = mc.MERROR_NOERROR) then
     errorOut(rc)
end

local function errorOut(rc)
     local inst, rc2 = mc.mcGetInstance()
     local msg, rc2 = mc.mcCntlGetErrorString(inst, rc)
    -- print some error message here
    rc2 = mc.mcSpindleSetDirection(inst, mc.MC_SPINDLE_OFF)   
    rc2 = mc.mcCntlMacroAlarm(inst, 3, msg)
end

Do you see the problem? It's turtles all the way down!

If my safe error handling routine that I only call when the return code from an API call fails depends on API calls that must themselves have their return codes checked (and could fail!) where's the bottom?

I buy into stopping the spindle explicitly via API vice trying to feed the gcode interpreter an M30 or something, and by extension, we should probably stop coolant, mist, and all axis movement too, and setting the ALARM state makes sense... but I have to use the API to do it so I have to test the return codes and around and around we go.