Die C/C++ Bindings ermöglichen es Bricks und Bricklets mit selbst erstellen C/C++ Programmen, die auf einem Mikrocontroller laufen, zu steuern. Die ZIP Datei für die Bindings beinhaltet:
source/bindings
den Quelltext der Bindingssource/hal_*
den Quelltext der HALs für einige Plattformenexamples/
die Beispiele für alle Bricks und BrickletsDie C/C++ Bindings für Mikrocontroller unterstützen Co-Prozessor-Bricklets, also diese mit einem 7-Pol-Anschluss, sowie das HAT Brick und das HAT Zero Brick. Die älteren Brickets mit 10-Pol-Anschluss, sowie andere Bricks werden nicht unterstützt. Siehe hier für eine vollständige Liste unterstützter Geräte.
Das C/C++-Programm, das die Bindings verwendet läuft auf dem Host. Als Host unterstützt werden aktuelle der ESP32 Brick und der ESP32 Ethernet Brick. In Zukunft werden weitere Mikrocontroller als Host unterstützt werden.
Die Bindings benötigen einen host-spezifischen Hardware Abstraction Layer (HAL). Siehe hier für Details.
Da es keine vorkompilierte Bibliothek für die C/C++ Bindings für Mikrocontroller gibt, gibt es in diese Sinne auch nichts zu installieren. Die empfohlene Art und Weise die Bindings zu verwenden, ist ihren Quelltext direkt in das jeweilige C/C++ Projekt mit einzubinden.
Die Beispiele für jeden unterstützten Brick und Bricklet sind nicht vollständig, da diese von der verwendeten Host-Hardware (und deren HAL) abhängen. Viele HALs beinhalten einen Beispiel-Treiber der jegliches Beispiel ausführen kann. Weitere Details sind in den spezifischen HAL Dokumentationen zu finden.
Alle Geräte-*_create
-Funktionen nehmen ein uid_or_port_name
Parameter,
das es dem Programm ermöglicht festzulegen mit welchem Gerät kommuniziert werden
soll. Dies kann auf drei Weise erfolgen:
NULL
wird das erste unbenutzte Gerät des entsprechenden Typs
ausgewählt unabhängig von UID und Port-Name.In diesem Fall bedeutet unbenutzt, dass das Gerät keinem Device-Objekt zugeordnet
ist. Zum Beispiel sind zwei Temperature Bricklet 2.0 angeschlossen, eins an Port A
und eins an Port B. Bei Übergabe von NULL
wählt der erste tf_temperature_v2_create
Aufruf das Bricklet an Port A aus. Der zweite Aufruf wählt das Bricklet an Port B,
da das Bricklet an Port A bereits benutzt wird.
Die C/C++ Bindings für Mikrocontroller funktionieren anders als die anderen verfügbaren Bindings. Während andere Bindings, die über TCP/IP mit einem Brick Daemon kommunizieren, eine IP Connection verwenden, benötigen die C/C++ Bindings für Mikrocontroller einen Hardware Abstraction Layer (HAL). Der HAL abstrahiert den plattformspezifischen Weg der SPI-Kommunikation.
Die Bindings beinhalten HALs für die folgenden Plattformen. Für andere Plattformen muss ein eigener HAL implementiert werden (siehe unten).
Falls die Bindings auf einer anderen Plattform verwendet werden sollen, muss ein eigener HAL implementiert werden. Diese Anleitung zeigt wie.
Callbacks funktionieren in den C/C++ Bindings für Mikrocontroller anders als
in anderen Bindings. Da es auf vielen der Zielplattformen kein Multi-Threading
gibt, wird nicht automatisch nach Callbacks gepollt. Stattdessen muss, wenn
Callbacks empfangen werden sollen, mit der in jedem HAL verfügbaren
tf_hal_callback_tick
-Funktion nach Callbacks gepollt werden.
Diese Funktion pollt nur angeschlossene Geräte, für die mindestens
ein Callback-Handler registriert ist.
Callback werden nicht von einem anderen Thread ausgeliefert, sondern
nur, während ein Getter, Setter oder die tf_hal_callback_tick
-Funktion
ausgeführt wird. Die Bindings sind deshalb während der Ausführung eines
Callback-Handlers in einem Zustand, der es nicht erlaubt weitere Pakete zu schicken.
Es ist nicht erlaubt, Getter, Setter oder Tick-Funktionen aus einem Callback-Handler aufzurufen
Die primäre Zielplatform für die Bindings sind Mikrocontroller,
deshalb sind sie nicht thread-sicher. Einige HALs unterstützen
kooperatives Multitasking, es sind aber keine Aufrufe der Bindings-API
erlaubt, während sie pausiert sind. Alle Funktionen geben während
die Bindings pausiert sind, oder gerade ein Callback ausgeliefert wird,
TF_E_LOCKED
zurück.
Um die beste Performance aus den Bindings zu holen, kann der folgenden Liste von Optimierungen gefolgt werden:
Erhöhen der SPI-Taktfrequenz von 1,4 MHz auf so nah wie möglich an 2 MHz. Eine zu hohe Taktfrequenz wird die Performance aber wieder verschlechtern, da die angeschlossenen Geräte die Daten nicht mehr empfangen können. In unseren Tests wurde die optimale Performance bei 1,95 bis 1,96 MHz erreicht, aber das ist stark abhängig vom Aufbau, dem HAL und der Stabilität der SPI Clock des Host-Systems.
Die SPI-Taktfrequenz kann in den HAL-Implementierungen eingestellt werden.
Bevorzugung von Callbacks. Die Bindings können ein angeschlossenes Gerät nach verfügbaren Callbacks fragen, indem ein einzelnes Byte über SPI geschickt wird. Wenn Getter verwendet werden um schnell veränderlichen Zustand abzufragen, muss jedes Mal eine komplette TFP-Anfrage, deren Antwort und ein Acknowledgment über SPI verschickt werden, was mindestens 23 Byte Datenverkehr bedeutet.
Wenn exakt bekannt ist, welche Callbacks in welchen Intervallen eintreffen werden,
sollte nicht tf_hal_callback_tick
verwendet werden, sondern ein eigenes Scheduling
für das Pollen mit den gerätespezifischen tf_[device]_callback_tick
-Funktionen verwendet werden.
Das erlaubt es, mehr Zeit für andere Aufgaben aufzuwenden. tf_hal_callback_tick
verwendet
einen Round-Robin-Scheduler um alle Geräte mit einem registrierten Callback Handler zu pollen.
Falls mehrere SPI-Einheiten verfügbar sind, können, soweit unterstützt, mehrere HAL-Instanzen verwendet werden. Das erlaubt es, mit mehreren Geräten parallel zu kommunizieren. Jede HAL-Instanz darf trotzdem nur von einem Thread verwendet werden.
Damit eine Firmware mit den Bindings auf kleinere Plattformen
wie den Arduino Uno passt, können die folgenden Konfigurationsoptionen
in bindings/config.h
angepasst werden:
TF_INVENTORY_SIZE
:
Die Größe des Inventory, also des Mappings von
UIDs auf die Ports unter denen die Geräte erreichbar sind.
Wenn pekannt ist, mit wie vielen Geräten kommuniziert werden soll,
kann die Größe auf diesen Wert gesetzt werden. Die HAL-Initialisierung
gibt TF_E_TOO_MANY_DEVICES
zurück, falls das Inventory zu klein war.TF_IMPLEMENT_CALLBACKS
:
Falls keine Callbacks benutzt werden sollen, kann dieses define entfernt werden, damit
der entsprechende Code nicht verwendet wirdTF_LOG_LEVEL
:
Durch reduzieren des Log-Levels werden viele String-Konstanten nicht einkompiliert.
Valide Werte sind:TF_LOG_LEVEL_NONE
: Deaktiviert das Logging komplettTF_LOG_LEVEL_ERROR
: Loggt nur HAL-spezifische Fehler wenn sie auftretenTF_LOG_LEVEL_INFO
: Loggt zusätzlich die Liste der gefundenen Geräte bei der HAL-InitialisierungTF_LOG_LEVEL_DEBUG
: Loggt zusätzlich alle internen Zustandsänderungen der SPITFP-ZustandsmaschineTF_IMPLEMENT_STRERROR
:
Wenn dieses define entfernt wird, wird die tf_hal_strerror
-Funktion nicht implementiert.
Damit können ungefähr 500 Bytes Speicherplatz freigemacht werden.Links zur API Referenz der HALs, Bricks und Bricklets sowie die Beispiele aus der ZIP Datei der Bindings sind in der folgenden Tabelle aufgelistet. Anleitungen für weiterführende Projekte finden sich im Abschnitt über Kits.