• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

Probleme mit dem Auslesen von Daten der Wii-Fernbedienung (C#)

Timon3

Team ModMii

Registriert
17 Juli 2013
Beiträge
499
Hallo zusammen!

Bei uns an der Schule ist momentan Facharbeitsphase. Dabei habe ich mich für Informatik entschieden (weil mir das Fach ziemlich viel Spaß macht). Für die Facharbeit wollte/will ich selbst die Daten der WiiMote "entschlüsseln" (also tatsächlich nutzbar machen) und darauf basierend eine Bibliothek schreiben. Klingt im ersten Moment ja nicht so komplex.

Also habe ich mir einen Bluetooth-Adapter geholt, alles installiert, WiiMote verbunden (klappt auch) und angefangen, indem ich mir den HID-Pfad hole. Klappt soweit, durch die VID und PID kann ich genau filtern, welches Device ich habe. Ich könnte das ganze durch P/Invoke natürlich selbst schreiben, aber es gibt dafür ganz ordentliche Bibliotheken (ich benutze diese hier. Das ist aber relativ egal, da ich auch den manuellen Weg schon erfolglos gegangen bin.

Zurück zum Problem. Jetzt will ich natürlich mit der Mote selbst was anstellen. Zuerstmal interessiert mich lesen. Dabei wird aber bei der asynchronen Operation das Callback nicht gerufen, und bei der synchronen kommt irgendwann eine Thread-Deadlock-Exception. Kacke, ich hab was falsch gemacht. Dachte ich. Aber dann hab ich mir einfach mal aus Jux aus einer bereits bestehenden Bibliothek abgeschaut, wie man genau die LEDs setzen kann. Kann doch jetzt gar nicht funktionieren! Aber ich hab es trotzdem mal probiert. Ergebnis: Ja, funktioniert ohne Probleme. Mist, was hab ich beim Lesen falsch gemacht? Nochmal probiert. Lesen geht. Jippie.

Nächster Morgen. PC angeschaltet, hochmotiviert weiter mit der Entwicklung gemacht - dachte ich, bis ich nochmal das lesen getestet habe. Funktioniert nicht. Hmpf. Anderen Bluetooth-Stack probiert - klappt genauso wenig. Anderen Bluetooth-Stick bestellt: Nada.

Da stehe ich nun also, mein Programm klappt nur sehr selten und vollkommen unreproduzierbar. In 95% aller Fälle kommt ein Read-Timeout oder ein Thread-Deadlock. Das nervigste ist: Ich hab meinen Code mit einer bereits bestehenden Bibliothek verglichen, die bei mir funktioniert. Ich hab keinen Unterschied gesehen.

Lange Rede, gar kein Sinn: Kann mir da jemand bei helfen? Ich wäre dafür jedenfalls unglaublich dankbar. Dieses Problem hat mich schon an die 10 Stunden googlen, neuinstallieren von verschiedensten Stacks, weinend in der Ecke liegen und noch mehr googlen gekostet.


Hier ist der betreffende Code:
[src=csharp]public partial class Form1 : Form {
private const int VID = 0x057E;
private const int PID = 0x0306;


private const int REPORT_LENGTH = 22;


private static HidDevice wiiMote;


public Form1()
{
InitializeComponent();
}


private void debug(Object pObject) {
}


private void connect()
{
wiiMote = HidDevices.Enumerate(VID, PID).FirstOrDefault();
if (wiiMote != null)
{
wiiMote.OpenDevice();
wiiMote.MonitorDeviceEvents = true;
wiiMote.Write(new byte[1]);
}
else
{
this.Text = "No Wiimote found!";
}
}


private void button1_Click(object sender, EventArgs e)
{
if (wiiMote.IsConnected && wiiMote.IsOpen)
{
HidDeviceData data = wiiMote.Read();
if (data.Status == HidDeviceData.ReadStatus.Success)
{
for (int i = 0; i < 22; i++)
{
Control[] ctrls = this.Controls.Find("label" + (i + 1), true);
if (ctrls.Length == 1)
ctrls[0].Text = i.ToString("X8") + ": " + data.Data.ToString("X8") + " " + data.Data.ToString();
}
}
}
}


private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
wiiMote.CloseDevice();
}


private void button2_Click(object sender, EventArgs e)
{
byte[] buff = new byte[2];
buff[0] = 0x11;
buff[1] = 0x20;
wiiMote.Write(buff);
}


private void Form1_Load(object sender, EventArgs e)
{
connect();
}
}[/src]


Hier der betreffende Code der Bibliothek:
[src=csharp]/// <summary>
/// Connect to a Wiimote paired to the PC via Bluetooth
/// </summary>
public void Connect()
{
int index = 0;
bool found = false;
Guid guid;


// get the GUID of the HID class
HIDImports.HidD_GetHidGuid(out guid);


// get a handle to all devices that are part of the HID class
// Fun fact: DIGCF_PRESENT worked on my machine just fine. I reinstalled Vista, and now it no longer finds the Wiimote with that parameter enabled...
IntPtr hDevInfo = HIDImports.SetupDiGetClassDevs(ref guid, null, IntPtr.Zero, HIDImports.DIGCF_DEVICEINTERFACE);// | HIDImports.DIGCF_PRESENT);


// create a new interface data struct and initialize its size
HIDImports.SP_DEVICE_INTERFACE_DATA diData = new HIDImports.SP_DEVICE_INTERFACE_DATA();
diData.cbSize = Marshal.SizeOf(diData);


// get a device interface to a single device (enumerate all devices)
while(HIDImports.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref guid, index, ref diData))
{
UInt32 size;


// get the buffer size for this device detail instance (returned in the size parameter)
HIDImports.SetupDiGetDeviceInterfaceDetail(hDevInfo, ref diData, IntPtr.Zero, 0, out size, IntPtr.Zero);


// create a detail struct and set its size
HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA diDetail = new HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA();


// yeah, yeah...well, see, on Win x86, cbSize must be 5 for some reason. On x64, apparently 8 is what it wants.
// someday I should figure this out. Thanks to Paul Miller on this...
diDetail.cbSize = (uint)(IntPtr.Size == 8 ? 8 : 5);


// actually get the detail struct
if(HIDImports.SetupDiGetDeviceInterfaceDetail(hDevInfo, ref diData, ref diDetail, size, out size, IntPtr.Zero))
{
Debug.WriteLine(index + " " + diDetail.DevicePath + " " + Marshal.GetLastWin32Error());


// open a read/write handle to our device using the DevicePath returned
mHandle = HIDImports.CreateFile(diDetail.DevicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, HIDImports.EFileAttributes.Overlapped, IntPtr.Zero);


// create an attributes struct and initialize the size
HIDImports.HIDD_ATTRIBUTES attrib = new HIDImports.HIDD_ATTRIBUTES();
attrib.Size = Marshal.SizeOf(attrib);


// get the attributes of the current device
if(HIDImports.HidD_GetAttributes(mHandle.DangerousGetHandle(), ref attrib))
{
// if the vendor and product IDs match up
if(attrib.VendorID == VID && attrib.ProductID == PID)
{
Debug.WriteLine("Found it!");
found = true;


// create a nice .NET FileStream wrapping the handle above
mStream = new FileStream(mHandle, FileAccess.ReadWrite, REPORT_LENGTH, true);


// start an async read operation on it
BeginAsyncRead();


// read the calibration info from the controller
try
{
ReadCalibration();
}
catch
{
// if we fail above, try the alternate HID writes
mAltWriteMethod = true;
ReadCalibration();
}


// force a status check to get the state of any extensions plugged in at startup
GetStatus();


break;
}
else
{
// otherwise this isn't the controller, so close up the file handle
mHandle.Close();
}
}
}
else
{
// failed to get the detail struct
throw new WiimoteException("SetupDiGetDeviceInterfaceDetail failed on index " + index);
}


// move to the next device
index++;
}


// clean up our list
HIDImports.SetupDiDestroyDeviceInfoList(hDevInfo);


// if we didn't find a Wiimote, throw an exception
if(!found)
throw new WiimoteException("Wiimote not found in HID device list.");
}


/// <summary>
/// Disconnect from the controller and stop reading data from it
/// </summary>
public void Disconnect()
{
// close up the stream and handle
if(mStream != null)
mStream.Close();


if(mHandle != null)
mHandle.Close();
}


/// <summary>
/// Start reading asynchronously from the controller
/// </summary>
private void BeginAsyncRead()
{
// if the stream is valid and ready
if(mStream != null && mStream.CanRead)
{
// setup the read and the callback
byte[] buff = new byte[REPORT_LENGTH];
mStream.BeginRead(buff, 0, REPORT_LENGTH, new AsyncCallback(OnReadData), buff);
}
}


/// <summary>
/// Callback when data is ready to be processed
/// </summary>
/// <param name="ar">State information for the callback</param>
private void OnReadData(IAsyncResult ar)
{
// grab the byte buffer
byte[] buff = (byte[])ar.AsyncState;


try
{
// end the current read
mStream.EndRead(ar);


// parse it
if(ParseInputReport(buff))
{
// post an event
if(WiimoteChanged != null)
WiimoteChanged(this, new WiimoteChangedEventArgs(mWiimoteState));
}


// start reading again
BeginAsyncRead();
}
catch(OperationCanceledException)
{
Debug.WriteLine("OperationCanceledException");
}
}[/src]
 
Oben