Blaues im Netz
Viele Anbieter von Smartphones und PDAs wie HP, Samsung und HTC setzen auf Microsofts Windows Mobile oder Embedded CE als Betriebssystem. Bluetooth-SDKs für deren .Net Compact Framework gibt es jedoch bislang nur von Fremdherstellern – darunter eine freie Entwicklungsumgebung.
- Markus Dobler
- Daniel Ritter
Unter anderem HP, Samsung und HTC bieten mit ihren Windows-Smartphones und -PDAs eine Alternative zur im Moment stark beachteten Konkurrenz: das speziell für mobile Anwendungen entwickelte .Net Compact Framework (CF), das zurzeit in Version 3.5 verfügbar ist. Allerdings bietet Microsoft als Bluetooth API nur eine C++-Variante an – eine .Net-Alternative zu Suns JSR-82 für J2ME fehlt. Auf der Suche nach einem Bluetooth-SDK für .Net findet man neben wenigen kommerziellen Anbietern (siehe Tabelle) zwangsläufig das von „In The Hand“ (s. Onlinequellen). Deren 32feet.NET SDK ist die erste Anlaufstelle, wenn man eine Bluetooth-Anwendung auf .Net CF entwickeln will.
| Anbieter von Bluetooth-SDKs fĂĽr .Net | |||
| Firma | InTheHand | Bluetools | BTFramework |
| Website | inthehand.com | franson.com | www.btframework.com |
| .Net Framework | 2.0 | 2.0 und 3.5 | 2.0 und höher |
| OBEX | + | +1 | + |
| Lizenz | Open Source | Desktop- und CF-Editionen, Standard: 99 US-$, Pro: 149 US$ | 200 – 2050 US-$, limitierte Demoversion |
| Bluetooth Adapter | mehrere (Liste) | 1 | mehrere, nur auf Microsofts Bluetooth Stack |
| Bluetooth Stacks | Microsoft2 | Microsoft, Widcomm | BlueSoleil (IVT), Microsoft, Toshiba, Widcomm |
| Sicherheit | PIN/Passphrase | k.A. | k.A. |
| Device Discovery | synchron/asynchron3 | synchron/asynchron | synchron/asynchron |
| Events | u.a. fĂĽr asynchronen Daten- und PIN-Austausch | u. a. beim Suchen und Verbindungsaufbau | k.A. |
| Profile | u.a. OBEX, Datei- und Objekttransfer (FTP, OPP etc.), Drucker (HCRP, BPP), audiovisuell (Headset, Freisprecheinrichtung) | k.A. | Datei- und Objekttransfer (FTP, OPP etc.), Custom RFCOMM-basierte Profile |
|
1 in separater Assembly 2 ab Version 2.4 Beta Widcomm-UnterstĂĽtzung (fehlerhaft) 3 fehlerhaft |
|||
In The Hand vertreibt sein Bluetooth-SDK unter einer „Custom License“, die eine freie Benutzung, Weiterentwicklung und den Verkauf in eigenen Produkten ermöglicht. Sowohl der Quelltext als auch die Assembly stehen mit einer knappen Dokumentation und einigen hilfreichen Beispielen sowie Anleitungen zum freien Herunterladen bereit.
Neben Bluetooth bietet das SDK Funktionen für IrDA (Infrarot) und das OBEX-Protokoll (OBject EXchange) zum Datenaustauch an [b]. Es läuft auf dem .Net CF ab Version 2.0 und unterstützt zusätzlich zu Windows Mobile ab Version 5.0 und Embedded CE ab Version 4.2 die Desktop-Betriebssysteme Windows XP sowie Vista. Version 2.3 des Open-Source-SDK bietet sowohl synchronen als auch asynchronen Austausch von Daten und kann mit mehreren Bluetooth-Adaptern arbeiten, die es intern in einer Liste verwaltet.
Mehrere Adapter, ein Stack
Als Sicherheitsmechanismus gibt es die einfache Abfrage einer alphanumerischen PIN beziehungsweise einer Passphrase. Fordert ein anderes Gerät eine solche PIN, wird ein Ereignis ausgelöst, auf das eine Callback-Routine reagieren kann. Die Beta-Version 2.4 unterstützt neben dem Windows-Stack ebenfalls die auf HPs iPAQ vorhandene Bluetooth-Implementierung von Widcomm. Sie lässt allerdings noch einigen Verbesserungsbedarf erkennen. „Stack“ heißt die hardwarenahe Implementierung des Bluetooth-Protokolls. Bluetooth-SDKs wie 32feet.NET unterstützen meist nur einige solcher Stacks.
Kleine Schwächen gibt es auch bei der Implementierung der asynchronen „DeviceDiscovery“: Sie ruft zurzeit die Callback-Routine auf, ohne eine Suche durchgeführt zu haben und liefert somit stets eine leere Geräteliste. Außerdem vermisst man beim Suchen und beim Verbindungsaufbau ein Ereigniskonzept, wie es die kommerziellen Anbieter haben. Dadurch ließen sich diese Funktionen asynchron ausführen, ohne sie in eine eigene Ereignisverarbeitung auslagern zu müssen.
Abgesehen davon bieten die Konkurrenzprodukte vergleichbare Merkmale und unterscheiden sich nur durch die breitere und vollständigere Unterstützung der Bluetooth-Stacks. Etwas unhandlich erweist sich BlueTools Version 1.0 bei der Adapter-Bereitstellung, da es nur einen gleichzeitig unterstützt. Diese Einschränkung dürfte allerdings höchstens für größere Geräte wie Laptops relevant sein.
Sowohl bei BlueTools als auch bei dem erst kĂĽrzlich erschienen BTFramework muss man eine Lizenz erwerben und wie im Falle von BlueTools einbinden:
Franson.BlueTools.License license =
new Franson.BlueTools.License(); license.LicenseKey = "Wo...K6"; FĂĽr die BlueTools-Lizenz fallen zurzeit zwischen 99 (Standard) und 149 US-Dollar (Professional) an. Vom BTFramework gibt es Lite-, Personal- und -Developer-Versionen, die zwischen 200 und 500 US-$ kosten. FĂĽr bis zu 2050 $ ist der Quelltext zu haben.
Aufgrund der marginalen Unterschiede zwischen den kommerziellen Entwicklungswerkzeugen und dem freien von In The Hand beziehen sich die Quelltextbeispiele und die Erläuterungen zum Einsatz und Debugging ausschließlich auf Letzteres.
Integration in VisualStudio
Für das Entwickeln von Anwendungen mit .Net CF benötigt man nur eine Installation von Microsofts Visual Studio, und die .Net CF Runtime ab Version 2.0 mit der Common Language Runtime (CLR) und den Klassenbibliotheken. Visual Studio bringt ab der Standard Edition die Voraussetzungen für das Erstellen mobiler Anwendungen mit und steht in einer 180 Tage lauffähigen Testversion kostenlos auf Microsofts Webseite zur Verfügung. Dort gibt es ebenfalls das .Net CF kostenlos.
Ist die Entwicklungsumgebung installiert und geöffnet, kann ein neues Projekt vom Typ Smart Devices angelegt werden, zum Beispiel „Device Application“. In dieser Variante erzeugt Visual Studio im Projekt automatisch die Datei Form1.cs, in der es die Oberfläche definiert. Der Entwickler ergänzt sie um den Quelltext der mobilen Anwendung. Schließlich ist das 32feet.Net SDK unter References hinzuzufügen, und die Bluetooth-Entwicklung für .Net kann beginnen.
Wie in Listing 1 gezeigt, liefert Bluetooth.PrimaryRadio den primären Bluetooth-Adapter, Bluetooth.AllRadios alle zurzeit angeschlossenen Geräte.
Listing 1: Synchrones Senden
public void sendSynchron()
{
// Referenziere erstes Bluetooth-Modul als
// primären Adapter. AllRadios liefert Liste
// der Module
BluetoothRadio radio
= BluetoothRadio.PrimaryRadio
// setze lokales Gerät auf "entdeckbar"
radio.Mode = RadioMode.Discoverable;
// erzeuge BluetoothClient-Objekt,
// Standardkonstruktor = lokales Gerät,
// Konstruktor mit BluetoothEndPoint-Angabe
// wird für Remote-Gerät verwendet
BluetoothClient bluetoothClient
= new BluetoothClient();
// Liste von Bluetooth-Geräten
BluetoothDeviceInfo[] bluetoothDevices
= bluetoothClient.DiscoverDevices();
foreach (BluetoothDeviceInfo bdi
in bluetoothDevices) {
// Angabe des Services als weiteren
// Parameter, um sich mit "Gerät" zu verbinden
BluetoothClient bcConn
= new BluetoothClient();
bcConn.Connect(bdi.DeviceAddress,
BluetoothService.DialupNetworking);
// bcConn eventuell in globale Liste auslagern
// für einheitlichen Zugriff auf Gerät
if (bcConn.Connected) {
byte[] MessageToSend
= Encoding.ASCII.GetBytes(
"Hello Remote Device!");
bcConn.Client.Send(MessageToSend);
// Verbindung schlieĂźen, Socket wird released
bcConn.Close();
}
}
}
Mehrere Endpunkte vermeiden Kollisionen
Um Laufzeitfehlern vorzubeugen, kann man mit BluetoothRadio.IsSupported die Verfügbarkeit von Bluetooth testen. Ebenfalls interessant ist der Zustand der Bluetooth-Adapter, den die Eigenschaft .Mode liefert. Er kann die Werte RadioMode.Connectable, RadioMode.Discoverable und RadioMode.PowerOff annehmen. Ist der gewünschte Adapter nicht sichtbar, also der Mode entweder Connectable oder PowerOff, sollte er auf Discoverable gesetzt werden, damit andere Geräte mit ihm Daten austauschen können. Die letzte Voraussetzung für das Auffinden anderer Geräte mit DiscoverDevices() ist das Erzeugen eines BluetoothClient, der gleichzeitig als Endpunkt fungiert. Die DiscoverDevices()-Methode ist überladen und liefert in der Default-Implementierung alle Geräte in Reichweite als BluetoothDeviceInfo-Liste. Die Ausgabe lässt sich unter anderem hinsichtlich maximaler Anzahl, remembered (schon bekannter), unknown (unbekannter), sowie discoverable only (sichtbarer) Geräte konfigurieren. Ist etwa nur unknown eingestellt, findet die Software dieselben Geräte wie bei discoverable only außer den schon bekannten.
Für den Aufbau einer Verbindung mit einem der gefundenen Geräte sollte das Programm einen dedizierten Endpunkt erzeugen. Das vermeidet Kollisionen bei mehreren Sendern und Empfängern. Die Verbindung stellt Connect(DeviceAddress address, BluetoothService profile) her, wobei die DeviceAddress des Verbindungspartners und als BluetoothService einer der Werte AdvancedAudioDistribution, CordlessTelephony, DialupNetworking, ObexObjectPush et cetera erforderlich ist.
Welche Bluetooth-Dienste der Empfänger bereitstellt, verrät Guid[] installedServices = bdi.InstalledServices. Das in Listing 1 verwendete Profil DialupNetworking ist eine Verbindungsart, die ohne einen PIN-/Passphrase-Austausch zwischen mobilen Geräten à la SetPin(BluetoothAddress device, string pin) als Authentifizierung auskommt.
Nach dem erfolgreichen Verbindungsaufbau, überprüfbar durch Auswertung der Property Connected erfolgt die Datenübertragung zum Beispiel mit dem synchronen Client.Send(byte[] data). Durch die Implementierung wirkt der synchrone Aufruf auf die laufende Anwendung nicht blockierend, sodass sie während des Sendevorgangs weiterarbeiten kann. Der Endpunkt selbst hingegen bleibt blockiert, solange die Daten gesendet werden.
Um die gesendeten Daten nicht blockierend zu empfangen, erzeugt der Empfänger zuerst unter Angabe des gewünschten Verbindungsprofils einen global sichtbaren BluetoothListener (siehe Listing 2). Mit ihm registriert er durch BeginAcceptBluetoothClient einen AsyncCallback, beispielsweise AsynchronousListening Dieser Callback wird durch ein Sende-Ereignis der Remote-Anwendung aufgerufen und bekommt dabei ein Objekt vom Typ IAsyncResult übergeben.
Listing 2: Synchrones Empfangen
//Erzeugen eines globalen Containers
BluetoothListener bl =
new BluetoothListener(BluetoothService.
DialupNetworking);
public void ListenAsynchron() {
// Starten des Listeners
bl.Start();
// Starte asynchrones "Lauschen"
// Festlegen einer asynchronen Callback-Routine
bl.BeginAcceptBluetoothClient(
new AsyncCallback(AsyncListening),bl);
}
private void AsyncListening(IAsyncResult result) {
// erzeuge lokales BluetoothClient Objekt fĂĽr
// Operation mit async result
BluetoothClient bc =
bl.EndAcceptBluetoothClient(result);
//erzeuge NetworkStream Objekt und referenziere
System.IO.Stream ns = bc.GetStream();
//erzeuge Liste mit Inhalt
List<byte> myResults = new List<byte>();
while (bc.Available > 0) {
//erzeuge Datenpuffer und fĂĽge Liste hinzu
byte[] buffer = new byte[512];
int rec = ns.Read(buffer, 0, buffer.Length);
//fĂĽge Inhalte des Puffers hinzu
for (int i = 0; i < buffer.Length; i++) {
myResults.Add(buffer[i]);
}
}
}
Wie beim Senden erzeugt das Programm lokal einen Endpunkt für den Empfang. Dazu dient die Operation EndAcceptBluetoothClient, die das Gegenstück zur Registrierung darstellt und das IAsyncResult-Objekt konsumiert. Die Endpunkt-Instanz enthält die gesendeten Daten als System.IO.Stream, den man wie gewohnt beliebig auspacken kann. Anders als bei der synchronen Variante kann man über einen weiteren Callback detaillierte Informationen wie das AsyncWaitHandle (wartet auf Abschluss des asynchronen Vorgangs) erhalten.
Wer sich schon einmal mit parallelem I/O beschäftigt hat, dem kommt das verwendete Programmiermuster mit begin/end, das hier als Begin/EndAcceptBluetoothClient auftritt, bekannt vor, denn es erinnert unter anderem an die nicht blockierenden, kollektiven Dateiaufrufe in MPI-IO (Message Passing Interface, [c]). Deren Spezifikation sieht das Konzept der Senderidentität vor, das hier implizit in der EndAcceptBluetoothClient-Methode steckt, die ein Objekt vom Typ BluetoothClient erzeugt. Da es sämtliche Operationen und Verbindungsdaten hält, stellt es bei der Kommunikation eine Referenz auf den Remote-Host dar.
Asynchron und synchron lesen und schreiben
Das Beispiel sendet synchron, könnte dies aber auch asynchron tun. Dazu muss man analog zum asynchronen Lesen Client.BeginSend einsetzen, das eine AsyncCallback-Methode startet. Sie verwendet einen Endpunkt für die Kommunikation und sendet die Daten als Byte-Array, das die Remote-Anwendung im IAsyncResult verpackt erhält.
Synchrones Lesen komplettiert das Ganze. Dafür instanziiert man einen Endpunkt in Gestalt des BluetoothClient, bereitet einen byte[] buffer für die zu empfangenden Daten vor und wartet blockierend mit Client.Receive(buffer) auf die Daten des anderen Geräts.
Signalstärke der Partner ermitteln
Eine Besonderheit des 32feet.Net SDK ist der Indikator für die Signalstärke, genannt „Received Signal Strengh Indication“ (RSSI, [d]). Er lässt sich mit der Property Rssi der BluetoothDeviceInfo ermitteln und liefert einen Wert zwischen 0 und 255. Um ihn auf das in der Bluetooth-Spezifikation vorgesehene Intervall [-128, +127] abzubilden, kann man unter anderem den Byte- in einen sbyte-Wert konvertieren, sollte dabei jedoch auf mögliche Ausnahmen achten.
Unabhängig von der Art der Darstellung lassen sich mit der RSSI-Information die Kommunikationskanäle zu den benachbarten Geräten bewerten. Aber aufgepasst: Wer diese Information benutzen will, benötigt mindestens Windows Mobile 5.0 oder CE 6.0. Des Weiteren unterstützt das SDK RSSI nur zwischen mobilen Geräten und wirft auf Desktop-Implementierungen eine NotSupportedException.
Zum Ausprobieren der eigenen Bluetooth-Implementierung empfiehlt sich die Installation eines der kostenlosen Emulatoren oder Images, die Microsoft auf seiner Mobile-Seite anbietet. Letztere unterstützen allerdings nicht zwangsläufig alle Bluetooth-Stacks und sollten wie die Version des .Net CF dahingehend in ihrer technischen Dokumentation überprüft werden.
Ist alles korrekt installiert, lassen sich mobile Geräte auf dem eigenen Desktop-Rechner simulieren und für sie geschriebene Anwendungen darauf ausführen. Dabei kommen „Cabinet“-Archivdateien (CAB) zum Einsatz, die man im Emulator oder auf dem mobilen Gerät auspackt und ausführt.
Was auf dem Desktop durch das Starten des Programms und die Auswahl eines Emulators funktioniert, lässt sich bei realen Geräten auf mindestens zweierlei Art erledigen. Dazu muss eine Übertragungssoftware wie ActiveSync (Windows XP) oder Windows-Mobile-Gerätecenter (Vista) installiert sein. Ob das Gerätecenter mit Windows 7 funktionieren wird, ist noch nicht klar. Damit lässt sich die erste Variante nutzen, bei der man einen Windows-Installer baut, auf dem Desktop ausführt und die Daten per ActiveSync auf das mobile Gerät überträgt. Etwas weniger aufwendig ist das Erstellen einer nativen Anwendung, die man auf das Gerät lädt und installiert. Das kann mit Visual Studio als automatische Bereitstellung konfiguriert werden. Dann erzeugt die IDE beim Projekt-Build eine Kopie und richtet sie auf dem verbundenen Gerät ein. Aufgrund der zeitaufwendigeren Kombination aus Build und Bereitstellung empfiehlt sich dies allerdings nur, wenn man bei jedem Build die Daten automatisch kopieren und entpacken will.
Nach einem erfolgreichen Aufspielen ist auf der Zielplattform eine ausführbare Datei samt benötigten Ressourcen vorhanden. Für ein reibungsloses Funktionieren sollte man nicht vergessen, den Bluetooth-Adapter in den Geräteeinstellungen zu aktivieren.
Mit Visual Studio funktioniert die Fehlersuche in mobilen Anwendungen wie üblich. Dabei verhält sich das verbundene Gerät wie der lokale Rechner. Voraussetzung dafür ist das Aufspielen einer Release-Version der Anwendung. Diese kann man wie auf dem Desktop mit Breakpoints versehen. Alternativ lässt sich die Debug-Version verwenden, die zusätzlich zum Debugging mit Diagnose-Anweisungen à la System.Diagnostics.Debug.WriteLine instrumentiert werden kann, die der Compiler in der Release-Version ignoriert.
Fazit
Durch den Einsatz von .Net-Bluetooth-SDKs lassen sich mobile Geräte relativ einfach zu drahtlosen Ad-hoc-Netzen verbinden. Der Markt für diese Programmierwerkzeuge scheint allerdings bisher wenig erschlossen zu sein. Obwohl Microsoft mit dem Visual Studio, der Übertragungssoftware und verschiedenen Emulatoren eine gut integrierte und umfassende Entwicklungsumgebung bereitstellt, überlässt es den Bluetooth-Markt anderen Anbietern.
In der Praxis führt daher zurzeit kein Weg an dem frei verfügbaren und quelloffenen 32feet.Net SDK von „In The Hand“ vorbei. Obwohl es in puncto Stabilität und Unterstützung der verschiedenen Bluetooth-Stacks einige Schwächen und Lücken offenbart, eignet es sich hervorragend für die Prototypentwicklung, da es grundlegende Funktionen wie die Suche nach Geräten, Verbindungsaufbau und Datenaustausch solide implementiert.
Für den produktiven Einsatz kann man entweder 32feet.Net an eigene Bedürfnisse und Qualitäts-Standards anpassen oder eines der kommerziellen SDKs kaufen. Einige von ihnen bieten „Partner-Support“, was eine schnellere Behebung gemeldeter Probleme bedeuten kann.
Markus Dobler
ist Fachinformatiker und studiert Wirtschaftsinformatik an der Dualen Hochschule Baden-Württemberg in Mannheim. Er hat langjährige Erfahrungen im C#- und .Net-Umfeld.
Daniel Ritter
hat Informatik an der Universität Heidelberg studiert und arbeitet zurzeit als Softwareentwickler und Projekt-Leiter/Architekt.
iX-TRACT
- FĂĽr Microsofts .Net-Compact-Framework gibt es noch kein hauseigenes Bluetooth-SDK. Zwei kommerzielle und ein freies Produkt stehen zur Auswahl.
- Das freie 32feet-Framework kann mehrere Bluetooth-Adapter anbinden und bietet rudimentäre Sicherheitsfunktionen.
- Es hat zwar einige Einschränkungen, eignet sich jedoch für die Erstellung von Prototypen.
(ck)