Hello Guest it is March 28, 2024, 04:36:22 PM

Author Topic: Scripting Custom Control Panel  (Read 1669 times)

0 Members and 1 Guest are viewing this topic.

Re: Scripting Custom Control Panel
« Reply #10 on: February 02, 2021, 09:45:29 AM »
Making the LED's work will be simple...

Your comments on the screen are following your numbers:
1.) This was done so you can press the same button to trigger a cycle start OR you can trigger an MDI event from the same button. This was done to emulate how it is done on industrial machines (we automatically swap the state in the background in the state machine). If you want to change how it works  you can do that. That's sort of the point of all this, make it your way.
2.)Error checking... Yup agree and they should have checked many of the error returns. The guys that work on the screens are not programmers they are machinist. The reason for this is that my self and Steve simply don't have time to go play screen guys. We did have them audit the screens for error checking but looks like I may have to review it again. Mind you some of them are not needed...
3.)Commented out code.. Machinist ... They are are worried that if they take the code out that they will not be able to find it later for someone. The screens are all under source control so we will never loose anything! They should have put comments to what changed in the Repo but I don't read that stuff for fun.
4.)The NOOP's are because we are building a chunk in the background of all the buttons and calls that are in the screen. This is to give you one programming environment. if  you don't put stuff in the functions they just don't have anything.
No worry they are not called and will not slow the screen

I am in the middle of TRYING to get a  release out and I made them do some house keeping :)

Fixing problems one post at a time ;)

www.newfangledsolutions.com
www.machsupport.com

Offline Bill_O

*
  •  563 563
    • View Profile
Re: Scripting Custom Control Panel
« Reply #11 on: February 02, 2021, 10:52:40 AM »
I made a pendant not a control panel but same thing for button.
Here is how I make my buttons work.
You can do a lot with these and how Lua/Mach4 function.

[mc.ISIG_INPUT0] = function (state)
    if (state == 1) then
      CycleStart()
   end
end,

[mc.ISIG_INPUT1] = function (state)
    if (state == 1) then
      mc.mcCntlRewindFile(inst)
   end
end,

[mc.ISIG_INPUT2] = function (state)
    if (state == 1) then
      CycleStop()
   end
end,

[mc.ISIG_INPUT3] = function (state)
   if (state == 1) then
      if (Pause == 1) then
         mc.mcCntlCycleStart(inst)
         Pause = 0
      elseif (Pause == 0) then
         mc.mcCntlFeedHold(inst)
         Pause = 1
      end
   end
end,

[mc.ISIG_INPUT4] = function (state)
      if (state == 0) then
         mc.mcCntlEnable(inst, true)
      else
         mc.mcCntlEnable(inst, false)
      end
end,

[mc.ISIG_INPUT20] = function (state)
    local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   if (state == 1) then
      mc.mcRegSetValue(AltRegH, 1)      
   else
      mc.mcRegSetValue(AltRegH, 0)   
   end
end,

[mc.ISIG_INPUT5] = function (state)
    local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
   if (state == 1) then
      if (AltVal == 0) then
      GoToWorkZero()
      elseif (AltVal == 1) then
      SetWorkZero()
      end
   end
end,

[mc.ISIG_INPUT6] = function (state)
    local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
   if (state == 1) then
      if (AltVal == 0) then
      ReturnToPosition()
      elseif (AltVal == 1) then
      RememberPosition()
      end
   end
end,

[mc.ISIG_INPUT7] = function (state)
    local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
   if (state == 1) then
      if (AltVal == 1) then
         wait = coroutine.create (RefAllHome)
      end
   end
end,




[mc.ISIG_INPUT8] = function (state)
   local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
      if (state == 1) then
      if (AltVal == 0) then
      Surface()
      elseif (AltVal == 1) then
      MaxDepth()
      end      
   end
end,

[mc.ISIG_INPUT11] = function (state)
      local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
   if (state == 1) then
      if (AltVal == 0) then
      CutSpeedMinus()
      elseif (AltVal == 1) then
      CutSpeedPlus()
      end            
   end
end,

[mc.ISIG_INPUT12] = function (state)
   local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)   
      if (state == 1) then
      if (AltVal == 1) then
      ExtraDepth()
      end      
   end
end,

[mc.ISIG_INPUT15] = function (state)
      if (state == 1) then
      SpeedsReset()
   end
end,

[mc.ISIG_INPUT16] = function (state)
      local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)   
      if (state == 1) then
      if (AltVal == 0) then
      MistOnOff()
      elseif (AltVal == 1) then
      SpindleOnOff()
      end                  
   end
end,

[mc.ISIG_INPUT19] = function (state)
      local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
   if (state == 1) then
      if (AltVal == 0) then
      JogSpeedMinus()
      elseif (AltVal == 1) then
      JogSpeedPlus()
      end            
   end
end,

[mc.ISIG_INPUT21] = function (state)
    local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
   if (state == 1) then
      if (AltVal == 0) then
         local MachHmdreg = mc.mcRegGetHandle(inst, 'iRegs0/MachHmd')
         local MachHmd = mc.mcRegGetValue(MachHmdreg)
         if (MachHmd == 0) then
            wx.wxMessageBox("Must set Machine Home")
         elseif (MachHmd == 1) then
--            mc.mcCntlGcodeExecute(inst, "m6")
            mc.mcCntlMdiExecute(inst, 'm6')
         end
      elseif (AltVal == 1) then
         local hsig = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT6)
         local sigOut6 = mc.mcSignalGetState(hsig)
         if (sigOut6 == 0) then
            mc.mcSignalSetState(hsig, 1)
         else
            mc.mcSignalSetState(hsig, 0)
         end
      end
   end
end,

[mc.ISIG_INPUT22] = function (state)
      local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
   if (state == 1) then
      if (AltVal == 0) then
      
      elseif (AltVal == 1) then
      
      end            
   end
end,

[mc.ISIG_INPUT25] = function (state)
    if (state == 1) then
      local Tool = mc.mcToolGetSelected(inst)
      --get max tools
      local ATCMaxTlsReg = mc.mcRegGetHandle(inst, 'iRegs0/ATCMaxTools')
      local ATCMaxTlsVal = mc.mcRegGetValue(ATCMaxTlsReg)   
      --if tool is 100(cam), 101(tks) or 102(tko) set tool to 0
      if (Tool == 100) or (Tool == 101) or (Tool == 102) then
         Tool = 0
      end
      --if tool is in range add one to tool #
      if (Tool <= (ATCMaxTlsVal - 1)) then
         Tool = (Tool + 1)
         mc.mcCntlSetPoundVar(inst, mc.SV_CUR_SELECTED_TOOL, Tool)
      end
   end
end,

[mc.ISIG_INPUT26] = function (state)
   local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)   
      if (state == 1) then
      if (AltVal == 1) then
         local TKSReg = mc.mcRegGetHandle(inst, 'iRegs0/TKStdOnOff')
         local TKSRegVal = mc.mcRegGetValue(TKSReg)
         local TKOReg = mc.mcRegGetHandle(inst, 'iRegs0/TKOscOnOff')
         local TKORegVal = mc.mcRegGetValue(TKOReg)
         local TKSSigH = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT7)
         local TKOSigH = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT8)
         local TKOscSigH = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT9)

         local ATCOnOffReg = mc.mcRegGetHandle(inst, 'iRegs0/ATCOnOff')
         local ATCOnOffVal = mc.mcRegGetValue(ATCOnOffReg)
         local ATCToolHReg = mc.mcRegGetHandle(inst, 'iRegs0/ATCToolHolder')

         local SMReg = mc.mcRegGetHandle(inst, 'iRegs0/SMOnOff')
         local SMRegVal = mc.mcRegGetValue(SMReg)   
         
         mc.mcRegSetValue(TKSReg, 0)
         mc.mcSignalSetState(TKSSigH, 0)
         mc.mcRegSetValue(TKOReg, 0)
         mc.mcSignalSetState(TKOSigH, 0)
         mc.mcSignalSetState(TKOscSigH, 0)
         
         --if atc on change current tool to tool holder tool
         if (ATCOnOffVal == 1) then
            local CurTool = mc.mcToolGetCurrent(inst)
            local ATCToolHVal = mc.mcRegGetValue(ATCToolHReg)
            if (CurTool == 100) or (CurTool == 101) or (CurTool == 102) then
               mc.mcToolSetCurrent(inst, ATCToolHVal)
               mc.mcCntlGcodeExecuteWait(inst, string.format("G43 H" .. tostring(ATCToolHVal)))
               mc.mcCntlSetPoundVar(inst, mc.SV_HEAD_SHIFT_X, 0.000)
               mc.mcCntlSetPoundVar(inst, mc.SV_HEAD_SHIFT_Y, 0.000)
            end
         end
         
         --turn off tang knife mode
         mc.mcCntlSetParameter(502, 0)
         mc.mcCntlSetLastError(inst, 'TK OFF')
         if (SMTempOn == 1) then
            mc.mcRegSetValue(SMReg, 1)
            SMTempOn = 0
         end
         
         --mc.mcRegSetValue(TKSReg, TKSRegVal)
         KeyTKSTemp = 0
         --mc.mcRegSetValue(TKOReg, TKORegVal)
         KeyTKOTemp = 0
      end      
   end
end,

[mc.ISIG_INPUT27] = function (state)
    local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
   if (state == 1) then
      if (AltVal == 1) then
         KeyTKSTemp = 1
         TKSOnOff()
      end
   end
end,

[mc.ISIG_INPUT28] = function (state)
    local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
   if (state == 1) then
      if (AltVal == 1) then
         KeyTKOTemp = 1
         TKOOnOff()
      end
   end
end,

[mc.ISIG_INPUT29] = function (state)
    if (state == 1) then
      local Tool = mc.mcToolGetSelected(inst)
      --get max tools
      local ATCMaxTlsReg = mc.mcRegGetHandle(inst, 'iRegs0/ATCMaxTools')
      local ATCMaxTlsVal = mc.mcRegGetValue(ATCMaxTlsReg)   
      --if tool is 100(cam), 101(tks) or 102(tko) set tool to MaxTool
      if (Tool == 100) or (Tool == 101) or (Tool == 102) then
         Tool = (ATCMaxTlsVal + 1)
      end
      --if tool is in range subtract one from tool #
      if (Tool >= 2) then
         Tool = (Tool - 1)
         mc.mcCntlSetPoundVar(inst, mc.SV_CUR_SELECTED_TOOL, Tool)
      end
   end
end,

[mc.ISIG_INPUT30] = function (state)
      local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
   if (state == 1) then
      if (AltVal == 0) then
      
      elseif (AltVal == 1) then
         local hsig = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT5)
         local sigOut5 = mc.mcSignalGetState(hsig)
         if (sigOut5 == 0) then
            mc.mcSignalSetState(hsig, 1)
         else
            mc.mcSignalSetState(hsig, 0)
         end
      end            
   end
end,

[mc.ISIG_INPUT31] = function (state)
      if (state == 1) then
      wait = coroutine.create (RefTKHome)
   end
end,

[mc.ISIG_INPUT32] = function (state)
    local AltRegH = mc.mcRegGetHandle(inst, 'iRegs0/Alt')
   local AltVal = mc.mcRegGetValue(AltRegH)
   local Sig9H = mc.mcSignalGetHandle(inst, mc.OSIG_OUTPUT9)
   local Sig9Val = mc.mcSignalGetState(Sig9H)
   if (state == 1) then
      if (AltVal == 1) then
         if (Sig9Val == 0) then
            mc.mcSignalSetState(Sig9H, 1)
            --wx.wxMilliSleep(1000)
         else
            mc.mcSignalSetState(Sig9H, 0)
            --wx.wxMilliSleep(1000)
         end
      end
   end
end,

Re: Scripting Custom Control Panel
« Reply #12 on: February 02, 2021, 10:58:00 AM »
So I'm tracking why CycleStart() has the MDI check in there - and I agree with the reasoning. Got it.

But why is CycleStart() wrapped in btnCycleStart_Left_Up_Script() - which only calls CycleStart()?

Here is my first kick at a replacement function:

Code: [Select]

-----------------------------------------------------------------------
-- FNR_CycleStart
--
-- To be called by the Cycle Start UI button and/or the button on the FNR Console (INPUT 10)
-- If we are in GCode mode, run the loaded program
-- If we are in MDI mode, run the MDI code
-- If we are in Feed Hold state, release it and continue
-- LED aware for the FNR lathe control console
--
-- Version History
-- V0.5 DG Feb 2 2021 First attempt
--------------------------------------------------------------------------

function FNR_CycleStart()

   -- Are we resuming a Feed Hold?
   local Feedstate, rc = mc.mcCntlFeedHoldState(inst)
   if (rc == mc.MERROR_NOERROR) then
        if (Feedstate == 1) then
             local ec = mc.mcCntlCycleStart(inst)  -- Resume program
             if (ec == mc.MERROR_NOERROR) then
                  -- We can probably trust shutting off a light
                  mc.mcSignalSetState(FNRPauseLED, 0)
                  mc.mcSignalSetState(FNRRunLED, 1)
             else
                  if (ec == mc.MERROR_NOT_NOW) then
                       -- lights stay the same, but record the error
                       mc.mcCntlSetLastError(inst, "Could not resume from feed hold ERROR_NOT_NOW")
                  end
             else
                  -- Should never get here - needs standard error handling trap
                  -- Just complain for now
                  mc.mcCntlSetLastError(inst, "Invalid Instance in CycleStart()")
             end
        else
             -- Not resuming a feed hold
             -- Are we in MDI or Program mode?
             -- Next bit is copypasta from original CycleStart() TODO: Add error handling
             local tab, rc = scr.GetProperty("MainTabs", "Current Tab") -- will lua throw a fit if I redefine a variable like this?
             local tabG_Mdione, rc = scr.GetProperty("nbGCodeMDI1", "Current Tab")
             if ((tonumber(tab) == 0 and tonumber(tabG_Mdione) == 1)) then
                  local state = mc.mcCntlGetState(inst);
                  if (state == mc.MC_STATE_MRUN_MACROH) then
                       -- Program Mode (?)
                       mc.mcCntlCycleStart(inst);
                       -- Turn on the run light
                       mc.mcSignalSetState(FNRRunLED, 1)
                  else
                       if (tonumber(tab) == 0) then
                            -- MDI Mode (?) 
                            scr.ExecMdi('mdi1');
                            -- Turn on the run light
                            mc.mcSignalSetState(FNRRunLED, 1)
                        end
                  end
             else
                  -- For some reason, if we fall through the tab check, we execute a Cycle Start anyway
                  -- Maybe for tool changes?
                  -- If this is a tool change acknowledgement, we don't set the light
                  -- FIXME: Understand how we get here and do the right thing 
                  mc.mcCntlCycleStart(inst);
             end
         end
    else
          -- Should never get here - needs standard error handling trap
          -- Just complain for now
          mc.mcCntlSetLastError(inst, "Couldn't get feed state in CycleStart()")
    end

    -- Belt and suspenders - check if program running, and turn on light if it is
    -- Maybe this invalidates need to turn on light elsewhere?
    -- FIXME: Is this valid for MDI?
    local cycle, rc = mc.mcCntlyIsInCycle(inst)
    if ((rc == mc.MERROR_NOERROR) && (cycle == 1)) then
         mc.mcSignalSetState(FNRRunLED, 1)
    else
         if ((rc == mc.MERROR_NOERROR) && (cycle == 0)) then
              mc.mcSignalSetState(FNRRunLED, 0)
         else
              -- Should never get here - needs standard error handling trap
              -- Just complain for now
              mc.mcCntlSetLastError(inst, "Couldn't determine run state in CycleStart()")
         end
    end
end       
Re: Scripting Custom Control Panel
« Reply #13 on: February 02, 2021, 11:03:28 AM »
the reason it is wrapped is because in the screen the "btnCycleStart" button uses it's left up event. We mash that all up and make a btnCycleStart_Left_Up_Script() call that we trigger from C++. Lua is a glue that you get use to customize the actions.

Was that any help?
Fixing problems one post at a time ;)

www.newfangledsolutions.com
www.machsupport.com
Re: Scripting Custom Control Panel
« Reply #14 on: February 02, 2021, 11:25:43 AM »
So why not have the screen button call CycleStart() from its left button up event?

The way the Feed Hold screen button calls an uwrapped function (which I remember seeing last night, but I can't verify right now because I'm not near that machine).

What value does the extra wrapper provide, other than the name change?
Re: Scripting Custom Control Panel
« Reply #15 on: February 02, 2021, 11:52:15 AM »
The button is not drawn by Lua. The button is done in C++ and you don't "need" to do any scripting to make a machine work. We have to know the name of the event to call in Lua from C++ for each button that has some Lua code. Not really any other way to do that. The Cycle start code COULD be in the button's On Up script and work but it would not be as easy to call from an input (SignalLib() ). That is why that was done.

The feedhold is doing the API call for feedhold because no matter what your doing feedhold is valid. We don't have an MDI  feedhold. The reason to wrap it the functions is if  you would like to add some code to be done around it.  Your LED's can be controlled in the PMC by looking at the state of the machine.

This was no thrown together in an afternoon :) we have reasons the system is designed the way it is. I am more than happy to talk about it.  When you really dig in and see all that is going on it is impressive. It took 10 years to make this all happen with a target we where focused on!
Fixing problems one post at a time ;)

www.newfangledsolutions.com
www.machsupport.com
Re: Scripting Custom Control Panel
« Reply #16 on: February 02, 2021, 12:12:29 PM »
The button is not drawn by Lua. The button is done in C++ and you don't "need" to do any scripting to make a machine work. We have to know the name of the event to call in Lua from C++ for each button that has some Lua code. Not really any other way to do that.

Right - but is that name not editable in the screen editor? If I change the name of the function called on the On Up event in the screen editor to CycleStart(), will it not work?

(Mach isn't here so I can't check)

Quote
The Cycle start code COULD be in the button's On Up script and work but it would not be as easy to call from an input (SignalLib() ). That is why that was done.

Hold that thought

Quote
The feedhold is doing the API call for feedhold because no matter what your doing feedhold is valid. We don't have an MDI  feedhold.

Fair ball. Got it.

Quote
The reason to wrap it the functions is if  you would like to add some code to be done around it.

Right.

So what is stopping me from:

Code: [Select]

function FNR_FeedHold()
  mc.mcCtlFeedHold(inst)
  mc.mcSignalSetState(FNRPauseLED, 1)
end


...and changing the name of the function called by the button onUp event to FNR_FeedHold() in the screen editor?
 
Quote
Your LED's can be controlled in the PMC by looking at the state of the machine.

Why do it that way, rather than via the scripts? The scripting language is pretty straightforward. I mean, it isn't perl, but that's a high standard to meet.

Quote
This was no thrown together in an afternoon :)

Well, you've got production-class machines running on this stuff... perhaps it deserves some love.

Quote
When you really dig in and see all that is going on it is impressive. It took 10 years to make this all happen with a target we where focused on!

Nobody is questioning that.

As it happens, I have a coding background - I wrote the DaimlerChrysler external supplier distributed user management system and coded the LDAP replication process that harmonized two *very* different user database schemas in real time... which I suppose dates me... but anyway, I grok all this stuff. But any time you pick up someone else's code you have to go through a process to understand how their thought processes work when they wrote it, because the code is influenced by a ton of external factors, ranging from "programmer experience level and personality" to "weird undocumented quirks of the programming language, discovered the hard way when something entirely sensible on paper blew up in reality".

And at the end of the day, I want my control console to work.
Re: Scripting Custom Control Panel
« Reply #17 on: February 02, 2021, 01:25:25 PM »
Quote
Right - but is that name not editable in the screen editor? If I change the name of the function called on the On Up event in the screen editor to CycleStart(), will it not work?

You can't set the name of the function .... that is the button name and the function. It is how we find it in the C++ world...

Code: [Select]
function FNR_FeedHold()
  mc.mcCtlFeedHold(inst)
  mc.mcSignalSetState(FNRPauseLED, 1)
end
Quote
...and changing the name of the function called by the button onUp event to FNR_FeedHold() in the screen editor?
You can do that, no problem.

If you want to do it in script that is cool ... it is your machine you can do it anyway you like :)

Also we have other events (signals) ! Here is al list I got from the header file
Code: [Select]
OSIG_MISC_START  (OSIG_OUTPUT_FINISH + 1) 
#define OSIG_RUNNING_GCODE   (OSIG_MISC_START + 0)
#define OSIG_FEEDHOLD        (OSIG_MISC_START + 1)
#define OSIG_BLOCK_DELETE    (OSIG_MISC_START + 2)
#define OSIG_SINGLE_BLOCK    (OSIG_MISC_START + 3)
#define OSIG_REVERSE_RUN     (OSIG_MISC_START + 4)
#define OSIG_OPT_STOP        (OSIG_MISC_START + 5)
#define OSIG_MACHINE_ENABLED (OSIG_MISC_START + 6)
#define OSIG_TOOL_CHANGE     (OSIG_MISC_START + 7)
#define OSIG_DIST_TOGO       (OSIG_MISC_START + 8)
#define OSIG_MACHINE_CORD    (OSIG_MISC_START + 9)
#define OSIG_SOFTLIMITS_ON   (OSIG_MISC_START + 10)
#define OSIG_JOG_INC         (OSIG_MISC_START + 11)
#define OSIG_JOG_CONT        (OSIG_MISC_START + 12)
#define OSIG_JOG_ENABLED     (OSIG_MISC_START + 13)
#define OSIG_JOG_MPG         (OSIG_MISC_START + 14)
#define OSIG_HOMED_X         (OSIG_MISC_START + 15)
#define OSIG_HOMED_Y         (OSIG_MISC_START + 16)
#define OSIG_HOMED_Z         (OSIG_MISC_START + 17)
#define OSIG_HOMED_A         (OSIG_MISC_START + 18)
#define OSIG_HOMED_B         (OSIG_MISC_START + 19)
#define OSIG_HOMED_C         (OSIG_MISC_START + 20)
#define OSIG_DWELL           (OSIG_MISC_START + 21)
#define OSIG_TP_MOUSE_DN (OSIG_MISC_START + 22)
#define OSIG_LIMITOVER       (OSIG_MISC_START + 23)
#define OSIG_CHARGE          (OSIG_MISC_START + 24)
#define OSIG_CHARGE2         (OSIG_MISC_START + 25)
#define OSIG_CURRENTHILOW    (OSIG_MISC_START + 26)
#define OSIG_SPINDLEON       (OSIG_MISC_START + 27)
#define OSIG_SPINDLEFWD      (OSIG_MISC_START + 28)
#define OSIG_SPINDLEREV      (OSIG_MISC_START + 29)
#define OSIG_COOLANTON       (OSIG_MISC_START + 30)
#define OSIG_MISTON          (OSIG_MISC_START + 31)
#define OSIG_DIGTRIGGER      (OSIG_MISC_START + 32)
#define OSIG_ALARM           (OSIG_MISC_START + 33)
#define OSIG_PRTSF           (OSIG_MISC_START + 34)
#define OSIG_TLCHB           (OSIG_MISC_START + 35) // Tool Change B
#define OSIG_WATO            (OSIG_MISC_START + 36) // Path wating signal
#define OSIG_RETRACT         (OSIG_MISC_START + 37) // Retract Signal
#define OSIG_MISC_FINISH     (OSIG_RETRACT)

The guys are going through the screens for the release and I jammed my head in to see how they looked ... Much better! I have been telling them NOT to comment out the code and keep it in the screens! But you know how that goes... you can only push mud up a hill for so long before you want to go get your own work done. I am currently trying to get the mouse wheel with a low level hook to windows. I can't debug it because it kills my hook as soon as it see's that I stopped the mouse messages ... So I am writing debug tools to do that. Frankly chatting with you has been a nice distraction.

Hope all the output signals helps, you should be able to use that to fire your LED's 
Thanks
Brian
Fixing problems one post at a time ;)

www.newfangledsolutions.com
www.machsupport.com