India Navi lag zwei Jahre in der Schublade

Der letzte Commit im India Navi Repository vor der langen Pause trägt das Datum 31. Mai 2024. Power Management für Light Sleep, eine neue Batterieanzeige, GPS-Punkte auf die SD-Karte loggen. Danach war Schluss. Das Studium, die Gruppenleitung, das Leben. Das Gerät lag in der Schublade, die Firmware auf GitHub und beide haben geduldig gewartet.

Balkendiagramm der Commits pro Quartal in Firmware und App von 2021 bis 2026, mit gut zwei Jahren Pause
Commits pro Quartal auf main in IndiaNavi_Firmware und IndiaNavi_App. Nach Mai 2024 war gut zwei Jahre Ruhe, im Oktober 2026 kamen 123 Commits zusammen.

Für alle, die India Navi nicht mehr auf dem Schirm haben: India Navi ist ein Offline-Navi zum Wandern. Kein Turn-by-Turn, kein „in 200 Metern links abbiegen“. Es zeigt die eigene Position auf einer Karte von der SD-Karte, dazu einen GPX-Track mit Höhenprofil, und aktualisiert das Bild jede Minute. Herzstück ist ein ESP32-S3 mit 16 MB Flash und 8 MB PSRAM, dazu das 7-Farben E-Paper von Waveshare mit 5,65 Zoll und 600 × 448 Pixeln und ein Quectel L96 als GNSS-Modul. Nicht verirren statt navigieren, das war von Anfang an das Ziel. Wer die Vorgeschichte nachlesen will: das Update vom Juni 2021 und die Firmware 2.0r2.

Der Splash Screen von India Navi: Schriftzug und ein Wanderer mit Rucksack und Stock
Der Wanderer mit Rucksack und Stock ist seit Jahren das Gesicht des Projekts. Die Vorlage liegt jetzt auch in der Dokumentation des Repositories.

Erst einmal wieder bauen können

Wer ein Embedded-Projekt zwei Jahre liegen lässt, kennt das: Nichts baut mehr. Die PlatformIO-Plattform hatte sich weiterbewegt, ESP-IDF auch. Der erste Schritt Ende September war deshalb das Update auf ESP-IDF 6.1 (espressif32 7.1.3) samt GCC 15. Klingt nach Versionsnummer hochdrehen, war es aber nicht. FatFs alloziert seine Puffer jetzt nur noch, wenn der Zeiger im FIL-Objekt NULL ist. Ohne Nullinitialisierung ist das Gerät beim Booten abgestürzt. Dazu ein Pufferüberlauf in ctime_r(), das 26 Byte braucht, und eine Handvoll geänderter API-Aufrufe für SD-Karte, Wakeup-Ursachen und HTTP-Client.

Ein Speicher-Audit, das wehgetan hat

Direkt danach habe ich den Code einmal komplett auf Speicherfehler durchsucht. Die Liste ist lang und liegt als MemoryAudit.md im Repository. Ein paar Highlights: Der NMEA-Parser hat seine Plugins als Zeiger auf den Stack des Aufrufers gespeichert. Ein PMTK001-Ack hat einen Funktionszeiger außerhalb des Arrays aufgerufen. Fehlte eine Kartenkachel, blieb der SD-Mutex gesperrt und das Gerät stand still. Der GPX-Parser hat unvollständige Dateien für immer neu geparst. Und das Höhenprofil hatte einen Heap-Überlauf. Dazu Lecks im OTA-Puffer alle 30 Sekunden und bei jedem Aus- und Einschalten.

Der spannendste Fund war aber kein Bug im klassischen Sinn. Ein GPX-Track mit 154 KB hat den kompletten internen RAM gefressen, 59 Byte waren noch übrig. Jeder Trackpunkt ist eine kleine Allokation, und kleine Allokationen landen im internen RAM. Dann konnte der SD-Kartentreiber seine DMA-Puffer nicht mehr anlegen und die Karte blieb weiß. Seitdem liegen Trackpunkte, Höhenprofil und Dateipuffer im PSRAM. Mit dem gleichen Track bleiben jetzt 30 KB internes RAM frei.

Altlasten abarbeiten

Am 6. Oktober habe ich mir dann die offenen Issues vorgenommen. Manche davon lagen schon peinlich lange herum. Das log.gpx wurde bei jedem Boot geleert und nie beschrieben, weil die GPS-Task auf ein Flag gewartet hat, das niemand gesetzt hat. Die Uhrzeit aus dem GPS war nur in Zeitzonen mit UTC+1 richtig, weil irgendwann jemand (ich) eine Stunde draufaddiert hat. Das Höhenprofil eines Tracks unter Meeresniveau wurde nie gezeichnet, weil der Wertebereich vorzeichenlos war. Und der nächste Wegpunkt war nur dann der nächste, wenn er auf beiden Achsen näher lag. Sechzehn Issues an einem Tag geschlossen, dazu ein Release v3.0.0. Die letzte Version davor war v2.1.1 aus dem Juni 2023.

Wie das in der Zeit möglich war

Ehrlich gesagt: Dieses Tempo hätte ich neben dem Job alleine nicht geschafft. Wer in die Commit-Historie schaut, sieht an vielen Stellen „Claude“ als Autor oder eine Claude-Session im Commit-Text. In meinem letzten Beitrag habe ich gefragt, wie ihr mit euren KI-Agenten redet. India Navi ist mein Versuchsfeld dafür geworden. Das Muster, das sich bewährt hat: Ich beschreibe das Problem mit Kontext und dem Ziel dahinter, der Agent liefert einen Pull Request, ich teste auf echter Hardware und schreibe dann die Fixes, die nur am Gerät auffallen. Nicht alles hat funktioniert. Ein Agent hat parallel angefangen, die ganze Firmware nach Rust zu portieren. Das liegt in eigenen Branches und ist nicht in main gelandet. Rust ist trotzdem ins Projekt gekommen, aber anders, dazu später mehr.

In den nächsten Beiträgen geht es um die App, um Bluetooth, um schnelleres Rendern und um Vektorkarten. In einem Monat ist ganz schön viel passiert.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert