Für das Erstellen von Windows-Anwendungen
ist Visual C++ eine der meistgenutzten Entwicklungsplattformen.
Mit dem folgenden C++ Programmbeispiel können Sie Ihr Web-IO Digital
mit seinen Inputs und Outputs in einer Windows-Anwendung abbilden. Darüber
hinaus können Sie die Outputs des Web-IO schalten.
Sie haben noch kein Web-IO und möchten das vorgestellte Beispiel
einfach mal ausprobieren?
Kein Problem: Wir stellen Ihnen das Web-IO Digital 2xInput, 2xOutput
gerne kostenlos für 30 Tage zu Verfügung. Einfach Musterbestellung
ausfüllen, wir liefern das Web-IO zum Test auf offene Rechnung.
Wenn Sie das Gerät innerhalb von 30 Tagen zurück schicken,
schreiben wir die Rechnung komplett gut.
mit einer IP-Adresse versehen - mit WuTility kein Problem
1. Zusammenstellen der verschiedenen Bedienelemente und Anzeigeobjekte
im Visual-C++-Form
2. Definition in der Header-Datei von MySocket und CWeb_IO_ClientDlg
Um die Eingaben in den Feldern IDC_IPTEXT, IDC_PORTTEXT, IDC_PASSWORDTEXT
und IDC_POLLINGTEXT in privaten Membervariablen der Klasse CWeb_IO_ClientDlg
zu speichern, werden in der Headerdatei einige Variablen definiert.
Um nicht für jede gesendete und empfangene Nachricht eine neue
Variable zu erzeugen, werden im Header dafür auch private Variablen
erzeugt. Der Eintrag in der Statusbar bekommt an dieser Stelle auch
eine Variable.
private: CString m_ip; CString m_message1; CString m_message2; CString m_rcv; CString m_password; int m_port; int m_range; public: CStatusBarCtrl*
m_statusBar;
Ebenfalls werden im Header einige benötigte Methoden vordeklariert.
Um nun auch eine Verbindung zu initialisieren, benötigen wir
noch eine Klasse, welche sich um das Senden und Empfangen von Daten
kümmert. Dazu wurde eine Datei namens MySocket erstellt, die von
der Klasse CAsyncSocket erbt. Somit werden alle öffentlichen Methoden
dieser Klasse an unsere Klasse vererbt und im Header nochmal deklariert.
Um auf die Methoden der Klasse CWeb_IO_ClientDlg später zugreifen
zu können, wird im Header ein Objekt deklariert.
Da die Klasse MySocket von der Klasse CAsyncSocket geerbt hat, werden
einige der benötigten Methoden für eine laufende Verbindung
überlagert. Somit kann die Appllikation später sowohl einwandfrei
Daten asynchron verschicken und empfangen, als auch auf die Terminierung
der Verbindung von Seiten des Web-IO reagieren.
Einrichten der Bedienelemente
Die Gruppe mit den Bedienelementen für das Web-IO wird zunächst
für die Bedienung gesperrt. Sobald eine Verbindung zu Stande kommt,
werden alle Elemente freigeschaltet, welche eine sinnvolle Ausführung
besitzen.
Um Meldungen in einer Statusleiste auszugeben, wird in dieser Methode
eine Statusbar erzeugt. Ausserdem wird die Klasse der MySocket-Klasse
übergeben, so dass beide miteinander verknüpft sind.
Um Variablen oder Methoden mit den Komponenten der Applikation zu verknüpfen,
kann man sich die Hilfe des Klassen-Assistenten von Visual C++ zu Nutze
machen, bzw ab Visual Studio 2003 die entsprechende Funktionalität
in den Klasseneigenschaften.
Einleiten der Verbindung
Durch Eingabe der IP-Adresse des Web-IO in das Textfeld IDC_IPTEXT und
dem Port 80 in das Textfeld IDC_PORTTEXT kann durch Betätigung
des Buttons IDC_CONNECT eine Verbindung aufgebaut werden. Falls keine
IP-Adresse oder kein Port eingetragen wird, erfolgt eine Meldung in
der Statusleiste
Verbindungsaufbau
Um nun eine TCP Verbindung aufbauen zu können, verwenden wir
in unserem Beispiel ein globales Objekt der Klasse MySocket, welches
Methoden wie Create(), Connect() und Close() zur Verfügung stellt.
Sollte ein negativer Port eingegeben worden sein
oder der Verbindungsaufbau fehlschlagen, so wird jeweils eine
Meldung ausgegeben.
Da die Verbindung nicht aufgebaut werden konnte, wird der Socket
auch wieder geschlossen, so dass eine neue Verbindung problemlos
erneut gestartet werden kann.
Ist alles gut gegangen werden alle Komponenten freigeschaltet,
welche nach erfolgreichem Aufbau genutzt werden können,
und der IDC_CONNECT Button wird gesperrt, um einen erneuten
Verbindungsaufbau bei bestehender Verbindung zu vermeiden.
Verbindung kommt zustande
Ist die Verbindung zustande gekommen, kann die Applikation mit dem
Web-IO eine Kommunikation durchführen, für welche die verschiedenen
Komponenten genutzt werden können.
Trennen der Verbindung
Die Verbindung bleibt solange bestehen, bis sie vom Benutzer durch
Klick auf den Disconnect-Button oder durch das Web-IO beendet wird.
Wird die Verbindung beendet, so wird eine Meldung ausgegeben.
Wenn die Verbindung abgebaut wird, müssen alle Elemente wieder
in ihre Ausgangsstellung transformiert werden, denn es soll dann nicht
mehr möglich sein, auf den IDC_DISCONNECT Button klicken zu können.
Nun ist die Verbindung wieder beendet und die Applikation
auf ihren Ausgangszustand zurückgesetzt.
6. Bedienung und Kommunikation von Client-Seite
Sobald eine Verbindung mit dem Web-IO zustande gekommen ist, kann
der Anwender durch Bedienung der entsprechenden Programmelemente Kommandos
an das Web-IO senden.
Setzen der Outputs
Die Outputs des Web-IO können mit Hilfe der beiden Checkboxen
IDC_OUTPUT0 und IDC_OUTPUT1 geschaltet werden. Die Checkbox vermerkt,
wenn sie angeklickt wird und löst daraufhin eine Aktion aus.
Um eine Anfrage an das Web-IO schicken zu können wird als erstes
geprüft, ob im Textfeld IDC_PASSWORDTEXT ein Passwort eingetragen
worden ist, ohne welches das Web-IO keine Anfragen annehmen würde.
Falls kein Passwort angegeben wurde, wird die Anfrage ohne Passwort
abgeschickt.
Im nächsten Schritt wird geprüft ob die
Checkbox bereits gesetzt ist oder nicht, wobei daraufhin jeweils der
Output entweder wieder zurückgesetzt oder gesetzt wird.
Output/Input-Status abfragen
Nun kann der Zustand der Outputs und Inputs auch überprüft
werden, um jeweils die Kontrollkästchen in der Applikation zu
aktualisieren. Der IDC_READALL0 Button liest den Zustand der Outputs
und der IDC_READALL1 Button liest den Zustand der Inputs. Der Befehl
zur Statusabfrage lautet ein wenig anders als der zum Setzen. Also
kann man mit "GET /output?PW=&" den Status der Outputs
abfragen.
Counter abfragen
Da eintreffende Input Ereignisse nur im Web-IO selbst vermerkt werden
und somit der innere Zähler hochgezählt wird, sollte dieser
auch abgefragt werden können. Die folgende Methode sendet eine
Anfrage an einen bestimmten Counter und fordert eine Antwort mit dem
aktuellen Stand des Zählers. Aus der Antwort des Web-IO wird
die Nummer des jeweiligen Counters und dessen Zählstand entnommen
und in der Applikation angezeigt.
Counter zurücksetzen
Da man den Zählstand ja lesen kann, sollte es auch möglich
sein den Zähler auf 0 zu setzen. Dafür wird eine Nachricht
an den jeweiligen Counter geschickt, welche diesen zurücksetzt.
Da alle Counterzustände mit einem Kommando gelesen
oder zurückgesetzt werden können, muss noch eine Methode
implementiert werden, welche den Antwortstring des Web-IO bearbeitet
und jedem Counter in der Applikation seinen spezifischen Zustand zuordnet.
void CWeb_IO_ClientDlg::readAndClearCounter(CString data)
{ int j = 0; CString counter[12];
for(int i = 0; i < data.GetLength(); i++) { if(data[i]
== ';') j++; else counter[j]
+= data[i]; }
Alle Kommandos und Anfragen an das Web-IO werden mit einem Antwort-String
quittiert. Dabei haben die Antworten je nach Type einen spezifischen
Aufbau.
Man unterscheidet die Antwort von einem einzelnen Output bzw. Input
und der aller Outputs und Inputs.
Für die Outputs: output;<Binärwert des Outputstatus im
hexadezimalen Format>
Für einen speziellen Output: outputx;<ON oder OFF>
Für die Inputs: input;<Binärwert des Outputstatus im hexadezimalen
Format>
Für einen speziellen Input: inputx;<ON oder OFF>
Dann gibt es noch den Antwortstring für einen Counter der folgendermassen
aussieht:.
counterx;<dezimaler Zählerstand>
oder counter;<dezimaler Zählerstand 0 >; <dezimaler Zählerstand
1 >; ... wenn alle Counter auf einmal gelesen werden sollen.
Alle Antwort-Strings sind mit einem 0-Byte abgeschlossen.
In unserer Applikation wird zum Empfang einer solchen Nachricht die
Methode OnReceive() aufgerufen. In dieser Methode wird die Antwort des
Web-IO verarbeitet.
Zyklisches Abfragen bestimmter Werte
Nun ist es wünschenwert, dass sich der Status einer einzelnen Komponenten
von selbst aktualisiert und somit die Applikation immer den aktuellen
Stand aufweist. Dazu wird in diesem Progamm ein Timer verwendet, welcher
in einem vom User bestimmten Zeitintervall zyklisch Abfragen an das
Web-IO schickt.
Dazu kann als erstes ein Integer-Wert in dem Feld IDC_POLLINGTEXT eingegeben
werden, der die Zeit in Millisekunden für die zyklische Abfrage
definiert. Falls kein Wert eingetragen wird, ist die Zeit für das
Intervall standardmässig auf 1 Sekunde gesetzt (1000 ms).
Natürlich wird auch der Fall abgefangen, dass der Nutzer eine unsinnige
Angabe macht, wie z.B. einen negativer Zeitwert. Darauf folgt sofort
eine Meldung und der Wert wird natürlich nicht übernommen.
void CWeb_IO_ClientDlg::OnChangePollingtext()
{ GetDlgItemText(IDC_POLLINGTEXT, m_message2); int check;
sscanf(m_message2, "%d", &check); if(check <= 0)
{
m_statusBar->SetText("No negative
value or character allowed!", 0, 0); return;
} m_range = check; m_statusBar->SetText("Range
changed!", 0, 0);
}
Um nun auch das zyklische Abfragen der Zustände
des Web-IO durchzuführen, was auch als Polling bezeichnet wird,
besteht die Auswahlmöglichkeit zwischen dem Polling der Outputs,
der Inputs oder der Counter.
Je Polling-Variante wird ein eigener Timer initialisiert. Der Timeraufruf
lautet dann jeweils "SetTimer(Nummer des Timers, Intervall, NULL)".
Betätigt man die Checkbox IDC_POLLING0 so wird das Polling auf
die Outputs angewendet. Dabei wird ein Timer initialisiert, wenn sie
gesetzt wird. Wird die Checkbox wieder zurückgesetzt, so wird
der Timer mit der entsprechenden Nummer auch wieder zerstört.
Beim Betätigen der Checkbox IDC_POLLING1 wird
das Polling auf die Inputs angewendet. Dabei wird auch ein neuer Timer
initialisiert, der dann von dieser Methode auch wieder zerstört
werden kann.
Nun wurden drei verschiedene Timer initialisiert,
welche laut dem Intervall in bestimmten Zeitabschnitten eine Aktion
auslösen, die bisher allerdings nicht gefangen wird. Um nämlich
die Events zu fangen muss noch eine Methode implementiert werden.
In dieser Methode wird das jeweilige Event des Timers, der sich gerade
meldet, gefangen und einer bestimmten Aktion zu gewiesen.
Zur Erinnerung: In unserem Fall werden die Zustände der Outputs,
der Inputs und der Counter je nach Event zyklisch abgefragt.
Das gesamte Programm wird auf dieser Seite zur Verfügung
gestellt, wobei es einige hier nicht erwähnte Dateien und Methoden
zusätzlich enthält. Die MFC Anwendung unter Visual C++ erzeugt
einen Overhead, der den graphischen Rahmen bildet, aber mit der Funktionalität
nicht direkt in Verbindung steht. Die Methoden und Variablen die Ihnen
auf dieser Seite präsentiert worden sind, werden in den von Visual
C++ erzeugten Rahmen implementiert und arbeiten dann als Einheit mit
der graphischen Oberfläche.
Das Beispiel Programm unterstützt alle gängigen Funktionen des Web-IO im Kommando-String
Modus, optimiert für das Web-IO
2x Digital Input, 2x Digital Output PoE. Für die anderen Web-IO Modelle
müssen ggf. Anpassung am Programm vorgenommen werden. Weitere Programmbeispiele
zur Socket-Programmierung finden Sie auf den Tool-Seiten zum Web-IO. Eine detaillierte Beschreibung zur Socketschnittstelle der
Web-IO Digital Modelle finden Sie im Referenzhandbuch.