NOTE: Please skip to the bottom of the article if you are using Windows 8.1 RTM.

Everyone loves a good challenge, and the additional device APIs featured in Windows 8.1 certainly presented a challenge. Having attended the BUILD conference in June I was thrilled to get the opportunity to re-present what I felt where some of the most drastic changes in the WinRT APIs – the extension of the Windows.Devices and Windows.Networking namespaces.

I’ve already blogged a summary about the API changes, so I don’t want to spend anytime here on what other surprises I encountered.For this particular post I want to focus on the addition of USB API’s in WinRT and how we can now start to access USB devices using C#/C++/JS from our modern/Windows store applications.

Introducing the OWI-535

So I had set myself a goal, integrate a USB device into a modern app and demonstrate it on stage. I thought it would be simple; but what I didn’t realise was the how scare USB peripherals where in Australia. The Windows.Devices.USB namespace excludes the more generic USB peripherals such as keyboard, mice, printers, scanners, and HID devices as they have their own APIs. So to execute this demo I needed to find a generic USB device. I walked around stores looking for a gadget that wasn’t Bluetooth, or iOS orientated and failed. Since I put the call out on Twitter for ideas, and within hours someone had introduced me to the OWI 535 robotic arm kit. The device is essentially a children’s toy. I ordered the kit and USB main board from Amazon and it arrived a few days later. What I failed to realise though is how basic the kit was. It is similar in fashion to the airfix kits I built as child. All the parts needed to be cut from the plastic moulding and you build the arm from the ground up, gear by gear. The box said aged 8+ – but it took me 3 hours to complete the assembly including some re-work due to misreading the instructions. Upon completion however you are presented with a robotic arm with a USB connection which *should* work on your computer. Enter the second complication – the driver OWI provide with the kit is a generic USB controller driver which is not signed by the manufacturer. So if you want to test your arm is working, you need to boot Windows 8 into advanced mode and turn off driver signing verification. This will allow you to install the software from the website, and run the supplied flash application to test all the gears are working correctly. I would highly recommend doing this, as I encountered issues and had to make some tweaks to obtain a full range of motion. Once you are happy you have a fully working robotic arms, lets move on to our modern app and WinUSB coding.

WinUSB – USB drivers for Windows 8

Previous USB devices installed into Windows that don’t have another device description (HID, Media, etc) usually present themselves as a USB controller. They either use a custom driver supplied by the manufacturer or a generic driver as documented in the device .inf file. The OWI robotic arm follows exactly the same system except the driver is unsigned.

If we want to access the device WinRT APIs this process actually changes. We need our devices to present themselves using a drive called a Universal Serial Bus Device, instead of the generic controller. This is a new driver referred too as WinUSB. Moving forward I hope more manufactures start deriving their USB devices to the new standard and updating their inf files (which can be pushed out via Windows update). For this demo though, as we hacked the device into Windows in the first place, we’ll bridge the gap using yet another hack.

Step 1 – remove the existing driver.

Step 2 –  Force the device to use the new WinUSB driver

image

 

image

 

image

 

OK we are now good to go, and can start moving into some coding.

 

Windows.Devices.USB – Accessing our device within a modern app

As with any modern application we are security sandboxed and we require explicit consent from the user to break out of this sandbox. We do this by declaring our intentions within the appx manifest file. Visual Studio 2013 currently doesn’t provide a GUI for editing the new capabilities within Windows 8.1 apps so we need to manually add the following elements to the XML file.

<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest" xmlns:m2="http://schemas.microsoft.com/appx/2013/manifest">
...
<Capabilities>
    ....
    <!--When the device's classId is FF * *, there is a predefined name for the class. You can use the name instead of the class id. 
          There are also other predefined names that correspond to a classId.-->
    <m2:DeviceCapability Name="usb">
      <m2:Device Id="vidpid:1267 0000">
        <m2:Function Type="classId:ff 00 00" />
      </m2:Device>
    </m2:DeviceCapability>
  </Capabilities>
</Package>

The above declaration is similar to previous device capabilities such as NFC, geolocation, etc. The one exception here is we are being specific about the device we wish to access by specifying the Vendor ID (VID) and Product Id (PID). We can be slightly more open with this standard, so for example if we wanted to create software for a range of devices by the same manufacturer we can edit this declaration to allow it. The biggest limitation is we cannot ask simply to access all USB devices. MSDN documents the criteria we can request here.

Once we have a declaration we can start writing some code. I’m going to execute these demos in C# but as with all APIs you can easily convert this to JS or C++.

The first thing we are going to do is use our Device APIs to identify if the device exists on the system. We have two ways of doing this, using a device watcher or as per the below code searching for the devices connected to the machine at that moment in time using the Windows.Devices.USB.USBDevice object.

const UInt32 vid = 0x1267;
const UInt32 pid = 0x0000;

 string aqs = UsbDevice.GetDeviceSelector(vid, pid);

 var deviceInfo = await DeviceInformation.FindAllAsync(aqs);
_usb = await UsbDevice.FromIdAsync(deviceInfo[0].Id);

 

The above code simply constructs a device selector or query string (similar to a SQL search) and executes it against the Windows.Devices.Enumeration.DeviceInformation object. This is essentially searching the OS device manager to see if any devices match. It returns a collection, and in this particular demo I know I only have on object attached so I use the first index, and use the method FromIdAsync on Windows.Devices.USB.USBDevice to open a connection to the USB device.

At this point we now have an open socket to the device we wish to communicate to, and can start passing data backwards and forwards. As the device we using controls several servo’s many of the commands we want to send are fairly similar so I’m going to demonstrate one only – but I’ll upload the full code for the project onto a Github repo.

Sending a command to the USB device in this instance is as simple as passing a command of 3 different values, which element we wish to control, in which direction, and for how long. This equates to a 3 byte array being sent on each payload, which is wrapped by a USB Setup control packet. Here is the raw code for sending a command:

 public async Task SendControl(int op1, int op2, int op3)
        {
            var bytes = new[] {Convert.ToByte(op1), Convert.ToByte(op2), Convert.ToByte(op3)};
            var buffer = bytes.AsBuffer();

            var setupPacket = new UsbSetupPacket();
            var requestType = new UsbControlRequestType();
            requestType.ControlTransferType = UsbControlTransferType.Vendor;
            requestType.Direction = UsbTransferDirection.Out;
            requestType.Recipient = UsbControlRecipient.Device;
            setupPacket.RequestType = requestType;
            setupPacket.Request = 6;
            setupPacket.Value = 0x0100;
            setupPacket.Length = buffer.Length;
            setupPacket.Index = 0;

            var transferred =  await _usb.SendControlOutTransferAsync(setupPacket, buffer);
            if (transferred == buffer.Length)
            {
                Debug.WriteLine("Message sent");
            }

}

The method takes x3 parameters which are constructed into our request. I’ll explain what we send in a second. To actually get the data to the device, it’s simply a matter of constructing a USBSetupPacket object. The method in which data is transferred to the device may vary, so this won’t necessarily work on other devices – so I recommend you consult any documentation you can find regarding the device you are using at this point.  The way I describe the setup packet to many people is similar to the HTTP Header on a HTTP request. It contains the meta data the protocol uses to deliver the object in the correct location. Many of the values are enums and are in-fact self explanatory = such as the direction, who is going to receive it, the length of the actual request. This setup packet is constant through every communication with the device, so once we have constructed it once prepare to re-use it many times. To send the actual packet to the device, we use the async method SendControlOutTransferAsync, which as the name implies sends a control package outwards. It takes 2 parameters the setup packet you’ve just constructed, and the byte array which has been converted to an IBuffer argument which represents the actual payload.

That is actually all that is required to control the device. In terms of an argument to pass in

await SendCommand(0x02, 0x00, 1000);

These parameters specify the motor which we are targeting (to open the grippers), the direction which is positive allowing , the time in milliseconds to operate. These commands vary slightly per motor so I’ll upload the full demo onto Github for you to play around with.

However that’s all that is required to have a Windows 8.1 tablet start talking to your OWI robotic arm. So next step – is making that awesome app.

Full source code for this demo app can be found here: https://github.com/lewisbenge/Win81-OWI535-RobotArm

Getting the device working on Windows 8.1 RTM

Since the RTM release appeared on MSDN within the last week the above code had actually stopped working. This is because the RTM build of Windows 8.1 enforces the criteria on WinUSB device drivers to expose a an interface GUID (which would normally be done either via the driver or device firmware). To get the device working with Windows 8.1 I have actually created an unsigned driver information file (.inf) for the OWI-535 device. This allows you to update the driver of the device installed as per the above instructions with the additional metadata required. At this time the driver file remains unsigned (I’m in two minds about personally signing this file) so you will need to boot into advanced mode and disable driver verification to install the new driver (instructions here: http://www.howtogeek.com/167723/how-to-disable-driver-signature-verification-on-64-bit-windows-8.1-so-that-you-can-install-unsigned-drivers/). Once you have rebooted, download the new inf file from here: https://github.com/lewisbenge/Win81-OWI535-RobotArm/blob/master/OWI-535.inf. Once you have the file on your machine simply open device manager, right click on the WinUSB device, and click update driver using the new file. From there all of the above code should work without issue.

If you have any problems with the driver file, or code please get in contact with me.

 


				
Tagged on:             

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>