Don't do long running code in the event scripts. Windows only supports ONE event loop for a program. If you click a button, that is an event that needs to run to completion before another event is processed. So long running code WILL prevent screen refreshes (DRO updates) etc... So how do you do that? Typically, is it implemented as a state machine in the PLC script. Or a LUA co-routine. Or by running a private script.
I won't go into LUA co-routines, as that is a subject all of its' own.
Depending on how complex the operation that you want to do it, you may be able to do the complete operation in a private script. A private script basically launches a thread to run the script. It will NOT have access to any of the global function in the screen scripts! However, you can load a module and run module code in them.
Private script method:
To make a script "private", simply put --PRIVATE as the first line of the script. I would suggest developing and debugging the script first before adding the --PRIVATE line. The end result will be a script that is launched from a new thread and return control immediately to the Windows event loop. How do you know it is done? The machine state will become idle. (mcCntlGetState()).
State machine method:
Instead of doing the whole long running code in a button script, just use the button script to set a flag. Then the PLC script should watch that and launch the LUA co-routine or start a state machine that is implemented in the PLC script.
Also, use the G code interpreter as a means to offload script duties that require movement. Do not wait on the G code to finish in the script, but rather let the G code interpreter launch the movement asynchronously. e.g. do not use mcCntlGcodeExecuteWait() but rather use mcCntlGcodeExecute(), which return immediately. Then determine the completion by looking at the sate of the machine with mcCntlGetState(). Look for it to go from running to idle.
Here is a pseudo code representation of a simple state machine
if flag set then
// do the first movement
myProcessState = 1
mcCntlGcodeExecute()
unset the flag
loop mcCntlGetState() until no longer idle. This means the G code has started.
end
if myProcessState == 1 then
if mcCntlGetState() == idle then
myProcessState = 2
end
end
if myProcessState == 2 then
// do the second movement
mcCntlGcodeExecute()
loop mcCntlGetState() until no longer idle. This means the G code has started.
myProcessState = 3
end
etc...
Now, your PLC script is going to get hairy looking real fast. So I would suggest implementing these state machines in LUA modules. These modules can be put in the Modules directory. They can then be "required" once in the screen load script and the accessed by the PLC script.
coner = require "myCornerFindingModule" -- now the PLC can access the functions in the myCornerFindingModule with corner
The button script may call a function that starts the state machine like:
corner.stateMachineStart()
and in the PLC script would call the state machine implementation like this:
corner.stateMachine(inst) -- the implementation. Basically a no op when it hasn't been started.
Steve