// clear out the USB input buffer public void FlushReadUSB() { // note the starting time so we don't wait forever DateTime t0 = DateTime.Now; // wait until a read would block int rptLen = inputReportLength; while ((DateTime.Now - t0).TotalMilliseconds < 100) { // set up a non-blocking read IntPtr buf = Marshal.AllocHGlobal(rptLen); try { unsafe { // set up the overlapped I/O descriptor Overlapped o = new Overlapped(0, 0, evov.SafeWaitHandle.DangerousGetHandle(), null); NativeOverlapped *no = o.Pack(null, null); // start the non-blocking read Marshal.WriteByte(buf, 0); HIDImports.ReadFile(fp, buf, rptLen, IntPtr.Zero, no); // check to see if it's ready immediately bool ready = evov.WaitOne(0); if (ready) { // it's ready - complete the read UInt32 readLen; int result = HIDImports.GetOverlappedResult(fp, no, out readLen, 0); } else { // Not ready - we'd have to wait to do a read, so the // buffer is empty. Cancel the read. HIDImports.CancelIo(fp); } // done with the overlapped I/O descriptor Overlapped.Unpack(no); Overlapped.Free(no); // if there was nothing ready to read, we've cleared out buffered // inputs, so we're done if (!ready) { return; } } } finally { Marshal.FreeHGlobal(buf); } } }
public bool WriteUSB(byte[] buf) { for (int tries = 0; tries < 3; ++tries) { unsafe { // write the data - the file handle is in overlapped mode, so we have to do // this as an overlapped write with an OVERLAPPED structure and an event to // monitor for completion Overlapped o = new Overlapped(0, 0, evov.SafeWaitHandle.DangerousGetHandle(), null); NativeOverlapped *no = o.Pack(null, null); IntPtr hbuf = Marshal.AllocHGlobal(buf.Length); try { Marshal.Copy(buf, 0, hbuf, buf.Length); HIDImports.WriteFile(fp, hbuf, buf.Length, IntPtr.Zero, no); // wait briefly for the write to complete if (evov.WaitOne(250)) { // successful completion - get the result UInt32 actual; int result = HIDImports.GetOverlappedResult(fp, no, out actual, 0); Overlapped.Unpack(no); Overlapped.Free(no); if (result == 0) { // the write failed - try re-opening the handle and go back // for another try TryReopenHandle(); continue; } else if (actual != buf.Length) { // length is wrong - the write failed return(false); } else { // success return(true); } } else { // The write timed out. Cancel the write and try reopening the handle. HIDImports.CancelIo(fp); Overlapped.Unpack(no); Overlapped.Free(no); if (TryReopenHandle()) { continue; } return(false); } } finally { Marshal.FreeHGlobal(hbuf); } } } // maximum retries exceeded - return failure return(false); }
public byte[] ReadUSB() { // try reading a few times, in case we lose the connection briefly int rptLen = inputReportLength; for (int tries = 0; tries < 3; ++tries) { unsafe { // set up a non-blocking ("overlapped") read IntPtr buf = Marshal.AllocHGlobal((int)rptLen); try { Marshal.WriteByte(buf, 0); Overlapped o = new Overlapped(0, 0, evov.SafeWaitHandle.DangerousGetHandle(), null); NativeOverlapped *no = o.Pack(null, null); HIDImports.ReadFile(fp, buf, rptLen, IntPtr.Zero, no); // Wait briefly for the read to complete. But don't wait forever - we might // be talking to a device interface that doesn't provide the type of status // report we're looking for, in which case we don't want to get stuck waiting // for something that will never happen. If this is indeed the controller // interface we're interested in, it will respond within a few milliseconds // with our status report. if (evov.WaitOne(100)) { // The read completed successfully! Get the result. UInt32 readLen; int result = HIDImports.GetOverlappedResult(fp, no, out readLen, 0); Overlapped.Unpack(no); Overlapped.Free(no); if (result == 0) { // The read failed. Try re-opening the file handle in case we // dropped the connection, then re-try the whole read. TryReopenHandle(); continue; } else if (readLen != rptLen) { // The read length didn't match what we expected. This might be // a different device (not a Pinscape controller) or a different // version that we don't know how to talk to. In either case, // return failure. return(null); } else { // The read succeed and was the correct size. Return the data. byte[] retbuf = new byte[rptLen]; Marshal.Copy(buf, retbuf, 0, rptLen); return(retbuf); } } else { // The read timed out. This must not be our control interface after // all. Cancel the read and try reopening the handle. HIDImports.CancelIo(fp); Overlapped.Unpack(no); Overlapped.Free(no); if (TryReopenHandle()) { continue; } return(null); } } finally { Marshal.FreeHGlobal(buf); } } } // don't retry more than a few times return(null); }
/// <summary> /// Reading in another Thread /// </summary> private void OnReadData(object threadSleepTime) { Log("Read Thread started"); try { int sleepTime = (int)threadSleepTime; while (readAsync) { byte[] buff = new byte[REPORT_LENGTH]; uint numberOfBytesRead = 0; NativeOverlapped overlapped = new NativeOverlapped(); overlapped.EventHandle = mre.SafeWaitHandle.DangerousGetHandle(); overlapped.OffsetHigh = 0; overlapped.OffsetLow = 0; bool result = HIDImports.ReadFile(this.SafeFileHandle.DangerousGetHandle(), buff, (uint)buff.Length, out numberOfBytesRead, ref overlapped); Log("ReadReport: " + result.ToString()); if (!result) { uint lastError = HIDImports.GetLastError(); if (lastError != HIDImports.ERROR_IO_PENDING) { Log("Read failed: " + lastError.ToString("X")); continue; } else { if (!HIDImports.GetOverlappedResult(this.SafeFileHandle.DangerousGetHandle(), ref overlapped, out numberOfBytesRead, true)) { lastError = HIDImports.GetLastError(); Log("Read failed: " + lastError.ToString("X")); continue; } if (overlapped.InternalHigh.ToInt32() == HIDImports.STATUS_PENDING || overlapped.InternalLow.ToInt32() == HIDImports.STATUS_PENDING) { Log("Read interrupted " + lastError.ToString("X")); if (!HIDImports.CancelIo(this.SafeFileHandle.DangerousGetHandle())) { lastError = HIDImports.GetLastError(); Log("CancelIO failed: " + lastError.ToString("X")); continue; } } } } // parse it if (buff != null) { if (ParseInputReport(buff)) { if (WiiControllerStateChanged != null) { WiiControllerStateChanged(this, new WiiControllerStateChangedEventArgs(this.WiiControllerState)); } } } Thread.Sleep(sleepTime); } } catch (ThreadAbortException ex) { Log("Thread abort!: " + ex.Message); } }