Here is my final (?) code that got my control panel et al working.
--------------------------------------------------------------
-- Added by DG May 30 2021 to enable the control panel
-- Monitor the switches on the control panel.
-- We break the three different mechanical switches into three separate function calls, since each function has a separate job.
-- We don't need to assign the MPG wheel since Mach handles that for us.
---------------------------------------------------------------
SigLib = {
-------------
-- Axis Select Switch
-- Must always be X or Y
    [mc.ISIG_INPUT5] = function (state)   -- X Axis Select signal 5
        PendantAxisChange()                     
    end,
    [mc.ISIG_INPUT4] = function (state)   -- Z Axis Select signl 4
        PendantAxisChange()                     
    end,
-------------
-- Jog Enable / Speed
-- 4-position rotary switch
-- No active signals mean JOG OFF
    [mc.ISIG_INPUT6] = function (state)       -- Enable Jog Speed 0.1 signal 6
        PendantSpeedChange()                 
    end,
    [mc.ISIG_INPUT7] = function (state)       -- Enable Jog Speed 0.01 signal 7
        PendantSpeedChange()                 
    end,
    [mc.ISIG_INPUT8] = function (state)       -- Enable Jog Speed 0.001 signal 8
        PendantSpeedChange()                     
    end,
	
-------------
-- Axis driver Alarms 
-- Each motor driver has an alarm line that goes high
-- if ********* goes south
-- Stop machine and recover using external reset switches
    [mc.ISIG_INPUT9] = function (state)       -- X Axis
        mc.mcCntlSetLastError(inst, "X Axis driver ALARM - STOPPING")
		eStop()
    end,
    [mc.ISIG_INPUT10] = function (state)       -- Z axis
        mc.mcCntlSetLastError(inst, "Z Axis driver ALARM - STOPPING")
		eStop()
    end,
	
-------------
-- Cycle Start Panel Button
    [mc.ISIG_INPUT1] = function (state)      -- Signal 1     
         InputCycleStart()
    end,
--------------
-- Feed Hold Panel Button
    [mc.ISIG_INPUT2] = function (state)      -- Signal 2     
        InputFeedHold()
    end,
---------------
-- Manual Spindle ON/OFF Panel Button
    [mc.ISIG_INPUT3] = function (state)      -- Starts the spindle manually signal 3
        InputManualSpindle()
    end,
	
----------------
-- Feed Hold Light
-- We waant to blink this during tool change
-- So watch the native FEED HOLD signal
-- And toggle the LED if Mach changes state
	[mc.OSIG_FEEDHOLD] = function (state)
		local inst = mc.mcGetInstance()     
		local hSig = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT6) -- Output 6
		if( state == 1) then
			mc.mcSignalSetState(hSig, mc.MC_ON)
		else
			mc.mcSignalSetState(hSig, mc.MC_OFF)
		end
	end,
--------------------
-- Tool Change
--- So we can blink the panel light
	[mc.OSIG_TOOL_CHANGE] = function (state)
		local inst = mc.mcGetInstance()   
		if( state == 1) then
			--Start timer to flash feed hold LED 500ms interval
			FeedHoldTimer:Start(500, false)
		else
			--Stop timer and turn off feed hold LED in case it's still on.
			FeedHoldTimer:Stop()
			local hSig = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT6) -- Output 6
			mc.mcSignalSetState(hSig, mc.MC_OFF)
		end
	end
}
---------------------------------------------------------------
-- Tool Change LED blink function
---------------------------------------------------------------
FeedHoldTimerPanel = wx.wxPanel (wx.NULL, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxSize( 0,0 ) )
FeedHoldTimer = wx.wxTimer(FeedHoldTimerPanel)
FeedHoldTimerPanel:Connect(wx.wxEVT_TIMER,
function (event)
    local inst = mc.mcGetInstance()
	local hSig = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT6) -- Output 6
	local sSig = mc.mcSignalGetState(hSig)
	if sSig == mc.MC_ON then
		mc.mcSignalSetState(hSig, mc.MC_OFF)
	else
		mc.mcSignalSetState(hSig, mc.MC_ON)
	end
end)
---------------------------------------------------------------
-- Control Panel Cycle Start
---------------------------------------------------------------
function InputCycleStart()
        -- Momentary pushbutton, so we get TWO signals with each button press:
        -- an "ON" and an "OFF"
        -- So check state and ignore the "OFF"
	local hStartButton
	local StartButtonState
	hStartButton, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT1)      -- signal 1
	StartButtonState, rc = mc.mcSignalGetState(hStartButton)
	mc.mcCntlSetLastError(inst, "Control Panel Cycle Start PRESS")
	if (StartButtonState == 1) then
   	    CycleStart()
   	    mc.mcCntlSetLastError(inst, "Control Panel CYCLE START")
	else
		mc.mcCntlSetLastError(inst, "Control Panel Cycle Start RELEASE")
	end
end
---------------------------------------------------------------
-- Control Panel Feed Hold
-- One push for Feed Hold, two pushes for Cycle Stop
---------------------------------------------------------------
function InputFeedHold()
	-- Momentary pushbutton, so we get TWO signals with each button press:
        -- an "ON" and an "OFF"
        -- So check state and ignore the "OFF"
	local hHoldButton
	local HoldButtonState
	hHoldButton, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT2)      -- signal 2
	HoldButtonState, rc = mc.mcSignalGetState(hHoldButton)
	if (HoldButtonState == 1) then
		mc.mcCntlSetLastError(inst, "Control Panel Feed Hold PRESS")
		-- If we are running a program, pause
		-- If we are already paused, stop
		local Running
		local Paused
		Running, rc = mc.mcCntlGetState(inst) 
		Paused, rc = mc.mcCntlFeedHoldState(inst)
		if (Paused == 1) then -- We are paused, so stop
				CycleStop()
				mc.mcCntlSetLastError(inst, "Control Panel CYCLE STOP")
				
		elseif ((Running == mc.MC_STATE_FRUN ) or (Running == mc.MC_STATE_MRUN)) then -- We are running, so do something. 
							                                      -- Have to check both File and MDI because
											      -- Mach differentiates between them!
				rc = mc.mcCntlFeedHold(inst)
				mc.mcCntlSetLastError(inst, "Control Panel FEED HOLD")
		else
			-- Spurious button press
			mc.mcCntlSetLastError(inst, "Not running or paused - IGNORE ME")
		end
	else
		mc.mcCntlSetLastError(inst, "Control Panel Feed Hold RELEASE")
	end
	
end
---------------------------------------------------------------
-- Control Panel Manual Spindle
---------------------------------------------------------------
function InputManualSpindle()
        -- Momentary pushbutton, so we get TWO signals with each button press:
        -- an "ON" and an "OFF"
        -- So check state and ignore the "OFF"
	local hSpindleButton
	local SpindleButtonState
	hSpindleButton, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT3)      -- signal 3
	SpindleButtonState, rc = mc.mcSignalGetState(hSpindleButton)
	if (SpindleButtonState == 1) then
		mc.mcCntlSetLastError(inst, "Control Panel Manual Spindle PRESS")
		local hsig = mc.mcSignalGetHandle(inst, mc.OSIG_SPINDLEFWD)
		local spinstate = mc.mcSignalGetState(hsig)
		if (spindstate == 0) then         -- If spindle is off, turn it on
			-- mc.mcSignalSetState(hsig, 1)
			SpinCW()
			mc.mcCntlSetLastError(inst, "Control Panel Manual Spindle ON")
		else                              -- Otherwise, turn it off
			-- mc.mcSignalSetState(hsig, 0)
			SpinCW()
			mc.mcCntlSetLastError(inst, "Control Panel Manual Spindle OFF")
		end
	else
            mc.mcCntlSetLastError(inst, "Control Panel Manual Spindle RELEASE")
	end
end
----------------------------
-- We use MPG 7
local MachMpgNumberForPendant = 7
local PendantStepSize = 0.001
local PendantDistanceX1 = PendantStepSize * 1    	-- Multiply by one (0.001)
local PendantDistanceX10 = PendantStepSize * 10    	-- Multiply by ten (0.01)
local PendantDistanceX100 = PendantStepSize * 100    	-- Multiply by one hundred (0.1)
-- Constants for readability
local UnmapMPG = -1         	-- Use this one for when Axis selector switch is set to OFF
local AxisNumber_X = 0       	-- Linear axis X
local AxisNumber_Z = 2       	-- Linear axis Z
---------------------------------------------------------------
-- Jog Speed/Enable Rotary Switch
---------------------------------------------------------------
function PendantSpeedChange()
    local hX1
    local hX10
    local hX100
    -- Need to get current state of axis selector switch so we move the right axis
    local hAxis_X  -- X Axis Select Switch
    local hAxis_Z  -- Z Axis Select Switch
   
    local Step1
    local Step10
    local Step100
    local msg
   
    hX1, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT8)        -- Speed 0.001 signal 8
    Step1, rc = mc.mcSignalGetState(hX1)
   
    hX10, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT7)       -- Speed 0.01 signal 7
    Step10, rc = mc.mcSignalGetState(hX10)
   
    hX100, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT6)      -- Speed 0.1 signal 6
    Step100, rc = mc.mcSignalGetState(hX100)
   
    -- Jog Active Light handle
 
    local hJogLight
    hJogLight, rc = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT5) -- Jog Light Signal 5
    -- Figure out which axis is active by reading the axis select switch
    hAxis_X, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT4)   -- If X is selected, activate X signal 4
    SelectAxis_X, rc = mc.mcSignalGetState(hAxis_X)
   
    hAxis_Z, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT5)   -- If Z is selected, activate Z signal 5
    SelectAxis_Z, rc = mc.mcSignalGetState(hAxis_Z)
    -- TODO - This should really check that we have X || Z, but not neither or both!
    if (SelectAxis_X == 1) then
        mc.mcMpgSetAxis(inst, MachMpgNumberForPendant, AxisNumber_X)    -- Map the MPG to control the X Axis
        mc.mcCntlSetLastError(inst, "Jog Axis X Selected")     		-- Show a message in the Screen Set
       
    elseif (SelectAxis_Z== 1) then
        mc.mcMpgSetAxis(inst, MachMpgNumberForPendant, AxisNumber_Z)    -- Map the MPG to control the Z Axis
        mc.mcCntlSetLastError(inst, "Jog Axis Z Selected")  		-- Show a message in the Screen Set
    end
 
    if (Step1 == 1) then
        mc.mcMpgSetInc(inst, MachMpgNumberForPendant, PendantDistanceX1 )
		mc.mcSignalSetState(hJogLight, 1)       			-- Turn Jog light on
        msg = "Jog Active X1 = " .. PendantDistanceX1
        mc.mcCntlSetLastError(inst, msg)  				-- Show a message in the Screen Set
    elseif (Step10 == 1) then
        mc.mcMpgSetInc(inst, MachMpgNumberForPendant, PendantDistanceX10)
		mc.mcSignalSetState(hJogLight, 1)       			-- Turn Jog light on
        msg = "Pendant Distance X10 = " .. PendantDistanceX10
        mc.mcCntlSetLastError(inst, msg)  				-- Show a message in the Screen Set
    elseif (Step100 == 1) then
        mc.mcMpgSetInc(inst, MachMpgNumberForPendant, PendantDistanceX100)
		mc.mcSignalSetState(hJogLight, 1)       			-- Turn Jog light on
        msg = "Pendant Distance X100 = " .. PendantDistanceX100
        mc.mcCntlSetLastError(inst, msg)  				-- Show a message in the Screen Set
    else
		-- If we got here, it means the one of the speed inputs changed, but none are active
		-- That means "JOG OFF"
		mc.mcMpgSetInc(inst, MachMpgNumberForPendant, 0 ) 		-- TODO Can we set the jog distance to 0?
		mc.mcSignalSetState(hJogLight, 0)       			-- Turn Jog light off
		mc.mcMpgSetAxis(inst, MachMpgNumberForPendant, UnmapMPG )   	-- Unmap the MPG, so it won't control any axes
        mc.mcCntlSetLastError(inst, "Jog Handle Disabled")  		-- Show a message in the Screen Set
    end
   
end
---------------------------------------------------------------
-- The Pendant's Axis switch changed.
-- Need to handle this for when the axis switch is flipped while jogging is active
---------------------------------------------------------------
function PendantAxisChange()
 
    -- handles
    local hAxis_X
    local hAxis_Z
    local SelectAxis_X
    local SelectAxis_Z
    -- Before we do anything, we need to check if the jog handle is assigned to axis -1
    -- If it is, jog is DISABLED, so we do nothing (the act of enabling jog will read the axis switch)
    -- Otherwise we enable jog, which is BAD
    -- TODO - need a function to check which axis is assigned
    -- This is a guess!
    local AxisState
    AxisState, rc = mc.mcMpgGetAxis(inst, MachMpgNumberForPendant)
    if (AxisState ~= UnmapMPG) then
        hAxis_X, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT4)   
        SelectAxis_X, rc = mc.mcSignalGetState(hAxis_X)
   
        hAxis_Z, rc = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT5)
        SelectAxis_Z, rc = mc.mcSignalGetState(hAxis_Z)
        -- Now actual axis Selection Switch processing code
        if (SelectAxis_X == 1) then
            mc.mcMpgSetAxis(inst, MachMpgNumberForPendant, AxisNumber_X)    -- Map the MPG to control the X Axis
            mc.mcCntlSetLastError(inst, "Pendant Axis X Selected")  	    -- Show a message in the Screen Set
       
        elseif (SelectAxis_Z== 1) then
            mc.mcMpgSetAxis(inst, MachMpgNumberForPendant, AxisNumber_Z)    -- Map the MPG to control the Z Axis
            mc.mcCntlSetLastError(inst, "Pendant Axis Z Selected")  	    -- Show a message in the Screen Set
   
        else
            -- This is a problem, because the axis select switch is one or the other
	    -- We have no high pin - so shut off jogging
            mc.mcMpgSetAxis(inst, MachMpgNumberForPendant, UnmapMPG )     	                -- Unmap the MPG, so it won't control any axes
            mc.mcCntlSetLastError(inst, "ABEND - no valid axis selected on control panel!")  	-- Show a message in the Screen Set
        end
     else
        mc.mcCntlSetLastError(inst, "Changed axis select while jog disabled - IGNORED")
     end
end
-- Set jog state when the Screen is loaded by Mach4
PendantSpeedChange()