Deine eigene LISP Machine
TL;DR:
Wer wollte nicht schon immer mal eine Lisp-Maschine mit einem echten RTOS sein Eigen nennen? Wenn möglich schön handlich, mit Wifi, serieller Console über USB und kosten darf es auch nicht mehr als 5 EUR. Mit dem beliebten ESP8266 von espressif ist das tatsächlich möglich.
Jonas Karlsson (yesoc) hat mit seinem Projekt esp-lisp einen Lisp Interpreter für den ESP8266 geschrieben. Der Funktionsumfang ist für sein Beta-Stadium schon beträchtlich. Die Lisp-Implementierung ist bereits gut ausgereift und bietet schon rudimentäre Interaktion mit dem ESP8266-Board selbst (IO-Pins, WiFi).
Da der ESP8266 nicht direkt an USB angeschlossen werden kann, empfiehlt es sich, ein fertiges Dev-Board wie das Wemos D1 Mini oder das CH340 NodeMCU V3 zu verwenden. Diese können direkt mit einem USB-Kabel an den PC angeschlossen werden.
ESP SDK compilieren
Achtung: Alle Befehle müssen in einer bash
Shell ausgeführt werden.
Als erstes werden wir das ESP Open SDK herunterladen und compilieren. Es enthält ein paar Hilftfunktionen, die wir für die weiteren Schritte benötigen. Evtl. müssen noch ein paar Pakete wie gperf
oder make
installiert werden. Bei mir war noch die Umgebungsvariable $LD_LIBRARY_PATH
gesetzt, diese musste ich zuvor noch leeren. Vor dem compilieren muss (Stand 15.03.2016) noch eine Datei gepatched werden, damit der Compilevorgang abgeschlossen werden kann.
git clone --recursive https://github.com/pfalcon/esp-open-sdk.git
cd esp-open-sdk
make STANDALONE=n
Im Anschluss muss die $PATH
Variable angepasst werden, so dass die darauffolgenden Befehle die gerade compilierten Tools finden. Es lohnt sich, alle folgenden Komponenten/Projekte in einem Unterverzeichnis auszuchecken. Am Ende sollten drei Unterverzeichnisse vorhanden sein. In diesem Unterverzeichnis muss zudem eine Datei mit dem Namen path-add-esp
angelegt und mit folgendem Inhalt gefüllt werden:
export PATH=/home/aaron/workbench/esp-open-sdk/xtensa-lx106-elf/bin:$PATH
RTOS ESP8266 SDK beschaffen
Im Anschluss benötigen wir das auf FreeRTOS basierende Framework für den ESP8266. Dies ist die Basis für esp-lisp. Hiervon benötigen wir hauptsächlich die Source-Files, compilieren müssen wir hier nichts. Dies folgt im nächsten Schritt.
cd ..
git clone --recursive https://github.com/SuperHouse/esp-open-rtos
Eine kleine Anpassung müssen wir aber auch hier machen. In der Datei include/ssid_config.h
muss die Zeile mit dem #warning
entfernt werden. Die WiFi-Daten müssen wir nicht angeben.
esp-lisp compilieren
Zuletzt brauchen wir noch den esp-lisp Code selbst. Und auch hier müssen wir eine kleine Änderung vornehmen, wenn python
in Version 3.x installiert ist (bei ArchLinux der Fall). Hierzu einfach die Datei xtensa-lx106-elf/bin/esptool.py
öffnen und in der ersten Zeile python
durch python2.7
austauschen. Das praktische Script run
erledigt dann den Rest für uns. Mit make flash
kann dann zuletzt die Firmware auf den ESP8266 aufgespielt werden (ein an USB angeschlossener ESP8266 vorausgesetzt).
cd ..
git clone https://github.com/yesco/esp-lisp.git
cd esp-lisp
./run
make flash
Starten
Die Serielle Verbindung zur Lisp-Maschine kann mit dem Script mcu
aufgebaut werden (das Programm screen
muss installiert sein).
./mcu
Nach einem Druck auf Enter
wird man mit einer REPL begrüßt.
lisp> (define fib (lambda (n) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2))))))
#fib
lisp> (fib 10)
89
Ziemlich cool ist die trace-Funktion (einschalten mit trace on
). Hier kann die Schrittweise Evaluation sehr anschaulich angezeigt werden. Das hilft vor allem beim Erlernen von Lisp.
lisp> trace on
lisp> (fib 2)
---> (fib 2)
ENV
---> (#if (#< n 2) 1 (#+ (#fib (#- n 1)) (#fib (#- n 2))))
ENV n=2
---> (#< n 2)
ENV n=2
nil <--- (#< n 2)
---> (#+ (#fib (#- n 1)) (#fib (#- n 2)))
ENV n=2
---> (#fib (#- n 1))
ENV n=2
---> (#- n 1)
ENV n=2
1 <--- (#- n 1)
---> (#if (#< n 2) 1 (#+ (#fib (#- n 1)) (#fib (#- n 2))))
ENV n=1
---> (#< n 2)
ENV n=1
t <--- (#< n 2)
1 <--- (#if (#< n 2) 1 (#+ (#fib (#- n 1)) (#fib (#- n 2))))
1 <--- (#fib (#- n 1))
---> (#fib (#- n 2))
ENV n=2
---> (#- n 2)
ENV n=2
0 <--- (#- n 2)
---> (#if (#< n 2) 1 (#+ (#fib (#- n 1)) (#fib (#- n 2))))
ENV n=0
---> (#< n 2)
ENV n=0
t <--- (#< n 2)
1 <--- (#if (#< n 2) 1 (#+ (#fib (#- n 1)) (#fib (#- n 2))))
1 <--- (#fib (#- n 2))
2 <--- (#+ (#fib (#- n 1)) (#fib (#- n 2)))
2 <--- (#if (#< n 2) 1 (#+ (#fib (#- n 1)) (#fib (#- n 2))))
2 <--- (#fib 2)
2
Ich habe für meine LISP-Machine ein kleines Gehäuse gedruckt. Im Innern arbeitet ein winziges Dev-Board, das ich mit ein paar Tropfen Sekundenkleber eingeklebt habe. Eine WS2812 RGB-LED, die auf dem Dev-Board praktischerweise aufgelötet ist, beleuchtet das Innere.
Bisher ist mein Gehäuse nur grundiert und es fehlt noch die Bemalung und die Aufschriften. Dennoch funktioniert der Winzling schon wie das Vorbild.
Erstaunlich, dass vor 30 Jahren solche Maschinen unbezahlbar und groß wie ein Kleiderschrank waren. Heute ist es nur noch Spielzeug und passt zwischen zwei Finger.