1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
|
\section{Implementierung}
\label{sec:demo}
Anhand der in Kapitel \ref{sec:demoapp} vorgestellten Machbarkeitsstudie wird gezeigt, welche Schritte n\"otig sind, um eine bidirektionale Kommunikation zwischen einer in Mono entwickelten GTK\#\ Anwendung und einer Real-time CORBA Applikation aufzubauen.
Des weiteren wird die Klasse \emph{CPX} vorgestellt, welche in allen Versuchen zum Zugriff auf die digitalen Ein- und Ausgabeports verwendet wurde.
Es wird gezeigt, wie in ACE/TAO mittels MakeProjectGenerator Projekte verwaltet werden.
\subsection{Zugriff auf die digitalen Ein- und Ausg\"ange der CPX}
Es wurde eine Klasse implementiert, welche den Zugriff auf die digitalen Ein- und Ausg\"ange der CPX erleichtert. Bei Instanzierung der Klasse, wird ein Memory Mapping des Speicherbereichs der digitalen Ein- und Ausg\"ange auf Membervariablen durchgef\"uhrt und der Interrupt bei \"Anderungen an einem digitalen Eingang auf ein Signal gemapped.
Eine setMethode besitzt als Parameter Wert und Port. Es wird der \"ubergebene Wert auf den entsprechenden Port geschrieben. Der getMethode wird als Parameter der Port mitgeteilt, welcher ausgelesen werden soll. Der aktuelle Wert des Portes wird von der Methode zur\"uckgeliefert.
\begin{figure}
\begin{center}
\includegraphics[width=0.3\textwidth]{./img/cpx_classdia.jpg}
\caption{UML Klassendiagramm: Zugriff auf digitale E/A Ports einer CPX}
\end{center}
\hrule
\end{figure}
\newpage
\subsection{Projektverwaltung mit MakeProjectCreator}
Zur Projektverwaltung wird in ACE/TAO der MakeProjectCreator (mpc) verwendet. Dieser ist in der ACE/TAO Distribution mit enthalten, denn das ACE/TAO Framework selbst verwendet den mpc zur Verwaltung der Quellen.
In einer .mpc-Datei wird die Struktur eines Projektes definiert:
\lstinputlisting{./cdrom/quellcode/versuch3/benchmark.mpc}
\begin{description}
\item[Zeile 1 und 13] In Klammer: Name des Projektes, hinter Doppelpunkt: Projekte von denen dieses Projekt abh\"angig ist (z.B. rt\_ server aus dem ACE/TAO Framework)
\item[Zeile 2 und 14] zus\"atzlich ben\"otigte Features
\item[Zeile 4 - 6 und 16 - 18] ben\"otigte Quelldateien, Reihenfolge definiert Abh\"angigkeiten
\item[Zeile 9 und 21] zus\"atzlich ben\"otigte header Files
\end{description}
Mit dem Befehl:
\begin{lstlisting}
mpc.pl -type gnuace bench.mpc
\end{lstlisting}
werden aus der mpc-Datei GNUMakefiles generiert. Durch eine andere Parametrisierung k\"onnten auch andere, zum Beispiel Visual Studio, Projekte erstellt werden.
Mit den Befehlen:
\begin{lstlisting}
make -f GNUMakefile.Benchmark_Receiver
make -f GNUMakefile.Benchmark_Supplier
\end{lstlisting}
werden die ausf\"uhrbaren Dateien erstellt.
\subsection{Kommunikation zwischen C\# und C++ mittels IIOP.NET und CORBA}
\label{sec:impldemo1}
\begin{figure}
\includegraphics[width=\textwidth]{./img/demo1.jpg}
\caption{UML Klassendiagramm: C\#\ - C++ Demoapplikation}
\label{img:demo1uml}
\end{figure}
Es wird auf die Implementierung, Codierung und den Start der in Kapitel \ref{sec:demoapp} beschriebenen Anwendung eingegangen. Als Hilfe beim Erstellen dieser Anleitung diente \cite{egiiop}
Die drei Applikationen Controller, Executor und Receiver wurden nach Abbildung \ref{img:demo1uml} entwickelt.
Beschreibung der einzelnen Programme und den zugeh\"origen Klassen:
\begin{description}
\item[Controller] C\# Applikation mit GTK\# Oberfl\"ache zur Bedienung, der Benutzer kann das Versenden eines Kommandos an den Executor veranlassen
\begin{description}
\item[Main] instanziert MainWindow
\item[MainWindow] instanziert CorbaHandler; implementiert die Funktionalit\"at der grafischen Oberfl\"ache
\item[CorbaHandler] hostet ein CORBA Objekt mit einer Methode zur Darstellung eines Strings auf der grafischen Oberfl\"ache; baut die Verbindung zum ExecCmd Interface des Executors auf; bedient das ExecCmd Interface
\item[Disp] implementiert das Display Interface
\end{description}
\item[Executor] C++ Applikation, empf\"angt Kommandos der grafischen Oberfl\"ache, kreiert und sendet entsprechende Prozessabbilder via RTCORBA an den Receiver
\begin{description}
\item[Executor] instanziert ORB und ExecCmd\_ i; bindet ExecCmd\_ i Objekt an ORB, registriert es bei einem Naming\_ Service
\item[ExecCmd\_ i] stellt Verbindung zum Display Interface des Controllers her und bedient es; stellt Verbindung zum Put Interface des Receivers her und sendet die generierten Prozessabbilde in Echtzeit an dieses Interface
\end{description}
\item[Receiver] C++ Applikation, empf\"angt Prozessabbilder des Executors und setzt entsprechend den digitalen Ausgang.
\begin{description}
\item[Receiver] instanziert ORB und Put\_ i; bindet Put\_ i Objekt an ORB, registriert es bei einem Naming\_ Service
\item[Put\_ i] instanziert CPX; stellt Funktionen zum Setzen des digitalen Ausgangs zur Verf\"ugung
\item[CPX] erm\"oglicht mit Memory Mapping und set- und get-Funktionen einen komfortablen Zugriff auf die digitalen Ein- und Ausg\"ange der CPX
\end{description}
\end{description}
\subsubsection{Codierung}
\begin{enumerate}
\item Ordnerstruktur anlegen:
\begin{lstlisting}
mkdir demo1
cd demo1
mkdir Executor
mkdir Receiver
\end{lstlisting}
\item Receiver erstellen
\begin{lstlisting}
cd Receiver
\end{lstlisting}
\begin{enumerate}
\item Das Interface Put wird in der Datei Receiver.idl definiert. Es besitzt Funktionen zum Verbindungsaufbau, Setzen aller digitalen Ausg\"ange und Setzen eines einzelnen digitalen Ausgangs:
\lstinputlisting{./cdrom/quellcode/demo1/Receiver/Receiver.idl}
\item Interface in C++ Code \"ubersetzen (Stub, Skeleton, Implementation und ServerTemplate). Da die Implementation editiert wird, empfiehlt es sich diese Datei umzubennen, damit bei einem erneuten IDL-Compiler Aufruf die \"Anderungen nicht verloren gehen.
\begin{lstlisting}
tao_idl -GI Receiver.idl
mv ReceiverI.cpp Receiver_ i.cpp
mv ReceiverI.h Receiver_ i.h
\end{lstlisting}
\item Die Dateien Receiver\_ i.cpp und Receiver\_ i.h repr\"asentieren das Objekt, welches vom Receiver zur Verf\"ugung gestellt wird. Es m\"ussen folgende Schritte durchgef\"uhrt werden:
\begin{enumerate}
\item Receiver\_ i.cpp: Include anpassen (ReceiverI.h in Receiver\_ i.h)
\item Receiver\_ i.h: cpx.h inkludieren, private member cpx von Typ CPX* anlegen
\item Receiver\_ i.cpp: im Konstruktor der Membervariable cpx eine neue Instanz von CPX zuweisen
\item Receiver\_ i.cpp: im Destruktor Speicher der Membervariable cpx wieder freigeben
\item Receiver\_ i.cpp: Code zum Port Setzen in Funktionen an der Stelle (\emph{\\your implementation here}) erg\"anzen
\end{enumerate}
\item MakeProjectCreator Projektbeschreibung Receiver.mpc anlegen:
\lstinputlisting{./cdrom/quellcode/demo1/Receiver/Receiver.mpc}
\item GNUMakefiles erzeugen:
\begin{lstlisting}
mpc.pl -type gnuace Receiver.mpc
\end{lstlisting}
\item Receiver bauen:
\begin{lstlisting}
make -f GNUMakefile.Receiver
\end{lstlisting}
\end{enumerate}
\item Controller anlegen
\begin{enumerate}
\item monodevelop starten
\item In Ordner \emph{demo1} ein neues GTK\#\ 2.0 Project \emph{Controller} anlegen. Da die Solution nur ein Projekt beinhalten wird, kein Unterverzeichnis f\"ur die Solution anlegen.
\item Die automatisch generierte Datei MainWindow.cs in der Designer Ansicht \"offnen
\item Eine grafische Oberfl\"ache mit den Komponenten und Bezeichnungen wie in Abbildung \ref{img:demo1GUIDesign} dargestellt erstellen
\begin{figure}[!thbp]
\includegraphics[width=0.8\textwidth]{./img/demo1GUI.jpg}
\caption{Bedienoberfl\"ache}
\label{img:demo1GUIDesign}
\hrulefill
\end{figure}
\item Signale einrichten: entryHost - Changed, buttonConnect - Clicked, buttonSubmit - Clicked, comboBoxMode - Changed
\item Der comboBoxMode folgende Items hinzuf\"ugen: Blink, Move, Flash
\item In MainWindow.cs die Funktionalit\"at der Bedienoberfl\"ache implementieren:
\lstinputlisting{./cdrom/quellcode/demo1/Controller/MainWindow.cs}
\item Display Interface erstellen (Controller.idl):
\lstinputlisting{./cdrom/quellcode/demo1/Controller/Controller.idl}
\item Aus dem Interface eine dll erstellen, welche die Interfacefunktionalit\"aten in IIOP.NET zur Verf\"ugung stellt
\begin{lstlisting}
mono /opt/iiop.net/IDLToCLSCompiler/IDLCompiler/bin/IDLToCLSCompiler.exe Display Controller.idl
\end{lstlisting}
\item Aus dem Interface C++ Code erstellen (Stub, Skeleton, ServerTemplates)
\begin{lstlisting}
tao_idl Controller.idl
\end{lstlisting}
\item Display.dll und /opt/iiop.net/IIOPChannel/bin/IIOPChannel.dll mit Rechtsklick auf References, Edit References, .NET Assembly zum Projekt hinzuf\"ugen
\end{enumerate}
\item Executor implementieren
\begin{lstlisting}
cd ../Executor
\end{lstlisting}
\begin{enumerate}
\item Interface ExecCmd in der Datei Executor.idl definieren. Die Funktion changeMode dient zum Wechseln des Modus (blink - 1, move - 2, flash - 3). Die Funktion setPorts setzt die Ausgansports der verbundenen CPX (wird momentan nicht verwendet, f\"ur Erweiterungen gedacht).
\lstinputlisting{./cdrom/quellcode/demo1/Executor/Executor.idl}
\item C++ Code aus dem Interface generieren (Stub, Skeleton, ServerTemplates und Implementation)
\begin{lstlisting}
tao_idl -GI Executor.idl
mv ExecutorI.h Executor_i.h
mv ExecutorI.cpp Executor_i.cpp
\end{lstlisting}
\item Include in Executor\_ i.cpp anpassen
\item Folgende Includes in Executor\_ i.h hinzuf\"ugen
\begin{lstlisting}
#include "../Controller/ControllerC.h"
#include "../Receiver/ReceiverC.h"
\end{lstlisting}
\item Die in Executor\_ i.h definierte Klasse Executor\_ ExecCmd\_ i um folgende privaten Membervariablen erweitern:
\begin{lstlisting}
Receiver::Put_var put;
Controller::Display_var display;
\end{lstlisting}
\item In Executor\_ i.cpp folgende Includes hinzuf\"ugen
\begin{lstlisting}
#include "orbsvcs/CosNamingC.h"
#include <TAO/RTCORBA/RTCORBA.h>
#include <iostream>
\end{lstlisting}
\item Der Klasse Executor\_ ExecCmd\_ i einen weiteren Konstruktor hinzuf\"ugen:
\begin{lstlisting}
Executor_ExecCmd_i (int argc, char* argv[], CORBA::ORB_var orb);
\end{lstlisting}
\item Im soeben hinzugef\"ugten Konstruktor Referenzen auf Display und Receiver Objekte vom NamingService abrufen und in entsprechenden Membervariablen speichern:
\begin{lstlisting}
try{
// get RTORB
CORBA::Object_var rtorb = orb->resolve_initial_references("RTORB");
RTCORBA::RTORB_var rtORB = RTCORBA::RTORB::_narrow(rtorb.in());
// NameService
CORBA::Object_var namingObject = orb->resolve_initial_references("NameService");
CosNaming::NamingContext_var namingContext = CosNaming::NamingContext::_narrow(namingObject.in());
CosNaming::Name name(1);
name.length(1);
// Connect to Receiver
name[0].id = CORBA::string_dup("Receiver");
CORBA::Object_var benchObj = namingContext->resolve(name);
put = benchmark::Put::_narrow(benchObj.in());
// Connect to Display
name.length(2);
name[0].id = CORBA::string_dup("manut.Controller");
name[1].id = CORBA::string_dup("Disp");
benchObj = namingContext->resolve(name);
display = Controller::Display::_narrow(benchObj.in());
display->show("ready!!!");
// Signal for ready2use
put->connect();
put->allPorts(0, 0, 0);
sleep(1);
put->onePort(1, 255);
sleep(1);
put->allPorts(0, 0, 0);
display->show("ready2use");
}catch(CORBA::Exception &e){
std::cerr<<e<<std::endl;
}
\end{lstlisting}
\item Die changeMode Funktion implementieren
\begin{lstlisting}
switch(mode){
case 1:
display->show("moving...");
std::cout<<"move"<<std::endl;
for(int i = 0; i<255; i++) put->allPorts(i,i,i);
break;
case 2:
display->show("blinking...");
std::cout<<"blink"<<std::endl;
for(int i = 0; i<255; i++) {
if (i%2) put->allPorts(255,255,255);
else put->allPorts(0,0,0);
}
break;
case 3:
display->show("flashing...");
std::cout<<"flash"<<std::endl;
for(int i = 0; i<255; i++){
if (i%3)put->allPorts(255,255,255);
else put->allPorts(0,0,0);
}
break;
default:
std::cerr<<"Mode not implemented"<<std::endl;
return false;
}
return true;
\end{lstlisting}
\item setPorts Methode implementieren:
\begin{lstlisting}
put->allPorts(one, two, three);
return true;
\end{lstlisting}
\item CORBA Server, welcher das ExecCmd Objekt hostet, in Executor.cpp implementieren:
\lstinputlisting{./cdrom/quellcode/demo1/Executor/Executor.cpp}
\item MakeProjectCreator Datei f\"ur den Executor erstellen:
\lstinputlisting{./cdrom/quellcode/demo1/Executor/Executor.mpc}
\item GNUMakefile erstellen und Executor bauen:
\begin{lstlisting}
mpc.pl -type gnuace Executor.mpc
make -f GNUMakefile.Executor
\end{lstlisting}
\end{enumerate}
\item C\# CorbaHandler implementieren
\begin{lstlisting}
cd ../Controller
\end{lstlisting}
\begin{enumerate}
\item Executor.dll aus Executor.idl erstellen:
\begin{lstlisting}
mono /opt/iiop.net/IDLToCLSCompiler/IDLCompiler/bin/IDLToCLSCompiler Executor ../Executor/Executor.idl
\end{lstlisting}
\item In monodevelop Rechtsklick auf \emph{References}, \emph{add References}, \emph{.Net Assembly}, Executor.dll ausw\"ahlen und mit \emph{add} zur Solution hinzuf\"ugen
\item Display Interface in der Datei Display.cs in die Klasse Disp implementieren. Die Funktion show stellt den \"ubergebenen String auf der grafischen Bedienoberfl\"ache dar:
\lstinputlisting{./cdrom/quellcode/demo1/Controller/Display.cs}
\item CorbaHandler.cs besitzt Funktionen zum Hosten des Display Objekts und zum Connecten zum ExecCmd Interface des Executors:
\lstinputlisting{./cdrom/quellcode/demo1/Controller/CorbaHandler.cs}
\item in monodevelop mit \emph{F8} Controller Solution \"ubersetzen
\end{enumerate}
\end{enumerate}
\subsubsection{Start der verteilten Anwendung}
Auf einer beliebigen CPX den NamingService starten:
\begin{lstlisting}
$TAO_ROOT/orbsvcs/Naming_Service/Naming_Service -ORBEndpoint iiop://<IP-dieser-CPX>:2809
\end{lstlisting}
Auf CPX 1 Receiver starten:
\begin{lstlisting}
./Receiver -ORBInitRef NameService=corbaloc:iiop:<IP-des-NamingServices>:2809/NameService
\end{lstlisting}
Auf CPX 2 Controller starten:
\begin{lstlisting}
mono Controller.exe
\end{lstlisting}
Nun wird in der grafischen Oberfl\"ache im Feld Host die IP der CPX mit dem NamingService eingetragen und auf Connect geklickt. Wird auf Connect geklickt, ohne dass eine IP-Adresse eingegeben wurde, so wird der NamingService an der eincodierten IP-Adresse gesucht.
Auf CPX 3 Executor starten:
\begin{lstlisting}
./Executor -ORBInitRef NameService=corbaloc:iiop:<IP-des-NamingServices>:2809/NameService
\end{lstlisting}
Dieser connected automatisch zum Display Interface des Controllers und signalisiert den Erfolg mit der Ausgabe von \emph{ready}.
Durch einen erneuten Klick auf Connect im Controller wird die Verbindung zwischen Controller und ExecCmd Interface aufgebaut.
Danach kann ein Mode ausgew\"ahlt werden und mit Submit entsprechend auf dem digitalen Ausgang von CPX 1 dargestellt werden.
|