Setting up NFS on Ubuntu 20.04

May 30, 2021

I have been experiencing random weirdness with CIFS on Ubuntu 20.04. Every now and then the current working directory will disappear. I can usually get things back to normal by “cd ..; cd myDir” but that’s a pain – more of a pain when a build has failed because the current directory evaporated on the Gradle script.

So I decided to try NFS. Setting up NFS is not too hard. I found a very useful page on that got me 90% of the way there.

Server setup

In short, on the server:

$ sudo apt install nfs-kernel-server
$ sudo systemctl enable --now nfs-server

Then edit /etc/exports on the server to include the line:


It looks as if there’s no easy way for NFS to handle DHCP unless the file server can look up the IP. Boo. Going onward and knowing my network is now less protected:

$ sudo exportfs -arv

At this point, the instructions start pointing you to server configuration. However, there’s a vital step omitted – pretty much every sane app will fail with “no locks available.” Why? StackExchange to the rescue. Enabling NFS doesn’t enable rpc-statd.

$ sudo systemctl enable rpc-statd
$ sudo systemctl start rpc-statd 

As the StackExchage article says, “Thanks, systemd!”

Client setup

Next you can set up the client:

$ sudo mount -t nfs4 my-server-fqdn:/myshareddisk /localmnt

Hey, it mounted, and it looks like a file system. Now anyone on my network can mount my NFS server! Exposing it to ransomware and all sorts of excellent things like that. Err… good?

Last step is to make it automount on the client by editing /etc/fstab:

my-server-fqdn:/myshareddisk	/localmnt	nfs4	defaults,user,exec	0	2

I’m really unsure about this, and may need to undo it or at least find a way to stop it advertising to everyone. But it’s that way for now.

Mounting a partition from a raw disk image

November 28, 2020

In the past I’d backed up an SD card with

dd if=/dev/sdc of=mydisk.img

Now I wanted to get something off of it. However, the SD card had two partitions on it. I wondered if there was a more elegant way to get data out than just writing it to another SD card. Turns out, there is! There’s a great post at that explains how to do it.

sudo losetup -v -f mydisk.img
sudo losetup -a

This gives me the /dev/loop* device that my image is mounted as. In my case, it was /dev/loop18. Next, I could use partx to create loop devices for the partitions:

sudo partx -v --add /dev/loop18

This created /dev/loop18p1 through /dev/loop18p(however many partitions I had). Once those partitions have been created, you can mount them like any other partition on a regular block device. Once you’re done,

sudo partx -v --delete /dev/loop18

will get rid of both the device and its partitions.

Annealing PLA in powdered salt using sous vide

October 31, 2020

Stefan of CNC Kitchen recently posted about annealing (and later re-melting) PLA prints to improve their strength and temperature resistance. I decided to do some experiments of my own.

My method was to print out some PLA objects, pack them in a salt powder that gets vacuum-sealed, and then toss that in the sous vide for 18 hours. The sous vide doesn’t get hot enough to re-melt PLA, so it doesn’t have exactly the same characteristics, but it does gain some benefit. The advantage to the sous vide method is that it’s more available than a constant-temperature oven.

I did informal tests on the annealed prints for a few characteristics:

  1. Smoothing – did the texture of the print change?
  2. Strength between layers – was the print any stronger between layers?
  3. Waterproofing – did the print eventually get waterlogged when placed in water?
  4. Temperature resistance – did the print get as flexible when subjected to increased temperatures as a non-annealed print?


I used four objects: a hollow spheroid, a 30x5x5 mm bar, a calibration cube, and a box with tabs that were oriented perpendicular to the layers. I ground up plain (uniodized) salt in a spice mill, and put that into a FoodSaver bag that was double-sealed at the bottom. Relative humidity when I sealed the bag was around 33%.

A bag of salt powder
A bag of salt powder

I nestled my prints in the salt, then vacuum-sealed the bag and double-sealed the top.

A sealed bag containing prints surrounded by salt powder
Sealed in the bag. The salt prevented sharp edges from poking holes.

Next, I tossed the bag in a pot of water along with an Anova Nano sous vide stick. I set the temperature for 80 C (176 F) and left it that way for 18 hours.

Cooking the bag at 80 C
Cooking at 80 C

After that, I turned the sous vide stick off and let the pot come to room temperature.


When I removed the salt from the bag, it had formed a solid mass that could be broken apart by hand. I carefully extracted the printed objects. The box lid and letters on the calibration cube letters were packed with salt, but that could be washed out easily.

Prints partially extracted from salt

I measured most of the objects, and found that they had indeed changed size – all were a few percent smaller than before annealing. So I knew annealing did something:

PrintOriginal dimension (mm)After annealing (mm)Change (as % of original)
Calibration cube X20.1319.9899.3
Calibration cube Y20.0819.8999.1
Calibration cube Z20.1519.9899.2
Spheroid diameter20.0819.7898.5
Spheroid height (Z)24.8224.7299.6
Bar length (X)30.2330.0699.4
Bar width (Y)5.145.0698.4
Bar height (Z)5.004.9599.0


Broken tabs on the box print
Tabs broke off just as easily after annealing
  1. Smoothing: unlike Stefan’s experiments with PLA re-melting, the annealed objects did not change texture. The plastic still showed the same layer lines and other 3D printer artifacts that non-annealed prints did. I attribute that to the fact that the plastic never flowed – the annealing temperature was always below the melting point.
  2. Strength: when I assembled the box, the tabs broke off exactly as they had when I printed non-annealed PLA using the “wrong” orientation. I couldn’t measure it, but I don’t think annealed PLA was any stronger between layers.
  3. Waterproofing: after immersing the spheroid in water for a week, it seemed to sink a little lower, but then stop. I don’t think I’d want to claim that annealing changed the waterproofing of the prints.
  4. Temperature resistance: this did appear to change. I put both the annealed and non-annealed bar prints on the printer bed at 73 C (163 F). After a few minutes, the non-annealed bar was flexible enough that it could be bent between my fingers. In contrast, the annealed print remained solid, and in fact snapped when I applied more pressure.
A non-annealed bar (bent) and an annealed bar (broken).
The non-annealed part was flexible after heating to 73 C. The annealed part was not.


Annealing sous vide is useful for imparting temperature resistance to PLA, and may be a valuable technique for PLA objects that need to live in a hot environment (such as a car in the summertime). Sous vide annealing is easier and more reliable than trying to anneal in a kitchen oven. Annealing alone does not change texture, strength between layers or waterproofing characteristics.

Persistent serial ports on Ubuntu

June 30, 2020

Last time I rebooted my file server (which has a couple of serial devices attached), it picked the wrong ones for /dev/ttyUSB0 and /dev/ttyUSB1. That meant the speeds (which I’d configured in minicomrc files) were wrong.

I needed to make the serial ports persistent. Again with the udev rules!

Luckily, there was a handy page at:

with what I needed to know. I ended up adding two rules in /lib/udev/rules.d/99-serial-aliases.rules:
# portal
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="AM00NPHK", MODE="0666", SYMLINK+="ttyPortal"
# wally
SUBSYSTEMS=="usb", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{serial}=="0130D901", MODE="0666", SYMLINK+="ttyWally"

I got these values by running lsusb -v (which in truth gives you everything you need to know) and:
udevadm info -a -n /dev/ttyUSB0 | grep serial | head -1
udevadm info -a -n /dev/ttyUSB1 | grep serial | head -1
on my two serial ports. (I could also grep idProduct and idVendor, but lsusb gave me the right ones already.)

Then delete (sigh) /lib/udev/rules.d/99-serial-aliases.rules~ that Emacs left over. Cause it gets read if you don’t. Sigh. I always forget.

After that a quick:
sudo udevadm control --reload-rules
sudo udevadm trigger

and I had my /dev/ttyPortal and /dev/ttyWally. Now to fix up those minicom configs…

Finding the characteristic impedance of an antenna cable

May 24, 2020

I recently stumbled on a cool video that showed how to compute the impedance of an antenna cable. Unfortunately it’s almost five minutes long, so I thought I’d summarize:

  1. Measure the capacitance of the cable when it’s open (C) in farads (F).
  2. Short one end.
  3. Measure the inductance of the cable from the non-shorted end (L) in henrys (H).
  4. Impedance (Z) = √(L/C) in ohms (Ω).

It works for both coaxial cables and ladder line. Neat trick!

Fixing a busy CP210x serial device on Ubuntu

April 5, 2020

I had the opportunity to reorganize my local machines. As part of that, I wanted to plug my firewall’s serial port into USB serial and pop that into my server. I have a CP2104 serial device that I bought with my PC Engines apu2 which I use for a firewall.

The USB serial device worked fine when plugged into my Windows 8 laptop, but I want my server to be able to connect to my firewall even when the network is down. Because the apu2 is headless, it’s nice to have something that’s plugged into a monitor when I need to fix things.

I plugged the USB serial port in, and tried to connect to my firewall with minicom. I got this instead:

$ minicom 
minicom: cannot open /dev/ttyUSB0: Device or resource busy

So, time to look at who has /dev/ttyUSB0 open:

$ sudo lsof | grep ttyUSB0
gpsd 416 root 3u CHR 188,0 0t0 176 /dev/ttyUSB0

Ok, why is gpsd holding /dev/ttyUSB0 open? It’s true I have a GPS attached to my server, but that runs as /dev/ttyACM0 and has nothing to do with /dev/ttyUSB0. Hmm… time to search and find this in the gpsd FAQ: Why does GPSD open non-GPS USB devices?

That made me suspicious. See, gpsd is trying to be too friendly – and to do that, it opens a whole bunch of possibly GPS devices even if they’re not GPS devices! Could that be my problem?

$ lsusb
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 008 Device 003: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP210x UART Bridge / myAVR mySmartUSB light
Bus 008 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 040: ID 1546:01a7 U-Blox AG 
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

Hmm… let’s take a peek in /lib/udev/rules.d/60-gpsd.rules:

... blah blah blah...
# Cygnal Integrated Products, Inc. CP210x Composite Device (Used by Holux m241 and Wintec grays2 wbt-201) [linux module: cp210x]
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", SYMLINK+="gps%n", TAG+="systemd", ENV{SYSTEMD_WANTS}="gpsdctl@%k.service"
... more blah...

So in an effort to detect the Holux m241 and Wintec grays2 wbt-201, it’s matching the vendor and product ID of my CP2104 serial device as well! Luckily, I don’t have any of those GPS devices, so a quick snip:

# Cygnal Integrated Products, Inc. CP210x Composite Device (Used by Holux m241 and Wintec grays2 wbt-201) [linux module: cp210x]
# commented out because it interferes with Andrew's PC Engines 2104 USB serial cable
#ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", SYMLINK+="gps%n", TAG+="systemd", ENV{SYSTEMD_WANTS}="gpsdctl@%k.service"

was all it took. Now my USB serial device shows up as a serial device, and is not held open by a GPS daemon.

I have to disagree with the GPSD FAQ’s statement, “It’s not a problem we can solve with clever programming, the devices simply don’t yield enough information about themselves to avoid conflicts.” Err, no… clever programming would have the user run through an install procedure which involved plugging the device in, and detecting the device. Then they could update the udev rules so that only the device that a user owned was stolen by gpsd, and not all serial devices on the planet that happened to match a vendor/product ID that they knew about.

Programing with a PICkit 2 on Linux

January 8, 2020

I recently bought a PICkit 2 clone (the ICA03) from Programming it has been something of a challenge, mostly because Microchip no longer really supports Linux programming of PIC chips.

First, I needed to get pk2cmd. There are lots of pointers to Microchip’s website, but all of them go to 404s. What I ended up using is a github repo: After reading the threatening license agreement, I cloned the repo and built it with make then sudo make install.

git clone
cd pk2cmd/pk2cmd
make linux
sudo make install

Even after installing PK2DeviceFile.dat in /usr/share and including /usr/share/pk2 on the path (ugh) per the instructions, I still wasn’t able to use it from anywhere except the directory I built it from. At some point I’ll need to look into that.

I plugged the PIC into the ZIF socket with the marking near the top, and made sure the selection switch was on 28-40.

Next, I took my .hex file and stuffed it in ~/pk2cmd/pk2cmd/. Then:

~/pk2cmd/pk2cmd$ sudo pk2cmd -P
Auto-Detect: Found part PIC16F886.

Yay! Let’s try writing the file:

~/pk2cmd/pk2cmd$ sudo ./pk2cmd -PPIC16F886 \
 -f my_hex_file.hex -MPC -Y

(I didn’t include IE on the -M switch because I think my hex file has ID and EEPROM memory in it. -Y does the verification.)

PICkit 2 Program Report
8-1-2020, 23:12:12
Device Type: PIC16F886

Program Succeeded.
PICkit 2 Verify Report
8-1-2020, 23:12:12
Device Type: PIC16F886

Verify Succeeded.

Operation Succeeded


Mapping a USB volume knob into a keyboard on Linux for SDR

December 16, 2019

I recently discovered the existence of USB volume knobs. A Reddit user posted an article about reflashing the firmware on one to convert it to a keyboard.



Inspired, I picked one up for $18 on eBay (“USB Volume Controller Knob Adjuster Switcher for Tablet PC Speaker Audio“) and thought that I might be able to do something similar.

It turns out, under Linux, this is pretty easy.

First, I plugged in the volume knob and saw that Linux detected it correctly and used it to adjust the volume. That was a promising start. I could see it show the “HDMI / DisplayPort” volume – and it went up when I turned the knob to the right, down when I turned the knob to the left, and muted when I pressed the knob.

Next, I wanted to see what events were being generated. I found some very useful instructions at and did them:

$ cat /proc/bus/input/devices
I: Bus=0003 Vendor=0483 Product=572d Version=0111
N: Name="STMicroelectronics USB Volume Control"
P: Phys=usb-0000:00:1d.0-
S: Sysfs=/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.7/2-1.7.2/2-
U: Uniq=2070363C4250
H: Handlers=kbd event8 
B: EV=13
B: KEY=3800000000 e000000000000 0
B: MSC=10

This showed me a few useful things:

  • The device vendor for my device is 0483 (the “I:” line)
  • The product ID for my device is 572d (also on the “I:” line)
  • The device is attached on /dev/input/event8 (on the “H:” line)

So now I could scan the events that came across when I moved the knob:

$ sudo evtest /dev/input/event8
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x483 product 0x572d version 0x111
Input device name: "STMicroelectronics USB Volume Control"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 113 (KEY_MUTE)
    Event code 114 (KEY_VOLUMEDOWN)
    Event code 115 (KEY_VOLUMEUP)
    Event code 163 (KEY_NEXTSONG)
    Event code 164 (KEY_PLAYPAUSE)
    Event code 165 (KEY_PREVIOUSSONG)
  Event type 4 (EV_MSC)
    Event code 4 (MSC_SCAN)
Testing ... (interrupt to exit)
Event: time 1576479720.245227, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00e9
Event: time 1576479720.245227, type 1 (EV_KEY), code 115 (KEY_VOLUMEUP), value 1
Event: time 1576479720.245227, -------------- SYN_REPORT ------------
Event: time 1576479720.253248, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00e9
Event: time 1576479720.253248, type 1 (EV_KEY), code 115 (KEY_VOLUMEUP), value 0
Event: time 1576479720.253248, -------------- SYN_REPORT ------------
Event: time 1576479722.325231, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00ea
Event: time 1576479722.325231, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 1
Event: time 1576479722.325231, -------------- SYN_REPORT ------------
Event: time 1576479722.333224, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00ea
Event: time 1576479722.333224, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 0
Event: time 1576479722.333224, -------------- SYN_REPORT ------------
Event: time 1576479724.381251, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00e2
Event: time 1576479724.381251, type 1 (EV_KEY), code 113 (KEY_MUTE), value 1
Event: time 1576479724.381251, -------------- SYN_REPORT ------------
Event: time 1576479724.389251, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00e2
Event: time 1576479724.389251, type 1 (EV_KEY), code 113 (KEY_MUTE), value 0
Event: time 1576479724.389251, -------------- SYN_REPORT ------------

Neat, even more useful things. In particular:

  • When I turn the knob to the right, I get an MSC_SCAN event of type c00e9 (along with a KEY_VOLUMEUP event)
  • When I turn the knob to the left, I get an MSC_SCAN event of type c00ea (along with a KEY_VOLUMEDOWN event)
  • When I push on the knob, I get an MSC_SCAN event of type c00e2 (along with a KEY_MUTE event)
  • Apparently the firmware supports KEY_NEXTSONG, KEY_PREVIOUSSONG and KEY_PLAYPAUSE as well. Huh.

I want to map those MSC_SCAN events to different key codes. In particular, I want a cursor-left key when I turn the knob to the left, a cursor-right key when I turn the knob to the right, and something useful (say, pressing the “m” key) when I press the knob. So I created a hwdb file for my device:

$ cat /etc/udev/hwdb.d/99-usb-knob.hwdb

You’ll recognize the vendor (0483) and the device (572d) that I found earlier. It’s important to use uppercase hex codes for vendor and product in the hwdb file – but not for the scan codes, which should be lowercase. The values on the right have to be lowercase, and correspond to the KEY_LEFT, KEY_RIGHT and KEY_M values from /usr/include/linux/input-event-codes.h. (You can pick any of the KEY_ values from there.) Then a quick bit of Linux magic to update the hardware database:

$ sudo systemd-hwdb update
$ sudo udevadm trigger

…and… exactly the same as before. I got the volume control displayed when I turned the knob.

After scratching my head and doing some searching, I happened on which gave me the clue I needed. My knob was being detected, but not as a keyboard – so it wasn’t being used as a keyboard input device.

So I created this file:

$ cat /etc/udev/rules.d/99-usb-knob.rules
ACTION=="add|change", KERNEL=="event[0-9]*", 
 ATTRS{idVendor}=="0483", ATTRS{idProduct}=="572d",

(That’s all on one line on my machine.) You’ll recognize the vendor and product ID from earlier, using lowercase for the hex this time. I added ID_INPUT_KEYBOARD to the list of attributes for this device.
Unplug the device, plug it back in, and hooray! I’m doing what I wanted to! When I turn the knob left, I go left. When I turn the knob right, I go right. When I press the knob, “m” shows up on the screen.

Now I just need to install an SDR program… and an SDR….

Updating OpenBSD

August 12, 2019

OpenBSD has a few different mechanism to update, depending on what the update is for.

For packages:
pkg_add -u

For the kernel and base system:

For firmware:

All of these need to get run with doas if you’re not root.

Finally, if you’re moving from one version to another:
pkg_add -u

Using an esp32 as an iBeacon

August 4, 2019

I recently discovered the esp32, which is an interesting device that has Bluetooth as well as wifi built in. That got me thinking about setting one up as an iBeacon.

First, I added my board in the File->Preferences->Additional Boards Manager URLs: was what I needed.

My next move was to install the 1.0.1 version of ESP32 BLE Arduino by Neil Kolban. Tools->Manage Libraries-> Select 1.0.1 and click Install.

From there, the BLE iBeacon example should be available. Under “Examples from Custom Libraries” you’ll  File->Examples and under “Examples from Custom Libraries” you’ll see ESP32 BLE Arduino->BLE_iBeacon.

Strangely, this example gets the BLE ID backwards according to my scanner app. It looks as if there might be a fix in the latest (1.0.1-dev) source, but for now I just enter my UUID backwards. On the line

#define BEACON_UUID "00112233-4455-6677-8899-aabbccddeeff" // UUID 1 128-Bit

I use instead:

#define BEACON_UUID "ffeeccdd-bbaa-9988-7766-554433221100" // UUID 1 128-Bit

Thanks to C, I didn’t need to do the two’s complement of the signal power myself:


Finally, I was getting advertising packets for multiple things (including an old test I’d tried). I had to erase the flash: --chip esp32 --port /dev/ttyUSB0 erase_flash

and then re-download in order to have only my iBeacon transmitting.