Tonuino - alternative Firmware

Projekt-Steckbrief

  • Difficulty: Experte 5/5
  • Kosten: 0€
  • Zeitaufwand: ~400h

Galerie

Image: birdshouse open Image: inside of the bird's house Image: Guitar Amp design Image: inside of Guitar Amp
Einige Anwendungsbeispiele von Tonuino - alternative Firmware.

C++ Eine für das Arduino-Framework geschriebene Software, die einen Mp3-Player (mit SD-Karte), ein NFC-Tag-Lesegerät und ein paar Bedienelemente verbindet, die zusammen wie eine Jukebox funktioniert welche über NFC-Tags gesteuert werden kann. Ein NFC-Tag wird mit einem Ordner auf der SD-Karte verknüpft, der Audiodateien enthält. Das Tag speichert auch Informationen über den gewünschten Wiedergabemodus für dieses Album, z. B. “Zufällig”. Sobald ein verknüpfter Tag in die Nähe der Jukebox gebracht wird, wird der konfigurierte Ordner im programmierten Wiedergabemodus abgespielt. Mit den Bedienelementen kann der Titel ausgewählt, die Lautstärke geändert und sogar durch ein Sprachmenü navigiert werden, das das Löschen eines Tags, das Verknüpfen/Konfigurieren eines Tags und das Sperren/Entsperren der Eingabetasten ermöglicht.

Motivation

Idee und phantastische Umsetzung hatte uch auf Thorsten Voß’ blog gesehen. Es begann mit einer Funktion (encoder support), die ich hinzufügen wollte. Leider war der ursprüngliche Code ein Monolith mit mehreren Tausend Zeilen Code und für mich schlechter Lesbarkeit, so dass es mir schwer fiel, meine Änderungen einzubringen. Also habe ich den Code von Grund auf neu geschrieben, um eine bessere Struktur, Lesbarkeit, Wartbarkeit und Erweiterbarkeit zu erreichen. Parallel dazu las ich einige Bücher über objektorientiertes Design in C++, Clean Code und Software Design Patterns und wandte einige davon dort an, wo ich sie für geeignet hielt. Auf diese Weise konnte ich sowohl die Modularität als auch die Lesbarkeit des Codes verbessern und habe außerdem gelernt, wie man Code in einem “größeren” Projekt schreibt.

Schwierigkeiten

Dies war mein erstes eigenes OO-C++-Projekt, und vielleicht war es für den Anfang ein wenig zu groß. All die für mich neuen Konzepte, das Schreiben an eine Schnittstelle, die erstmalige Verwendung von Platformio als IDE, die Verwendung des googletest unit test framework, die Verwendung von Coding Patterns wie factory oder Dependency Injection kostete mich Abend um Abend über fast ein Jahr, bis dieses Projekt abgeschlossen werden konnte. Und es gibt immer noch etwas zu überarbeiten und zu verbessern.

Übersicht

  • Unit-Test-Suite mit über 250 Testfällen
  • Serielle Debug-Ausgabe konfigurierbar
  • Lose gekoppelte C++ OO-Architektur
  • Einzelne Module mit klaren Aufgaben, skalierbar und leicht zugänglich für zukünftige Funktionen
  • benutzerdefinierte Hardware-Abstraktionsschicht; der größte Teil des Codes sollte ohne Änderungen auf andere MCUs portierbar sein
  • eigenes Dependency Injection Framework (Loader Klasse)

Funktionen

  • Konfigurierbare Benutzereingabe (Tasten oder Encoder)
  • Auto-Poweroff, wenn für eine konfigurierbare Zeit keine Taste gedrückt wird
  • Einschalten durch Drücken der “Play”-Taste
  • Autoplay-Funktion
  • Status-Led-Funktion
  • Sperren/Entsperren der Benutzereingabe
  • Mehrere Wiedergabemodi [Album, Zufall, Speichern des Titelfortschritts, Nur ein Titel] pro Nfc-Tag verfügbar
  • Sprachmenüs zum Verknüpfen oder Löschen von Nfc-Tags
  • Optimiert für Batterieanwendungen (z.B. Powerbank) unter Verwendung von Ruhezuständen
  • Niedriger Stromverbrauch @5V: ~40mA im Leerlauf, ~75mA bei mittlerer Lautstärke
  • Konfigurationsdatei für Startlautstärke, Einschlaf-Timer etc.
  • Automatische Wiederherstellung bei Eingabeaufforderung, die niemand bedient
  • Sprachansagen für die häufigsten Fehlermeldungen

Nicht enthaltene Funktionen

  • Keine Erkennung des Ladezustands der Powerbank
  • Kein Konfigurationsmenü (Startlautstärke, Dauer des Einschlaf-Timers, Standby-Dauer usw.)

Dokumentation

Das Projekt ist für das Arduino Framework erstellt - getestet auf einem Arduino nano Board - unter Verwendung der PlatformIO IDE. Die folgenden Abschnitte zeigen das Design.

Projekt Modulübersicht

Ordnername in /lib Zweck
Arduino minimalistische hardwarenahe Implementierungen, nicht Unit-testbar
Arduino_HardwareAbstraction Hardware-Abstraktion, um Portabilität und Testen zu ermöglichen
Config Systemkonfigurationsparameter
Folder Geschäftslogik für Wiedergabeliste und Wiedergabemodus
Loader Dependency Injection Framework
MessageHandler Systemnachrichten und Debug-Framework
Mp3 Mp3-Steuerung (Status, Ordner, Sprachausgabe, Anzeigen)
Nfc Tag-Steuerung (Status, Lesen, Schreiben, Löschen)
PowerManager Steuerung von Status-LED und Ruhezustand abhängig vom Systemstatus
Tonuino Haupt-Task-Scheduler
UserInput Verarbeitung von Tasten- oder Encoder-Eingaben
Utilities Timer, Led-Steuerung, Pin-Steuerung
VoiceMenu Geschäftslogik für das Menü Link / Löschen / Konfiguration

Verwendete externe Bibliotheken

Automatische Installation durch Platformios “Library Dependency Finder” beim erstem Kompiliervorgang

Klassendiagramme

Klassendiagramme wären zu viel nicht-automatisierte Arbeit gewesen. Stattdessen habe ich das hier vorbereitet:

Software-Modulübersicht

Sie sollte ein genaues Verständnis dafür vermitteln, wie die Softwaremodule zusammenwirken und welche APIs die Module anbieten.

Los geht’s!

Es ist Zeit zum Selbermachen! Klonen Sie mein repository, um zu beginnen. Das README.md Dokument bietet einen leichten Einstieg. Ich empfehle die Verwendung von PlatformIO für dieses Projekt. Nachfolgend finden Sie alles, was Sie brauchen, um mit dem Design Ihres einzigartigen Lautsprechers zu beginnen.

Testen

Unit-Tests

Unit-Tests werden mit dem gtest C++ Unit-Test-Framework geschrieben. Sie befinden sich im Ordner test/desktop. Zu beachten ist, dass googletest die Installation von gcc mit einigen Bibliotheken voraussetzt. Die Anleitung dazu findet man in einem meiner anderen Projekte{:rel=”noopener noreferrer”, in der PlatformIO CLI (Terminal) ausgeführt werden.

Akzeptanztests

Obwohl diese Tests automatisiert werden könnten, ist es viel einfacher, diese Tests von Hand durchzuführen, nachdem Sie Ihren µC programmiert und alle elektronischen Komponenten zusammengesetzt haben. Jede Zeile in den folgenden Tabellen ist ein eigenständiger Testfall. Die Testsuiten (Überschrift Name) haben eine System Pre: Eigenschaft, die vor der Ausführung der einzelnen Testfälle wiederhergestellt werden muss. Wenn die Erwartungsklausel erfüllt ist, ist der Test BESTANDEN. Ich habe die Tests auf Englisch belassen, weil sie recht eng mit dem Code korrespondieren.

Switching ON

System Pre: System is OFF

Action Expectation
press Play/Pause button LED flashes slowly?
press Play/pause button Welcome prompt plays?

Switching OFF

System Pre: System is ON

Action Expectation
Playback on pause, no button input System switches off after a time?
System shutdown Farewell prompt plays?
System shutdown LED switched off?

Play Help Prompt

System Pre: System is ON

Action Expectation
Long press Play/Pause button Help prompt plays?
Help prompt playing Can be interrupted with any button press?

Behavior without Tag

System Pre: System is ON, no Tag present

Action Expectation
press Play/Pause button prompts “couldn’t find track” error?
press Next button prompts “couldn’t find track” error?
press Prev button prompts “couldn’t find track” error?
doubleclick Play/Pause button Delete Menu prompt played?

Behavior with Tag

System Pre: System is ON, linked Tag available

Precondition Action Expectation
no Tag placed place known Tag starts Playback of correct Folder?
active playback press Next button plays next track?
active playback press Next button next track in accordance with selected playMode of Folder?
active playback long press Next button increases volume?
active playback press Prev button plays previous track?
active playback press Prev button previous track in accordance with selected playMode of Folder?
active playback long press Prev button decreases volume?
active playback press Play/Pause button pauses track?
paused playback press Play/Pause button resumes track?
active playback doubleclick Play/Pause button Lock prompt played?
active playback doubleclick Play/Pause button Playback resumes after Lock prompt played?
active playback doubleclick Play/Pause button locks button input?
locked button input doubleclick Play/Pause button Unlock prompt played?
locked button input doubleclick Play/Pause button Playback resumes after Unlock prompt played?
locked button input doubleclick Play/Pause button unlocks button input?
paused playback doubleclick Play/Pause button Playback resumes after Lock prompt played?

Behavior with unlinked Tag

System Pre: System is ON

Action Expectation
place unlinked Tag plays LinkMenu Prompt?
navigate through LinkMenu plays Configuration Success Prompt?
place Tag again plays linked folder?

Hardware

Materialliste

Ich habe ersucht mit möglichst wenigen Einzelteilen auszukommen. Für ein Projekt dieser Größe ist die Liste denke ich recht kurz geblieben.

Menge Artikel Zweck
1 Arduino (z.B. Nano) Gehirn
1 Dfplayer Mini Mp3 Player Mund
1 Micro SD Karte Speicher
1 MFRC522 Nfc-Leser Psi-Sense
1 Bistabiles Relais 5V, z.B. HFE20 Kaffee - kein Schlaf
2 Dioden z.B. 1n4007 Venenklappe
1 PNP-Transistor z. B. BC327 Kaffeemaschinenschalter
2 Widerstände 1k Blutstromaufbereiter
1 Widerstand 220 Blinkstärke dimmen
1 LED, Farbe nach Wahl blinken
1 Powerbank/ 5V Versorgung Lebensmittel
3 Drucktasten, z.B. Cherry MX Tasten Drucksensoren
1 Lautsprecher, z.B. 5W@4Ohms Stimmbänder
1 USB-A-Stecker Strohhalm
1 Gehäuse Körper

Zusätzliche Komponenten und Tipps

Überbrückungsdrähte, Platine, Buchsen und Verbrauchsmaterial nach eigenem Ermessen Wie beim “Original”-Projekt; alternativ einen Drehgeber anstelle der Drucktasten kaufen und das Projekt so konfigurieren, dass er verwendet wird. Da das System für den Batteriebetrieb optimiert ist, nehmen Sie ein bi-stabiles Relais oder einen JFET-Transistor (mit niedriger Gate-Spannung und niedrigem Source-Drain-Spannungsabfall) für die KeepAlive-Funktionalität, die den zusätzlichen Strom durch die ständig eingeschalteten Relaisspulen mindert. Eine billige Powerbank reicht für viele Stunden. Alternativ können z.B. 3xAA-Batterien verwendet werden - allerdings macht der Dfmini dann ordentlich Krach, wenn nicht genügend Strom durch laufende Resets geliefert werden kann (und kann sogar durch Stromstöße gebrickt werden, also Vorsicht).

Schaltplan

Stromlaufplan