INDI-Module

Hier entscheidet sich alles

class IndiModule : public Basemodule, public INDI::BaseClient

Eine einzige Zeile, und doch ist das gesamte Framework darin enthalten: IndiModule ist der Treffpunkt zweier Welten.

  • Basemodule spricht mit dem Benutzer.
  • INDI::BaseClient spricht mit der Hardware.
  • IndiModule erbt nicht ein bisschen von jedem: es erbt wirklich von beiden gleichzeitig, und genau diese Position, direkt zwischen beiden, macht es zu dem Ort, an dem die eigentliche Intelligenz eines Devices geschrieben wird — ein Focuser, ein Sequencer, ein Polar Alignment sind nichts anderes als das: die Übersetzung einer Benutzeranfrage in einen Hardwarebefehl, und einer Hardwaremessung in eine Benutzerinformation.

Und das ist keine bloße Redewendung: ein IndiModule ist ein vollwertiger INDI-Client, genau wie Ekos oder jeder andere Client. Alle Methoden von INDI::BaseClient sind da, direkt nutzbar (connectServer(), watchDevice(), setBLOBMode()…) — ein Modul ist nie auf die reinen Helfer giveMeA*()/defineMeAsXxx() beschränkt, die weiter unten vorgestellt werden, diese sind nur eine Abkürzung für die häufigsten Fälle.

Die Funktionsweise des INDI-Clients selbst — Protokoll, Lebenszyklus von Device/Property, BLOBs — ist Sache der INDI-Entwicklerdokumentation, nicht dieser hier: hier geht es nur um das, was IndiModule darüber hinaus hinzufügt.

Zwei Callback-Schichten

IndiModule fängt selbst die rohen Callbacks von INDI::BaseClient ab (newDevice, newProperty, removeProperty, updateProperty), um seine eigene interne Buchhaltung zu führen (Aktualisierung der Werteliste der Devices, automatische Verbindung beim Start…), und ruft dann eine öffentliche, virtuelle Version auf, die dazu gedacht ist, vom konkreten Modul überschrieben zu werden:

newDevice()       (privé, IndiModule)  →  onNewDevice()       (virtuel, à surcharger)
newProperty()     (privé, IndiModule)  →  onNewProperty()     (virtuel, à surcharger)
removeProperty()  (privé, IndiModule)  →  onRemoveProperty()  (virtuel, à surcharger)

updateProperty() ist eine Ausnahme: es ist protected, nicht privat, genau damit ein Modul, das einen direkteren Zugriff braucht (Bildaufnahme, siehe weiter unten), es selbst überschreiben kann — vorausgesetzt, es ruft zuerst IndiModule::updateProperty(property) auf, sonst geht die automatische Aktualisierung von devices.* bei der Verbindung verloren.

onUpdateProperty() reicht in den allermeisten Fällen

onUpdateProperty() (öffentlich, virtuell) überschreiben statt updateProperty() (protected) direkt — das tun helloindi und helloindiwrite weiter unten. Nur ein Modul, das sehr früh in der Kette einen Property-Typ unterscheiden muss, wie eine Bildaufnahme (BLOB), hat einen Grund, updateProperty() selbst zu überschreiben.

Der Device-Picker: giveMeADevice()

giveMeADevice("device", "Device", INDI::BaseDevice::GENERAL_INTERFACE);

Fügt ein Auswahlelement in die Property devices hinzu (im Handumdrehen erzeugt), deren Werteliste nur die Devices anbietet, die tatsächlich auf dem INDI-Bus vorhanden sind und die angeforderte Schnittstelle (GENERAL_INTERFACE, TELESCOPE_INTERFACE, CCD_INTERFACE, FOCUSER_INTERFACE…) bereitstellen. Der im ersten Argument übergebene Name (hier "device") ist der Schlüssel des Elements in devices — getString("devices", "device") liefert das vom Benutzer gewählte Device.

Ein paar häufige Standard-INDI-Vektoren

Das INDI-Protokoll selbst bleibt außerhalb des Rahmens (siehe oben), aber ein paar Vektoren kommen in praktisch allen Modulen vor, die eine Kamera oder einen Focuser steuern — es lohnt sich, sie nicht jedes Mal neu zu entdecken:

BedarfVektorElementWie
Einen Focuser auf eine absolute Position bewegenABS_FOCUS_POSITIONFOCUS_ABSOLUTE_POSITIONsendModNewNumber(), um sich dorthin zu bewegen, onUpdateProperty() oder getModNumber(), um die aktuelle Position zu verfolgen
Eine Kamera neu zuschneidenCCD_FRAMEX/Y/WIDTH/HEIGHTframeSet(device, x, y, w, h) — IndiModule-Helfer, der rohe Vektor wird nicht benötigt
Den Frame einer Kamera zurücksetzenCCD_FRAME_RESET— (Switch)frameReset(device) — IndiModule-Helfer, ebenso
Eine laufende Belichtung abbrechenCCD_ABORT_EXPOSUREABORTsendModNewSwitch(device, "CCD_ABORT_EXPOSURE", "ABORT", ISS_ON)
abortfocus (defineMeAsFocuser) sendet standardmäßig nichts an das Device

Die von defineMeAsFocuser() gesetzte Aktion abortfocus (Die vorgefertigten Familien) stoppt die Sequenz auf OST-Seite — das Focus-Modul des Core befiehlt dem Device niemals FOCUS_ABORT_MOTION, es sendet einfach keine neue Position mehr. Zu prüfen, ob der verwendete Treiber einen expliziten Abort während der Bewegung benötigt.

Die fünf Beispiele

Jedes Beispiel fügt dem vorherigen genau ein Konzept hinzu: