Auf das Device einwirken
Beispielmodul: helloindiactions.
In Properties dynamisch erzeugen änderte der Aktions-Button den internen Zustand des Moduls (hellodyn). Hier ändert die Aktion tatsächlich etwas auf dem Device — das Device selbst speichert es dauerhaft, nicht das Modul.
HelloIndiActions::HelloIndiActions(...)
: IndiModule(...)
{
giveMeADevice("device", "Device", INDI::BaseDevice::GENERAL_INTERFACE);
giveMeAnActions();
OST::ElementBool *saveconfig = new OST::ElementBool("saveconfig", "Save device config", "1", "");
saveconfig->setDirectEdit(true);
getProperty("actions")->addElt(saveconfig);
}giveMeAnActions() baut die Property actions (zu Beginn leer); addElt() fügt ihr das Element saveconfig hinzu, in C++, wie in Properties dynamisch erzeugen — dieses Kapitel ändert nichts an der Art, eine Property aufzubauen, nur an dem, was passiert, wenn sie ausgelöst wird.
void HelloIndiActions::onExternalEvent(OST::ExtEvent event)
{
if (event.ev != OST::ExtEvType::SV || event.prpkey != "actions" || event.eltkey != "saveconfig") return;
sendModNewSwitch(getString("devices", "device"), "CONFIG_PROCESS", "CONFIG_SAVE", ISS_ON);
getEltBool("actions", "saveconfig")->setValue(false, true);
}CONFIG_PROCESS/CONFIG_SAVE ist ein INDI-Standardswitch, auf jedem Treiber vorhanden (die aktuelle Konfiguration speichern) — das macht dieses Beispiel gegen jedes beliebige verbundene Device testbar, ohne von einer Funktion abhängig zu sein, die nur einem bestimmten Simulator eigen ist.
Diese Helfer schreiben jeweils nur ein einziges Element: sie holen die Property so, wie sie derzeit auf Client-Seite bekannt ist, ändern den Wert des betroffenen Elements und senden dann den vollständigen Vektor zurück — die anderen Elemente gehen mit ihrem zuletzt bekannten Wert mit, nicht notwendigerweise 0, nicht notwendigerweise dem, was der Treiber erwartet.
Konkretes Beispiel: einen Guiding-Impuls an eine Montierung senden. TELESCOPE_TIMED_GUIDE_NS hat zwei Elemente, TIMED_GUIDE_N und TIMED_GUIDE_S — man pulst immer nur in eine Richtung zur selben Zeit, daher erwartet der Treiber, bei jedem Senden beide Werte zu erhalten, wobei einer von ihnen explizit 0 sein muss. Schreibt man nur TIMED_GUIDE_N über sendModNewNumber(), geht TIMED_GUIDE_S mit seinem zuletzt bekannten Wert mit — potenziell ungleich null, was der Treiber einfach ignorieren oder falsch interpretieren kann.
In solchen Fällen ist es besser, direkt auf die Ebene von INDI::BaseClient herabzusteigen (siehe die Übersicht: ein IndiModule ist ein echter INDI-Client): den vollständigen INDI::PropertyNumber selbst aufbauen, jedes Element explizit festlegen und dann direkt sendNewNumber() aufrufen — statt einem Helfer zu vertrauen, der für den einfachen Fall einer Property mit nur einem relevanten Element gedacht ist.