.. include:: ../../../../lib_xud/doc/rst/version.rst

.. include:: ../../README.rst

|newpage|

Overview
--------

Introduction
............

The USB specification allows the creation of completely custom USB
devices which do not conform to any other of the USB device class standards.

These types of devices when enumerating as a USB device declares to the host 
that it is vendor specific and that the host should not attempt to
interface to it in any way other than to enumerate the device on the USB bus.

A vendor specific device can contain a number of endpoints and endpoint types 
which relate to this vendor specific device and the device class descriptor is used to specify how the device is structured.

Examples of such devices would include

  - Adapters which bridge debug interfaces such as JTAG to a host PC

  - Devices which control a variety of custom interfaces from a host PC

  - Systems which stream large amounts of captured data to a host PC

In most cases these systems implement a custom command set over USB in order
to send commands to the USB device to perform operations. 

These devices also require a custom driver for the host machine on Windows as
there is no OS support for custom vendor specific devices. In most cases the 
interface provided by the USB device is also vendor specific and requires
a vendor specific host application in order to use the device.

There is no USB specification for devices of this type as it is vendor specific,
the specification for the USB 2.0 standard in general can be found here,

(http://www.usb.org/developers/docs/usb20_docs/usb_20_081114.zip)

Block diagram
.............

.. figure:: images/block_diagram.*
   :scale: 100%
   :align: center

   Block diagram of USB vendor specific device application example

USB Vendor Specific Device Application Note
-------------------------------------------

The demo in this note uses the XMOS USB device library and shows a simple program that creates a basic vendor specific device which responds to data transfer requests from the host PC.

For the USB HID class application example, the system comprises three tasks running on separate logical cores of a xCORE-USB multicore microcontroller. 

The tasks perform the following operations.

   - A task containing the USB library functionality to communicate over USB

   - A task implementing Endpoint0 responding to standard USB control requests

   - A task implementing the application code for our custom bulk interface

These tasks communicate via the use of xCONNECT channels which allow data to be passed between application code running on the separate logical cores.

The following diagram shows the task and communication structure for this USB printer device class application example.  

.. figure:: images/task_diagram.*

        Task diagram of vendor specific bulk endpoint device
    

Makefile additions for this example
...................................

To start using the USB library, you need to add ``lib_xud`` to your makefile::

	USED_MODULES = ...  lib_xud ...

You can then access the USB functions in your source code via the usb.h header file::

	#include <usb_device.h>

Declaring resource and setting up the USB components
....................................................
 
``main.xc`` contains the application implementation for a USB vendor specific device. There are some defines in it that are used to configure the XMOS USB device library. These are displayed below.

The second set of defines describe the endpoint configuration for this device. This example has bi-directional communication with the host machine via the standard endpoint0 and an endpoint for implementing the vendor specific bulk endpoint with is also bi-directional.

.. literalinclude:: main.xc
   :start-on: [XUD_EP_COUNT_OUT
   :end-before: return

These defines are passed to the setup function for the USB library which is called 
from ``main()``.

The application main() function
...............................

Below is the source code for the main function of this application, which is taken from
the source file ``main.xc``

.. literalinclude:: main.xc
   :start-on: int main

Looking at this in a more detail you can see the following:

  - The par functionality describes running three separate tasks in parallel

  - There is a function call to configure and execute the USB library: ``XUD_Main()``

  - There is a function call to startup and run the Endpoint0 code: ``Endpoint0()``

  - There is a function to deal with the custom bulk endpoints ``bulk_endpoint()``

  - The define USB_TILE describes the tile on which the individual tasks will run

  - In this example all tasks run on the same tile as the USB PHY although this is only a requirement of ``XUD_Main()``

  - The xCONNECT communication channels used by the application are set up at the beginning of ``main()``

  - The USB defines discussed earlier are passed into the function ``XUD_Main()``

Configuring the USB Device ID
.............................

The USB ID values used for Vendor ID (VID), Product ID (PID) and device version number are defined in the file ``endpoint0.xc``. These are used by the host machine to determine the vendor of the device (in this case XMOS) and the product plus the firmware version.

.. literalinclude:: endpoint0.xc
   :start-on: BCD_DEVICE
   :end-on: PRODUCT_STR_INDEX

USB Vendor Specific Class specific defines
..........................................

The USB Vendor Specific Class is configured in the file ``endpoint0.xc``. 
Below there are a set of standard defines which are used to configure the 
USB device descriptors to setup a USB vendor specific device running on an 
xCORE microcontroller.

.. literalinclude:: endpoint0.xc
   :start-on: VENDOR_SPECIFIC_CLASS
   :end-on: VENDOR_SPECIFIC_PROTOCOL

These are defined in the USB standard as required in the device description for
vendor specific devices and for configuring them as such with the USB host machine.
   
USB Device Descriptor
.....................

``endpoint0.xc`` is where the standard USB device descriptor is declared for a vendor specific device. Below is the structure which contains this descriptor. This will be requested by the host when the device is enumerated on the USB bus. This descriptor contains the vendor specific defines described above.

.. literalinclude:: endpoint0.xc
   :start-on: devDesc 
   :end-on: }

From this descriptor you can see that product, vendor and device firmware revision are all coded into this structure. This will allow the host machine to recognise our vendor specific device when it is connected to the USB bus.

|newpage|

USB Configuration Descriptor
............................

The USB configuration descriptor is used to configure the device  class and the endpoint setup. For the USB vendor specific device provide in this example the configuration descriptor which is read by the host is as follows.

.. literalinclude:: endpoint0.xc
   :start-on: cfgDesc
   :end-on: }

This decriptor is in the format decribed by the USB 2.0 standard and contains the encoding for the endpoints related to control endpoint 0 and also the descriptors that decribe the 2 bulk endpoints which form our custom device.

|newpage|

USB string descriptors
......................

The final descriptor for our vendor specific device is the string descriptor which the host machine uses to report to the user when the device is enumerated and when the user queries the device on the host system. This is setup as follows.

.. literalinclude:: endpoint0.xc
   :start-on: String table
   :end-on: }

USB Vendor Specific Class Endpoint0
...................................

The function ``Endpoint0()`` contains the code for dealing with device requests made from 
the host to the standard endpoint0 which is present in all USB devices. 

There are no additional requests which need to be handled for a vendor specific device.

.. literalinclude:: endpoint0.xc
   :start-on: Endpoint 0 Task

|newpage|

Handling requests to the custom bulk endpoints
..............................................

The application endpoints for receiving and transmitting to the host machine are implemented in the file ``main.xc``. This is contained within the function ``bulk_endpoint()`` which is shown below:

.. literalinclude:: main.xc
   :start-on: bulk_endpoint(
   :end-before: The main

From this you can see the following.

  - A buffer is declared to communicate and transfer data with the host ``host_transfer_buf`` of size BUFFER_SIZE.

  - This task operates inside a ``while (1)`` loop which repeatedly deals with a sequence of requests from the host to send data to the device and then host to then read data from the device.

  - A blocking call is made to the XMOS USB device library to receive (using ``XUD_GetBuffer``) and send data (using ``XUD_SetBuffer``) to the host machine at every loop iteration.

  - The function performs some basic processing on the recieved host buffer and simply
    increments the values in the buffer received from the host and then sends it back.

  - This simple processing could easily be replaced with access to a piece of hardware connected to the xCORE GPIO or communication with another parallel task.
 
|appendix|
|newpage|

Demo Hardware Setup
-------------------

To setup the demo hardware the following boards are required.

  - xCORE-200 or xCORE.AI EXPLORER Board
  - xTAG debug adaptor
  - 1 x Micro-B USB cable
  - The xCORE-200 EXPLORER board requires an additonal USB Micro-b cable to supply power

.. figure:: images/explorerkit-200.*
   :scale: 110%
   :align: center

   XMOS xCORE-200 EXPLORER Board

The hardware should be configured as follows for this demonstration:

  - The XTAG debug adapter should be connected to the XSYS connector and
    the XTAG USB should be connected to the host machine.

  - The EXPLORER board should be connected to the host machine using a USB 
    cable.

  - (The xCORE-200 EXPLOERE board should have the power supplied via the *5V IN* receptical)

The use of xSCOPE is required in this application so that the print messages that are generated on 
the device as part of the demo do not interfere with the real-time behavior of the USB device.

|newpage|

Host Application Setup
----------------------

Test application
................

This simple host example demonstrates simple bulk transfer requests between
the host processor and the XMOS device.

The application simply transfers a data buffer to the device and back.
The device increments the data values before returning the new values
to the host. The host then increments the values and sends them again
a number of times.

The binaries and (where required) setup scripts are provided for each
sample platform in the named directory.

Windows driver
..............

On Windows you require a custom driver to support the vendor specific USB
device. This is provided in the driver directory within the Win32 directory. When starting the device for the first time you will need to point Windows at this
directory when it requests a driver to install for the device.

Licensing
.........

libusb is written in C and licensed under the LGPL-2.1.


Compilation instructions
........................

If you require to recompile the binary test program then the instructions to do so are below for each platform,

Win32::

  cl -o bulktest ..\bulktest.cpp -I ..\libusb\Win32 ..\libusb\Win32\libusb.lib

OSX::

  g++ -o bulktest ../bulktest.cpp -I ../libusb/OSX ../libusb/OSX/libusb-1.0.0.dylib -m32

Linux32::

  g++ -o bulktest ../bulktest.cpp -I ../libusb/Linux32 ../libusb/Linux32/libusb-1.0.a -lpthread -lrt

Linux64::

  g++ -o bulktest ../bulktest.cpp -I ../libusb/Linux64 ../libusb/Linux64/libusb-1.0.a -lpthread -lrt


Launching the demo application
------------------------------

Once the demo example has been built either from the command line using
xmake or via the build mechanism of xTIMEcomposer studio the applcation
can be executed on the xCORE-200 or xCORE.AI EXPLORER Board. 

Once built there will be a ``bin`` directory within the project which
contains the binary for the xCORE device. The xCORE binary has a XMOS standard 
.xe extension.

Launching from the command line
...............................

From the command line the ``xrun`` tool is used to download code to the
xCORE device. Changing into the bin directory of the project
the code can be executed on the xCORE microcontroller as follows::

> xrun app_vendor_specific_demo.xe          <-- Download and execute the xCORE code

Once this command has executed the vendor specific USB device should have 
enumerated on the host machine

Launching from xTIMEcomposer Studio
...................................

From xTIMEcomposer Studio the run mechanism is used to download code to the
xCORE device. Select the xCORE binary from the bin directory, right click 
and then run as xCORE application will execute the code on the xCORE device.

Once this command has executed the vendor specific USB device should have 
enumerated on your machine

Running the vendor specific host demo
......................................

To run the example, source the appropriate setup script and then execute
the 'bulktest' application from the command line.

This will connect to the USB device running on the xCORE microcontroller and
transfer data buffers back and forth.

The output should be similar to below::

  XMOS Bulk USB device opened .....
  Timing write/read of 1000 512-byte buffers.....
  125 ms (7.81 MB/s)
  XMOS Bulk USB device data processed correctly .....
  XMOS Bulk USB device closed .....

This application is intended as a simple demonstration application and has not
been programmed for efficient data transfer. The performance reported for this
simple application will vary depending on the capabilities of your USB host and host operating system.

|newpage|

Bulk read benchmark example
---------------------------

Currently the optimized bulk read benchmark is only supported on OSX and Linux, Windows is not
supported at this time.

Included with the example host code is a bulk read benchmark demo. This demonstrates high performance
data throughput from the device to the host. The main difference is in the host code which uses 
asynchronous non blocking calls to utilize the USB bus more effectively. In order to run this benchmark 
you need to do the following.

Device code changes
...................

There is an replacement function that needs to be used in the xCORE device code, this can be swapped in
by editing 'src/main.xc' and changing the call in main() from 'bulk_endpoint' to 'bulk_endpoint_read_benchmark'. This function is a simplified version of the one used in the full example but only deals with read requests from the USB host.

The code can be seen below,

.. literalinclude:: main.xc
   :start-on: bulk_endpoint_read_benchmark(
   :end-before: /*

From this the following can be seen,

  - The host transfer length is set to 512 bytes to match the host application

  - The while loop has been unrolled to contain 8 calls to 'XUD_SetBuffer'

  - The from host endpoint is not used but it still needs to be initialized

Once you have made the changes to the application mentioned above it needs to be rebuilt and
executed using the instructions in APPENDIX C

Host code changes
.................

There is a new host application provided to work with this example, it is contained in the file
'bulk_read_benchmark.cpp' which is in the host directory. In order to use this you will need to use 
the instructions for building the host application in APPENDIX B for your required platform. The only change to the command line it to replace the file 'bulktest.cpp' with 'bulk_read_benchmark.cpp'. 

Once you have built this it can be executed as described in APPENDIX C.3

This example runs forever and will need to be terminated with a ctrl-C when required.

The output should look as follows, with the performance depending on host platform and USB hardware::

  XMOS Bulk USB device opened .....
  Read transfer rate 32.19 MB/s
  Read transfer rate 34.94 MB/s
  Read transfer rate 39.56 MB/s
  Read transfer rate 39.62 MB/s
  Read transfer rate 39.56 MB/s
  Read transfer rate 39.56 MB/s
  Read transfer rate 39.56 MB/s
  Read transfer rate 39.56 MB/s
  Read transfer rate 39.56 MB/s

|newpage|

References
----------
  
.. nopoints::

  * XMOS Tools User Guide

    http://www.xmos.com/published/xtimecomposer-user-guide

  * XMOS xCORE Programming Guide

    http://www.xmos.com/published/xmos-programming-guide
  
  * XMOS xCORE-USB Device Library: 

    http://www.xmos.com/published/xuddg

  * XMOS USB Device Design Guide: 

    http://www.xmos.com/published/xmos-usb-device-design-guide

  * USB 2.0 Specification

    http://www.usb.org/developers/docs/usb20_docs/usb_20_081114.zip

|newpage|

Full source code listing
------------------------

Source code for endpoint0.xc
............................

.. literalinclude:: endpoint0.xc
  :largelisting:

Source code for main.xc
.......................

.. literalinclude:: main.xc
  :largelisting:

|newpage|

