--************************************************
--*** Set these values up to suit your machine ***
-- Values set HERE are in MM. If the value can be set in SheetCAM it is in the UNITS (MM or Inches) you have in SheetCAM
--************************************************
refDistance = 25 -- this is the distance between each torch reference in MILLIMETRES.(can be set from POST Options button in UNITS)
lineNumber = 0 --set this to 1 if you want the G-Code to have assigned line numbers on each line.  Default is 0 for LinuxCNC
minLength = 0   -- default minumum length of cut for DTHC operation (set dynamically)
fullTAP = 0 --set this to 1 for TAP via Hypertherm RS485 (requires options)
plasmaDrill = 1 --set this to 1 to use a plasma for a drill tool .   Set it to 0 to use a drill or router bit
warnings = true  -- set this to false to turn off the Check Parameters warnings on a toolchange
verbose = true  --  set this to false to turn off the G-Code comments (except code snips)
-- make sure you have the PROBE input  in LINUXCNC Input Signals enabled and mapped to the probe switch input
startCode = " M3 S100" --S command needed for LINUXCNC
noTouchOff = true  -- set to true if you want to run in simulation without touchoffs.  Normal setting would be false
extTOff = true  -- set this to true to use a subroutine in CommandCNC to call a touch off sequence and apply the external switchoffset value.
--  Leave this at "true" for commandCNC versions 0.6.0 and later

--******************************************************************************************************************************************
--  do not change the following values unless you are told to do so by an experienced LinuxCNC user or vendor of your controller or table
toolTrack = .254  -- Default .254 mm. This is the blending tolerance in MM (deviation from toolpath)  the Path Blending allows.
--                   Lower numbers favors tight tracking over the defined feedrate (slows down)
toolTolerance = .0254 -- Default .0254 mm.T his is the linear tolerance for multiple nodes in the same toolpath.
--                   Lower numbers cause nodes out of line by less than the toolTolerance amount to be a single line
--*******************************************************************************************************************************************

--Scriber X,Y,Z offsets in MILLIMETRES. Do not use inches here even if you want inch code
--For the marker use the scriber Z as the offset from Z zero you want the Z to move to during a scribe.
--Change these values to suit your scriber setup
scriberX = 25
scriberY = 25
scriberZ = 50
--scriber axis. Leave this as nil if the scriber is fixed to the same axis as the torch
scriberAxis = nil

--this value when set to "true" will set the Z to lift to rapid height between paths when using the marker tool.
--if false it will not lift the Z between paths but will at the end
markerZ = true
drillZ = .250

torchOnCode   = " M64 P1"
torchOffCode   = " M65 P1"

--**************************************************************************
--***                      End of settings                ***
--***  DO NOT CHANGE ANYTHING BELOW THIS LINE   ***
--**************************************************************************

function OnAbout(event)
    ctrl = event:GetTextCtrl()
    ctrl:AppendText("Custom Post for CommadnCNC for Linux: \n")
    ctrl:AppendText("For CandCNC Linux hardware \n")
    ctrl:AppendText("with/without Plate marker\n")
    ctrl:AppendText("Adds expanded Tooltable parameters (DCC) for Electronics Cut Chart\n")
    ctrl:AppendText("This version allows setting POST variables to turn TAP and Auto Tune for DTHCIV on/off")
    ctrl:AppendText("Adds options for SOFT PIERCE ,  MIN CUT LENGTH, PECK PIERCE and SOFT PECK\n")
    ctrl:AppendText("Use with SheetCAM TNG version 6.0.14 or higher or Development ver 6.1.16 \n")
    ctrl:AppendText("Designed for use with LINUXCNC version 0.5.0  or later and CandCNC DTHCIV with Floating head Touch-n-Go\n")
    local window = ctrl:GetParent()
    local btn = wx.wxButton(window, wx.wxID_ANY, "Set custom post options")
    btn:Connect(wx.wxID_ANY, wx.wxEVT_COMMAND_BUTTON_CLICKED, OnButton)
    ctrl:GetContainingSizer():Insert(2, btn, 0, wx.wxALL, 5)
end


post.DefineVariable("cutDistance",sc.unitLINEAR,0,1e17)
post.DefineVariable("slowPercent",sc.unitPERCENT,-1e17,1e17)

if(fullTAP > 0) then
    post.DefineCustomToolParam("JetOperation", "Soft Pierce %", "softPierce", sc.unit0DECPLACE,100, 40, 100)
    post.DefineCustomToolParam("PlasmaTool", "Preset current", "presetAmps", sc.unit0DECPLACE, 45, 10, 200)
    post.DefineCustomToolParam("PlasmaTool", "Preset Air Pressure", "presetPSI", sc.unit0DECPLACE, 75, 50, 100)
else
    softPierce = 0
    presetAmps = 0
    presetPSI  = 0
end
post.DefineCustomToolParam("PlasmaTool", "Preset volts", "presetVolts", sc.unit0DECPLACE, 49, 0, 200)
post.DefineCustomToolParam("PlasmaTool", "DTHC delay -sec", "dthcDelay", sc.unit2DECPLACE, 0, 0, 99)
post.DefineCustomToolParam("PlasmaTool", "Tip Size -Amps", "tipSize", sc.unit0DECPLACE, 25, 45, 200)
post.DefineCustomToolParam("PlasmaTool", "NO DTHC - 0", "dthcOff", sc.unit0DECPLACE, 1, 0, 1)
post.DefineCustomToolParam("JetOperation", "Min Cut Length for DTHC", "minLength", sc.unit1DECPLACE, 1, .0, 100)
post.DefineCustomToolParam("FlameTool", "Set Z Zero Manually ? - 1 is YES", "manualZSet", sc.unit0DECPLACE, 0, 1, 1)

-- post.DefineCustomToolParam("JetOperation", "Toolpath tracking", "toolTrack", sc.unit3DECPLACE, .010, .0, .100)
if (toolTrack)  then
    --nothing
else
    toolTrack = .001
end

if(plasmaDrill > 0) then
    if(fullTAP > 0) then
        post.DefineCustomToolParam("DrillOperation", "Preset Current Amps", "presetAmps", sc.unit0DECPLACE, 45, 0, 200)
        post.DefineCustomToolParam("DrillOperation", "Preset Air Pressure PSI", "presetPSI", sc.unit0DECPLACE, 75, 0, 200)
    else
        softPierce = 0
        presetAmps = 0
        presetPSI  = 0
    end
    post.DefineCustomToolParam("DrillOperation", "Peck Delay Sec", "peckPierce", sc.unit2DECPLACE, 0, 0, 1)
    post.DefineCustomToolParam("DrillOperation", "Soft Mark Percent", "softPeck", sc.unit0DECPLACE, 50, 10, 100)
end
post.DefineCustomOption("Ref Distance", "refDistance", sc.unitLINEAR, 0, 10000)
-- post.DefineCustomOption("Switch Offset", "switchOffset", sc.unitLINEAR, 0, 10000)--took this out to remove swtichOffset from Custom Post Options in LINUX



function OnButton(evt)
    post.ShowCustomOptions("Post settings")
end


function OnInit()
    
    offX = 0
    offY = 0
    offZ = 0
    
    post.SetCommentChars ("()", "[]")  --make sure ( and ) characters do not appear in system text
    post.Text (" (Filename: ", fileName, ")\n")
    post.Text (" (Post processor: ", postName, ")\n")
    post.Text (" (Date: ", date, ")\n")
    if(scale == metric) then
        post.Text (" G21 (Units: Metric)\n") --metric mode
    else
        post.Text (" G20 (Units: Inches)\n") --inch mode
    end
    post.Text (" G90 G40\n")
    post.Text (" F69\n")
    post.Text (" M52 P1 (Enable Adaptive Feed for arcs)\n") 
    
    post.Text (" G64 P")
    post.Number (toolTrack * scale, "0.000")
    post.Text(" Q")
    post.Number (toolTolerance * scale, "0.000")
  
    post.Text (" (tracking tolerances set to " , toolTrack * scale, ") \n")  

    if(presetVolts) then
        --don't do anything
    else
        presetVolts = 0 --don't pass a null
    end
    
    if(tipSize) then
        --don't do anything
    else
        tipSize = 25 --don't pass a null
    end
    
    if(presetAmps) then
        --don't do anything
    else
        presetAmps = 0 --don't pass a null
    end
    
    if(presetPSI) then
        --don't do anything
    else
        presetPSI = 0 --don't pass a null
    end
    
    if(softPierce) then
        --don't do anything
    else
        softPierce = 100 --don't pass a null
    end
    
    if(entityLength) then
        --don't do anything
    else
        entityLength = 0 --don't pass a null
    end
	if plungeSafety < 10 then   --minimum plungeSafety clearance is 9mm
	   plungeSafety  = 10
	end
	if safeZ <= plungeSafety then --Rapid claearnce has to be greater than plunge safety or we set it to double
       safeZ = plungeSafety * 2
    end
    off2X = .0254
    off2Y = .0254
    newOp = false
    minArcSize = 0.2 --arcs smaller than this are converted to moves
    firstRef = true
    currentZAxis = "Z"
    finalCut = false
    dist = 9999999
    lastz = 0
end

function OnNewLine()
    if (linenumber == 1) then
        post.Text ("N")
        post.Number (lineNumber, "0000")
        lineNumber = lineNumber + 10
    else
        post.Text (" ")
    end
end
local function round(x, n)--added by TLC
--n = math.pow(10, n or 0)
    x = x * 100
    if x >= 0 then x = math.floor(x + 0.5) else x = math.ceil(x - 0.5) end
    return x / n
end

function OnFinish()
   finalCut = true
   endXRND = round(endX, 100)
	endYRND = round(endY, 100)
	curXRND = round(currentX, 100)
	curYRND = round(currentY, 100)

  if (endXRND == curXRND) and (endYRND == curYRND) then --see if the current X and Y position is the same final move
	   post.Text (" (No Parking values detected.  Moving back to zero, zero)\n ")
	   endX = 0
	   endY = 0
   else
	   post.Text (" (End of job , noving to predefined Parking position)\n ")
   end
	offX = 0
   offY = 0
   offZ = 0
   OnRapid()--make the final rapid move
   --post.Text(torchOffCode)
   post.Eol()
   post.Text (" M5 M30\n")	
end


function OnRapid()
    if(endX < 1e17 and endY < 1e17) then --don't update the distance moved if X or Y are unknown
        local len = math.hypot((endX + offX)-currentX , (endY + offY)-currentY)
        dist = dist + len
	end
	
	post.ModalText (" G0 ")
	post.ModalNumber (" X", (endX + offX) * scale, "0.000")
   post.ModalNumber (" Y", (endY + offY) * scale, "0.000")
   finalCut = false
    post.Eol()
end -- end on Rapid Function


function OnMove()
    local len = math.hypot(endX - currentX , endY - currentY)
    dist = dist + len
    if (toolName == "CenterPunch") then
        -- do nothing
    else
        if(toolClass == "MarkerTool") then
            post.ModalText (" G1")
            post.ModalNumber (" X", (endX + offX) * scale, "0.000")
            post.ModalNumber (" Y", (endY + offY) * scale, "0.000")
        else
            post.ModalText (" G1")
            post.ModalNumber (" X", (endX + offX) * scale, "0.000")
            post.ModalNumber (" Y", (endY + offY) * scale, "0.000")
            --post.ModalNumber (" F", feedRate * scale, "0.0##")
        end
        post.Eol()
    end
    if (fullTAP > 0 ) then
        if (softPierce >0 ) then
            piercePlunge = 1
            piercePlunge = (softPierce /100)
            feedRate2 = (feedRate * piercePlunge) -- lower the feedrate for soft pierce
        end
    else
        feedRate2 = feedRate
    end  -- end TAP
    --post.ModalNumber (" F", feedRate * scale, "0.0###")
    post.Eol()

end --end of OnMove function


function OnArc()
    local radius = math.hypot(currentX - arcCentreX, currentY - arcCentreY)
    dist = dist + radius * math.abs(arcAngle)
    if(arcAngle <0) then
        post.ModalText (" G3")
    else
        post.ModalText (" G2")
    end
    post.ModalNumber (" X", (endX + offX) * scale, "0.000")
    post.ModalNumber (" Y", (endY + offY) * scale, "0.000")
    post.Text (" I")
    post.Number ((arcCentreX - currentX) * scale, "0.000")
    post.Text (" J")
    post.Number ((arcCentreY - currentY) * scale, "0.000")
    --post.ModalNumber (" F", feedRate* scale, "0.0###")
    post.Eol()
end -- end OnArcfunction



function OnPenDown()
    if(toolClass == "MarkerTool") or (toolClass == "DrillTool") then
        if(toolClass == "MarkerTool") then
            punchDown = true
        end
        if (toolName =="CenterPunch" ) then
            if (firstRef == true) then --this runs a reference at the first but not afterwards
                Reference()
            end
            --post.Text(" M7\n")
        else --its not special center punch tool
            if (toolClass == "DrillTool") then --- which is a plasma peck process - no offset
                if (firstRef == true) then
                    Reference()
                    offX = 0
                    offY = 0
                    offZ = 0
                    post.Text (" M5")
                    post.Eol()
                    offZ = (drillStart/(-1) )
                    if (peckPierce ) then
                        post.Text (" G4 P", peckPierce)
                        post.Text ("  (Peck delay time)")
                        post .Eol()
                    end
                else-- not first ref
                    if (peckPierce ) then
                        post.Text (" G4 P", peckPierce)
                        post.Text ("  (Peck delay time)")
                        post .Eol()
                    end
                end --end first ref check
            else -- it is not a a Drill Tool so it is an engraver/plate marker
                if (firstRef == true) then--this is for engraving lines and char with scriber offsets
                    Reference()--use the center of the torch as a probe for touch off then offset XYand Z
                    offX = scriberX
                    offY = scriberY
                    offZ = scriberZ
				
                    post.Text (" (plate marker - engrave tool)")
                    post.Eol()
				        post.NonModalNumber ("(Marker: X offset = " , scriberX * scale, "0.000")
				        post.NonModalNumber ("  Marker: Y offset = " , scriberY * scale, "0.000")
				        post.Text (")")
				        post.Eol()
                end	--end if first ref
								
                post.Text (" G0 ")--this is not an onrapid move so the movements have to be defined
                post.ModalNumber (" X", (currentX + offX) * scale, "0.000")
                post.ModalNumber (" Y", (currentY + offY) * scale, "0.000")
				    post.Text (" (move to scriber offsets)")
                post.Eol()
				    post.Text(" (turn on Plate Marker)")
				    post.Eol()
				
            end -- end  if plasma drill tool
        end -- end center punch loop
    else -- not a marker or drill tool or plate engraver (maybe a Flametool?)
        if (firstRef) or (dist >= refDistance) then
            dist = 0
            Reference()
 			   offX = 0
            offY = 0
            offZ = 0
        end
		    if (fullTAP == 1) and (softPierce > 0) and (softPierce < 100) then -- turn off the DTHC but set the current to softpierce before the torch fires
	 		    softPierceRND = round(softPierce,10)
		    end
        if (preheat > 0) then
            post.Text ("\n G4 P")
            post.Number (preheat,"0.###")
            post.Eol()
        end
    end  --end outer loop

end --end OnPenDown function


function Reference()
  if (toolClass == "FlameTool") then
		   
		   post.Text ("(****************************************)\n")
		   post.Text (" (Flame tools do not do an auto touch off)\n")
		   
		   return
	end
   post.Text (" F#<_hal[plasmac.cut-feed-rate]>\n")
   post.Text (" M3 S1\n") -- start cutting
 end --end ref function


function OnPenUp()
    if (toolClass == "MarkerTool") then
        if (punchDown == true) then
            post.ModalText(" M9\n")
            punchDown = false
			
        end
    else
	    if (toolClass == "DrillTool") then
  		   --skip the tiny extension
		else
          post.ModalText (" G1")--this is supposed to add a tiny segment before the M5
          post.ModalNumber (" X", (currentX + off2X) * scale, "0.000")
          post.ModalNumber (" Y", (currentY + off2Y) * scale, "0.000")
          if (verbose == true) then
             post.Text (" (Add tiny extension)")
          end
		end
      post.Eol()
		if (toolClass == "PlasmaTool")then
        --post.Text(torchOffCode)
        post.Eol()
		end
    post.Text (" M5\n")
    end -- end marker tool
end --end OnPenUp function


function OnNewOperation()
    newOp = true
    post.Text (" (Operation: ", operationName, ")\n")
    if (plungeRate <= 0) then
        post.Warning("WARNING: Plunge rate is zero")
    end
    if (feedRate <= 0) then
        post.Warning("WARNING: Feed rate is zero")
    end
end--end function

 

function OnToolChange()
    offX = 0
    offY = 0
    offZ = 0
    
	if(toolClass == "FlameTool" ) then
    post.Text (" (Flame Cutting NO DTHC)\n")
	  post.Eol()
	  post.Text (" (Flame tool number: ", tool ,")")
	  post.Eol()
	  post.Text(" (Preheat: ", preheat , ") \n")
	  --post.Text(" (Feedrate: ", feedRate * scale , ") \n")
	  post.Text (" M0 \n")
	  post.Text (" (Make sure you are running an Oxy-Fuel CONFIG.)\n ")
	  post.Text (" (Hit the STOP button ")
	  post.Text (" Jog the Z down manually or use an adjustable holder)\n")
	  post.Text (" (touch the tip of the torch to the top of the metal, ")
	  post.Text (" and then hit the Z Home button)\n ")
	  post.Text (" (Hit the RUN FROM LINE to continue )\n")
	  return --skip the rest of the tool change section
	end
	
    if (toolClass =="DrillTool" ) then -- used as a plasma tool
    
         post.Text (" (tool number: ", tool ," ")
         post.Text (" Plasma peck drill )")
         post.Eol()
         post.Text (" ( Distance between Touch-offs: " , refDistance * scale, " ")
	      post.Text (" M190 P" , tool," (Load Plasmac Plasma Controller Tool #",tool,")\n")         
         post.Text (" M66 P3 L3 Q2  (Wait for the Plasmac Plasma Controller to acknowledge the change)\n")         
         post.Text ("M1\n")         
         if(scriberAxis and scriberAxis ~= currentZAxis) then
				OnRapid()
				currentZAxis = scriberAxis
         end
        if(fullTAP ~= 0) then --check for TAP being used
            if(presetAmps > 0) then
                if (verbose == true) then
                    post.Text(" ( Preset Cut Current: ",presetAmps, " Amps)")
                    post .Eol()
                end
            end
            if(presetPSI > 0) then
                if (verbose == true) then
                    post.Text(" ( Preset Air Pressure: ",presetPSI, " PSI)")
                    post .Eol()
                end
            else
                post.Text("(Using Auto Air Pressure)")
                post.Eol()
            end -- end preset psi
        end  --end fullTAP
        if(scriberAxis and scriberAxis ~= currentZAxis) then
            OnRapid()
            currentZAxis = scriberAxis
        end
        firstRef = true
		
    end -- drilltool
	
    if (toolClass== "PlasmaTool") then

        if (verbose == true) then
            if(presetVolts >0) then
                post.Text ( " (Preset Volts: ",presetVolts,") " )
            end
            if (fullTAP ~=0) then --check to see if full tap
                if(presetAmps >0) then
                    post.Text ( " (Preset AMPS: " ,presetAmps,") ")
                    post.Eol()
                else
                    post.Eol()
                end
                if(presetPSI>0) then
                    post.Text ( " ( Air Pressure Preset: " ,presetPSI,") ")
                    post.Eol()
                end
                if (softPierce > 0 ) then
                    softPierce2  = (softPierce / 10)
                    if (softPierce2 >= 10 ) then
                        softPierce2 = 0
                    end
                else
                    softPierce2 = 0
                end -- end softpierce
                if(softPierce2 > 0 ) then
                    post.Text ( " ( Soft Pierce : " ,softPierce," percent ) ")
                    post.Eol()
                else
                    post.Text ( " ( Soft pierce is off )")
                    post.Eol()
                end
            end -- end of fullTap check
            if(tipSize>0) then
                post.Text ( "( Suggested Tip Size: " ,tipSize," )")
                post.Eol()
            end
            if(minLength > 0 ) then
                post.Text ( " ( Min Cut Length for DTHC ON : " ,minLength ," units ) ")
                post.Eol()
            end
            post.Eol()
        end -- end of verbose check
	    	if(scriberAxis and scriberAxis == currentZAxis) then --always use Z as the Z axis
            OnRapid()
            currentZAxis = "Z"
        end
        if(presetVolts > 0) then
            if (verbose == true) then
                post.Text(" (Preset Volts set to ",presetVolts ," Volts)")
            end
            post.Eol()
        else
            post.Text ( "(No Preset Volts)\n" )
        end --end presetVolts
        if(fullTAP ~= 0) then --check for TAP being used
            if(presetAmps > 0) then
               --post.Text( " M68 E0 Q4" ,presetAmps, " ")
                if (verbose == true) then
                    post.Text (" ( Preset Amps set to ", presetAmps, " Amps)")
                end
                post.Eol()
                post.Text (" G4 P.1")
                post.Eol()
            end -- end presetAMPS
            if(presetPSI > 0) then
                 if (verbose == true) then
                    post.Text (" ( Air pressure set to ", presetPSI, " PSI)")
                end
                post.Eol()
                post.Text (" G4 P.1")
                post.Eol()
            else
                post.Text("(Default Air Pressure)")
                post.Eol()
            end --end presetPSI
        end --end check for fullTAP
 	     post.Text (" M190 P" , tool," (Load Plasmac Plasma Controller Tool #",tool,")\n")
        post.Text (" M66 P3 L3 Q2  (Wait for the Plasmac Plasma Controller to acknowledge the change)\n")      
       if (warnings == true) then
            post.Text (" ( Settings Check)\n")
            post.Text (" ( ###########################)\n")
            post.Text (" ( Paused:  Check the Plasmac Plasma Controller Settings )\n")
            post.Text (" ( Hit RUN to continue)\n")
            post.Text (" ( ###########################)\n")
        else
            post.Text (" (Pause off)\n")
            post.Text ("( ###########################)\n")  
        end --end warnings
        post.Text (" M1\n")
    end -- end of plasma tool loop
	if(toolClass == "MarkerTool" ) then
     post.Text (" (Plate Marker NO DTHC)\n")
	  post.Text ("G4 P.1")
	  post.Eol()
	  if(scriberAxis and scriberAxis ~= currentZAxis) then --use scriberAxis for Z
		OnRapid()
		currentZAxis = scriberAxis
	   end
	end
    
		
end --end for toolchangefunction


function OnNewPart()
   post.Text(" (Part: ",partName,")\n");
end

function OnDrill()
     post.Text ("(Drill Process)\n")
     OnRapid()
     currentX = endX
     currentY = endY
     OnPenDown()
     OnPenUp()
     OnRapid()
end