AN82072 PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers.pdf

AN82072
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Author: Robert Murphy
Associated Project: Yes
Associated Part Family: All PSoC 3 and PSoC 5
Software Version: PSoC Creator™ 3.3 and higher
Related Application Notes: For a complete list of the application notes, click here.
AN82072 discusses how to use PSoC® 3 and PSoC 5LP devices to transfer generic data across USB using native
OS drivers included with Windows, Mac OS, and Linux. These drivers are part of the Human Interface Device (HID)
class, which is commonly used to support devices such as mice and keyboards, but can also be used for generic
data transfers. A PSoC project and a program for each operating system (with source code) demonstrating generic
data transfers are included with this application note.
Contents
1
2
3
4
5
6
Introduction ...............................................................1
The HID Class ..........................................................2
What is a Generic HID? ............................................3
Generic HID Report Descriptor .................................4
Supporting 64-Byte HID Reports ..............................9
Example Project: Generic Data Transfer via HID ... 10
6.1
PSoC Creator Configuration .......................... 10
6.2
Development Kit Configuration ...................... 21
6.3
Developing Desktop Applications .................. 24
6.4
Microsoft Windows Host Application .............. 25
6.5
Mac OS X Host Application............................ 28
6.6
Linux PC Application ...................................... 30
7
Writing Host Applications to Interface with HIDs..... 33
1
7.1
Windows Application Code ............................ 33
7.2
Mac OS X Application Code .......................... 38
7.3
Linux Application Code .................................. 44
8
Conclusion.............................................................. 47
9
Related Resources ................................................. 48
9.1
Application Notes ........................................... 48
9.2
Programming Language Books ..................... 48
A
Appendix A: (main.c) .............................................. 49
B
Appendix B: Form1.cs for Windows ....................... 52
C
Appendix C: AppDelegate.c for Mac OS X ............. 57
D
Appendix D: Linux_GenericHID_CLI.c for Linux..... 64
Document History............................................................ 69
Worldwide Sales and Design Support ............................. 70
Introduction
When developing a USB device to communicate with a PC for general data transfer, consider three primary device
classes: Human Interface, Communication, and Vendor Specific. Many developers adopt the Communication Device
class because it creates an easy-to-use COM port interface (which many PSoC users will better recognize as a
USBUART). Others elect to use the Vendor Specific Device class due to its extreme configurability with limitations
based solely on the restrictions of the USB specification and a company's development resources.
The largest downside to Communication and Vendor Specific device types is that frequently, when you attach a
peripheral to a computer, regardless of the operating system, the computer prompts for a device driver in the form of
an INF and/or a SYS file. To support multiple operating systems, the developer must maintain multiple driver files.
This requirement not only adds effort and frustration to the end-user but also development time and cost to the
company that developed the device.
However, the requirement changes if your USB data transfer needs are simple, specifically in an instance where you
do not need to send a lot of data very quickly. In that case, you can use the USB Human Interface Device (HID) class
for simple data transfer. This is the same device class used for keyboards and mice. The advantage to a HID method
is that you can create a simple and reliable way to communicate with a PC, without the need to provide a driver file.
This implementation is multi-platform without adding additional USB descriptor code to the device firmware.
www.cypress.com
Document No. 001-82072 Rev. *D
1
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Figure 1. HID and Operating System Synergy
Configuring a PSoC to accomplish a HID transfer is relatively simple if you follow a few instructions. It requires that
you configure a USBFS component, create a HID descriptor that defines two generic multiple byte containers to send
and receive data, and call several USB API functions in PSoC Creator to handle the data. This application note
explains the conceptual framework, describes how to configure PSoC 3 and PSoC 5LP devices as a generic HID,
and demonstrates how one PSoC device can communicate with a computer running Microsoft® Windows®, Apple®
Macintosh®, or Linux™.
Note: Some entry-level knowledge of USB and the HID class is recommended prior to reading this application note.
To prepare yourself for the concepts discussed in this document, see the Cypress application notes AN57294 – USB
101: An Introduction to Universal Serial Bus 2.0 and AN57473 – PSoC® 3 / PSoC 5LP USB HID Fundamentals.
2
The HID Class
The HID class is probably the most recognized of all the standardized USB classes available. It includes commonly
known devices such as mice, keyboards, and joysticks. In fact, AN57473 and AN58726 - PSoC® 3 / PSoC 5LP USB
HID Intermediate (with Keyboard and Composite Device) use these as examples for the HID class on PSoC 3 and
PSoC 5LP devices.
All HID data is transferred across the bus in a report. Reports are essentially containers of information in a structured
format sent and received by the host and device. Typically, in well-known HIDs such as a keyboard or mouse, the
host knows exactly what to do with the data it receives and what kind of data it should send. The host knows this
because the HID Report Descriptor has Usage labels that define specific data in the report as information about
button and switch state, LED status, or cursor position.
The greatest benefit of a HID is that for many years computer operating systems have included a standard class HID
driver to support various HID peripherals directly out of the box. This makes HID a great choice for any USB device
that contains a low data rate and can handle a limited latency. There are few additional considerations when
evaluating HID:





All data transactions must use either control or interrupt transfers.
The maximum transfer size is 64 bytes.
The maximum transfer rate is one for every 1 ms frame, which limits the throughput to 64 KB/s.
It supports only one Input Endpoint and one Output Endpoint.
The host periodically polls the HID for data.
If all these constraints are acceptable, then HID may prove a viable option for your next USB design.
www.cypress.com
Document No. 001-82072 Rev. *D
2
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
3
What is a Generic HID?
Support for HID has been in computer operating systems for many years. Specifically, Windows 98 was the first
operating system to include support for the USB class. Because of this, many manufacturers with devices requiring
USB connectivity are considering HID for their generic data transfer needs. The term "Human Interface Device" does
not imply that you need to have some type of human interface to use this class. In fact, many devices, such as UPSs
and programmable remotes, use the HID class for cross platform support. A HID configured to transfer generic data
is known as a Generic HID. These devices use the integrated HID drivers that operating systems already contain to
send any data that fits into a packet up to 64 bytes.
Custom HIDs are very similar to the traditional vendor-specific devices discussed in AN56377 - PSoC 3 and
PSoC 5LP USB Transfer Types, which require a custom driver. Configuration of a generic HID is identical to the
configuration of a more traditional HID such as a keyboard. The difference is in the HID Report Descriptor. The HID
Report Descriptor has Usage labels, which define the data sent in the reports. However, rather than defining the data
as buttons, switches, or LEDs, the Usage labels define the data as Vendor Specific. This allows us to create a
generic container of data that does not contain a specific function or purpose. Undefined bytes of data are sent in the
HID Reports between the device and host. It is then the responsibility of the host application and device firmware to
know what to do with the data.
With a Generic HID, you can develop a single PSoC USB device that works on all computing platforms without the
need to issue firmware updates later in the project roadmap or to plan for the support in advance. It requires only the
development of a host software application interface for each supported operating system. Another way to
significantly reduce development time is to choose a common programming language and USB library to interface
with the USB device. This reduces development time primarily by creating a common ground that can easily be
ported to the various operating systems.
Figure 2. Examples of HID and Generic HIDs
www.cypress.com
Document No. 001-82072 Rev. *D
3
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
4
Generic HID Report Descriptor
A report descriptor describes each piece of data that the device generates and receives as well as what that data
represents. For example, the report descriptor may define items that relate to button status or position information
such as the cursor movement of a mouse. For a Generic HID, the report descriptor creates generic data structures
that are used as containers to transmit data between the device and the host. The content of the data inside the
container is irrelevant. As a result, it is the responsibility of the device and the host application to know what the data
is, where to store it in the report, and determine proper endianness.
Note: With a HID, the configuration of the report descriptor is independent of the host computer operating system.
One Report Descriptor functions across multiple operating systems.
For the example project in this application note, we configure the Report Descriptor to address several requirements.
First, there are two reports: one to send data to the host (Input Report) and another to receive data from the host
(Output Report). Additionally, we send and receive only 8 bytes of data, although it is possible to expand this to 64
bytes. Figure 3 is a conceptualization of the container based on those requirements.
Figure 3. Input and Output Data Container
Input Report Data
Output Report Data
Input Byte 1
Output Byte 1
Input Byte 2
Output Byte 2
Input Byte 3
Output Byte 3
Input Byte 4
Output Byte 4
Input Byte 5
Output Byte 5
Input Byte 6
Output Byte 6
Input Byte 7
Output Byte 7
Input Byte 8
Output Byte 8
For the project, we also define the data sent to and received from the host. Table 1 lists the function and data
requirements of this project. MM
Table 1. Project Functions and Data Requirements
Report
www.cypress.com
Function
Bytes
Input
Push button status (asserted vs. de-asserted)
1
Input
ADC measurement result
4
Output
LED control signal (on vs. off)
1
Output
PWM duty cycle
1
Document No. 001-82072 Rev. *D
4
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Knowing the data size and direction, we can now choose our organization scheme for the containers. Because the
definition is for a generic data container, it does not matter where in the container we place the data. Figure 4 shows
the structure of the data. In Figure 4, the bytes of the report used in the example application are shaded in white while
the unused bytes are shaded in gray. The unused bytes represent data used by neither the PSoC nor the host
application. All the unused areas of the report are available to transfer additional data if you wish to expand the
example application.
Figure 4. Data Format for Input and Output
The next step is to define the HID Report Descriptor used to implement these reports. While the structure used to
format the data is important, note that we do not care about the organization structure when defining the HID Report
Descriptor. Figure 5 shows a HID Report Descriptor that creates 8-byte Input and Output Reports.
Figure 5. Report Descriptor for Generic HID
www.cypress.com
Document No. 001-82072 Rev. *D
5
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Next, we step through the HID Report Descriptor to better understand it. From an initial glance, it appears that most
of the information is just for bi-directional communication. Because our device does not conform to a specific,
predefined HID class, we must create a descriptor for a generic, vendor-defined HID. In previous HID examples such
as those in AN57473 and AN58726, we relied on a Usage Page of Generic Desktop Control whose function is for
applications such as mice, keyboards, joysticks, controllers, and so on. However, for a device whose only purpose is
to move data via the HID class, we use the Vendor Defined Page. We assign a Usage value of ‘01’ to indicate a
Vendor Usage label (Figure 6).
Figure 6. Vendor Defined Usage Page
Because this application sends data to a PC host and receives data from the PC, there are two sections of the HID
report descriptor: a portion that configures the Output Report and another portion that configures the Input Report.
Figure 7 outlines the sections responsible for the Output and Input.
Figure 7. Output and Input Sections of Report Descriptor
We start with configuration of the Usage Minimum and Maximum of the report descriptor. AN57473 describes these
parameters as follows:
“Usage Minimum and Maximum: Used to link Usage IDs to the data in an array or bitmap. The Usage Minimum
defines the starting point and the Usage Maximum defines the ending point.”
www.cypress.com
Document No. 001-82072 Rev. *D
6
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Therefore, we use the Usage Minimum and Usage Maximum to give each element (each byte) in the Input Report
and Output Report a vendor-defined usage (as opposed to a usage that defines the element as a button). To assign
all 8 bytes in each report, we set the Usage Minimum value to 1 and the Usage Maximum value to 8. Figure 8 shows
this configuration of the HID report descriptor. The red outline (upper box) indicates the configuration for the Output
Report, and the blue outline (lower box) indicates the configuration for the Input Report.
Figure 8. Usage Maximum/Minimum Configuration
Next, we configure the Logical Minimum and Maximum for the generic HID. AN57473 describes these parameters as
follows:
“Logical Maximum and Minimum: Determines the limits for reported values in an array or variable. For example, a
mouse that reports position values from 127 to -127 has a logical maximum of 127 and a logical minimum of -127."
Because each element is one byte in length, we define a Logical Minimum of ‘0x00’ and a Logical Maximum of ‘0xFF’
to allow a full-scale range of 8 bits. Figure 9 shows this configuration of the HID report descriptor. The red outline
indicates the configuration for the Output Report, and the blue outline indicates the configuration for the Input Report.
Figure 9. Logical Maximum/Minimum for Output Report
www.cypress.com
Document No. 001-82072 Rev. *D
7
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Now, we configure the report descriptor Report Size and Report Count. These two parameters determine the size of
the Input and Output Reports. AN57473 describes these parameters as:
“Report Size: Determines the size in bits of a field in an Input, Output, or Feature item.
“Report Count: Specifies number of data fields for an Input, Output, or Feature item.”
Figure 10 on page 6 shows the Report Size and Report Count for both the Input and the Output Reports. Based on
the definitions, the Report Size defines that each report field is 8 bits in length. To elaborate, if each report was an
array, the Report Size parameter would define each array element as 8 bits in size. Additionally, the Report Count
indicates that there are eight reports (also known as data fields). The result is an Input Report comprised of eight,
8-bit values. The Output Report is the same.
Figure 10. Report Size and Report Count Configuration
The final step for the HID Report Descriptor is to configure the Input and Output Items. Until now, all the parameters
for the Input and Output Reports are the same. It is the Item parameter that distinguishes between input and output
as shown in Figure 11.
Figure 11. Input and Output Item Configuration
www.cypress.com
Document No. 001-82072 Rev. *D
8
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Normally with non-generic HIDs, we make specific configuration settings to the Input and Output Items. Because this
application only creates containers for data, we can ignore these adjustments. Figure 12 demonstrates the lack of
adjustments to the Input and Output Items. It shows the configuration window as it appears in PSoC Creator. The bit
fields are all set to their default value of 0'b. Any change to these parameters does not affect the overall functionality
of the project.
Figure 12. OUTPUT/INPUT Item Bit Configuration
5
Supporting 64-Byte HID Reports
It only requires four edits to the HID report descriptor in order to expand from 8-byte reports to 64-byte reports.
Change the Usage Maximum and the Report Count items from a value of 8 to a value of 64 for both the Input and
Output portion of the descriptor (Figure 13). Additionally, you need to change the Input and Output Endpoint
Maximum Packet Size to 64 (from its default configuration of 8). We will look at how to accomplish this later.
Figure 13. How to Edit the Report Descriptor for 64-Bytes
Increase Usage
Maximum to 64
Increase Report
Count to 64
www.cypress.com
Document No. 001-82072 Rev. *D
9
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
6
Example Project: Generic Data Transfer via HID
This example project demonstrates both sides of the application. It demonstrates how to use and create a host
application to communicate between a computer running the Windows, Mac, or Linux operating system. It also
demonstrates how to use and configure the USBFS component in PSoC Creator to use the HID protocol. We transfer
information such as an ADC measurement and the status of a push button to the host via an Input transfer. The host
uses an Output transfer to send data to the PSoC to control the ON/OFF state of an LED along with the duty cycle of
a PWM connected to another LED. We demonstrate the process with the user interfaces for all three operating
systems.
6.1
PSoC Creator Configuration
6.1.1
Create the Project
1. Open PSoC Creator.
2.
Create an empty project, selecting either PSoC 3 or PSoC 5LP, and name it MyFirstGenericDevice.
3.
Place the following components from the PSoC Creator Component Catalog on to the schematic entry page
(TopDesign.cysch):





4.
USBFS
Character LCD
Delta Sigma ADC
PWM
Pin Components

Analog Pin (Quantity 1)

Digital Input Pin (Quantity 1)

Digital Output Pin (Quantity 2)
Use the wiring tool to arrange and connect the components as shown in Figure 14.
The gray boxes and annotation components are for clarification and not required for functionality. In addition, we
changed default names of the components. Modify the component names to ensure proper building and functionality
of the PSoC Creator project.
Figure 14. PSoC Creator Project Schematic Layout
www.cypress.com
Document No. 001-82072 Rev. *D
10
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
After arranging and placing all the components appropriately, the next step is to configure them so that they function
properly in our application. We start by configuring the USBFS component because it is the core component and
most important component in this design.
6.1.2
Configure the USBFS Component
1. Right-click the USBFS component and select Configuration.
The Configuration dialog box appears displaying the Device Descriptor tab.
2.
In the Descriptor tree, click Device Descriptor. Configure options for the Device Attributes as follows and
shown in Figure 15:





Vendor ID: 0x04B4
Product ID: 0xE177
Device Release: 0x100
Manufacturing String: Cypress Semiconductor
Product String: PSoC Generic HID Data Transfer
In this descriptor, the only hard requirement is to change the Vendor ID (VID) and Product ID (PID). The VID
used (0x04B4) is a specific Cypress Semiconductor VID. It is acceptable to use it in this example. However, you
must use a VID assigned to your company when you develop an application for production. The PID chosen is
unique to this application. You can optionally change the various strings such as the Product String and the
Manufacturing String.
Figure 15. USBFS Device Descriptor Configuration
www.cypress.com
Document No. 001-82072 Rev. *D
11
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
3.
In the Descriptor tree, click Configuration Descriptor. Configure options for Configuration Attributes as
follows and shown in Figure 16:



Configuration String: Example Project
Max Power (mA): 20
Device Power: Bus Powered
Figure 16. USBFS Configuration Descriptor Configuration
The key settings in this section are to define the USB device as Bus Powered and to request a power budget of
20 mA from the host. Less than 20 mA for the application is acceptable, but we cannot exceed this requirement.
Because we do not require Remote Wakeup functionality, we disable it.
www.cypress.com
Document No. 001-82072 Rev. *D
12
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
4.
In the Descriptor tree, click Alternate Setting 0. Configure options for Interface Attributes as follows and
shown in Figure 17:



Interface String: USB Data Interface
Class: HID
Subclass: No subclass
Each interface can have multiple Alternate Settings to allow for multiple endpoint configurations. In this
application, we only have one alternate setting (the default one). If we had more, we would configure all the
Alternate Settings via the Interface Descriptor. Here, we specify that the device conforms to the HID class. Notice
that as you change the Class from Undefined to HID, an additional Descriptor appears in the Descriptor Root
tree: the HID Class Descriptor.
Figure 17. USBFS Interface Descriptor Configuration
5.
Click the Add Endpoint button. The location of this button is shown in Figure 18.
An additional Endpoint Descriptor appears in the Descriptor tree.
Figure 18. USBFS Adding Additional Endpoint Descriptor
www.cypress.com
Document No. 001-82072 Rev. *D
13
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
6.
Use the following steps to use the HID Descriptor to create a report descriptor. The layout of the HID descriptor
tool is shown in Figure 19.
Figure 19. USBFS HID Descriptor Creation
Step 1
Step 2
Step 3
Step 4
Step 5
a.
Click the HID Descriptor tab.
b.
Click the Add Report button.
c.
Select an item from the HID Item List.
d.
Select a value from the Item Value list.
e.
When the Item Value box contains a text field for a particular Item selected, click either the Decimal or
Hexadecimal radio option and enter the desired value in the field.
f.
Repeat steps 3 to 5 for each item in the report descriptor until it resembles Figure 20.
www.cypress.com
Document No. 001-82072 Rev. *D
14
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Figure 20. USBFS Completed HID Descriptor
7.
Click the Device Descriptor tab. In the Descriptor tree, click HID Class Descriptor. Configure options for
Device Attributes as follows and shown in Figure 21:



Descriptor Type: Report
Country Code: Not Supported
HID Report: Generic HID
Because the project uses a Report Descriptor, we set the Descriptor Type to Report. Because the project is not
specific to any country, we set Country Code to Not Supported. Finally, the HID Class Descriptor must point to
the HID Report Descriptor. To create this link, we set the HID Report to the name of our HID Report Descriptor,
which in our example is Generic HID.
Figure 21. USBFS HID Class Descriptor
www.cypress.com
Document No. 001-82072 Rev. *D
15
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
8.
In the Descriptor tree, click the first Endpoint Descriptor entry. Configure options for Endpoint Attributes as
follows and shown in Figure 22:





Endpoint Number: EP1
Direction: IN
Transfer Type: INT
Interval: 10
Max Packet Size: 8
The first entry is for the IN Endpoint. It acts as a buffer for data sent to the host. First, we define this endpoint as
Endpoint 1 (EP1). Next, we set the direction of the endpoint as an Input. Because this application is an HID, the
specification requires that we use Interrupt (INT) transfers. We then set the frequency (or Interval) the host polls
the device to a value of 10 ms. Finally, we set our Maximum Packet Size to a value of 8 bytes.
Figure 22. USBFS IN Endpoint Descriptor
9.
Repeat step 8 for the second endpoint to configure it as an OUT endpoint with the following attributes. The
purpose of this endpoint is to act as a buffer for data that is received from the host.





Endpoint Number: EP2
Direction: OUT
Transfer Type: INT
Interval: 10
Max Packet Size: 8
10. Click the Apply button, and then click the OK button to close out the configuration wizard.
www.cypress.com
Document No. 001-82072 Rev. *D
16
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
6.1.3
Configure Other Components
With the USBFS component fully configured, there are still configuration settings to enter for the other components in
the project to finalize the application. We start with the ADC component.
1.
From the PSoC Creator schematic, double-click the ADC component.
2.
Configure the ADC component as shown in the following screenshot (Figure 23). Click OK to save and close the
configuration for the ADC component.
What we primarily need is to max out the resolution to 20 bits, adjust the sample rate, set the ADC to function in
single-ended mode, and set the input range from VSSA to VDDA.
Figure 23. Delta Sigma ADC Configuration Wizard
3.
Double-click the PWM component. Configure the PWM component as shown in the following screenshot. After
all changes are made, click OK to save and close the configuration for the PWM component.
www.cypress.com
Document No. 001-82072 Rev. *D
17
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
4.
Double-click the input clock to the PWM and configure it so that its frequency is set to 100 kHz as shown in
Figure 24. Click OK to close the configure PWM_Clock dialog box.
Figure 24. PWM Clock Configuration
5.
In our application, two of the digital pins, SW_In and LED_2, do not have hardware connections to other
components in the schematic. Therefore, we remove the hardware connection terminals to avoid generating an
error when the project builds. To remove the hardware connector from the pin, double-click the SW_In pin. On
the Type tab, clear the HW Connection check box as shown in Figure 25.
Figure 25. SW_In Input Pin Configuration – HW Connection
www.cypress.com
Document No. 001-82072 Rev. *D
18
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
6.
Since SW_In is a digital input, we must also change the drive mode. Click the General tab. Use the Drive Mode
drop list to select Resistive Pull Up as shown in Figure 26. Click OK to close the dialog box.
Figure 26. SW_In Pin Configuration – Drive Mode
7.
Repeat step 5 for the LED_2 pin.
Note: The Character LCD component does not require any special configuration to ensure proper functionality.
The default configuration for the other digital output pin, LED_1, is also acceptable in this application. Do not
change these components.
6.1.4
Configure Pin and Clocking Resources
With all the PSoC Creator components configured, we now configure the clocking resources and pin placements.
1.
In the Workspace Explorer window, locate and double-click MyFirstGenericDevice.cydwr.
The Pin Selection tab appears.
2.
Change the pin placement to resemble Figure 27:
This project functions on a CY8CKIT-030/CY8CKIT-050 without any jumper wires. A CY8CKIT-001 requires
minimal jumper wires, as there are not any hardwired traces on the PCB to the various external components
required.
Figure 27. PSoC Project Pin Assignment
www.cypress.com
Document No. 001-82072 Rev. *D
19
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
3.
Click on the Clocks tab. Double-click one of the clocks to open the configuration window. If using a PSoC 3 or
PSoC 5LP device, adjust the clock settings so that the clock GUI appears as follows in Figure 28.
Figure 28. PSoC Clock Configuration
6.1.5
Place Code in main.c
With the PSoC internal hardware configured, we now configure the device firmware, specifically by adding code to
the main.c file. Locate the code in Appendix A: (main.c) and place it into the main.c file located in PSoC Creator.
main.c is in the Source Files folder in the Workspace Explorer.
With the code added to main.c and all the components configured, you can build the project. You should expect the
process to complete successfully with no errors or warnings. Use a MiniProg3 Programmer to program the hex file
into the PSoC 3 or PSoC 5LP device.
www.cypress.com
Document No. 001-82072 Rev. *D
20
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
6.2
Development Kit Configuration
The project files included in this application note for PSoC 3 and PSoC 5LP devices work on two development kit
platforms: CY8CKIT-030/050 and CY8CKIT-001. The CY8CKIT-003/014, which are the PSoC 3 and PSoC 5LP First
Touch Kits, do not function with this project as the USB pins do not bond out to a USB connector. The USB connector
present on the boards is used solely to program the device. Table 2 summarizes the kits supported by this document.
Table 2. Supported PSoC 3/PSoC 5LP Kits
Kit
6.2.1
Picture
Supported
CY8CKIT-003
No
CY8CKIT-001
Yes
CY8CKIT-030/050
Yes
Using the CY8CKIT-030/050
With CY8CKIT-030/050, the project does not require any external connections except for the USB cable. Verify that
the LCD is in the LCD port (Port 2) on the bottom of the board as shown in Figure 29.
Figure 29. CY8CKIT-030/050 Configuration
www.cypress.com
Document No. 001-82072 Rev. *D
21
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Additionally, confirm that the following jumper settings are made to provide the proper power to the PSoC device. See
Figure 30 for additional details.


J10 - Move jumper to 3.3 V position
J11 - Move jumper to 3.3 V position
Figure 30. CY8CKIT-030/050 J10 and J11 Jumpers

6.2.2
J30 - Add jumper to provide power to potentiometer (VR)
Using the CY8CKIT-001
With the CY8CKIT-001, you must complete some wiring on the board prior to testing the application. The following
changes are required for proper functionality. See Figure 31 for additional details:






J8 - Move jumper to VBUS position
SW3 - Move switch to 3.3 V position
P6[1] - Connect to SW1 using jumper wire
P6[2] - Connect to LED1 using jumper wire
P6[3] - Connect to LED2 using jumper wire
P6[5] - Connect to VR using jumper wire
Figure 31. CY8CKIT-0010 J8 and SW3
SW3
J8
After these changes, the CY8CKIT-001 board should look similar to Figure 32. You must also verify that the
Character LCD is in the LCD port socket (Port 2) at the top of the DVK as shown in Figure 32. Additionally, verify that
the processor module is appropriate for evaluation with either PSoC 3 or PSoC 5LP.
www.cypress.com
Document No. 001-82072 Rev. *D
22
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Figure 32. CY8CKIT-001 Configuration
With your development kit (DVK) properly configured, attach a USB cable between a host computer and the USB
interface connecter on the DVK board. Note that for the CY8CKIT-030/050 boards, which contain two USB
connectors, the connector closest to the right side of the board is used to program the PSoC. The connector to the
left of that is for USB data communication.
Figure 33. USB Connector Identification on CY8CKIT-030/050
USB Connector
for Data Transfer
www.cypress.com
USB Connector
for Programming
Document No. 001-82072 Rev. *D
23
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
6.3
Developing Desktop Applications
The next step is to develop a PC application to interface with the device so that the two can communicate. There are
several decisions to make prior to development such as the selection of programming language, IDE, and USB
library.
Programming Language – Selection often depends on the operating system for which you are developing. For
example, Windows favors Microsoft .NET® languages such as C#, C++, and Visual Basic®. Mac OS X® favors its
native object-oriented C programming language, Cocoa®, but it also includes mainstream support for Java ®. While
Linux® does not seem to play favorites; C is the more native language.
USB Library – The USB library interfaces with the USB device. A library is a compiled set of function calls that make
it easy to interface with the device. While it is possible to write your own library to interface with the device, often this
is neither necessary nor practical. There are many libraries available. Some have specific programming language
requirements. Table 3 shows a list of some of the more popular USB libraries and the languages they support.
Table 3. List of Commonly Used USB Libraries
USB Library
Operating System Support
Programming Language Support
CyUSB
Windows
.NET Languages
LibUSB
Linux, Mac, Windows
C
IOKit
Mac
Objective-C
jUSB
Windows, Linux
Java
PyUSB
Linux (PyUSB), Windows (PyWinUSB)
Python®
To simplify things, this application note includes host applications for each operating system. Additionally, the USB
library and programming language are dependent on the operating system. I chose the programming language based
on the most commonly used language for the respective operating system. Additionally, I kept all the languages in the
same C language family, using only C derivatives. Table 4 shows a list of each operating system and the
programming language and library chosen.
Table 4. Application Note Example Project Usage
OS
Programming Language
USB Library
Windows
C#
CyUSB
Mac OS X
Cocoa (Objective-C)
IOKit
Linux
C
LibUSB
IDE – Recall that each host application, regardless of the operating system, displays two Input variables and controls
two Output variables. With the Input Report, the application receives 20-bit ADC data and displays the decimal value
on the host application. At the PSoC, the LCD can display this value. The GUI on the host also displays the status of
a push button (asserted or de-asserted). With the Output Report, the host application controls the state of an LED (on
or off) on a PSoC development board based on the state of a checkbox or radio button. The application also controls
the Duty Cycle of a PWM; it reads a value from a text field and sends the value to the PSoC where the result appears
on an LED and on a character LCD.
www.cypress.com
Document No. 001-82072 Rev. *D
24
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
6.4
Microsoft Windows Host Application
I developed the Windows host application using the Microsoft Visual C#® Express IDE. It was written in the C#
programming language using CyUSB as the USB library. The reason to select CyUSB for this project is its simplicity,
its basis off of the Win32 API, and the readily available documentation and support from Cypress on interfacing
CyUSB with Cypress products.
To run the application:
1.
Verify that the Windows executable file (Generic HID UI.exe) and the CYUSB.dll are in the same folder.
The files are included in the project files associated with this application note. If the .dll and executable are not in the
same folder, the application fails to launch correctly.
2.
Double-click the Windows executable file in the project files.
Figure 34 shows the application when a device is connected and when it is disconnected.
Figure 34. Generic HID Test Interface in Windows
3.
By default, the application uses the VID and PID shown in Figure 34 (VID = 0x04B4 and PID = 0xE177). If you
use the USBFS configuration wizard in the PSoC to change the VID and PID, edit the values in the Settings
section to match your PSoC entries. Then click the Set button.
www.cypress.com
Document No. 001-82072 Rev. *D
25
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
4.
To control the PWM duty cycle and the LED state on the PSoC, use the Output section. In the PWM Duty Cycle
text box, type a new value or use the arrows to increase or decrease the value as shown in Figure 35. Click the
Update button to perform the Output transfer. An acceptable range for this field is between 1 and 100. The
change takes effect on LED_3 on CY8CKIT-030/050 kits.
Figure 35. Host Tool Control of LED Duty Cycle
www.cypress.com
Document No. 001-82072 Rev. *D
26
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
5.
Underneath the PWM Duty Cycle field is the on/off control for LED_4 on the CY8CKIT-030. To turn the LED on,
check the LED check box. To turn the LED off, clear the LED check box. Refer to Figure 36 for more details.
Figure 36. Host Tool Control of LED State (On/Off)
6.
There are two variables in the Input section: ADC Value and Switch Status. These are for observation only. You
cannot edit these fields in the host application. By default, the configuration of the ADC in the PSoC project is for
20-bits of resolution. The Switch Status indicator is a bar that is green when SW2 on the CY8CKIT-030/050 is
pressed and is red when the button is released, as shown in Figure 37.
Figure 37. Host Tool Display of Push Button Status
Switch Pressed
www.cypress.com
Switch Not Pressed
Document No. 001-82072 Rev. *D
27
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
6.5
Mac OS X Host Application
We developed the Mac OS host application using XCode® (Version 4.2.1), which is the integrated development
environment for Apple Mac and iOS® devices. It is written in the Cocoa programming language, an Objective-C based
language, with IOKit as the USB library. Specifically, it uses a subset of IOKit called IOHIDLib.
To run the application:
1.
Double-click the application file Generic HID Test Interface.app in the project files.
The file is included in the project files associated with this application note.
Figure 38 shows the application when the device is connected.
Figure 38. Generic HID GUI in Mac OS X
2.
By default, the application uses the VID and PID described earlier in this application note (VID = 0x0484 and
PID = 0xE177). If you use the USBFS configuration wizard in the PSoC to change the VID or PID, edit the values
in the Settings section to match your PSoC entries. Then click the Set button.
www.cypress.com
Document No. 001-82072 Rev. *D
28
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
3.
Use the Output section to control the PWM duty cycle and LED state. In the PWM Duty Cycle text box, type a
new value as shown in Figure 39. Click the Send button to perform the Output transfer.
An acceptable range for this field is between 1 and 100. Do not use the % symbol. The change takes effect on
LED_3.
Figure 39. Host Tool Control of LED Duty Cycle
4.
Underneath the PWM Duty Cycle field is the on/off control for LED_4 on the CY8CKIT-030/50. To turn the LED
on, select the On radio option. To turn the LED off, select the Off radio option. Refer to Figure 40 for more
details.
Figure 40. Host Tool Control of LED State (On/Off)
5.
There are two variables in the Input section: ADC Value and Switch Status. These are for observation only. You
cannot edit these fields in the host application. Use the PSoC application code to change these values.
www.cypress.com
Document No. 001-82072 Rev. *D
29
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
By default, the configuration of the ADC in the PSoC project is for 20-bits of resolution. The Switch Status
indicator is a bar that is red when SW2 on the CY8CKIT-030/050 is pressed and is clear when the button is
released, as shown in Figure 41.
Figure 41. Host Tool Display of Push Button Status
Switch Pressed
6.6
Switch Not Pressed
Linux PC Application
For the Linux implementation, rather than an application similar to the Windows and Mac platforms, we use a
Command Line Interface (CLI) to ensure support across multiple Linux distributions (such as Ubuntu®, Gentoo™,
Slackware®, and so on) and desktop environments (such as Gnome™, KDE®, XFCE™, Fluxbox and so on).The
application runs entirely through the Linux terminal. To demonstrate how to stream data using a CLI, the host
application performs a total of ten reads, one every second, and display the results on the terminal window. You can
use the application code to change the interval between reads and the total number of reads.
We developed the application initially using Ubuntu Linux. It is written in the C programming language using LibUSB
as the USB library. You must compile the C code on your machine prior to running the application. Included with this
application note is the C file Linux_GenericHID_CLI.c. See Appendix D: Linux_GenericHID_CLI.c for Linux for print
copy of the code.
1.
There are two prerequisites to run the application in Linux: GCC Compiler and LibUSB. These are available via
your distributions package manager. Most distributions install a GCC compiler. On Ubuntu Linux, you can check
for this dependency with the command seen in Code 1. If a GCC compiler is installed, a message appears
similar to that seen in Figure 42.
Code 1. Command to Check for GCC Compiler
$ gcc –version
Figure 42. Checking for GCC Compiler in Linux
www.cypress.com
Document No. 001-82072 Rev. *D
30
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
2.
If not already on the host computer, you must install LibUSB. There are two methods to install LibUSB: download
a copy directly from the SourceForge project page located at http://sourceforge.net/projects/libusb/ or install
LibUSB via a package manager in the Linux distribution. Using Ubuntu Linux as a reference, install LibUSB with
the command seen in Code 2.
The actual terminal command varies based on the Linux distribution.
Code 2. Command to Install LibUSB
$ sudo apt-get install libusb-1.0-0-dev
Figure 43. Installing LibUSB in Ubuntu Linux
3.
Use the Linux terminal to navigate to the Linux_GenericHID_CLI.c file. Compile the host application with the
command as seen in Code 3. All of Code 3 should be placed on a single command line.
If the code compiles correctly, a new executable file appears on the desktop as shown in Figure 44.
Code 3. Command to Compile Host Application
$ gcc –o Linux_GenericHID_CLI.c Linux_GenericHID_CLI –I/usr/local/include/libusb-1.0 –
L/usr/local/lib –lusb-1.0
Figure 44. Compiled Linux Application
www.cypress.com
Document No. 001-82072 Rev. *D
31
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
4.
Run the host application from the terminal with the command as seen in Code 4.
Code 4. Command to Run Host Application
$ sudo ./Linux_GenericHID_CLI
Figure 45 shows the output of the CLI application. Use the Output Data section where you can view the data
transferred to the PSoC. Use the Input Data section, you can view the data received from the PSoC device. The
display also shows the multiple sequential reads which demonstrate the ability to stream continuous data.
Figure 45. Output from CLI Host Application in Linux
Note: If you prefer an IDE for the code and application development, I recommend Eclipse, a free and open-source
code editor. To add support for C, you can download an add-on from Eclipse and set up the dependencies for
LibUSB. It takes some extra effort; you can find out how to accomplish this by doing some Internet research.
www.cypress.com
Document No. 001-82072 Rev. *D
32
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
7
Writing Host Applications to Interface with HIDs
While this application note includes the source code for the PC applications on multiple operating systems, this
application note assumes a general understanding of the specific IDEs used along with their respective programming
languages. If you need information on how to use any of the IDEs or how to learn C, C#, or Objective-C, please
reference other resources. A list of books at the end of this application can assist you in learning these languages.
The next few sections describe the key components of the source code for the developed GUIs to interface with USB.
For simplification, we exclude portions of the code to handle button presses and to manipulate the data. Refer to the
sample code in the Appendices and accompanying projects for more details. The projects also include detailed
source code comments.
7.1
Windows Application Code
The CYUSB.dll makes interfacing with a PSoC HID very simple and requires minimal code from a developer’s standpoint. The developer just needs to place a few lines of code into a C# application project to create an interface to a
USB HID. Be aware that if opening the Windows application code provided with this application note, the files are
intended to be used with Windows Visual C# Express 2010.
7.1.1
A d d t h e C yU S B R e f e r e n c e
For the application to function properly, you must add the CyUSB.dll reference to your project. You can find
CyUSB.dll either in the project files associated with this application note or in the Cypress SuiteUSB
(http://www.cypress.com/?rID=34870).
1.
In the Solution Explorer of Microsoft Visual C# Express, right-click the References folder, and select Add
Reference.
2.
Click the Browse tab, and then navigate to the location of the CyUSB.dll file. If you choose to use the DLL
included with the application note, it is in the ../Host Applications/Windows Application folder of the associated
project files.
3.
Click to select CyUSB.dll, and then click OK.
The CyUSB reference appears in the Solution Explorer as shown in Figure 46.
Figure 46. CyUSB Reference in Solution Explorer
www.cypress.com
Document No. 001-82072 Rev. *D
33
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
4.
To easily access the Cypress USB library, add the CyUSB namespace. The line of code “using CyUSB”, as
shown in Figure 47, directs the compiler to look for functions in the CyUSB DLL without inclusion of the library
name in each call. To add this, right click on the Form1.cs file in the Solution Explorer, click on View Code, and
add the namespace at the top of the file.
Figure 47. CyUSB in C# Application Code
7.1.2
Initialize the USB HID Application
After adding a reference to the CyUSB.dll to the project, you can initialize the USB HID application.
1.
Define four variables with the commands as seen in Code 5:




2.
Vendor ID (integer)
Product ID (integer)
usbDevices (variable) – An instance of the USBDeviceList class and includes a dynamic list of USB devices
that are accessible via the HID class library
myHidDevice – An instance of the CyHidDevice class used as a handle for devices attached to a HID driver
Initialize the host application with the commands as seen
in Code 6. The code completes the following tasks:

InitializeComponent() – A function call
generated by the Visual C# tool that loads the GUI

usbDevices.DeviceAttached – A class instance
that populates with the list of all active USB devices
that conform to the standard HID class

EventHandler(usbDevices_DeviceAttached)
– Creates an event handler for USB devices attached
to the host

EventHandler(usbDevices_DeviceRemoved) –
Creates an event handler for USB devices removed
from the host

GetDevice – A function call that checks the Vendor
ID and Product ID of attached devices to determine
whether or not they belong with the host application.
www.cypress.com
Code 5. Initialization Variables for Windows
Example (C#)
Document No. 001-82072 Rev. *D
namespace WindowsFormsApplication1
{
public partial class
GenericHidForm : Form
{
// Pointer to list of USB
devices
USBDeviceList usbDevices =
null;
// Handle of USB device
CyHidDevice myHidDevice =
null;
// Cypress Vendor ID (VID)
int VID = 0x04B4;
// Example Project Product
ID (PID)
int PID = 0xE177;
}
}
34
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Code 6. Application Initialization Code (C#)
public GenericHidForm()
{
//Initialize the main GUI
InitializeComponent();
// Create a list of CYUSB devices for this application
usbDevices = new USBDeviceList(CyConst.DEVICES_HID);
//Add event handler for device attachment
usbDevices.DeviceAttached += new EventHandler(usbDevices_DeviceAttached);
//Add event handler for device removal
usbDevices.DeviceRemoved += new
EventHandler(usbDevices_DeviceRemoved);
//Connect to the USB device
GetDevice();
}
7.1.3
Get the HID
The GetDevice function as shown in Code 7 looks through the usbDevices list for a device that matches the VID and
PID defined previously in Code 5. If it finds a matching device, then myHidDevice contains the handle to that specific
USB device, rather than a value of NULL. Be aware that the VID and PID are not the only way to identify a USB
device. Once myHidDevice is no longer set to NULL, we then turn on the background timer and create a text label
Status to say “Connected”. The purpose of the timer is to create an interrupt where the firmware can periodically poll
the device for data (typically every 10 ms based on timer configuration).
Code 7. Code to Acquire USB Device (C#)
public void GetDevice()
{
//Look for device matching VID/PID
myHidDevice = usbDevices[Vendor_ID, Product_ID]
as CyHidDevice;
if (myHidDevice != null)
{
InputTimer.Enabled = true;
Status.Text = “Connected”;
Status.ForeColor = Color.Green;
}
else
{
Status.Text = “Disconnected”;
Status.ForeColor = Color.Red;
InputTimer.Enabled = false;
}
}
www.cypress.com
Document No. 001-82072 Rev. *D
35
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
7.1.4
D e vi c e R e m o va l a n d A t t a c h m e n t E ve n t H a n d l e r s
Code 8 shows the code for the event handler when a device is attached. The code checks to see if there is a device
already attached. If there already is an attached device, then nothing needs to be done and the function exits.
Otherwise, the system calls the GetDevice function to determine if the newly attached device matches the defined
VID and PID.
Code 8. Event Handler for Device Attachment (C#)
//Handler for Device Attach
void usbDevices_DeviceAttached(object sender, EventArgs e)
{
if (myHidDevice == null)
{
GetDevice();
// Process device status
}
}
Code 9 shows the code for the event handler when a device is removed. The code checks to determine whether or
not the device removal affects the application. This happens when the device removed is the application device. The
code casts the parameter “e” from EventArgs in the function prototype to USBEventArgs class and saves it as
usbEvent. After that, it queries the PID and VID for the device removed. If it determines that the removed device was
the application device, then the application no longer has a connection to the USB device and must take the
appropriate actions. The application does not close. Instead, it disables the timer, updates the GUI to say
“Disconnected” (by calling GetDevice), and resets the device handle to NULL.
Code 9. Event Handler for Device Removal (C#)
//Handler for Device Removal
void usbDevices_DeviceRemoved(object sender, EventArgs e)
{
USBEventArgs usbEvent = e as USBEventArgs;
// Check that it was the expected device that was removed
if ((usbEvent.ProductID == PID) && (usbEvent.VendorID == VID))
{
// Disable interrupts for polling HID
InputTimer.Enabled = false;
// Set HID pointer to NULL
myHidDevice = null;
// Process device status
GetDevice();
}
}
www.cypress.com
Document No. 001-82072 Rev. *D
36
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
7.1.5
S e n d a n d R e c e i ve D a t a
The host application must request data from the device as it is not sent automatically. This application uses a timer to
trigger the host to send a request to the device for new data as shown in Code 10. The timer code performs a
ReadInput that requests an Input Report from the device. After an Input transfer, the bytes transferred from the
device are stored in the Inputs.DataBuf. DataBuf is a member of CyHidReport and serves as the data buffer for HID
transfers. RptByteLen defines the length of DataBuf in bytes. RptByteLen reflects the ReportByteLength defined by
the device report descriptor and is located in the XxxxReportByteLength field of the HIDP_CAPS structure reported
for the Features, Inputs, or Outputs.
Code 10. InputTimer Code (Input Request) (C#)
private void InputTimer_Tick(object sender, EventArgs e)
{
if (myHidDevice != null)
{
// Disable timer
InputTimer.Enabled = false;
//Query the device for new data
myHidDevice.ReadInput();
InputTimer.Enabled = true;
}
}
ReadInput uses the Win32 ReadFile() function to read RptByteLen bytes from the device. The endpoint for this
transaction is device dependent. It is also important to note that for most transfer operations DataBuf[0] contains the
ReportID for the transfer. Report data begins at DataBuf[1]. This applies to Input, Output, and Feature Reports. Code
11 shows an example of how to request an Input report and then store it in a one-byte variable called myVariable.
Code 11. Code to Request Data from Device (Input) (C#)
myHidDevice.ReadInput();
myVariable =
myHidDevice.Inputs.DataBuf[1];
Sending data to the device is as simple as reading data from the device as shown in Code 12. Prior to transferring
data to the device, pre-load the desired bytes into Outputs.DataBuf, and then call WriteOutput. WriteOutput uses the
Win32
WriteFile() function to write RptByteLen bytes to the device. The endpoint for this transaction is device
dependent.
Code 12. Code to Send Data to Device (Output) (C#)
//Load data into Output Buffer
myHidDevice.Outputs.DataBuf[1] = 50;
//Function call to send data to device
myHidDevice.WriteOutput();
7.1.6
Closing Thoughts for Windows
Now you should have the general idea of how to interface a PSoC with a Windows application using C# and the
CyUSB driver. Be aware that the application code listed for Windows left out some of the code to handle the GUI
functionality such as button presses, text fields, and so on. For more information, please refer to the accompanying
C# project or the code shown in Appendix B: Form1.cs for Windows. To edit the project files, you must have a copy of
Microsoft Visual C# Express®.
www.cypress.com
Document No. 001-82072 Rev. *D
37
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
7.2
Mac OS X Application Code
Configuring an Xcode project to properly interface with an HID is a multiple step process, and it is a bit more involved
than with Windows. Upon loading the Xcode application, there are a few key steps required to interface with a HID.
Be aware that if opening the OS X application code provided with this application note, the files are intended to be
used with Xcode Version 4.3, which requires OS X 10.7 (Codename: Lion).
7.2.1
Add Toolkit Library and Configure HID Manager
For the application to function properly, it must include a reference to the IO Toolkit, which will act as our USB library
for Mac OS X.
1.
Presumably, we need to follow some simple steps here to open and begin configuring a new project in Xcode. To
start, open Xcode, and create a new Cocoa project for Mac OS X as shown in Figure 48.
Figure 48. Creating a New Cocoa Application
www.cypress.com
Document No. 001-82072 Rev. *D
38
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
2.
When the new project is created, a project configuration window appears. Verify that the Summary tab (located
on the top of Xcode) is selected. In the Linked Framework and Libraries section, click the + button and locate
IOKit.framework. Upon selecting the proper framework file, the Xcode window looks similar to Figure 49 below.
Figure 49. Linking Apple Framework to New Application
3.
Once the IOKit framework has been added, the library needs to be included in the project file. To add this, click
on in AppDelegate.m of the Xcode project. The following code snippet, shown in Code 13, is an excerpt from the
application’s .m file. Notice the inclusion of IOHIDLib from the IOKit library.
Code 13. Include Files for OS X Application
#import "AppDelegate.h"
#include <studio.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDLib.h>
4.
Setup a reference to the HID Manager with the commands in Code 14. Mac OS X includes the HID Manager to
support the following:

HID Manager API – Provides definitions and functions an application can use to interface with HID class
devices


Apple HID Drivers
In-Kernel Infrastructure – The base classes, kernel-user space memory mapping and queuing code, and the
HID parser
For application code to interface a HID with the Mac OS X, the only important consideration is the HID Manager
API. The rest is handled behind the scenes by the Mac Kernel.
www.cypress.com
Document No. 001-82072 Rev. *D
39
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Code 14. HID Manager Reference Setup Code (Obj-C)
/**** Setup Manager and schedule it with main run loop ****/
//Define an IOHID Manager Reference
IOHIDManagerRef tIOHIDManagerRef;
//Create the HID Manager reference
tIOHIDManagerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
//Schedule a HID manager with current run loop.
IOHIDManagerScheduleWithRunLoop(tIOHIDManagerRef, CFRunLoopGetCurrent(),
kCFRunLoopDefaultMode);
//Open the HID manager reference and return status
tIOReturn = IOHIDManagerOpen(tIOHIDManagerRef, kIOHIDOptionsTypeNone);
5.
The matching dictionary restricts the access of the HID Manager to only certain devices. In this case, we restrict
access to only devices with a certain VID and PID. You can define a single matching dictionary or an array of
dictionaries to add a more intense filtering process. Set up a matching dictionary with the commands shown in
Code 15.
Code 15. Device Matching Dictionary Setup (Obj-C)
// Variable Definition for VID/PID
unsigned long long VendorID = 0x04B4;
unsigned long long ProductID = 0xE177;
//Create a dictionary
myDictionary = [NSMutableDictionary dictionary];
//Configure dictionary with matching criteria for Product ID
[myDictionary setObject:[NSNumber numberWithLong:ProductID]forKey:[NSString
stringWithCString:kIOHIDProductIDKey encoding:NSUTF8StringEncoding]];
//Configure dictionary with matching criteria for Vendor ID
[myDictionary setObject:[NSNumber numberWithLong:VendorID]forKey:[NSString
stringWithCString:kIOHIDVendorIDKey encoding:NSUTF8StringEncoding]];
//Set matching criteria (Vendor ID & Product ID)
IOHIDManagerSetDeviceMatching(tIOHIDManagerRef, (CFMutableDictionaryRef) myDictionary);
Code 16. Define Buffer Pointers and Size (Obj-C)
//Pointers to Input and Output Buffers in Memory
char *inputBuffer;
char *outputBuffer;
size_t bufferSize = 8;
www.cypress.com
Document No. 001-82072 Rev. *D
40
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
7.2.2
Get the HID
With the matching criteria defined, we can acquire the HID with the commands shown in Code 17.
Code 17. Acquire Matching Device (Obj-C)
/******** Acquire the Device *********/
//Determine devices that match current matching criteria
NSSet * allDevices = [((NSSet *) IOHIDManagerCopyDevices(tIOHIDManagerRef))autorelease];
NSArray *deviceRefs = [allDevices allObjects];
deviceRef = ([deviceRefs count])? (IOHIDDeviceRef)[deviceRefs objectAtIndex:0]:nil;
Note: This code references the first device it finds that matches the criteria in the DeviceRefs array. It ignores
subsequent devices with the same matching criteria (VID and PID). There is a way to handle the attachment of
multiple devices that match the criteria. However, discussion of this condition is outside the scope of this application
note.
7.2.3
1.
Use the IOHIDManagerCopyDevices function to determine what devices attached to the host match the current
matching criteria.
2.
Create an array list of all the devices attached that match the criteria.
3.
If a device matches the criteria, set the deviceRef reference to that device.
4.
The last line of code acts as an IF/ELSE statement to evaluate if any devices are detected with the matching
criteria. If so, then deviceRef points to the first element in the array. If no devices match the criteria, then
deviceRef points to nil (equivalent to null).
Create Buffers for Data
Now, we set up buffers for the Input and Output data.
1.
Create a pointer to the buffers as shown in Code 16.
2.
Use the malloc() function to allocate memory for buffers with the commands shown in Code 18.
The malloc() function allocates bytes of memory and returns a pointer to the allocated memory. The parameter
passed defines the size of the memory allocated.
Code 18. Allocate Input and Output Buffer Size (Obj-C)
/***** Allocate Memory Space for Buffers *****/
inputBuffer = malloc(bufferSize);
outputBuffer = malloc(bufferSize);
www.cypress.com
Document No. 001-82072 Rev. *D
41
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
7.2.4
S e t U p Ap p l i c a t i o n t o R e c e i ve D a t a
Code 19 shows how to register a routine that is called when the HID receives an Input Report. This routine takes the
form of a callback function. Because this function will continuously be called automatically, we only need to call this
particular function shown below once in order to properly register it as a callback function. To aid in understanding
what the variables being passed in the callback register function, refer to Table 5.
Code 19. HID Get Report Callback Setup (Obj-C)
/** Configure Callback for Input Reports **/
IOHIDDeviceRegisterInputReportCallback(deviceRef,(uint8_t *)inputBuffer, bufferSize,
MyInputCallback, NULL);
Table 5. IOHIDDeviceRegisterInputReportCallback()
Parameter
Name
Purpose
st
deviceRef
The HID reference
nd
inputBuffer
The address of where to store the Input report
rd
MyInputCallback
The callback routine
th
NULL
A user context parameter passed to the callback routine
1
2
3
4
After the host receives data from an Input report, you can reference the data in the array inputBuffer[7..0] to use it.
The manipulation of the data is typically handled in the callback function.
7.2.5
S e t U p Ap p l i c a t i o n t o S e n d D a t a
Code 20 shows how to configure for an Output report. We use a synchronous IOHIDDeviceSetReport() function. You
can also use the asynchronous IOHIDDeviceSetValueWithCallback(). To aid in the understanding of the variables
being passed in the SetReport function, refer to Table 6.\
Code 20. Sending a HID Report Code Example (Obj-C)
/***** Send the HID Report (Output) *****/
IOHIDDeviceSetReport(deviceRef, kIOHIDReportTypeOutput, 0, (uint8_t*)outputBuffer,
bufferSize);
Table 6. IOHIDDeviceSetReport()
Parameter
1st
Name
Purpose
deviceRef
The HID reference
2
kIOHIDReportTypeOutput
The IOHIDReportType object for the report
3rd
0
The Report ID
4th
outputBuffer
The address of the Output report buffer
5th
bufferSize
The size of the report being sent
nd
www.cypress.com
Document No. 001-82072 Rev. *D
42
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
7.2.6
D e vi c e R e m o va l a n d A t t a c h m e n t C a l l b a c k s
While the initialization code works well for a device plugged in during the application launch, we must now implement
code to accommodate an HID attached or removed while the application runs.
1.
Declare two functions called when one a device is attached or removed with the commands in Code 21. This can
be little tricky as it requires a mixture of C code with Objective-C. The first step is to create callback functions in C
that in turn call class functions in Objective-C.
Code 21. C Callback Function for Attach and Removal Events (Obj-C)
/* Function to execute initHID upon device matching */
static void Handle_DeviceMatchingCallback(void *inContext, IOReturn inResult, void
*inSender, IOHIDDeviceRef inIOHIDDeviceRef)
{
/* Call the Class Method */
[(AppDelegate *) inContext deviceMatchingResult:inResult sender:inSender
device:inIOHIDDeviceRef];
}
static void Handle_DeviceRemovalCallback(void *inContext, IOReturn inResult, void
*inSender, IOHIDDeviceRef inIOHIDDeviceRef)
{
/* Call the Class Method */
[(AppDelegate *) inContext deviceRemovalResult:inResult sender:inSender
device:inIOHIDDeviceRef];
}
2.
Call the Objective-C class function that handles the appropriate action for attachment or removal with the
commands in Code 22.
Code 22. Objective-C Function for Attach and Removal Events
/* Function to execute initHID upon device matching */
- (void) deviceMatchingResult: (IOReturn) inResult sender: (void *) inSender device:
(IOHIDDeviceRef) inIOHIDDeviceRef
{
[self initHID];
}
/* Function to execute termHID upon device removal */
- (void) deviceRemovalResult: (IOReturn) inResult sender: (void *) inSender device:
(IOHIDDeviceRef) inIOHIDDeviceRef
{
[self termHID];
}
3.
The Objective-C function initHID executes the code required to acquire a HID based on the matching criteria.
The function termHID executes the code required to clear deviceRef when a formally connected and matched
HID is removed. Once those functions are defined, the next step is to register the callbacks with the commands
in Code 23.
Code 23. Register Callbacks for Attachment and Removal (Obj-C)
IOHIDManagerRegisterDeviceMatchingCallback(tIOHIDManagerRef, Handle_DeviceMatchingCallback,
self);
IOHIDManagerRegisterDeviceRemovalCallback(tIOHIDManagerRef, Handle_DeviceRemovalCallback, self);
www.cypress.com
Document No. 001-82072 Rev. *D
43
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
7.2.7
Add and Respond to a Timer Event
The final step to develop a USB HID OS X application is to configure and use a timer. A timer in a USB application on
the host serves multiple purposes. Commonly, a timer periodically polls for available data on the HID and then reads
data from an endpoint if present. We adopted this method in our Windows application. Since we used a callback for
the input data in the Mac OS application, we use the timer to periodically update the GUI with input data. Our
example is set to refresh every 10 ms. Configure the timer with the commands in Code 24.
Code 24.Setup Timer Event Code Example (Obj-C)
//Start Timer
timer = [NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(idleTimer
userInfo:nil
repeats:YES];
We must also define a function for the timer to jump to every time it ticks. Since we configured the timer to jump to
itself, we used the following function (idleTimer). We can see this function in Code 25. Inside the function, the various
GUI items that are to be updated, such as text fields and progress bars, would be placed here. Another key
configuration is to set “repeats” to “YES” which will ensure that this timer is continuous and not just a single shot.
Code 25. Function for Timer Ticks (Obj-C)
/**** Function for Timer Ticks ****/
- (void) idleTimer: (NSTimer *) inTimer
{
//Place code to update GUI
}
7.2.8
Closing Thoughts for Mac OS X
For more information on the implementation on Mac OS X, including the source code, please see Appendix C:
AppDelegate.c for Mac OS X or take a look at the Xcode project included with the project files. You can also find
additional resources in Xcode such as documentation and example projects maintained by Apple
7.3
Linux Application Code
Unlike the Windows and Mac host applications, the Linux host application does not use an IDE. We use a standard
text editor to implement the C. When the time comes to build, compile, and run the application, we rely on the Linux
terminal.
7.3.1
USB HID Application Initialization
1. Prior to writing the main application code, we must add four includes to the C file. While stdio.h and stdlib.h are
standard for many commonly used C functions, the libusb.h is essential to this application. Access to the libusb
API makes this application function. The application uses time.h to add a delay between the multiple Input
transfers. Code 26 shows the include files used in the Linux application.
Code 26. Include Files for LibUSB Application
#include
#include
#include
#include
www.cypress.com
<stdio.h>
<stdlib.h>
<libusb.h>
<time.h>
Document No. 001-82072 Rev. *D
44
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
2.
Declare four constant values as shown in Code 27:

INTERFACE_NUMBER – The interface number of the device we want to communicate with. On a composite
device, this can be one of a range of numbers. Since we only have a single interface on this device, the
Interface Number is 0.

TIMEOUT_MS – The amount of time in milliseconds (after performing an Output or Input request) the
application waits for a response before giving up and moving on.

NUMBER_INPUT_TRANSACTIONS – The number of times to perform an Input transaction before releasing
the device.

TIME_DELAY – The delay interval in seconds between each Input request.
Code 27.Global Variables for Linux Application RECEIVING
static
static
static
static
3.
45ons
45ons
45ons
45ons
tint
tint
tint
tint
INTERFACE_NUMBER = 0;
TIMEOUT_MS = 5000;
NUMBER_INPUT_ITERATIONS = 10;
TIME_DELAY = 1;
Next we need to define a few more key variables for our application. First, we need to define the VID and PID for
the application. These variables have been preset and configured as constants, rather than asking for a VID and
PID each time someone wants to run the application. We also need to define a device handle and a couple
status flags to be used in the application as shown in Code 28.
Code 28. Local Variables for Linux Application RECEIVING
/* Initialize and Set Default Vendor ID and Product ID */
const int VID = 0x04B4;
const int PID = 0xE177;
struct libusb_device_handle *devh = NULL;
int device_ready = 0;
int result = 0;
4.
Use the Vendor ID and Product ID to initialize the device handler to a specific device. It returns a handle for the
first matching device found. After verifying that the device handler is no longer NULL, detach the device from the
kernel. Once the device is free from the kernel, the final step is to claim the device for our application. The
commands to complete this series of tasks is shown in Code 29.
Code 29. Acquiring Device for Linux Application RECEIVING
result = libusb_init(NULL);
devh = libusb_open_device_with_vid_pid(NULL, VID, PID);
if (devh != NULL)
{
libusb_detach_kernel_driver(devh, 0);
result = libusb_claim_interface(devh, 0);
if(result != 0)
{
device_ready = 1;
}
}
5.
Further in the main loop, check to see if LibUSB successfully acquired the device. If so, call the function
Perform_Input_and_Output_Transfers and pass the device handler so the application knows which device to
communicate with. After executing the function, release the interface. This sequence is shown in Code 30.
www.cypress.com
Document No. 001-82072 Rev. *D
45
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Code 30. Performing Input/Output Transfers RECEIVING
if(device_ready)
{
//Send and receive data
Perform_Input_and_Output_Transfers(devh);
// Finished using the device.
Libusb_release_interface(devh, 0);
}
6.
Table 7 describes additional variables required by the Perform_Input_Output_Transfers() function. We must also
define a buffer to store the data prior to sending it to the device and after receiving it from the device. Finally,
there are variables to declare for status flags and to store information on the button status and ADC result.
Define these variables and buffers with the commands in Code 31.
Table 7. Variables Required by Perform_Input_and_Output_Transfers()
Variable
Purpose
Value
INTERRUPT_IN_ENDPOINT
Address of the Input endpoint
0x81
INTERRUPT_OUT_ENDPOINT
Address of the Output endpoint
0x02
MAX_INTERRUPT_IN_TRANSFER_SIZE
Maximum packet size for data received
8 (bytes)
MAX_INTERRUPT_OUT_TRANSFER_SIZE
Maximum packet size for data sent
8 (bytes)
Code 31. Linux Code for Variable Declarations of Transfers
// Assign Endpoint Addresses
static 46ons tint INTERRUPT_IN_ENDPOINT = 0x81;
static 46ons tint INTERRUPT_OUT_ENDPOINT = 0x02;
// With firmware support, transfers can be > the endpoint’s max packet size.
Static 46ons tint MAX_INTERRUPT_IN_TRANSFER_SIZE = 8;
static 46ons tint MAX_INTERRUPT_OUT_TRANSFER_SIZE = 8;
unsigned char data_in[MAX_INTERRUPT_IN_TRANSFER_SIZE];
unsigned char data_out[MAX_INTERRUPT_OUT_TRANSFER_SIZE];
int bytes_transferred;
int result = 0;
int ADC_Result = 0;
int Switch_Status = 0
www.cypress.com
Document No. 001-82072 Rev. *D
46
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
In Code 32, we load the OUT buffer based on code received from the CLI. With the buffer loaded, call
libusb_interrupt_transfer() to perform an output transaction based on the parameters passed. The buffer stores the
data in the data_out[ ] array prior to transfer.
Code 32. LibUSB Code for Out Transfer
data_out[0]= LED_State;
data_out[1] = PWM_DutyCycle;
result = libusb_interrupt_transfer(devh,
INTERRUPT_OUT_ENDPOINT,
data_out,
MAX_INTERRUPT_OUT_TRANSFER_SIZE,
&bytes_transferred,
TIMEOUT_MS);
7.
In Code 33, we can see a similar use of the libusb_interrupt_transfer function to perform an IN transaction. With
the buffer loaded, call libusb_interupt_transfer() to perform an input transaction based on the parameters passed.
The buffer stores the data after the transfer in the data_in[ ] array.
Code 33. LibUSB Code for In Transfer
result = libusb_interrupt_transfer(devh,
INTERRUPT_IN_ENDPOINT,
data_in,
MAX_INTERRUPT_OUT_TRANSFER_SIZE,
&bytes_transferred,
TIMEOUT_MS);
Both the IN and OUT transfers use the function libusb_interrupt_transfer. The function prototype for
libusb_interrupt_tranfser is shown in Code 34. In this function, the parameters are as follows:




dev_handle – A handle for the device to communicate with.


transfer – Output location for the number of bytes that were actually transferred.
endpoint – The address for a valid endpoint to communicate with.
data - Data buffer for either input or output data.
length – In the case of an Output, the number of bytes to transfer in the data buffer. In the case of an Input, the
number of bytes to receive in the data buffer.
timeout – timeout in milliseconds that the function should wait before giving up due to no response being
received.
Code 34. LibUSB Code for In Transfer
8
Conclusion
This application note discusses the benefits of using the HID class for general data communication. After reading this
application note, you will be more comfortable using the various operating applications with the PSoC device. Users
who want to explore building upon the designs provided can adjust the maximum packet size to send more data.
Another option is to build upon the host applications provided and the available space in the Input and Output reports
to send data to perform additional functionality.
www.cypress.com
Document No. 001-82072 Rev. *D
47
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
9
Related Resources
9.1
Application Notes







9.2
AN57294 – USB 101: An Introduction to Universal Serial Bus 2.0
AN57473 – PSoC® 3 / PSoC 5LP USB HID Fundamentals with Mouse and Joystick
AN58726 – PSoC® 3 / PSoC 5LP USB HID Intermediate (with Keyboard and Composite Device)
AN56377 – PSoC® 3 / PSoC 5LP USB Transfer Types
AN023 – USB Compliance Testing Overview
AN14557 – Introduction to CYUSB.dll Based Application Development Using C#
AN61744 – Introduction to CYAPI.lib Based Application Development Using VC++
Programming Language Books

C#:




C# Unleashed
Visual C# 2012 How to Program
C:


Head First C#: A Learners Guide to Real-World Programming with Visual C# and .NET
The C Programming Language
Objective-C:


Cocoa Programming for Mac OS X
Objective C Programming: The Big Nerd Ranch Guide
About the Author
Name:
Robert Murphy
Title:
Systems Engineer Staff.
Background:
Robert Murphy graduated from Purdue University with a Bachelor Degree in Electrical Engineering
Technology
www.cypress.com
Document No. 001-82072 Rev. *D
48
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
A
Appendix A: (main.c)
#include <device.h>
#include <stdio.h>
/* Declare defines for constant variables */
#define DEVICE_ID 0
#define IN_ENDPOINT 0x01
#define OUT_ENDPOINT 0x02
#define MAX_NUM_BYTES 8
#define UnassignedAddress 0
/* Array Positioning for IN Data */
#define Button_Status_Pos 0
#define ADC_Pos_1 1
#define ADC_Pos_2 2
#define ADC_Pos_3 3
#define ADC_Pos_4 4
/* Array Positioning for OUT Data */
#define LED_State_Pos 0
#define PWM_DC_Pos 1
/* Input and Output Data Buffers */
uint8 IN_Data_Buffer[8]; /* [0] = Button Status, [1..4] = ADC Result, [5..7] = Unused */
uint8 OUT_Data_Buffer[8]; /* [0] = LED State, [1] = PWM Duty Cycle, [2..7] = Unused */
/* Display buffer for Character LCD */
char ADC_Display_Data[10];
char PWM_Duty_Display_Data[5];
/* Various Application Variables */
int32 ADC_Result;
int8 PWM_DutyCycle;
uint8 OUT_COUNT;
uint16 LCD_Update_Timer = 0x00;
/* Function Prototypes */
void Process_EP2 (void);
void Process_EP1 (void);
void Update_LCD (void);
void main (void)
{
/*Enable Global Interrupts */
CYGlobalIntEnable;
/*Initalize ADC */
ADC_Start();
ADC_StartConvert();
/*Initalize LCD and place static text */
LCD_Start();
LCD_Position(0,0);
LCD_PrintString("PSoC Generic HID");
LCD_Position(1,0);
LCD_PrintString("AD:");
LCD_Position(1,11);
LCD_PrintString("D:");
/*Initalize PWM */
PWM_Start();
PWM_WriteCompare(10);
/*Initalize LED Off */
LED_2_Write(1);
/* Start USBFS Operation for the DEVICE_ID and with 5V operation
USBFS_Start(0, USBFS_DWR_VDDD_OPERATION);
www.cypress.com
Document No. 001-82072 Rev. *D
*/
49
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
/* Ensure device is configured before running code */
while(USBFS_bGetConfiguration() == 0x00)
{
/* Waiting for device to be configured */
}
for(;;)
{
/* Prepare the push button and ADC data to be sent to the host */
Process_EP1();
/*Check to see if the IN Endpoint is empty. If so, load it with Input data to be tranfered */
if(USBFS_GetEPState(IN_ENDPOINT) == USBFS_IN_BUFFER_EMPTY)
{
/* Load data located in IN_Data_Buffer and load it into the IN endpoint */
USBFS_LoadEP(IN_ENDPOINT, IN_Data_Buffer, MAX_NUM_BYTES);
/* Enable the OUT endpoint to recieve data */
USBFS_EnableOutEP(OUT_ENDPOINT);
}
/* Check to see if the OUT Endpoint is full from a recieved transaction. */
if(USBFS_GetEPState(OUT_ENDPOINT) == USBFS_OUT_BUFFER_FULL)
{
/* Get the number of bytes recieved */
OUT_COUNT = USBFS_GetEPCount(OUT_ENDPOINT);
/* Read the OUT endpoint and store data in OUT_Data_Buffer */
USBFS_ReadOutEP(OUT_ENDPOINT, OUT_Data_Buffer, OUT_COUNT);
/* Re-enable OUT endpoint */
USBFS_EnableOutEP(OUT_ENDPOINT);
}
/* Process the data recieved from the host */
Process_EP2();
/* Impliment a perodic delay for updating the LCD */
if(LCD_Update_Timer >= 0x08FF)
{
/* Call function to update Character LCD with ADC and PWM Duty Cycle value */
Update_LCD();
}
/* Increment LCD Timer */
LCD_Update_Timer ++;
}
}
/**********************************************************************
* NAME: Process_EP2
*
* DESCRIPTION: Function to process the OUT data (data sent from the PC).
* This data includes the state of LED_2 (On or Off) and the duty cycle
* of the PWM attached to LED_1.
*
***********************************************************************/
void Process_EP2 (void)
{
/* Update PWM Compare Value */
if((OUT_Data_Buffer[PWM_DC_Pos] > 0) && (OUT_Data_Buffer[PWM_DC_Pos] <= 100))
{
PWM_DutyCycle = OUT_Data_Buffer[PWM_DC_Pos];
PWM_WriteCompare(PWM_DutyCycle);
}
/* Check to see if LED_2 Should be on */
if(OUT_Data_Buffer[LED_State_Pos] != 0)
{
LED_2_Write(1);
}
else
www.cypress.com
Document No. 001-82072 Rev. *D
50
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
{
LED_2_Write(0);
}
}
/**********************************************************************
* NAME: Process_EP1
*
* DESCRIPTION: Function to process the IN data (data sent to the PC).
* This data includes the value read from the DelSig ADC and the current
* status of push button connected to SW_In.
*
***********************************************************************/
void Process_EP1 (void)
{
/* Check Status of Switch 1 */
if(SW_In_Read() != 0)
{
IN_Data_Buffer[Button_Status_Pos] = 0x00;
}
else
{
IN_Data_Buffer[Button_Status_Pos] = 0xff;
}
/* Check if ADC data is ready */
if(ADC_IsEndConversion(ADC_RETURN_STATUS) != 0x00)
{
/* Read ADC Sample */
ADC_Result = ADC_GetResult32();
/* Load Bits 7-0 of ADC_Value into the Input Buffer */
IN_Data_Buffer[ADC_Pos_1] = (int8) 0x000000FF & (ADC_Result >>
24);
/* Load Bits 15-8 of ADC_Value into the Input Buffer */
IN_Data_Buffer[ADC_Pos_2] = (int8) 0x000000FF & (ADC_Result >>
16);
/* Load Bits 23-16 of ADC_Value into the Input Buffer */
IN_Data_Buffer[ADC_Pos_3] = (int8) 0x000000FF & (ADC_Result >>
8);
/* Load Bits 31-24 of ADC_Value into the Input Buffer */
IN_Data_Buffer[ADC_Pos_4] = (int8) 0x000000FF & ADC_Result;
}
}
/**********************************************************************
* NAME: Update_LCD
*
* DESCRIPTION: Function periodically update the Character LCD with the
* ADC value and PWM duty cycle.
*
***********************************************************************/
void Update_LCD (void)
{
/* Convert ADC Value to CHAR and display on Character LCD */
sprintf(ADC_Display_Data, "%-7ld", ADC_Result);
LCD_Position(1,3);
LCD_PrintString(ADC_Display_Data);
/* Convert PWM Duty Cycle to CHAR and display on Character LCD */
sprintf(PWM_Duty_Display_Data, "%-3d", (int16)PWM_ReadCompare());
LCD_Position(1,13);
LCD_PrintString(PWM_Duty_Display_Data);
/* Reset LCD Update Timer */
LCD_Update_Timer = 0x00;
}
/* [] END OF FILE */
www.cypress.com
Document No. 001-82072 Rev. *D
51
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
B
using
using
using
using
using
using
using
using
using
Appendix B: Form1.cs for Windows
System;
System.Collections.Generic;
System.ComponentModel;
System.Data;
System.Drawing;
System.Linq;
System.Text;
System.Windows.Forms;
CyUSB;
namespace WindowsFormsApplication1
{
public partial class GenericHidForm : Form
{
// *********************** START OF PROGRAM MAIN ****************************** //
//Constant variables for locations in Input and Output Data Arrays
//Constants fro Input Buffer Array
const uint Switch_Status_Position = 1;
const uint ADC_Byte1_Position = 2;
const uint ADC_Byte2_Position = 3;
const uint ADC_Byte3_Position = 4;
const uint ADC_Byte4_Position = 5;
//Constants fro Output Buffer Array
const uint LED_State_Position = 1;
const uint PWM_DutyCycle_Position = 2;
USBDeviceList usbDevices = null;
CyHidDevice myHidDevice = null;
// Pointer to list of USB devices
// Handle of USB device
uint
uint
uint
uint
//
//
//
//
AdcCounts_1
AdcCounts_2
AdcCounts_3
AdcCounts_4
=
=
=
=
0;
0;
0;
0;
READ:
READ:
READ:
READ:
ADC
ADC
ADC
ADC
count
count
count
count
from
from
from
from
PSOC,
PSOC,
PSOC,
PSOC,
ADC_Result[7..0]
ADC_Result[15..8]
ADC_Result[23..16]
ADC_Result[31..24]
uint DutyCycle = 0;
// WRITE: Duty cycle to set PSOC PWM
int VID = 0x04B4;
int PID = 0xE177;
// Cypress Vendor ID
// Example Project Product ID
NumericUpDown DutyCycleUpDown;
// Handler for PWM up/down control
/**********************************************************************
* NAME: GenericHIDForm
*
* DESCRIPTION: Main function called initially upon the starting of the
* application. Used to un-initialized variables, the GUI application, register
* the event handlers, and check for a connected device.
*
***********************************************************************/
public GenericHidForm()
{
//Initialize the main GUI
InitializeComponent();
//Set initial values
DutyCycleUpDown = new NumericUpDown();
DutyCycleUpDown.Value = 10;
DutyCycleUpDown.Minimum = 0;
DutyCycleUpDown.Maximum = 100;
//Callback to set numeric updown box value
www.cypress.com
Document No. 001-82072 Rev. *D
52
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
DutyCycleUpDown.ValueChanged += new EventHandler(DutyCycleUpDown_OnValueChanged);
// Create a list of CYUSB devices for this application
usbDevices = new USBDeviceList(CyConst.DEVICES_HID);
//Add event handlers for device attachment and device removal
usbDevices.DeviceAttached += new EventHandler(usbDevices_DeviceAttached);
usbDevices.DeviceRemoved += new EventHandler(usbDevices_DeviceRemoved);
//Connect to the USB device
GetDevice();
}
/**********************************************************************
* NAME: DutyCycleUpDown_OnValueChanged
*
* DESCRIPTION: Event Handler for the numeric up/down text field. This
* function is called when the value in the next field is updated with
* the arrows so that the value is the text field can be properly updated
* to reflect the change.
*
***********************************************************************/
private void DutyCycleUpDown_OnValueChanged(object sender, EventArgs e)
{
Console.WriteLine(DutyCycleUpDown.Value);
}
/**********************************************************************
* NAME: usbDevices_DeviceRemoved
*
* DESCRIPTION: Event handler for the removal of a USB device. When the removal
* of a USB device is detected, this function will be called which will check to
* see if the device removed was the device we were using. If so, then reset
* device handler (myHidDevice), disable the timer, and update the GUI.
*
***********************************************************************/
public void usbDevices_DeviceRemoved(object sender, EventArgs e)
{
USBEventArgs usbEvent = e as USBEventArgs;
if ((usbEvent.ProductID == PID) && (usbEvent.VendorID == VID))
{
InputTimer.Enabled = false;
// Disable interrupts for polling HID
myHidDevice = null;
GetDevice();
// Process device status
}
}
/**********************************************************************
* NAME: usbDevices_DeviceAttached
*
* DESCRIPTION: Event handler for the attachment of a USB device. The function
* first checks to see if a matching device is already connected by seeing
* if the handler (myHidDevice) is null. If no device is previously attached,
* the function will call GetDevice to check and see if a matching device was
* attached.
*
***********************************************************************/
public void usbDevices_DeviceAttached(object sender, EventArgs e)
{
if (myHidDevice == null)
{
GetDevice();
// Process device status
}
}
www.cypress.com
Document No. 001-82072 Rev. *D
53
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
/**********************************************************************
* NAME: GetDevice
*
* DESCRIPTION: Function checks to see if a matching USB device is attached
* based on the VID and PID provided in the application. When a device is
* found, it is assigned a handler (myHidDevice) and the GUI is updated to
* reflect the connection. Additionally, if the device is not connected,
* the function will update the GUI to reflect the disconnection.
*
***********************************************************************/
public void GetDevice()
{
//Look for device matching VID/PID
myHidDevice = usbDevices[VID, PID] as CyHidDevice;
if (myHidDevice != null)
{
//Check to see if device is already connected
Status.Text = “Connected”;
Status.ForeColor = Color.Green;
SwStatus.Enabled = true;
InputTimer.Enabled = true;
Update_LED();
Update_PWMDutyCycle();
//Enable background timer
//Initialize the LED based on current GUI configuration
//Initialize the PWM based on current GUI configuration
}
else
{
Status.Text = “Disconnected”;
Status.ForeColor = Color.Red;
}
}
/**********************************************************************
* NAME: Update_PWMDutyCycle
*
* DESCRIPTION: Function used to update the state of the PWM Duty Cycle
* on the PSoC device end by reading the value on the PWM Duty Cycle text field
* (DutyTextBox), applying the change to the Output Data Buffer, and
* writing the OUT report.
*
***********************************************************************/
public void Update_PWMDutyCycle()
{
//Update the Output Buffer for PWM based on selected checkbox setting
DutyCycle = Convert.ToUInt32(DutyTextBox.Text);
myHidDevice.Outputs.DataBuf[PWM_DutyCycle_Position] = (byte)DutyCycle;
myHidDevice.WriteOutput();
}
/**********************************************************************
* NAME: Update_LED
*
* DESCRIPTION: Function used to update the state of the LED on the PSoC
* device end by checking the current status of the LED check box,
* applying the change to the Output Data Buffer, and writing the OUT report.
*
***********************************************************************/
public void Update_LED()
{
//Update the Output Buffer for LED based on selected checkbox setting
www.cypress.com
Document No. 001-82072 Rev. *D
54
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
if (LED_State_CheckBox.Checked)
{
myHidDevice.Outputs.DataBuf[LED_State_Position] = 0xFF;
}
else
{
myHidDevice.Outputs.DataBuf[LED_State_Position] = 0x00;
}
myHidDevice.WriteOutput();
}
/**********************************************************************
* NAME: InputTimer_Tick
*
* DESCRIPTION: Function called by Timer (InputTimer) which is used to poll
* for input data every 10ms. Function will check contents of Input Data
* and change display of switch status and update the ADC Value field.
*
***********************************************************************/
private void InputTimer_Tick(object sender, EventArgs e)
{
if (myHidDevice != null)
{
// Disable timer so we don’t get another interrupt until we service this interrupt
InputTimer.Enabled = false;
// This CyUSB.DLL method uses the Win32 ReadFile() function to read IN data transferred
to our application from the device
myHidDevice.ReadInput();
// Check to see if Push Button is pressed. Update GUI based on results
if (myHidDevice.Inputs.DataBuf[Switch_Status_Position] != 0x00)
{
SwStatus.BackColor = Color.Lime;
SwStatus.Text = “ON”;
}
else
{
SwStatus.BackColor = Color.Red;
SwStatus.Text = “OFF”;
}
//Unload the ADC Data from the Input Buffer to application variables
AdcCounts_1 = myHidDevice.Inputs.DataBuf[ADC_Byte1_Position];
AdcCounts_2 = myHidDevice.Inputs.DataBuf[ADC_Byte2_Position];
AdcCounts_3 = myHidDevice.Inputs.DataBuf[ADC_Byte3_Position];
AdcCounts_4 = myHidDevice.Inputs.DataBuf[ADC_Byte4_Position];
//Compose the overall ADC value by shifting and adding the multiple ADC bytes
String AdcValue = ((AdcCounts_1 << 24) + (AdcCounts_2 << 16) + (AdcCounts_3 << 8) +
AdcCounts_4).ToString();
AdcValueBox.Text = AdcValue;
//Re-enable the timer
InputTimer.Enabled = true;
}
}
/**********************************************************************
* NAME: Update_PWM_Click
*
* DESCRIPTION: When “Update” button is pressed to update PWM value, function
* checks to see if a matching USB device is currently connected. If so, function
* calls another function to update the PWM Duty Cycle on the device.
*
***********************************************************************/
www.cypress.com
Document No. 001-82072 Rev. *D
55
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
private void Update_PWM_Click(object sender, EventArgs e)
{
//Respond to user pressing “Update” button. Make sure device is connected before hand.
If (myHidDevice != null)
{
Update_PWMDutyCycle();
}
}
/**********************************************************************
* NAME: Set_VidPid_Click
*
* DESCRIPTION: Updates the applications Vendor ID and Product ID based on
* user input when the “Set” button is clicked. This will cause the default VID
* and PID of 0x04B4 and 0xE177 to be overwritten. The function will then
* call GetDevice() to check for matching USB device.
*
***********************************************************************/
private void Set_VidPid_Click(object sender, EventArgs e)
{
//Respond to update of VID and PID value by pressing the “Set” button
VID = Convert.ToInt32(VidTextBox.Text, 16);
PID = Convert.ToInt32(PidTextBox.Text, 16);
GetDevice();
}
/**********************************************************************
* NAME: LED_State_CheckBox_CheckedChanged
*
* DESCRIPTION: When state of the LED State check box is changed, function
* checks to see if a matching USB device is currently connected. If so, function
* calls another function to update the LED state on the device.
*
***********************************************************************/
private void LED_State_CheckBox_CheckedChanged(object sender, EventArgs e)
{
//Respond to change in LED checkbox state. Make sure device is connected before hand.
If (myHidDevice != null)
{
Update_LED();
}
}
private void VidTextBox_MaskInputRejected(object sender, MaskInputRejectedEventArgs e)
{
}
private void AdcValueBox_TextChanged(object sender, EventArgs e)
{
}
}
}
www.cypress.com
Document No. 001-82072 Rev. *D
56
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
C
Appendix C: AppDelegate.c for Mac OS X
#import “AppDelegate.h”
#include <stdio.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDLib.h>
/**************************************************/
/* Function Prototype */
/*************************************************/
@interface AppDelegate (private)
- (void) initHID;
- (void) termHID;
- (void) idleTimer: (NSTimer *) inTimer;
- (void) deviceMatchingResult: (IOReturn) inResult sender: (void *) inSender device:
(IOHIDDeviceRef) inIOHIDDeviceRef;
- (void) deviceRemovalResult: (IOReturn) inResult sender: (void *) inSender device:
(IOHIDDeviceRef) inIOHIDDeviceRef;
@end
static void MyInputCallback (void *context, IOReturn result, void *sender,
IOHIDReportType type, uint32_t reportID, uint8_t *report, CFIndex reportLength);
static void Handle_DeviceMatchingCallback(void *inContext, IOReturn inResult, void
*inSender, IOHIDDeviceRef inIOHIDDeviceRef);
static void Handle_DeviceRemovalCallback(void *inContext, IOReturn inResult, void
*inSender, IOHIDDeviceRef inIOHIDDeviceRef);
@implementation AppDelegate
@synthesize window;
/**************************************************/
/* Variables for Application */
/*************************************************/
uint8 AdcCounts_1;
uint8 AdcCounts_2;
uint8 AdcCounts_3;
uint8 AdcCounts_4;
double AdcValue;
uint8 SwStatus;
uint8 LedStatus = 0x01;
double PWM_Duty = 10;
unsigned long long VendorID = 0x04B4;
unsigned long long ProductID = 0xE177;
size_t bufferSize = 8;
char *inputBuffer;
char *outputBuffer;
IOHIDDeviceRef deviceRef;
IOHIDManagerRef tIOHIDManagerRef;
NSMutableDictionary *myDictionary;
uint8 FirstTimeConfig = 0x00;
www.cypress.com
Document No. 001-82072 Rev. *D
57
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
/**************************************************/
/* Functions */
/*************************************************/
- (void)dealloc
{
[super dealloc];
}
- (void)applicationDidFinishLaunchingNSNotification *)aNotification
{
// Insert code here to initialize your application
[self initHID];
}
//Clean up application before closing
-(void)applicationWillTerminateNSNotification *)notification
{
IOHIDManagerRegisterDeviceMatchingCallback(tIOHIDManagerRef, NULL, NULL);
IOHIDManagerRegisterDeviceRemovalCallback(tIOHIDManagerRef, NULL, NULL);
IOHIDManagerUnscheduleFromRunLoop(tIOHIDManagerRef, CFRunLoopGetCurrent(),
kCFRunLoopDefaultMode);
if (myDictionary)
{
CFRelease(myDictionary);
myDictionary = NULL;
}
[timer release];
}
//Timer Function. Executed each timer tick
- (void) idleTimer: (NSTimer *) inTimer
{
//Update the GUI with INPUT data
if(SwStatus != 0x00)
{
[SwStatusField setIntValue:1];
}
else
{
[SwStatusField setIntValue:0];
}
[ADCValueField setDoubleValue:AdcValue];
}
/**************************************************/
/* Function to Initialize the HID */
/*************************************************/
-(void) initHID
{
IOReturn tIOReturn;
www.cypress.com
Document No. 001-82072 Rev. *D
58
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
//Only run this section if it is the first time the application has been opened
if(FirstTimeConfig == 0x00)
{
/************* Setup Manager and schedule it with main run loop *********/
//Create the HID Manager reference
tIOHIDManagerRef = IOHIDManagerCreate(kCFAllocatorDefault,
kIOHIDOptionsTypeNone);
//Schedule a HID manager with current run loop.
IOHIDManagerScheduleWithRunLoop(tIOHIDManagerRef, CFRunLoopGetCurrent(),
kCFRunLoopDefaultMode);
//Open the HID manager reference
tIOReturn = IOHIDManagerOpen(tIOHIDManagerRef, kIOHIDOptionsTypeNone);
/************ Configure Matching Criteria for Device Detection *************/
//Create a dictionary
myDictionary = [NSMutableDictionary dictionary];
//Configure dictionary with matching criteria for Product ID
[myDictionary setObject:[NSNumber numberWithLong:ProductID]forKey:[NSString
stringWithCString:kIOHIDProductIDKey encoding:NSUTF8StringEncoding]];
//Configure dictionary with matching criteria for Vendor ID
[myDictionary setObject:[NSNumber numberWithLong:VendorID]forKey:[NSString
stringWithCString:kIOHIDVendorIDKey encoding:NSUTF8StringEncoding]];
//Set matching criteria (Vendor ID and Product ID)
IOHIDManagerSetDeviceMatching(tIOHIDManagerRef, (CFMutableDictionaryRef)
myDictionary);
//Set flag indicating the completion of initial configuration
FirstTimeConfig = 0xFF;
}
/************* Acquire the Device ****************/
//Determine the devices attached that meet the matching criteria
NSSet * allDevices = [((NSSet
*)IOHIDManagerCopyDevices(tIOHIDManagerRef))autorelease];
//Create an array list of matching devices
NSArray *deviceRefs = [allDevices allObjects];
//Set our device reference/handler to the first device detected that meets the
matching criteria
deviceRef = ([deviceRefs count])? (IOHIDDeviceRef)[deviceRefs
objectAtIndex:0]:nil;
//If device is now connected
if(deviceRef != 0x00)
{
//Update GUI to reflect connected device
[StatusLabel setTextColor:[NSColor greenColor]];
[StatusLabel setStringValue:@”Connected”];
[PWMDutyField setIntValue:PWM_Duty];
//Allocate RAM for Input and Output buffer
inputBuffer = malloc(bufferSize);
www.cypress.com
Document No. 001-82072 Rev. *D
59
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
outputBuffer = malloc(bufferSize);
//Register callback routine for when an Input report is received
IOHIDDeviceRegisterInputReportCallback(deviceRef, (uint8_t *)inputBuffer,
bufferSize, MyInputCallback, NULL);
//Load initial Output data
outputBuffer[0] = LedStatus;
outputBuffer[1] = PWM_Duty;
//Perform an Output transaction to the PSoC device
IOHIDDeviceSetReport(deviceRef, kIOHIDReportTypeOutput, 0,
(uint8_t*)outputBuffer, bufferSize);
}
else
{
//Update GUI to reflect a device disconnect
[StatusLabel setTextColor:[NSColor redColor]];
[StatusLabel setStringValue:@”Disconnected”];
}
//Start Timer
timer = [NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(idleTimer
userInfo:nil
repeats:YES];
//Register callback routines for when a device is attached or removed from Mac
IOHIDManagerRegisterDeviceMatchingCallback(tIOHIDManagerRef,
Handle_DeviceMatchingCallback, self);
IOHIDManagerRegisterDeviceRemovalCallback(tIOHIDManagerRef,
Handle_DeviceRemovalCallback, self);
}
- (void) termHID
{
//Check to make sure a device was connected
if (tIOHIDManagerRef)
{
//Update GUI to reflect disconnect
[StatusLabel setTextColor:[NSColor redColor]];
[StatusLabel setStringValue:@”Disconnected”];
//Disable Timer
[timer invalidate];
timer = nil;
//Reset device handler to nill
deviceRef = nil;
}
}
/****************************************************/
/* Function to execute initHID upon device matching */
/*****************************************************/
- (void) deviceMatchingResult: (IOReturn) inResult sender: (void *) inSender device:
(IOHIDDeviceRef) inIOHIDDeviceRef
{
[self initHID];
www.cypress.com
Document No. 001-82072 Rev. *D
60
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
}//deviceRemovalResul
/****************************************************/
/* Function to execute initHID upon device removal */
/****************************************************/
- (void) deviceRemovalResult: (IOReturn) inResult sender: (void *) inSender device:
(IOHIDDeviceRef) inIOHIDDeviceRef
{
[self termHID];
}//deviceRemovalResult
/********************************************/
/* Function to control LED ON/OFF
*/
/* Tiggered by change in radio button state */
/********************************************/
- (IBAction)LED_Changeid)sender
{
//Error catch to make sure device is connected before proceeding
require(deviceRef, Oops);
//Update Output buffer based on selected radio button (On or Off)
switch ([[sender selectedCell] tag])
{
case 1:
LedStatus = 0x01;
outputBuffer[0] = LedStatus;
break;
case 0:
LedStatus = 0x00;
outputBuffer[0] = LedStatus;
break;
default:
break;
}
//Perform Output transaction
IOHIDDeviceSetReport(deviceRef, kIOHIDReportTypeOutput, 0, (uint8_t*)outputBuffer,
bufferSize);
//If no matching device is detected, do nothing.
Oops:;
}
/**************************************************/
/* Function to Update device VID and PID Matching */
/* Tiggered by pressing the “Set” button
*/
/**************************************************/
-(IBAction)USB_Updateid)sender
{
//Read the string from the text field and convert to hex value.
//Update Product ID from text field
NSString *myPID = [PIDField stringValue];
NSScanner* myPidScanner = [NSScanner scannerWithString:myPID];
[myPidScanner scanHexLongLong: &ProductID];
www.cypress.com
Document No. 001-82072 Rev. *D
61
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
//Update Vendor ID from text field
NSString *myVID = [VIDField stringValue];
NSScanner* myVidScanner = [NSScanner scannerWithString:myVID];
[myVidScanner scanHexLongLong: &VendorID];
//Create a new matching 62ons tint62 for the new VID and PID values
myDictionary = [NSMutableDictionary dictionary];
[myDictionary setObject:[NSNumber numberWithLong:ProductID]forKey:[NSString
stringWithCString:kIOHIDProductIDKey encoding:NSUTF8StringEncoding]];
[myDictionary setObject:[NSNumber numberWithLong:VendorID]forKey:[NSString
stringWithCString:kIOHIDVendorIDKey encoding:NSUTF8StringEncoding]];
//Set single matching criteria
IOHIDManagerSetDeviceMatching(tIOHIDManagerRef, (CFMutableDictionaryRef)
myDictionary);
//Initalize new USB device
[self initHID];
}
/*******************************************/
/* Function to update PWM duty cycle
*/
/* Triggered by pressing “Update” button
*/
/*******************************************/
-(IBAction)PWM_Updateid)sender
{
//Error check to make sure device is connected before proceeding
require(deviceRef, Oops);
//Convert String in textfield to Double
PWM_Duty = [PWMDutyField doubleValue];
//Check to see if an out of range value receiving.
//If so, change to closest acceptable value.
If(PWM_Duty > 100)
{
PWM_Duty = 100;
[PWMDutyField setIntValue:PWM_Duty];
}
if(PWM_Duty < 1)
{
PWM_Duty = 1;
[PWMDutyField setIntValue:PWM_Duty];
}
//Update Output Buffer with PWM value
outputBuffer[1] = PWM_Duty;
//Perform Output transfer
IOHIDDeviceSetReport(deviceRef, kIOHIDReportTypeOutput, 0, (uint8_t*)outputBuffer,
bufferSize);
//If no matching device is detected, do nothing.
Oops:;
www.cypress.com
Document No. 001-82072 Rev. *D
62
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
}
@end
/**************************************************/
/* Call Back Functions */
/*************************************************/
/*******************************************/
/* Function to handle Input Reports
*/
/* Triggered by receiving an Input Report */
/*******************************************/
static void MyInputCallback (void *context, IOReturn result, void *sender,
IOHIDReportType type, uint32_t reportID, uint8_t *report, CFIndex reportLength)
{
//Unload the inputBuffer into specific variables
SwStatus = inputBuffer[0];
AdcCounts_1 = inputBuffer[1];
AdcCounts_2 = inputBuffer[2];
AdcCounts_3 = inputBuffer[3];
AdcCounts_4 = inputBuffer[4];
//Reconstruct the ADC value from 4 8-bit values
AdcValue = (AdcCounts_1 << 24) + (AdcCounts_2 << 16) + (AdcCounts_3 << 8) +
AdcCounts_4;
}
//Handle for the Device Matching Callback
static void Handle_DeviceMatchingCallback(void *inContext, IOReturn inResult, void
*inSender, IOHIDDeviceRef inIOHIDDeviceRef)
{
/* Call the Class Method */
[(AppDelegate *) inContext deviceMatchingResult:inResult sender:inSender
device:inIOHIDDeviceRef];
}
// Handle_DeviceMatchingCallback
//Handle for the Device Removed Callback
static void Handle_DeviceRemovalCallback(void *inContext, IOReturn inResult, void
*inSender, IOHIDDeviceRef inIOHIDDeviceRef)
{
/* Call the Class Method */
[(AppDelegate *) inContext deviceRemovalResult:inResult sender:inSender
device:inIOHIDDeviceRef];
}
// Handle_DeviceRemovalCallback
www.cypress.com
Document No. 001-82072 Rev. *D
63
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
D
Appendix D: Linux_GenericHID_CLI.c for Linux
/* USB HID App for Linux */
#include <stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>
#include <time.h>
#define PASS 0
#define
#define
#define
#define
/* Array positioning for IN Data */
Button_Status_Pos 0
ADC_Pos_1 1
ADC_Pos_2 2
ADC_Pos_3 3
#define ADC_Pos_4 4
/* Array positioning for OUT Data */
#define LED_State_Pos 0
#define PWM_DC_Pos 1
/* Miscellaneous Result Defines */
#define PASS 0
#define FAIL -1
/* Miscellaneous variables for timing and interface referencing */
static const int INTERFACE_NUMBER = 0;
static const int TIMEOUT_MS = 5000;
static const int NUMBER_INPUT_ITERATIONS = 10;
static const int TIME_DELAY = 1;
/* Initialize and Set Default Vendor ID (VID) and Product ID (PID) */
static const int VID = 0x04B4;
static const int PID = 0xE177;
/* Endpoint Addresses defined in Endpoint Descriptor */
static const int IN_ENDPOINT_ADDRESS = 0x81;
static const int OUT_ENDPOINT_ADDRESS = 0x02;
/* Maximum Input and Output Transfer size */
static const int MAXIMUM_IN_TRANSFER_SIZE = 8;
static const int MAXIMUM_OUT_TRANSFER_SIZE = 8;
/* Function prototype to handle Input and Output transactions */
void Perform_Input_and_Output_Transfers(libusb_device_handle *MyHIDDevice, int
LED_State, int PWM_DutyCycle);
int main (void)
{
struct libusb_device_handle *MyHIDDevice = NULL;
int Device_Status = 0;
int Result = 0;
int LED_State;
int PWM_DutyCycle;
/* Initialize LibUSB */
Result = libusb_init(NULL);
/* Ensure that the LibUSB initializing was successful */
if (Result == PASS)
{
www.cypress.com
Document No. 001-82072 Rev. *D
64
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
printf(“\n”);
printf(“/******* PSoC 3 / PSoC 5LP Generic HID CLI *******/\n”);
printf(“Product ID: 0x%.4x”, PID);
printf(“\n”);
printf(“Vendor ID: 0x%.4x”, VID);
printf(“\n”);
/* Finds matching device and assigns device handle */
MyHIDDevice = libusb_open_device_with_vid_pid(NULL, VID, PID);
/* Check to see if HID was detected and properly assigned a handle */
if (MyHIDDevice != NULL)
{
/* Detach the Linux HID driver from the device to allow the use of libusb */
Result = libusb_detach_kernel_driver(MyHIDDevice, INTERFACE_NUMBER);
if(Result == PASS)
{
/* Claim USB interface for Application */
Result = libusb_claim_interface(MyHIDDevice, INTERFACE_NUMBER);
/* Ask user to provide parameters for Output Report */
switch(Result)
{
case LIBUSB_SUCCESS:
Device_Status = 1;
fprintf(stderr, “Device Connected \n”);
printf(“Enter a Desired State for LED_1 (0 or 1): “);
scanf(“%d”, &LED_State);
printf(“Enter a Desired PWM Duty Cycle for LED_2 (1-100): “);
scanf(“%d”, &PWM_DutyCycle);
break;
case LIBUSB_ERROR_NOT_FOUND:
fprintf(stderr, “The requested interface does not exist. \n”);
break;
case LIBUSB_ERROR_BUSY:
fprintf(stderr, “Another program or driver has claimed the
interface. \n”);
break;
case LIBUSB_ERROR_NO_DEVICE:
fprintf(stderr, “The device has been disconnected. \n”);
break;
default:
fprintf(stderr, “An Error has occurred. Application cannot
continue. \n”);
break;
}
}
}
else
{
fprintf(stderr, “Unable to locate an attached device that matches.\n”);
}
www.cypress.com
Document No. 001-82072 Rev. *D
65
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
}
else
{
fprintf(stderr, “Unable to initialize LibUSB. Please ensure that it is properly
Installed \n”);
}
if(Device_Status)
{
/* Send and receive data */
Perform_Input_and_Output_Transfers(MyHIDDevice, LED_State, PWM_DutyCycle);
/* Finished using the device */
libusb_release_interface(MyHIDDevice, 0);
/* Turn control of device back over to kernel HID driver */
libusb_attach_kernel_driver (MyHIDDevice, 0);
}
return 0;
}
void Perform_Input_and_Output_Transfers(libusb_device_handle *MyHIDDevice, int
LED_State, int PWM_DutyCycle)
{
/* Declare area in RAM for Input and Output Data Buffer */
unsigned char In_Data_Buffer[MAXIMUM_IN_TRANSFER_SIZE];
unsigned char Out_Data_Buffer[MAXIMUM_OUT_TRANSFER_SIZE];
/* Various variables for application code */
int ADC_Result = 0;
int Switch_Status = 0;
int Transfer_Count;
int Result = 0;
int In_Iteration_Count = 0;
/* Check to ensure LED_State is either ‘1’ or ‘0’. If not, variable will be
adjusted. */
if(LED_State > 1)
{
LED_State = 1;
}
if(LED_State < 0)
{
LED_State = 0;
}
/* Check to ensure PWM_DutyCycle is between 1 and 100. If not, variable will be
adjusted. */
if(PWM_DutyCycle > 100)
{
PWM_DutyCycle = 100;
}
if(PWM_DutyCycle < 1)
{
PWM_DutyCycle = 1;
}
www.cypress.com
Document No. 001-82072 Rev. *D
66
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
/* Store output data in output buffer prior to prior to transferring */
Out_Data_Buffer[LED_State_Pos]= LED_State;
Out_Data_Buffer[PWM_DC_Pos] = PWM_DutyCycle;
/* Perform Output Transfer to PSoC */
Result = libusb_interrupt_transfer(MyHIDDevice,
Out_Data_Buffer, MAXIMUM_OUT_TRANSFER_SIZE,
&Transfer_Count, TIMEOUT_MS);
OUT_ENDPOINT_ADDRESS,
/* Check to see if Output transaction was successful */
if (Result == PASS)
{
printf(“\n”);
printf(“/********** Output Data **********/\n”);
if (LED_State == 0)
{
printf(“Turn LED_1 Off”);
printf(“\n”);
}
else
{
printf(“Turn LED_1 On”);
printf(“\n”);
}
printf(“Set PWM Duty Cycle of LED_2 to %d%%”, PWM_DutyCycle);
printf(“\n”);
printf(“\n”);
}
else
{
printf(“Error Has Occurred with Output Transfer \n”);
printf(“\n”);
}
/* Request IN report from PSoC. Performs in a loop. Number of cycles dependent on
NUMBER_INPUT_ITERATIONS */
printf(“/********** Input Data **********/\n”);
for(In_Iteration_Count=0; In_Iteration_Count<NUMBER_INPUT_ITERATIONS;
In_Iteration_Count++)
{
Result = libusb_interrupt_transfer(MyHIDDevice,
IN_ENDPOINT_ADDRESS,
In_Data_Buffer,
MAXIMUM_IN_TRANSFER_SIZE,
&Transfer_Count,
TIMEOUT_MS);
/* Check to see if Input request was successful */
if (Result == PASS)
{
/* Unload data from Input Buffer and format ADC Data */
ADC_Result = (In_Data_Buffer[ADC_Pos_1] << 24) + (In_Data_Buffer[ADC_Pos_2] <<
16) + (In_Data_Buffer[ADC_Pos_3] << 8) +
In_Data_Buffer[ADC_Pos_4];
Switch_Status = In_Data_Buffer[Button_Status_Pos];
www.cypress.com
Document No. 001-82072 Rev. *D
67
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
/* Print Input Data in the Terminal */
printf(“ADC Value: %07d \n”, ADC_Result);
if(Switch_Status == 0)
{
printf(“Switch is Not Pressed \n”);
printf(“\n”);
}
else
{
printf(“Switch is Pressed \n”);
printf(“\n”);
}
}
else
{
printf(“Error Occurred with Input Transfer \n”);
printf(“\n”);
}
/* Time is seconds to wait between Input requests */
sleep(TIME_DELAY);
}
}
www.cypress.com
Document No. 001-82072 Rev. *D
68
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Document History
Document Title: AN82072 - PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Document Number: 001-82072
Revision
ECN
Orig. of
Change
Submission
Date
Description of Change
**
3749838
RLRM
09/21/2012
New Spec.
*A
3819496
RLRM
11/22/2012
Updated for PSoC 5LP.
*B
4497191
KLMZ
09/09/2014
Updated title to include in PSoC USB HID AN Family, Updated screenshots for
Creator 3.0
*C
5067967
RLRM
01/06/2016
Updated Linux instructions, fixed typo in OS X application.
Updated to new template.
*D
5220391
RLRM
04/20/2016
Updated hyperlinks across the document.
Updated Related Resources:
Updated Application Notes:
Removed reference of AN52970.
Updated to new template.
www.cypress.com
Document No. 001-82072 Rev. *D
69
PSoC® 3 and PSoC 5LP USB General Data Transfer with Standard HID Drivers
Worldwide Sales and Design Support
Cypress maintains a worldwide network of offices, solution centers, manufacturer’s representatives, and distributors. To find
the office closest to you, visit us at Cypress Locations.
PSoC® Solutions
Products
ARM® Cortex® Microcontrollers
cypress.com/arm
cypress.com/psoc
Automotive
cypress.com/automotive
PSoC 1 | PSoC 3 | PSoC 4 | PSoC 5LP
Clocks & Buffers
cypress.com/clocks
Interface
cypress.com/interface
Lighting & Power Control
cypress.com/powerpsoc
Community
Memory
cypress.com/memory
PSoC
cypress.com/psoc
Technical Support
Touch Sensing
cypress.com/touch
USB Controllers
cypress.com/usb
Wireless/RF
cypress.com/wireless
Cypress Developer Community
| Forums | Blogs | Video | Training
cypress.com/support
PSoC is a registered trademark of Cypress Semiconductor Corp. PSoC Creator is a trademark of Cypress Semiconductor Corp. All other trademarks or
registered trademarks referenced herein are the property of their respective owners.
Cypress Semiconductor
198 Champion Court
San Jose, CA 95134-1709
Phone
Fax
Website
: 408-943-2600
: 408-943-4730
: www.cypress.com
© Cypress Semiconductor Corporation, 2012-2016. The information contained herein is subject to change without notice. Cypress Semiconductor
Corporation assumes no responsibility for the use of any circuitry other than circuitry embodied in a Cypress product. Nor does it convey or imply any
license under patent or other rights. Cypress products are not warranted nor intended to be used for medical, life support, life saving, critical control or
safety applications, unless pursuant to an express written agreement with Cypress. Furthermore, Cypress does not authorize its products for use as
critical components in life-support systems where a malfunction or failure may reasonably be expected to result in significant injury to the user. The
inclusion of Cypress products in life-support systems application implies that the manufacturer assumes all risk of such use and in doing so indemnifies
Cypress against all charges.
This Source Code (software and/or firmware) is owned by Cypress Semiconductor Corporation (Cypress) and is protected by and subject to worldwide
patent protection (United States and foreign), United States copyright laws and international treaty provisions. Cypress hereby grants to licensee a
personal, non-exclusive, non-transferable license to copy, use, modify, create derivative works of, and compile the Cypress Source Code and derivative
works for the sole purpose of creating custom software and or firmware in support of licensee product to be used only in conjunction with a Cypress
integrated circuit as specified in the applicable agreement. Any reproduction, modification, translation, compilation, or representation of this Source
Code except as specified above is prohibited without the express written permission of Cypress.
Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THIS MATERIAL, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress reserves the
right to make changes without further notice to the materials described herein. Cypress does not assume any liability arising out of the application or
use of any product or circuit described herein. Cypress does not authorize its products for use as critical components in life-support systems where a
malfunction or failure may reasonably be expected to result in significant injury to the user. The inclusion of Cypress’ product in a life-support systems
application implies that the manufacturer assumes all risk of such use and in doing so indemnifies Cypress against all charges.
Use may be limited by and subject to the applicable Cypress software license agreement.
www.cypress.com
Document No. 001-82072 Rev. *D
70