(As you might have noticed, I started writing some posts in English now. I've been meaning to do that for some, maintaining two language versions for each post, but this has proven to be too much work. So for now, posts that may be useful for a wider (international) audience will be written in English.)
[trigger warning: Lisp]
So recently I got myself a brand, new Raspberry Pi 2. It's the first time I'm playing around with such platform, so I'm still exploring the possible applications. And of course the, first thing I thought about is how to get a decent Lisp working on it. This series of posts will describe my experiences with the process of setting up a Lisp environment and using it for basic hardware development.
For those of you who don't know, Raspberry Pi is a small computer based on ARM architecture, with storage provided via SD card and a bunch of general-purpose IO (GPIO) pins for interfacing with other electronics. It's two main features are low power requirements and being something between an Arduino and an actual PC.
Setting up the Pi
I don't want to go into too many details, as the process is well covered in various tutorials. What I did is, I took the SD card from my cell phone (Raspberry Pi 2 uses microSD cards instead of SD the previous one required) and flashed it with Raspbian, a Debian Linux derivative. I plugged a screen and a keyboard to it on the first run, and later just left it running headless attached to my home router, configuring the latter to always assign the same IP address to the Pi.
Since Raspberry Pi is an ARM machine, my choice of Common Lisp implementations were limited. Fortunately, the two most popular (and the ones I like the most) implementations - SBCL and CCL - both support ARM architecture[1].[1] - There's also ECL (Embeddable Common Lisp) that apparently works well on ARMs, but I haven't looked at it in like three years, so I decided to skip it for now. I favour those two implementations because they are the most robust and performant of those freely available[2].
The conventional wisdom goes like this: SBCL is the best choice on Linux, and CCL is the best on Windows[3] and MacOS. But in case of Raspberry Pi, even though I'm running Linux, I ended up using CCL[2] - There're Allegro CL and LispWorks that are cool and professional and all, but I don't quite feel like shelling out money for it just yet. Also, I don't think they work on ARM. instead of SBCL, because the former has native threading support while the latter does not (for now). And threading makes all the difference - Raspberry Pi 2 has only 900MHz processor, but it's quad-core. You can really feel the speed gains coming from parallelism when doing any kind of interactive work.
For the sake of completeness, I shall describe the installation of both implementations.[3] - Mostly because SBCL on Windows tends to crash and print messages about some Kitten of Death.
SBCL
There is nothing fancy in SBCL installation process - just go to the SBCL download page and download the newest build for the Linux ARMhf platform. Extract the downloaded file (tar -xvjf filename.tar.bz2
, in case you don't remember ;)) and follow instructions from the INSTALL file.
CCL
Go to the CCL download page and fetch the newest CCL for ARM. Unpack it (tar -xvvzf filename.tar.gz
this time ;)). You will have an armcl
executable file, which is the CCL executable. However, if you go and actually run it, it may crash. If so, it means you'll need to rebuild the Lisp kernel for your platform.
Go to the lisp-kernel/linuxarm
directory. Make sure you have an uncommented line in the float_abi.mk
file that says FLOAT_ABI_OPTION = -mfloat-abi=hard
. Then, run make
inside the lisp-kernel/linuxarm
directory. After the compilation process finishes, you should have a working armcl
executable.
Working with Lisp on a remote machine
Having a Lisp on a Raspberry Pi is a good excuse to learn how to develop a Lisp program remotely. This involves editing remote files on a local machine and executing Lisp code remotely.
Since the best IDE for Common Lisp is Emacs with SLIME, let's see how this operating system editor can help us.
Connecting to a remote Lisp
First of all, you need to make sure you have fresh versions of SLIME on both your Pi and the machine you want to connect from. Use Quicklisp ((ql:quickload :SWANK)
) on the former, and Emacs package manager (or direct download) on the latter[4].[4] - You could also install SLIME locally via QuickLisp. Do a (ql:quickload :quicklisp-slime-helper)
and follow instructions from here. I've heard that this is *the* recommended way of installing SLIME now, but I haven't tested it yet.
After that's done, you need to run a SWANK server in your Lisp instance and make sure you can establish a secure connection with it.
A good way to approach it is to use SSH port forwarding. If you want to connect to your Lisp instance, establish an SSH connection with port tunneling, using a command like this:
ssh -L 8885:localhost:4005 user@raspberrypi
It's just a normal SSH connection, but additionally, it will securely map the port 8885 on your machine to the remote 4005 port.
On the remote side, inside your Lisp image, run the following code:
(swank:create-server :port 4005 :dont-close t)
It's a good idea to run your Lisp under screen or tmux, so that you can leave the program running and only connect (with port forwarding) to the Raspberry Pi when you need to do actual development.
When you've done all this, all that remains is to switch to your local Emacs instance and do M-x slime-connect
and connect SLIME to the port 4005. You should be able to execute code on Raspberry Pi via Lisp REPL now.
With SLIME connected, you'll also be able to use shortcuts like C-c C-c
to dynamically evaluate any opened code inside the remote Lisp image.
Editing code remotely
Developing on a remote machine involves changing code on it. You may of course set up git repository and clone it on both local and remote machine, but doing commit-push-pull dance to move the code around is tiring. Fortunately, Emacs gives you a way to directly edit files on a remote machine.
This feature is known as TRAMP (Transparent Remote Access, Multiple Protocols), and comes with Emacs by default. It allows you to edit files over various protocols as if they were just local files on your hard drive[5].[5] - It's primary use, however, seems to be editing files as a superuser. If you want to access a file with superuser rights, instead of launching a new Emacs instance with sudo
, you can use TRAMP like this: C-x C-f /sudo:root@localhost:/
- at this point you will be prompted for your password and, after successful authorization, you can continue typing in the path of the file you want to visit.
To use it over SSH with the Raspberry Pi, open the file using C-x C-f
, but enter a path like this:
/ssh:user@raspberrypi:/
You will be then prompted for password, and after successful authorization, you will see that you're able to access remote device's file system. You can now open your remote file, and any changes you save to it will be written directly on the remote device.
Emacs of course caches the established connection, so you don't have to give your password again to save data or open more remote files.
Note however, that there's a caveat - after you leave Emacs idle for some time (like, half an hour or more) the connection timeouts, and it's easy for Emacs to get stuck trying to reconnect. It's a weird problem I don't have any solution for yet. There is a lot written about it on Emacs Wiki though, so make sure to check it out, and in the meantime, be prepared to kill Emacs after you're done with remote work.
Using Lisp for something interesting
So now that we have a working Lisp on a Raspberry Pi and a proper development setup, what interesting things can we do with it? Well, this post is already too long, so I will leave that for later - but as a little sneak peak, so far I've managed to run a webserver that exposes readings from internal SOC temperature sensor and external thermometer. Stay tuned for this and more lispy stuff on Raspberry Pi.