Software Simplification
I decided to simplify the user-facing software of the radio by implementing a
small mpd
client I’m calling radplay
. I originally intended to use an
existing client called ncmpc
, but it is far too advanced for the simple
user-control I have in mind. Ideally I would like to reduce the controls of the
radio to two rotary encoders – one to select a station and the other to change
the volume.
It took a couple weeks of on and off hacking, but I came up with a Python
program that acts as a front-end to mpd
with a couple bonus features. On top
of controlling playback, radplay
loads station configuration from external
storage and manages the WiFi connection of the Pi via wpa_cli
. The radplay
program also controls a GPIO pin that is wired to a relay that interrupts the
TV’s power supply. This allows the screen to be put to sleep when there is no
activity after a few minutes. Only the station control knob of the radio will
wake the screen; the volume can be changed without toggling the TV state. As
of now radplay
gets user input from getch()
within curses so I have been
using a standard USB keyboard for controlling the radio. I plan to build
dedicated controls using rotary encoders and use a hardware overlay to emulate
key presses.
To make configuration as user-friendly as possible I combined all user
controlled options into a single single file called radio.conf
that is loaded
from a USB drive. The user configuration is loaded once when radplay
is
started and whenever the SIGHUP
signal is received from an mdev
script
that automatically mounts USB storage devices. This makes it possible to change
stations or WiFi settings without rebooting the radio. Moving the user
configuration to external storage also allows for a completely read-only setup
of the Pi’s operating system which means the radio can but turned off at any
point without worrying about corrupting the SD card contents.
Like ncmpc
, radplay
is a curses application targeting console use. The
default font in use by Alpine Linux is a little small for use on my tiny TV so
I set up a large variant of terminus
in /etc/conf.d/consolefont
and set it
to be activated at boot using the
consolefont service.
To make everything feel a bit more polished I set up a splash screen to be
shown during boot. I managed to find a
nice example on the Alpine Wiki
that made use of BusyBox’s fbsplash
program which is enabled in the Raspberry
Pi build of Alpine. The fbsplash
program loads a file called fbsplash.ppm
directly from the FAT32 partition of the SD card and shows it on the
framebuffer in place of the console.
One problem I found with this approach is that fbsplash
does not relinquish
the framebuffer after boot and the console is not restored. I played around
with many console related commands and finally found that killing fbsplash
and using chvt 1
to switch back to tty1
would clear the splash and return
to a blanked console that could be awoken by pressing a key on the keyboard.
After more experimentation and searching I found
someone else with a similar problem
and an incantation that will unblank the framebuffer and show the contents of
the console attached to it: echo 0 > /sys/class/graphics/fb0/blank
.
With the splash screen in place I still had a couple of minor distractions
during boot. The contents of the boot log was visible for a few seconds after
the splash was cleared just before radplay
was started. I changed the
console
kernel option in cmdline.txt
to tty2
to hide all boot output
from view. I also added consoleblank=0
to prevent the console from blanking
after a timeout and vt.global_cursor_default=0
to hide the blinking cursor
that appeared whenever the console was empty.
Now that I have a fairly complete software stack I can focus on building out the remaining hardware of the radio. All I have left to do is to add rotary encoders and a nice faceplate to tie everything together.