Shameless Self Promotion

— The Aaron Brady Story

Welcome to my web page. I have others, but this is probably the one that you're looking for. If it's not, you may be looking for my previous blog, my personal journal, my GitHub, my Lanyrd or my LinkedIn profile. If you're looking to communicate you might be looking for my Keybase or my Twitter (it's @insom).


Sun, Apr 2, 2017 — #

blows dust off blog

It’s not that I haven’t been busy! I’ve built and upgraded, and broken, a CNC mill. I’ve converted a 70’s toy to accept WiFi and speak Python. I even converted another PS2 keyboard to USB .. kinda. I just haven’t written any of it up on my blog.

I knew I had to write up the even older stuff about FPGAs etc., and I think that was holding me back.

This is not that post.

This is a post about using WireGuard, VXLANs and Linux bridge devices to make your own private network between hosts that can neccessarily all talk to each other.

The WireGuard quickstart is pretty comprehensive, so I’m not going to duplicate it here. For my part, I have five machines:

Machine Location
rho Paris, FR
epsilon Eastern US
vorke Ottawa, CA
bob Stafford, UK
pi0 Roaming

Rho, Epsilon and Bob have static IP addresses and are reachable from the outside. Vorke has a dynamic IP address which is reachable from the outside. Pi0 could be anywhere, has a dynamic IP and is usually behind NAT.

I checked out the WireGuard source and built the kernel module. Because I’m a lesson to others, I am using a mix of x86, amd64 and armel. I’m also using a mix of Debian, Ubuntu and VoidLinux, and my Paris machine is a Marvell Armada SoC. Don’t be like me.

Let’s assume that

cd WireGuard/src ; make ; sudo make install

does the right things for you. You’ll have a wg utility on your path, a new kernel module in the directory that matches your running kernel and an /etc/wireguard directory, waiting for a config.

I changed to /etc/wireguard on each machine and generated my keys:

wg genkey | tee privatekey | wg pubkey > publickey

Then I assigned out of thin air. (It’s in an RFC1918 network, so this is fine. Anything starting with 10. is fair game as long as no other network you are connected to is using it).

Each machine has a config which lists the other nodes in it:

# Rho
PrivateKey = REDACTED
ListenPort = 56560

# Bob
PublicKey  = REDACTED
AllowedIPs =
Endpoint   =

# Epsilon
PublicKey  = REDACTED
AllowedIPs =
Endpoint =

# Vorke
PublicKey  = REDACTED
AllowedIPs =

# Pi0
PublicKey  = REDACTED
AllowedIPs =

You don’t have to always list every node in the config, only the other nodes that you expect that machine will talk to. For example, I’ve only put Pi0 in Rho’s config, because those two machines only talk to each other via WireGuard.

You’ll notice that Endpoint is only filled in for machines which are publically reachable on a static IP. The other machines will initiate a connection out to the static ones. Once that happens, the static ones know to use that existing UDP socket pair to talk back to them.

I create and configure the WireGuard network interfaces on every machine:

modprobe ipv6
modprobe udp_tunnel
modprobe ip6_udp_tunnel
ip link add dev wg0 type wireguard
wg setconf wg0 /etc/wireguard/config
ip link set up dev wg0
ip addr add dev wg0 # pick a unique IP for each machine

You can verify that everything is working now by pinging from place to place. If you’re okay with the wg kernel module making routing decisions for you, and having to have all nodes be able to talk to all other nodes, you could stop now.

I wasn’t happy with this, and I also wanted to deal with the issue of MTU. On my network, the wg0 device has an MTU of 1420. This should be fine, because we have path-MTU discovery, but we live in crappy times and between overzealous filtering of ICMP, refusal to route fragmented packets and anycast IPs that do the wrong thing, this will cause problems at some point.

My solution for this is to run VXLANs over the encrypted point-to-point tunnels that WireGuard have given us. They are effectively VLANs which are implemented in UDP instead of at layer 2.

These act more like regular network devices, their routing (and switching) decisions work in standard ways, and I can tell the kernel to make the devices have 1500-byte MTUs and just send fragmented packets over WireGuard. It won’t neccessarily be efficient, but it will work.

Each of these VXLANs is going to form a point to point network of their own. I like to think of them as “virtual wires”. Or cloud Ethernet. Or something. Given a bunch of virtual wires which connect between each other but don’t form a complete mesh, I thought of a few ways to make this work:

  • Static routing over the IPs. I don’t have a lot of hosts, but I have enough for this to become annoying, and it wouldn’t provide any form of redundancy.
  • Use a dynamic routing protocol (like BGP). Because the hosts don’t form a full mesh, they couldn’t live inside the same autonomous system, but I could allocate a bunch of ASes from the test range (64512 and above).
    This could be cool because I could join my BGP based Calico network in. It does mean configuring some routing software (probably Quagga). I may still revisit this, but it wasn’t what I chose to do.
  • Solve this at layer 2 by using Linux bridges and the spanning tree protocol.

Spanning tree will mean that I really can just treat these VXLANs like cables – connect them all to a core switch, connect them to each other, and let STP avoid switching loops.

In real network gear, if you have two connections between Switch A and Switch B, you would cause a switching loop – packets going to Switch B from A would end up going back to A and then back to B and bad, bad things would start to happen.

To avoid this, when a layer 1 connection comes up on an STP enabled switch it sends some broadcast packets called BPDUs. If it receives that packet back on another interface, it will disable one of the two interfaces to avoid a loop. No real traffic can flow until this process has run its course, which takes around 30 seconds.

Apart from avoiding pain when connecting network equipment together, STP also gives you a layer of redundancy – if the active port stops sending packets, your switch can attempt to bring the port which was disconnected (‘Blocked’ in STP speak) into to use (‘Forwarding’).

This is going to be great for my internetwork, because if one of the nodes is unavailable then all of the rest of the nodes which have cross connects will eventually notice and reconfigure themselves into a mostly working network.

Because it doesn’t require every node to talk to every other, connections like Pi0 – which only has one upstream connection, are treated just like an access port on a switch. They have no redundancy, but they are considered down-stream of which every Linux bridge they are connected to.

brctl addbr internet
brctl stp internet on
case $(uname -n) in
    ip addr add dev internet
    ip link add vorke   type vxlan remote id 1 dstport 4789
    ip link add bob     type vxlan remote id 2 dstport 4789
    ip link add rho     type vxlan remote id 4 dstport 4789
    ip addr add dev internet
    ip link add bob     type vxlan remote id 3 dstport 4789
    ip link add epsilon type vxlan remote id 1 dstport 4789
    ip link add rho     type vxlan remote id 5 dstport 4789
sudo ip link set up dev internet
for i in epsilon bob vorke rho pi0; do
    ip link set up $i
    brctl addif internet $i
    ethtool -K $i tx off

The above establishes VXLANs between the different hosts (only two are included, for brevity), adds them to an STP enabled bridge and configures IPs on the bridge devices.

Because of a bug … somewhere (I suspect WireGuard) I had to disable hardware accelerated tx checksums, that’s what the ethtool line is doing.


We can view the status of things with brctl showstp internet:

EPSILON:~$ sudo brctl showstp internet
 bridge id              8000.5299c5e0d97b
 designated root        8000.16500a8e632a
 root port                 1                    path cost                100
 max age                  20.00                 bridge max age            20.00
 hello time                2.00                 bridge hello time          2.00
 forward delay            15.00                 bridge forward delay      15.00
 ageing time             300.00
 hello timer               0.00                 tcn timer                  0.00
 topology change timer     0.00                 gc timer                 276.72

bob (1)
 port id                8001                    state                forwarding
 designated root        8000.16500a8e632a       path cost                100
 designated bridge      8000.16500a8e632a       message age timer         19.86
 designated port        8002                    forward delay timer        0.00
 designated cost           0                    hold timer                 0.00

rho (3)
 port id                8003                    state                  blocking
 designated root        8000.16500a8e632a       path cost                100
 designated bridge      8000.3a3bee4c8584       message age timer         19.87
 designated port        8002                    forward delay timer        0.00
 designated cost         100                    hold timer                 0.00

vorke (2)
 port id                8002                    state                  blocking
 designated root        8000.16500a8e632a       path cost                100
 designated bridge      8000.42031e2df8ce       message age timer         19.88
 designated port        8002                    forward delay timer        0.00
 designated cost         100                    hold timer                 0.00

EPSILON:~$ ping
PING ( 56(84) bytes of data.
64 bytes from icmp_seq=1 ttl=64 time=196 ms
64 bytes from icmp_seq=2 ttl=64 time=196 ms
64 bytes from icmp_seq=3 ttl=64 time=197 ms

You can see from the above the Epsilon (US) isn’t using its connection to either Rho (FR) or Vorke (CA). It’s only using Bob (UK). And that means when I use ping, even though Canada and the US share a land mass, my packets take nearly 200ms to return: the traffic is going over to England and back, crossing the Atlantic twice.

The full script for this is available in this gist.

Tue, Dec 27, 2016 — #

In my short electronics career, I’ve built headphone and power amplifiers, including a valve amp, and a microphone pre-amp of my own (extremely simple) design. I’ve modified others, too.

I like the sounds of these devices to a greater or lesser degree, possibly for pretty unscientific reasons.

One thing I’ve wanted to do for a while is stick some science on it and actually measure their frequency responses.

I recently had a good excuse because I found my microphone pre-amp and I was going to rebuild it properly and put it in a box but I also found this SSM2019 chip that I’d received a sample of from Analog.

The SSM2019 is effectively a pre-amp on a chip, only requiring power, signal and a 10K variable resistor to control gain. Its datasheet promises a flat frequency response past 20KHz, which is about as good as human hearing range

There was no point in rebuilding my basic LM348N-based amp if the SSM was going to be better and even simpler.

Curiously, the LM348N doesn’t list frequency response on its datasheet (as available from Digikey). I found a Fairchild version on a Russian website which suggests it falls off well before 10KHz.

As a happy coincidence, Hackaday recently ran an article called “Controlling Your Instruments From A Computer: Doing Something Useful”. In it, Jenny List measured a filter she designed against the simulation (and found the real one wanting). She used a Rigol oscilloscope for the readings and a Raspberry Pi as a signal generator. I have both of those! This was all going to be a walk in the park!


I checked out her fork of freq_pi and used the Rigol to verify that GPIO4 on the Pi was outputing some very stable square waves. Then I found it’s only capable of generating waves from 61KHz to 250Mhz. (Well, I say only. That’s incredibly useful, just not for me).

It was time to completely switch tack.

Last Christmas I was given an Analog Devices ADALM1000. This is a combination two channel signal generator / oscilloscope aimed at the educational market.

The basic idea is that you build some filters or op-amp designs and have one channel generate a signal, and then measure it with the other channel.

That sounds great for testing an amplifier too, and it’s capable of generating a sine-wave from 1Hz to 20KHz, so it perfectly matches the range I’d like to test.


This is everything held together with crocodile clips. This photo actually shows me testing my NP100v12 valve amp, but the basic set up is the same.

I connected channel A to the ground and input of the pre-amp and channel B to ground and output. I powered the amp from a 9V battery to avoid introducting any mains hum.


This is the Alice software for the ADALM1000. It’s all written in Python and pretty hackable. It’s not as polished as the Pixelpulse software which is also available from Analog, but once you get used to it this software is far easier to control accurately.

In this screen shot I’ve set channel A to be AWG (arbitrary waveform generator). The shape is sine (you can’t see that, it’s hidden under the shape menu). Input amplitude is from 0 to 0.1V, and we’re generating a 100Hz wave as a test.

Channel B is measuring voltage. It’s set to display the waveform as well as the peak voltage (Vmax – 1.01V here). Our gain (G) here is 10.

By changing the frequency I created a table of Hz vs. Vmax:

10 1.03
50 1.03
100 1.01
500 1.005
1000 1.015
2500 1.00
5000 0.98
10000 0.92
15000 0.84
20000 0.75

This isn’t very clear, although even I can see the drop-off starting after 5000Hz.

A little Python script to generate a plot will help with visualising what this means.



Expect a follow up when I build the SSM2019 based pre-amp, I guess.

Mon, Dec 19, 2016 — #

My furnace is broken. Again.

I have internal temperature graphs that show what’s going on, courtesy of a BME280 Adafruit board that I bought:

House Temperature

You can see the slow build up to temperature, the rapid cycling at or near the top of the cycle and when the furnace gives up and the temperature creeps down. Oh, and by the way, it’s pretty cold out.

Google reckoned it was down to -20 last night, but I honestly can’t get my brain around a temperature like that and I always feel it’s milder at my house than Google (or the Weather Channel) say it is.

It’s time to science this up.

I had actually ordered another BME280 board from eBay more than a month ago, at the same time as the Adafruit order from, and it just showed up yesterday. What perfect timing.

I already had a couple of ESP8266 boards which had arrived with my belongings from the UK, so I followed the tutorial to compile and install MicroPython on one, grabbed this great MicroPython library for the BME280 part and wired it all up.

I needed to use the WebREPL server to upload both the library and my new file which contains all of the Python I had to write for this. Basically it just sends a UDP packet to my Raspberry Pi every few seconds.

There’s a tiny Ruby script on the Pi submitting the data that it receives into Graphite, and Grafana makes the pretty graphs.

I used the Xiaomi battery pack I blogged about before to power the whole lot. As that previous post mentions, the battery pack will turn off if there isn’t enough current being drawn. Unfortunately the ESP8266 and the BME280 are too damned power efficient, only drawing 73mA. This is less than the 90mA that we need.

The Warm Unit

I added the four-200Ω resistor pack, bringing the consumption (according to my ammeter) to 170mA total. This is wasteful but, meh, this is a quick hack. It also gives me a nice LED to see that the power is on.

This is a useful feature because I threw the whole thing into a transparent box to weather proof it, and now I can see if it’s on or not without going out into the cold.

The Cold Unit

Here’s the completed graph:

Outside Temperature

You can see that it took a little while for the unit to get down to outside temperature, it dropped to -18C at the lowest point, and the battery ran for 16 hours.

The current consumption is (0.17A × 5.1V) 0.87W, so the power should have run for ~18 hours, but given that it was -18C below, I think it’s fair to say that the battery did pretty well.

Tue, Dec 13, 2016 — Z80 BASIC on a Cyclone IV FPGA

Learning some VHDL, with a lot of detours.

Read more…

Sun, Nov 20, 2016 — #

A quick howto. Void Linux is a minimal Linux distribution that aggressively tracks upstream software with a rolling release model. They use runit as their init and have the option to use musl as their libc.

Binaries are available for x86_64 and ARM platforms, with a distribution available for the Raspberry Pi 1 (which is close enough to the Zero).

Unfortunately, it looks like the default Pi build expects you to have a console and keyboard on the machine. As I only have a serial terminal, the first thing that I did was set it up to print console messages to the built-in UART, and set up a getty on /dev/ttyACM0.

Follow the installation instructions, and while you have the filesystem mounted, change boot/cmdline.txt to:

root=/dev/mmcblk0p2 rw rootwait console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 loglevel=4 elevator=noop

That will take care of the boot messages. To be able to actually log in, we’re going to need to change to etc/runsvdir/default (relative to your mount-point, /mnt/rootfs for me) and create a symbolic link to a file which won’t actually exist for you:

ln -sf /etc/sv/agetty-ttyAMA0

That’s going to make sure that a getty on ttyAMA0 loads on boot. This was already included in the distribution, it just wasn’t enabled by default.

The next step was enabling CDC Ethernet – I think that this is one of the best features of the Zero, you can have a little computer that you plug in with a Micro USB lead and you can SSH straight to it.

To make the module load at boot time create the modules-load.d folder and list the modules in the order that we need them (dwc2 for gadget support, g_ether for CDC Ethernet support)

mkdir -p etc/modules-load.d
tee etc/modules-load.d/ether.conf << EOF

Because I like the device to always get the same DHCP lease and show up as the same network device when plugged into my laptop, I also set the host and device addresses:

tee etc/modprobe.d/ether.conf << EOF
options g_ether host_addr=32:70:05:18:ff:78 dev_addr=46:10:3a:b3:af:d9

Finally, I make sure that the Zero will DHCP for this new network device the first time that I plug it in:

cd etc/sv
cp -r dhcpcd-eth0 dhcpcd-usb0
ex dhcpcd-usb0/run
cd ../../etc/runit/runsvdir/default
rm dhcpcd
ln -sf /etc/sv/dhcpcd-usb0 # this absolute path won't exist yet

That’s it for the Zero, just unmount the filesystems and pop the MicroSD card into your Raspberry Pi.

I use Ubuntu on my laptop, so when I plugged in my Zero, it detected a new network device. Select ‘Edit Connections…’ in the Network Manager applet to reconfigure this new USB device that has shown up - you’ll want to go to ‘IPv4 Settings’ and then choose ‘Shared to other computers’. Okay your way out an wait a few seconds for everything to catch up.

The IP address of your Zero should in /var/lib/misc/dnsmasq.leases – SSH in and enjoy!

Sun, Nov 6, 2016 — Weather

Just another Arduino weather monitor

Read more…

Mon, Oct 10, 2016 — #

It’s my first Thanksgiving in Canada, so I took the opportunity (and extra day off of work) to clear out the wood-room in the basement.

My landlord had left woodworking tools behind when they moved across country, but the room had enough spiders, webs and saw-dust that I .. uh .. hadn’t gotten around to using them yet.

I saw a cheap frame for a desk in IKEA’s Seconds section but they had no table tops. I was sure I could get one, so I picked it up any way. When I found a stack of old fencing in the garage, I was sure it would do. It was in pretty bad condition, but basically straight and flat:


Some industrial extension cord, lights and a lot of vacuuming and sweeping later, and I was ready to chop it down:


Then a go with the orbital sander:


Because I’ve not even really been to a hardware store yet, I only had one sheet of sandpaper, thankfully it was enough. The dry fit turned out well; a few pieces needed some sanding on their ends for ease, but I standed them all to avoid future splinters.


It’s not perfectly flat, but for basically free wood and basically free tools on a free day, I’m really pleased.


Sun, Sep 25, 2016 — #

I got a new job in a new place, and with that job comes a new set of programming languages.

I’ve been lucky to be able to mostly code in Python for the last few years. It’s my default language and the closest to the way that I think, but this has meant I’ve let other language skills that I have atrophy a bit. The most relevant of these is Ruby.

I posted before about, it’s a great way to get up and running with a new language, especially if you’re already a programmer or have a little experience. Generally speaking the solutions to the problems you’re given take you on a bit of a trip around the core concepts of each language and its standard library.

That being said, I was still reaching for Python and not for Ruby when solving problems. So I’ve decided that those those little “helper” things I would have done in Python will now be done in Ruby. I had to do a similar thing when I learned C (after BASIC); I kept sliding back to BASIC for tasks until I forced myself.

I’ve got a new broadband supplier and a new router set up. I was previously terminating my PPPoE on a Raspberry Pi, but now I’m just using the supplier’s router. Also my IP is way more unstable on this supplier, so I keep not being able to SSH in to my house - updating my record by hand isn’t going to cut it.

Previously I had this script:

IP=$(ip a | grep 'inet.*ppp0' | awk '{print $2}')
nsupdate -k /root/ddns.txt <<EOF
update delete 300 a
update add 300 a $IP

It relied on a BIND TSIG key being in /root/ddns.txt. Not having the IP terminate on the router means I’m going to have to use a third party service to find out my IP. I’ve chosen

The first draft of the code is pretty basic. It has hardcoded everything and doesn’t handle any errors, but it worked. A few commits later and the final version is over twice as long, mainly due to argument parsing and trying to be clever about our inputs.

It also gets an (almost) clean bill of health from Rubocop. It sports a Gemfile (for bundler) and a gemspec, so I can publish it on

To use it, you’ll need a BIND master server for your zone with a TSIG key configured. There’s examples in the README

I suspect not that many people run their own BIND for a small installation, but I much prefer using an RFC-ed protocol over just some proprietary or jerry-rigged REST API.

Sun, Jul 31, 2016 — #

I know that there’s really nothing worse than blog posts that promise that a real blog post will follow soon, but this is one of those.

I’m in the process of packing up to move across the Atlantic to Canada (Ottawa, ON), and a lot of my electronics projects require tools and parts that I’ve now mostly packed away. My relatively quiet period is because instead of writing about my projects, I’ve been trying to do as much as possible before it all got packed up (or given away, or sold).

I have done things, but now I have writer’s debt. Hopefully this will all work out because with my tools packed away, I can catch up on some of the writing and documenting of projects that I’ve let lapse.

To be documented:

  • Building a USB Blaster to ARM JTAG adaptor.
  • Using OpenOCD and gdb to interactively debug an STM32 microcontroller.
  • Using OpenOCD to upload FPGA images to an Altera board on Linux.
  • Creating a simple VHDL module (with address decoding) to extend Grant Searle’s Multicomp.
  • Installing Sensu and Uchiwa as an unprivileged user (without system packaging).
  • Developing kernel modules on Ubuntu.
  • Using the OV7670 and OV7648 OmniVision cameras.

So: lots. I can’t promise I’ll get to everything, but I’m going to try.

Tue, Jul 19, 2016 — #

For work today I took a long-standing card to hook up our internal Asterisk phone system with some form of Caller ID database. You can make Asterisk use MySQL or fork a Python process using AGI, but I didn’t want any of this to be “in-band”.

In the past I’ve used simple Flask services to provide simplified JSON APIs so I can encapsulate logic in a language that I prefer, and not the scripting or configuration language I’m stuck using (like collectd’s or Asterisk’s).

The result is up on iWeb’s GitHub

The software will receive a POST from Asterisk with the source and destination number, and that POST is expected to return a name to display on the Caller ID as the only body. It also has a very simple Bootstrap GUI for updating the numbers, which shows incoming calls to the office, newest first:


The little bit of Asterisk scripting required is just this:

exten => _X.,1,Set(CALLERID(name)=${CURL("${EXTEN}",from=${CALLERID(num)})})

That part after the last comma is verbatim posted as the contents of the request, the from= is required to make it kind-of URL encoded.

None of this really stands up to security scrutiny on the WAN, so it’s all best kept on internal networks, but for a small network or a house, it should work pretty well.

Fri, Jul 1, 2016 — #

In May, Kevin Cuzner posted instructions on bootstrapping a Cortex M3 microcontroller without a dev board. It hit Hackaday and grabbed my attention because I happened to have a couple of those chips on boards I’d been using to play with Forth.

He’s done the hard work of carving the neccessary include files out of ST’s SDK, and wraps the whole thing up in an easy to use Makefile. Great! I made one little tweak (for Ubuntu Xenial support), and it all builds smoothly.

He’s included an openocd.cfg config file, but I don’t have an ST-Link device to load the output with. Luckily, you can kind of smush the instructions Jean-Claude Wippler put together to upload your program.

Grab stm32loader from GitHub. Put BOOT0 in the 1 position, and BOOT1 in the 0 position. Reset your board and run the following to upload the .bin that make generated to 0x80000000.

lappy:~/Repo/stm32f103c8-blink aaron$ python -a 0x08000000 \
    -g 0x08000000 -p /dev/ttyUSB0 -e -w bin/blink.bin
Bootloader version 22
Chip id: 0x410 (STM32 Medium-density)
Write 256 bytes at 0x8000000
Write 256 bytes at 0x8000100
Write 256 bytes at 0x8000200
Write 256 bytes at 0x8000300
Write 256 bytes at 0x8000400
Write 256 bytes at 0x8000500
Write 256 bytes at 0x8000600
Write 256 bytes at 0x8000700
Write 256 bytes at 0x8000800
Write 256 bytes at 0x8000900
Write 256 bytes at 0x8000A00
Write 256 bytes at 0x8000B00

And you’re done! I can confirm that I have a blinking LED on port PB0.

Thu, Jun 30, 2016 — attiny461-atx

An ATtiny461-based power supply controller, emulating ATX semantics

Read more…

Sun, Jun 26, 2016 — #

This is really two very, very small hacks smushed together, but I realised I never wrote them up.

In October, I made up a nicely finished version of a hack I’ve used lots of times before: a USB-A plug to convenient 5V output. I put male and female 5V and male and female ground DuPont wires on the end and used heat-shrink tubing to make everything look less bad. The nice woven USB lead that I started with makes everything look a bit nicer, IMHO.

USB to 5V

For Christmas, I got a 5000mAh* Xiaomi battery pack. There’s an asterisk there because it’s 5000mAh at 3.7V, and the actual rating of 3300mAh at 5.1V isn’t mentioned anywhere except on the bottom of the unit itself. About 10% of the capacity of the unit is lost to the boost convertor, which seems alright to me.

Let’s call it 16Wh.

I don’t actually need to charge my phone on the go very often, my sedentary lifestyle means I move from one place where I have access to power, to another. Work, home, coffee shop, transit. But I would like a source of 5V for electronics projects that doesn’t tie me to a desk or a power outlet.

The Xiaomi charger will turn off if it detects that the device it’s charging is “full”. It appears to do this by monitoring the average current draw. My Arduino projects don’t draw enough to keep it on; damn their efficiency.

By experimentation, I found that around 90mA is sufficient to keep the charger on: I just kept trying lower and lower resistors and measuring the current draw with a multimeter until the unit steadily stayed on.

Power sink

I’m using four 220Ω 1/4W resistors in parallel, so we divide the amount of resistance to get 55Ω and then divide that into the 5.1V to get our current draw:

5.1V / (220Ω / 4) = 0.093A

Okay, that’s good enough to keep the charger on. How much heat are we dissipating by doing this?

0.093A × 5.1V = 0.47W

Half a watt! That’s hot enough to cause the current sink to be uncomfortable to touch after a while, but not dangerous, and only half of what the resistors are rated for. This is why I used four larger resistance resistors, rather fewer (or one) lower ohm ones.

I added an LED, itself protected by a current limiting resistor, just to verify when the unit is on. The 1 and 4 pins on the East side of the board are connected to the 5V and ground inputs on the West side, or I can just use the male DuPont wires to power my projects. Simple but useful.

Wed, Jun 22, 2016 — #

This one is basically a HOWTO I’ve been meaning to write up. I may need a whole new template in Hugo for this kind of thing, if I make a habit of it.

There are situations where you may want to use a Let’s Encrypt certificate but you can’t run the client on the target machine. Two that I’ve come across are:

  • Hosting without shell access
  • Very small VMs without enough RAM to run the full Certbot client

Also, because you shouldn’t run anything as root that you don’t need to, let’s make the whole thing work for our regular user account. You’re going to need Python’s virtualenv package (sudo apt-get install python-virtualenv on Debian or Ubuntu), as well as git for the next step. All of the smarts can run on any machine you trust, such as a laptop, local VM or even on a MacBook.

Clone Certbot and pick a release to check out:

git clone
cd certbot
git checkout v0.8.1

Okay, now we’ll make a virtualenv - this is a private Python installation that we can install packages into without root permissions, and allows us to avoid conflicts that might arise from installing conflicting versions of packages for different applications.

virtualenv venv

And we’ll install our checked out copy of Certbot into our virtualenv:

venv/bin/python install

Lots of text will scroll by, hopefully it worked for you. Let me know if not.

Now we have Certbot installed locally, we’ll need to set up some directories for it to work with. It defaults to using system directories which require running as root, but we really don’t want to do that. Let’s make our own:

mkdir -p ~/.le/etc ~/.le/var/lib ~/.le/var/log

And let’s register our certificate:

venv/bin/certbot certonly --text -d --keep-until-expiring \
--agree-tos --config-dir ~/.le/etc --work-dir ~/.le/var/lib --logs-dir \
~/.le/var/log --manual --register-unsafely-without-email

You need to swap out for your own domain name - the one which currently points at your remote hosting. You can specify more than one -d option with more than one domain, but they will all need to be reachable for verification. I just need one.

You’ll get a wall of text, including a warning that your IP will be logged, which I’ve agreed to and you will need to, too.

NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
(Y)es/(N)o: y
Make sure your web server displays the following content at before continuing:


Okay, so just create a file called “2qruN2PEJL_-7OBFUSCATEDxhrHLazCOr3UFNrCBJbQ” with the contents “2qruN2PEJL_-75R2436OBFUSCATEDzCOr3UFNrCBJbQ.mGoimgyJQKeruGrLgfDglJlhFMDvhcWLYIV2FNBOWhM,“. Your value for both the filename and the contents will be different so you can’t just copy them from this post.

Upload your file to the .well-known/acme-challenge folder on your web hosting. Once you’ve done that, press enter on the client to let the Let’s Encrypt servers continue with their challenge.

If it’s successful, you’ll get a message like this:

 - Congratulations! Your certificate and chain have been saved at
   /home/aaron/.le/etc/live/ Your cert will
   expire on 2016-09-20. To obtain a new or tweaked version of this
   certificate in the future, simply run certbot again. To
   non-interactively renew *all* of your certificates, run "certbot
 - Your account credentials have been saved in your Certbot
   configuration directory at /home/aaron/.le/etc. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:
   Donating to EFF:          

The private key will be in your ~/.le/etc/live/<domain>/ directory, along with the certificate, CA chain, and CA chain with certificate in one bundle (fullchain.pem).

You should refer to your webserver or web hosting’s instructions on how to install the certificates, but that’s the process of obtaining them done.

The way that I’ve run the command will not result in you getting notified about your certificate expiring, so you should place a reminder for yourself around 80 days in the future to repeat this process.

Tue, Jun 21, 2016 — #

One of the things I didn’t cover in my last post was my problems flashing an ATtiny461. It just wouldn’t take, and even my spare wouldn’t. It’s probably me, but as a friend was placing an order with a UK supplier, I thought I’d piggyback on that and get an ATtiny85 - a more suitable chip for what I had in mind.

It’s a little unfortunate that I named the project attiny461-atx. Whoops! I’ve created a branch with the ‘85 compatible code on it. Because this chip really is tiny, it only has a PORTB. My previous code took some liberties by using each of PORTA and PORTB for input and output respectively, and I’ve tidied those up in my latest commits.

Chip with Programmer

An IDC10 to breadboard adaptor has once again proven to be a great purchase. I think I might pick up IDC to breadboard adaptors in a variety of pin counts, even. This suits so well because the USBasp clone that I’m using defaults to a 10 pin layout.

PB4 is connected to an LED and PB3 to a switch with pull-ups enabled, and then on to ground. PB4 will be brought high to simulate the PSU coming on, but in the final circuit it’s actually going to be pulling the pin down, as that’s what triggers an ATX PSU to power on.

I can’t continue tonight as I sold my spare IEC leads at the weekend, but hopefully I’ll nail this at lunch tomorrow using Boo-the-Power-Supply.

It’s been a busy day, electronics-wise: Bas, Jon and I got some “Hello, World” Verilog up and running on an FPGA board I ordered (harder than it sounds, easier than I thought it would be), and I even had time to flash a newer firmware onto my DSO138 scope kit.

It turns out it runs the same CPU as the boards I’ve been running Forth on, so the process of flashing it was pretty straightforward, though instead of two jumpers you need to solder two sets of pads together, then remove the solder blobs after programming. Perhaps a little less user friendly.

Now, it can auto-centre its trigger. Here’s a shot of one of the output pins from the 74HC374 on my Z80 - including the duty cycle and frequency counter that I’ve only just discovered are included:


In other words, it takes 45 milliseconds to get from line 4 to line 15 of this program.

Wed, Jun 15, 2016 — Z80 Microcomputer

The retro-computing itch comes to us all. Latest update: Actual IO.

Read more…

Sat, Jun 11, 2016 — #

I am become yak, destroyer of progress.

I was playing with one of my left-over populated Radio 1 boards. I’ve recently gotten a USBasp (knock-off) from eBay and back when I was designing the board I actually thought ahead. I put a standard 6-pin programming header on the board, even though I was just using a Bus Pirate to flash them.

I wasn’t sure what state the fuses and firmware were in, so I read them with avrdude and plugged them into an online fuse calculator. That’s when I saw you can actually clock these down to 128KHz on the internal RC oscillator. Interesting! The board was running a version of the Arduino blink sketch anyway - how slow is 128KHz? So, I set the fuses to find out:

% avrdude -c usbasp-clone -p m328p -U lfuse:w:0xe3:m
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions
avrdude: writing lfuse (1 bytes)

(Check out that warning: it’s going to be relevant in a minute).

Flashing the Radio 1 board

Cool, so at this rate it takes an age to flash the LED. I’m not sure what I was expecting. I’ll just put it back how it was:

% avrdude -c usbasp-clone -p m328p -U lfuse:w:0xe2:m
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: error: program enable: target doesn't answer. 1
avrdude: initialization failed, rc=-1
         Double check connections and try again, or use -F to override
         this check.


The 328 is now clocked too slow to speak SPI at the default rate, so I can’t flash it back. The USBasp is running too old a firmware to slow down its clock. Now to begin “a game of programmers”.

I need to use the USBasp to program a Boarduino with the Arduino firmware (it previously had its Arduino bootloader wiped):

ASP on Boarduino Action

Then I use the FTDI to put the ArduinoISP sketch on the Boarduino, and upload new firmware onto the USBasp:

Revenge of the Boarduino!

% avrdude -c avrisp -p m8 -P /dev/ttyUSB0 -b 19200
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.02s
avrdude: Device signature = 0x1e9307 (probably m8)

Now I can use the USBasp to fix the Radio 1 board:

% avrdude -c usbasp -p m328p -U lfuse:w:0xe2:m -B 1000
avrdude: set SCK frequency to 1000 Hz
avrdude: AVR device initialized and ready to accept instructions
avrdude: writing lfuse (1 bytes):

Success! Now I’m back at the beginning!

Well, while I’ve got all this kata in my head, I might as well put the Arduino bootloader back on some other knock-offs:

Deek Robot Arduino Mini

Right, now I can get some work done. Oh. It’s dark out. Maybe tomorrow.

Thu, Jun 9, 2016 — #

I’m sure I’m not the only person who does this:

I’ve built a project as a proof of concept. It worked fine, and now I’m retrospectively writing it up for my blog. Unfortunately, I can see improvements I could make, so as I’m writing it up I’m kind-of changing it (well, very changing it).


First off, I didn’t really start with a schematic, I used some basic diagrams I found of an example circuit for a non-inverting amplifier. I didn’t use an LM741, because I actually had a few LM348N’s lying around. I haven’t put that in the schematic because it’s a little embarrassing to waste a quad op-amp on a single channel design.

Actual Board

(Witness my profligate waste of a quad op-amp!)

These fancy 3.5mm connectors on the schematic aren’t the kind that I used - I’ve put them in the schematic because the footprint was already in my KiCad library and it would save me the job of adding a new parts library.

I was tempted to swap that 100K in R4 for a potentiometer, but now we’re into the realm of fantasy: that’s a very different circuit than I actually built and without building it an experimenting I’m not confident whether I should be using a logarithmic or linear pot.

I’m probably going to finish this design off by actually laying out a PCB and - because I can’t help myself - probably getting it made. When I do that, I might bring R4 out on a two pin connector so that it can be swapped out with other resistances or pots. That is something I actually have done on the real design:

Pluggable Resistance

Mon, Jun 6, 2016 — #

I got my Forth green square.

Mecrisp Hello World

Bas’ and my LCD driver for the PCD8544 display is now in the upstream Embello repository. The API it exports to the graphics.fs library is just three words:

: putpixel ( x y -- ) ;
: clear ( -- ) ;
: display ( -- ) ;

Of course, there’s quite a bit under the hood. putpixel was challenging and he fact that dup dup and 2dup do very different things was time consuming to find, but now it’s done.

I love this environment and have given AmForth a go on a spare Arduino Uno. Using AmForth as a read-eval-print-loop allowed for interactively exploring an STP16CL596 (16 bit shift register / current sink) hooked up to a common anode LED matrix (5x7).

It’s slow. Way slower than Mecrisp, but then the CPU is 8bit instead of 32bit and the clock is only 16MHz instead of 72Mhz, so that’s to be expected really. It’s still as low level though, let’s set PORTD pins 2 through 6 to output, then turn on PD2

$7C DDRD c!
$4 PORTD c!

Okay, so this is just the same as

DDRD = 0x7c;
PORTD = 0x4;

in C, but the important part is there was no compilation step inbetween - just poke bits of RAM and see what happens - if anything goes wrong, just hit reset and try again.

Unfortunately the speed is an issue. Bas plans to drive the matrix display with persistence of vision, and neither of us thinks we can optimise the Forth enough to make that work at just 16Mhz.

Back to C, it is.

Wed, May 25, 2016 — #

It’s nearly two weeks since I wrote up that butchered USB TTL serial adaptor and no updates! I’ve not been inactive: actually I’ve been having a great time bringing up Forth on those STM32 Cortex M3 boards and writing SPI and I2C access routines.

It may not sound like exciting stuff, but have a look at this bit-banged I2C implementation by JeeLabs - 31 lines including comments — it’s so small.

A colleague has ordered a board of their own, just because it will give them a REPL that they can use to exercise I2C and SPI devices with.

I’ve been writing some Forth words to talk to the Nokia 5110 LCD (also known as the PCB8544). This speaks SPI but with some extra control lines, and it’s one directional - there’s no facility to read from the LCD or even to receive ACKs.

If you’re not familiar with Forth, it’s a stack based language invented by Chuck Moore. “Functions” in other languages are just “words” in forth. Their calling convention is typically just how many words they read of the stack and what they put back. For example, this word takes nothing off the stack, and leaves nothing afterwards:

: lcd-pins ( -- )
    dup LCD_CD io-mode!
    dup LCD_RESET io-mode!
    drop ;

dup duplicates the top word. drop drops the top word. Already I can see a quick win - that second dup is extraneous, if I lose it, I can lose the drop, too. I really want:

: lcd-pins ( -- )
    dup LCD_CD io-mode!
    LCD_RESET io-mode!  ;

This is what Forth programming is like for me, little eureka moments where I realise I can save a byte or a word. You chain these little words together into larger ones. Writing a word that’s more than a few lines long is tricky, and it’s not fun to debug, so you end up keeping your code short and writing lots of very small words.

: lcd-command ( command -- )
    LCD_CD ioc! +spi >spi -spi ;
: lcd-invert ( -- )
: lcd-normal ( -- )

(That ( command -- ) means that it takes one entry off the stack, its command, and consumes it, putting nothing on the stack after it’s done).

The flip side of this very terse and dense code is that it’s reasonably painstaking to write. Bas and I might spend half a lunch break and write 6 lines of code. But they’re a beautiful six lines!

We’ve had some success keeping a framebuffer in RAM and pushing it out to SPI. There’s some glitches to sort though, but I soon hope to have my first Forth pull request. That’ll be a well earned green square.


Thu, May 12, 2016 — Butchered USB TTL Serial Adaptor

Turning a USB to RS232 adaptor into a slightly worse USB to TTL Serial adaptor.

Read more…

Sun, May 8, 2016 — Learn to Solder Badges

First experiences in schematic-less PCB Design. Latest update: Built the first kit

Read more…

Fri, Apr 22, 2016 — #

It’s not quite contributing to Open Source, but I have been strengthening some atrophied Go and Ruby muscles with the excellent This takes the programming koans or kata format (solve this problem, here’s a unit test that will tell you if you’ve solved it correctly) and goes further.

I’ve only done a few exercises in each language, but more than just hammering out brutal code to get the tests to pass, there’s a community element which praises good code and nitpicks (their word) code which would be improved.

My Ruby Hamming solution has three iterations, because I’d received some great feedback from another user in iteration one, and then was inspired to look closer at how my code could be more elegant after submitting my own second iteration. It adds a whole other experience on top of getting a ‘pass’ from your test runner.

My Go Hamming solution was way too complex the first time, despite passing. The third iteration is an improvement but it still seems long - or maybe it just feels long compared to how terse the Ruby version is.

Each language’s tests seem to be tailored to the languages idioms, too: the Roman Numerals exercise required to me to extend Ruby’s Fixnum with a new to_roman method, rather than just create a new class with a static method on it.

Go check them out, maybe pick a language you know well for the first choice and, once you’re happy you understand the algorithm required to solve each problem, try something new.

Thu, Apr 21, 2016 — #

I’ve officially bowed out of adding multiple API keys to Cachet. It feels bad, but it feels better than just continuing to leave an open PR unworked on.

In other green square news, I have yet another CloudStack issue opened. This one wasn’t just my work, three of us at iWeb spend a full working day trying to figure the problem out. It looks like another commenter on that issue had the same problem and worked around it - but for at least a release CloudStack hasn’t been able to migrate virtual machines which use VXLANs.

This is actually only the bottom problem in a stack; we found this while trying to replicate a different bug which may actually lie in the Linux kernel (or our specific Linux networking configuration) - expect updates if we solve that one.

It requires so much intense concentration to chase bugs like this and when you come out the other side the sense of relief and achievement is amazing, but every obscure bug like this leads to some soul searching: after seeing packets arrive on a NIC and then disappear before hitting the right Linux bridge device, we were questioning whether we just misunderstood some basic tcpdump BPF syntax. You know, just a tool I’ve been using for 15 years.

Sun, Apr 17, 2016 — #

It’s been a full weekend, but not much in the way of software or programming. What I do have to show off is my microphone pre-amplifier.

I had borrowed a nice mic from work, a Blue Snowball with a USB ADC built in, but I’d had it a long time and thought I should really get my own microphone.

The mic-in ports on most hardware is terrible though- that’s what’s been so great about the rise of “podcast mics”: they often include USB so there’s minimal messing around with an analogue signal path.

I’m too cheap to buy one of those, so I got a £7 dynamic mic, the cheapest thing with Prime delivery, and decided I would build my own pre-amp — how hard can it be?

I’m going to do a proper project write up when I’m less tired, but the spoiler is: It’s not hard, unless you want it to sound good. Then it’s maddeningly difficult.


Sun, Apr 10, 2016 — PiGlow Adaptor

Circuit, 3D and PCB design. Soldering, programming and printing. My first full-stack project.

Read more…

Wed, Apr 6, 2016 — #

Look at those gaps!

An Imperfect Record

I think that chasing green squares has become too cynical for me— it’s caused me to neglect a larger PR (on Cachet) because starting fresh, smaller, changes is likely to generate a better looking picture.

I literally considered delaying one of my two two pull requests yesterday so that I could drag them out to a streak. That’s no way to be.

I’m glad I’ve broken my streak, now I can concentrate on doing better work, not just more work.

Fri, Apr 1, 2016 — #

Well, that went a bit badly didn’t it?

Two pretty disrupted evenings (for personal reasons) and I’ve let my writing streak and French (Duolingo) streak slip. I got a contribution in yesterday at least! But I didn’t write about it. And I haven’t moved on my PR. And, I’ve got to be honest; I’m not going to do it tonight, either.

Tue, Mar 29, 2016 — #

Only one commit tonight, sorry. I’ve bungled my way through the routes file and submitting a form, but am not yet creating a model to add to the user. What I think I have left:

  • Add an API key when you’re asked to in the UI
  • Create a default API key for new users
  • Add seeds for API keys to allow tests
  • Create a migration which adds ApiKey models to match existing users’ api_key fields.
  • Fix up the login checks to actually authenticate API requests against the new model (oh yeah, that!)

Bonus round:

  • Maybe add some tests around adding and revoking keys

Sun, Mar 27, 2016 — #

(If you think things have been quiet on the journal front, check out the updates to my Z80 project - I’ve been doing those instead for a few days)

Last time, I had added a new model to Cachet but created the database table and populated it by hand. Laravel seems really similar to Alembic and it also lets you create a migration with a command. In this case:

$ php artisan make:migration CreateApiKeysTable
Created Migration: 2016_03_27_195948_CreateApiKeysTable

This creates a skeleton class with an up and a down method which you can use to migrate and to rollback, respectively. Alembic fills this with a reasonably accurate guess of what’s changed in your models since the last migration, but Illuminate/Laravel really do leave it up to the developer.

The documentation lists a few examples. Those, along with the existing migrations written by Cachet developers, are enough for me to end up with a working migration: [Commit]

I’ve changed my mind about an ‘active’ flag. It’s easy enough to delete and create new keys. I’ve added a description too, and told Laravel to manage the timestamps of the model. This is a neat feature that keeps the created_at and updated_at fields up-to-date automatically.

I’ve always found that knowing the creation date (and last used date, but let’s not get ahead of ourselves) of my GitHub API keys is really useful, so I’m hoping it’ll make a nice touch in the UI.

Speaking of the UI, Cachet uses Bootstrap, so I spent a little time trying to come up with a form layout that I liked, now that there’s at least two pieces of information that will need to be submitted. I tried horizontal and inline forms, and I reverted a few times. For now, it’s getting late so I’ll push what I have and think about it away from the computer for a bit.

This whole PR is taking a bit longer than I thought that it would, but it’s good to learn a bit more about “modern style” PHP development, as I’ve been involved in Magento and WordPress for so long.