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

  • Upstart vs. NFS Mounts vs. LightDM: Success!

    That comment suggested a different solution to the problem of having the display manager start before the NFS mounts complete. When that happens, you can sign in and start programs that won’t have access to their data, producing all manner of heartache and confusion.

    One complication: it seems /etc/rc.local starts and runs before the network (among other tidbits) gets connected and becomes ready, which means you can’t just plunk your code in that file like you used to, at least not in Ubuntu. Fixing that requires an upstart script triggered when the network interface finally hauls itself to its feet.

    There’s no actual link between the NFS mount commands and the display manager startup, but it seems that if you don’t attempt to mount the NFS shares before the network becomes active (which is what happen with shares automounted through /etc/fstab), but wait for the network to come up and then issue the mounts, the shares mount almost instantly and become ready by the time the display manager presents the login screen. That’s better than the kludge I had figured out and works fine, so I’ll run with it until something else breaks.

    The not-quite-deterministic fix has three parts:

    • Use noauto in the fstab entries for the NFS shares
    • Create an upstart script to mount those shares after eth0 lights up
    • Allow lightdm to start up normally (i.e., remove my hackish attempts)

    A sample line from fstab, with the vital noauto option:

    oyster:/mnt/bulkdata	/mnt/bulkdata	nfs	noauto,noatime	0 0
    

    The /etc/init/local.conf script assumes the network interface will be eth0, which does not generalize to wireless networks on laptops and suchlike. You could add some Boolean logic to wait for the first of several interfaces, I suppose:

    description "Stuff that should be in /etc/rc.local"
    author "Ed Nisley - KE4ZNU"
    
    start on (local-filesystems and net-device-up IFACE=eth0)
    stop on shutdown
    script
    
    logger Starting local init...
    
    logger Mounting NFS filesystems
    mount /mnt/bulkdata
    mount /mnt/userfiles
    mount /mnt/diskimages
    mount /mnt/music
    
    logger Ending local init
    
    end script
    

    The lightdm.conf file reverts to the distribution version, with this starting trigger:

    start on ((filesystem
               and runlevel [!06]
               and started dbus
               and (drm-device-added card0 PRIMARY_DEVICE_FOR_DISPLAY=1
                    or stopped udev-fallback-graphics))
              or runlevel PREVLEVEL=S)
    

    It’s worth noting that the upstart interpreter hates comment lines embedded within statements: it does not regard them as whitespace and does not ignore them. Just don’t do it. That explains some of the problems I encountered before, but fixing those problems did not eliminate the overall issue.

    The end result of all that hocus-pocus makes the box boot the way it used to: the display manager comes up promptly, presents the GUI login screen, and the NFS mounts are ready when you are.

  • DVI Dual Link Display vs. DMS-59 Connector

    This is not made obvious at the outset, but a video card with a DMS-59 connector that can drive a pair of Single Link DVI monitors cannot drive a single Dual Link DVI monitor: the DMS-59 connector doesn’t have the required signals.

    The fact that each of the Single Link DVI connectors on the end of the DMS-59 Y-splitter cable have enough pins (well, holes) to mate with a Dual Link DVI cable doesn’t clarify the situation.

    Of course, you can’t combine two separate Single Link outputs into a Dual Link input.

    An HDMI 1.4 cable can support a single 2560×1440 monitor, but not from this resolutely low-res video card.

  • HAL Pin Names for an Arduino Leonardo Knockoff

    Going through the usual dance to reveal the HAL pin names for an Arduino Leonardo knockoff shows that it is, indeed, both a mouse and a keyboard.

    Arduino Leonardo knockoff - LinuxCNC box
    Arduino Leonardo knockoff – LinuxCNC box

    Pawing through less /proc/bus/input/devices reveals:

    I: Bus=0003 Vendor=2341 Product=8036 Version=0101
    N: Name="Arduino LLC Arduino Leonardo"
    P: Phys=usb-0000:00:1d.0-1/input2
    S: Sysfs=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1:1.2/input/input3
    U: Uniq=
    H: Handlers=kbd mouse1 event3
    B: EV=100017
    B: KEY=70000 0 0 0 0 e080ffdf 1cfffff ffffffff fffffffe
    B: REL=103
    B: MSC=10
    

    Tweaking the permissions:

    sudo chgrp users /dev/input/event3
    sudo chgrp users /dev/input/mouse1
    sudo chmod g+w /dev/input/event3
    sudo chmod g+w /dev/input/mouse1
    

    The output of lsusb shows something interesting:

    Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
    Bus 004 Device 006: ID 06f2:0011 Emine Technology Co. KVM Switch Keyboard
    Bus 004 Device 005: ID 046d:c401 Logitech, Inc. TrackMan Marble Wheel
    Bus 004 Device 004: ID 04d9:1203 Holtek Semiconductor, Inc. MC Industries Keyboard
    Bus 004 Device 003: ID 046d:c216 Logitech, Inc. Dual Action Gamepad
    Bus 004 Device 002: ID 0451:2046 Texas Instruments, Inc. TUSB2046 Hub
    Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
    Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
    Bus 002 Device 002: ID 2341:8036
    Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
    Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    

    For whatever reason, this board doesn’t report a device name. It’s plugged into the same USB port as that mouse, so it gets the same Bus and Device numbers, which helps confirm that’s the board.

    Querying the attributes with udevadm produces the all-important product string:

    udevadm info --query=all --attribute-walk --name=/dev/bus/usb/002/002
    ... snippage ...
      looking at device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1':
        KERNEL=="2-1"
        SUBSYSTEM=="usb"
        DRIVER=="usb"
        ATTR{configuration}==""
        ATTR{bNumInterfaces}==" 3"
        ATTR{bConfigurationValue}=="1"
        ATTR{bmAttributes}=="80"
        ATTR{bMaxPower}=="500mA"
        ATTR{urbnum}=="17"
        ATTR{idVendor}=="2341"
        ATTR{idProduct}=="8036"
        ATTR{bcdDevice}=="0100"
        ATTR{bDeviceClass}=="02"
        ATTR{bDeviceSubClass}=="00"
        ATTR{bDeviceProtocol}=="00"
        ATTR{bNumConfigurations}=="1"
        ATTR{bMaxPacketSize0}=="64"
        ATTR{speed}=="12"
        ATTR{busnum}=="2"
        ATTR{devnum}=="2"
        ATTR{version}==" 2.00"
        ATTR{maxchild}=="0"
        ATTR{quirks}=="0x0"
        ATTR{authorized}=="1"
        ATTR{manufacturer}=="Arduino LLC"
        ATTR{product}=="Arduino Leonardo"
    

    Then we know enough to discover what it can do:

    halrun
    halcmd: loadusr -W hal_input -KRAL Leo
    halcmd: show all
    Loaded HAL Components:
    ID      Type  Name                                      PID   State
         5  User  hal_input                                 11265 ready
         3  User  halcmd11264                               11264 ready
    
    Component Pins:
    Owner   Type  Dir         Value  Name
         5  bit   OUT         FALSE  input.0.btn-middle
         5  bit   OUT          TRUE  input.0.btn-middle-not
         5  bit   OUT         FALSE  input.0.btn-mouse
         5  bit   OUT          TRUE  input.0.btn-mouse-not
         5  bit   OUT         FALSE  input.0.btn-right
         5  bit   OUT          TRUE  input.0.btn-right-not
         5  bit   OUT         FALSE  input.0.key-0
         5  bit   OUT          TRUE  input.0.key-0-not
         5  bit   OUT         FALSE  input.0.key-1
         5  bit   OUT          TRUE  input.0.key-1-not
         5  bit   OUT         FALSE  input.0.key-102nd
         5  bit   OUT          TRUE  input.0.key-102nd-not
         5  bit   OUT         FALSE  input.0.key-2
         5  bit   OUT          TRUE  input.0.key-2-not
         5  bit   OUT         FALSE  input.0.key-3
         5  bit   OUT          TRUE  input.0.key-3-not
         5  bit   OUT         FALSE  input.0.key-4
         5  bit   OUT          TRUE  input.0.key-4-not
         5  bit   OUT         FALSE  input.0.key-5
         5  bit   OUT          TRUE  input.0.key-5-not
         5  bit   OUT         FALSE  input.0.key-6
         5  bit   OUT          TRUE  input.0.key-6-not
         5  bit   OUT         FALSE  input.0.key-7
         5  bit   OUT          TRUE  input.0.key-7-not
         5  bit   OUT         FALSE  input.0.key-8
         5  bit   OUT          TRUE  input.0.key-8-not
         5  bit   OUT         FALSE  input.0.key-9
         5  bit   OUT          TRUE  input.0.key-9-not
         5  bit   OUT         FALSE  input.0.key-a
         5  bit   OUT          TRUE  input.0.key-a-not
         5  bit   OUT         FALSE  input.0.key-apostrophe
         5  bit   OUT          TRUE  input.0.key-apostrophe-not
         5  bit   OUT         FALSE  input.0.key-b
         5  bit   OUT          TRUE  input.0.key-b-not
         5  bit   OUT         FALSE  input.0.key-backslash
         5  bit   OUT          TRUE  input.0.key-backslash-not
         5  bit   OUT         FALSE  input.0.key-backspace
         5  bit   OUT          TRUE  input.0.key-backspace-not
         5  bit   OUT         FALSE  input.0.key-c
         5  bit   OUT          TRUE  input.0.key-c-not
         5  bit   OUT         FALSE  input.0.key-capslock
         5  bit   OUT          TRUE  input.0.key-capslock-not
         5  bit   OUT         FALSE  input.0.key-comma
         5  bit   OUT          TRUE  input.0.key-comma-not
         5  bit   OUT         FALSE  input.0.key-compose
         5  bit   OUT          TRUE  input.0.key-compose-not
         5  bit   OUT         FALSE  input.0.key-d
         5  bit   OUT          TRUE  input.0.key-d-not
         5  bit   OUT         FALSE  input.0.key-delete
         5  bit   OUT          TRUE  input.0.key-delete-not
         5  bit   OUT         FALSE  input.0.key-dot
         5  bit   OUT          TRUE  input.0.key-dot-not
         5  bit   OUT         FALSE  input.0.key-down
         5  bit   OUT          TRUE  input.0.key-down-not
         5  bit   OUT         FALSE  input.0.key-e
         5  bit   OUT          TRUE  input.0.key-e-not
         5  bit   OUT         FALSE  input.0.key-end
         5  bit   OUT          TRUE  input.0.key-end-not
         5  bit   OUT         FALSE  input.0.key-enter
         5  bit   OUT          TRUE  input.0.key-enter-not
         5  bit   OUT         FALSE  input.0.key-equal
         5  bit   OUT          TRUE  input.0.key-equal-not
         5  bit   OUT         FALSE  input.0.key-esc
         5  bit   OUT          TRUE  input.0.key-esc-not
         5  bit   OUT         FALSE  input.0.key-f
         5  bit   OUT          TRUE  input.0.key-f-not
         5  bit   OUT         FALSE  input.0.key-f1
         5  bit   OUT          TRUE  input.0.key-f1-not
         5  bit   OUT         FALSE  input.0.key-f10
         5  bit   OUT          TRUE  input.0.key-f10-not
         5  bit   OUT         FALSE  input.0.key-f11
         5  bit   OUT          TRUE  input.0.key-f11-not
         5  bit   OUT         FALSE  input.0.key-f12
         5  bit   OUT          TRUE  input.0.key-f12-not
         5  bit   OUT         FALSE  input.0.key-f2
         5  bit   OUT          TRUE  input.0.key-f2-not
         5  bit   OUT         FALSE  input.0.key-f3
         5  bit   OUT          TRUE  input.0.key-f3-not
         5  bit   OUT         FALSE  input.0.key-f4
         5  bit   OUT          TRUE  input.0.key-f4-not
         5  bit   OUT         FALSE  input.0.key-f5
         5  bit   OUT          TRUE  input.0.key-f5-not
         5  bit   OUT         FALSE  input.0.key-f6
         5  bit   OUT          TRUE  input.0.key-f6-not
         5  bit   OUT         FALSE  input.0.key-f7
         5  bit   OUT          TRUE  input.0.key-f7-not
         5  bit   OUT         FALSE  input.0.key-f8
         5  bit   OUT          TRUE  input.0.key-f8-not
         5  bit   OUT         FALSE  input.0.key-f9
         5  bit   OUT          TRUE  input.0.key-f9-not
         5  bit   OUT         FALSE  input.0.key-g
         5  bit   OUT          TRUE  input.0.key-g-not
         5  bit   OUT         FALSE  input.0.key-grave
         5  bit   OUT          TRUE  input.0.key-grave-not
         5  bit   OUT         FALSE  input.0.key-h
         5  bit   OUT          TRUE  input.0.key-h-not
         5  bit   OUT         FALSE  input.0.key-home
         5  bit   OUT          TRUE  input.0.key-home-not
         5  bit   OUT         FALSE  input.0.key-i
         5  bit   OUT          TRUE  input.0.key-i-not
         5  bit   OUT         FALSE  input.0.key-insert
         5  bit   OUT          TRUE  input.0.key-insert-not
         5  bit   OUT         FALSE  input.0.key-j
         5  bit   OUT          TRUE  input.0.key-j-not
         5  bit   OUT         FALSE  input.0.key-k
         5  bit   OUT          TRUE  input.0.key-k-not
         5  bit   OUT         FALSE  input.0.key-kp0
         5  bit   OUT          TRUE  input.0.key-kp0-not
         5  bit   OUT         FALSE  input.0.key-kp1
         5  bit   OUT          TRUE  input.0.key-kp1-not
         5  bit   OUT         FALSE  input.0.key-kp2
         5  bit   OUT          TRUE  input.0.key-kp2-not
         5  bit   OUT         FALSE  input.0.key-kp3
         5  bit   OUT          TRUE  input.0.key-kp3-not
         5  bit   OUT         FALSE  input.0.key-kp4
         5  bit   OUT          TRUE  input.0.key-kp4-not
         5  bit   OUT         FALSE  input.0.key-kp5
         5  bit   OUT          TRUE  input.0.key-kp5-not
         5  bit   OUT         FALSE  input.0.key-kp6
         5  bit   OUT          TRUE  input.0.key-kp6-not
         5  bit   OUT         FALSE  input.0.key-kp7
         5  bit   OUT          TRUE  input.0.key-kp7-not
         5  bit   OUT         FALSE  input.0.key-kp8
         5  bit   OUT          TRUE  input.0.key-kp8-not
         5  bit   OUT         FALSE  input.0.key-kp9
         5  bit   OUT          TRUE  input.0.key-kp9-not
         5  bit   OUT         FALSE  input.0.key-kpasterisk
         5  bit   OUT          TRUE  input.0.key-kpasterisk-not
         5  bit   OUT         FALSE  input.0.key-kpdot
         5  bit   OUT          TRUE  input.0.key-kpdot-not
         5  bit   OUT         FALSE  input.0.key-kpenter
         5  bit   OUT          TRUE  input.0.key-kpenter-not
         5  bit   OUT         FALSE  input.0.key-kpminus
         5  bit   OUT          TRUE  input.0.key-kpminus-not
         5  bit   OUT         FALSE  input.0.key-kpplus
         5  bit   OUT          TRUE  input.0.key-kpplus-not
         5  bit   OUT         FALSE  input.0.key-kpslash
         5  bit   OUT          TRUE  input.0.key-kpslash-not
         5  bit   OUT         FALSE  input.0.key-l
         5  bit   OUT          TRUE  input.0.key-l-not
         5  bit   OUT         FALSE  input.0.key-left
         5  bit   OUT          TRUE  input.0.key-left-not
         5  bit   OUT         FALSE  input.0.key-leftalt
         5  bit   OUT          TRUE  input.0.key-leftalt-not
         5  bit   OUT         FALSE  input.0.key-leftbrace
         5  bit   OUT          TRUE  input.0.key-leftbrace-not
         5  bit   OUT         FALSE  input.0.key-leftctrl
         5  bit   OUT          TRUE  input.0.key-leftctrl-not
         5  bit   OUT         FALSE  input.0.key-leftmeta
         5  bit   OUT          TRUE  input.0.key-leftmeta-not
         5  bit   OUT         FALSE  input.0.key-leftshift
         5  bit   OUT          TRUE  input.0.key-leftshift-not
         5  bit   OUT         FALSE  input.0.key-m
         5  bit   OUT          TRUE  input.0.key-m-not
         5  bit   OUT         FALSE  input.0.key-minus
         5  bit   OUT          TRUE  input.0.key-minus-not
         5  bit   OUT         FALSE  input.0.key-n
         5  bit   OUT          TRUE  input.0.key-n-not
         5  bit   OUT         FALSE  input.0.key-numlock
         5  bit   OUT          TRUE  input.0.key-numlock-not
         5  bit   OUT         FALSE  input.0.key-o
         5  bit   OUT          TRUE  input.0.key-o-not
         5  bit   OUT         FALSE  input.0.key-p
         5  bit   OUT          TRUE  input.0.key-p-not
         5  bit   OUT         FALSE  input.0.key-pagedown
         5  bit   OUT          TRUE  input.0.key-pagedown-not
         5  bit   OUT         FALSE  input.0.key-pageup
         5  bit   OUT          TRUE  input.0.key-pageup-not
         5  bit   OUT         FALSE  input.0.key-pause
         5  bit   OUT          TRUE  input.0.key-pause-not
         5  bit   OUT         FALSE  input.0.key-q
         5  bit   OUT          TRUE  input.0.key-q-not
         5  bit   OUT         FALSE  input.0.key-r
         5  bit   OUT          TRUE  input.0.key-r-not
         5  bit   OUT         FALSE  input.0.key-right
         5  bit   OUT          TRUE  input.0.key-right-not
         5  bit   OUT         FALSE  input.0.key-rightalt
         5  bit   OUT          TRUE  input.0.key-rightalt-not
         5  bit   OUT         FALSE  input.0.key-rightbrace
         5  bit   OUT          TRUE  input.0.key-rightbrace-not
         5  bit   OUT         FALSE  input.0.key-rightctrl
         5  bit   OUT          TRUE  input.0.key-rightctrl-not
         5  bit   OUT         FALSE  input.0.key-rightmeta
         5  bit   OUT          TRUE  input.0.key-rightmeta-not
         5  bit   OUT         FALSE  input.0.key-rightshift
         5  bit   OUT          TRUE  input.0.key-rightshift-not
         5  bit   OUT         FALSE  input.0.key-s
         5  bit   OUT          TRUE  input.0.key-s-not
         5  bit   OUT         FALSE  input.0.key-scrolllock
         5  bit   OUT          TRUE  input.0.key-scrolllock-not
         5  bit   OUT         FALSE  input.0.key-semicolon
         5  bit   OUT          TRUE  input.0.key-semicolon-not
         5  bit   OUT         FALSE  input.0.key-slash
         5  bit   OUT          TRUE  input.0.key-slash-not
         5  bit   OUT         FALSE  input.0.key-space
         5  bit   OUT          TRUE  input.0.key-space-not
         5  bit   OUT         FALSE  input.0.key-sysrq
         5  bit   OUT          TRUE  input.0.key-sysrq-not
         5  bit   OUT         FALSE  input.0.key-t
         5  bit   OUT          TRUE  input.0.key-t-not
         5  bit   OUT         FALSE  input.0.key-tab
         5  bit   OUT          TRUE  input.0.key-tab-not
         5  bit   OUT         FALSE  input.0.key-u
         5  bit   OUT          TRUE  input.0.key-u-not
         5  bit   OUT         FALSE  input.0.key-up
         5  bit   OUT          TRUE  input.0.key-up-not
         5  bit   OUT         FALSE  input.0.key-v
         5  bit   OUT          TRUE  input.0.key-v-not
         5  bit   OUT         FALSE  input.0.key-w
         5  bit   OUT          TRUE  input.0.key-w-not
         5  bit   OUT         FALSE  input.0.key-x
         5  bit   OUT          TRUE  input.0.key-x-not
         5  bit   OUT         FALSE  input.0.key-y
         5  bit   OUT          TRUE  input.0.key-y-not
         5  bit   OUT         FALSE  input.0.key-z
         5  bit   OUT          TRUE  input.0.key-z-not
         5  s32   OUT             0  input.0.rel-wheel-counts
         5  float OUT             0  input.0.rel-wheel-position
         5  bit   IN          FALSE  input.0.rel-wheel-reset
         5  float IN              1  input.0.rel-wheel-scale
         5  s32   OUT             0  input.0.rel-x-counts
         5  float OUT             0  input.0.rel-x-position
         5  bit   IN          FALSE  input.0.rel-x-reset
         5  float IN              1  input.0.rel-x-scale
         5  s32   OUT             0  input.0.rel-y-counts
         5  float OUT             0  input.0.rel-y-position
         5  bit   IN          FALSE  input.0.rel-y-reset
         5  float IN              1  input.0.rel-y-scale
    

    That’s a pretty decent assortment of directly usable names and features, even without keyboard LEDs. The mouse pins could be repurposed for general sensor values:

    • counts = integer = accumulated encoder wheel ticks
    • position = float = count / scale (why divided? I don’t know)
    • scale = float = turns counts into position
    • reset = bit = resets position or maybe count (not sure)

    I think you could use count to transfer a bare ADC reading from the Leonardo, then use scale to get the actual voltage in “position”. In that situation, reset wouldn’t be at all useful.

    The keyboard pins could transfer Boolean sensors.

    You’d want to give HAL exclusive control of the Leonardo-is-not-a-mouse, because the incoming data would make hash of the, ah, LinuxCNC UI experience in short order. I’m not sure how to control that; the Leonardo advice boils down to “be careful” and “use a physical switch”.

    I have *no* idea where the names come from, but apparently the OS / kernel / something has a HID layer that translates bare USB capability bits into strings. How that relates to a particular device, what the choices might be, how one could add / replace the names for a given device, and all that, I don’t know yet.

  • Poking Around in Upstart

    The hack I added to the lightdm startup script occasionally causes it to hang, which suggests a timing problem. The result leaves the default text-mode login screen active on VT1, after which I can log in and issue sudo lightdm start to produce the usual GUI screen. Using startx doesn’t (seem to) start the display manager, resulting in all manner of weird behavior.

    The definitive Upstart info seems to be in the Upstart Intro, Cookbook, and Best Practises document.

    The stanza I modified looks like this:

    start on ((filesystem
               and runlevel [!06]
               and started dbus
               and (drm-device-added card0 PRIMARY_DEVICE_FOR_DISPLAY=1
                    or stopped udev-fallback-graphics)
               and mounted MOUNTPOINT=/mnt/bulkdata)
              or runlevel PREVLEVEL=S)
    

    According to the timing diagram in section 10.1.8, the filesystem event should happen after all the remote filesystems have been mounted, which seems like that stanza might produce a race condition. So just waiting for the filesystem event should suffice, but it doesn’t; that’s why I had to add the mounted event.

    According to the example in section 11.14, that stanza should probably look like:

    start on ((filesystem
               and (runlevel [!06]
               and (started dbus
               and (drm-device-added card0 PRIMARY_DEVICE_FOR_DISPLAY=1
                    or stopped udev-fallback-graphics))))
              or runlevel PREVLEVEL=S)
    

    The additional parentheses around successive conditions seem to serialize them, so that they need not all occur at the same time.

    At least I think that’s how it should work…

    Unfortunately, it doesn’t.  The good news is that it’s converted the intermittent failure into a hard fault, which is generally a step in the right direction.

    Changing the stanza to:

    #start on ((filesystem
    start on ((mounted MOUNTPOINT=/mnt/bulkdata
               and runlevel [!06]
               and started dbus
               and (drm-device-added card0 PRIMARY_DEVICE_FOR_DISPLAY=1
                    or stopped udev-fallback-graphics))
    #           and mounted MOUNTPOINT=/mnt/bulkdata))
              or runlevel PREVLEVEL=S)
    

    … also fails hard.

    At this point, I have no idea what to do, so I’ve restored the original stanza.

  • Eagle HAL Configuration: Nostromo N52 Controller

    Combining some of the pin names generated by hal_input with the recipe for creating HAL devices, here’s a test configuration that hitches an old Nostromo N52 controller to a LinuxCNC system (clicky for more dots):

    Nostromo N52 Controller - HAL config
    Nostromo N52 Controller – HAL config

    The F01 key lights the red LED, the Orange Button lights the green LED, and a oneshot timer pulses the blue LED for half a second after the Button closes. The Thread block defines the connections from the functions to the main timing routine, and the loadrt block defines the thread timing. The hal_input module takes care of its own input sampling in userspace.

    Now, for the classic embedded system “Hello, world!” test:

    Nostromo N52 Controller - F01 test
    Nostromo N52 Controller – F01 test

    It’s amazing how good an LED can make you feel…

    A halscope shot shows the timing relation between the Orange Button (confusingly hitched to the greenkey signal) and the oneshot pulse:

    HalScope - oneshot triggering
    HalScope – oneshot triggering

    That schematic produces this HAL configuration file:

    # HAL config file automatically generated by Eagle-CAD ULP:
    # [/mnt/bulkdata/Project Files/eagle/ulp/hal-write-2.5.ulp]
    # (C) Martin Schoeneck.de 2008
    # Charalampos Alexopoulos 2011
    # Mods Ed Nisley KE4ZNU 2010 2013
    # Path        [/mnt/bulkdata/Project Files/eagle/projects/LinuxCNC HAL Configuration/]
    # ProjectName [Nostromo]
    # File name   [/mnt/bulkdata/Project Files/eagle/projects/LinuxCNC HAL Configuration/Nostromo.hal]
    # Created     [12:28:04 14-Feb-2013]
    
    ####################################################
    # Load realtime and userspace modules
    loadrt threads name1=test-thread period1=1000000
    loadusr -W hal_input -K +Nostromo:0 -KRL +Nostromo:1
    loadrt constant		count=1
    loadrt oneshot		count=1
    
    ####################################################
    # Hook functions into threads
    addf oneshot.0		test-thread
    addf constant.0		test-thread
    
    ####################################################
    # Set parameters
    
    ####################################################
    # Set constants
    setp constant.0.value	0.5
    
    ####################################################
    # Connect Modules with nets
    net bluepulse input.1.led-scrolll oneshot.0.out
    net duration constant.0.out oneshot.0.width
    net greenkey input.0.key-leftalt oneshot.0.in input.1.led-capsl
    net redkey input.0.key-tab input.1.led-numl
    

    A snapshot of the Nostromo.sch, Nostromo.hal, hal_config.lbr, and hal-write-2.5.ulp files is in Nostromo-N52.zip.odt. Rename it to get rid of the ODT suffix, unzip it, and there you go.

  • Gratuitous Engine Jeweling

    While pondering whether I should use the carcass of an old Dell PC to house the stepper drivers and control logic for the LinuxCNC M2 project, I bandsawed a scrap of aluminum sheet to about the right size. It had some truly nasty gouges and bonded-on crud, so I chucked up a wire brush cup in the drill press and had at it:

    Machine jeweled baseplate
    Machine jeweled baseplate

    It’s obvious I haven’t done jeweling in a long time, isn’t it? Even a crude engine jeweling job spiffs things right up, though, even if a cough showcase job like this deserves straighter lines and more precise spacing. The aluminum sheet is far too large for the Sherline, which put CNC right out of consideration, and I’m not up for sufficient crank spinning on the big manual mill.

    I match-marked mounting holes directly from the harvested motherboard and drilled them, whereupon I discovered that the aluminum is a dead-soft gummy alloy that doesn’t machine cleanly: it won’t become the final baseplate.

    Memo to Self: Use the shop vacuum with the nozzle spinward of the brush, fool.

  • LinuxCNC HAL Pin Names: Belkin Nostromo N52 SpeedPad

    A (formerly Belkin, now Razer, which is evidently unrelated to Mazer Rackham) Nostromo N52 SpeedPad might not be a perfect CNC pendant, but it does have plenty of buttons and an (oddly oriented) XY joypad that might be useful for, say, a 3D printer controller running LinuxCNC.

    Belkin Nostromo N52 SpeedPad
    Belkin Nostromo N52 SpeedPad

    Following the same path as with the Logitech Dual Action Gamepad that became the Joggy Thing, we find that the N52 reports itself as a keyboard and a mouse:

    less /proc/bus/input/devices
    
    ... snippage ...
    I: Bus=0003 Vendor=050d Product=0815 Version=0110
    N: Name="Honey Bee  Nostromo SpeedPad2 "
    P: Phys=usb-0000:00:02.0-10/input0
    S: Sysfs=/devices/pci0000:00/0000:00:02.0/usb2/2-10/2-10:1.0/input/input3
    U: Uniq=
    H: Handlers=kbd event3
    B: EV=100013
    B: KEY=e080ffdf 1cfffff ffffffff fffffffe
    B: MSC=10
    
    I: Bus=0003 Vendor=050d Product=0815 Version=0110
    N: Name="Honey Bee  Nostromo SpeedPad2 "
    P: Phys=usb-0000:00:02.0-10/input1
    S: Sysfs=/devices/pci0000:00/0000:00:02.0/usb2/2-10/2-10:1.1/input/input4
    U: Uniq=
    H: Handlers=mouse1 event4
    B: EV=20017
    B: KEY=70000 0 0 0 0 0 0 0 0
    B: REL=103
    B: MSC=10
    B: LED=7
    

    The corresponding device files belong to the root user:

    ll /dev/input
    ... snippage ...
    crw-r-----  1 root root 13, 67 2013-02-08 11:06 event3
    crw-r-----  1 root root 13, 68 2013-02-08 11:06 event4
    ... snippage ...
    crw-r-----  1 root root 13, 33 2013-02-08 11:06 mouse1
    

    Which calls for some udev trickery to change the owner & permissions during boot / hotplugging so that it becomes available to mere mortals such as I.

    First, get the bus connection information:

    lsusb
    ... snippage ...
    Bus 002 Device 004: ID 050d:0815 Belkin Components Nostromo n52 HID SpeedPad Mouse Wheel
    ... snippage ...
    

    Then dump the attributes:

    udevadm info --query=all --attribute-walk --name=/dev/bus/usb/002/004
    
    Udevadm info starts with the device specified by the devpath and then
    walks up the chain of parent devices. It prints for every device
    found, all possible attributes in the udev rules key format.
    A rule to match, can be composed by the attributes of the device
    and the attributes from one single parent device.
    
      looking at device '/devices/pci0000:00/0000:00:02.0/usb2/2-10':
        KERNEL=="2-10"
        SUBSYSTEM=="usb"
        DRIVER=="usb"
        ATTR{configuration}==""
        ATTR{bNumInterfaces}==" 2"
        ATTR{bConfigurationValue}=="1"
        ATTR{bmAttributes}=="80"
        ATTR{bMaxPower}==" 90mA"
        ATTR{urbnum}=="1354"
        ATTR{idVendor}=="050d"
        ATTR{idProduct}=="0815"
        ATTR{bcdDevice}=="0210"
        ATTR{bDeviceClass}=="00"
        ATTR{bDeviceSubClass}=="00"
        ATTR{bDeviceProtocol}=="00"
        ATTR{bNumConfigurations}=="1"
        ATTR{bMaxPacketSize0}=="8"
        ATTR{speed}=="1.5"
        ATTR{busnum}=="2"
        ATTR{devnum}=="4"
        ATTR{version}==" 1.10"
        ATTR{maxchild}=="0"
        ATTR{quirks}=="0x0"
        ATTR{authorized}=="1"
        ATTR{manufacturer}=="Honey Bee "
        ATTR{product}=="Nostromo SpeedPad2 "
    
    ... snippage ...
    

    Note the trailing blank in the manufacturer and product values.

    Create a new rules file /etc/udev/rule/90-Nostromo.rules to change the group and permissions:

    # Belkin Nostromo N52 SpeedPad controller for LinuxCNC
    # Ed Nisley - KE4ZNU - February 2013
    
    ATTRS{product}=="Nostromo SpeedPad2",GROUP="plugdev",MODE="0660"
    

    Note that the file name must start with a number around 90- to avoid being clobbered by a rule in /lib/udev/rules.d/50-udev-default.rules that (re)sets the permissions to 0640; the doc suggests that rules without numbers happen after all the number rules, so perhaps you could just use meaningful names. That took an embarrassingly long time to figure out…

    There’s no need for the trailing blank in that rule, as the match proceeds left-to-right and stops at the end of the test string.

    You must, perforce, be in the plugdev group. If not, add yourself.

    You need not unplug the N52 to test the rule. Just use:

    sudo udevadm trigger
    

    Which produces the desired result:

    crw-rw----  1 root plugdev 13, 67 2013-02-08 15:09 event3
    crw-rw----  1 root plugdev 13, 68 2013-02-08 15:09 event4
    ... snippage ...
    crw-rw----  1 root plugdev 13, 33 2013-02-08 15:09 mouse1
    

    Poking around using, among other things, xev reveals:

    • Main keypad is the left half of a standard QWERTY keyboard
    • Joypad returns cursor keys, center push = nothing
    • Orange button is, weirdly, the Left-Alt key
    • Wheel is a mouse scroll wheel
    • Push wheel = middle mouse button
    • Thumb pad = space
    • RGB LEDs are, respectively, num-, caps-, and scroll-lock

    Then load HAL:

    halrun
    loadusr -W hal_input -K +Nostromo:0 -KRL +Nostromo:1
    show pin input.*
    loadusr halmeter
    

    The + prefix tells HAL to capture the named device and prevent its events from reaching X. The KRL codes suggest which functions you’re interested in for that particular device. The suffix digit selects successive devices for multiple gadgets matching the same name string.

    Apparently, the N52 reports it can produce all the usual keyboard and mouse values & buttons, even if they’re not connected to physical hardware. I suspect it has generic keyboard / mouse controllers inside, with just a few of the usual matrix crosspoints connected to switches.

    The basic key mapping, sorted by the Nostromo functions:

    Type Dir Name Nostromo key
    bit OUT input.0.key-tab F1
    bit OUT input.0.key-q F2
    bit OUT input.0.key-w F3
    bit OUT input.0.key-e F4
    bit OUT input.0.key-r F5
    bit OUT input.0.key-capslock F6
    bit OUT input.0.key-a F7
    bit OUT input.0.key-s F8
    bit OUT input.0.key-d F9
    bit OUT input.0.key-f F10
    bit OUT input.0.key-leftshift F11
    bit OUT input.0.key-z F12
    bit OUT input.0.key-x F13
    bit OUT input.0.key-c F14
    bit OUT input.0.key-space F15
    bit OUT input.0.key-leftalt Orange button
    bit OUT input.0.key-right Pad bottom
    bit OUT input.0.key-down Pad front
    bit OUT input.0.key-up Pad rear
    bit OUT input.0.key-left Pad top
    bit OUT input.1.btn-middle Wheel press
    s32 OUT input.1.rel-wheel-counts Scroll wheel
    bit IN input.1.led-numl Red LED
    bit IN input.1.led-capsl Green LED
    bit IN input.1.led-scrolll Blue LED

    The bit pins also have inverted values available on the corresponding -not pins. The LEDs have an -invert that flips the sense of the input pin. The rel-wheel pin has other useful tidbits as suffixes; the count changes by ±1 for each wheel detent.

    The Tab key and all the letters auto-repeat, the various Shift and Alt keys do not. That seems to make no difference to the bit values reported by HAL.

    The complete table, sorted by HAL pin name:

    Type Dir Name Nostromo key
    bit OUT input.0.key-0
    bit OUT input.0.key-0-not
    bit OUT input.0.key-1
    bit OUT input.0.key-1-not
    bit OUT input.0.key-102nd
    bit OUT input.0.key-102nd-not
    bit OUT input.0.key-2
    bit OUT input.0.key-2-not
    bit OUT input.0.key-3
    bit OUT input.0.key-3-not
    bit OUT input.0.key-4
    bit OUT input.0.key-4-not
    bit OUT input.0.key-5
    bit OUT input.0.key-5-not
    bit OUT input.0.key-6
    bit OUT input.0.key-6-not
    bit OUT input.0.key-7
    bit OUT input.0.key-7-not
    bit OUT input.0.key-8
    bit OUT input.0.key-8-not
    bit OUT input.0.key-9
    bit OUT input.0.key-9-not
    bit OUT input.0.key-a F7
    bit OUT input.0.key-a-not
    bit OUT input.0.key-apostrophe
    bit OUT input.0.key-apostrophe-not
    bit OUT input.0.key-b
    bit OUT input.0.key-b-not
    bit OUT input.0.key-backslash
    bit OUT input.0.key-backslash-not
    bit OUT input.0.key-backspace
    bit OUT input.0.key-backspace-not
    bit OUT input.0.key-c F14
    bit OUT input.0.key-c-not
    bit OUT input.0.key-capslock F6
    bit OUT input.0.key-capslock-not
    bit OUT input.0.key-comma
    bit OUT input.0.key-comma-not
    bit OUT input.0.key-compose
    bit OUT input.0.key-compose-not
    bit OUT input.0.key-d F9
    bit OUT input.0.key-d-not
    bit OUT input.0.key-delete
    bit OUT input.0.key-delete-not
    bit OUT input.0.key-dot
    bit OUT input.0.key-dot-not
    bit OUT input.0.key-down Pad left
    bit OUT input.0.key-down-not
    bit OUT input.0.key-e F4
    bit OUT input.0.key-e-not
    bit OUT input.0.key-end
    bit OUT input.0.key-end-not
    bit OUT input.0.key-enter
    bit OUT input.0.key-enter-not
    bit OUT input.0.key-equal
    bit OUT input.0.key-equal-not
    bit OUT input.0.key-esc
    bit OUT input.0.key-esc-not
    bit OUT input.0.key-f F10
    bit OUT input.0.key-f-not
    bit OUT input.0.key-f1
    bit OUT input.0.key-f1-not
    bit OUT input.0.key-f10
    bit OUT input.0.key-f10-not
    bit OUT input.0.key-f11
    bit OUT input.0.key-f11-not
    bit OUT input.0.key-f12
    bit OUT input.0.key-f12-not
    bit OUT input.0.key-f2
    bit OUT input.0.key-f2-not
    bit OUT input.0.key-f3
    bit OUT input.0.key-f3-not
    bit OUT input.0.key-f4
    bit OUT input.0.key-f4-not
    bit OUT input.0.key-f5
    bit OUT input.0.key-f5-not
    bit OUT input.0.key-f6
    bit OUT input.0.key-f6-not
    bit OUT input.0.key-f7
    bit OUT input.0.key-f7-not
    bit OUT input.0.key-f8
    bit OUT input.0.key-f8-not
    bit OUT input.0.key-f9
    bit OUT input.0.key-f9-not
    bit OUT input.0.key-g
    bit OUT input.0.key-g-not
    bit OUT input.0.key-grave
    bit OUT input.0.key-grave-not
    bit OUT input.0.key-h
    bit OUT input.0.key-h-not
    bit OUT input.0.key-home
    bit OUT input.0.key-home-not
    bit OUT input.0.key-i
    bit OUT input.0.key-i-not
    bit OUT input.0.key-insert
    bit OUT input.0.key-insert-not
    bit OUT input.0.key-j
    bit OUT input.0.key-j-not
    bit OUT input.0.key-k
    bit OUT input.0.key-k-not
    bit OUT input.0.key-kp0
    bit OUT input.0.key-kp0-not
    bit OUT input.0.key-kp1
    bit OUT input.0.key-kp1-not
    bit OUT input.0.key-kp2
    bit OUT input.0.key-kp2-not
    bit OUT input.0.key-kp3
    bit OUT input.0.key-kp3-not
    bit OUT input.0.key-kp4
    bit OUT input.0.key-kp4-not
    bit OUT input.0.key-kp5
    bit OUT input.0.key-kp5-not
    bit OUT input.0.key-kp6
    bit OUT input.0.key-kp6-not
    bit OUT input.0.key-kp7
    bit OUT input.0.key-kp7-not
    bit OUT input.0.key-kp8
    bit OUT input.0.key-kp8-not
    bit OUT input.0.key-kp9
    bit OUT input.0.key-kp9-not
    bit OUT input.0.key-kpasterisk
    bit OUT input.0.key-kpasterisk-not
    bit OUT input.0.key-kpdot
    bit OUT input.0.key-kpdot-not
    bit OUT input.0.key-kpenter
    bit OUT input.0.key-kpenter-not
    bit OUT input.0.key-kpminus
    bit OUT input.0.key-kpminus-not
    bit OUT input.0.key-kpplus
    bit OUT input.0.key-kpplus-not
    bit OUT input.0.key-kpslash
    bit OUT input.0.key-kpslash-not
    bit OUT input.0.key-l
    bit OUT input.0.key-l-not
    bit OUT input.0.key-left Pad top
    bit OUT input.0.key-left-not
    bit OUT input.0.key-leftalt Orange button
    bit OUT input.0.key-leftalt-not
    bit OUT input.0.key-leftbrace
    bit OUT input.0.key-leftbrace-not
    bit OUT input.0.key-leftctrl
    bit OUT input.0.key-leftctrl-not
    bit OUT input.0.key-leftmeta
    bit OUT input.0.key-leftmeta-not
    bit OUT input.0.key-leftshift F11
    bit OUT input.0.key-leftshift-not
    bit OUT input.0.key-m
    bit OUT input.0.key-m-not
    bit OUT input.0.key-minus
    bit OUT input.0.key-minus-not
    bit OUT input.0.key-n
    bit OUT input.0.key-n-not
    bit OUT input.0.key-numlock
    bit OUT input.0.key-numlock-not
    bit OUT input.0.key-o
    bit OUT input.0.key-o-not
    bit OUT input.0.key-p
    bit OUT input.0.key-p-not
    bit OUT input.0.key-pagedown
    bit OUT input.0.key-pagedown-not
    bit OUT input.0.key-pageup
    bit OUT input.0.key-pageup-not
    bit OUT input.0.key-pause
    bit OUT input.0.key-pause-not
    bit OUT input.0.key-q F2
    bit OUT input.0.key-q-not
    bit OUT input.0.key-r F5
    bit OUT input.0.key-r-not
    bit OUT input.0.key-right Pad bottom
    bit OUT input.0.key-right-not
    bit OUT input.0.key-rightalt
    bit OUT input.0.key-rightalt-not
    bit OUT input.0.key-rightbrace
    bit OUT input.0.key-rightbrace-not
    bit OUT input.0.key-rightctrl
    bit OUT input.0.key-rightctrl-not
    bit OUT input.0.key-rightmeta
    bit OUT input.0.key-rightmeta-not
    bit OUT input.0.key-rightshift
    bit OUT input.0.key-rightshift-not
    bit OUT input.0.key-s F8
    bit OUT input.0.key-s-not
    bit OUT input.0.key-scrolllock
    bit OUT input.0.key-scrolllock-not
    bit OUT input.0.key-semicolon
    bit OUT input.0.key-semicolon-not
    bit OUT input.0.key-slash
    bit OUT input.0.key-slash-not
    bit OUT input.0.key-space F15
    bit OUT input.0.key-space-not
    bit OUT input.0.key-sysrq
    bit OUT input.0.key-sysrq-not
    bit OUT input.0.key-t
    bit OUT input.0.key-t-not
    bit OUT input.0.key-tab F1
    bit OUT input.0.key-tab-not
    bit OUT input.0.key-u
    bit OUT input.0.key-u-not
    bit OUT input.0.key-up Pad right
    bit OUT input.0.key-up-not
    bit OUT input.0.key-v
    bit OUT input.0.key-v-not
    bit OUT input.0.key-w F3
    bit OUT input.0.key-w-not
    bit OUT input.0.key-x F13
    bit OUT input.0.key-x-not
    bit OUT input.0.key-y
    bit OUT input.0.key-y-not
    bit OUT input.0.key-z F12
    bit OUT input.0.key-z-not
    bit OUT input.1.btn-middle Wheel press
    bit OUT input.1.btn-middle-not  … inverted
    bit OUT input.1.btn-mouse
    bit OUT input.1.btn-mouse-not
    bit OUT input.1.btn-right
    bit OUT input.1.btn-right-not
    bit IN input.1.led-capsl Green LED
    bit IN input.1.led-capsl-invert
    bit IN input.1.led-numl Red LED
    bit IN input.1.led-numl-invert
    bit IN input.1.led-scrolll Blue LED
    bit IN input.1.led-scrolll-invert
    s32 OUT input.1.rel-wheel-counts Scroll wheel
    float OUT input.1.rel-wheel-position  =count/scale
    bit IN input.1.rel-wheel-reset Clear pos’n
    float IN input.1.rel-wheel-scale  count→pos’n
    s32 OUT input.1.rel-x-counts
    float OUT input.1.rel-x-position
    bit IN input.1.rel-x-reset
    float IN input.1.rel-x-scale
    s32 OUT input.1.rel-y-counts
    float OUT input.1.rel-y-position
    bit IN input.1.rel-y-reset
    float IN input.1.rel-y-scale