7 Aufgabe 6: Implementierung Teil 1

Werbung
7 Aufgabe 6: Implementierung Teil 1
Ausgabe: Montag, 17.05.2010.
Abgabe: (Eintrag ins SVN-System) Montag, 31.5.2010: 18:00 Uhr.
7.1 Anleitung
7.1.1 Gruppe A: Programmierung der BTnode
Allgemeines Die BTNode System-Software wurde im Rahmen der Aufgabe 2 bereits
eingeführt. Im Rahmen dieser Aufgabe werden Funktionen zum Steuern der LEDs (Einund Ausgabe über GPIO Pins), der I/O Pins, sowie zur Überwachung des Analog/Digital Wandlers bearbeitet. Es sind dies die hardwarenahen Funktionen, beispielsweise die
“Aktorfunktionen die in einigen Sequenzdiagrammen aufgeführt sind.
”
Der BTNode-Monitor
Um Rückmeldungen aus einem BTNode-Programm zu ermöglichen, steht in der BTNutOS Library ein Monitor -Modul zur Verfügung. Der Monitor erlaubt es, Nachrichten von
einer BTNode über einen seriellen Port mit einer Art printf-Befehl an einen PC zu senden und sie direkt in einem Terminalprogramm anzuzeigen. Zudem können textbasierte
Befehle vom Terminal gestartet werden.
Dieses Feature wird durch die ATMega128 UART Ports – UART (Universal Asynchronous Receiver Transmitter) – realisiert. Die ATMega128 hat zwei UART Schnittstellen – UART0 und UART1. UART0 wird benutzt, um die Kommunikation mit dem
Bluetooth-Chip zu realisieren. UART1 kann benutzt werden, um ASCII-Text zu einem
Terminal, d.h. zu einem Programm im Host Computer zu schicken. Bevor Messages über
den Monitor geschickt werden können, muss der UART1 mit folgendem Code eingestellt
werden:
1
2
# include < stdio .h > // freopen, includes <io.h> for ioctl
# include < dev / usartavr .h > // NutRegisterDevice, APP UART, UART SETSPEED
3
4
5
6
7
8
9
void init_stdout ( void ) {
u_long baud = 57600;
NutR egiste rDevic e (& APP_UART , 0 , 0) ;
freopen ( APP_UART . dev_name , " r + " , stdout ) ; // ”r+”: read+write
_ioctl ( _fileno ( stdout ) , UART_SETSPEED , & baud ) ;
}
61
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
Obige Funktion initialisiert den UART1 mit einer Übertragungsrate von 57600Bits/s,
registriert diesen Kanal als ein Device unter dem Betriebssystem BTNut/OS und öffnet
eine Verbindung die Schreiben und Lesen erlaubt. Jetzt können mit der Funktion printf
Nachrichten geschickt werden, wie folgendes Beispiel zeigt:
1
2
3
4
5
6
7
8
9
int main ( void )
{
btn _hardw are_in it () ; /∗ i n i t i a l i z e SRAM ∗/
init_stdout () ;
int variable = 13;
printf ( " Hello world , " ) ;
printf ( " my lucky number is % d \ n " , variable ) ;
for (;;) ; /∗ main s h o u l d n e v e r r e t u r n ∗/
}
Der Monitor soll beim Debugging von Programmen und Funktionen helfen, er bietet
eine bessere Schnittstelle zum Programmierer als die LEDs. Mehr über den Monitor erfahren Sie in den Beispielprogrammen, die mit dem BTNode-Paket geliefert werden.
TIPP: Schließen Sie das Terminalprogramm im Host, bevor Sie ein Programm in die
BTNode laden, sonst können Fehler im geladenen Code auftreten.
AVR Hardware – Ein-/Ausgabe Ports
Die allgemeinen Charakteristika des AVR ATMega128L Mikroprozessors wurden schon
in der Aufgabe 2 diskutiert. Die ATMega128L enthält 6 bidirektionalen Ein-/AusgabePorts jeweils mit 8 Bits. Da diese Ports unterschiedlichen Funktionalitäten, wie z.B. Seriellschnittstelle, Interrupteingänge und A/D Wandlerschnittstelle, übernehmen können,
soll eine Einstellung der vorliegenden Schaltung für die Nutzung programmiert werden.
Mehr Informationen können in [1] gefunden werden.
Die Schaltung des Ein-/Ausgabe-Ports des AVR Controllers, dargestellt in der Abbildung 7.1, haben true Read-Modify-Write Funktionalität. Das bedeutet, dass es möglich
ist, die Richtung eines einzelnen Pins (Ein- oder Ausgabe) zu ändern, ohne versehentlich die Richtung eines anderen Pins mit zu verändern. Dies gilt ebenfalls, wenn der
Wert des Treibers eines Output-Pins geändert wird, oder Pull-Up-Transistoren einausgeschaltet werden. Das Betriebssystem des AVR Controllers stellt dazu zwei Funktionen zur Verfügung:
• cbi(PORT, Pin-Nr.) - Löscht Pin (Pin-Nr.) an Port (PORT)
• sbi(PORT, Pin-NR.) - Setzt Pin (Pin-Nr.) an Port (PORT)
62
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
Abbildung 7.1: Schaltbild der General-Purpose I/O-Pins von Atmega128L [1]
AVR Hardware – Analog/Digital Wandler
In der Natur vorkommende Signale sind analog. Möchte man analoge Signale aus der
realen Welt mit der digitalen Welt der Computer in Verbindung bringen, so muss eine
Umwandlung der Information von analoger in digitale Form und umgekehrt durchgeführt
werden. Ein Analog-Digital-Wandler (auch: Analog-Digital-Umsetzer, A/D-Wandler oder
englisch ADC für Analog-to-Digital-Converter) wandelt nach unterschiedlichen Methoden analoge Eingangssignale in digitale Daten bzw. einen Datenstrom um, der dann
weiterverarbeitet oder gespeichert werden kann. In der ersten Stufe einer signalverarbeitenden Maschine, der Sample-and-Hold-Stufe“ werden nach einer Filterung des Signals
”
in gleichem zeitlichen Abstand ’Proben’ des Signals gezogen, die nun zeitdiskret sind,
aber immer noch jeden beliebigen Wert der Amplitude aufweisen können, Abbildung
7.2. Man nennt dieses Signal im Englischen auch “sampled signal .
”
63
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
Abbildung 7.2: Signaltypen
Nach dem Sample-and-Hold-Baustein wird das Signal nun vom AD-Wandler in digitale Form gebracht. Dabei weist der AD-Wandler jedem kontinuierlichen Wertebereich
der Amplitude einen bestimmten Wert zu. So erhält man ein sowohl zeit- als auch amplitudendiskretes Signal, das in einem Signalprozessor verarbeitet werden kann.
Das Gegenstück ist der Digital-Analog-Wandler oder DAC. Nach der Bearbeitung im
Signalprozessor kann das Signal durch einen D/A-Wandler wieder in analoge Form transformiert werden. Es liegt dann wieder in zeitkontinuierlicher, aber amplitudendiskreter
Form vor. Man sieht also, dass das ursprüngliche analoge Signal nicht wieder gänzlich
rekonstruiert werden kann. Bei genügend hoher Auflösung der beteiligten Komponenten
(A/D-Wandler, Signalprozessor, D/A-Wandler) kann das Ausgangssignal aber als analog
angesehen werden.
Der ATmega128 CPU verfügt über einen A/D-Wandler mit einer 10-bit Auflösung,
Abbildung 7.3. Der A/D-Wandler ist an einen 8-Kanal Multiplexer angeschlossen, der
die 8 Pins des Ports F als Eingänge hat. Der A/D-Wandler wird konfiguriert, indem die
Special Purpose Register geschrieben werden. Der Status und das Ergebnis der Konvertierung kann wiederum aus den Special Purpose Registern ausgelesen werden.
Auch der A/D-Wandler wird durch das Schreiben von Special Purpose Registern konfiguriert. Auf den Status und das Ergebnis der Konvertierung kann dadurch zugegriffen
64
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
werden, dass die Special Purpose Register gelesen werden. Im Falle des A/D-Wandlers
werden zwei 8-bit Register namens ADMUX und ADCSRA für die Konfiguration und
die Statusinformationen verwendet. Die 8-bit Register ADCH und ADCL werden für das
Ergebnis der Konvertierung verwendet.
Abbildung 7.3: A/D-Wandler im ATmega128L, S.131 aus Dokumentation des ATmega128L (im SVN unter Literatur eingecheckt)
Wir wollen jetzt die Spannung der Batterie messen und das Ergebnis mit Hilfe der
LEDs anzeigen. Die Lösung sollte wie folgt aussehen:
65
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
Der Lückencode der get_battery_voltage Funktion sieht wie folgt aus:
Im ersten Schritt wird das Register ADMUX konfiguriert. Wie im Manual der ATmega128L (http://www.atmel.com/dyn/resources/prod_documents/doc2467.pdf) auf
der Seite 244 zu sehen ist, ist das BAT SENSE Signal mit dem Pin 3 des Ports F verbunden. Dem Manual entnehmen wir ebenfalls (Seite 239), dass dieser Pin der dritte
Kanal des A/D-Wandlers ist. Die Tabelle 98 auf der Seite 244 zeigt, dass die Bits MUX1
und MUX0 vom ADMUX Register gesetzt sein müssen, damit die Spannung am Kanal 3
des A/D-Wandlers gemessen werden kann. Das ADLAR Bit bleibt auf Null gesetzt. Die
Bits REFS1 und REFS0 bleiben ebenfalls auf Null gesetzt, weil wir die externe Spannungsreferenz benutzen, die an den AREF Pin des ATmega128 angeschlossen ist.
ACHTUNG: BENUTZEN SIE KEINE ANDEREN EINSTELLUNGEN FÜR DIE
REFSx BITS, WEIL DADURCH DER MIKROKONTROLLER BESCHÄDIGT WERDEN KÖNNTE!
7.1.2 Gruppe B - Einführung in die MIDlet-Programmierung mit Java2ME
Allgemeines In der ersten Implementierungsphase soll ein MIDlet programmiert werden, welches auf Benutzereingaben reagieren kann, eine Inquiry durchführt, die Dienstabfrage an gefundene Geräte schickt und die daraufhin erhaltenen Dienste dem Nutzer
präsentiert. Das Nutzen der Dienste sowohl des Host als auch der BTnodes soll in den
Aufgaben 7 und 8 implementiert werden.
Java2ME ist eine Umsetzung der Programmiersprache Java für embedded consumer
products wie etwa Mobiltelefone oder PDAs. JSR 30 und JSR 37 (Java Specification
Request) definieren J2ME. Java Micro Edition kann in verschiedenen Konfigurationen
eingesetzt werden. Eine Konfiguration ist eine Menge von Java APIs, Klassenbibliotheken und einer virtuellen Maschine, die auf eine bestimmte Gerätefamilie mit ähnlichen
Anforderungen konzipiert ist, d.h. eine Konfiguration stellt eine Spezifikation für eine Familie von Endgeräten dar. Die Entwicklung von Konfigurationen für J2ME wird
hauptsächlich durch die Firma Sun und deren Entwicklungspartner vorangetrieben. Derzeit existieren zwei Standardkonfigurationen, nämlich Connected Device Configuration
(CDC) und Connected Limited Device Configuration (CLDC).
66
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
Die CDC (JSR 218) ist eine J2ME Konfiguration für Geräte, die eine komplette Implementierung der JVM und eine Menge von APIs benötigen, die durch das Hinzufügen
von Profilen die gesamte Java SE Plattform API einschließen können. Typische Implementierungen benutzen nur einen Teil der SE APIs, indem nur eine bestimmte Anzahl
an Profilen eingebunden wird.
Die CLDC (JSR 30 und JSR 139) definiert die kleinstmögliche Konfiguration
einer J2ME-Laufzeitumgebung. Zu den größten Einschränkungen in Version 1.0 zählt
der Verzicht auf Fließkommaberechnungen. Das betrifft sowohl Variablen, die als float,
double, als auch als java.lang.Float und java.lang.Double deklariert sind. Weiterentwicklungen der CLDC in Version 1.1 führten u. a. zu einer Wiedereinführung der Fließkommaunterstützung. CLDC wird hauptsächlich in Mobilen Geräten in Verbindung mit
dem ”Mobile Information Device Profile”(MIDP) benutzt.
MIDP (Mobile Information Device Profile) ist ein Profil der Java 2 Micro Edition (J2ME), das speziell auf die Fähigkeiten kleiner mobiler Endgeräte wie Mobiltelefon
oder Pager ausgelegt ist. Profile sind die APIs, die es für eine Konfiguration gibt. Sie
stellen eine weitere Art der Anpassungsmöglichkeit der Java2 API an Anforderungen für
Gerätefamilien dar. Applikationen auf Basis von MIDP nennt man kurz MIDlets (z.B.
Java-Spiele für Handys). Das MIDP umfasst Funktionen zur Ansteuerung und Abfrage
von Einhandtastaturen, Miniaturbildschirmen, flüchtigen und nicht-flüchtigen Speichern
im Kilobyte-Bereich etc. Es existieren bisher MIDP 1.0 (JSR 37) und MIDP 2.0
(JSR 118), das einige Erweiterungen aufweist. MIDP 3.0 ist bereits als JSR 271 in
Bearbeitung. In unserem Projekt verwenden wir Mobiltelefone, die MIDP 2.0-fähig sind.
Konfigurationen bieten eine breite Variabilität für verschiedene Einsatzzwecke, sind
jedoch oft nicht ausreichend, um die komplette Funktionalität verschiedener Geräte verwenden zu können. Daher gibt es Erweiterungen, die interne Gerätefunktionen unterstützen, wie z.B. Bluetoothfunktionalität (siehe JSR 82), die für unsere Zwecke
benutzt werden wird, Abbildung 7.4.
Die Entwicklung von Konfigurationen, Profilen und Erweiterungen wird im Rahmen
des ”Java Community Process”(JCP) durchgeführt, an denen auch namhafte Firmen
wie Nokia, Siemens oder IBM beteiligt sind.
Als Benutzeroberfläche bieten MIDP-APIs eine Menge von User-Interface-Elementen
(UI). Diese ermöglichen Interaktionen zwischen Benutzer und MIDlet und befinden sich
im Paket javax.microedition.lcdui.
Die High-Level-API (vgl. Abb. 7.5) stellt Ein- und Ausgabefelder, wie z. B. Textfelder
(TextField) oder Fortschrittsanzeigen (Gauge), zur Verfügung. Sie sind der Elternklasse
Item untergeordnet. Objekte vom Typ Item“ können auf einem Formular platziert wer”
den, sind jedoch nur eingeschränkt positionierbar. Formulare sind Objekte der Klasse
Form“. Sie können an das aktuelle Display angehängt werden und verschiedene UI”
Elemente beinhalten. Das MIDlet kann Wechsel zwischen Formularen anfordern sowie
während der Laufzeit UI-Elemente hinzufügen und auf Benutzereingaben reagieren.
67
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
Abbildung 7.4: CLDC/MIDP-Architektur, spezifiziert in JSR082
Die wichtigsten UI-Elemente sind (vgl. Abb. 7.5):
• Form: Container für andere UI-Elemente
• Item: Repräsentiert einen Menüeintrag. Mehrere Items können in einem Menü zusammengefasst und an ein Formular angehängt werden
• Alert: Popup-Nachrichten die den Benutzer über Fehler, Exceptions, Warnungen
oder über sonstige Informationen benachrichtigen
• ChoiceGroup: Implementiert eine Selektionsmöglichkeit zwischen mehreren Einträgen. Die Auswahl ausschließlich einzelner (engl. single choice“) oder auch meh”
rerer Einträge (engl. multiple choice“) ist möglich
”
• TextBox: Einzeilige Eingabefelder, in denen der Benutzer Text einfügen bzw. editieren kann
• TextField: Ähnlich einer TextBox, allerdings mehrzeilig
• Gauge: Fortschrittsanzeige
• Ticker: Anzeige von bewegtem Text
Im Gegensatz hierzu arbeitet die Low-Level-API auf Pixelebene. Die Klasse Can”
vas“ ist der Eingangspunkt für graphische Zeichnungen. Sie selbst beinhaltet hierfür
keine Methoden, jedoch stellt sie die Callback-Funktion paint() bereit. Sie wird immer
dann aufgerufen, wenn der Programmmanager entscheidet, das Display neu zu zeichnen.
Ihr einziger Parameter ist ein Objekt Graphics, welches sämtliche Zeichnungsfunktionen,
wie beispielsweise drawLine() zum Zeichnen einer Linie oder fillRect() zum Ausfüllen eines Rechtecks, beinhaltet.
68
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
Abbildung 7.5: High level und Low level MIDP API
Grundsätzlich kann man zwischen reinen Hintergrundapplikationen und jenen unterscheiden, die mit dem Benutzer interagieren. Interaktive Applikationen können auf das
Display über ein Objekt Display zugreifen. Man erhält es als Rückgabeobjekt der statischen Methode getDisplay() mit dem MIDlet als Argument. Die Methode setCurrent()
bestimmt, welches Objekt Displayable den Inhalt eines Displays darstellen soll. Displayable ist die Elternklasse von Screen und Canvas. Ihr sind alle UI-Klassen unterstellt.
Mit anderen Worten, sie definiert sämtliche Objekte die am Display angezeigt werden
können.
MIDLET Programmierung auf dem Mobiltelefon
Die angegebenen Code-Schnipsel sind Beispiele. Sie haben die erste Kommunikation bereits in Aufgabe 3 durchgeführt. Die endgültige Implementierung hängt von der Spezifikation und von Ihrem Klassendiagramm im Entwurfsdokument ab.
In Aufgabe 2 und 3 haben Sie bereits gesehen, welche Funktionalität ein MIDlet bietet.
Die Bluetooth Demo aus dem Wireless Toolkit sollte Ihnen dabei zeigen welche einzelnen
Schritte für eine Bluetooth Kommunikation nötig sind.
Nun ist es Ihre Aufgabe ein eigenes MIDlet zu entwerfen, welches den im Pflichtenheft definierten Anforderungen entspricht. Dabei soll in dieser Aufgabe das Augenmerk
auf dem Starten des MIDlets, dem Suchen nach Bluetooth-Geräten in der Umgebung
und der Dienstanfrage liegen. Dazu gibt es eine gute Einführung in einer MastersThesis von André N. Klingsheim, siehe [6]. Darin wird der Aufbau eines MIDlets
69
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
Schritt für Schritt erklärt und mit beigefügtem Source-Code erläutert. Allerdings benutzt
Klingsheim die Service-Discovery“-Methode, die in unserer Umgebung mit dem Nokia
”
6680-Telefon nicht funktioniert (Wir verwenden dafür das Serial Port Profile SPP). Ein
weiters gutes Buch ist von Kumar et al. (Java Programming with Bluetooth: Eine Kopie der für Sie interessanten Kapitel finden Sie im Abschnitt “Literatur in unserm SVN).
”
Implementieren Sie das dort vorgestellte MIDlet und fügen Sie folgende Funktionalität
hinzu:
• In der Funktion startApp() soll dem Benutzer ein Willkommensbildschirm präsentiert werden, welcher die Möglichkeit bietet mit der DeviceSearch zu beginnen,
oder das Programm zu beenden.
• In der Funktion commandAction(Command c, Displayable s) werden die Benutzereingaben verarbeitet. So soll z.B. bei Command OK“ auf Menüeintrag Start
”
”
DeviceSearch“, welchen Sie aus dem Objekt Displayable s herauslesen können, die
Inquiry gestartet werden, bzw. wie im Beispiel eine Funktion doDeviceDiscovery()
ausgeführt werden.
• In der Funktion inquiryCompleted(int param) soll dem Benutzer die Liste der
gefundenen Geräte präsentiert werden. Dabei müssen Sie darauf achten, dass die
Liste der Geräte auf dem Display auswählbar ist, sodass es möglich ist, ein Gerät
zu selektieren und die Service-Suche zu starten.
• Da die Service-Suche über das DiscoveryListener Interface aufgrund von Kompatibiltätsproblemen nicht einwandfrei funktioniert, können Sie die Funktionen
– public void servicesDiscovered(int transID, ServiceRecord[] serviceRecord
){} und
– public void serviceSearchCompleted(int transID, int respCode){}
leer lassen, müssen sie jedoch aufgrund des Interfaces so übernehmen. Sollte ihre
Entwicklungsumgebung automatisch in den Rumpf der Methoden eine UnsupportedOperationException einfügen, so kommentieren Sie diese Zeile bitte aus, denn
die Klasse ist nicht jedem Endgerät bekannt und kann daher Fehler verursachen.
• In der Funktion doDeviceDisocovery() soll dem Nutzer an allen Stellen an denen
//Error handling Code here steht eine Fehlermeldung ausgegeben werden, aus
welcher ersichtlich ist, an welcher Stelle das Programm einen Fehler ausgeworfen
hat.
• Zur Dienstsuche müssen Sie in der Funktion commandAction(Command c, Displayable
s) bei Command OK“ und einem ausgewählten Gerät den in der Spezifikation
”
definierten String an das betreffende Gerät senden.
70
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
Dienstsuche
Zur Dienstsuche können Sie folgendes Verfahren benutzen:
Zunächst benötigen Sie die Bluetooth-Adresse des betreffenden Geräts. Diese erhalten
Sie aus dem Objekt RemoteDevice in der Funktion deviceDiscovered().
Sie benötigen dann eine Verbindung zu diesem RemoteDevice:
StreamConnection streamConn = (StreamConnection)Connector.open(url);
Die Connector-Klasse aus javax.microedition.io.Connector öffnet eine Verbindung und
gibt ein Connection-Objekt zurück, welches in die entsprechende Verbindungsart gecastet werden kann (hier also StreamConnection). Der url-Parameterstring muss dem URLFormat aus RFC 2396 entsprechen. Er hat die allgemeine Form wie folgt:
{scheme}:{target}[{params}]
• {scheme}: Name des Protkolls, z.B. btspp oder http
• {target}: Eine Netzwerkadresse, bluetooth address of remoteDevice:1“
”
• [{params}]: Weitere Parameter der Form ;x=Y“, z.B. ;app-name=MobilerKnoten“
”
”
Wird das ServiceDiscoveryProtocol verwendet, dann wird hinter der target-Netzwerkadresse die PSM (Protocol Service Muliplexer, wichtigster Parameter der L2CAP-Verbindung,
siehe [11]) angegeben, um einen speziellen Dienst im Server anzusprechen. PSM 1 (genauer 0x0001) enspricht z.B. dem ServiceDiscoveryProtocol. Da wir in unserer Umgebung
das ServiceDiscoveryProtocol nicht verwenden (können), benötigen wir auch den PSM
nicht.
Wir verwenden, abhängig vom anzusprechenden Gerät, btl2cap und btspp als scheme.
Die Connector-Strings sehen dann folgendermaßen aus:
BTNode:
"btl2cap://"+ [MAC-Adresse des BTN] + ":0xE001"
. . . und für den Host:
"btspp://"+ [MAC-Adresse des Hosts] + ":1;encrypt=false;authenticate=false"
Der Verbindungsaufbau zur BTNode
L2CAPConnection l2cap;
l2cap = (L2CAPConnection)Connector.open(String BTN-ConnectorString (s. oben));
Eine Nachricht wird folgendermaßen verschickt:
byte[] meineNachricht;
71
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
l2cap.send(meineNachricht);
und um eine Nachricht zu empfangen:
byte[] antwort;
l2cap.receive(antwort);
Verbindungsaufbau zum Host
StreamConnection streamConn;
streamConn=(StreamConnection)Connector.open(String SPP-ConnectorString(s.o.));
Input-/Output-Streams zum Empfangen und Senden von Daten:
DataInputStream inStream = streamConn.openDataInputStream();
DataOutputStream outStream = streamConn.openDataOutputStream();
Senden Sie nun über diese Verbindung den in der Spezifikation festgelegten String.
Benutzen Sie für Input und Output über Bluetooth die Funktionen writeUTF(String s)
und readUTF():
String request = "ihrString";
outStream.writeUTF(request);
Da es sich bei der geöffneten Verbindung um eine Verbindung mit Puffer handelt,
müssen Sie diesen leeren und somit die Nachricht senden:
outStream.flush();
Schließen Sie danach den OutputSream, nicht jedoch ihre StreamConnection:
outStream.close();
Danach müssen Sie nur noch auf die Antwort der Gegenstelle warten:
Dazu benötigen Sie den InputStream und warten auf eingehende Daten:
inStream = streamConn.openDataInputStream();
String answer=null;
answer = inStream.readUTF();
Schließen Sie den InputStream und die StreamConnection:
inStream.close();
72
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
streamConn.close();
Parsen Sie nun den erhaltenen answer String und präsentieren dem Benutzer die angebotenen Dienste.
Weitere hilfreiche Links
• http://www.nokia.de/de/mobiltelefone/modelluebersicht/6680/startseite/150206.html
• http://jcp.org/en/jsr/all
• http://www.m-software.de/handy-galerie/Nokia/6680.php
• http://java.sun.com/products/midp/
• http://java.sun.com/products/cldc/
• http://wireless.klings.org/klings jabwt master thesis.pdf
• http://de.wikipedia.org/wiki/MIDP
• http://developers.sun.com/techtopics/mobility/midp/articles/bluetooth2/
• http://java.sun.com/products/sjwtoolkit
• http://www.mobileinfo.com/
• http://java.sun.com/javame/reference/apis/jsr082/
• http://java.sun.com/javame/reference/apis/jsr139/
• http://java.sun.com/javame/reference/apis/jsr118/
73
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
7.1.3 Gruppe C - BT-Server-Programmierung mit JavaSE
Allgemeines Ziel ist die Programmierung eines Servers im Host, der selbst drei Dienste anbietet. Zusätzlich soll die “Diensteliste als Antwort auf eine Dienstanfrage eines
”
entfernten Gerätes die im Host registrierten Dienste an das anfragende Gerät zurückgeben. Für die Programmierung soll die Java BT Implementierung von Benhui Bluecove
(für Windows) sowie das Java J2SE Development Kit und die J2SE Runtime Environment 5.0 Update 10 oder höher verwendet werden. Als Entwicklungsumgebung bietet
sich eclipse an. Hier muss ein neues Java-Projekt angelegt werden. Es muss die Benhui
Bluecove Bibliothek ins Projekt eingebunden werden (über Rechte Maustaste auf
Projekt → BuildPath → Configure Build Path → Add External Jars).
Das Gegenstück zu dem hier zu entwickelnden Hostprogramm ist das Clientprogramm
der Gruppe B. Zum Testen sprechen Sie sich bitte mit der Gruppe B ab.
Grundstruktur eines Servers
Ein BT-Server legt für jedes Gerät, mit dem er eine Verbindung eingeht, einen Thread
an. Die Programmierschritte im Server sind:
• Initialisierung des BT-Stacks
• Antworte auf eine Dienste-Anfrage
• Warte auf Client-Verbindungsanfragen und akzeptiere diese und bearbeite ClientAnforderungen
• Schließe den Dienst ab
Es existieren einige Tutorials von SUN im Netz, die recht gut sind. Wir empfehlen:
• Tutorial 1:
http://developers.sun.com/techtopics/mobility/apis/articles/bluetoothcore/
• Tutorial 2:
http://developers.sun.com/techtopics/mobility/midp/articles/bluetooth2/
Außerdem zu empfehlen ist die Homepage von Benhui, auf der Beispielprogramme
und viele nützliche Informationen sowie ein Diskussionsforum zu finden sind.
Initialisierung des Servers
Um einen Dienst im Server zu registrieren, ist zunächst die Initialisierung des lokalen
Bluetooth-Stacks und des lokalen BT-Gerätes nötig, d.h. der angeschlossene BT-Dongle
muss über die JavaAPI initialisiert werden. Ein Aufruf von:
LocalDevice localDevice = getLocalDevice();
74
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
aus dem javax.bluetooth.* -Paket erledigt dies. Zusätzlich muss ein StreamConnectionNotifier -Objekt angelegt werden, welche ähnlich wie ein Server-Socket eingehende Verbindung akzeptiert. Die Initialisierung des StreamConnectionNotifiers geschieht über
folgenden Aufruf:
StreamConnectionNotifier serverconn = (StreamConnectionNotifier)Connector.open
(url);
Die Connector-Klasse aus javax.microedition.io.Connector öffnet eine Verbindung und
gibt ein Connection- Objekt zurück, welches in die entsprechende Verbindungsart gecastet werden kann (hier also StreamConnectionNotifier). Der url-Parameterstring muss
dem URL-Format aus RFC 2396 entsprechen. Er hat die allgemeine Form wie folgt:
{scheme}:[target][params]
• {Scheme}: Name des Protkolls, z.B. btspp oder http. (Bei uns: btspp)
• {target}: Eine Netzwerkadresse, für den lokalen Host “localhost:1 , für entfernte
”
Geräte eine BT-Adresse
• {params}: Weitere Parameter der Form “;x=Y , z.B. “;app-name=HostNode
”
”
Hinter der target-Netzwerkadresse wird die PSM (Protocol Service Muliplexer, wichtigster Parameter der L2CAP-Verbindung, siehe [1]) angegeben, um einen speziellen
Dienst im Server anzusprechen. PSM 1 (genauer 0x0001) entspricht z.B. dem ServiceDiscoveryProtocol, das wir allerdings nicht verwenden. Auf diese Weise kann später
mittels der UUIDs für die Serverdienste ein Dienst gezielt ausgewählt werden (eine PSM
entspricht letztlich einer UUID, da die 16- bzw. 32-Bit-PSM intern in eine 128-Bit UUID
umgewandelt wird (siehe BluetoothAPI:UUID für eine Beschreibung der UUID-Klasse).
Obwohl wir das Service Discovery Protokoll (SDP) nicht verwenden, hier noch einige
Bemerkungen dazu: Die UUIDs für die Serverdienste müssen angelegt und im ServiceRecord des Hosts abgelegt werden. Damit sind die Services im ServiceRecord der localDevice registriert und können bei einer ServiceDiscovery durch ein entferntes Gerät gefunden
werden. Eine Beschreibung des SDP findet sich in der Bluetooth Core Specification v2.0.
Akzeptieren einer Client Verbindung
In dieser Aufgabe geht es darum, eingehende Clientverbindungen zu verarbeiten. Die
Dienstauswahl geschieht hier vereinfacht über den Austausch von Strings, die im Host
geparst werden. Das Mobiltelefon (MT) schickt zuerst einen String, der in der Spezifikation definiert ist, an den Host. Im Host soll dies erkannt werden und die registrierten
Dienste ebenfalls als String zurückgeschickt werden (siehe Spezifikation). Dieser String
kann vom MT wiederum erkannt werden, welches dann die einzelnen Dienste zur Auswahl freigibt. Das Handling der angebotenen Dienste wird in den folgenden Aufgaben
durchgeführt. Hier soll zunächst nur die Dienst-Antwort auf die Dienstanfrage des Client
75
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
implementiert werden.
Akzeptieren einer Clientverbindung wird durch:
StreamConnection clientconn = serverconn.acceptAndOpen();
ausgeführt. Dadurch wird ein StreamConnection Objekt erstellt, über das verschiedene
Schreib- und Leseoperationen durchgeführt werden können.
Dienstanfrage: “Service Discovery
”
Für die Service Discovery sendet in diesem Projekt das Mobiltelefon einen String (über
das “Serial Port Profile SPP) “SendServices an den Server. Dieser parst den String
”
”
und schickt seinerseits einen String mit der Liste der angebotenen Dienste (also ”TelefonService, Gebäudeplan-Service, Quiz-Service-String”) zurück. Falsche (unverständliche)
Anfragen vom Handy sollten mit einer Fehlermeldung beantwortet werden.
Benutzen Sie für Input und Output über Bluetooth die Funktionen writeUTF(String
s) und readUTF(). Sie müssen zunächst ein DataInputStream Objekt für die eingehende
Anfrage erzeugen:
DataInputStream in = clientconn.openDataInputStream();
bevor Sie mit String s = in.readUTF(); den eingehenden String lesen können. Analog
läuft das Schreiben auf den DataOutputStream ab:
DataOutputStream out = clientconn.openDataOutputStream();
out.writeUTF("ihreantwort");
Da es sich bei der geöffneten Verbindung um eine Verbindung mit Puffer handelt,
müssen Sie diesen leeren und somit die Nachricht senden:
outStream.flush();
Schließen Sie danach den OutputSream, nicht jedoch ihre Stream Connection:
outStream.close();
76
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
7.2 Aufgabe 6
Allgemeines: Für alle Gruppen:
Mit der Aufgabe 6 beginnt die Implementierungs-Phase (Programmierung). Für die
Implementierung, wie sie im Pflichtenheft und in der Spezifikation beschrieben ist, haben
Sie drei Wochen Zeit, (d. h. die Aufgaben 6 bis 8 einschließlich sind Programmieraufgaben). Da Ihre erste Kommunikation bzw. Verbindung mit Ihrer Nachbargruppe bereits in
Aufgabe 3 gelöst wurde, ist der weitere Datenaustausch mit den entsprechenden Anzeigen wahrscheinlich wesentlich einfacher. Wir haben die Implementierung der einzelnen
Funktionen des Pflichtenhefts etwa gleichmäßig auf die Aufgaben 6 bis 8 verteilt. Da Sie
die Funktionen bereits alle in der Spezifikation spezifiziert haben, können Sie natürlich
auch vorarbeiten, wenn Sie wollen. Halten Sie sich an Ihre SW-Architektur, an die Sequenzdiagramme, bzw. an Ihr Klassendiagramm aus dem Entwurfsdokument. Achten Sie
darauf, dass Ihr Code gut strukturiert, gut lesbar und verständlich ist (Kommentare!).
Die Tutoren werden sich Ihren Code zu gegebener Zeit kritisch anschauen.
7.2.1 Gruppe A:
Lesen Sie die Anleitung für Aufgabe 6. Die Kommentarköpfe Ihrer Programme bitte so
schreiben, dass das Werkzeug doxygen sie versteht und daraus eine Entwicklungsdokumentation erstellen kann.
Aufgaben zu den Ein-/Ausgabeports: Vorbereitung der Module Aktorfunktionen“
”
und Notfall-Sensor“
”
1. Auf der BTnode befinden sich 4 LEDs. Schreiben Sie ein Programm, das mit Hilfe
der BTNut/OS API LED 1 einschaltet.
2. Erweitern Sie das unter Punkt 1 entwickelte Programm, um die folgende Punkte
zu vervollständigen:
a) Die Funktionalität für das Einschalten der LED 1 soll in eine Funktion gekapselt sein. Diese Funktion ist Teil des Aktorfunktionen“-Moduls, das im Ent”
wurfsdokument beschrieben ist. Achtung: Nennen Sie die Funktionen/Funktionsaufrufe (Befehle) entsprechend der Beschreibung in der Spezifikation.
Schreiben Sie eine zweite Funktion, die das Ausschalten des LEDs bewirkt.
b) Die LEDs sind geeignet für Tests, da sie schon korrekt am Mikrokontroller
angeschlossen sind. Um die Funktionalität des Ein-/Ausschaltens der Lampe
zu implementieren, soll der richtige I/O Port verwendet werden. Ändern Sie
die Funktionen, um den Pin 3 auf Port E zu steuern.
3. Der Pin 1 von Port F (PF1) der Atmega128 CPU ist mit dem Notfallsensor verbunden. Schreiben Sie ein Programm mit Hilfe des BTNut/OS API, das diesen Pin
als Eingang einstellt. Wird der Notfallsensor aktiviert, soll auf der BTNode die
LED 1 eingeschaltet werden. Kapseln Sie diese Funktionalität in eine Funktion.
77
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
Diese Funktion ist Teil des Notfall-Sensor“-Moduls, das im Entwurfsdokument
”
beschrieben ist und wird beim Notfall-Status-Polling“ benutzt.
”
4. Der Pin 3 von Port E (PE3) der Atmega128 CPU ist mit der Lampe verbunden.
Schreiben Sie ein Programm mit Hilfe von BTNut/OS API, das den Status dieses
Pins überprüft (Achtung, hier soll der Pin immer als Output bleiben!). Kapseln
Sie diese Funktionalität in einer Funktion. Diese Funktion ist Teil des Aktor”
funktionen“-Moduls, das im Entwurfsdokument beschrieben ist, und wird bei der
Beleuchtung als Status Polling“ benutzt.
”
Achtung: Sie haben zwei kleine Platinen erhalten, auf denen jeweils ein Schalter
(Notfallschalter) und eine LED montiert ist. Die Port-Verbindungen der Platinen
zum Schalter und zur LED sind nicht einheitlich!
Aufgaben zum A/D-Wandler. Vorbereitung des Moduls Batterie-Sensor“
”
1. Jetzt sind Sie an der Reihe, das ADCSRA Register zu konfigurieren. Für maximale Präzision wollen wir die langsamste Konvertierungsgeschwindigkeit benutzen. Wir benutzen keinen Interrupt und führen eine einzige Konvertierung durch.
Nachdem der A/D-Wandler eingestellt worden ist, kann mit der Konvertierung
begonnen werden. Dies geschieht, sobald das ADSC Bit des ADCSRA Registers
gesetzt wird. Wenn die Konvertierung durchgeführt ist, wird dieses Bit automatisch zurückgesetzt. Warten Sie darauf und lesen sie dann das Ergebnis aus den
Registern ADCL und ADCH aus. Berechnen Sie die Konvertierungsergebnisse, die
Sie für die Batteriespannung von 1 V und 2 V erwarten. Bekanntermaßen beträgt
die Referenzspannung 3300 Millivolt, der A/D-Wandler liefert 10-Bit Werte und
das BAT SENSE Signal entspricht der Hälfte der Batteriespannung (siehe Schaltkreise Schematics“).
”
TIPP1: Falls das Konvertierungsergebnis immer Null ist, stellen Sie sicher, dass Sie
(i) Batterien in die BTnode eingebaut haben oder die Batterien-Kontakte an die
externe Spannungsversorgung angeschlossen haben und (ii) die Stromversorgung
(power switch) angeschaltet ist (wenn die BTnode an das USB-Kabel angeschlossen
ist, wird die BTnode mit Strom versorgt auch wenn der power switch ausgeschaltet
ist. Dann ist aber das BAT SENSE Signal immer Null).
TIPP2: Verwenden Sie die Programmstruktur, die in dem Lückencode vorgegeben
ist.
2. Integrieren Sie den in der Anleitung gegebenen Lückencode in ein BTNode Programm. Vervollständigen Sie dieses Programm, so dass Sie die Batteriespannung
messen können.
3. Erweitern Sie das in Aufgabe 1.1 entwickelte Programm, um die folgende Punkte
zu vervollständigen:
78
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
a) Die Funktionalität für die Überwachung der Batterie soll in eine Funktion
gekapselt werden. Diese Funktion ist Teil des Batterie-Sensor“-Moduls, das
”
im Entwurfsdokument beschrieben ist. Achtung: Nennen Sie Sie diese Funktion und die Funktionsaufrufe bzw. Befehle, entsprechend der Beschreibung
im Entwurfsdokument.
TIPP: Sie finden mehr Informationen dazu in den Beispielen die in [3] veröffentlicht sind.
7.2.2 Gruppe B:
Die Anleitung für Aufgabe 6 gibt Ihnen eine Einführung in die MIDlet-Programmierung,
die Sie bereits in Aufgabe 3 kennen gelernt haben. Verwenden Sie die Schnittstellen, die
in der Spezifikation beschrieben sind. Die Kommentarköpfe bitte so schreiben, dass das
Werkzeug Javadoc sie versteht und daraus eine Entwicklungsdokumentation erstellen
kann. (Anmerkungen dazu: siehe unten).
1. Schreiben Sie ein MIDlet entsprechend Ihrem Klassendiagramm im Entwurfsdokument mit den Funktionen:
a) Inquiry und Geräte-Anzeige (bereits in Aufgabe 3 gelöst)
b) Dienstanfrage beim Host, danach Anzeige der Host-Dienste.
c) Der Telefondienst soll ausgewählt werden können. Die Telefondienst-Anfrage
wird zum Host geschickt.
d) Die Host-Antwort auf die Telefondienst-Anfrage soll angezeigt werden (also
z.B. eine Telefonnummer). Verwenden Sie dafür NetBeans (oder eclipse) als
Editor.
2. Kompilieren Sie Ihr MIDlet (als Client) entweder mit NetBeans oder mit dem
Java Wireless Toolkit. Erstellen Sie eine JAR-Datei und laden Sie diese in Ihr
Mobiltelefon
Testen Sie Ihre Anwendung zusammen mit Gruppe C. Testen Sie auch Fehlerfälle.
7.2.3 Gruppe C:
Die Anleitung für Aufgabe 6 gibt Ihnen eine Einführung in die Java-Programmierung
auf dem Host, die Sie bereits in Aufgabe 3 kennen gelernt haben. Verwenden Sie die
Schnittstellen, die in der Spezifikation beschrieben sind und halten Sie sich an das Klassendiagramm, das Sie im Entwurfsdokument dargestellt haben.
Die Kommentarköpfe Ihres Codes bitte so schreiben, dass das Werkzeug Javadoc (siehe
unten) sie versteht und daraus eine Entwicklungsdokumentation erstellen kann.
1. Schreiben Sie ihr erstes Serverprogramm mit den Funktionen:
a) Initialisierung mit Sichtbarmachung“ Ihres Geräts für andere BT-Geräte.
”
79
Programmierprojekt Sommersemester 2010
Uni Tübingen, Arbeitsbereich Technische Informatik
b) Bereit zum Entgegennehmen der Dienstanfrage von Gruppe B. Anzeige der
Anfrage.
c) Dienstantwort mit Liste der Dienste an Gruppe B schicken. Anzeige der Antwort.
d) Programmieren Sie den Telefondienst. Das MT schickt eine TelefondienstAnfrage, die Sie mit einer Telefonnummer beantworten müssen. Anzeige der
Antwort.
e) Zeigen Sie in Ihrem GUI-Fenster das Ergebnis der Inquiry an.
Testen Sie Ihre Anwendung zusammen mit Gruppe B. Testen Sie auch Fehlerfälle.
Bemerkungen zu Javadoc
Ein Beispielkommentar einer Klasse und Funktion sieht wie folgt aus:
/**
* Ein Hello-World-Programm in Java.
* Dies ist ein Javadoc-Kommentar.
* Praktikum WS 2009. Aufgabe A6-1
* @author Alice Weiss, Gruppe B
* Datum:
* @version 1.0
*/
Literatur:
http://de.wikipedia.org/wiki/Javadoc}
http://homepages.fh-giessen.de/~hg7132/javaprog/uebungen/javadoc_tutorial.html
http://java.sun.com/j2se/javadoc/index.jsp
80
Literaturverzeichnis
[1] AVR Spezifikationsblatt.
documents/doc2467.pdf.
http://www.atmel.com/dyn/resources/prod_
[2] Btnodes - a distributed environment for prototyping ad hoc networks.
http://www.btnode.ethz.ch/BTnodes.
[3] BTnodes - Documentation. http://www.btnode.ethz.ch/static_docs/doxygen/
btnut/.
[4] Sony Ericsson.
On-device-debugging tutorial for netbeans.
http:
//developer.sonyericsson.com/site/global/newsandevents/latestnews/
newssept06/p_getstarted_ondevice_debugging_netbeans_tutorial.jsp.
[5] The Eclipse Foundation. Eclipse - open development platform. http://eclipse.
org/.
[6] André N. Klingsheim. J2me bluetooth programming. http://wireless.klings.
org/klings_jabwt_master_thesis.pdf.
[7] Sun Microsystems. Java me technology apis & docs.
javame/reference/apis.jsp.
http://java.sun.com/
[8] Sun Microsystems. Netbeans ide. http://www.netbeans.org.
[9] Sun Microsystems. Netbeans mobility pack for midp/cldc 5.5 quick start guide.
http://www.netbeans.org/kb/55/quickstart-mobility.html.
[10] BlueZ Project. Bluez - official linux bluetooth protocol stack. http://www.bluez.
org.
[11] Martin Sauter. Grundkurs Mobile Kommunikationssysteme. Vieweg Verlag, 2004.
[12] Open Source.
Winavr user manual.
WinAVR-user-manual.html.
http://winavr.sourceforge.net/
[13] Inc. Sun Microsystems. Jsr 82 bluetooth api and obex api. http://java.sun.com/
javame/reference/apis/jsr082/.
[14] AvetanaBT Team. Avetanabt - java library for bluetooth (jsr-82).
sourceforge.net/projects/avetanabt/.
[15] BlueCove Team. Bluecove - java library for bluetooth (jsr-82).
81
http://
Herunterladen