HID in Windows 8.1 mit Wiimote

Wer sich mit den Eigenschaften des Wiimote Controllers beschäftigt, kann nur begeistert sein. Dabei ist das Ding sieben Jahre alt. Beschleunigungssensoren, Infrarot Kamera, LED, Buttons, Vibration, Bluetooth und ganz abgefahren einen Lautsprecher auf den man streamen kann. Und das alles für ca 30 Euro.

Windows 8.1 erkennt unzählige USB oder auch Bluetooth Geräte als HID (human Input devices). WinRT bietet eine einfach API um diese Devices verwenden zu können. Dieser Blog Artikel zeigt wie man in einer XAML Windows Store App (modern UI/METRO) Anwendung einen Spiele Controller verwendet.

wiimote 3 axis

In Windows 8.1 kann dieser Controller per Bluetooth relativ einfach verbunden (gepaired) werden. Auch wenn ein PIN Code gefordert wird, kann dieser übersprungen werden. In den Blogs stehen unterschiedliche Anweisungen (die bei mir alle nicht funktionieren) für das Pairing mit Pin. Ich habe nicht herausgefunden, wie man die PIN des Wii Controllers herausfindet. Geht auch so.

Ohne Sicherheits Code entweder die Tasten 1 und 2 gleichzeitig drücken oder den roten Knopf beim Batteriefach. Die vier blauen LEDs blinken dann. Die Bluetooth Pairing Code einfach leer lassen und weiter drücken.
Screenshot (29)

Die  Wii erscheint dann als HID Device im Geräte Manager

image

Wer sich mit den HID Device Code Beispielen beschäftigt weis, das es zwei oder besser vier Parameter braucht um das Gerät überhaupt ansprechen zu können. Geübte HID Profis finden das in den Device Settings.

image

Andere (wie ich) brauchen Doku oder Werkzeuge.  Sehr nützlich für den Start ist ein Testtoolgefunden auf Codeplex SimpleHIDTest. So findet sich der Wii Controller als Nintendo RVL-CNT-01.

image

Dadurch erhält man die Parameter für die HID Device Klasse (Zeile 2).  UsagePage, UsageID, vendorid, ProductID. Diese sind für jedes Gerät anders. Es existieren sogar zwei Wii Varianten.

   1:   Private Async Function Button_Click(sender As Object, e As RoutedEventArgs) As Task
   2:          Dim deviceSelector = HidDevice.GetDeviceSelector(&H1, &H5, &H57E, &H306)
   3:          Dim devices = Await DeviceInformation.FindAllAsync(deviceSelector)
   4:          Dim device = devices.Item(0)
   5:          devicehandler = Await HidDevice.FromIdAsync(device.Id, FileAccessMode.ReadWrite)
   6:          AddHandler deviceHandler.InputReportReceived, AddressOf inputrec
   7:   End Function

Im VB.NET Code wird dann ein Event registriert um die eingehenden Daten zu erhalten. Die Daten enhalten immer exakt 22 Bytes (siehe Bild oben Hex 16).

   1:    Private Async Function inputrec(sender As HidDevice, 
args As HidInputReportReceivedEventArgs) As Task
   2:          Dim buf As IBuffer = args.Report.Data
   3:          Dim bufarray = buf.ToArray
   4:          If bufarray(0) = InputReport.Buttons Then
   5:              Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
   6:                              Sub()
   7:                                  txtButton.Text = ParseButtons(bufarray)
   8:                              End Sub)
   9:          End If
  10:  End Function

Aber noch weis niemand was die Daten aus dem Byte Array bedeuten. Dies ist für jedes HID Device extrem unterschiedlich bis auf Bit Ebene. Aufschluss gibt ein Dokument in dem die Wii Commands beschrieben sind. Es gibt Channels in denen die 22 Byte Arrays gesendet oder empfangen werden. Jede Funktion hat einen eigenen Channel oder auch mehrere. Diese Information stammt aus einem PDF.

Das erste Byte definiert den Channel und die zwei nächsten die nötigen Daten. Ein Tastendruck kommt auf Kanal Hex 30 (0x30).

Ein weiteres Tool zeigt die eingehenden Daten und erlaubt sogar Daten an die Wii zu senden. Da der Autor verstorben ist, gibt es keine Source Code zu SimpleHIDWrite3.

image

Man erkennt beim drücken des B Buttons (unten am Controller) die ankommenden Hex Werte. Eine Enumeration macht den Code später lesbarer und wird im vorigen Listing Zeile 4 bereits angewandt.

   1:  Public Enum InputReport As Byte
   2:      Status = &H20
   3:      ReadData = &H21
   4:      Buttons = &H30
   5:      ButtonsAccel = &H31
   6:      IRAccel = &H33
   7:      ButtonsExtension = &H34
   8:      ExtensionAccel = &H35
   9:      IRExtensionAccel = &H37
  10:  End Enum

Das Parsing der Daten erscheint etwas ungewohnt und kann recht umfangreich ausfallen. Immerhin können mehre Buttons gleichzeitig gedrückt werden.  Folgendes VB.NET Code Beispiel dient nur als Idee und liefert für die Buttons A oder B einen Wert.

   1:   Private Function ParseButtons(ByVal buff() As Byte) As String
   2:          If buff(2) = &H8 Then
   3:              Return "A"
   4:          End If
   5:          If buff(2) = &H4 Then
   6:              Return "B"
   7:          End If
   8:          Return "-"
   9:   End Function

Da beim loslassen des Buttons wiederum 22 Bytes kommen (siehe Bild SimpleHIDWrite) wird auch das per Event registriert und behandelt (hier Zeile 8)

Im vorigen Screenshot wurde in der Zeile wr die linke LED des Controllers eingeschalten. Man spricht im HID Umfeld von Reports die gelesen oder geschrieben werden.

image

Die ersten 4 Bits stehen für die 4 LEDS, der rechte Teil löst die Vibration aus. Der Kanal ist 11.

Damit sollte folgender Code in der Windows 8 Store App die blaue LED links einschalten.

   1:  Private Async Function CheckBox_Checked(sender As Object, e As RoutedEventArgs) As Task
   2:          Dim report = devicehandler.CreateOutputReport()
   3:          Dim daten() As Byte = {&H11, &H10, &H0, &H0, &H0,
   4:                                 &H0, &H0, &H0, &H0, &H0,
   5:                                 &H0, &H0, &H0, &H0, &H0,
   6:                                 &H0, &H0, &H0, &H0, &H0,
   7:                                 &H0, &H0}
   8:   
   9:          report.Data = daten.AsBuffer
  10:          Await devicehandler.SendOutputReportAsync(report)
  11:  End Function

WICHTIG: Dies klappt bei mir nicht! Vielleicht hat ja jemand einen Tipp.

Danke an Brian Peek für Support.

Kommentare sind geschlossen