#!/usr/bin/env python3
#
#    This is PNCconf, a graphical configuration editor for LinuxCNC
#    Copyright 2007 Jeff Epler <jepler@unpythonic.net>
#    Pncconf 1.1 revamped by Chris Morley 2014
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#    This builds the HAL files from the collected data.
#
import os
import time
import shutil

class HAL:
    def __init__(self,app):
        # access to:
        self.d = app.d  # collected data
        global SIG
        SIG = app._p    # private data (signal names)
        self.a = app    # The parent, pncconf
        global _PD
        _PD = app._p    # private data





    def write_halfile(self, base):
        def writebackup(origname):
            path, ext = os.path.splitext(origname)
            name = path.replace(base+"/","")
            print(base)
            print(path,name,ext)
            shutil.copy(origname ,os.path.join(base,"backups",name + str(time.time()).replace('.', '') + ext) )
        self._substitution_list = []
        axis_convert = ("x","y","z","a")
        halui_cmd_count = 0
        filename = os.path.join(base, self.d.machinename + ".hal")
        file = open(filename, "w")
        print(_("# Generated by PNCconf at %s") % time.asctime(), file=file)
        print(_("# Using LinuxCNC version:  %s") % self.d.linuxcnc_version, file=file)
        print(_("# If you make changes to this file, they will be"), file=file)
        print(_("# overwritten when you run PNCconf again"), file=file)
        print(file=file)
        if self.d.pyvcp and not self.d.frontend == _PD._AXIS and not self.d.frontend == _PD._QTPLASMAC:
            size = pos = geo = ""
            if self.d.pyvcpposition or self.d.pyvcpsize:
                if self.d.pyvcpposition:
                    pos = "+%d+%d"% (self.d.pyvcpxpos,self.d.pyvcpypos)
                if self.d.pyvcpsize:
                    size = "%dx%d"% (self.d.pyvcpwidth,self.d.pyvcpheight)
                geo = " -g %s%s"%(size,pos)
            print("loadusr -Wn pyvcp pyvcp%s -c pyvcp [DISPLAY](PYVCP)"%(geo), file=file)
        if self.d.gladevcp and self.d.standalonegvcp:
            fmax = geo = pos = size =  ""
            if self.d.gladevcpposition or self.d.gladevcpsize:
                if self.d.gladevcpposition:
                    pos = "+%d+%d"% (self.d.gladevcpxpos,self.d.gladevcpypos)
                if self.d.gladevcpsize:
                    size = "%dx%d"% (self.d.gladevcpwidth,self.d.gladevcpheight)
                geo = " -g %s%s"%(size,pos)
            if self.d.gladevcpforcemax: fmax = " -m True"
            theme = self.d.gladevcptheme
            if theme == "Follow System Theme":theme = ""
            else: theme = " -t "+theme
            print("loadusr -Wn gladevcp gladevcp -c gladevcp%s%s%s -H gvcp_call_list.hal gvcp-panel.ui"%(theme,fmax,geo), file=file)
        print("loadrt [KINS]KINEMATICS", file=file)
        # qtplasmac requires 3 spindles
        if self.d.frontend == _PD._QTPLASMAC:
            print("loadrt [EMCMOT]EMCMOT servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS num_spindles=[TRAJ]SPINDLES", file=file)
        else:
            print("loadrt [EMCMOT]EMCMOT servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[KINS]JOINTS", file=file)
        # pre process mesa commands
        mesa_load_cmnd,mesa_read_cmnd,mesa_write_cmnd = self.a.hostmot2_command_string(substitution = self.d.useinisubstitution)
        if self.d.number_pports:
            # pre process pport commands
            pport_load_cmnd,pport_read_cmnd,pport_write_cmnd = self.a.pport_command_string()
        # print(the mesa load commands)
        for i in mesa_load_cmnd:
            print("%s"%i, file=file)

        if self.d.number_pports>0:
            # print(the pport load commands)
            for i in pport_load_cmnd:
                print("%s"%i, file=file)


        if self.d.joystickjog:
            print("loadusr -W hal_input -KRAL %s\n"% self.d.usbdevicename, file=file)

        spindle_enc = counter = probe = pwm = pump = estop = False
        spindle_on = spindle_cw = spindle_ccw = False
        mist = flood = brake = at_speed = bldc = False
        cstart = abort = sstep = False
        if self.a.findsignal("s-encoder-a"):
            spindle_enc = True
        if self.a.findsignal("probe"):
            probe = True
        if self.a.findsignal("abort"):
            abort = True
        if self.a.findsignal("s-pwm-pulse"):
            pwm = True
        if self.a.findsignal("charge-pump"):
            pump = True
        if self.a.findsignal("cycle-start"):
            cstart = True
        if self.a.findsignal("estop-ext"):
            estop = True
        if self.a.findsignal("single-step"):
            sstep = True
        if self.a.findsignal("spindle-enable"):
            spindle_on = True
        if self.a.findsignal("spindle-cw"):
            spindle_cw = True
        if self.a.findsignal("spindle-ccw"):
            spindle_ccw = True
        if self.a.findsignal("coolant-mist"):
            mist = True
        if self.a.findsignal("coolant-flood"):
            flood = True
        if self.a.findsignal("spindle-brake"):
            brake = True
        if self.a.findsignal("spindle-at-speed"):
            at_speed = True
        for i in self.d.available_axes:
            if self.d[i+"bldc_option"]:
                bldc = True
                break
        chargepump = self.a.findsignal("charge-pump-out")
        # load PID component:
        # if axis needs PID- (has pwm signal) then add its letter to pidlist
        temp = ""
        for i in self.d.available_axes:
            #print("looking at available axis : ",i)
            #if not self.a.findsignal(i+"-encoder-a") and not self.a.findsignal(i+"-resolver"):
            #    continue
            temp = temp + "pid.%s,"%i
            tandemjoint = self.a.tandem_check(i)
            if tandemjoint:
                temp = temp + "pid.%s2,"%i
        # if user requested PID components add them to the list as well, starting at 0 and working up
        for i in range(0,self.d.userneededpid):
                temp=temp+"pid.%d,"% (i)
        pidlist = temp.rstrip(",")
        if not pidlist == "":
            print("loadrt pid names=%s"% pidlist, file=file)

        if bldc or self.d.userneededbldc:
            self.d._bldcconfigstring = ""
            if bldc:
                for i in self.d.available_axes:
                    temp = self.d[i+"bldc_config"]
                    #print(i,temp)
                    if temp:
                        self.d._bldcconfigstring = self.d._bldcconfigstring + temp + ","
            if self.d.userneededbldc:
                    self.d._bldcconfigstring = self.d._bldcconfigstring + self.d.userneededbldc + ","
            temp = self.d._bldcconfigstring.rstrip(",")
            if not temp == "":
                print("loadrt bldc cfg=%s"% temp, file=file)

        if (self.d.pyvcp and self.d.pyvcpconnect == 1) or self.d.gladevcp or self.d.userneededabs >0:
            self.d.absnames=""
            needed = False
            if self.d.gladevcp and self.d.spindlespeedbar: needed = True
            if self.d.pyvcphaltype == 1 and self.d.pyvcpconnect == 1 and self.d.pyvcp: needed = True
            if needed:
                self.d.absnames=self.d.absnames+"abs.spindle"
                if self.d.userneededabs >0:
                    self.d.absnames=self.d.absnames+","
            for i in range(0,self.d.userneededabs):
                self.d.absnames = self.d.absnames+"abs.%d"% (i)
                if i != self.d.userneededabs-1:
                    self.d.absnames = self.d.absnames+","
            if not self.d.absnames == "":
                print("loadrt abs names=%s"% self.d.absnames, file=file)

        if (self.d.pyvcp and self.d.pyvcpconnect == 1) or self.d.gladevcp or self.d.userneededlowpass >0:
            self.d.lowpassnames=""
            needed = False
            for i in range(0,self.d.userneededlowpass):
                self.d.lowpassnames = self.d.lowpassnames+"lowpass.%d,"% (i)
            if self.d.pyvcphaltype == 1 and self.d.pyvcpconnect == 1 and self.d.pyvcp: needed = True
            if self.d.gladevcp and self.d.spindlespeedbar: needed = True
            if needed:
                self.d.lowpassnames=self.d.lowpassnames+"lowpass.spindle"
            temp = self.d.lowpassnames.rstrip(",")
            self.d.lowpassnames = temp
            if not self.d.lowpassnames == "":
                print("loadrt lowpass names=%s"% temp, file=file)

        pytest = self.d.pyvcp and self.d.pyvcphaltype == 1 and self.d.pyvcpconnect == 1
        gladetest = self.d.gladevcp and self.d.spindlespeedbar
        self.d.scalenames=[]
        names=''
        if spindle_enc and (pytest or gladetest):
            self.d.scalenames.append("scale.spindle")
        if self.d.suseoutputrange2:
            self.d.scalenames.append("scale.gear")
        if self.d.userneededscale >0:
            for i in range(0,self.d.userneededscale):
                self.d.scalenames.append("scale.%d"% (i))
        if not self.d.scalenames == []:
            for num,temp in enumerate(self.d.scalenames):
                if num ==0:
                    names+='%s'%temp
                else:
                    names+=',%s'%temp
            print("loadrt scale names=%s"% names, file=file)
        if pump:
            print("loadrt charge_pump", file=file)
        if not at_speed and self.d.suseatspeed:
            print("loadrt near", file=file)
        if self.d.classicladder:
            print(("loadrt classicladder_rt numPhysInputs=%d numPhysOutputs=%d numS32in=%d"
                          " numS32out=%d numFloatIn=%d numFloatOut=%d numBits=%d numWords=%d") \
                          %(self.d.digitsin , self.d.digitsout , self.d.s32in, self.d.s32out, self.d.floatsin, self.d.floatsout,self.d.bitmem,self.d.wordmem), file=file)

        # load mux16
        self.d.mux16names=""
        for i in range(0,self.d.userneededmux16):
            self.d.mux16names = self.d.mux16names+"mux16.%d,"% (i)
        if self.d.joystickjog:
           self.d.mux16names = self.d.mux16names+"jogspeed,"
        if self.d.externalmpg:
            self.d.mux16names = self.d.mux16names+"jogincr,"
        if self.d.externalfo:
            self.d.mux16names = self.d.mux16names+"foincr,"
        if self.d.externalmvo:
            self.d.mux16names = self.d.mux16names+"mvoincr,"
        if self.d.externalso:
            self.d.mux16names = self.d.mux16names+"soincr,"
        if self.d.scaleselect:
            self.d.mux16names = self.d.mux16names+"ratio_select,"
        temp = self.d.mux16names.rstrip(",")
        self.d.mux16names = temp
        if temp:
            print("loadrt mux16 names=%s"% (self.d.mux16names), file=file)

        # qtplasmac requires plasmac.comp
        if self.d.frontend == _PD._QTPLASMAC:
            print("loadrt plasmac", file=file)

        # load user custom components
        for i in self.d.loadcompbase:
            if i == '': continue
            else:
                print(i, file=file)
        for i in self.d.loadcompservo:
            if i == '': continue
            else:
                print(i, file=file)

        print(file=file)
        # print(parport read commands)
        if self.d.number_pports:
            for i in pport_read_cmnd:
                print("%s"%i, file=file)

        if pump: print("addf charge-pump servo-thread", file=file)

        for i in self.d.addcompbase:
            if not i == '':
                print(i +" base-thread", file=file)

        # print(mesa read commands)
        if self.d.number_mesa:
            for i in mesa_read_cmnd:
                print("%s"%i, file=file)

        print("addf motion-command-handler   servo-thread", file=file)
        print("addf motion-controller        servo-thread", file=file)

        if not pidlist == "":
            temp = pidlist.split(",")
            for i in temp:
                print("addf %s.do-pid-calcs       servo-thread"% i, file=file)

        if bldc or self.d.userneededbldc:
            temp=self.d._bldcconfigstring.split(",")
            for num,j in enumerate(temp):
                print("addf bldc.%d servo-thread"% num, file=file)

        if self.d.classicladder:
            print("addf classicladder.0.refresh servo-thread", file=file)

        # mux16 addf
        temp=self.d.mux16names.split(",")
        if not temp == ['']:
            for j in (temp):
                j ='{0:<24}'.format(j)
                print("addf %s servo-thread"% j, file=file)
        # scale addf
        needed = False
        if not self.d.scalenames == '':
            for j in self.d.scalenames:
                j ='{0:<24}'.format(j)
                print("addf %s servo-thread"% j, file=file)
        # abs addf
        needed = False
        if self.d.pyvcp and self.d.pyvcphaltype == 1 and self.d.pyvcpconnect == 1: needed = True
        if self.d.userneededabs > 0 or (self.d.gladevcp and self.d.spindlespeedbar): needed = True
        if needed:
            temp=self.d.absnames.split(",")
            for j in (temp):
                j ='{0:<24}'.format(j)
                print("addf %s servo-thread"% j, file=file)
        # lowpass addf
        needed = False
        if self.d.pyvcp and self.d.pyvcphaltype == 1 and self.d.pyvcpconnect == 1: needed = True
        if self.d.userneededlowpass > 0 or (self.d.gladevcp and self.d.spindlespeedbar): needed = True
        if needed:
            temp=self.d.lowpassnames.split(",")
            for j in (temp):
                j ='{0:<24}'.format(j)
                print("addf %s servo-thread"% j, file=file)

        for i in self.d.addcompservo:
            if not i == '':
                print(i +" servo-thread", file=file)
        if not at_speed and self.d.suseatspeed:
            print("addf near.0                   servo-thread", file=file)
        # qtplasmac addf
        if self.d.frontend == _PD._QTPLASMAC:
            print("addf plasmac                  servo-thread", file=file)
        # print(parport write commands)
        if self.d.number_pports:
            for i in pport_write_cmnd:
                print("%s"%i, file=file)
        if self.d.number_mesa:
            # print(mesa write commands)
            for i in mesa_write_cmnd:
                print("%s"%i, file=file)

        if chargepump:
            steppinname = self.a.make_pinname(chargepump, substitution = self.d.useinisubstitution)
            print(file=file)
            print(_("# ---Chargepump StepGen: 10000 velocity-cmd = 10Khz square wave output---"), file=file)
            print(file=file)
            print("setp   " + steppinname + ".dirsetup        100", file=file)
            print("setp   " + steppinname + ".dirhold         100", file=file)
            print("setp   " + steppinname + ".steplen         100", file=file)
            print("setp   " + steppinname + ".stepspace       100", file=file)
            print("setp   " + steppinname + ".step_type       2", file=file)
            print("setp   " + steppinname + ".control-type    1", file=file)
            print("setp   " + steppinname + ".maxaccel        0", file=file)
            print("setp   " + steppinname + ".maxvel          0", file=file)
            print("setp   " + steppinname + ".position-scale  1", file=file)
            print("setp   " + steppinname + ".velocity-cmd    10000", file=file)
            print(file=file)
            print("net x-enable                                 => " + steppinname +".enable", file=file)

        # do the qtplasmac connections and preferences file
        if self.d.frontend == _PD._QTPLASMAC:
            self.qtplasmac_connections(file, base)
            prefsfile = os.path.join(base, self.d.machinename + ".prefs")
            self.qtplasmac_prefs(prefsfile)

        print(file=file)
        self.connect_output(file)
        print(file=file)
        self.connect_input(file)
        print(file=file)

        ##############################################################
        # connect joints
        ##############################################################
        # self.d.axes:
        # 0 = xyz
        # 1 = xz
        # 2 = xyza

        if not self.d.axes in(0,1,2):
            print('error in number of axis identity: ', self.d.axes)
            return
        jnum = 0
        coords = ['x']
        # Always add X axis
        self.connect_joint(file, jnum, 'x')
        tandemjoint = self.a.tandem_check('x')
        if tandemjoint:
            jnum += 1
            coords.append('x2')
            self.connect_joint(file, jnum, 'x2')

        # Maybe add Y Axis ###################
        if self.d.axes in(0,1):
            jnum += 1
            coords.append('y')
            self.connect_joint(file, jnum, 'y')
            tandemjoint = self.a.tandem_check('y')
            if tandemjoint:
                jnum += 1
                coords.append('y2')
                self.connect_joint(file, jnum, 'y2')

        # Always add Z Axis ##################
        jnum += 1
        coords.append('z')
        self.connect_joint(file, jnum, 'z')
        tandemjoint = self.a.tandem_check('z')
        if tandemjoint:
            jnum += 1
            coords.append('z2')
            self.connect_joint(file, jnum, 'z2')

        # Maybe add A axis ###################
        if self.d.axes == 1:
            jnum += 1
            coords.append('a')
            self.connect_joint(file, jnum, 'a')
            tandemjoint = self.a.tandem_check('a')
            if tandemjoint:
                jnum += 1
                coords.append('a2')
                self.connect_joint(file, jnum, 'a2')

        # qtplasmac doesn't require these:
        if self.d.frontend != _PD._QTPLASMAC:
            # usually add Spindle ##################
            if self.d.include_spindle:
                self.connect_joint(file, 0, 's') # 9 for [SPINDLE_9]

            print(file=file)
            print("#******************************", file=file)
            print(_("# connect miscellaneous signals"), file=file)
            print("#******************************", file=file)
            print(file=file)
            print(_("#  ---HALUI signals---"), file=file)
            print(file=file)

            for axletter in coords:
                if len(axletter) == 1:
                    # support for KINEMATICS_IDENTITY kins only
                    # Assumption: gui uses halui teleop jogging for KINEMATICS_IDENTITY configs
                    #             (axis gui does this for joints_axes)
                    print("net axis-select-%s  halui.axis.%s.select"% (axletter,axletter), file=file)
                    print("net jog-%s-pos      halui.axis.%s.plus"% (axletter,axletter), file=file)
                    print("net jog-%s-neg      halui.axis.%s.minus"% (axletter,axletter), file=file)
                    print("net jog-%s-analog   halui.axis.%s.analog"% (axletter,axletter), file=file)
                    # joints only items (no corresponding axis item):
                    print("net %s-is-homed     halui.joint.%d.is-homed"% (axletter,coords.index(axletter)), file=file)
                else:
                    print("net %s-is-homed    halui.joint.%d.is-homed"% (axletter,coords.index(axletter)), file=file)

            print("net jog-selected-pos      halui.axis.selected.plus", file=file)
            print("net jog-selected-neg      halui.axis.selected.minus", file=file)
            print("net spindle-manual-cw     halui.spindle.0.forward", file=file)
            print("net spindle-manual-ccw    halui.spindle.0.reverse", file=file)
            print("net spindle-manual-stop   halui.spindle.0.stop", file=file)
            print("net machine-is-on         halui.machine.is-on", file=file)
            print("net jog-speed             halui.axis.jog-speed", file=file)
            print("net MDI-mode              halui.mode.is-mdi", file=file)
            if not self.d.frontend == _PD._TOUCHY and cstart == True:
                print("net cycle-start           halui.program.run", file=file)
            if sstep == True:
                print("net single-step           halui.program.step", file=file)
            if abort == True:
                print("net abort                 halui.abort", file=file)
            print(file=file)
            if pump:
                print(_("#  ---charge pump signals---"), file=file)
                print("net estop-out       =>  charge-pump.enable", file=file)
                print("net charge-pump     <=  charge-pump.out", file=file)
                print(file=file)
            print(_("#  ---coolant signals---"), file=file)
            print(file=file)
            print("net coolant-mist      <=  iocontrol.0.coolant-mist", file=file)
            print("net coolant-flood     <=  iocontrol.0.coolant-flood", file=file)
            print(file=file)
            print(_("#  ---probe signal---"), file=file)
            print(file=file)
            print("net probe-in     =>  motion.probe-input", file=file)
            print(file=file)
        if self.d.externaljog:
            print(_("# ---jog button signals---"), file=file)
            print(file=file)
            print("sets    jog-speed %f"% self.d.jograpidrate, file=file)
            print(file=file)
        if self.d.joystickjog:
            print(_("# ---USB device jog button signals---"), file=file)
            print(file=file)
            print(_("# connect selectable mpg jog speeds "), file=file)
            print("net jog-speed-a           =>  jogspeed.sel0", file=file)
            print("net jog-speed-b           =>  jogspeed.sel1", file=file)
            print("net jog-speed             <=  jogspeed.out-f", file=file)
            print("setp    jogspeed.in00          %f"% (self.d.joystickjograpidrate0), file=file)
            print("setp    jogspeed.in01          %f"% (self.d.joystickjograpidrate1), file=file)
            print("setp    jogspeed.in02          %f"% (self.d.joystickjograpidrate2), file=file)
            print("setp    jogspeed.in03          %f"% (self.d.joystickjograpidrate3), file=file)
            if not self.d.joycmdrapida =="":
                print("net jog-speed-a           <=  %s"% (self.d.joycmdrapida), file=file)
            if not self.d.joycmdrapidb =="":
                print("net jog-speed-b           <=  %s"% (self.d.joycmdrapidb), file=file)
            for axletter in axis_convert:
                if axletter in self.d.available_axes:
                    pin_pos = self.d["joycmd"+axletter+"pos"]
                    pin_neg = self.d["joycmd"+axletter+"neg"]
                    if not pin_pos == "" and not pin_neg =="":
                        print("net jog-%s-pos            %s"% (axletter,pin_pos), file=file)
                        print("net jog-%s-neg            %s"% (axletter,pin_neg), file=file)
                    pin_analog = self.d["joycmdanalog"+axletter]
                    if not pin_analog == "":
                        print("net jog-%s-analog         %s"% (axletter,pin_analog), file=file)
            print(file=file)

        # check for shared MPG
        pinname = self.a.make_pinname(self.a.findsignal("select-mpg-a"), substitution = self.d.useinisubstitution)
        if pinname:
            print("shared MPG", pinname)
            ending = ""
            if "enc" in pinname: ending = ".count"
            print(_("# ---jogwheel signals to mesa encoder - shared MPG---"), file=file)
            print(file=file)
            print("net axis-selected-count     <=  %s%s"% (pinname,ending), file=file)
            if 'encoder' in ending:
                print("setp    %s.filter true" % pinname, file=file)
                print("setp    %s.counter-mode true" % pinname, file=file)
            print(file=file)
            # was jogging MPG option selected?
            if self.d.externalmpg:
                    print(_("#  ---mpg signals---"), file=file)
                    print(file=file)
                    if not self.d.multimpg:
                        for axletter in axis_convert:
                            if axletter in self.d.available_axes:
                                print(_("#       for axis %s MPG") % axletter, file=file)
                                print("setp    axis.%s.jog-vel-mode 0" % axletter, file=file)
                                print("net selected-jog-incr    =>  axis.%s.jog-scale" % axletter, file=file)
                                print("net axis-select-%s       =>  axis.%s.jog-enable"% (axletter,axletter), file=file)
                                print("net axis-selected-count =>  axis.%s.jog-counts"% axletter, file=file)
                            print(file=file)
        # check for dedicated axis MPG jogging option
        for axletter in axis_convert:
            if axletter in self.d.available_axes:
                pinname = self.a.make_pinname(self.a.findsignal(axletter+"-mpg-a"), substitution = self.d.useinisubstitution)
                if pinname:
                    ending = ""
                    if "enc" in pinname: ending = ".count"
                    print(_("# ---jogwheel signals to mesa encoder - %s axis MPG---") % axletter, file=file)
                    print(file=file)
                    print("net %s-jog-count          <=  %s%s"% (axletter, pinname,ending), file=file)
                    if 'encoder' in ending:
                        print("setp    %s.filter true" % pinname, file=file)
                        print("setp    %s.counter-mode false" % pinname, file=file)
                    print(file=file)
                    if self.d.externalmpg:
                        print(_("#  ---mpg signals---"), file=file)
                        print(file=file)
                        if self.d.multimpg: # means MPG per axis
                            print("setp    axis.%s.jog-vel-mode 0" % axletter, file=file)
                            print("net %s-jog-enable         =>  axis.%s.jog-enable"% (axletter, axletter), file=file)
                            print("net %s-jog-count          =>  axis.%s.jog-counts" % (axletter, axletter), file=file)
                            print("net selected-jog-incr    =>  axis.%s.jog-scale" % axletter, file=file)
                            print("sets %s-jog-enable    true"% (axletter), file=file)
                            print(file=file)
        if self.d.externalmpg and not self.d.frontend == _PD._TOUCHY:# TOUCHY GUI sets its own jog increments:
            if self.d.incrselect :
                print(_("# connect selectable mpg jog increments "), file=file)
                print(file=file)
                print("net jog-incr-a           =>  jogincr.sel0", file=file)
                print("net jog-incr-b           =>  jogincr.sel1", file=file)
                print("net jog-incr-c           =>  jogincr.sel2", file=file)
                print("net jog-incr-d           =>  jogincr.sel3", file=file)
                print("net selected-jog-incr    <=  jogincr.out-f", file=file)
                if self.d.mpgdebounce:
                    print("    setp jogincr.debounce-time      %f"% self.d.mpgdebouncetime, file=file)
                print("    setp jogincr.use-graycode      %s"% self.d.mpggraycode, file=file)
                print("    setp jogincr.suppress-no-input %s" % self.d.mpgignorefalse, file=file)
                for i in range(0,16):
                    value = self.d["mpgincrvalue%d"% i]
                    print("    setp jogincr.in%02d          %f"% (i,value), file=file)
                print(file=file)
            else:
                print("sets selected-jog-incr     %f"% (self.d.mpgincrvalue0), file=file)
                print(file=file)

        # check for dedicated feed override MPG
        pinname = self.a.make_pinname(self.a.findsignal("fo-mpg-a"), substitution = self.d.useinisubstitution)
        if pinname:
            ending = ""
            if "enc" in pinname: ending = ".count"
            print(_("# ---feed override signals to mesa encoder - mpg---"), file=file)
            print(file=file)
            print("net fo-count     <=  %s%s"% (pinname,ending), file=file)
            if 'encoder' in ending:
                print("setp    %s.filter true" % pinname, file=file)
                print("setp    %s.counter-mode true" % pinname, file=file)
            print(file=file)
        # was feed override option selected? MPG or switch selected?
        if self.d.externalfo:
            if self.d.fo_usempg:
                print(_("# connect feed override increments - MPG"), file=file)
                print(file=file)
                print("    setp halui.feed-override.direct-value false", file=file)
                print("    setp halui.feed-override.scale .01", file=file)
                if pinname: # dedicated MPG
                    if self.a.findsignal("fo-enable"): # make it enable-able externally
                        print("net  fo-enable           => halui.feed-override.count-enable", file=file)
                    else:
                        print("    setp halui.feed-override.count-enable true", file=file)
                    print("net fo-count            =>  halui.feed-override.counts", file=file)
                else: # shared MPG
                    print("net fo-enable            => halui.feed-override.count-enable", file=file)
                    print("net axis-selected-count => halui.feed-override.counts", file=file)
                print(file=file)
            elif self.d.fo_useswitch:
                print(_("# connect feed override increments - switches"), file=file)
                print(file=file)
                print("    setp halui.feed-override.count-enable true", file=file)
                print("    setp halui.feed-override.direct-value true", file=file)
                print("    setp halui.feed-override.scale .01", file=file)
                print("net feedoverride-incr   =>  halui.feed-override.counts", file=file)
                print("net fo-incr-a           =>  foincr.sel0", file=file)
                print("net fo-incr-b           =>  foincr.sel1", file=file)
                print("net fo-incr-c           =>  foincr.sel2", file=file)
                print("net fo-incr-d           =>  foincr.sel3", file=file)
                print("net feedoverride-incr   <=  foincr.out-s", file=file)
                if self.d.fodebounce:
                    print("    setp foincr.debounce-time      %f"% self.d.fodebouncetime, file=file)
                print("    setp foincr.use-graycode      %s"% self.d.fograycode, file=file)
                print("    setp foincr.suppress-no-input %s" % self.d.foignorefalse, file=file)
                for i in range(0,16):
                    value = self.d["foincrvalue%d"% i]
                    print("    setp foincr.in%02d          %f"% (i,value), file=file)
                print(file=file)

        # check for dedicated max velocity MPG
        pinname = self.a.make_pinname(self.a.findsignal("mvo-mpg-a"), substitution = self.d.useinisubstitution)
        if pinname:
            ending = ""
            if "enc" in pinname: ending = ".count"
            print(_("# ---max velocity override signals to mesa encoder - mpg---"), file=file)
            print(file=file)
            print("net mvo-count     <=  %s%s"% (pinname,ending), file=file)
            if 'encoder' in ending:
                print("setp    %s.filter true" % pinname, file=file)
                print("setp    %s.counter-mode true" % pinname, file=file)
            print(file=file)
        # was max velocity override option selected? MPG or switch selected?
        if self.d.externalmvo:
            temp=[]
            for i in self.d.available_axes:
                temp.append(float(self.d[i+"maxvel"]))
            scale = max(temp)/100
            if self.d.mvo_usempg:
                print(_("# connect max velocity override increments - MPG"), file=file)
                print(file=file)
                print("    setp halui.max-velocity.direct-value false", file=file)
                print("    setp halui.max-velocity.scale %04f"% scale, file=file)
                if pinname: # dedicated MPG
                    if self.a.findsignal("mvo-enable"): # make it enable-able externally
                        print("net mvo-enable           =>  halui.max-velocity.count-enable", file=file)
                    else:
                        print("    setp halui.max-velocity.count-enable true", file=file)
                    print("net mvo-count            =>  halui.max-velocity.counts", file=file)
                else: # shared MPG
                    print("net mvo-enable           =>  halui.max-velocity.count-enable", file=file)
                    print("net axis-selected-count =>  halui.max-velocity.counts", file=file)
                print(file=file)
            elif self.d.mvo_useswitch:
                print(_("# connect max velocity override increments - switches"), file=file)
                print(file=file)
                print("    setp halui.max-velocity.count-enable true", file=file)
                print("    setp halui.max-velocity.direct-value true", file=file)
                print("    setp halui.max-velocity.scale %04f"% scale, file=file)
                print("net max-vel-override-incr   =>  halui.max-velocity.counts", file=file)
                print("net mvo-incr-a           =>  mvoincr.sel0", file=file)
                print("net mvo-incr-b           =>  mvoincr.sel1", file=file)
                print("net mvo-incr-c           =>  mvoincr.sel2", file=file)
                print("net mvo-incr-d           =>  mvoincr.sel3", file=file)
                print("net max-vel-override-incr   <=  mvoincr.out-s", file=file)
                if self.d.mvodebounce:
                    print("    setp mvoincr.debounce-time      %f"% self.d.mvodebouncetime, file=file)
                print("    setp mvoincr.use-graycode      %s"% self.d.mvograycode, file=file)
                print("    setp mvoincr.suppress-no-input %s" % self.d.mvoignorefalse, file=file)
                for i in range(0,16):
                    value = self.d["mvoincrvalue%d"% i]
                    print("    setp mvoincr.in%02d          %f"% (i,value), file=file)
                print(file=file)

        # check for dedicated spindle override MPG
        pinname = self.a.make_pinname(self.a.findsignal("so-mpg-a"), substitution = self.d.useinisubstitution)
        if pinname:
            ending = ""
            if "enc" in pinname: ending = ".count"
            print(_("# ---spindle override signals to mesa encoder - mpg---"), file=file)
            print(file=file)
            print("net so-count     <=  %s%s"% (pinname,ending), file=file)
            if 'encoder' in ending:
                print("setp    %s.filter true" % pinname, file=file)
                print("setp    %s.counter-mode true" % pinname, file=file)
            print(file=file)
        if self.d.externalso:
            if self.d.so_usempg:
                print(_("# connect spindle override increments - MPG"), file=file)
                print(file=file)
                print("    setp halui.spindle.0.override.direct-value false", file=file)
                print("    setp halui.spindle.0.override.scale .01", file=file)
                if pinname: # dedicated MPG
                    if self.a.findsignal("so-enable"): # make it enable-able externally
                        print("net so-enable             =>  halui.spindle.0.override.count-enable", file=file)
                    else:
                        print("    setp halui.spindle.0.override.count-enable true", file=file)
                    print("net so-count              =>  halui.spindle.0.override.counts", file=file)
                else: # shared MPG
                    print("net so-enable             =>  halui.spindle.0.override.count-enable", file=file)
                    print("net axis-selected-count  =>  halui.spindle.0.override.counts", file=file)
                print(file=file)
            elif self.d.so_useswitch:
                print(_("# connect spindle override increments "), file=file)
                print(file=file)
                print("    setp halui.spindle.0.override.count-enable true", file=file)
                print("    setp halui.spindle.0.override.direct-value true", file=file)
                print("    setp halui.spindle.0.override.scale .01", file=file)
                print("net spindleoverride-incr  =>  halui.spindle.0.override.counts", file=file)
                print("net so-incr-a             =>  soincr.sel0", file=file)
                print("net so-incr-b             =>  soincr.sel1", file=file)
                print("net so-incr-c             =>  soincr.sel2", file=file)
                print("net so-incr-d             =>  soincr.sel3", file=file)
                print("net spindleoverride-incr  <=  soincr.out-s", file=file)
                if self.d.sodebounce:
                    print("    setp soincr.debounce-time      %f"% self.d.sodebouncetime, file=file)
                print("    setp soincr.use-graycode      %s"% self.d.sograycode, file=file)
                print("    setp soincr.suppress-no-input %s" % self.d.soignorefalse, file=file)
                for i in range(0,16):
                    value = self.d["soincrvalue%d"% i]
                    print("    setp soincr.in%02d          %f"% (i,value), file=file)
                print(file=file)
        print(_("#  ---motion control signals---"), file=file)
        print(file=file)
        print("net in-position               <=  motion.in-position", file=file)
        print("net machine-is-enabled        <=  motion.motion-enabled", file=file)
        print(file=file)
        print(_("#  ---digital in / out signals---"), file=file)
        print(file=file)
        for i in range(4):
            dout = "dout-%02d" % i
            if self.a.findsignal(dout):
                comment = ""
                if self.d.frontend == _PD._QTPLASMAC and dout in ['dout-01','dout-02','dout-03']:
                    comment = "#qtplasmac uses digital output %s:\n#" % dout
                print("%snet %s     <=  motion.digital-out-%02d" % (comment, dout, i), file=file)
        for i in range(4):
            din = "din-%02d" % i
            if self.a.findsignal(din):
                print("net %s     =>  motion.digital-in-%02d" % (din, i), file=file)
        print(_("#  ---estop signals---"), file=file)
        print(file=file)
        print("net estop-out     <=  iocontrol.0.user-enable-out", file=file)
        if  self.d.classicladder and self.d.ladderhaltype == 1 and self.d.ladderconnect: # external estop program
            print(file=file)
            print(_("# **** Setup for external estop ladder program -START ****"), file=file)
            print(file=file)
            print("net estop-out     => classicladder.0.in-00", file=file)
            print("net estop-ext     => classicladder.0.in-01", file=file)
            print("net estop-strobe     classicladder.0.in-02   <=  iocontrol.0.user-request-enable", file=file)
            print("net estop-outcl      classicladder.0.out-00  =>  iocontrol.0.emc-enable-in", file=file)
            print(file=file)
            print(_("# **** Setup for external estop ladder program -END ****"), file=file)
        elif estop:
            print("net estop-ext     =>  iocontrol.0.emc-enable-in", file=file)
        else:
            print("net estop-out     =>  iocontrol.0.emc-enable-in", file=file)
        print(file=file)
        # qtplasmac doesn't require these:
        if self.d.frontend != _PD._QTPLASMAC:
            if self.d.toolchangeprompt:
                print(_("#  ---manual tool change signals---"), file=file)
                print(file=file)
                print("net tool-change-request    <= iocontrol.0.tool-change", file=file)
                print("net tool-change-confirmed  => iocontrol.0.tool-changed", file=file)
                print("net tool-number            <= iocontrol.0.tool-prep-number", file=file)
                print(file=file)

                if not self.d.frontend in (_PD._QTDRAGON,_PD._GMOCCAPY):
                    print(_("#  ---Use external manual tool change dialog---"), file=file)
                    print(file=file)
                    print("loadusr -W hal_manualtoolchange", file=file)
                    print("net tool-change-request    =>  hal_manualtoolchange.change", file=file)
                    print("net tool-change-confirmed  <=  hal_manualtoolchange.changed", file=file)
                    print("net tool-number            =>  hal_manualtoolchange.number", file=file)
                    print(file=file)

                if self.d.frontend == _PD._GMOCCAPY:
                    print(_("#  ---signals to show tool offset in the GUI---"), file=file)
                    print(file=file)
                    print("net tooloffset-x  <=  motion.tooloffset.x", file=file)
                    print("net tooloffset-z  <=  motion.tooloffset.z", file=file)
                    print(file=file)
                    gm = os.path.join(base, "gmoccapy_postgui.hal")
                    f1 = open(gm, "w")
                    print(_("# Generated by PNCconf at %s") % time.asctime(), file=f1)
                    print(_("# Using LinuxCNC version:  %s") % self.d.linuxcnc_version, file=f1)
                    print(_("# If you make changes to this file, they will be"), file=f1)
                    print(_("# overwritten when you run PNCconf again"), file=f1)
                    print(file=f1)
                    print(_("#  ---manual tool change signals to gmoccapy's dialog---"), file=f1)
                    print(file=f1)
                    print("net tool-change-request    => gmoccapy.toolchange-change", file=f1)
                    print("net tool-change-confirmed  <= gmoccapy.toolchange-changed", file=f1)
                    print("net tool-number            => gmoccapy.toolchange-number", file=f1)
                    print(file=f1)
                    print(_("#  ---signals to show tool offset in the GUI---"), file=f1)
                    print(file=f1)
                    print("net tooloffset-x  => gmoccapy.tooloffset-x", file=f1)
                    print("net tooloffset-z  => gmoccapy.tooloffset-z", file=f1)
                    print(file=f1)
                    print(_("#  ---spindle-at-speed indicator---"), file=f1)
                    print(file=f1)
                    print(_("net spindle-at-speed => gmoccapy.spindle_at_speed_led"), file=f1)
                    f1.close()
                elif self.d.frontend == _PD._QTDRAGON:
                    qt = os.path.join(base, "qtvcp_postgui.hal")
                    if not os.path.exists(qt):
                        f1 = open(qt, "w")
                        print(_("#  ---manual tool change signals to qtdragon's dialog---"), file=f1)
                        print(file=f1)
                        print("net tool-change-request    => hal_manualtoolchange.change", file=f1)
                        print("net tool-change-confirmed  <= hal_manualtoolchange.changed", file=f1)
                        print("net tool-number            => hal_manualtoolchange.number", file=f1)
                        f1.close()

                print(_("#  ---ignore tool prepare requests---"), file=file)
                print("net tool-prepare-loopback   iocontrol.0.tool-prepare      =>  iocontrol.0.tool-prepared", file=file)
                print(file=file)

            else:
                print(_("#  ---toolchange signals for custom tool changer---"), file=file)
                print(file=file)
                print("net tool-number             <=  iocontrol.0.tool-prep-number", file=file)
                print("net tool-change-request     <=  iocontrol.0.tool-change", file=file)
                print("net tool-change-confirmed   =>  iocontrol.0.tool-changed", file=file)
                print("net tool-prepare-request    <=  iocontrol.0.tool-prepare", file=file)
                print("net tool-prepare-confirmed  =>  iocontrol.0.tool-prepared", file=file)
                print(file=file)

        # qtplasmac tool change passthrough
        else:
            print(_("\n# ---QTPLASMAC TOOLCHANGE PASSTHROUGH---"), file=file)
            print("net tool:change iocontrol.0.tool-change  => iocontrol.0.tool-changed", file=file)
            print("net tool:prep   iocontrol.0.tool-prepare => iocontrol.0.tool-prepared", file=file)
        if self.d.classicladder:
            print(file=file)
            if self.d.modbus:
                print(_("# Load Classicladder with modbus master included (GUI must run for Modbus)"), file=file)
                print(file=file)
                print("loadusr classicladder --modmaster custom.clp", file=file)
                print(file=file)
            else:
                print(_("# Load Classicladder without GUI (can reload LADDER GUI in AXIS GUI"), file=file)
                print(file=file)
                print("loadusr classicladder --nogui custom.clp", file=file)
                print(file=file)
            if self.d.laddertouchz:
                othercmds = self.d.gladevcphaluicmds
                print(_("#  --- Classicladder signals for Z axis Auto touch off program---"), file=file)
                print("net auto-touch-z    =>   classicladder.0.in-00", file=file)
                print("net MDI-mode        =>   classicladder.0.in-01", file=file)
                print("net in-position     =>   classicladder.0.in-02", file=file)
                print("net z-touchoff-cmd       classicladder.0.out-00   =>    halui.mdi-command-%02d"% (othercmds), file=file)
                print("net z-zero-cmd           classicladder.0.out-01   =>    halui.mdi-command-%02d"% (othercmds +1), file=file)
                print("net rapid-away-cmd       classicladder.0.out-02   =>    halui.mdi-command-%02d"% (othercmds +2), file=file)

        gvcp_options_filename = os.path.join(base, "gvcp_options.hal")
        gvcp_call_filename  = os.path.join(base, "gvcp_call_list.hal")
        if self.d.gladevcp and self.d.frontend != _PD._QTPLASMAC:
                # write the call_list
                # the call_list allows multiple hal files to be loaded post gladevcp
                # this simplifies the problem of overwriting the users custom HAL code
                # when they change gvcp sample options
                # if the user asks for existing instead of sample then if the call_list file exists
                # don't overwrite it
            if (not self.d.gladesample and not os.path.exists(gvcp_call_filename)) or self.d.gladesample:
                f1 = open(gvcp_call_filename, "w")
                print(_("# These files are loaded post gladeVCP, in the order they appear"), file=f1)
                print(file=f1)
                if self.d.gladesample:
                    print("source gvcp_options.hal", file=f1)
                print("source custom_gvcp.hal", file=f1)
                # write hal file for sample options selected
            if self.d.gladesample:
                    # copy glade panel from temp file to config
                gvcp = os.path.join(base, "gvcp-panel.ui")
                if os.path.exists(gvcp):
                    writebackup(gvcp)
                shutil.copy2('/tmp/gvcp-panel.ui', gvcp)
                    # write gvcp options HAL file
                f1 = open(gvcp_options_filename, "w")
                print(_("# _DO NOT_ include your HAL commands here."), file=f1)
                print(_("# Put custom HAL commands in custom_gvcp.hal"), file=f1)
                print(file=f1)
                if self.d.spindlespeedbar:
                    print(_("# **** Setup of spindle speed display using gladevcp ****"), file=f1)
                    print(file=f1)
                    if spindle_enc:
                        print(("net spindle-fb-rpm-abs-filtered       =>   gladevcp.spindle-speed"), file=f1)
                    else:
                        print(("net spindle-vel-cmd-rpm-abs    =>    gladevcp.spindle-speed"), file=f1)
                if self.d.spindleatspeed:
                    print(("net spindle-at-speed        =>    gladevcp.spindle-at-speed-led"), file=f1)
                i = 0
                print(_("# **** Setup GLADE MDI buttons ****"), file=f1)
                print(("net machine-is-on          =>    gladevcp.button-box-active"), file=f1)
                for temp in(("zerox","zero-x","x"),("zeroy","zero-y","y"),("zeroz","zero-z","z"),("zeroa","zero-a","a")):
                    if self.d[temp[0]]:
                        print(("# **** MDI Command %d - %s-axis is specified in the machine named INI file under [HALUI] heading ****"%(i,temp[1])), file=f1)
                        print(("net MDI-%s            gladevcp.%s          =>  halui.mdi-command-%02d")%(temp[0],temp[1],i), file=f1)
                        if self.d.require_homing:
                            print(("net %s-is-homed      =>    gladevcp.%s-active"% (temp[2],temp[1])), file=f1)
                        else:
                            print(("net machine-is-on          =>    gladevcp.%s-active"% (temp[1])), file=f1)
                        print(file=f1)
                        i += 1
                if self.d.autotouchz:
                    print(_("# **** Z axis touch-off button - requires the touch-off classicladder program ****"), file=f1)
                    print(("net auto-touch-z      <=    gladevcp.auto-touch-z"), file=f1)
                    print(("net MDI-mode          =>    gladevcp.auto-touch-z-active"), file=f1)
                    print(file=f1)
        else:
            # gvcp was not selected remove any existing related HAl files
            if os.path.exists(gvcp_options_filename):
                os.remove(gvcp_options_filename)
            if os.path.exists(gvcp_call_filename):
                os.remove(gvcp_call_filename)

        if self.d.pyvcp and self.d.frontend != _PD._QTPLASMAC:
            vcp = os.path.join(base, "pyvcp-panel.xml")
            if not os.path.exists(vcp):
                f1 = open(vcp, "w")
                print("<?xml version='1.0' encoding='UTF-8'?>", file=f1)
                print("<!-- ", file=f1)
                print(_("Include your PyVCP panel here.\n"), file=f1)
                print("-->", file=f1)
                print("<pyvcp>", file=f1)
                print("</pyvcp>", file=f1)

        # If the user asked for pyvcp sample panel add the HAL commands too
        pyfilename = os.path.join(base, "pyvcp_options.hal")
        if self.d.pyvcp and self.d.pyvcphaltype == 1 and self.d.pyvcpconnect and self.d.frontend != _PD._QTPLASMAC: # spindle speed display
            f1 = open(pyfilename, "w")
            print(_("# _DO NOT_ include your HAL commands here."), file=f1)
            print(_("# Put custom HAL commands in custom_postgui.hal"), file=f1)
            print(_("""# The commands in this file are run after the GUI loads"""), file=f1)
            print(file=f1)
            print(_("# **** Setup of spindle speed display using pyvcp -START ****"), file=f1)
            print(file=f1)
            if spindle_enc:
                print(("net spindle-fb-rpm-abs-filtered       =>   pyvcp.spindle-speed"), file=f1)
            else:
                print(("net spindle-vel-cmd-rpm-abs    =>    pyvcp.spindle-speed"), file=f1)
            print(("net spindle-at-speed        =>    pyvcp.spindle-at-speed-led"), file=f1)
            print(file=f1)
            print(_("# **** Setup of spindle speed display using pyvcp -END ****"), file=f1)
            print(file=f1)
        else:
            if os.path.exists(pyfilename):
                os.remove(pyfilename)

        # pncconf adds a custom.hal and custom_postgui.hal file if one is not present
        if self.d.frontend != _PD._QTPLASMAC:
            customfiles = "custom","custom_postgui","shutdown","custom_gvcp"
        else:
            customfiles = "custom","custom_postgui","shutdown"
        for i in customfiles:
            custom = os.path.join(base, i+".hal")
            if not os.path.exists(custom):
                f1 = open(custom, "w")
                print(_("# Include your %s HAL commands here")%i, file=f1)
                print(_("# This file will not be overwritten when you run PNCconf again"), file=f1)

        if self.d.frontend == _PD._TOUCHY:# TOUCHY GUI
                touchyfile = os.path.join(base, "touchy.hal")
            #if not os.path.exists(touchyfile):
                f1 = open(touchyfile, "w")
                print(_("# These commands are required for Touchy GUI"), file=f1)
                print(("net cycle-start          =>   touchy.cycle-start"), file=f1)
                print(("net abort                =>   touchy.abort"), file=f1)
                print(("net single-step          =>   touchy.single-block"), file=f1)
                print(("net selected-jog-incr    <=   touchy.jog.wheel.increment"), file=f1)
                print(("net axis-selected-count =>   touchy.wheel-counts"), file=f1)
                print(("net jog-x-pos  => touchy.jog.continuous.x.positive"), file=f1)
                print(("net jog-x-neg  => touchy.jog.continuous.x.negative"), file=f1)
                print(("net jog-y-pos  => touchy.jog.continuous.y.positive"), file=f1)
                print(("net jog-y-neg  => touchy.jog.continuous.y.negative"), file=f1)
                print(("net jog-z-pos  => touchy.jog.continuous.z.positive"), file=f1)
                print(("net jog-z-neg  => touchy.jog.continuous.z.negative"), file=f1)
                print(("net quillup  => touchy.quill-up"), file=f1)
                for axletter in enumerate(axis_convert):
                    if axletter in self.d.available_axes:
                        print("net axis-select-%s   <=   touchy.jog.wheel.%s"% (axletter, axletter), file=f1)

        # include Automation Direct GS2 VFD HAL file
        fname = os.path.join(base, "gs2_vfd.hal")
        if self.d.serial_vfd and self.d.gs2_vfd:
            self.write_gs2_vfd(fname)
        else:
            if os.path.exists(fname):
                os.remove(fname)

        # include Mitsubishi FR VFD HAL file
        fname = os.path.join(base, "mitsub_vfd.hal")
        if self.d.serial_vfd and self.d.mitsub_vfd:
            self.write_mitsub_vfd(fname)
        else:
            if os.path.exists(fname):
                os.remove(fname)

        if self.d.classicladder:
           if not self.d.laddername == "custom.clp":
                filename = os.path.join(_PD.DISTDIR, "configurable_options/ladder/%s" % self.d.laddername)
                original = os.path.expanduser("~/linuxcnc/configs/%s/custom.clp" % self.d.machinename)
                if os.path.exists(filename): # check for the master file to copy from
                  if os.path.exists(original):
                     #print("custom file already exists")
                     writebackup(original)
                     #shutil.copy( original,os.path.expanduser("~/linuxcnc/configs/%s/backups/custom_backup.clp" % self.d.machinename) )
                     print("made backup of existing custom")
                  shutil.copy( filename,original)
                  #print("copied ladder program to usr directory")
                  #print("%s" % filename)
                else:
                     print("Master or temp ladder files missing from configurable_options dir")
        if self.d.pyvcp and not self.d.pyvcpexist and self.d.frontend != _PD._QTPLASMAC:
           panelname = os.path.join(_PD.DISTDIR, "configurable_options/pyvcp/%s" % self.d.pyvcpname)
           originalname = os.path.expanduser("~/linuxcnc/configs/%s/pyvcp-panel.xml" % self.d.machinename)
           if os.path.exists(panelname):
                  if os.path.exists(originalname):
                     #print("custom PYVCP file already exists")
                     writebackup(originalname)
                     #shutil.copy( originalname,os.path.expanduser("~/linuxcnc/configs/%s/backups/pyvcp-panel_backup.xml" % self.d.machinename) )
                     print("made backup of existing custom")
                  shutil.copy( panelname,originalname)
                  #print("copied PYVCP program to usr directory")
                  #print("%s" % panelname)
           else:
                  print("Master PYVCP file: %s missing from configurable_options dir"% self.d.pyvcpname)
        file.close()
        self.d.add_md5sum(filename)

    def write_gs2_vfd(self,filename):
        p = self.d.gs2_vfd_port
        b = self.d.gs2_vfd_baud
        s = int(self.d.gs2_vfd_slave)
        a = int(self.d.gs2_vfd_accel)
        d = int(self.d.gs2_vfd_deaccel)
        f1 = open(filename, "w")
        print(_("# Generated by PNCconf at %s") % time.asctime(), file=f1)
        print(file=f1)
        print(_("#    Automation Direct GS2 VFD for spindle control"), file=f1)
        print(file=f1)
        print(_("#    The communications switches must be set to RS-232C"), file=f1)
        print(_("#    The motor parameters must be set to match the motor"), file=f1)
        print(_("#    P3.00 (Source of Operation Command) must be set to Operation determined by RS-485 interface, 03 or 04"), file=f1)
        print(_("#    P4.00 (Source of Frequency Command) must be set to Frequency determined by RS232C/RS485 communication interface, 05"), file=f1)
        print(_("#    P9.01 (Transmission Speed) must be set to the specified baud, 9600 = 01"), file=f1)
        print(_("""#    P9.02 (Communication Protocol) must be set to "Modbus RTU mode, 8 data bits, no parity, 2 stop bits", 03"""), file=f1)
        print(file=f1)
        print("loadusr -Wn spindle-vfd gs2_vfd -d %s -r %s -p none -s 2 -t %s -n spindle-vfd -A %s -D %s"%(p,b,s,a,d), file=f1)
        print("net spindle-cw           => spindle-vfd.spindle-fwd", file=f1)
        print("net spindle-enable       => spindle-vfd.spindle-on", file=f1)
        print("net spindle-at-speed     <= spindle-vfd.at-speed", file=f1)
        print("net spindle-vel-cmd-rpm  => spindle-vfd.speed-command", file=f1)
        f1.close()

    def write_mitsub_vfd(self,filename):
        f1 = open(filename, "w")
        print(_("# Generated by PNCconf at %s") % time.asctime(), file=f1)
        print(file=f1)
        print(_("#    Misubishi FR VFD for spindle control"), file=f1)
        f1.close()

    def write_readme(self, base):
        filename = os.path.join(base, "README")
        file = open(filename, "w")
        print(_("Generated by PNCconf at %s") % time.asctime(), file=file)
        print(file=file)
        if  self.d.units == _PD._IMPERIAL: unit = "an imperial"
        else: unit = "a metric"
        if self.d.frontend == _PD._AXIS: display = "AXIS"
        elif self.d.frontend == _PD._TKLINUXCNC: display = "Tklinuxcnc"
        elif self.d.frontend == _PD._GMOCCAPY: display = "TOUCHY"
        elif self.d.frontend == _PD._TOUCHY: display = "TOUCHY"
        else: display = "an unknown"
        if self.d.axes == 0:machinetype ="XYZ"
        elif self.d.axes == 1:machinetype ="XYZA"
        elif self.d.axes == 2:machinetype ="XZ-Lathe"
        print(self.d.machinename,_("configures LinuxCNC as:\n"), file=file)
        print(unit,machinetype,_("type CNC\n"), file=file)
        print(display,_("will be used as the frontend display"), file=file)
        print(file=file)
        if self.d.number_mesa != 0:
            for boardnum in range(0,int(self.d.number_mesa)):
                print("Mesa hardware I/O card - board %d is designated as\n"% boardnum,self.d["mesa%d_currentfirmwaredata"% boardnum][_PD._BOARDTITLE], file=file)
                print("with", self.d["mesa%d_currentfirmwaredata"% boardnum][_PD._MAXGPIO], "I/O pins and firmware is:", self.d["mesa%d_firmware"% boardnum], file=file)
                print(file=file)
            for boardnum in range(0,int(self.d.number_mesa)):
                for concount,connector in enumerate(self.d["mesa%d_currentfirmwaredata"% boardnum][_PD._NUMOFCNCTRS]) :
                    print("** Mesa %s -> Board #"% self.d["mesa%d_boardtitle"% boardnum],boardnum,_(" connector")," %d **\n"% connector, file=file)
                    print("connector    board     num   component    signal        ", file=file)
                    print("number    position           type        name\n", file=file)
                    conpin = 1
                    for pin in range (0,24):
                        dummy,compnum = self.d["mesa%d_currentfirmwaredata"% (boardnum)][_PD._STARTOFDATA+pin+(concount*24)]
                        temp = self.d["mesa%dc%dpin%d" % (boardnum,connector,pin) ]
                        tempinv = self.d["mesa%dc%dpin%dinv" % (boardnum,connector,pin) ]
                        temptype = self.d["mesa%dc%dpin%dtype" % (boardnum,connector,pin) ]
                        if temptype in(_PD.GPIOI,_PD.GPIOO,_PD.GPIOD):
                            compnum = pin+(concount*24)
                        if tempinv:
                            invmessage = _("invrt")
                        else: invmessage =""
                        print(("P%d-%d   %d   (%d %s)  %s  %s\n"%(connector,conpin,pin,compnum,temptype,temp,invmessage)), file=file)
                        #print(("    connected to signal:'%(data)s'%(mess)s\n" %{'data':temp, 'mess':invmessage}), file=file)
                        conpin +=2
            print(file=file)
        templist = ("pp1","pp2","pp3")
        for j, k in enumerate(templist):
            if self.d.number_pports < (j+1): break
            print(_("%(name)s Parport" % { 'name':k}), file=file)
            for x in (2,3,4,5,6,7,8,9,10,11,12,13,15):
                temp = self.d["%sIpin%d" % (k, x)]
                tempinv = self.d["%sIpin%dinv" % (k, x)]
                if tempinv:
                    invmessage = _("-> inverted")
                else: invmessage =""
                print(_("pin# %(pinnum)d is connected to input signal:'%(data)s' %(mesag)s"
                %{ 'pinnum':x,'data':temp,'mesag':invmessage}), file=file)
            for x in (1,2,3,4,5,6,7,8,9,14,16,17):
                temp = self.d["%sOpin%d" % (k, x)]
                tempinv = self.d["%sOpin%dinv" % (k, x)]
                if tempinv:
                    invmessage = _("-> inverted")
                else: invmessage =""
                print(_("pin# %(pinnum)d is connected to output signal:'%(data)s' %(mesag)s"
                %{ 'pinnum':x,'data':temp,'mesag':invmessage}), file=file)
            print(file=file)
        file.close()
        self.d.add_md5sum(filename)

#*******************
# helper functions
#*******************

    def build_pid(self, file, jnum, let, stepflag):
        title = 'JOINT'
        if let == 's':
            title = 'SPINDLE'
        print("setp   pid.%s.Pgain     [%s_%d]P" % (let, title, jnum), file=file)
        print("setp   pid.%s.Igain     [%s_%d]I" % (let, title, jnum), file=file)
        print("setp   pid.%s.Dgain     [%s_%d]D" % (let, title, jnum), file=file)
        print("setp   pid.%s.bias      [%s_%d]BIAS" % (let, title, jnum), file=file)
        print("setp   pid.%s.FF0       [%s_%d]FF0" % (let, title, jnum), file=file)
        print("setp   pid.%s.FF1       [%s_%d]FF1" % (let, title, jnum), file=file)
        print("setp   pid.%s.FF2       [%s_%d]FF2" % (let, title, jnum), file=file)
        print("setp   pid.%s.deadband  [%s_%d]DEADBAND" % (let, title, jnum), file=file)
        if let =='s' and self.d.suseoutputrange2:
            print("net ratio_select.out   pid.%s.maxoutput " % (let), file=file)
        else:
            print("setp   pid.%s.maxoutput [%s_%d]MAX_OUTPUT" % (let, title, jnum), file=file)
        # steppers
        print("setp   pid.%s.error-previous-target true" % let, file=file)
        # steppers
        if stepflag:
            if  self.d.units == _PD._IMPERIAL:
                me = .0005
            else:
                me = .0127
            print('# This setting is to limit bogus stepgen',file=file)
            print('# velocity corrections caused by position',file=file)
            print('# feedback sample time jitter.',file=file)
            print("setp   pid.%s.maxerror %f" % (let, me),file=file)
        print(file=file)
        if let == 's':
            name = "spindle"
        else:
            name = let
        print("net %s-index-enable  =>  pid.%s.index-enable" % (name, let), file=file)
        print("net %s-enable        =>  pid.%s.enable" % (name, let), file=file)

        if let == 's':
            if self.d.susenegativevoltage:
                signal = "spindle-vel-cmd-rpm"
                fbsignal= "spindle-vel-fb-rpm"
            else:
                signal = "spindle-vel-cmd-rpm-abs"
                fbsignal= "spindle-vel-fb-rpm-abs"
            print("net %s     => pid.%s.command" % (signal, let), file=file)
            print("net %s      => pid.%s.feedback"% (fbsignal, let), file=file)
            if self.d.suseoutputrange2:
                print("net spindle-pid-out  pid.s.output    => scale.gear.in", file=file)
                print("net gear-ratio       ratio_select.out-f => scale.gear.gain", file=file)
                print("setp ratio_select.in00 %f" % (1/float(self.d.gsincrvalue0)), file=file)
                print("setp ratio_select.in01 %f" % (1/float(self.d.gsincrvalue1)), file=file)
                #print("setp ratio_select.in2 %f" % self.d.gsincrvalue2, file=file)
                #print("setp ratio_select.in4 %f" % self.d.gsincrvalue4, file=file)
                print("net gear-select-a         =>  ratio_select.sel0", file=file)
                #print("net gear-select-b ratio_select.sel1", file=file)
                #print("net gear-select-c ratio_select.sel2", file=file)
                print("net spindle-output        <=  scale.gear.out", file=file)
            else:
                print("net spindle-output        <=  pid.%s.output"% (let), file=file)
        else:
           print("net %s-pos-cmd       =>  pid.%s.command" % (name, let), file=file)
           #print("net %s-vel-cmd       =>  pid.%s.command-deriv" % (name, let), file=file) # This must be connected to something
           print("net %s-pos-fb        =>  pid.%s.feedback"% (name,let), file=file)
           print("net %s-output        <=  pid.%s.output"% (name, let), file=file)
           #print(file, "net %s-vel-fb           => pid.%s.feedback-deriv"% (name, let), file=file) # This must be connected to something
        print(file=file)

    def connect_joint(self, file, jnum, let):
        def get(s): return self.d[let + s]
        title = 'JOINT'
        if let == 's':
            title = 'SPINDLE'
        closedloop = False
        pwmpin = self.a.pwmgen_sig(let)
        pwmpinname = self.a.make_pinname(pwmpin, substitution = self.d.useinisubstitution)
        if pwmpinname and not 'serial' in pwmpin: # TODO allow sserial PWM to be inverted
            pwminvertlist = self.a.pwmgen_invert_pins(pwmpin)
        if not pwmpin == None:
            pwmtype = self.a.pwmgen_sig(let)+"type"
        else:
            pwmtype = None
        tppwmpinname = self.a.make_pinname(self.a.tppwmgen_sig(let), substitution = self.d.useinisubstitution)
        tppwm_six = self.a.tppwmgen_has_6(let)
        steppinname = self.a.make_pinname(self.a.stepgen_sig(let), substitution = self.d.useinisubstitution)
        try:
            bldc_control = self.d[let+"bldc_option"]
        except:
            bldc_control = False
        if steppinname:
            stepinvertlist = self.a.stepgen_invert_pins(self.a.stepgen_sig(let))
        encoderpinname = self.a.make_pinname(self.a.encoder_sig(let), substitution = self.d.useinisubstitution)
        amp8i20pinname = self.a.make_pinname(self.a.amp_8i20_sig(let), substitution = self.d.useinisubstitution)
        resolverpinname = self.a.make_pinname(self.a.resolver_sig(let), substitution = self.d.useinisubstitution)
        potpinname = self.a.make_pinname(self.a.potoutput_sig(let), substitution = self.d.useinisubstitution)
        if potpinname:
            potinvertlist = self.a.spindle_invert_pins(self.a.potoutput_sig(let))
        if steppinname and encoderpinname and not let == 's': closedloop = True
        if (encoderpinname or resolverpinname) and (pwmpinname or tppwmpinname or amp8i20pinname): closedloop = True
        print(let + " is closedloop? "+ str(closedloop))
        print(" ENCODER:",encoderpinname," RESOLVER:",resolverpinname)
        print(" PWM:",pwmpinname," 3PWM:",tppwmpinname," 8i20:",amp8i20pinname)
        print(" STEPPER:",steppinname)
        print(" POTENTIOMETER:",potpinname)
        lat = self.d.latency
        print("#*******************", file=file)
        if let.upper() == 'S':
            print(_("#  SPINDLE"), file=file)
        elif len(let) >1:
            print("#  Tandem AXIS %s %s %d" % (let.upper(), title, jnum ), file=file)
        else:
            print("#  AXIS %s %s %d" % (let.upper(), title, jnum ), file=file)
        print("#*******************", file=file)
        print(file=file)

        if bldc_control:
            bldc = self.d[let+"bldc_config"]
            print(_("# -- BLDC setup --"), file=file)
            print("setp   bldc.%d.drive-offset       %d" % (jnum,self.d[let+"bldc_drive_offset"]), file=file)
            print("setp   bldc.%s.rev                %d" % (jnum,self.d[let+"bldc_reverse"]), file=file)
            if "q" in(bldc):
                print("setp   bldc.%d.scale              %d" % (jnum,self.d[let+"bldc_scale"]), file=file)
                print("setp   bldc.%d.poles              %d" % (jnum,self.d[let+"bldc_poles"]), file=file)
            if "i" in(bldc):
                print("setp   bldc.%s.initvalue          %d" % (jnum,self.d[let+"bldc_inital_value"]), file=file)
            if "i" in(bldc) or "a" in(bldc):
                print("setp   bldc.%s.lead-angle         %d" % (jnum,self.d[let+"bldc_lead_angle"]), file=file)
                print("setp   bldc.%d.encoder-offset     %d" % (jnum,self.d[let+"bldc_encoder_offset"]), file=file)
            if "h" in(bldc):
                print("setp   bldc.%d.pattern            %d" % (jnum,self.d[let+"bldc_pattern_in"]), file=file)
                print("net %s-hall1-in      bldc.%d.hall1"% (let,jnum), file=file)
                print("net %s-hall2-in      bldc.%d.hall2"% (let,jnum), file=file)
                print("net %s-hall3-in      bldc.%d.hall3"% (let,jnum), file=file)
            if "f" in(bldc):
                print("net %s-c1-in     bldc.%d.C1"% (let,jnum), file=file)
                print("net %s-c2-in     bldc.%d.C2"% (let,jnum), file=file)
                print("net %s-c4-in     bldc.%d.C4"% (let,jnum), file=file)
                print("net %s-c8-in     bldc.%d.C8"% (let,jnum), file=file)
            if "H" in(bldc):
                print("setp   bldc.%d.output-pattern     %d" % (jnum,self.d[let+"bldc_pattern_out"]), file=file)
                print("net %s-hall1-out     bldc.%d.hall1-out"% (let,jnum), file=file)
                print("net %s-hall2-out     bldc.%d.hall2-out"% (let,jnum), file=file)
                print("net %s-hall3-out     bldc.%d.hall3-out"% (let,jnum), file=file)
            if "6" in(bldc) :
                if "B" in(bldc):
                    print("net %s-a-high-on     bldc.%d.A-high-on"% (let,jnum), file=file)
                    print("net %s-a-low-on      bldc.%d.A-low-on"% (let,jnum), file=file)
                    print("net %s-b-high-on     bldc.%d.B-high-on"% (let,jnum), file=file)
                    print("net %s-b-low-on      bldc.%d.B-low-on"% (let,jnum), file=file)
                    print("net %s-c-high-on     bldc.%d.C-high-on"% (let,jnum), file=file)
                    print("net %s-c-low-on      bldc.%d.C-low-on"% (let,jnum), file=file)
                else:
                    print("net %s-a-high-value      bldc.%d.A-high"% (let,jnum), file=file)
                    print("net %s-a-low-value       bldc.%d.A-low"% (let,jnum), file=file)
                    print("net %s-b-high-value      bldc.%d.B-high"% (let,jnum), file=file)
                    print("net %s-b-low-value       bldc.%d.B-low"% (let,jnum), file=file)
                    print("net %s-c-high-value      bldc.%d.C-high"% (let,jnum), file=file)
                    print("net %s-c-low-value       bldc.%d.C-low"% (let,jnum), file=file)
            elif "B" in(bldc):
                print("net %s-a-on          bldc.%d.A-on"% (let,jnum), file=file)
                print("net %s-b-on          bldc.%d.B-on"% (let,jnum), file=file)
                print("net %s-c-on          bldc.%d.C-on"% (let,jnum), file=file)
            elif "F" in(bldc):
                print("net %s-c1-out        bldc.%d.C1-out"% (let,jnum), file=file)
                print("net %s-c2-out        bldc.%d.C2-out"% (let,jnum), file=file)
                print("net %s-c4-out        bldc.%d.C4-out"% (let,jnum), file=file)
                print("net %s-c8-out        bldc.%d.C8-out"% (let,jnum), file=file)
            else:
                print("net %s-a-value       bldc.%d.A-value"% (let,jnum), file=file)
                print("net %s-b-value       bldc.%d.B-value"% (let,jnum), file=file)
                print("net %s-c-value       bldc.%d.C-value"% (let,jnum), file=file)
            print(file=file)
            print("net %s-pos-rawcounts      bldc.%d.rawcounts"% (let,jnum), file=file)
            print("net %s-index-enable      bldc.%d.index-enable"% (let,jnum), file=file)
            print("net %s-bldc-current      bldc.%d.out"% (let,jnum), file=file)
            print("net %s-meas-angle        bldc.%d.phase-angle"% (let,jnum), file=file)
            print("net %s-output             bldc.%d.value"% (let,jnum), file=file)
            print("net %s-enable             bldc.%d.init"% (let,jnum), file=file)
            print("net %s-is-init           bldc.%s.init-done"% (let,jnum), file=file)
            print(file=file)

        stepflag = bool(steppinname !=None)
        self.build_pid(file, jnum, let, stepflag)

        if tppwmpinname:
                print(_("# ---TPPWM Generator signals/setup---"), file=file)
                if tppwm_six:
                    print(_("# six output 3pwg"), file=file)
                else:print(_("# three output 3pwg"), file=file)
                print(_("# TODO write some commands!"), file=file)
                print(file=file)

        if amp8i20pinname:
                print(_("# ---8i20 amplifier card signals/setup---"), file=file)
                print(file=file)
                print("setp       %s.max_current %.3f"% (amp8i20pinname,self.d[let+"8i20maxcurrent"]), file=file)
                print("net %s-meas-angle =>       %s.angle"% (let,amp8i20pinname), file=file)
                print("net %s-bldc-current =>     %s.current"% (let,amp8i20pinname), file=file)
                print("net %s-enable =>            %s.amp_enable"% (let,amp8i20pinname), file=file)
                print(file=file)

        if potpinname:
                # sserial digital potentiometer outputs for spindle eg 7i76 board
                print(_("# ---digital potentiometer output signals/setup---"), file=file)
                print(file=file)
                print("setp   "+potpinname+"spinout-minlim    [%s_%d]OUTPUT_MIN_LIMIT"% (title, jnum), file=file)
                print("setp   "+potpinname+"spinout-maxlim    [%s_%d]OUTPUT_MAX_LIMIT"% (title, jnum), file=file)
                print("setp   "+potpinname+"spinout-scalemax  [%s_%d]OUTPUT_SCALE"% (title, jnum), file=file)
                for i in potinvertlist:
                    if i == _PD.POTO:
                        print("setp   "+potpinname+"spindir-invert   true", file=file)
                    if i == _PD.POTE:
                        print("setp   "+potpinname+"spinena-invert   true", file=file)
                print(file=file)
                print("net spindle-output      => " + potpinname + "spinout", file=file)
                print("net spindle-enable      => " + potpinname +"spinena", file=file)
                print("net spindle-ccw         => " + potpinname +"spindir", file=file)
                print(file=file)

        if pwmpinname:
            print(_("# ---PWM Generator signals/setup---"), file=file)
            print(file=file)
            # sserial daughter board PWMGENS eg 7i77
            if "analogout" in pwmpinname:
                rawpinname = self.a.make_pinname(pwmpin, gpionumber = False, prefixonly = True, substitution = self.d.useinisubstitution) # dont want the component name

                if let == 's':
                    print("setp   "+pwmpinname+"-scalemax  [%s_%d]OUTPUT_SCALE"% (title, jnum), file=file)
                    print("setp   "+pwmpinname+"-minlim    [%s_%d]OUTPUT_MIN_LIMIT"% (title, jnum), file=file)
                    print("setp   "+pwmpinname+"-maxlim    [%s_%d]OUTPUT_MAX_LIMIT"% (title, jnum), file=file)
                    print(file=file)
                    print("net spindle-output      => " + pwmpinname, file=file)
                    if 'analogout5' in pwmpinname: # on the 7i77 analog out 5 has it's own enable
                        print("net spindle-enable      => " + rawpinname + "spinena", file=file)
                else:
                    print("setp   "+pwmpinname+"-scalemax  [%s_%d]OUTPUT_SCALE"% (title, jnum), file=file)
                    print("setp   "+pwmpinname+"-minlim    [%s_%d]OUTPUT_MIN_LIMIT"% (title, jnum), file=file)
                    print("setp   "+pwmpinname+"-maxlim    [%s_%d]OUTPUT_MAX_LIMIT"% (title, jnum), file=file)
                    print(file=file)
                    print("net %s-output     => "% (let) + pwmpinname, file=file)
                    print("net %s-pos-cmd    <= joint.%d.motor-pos-cmd" % (let, jnum ), file=file)
                    print("net %s-enable     <= joint.%d.amp-enable-out"% (let,jnum), file=file)
                    if 'analogout5' in pwmpinname: # on the 7i77 analog out 5 has it's own enable
                        print("net %s-enable   %spinena"% (let,rawpinname), file=file)
                    if let == "x":
                        print(_("# enable _all_ sserial pwmgens"), file=file)
                        print("net %s-enable   => %sanalogena"% (let,rawpinname), file=file)
                print(file=file)

            else:
                # mainboard PWMGENS
                pulsetype = 1
                if self.d[pwmtype] == _PD.PDMP: pulsetype = 3
                if self.d[pwmtype] == _PD.UDMU: pulsetype = 2
                print("setp   "+pwmpinname+".output-type %d"% pulsetype, file=file)
                print("setp   "+pwmpinname+".scale  [%s_%d]OUTPUT_SCALE"% (title, jnum), file=file)
                for i in pwminvertlist:
                    print("setp    "+i+".invert_output true", file=file)
                print(file=file)
                if let == 's':
                    print(file=file)
                    if closedloop or self.d.suseoutputrange2:
                        print("net spindle-output      => " + pwmpinname + ".value", file=file)
                        print("net spindle-enable      => " + pwmpinname +".enable", file=file)
                    else:
                        print("net spindle-vel-cmd-rpm     => " + pwmpinname + ".value", file=file)
                        print("net spindle-enable      => " + pwmpinname +".enable", file=file)
                else:
                    print("net %s-output                             => "% (let) + pwmpinname + ".value", file=file)
                    print("net %s-pos-cmd    joint.%d.motor-pos-cmd" % (let, jnum ), file=file)
                    print("net %s-enable     joint.%d.amp-enable-out  => "% (let,jnum) + pwmpinname +".enable", file=file)
                print(file=file)

        if steppinname:
            if len(let) >1:
                print(_("# Step Gen signals/setup for tandem axis"), file=file)
            else:
                print(_("# Step Gen signals/setup"), file=file)
            print(file=file)
            print("setp   " + steppinname + ".dirsetup        [%s_%d]DIRSETUP"% (title, jnum), file=file)
            print("setp   " + steppinname + ".dirhold         [%s_%d]DIRHOLD"% (title, jnum), file=file)
            print("setp   " + steppinname + ".steplen         [%s_%d]STEPLEN"% (title, jnum), file=file)
            print("setp   " + steppinname + ".stepspace       [%s_%d]STEPSPACE"% (title, jnum), file=file)
            print("setp   " + steppinname + ".position-scale  [%s_%d]STEP_SCALE"% (title, jnum), file=file)
            print("setp   " + steppinname + ".step_type        0", file=file)
            print("setp   " + steppinname + ".control-type     1", file=file)
            print("setp   " + steppinname + ".maxaccel         [%s_%d]STEPGEN_MAXACCEL"% (title, jnum), file=file)
            print("setp   " + steppinname + ".maxvel           [%s_%d]STEPGEN_MAXVEL"% (title, jnum), file=file)

            # invert step pins if requested
            # step does not have alias pin names so we invert it's GPIO pin
            for i in stepinvertlist[0]:
                   print("setp   " + steppinname + ".step.invert_output   true", file=file)
            # step direction has an alias pin
            for i in stepinvertlist[1]:
                   print("setp   " + steppinname + ".direction.invert_output   true", file=file)
            if let == "s":
                print(file=file)
                print("net machine-is-on           =>  " + steppinname + ".enable", file=file)
                print("net spindle-vel-cmd-rps     =>  "+ steppinname + ".velocity-cmd", file=file)
                if not encoderpinname and not resolverpinname:
                    print("net spindle-vel-fb-rps         <=  "+ steppinname + ".velocity-fb", file=file)
            else:
                print(file=file)
                print(_("# ---closedloop stepper signals---"), file=file)
                print(file=file)
                print("net %s-pos-cmd    <= joint.%d.motor-pos-cmd" % (let, jnum ), file=file)
                print("net %s-vel-cmd    <= joint.%d.vel-cmd" % (let, jnum ), file=file)
                print("net %s-output     => "% (let) + steppinname + ".velocity-cmd", file=file)
                print("net %s-pos-fb     <= "% (let) + steppinname + ".position-fb", file=file)
                print("net %s-pos-fb     => joint.%d.motor-pos-fb" % (let, jnum ), file=file)
                print("net %s-enable     <= joint.%d.amp-enable-out"% (let,jnum), file=file)
                print("net %s-enable     => %s.enable"% (let, steppinname), file=file)
                print(file=file)

        if encoderpinname:
            countmode = 0
            if let == "s" and self.d.ssingleinputencoder: countmode = 1
            print(_("# ---Encoder feedback signals/setup---"), file=file)
            print(file=file)
            print("setp    "+encoderpinname+".counter-mode %d"% countmode, file=file)
            print("setp    "+encoderpinname+".filter 1", file=file)
            print("setp    "+encoderpinname+".index-invert 0", file=file)
            print("setp    "+encoderpinname+".index-mask 0", file=file)
            print("setp    "+encoderpinname+".index-mask-invert 0", file=file)
            print("setp    "+encoderpinname+".scale  [%s_%d]ENCODER_SCALE"% (title, jnum), file=file)
            print(file=file)
            if let == 's':
                print("net spindle-revs             <=   " + encoderpinname + ".position", file=file)
                print("net spindle-vel-fb-rps       <=   " + encoderpinname + ".velocity", file=file)
                print("net spindle-vel-fb-rpm       <=   " + encoderpinname + ".velocity-rpm", file=file)
                print("net spindle-index-enable     <=>  " + encoderpinname + ".index-enable", file=file)
            else:
                print("net %s-pos-fb               <=  "% (let) + encoderpinname+".position", file=file)
                print("net %s-vel-fb               <=  "% (let) + encoderpinname + ".velocity", file=file)
                print("net %s-pos-fb               =>  joint.%d.motor-pos-fb" % (let, jnum), file=file)
                print("net %s-index-enable    joint.%d.index-enable  <=>  "% (let, jnum) + encoderpinname + ".index-enable", file=file)
                print("net %s-pos-rawcounts        <=  "% (let) + encoderpinname + ".rawcounts", file=file)
            print(file=file)

        if resolverpinname:
            print(_("# ---Resolver feedback signals/setup---"), file=file)
            print(file=file)
            print("setp    "+resolverpinname+".velocity-scale 1 # mptor speed in RPS", file=file)
            print("setp    "+resolverpinname+".scale  [%s_%d]RESOLVER_SCALE"% (title, jnum), file=file)
            print(file=file)
            print("net %s-pos-rawcounts        <=  "% (let) + resolverpinname + ".rawcounts", file=file)
            if let == 's':
                print("net spindle-revs             <=   " + resolverpinname + ".position", file=file)
                print("net spindle-vel-fb-rps       <=   " + resolverpinname + ".velocity", file=file)
                print("net spindle-vel-fb-rpm       <=   " + resolverpinname + ".velocity-rpm", file=file)
                print("net spindle-index-enable     <=>  " + resolverpinname + ".index-enable", file=file)
            else:
                print("net %s-pos-fb               <=  "% (let) + resolverpinname+".position", file=file)
                print("net %s-vel-fb               <=  "% (let) + resolverpinname + ".velocity", file=file)
                print("net %s-pos-fb               =>  joint.%d.motor-pos-fb" % (let, jnum), file=file)
                print("net %s-index-enable    joint.%d.index-enable  <=>  "% (let, jnum) + resolverpinname + ".index-enable", file=file)
            print(file=file)

        if let =='s':
            print(_("# ---setup spindle control signals---"), file=file)
            print(file=file)
            print("net spindle-vel-cmd-rps        <=  spindle.0.speed-out-rps", file=file)
            print("net spindle-vel-cmd-rps-abs    <=  spindle.0.speed-out-rps-abs", file=file)
            print("net spindle-vel-cmd-rpm        <=  spindle.0.speed-out", file=file)
            print("net spindle-vel-cmd-rpm-abs    <=  spindle.0.speed-out-abs", file=file)
            print("net spindle-enable             <=  spindle.0.on", file=file)
            print("net spindle-cw                 <=  spindle.0.forward", file=file)
            print("net spindle-ccw                <=  spindle.0.reverse", file=file)
            print("net spindle-brake              <=  spindle.0.brake", file=file)
            print("net spindle-revs               =>  spindle.0.revs", file=file)
            print("net spindle-at-speed           =>  spindle.0.at-speed", file=file)
            print("net spindle-vel-fb-rps         =>  spindle.0.speed-in", file=file)
            print("net spindle-index-enable      <=>  spindle.0.index-enable", file=file)
            print(file=file)
            if not self.a.findsignal("spindle-at-speed"):
                print(_("# ---Setup spindle at speed signals---"), file=file)
                print(file=file)
                if (encoderpinname or resolverpinname) and self.d.suseatspeed:
                    if self.d.susenearrange:
                        near_scale = 1
                        near_range = self.d.snearrange/60
                    else:
                        near_scale =  self.d.snearscale
                        near_range = 0
                    print("net spindle-vel-cmd-rps    =>  near.0.in1", file=file)
                    print("net spindle-vel-fb-rps         =>  near.0.in2", file=file)
                    print("net spindle-at-speed       <=  near.0.out", file=file)
                    print("setp near.0.scale %f"%near_scale, file=file)
                    print("setp near.0.difference %f"% near_range, file=file)
                    print(file=file)
                else:
                    print("sets spindle-at-speed true", file=file)
                    print(file=file)
            if encoderpinname or resolverpinname:
                if (self.d.pyvcp and self.d.pyvcpconnect == 1 and self.d.pyvcphaltype == 1) \
                  or self.d.gladevcp and self.d.spindlespeedbar:
                    print(_("#  Use ACTUAL spindle velocity from spindle encoder"), file=file)
                    print(_("#  spindle-velocity bounces around so we filter it with lowpass"), file=file)
                    print(_("#  spindle-velocity is signed so we use absolute component to remove sign"), file=file)
                    print(_("#  ACTUAL velocity is in RPS not RPM so we scale it."), file=file)
                    print(file=file)
                    print(("setp     scale.spindle.gain 60"), file=file)
                    print(("setp     lowpass.spindle.gain %f"% self.d.sfiltergain), file=file)
                    print(("net spindle-vel-fb-rps        =>     scale.spindle.in"), file=file)
                    print(("net spindle-fb-rpm               scale.spindle.out       =>   abs.spindle.in"), file=file)
                    print(("net spindle-fb-rpm-abs           abs.spindle.out         =>   lowpass.spindle.in"), file=file)
                    print(("net spindle-fb-rpm-abs-filtered  lowpass.spindle.out  "), file=file)
            return

        min_limsig = self.a.min_lim_sig(let)
        if not min_limsig: min_limsig = "%s-neg-limit" % let
        max_limsig = self.a.max_lim_sig(let)
        if not max_limsig: max_limsig = "%s-pos-limit" % let
        homesig = self.a.home_sig(let)
        if not homesig: homesig = "%s-home-sw" % let
        print(_("# ---setup home / limit switch signals---"), file=file)
        print(file=file)
        print("net %s     =>  joint.%d.home-sw-in" % (homesig, jnum), file=file)
        print("net %s     =>  joint.%d.neg-lim-sw-in" % (min_limsig, jnum), file=file)
        print("net %s     =>  joint.%d.pos-lim-sw-in" % (max_limsig, jnum), file=file)
        print(file=file)

    def connect_input(self, file):
        print(_("# external input signals"), file=file)

        def write_pins(pname,p,i,t):
            # for input pins
            if t in (_PD.GPIOI, _PD.INM0):
                if not p == "unused-input":
                    pinname = self.a.make_pinname(pname, substitution = self.d.useinisubstitution)
                    print("\n# ---",p.upper(),"---", file=file)
                    if "parport" in pinname:
                        if i: print("net %s     <= %s-not" % (p, pinname), file=file)
                        else: print("net %s     <= %s" % (p, pinname), file=file)
                    elif "sserial" in pname or t == _PD.INM0:
                        if i: print("net %s     <=  "% (p)+pinname +"-not", file=file)
                        else: print("net %s     <=  "% (p)+pinname, file=file)
                    else:
                        if i: print("net %s     <=  "% (p)+pinname +".in_not", file=file)
                        else: print("net %s     <=  "% (p)+pinname +".in", file=file)
            # for encoder pins
            elif t in (_PD.ENCA,_PD.MXE0,_PD.MXE1):
                if not p == "unused-encoder":
                    for sig in (self.d.halencoderinputsignames):
                       if p == sig+"-a":
                            pinname = self.a.make_pinname(self.a.findsignal( p ), substitution = self.d.useinisubstitution)
                            print("\n# ---",sig.upper(),"---", file=file)
                            print("net %s         <=  "% (sig+"-position")+pinname +".position", file=file)
                            print("net %s            <=  "% (sig+"-count")+pinname +".count", file=file)
                            print("net %s         <=  "% (sig+"-velocity")+pinname +".velocity", file=file)
                            print("net %s            <=  "% (sig+"-reset")+pinname +".reset", file=file)
                            print("net %s     <=  "% (sig+"-index-enable")+pinname +".index-enable", file=file)
                            for ending in ("counter-mode","filter","index-invert","indek-mask","index-mask-invert","scale","vel-timeout"):
                                title = sig + "-%s"% ending
                                name = pinname + ".%s"% ending
                                self._substitution_list.append((title.upper(),name))
                            self._substitution_list.append(("",""))
                            break
            elif t in (_PD.RES0,_PD.RES1,_PD.RES2,_PD.RES3,_PD.RES4,_PD.RES5):
                if not p == "unused-resolver":
                    for sig in (self.d.halresolversignames):
                       if p == sig:
                            pinname = self.a.make_pinname(self.a.findsignal( p ), substitution = self.d.useinisubstitution)
                            print("\n# ---",sig.upper(),"---", file=file)
                            print("net %s         <=  "% (sig+"-position")+pinname +".position", file=file)
                            print("net %s            <=  "% (sig+"-count")+pinname +".count", file=file)
                            print("net %s            <=  "% (sig+"-angle")+pinname +".angle", file=file)
                            print("net %s            <=  "% (sig+"-error")+pinname +".error", file=file)
                            print("net %s         <=  "% (sig+"-velocity")+pinname +".velocity", file=file)
                            print("net %s            <=  "% (sig+"-reset")+pinname +".reset", file=file)
                            print("net %s     <=  "% (sig+"-index-enable")+pinname +".index-enable", file=file)
                            for ending in ("scale","velocity-scale"):
                                title = sig + "-%s"% ending
                                name = pinname + ".%s"% ending
                                self._substitution_list.append((title.upper(),name))
                            self._substitution_list.append(("",""))
                            break
            # for analog in pins
            elif t == (_PD.ANALOGIN):
                if not p == "unused-analog-input":
                            pinname = self.a.make_pinname(self.a.findsignal( p ), substitution = self.d.useinisubstitution)
                            print("\n# ---",p.upper(),"---", file=file)
                            print("net %s         <=  "% (p)+pinname, file=file)

        # mesa mainboards
        for boardnum in range(0,int(self.d.number_mesa)):
            for concount,connector in enumerate(self.d["mesa%d_currentfirmwaredata"% (boardnum)][_PD._NUMOFCNCTRS]) :
                for pin in range(0,24):
                    pname = 'mesa%dc%dpin%d' % (boardnum,connector, pin)
                    p = self.d['mesa%dc%dpin%d' % (boardnum,connector, pin)]
                    i = self.d['mesa%dc%dpin%dinv' % (boardnum,connector, pin)]
                    t = self.d['mesa%dc%dpin%dtype' % (boardnum,connector, pin)]
                    write_pins(pname,p,i,t)
        # sserial
            if self.d["mesa%d_numof_sserialports"% (boardnum)]: # only check if we have sserialports
                print(file=file)
                port = 0
                for channel in range (0,self.d["mesa%d_currentfirmwaredata"% boardnum][_PD._MAXSSERIALCHANNELS]):
                    if channel > _PD._NUM_CHANNELS: break
                    for pin in range (0,_PD._SSCOMBOLEN):
                        pname = 'mesa%dsserial%d_%dpin%d' % (boardnum,port,channel,pin)
                        p = self.d['mesa%dsserial%d_%dpin%d' % (boardnum,port,channel,pin)]
                        i = self.d['mesa%dsserial%d_%dpin%dinv' % (boardnum,port,channel,pin)]
                        t = self.d['mesa%dsserial%d_%dpin%dtype' % (boardnum,port,channel,pin)]
                        write_pins(pname,p,i,t)
        # parports
        templist = ("pp1","pp2","pp3")
        for j, k in enumerate(templist):
            if self.d.number_pports < (j+1): break
            print(file=file)
            for x in (2,3,4,5,6,7,8,9,10,11,12,13,15):
                pname = "%s_Ipin%d" % (k, x)
                p = self.d[pname]
                i = self.d[pname+"_inv"]
                if not p == "unused-input":
                    write_pins(pname,p,i,_PD.GPIOI)

    def connect_output(self, file):
        print(_("# external output signals"), file=file)

        def write_pins(pname,p,i,t,boardnum,connector,port,channel,pin):
            # for output /open drain pins
            if t in (_PD.GPIOO,_PD.GPIOD,_PD.SSR0,_PD.OUTM0):
                if not p == "unused-output":
                    pinname = self.a.make_pinname(pname, substitution = self.d.useinisubstitution)
                    print("\n# ---",p.upper(),"---", file=file)
                    if "parport" in pinname:
                        if p == "force-pin-true":
                            print("setp %s true"% (pinname), file=file)
                        else:
                            print("net %s  =>     %s"% (p,pinname), file=file)
                    else:
                        if "sserial" in pname:
                            temp = pinname
                        # mainboard GPIOO require extra setup commands
                        else:
                            if t not in (_PD.SSR0,_PD.OUTM0): print("setp %s true"% (pinname + ".is_output"), file=file)
                            if t == _PD.GPIOD: print("setp    "+pinname+".is_opendrain  true", file=file)
                            if t in (_PD.SSR0,_PD.OUTM0):
                                temp = pinname
                            else:
                                temp = pinname + ".out"
                        # set pin true if force-pin-true otherwise connect to a signal
                        if p == "force-pin-true":
                            print("setp %s true"% (temp), file=file)
                        else:
                            comment = ""
                            if self.d.frontend == _PD._QTPLASMAC and p in ['dout-01','dout-02','dout-03']:
                                comment = "#qtplasmac uses digital output %s:\n#" % p
                            print("%snet %s  =>     %s"% (comment,p,temp), file=file)
                    if i: # invert pin
                        if t in (_PD.SSR0,_PD.OUTM0):
                            print("setp %s true"%  (pinname.replace('.out-', '.invert-')), file=file)
                        else:
                            if "sserial" in pname:
                                ending = "-invert"
                            elif "parport" in pinname: ending = "-invert"
                            else: ending = ".invert_output"
                            print("setp %s true"%  (pinname + ending ), file=file)

            # for pwm pins
            elif t in (_PD.PWMP,_PD.PDMP,_PD.UDMU):
                if not p == "unused-pwm":
                    for sig in (self.d.halpwmoutputsignames):
                        if p == (sig+"-pulse"):
                            pinname = self.a.make_pinname(pname, substitution = self.d.useinisubstitution)
                            print("\n# ---",sig.upper(),"---", file=file)
                            if t == _PD.PWMP:
                                print("setp    "+pinname +".output-type 1", file=file)
                            if t == _PD.UDMU:
                                print("setp    "+pinname +".output-type 2", file=file)
                            elif t == _PD.PDMP:
                                print("setp    "+pinname +".output-type 3", file=file)
                            print("net %s     <=  "% (sig+"-enable")+pinname +".enable", file=file)
                            print("net %s      <=  "% (sig+"-value")+pinname +".value", file=file)
                            for ending in ("scale","output-type"):
                                title = sig + "-%s"% ending
                                name = pinname + ".%s"% ending
                                self._substitution_list.append((title.upper(),name))
                            self._substitution_list.append(("",""))
                            break
            # for TP pwm pins
            elif t == (_PD.TPPWMA):
                if not p == "unused-tppwmgen":
                    for sig in (self.d.haltppwmoutputsignames):
                        if p == (sig+"-a"):
                            pinname = self.a.make_pinname(pname, substitution = self.d.useinisubstitution)
                            print("\n# ---",sig.upper(),"---", file=file)
                            print("net %s           <=  "% (sig+"-enable")+pinname +".enable", file=file)
                            print("net %s           <=  "% (sig+"-a-value")+pinname +".A-value", file=file)
                            print("net %s           <=  "% (sig+"-b-value")+pinname +".B-value", file=file)
                            print("net %s           <=  "% (sig+"-c-value")+pinname +".C-value", file=file)
                            print("net %s           <=  "% (sig+"-fault")+pinname +".fault", file=file)
                            for ending in ("scale","deadtime","fault-invert","sample-time"):
                                title = sig + "-%s"% ending
                                name = pinname + ".%s"% ending
                                self._substitution_list.append((title.upper(),name))
                            self._substitution_list.append(("",""))
                            break
            # for stepper pins
            elif t == (_PD.STEPA):
                if not p == "unused-stepgen":
                    for sig in (self.d.halsteppersignames):
                        if p == (sig+"-step"):
                            pinname = self.a.make_pinname(pname, substitution = self.d.useinisubstitution)
                            print("\n# ---",sig.upper(),"---", file=file)
                            print("net %s           <=  "% (sig+"-enable")+pinname +".enable", file=file)
                            print("net %s            <=  "% (sig+"-count")+pinname +".counts", file=file)
                            print("net %s     <=  "% (sig+"-cmd-position")+pinname +".position-cmd", file=file)
                            print("net %s     <=  "% (sig+"-act-position")+pinname +".position-fb", file=file)
                            print("net %s         <=  "% (sig+"-velocity")+pinname +".velocity-fb", file=file)
                            pinlist = self.a.list_related_pins([_PD.STEPA,_PD.STEPB], boardnum, connector, channel, pin, 0)
                            for i in pinlist:
                                if self.d[i[0]+"inv"]:
                                    gpioname = self.a.make_pinname(i[0],gpionumber = True, substitution = self.d.useinisubstitution)
                                    print("setp    "+gpioname+".invert_output true", file=file)
                            for ending in ("position-scale","maxvel","maxaccel","steplen","stepspace","dirsetup","dirhold","step_type"):
                                title = sig + "-%s"% ending
                                name = pinname + ".%s"% ending
                                self._substitution_list.append((title.upper(),name))
                            self._substitution_list.append(("",""))
                            break
            # potentiometer outpot
            elif t == (_PD.POTO):
                print(pname)
                if not p == "unused-pot":
                    for sig in (self.d.halpotsignames):
                        print("looking",p,sig)
                        if p == (sig+"-output"):
                            pinname = self.a.make_pinname(pname, substitution = self.d.useinisubstitution)
                            print("\n# ---",sig.upper(),"---", file=file)
                            print("net %s            =>  "% (sig+"-enable")+pinname +".spinena", file=file)
                            print("net %s            =>  "% (sig+"-output")+pinname +".spinout", file=file)
                            print("net %s          =>  "% (sig+"-direction")+pinname +".spindir", file=file)
                            pinlist = self.a.list_related_pins([_PD.POTO,_PD.POTE], boardnum, port, channel, pin, 0)
                            for i in pinlist:
                                if self.d[i[0]+"inv"]:
                                    if self.d[i[0]+"type"] == _PD.POTO:
                                        print("setp    "+pinname+".spindir-invert true", file=file)
                                    if self.d[i[0]+"type"] == _PD.POTE:
                                        print("setp    "+pinname+".spinena-invert true", file=file)
                            for ending in ("spindir-invert","spinena-invert","spinout-maxlim","spinout-minlim","spinout-scalemax"):
                                title = sig + "-%s"% ending
                                name = pinname + ".%s"% ending
                                self._substitution_list.append((title.upper(),name))
                            self._substitution_list.append(("",""))
                            break
        # mesa mainboards
        for boardnum in range(0,int(self.d.number_mesa)):
            for concount,connector in enumerate(self.d["mesa%d_currentfirmwaredata"% (boardnum)][_PD._NUMOFCNCTRS]) :
                for pin in range(0,24):
                    pname = 'mesa%dc%dpin%d' % (boardnum,connector, pin)
                    p = self.d['mesa%dc%dpin%d' % (boardnum,connector, pin)]
                    i = self.d['mesa%dc%dpin%dinv' % (boardnum,connector, pin)]
                    t = self.d['mesa%dc%dpin%dtype' % (boardnum,connector, pin)]
                    write_pins(pname,p,i,t,boardnum,connector,None,None,pin)
            # mesa sserial
            if self.d["mesa%d_numof_sserialports"% (boardnum)]: # only check if we have sserialports
                print(file=file)
                port = 0
                for channel in range (0,self.d["mesa%d_currentfirmwaredata"% boardnum][_PD._MAXSSERIALCHANNELS]):
                    if channel > _PD._NUM_CHANNELS: break
                    for pin in range (0,_PD._SSCOMBOLEN):
                        pname = 'mesa%dsserial%d_%dpin%d' % (boardnum,port,channel,pin)
                        p = self.d['mesa%dsserial%d_%dpin%d' % (boardnum,port,channel,pin)]
                        i = self.d['mesa%dsserial%d_%dpin%dinv' % (boardnum,port,channel,pin)]
                        t = self.d['mesa%dsserial%d_%dpin%dtype' % (boardnum,port,channel,pin)]
                        write_pins(pname,p,i,t,boardnum,None,port,channel,pin)
        # parports
        templist = ("pp1","pp2","pp3")
        for j, k in enumerate(templist):
            if self.d.number_pports < (j+1): break
            print(file=file)
            for x in (1,2,3,4,5,6,7,8,9,14,16,17):
                pname = "%s_Opin%d" % (k, x)
                p = self.d[pname]
                i = self.d[pname+"_inv"]
                if not p == "unused-output":
                    write_pins(pname,p,i,_PD.GPIOO,None,None,None,None,None)

    # qtplasmac hal connections
    def qtplasmac_connections(self, file, base):
        print(_("\n# ---PLASMA INPUT DEBOUNCE---"), file=file)
        print(_("#values for these are in custom.hal"), file=file)
        print("loadrt dbounce names=db_breakaway,db_float,db_ohmic,db_arc-ok", file=file)
        print("addf db_float     servo-thread", file=file)
        print("addf db_ohmic     servo-thread", file=file)
        print("addf db_breakaway servo-thread", file=file)
        print("addf db_arc-ok    servo-thread", file=file)
        print(_("\n# ---JOINT ASSOCIATED WITH THE Z AXIS---"), file=file)
        jnum = 0
        tandemjoint = self.a.tandem_check('x')
        if tandemjoint:
            jnum += 1
        jnum += 1
        tandemjoint = self.a.tandem_check('y')
        if tandemjoint:
            jnum += 1
        jnum += 1
        print("net plasmac:axis-position joint.{:d}.pos-fb => plasmac.axis-z-position".format(jnum), file=file)
        print(_("\n# ---PLASMA INPUTS---"), file=file)
        print(_("# ---all modes---"), file=file)
        print("net plasmac:float-switch     => db_float.in", file=file)
        print("net plasmac:breakaway        => db_breakaway.in", file=file)
        print("net plasmac:ohmic-probe      => db_ohmic.in", file=file)
        print("net plasmac:ohmic-sense-in   => plasmac.ohmic-sense-in", file=file)
        print(_("# ---modes 0 & 1"), file=file)
        print("net plasmac:arc-voltage-in   => plasmac.arc-voltage-in", file=file)
        print(_("# ---modes 1 & 2"), file=file)
        print("net plasmac:arc-ok-in        => db_arc-ok.in", file=file)
        print(_("# ---mode 2"), file=file)
        print("net plasmac:move-up          <= plasmac.move-up", file=file)
        print("net plasmac:move-down        <= plasmac.move-down", file=file)
        print(_("\n# ---PLASMA OUTPUTS---"), file=file)
        print(_("# ---all modes---"), file=file)
        print("net plasmac:ohmic-enable     <= plasmac.ohmic-enable", file=file)
        print("net plasmac:scribe-arm       <= plasmac.scribe-arm", file=file)
        print("net plasmac:scribe-on        <= plasmac.scribe-on", file=file)
        # check for arc voltage encoder
        self.d.qtplasmacvscale = 1
        self.d.qtplasmacvoffset = 0
        pinname = self.a.make_pinname(self.a.findsignal("arc-volt-enc-a"), substitution = self.d.useinisubstitution)
        if pinname:
            ending = ""
            if "enc" in pinname: ending = ".velocity"
            if self.d.voltsrdiv < 150:
                dratio = self.d.voltsrdiv
            else:
                dratio = (self.d.voltsrdiv + 100000) / 100000
            if self.d.voltsmodel.startswith("2"):
                if "(W1 down)" in self.d.voltsmodel:
                    thcadvolts = 5
                else:
                    thcadvolts = 10
            else:
                thcadvolts = int(self.d.voltsmodel)
            self.d.qtplasmacvscale = dratio / (((self.d.voltsfullf - self.d.voltszerof) * 1000) / int(self.d.voltsfjumper) / thcadvolts)
            self.d.qtplasmacvoffset = self.d.voltszerof * 1000 / int(self.d.voltsfjumper)
            # arc voltage in hal file
            print(_("\n# ---ARC VOLTAGE ENCODER---"), file=file)
            print("net plasmac:arc-voltage-in <= %s%s"% (pinname, ending), file=file)
            print("setp {}.counter-mode  1".format(pinname), file=file)
            print("setp {}.filter        1".format(pinname), file=file)
            print("setp {}.scale        -1".format(pinname), file=file)
        # check for ohmic sensing with a relay contact or similar
        pinname = self.a.make_pinname(self.a.findsignal("plasmac:ohmic-sense-in"), substitution = self.d.useinisubstitution)
        if pinname:
            vscale = 1
            voffset = 0
            print(_("\n# ---OHMIC SENSE LINK---"), file=file)
            print("net plasmac:ohmic-probe <= plasmac.ohmic-sense-out", file=file)
        # write custom hal file
        chfile = os.path.join(base, "custom.hal")
        if not os.path.exists(chfile):
            f1 = open(chfile, "w")
            print(_("# Include your custom HAL commands here"), file=f1)
            print(_("# This file will not be overwritten when you run PNCconf again"), file=f1)
            print(_("\n# ---COMMON PLASMAC DEBOUNCE---"), file=f1)
            print(_("# for the float and ohmic inputs each increment in delay is"), file=f1)
            print(_("# is a 0.001mm (0.00004\") increase in any probed height result"), file=f1)
            print("setp db_float.delay     5", file=f1)
            if pinname:
                print(_("# set to zero if using internal ohmic sensing"), file=f1)
                print("setp db_ohmic.delay     0", file=f1)
            else:
                print("setp db_ohmic.delay     5", file=f1)
            print("setp db_breakaway.delay 5", file=f1)
            print("setp db_arc-ok.delay    5", file=f1)
            if pinname:
                self.plasmac_ohmic_sense(f1)
            # hints for fine tuning
            print(_("\n\n\n########################################"), file=f1)
            print(_("# The following variables are available for fine tuning some parameters."), file=f1)
            print(_("# To use any of these, uncomment the required setp line and set an appropriate value.\n"), file=f1)
            print(_("# Dampen excessive noise on the arc voltage input"), file=f1)
            print(_("# default = 0 (volts)"), file=f1)
            print("#setp plasmac.lowpass-frequency 0\n", file=f1)
            print(_("# The time delay from losing the arc ok signal until QtPlasmaC reacts to the arc loss."), file=f1)
            print(_("# default = 0.0 (seconds)"), file=f1)
            print("#setp plasmac.arc-lost-delay 0.0\n", file=f1)
            print(_("# For mode 0 Arc-OK only, the number of consecutive readings within the threshold that are required to set the Arc-OK signal."), file=f1)
            print(_("# default = 6"), file=f1)
            print("#setp plasmac.arc-ok-counts 6\n", file=f1)
            print(_("# For mode 0 Arc-OK only, the maximum voltage deviation that is allowed for a valid voltage to set the Arc OK signal."), file=f1)
            print(_("# default = 10 (volts)"), file=f1)
            print("#setp plasmac.arc-ok-threshold 10\n", file=f1)
            print(_("# The voltage above and below 0V that will display as 0V. Prevents small fluctuations from flickering the voltage display."), file=f1)
            print(_("# default = 0 (volts)"), file=f1)
            print("#setp plasmac.zero-window 0\n", file=f1)
            print(_("# The distance (in millimeters) away from the Z MAX_LIMIT that QtPlasmaC will allow the Z axis to travel while under machine control."), file=f1)
            print(_("# default = 5 (mm)"), file=f1)
            print("#setp plasmac.max-offset 5\n", file=f1)
            print(_("# The required number of consecutive times that the threshold has been exceeded before applying the void lock to the THC."), file=f1)
            print(_("# default = 2"), file=f1)
            print("#setp plasmac.kerf-error-max 2\n", file=f1)
            f1.close()
        else:
            f1 = open(chfile, "r")
            chdata = f1.readlines()
            f1.close()
            ohmics = False
            for line in chdata:
                if "plasmac.ohmic-sense" in line:
                    return
            f1 = open(chfile, "w")
            for line in chdata:
                if "db_ohmic.delay" in line and line.split("delay")[1].strip() != '0':
                    print(_("# set to zero if using internal ohmic sensing"), file=f1)
                    line = "setp db_ohmic.delay     0"
                print(line.strip(), file=f1)
            self.plasmac_ohmic_sense(f1)

    def qtplasmac_prefs(self, prefsfile):
        def putPrefs(prefs, file, section, option, value):
            if prefs.has_section(section):
                prefs.set(section, option, str(value))
                prefs.write(open(prefsfile, "w"))
            else:
                prefs.add_section(section)
                prefs.set(section, option, str(value))
                prefs.write(open(prefsfile, "w"))
        from configparser import RawConfigParser
        prefs = RawConfigParser()
        prefs.optionxform = str
        putPrefs(prefs, prefsfile, 'PLASMA_PARAMETERS', 'Arc Voltage Offset', '{:.3f}'.format(self.d.qtplasmacvoffset))
        putPrefs(prefs, prefsfile, 'PLASMA_PARAMETERS', 'Arc Voltage Scale', '{:.6f}'.format(self.d.qtplasmacvscale))
        putPrefs(prefs, prefsfile, 'GUI_OPTIONS', 'Mode', self.d.qtplasmacmode)
        putPrefs(prefs, prefsfile, 'GUI_OPTIONS', 'Estop type', self.d.qtplasmacestop)
        dro = 'top' if self.d.qtplasmacdro else 'bottom'
        putPrefs(prefs, prefsfile, 'GUI_OPTIONS', 'DRO position', dro)
        putPrefs(prefs, prefsfile, 'GUI_OPTIONS', 'Flash error', self.d.qtplasmacerror)
        putPrefs(prefs, prefsfile, 'GUI_OPTIONS', 'Hide run', self.d.qtplasmacstart)
        putPrefs(prefs, prefsfile, 'GUI_OPTIONS', 'Hide pause', self.d.qtplasmacpause)
        putPrefs(prefs, prefsfile, 'GUI_OPTIONS', 'Hide abort', self.d.qtplasmacstop)
        for ub in range(1, 21):
            putPrefs(prefs, prefsfile, 'BUTTONS', '{} Name'.format(ub), self.d.qtplasmac_bnames[ub-1])
            putPrefs(prefs, prefsfile, 'BUTTONS', '{} Code'.format(ub), self.d.qtplasmac_bcodes[ub-1])
        putPrefs(prefs, prefsfile, 'POWERMAX', 'Port', self.d.qtplasmacpmx)

    def plasmac_ohmic_sense(self, f1):
        print(_("\n# ---OHMIC SENSE CONTACT DEBOUNCE---"), file=f1)
        print("setp plasmac.ohmic-sense-off-delay  3", file=f1)
        print("setp plasmac.ohmic-sense-on-delay   3", file=f1)

# BOILER CODE
    def __getitem__(self, item):
        return getattr(self, item)
    def __setitem__(self, item, value):
        return setattr(self, item, value)
