public bool WriteUSB(byte[] buf) { for (int tries = 0; tries < 3; ++tries) { UInt32 actual; if (HIDImports.WriteFile(fp, buf, 9, out actual, ref ov) == 0) { // try re-opening the handle, if it's an "invalid handle" error if (TryReopenHandle()) { continue; } Log.Write("Pinscape Controller USB error sending request to device: " + GetLastWin32ErrMsg()); return(false); } else if (actual != 9) { Log.Write("Pinscape Controller USB error sending request: not all bytes sent"); return(false); } else { return(true); } } // maximum retries exceeded - return failure return(false); }
public byte[] ReadUSB() { for (int tries = 0; tries < 3; ++tries) { const int rptLen = 15; byte[] buf = new byte[rptLen]; buf[0] = 0x00; uint actual; if (HIDImports.ReadFile(fp, buf, rptLen, out actual, ref ov) == 0) { // if the error is 6 ("invalid handle"), try re-opening the device if (TryReopenHandle()) { continue; } Log.Write("Pinscape Controller USB error reading from device: " + GetLastWin32ErrMsg()); return(null); } else if (actual != rptLen) { Log.Write("Pinscape Controller USB error reading from device: not all bytes received"); return(null); } else { return(buf); } } // don't retry more than a few times return(null); }
// Search the Windows USB HID device set for Pinscape controllers private static List <Device> FindDevices() { // set up an empty return list List <Device> devices = new List <Device>(); // get the list of devices matching the HID class GUID Guid guid; HIDImports.HidD_GetHidGuid(out guid); IntPtr hdev = HIDImports.SetupDiGetClassDevs(ref guid, null, IntPtr.Zero, HIDImports.DIGCF_DEVICEINTERFACE); // set up the attribute structure buffer HIDImports.SP_DEVICE_INTERFACE_DATA diData = new HIDImports.SP_DEVICE_INTERFACE_DATA(); diData.cbSize = Marshal.SizeOf(diData); // read the devices in our list for (uint i = 0; HIDImports.SetupDiEnumDeviceInterfaces(hdev, IntPtr.Zero, ref guid, i, ref diData); ++i) { // get the size of the detail data structure UInt32 size = 0; HIDImports.SetupDiGetDeviceInterfaceDetail(hdev, ref diData, IntPtr.Zero, 0, out size, IntPtr.Zero); // now actually read the detail data structure HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA diDetail = new HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA(); diDetail.cbSize = (IntPtr.Size == 8) ? (uint)8 : (uint)5; if (HIDImports.SetupDiGetDeviceInterfaceDetail(hdev, ref diData, ref diDetail, size, out size, IntPtr.Zero)) { // create a file handle to access the device IntPtr fp = HIDImports.CreateFile( diDetail.DevicePath, HIDImports.GENERIC_READ_WRITE, HIDImports.SHARE_READ_WRITE, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero); // read the attributes HIDImports.HIDD_ATTRIBUTES attrs = new HIDImports.HIDD_ATTRIBUTES(); attrs.Size = Marshal.SizeOf(attrs); if (HIDImports.HidD_GetAttributes(fp, ref attrs)) { // presume this is a Pinscape Controller, then look for reasons it's not bool ok = true; // read the product name string String name = "<not available>"; byte[] nameBuf = new byte[128]; if (HIDImports.HidD_GetProductString(fp, nameBuf, 128)) { name = System.Text.Encoding.Unicode.GetString(nameBuf).TrimEnd('\0'); } // If the vendor and product ID match an LedWiz OR our private ID, and the // product name contains "pinscape", and it's product version 7 or higher, // it's a Pinscape controller with the extended protocol features. bool isLW = ((ushort)attrs.VendorID == 0xFAFA && (attrs.ProductID >= 0x00F0 && attrs.ProductID <= 0x00FF)); bool isPS = ((ushort)attrs.VendorID == 0x1209 && ((ushort)attrs.ProductID == 0xEAEA)); ok &= ((isLW || isPS) && Regex.IsMatch(name, @"\b(?i)pinscape\b") && attrs.VersionNumber >= 7); // Newer versions of the device software can present multiple USB HID // interfaces, including Keyboard (usage page 1, usage 6) and Media // Control (volume up/down/mute buttons) (usage page 12, usage 1). // The output controller is always part of the Joystick interface // (usage page 1, usage 4). HidP_GetCaps() returns the USB usage // information for the first HID report descriptor associated with // the interface, so we can determine which interface we're looking // at by checking this information. Start by getting the preparsed // data from the Windows HID driver. IntPtr ppdata; if (ok && HIDImports.HidD_GetPreparsedData(fp, out ppdata)) { // get the device caps HIDImports.HIDP_CAPS caps = new HIDImports.HIDP_CAPS(); HIDImports.HidP_GetCaps(ppdata, ref caps); // This Pinscape interface accepts output controller commands only // if it's the joystick type (usage page 1 == generic desktop, usage // 4 == joystick). If it doesn't match, it must be a secondary HID // interface on the same device, such as the keyboard or media // controller interface. Skip those interfaces, as they don't // accept the output controller commands. ok &= (caps.UsagePage == 1 && caps.Usage == 4); // done with the preparsed data HIDImports.HidD_FreePreparsedData(ppdata); } // If we passed all tests, this is the output controller interface for // a Pinscape controller device, so add the device to our list. if (ok) { // add the device to our list devices.Add(new Device(fp, diDetail.DevicePath, name, attrs.VendorID, attrs.ProductID, attrs.VersionNumber)); // the device list object owns the handle nwo fp = System.IntPtr.Zero; } } // done with the file handle if (fp.ToInt32() != 0 && fp.ToInt32() != -1) { HIDImports.CloseHandle(fp); } } } // return the device list return(devices); }
private IntPtr OpenFile() { return(HIDImports.CreateFile( path, HIDImports.GENERIC_READ_WRITE, HIDImports.SHARE_READ_WRITE, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero)); }