YASDI 'C'-Tutorial

Hier folgt ein kleines simples C-Tutorial, das zeigt, wie leicht man mit YASDI einen SMA-Wechselrichter (oder auch SunnyBoyControl, Baudrate hierzu beachten) abfragen kann. Voraussetzung ist, dass YASDI korrekt compiliert worden ist (die Binaer-Version kann natuerlich auch verwendet werden) und die H-Datei der Bibliothek verfuegbar ist. Naeheres beim Tutorial "YASDI compilieren" (bald).

Auf die Fehlerueberpruefung wird im folgenden weitgehen verzichtet, um das Beispiel uebersichtlich zu gestalten. Die meisten Funktionen bieten durch den Rueckgabewert die Moeglichkeit (und Notwendigkeit) zur Fehlerueberpruefung der Kommunikation. Diese ist in einer eigenen Applikation unbedingt vorzusehen...

Auf geht's:

Als Erstes wird die H-Datei der Master-Library eingebunden:
#include "libyasdimaster.h"

Die Datei befindet sich im YASDI-Unterverzeichnis "libs". Zusaetzlich benoetigt man noch Zugriff auf die Verzeichnisse "smalib" und "include". Man fuegt diese am Besten als Include-Pfad dem Compiler hinzu. Jetzt die Main-Funktion erzeugen und ein paar lokale Variablen, die wir noch gleich brauchen werden:

int main(void)
{
   int i;
   DWORD channelHandle=0;  /* channel handle             */
   DWORD SerNr=0;          /* Serial number of 1. Device */ 
   DWORD DeviceHandle[10]; /* place for 10 device ID's   */
   int ires=0;             /* result code                */
   DWORD dwBDC=0;          /* BusDriverCount             */
   double value;           /* Channel value              */
   char valuetext[17];     /* channel text value         */

Den YASDI-Master nun initialisieren mit:

   
   yasdiMasterInitialize("./yasdi.ini",&dwBDC);

Die Variable 'dwBDC' nimmt die Anzahl der verfuegbaren BusDriver auf (Anzahl der Schnittstellen, z.B. COM1, COM2 ....), die in YASDI zur Zeit konfiguriert wurden. Wir gehen mal davon aus, dass wir nur mit COM1 mit dem SunnyBoy sprechen wollen, also nur einen "BusDriver" haben. Der 1. Parameter der Funktion gibt den Pfad zur Konfigurationsdatei von YASDI an. Hier wird auf ein INI-File verwiesen. Ein Beispiel einer YASDI-INI-Datei. Fuer Embedded-Systeme gibt es die Moeglichkeit, die Konfiguration direkt im Code abzulegen (also keine INI-Datei, sondern eine platzsparende Struktur), so dass man in diesem Fall einfach einen Leerstring uebergeben wuerde... Der 2. Parameter ist ein Verweis auf eine Variable "dwBDC", die die Anzahl der zur Verfuegung stehenden "BusDriver" nach dem Funktionsausfruf enthaelt.

   yasdiMasterSetDriverOnline( 0 );

setzt den 1. BusDriver Online, d.h. ueber den BusDriver ann mit den Geraeten nun gesprochen werden. Alle YASDI-BusDriver besitzen ID's, die ab "0" beginnen. Fuer alle BusDriver, die fuer die Kommunikation verwendet werden sollen, muss die Funktion mit der entsprechenden ID aufgerufen werden.

   ires = yasdiDoMasterCmdEx("detection", 1, 0, 0);

Leitet nun eine Geraeterfassung ein. Der 1. Parameter muss hierzu die Zeichenkette "detection" enthalten.
Parameter 2 gibt die Anzahl der zu suchenden Geraete an. Dies ist die Mindestzahl von Geraeten. Falls sich mehr melden, werden diese ebenfalls erfasst.
Parameter 3 und 4 sind zur Zeit unbenutzt.
Die Funktion ist synchron, d.h. sie blockiert solange, bis die Geraete gefunden wurden oder falls nicht, bricht nach einer gewissen Zeit selbst ab. Der Rueckgabewert (jetzt in "ires") gibt den Status an. Bei "0" konnten alle Geraete erfasst werden. Bei Negativwerten ist ein Fehler aufgetreten. Der Negativwert entscheidet die Art des Fehlers (siehe API Referenz)...

   ires = GetDeviceHandles(DeviceHandle, 10 );

Die Funktion liefert alle gefundenen Geraete und kopiert die Geraete als ID's in das angegebene C-Array. Der 2. Parameter besagt, dass nicht mehr als 10 Handles in das Array kopiert werden sollen (wenn mehrere Geraete gesucht werden sollen). Wir gehen jetzt davon aus, es wuerde sich genau ein Geraet melden. Die Funktion liefert immer die Anzahl der benutzen Plaetze im Array zurueck, hier also den Wert "1".


Nun geben wir einfach mal die Seriennummer des Geraetes aus. Das geht so:
   ires = GetDeviceSN( DeviceHandle[0], &SerNr )
   printf("Serial Number: %ld\n", SerNr );

Der erste Parameter ist die Geraete ID. Parameter 2 ist ein Zeiger auf ein DWORD zur Aufnahme der Seriennummer.

Nun moechten wir mal den Kanalwert des Kanals "Pac" (aktuelle AC Leistung) lesen. Das macht man einfach so:
   channelHandle = FindChannelName(DeviceHandle[0], "Pac");
Liefert eine Referenz auf den Kanal ("KanalID" oder auch "Channel-Handle") falls gefunden oder "0" falls es den Kanal nicht gibt. Der 1. Parameter ist das Handle des Geraetes, von dem der Kanal gesucht werden soll. Wir haben nun eine gueltige ID auf den Kanal. Nun moechten wir den eigentlichen Kanalwert abfragen. Das geht nun so:
   ires = GetChannelValue(channelHandle,    /* chan. handle */
                          DeviceHandle[0],  /* dev. handle  */
                          &value,           /* value        */ 
                          valuetext,        /* txt value    */           
                          16,               /* text value size */  
                          5 );              /* value age    */ 
   printf("Current Value is %lf\n", value);                                

Parameter 1 ist das Kanalhandle, 2. Parameter das Geraetehandle, 3. Parameter ist ein Pointer auf einen "double" Variable, der nach Ruecksprung der Funktion den Kanalwert numerisch beinhaltet. "Valuetext" nimmt ggf. den textuellen Kanalwert z.B. bei Statustextkanaelen auf (ist optional). Die "16"gibt die Textpuffergroesse an, die YASDI hierzu beschreiben darf. Der letzte Parameter gibt das Maximal-Alter des Kanalwertes in Sekunden an (5 Sekunden ist ein guter Wert). Falls YASDI einen neueren Wert zwischengespeichert hat, als angegeben, wird YASDI diesen Messwert zurueckgeliefern. Dieser ist sehr schnell verfuegbar, da das Gereat nicht erneut gefragt werden muss. Falls der interne Wert in YASDI zu alt ist, wird das entsprechende Geraet hierzu befragt. Dies kann ggf. mehrere Sekunden dauern. Die Funktion blockiert bis zum Ergebnis (synchron). Timeouts werden ggf. in der Resultatsvariable "ires" zurueckgeliefert. Eine "0" bedeutet hier wieder ok.

Am Ende des Programmes muss YASDI dann wieder deinitialisiert werden und gibt damit alle seine belegten Ressourcen wieder frei:
   yasdiMasterShutdown();
   
   return (0);
} /* main */

Dies braucht nur einmal am Ende durchgefuehrt zu werden, kurz bevor man die eigene Applikation beendet wird (falls ueberhaupt). In der Zwischenzeit koennen weitere Kanalwertabfragen oder Geraeteerfassungen durchgefuehrt werden...