David's Blog

Yes I am a geek, but no I don't care

New laptop for Linux experiments

So my trusty old Toshiba Satellite T130 has started to fail. The keyboard has started to go wrong, it seems to miss out random keystrokes, which is really annoying. It's a shame, because apart from that the machine is still working fine. But I decided that it was time for it to be replaced. I didn't want to spend very much money on a new laptop, because the old Toshiba was running Elementary OS very nicely. So I didn't need a super fast processor or anything. I ended up going for the cheapest laptop with 4GB RAM that I could find. So I am typing this on a Lenovo ideapad 100 15iby. It was less than £190, which is pretty reasonable I think. So far I am pretty happy with it.

This machine does feel cheap. It seems very plasticy and the touchpad buttons rattle a little bit as I type. I don't think that it is as robust as the Toshiba, but for the price it seems like good value. It only has a Celeron processor, but it still seems to fly along when running Elementary OS. When I first got the machine, it was running Windows and that was a slightly more painful experience. Although I only kept Windows for a few minutes - just long enough to apply the firmware updates from Lenovo so that I had the most recent BIOS. After that, I blew everything away and installed Elementary OS Freya from a DVD (the ideapad does have an internal DVD drive). I don't have anything against Windows, but I don't think that I'd be happy running Windows on this laptop - I think I would find it too slow on this hardware.

I had no problems installing Linux, everything worked right out of the box - even the special volume and brightness buttons on the keyboard.

After installing the OS, the next things I installed were:

  • Docker
  • Kate / Konsole (for coding in C)
  • Spotify
  • Chrome (and the Chromecast plugin)
  • Nim / Nimble / Aporia
  • FileZilla
  • TLP in the hope of getting more out of the battery

The ideapad version I've got does not appear to have bluetooth (I think that it's an optional extra on this machine) but I managed to find a tiny Bluetooth dongle on Amazon which seems to do the trick. So anyway, let's see how it goes!

A little more about Nim

I am still tinkering with the Nim programming language, and quite enjoying it. I find the language to be well thought out, and it's very easy to build little libraries which have unit tests included in them. I like that idea.

But I have noticed that the binaries can be quite a lot bigger than my equivalent C programs, which I suppose is to be expected. So I have also been experimenting with the UPX packer which helps to keep the file size down ... this could be useful if you want to run your Nim programs on something tiny, like a router.

In the end, I did buy a copy of the Nim in Action book, available through Manning's early access program. I'd recommend this book to people who are learning Nim, I found it easy to follow and enjoyable to read.

Nim in Action book

Because Nim has not reached v1 yet, for the moment I'm only using it for experimentation and hobbyist type stuff. But when it actually hits v1, I think that I'd consider using it for real work too.

Updated!

I have just migrated this blog to a newer version, so hopefully everything will work and all the old content will have been transferred over...  And I should be able to continue blogging again soon ... as long as I can tear myself away from learning Nim.

First steps into the world of Nim

I was recently doing a bit of reading up on the Rust programming language, but a stray comment somewhere about the Nim programming language sent me off on a bit of a tangent. The thing that really got me interested in Nim was that it compiles to C, and I noticed that this brings quite some options for portability. One of the reasons why I like programming in C is that you can run the code on all kinds of machines, from tiny embedded devices to supercomputers. But that does come at a cost, because it takes longer and you often have lots more typing to do because of all that boilerpate stuff.

But it looks like Nim would allow you to be quite productive, whilst the resulting executables should still be efficient and fast. To get some ideas, I went off to Rosetta Code and found the Nim code for a simple webserver which looks like this:

import asynchttpserver, asyncdispatch
 
proc cb(req: Request) {.async.} =
  await req.respond(Http200, "Hello, World!")
 
asyncCheck newAsyncHttpServer().serve(Port(8080), cb)
runForever()

Being able to create a webserver with just a few lines of code, and with the potential for the code to be portable and run on all kinds of devices seemed very tempting! By this point, I'd forgotten about Rust and wanted to explore Nim a bit further.

So whilst Nim has not reached v1.0 yet, it certainly looked very compelling. The compiler documentation made it look like cross-compilation was not that difficult, so I decided to try and cross-compile some code for a router running OpenWrt. Before going off and spendng a lot of time learning a new language, I wanted to see that I *really* can write portable code. I was very happy to see that in just a few minutes I had the example webserver code running on my TP-Link WR740N, as shown here:

To my amazement and joy, this really wasn't that hard. After installing Nim, I had to edit Nim/config/nim.cfg to point to my cross-compile toolchain, so I ended up with these lines:

mips.linux.gcc.exe =
 "/home/openwrt/openwrt/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/
bin/mips-openwrt-linux-gcc"
mips.linux.gcc.linkerexe =
 "/home/openwrt/openwrt/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/
bin/mips-openwrt-linux-gcc"

Then, after doing that I simply needed to pass the correct parameters to the Nim compiler, like this:

nim c --cpu:mips --os:linux webserver.nim

Which cross-compiled the example webserver ready for it to run on my TP-Link WR740N. That actually seems pretty awesome. I think that I need to learn more, perhaps I'll even go and buy the Nim in Action book. All this stuff worked perfectly without any trouble, which is pretty rare, so I am left feeling very impressed so far.

Radio streaming with OpenWrt

I have been doing a bit more playing around with USB sound cards and OpenWrt. I thought that a pretty good use for my HooToo HT-TM02 would be as an internet radio player. So I have been experimenting. I installed the following packages (I already had USB support working):

  • kmod-usb-audio
  • madplay
  • alsa-utils

Which enables me to play internet radio streams from the command line. I have been trying the stations listed on www.intenet-radio.com. If the station shows a PLS link, I found that you can download it as a playlist-file and extract the URL from inside using a text editor. In many cases, this seems to work very well (but not all streams worked). Then just use this command on OpenWrt and replace the URL:

wget -O - [URL] | madplay - -a-30 -o wave:- | aplay

Which will play the stream (I'm dropping the volume with -30 in that example). In reality, I've been using all the commands in quiet mode and in the background, like this:

wget -q -O - [URL] | madplay -Q - -a-30 -o wave:- | aplay -q &

...which just plays the stream in the background without any other output to the console. In addition, I also found the BBC radio station streams listed on this website which is pretty useful (and also the French station, Fip for good measure):

  • http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1_mf_p
  • http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1xtra_mf_p
  • http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio2_mf_p
  • http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio3_mf_p
  • http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio4fm_mf_p
  • http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio4lw_mf_p
  • http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio4extra_mf_p
  • http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio5live_mf_p
  • http://bbcmedia.ic.llnwd.net/stream/bbcmedia_6music_mf_p
  • http://bbcmedia.ic.llnwd.net/stream/bbcmedia_asianet_mf_p
  • http://bbcmedia.ic.llnwd.net/stream/bbcmedia_nangaidheal_mf_p
  • http://audio.scdn.arkena.com/11016/fip-midfi128.mp3

A better way to set the volume from the command line, is to use the amixer command, I'm using something like this:

amixer sset Headphone 50%

Although the more fancy alsamixer command seems to work fine as well.

After using that for a while, I think it's a very good use for the HooToo, so I am building a simple front end and will keep it as a miniature internet radio player.

Hootoo + OpenWrt + Velleman K8055N

One of the things that I had kicking around at home was a Velleman K8055N (actually mine was the pre-made version, the the VM110N) - but I think they are essentialy the same thing. I decided that it would be really cool to try it out on OpenWrt ... so that eventually I could try interfacing a tiny embedded Linux machine with the outside world.

Some quick googling led me to this driver which I tried on a Debian Virtual Machine first, and then decided to run it on my Hootoo HT-TM02. I used a docker container to build the kernel module according to the instructions, and then copied it over onto the device for installation.

The first attempt at installing the module gave the following error:

Collected errors:
 * satisfy_dependencies_for: Cannot satisfy the following dependencies for
 kmod-k8055d:
 * 	kernel (= 3.18.23-1-e2416fa0abee73ea34d947db4520f4e9) *

Which I assumed was just OpenWrt being a bit over cautious, because I was actually running kernel v3.18.23. So I took the risk and overrode the error, with this command:

opkg install /tmp/kmod-k8055d_0.2.1_3.18.23-ramips-1_ramips_24kec.ipk --nodeps

Perfect, it worked! So the K8055N is now accessible in the file system under /proc. To celebrate, I hooked up the digital-to-analoge converter to an old voltmeter, so I could watch the needle bounce around in response to what I'm typing on the command line:

I think that's pretty awesome, although I don't know what I'll use it for. Perhaps I'll build some kind of Web API and allow inputs and outputs to be controlled from a browser. Or ... come to think of it, I could build a really cool CPU meter with the output showing via the needle of the voltmeter.

Hacking your Hootoo

For my wedding anniversary this year, my wife bought me a Hootoo HT-TM02 (amongst other things). How nerdy is that? But it's a nice little machine which can have the default firmware replaced with OpenWrt. For about USD $16.00 it's a very cheap way to have an embedded Linux machine. Personally, I didn't even try the standard firmware and put OpenWrt on straight away. It was pretty easy, but you need a USB stick to give the device some extra storage during the initial upgrade process. The instructions are here and the process was very smooth.

As soon as I had the initial OpenWrt installation, I decided to switch to trunk OpenWrt, so I used the sysupgrade command to install the 15.05 trunk image from here. So this left me with a device running trunk OpenWrt. I then held the reset button in (whilst the device was powered on) for 30 seconds to make sure that the configs were all at default settings.

Next, I decided to install relayd to bridge the LAN (ethernet) port with my existing Wi-Fi network. I followed the instructions here and that seemed to work fine. I felt that I had followed those instructions exactly; but the OpenWrt firewall was still getting in the way. So I just went ahead and disabled the firewall by using:

/etc/init.d/firewall disable

After doing that, I can switch off the Wi-Fi on my laptop, connect a network cable between the Hootoo and the laptop and I'm on my network. The Hootoo is acting as a bridge between my own Wi-Fi and its own ethernet socket, very nice!

The next thing I need to do is cross-compile some code and get it running on the Hootoo.

An update to my 'rCPU' remote monitoring webserver

I thought that it was about time I had a fiddle with the tool I made to remotely monitor CPU use. I have mainly been using it on my Raspberry Pi 2. I switched the javascript library from Smoothie Charts to Flot, in the hope of getting better browser support. But I was able to take advantage of some features of flot at the same time. So this is how it looks now:

That clip was recorded by remotely monitoring my Raspberry Pi 2 from my MacBook. Hopefully it's a worthwhile improvement. The code is all on GitHub: davidsblog/rCPU.

More Docker as a cross-compiler

Now that I work in the Silicon Shed, I decided that I needed to have some more Linux in there ... and restore some balance to the universe. So I thought that a good place to start would be with OpenWrt running on my router. I already had a TP-Link WR740n lying around which I had been playing with before. So I went and got the latest version of OpenWrt (which was Chaos Calmer, 15.05) and installed that. Cool! Now I have a nice little router with plenty of features to play with, and it's an embedded Linux box as well.

But having gotten that far, I decided to set up a new cross-compile environment. I had done this before using Virtual Machines, but this time I wanted to use Docker to make it easier to compile my C programs using whatever machine I happen to be sitting in front of. I started by creating a base Docker image with all the files in place to give me a buildroot. In my Dockerfile I used Debian Jessie as the starting point and then added all the files by cloning them from OpenWrt's git repository. That generic image can be found here at davidsblog/openwrt-build-15-05. It's an automated build with the source files coming from GitHub. I also wanted to do the same with the next stage - actually compiling OpenWrt from sources ... but when I tried, DockerHub timed out the build. The OpenWrt build process can take a few hours. So the rest could not be done as an automated build.

I used my base image to create a .config file for the WR740n using the make menuconfig command and then copied that .config file and referenced it in my next Dockerfile. This new Dockerfile takes the base image, adds the config file and then calls make to actually build my specific cross-compile environment for the WR740n. If somebody wanted to make a cross-compiler for a different device they would just need to change the config file for their own device and use docker build to create an image.

So I built the image and pushed it out to DockerHub as davidsblog/openwrt-build-wr740n. As long as you have the bandwidth, it's much easier to be able to pull a pre-configured cross-compiler than to set one up from scratch. And it's really easy to use.

This is how I'm using it: I created a script called /usr/local/bin/740ncc which contains this:

#!/bin/bash
docker run --rm -v ${PWD}:/src davidsblog/openwrt-wr740n:latest \
     /bin/sh -c "cd /src; $*"

So then, on my local machine, I navigate to the folder containing the C sources I want to cross-compile. Now I can type something like 740ncc make and the make command will be routed to a docker container which will do the cross-compilation for the WR740n. The compiled program will be on your local machine (not in the Docker container) just as if you had compiled it locally. I think that's very not-bad. I am also using Dockers --rm parameter so that the container is automatically removed afterwards. Here's an example where I'm building my rCPU monitoring webserver for the TP-Link WR740n:

I also discovered something interesting during all this: using the find command inside the same Docker image but on different machines does not always show the results in the same order. This had me puzzling for a while when I was using the find command in one of my scripts. I used the image on Ubuntu and the order of the find results was different to the same image running on my laptop on Elementary OS. In my experience, on the same machine the order of results from find is the same. I was expecting it to be the same for a container too, but obviously you can't rely on that. Interesting.

The Silicon Shed

I've been a bit quiet recently, my blog hasn't gotten much attention. But I have been getting up to speed with my new job and so I've been adjusting to my new routine.

Nowadays I work from home, which is nice because I don't have to commute. I am particularly enjoying that, because sitting in the car for hours a day always seemed like a waste of time. This also means that I don't need to wake up at 6am each day...

But to separate home life from work life I have made a separate office by converting my garage. So this means that I don't actually work in the house. I find that this really helps - I don't get distracted during working hours. It's worked out very well. Here's a picture of me sitting at my new desk:

My colleagues have named my new workspace the Silicon Shed and the name has really stuck. I have even tried to set things up so that a colleague can come over and join me for a bit of pair-programming. When I was reading the book "Hello, Startup" this sentence particularly made me smile:

"At this very moment, somewhere in the world, two programmers are sitting in a garage and creating our future, one line of code at a time."

These days I find myself mostly working with Azure WebJobs (which are awesome) and doing lots of C# async stuff. But when you work for a small company anything can happen, so that's a massive oversimplification really. Every day I'm learning something new, which is part of the fun.