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: PC Tweakage

Remembering which tweaks worked

  • Sherline vs. LinuxCNC 2.9.8

    Sherline vs. LinuxCNC 2.9.8

    Notes on finally getting the Sherline CNC mill operating in its new home, with a suitable Axis startup image:

    Sherline setup 2026-06
    Sherline setup 2026-06

    The gray countertop from its former home sits on foam strips soaking up a slight warp with enough isolation to keep things quiet.

    The gantry required the usual fiddling to make the cable hoist the Z axis directly upward, with the orange flag on the counterweight barely visible below the monitor.

    I recently touched the box of precision XYZ positioners and there might be something useful, albeit grossly overqualified, in there to simplify dropping the laser pointer beam directly through the spindle bore.

    A clean installation of LinuxCNC 2.9.8 on an ancient Dell Optiplex 9020 proceeded smoothly. Installing x11vnc let the rest of the proceedings happen from upstairs in the Comfy Chair. For unknown reasons, vinagre works better than Reminna as a VNC client, after recalling F11 enters / exits fullscreen mode.

    The mesaflash utility accompanying LinuxCNC 2.9.8 did not recognize the Mesa 6i25 card. Fetching & compiling the most recent version (3.5.17) cleared that hump and flashed the bitmap:

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

    The 6i25 wants to be known as a 5i25, with its jumpers in their default positions:

    Mesa 6i25 - jumper locations
    Mesa 6i25 – jumper locations

    For unknown reasons, the button originally known as btn-trigger became btn-joystick for a while and has now reverted to btn-trigger. It’s labeled 1 in the four-button cluster:

    Logitech Dual-Action Gamepad - relabeled
    Logitech Dual-Action Gamepad – relabeled

    Which required changing the pin name in the Kicad library component:

    Sherline HAL schematic - Logitech button 1 name
    Sherline HAL schematic – Logitech button 1 name

    Which required converting the old Kicad library format into the new Kicad library format, a completely automatic process without, AFAICT, any unpleasant side effects.

    The new name fed into the schematic as expected, after minor fumbling while re-adding the modified component and setting its annotation number:

    Sherline HAL schematic - Logitech AZ button logic
    Sherline HAL schematic – Logitech AZ button logic

    The X axis home microswitch has (apparently) become more bouncy while it was idle, so I increased the number of samples before HAL sees a change in that GPIO input:

    Sherline HAL schematic - home switch debounce
    Sherline HAL schematic – home switch debounce

    The dbounce block runs in the servo thread at 1 m per tick, so those 20 samples take all of 20 ms while the X axis moves 0.15 mm. At some point I should apply a scope to that switch, but for now It Just Works™.

    Considerably to my surprise, compiling the modified Kicad schematic into a HAL file proceeded without incident, despite various Python updates in the last five years.

    Kicad produces an “intermediate XML file” containing the netlist data intended for a conversion / export program, which is basically what my Kicad-to-HAL lashup does. I told Kicad to use Bash’s true command as a converter:

    Sherline HAL schematic - netlist export
    Sherline HAL schematic – netlist export

    So I can run the Kicad-to-HAL converter manually:

    python ../Kicad\ Conversion/Kicad-to-HAL.py Sherline\ HAL\ -\ Logitech\ Gamepad\ jogging.xml Sherline.hal
    

    You could tell Kicad to run it and it would probably Just Work™, but I’m used to peering at the results and dinking with my program.

    Which produced a new Sherline.hal file that Just Worked™ with the existing Sherline.ini file containing the configuration constants.

    The Sherline has cut only air so far, but, as the man said, “E pur si muove.”

  • Keychron C3 Pro Keyboard: Taming

    Keychron C3 Pro Keyboard: Taming

    Having set the Moonlander to use Auto Shift, I’ve come to depend on it, so I got a Keychron C3 Pro keyboard for one of the Basement Shop’s PCs because it glows in the dark and can be configured with QMK:

    Keychron C3 Pro - tamed
    Keychron C3 Pro – tamed

    The default setup has rainbow hues cycling across the keyboard, which I find entirely too distracting. Although you can manually select the solid-color variant from the myriad possibilities using the keyboard, I forced a solid color with this config.h file:

    #define RGB_MATRIX_DEFAULT_ON true // Sets the default enabled state, if none has been set
    #define RGB_MATRIX_DEFAULT_MODE RGB_MATRIX_SOLID_COLOR // Sets the default mode, if none has been set
    #define RGB_MATRIX_DEFAULT_HUE 36  // Sets the default hue value, if none has been set
    #define RGB_MATRIX_DEFAULT_SAT 255 // Sets the default saturation value, if none has been set
    #define RGB_MATRIX_DEFAULT_VAL 255 // Sets the default brightness value, if none has been set
    
    

    Enabling Auto Shift requires this rules.mk file:

    AUTO_SHIFT_ENABLE = yes
    

    Both of those go in the keymap directory defining the keyboard mapping for my custom setup:

    qmk_firmware/keyboards/keychron/c3_pro/ansi/rgb/keymaps/ednisley
    

    The keymap.c file remains unchanged, although I’m mildly tempted to toss the Mac layouts overboard.

    For the record, setting QMK to compile that keyboard configuration goes like this:

    qmk setup -H /base_directory/…/qmk_firmware
    <snippage>
    qmk new-keymap -kb keychron/c3_pro/ansi/rgb -km ednisley
    qmk config user.keyboard=keychron/c3_pro/ansi/rgb user.keymap=ednisley
    qmk compile
    qmk flash
    

    Flashing the keyboard firmware goes like this:

    • Run qmk flash
    • Unplug the USB cable
    • Hold down the Esc key
    • Plug in the USB cable
    • Release the Esc key

    I should boot the Atreus configuration into the current decade, but that’s for later.

  • Kensington Expert Mouse Trackball: Switch Failure

    Kensington Expert Mouse Trackball: Switch Failure

    All of my Kensington Expert Mouse Trackballs have worked fine for the last several years, despite their previous history of scroll ring troubles, until the main button on the trackball at my left hand stopped responding to thumb pressure.

    You can tell that button has done a lot of clicking:

    Kensington Expert Mouse Trackball - worn button
    Kensington Expert Mouse Trackball – worn button

    The switch layout comes as no surprise:

    Kensington Expert Mouse Trackball - switch layout
    Kensington Expert Mouse Trackball – switch layout

    Those are Genuine Omron D2F-01 SPDT switches and the replacements are Genuine Anonymous D2F-01F. While I had the cover off, I replaced all four switches.

    Protip: The black cable on the right must go under the three wires between the PCBs. Arranged as shown, the scroll ring will drag on the cable.

    I dismantled the switches and put their Common bar under the microscope. I believe these contacts rest on the Normally Closed switch terminal, which is electrically inert:

    Kensington Expert Mouse Trackball - NC contacts
    Kensington Expert Mouse Trackball – NC contacts

    Three of them have about the same amount of wear:

    Kensington Expert Mouse Trackball - NC contact 2
    Kensington Expert Mouse Trackball – NC contact 2

    The leftmost one looks worse:

    Kensington Expert Mouse Trackball - NC contact 1
    Kensington Expert Mouse Trackball – NC contact 1

    Flipping them over (in the same order) exposes what I think are their Normally Open contacts responsible for all the button action:

    Kensington Expert Mouse Trackball - NO contacts
    Kensington Expert Mouse Trackball – NO contacts

    Again, the rightmost three look about the same and the contact on the left shows more wear, plus what looks like a soot streak:

    Kensington Expert Mouse Trackball - NO Contacts 1 2
    Kensington Expert Mouse Trackball – NO Contacts 1 2

    A closer look:

    Kensington Expert Mouse Trackball - NO Contact 1
    Kensington Expert Mouse Trackball – NO Contact 1

    These things operate at logic levels, so most of the damage surely comes from mechanical erosion and the soot is pulverized metal.

    While waiting for the switches to arrive, I deployed an Expert Mouse Trackball from a PC in the Basement Shop. The repaired unit went down there, so its new switches should survive longer even if they’re of mediocre quality.

  • Monitor Arm Tilt Adjustment: Bad Part Repair

    Monitor Arm Tilt Adjustment: Bad Part Repair

    The tilt (it’s really “pitch”, but I can’t make a case for being that pedantic) adjustment on a recently arrived monitor stand / arm was nonfunctional, because the metal clamp had been bent about a millimeter too narrow to fit the plastic core. This is how it should look:

    Monitor tilt adjustment - installed
    Monitor tilt adjustment – installed

    As delivered, the plastic core was 32-ish mm wide and the gap at the base of the metal clamp was 31 mm, so the clamp arms stuck out at an angle on both ends of the core .

    Because the cap screw bottomed out on the threads in the far side of the clamp, it couldn’t be tightened enough to force the clamp arms against the core.

    Well, if the core is a millimeter too large for the clamp, shortening it should solve the problem; I can always shorten the screw if it comes to that.

    Quick! To the mini-lathe:

    Monitor tilt adjustment - lathe setup
    Monitor tilt adjustment – lathe setup

    Shaving half a millimeter from each side:

    Monitor tilt adjustment - shaved
    Monitor tilt adjustment – shaved

    Twirling a deburring bit in each hole got rid of the swarf.

    Rather than trimming the cap screw, a pair of fender washers keep it from bottoming out. With the core fitting into the clamp, the arms grip the core firmly on both sides with plenty of friction:

    Monitor tilt adjustment - tweaked
    Monitor tilt adjustment – tweaked

    I’ve bought this brand of arm before and the most recent pair have definitely been cheapnified from earlier ones. Because only one had a bad tilt clamp, the OEM may be in the middle of a changeover and shipped it with mismatched parts.

    I wonder how many stands / arms get returned because they just don’t work?

  • Desktop PC Fuzz

    Desktop PC Fuzz

    Obviously, I haven’t popped the top on this PC for a while:

    Optiplex 9020 - intake fuzz
    Optiplex 9020 – intake fuzz

    Some fuzz made it past the grille:

    Optiplex 9020 - internal fuzz
    Optiplex 9020 – internal fuzz

    PSA: In the unlikely event you still use a desktop PC, it’s time to pop the top on yours, too.

  • SVG Attack Vector

    SVG Attack Vector

    An obvious spam email blew past the filters:

    Spam SVG Audio - email
    Spam SVG Audio – email

    You can tell it’s spam, too. Right?

    Those of you running Windows should have undone whatever setting removes file extensions from the usual views, because by default Windows won’t bother you with such trivia.

    But, hey, maybe an SVG file can contain an audio recording. I mean, there’s an online file converter for that, so it must be a thing.

    Spoiler: Audio-in-SVG really is a thing.

    Having been around this block a couple of times, though, let’s peek inside the SVG file with a text editor:

    Spam SVG Audio - attachment
    Spam SVG Audio – attachment

    Huh. Not an audio recording, but a Javascript one-liner with a URL/URI/IRI/whatever aiming Your Default Browser at a presumably compromised server.

    I didn’t go further, but surely the payload would wrestle Your Default Browser into a position allowing insertion of a remote compromise.

    Well played, spammer!

    Just another entry in the “Why friends don’t let friends run Windows” category, despite knowing whenever security and convenience come into conflict, convenience always wins.

  • GIMP 3.0 vs. XSane vs. gimp-xsanecli

    GIMP 3.0 vs. XSane vs. gimp-xsanecli

    For reasons I do not profess to understand, GIMP 3.0 does not work with plugins written for GIMP 2.0, including the XSane plugin that handles scanning. This seems like an obvious oversight, but after three months it also seems to be one of those things that’s like that and that’s the way it is.

    Protracted searching turned up gimp-xsanecli, a GIMP 3.0 plugin invoking XSane through its command-line interface to scan an image into a temporary file, then stuff the file into GIMP. Unfortunately, it didn’t work over the network with the Epson ET-3830 printer / scanner in the basement.

    It turns out gimp-xsanecli tells XSane to output the filename it’s using, then expects to find the identifying XSANE_IMAGE_FILENAME string followed by the filename on the first line of whatever it gets back:

    if result != 'XSANE_IMAGE_FILENAME: ' + png_out:
      Gimp.message('Unexpected XSane result: ' + result)
      return Gimp.ValueArray.new_from_values([GObject.Value(Gimp.PDBStatusType, Gimp.PDBStatusType.EXECUTION_ERROR)])
    
    

    The font ligature that may or may not mash != into is not under my control.

    Protracted poking showed the scanner fires a glob of HTML through proc/stdout into gimp-xsanecli before XSane produces its output, but after the scan completes:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN "
    "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
    … snippage …
    </head>
    <body><noscript>Enable your browser's JavaScript setting.</noscript></body></HTML>XSANE_IMAGE_FILENAME: /tmp/out.png
    

    Complicating the process:

    • The HTML glob only appears on the first scan, after which XSane produces exactly what gimp-xsanecli expects
    • There is no newline separating the glob from the expected output on the last line

    So …

    Insert a while loop into the main loop to strip off the HTML glob line by line by line:

            while True:
                    # Wait until XSane prints the name of the scanned file, indicating scanning is finished
                    # This blocks Python but that is ok because GIMP UI is not affected
    
                    # discard HTML header added by scanner to first scan
                    while True :
    
                            result = proc.stdout.readline().strip()
    
                            if r'</body>' in result :
                                    result = result.partition(r'</HTML>')[-1]
                            #        Gimp.message('Found end of HTML: ' + result)
                                    break
    
                            elif 'XSANE_IMAGE_FILENAME:' in result :
                            #        Gimp.message('Found filename: ' + result)
                                    break
    
                            else :
                            #        Gimp.message('Discarding: ' + result)
                                    continue
    
                    if result == '':
                            # XSane was closed
                            break
    
                    if result != 'XSANE_IMAGE_FILENAME: ' + png_out:
                            Gimp.message('Unexpected XSane result: ' + result)
                            return Gimp.ValueArray.new_from_values([GObject.Value(Gimp.PDBStatusType, Gimp.PDBStatusType.EXECUTION_ERROR)])
    
                    # Open image
                    image = Gimp.file_load(Gimp.RunMode.NONINTERACTIVE, Gio.File.new_for_path(png_out))
                    Gimp.Display.new(image)
    
                    # Remove temporary files
                    os.unlink(png_out)
    
                    if not SCAN_MULTIPLE:
                            proc.terminate()
                            break
    
            os.rmdir(tempdir)
    
            return Gimp.ValueArray.new_from_values([GObject.Value(Gimp.PDBStatusType, Gimp.PDBStatusType.SUCCESS), GObject.Value(Gimp.Image.__gtype__, image)])
    
    

    While it’s tempting to absorb the whole thing in one gulp with proc.stdout.read().strip(), that doesn’t work because nothing arrives until the XSane subprocess terminates, which is not what you want.

    A scan to show It Just Works™ :

    I expect it doesn’t work under a variety of common conditions, but … so far so good.