I plan to put it in a separate window next and/or both just replace the current jog tab. You are correct the way it is implemented now is not practical nor very usable; a separate window will be much better.
In my view, a significant portion of our effort is an investment in learning the system. To that end, it makes perfect sense to experiment with multiple ways to do things. For example, I went a little nuts with the screen load script and signaling, but soon it became evident that not every action that CAN be moved to that location, is best suited to that method, nor is it convenient AT ALL to have the variables declared in a completely different place than where you will use them. So, I spent nearly as much time moving things BACK to the PLC from whence they came and unlinking processes from signaling.
Ultimately, it all contributes to knowledge of the system, so I don't consider it time wasted.
By your effort, you now have experience and knowledge of incorporating widgets into the MACH4 screens and also leaving them to float in their own window. Some processes will favor one over the other, and now you can do either, as you see fit.
Polling was not the best choice but it was the only way I could see at the time to update the widgets on the screen. Please note that the jog controls and jog input currently use signaling so the control inputs are not delayed by polling. ONLY the images on the screen are updated by polling Not the controls themselves.
An approach to consider is to have the command side act on interrupts (signaling) and then have a 'last act' be updating the display data and/or resetting controls. In this way, you still eliminate polling, very little processor overhead is added to the (overall) interrupt response and the data display is always current and also acts as a monitor of the underlying actions.
An example: On my motor controller, the user (or an embedded macro) enters the desired RPM into a MACH screen DRO. It would be simple to consider that DRO to be the current RPM, but the RPM is collected from that DRO, sent to the controller, the controller compares it to an number of parameters and current operating conditions, calculates and sends a command to the DSS to alter the step stream frequency, and then reports the actual set RPM (which may or may not be what was requested) back to MACH for display in a separate 'current RPM' DRO.
In this scheme, the entire process is 'in effect' monitored and the returned RPM is an indication that the function was carried out. Also, if the RPM returned is different from what was requested, that indicates that an invalid (usually exceeding the motor's maximum) RPM was requested.
I don't know at this point if MACH signaling is uber sensitive to the complexity of the response (as are processor interrupts generally), but it is a good practice to keep the responding function as short as is practical. Unless there is a compelling reason to do otherwise, on interrupt, I typically just set a flag and return. The flag is then picked up, reset, and the actual response is executed. This adds some micro seconds to the response, but that is generally less consequential than running an interrupt response too long.
This may not all make sense to readers, but in a nutshell, if you are using interrupts or signals and you start getting system hangs, the likely culprit is the length of the functions being executed. In the specific case of an MPG, you would replace:
InterruptEvent -> process encoder input, have a beer, update screen, have another beer, reset controls, watch the game, -> return
with
InterruptEvent -> EncoderDataReadyFlag = true; -> return
A few millis may pass here, but it would require an extremely critical timing event to make a difference - very unlikely to effect an MPG. Most importantly, other interrupts can come in during this period and be processed and the system will not hang.
Here is the 'catch net' routine, which can be anywhere the program continuously loops:
if (EncoderDataReadyFlag) then
EncoderDataReadyFlag = false;
process encoder input, wash the car, visit aunt betty, etc, etc
Now do all the controls stuff that used to be done by polling;
end
or if you are into functions:
if (EncoderDataReadyFlag) then
EncoderDataReadyFlag = false; -- don't forget to always reset the flag!
DoEncoderStuff
end
Function DoEncoderStuff -- I don't remember the correct syntax here
blah blah blah
end