Archive for category Software

Raspberry Pi vs. Avahi

It turns out that the various Avahi daemons performing the magick between whatever.local names and dotted-quad addresses for Raspberry Pi descend into gibbering madness when confronted with:

  • One name corresponding to multiple IP addresses
  • One IP address used for multiple MAC addresses
  • Multiple names for one IP address
  • Multiple names for one MAC address
  • Multiple IP addresses for one MAC address
  • Multiple MAC addresses for one IP address
  • Any and all combinations of the above at various times

The least of the confusion involved an incorrect IP address linked to a familiar name pulled from deep history by a baffled daemon doing the best it can with what it thinks it know. Despite what I concluded, rather early in the process, there’s no real error, other than what amounted to a self-inflicted fast-flux nameserver attack.

Anyhow, I devoted the better part of an afternoon to sorting out the mess, which involved labeling all the streaming radio players with their MAC addresses and rebooting them one-by-one to allow all the daemons time to recognize the current situation:

Raspberry Pi 3 - WiFi MAC address

Raspberry Pi 3 – WiFi MAC address

That label corresponds to the Pi 3’s on-board WiFi adapter.

For Pi 2 boxen, the MAC address travels with the WiFi adapter jammed into a USB port:

SunFounder WiFi Adapter - MAC address

SunFounder WiFi Adapter – MAC address

I didn’t label the (unused) Ethernet jacks, figuring I’d solve that problem after it trips me up.



Raspberry Pi Streaming Radio Player: Room Customization

Sometimes you (well, I) want a bit of late-night music, which is now one button press away. However, I initially set things up so the Raspberry Pi’s startup code executed a Python script on a network share from the file server in the basement, which shuts down around midnight after the daily backup.

Keeping a local copy meant having to update that copy whenever I tweak the code, a nuisance not to be tolerated. This Bash (or whatever) code in /etc/rc.local figures out if the server is up and, if so, updates the local copy from the server. If the server isn’t up, then it just runs with what it has:

# was !/bin/sh -e

... snippage ...


ping -c 1 $server
if [ $? -eq 0 ]
  mount -o ro ${server}:/mnt/bulkdata/Project\ Files/Streaming\ Media\ Player/Firmware/ /mnt/part
  rsync -auv /mnt/part/ /home/pi
  umount /mnt/part

sudo -u pi sh -c 'python /home/pi/ any' &

N.B.: you must remove the -e from the shebang, because otherwise the script jams to a stop when the ping fails. Took me a while to figure that out, yup.

Use raspi-config to force the startup sequence to wait until the network is available. Turns out that the DHCP process can stall for half a minute, so fixed timeouts don’t work.

Hardcoding the server IP address eliminates a whole bunch of mysterious failures apparently due to whatever handles the translation from mollusk.local to the dotted quad. Maybe that’s not really a problem, but I’ll run with it.

Now the streamers fetch the Latest and Greatest version whenever they’re on during the day and run their local copy, with the room parameter telling it where it lives.

Life is good!



Raspberry Pi Streaming Radio Player: Command Line Parsing

Some experience suggested different default stations & volume settings for the streamers in various rooms, so the Python code now parses its command line to determine how to configure itself:

import argparse as args

cmdline = args.ArgumentParser(description='Streaming Radio Player',epilog='KE4ZNU -')
cmdline.add_argument('Loc',help='Location: BR1 BR2 ...',default='any',nargs='?')
args = cmdline.parse_args()

I should definitely pick a different variable name to avoid the obvious clash.

With that in hand, the customization takes very effort:

CurrentKC = 'KEY_KP7'
MuteDelay = 8.5         # delay before non-music track; varies with buffering
UnMuteDelay = 7.5       # delay after non-music track
MixerVol = '15'         # mixer gain

Location = vars(args)['Loc'].upper()
print 'Player location: ',Location'Player setup for: ' + Location)

if Location == 'BR1':
  CurrentKC = 'KEY_KPDOT'
  MixerVol = '10'
elif Location == 'BR2':
  MuteDelay = 6.0
  UnMuteDelay = 8.0
MixerVol = '5'

The Location = vars() idiom returns a dictionary of all the variables and their values, of which there’s only one at the moment. The rest of the line extracts the value and normalizes it to uppercase.

Now we can poke the button and get appropriate music without having to think very hard.

Life is good!

The Python source code, which remains in dire need of refactoring, as a GitHub Gist:


1 Comment

Read-Only MicroSDHC Card

I iterated this sequence three times before I caught on:

  • ssh into Raspberry Pi
  • Edit /etc/rc.local, save changes
  • Reboot, observe the changes had no effect
  • cat /etc/rc.local shows no changes

Then I:

  • Edited / saved
  • Listed the file to verify the changes
  • Rebooted, observe no effect from changes
  • Listed the file again: the changes were gone


Defunct 8 GB MicroSDHC card

Defunct 8 GB MicroSDHC card

It turns out the card went read-only without warning, so I was displaying the contents of the file cache buffers after the edit, not the data stored on the card. Rebooting started with empty caches, read the previous file contents, and behaved accordingly.

The F3 utilities now live in the Ubuntu repository and no longer require compiling from source. The result:

sudo f3probe --time-ops /dev/sdb
F3 probe 6.0
Copyright (C) 2010 Digirati Internet LTDA.
This is free software; see the source for copying conditions.

WARNING: Probing normally takes from a few seconds to 15 minutes, but
         it can take longer. Please be patient.

Probe finished, recovering blocks... Done

Bad news: The device `/dev/sdb' is damaged

Device geometry:
	         *Usable* size: 0.00 Byte (0 blocks)
	        Announced size: 7.35 GB (15415296 blocks)
	                Module: 8.00 GB (2^33 Bytes)
	Approximate cache size: 0.00 Byte (0 blocks), need-reset=no
	   Physical block size: 512.00 Byte (2^9 Bytes)

Probe time: 164.4ms
 Operation: total time / count = avg time
      Read: 107.1ms / 4098 = 26us
     Write: 56.6ms / 2049 = 27us
     Reset: 0us / 0 = 0us

That card has been kicking around for a while and started out as a no-name generic in some random gadget. Of course, those fancy Sony MicroSD cards weren’t shining examples of durability, either.

I’m mildly astonished the streaming player worked perfectly with what amounts to a read-only filesystem, but that’s what caching is all about: there was no need to write the data to “disk”.



IBM 5100 APL: Nested Emulators

A discussion about Raspberry Pi performance prompted this:

IBM 5110 Emulator - Javascript on Raspberry Pi

IBM 5110 Emulator – Javascript on Raspberry Pi

From the inside out:

Starting the show takes 17 seconds from clicking the Restart button (second from right, top row) to APL’s Clear WS prompt. I have no idea how that compares with a Genuine IBM 5100.

I distinctly remember writing APL programs, but that’s about as far as my memory will take me. [sigh]


Making and Mounting SD Card Backup Images

The process of creating, configuring, and backing up a Raspberry Pi goes a little something like this:

unzip /mnt/diskimages/ISOs/Raspberry\ Pi/
sudo dcfldd statusinterval=16 bs=4M if=2016-11-25-raspbian-jessie-lite.img of=/dev/sdb
... Micro SD card to Pi, boot, perform various configuration tweaks ...
... card back to PC ...
sudo dcfldd statusinterval=16 bs=4M if=/dev/sdb of=Streamer5-2017-01-02.img
zip -1 Streamer5-2017-01-02.img
rsync -ahuv --progress /mnt/diskimages/ISOs/Raspberry\ Pi/

The ZIP operation crushes an 8 GB image down to 1.6 GB, obviously depending on most of the image being filled with binary zeros or foxes or something trivial like that. You could work around that with fsarchiver, at the cost of handling each partition separately.

You can pipe the incoming image through GZIP when you don’t need the image right away:

sudo dcfldd statusinterval=16 bs=4M if=/dev/sdb | gzip -1c > Streamer5-2017-01-02.gz

There’s an obvious gotcha when you try to write an image to a (slightly) smaller card than the one it came from. Writing a smaller image on a larger card works just fine.

With a raw image in hand, you must know the disk partition offsets within the image to mount them in loopback mode:

fdisk -l Streamer5-2017-01-02.img
Disk Streamer5-2017-01-02.img: 7.4 GiB, 7892631552 bytes, 15415296 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc280d360

Device                    Boot  Start      End  Sectors  Size Id Type
Streamer5-2017-01-02.img1        8192   137215   129024   63M  c W95 FAT32 (LBA)
Streamer5-2017-01-02.img2      137216 15415295 15278080  7.3G 83 Linux

Knowing the offsets, the mounts go like this:

sudo mount -o loop,offset=$(( 8192*512 )) Streamer5-2017-01-02.img /mnt/loop/
... snippage ...
sudo mount -o loop,offset=$(( 137216*512 )) Streamer5-2017-01-02.img /mnt/loop/

Because a Jessie Lite system will fit neatly into a 2 GB SD Card, you can trim the disk image to eliminate most of the unused space:

sudo losetup -f

sudo losetup /dev/loop0 Streamer5-2017-01-02.img

sudo partprobe /dev/loop0

sudo gparted /dev/loop0
... resize ext4 partition from 7 GB to 1.8 GB

sudo losetup -d /dev/loop0

fdisk -l Streamer5-2017-01-02.img
Disk Streamer5-2017-01-02.img: 7.4 GiB, 7892631552 bytes, 15415296 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc280d360

Device                    Boot  Start     End Sectors  Size Id Type
Streamer5-2017-01-02.img1        8192  137215  129024   63M  c W95 FAT32 (LBA)
Streamer5-2017-01-02.img2      137216 3833855 3696640  1.8G 83 Linux

truncate --size=$(( (3833855+1)*512 )) Streamer5-2017-01-02.img
... or, if you don't care about an exact fit, use ...
truncate --size=2G Streamer5-2017-01-02.img

The partition and filesystem will plump up to fill the SD Card during the first boot on the Raspberry Pi.

There exist automagic utilities for all that, but practicing simple stuff helps keep it all fresh…



Xubuntu 16.04 LTS Bringup

Notes on updating my desktop Optiplex 980 from Xubuntu 14.04 LTS to 16.04 LTS, after being unable to compile OpenSCAD, Slic3r, and GNU Radio from source. Blowing three days on reconfiguration & tweakage after a clean install is the price one pays to get rid of a few years of cruft; the old version remains bootable and lootable on another partition, Just In Case.


  • nfs-common
  • xfce-goodies
  • hp2xx
  • xsane, xscanimage
  • kate (which hauls in a big hunk of wayland, alas)
  • digikam
  • chromium-browser
  • devilspie2
  • dropbox (from site)
  • remmina


The hacks required to ensure NFS mounts happen before signing in seem to be obsolete. Given that systemd now controls everything, I have NFI how to proceed if that’s not the case.

The Xubuntu load progress display looks like it’s scaled up from 640×480.

There seems no way to disable on-screen notifications without deep hackery; some of the collateral damage involves the death of the volume control applet in the indicator panel thingy, so I didn’t try very hard.

The aforementioned volume control now fires up the Pulseaudio control dialog. That display explained why the audio came out of the 980’s crappy internal speaker, but switching it to the HDMI output produced only silence. After blowing away ~/.config/pulse and rebooting that sucker, it’s all good: Linux audio remains a slow-motion train wreck.

The initial sign-on dialog appears on the portrait monitor, minus rotation, because the dialog box follows the mouse pointer: the initial mouse position sits one pixel beyond the landscape monitor. Blind-type the password, whack Enter, and it’s all good.

FWIW, I’ve installed the XFCE flavor of Mint Linux on the laptops, but that’s basically Xubuntu with (some of) the ugly sanded off and really doesn’t buy much for somebody who pays no attention to eyecandy.