Hello Guest it is September 16, 2026, 01:05:48 AM

Author Topic: MachPro upgrade questions  (Read 244 times)

0 Members and 1 Guest are viewing this topic.

Re: MachPro upgrade questions
« Reply #10 on: September 15, 2026, 12:08:41 PM »
Hi,

I am not 100% confident in what you mean. We do have a signal library, but I don't believe this implementation was in Mach4. It was added with the CommonGUIModule inside of MachPro.

The main implementation is in CommonGUIModule:

SIG_LIBRARY_INST[_inst]: common, per-Mach-instance handlers.
MACHINE_TYPE_SIG_LIBRARY_INST[_inst]: machine-specific handlers, such as mill, plasma, grinder, or height-control behavior.
SCREEN_SIG_LIBRARY_INST[_inst]: screen-specific handlers for multi-instance screens.
SCREEN_SIG_LIBRARY: legacy/global screen handlers used by older screen versions.
Each table is keyed by a Mach signal ID. The value is a Lua callback:

Code: [Select]
SIG_LIBRARY_INST[_inst][signalId] = function(sig_state)
    -- Handle the signal transition
end

When Mach reports a signal transition, CommonSignalScript() converts the state to a Boolean and calls _CommonSignalScript(). That function dispatches the event through the layers above, then runs the generic SignalScript hooks:

CommonSignalScript
  • SignalScript callback
  • SIG_LIBRARY_INST[instance][signal]
  • MACHINE_TYPE_SIG_LIBRARY_INST[instance][signal]
  • SCREEN_SIG_LIBRARY_INST[instance][signal]
  • SCREEN_SIG_LIBRARY[signal]
  • SignalScript hooks

The common table is rebuilt by UpdateSignalLibraryArray() in CommonGUIModule. It registers handlers for:

  • Axis positive and negative limit status signals
  • Axis homed signals
  • Toolpath mouse down/up
  • Motion-inhibit interlock input
  • Machine enabled/disabled state
  • Spindle-brake output lookup
It also stores the resolved spindle-brake signal ID in SIG_LIBRARY_INST[_inst].SpindleBrakeOutput and SIGNAL_LIB_ARRAY.SpindleBrakeOutput.

The rebuild entry point is CommonUpdateSignalLibraryArray() in CommonGUIModule. It:

  • Calls the active screen/module’s UpdateSignalLibraryArray(), if present.
  • Reads auxiliary-output button mappings from the profile.
  • Enables or disables the corresponding auxiliary screen buttons.
  • Runs the UpdateSignalLibrary hooks, allowing machine-specific modules to register more callbacks.
The screen-specific tables are populated separately. For example:

  • V2 screens build SCREEN_SIG_LIBRARY_INST[_inst] in CommonScreenV02.
  • Mill and plasma modules populate MACHINE_TYPE_SIG_LIBRARY_INST for tool-changer signals in MillGUIModule.lua and PlasmaGUIModule.
  • Height controllers add their own signal handlers in HeightControllers

This Lua “library” sits above the actual Mach signal subsystem. The actual signal objects are handled by the C++/Mach API layer using functions such as mcSignalGetHandle, mcSignalGetNextHandle, mcSignalGetInfo, mcSignalGetState, and mcSignalMap. The API documentation explicitly distinguishes signals from physical I/O: signals can be mapped to I/O, but the signal abstraction does not depend on a particular I/O device.


TableScopePurpose
SIG_LIBRARY_INSTPer Mach instanceCommon machine behavior
MACHINE_TYPE_SIG_LIBRARY_INST  Per Mach instanceMachine-specific behavior, such as mill, plasma, grinder, or height control
SCREEN_SIG_LIBRARY_INSTPer Mach instanceScreen-specific behavior
SCREEN_SIG_LIBRARYGlobal/legacyOlder single-instance screen handlers

Each table uses a signal ID as its key and a Lua function as its value:

Code: [Select]
SIG_LIBRARY_INST[instanceIndex][signalId] = function(signalState)
    -- React to the signal transition
end
signalState is normalized to a Boolean before dispatch.

Dispatch sequence
When Mach detects a signal transition, the following path is used:

  • CommonSignalScript()
    • _CommonSignalScript()
      • module SignalScript()
      • SIG_LIBRARY_INST[instance][signal]
      • MACHINE_TYPE_SIG_LIBRARY_INST[instance][signal]
      • SCREEN_SIG_LIBRARY_INST[instance][signal]
      • SCREEN_SIG_LIBRARY[signal]
      • SignalScript hooks

The dispatcher does not stop after the first matching table. A signal can therefore have common, machine-specific, and screen-specific behavior.

Building the common library
CommonGUIModule.UpdateSignalLibraryArray() registers the standard handlers, including:

  • Positive and negative axis-limit status signals
  • Axis-homed signals
  • Toolpath mouse events
  • Motion-inhibit interlock input
  • Machine enable and disable signals
  • Spindle-brake output lookup

The wrapper, CommonGUIModule.CommonUpdateSignalLibraryArray(), also:
  • Calls a machine module’s UpdateSignalLibraryArray(), if implemented
  • Reads auxiliary output-button assignments from the Mach profile
  • Updates auxiliary-button enabled states
  • Runs the UpdateSignalLibrary hooks

nstance indexing
The tables are indexed by the untagged instance index:
Code: [Select]
local instanceIndex = w.GetUTI(inst)
Handlers registered for one instance should remain associated with that instance. This matters in multi-instance configurations because the same signal number may have different mappings or machine behavior in different instances.

Registration example
A machine module can register a handler for an OEM-mapped signal like this:

Code: [Select]
local signalInfo = w.GetOEMParamIOSigObject(
    "TC_ToolReleaseButtonInput",
    instanceIndex
)

if signalInfo ~= nil and signalInfo["type"] == "Input Signal" then
    MACHINE_TYPE_SIG_LIBRARY_INST[instanceIndex][signalInfo["sigid"]] =
        function(signalState)
            m.ToolReleaseButtonInputChanged(signalState, 1)
        end
end

The mill and plasma implementations follow this pattern in MillGUIModule and PlasmaGUIModule.

Use Case: Tool Release Button
A useful example is a tool changer with a physical tool-release button.

Requirement
When the operator presses or releases the tool-release input:

  • The machine-specific tool-changer logic should run.
  • The handler should use the signal mapping configured for the current instance.
  • Multiple spindles or indexed tool-release inputs should be supported.

Registration
During signal-library setup, the machine module resolves the OEM parameter to its actual signal ID and registers a callback:

Code: [Select]
local signalInfo = w.GetOEMParamIOSigObject(
    "TC_ToolReleaseButtonInput",
    instanceIndex
)

if signalInfo ~= nil and signalInfo["type"] == "Input Signal" then
    MACHINE_TYPE_SIG_LIBRARY_INST[instanceIndex][signalInfo["sigid"]] =
        function(signalState)
            m.ToolReleaseButtonInputChanged(signalState, 1)
        end
end

For a second spindle, the module can resolve a parameter such as:

Code: [Select]
TC_ToolReleaseButtonInput2
and register a callback that passes spindle index 2.

Runtime behavior

When the physical input changes:

Mach updates the underlying signal.
Mach invokes CommonSignalScript.
The signal ID is used to look up the callback in MACHINE_TYPE_SIG_LIBRARY_INST.
The callback invokes:
  • Mach updates the underlying signal.
  • Mach invokes CommonSignalScript.
  • The signal ID is used to look up the callback in MACHINE_TYPE_SIG_LIBRARY_INST.
[li]The callback invokes:
[/li][/list]
Code: [Select]
[code]m.ToolReleaseButtonInputChanged(signalState, spindleIndex)[/code]
    [/li]
  • The tool-changer module performs the configured action.

This keeps the machine module independent of the physical I/O device. The module only needs to know the logical OEM parameter and the resolved Mach signal ID.

Another Use Case: Machine Enable State
The common library registers mc.OSIG_MACHINE_ENABLED for every instance. Its callback updates the cached enable state and starts the appropriate enable or disable sequence.

The handler also performs special startup protection because Mach can emit an initial disabled state while signal synchronization is taking place. That logic is in CommonGUIModule.lua.

This is a good example of behavior that belongs in SIG_LIBRARY_INST rather than a machine-specific table because every screen and machine type needs consistent machine-enable behavior.

When to use each layer:

Use SIG_LIBRARY_INST when:
  • The behavior is common to all machine types.
  • It is instance-specific.
  • It concerns limits, homing, machine enable, or core GUI behavior.

Use MACHINE_TYPE_SIG_LIBRARY_INST when:
  • The behavior belongs to a machine family.
  • The signal is related to a tool changer, plasma THC, grinder, or similar subsystem.
  • The same machine module may register different signals per instance.

Use SCREEN_SIG_LIBRARY_INST[ when:
  • The callback updates controls belonging to a particular screen.
  • The screen supports multiple Mach instances.

Use SCREEN_SIG_LIBRARY when:
  • The behavior is legacy/global screen behavior.
  • The callback is intentionally not instance-specific.

Use SCREEN_SIG_LIBRARY only for legacy/global screen behavior where the callback is intentionally not instance-specific.

Relationship to the Lua Signal Library
The Lua signal library described earlier operates above this lower-level signal/I/O layer:
Physical hardware or simulated device
  • HMCIO I/O handle
  • mcSignalMap()
  • HMCSIG logical signal
  • CommonSignalScript()
  • Lua signal-library callback

For example, a tool-release button may be physically connected to an input device. The device is mapped to a logical signal. The GUI layer then registers a Lua callback keyed by that signal ID:
Code: [Select]
MACHINE_TYPE_SIG_LIBRARY_INST[instanceIndex][signalId] =
    function(signalState)
        m.ToolReleaseButtonInputChanged(signalState, spindleIndex)
    end
The callback does not need to know whether the signal came from:
  • A simulator
  • A motion controller
  • An Ethernet I/O device
  • A PCI or USB device
  • Another plugin

I hope this info dump can help solve your questions?

Something else that will be beneficial if you wish to do any custom development for MachPro:
https://support.machmotion.com/docs/current/dir_f2541a3b18981391fa76fac5599e978a.html

This is some of our code documentation. 

I would highly recommend using the wrapper modules functions instead of the core mach API's as we have built in error handling for most of these functions. You should be able to invoke the wrapper module from anywhere with "w."
Thanks,

Paul
Re: MachPro upgrade questions
« Reply #11 on: September 15, 2026, 03:11:38 PM »
Hi Paul,
thanks for your extensive reply.

I get a general sense as to how MachPro handles signals, but my programming skills are only fair and my understanding of your terminology is poor.
I do rather believe however that MachPro and Mach4 have a similarity.

In Mach4, for which I am familiar each screen set has a ScreenLoad script, and in that script there is a Lua table called SigLib{...........}. Given that the ScreenLoad script
is part of the screen set, and most operators choose to use say wx4.set or wx6.set as a basis for their own personalised copy, and thus survive Mach build updates.

This is the SigLib table in my current Mach4 installation:
Code: [Select]
---------------------------------------------------------------
-- Signal Library
---------------------------------------------------------------
SigLib = {
[mc.OSIG_MACHINE_ENABLED] = function (state)
    machEnabled = state;
    ButtonEnable()
end,

[mc.ISIG_INPUT0] = function (state)
   
end,

[mc.ISIG_INPUT1] = function (state) -- this is an example for a condition in the signal table.
   -- if (state == 1) then   
--        CycleStart()
--    --else
--        --mc.mcCntlFeedHold (0)
--    end

end,

[mc.OSIG_JOG_CONT] = function (state)
    if( state == 1) then
       scr.SetProperty('labJogMode', 'Label', 'Continuous');
       scr.SetProperty('txtJogInc', 'Bg Color', '#C0C0C0');--Light Grey
       scr.SetProperty('txtJogInc', 'Fg Color', '#808080');--Dark Grey
    end
end,

[mc.OSIG_JOG_INC] = function (state)
    if( state == 1) then
        scr.SetProperty('labJogMode', 'Label', 'Incremental');
        scr.SetProperty('txtJogInc', 'Bg Color', '#FFFFFF');--White   
        scr.SetProperty('txtJogInc', 'Fg Color', '#000000');--Black
   end
end,

[mc.OSIG_JOG_MPG] = function (state)
    if( state == 1) then
        scr.SetProperty('labJogMode', 'Label', '');
        scr.SetProperty('txtJogInc', 'Bg Color', '#C0C0C0');--Light Grey
        scr.SetProperty('txtJogInc', 'Fg Color', '#808080');--Dark Grey
        --add the bits to grey jog buttons becasue buttons can't be MPGs
    end
end,
[mc.ISIG_INPUT20] = function(state) --X servo alarm port1 pin10
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/XAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/XAlarm")
mc.mcRegSetValue(handle,0)
end
end,
[mc.ISIG_INPUT21] = function(state) --Y servo alarm port1 pin11
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/YAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/YAlarm")
mc.mcRegSetValue(handle,0)
end
end,
[mc.ISIG_INPUT22] = function(state) --Z servo alarm port1 pin12
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/ZAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/ZAlarm")
mc.mcRegSetValue(handle,0)
end
end,
[mc.ISIG_INPUT23] = function(state) --A servo alarm port1 pin13
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/AAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/AAlarm")
mc.mcRegSetValue(handle,0)
end
end,
[mc.ISIG_INPUT24] = function(state) --B servo alarm port1 pin15
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/BAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/BAlarm")
mc.mcRegSetValue(handle,0)
end
end,
[mc.ISIG_INPUT29] = function(state) --C servo alarm port2 pin2
if(state==1)then
mc.mcCntlEStop(inst)
local handle=mc.mcRegGetHandle(inst,"iRegs0/CAlarm")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/CAlarm")
mc.mcRegSetValue(handle,0)
end
end,

[mc.ISIG_INPUT25] = function(state) --AXIS1 port3 pin6
if(state==1)then
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS1")
mc.mcRegSetValue(handle,0)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS1")
mc.mcRegSetValue(handle,1)
end
ChangeJogAxis()
end,
[mc.ISIG_INPUT26] = function(state) --AXIS2 port3 pin7
if(state==1)then
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS2")
mc.mcRegSetValue(handle,0)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS2")
mc.mcRegSetValue(handle,1)
end
ChangeJogAxis()
end,
[mc.ISIG_INPUT27] = function(state) --AXIS3  port3 pin8
if(state==1)then
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS3")
mc.mcRegSetValue(handle,0)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/AXIS3")
mc.mcRegSetValue(handle,1)
end
ChangeJogAxis()
end,

[mc.ISIG_INPUT28] = function(state) --FEEDHOLD port3 pin9
mc.mcCntlFeedHold(inst)
end,
[mc.ISIG_INPUT30] = function(state) --AXIS3  port3 pin8
if(state==1)then
local handle=mc.mcRegGetHandle(inst,"iRegs0/Velocity1")
mc.mcRegSetValue(handle,1)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/Velocity1")
mc.mcRegSetValue(handle,0)
end
ChangeJogAxis()
end,
[mc.ISIG_INPUT31] = function(state) --AXIS3  port3 pin8
if(state==1)then
local handle=mc.mcRegGetHandle(inst,"iRegs0/Velocity2")
mc.mcRegSetValue(handle,0)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/Velocity2")
mc.mcRegSetValue(handle,1)
end
ChangeJogAxis()
end,
[mc.ISIG_INPUT1]=function(state)

if(state==1)then

local handle=mc.mcRegGetHandle(inst,"iRegs0/Trial")
local LEDState=mc.mcRegGetValue(inst,handle)
wx.wxMessageBox("LED State=="..tostring(LEDState))
if(LEDState==1)then
wx.wxMessageBox("here"..tostring(LEDState))
local handle=mc.mcRegGetHandle(inst,"iRegs0/Trial")
mc.mcRegSetValue(handle,0)
else
local handle=mc.mcRegGetHandle(inst,"iRegs0/Trial")
mc.mcRegSetValue(handle,1)
end
end
end,

}

Several of the signals are generic and came fro the donor screen set, wx6.set in this case, but quite a number more are signal entries specific to my machine and I coded them.
I think you are familiar with the general idea, whenever Mach detects a signal change, of any description , from any source,  the SignalScript runs, wherein it interrogates the
SigLib table, and if it encounters an entry for that signal identity it executes the function in that table entry. My understanding is that MachPro is similar.

Where MachPro and Mach4 differ is that the SigLib table is immediately readily available to the user to add signal entries or change functionalities. Because the SigLib table is in the
ScreenLoad script it is in effect custom to the users machine.

As you can see from the code I have entries for the servo axis alarms, with each latching data into a register, and enacting an Estop. Easy.
Other signals are from my wired pendant. The SigLib entries capture those signal events and invoke functions also within the ScreenLoad script. This is a method I am very familiar with,
it is both simple and yet immensly flexible and powerful.

Why did you deem in necessary to do away with it?

Craig
'I enjoy sex at 73.....I live at 71 so its not too far to walk.'