The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Category: Electronics Workbench

Electrical & Electronic gadgets

  • Kicad-to-HAL: Proof of Concept

    Kicad-to-HAL: Proof of Concept

    So it turns out a few hundred lines of Python can convert a Kicad schematic:

    Gamepad Axis Priority - schematic sample
    Gamepad Axis Priority – schematic sample

    Into a LinuxCNC HAL machine configuration file:

    loadrt and2		count=22 
    loadrt flipflop		count=5 
    loadrt not		count=8 
    <<< … etc … >>>
    
    addf and2.0		servo-thread
    <<< … etc … >>>
    
    net X-Knob-Active <= or2.2.out => and2.1.in0 not.0.in
    net X-Knob-Inactive <= not.0.out => and2.2.in0 and2.3.in0
    <<< … etc … >>>
    net Y-Knob-Active <= or2.3.out => and2.3.in1 not.1.in
    net Y-Knob-Inactive <= not.1.out => and2.2.in1
    <<< … etc … >>>
    net _Axis_Priority_XY-Reset <= and2.2.out => flipflop.0.reset flipflop.1.reset
    net _Axis_Priority_Y-Disable <= not.5.out => and2.1.in1
    net _Axis_Priority_Y-Select <= and2.3.out => and2.7.in0
    net _Axis_Priority_Y-Set <= and2.7.out => flipflop.1.set
    

    The Kicad schematic interconnects components from a library defining LinuxCNC HAL devices:

    Kicad symbol - AND2
    Kicad symbol – AND2

    The process goes a little something like this:

    • Draw schematic using components in LinuxCNC-HAL.lib
    • Add missing components to LinuxCNC-HAL.lib
    • Iterate
    • Annotate schematic (starting from 0)
    • Generate netlist in XML format
    • Run Kicad-to-HAL.py with Python 3.9.2 (sorry)
    • Fix whatever LinuxCNC complains about
    • Iterate
    • Fix logic flaws by adjusting schematic
    • Iterate

    The Kicad components include magick HAL features, the Python program rides roughshod over Kicad conventions, and this thing stands deep in “It works for me!” territory, but I must coerce my notes into something resembling coherence before I forget the grisly details.

    More to follow, but you can peruse the Python3 source code and Kicad library as a GitHub Gist:

    # Parse Kicad schematic netlist into a LinuxCNC HAL configuration file
    #
    # Ed Nisley – KE4ZNU
    # 2021-03
    import argparse
    from pathlib import Path
    from lxml import etree
    # ———-
    # remove Kicad annotation from reference as needed
    # kref = Kicad annotated reference
    # component has field entries for anything other than and value
    def cleanHALref(kref):
    comp = etree.XPath('comp[@ref="' + kref + '"]')(components)[0]
    fields = etree.XPath('fields/field[@name="StripAnno"]')(comp)
    if len(fields) and (fields[0].text).startswith("1"):
    retval = kref.rpartition(".")[0]
    else:
    retval = kref
    # print('strip: {} -> {}'.format(kref,retval))
    return retval
    # ———-
    # do the whole thing
    parser = argparse.ArgumentParser(
    description="Process Kicad schematic netlist into LinuxCNC HAL configuration file"
    )
    parser.add_argument("netlist", help="input: Kicad XML netlist file describing HAL configuration")
    parser.add_argument("hal", help="output: LinuxCNC HAL configuration file")
    args = parser.parse_args()
    xmlfn = Path(args.netlist)
    if not xmlfn.exists():
    print("** No such file: {!s}".format(xmlfn))
    exit()
    print("Opening XML file: {!s}".format(xmlfn))
    Netlist = etree.parse(xmlfn.name)
    halfn = Path(args.hal)
    if halfn is None:
    halfn = xmlfn.with_name(xmlfn.stem + ".hal")
    print("Writing HAL file: {!s}".format(halfn))
    halfile = open(halfn, "w")
    design = etree.XPath("//design")(Netlist)[0]
    print("XML date: {}".format(etree.XPath("date")(design)[0].text))
    libraries = etree.XPath("//libraries")(Netlist)[0]
    print("Libraries:")
    for l in libraries:
    print(" {}".format(etree.XPath("uri")(l)[0].text))
    components = etree.XPath("//components")(Netlist)[0]
    print("Components: {:.0f}".format(etree.XPath("count(comp)")(components)))
    libparts = etree.XPath("//libparts")(Netlist)[0]
    print("Library parts: {:.0f}".format(etree.XPath("count(libpart)")(libparts)))
    nets = etree.XPath("//nets")(Netlist)[0]
    print("Nets: {:.0f}".format(etree.XPath("count(net)")(nets)))
    halfile.write("# LinuxCNC HAL file\n\n# Kicad netlist: {}\n".format(xmlfn))
    halfile.write("# {}\n\n".format(etree.XPath("date")(design)[0].text))
    # —–
    # load realtime modules
    # LOADRT components
    comps = etree.XPath('comp[value="LOADRT"]')(components)
    comps.sort(key=lambda r: r.attrib["ref"])
    # print('LRT sort: {}'.format(comps))
    llist = []
    for comp in comps:
    ref = comp.attrib["ref"]
    fld = etree.XPath('fields/field[@name="LoadRT"]')(comp)[0]
    # print(' cfg: {} -> {}'.format(ref,fld.text))
    llist += ["loadrt {}\t\t# {}".format(fld.text, ref)]
    if len(llist):
    llist += [" "]
    # collect all other components with a LoadRT field
    # a leading + indicates a component using Kicad reference counting
    # concatenate rest of field in order of ref sequence
    rtfs = etree.XPath('comp[value!="LOADRT"]/fields/field[@name="LoadRT"]')(components)
    # print('Flds: {}'.format(rtfs))
    rtfs.sort(key=lambda f: f.xpath("ancestor::comp")[0].attrib["ref"])
    modules = {}
    for f in rtfs:
    comp = etree.XPath("ancestor::comp")(f)[0]
    ref = comp.attrib["ref"]
    mod = (etree.XPath("libsource")(comp)[0]).attrib["part"]
    # print(' ref: {} mod: {}'.format(ref,mod))
    if f.text.startswith("+"):
    if mod in modules:
    modules[mod][0] += 1
    modules[mod][1] += f.text.lstrip("+ ")
    else:
    modules.update({mod: [1, f.text.lstrip("+ ")]})
    # print(" added {} {}".format(mod,modules[mod]))
    else:
    llist += ["loadrt {}\t{}\t\t# {}".format(mod, f.text, ref)]
    if len(modules):
    # print('modules: {}'.format(modules))
    for mod, v in sorted(modules.items(), key=lambda kv: kv[0]):
    llist += ["loadrt {}\t\tcount={} {}".format(mod.lower(), v[0], v[1])]
    if len(llist):
    halfile.write("\n#——\n# LoadRT modules\n\n")
    halfile.write("\n".join(llist) + "\n")
    # —–
    # collect LoadUsr fields from components
    llist = []
    ufs = etree.XPath('comp/fields/field[@name="LoadUsr"]')(components)
    # print('Flds: {}'.format(ufs))
    for f in ufs:
    comp = etree.XPath("ancestor::comp")(f)[0]
    ref = comp.attrib["ref"]
    if len(f.text):
    llist += ["loadusr {}\t\t# {}".format(f.text, ref)]
    if len(llist):
    halfile.write("\n#——\n# LoadUsr modules\n\n")
    halfile.write("\n".join(llist) + "\n")
    # —–
    # collect power-input pins into addf statements
    halfile.write("\n#——\n# Function hookups\n\n")
    addflist = []
    # find library THREAD part to get pins for addf sequencing
    tpart = etree.XPath('libpart[@part="THREAD"]')(libparts)[0]
    tpins = etree.XPath("pins/pin")(tpart)
    # print('tpart: {}'.format(tpart))
    # print('tpins: {}'.format(tpins))
    # step through all THREAD components
    tcomps = etree.XPath('comp[value="THREAD"]')(components)
    # print('tcomps: {}'.format(tcomps))
    for tcomp in tcomps:
    tcref = tcomp.attrib["ref"]
    # print('tcomp: {} tref: {}'.format(tcomp,tcref))
    for tpin in tpins:
    pnum = tpin.attrib["num"]
    pname = tpin.attrib["name"]
    # use pin number to find other nodes in net
    pnode = etree.XPath('net/node[@ref="' + tcref + '" and @pin="' + pnum + '"]')(nets)[0]
    nodes = etree.XPath("preceding-sibling::node")(pnode)
    nodes += etree.XPath("following-sibling::node")(pnode)
    # print('nodes: {}'.format(nodes))
    if len(nodes) == 0:
    continue
    nlist = ["# Position: " + pname + "\n"]
    # print(' thread position: {}'.format(pname))
    for node in nodes:
    ref = node.attrib["ref"]
    cleanref = cleanHALref(ref)
    pin = node.attrib["pin"]
    # print(' node: {} ref: {} = {} pin: {}'.format(node,ref,cleanref,pin))
    # look up destination pin name to weed out "_" defaults
    # and find "/" prefix indicating no ref prefix
    dval = etree.XPath('comp[@ref="' + ref + '"]/value')(components)[0]
    # print(' dval: {} {}'.format(dval,dval.text))
    dsrc = etree.XPath('comp[@ref="' + ref + '"]/libsource')(components)[0]
    dpart = dsrc.attrib["part"]
    # print(' dsrc: {} {}'.format(dsrc,dpart))
    ldparts = etree.XPath('libpart[@part="' + dpart + '"]')(libparts)
    # print(' ldparts: {}'.format(ldparts))
    if len(ldparts):
    ldpart = ldparts[0]
    ldpin = etree.XPath('pins/pin[@num="' + pin + '"]')(ldpart)[0]
    ldpname = ldpin.attrib["name"]
    # print(' ldpin: {} name: {} part: {}'.format(ldpin,ldpname,dpart))
    if ldpname == "_":
    nlist += ["addf {}\t\t{}".format(cleanref, cleanHALref(tcref))]
    else:
    if ldpname.startswith("/"):
    nlist += [
    "addf {}\t\t{}".format(ldpname.removeprefix("/"), cleanHALref(tcref))
    ]
    else:
    nlist += ["addf {}.{}\t\t{}".format(cleanref, ldpname, cleanHALref(tcref))]
    if pname == "_":
    nlist.sort()
    addflist += nlist + [" "]
    if len(addflist):
    halfile.write("\n".join(addflist) + "\n")
    # —–
    # set parameter values
    # trace through nets to find other nodes to set
    params = 0
    parlist = []
    for comp in components:
    ref = comp.attrib["ref"]
    # ignore non-parameter components
    if not ref.startswith("parameter."):
    continue
    params += 1
    value = etree.XPath("value")(comp)[0].text
    # print('param: {} = {}'.format(ref,value))
    pnode = etree.XPath('net/node[@ref="' + ref + '"]')(nets)[0]
    nodes = etree.XPath("preceding-sibling::node")(pnode) + etree.XPath("following-sibling::node")(
    pnode
    )
    for node in nodes:
    nref = node.attrib["ref"]
    npin = node.attrib["pin"]
    ncomp = etree.XPath('comp[@ref="' + nref + '"]')(components)[0]
    nls = etree.XPath("libsource")(ncomp)[0]
    nname = nls.attrib["part"]
    lpart = etree.XPath('libpart[@part="' + nname + '"]')(libparts)[0]
    lpin = etree.XPath('pins/pin[@num="' + npin + '"]')(lpart)[0]
    # print('ref: {} nref: {} npin: {} lpin: {}'.format(ref,cleanHALref(nref),npin,lpin))
    parlist += [
    "setp {}.{} {}\t\t# {}".format(cleanHALref(nref), lpin.attrib["name"], value, ref)
    ]
    if len(parlist):
    halfile.write("\n#——\n# Parameters\n\n")
    parlist.sort()
    halfile.write("\n".join(parlist) + "\n")
    print("Parameters: {}".format(params))
    # —–
    # set constant parameters
    # the .value pin is hardcoded here to keep the schematic part tidy
    consts = 0
    conlist = []
    for comp in components:
    ref = comp.attrib["ref"]
    # ignore non-constant components
    if not ref.startswith("constant."):
    continue
    consts += 1
    value = etree.XPath("value")(comp)[0].text
    # print('const: {} = {}'.format(ref,value))
    pval = ref + ".value"
    conlist += ["setp {} {}".format(pval, value)]
    if len(conlist):
    halfile.write("\n#——\n# Constants\n\n")
    conlist.sort()
    halfile.write("\n".join(conlist) + "\n")
    print("Constants: {}".format(consts))
    # —–
    # generate HAL net connections
    halfile.write("\n#——\n# Nets\n\n")
    hallist = []
    single = 0
    multi = 0
    netID = 1
    for net in nets:
    name = net.attrib["name"]
    # skip special net for unconnected addf functions
    if name == "_":
    multi += 1
    continue
    # print('net {}'.format(net.attrib))
    nodes = etree.XPath("node")(net)
    # skip single-pin nets
    # suppress error for pin names starting with *
    if len(nodes) < 2:
    if not (name.startswith("Net-") or name.startswith("*")):
    hallist += [
    "#* Named net with single pin: {} {}\n".format(nodes[0].attrib["ref"], name)
    ]
    single += 1
    continue
    nameclean = name.translate(name.maketrans("/ ", "__", "()"))
    # print('name: {} -> {}'.format(name,nameclean))
    multi += 1
    halstr = "net "
    halsinks = []
    outputs = 0
    for node in nodes:
    ref = node.attrib["ref"]
    pnum = node.attrib["pin"]
    # print('node: {}'.format(node.attrib))
    comp = etree.XPath('comp[@ref="' + ref + '"]')(components)[0]
    ls = etree.XPath("libsource")(comp)[0]
    # print('libsource: {}'.format(ls.attrib))
    lpart = etree.XPath('libpart[@part="' + ls.attrib["part"] + '"]')(libparts)[0]
    # print('libpart: {}'.format(lpart.attrib))
    lpin = etree.XPath('pins/pin[@num="' + pnum + '"]')(lpart)[0]
    pname = lpin.attrib["name"]
    cleanname = pname.lstrip("*")
    ptype = lpin.attrib["type"]
    # print('pin: {} {}'.format(ptype,pname))
    if ptype == "output":
    if name.startswith("Net-"):
    halstr += "N_{:0>3d} <= {}.{} => ".format(netID, cleanHALref(ref), cleanname)
    netID += 1
    else:
    halstr += "{} <= {}.{} => ".format(nameclean, cleanHALref(ref), cleanname)
    outputs += 1
    else:
    halsinks += [cleanHALref(ref) + "." + cleanname]
    halstr += " ".join(sorted(halsinks))
    if "parameter" in halstr or "-thread" in halstr: # discard parameters and threads
    # print('discard: {}'.format(halstr))
    multi -= 1
    continue
    elif outputs == 0:
    halstr = "#* No output pins: {}\n".format(halstr)
    elif outputs > 1:
    halstr = "#* Multiple output pins: {}\n".format(halstr)
    # print('result {}'.format(halstr))
    hallist += [halstr]
    if len(hallist):
    hallist.sort()
    halfile.write("\n".join(hallist) + "\n")
    halfile.write("\n#——\n# Done!\n")
    halfile.close()
    # print(' = 1 : {:d}'.format(single))
    # print(' > 1 : {:d}'.format(multi))
    view raw Kicad-to-HAL.py hosted with ❤ by GitHub
    EESchema-LIBRARY Version 2.4
    #encoding utf-8
    #
    # AND2
    #
    DEF AND2 and2. 0 0 N Y 1 F N
    F0 "and2." 0 200 50 H V C CNN
    F1 "AND2" 0 0 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    A 0 0 150 0 900 0 1 0 f 150 0 0 150
    A 0 0 150 0 -900 0 1 0 f 150 0 0 -150
    P 4 0 1 0 0 150 -150 150 -150 -150 0 -150 f
    X in0 1 -300 100 150 R 50 50 1 1 I
    X in1 2 -300 -100 150 R 50 50 1 1 I
    X out 3 300 0 150 L 50 50 1 1 O
    X _ 4 -250 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # COMP
    #
    DEF COMP comp. 0 20 N Y 1 F N
    F0 "comp." -50 300 50 H V C CNN
    F1 "COMP" -50 200 50 H V C CNN
    F2 "" 300 -50 50 H I C CNN
    F3 "" 300 -50 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    T 0 -100 -50 50 0 0 0 + Normal 0 C C
    T 0 -100 50 50 0 0 0 – Normal 0 C C
    S 200 150 -300 250 0 1 0 f
    S -300 150 200 -350 1 1 0 N
    X in0 1 -400 50 100 R 50 50 1 1 I
    X out 2 300 50 100 L 50 50 1 1 O
    X in1 3 -400 -50 100 R 50 50 1 1 I
    X hyst 4 -400 -250 154 R 50 50 1 1 I I
    X _ 5 -400 -150 100 R 50 50 1 1 W NC
    X equal 6 300 -50 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # CONSTANT
    #
    DEF CONSTANT constant. 0 0 N N 1 F N
    F0 "constant." 0 100 50 H I C CNN
    F1 "CONSTANT" 150 0 50 H V R CNN
    F2 "" 250 -250 50 H I C CNN
    F3 "" 250 -250 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    P 4 0 1 0 -250 50 200 50 200 -50 -250 -50 N
    X out 1 400 0 200 L 50 50 1 1 O
    X _ 2 -350 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # CONV_FLOAT_S32
    #
    DEF CONV_FLOAT_S32 conv-float-s32. 0 20 N Y 1 F N
    F0 "conv-float-s32." 0 300 50 H V C CNN
    F1 "CONV_FLOAT_S32" 0 200 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "+" 0 100 50 H I C CNN "LoadRT"
    DRAW
    S 400 150 -400 250 0 1 0 f
    S -400 150 400 -150 1 1 0 N
    X in 1 -500 100 100 R 50 50 1 1 I
    X clamp 2 -500 -100 157 R 50 50 1 1 I I
    X out-of-range 3 500 0 100 L 50 50 1 1 O
    X out 4 500 100 100 L 50 50 1 1 O
    X _ 5 -500 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # CONV_FLOAT_U32
    #
    DEF CONV_FLOAT_U32 conv-float-u32. 0 40 N Y 1 F N
    F0 "conv-float-u32." 0 300 50 H V C CNN
    F1 "CONV_FLOAT_U32" 0 200 50 H V C CNN
    F2 "" 0 50 50 H I C CNN
    F3 "" 0 50 50 H I C CNN
    F4 "+" 0 100 50 H I C CNN "LoadRT"
    DRAW
    S -400 150 400 -150 1 1 0 N
    S 400 150 -400 250 1 1 0 f
    X in 1 -500 100 100 R 50 50 1 1 I
    X clamp 2 -500 -100 157 R 50 50 1 1 I I
    X out-of-range 3 500 0 100 L 50 50 1 1 O
    X out 4 500 100 100 L 50 50 1 1 O
    X _ 5 -500 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # DBOUNCE
    #
    DEF DBOUNCE dbounce. 0 20 N Y 1 F N
    F0 "dbounce." 0 300 50 H V C CNN
    F1 "DBOUNCE" 0 200 50 H V C CNN
    F2 "" 600 -350 50 H I C CNN
    F3 "" 600 -350 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 200 150 -200 250 0 1 0 f
    S -200 150 200 -150 1 1 0 N
    X in 1 -300 100 100 R 50 50 1 1 I
    X out 2 300 100 100 L 50 50 1 1 O
    X delay 3 -300 -100 100 R 50 50 1 1 I
    X _ 4 -300 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # FLIPFLOP
    #
    DEF FLIPFLOP flipflop. 0 20 N Y 1 F N
    F0 "flipflop." 0 450 50 H V C CNN
    F1 "FLIPFLOP" 0 350 50 H V C CNN
    F2 "" 400 -150 50 H I C CNN
    F3 "" 400 -150 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 200 300 -200 400 0 1 0 f
    S -200 300 200 -300 1 1 0 N
    X data 2 -300 200 100 R 50 50 1 0 I
    X out 5 300 0 100 L 50 50 1 0 O
    X reset 1 -300 -200 100 R 50 50 1 1 I
    X clk 3 -300 100 100 R 50 50 1 1 I
    X set 4 -300 -100 100 R 50 50 1 1 I
    X _ 6 -300 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # HALUI
    #
    DEF HALUI halui. 0 40 N Y 1 F N
    F0 "halui." 0 500 59 H V C CNN
    F1 "HALUI" 0 400 50 H V C CNN
    F2 "" -150 300 50 H I C CNN
    F3 "" -150 300 50 H I C CNN
    F4 "1" 350 400 50 H V C CNN "StripAnno"
    DRAW
    S -400 -300 400 350 0 1 0 N
    S -400 450 400 350 0 1 0 f
    X abort 1 -500 250 100 R 0 50 1 0 I
    X home-all 2 -500 100 100 R 50 50 1 1 I
    X mdi-command-00 ~ -500 -100 100 R 50 50 1 1 I
    X mdi-command-01 ~ -500 -200 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_AXIS
    #
    DEF HALUI_AXIS halui.axis. 0 40 N Y 1 F N
    F0 "halui.axis." 0 400 50 H V C CNN
    F1 "HALUI_AXIS" 0 300 50 H V C CNN
    F2 "" 450 400 50 H I C CNN
    F3 "" 450 400 50 H I C CNN
    F4 "1" 500 300 50 H V C CNN "StripAnno"
    DRAW
    S -550 -50 550 250 0 1 0 N
    S 550 350 -550 250 0 1 0 f
    X jog-deadband 1 -650 50 100 R 50 50 1 1 I
    X jog-speed 2 -650 150 100 R 50 50 1 1 I
    X selected 3 650 150 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_AXIS_L
    #
    DEF HALUI_AXIS_L halui.axis.x. 0 40 N Y 1 F N
    F0 "halui.axis.x." 0 400 50 H V C CNN
    F1 "HALUI_AXIS_L" 0 300 50 H V C CNN
    F2 "" -100 350 50 H I C CNN
    F3 "" -100 350 50 H I C CNN
    F4 "1" 600 300 50 H V C CNN "StripAnno"
    DRAW
    S -650 350 650 250 0 1 0 f
    S 650 250 -650 -600 0 1 0 N
    X analog 1 -750 50 100 R 50 50 1 1 I
    X pos-relative 10 750 -150 100 L 50 50 1 1 O
    X select 11 -750 200 100 R 50 50 1 1 I
    X increment 2 -750 -100 100 R 50 50 1 1 I
    X increment-minus 3 -750 -200 100 R 50 50 1 1 I
    X increment-plus 4 -750 -300 100 R 50 50 1 1 I
    X is-selected 5 750 200 100 L 50 50 1 1 O
    X minus 6 -750 -450 100 R 50 50 1 1 I
    X plus 7 -750 -550 100 R 50 50 1 1 I
    X pos-commanded 8 750 50 100 L 50 50 1 1 O
    X pos-feedback 9 750 -50 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_AXIS_SELECTED
    #
    DEF HALUI_AXIS_SELECTED halui.axis.selected. 0 40 N Y 1 F N
    F0 "halui.axis.selected." 50 400 50 H V C CNN
    F1 "HALUI_AXIS_SELECTED" 50 300 50 H V C CNN
    F2 "" 1200 850 50 H I C CNN
    F3 "" 1200 850 50 H I C CNN
    F4 "1" 550 300 50 H V C CNN "StripAnno"
    DRAW
    S -500 -500 600 250 1 1 0 N
    S 600 350 -500 250 1 1 0 f
    X increment 1 -600 150 100 R 50 50 1 1 I
    X increment-minus 2 -600 0 100 R 50 50 1 1 I
    X increment-plus 3 -600 -100 100 R 50 50 1 1 I
    X minus 4 -600 -300 100 R 50 50 1 1 I
    X plus 5 -600 -400 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_ESTOP
    #
    DEF HALUI_ESTOP halui.estop. 0 40 N Y 1 F N
    F0 "halui.estop." 0 300 50 H V C CNN
    F1 "HALUI_ESTOP" 0 200 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "1" 300 200 50 H V C CNN "StripAnno"
    DRAW
    S -350 -150 350 150 0 1 0 N
    S 350 150 -350 250 0 1 0 f
    X activate 1 -450 100 100 R 0 50 1 1 I
    X is-activated 2 450 0 100 L 0 50 1 1 O
    X reset 3 -450 -100 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_FEED_OVERRIDE
    #
    DEF HALUI_FEED_OVERRIDE halui.feed-override. 0 40 N Y 1 F N
    F0 "halui.feed-override." 0 450 50 H V C CNN
    F1 "HALUI_FEED_OVERRIDE" 0 350 50 H V C CNN
    F2 "" 200 50 50 H I C CNN
    F3 "" 200 50 50 H I C CNN
    F4 "1" 500 350 50 H V C CNN "StripAnno"
    DRAW
    S -450 -400 450 300 0 1 0 N
    S 450 300 -450 400 0 1 0 f
    X count-enable 1 -550 250 100 R 0 50 1 1 I
    X counts 2 -550 150 100 R 0 50 1 1 I
    X decrease 3 -550 -100 100 R 0 50 1 1 I
    X direct-value 4 -550 -250 100 R 0 50 1 1 I
    X increase 5 -550 0 100 R 0 50 1 1 I
    X scale 6 -550 -350 100 R 0 50 1 1 I
    X value 7 550 250 100 L 0 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_FLOOD
    #
    DEF HALUI_FLOOD halui.flood. 0 40 N Y 1 F N
    F0 "halui.flood." 0 250 50 H V C CNN
    F1 "HALUI_FLOOD" 0 150 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "1" 350 150 50 H V C CNN "StripAnno"
    DRAW
    S -300 100 300 -100 1 1 0 N
    S -300 200 300 100 1 1 0 f
    X is-on 1 400 0 100 L 0 50 1 1 O
    X off 2 -400 -50 100 R 0 50 1 1 I
    X on 3 -400 50 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_JOINT
    #
    DEF HALUI_JOINT halui.joint. 0 40 N Y 1 F N
    F0 "halui.joint." 0 200 50 H V C CNN
    F1 "HALUI_JOINT" 0 100 50 H V C CNN
    F2 "" 750 150 50 H I C CNN
    F3 "" 750 150 50 H I C CNN
    F4 "1" 400 100 50 H V C CNN "StripAnno"
    DRAW
    S 450 50 -450 -250 1 1 0 N
    S 450 50 -450 150 1 1 0 f
    X jog-deadband 1 -550 -150 100 R 50 50 1 1 I
    X selected 2 550 -50 100 L 50 50 1 1 O
    X jog-speed 3 -550 -50 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_JOINT_N
    #
    DEF HALUI_JOINT_N halui.joint.0. 0 40 N Y 1 F N
    F0 "halui.joint.0." 0 300 50 H V C CNN
    F1 "HALUI_JOINT_N" 0 200 50 H V C CNN
    F2 "" 400 300 50 H I C CNN
    F3 "" 400 300 50 H I C CNN
    F4 "1" 700 200 50 H V C CNN "StripAnno"
    DRAW
    S -800 -1050 750 150 0 1 0 N
    S 750 150 -800 250 0 1 0 f
    X minus 1 -900 -850 100 R 50 50 1 1 I
    X analog 10 -900 -350 100 R 50 50 1 1 I
    X is-selected 11 850 50 100 L 50 50 1 1 O
    X is-homed 12 850 -100 100 L 50 50 1 1 O
    X increment-plus 13 -900 -700 100 R 50 50 1 1 I
    X increment-minus 14 -900 -600 100 R 50 50 1 1 I
    X increment 15 -900 -500 100 R 50 50 1 1 I
    X home 16 -900 -100 100 R 50 50 1 1 I
    X has-fault 17 850 -950 100 L 50 50 1 1 O
    X unhome 2 -900 -200 100 R 50 50 1 1 I
    X select 3 -900 50 100 R 50 50 1 1 I
    X plus 4 -900 -950 100 R 50 50 1 1 I
    X override-limits 5 850 -850 100 L 50 50 1 1 O
    X on-soft-min-limit 6 850 -700 100 L 50 50 1 1 O
    X on-soft-max-limit 7 850 -600 100 L 50 50 1 1 O
    X on-hard-min-limit 8 850 -450 100 L 50 50 1 1 O
    X on-hard-max-limit 9 850 -350 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_JOINT_SELECTED
    #
    DEF HALUI_JOINT_SELECTED halui.joint.selected. 0 40 N Y 1 F N
    F0 "halui.joint.selected." 0 500 50 H V C CNN
    F1 "HALUI_JOINT_SELECTED" 0 400 50 H V C CNN
    F2 "" 150 450 50 H I C CNN
    F3 "" 150 450 50 H I C CNN
    F4 "1" 700 400 50 H V C CNN "StripAnno"
    DRAW
    S 750 350 -800 -550 0 1 0 N
    S 750 350 -800 450 0 1 0 f
    X is-homed 1 850 250 100 L 50 50 1 1 O
    X increment-plus 10 -900 -200 100 R 50 50 1 1 I
    X increment-minus 11 -900 -100 100 R 50 50 1 1 I
    X increment 12 -900 0 100 R 50 50 1 1 I
    X home 13 -900 250 100 R 50 50 1 1 I
    X has-fault 14 850 150 100 L 50 50 1 1 O
    X unhome 2 -900 150 100 R 50 50 1 1 I
    X plus 3 -900 -450 100 R 50 50 1 1 I
    X override-limits 4 850 -450 100 L 50 50 1 1 O
    X on-soft-min-limit 5 850 -350 100 L 50 50 1 1 O
    X on-soft-max-limit 6 850 -250 100 L 50 50 1 1 O
    X on-hard-min-limit 7 850 -100 100 L 50 50 1 1 O
    X on-hard-max-limit 8 850 0 100 L 50 50 1 1 O
    X minus 9 -900 -350 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_LUBE
    #
    DEF HALUI_LUBE halui.lube. 0 40 N Y 1 F N
    F0 "halui.lube." 0 250 50 H V C CNN
    F1 "HALUI_LUBE" -50 150 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "1" 250 150 50 H V C CNN "StripAnno"
    DRAW
    S -300 100 300 -100 1 1 0 N
    S -300 200 300 100 1 1 0 f
    X is-on 1 400 0 100 L 0 50 1 1 O
    X off 2 -400 -50 100 R 0 50 1 1 I
    X on 3 -400 50 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_MACHINE
    #
    DEF HALUI_MACHINE halui.machine. 0 40 N Y 1 F N
    F0 "halui.machine." 0 300 50 H V C CNN
    F1 "HALUI_MACHINE" 0 200 50 H V C CNN
    F2 "" 2450 1450 50 H I C CNN
    F3 "" 2450 1450 50 H I C CNN
    F4 "1" 400 200 50 H V C CNN "StripAnno"
    DRAW
    S -400 -250 450 150 0 1 0 N
    S 450 150 -400 250 0 1 0 f
    X is-on 1 550 50 100 L 0 50 1 1 O
    X off 2 -500 -50 100 R 0 50 1 1 I
    X on 3 -500 50 100 R 0 50 1 1 I
    X units-per-mm 4 550 -150 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_MAX_VELOCITY
    #
    DEF HALUI_MAX_VELOCITY halui.max-velocity. 0 40 N Y 1 F N
    F0 "halui.max-velocity." 0 550 50 H V C CNN
    F1 "HALUI_MAX_VELOCITY" -50 450 50 H V C CNN
    F2 "" 1350 900 50 H I C CNN
    F3 "" 1350 900 50 H I C CNN
    F4 "1" 450 450 50 H V C CNN "StripAnno"
    DRAW
    S -500 -400 500 400 0 1 0 N
    S 500 400 -500 500 0 1 0 f
    X direct-value 1 -600 -200 100 R 50 50 0 0 I
    X count 2 -600 200 100 R 0 50 1 1 I
    X count-enable 3 -600 300 100 R 0 50 1 1 I
    X decrease 4 -600 50 100 R 0 50 1 1 I
    X increase 5 -600 -50 100 R 0 50 1 1 I
    X scale 6 -600 -300 100 R 0 50 1 1 I
    X value 7 600 200 100 L 0 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_MIST
    #
    DEF HALUI_MIST halui.mist. 0 40 N Y 1 F N
    F0 "halui.mist." 0 250 50 H V C CNN
    F1 "HALUI_MIST" 0 150 50 H V C CNN
    F2 "" 0 -50 50 H I C CNN
    F3 "" 0 -50 50 H I C CNN
    F4 "1" 300 150 50 H V C CNN "StripAnno"
    DRAW
    S -300 100 350 -100 0 1 0 N
    S -300 200 350 100 0 1 0 f
    X is-on 1 450 0 100 L 0 50 1 1 O
    X off 2 -400 -50 100 R 0 50 1 1 I
    X on 3 -400 50 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_MODE
    #
    DEF HALUI_MODE halui.mode. 0 40 N Y 1 F N
    F0 "halui.mode." 0 500 50 H V C CNN
    F1 "HALUI_MODE" 0 400 50 H V C CNN
    F2 "" 900 750 50 H I C CNN
    F3 "" 900 750 50 H I C CNN
    F4 "1" 350 400 50 H V C CNN "StripAnno"
    DRAW
    S -400 -650 400 350 0 1 0 N
    S 400 350 -400 450 0 1 0 f
    X auto 1 -500 250 100 R 0 50 1 1 I
    X teleop 10 -500 -550 100 R 0 50 1 1 I
    X is-auto 2 500 250 100 L 0 50 1 1 O
    X is-joint 3 500 50 100 L 0 50 1 1 O
    X is-manual 4 500 -150 100 L 0 50 1 1 O
    X is-mdi 5 500 -350 100 L 0 50 1 1 O
    X is-teleop 6 500 -550 100 L 0 50 1 1 O
    X joint 7 -500 50 100 R 0 50 1 1 I
    X manual 8 -500 -150 100 R 0 50 1 1 I
    X mdi 9 -500 -350 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_PROGRAM
    #
    DEF HALUI_PROGRAM halui.program. 0 40 N Y 1 F N
    F0 "halui.program." -50 550 50 H V C CNN
    F1 "HALUI_PROGRAM" -50 450 50 H V C CNN
    F2 "" 50 300 50 H I C CNN
    F3 "" 50 300 50 H I C CNN
    F4 "1" 400 450 50 H V C CNN "StripAnno"
    DRAW
    S -500 400 450 -950 0 1 0 N
    S 450 400 -500 500 0 1 0 f
    X block-delete.is-on 1 550 -750 100 L 0 50 1 1 O
    X pause 10 -600 -50 100 R 0 50 1 1 I
    X resume 11 -600 -150 100 R 0 50 1 1 I
    X run 12 -600 300 100 R 0 50 1 1 I
    X step 13 -600 200 100 R 0 50 1 1 I
    X stop 14 -600 100 100 R 0 50 1 1 I
    X block-delete.off 2 -600 -850 100 R 0 50 1 1 I
    X block-delete.on 3 -600 -650 100 R 0 50 1 1 I
    X is-idle 4 550 200 100 L 0 50 1 1 O
    X is-paused 5 550 -50 100 L 0 50 1 1 O
    X is-running 6 550 300 100 L 0 50 1 1 O
    X optional-stop.is-on 7 550 -400 100 L 0 50 1 1 O
    X optional-stop.off 8 -600 -500 100 R 0 50 1 1 I
    X optional-stop.on 9 -600 -300 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_RAPID_OVERRIDE
    #
    DEF HALUI_RAPID_OVERRIDE halui.rapid-override. 0 40 N Y 1 F N
    F0 "halui.rapid-override." 0 450 50 H V C CNN
    F1 "HALUI_RAPID_OVERRIDE" -50 350 50 H V C CNN
    F2 "" 1050 750 50 H I C CNN
    F3 "" 1050 750 50 H I C CNN
    F4 "1" 500 350 50 H V C CNN "StripAnno"
    DRAW
    S -550 -500 550 300 1 1 0 N
    S 550 300 -550 400 1 1 0 f
    X count-enable 1 -650 200 100 R 0 50 1 1 I
    X counts 2 -650 100 100 R 0 50 1 1 I
    X decrease 3 -650 -150 100 R 0 50 1 1 I
    X direct-value 4 -650 -300 100 R 0 50 1 1 I
    X increase 5 -650 -50 100 R 0 50 1 1 I
    X scale 6 -650 -400 100 R 0 50 1 1 I
    X value 7 650 200 100 L 0 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HALUI_SPINDLE_N
    #
    DEF HALUI_SPINDLE_N halui.spindle.0. 0 40 N Y 1 F N
    F0 "halui.spindle.0." 0 900 50 H V C CNN
    F1 "HALUI_SPINDLE_N" 0 800 50 H V C CNN
    F2 "" -50 1450 50 H I C CNN
    F3 "" -50 1450 50 H I C CNN
    F4 "1" 550 800 50 H V C CNN "StripAnno"
    DRAW
    S -650 -950 600 750 0 1 0 N
    S 600 750 -650 850 0 1 0 f
    X override.direct-value 11 -750 -850 100 R 50 50 0 0 I
    X override.counts 1 -750 -550 100 R 0 50 1 1 I
    X override.decrease 10 -750 -650 100 R 0 50 1 1 I
    X override.count-enable 12 -750 -450 100 R 0 50 1 1 I
    X is-on 13 700 -100 100 L 0 50 1 1 O
    X increase 14 -750 150 100 R 0 50 1 1 I
    X forward 15 -750 400 100 R 0 50 1 1 I
    X decrease 16 -750 50 100 R 0 50 1 1 I
    X brake.off 17 -750 550 100 R 0 50 1 1 I
    X brake-on 18 -750 650 100 R 0 50 1 1 I
    X brake-is-on 19 700 650 100 L 0 50 1 1 O
    X stop 2 -750 -200 100 R 0 50 1 1 I
    X start 3 -750 -100 100 R 0 50 1 1 I
    X runs-forward 4 700 400 100 L 0 50 1 1 O
    X runs-backwards 5 700 300 100 L 0 50 1 1 O
    X reverse 6 -750 300 100 R 0 50 1 1 I
    X override.value 7 700 -350 100 L 0 50 1 1 O
    X override.scale 8 -750 -350 100 R 0 50 1 1 I
    X override.increase 9 -750 -750 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HALUI_TOOL
    #
    DEF HALUI_TOOL halui.tool. 0 40 N Y 1 F N
    F0 "halui.tool." -50 750 50 H V C CNN
    F1 "HALUI_TOOL" -50 650 50 H V C CNN
    F2 "" -50 300 50 H I C CNN
    F3 "" -50 300 50 H I C CNN
    F4 "1" 250 650 50 H V C CNN "StripAnno"
    DRAW
    S -400 600 300 700 0 1 0 f
    S 300 600 -400 -800 0 1 0 N
    X diameter 1 400 400 100 L 0 50 1 1 O
    X length-offset.z 10 400 -700 100 L 0 50 1 1 O
    X number 11 400 500 100 L 0 50 1 1 O
    X length-offset.a 2 400 250 100 L 0 50 1 1 O
    X length-offset.b 3 400 150 100 L 0 50 1 1 O
    X length-offset.c 4 400 50 100 L 0 50 1 1 O
    X length-offset.u 5 400 -150 100 L 0 50 1 1 O
    X length-offset.v 6 400 -250 100 L 0 50 1 1 O
    X length-offset.w 7 400 -350 100 L 0 50 1 1 O
    X length-offset.x 8 400 -500 100 L 0 50 1 1 O
    X length-offset.y 9 400 -600 100 L 0 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # HAL_MANUALTOOLCHANGE
    #
    DEF HAL_MANUALTOOLCHANGE hal_manualtoolchange. 0 40 Y Y 1 F N
    F0 "hal_manualtoolchange." -50 300 59 H V C CNN
    F1 "HAL_MANUALTOOLCHANGE" -100 200 50 H V C CNN
    F2 "" 0 -100 50 H I C CNN
    F3 "" 0 -100 50 H I C CNN
    F4 "1" 450 200 50 H V C CNN "StripAnno"
    F5 "-W hal_manualtoolchange" -50 100 50 H V C CNN "LoadUsr"
    DRAW
    S -600 -450 500 50 1 1 0 N
    S 500 50 -600 250 1 1 0 f
    X change 1 -700 -50 100 R 0 50 1 0 I
    X change_button 2 -700 -200 100 R 0 50 1 0 I
    X changed 3 600 -50 100 L 0 50 1 0 O
    X number 4 -700 -350 100 R 0 50 1 0 I
    ENDDRAW
    ENDDEF
    #
    # HM2_5I25
    #
    DEF HM2_5I25 hm2_5i25.0. 0 20 N Y 1 F N
    F0 "hm2_5i25.0." 0 500 50 H V C CNN
    F1 "HM2_5I25" 0 400 50 H V C CNN
    F2 "" 550 -200 50 H I C CNN
    F3 "" 550 -200 50 H I C CNN
    F4 "1" 400 400 50 H V C CNN "StripAnno"
    DRAW
    S -450 350 450 -550 0 1 0 N
    S 450 350 -450 450 0 1 0 f
    X watchdog.timeout_ns 8 -550 50 157 R 50 50 1 0 I I
    X watchdog.has_bit 1 550 -50 100 L 50 50 1 1 O
    X led.CR01 2 -550 300 100 R 50 50 1 1 I
    X led.CR02 3 -550 200 100 R 50 50 1 1 I
    X read 4 -550 -150 100 R 50 50 1 1 W C
    X *read_gpio 5 -550 -350 100 R 50 50 1 1 W NC
    X write 6 -550 -250 100 R 50 50 1 1 W C
    X *write_gpio 7 -550 -450 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # HM2_5I25_GPIO
    #
    DEF HM2_5I25_GPIO hm2_5i25.0.gpio.000. 0 40 N Y 1 F N
    F0 "hm2_5i25.0.gpio.000." 0 300 50 H V C CNN
    F1 "HM2_5I25_GPIO" -50 200 50 H V C CNN
    F2 "" 150 -250 50 H I C CNN
    F3 "" 150 -250 50 H I C CNN
    F4 "1" 350 200 50 H V C CNN "StripAnno"
    DRAW
    S -400 150 400 250 0 1 0 f
    S 400 150 -400 -350 0 1 0 N
    X in 1 500 100 100 L 50 50 1 1 O
    X in_not 2 500 0 100 L 50 50 1 1 O
    X invert_output 3 -500 -200 157 R 50 50 1 1 I I
    X is_opendrain 4 -500 -300 157 R 50 50 1 1 I I
    X is_output 5 -500 -100 157 R 50 50 1 1 I I
    X out 6 -500 100 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # HM2_5I25_STEPGEN
    #
    DEF HM2_5I25_STEPGEN hm2_5i25.0.stepgen.00. 0 20 N Y 1 F N
    F0 "hm2_5i25.0.stepgen.00." -50 900 50 H V C CNN
    F1 "HM2_5I25_STEPGEN" -50 800 50 H V C CNN
    F2 "" 0 500 50 H I C CNN
    F3 "" 0 500 50 H I C CNN
    F4 "1" 400 800 50 H V C CNN "StripAnno"
    DRAW
    S -500 750 450 -1250 0 1 0 N
    S -500 850 450 750 0 1 0 f
    X control-type 1 -600 500 100 R 50 50 1 1 I
    X position-scale 10 -600 -50 157 R 50 50 1 1 I I
    X step_type 11 -600 -1150 157 R 50 50 1 1 I I
    X steplen 12 -600 -200 157 R 50 50 1 1 I I
    X stepspace 13 -600 -300 157 R 50 50 1 1 I I
    X step.invert_output 14 -600 -400 157 R 50 50 1 1 I I
    X direction.invert_output 15 -600 -750 157 R 50 50 1 1 I I
    X velocity-cmd 16 -600 200 100 R 50 50 1 1 I
    X velocity-fb 17 550 100 100 L 50 50 1 1 O
    X counts 2 550 650 100 L 50 50 1 1 O
    X dirhold 3 -600 -650 157 R 50 50 1 1 I I
    X dirsetup 4 -600 -550 157 R 50 50 1 1 I I
    X enable 5 -600 650 100 R 50 50 1 1 I
    X maxaccel 6 -600 -1000 157 R 50 50 1 1 I I
    X maxvel 7 -600 -900 157 R 50 50 1 1 I I
    X position-cmd 8 -600 400 100 R 50 50 1 1 I
    X position-fb 9 550 300 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # IOCONTROL
    #
    DEF IOCONTROL iocontrol.0. 0 40 N Y 1 F N
    F0 "iocontrol.0." 0 700 59 H V C CNN
    F1 "IOCONTROL" 0 600 50 H V C CNN
    F2 "" -100 200 50 H I C CNN
    F3 "" -100 200 50 H I C CNN
    F4 "1" 650 600 50 H V C CNN "StripAnno"
    DRAW
    S -750 550 700 650 1 1 0 f
    S 700 550 -750 -950 1 1 0 N
    X coolant-flood 1 800 -50 100 L 0 50 1 0 O
    X tool-prep-pocket 10 800 -750 100 L 0 50 1 0 O
    X tool-prepare 11 800 -550 100 L 0 50 1 0 O
    X tool-prepared 12 -850 -550 100 R 0 50 1 0 I
    X user-enable-out 13 800 450 100 L 0 50 1 0 O
    X user-request-enable 14 800 350 100 L 0 50 1 0 O
    X coolant-mist 2 800 -150 100 L 0 50 1 0 O
    X emc-enable-in 3 -850 450 100 R 0 50 1 0 I
    X lube 4 800 150 100 L 0 50 1 0 O
    X lube-level 5 -850 150 100 R 0 50 1 0 I
    X tool-change 6 800 -850 100 L 0 50 1 0 O
    X tool-changed 7 -850 -850 100 R 0 50 1 0 I
    X tool-number 8 800 -350 100 L 0 50 1 0 O
    X tool-prep-number 9 800 -650 100 L 0 50 1 0 O
    X tool-prep-index 15 800 -450 157 L 50 50 1 1 O I
    ENDDRAW
    ENDDEF
    #
    # JOINT_N
    #
    DEF JOINT_N joint.0. 0 40 N Y 1 F N
    F0 "joint.0." 0 800 50 H V C CNN
    F1 "JOINT_N" 0 700 50 H V C CNN
    F2 "" 1050 150 50 H I C CNN
    F3 "" 1050 150 50 H I C CNN
    F4 "1" 700 700 50 H V C CNN "StripAnno"
    DRAW
    S -700 650 750 -1500 0 1 0 N
    S -700 650 750 750 0 1 0 f
    X jog-enable 1 -800 -950 100 R 50 50 1 1 I
    X motor-pos-cmd 10 850 550 100 L 50 50 1 1 O
    X jog-vel-mode 11 -800 -1150 100 R 50 50 1 1 I
    X jog-scale 12 -800 -1050 100 R 50 50 1 1 I
    X active 13 850 50 100 L 50 50 1 1 O
    X jog-counts 14 -800 -850 100 R 50 50 1 1 I
    X jog-accel-fraction 15 -800 -750 100 R 50 50 1 1 I
    X is-unlocked 16 -800 -600 100 R 50 50 1 1 I
    X index-enable 17 -800 -450 100 R 50 50 1 1 B
    X homing 18 850 -450 100 L 50 50 1 1 O
    X homed 19 850 -350 100 L 50 50 1 1 O
    X unlock 2 850 -600 100 L 50 50 1 1 O
    X home-sw-in 20 -800 -350 100 R 50 50 1 1 I
    X faulted 21 850 -150 100 L 50 50 1 1 O
    X error 22 850 -50 100 L 50 50 1 1 O
    X amp-fault-in 23 -800 -150 100 R 50 50 1 1 I
    X amp-enable-out 24 850 450 100 L 50 50 1 1 O
    X pos-lim-sw-in 3 -800 -1400 100 R 50 50 1 1 I
    X pos-hard-limit 4 850 -1400 100 L 50 50 1 1 O
    X pos-fb 5 850 200 100 L 50 50 1 1 O
    X pos-cmd 6 850 300 100 L 50 50 1 1 O
    X neg-lim-sw-in 7 -800 -1300 100 R 50 50 1 1 I
    X neg-hard-limit 8 850 -1300 100 L 50 50 1 1 O
    X motor-pos-fb 9 -800 550 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # LOADRT
    #
    DEF LOADRT loadrt.0. 0 0 N N 1 F N
    F0 "loadrt.0." 0 250 50 H V C CNN
    F1 "LOADRT" -50 150 50 H V C CNN
    F2 "" 800 -500 50 H I C CNN
    F3 "" 800 -500 50 H I C CNN
    F4 "Component + options go here" -250 50 50 H V L CNN "LoadRT"
    F5 "1" 250 150 50 H V C CNN "StripAnno"
    DRAW
    P 2 0 0 0 300 100 950 100 N
    P 2 0 0 0 300 200 300 100 N
    P 3 0 0 0 -300 100 -300 0 950 0 N
    P 4 0 1 0 300 200 -300 200 -300 100 300 100 f
    ENDDRAW
    ENDDEF
    #
    # LOADUSR
    #
    DEF LOADUSR loadusr.0. 0 0 N N 1 F N
    F0 "loadusr.0." 0 250 50 H V C CNN
    F1 "LOADUSR" -50 150 50 H V C CNN
    F2 "" 850 -500 50 H I C CNN
    F3 "" 850 -500 50 H I C CNN
    F4 "Module + options go here" -250 50 50 H V L CNN "LoadUsr"
    F5 "1" 250 150 50 H V C CNN "StripAnno"
    DRAW
    P 2 1 1 0 300 100 850 100 N
    P 2 1 1 0 300 200 300 100 N
    P 3 1 1 0 -300 100 -300 0 850 0 N
    P 4 1 1 0 300 200 -300 200 -300 100 300 100 f
    ENDDRAW
    ENDDEF
    #
    # LOGIC
    #
    DEF LOGIC logic.0. 0 20 N Y 1 F N
    F0 "logic.0." 0 650 50 H V C CNN
    F1 "LOGIC" 0 550 50 H V C CNN
    F2 "" 350 -200 50 H I C CNN
    F3 "" 350 -200 50 H I C CNN
    F4 "1" 300 550 50 H V C CNN "StripAnno"
    F5 "+ personality=0x108" -50 -550 50 H V C CNN "LoadRT"
    DRAW
    T 0 -50 400 50 0 0 0 " 100" Normal 0 L C
    T 0 -50 300 50 0 0 0 " 200" Normal 0 L C
    T 0 -50 200 50 0 0 0 " 400" Normal 0 L C
    T 0 -50 100 50 0 0 0 " 800" Normal 0 L C
    T 0 -50 0 50 0 0 0 1000 Normal 0 L C
    S 350 500 -400 600 0 1 0 f
    S -400 500 350 -500 1 1 0 N
    X in-00 1 -500 400 100 R 50 50 1 1 I
    X or 10 450 300 100 L 50 50 1 1 O
    X xor 11 450 200 100 L 50 50 1 1 O
    X nand 12 450 100 100 L 50 50 1 1 O
    X nor 13 450 0 100 L 50 50 1 1 O
    X _ 14 -500 -400 100 R 50 50 1 1 W NC
    X in-01 2 -500 300 100 R 50 50 1 1 I
    X in-02 3 -500 200 100 R 50 50 1 1 I
    X in-03 4 -500 100 100 R 50 50 1 1 I
    X in-04 5 -500 0 100 R 50 50 1 1 I
    X in-05 6 -500 -100 100 R 50 50 1 1 I
    X in-06 7 -500 -200 100 R 50 50 1 1 I
    X in-07 8 -500 -300 100 R 50 50 1 1 I
    X and 9 450 400 100 L 50 50 1 1 O
    ENDDRAW
    ENDDEF
    #
    # LOGITECH_GAMEPAD_GUF13A
    #
    DEF LOGITECH_GAMEPAD_GUF13A input.0. 0 40 N Y 2 L N
    F0 "input.0." 0 1850 50 H V C CNN
    F1 "LOGITECH_GAMEPAD_GUF13A" -50 1750 50 H V C CNN
    F2 "" 5500 3600 50 H I C CNN
    F3 "" 5500 3600 50 H I C CNN
    F4 "1" 550 1750 50 H V C CNN "StripAnno"
    F5 "-W hal_input -KA Dual" -50 1650 50 H V C CNN "LoadUsr"
    DRAW
    T 0 -350 1400 59 0 2 1 1 Normal 0 L B
    T 0 -400 -1300 59 0 2 1 10 Normal 0 L B
    T 0 -350 1100 59 0 2 1 2 Normal 0 L B
    T 0 -350 800 59 0 2 1 3 Normal 0 L B
    T 0 -350 500 59 0 2 1 4 Normal 0 L B
    T 0 -350 200 59 0 2 1 5 Normal 0 L B
    T 0 -350 -100 59 0 2 1 6 Normal 0 L B
    T 0 -350 -400 59 0 2 1 7 Normal 0 L B
    T 0 -350 -700 59 0 2 1 8 Normal 0 L B
    T 0 -350 -1000 59 0 2 1 9 Normal 0 L B
    T 0 -550 -1600 59 0 2 1 "L Push" Normal 0 L B
    T 0 -550 -1900 59 0 2 1 "R Push" Normal 0 L B
    S -850 -1400 750 1600 1 1 0 N
    S 750 1600 -850 1800 1 1 0 f
    S -650 1600 600 1800 2 1 0 f
    S 600 -1950 -650 1600 2 1 0 N
    X abs-z-offset 1 -950 -500 100 R 0 50 1 1 I
    X abs-z-is-pos 11 850 -700 100 L 0 50 1 1 O
    X abs-z-is-neg 12 850 -800 100 L 0 50 1 1 O
    X abs-z-fuzz 13 -950 -800 100 R 0 50 1 1 I
    X abs-z-flat 14 -950 -700 100 R 0 50 1 1 I
    X abs-z-counts 15 850 -500 100 L 0 50 1 1 O
    X abs-y-scale 16 -950 -100 100 R 0 50 1 1 I
    X abs-y-position 17 850 -100 100 L 0 50 1 1 O
    X abs-y-offset 18 -950 0 100 R 0 50 1 1 I
    X abs-y-is-pos 28 850 -200 100 L 0 50 1 1 O
    X abs-hat0y-flat 37 -950 800 100 R 0 50 1 1 I
    X abs-rz-flat 38 -950 -1200 100 R 0 50 1 1 I
    X abs-rz-counts 39 850 -1000 100 L 0 50 1 1 O
    X abs-hat0y-scale 40 -950 900 100 R 0 50 1 1 I
    X abs-hat0y-position 41 850 900 100 L 0 50 1 1 O
    X abs-hat0y-offset 42 -950 1000 100 R 0 50 1 1 I
    X abs-hat0y-is-pos 43 850 800 100 L 0 50 1 1 O
    X abs-hat0y-is-neg 44 850 700 100 L 0 50 1 1 O
    X abs-hat0y-fuzz 45 -950 700 100 R 0 50 1 1 I
    X abs-rz-fuzz 46 -950 -1300 100 R 0 50 1 1 I
    X abs-hat0y-counts 47 850 1000 100 L 0 50 1 1 O
    X abs-hat0x-scale 48 -950 1400 100 R 0 50 1 1 I
    X abs-hat0x-position 49 850 1400 100 L 0 50 1 1 O
    X abs-hat0x-offset 50 -950 1500 100 R 0 50 1 1 I
    X abs-hat0x-is-pos 51 850 1300 100 L 0 50 1 1 O
    X abs-hat0x-is-neg 52 850 1200 100 L 0 50 1 1 O
    X abs-hat0x-fuzz 53 -950 1200 100 R 0 50 1 1 I
    X abs-hat0x-flat 54 -950 1300 100 R 0 50 1 1 I
    X abs-x-is-neg 55 850 200 100 L 0 50 1 1 O
    X abs-y-is-neg 56 850 -300 100 L 0 50 1 1 O
    X abs-y-fuzz 57 -950 -300 100 R 0 50 1 1 I
    X abs-y-flat 58 -950 -200 100 R 0 50 1 1 I
    X abs-y-counts 59 850 0 100 L 0 50 1 1 O
    X abs-x-scale 60 -950 400 100 R 0 50 1 1 I
    X abs-x-position 61 850 400 100 L 0 50 1 1 O
    X abs-x-offset 62 -950 500 100 R 0 50 1 1 I
    X abs-x-is-pos 63 850 300 100 L 0 50 1 1 O
    X abs-hat0x-counts 64 850 1500 100 L 0 50 1 1 O
    X abs-x-fuzz 65 -950 200 100 R 0 50 1 1 I
    X abs-x-flat 66 -950 300 100 R 0 50 1 1 I
    X abs-x-counts 67 850 500 100 L 0 50 1 1 O
    X abs-rz-scale 68 -950 -1100 100 R 0 50 1 1 I
    X abs-rz-position 69 850 -1100 100 L 0 50 1 1 O
    X abs-rz-offset 70 -950 -1000 100 R 0 50 1 1 I
    X abs-rz-is-pos 71 850 -1200 100 L 0 50 1 1 O
    X abs-rz-is-neg 72 850 -1300 100 L 0 50 1 1 O
    X abs-z-scale 8 -950 -600 100 R 0 50 1 1 I
    X abs-z-position 9 850 -600 100 L 0 50 1 1 O
    X btn-base4 10 700 -1200 100 L 0 50 2 1 O
    X btn-pinkie-not 19 700 -100 100 L 0 50 2 1 O
    X btn-base3-not 2 700 -1000 100 L 0 50 2 1 O
    X btn-top2-not 20 700 200 100 L 0 50 2 1 O
    X btn-top2 21 700 300 100 L 0 50 2 1 O
    X btn-top-not 22 700 500 100 L 0 50 2 1 O
    X btn-top 23 700 600 100 L 0 50 2 1 O
    X btn-thumb2-not 24 700 800 100 L 0 50 2 1 O
    X btn-thumb2 25 700 900 100 L 0 50 2 1 O
    X btn-thumb-not 26 700 1100 100 L 0 50 2 1 O
    X btn-thumb 27 700 1200 100 L 0 50 2 1 O
    X btn-pinkie 29 700 0 100 L 0 50 2 1 O
    X btn-base3 3 700 -900 100 L 0 50 2 1 O
    X btn-joystick-not 30 700 1400 100 L 0 50 2 1 O
    X btn-joystick 31 700 1500 100 L 0 50 2 1 O
    X btn-base6-not 32 700 -1900 100 L 0 50 2 1 O
    X btn-base6 33 700 -1800 100 L 0 50 2 1 O
    X btn-base5-not 34 700 -1600 100 L 0 50 2 1 O
    X btn-base5 35 700 -1500 100 L 0 50 2 1 O
    X btn-base4-not 36 700 -1300 100 L 0 50 2 1 O
    X btn-base2-not 4 700 -700 100 L 0 50 2 1 O
    X btn-base2 5 700 -600 100 L 0 50 2 1 O
    X btn-base-not 6 700 -400 100 L 0 50 2 1 O
    X btn-base 7 700 -300 100 L 0 50 2 1 O
    ENDDRAW
    ENDDEF
    #
    # MOTION
    #
    DEF MOTION motion. 0 40 N Y 1 F N
    F0 "motion." 0 1550 59 H V C CNN
    F1 "MOTION" 0 1450 50 H V C CNN
    F2 "" 0 350 50 H I C CNN
    F3 "" 0 350 50 H I C CNN
    F4 "1" 600 1450 50 H V C CNN "StripAnno"
    DRAW
    S -600 1400 650 -1100 1 1 0 N
    S 650 1400 -600 1500 1 1 0 f
    X feed-hold 1 -700 1000 100 R 0 50 1 0 I
    X coord-mode 10 750 950 100 L 0 50 1 0 O
    X distance-to-go 11 750 350 100 L 0 50 1 0 O
    X probe-input 12 -700 600 100 R 0 50 1 0 I
    X in-position 13 750 1300 100 L 0 50 1 0 O
    X adaptive-feed 14 -700 800 100 R 0 50 1 0 I
    X enable 15 -700 1300 100 R 0 50 1 0 I
    X digital-out-03 16 750 -750 100 L 0 50 1 0 O
    X digital-out-02 17 750 -650 100 L 0 50 1 0 O
    X digital-out-01 18 750 -550 100 L 0 50 1 0 O
    X digital-out-00 19 750 -450 100 L 0 50 1 0 O
    X homing-inhibit 2 -700 450 100 R 0 50 1 0 I
    X analog-out-00 20 750 -200 100 L 0 50 1 0 O
    X analog-out-01 21 750 -300 100 L 0 50 1 0 O
    X digital-in-03 22 -700 -750 100 R 0 50 1 0 I
    X digital-in-02 23 -700 -650 100 R 0 50 1 0 I
    X digital-in-01 24 -700 -550 100 R 0 50 1 0 I
    X analog-in-00 25 -700 -200 100 R 0 50 1 0 I
    X analog-in-01 26 -700 -300 100 R 0 50 1 0 I
    X digital-in-00 27 -700 -450 100 R 0 50 1 0 I
    X feed-inhibit 3 -700 900 100 R 0 50 1 0 I
    X on-soft-limit 30 750 -50 100 L 0 50 1 0 O
    X requested-vel 31 750 500 100 L 0 50 1 0 O
    X teleop-mode 32 750 750 100 L 0 50 1 0 O
    X motion-type 4 750 1100 100 L 0 50 1 0 O
    X motion-enabled 5 750 1200 100 L 0 50 1 0 O
    X offset-limited 6 750 100 100 L 0 50 1 0 O
    X current-vel 7 750 600 100 L 0 50 1 0 O
    X coord-error 8 750 850 100 L 0 50 1 0 O
    X offset-active 9 750 200 100 L 0 50 1 0 O
    X /motion-controller 28 -700 -1000 100 R 50 50 1 1 W C
    X /motion-command-handler 29 -700 -900 100 R 50 50 1 1 W C
    ENDDRAW
    ENDDEF
    #
    # MUX2
    #
    DEF MUX2 mux2. 0 20 N Y 1 F N
    F0 "mux2." 0 300 50 H V C CNN
    F1 "MUX2" 0 200 50 H V C CNN
    F2 "" 350 -150 50 H I C CNN
    F3 "" 350 -150 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S -150 150 150 -250 0 1 0 N
    S 150 150 -150 250 0 1 0 f
    X in0 1 -250 100 100 R 50 50 1 1 I
    X in1 2 -250 0 100 R 50 50 1 1 I
    X sel 3 -250 -200 100 R 50 50 1 1 I
    X out 4 250 100 100 L 50 50 1 1 O
    X _ 5 -250 -100 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # MUX4
    #
    DEF MUX4 mux4. 0 20 N Y 1 F N
    F0 "mux4." 0 450 50 H V C CNN
    F1 "MUX4" 0 350 50 H V C CNN
    F2 "" 400 -100 50 H I C CNN
    F3 "" 400 -100 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 150 300 -150 400 0 1 0 f
    S -150 300 150 -400 1 1 0 N
    X in0 1 -250 250 100 R 50 50 1 1 I
    X in1 2 -250 150 100 R 50 50 1 1 I
    X in2 3 -250 50 100 R 50 50 1 1 I
    X in3 4 -250 -50 100 R 50 50 1 1 I
    X sel0 5 -250 -250 100 R 50 50 1 1 I
    X sel1 6 -250 -350 100 R 50 50 1 1 I
    X out 7 250 250 100 L 50 50 1 1 O
    X _ 8 -250 -150 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # MUX8
    #
    DEF MUX8 mux8. 0 20 N Y 1 F N
    F0 "mux8." 0 750 50 H V C CNN
    F1 "MUX8" 0 650 50 H V C CNN
    F2 "" 350 -100 50 H I C CNN
    F3 "" 350 -100 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 150 600 -150 700 0 1 0 f
    S -150 600 150 -600 1 1 0 N
    X in0 1 -250 550 100 R 50 50 1 1 I
    X sel1 10 -250 -450 100 R 50 50 1 1 I
    X sel2 11 -250 -550 100 R 50 50 1 1 I
    X _ 12 -250 -250 100 R 50 50 1 1 W NC
    X in1 2 -250 450 100 R 50 50 1 1 I
    X in2 3 -250 350 100 R 50 50 1 1 I
    X in3 4 -250 250 100 R 50 50 1 1 I
    X in4 5 -250 150 100 R 50 50 1 1 I
    X in5 6 -250 50 100 R 50 50 1 1 I
    X in6 7 -250 -50 100 R 50 50 1 1 I
    X out 7 250 550 100 L 50 50 1 1 O
    X in7 8 -250 -150 100 R 50 50 1 1 I
    X sel0 9 -250 -350 100 R 50 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # NOT
    #
    DEF NOT not. 0 0 N N 1 F N
    F0 "not." 100 150 50 H V C CNN
    F1 "NOT" 0 0 50 H V C CNN
    F2 "" 350 -250 50 H I C CNN
    F3 "" 350 -250 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    C 225 0 25 0 1 0 f
    P 4 1 0 10 -100 150 -100 -150 200 0 -100 150 f
    X in 1 -250 0 150 R 50 50 1 1 I
    X out 2 450 0 197 L 50 50 1 1 O
    X _ 3 -200 -100 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # OR2
    #
    DEF OR2 or2. 0 0 N N 1 F N
    F0 "or2." 0 200 50 H V C CNN
    F1 "OR2" 0 0 50 H V C CNN
    F2 "" 50 0 50 H I C CNN
    F3 "" 50 0 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    A -360 0 258 354 -354 1 1 10 N -150 150 -150 -150
    A -47 -52 204 150 837 1 1 10 f 150 0 -24 150
    A -47 52 204 -150 -837 1 1 10 f 150 0 -24 -150
    P 2 1 1 10 -150 -150 -25 -150 f
    P 2 1 1 10 -150 150 -25 150 f
    P 12 1 1 -1000 -25 150 -150 150 -150 150 -140 134 -119 89 -106 41 -103 -10 -109 -59 -125 -107 -150 -150 -150 -150 -25 -150 f
    X in0 1 -300 100 177 R 50 50 1 1 I
    X in1 2 -300 -100 177 R 50 50 1 1 I
    X out 3 300 0 150 L 50 50 1 1 O
    X _ 4 -200 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # PARAMETER
    #
    DEF PARAMETER parameter. 0 0 N N 1 F N
    F0 "parameter." 0 100 50 H I C CNN
    F1 "PARAMETER" 200 0 50 H V R CNN
    F2 "" 300 0 50 H I C CNN
    F3 "" 300 0 50 H I C CNN
    DRAW
    P 4 1 1 0 -350 50 300 50 300 -50 -350 -50 N
    X out 1 400 0 154 L 50 50 1 0 O I
    ENDDRAW
    ENDDEF
    #
    # PID
    #
    DEF PID pid.0. 0 40 N Y 1 F N
    F0 "pid.0." 0 1400 50 H V C CNN
    F1 "PID" 0 1300 50 H V C CNN
    F2 "" 750 600 50 H I C CNN
    F3 "" 750 600 50 H I C CNN
    F4 "1" 600 1300 50 H V C CNN "StripAnno"
    DRAW
    S -550 1250 650 -1750 0 0 0 N
    S 650 1250 -550 1350 0 0 0 f
    X do-pid-calcs 1 -650 -1650 100 R 0 50 1 0 I C
    X maxerrorD 10 -650 -1000 100 R 0 50 1 0 I
    X maxerror 11 -650 -900 100 R 0 50 1 0 I
    X maxcmdDDD 12 -650 -1450 100 R 0 50 1 0 I
    X maxcmdDD 13 -650 -1350 100 R 0 50 1 0 I
    X maxcmdD 14 -650 -1250 100 R 0 50 1 0 I
    X index-enable 15 -650 600 100 R 0 50 1 0 I
    X Igain 16 -650 100 100 R 0 50 1 0 I
    X FF3 17 -650 -450 100 R 0 50 1 0 I
    X FF2 18 -650 -350 100 R 0 50 1 0 I
    X FF1 19 -650 -250 100 R 0 50 1 0 I
    X command 2 -650 950 100 R 0 50 1 0 I
    X FF0 20 -650 -150 100 R 0 50 1 0 I
    X feedback-deriv 21 -650 1100 100 R 0 50 1 0 I
    X feedback 22 -650 1200 100 R 0 50 1 0 I
    X error-previous-target 23 -650 -650 100 R 0 50 1 0 I
    X error 24 750 850 100 L 0 50 1 0 O
    X enable 25 -650 700 100 R 0 50 1 0 I
    X Dgain 26 -650 0 100 R 0 50 1 0 I
    X deadband 27 -650 350 100 R 0 50 1 0 I
    X command-deriv 28 -650 850 100 R 0 50 1 0 I
    X bias 29 -650 450 100 R 0 50 1 0 I
    X saturated-s 3 750 600 100 L 0 50 1 0 O
    X saturated-count 4 750 500 100 L 0 50 1 0 O
    X saturated 5 750 700 100 L 0 50 1 0 O
    X Pgain 6 -650 200 100 R 0 50 1 0 I
    X output 7 750 950 100 L 0 50 1 0 O
    X maxoutput 8 -650 -750 100 R 0 50 1 0 I
    X maxerrorI 9 -650 -1100 100 R 0 50 1 0 I
    ENDDRAW
    ENDDEF
    #
    # SCALE
    #
    DEF SCALE scale. 0 20 N Y 1 F N
    F0 "scale." 0 300 50 H V C CNN
    F1 "SCALE" 0 200 50 H V C CNN
    F2 "" 550 -350 50 H I C CNN
    F3 "" 550 -350 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 150 150 -150 250 0 1 0 f
    S -150 150 150 -250 1 1 0 N
    X in 1 -250 100 100 R 50 50 1 1 I
    X gain 2 -250 -100 100 R 50 50 1 1 I
    X offset 3 -250 -200 100 R 50 50 1 1 I
    X out 4 250 100 100 L 50 50 1 1 O
    X _ 5 -250 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # SPINDLE
    #
    DEF SPINDLE spindle.0. 0 40 N Y 1 F N
    F0 "spindle.0." -50 900 50 H V C CNN
    F1 "SPINDLE" -50 800 50 H V C CNN
    F2 "" -50 100 50 H I C CNN
    F3 "" -50 100 50 H I C CNN
    F4 "1" 550 800 50 H V C CNN "StripAnno"
    DRAW
    S -650 750 600 -1000 1 1 0 N
    S 600 750 -650 850 1 1 0 f
    X at-speed 1 -750 -650 100 R 0 50 1 1 I
    X index-enable 10 -750 200 100 R 0 50 1 1 B
    X amp-fault-in 11 -750 -200 100 R 0 50 1 1 I
    X speed-out-abs 12 700 -700 100 L 0 50 1 1 O
    X speed-out-rps-abs 13 700 -900 100 L 0 50 1 1 O
    X speed-out-rps 14 700 -800 100 L 0 50 1 1 O
    X speed-cmd-rps 15 700 -450 100 L 0 50 1 1 O
    X orient-mode 16 700 -200 100 L 0 50 1 1 O
    X orient-angle 17 700 -100 100 L 0 50 1 1 O
    X speed-in 18 -750 -550 100 R 0 50 1 1 I
    X revs 19 -750 -300 100 R 0 50 1 1 I
    X speed-out 2 700 -550 100 L 0 50 1 1 O
    X orient-fault 20 -750 -50 100 R 0 50 1 1 I
    X is-oriented 21 -750 50 100 R 0 50 1 1 I
    X orient 3 700 0 100 L 0 50 1 1 O
    X locked 4 700 200 100 L 0 50 1 1 O
    X reverse 5 700 450 100 L 0 50 1 1 O
    X on 6 700 650 100 L 0 50 1 1 O
    X forward 7 700 550 100 L 0 50 1 1 O
    X brake 8 700 350 100 L 0 50 1 1 O
    X inhibit 9 -750 650 100 R 0 50 1 1 I
    ENDDRAW
    ENDDEF
    #
    # THREAD
    #
    DEF THREAD name-thread. 0 40 N Y 1 F N
    F0 "name-thread." 0 550 59 H V C CNN
    F1 "THREAD" 0 450 50 H V C CNN
    F2 "" 100 100 50 H I C CNN
    F3 "" 100 100 50 H I C CNN
    F4 "1" 400 450 50 H V C CNN "StripAnno"
    DRAW
    T 0 300 0 50 0 0 0 "Add in order found" Normal 0 R C
    T 0 300 350 50 0 0 0 "First in thread" Normal 0 R C
    T 0 250 -350 50 0 0 0 "Last in thread" Normal 0 R C
    S -450 400 450 500 0 1 0 f
    S 450 -450 -450 400 0 1 0 N
    X 1 1 550 350 100 L 0 50 1 0 w C
    X 2 2 550 250 100 L 0 50 1 0 w C
    X 3 3 550 150 100 L 0 50 1 0 w C
    X _ 4 550 0 100 L 0 50 1 0 w C
    X -3 5 550 -150 100 L 0 50 1 0 w C
    X -2 6 550 -250 100 L 0 50 1 0 w C
    X -1 7 550 -350 100 L 0 50 1 0 w C
    ENDDRAW
    ENDDEF
    #
    # THREAD_FLAG
    #
    DEF THREAD_FLAG thread-flag. 0 0 N N 1 F N
    F0 "thread-flag." 0 250 50 H V C CNN
    F1 "THREAD_FLAG" 0 150 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "1" 100 50 50 H V C CNN "StripAnno"
    DRAW
    P 6 0 1 0 0 0 0 50 -40 75 0 100 40 75 0 50 N
    X thread 1 0 0 0 U 50 50 0 0 B C
    ENDDRAW
    ENDDEF
    #
    # TIMEDELAY
    #
    DEF TIMEDELAY timedelay. 0 20 N Y 1 F N
    F0 "timedelay." 0 350 50 H V C CNN
    F1 "TIMEDELAY" 0 250 50 H V C CNN
    F2 "" 0 150 50 H I C CNN
    F3 "" 0 150 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 250 200 -250 300 0 1 0 f
    S -250 200 250 -200 1 1 0 N
    X in 1 -350 150 100 R 50 50 1 1 I
    X on-delay 2 -350 -50 100 R 50 50 1 1 I
    X off-delay 3 -350 -150 100 R 50 50 1 1 I
    X out 4 350 150 100 L 50 50 1 1 O
    X elapsed 5 350 50 100 L 50 50 1 1 O
    X _ 6 -350 50 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # TOGGLE
    #
    DEF TOGGLE toggle. 0 20 N Y 1 F N
    F0 "toggle." 0 300 50 H V C CNN
    F1 "TOGGLE" 0 200 50 H V C CNN
    F2 "" 300 -50 50 H I C CNN
    F3 "" 300 -50 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    S 250 150 -200 250 0 1 0 f
    S -200 150 250 -150 1 1 0 N
    X in 1 -300 100 100 R 50 50 1 1 I
    X out 2 350 100 100 L 50 50 1 1 O
    X debounce 4 -250 -100 100 R 50 50 1 1 I I
    X _ 5 -300 0 100 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    # XOR2
    #
    DEF XOR2 xor2. 0 0 N N 1 F N
    F0 "xor2." -50 200 50 H V C CNN
    F1 "XOR2" 25 0 50 H V C CNN
    F2 "" 0 0 50 H I C CNN
    F3 "" 0 0 50 H I C CNN
    F4 "+" 0 0 50 H I C CNN "LoadRT"
    DRAW
    A -385 0 258 354 -354 1 1 10 N -175 150 -175 -150
    A -360 0 258 354 -354 1 1 10 N -150 150 -150 -150
    A -47 -52 204 150 837 1 1 10 f 150 0 -24 150
    A -47 52 204 -150 -837 1 1 10 f 150 0 -24 -150
    P 2 1 1 10 -150 -150 -25 -150 f
    P 2 1 1 10 -150 150 -25 150 f
    P 12 1 1 -1000 -25 150 -150 150 -150 150 -140 134 -119 89 -106 41 -103 -10 -109 -59 -125 -107 -150 -150 -150 -150 -25 -150 f
    X in0 1 -350 100 228 R 50 50 1 1 I
    X in1 2 -350 -100 228 R 50 50 1 1 I
    X out 3 300 0 150 L 50 50 1 1 O
    X _ 4 -250 0 150 R 50 50 1 1 W NC
    ENDDRAW
    ENDDEF
    #
    #End Library

  • Schauer Solid State Battery Charger: Digital Meter Retrofit

    Schauer Solid State Battery Charger: Digital Meter Retrofit

    The Forester’s battery has been on life support from an ancient Schauer “Solid State” charger (which may have Come With The House™) for the last year:

    Schauer battery charger - analog ammeter
    Schauer battery charger – analog ammeter

    A remote Squidwrench session provided an opportunity to replace its OEM ammeter with a cheap volt-amp meter:

    Schauer battery charger - digital meter
    Schauer battery charger – digital meter

    The charger is “solid state” because it contains silicon electronics:

    Schauer battery charger - solid state components
    Schauer battery charger – solid state components

    That’s an SCR implanted in the aluminum heatsink. The other side has a Motorola 18356 house number, a date code that might be 523, and the word MEXICO. The company now known as NXP says Motorola opened its Guadalajara plant in 1969, so they could have built the SCR in either 1973 or 1975; it’s not clear who manufactures what these days.

    The black tubing contains at least one part with enough value to justify the (presumably) Kovar lead; nowadays, it would be a “gold tone” finish. It’s probably a Zener diode setting the trickle-charging voltage, joined to the resistor lead in the crimped block. I don’t know if the glass diode is soldered to the Zener, but I’m reasonably sure if the third lead came from a transistor tucked inside the sleeve, we’d read about it on the charger’s front cover.

    In an ideal world, a digital meter would fit into a matching rectangular hole in the front panel, but that’s not the world we live in. After wrestling my gotta-make-a-solid-model jones to the floor, I got primal on a random slab of soft-ish plastic sheet:

    Schauer battery charger - bezel nibbling
    Schauer battery charger – bezel nibbling

    There’s nothing like some bandsaw / belt sander / nibbler action to jam a square peg into a round hole:

    Schauer battery charger - bezel test fit
    Schauer battery charger – bezel test fit

    It’s actually a firm press fit; whenever something like that happens, you know the project will end well.

    Hot melt glue FTW:

    Schauer battery charger - digital meter wiring
    Schauer battery charger – digital meter wiring

    The new meter’s (heavy) red-black leads go to the same terminals as the old meter’s wires, paying attention to the polarity. I splurged with insulated QD terminals on the old wires where a joint was needed.

    The meter’s thin red lead expects to see a power supply under 50 V with no particular regulation requirements, so I used the same flying-component design as the rest of the charger:

    Schauer battery charger - meter power supply
    Schauer battery charger – meter power supply

    The meter draws basically no current, at least on the scale of an automotive battery charger, so the 220 µf cap holds pretty nearly the peak 18 V half-wave rectified from the center tap by a 1N5819 Schottky diode.

    Those two squares riveted to the back panel are genuine selenium rectifiers, from back in the day when silicon power diodes weren’t cheap and readily available. They also limit the charger’s peak current and have yet to emit their incredibly foul stench upon failure; you always know exactly what died when that happens.

    Selenium rectifiers were pretty much obsolete by the early 1970s, agreeing with a 1973 date code. Schauer might have been working through their stockpile of obsolete rectifiers, which would have been sunk-cost-cheap compared to silicon diodes.

    The meter’s thin black lead goes to the power supply common point, which turns out to be where those rectifiers meet. The larger black wire goes off to the meter’s fat black lead on the other side of the aluminum heatsink, joining it in a new insulated QD terminal.

    The meter’s thin yellow wire is its voltage sense input, which gets soldered directly to the hot lead of the SCR.

    The meter indicates DC voltages and currents, which definitely isn’t the situation in the 100 Ω power resistor shown in the second picture.

    The voltage:

    Schauer battery charger - voltage waveform
    Schauer battery charger – voltage waveform

    And the current at 20 mA/div, showing why silicon replaced selenium:

    Schauer battery charger - current waveform
    Schauer battery charger – current waveform

    Yes, the current does go negative while the rectifiers figure out what to do next.

    The charger seems a little happier out in the garage:

    Schauer battery charger - in use
    Schauer battery charger – in use

    The battery holds the voltage steady at 13.7 V, with the charger producing 85 mV blips every second or so:

    Schauer battery charger - float V pulse
    Schauer battery charger – float V pulse

    Those blips correspond to 3 A pulses rammed into the battery:

    Schauer battery charger - float A pulse - 1 A-div
    Schauer battery charger – float A pulse – 1 A-div

    They’re measured across a 1 Ω series resistor that’s surely limiting the maximum current: 18 V from the transformer minus 13.7 V on the battery minus other IR losses doesn’t leave room for anything more than 3 V across the resistor. I wasn’t going to haul the Tek current probes out to the garage just for the occasion.

    Opening the Forester’s door to turn on all its LED interior lights bumps the meter to about 1 A, although the truth is more complicated:

    Schauer battery charger - loaded A pulse - 1 A-div
    Schauer battery charger – loaded A pulse – 1 A-div

    The average current is, indeed, just under 1 A, but in this situation the meter’s cool blue number seems more like a comfort indicator than anything particularly reliable.

    All I really wanted from the meter was an indication that the trickle charger was trickling, so I disconnected Tiny Scope, declared victory, and closed the garage door.

  • Discrete LM3909 Blue LED: Off at 1.0 V

    Discrete LM3909 Blue LED: Off at 1.0 V

    The blue LED inside the radome got fainter as the alkaline AA cells faded away, but remained visible in a dark room until the discrete LM3909 circuitry stopped oscillating with the battery at 1.0 V. One of the cells had flatlined, with the other supplying what little current was needed.

    The circuitry restarted with a pair of weak alkalines applying 2.4 V across the bus bars:

    LM3909 Blue - 2.4 V alkaline
    LM3909 Blue – 2.4 V alkaline

    The LED waveform shows it needs about 2 V:

    LM3909 Blue - 2.4 V alkaline
    LM3909 Blue – 2.4 V alkaline

    It’s barely visible in normal room light and strikingly bright at night.

  • Juki JC-001 Foot Control: Resolving Uncommanded Thread Cutting

    Juki JC-001 Foot Control: Resolving Uncommanded Thread Cutting

    Mary’s most recent quilt arranges her color choices in Judy Niemeyer’s Stellar Snowflake pattern:

    Stellar Snowflake Quilt - in progress
    Stellar Snowflake Quilt – in progress

    Her Juki TL-2010Q sewing machine has a built-in thread cutter activated by pressing down on the heel end (to the left) of the foot control:

    Juki JC-001 Foot Control - overview
    Juki JC-001 Foot Control – overview

    The machine had previously performed “uncommanded” thread cuts on other projects, but the many short segments in this pattern triggered far too many cuts. I aimed a camera at her foot on the pedal and she was definitely not pressing down with her heel when the cutter fired.

    In point of fact, the thread cutter fired when she was just starting a new segment, where she was gently pressing down on the toe end (to the right) of the pedal to start at the slowest possible speed.

    For completeness, the underside of the pedal:

    Juki JC-001 Foot Control - bottom
    Juki JC-001 Foot Control – bottom

    There are no screws holding it together. The top cover pivots on a pair of plastic pegs sticking out from the base near the middle of the cable spool. Disassembly requires jamming a pair of husky Prydrivers in there and applying enough brute force to pry both sides outward farther than you (well, I) think they should bend. This will scar the bottom of the case, but nobody will ever notice.

    The foot control cable plugs into the machine through what looks like an ordinary two-conductor coax plug, just like the ones on wall warts delivering power to gadgets around the house. In this day and age, the communications protocol could be anything from a simple resistor to a full-frontal 1-Wire encrypted data exchange.

    Based on the old Kenmore foot pedals, I expected a resistive control and, indeed, a simple test gave these results:

    • Idle = 140 kΩ
    • Heel pressed (cut) = 46 kΩ
    • Toe slight press (slow running) = 20 kΩ
    • Toe full press (fast running) = 0.2 kΩ

    We can all see where this is going, but just to be sure I pried the top off the control to reveal the insides:

    Juki JJC-001 Foot Control - interior
    Juki JJC-001 Foot Control – interior

    The two cylindrical features capture the ends of a pair of stiff compression springs pressing the top of the pedal upward.

    The small, slightly stretched, extension spring in the middle pulls the slider to the left (heelward), with a ramp in the top cover forcing it to the right (toeward) as the speed increases.

    The top cover includes a surprisingly large hunk of metal which may provide enough mass to make the pedal feel good:

    Juki JC-001 Foot Control - top underside
    Juki JC-001 Foot Control – top underside

    The ramp is plastic and the slider has a pair of nylon (-ish) rollers, so there’s not much friction involved in the speed control part of motion. Yes, this is oriented the other way, with the heel end over on the right.

    The metal insert pivots in the serrated plastic section near the middle, with the two husky extension springs visible on the left holding it against the plastic cover. The two rectangular features on the left rest under the plastic flanges on the right of the base to prevent the metal insert from moving upward, so pressing the heel end down pulls the cover away from the insert to let the slider rollers move toward the right end of the ramp, into roughly the position shown in the interior view.

    A closeup look at the slider shows the rollers and the PCB holding all of the active ingredients:

    Juki JC-001 Foot Control - Resistor Slider
    Juki JC-001 Foot Control – Resistor Slider

    I think the trimpot adjusts the starting resistance for the slider’s speed control travel. It is, comfortingly, roughly in the middle of its range.

    A top view shows the fixed 140 kΩ resistor (brown yellow black orange, reading from the right) setting the idle resistance:

    Juki JC-001 Foot Control - PCB top view
    Juki JC-001 Foot Control – PCB top view

    Measuring the resistance while gently teasing the slider showed that it’s possible to produce a resistance higher than 20 kΩ and lower than 140 kΩ, although it requires an exceedingly finicky touch and is completely unstable.

    Before looking inside the pedal, we thought the cutter was triggered by an actual switch closure with the heel end most of the way downward against those stiff springs, which meant the failure came from a switch glitch. Now, we think the earlier and infrequent uncommanded thread cuts trained Mary to start very carefully to be very sure she wasn’t glitching the cutter’s hypothetical switch. Of course, her gradually increasing toe pressure moved the slider very slowly through its idle-to-running transition: she was optimizing her behavior to produce exactly the resistance required to trigger the cutter.

    She now sets the machine’s speed control midway between Turtle and Hare to limit its top speed, presses the pedal with more confidence to minimize the time spent passing through the danger zone, and has had far few uncommanded thread cuts. We think it’s now a matter of retraining her foot to stomp with conviction; there’s no hardware or software fix.

    I’m sure Juki had a good reason to select the resistances they did, but I would have gone for a non-zero minimum resistance at the fast end of travel and a zero-resistance switch to trigger the cutter.

  • Mesa 5i25 Superport: Reflash and Step-Direction Pin Swap

    Mesa 5i25 Superport: Reflash and Step-Direction Pin Swap

    For reasons lost in the mists of time, the DB-25 pinout used in the Sherline CNC Driver Box is kinda-sorta the same as everybody else’s DB-25 pinout, with minor difference of swapping the Step and Direction pins on each axis. This made no difference with the LinuxCNC parallel port driver, because (nearly) all pins are alike to it, but having recently found the Mesa 5i25 Everything I/O card and being desirous of upgrading to the latest & Greatest LinuxCNC, I figured why not throw all the balls in the air at once?

    Although it’s theoretically possible to recompile the FPGA source code to swap the pins, the least horrible alternative was converting a null modem (remember null modems?) into a passthrough pinswapper:

    DB-25 Parallel Adapter - Step-Direction pin swap
    DB-25 Parallel Adapter – Step-Direction pin swap

    Make sure you put jumper W2 in the DOWN position to route pins 22-25 to DC ground, rather than +5 V. W1 does the same for the internal header, herein unused, but it’s in the same position just for neatness.

    Similarly, put both W3 and W4 in their UP position to enable +5 V tolerance, connect the pullups to +5 V, and enable the pullups, thereby keeping the Sherline logic happy.

    Jumper W5 must be UP in order to have the thing work.

    The relevant diagram:

    Mesa 5i25 - jumper locations
    Mesa 5i25 – jumper locations

    Flashing the 5i25 with the Probotix PBX-RF firmware produced the best fit to a simple parallel port:

    sudo mesaflash --verbose --device 5i25 --write 5i25/configs/hostmot2/5i25_prob_rfx2.bit
    sudo mesaflash --verbose --device 5i25 --reload
    

    The mesaflash utility and all the BIT files come from their 5i25.zip file with all the goodies.

    The Gecko G540 pinout came in a close second and, should the Sherline box go toes-up, I’ll probably replace it with a G540 and (definitely) rewire the steppers from Sherline’s unipolar drive to bipolar drive mode.

    The 5i25 pinout now looks like this:

    halrun
    
    halcmd: loadrt hostmot2
    Note: Using POSIX realtime
    hm2: loading Mesa HostMot2 driver version 0.15
    
    halcmd: loadrt hm2_pci
    hm2_pci: loading Mesa AnyIO HostMot2 driver version 0.7
    hm2_pci: discovered 5i25 at 0000:04:02.0
    hm2/hm2_5i25.0: Low Level init 0.15
    hm2/hm2_5i25.0: 34 I/O Pins used:
    hm2/hm2_5i25.0:     IO Pin 000 (P3-01): IOPort
    hm2/hm2_5i25.0:     IO Pin 001 (P3-14): PWMGen #0, pin Out0 (PWM or Up) (Output)
    hm2/hm2_5i25.0:     IO Pin 002 (P3-02): StepGen #0, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 003 (P3-15): IOPort
    hm2/hm2_5i25.0:     IO Pin 004 (P3-03): StepGen #0, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 005 (P3-16): PWMGen #0, pin Out1 (Dir or Down) (Output)
    hm2/hm2_5i25.0:     IO Pin 006 (P3-04): StepGen #1, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 007 (P3-17): IOPort
    hm2/hm2_5i25.0:     IO Pin 008 (P3-05): StepGen #1, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 009 (P3-06): StepGen #2, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 010 (P3-07): StepGen #2, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 011 (P3-08): StepGen #3, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 012 (P3-09): StepGen #3, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 013 (P3-10): IOPort
    hm2/hm2_5i25.0:     IO Pin 014 (P3-11): Encoder #0, pin A (Input)
    hm2/hm2_5i25.0:     IO Pin 015 (P3-12): Encoder #0, pin B (Input)
    hm2/hm2_5i25.0:     IO Pin 016 (P3-13): Encoder #0, pin Index (Input)
    hm2/hm2_5i25.0:     IO Pin 017 (P2-01): IOPort
    hm2/hm2_5i25.0:     IO Pin 018 (P2-14): PWMGen #1, pin Out0 (PWM or Up) (Output)
    hm2/hm2_5i25.0:     IO Pin 019 (P2-02): StepGen #4, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 020 (P2-15): IOPort
    hm2/hm2_5i25.0:     IO Pin 021 (P2-03): StepGen #4, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 022 (P2-16): PWMGen #1, pin Out1 (Dir or Down) (Output)
    hm2/hm2_5i25.0:     IO Pin 023 (P2-04): StepGen #5, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 024 (P2-17): IOPort
    hm2/hm2_5i25.0:     IO Pin 025 (P2-05): StepGen #5, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 026 (P2-06): StepGen #6, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 027 (P2-07): StepGen #6, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 028 (P2-08): StepGen #7, pin Step (Output)
    hm2/hm2_5i25.0:     IO Pin 029 (P2-09): StepGen #7, pin Direction (Output)
    hm2/hm2_5i25.0:     IO Pin 030 (P2-10): IOPort
    hm2/hm2_5i25.0:     IO Pin 031 (P2-11): Encoder #1, pin A (Input)
    hm2/hm2_5i25.0:     IO Pin 032 (P2-12): Encoder #1, pin B (Input)
    hm2/hm2_5i25.0:     IO Pin 033 (P2-13): Encoder #1, pin Index (Input)
    hm2/hm2_5i25.0: registered
    hm2_5i25.0: initialized AnyIO board at 0000:04:02.0

    P3 is the DB-25 on the back panel and P2 is the internal IDC header.

  • X10 RR501 Transceiver: Heat Death

    X10 RR501 Transceiver: Heat Death

    Must be something in the air:

    X10 RR501 Transceiver - overheated Zener
    X10 RR501 Transceiver – overheated Zener

    Another overheated Zener in another shunt power supply!

    This BZY97C is still a diode, although I didn’t test its 68 V breakdown spec. I have no idea what they’re doing with that much juice inside an X10 RF box and have nowhere near enough interest to find out.

    It still doesn’t work after a Laying On of Hands: out it goes.

  • Fuvaly Bucked Lithium AA Cells

    Behold lithium battery technology, a USB charger, and a buck voltage converter mashed into an AA alkaline package:

    Fuvaly Bucked Lithium AA - label
    Fuvaly Bucked Lithium AA – label

    Those are two of a quartet bought from a randomly named Amazon seller to appease my ancient venerable classic Sony DSC-H5’s need for more voltage than new and freshly charged NiMH AA cells can provide for more than a few tens of minutes.

    The label claims 1500 mA·h, not the 1120 mA·h I measured:

    Fuvaly Bucked Li AA - mAh - 2021-02
    Fuvaly Bucked Li AA – mAh – 2021-02

    My numbers would be higher with a load less than 500 mA. I doubt the 2.5 A maximum current rating.

    The claim of 2.25 W·h is rather optimistic:

    Fuvaly Bucked Li AA - 2021-02
    Fuvaly Bucked Li AA – 2021-02

    Back of the envelope: 2.25 W·h at 1.5 V equals 1.5 A·h, all right. If you squint carefully, though, the output voltages run around 1.4 V, some of which is surely IR drop in my battery holder & test wiring, but it still knocks nearly 10% off the wattage and doesn’t seem to add to the runtime.

    The camera’s battery charge indicator will obviously show Full right up until it shuts off, but I’ve always carried a spare pair of cells in my pocket anyway.

    Recharging them with a USB meter in series required 425 to 600 mA·h at about 4.8 V, so about 2.5 W·h.

    Enlarging the instructions from the back of the box, should they become useful:

    Fuvaly Bucked Lithium AA - Instructions
    Fuvaly Bucked Lithium AA – Instructions

    Nowhere does the package mention the “brand name”, manufacturer, specifications, or much of anything substantial. I suppose anybody selling white-label products appreciates this level of detail.