USB port operation programming interface. USB programming in Android. We use the USB interface for communication. Main properties and events of the TJvHidDevice class

The USB bus (Universal Serial Bus) appeared on January 15, 1996, with the approval of the first version of the standard by Intel, DEC, IBM, NEC, Northen Telecom and Compaq.

The main goal of the standard set for its developers is to create the ability for users to work in Plug&Play mode with peripheral devices. This means that it must be possible to connect the device to a running computer, automatically recognize it immediately after connection and then install the appropriate drivers. In addition, it is advisable to supply power to low-power devices from the bus itself. Bus speed should be sufficient for the vast majority peripheral devices. USB controller should take only one interrupt, regardless of the number of devices connected to the bus, that is, solve the problem of lack of resources on internal IBM buses PC compatible computer.

Almost all the tasks were solved in the USB standard and in the spring of 1997 computers equipped with connectors for USB connections devices. Now USB has become so actively implemented by manufacturers of computer peripherals that, for example, the iMAC computer from Apple Computers has only USB as an external bus.

USB Capabilities 1.0 are as follows:

1. high data transfer speed (full-speed) – 12 MB it/With;

2. maximum cable length for high speed exchange – 5 meters;

3. low data exchange speed (low-speed) – 1.5 MB it/With;

4. maximum cable length for low data transfer speed is 3 meters;

5. maximum number of connected devices – 127;

6. possible simultaneous connection of devices with different exchange rates;

8. maximum current consumption per device – 500 mA.

Therefore, it is advisable to connect almost any peripheral devices to USB 1.0, except digital video cameras and high-speed hard drives. This interface is especially convenient for connecting frequently connected/disconnected devices, such as digital cameras.
The ability to use only two data rates limits the usability of the bus, but significantly reduces the number of interface lines and simplifies the hardware implementation.
Power directly from USB is only possible for low power devices such as keyboards, mice, joysticks, etc.

USB signals are transmitted via a 4-wire cable, shown schematically in the figure below:

Figure 2.6.1 – Signal USB wires

Here GND is the common wire circuit for powering peripheral devices, Vbus is +5 V also for power circuits. The D+ bus is for transmitting data on the bus, and the D- bus is for receiving data.
Support cable full speed tires (full-speed) is performed as twisted pair, is protected by a screen and can also be used to operate in low-speed mode. A cable for operation only at minimum speed (for example, to connect a mouse) can be any and unshielded.
The connectors used to connect peripheral devices are divided into series: “A” series connectors (plug and socket) are intended only for connection to a source, such as a computer, “B” series connectors (plug and socket) are only for connection to a peripheral device.

USB connectors have the following pin numbering, shown in Table 2.6.1.

Table 2.6.1 – Purpose and marking of USB contacts

In 1999, the same consortium computer companies, who initiated the development of the first version of the USB bus standard, began to actively develop version 2.0 of USB, which is distinguished by the introduction of an additional high-speed (Hi-speed) mode. The bus bandwidth has been increased 40 times, up to 480 Mbit/s, which made it possible to transfer video data via USB.
Compatibility of all previously released peripherals and high speed cables is completely preserved. The 2.0 standard controller is already integrated into the system logic set of programmable devices (for example, motherboard personal computer).

In 2008 Intel companies, Microsoft, Hewlett-Packard, Texas Instruments, NEC and NXP Semiconductors created the USB 3.0 standard specification. In the USB 3.0 specification, the connectors and cables of the updated standard are physically and functionally compatible with USB 2.0, but in addition to the four communication lines, four more have been added. However, new contacts in USB connectors 3.0 are located separately from the old ones on a different contact row. The USB 3.0 specification increases the maximum transfer speed to 5 Gbps - which is an order of magnitude higher than the 480 Mbps that USB 2.0 can provide. In addition, the maximum current has been increased from 500 mA to 900 mA per device, allowing you to power some devices that previously required a separate power supply.

Suppose you have developed a USB device that you need to work with using a computer. This can be achieved in at least two ways:

1. development of a full-featured driver operating system;

2. use of the interface special class USB devices are called HID (Human Interface Device) devices.

The first method is universal: having sufficient knowledge in the field of writing drivers, you can program it to work with any device at any speed supported by USB. But this is quite a difficult task.

The second way is as follows. There is an interface supported by modern operating systems for computer-human interface devices or HID devices, such as:

1. keyboards, mice, joysticks;

2. various sensors and readers;

3. gaming steering and pedals;

4. buttons, switches, regulators.

Any such device, if it meets the requirements for HID devices, will be automatically recognized by the system and will not require writing special drivers. In addition, programming them is usually much simpler than writing a custom device driver. Unfortunately, this method has a significant drawback: the speed of information exchange with the HID device is very limited and amounts to a maximum of 64 kB/s.

In principle, based on HID technology, it is possible to organize interaction with any device, even if it is not in the strict sense a human-computer interface device. This eliminates the time-consuming development of a unique device driver and saves time on developing a new USB device. On the host side, communication with the device will be controlled by the standard HID driver included with the operating system. You just need to do it from the device side minimum requirements USB-HID protocol.

It is worth noting that many USB devices, which at first glance do not fall under the definition of human interaction devices, are still more logical to be implemented as HID devices. This phenomenon is common in the manufacturing equipment field, which has recently experienced a massive adoption of USB technology. For example, consider a laboratory power supply with the ability to set the parameters of its output signals from a computer using a USB interface. The power source itself is undoubtedly not a means of interaction with a person. However, in this case, the functions implemented via a USB connection duplicate the keyboard, controls and indicators installed on the device itself. And these controls fall within the definition of HID. Accordingly, it is most logical to organize a power supply with these USB functions as an HID device.

In the considered example for normal operation A low data transfer rate will be sufficient; in other cases, devices can be very demanding on the exchange rate. Low transfer speed is the main limitation of the HID device design option, which, in comparison with the 12 Mbit/s full speed of the USB 1.0 bus, looks like a big disadvantage of HID technology in the matter of choosing a specific USB implementation. However, for many communication tasks, the specified speed is quite enough and the HID architecture as a specialized tool takes its rightful place among the methods of organizing data exchange.

There are two types of HID devices: those that participate (boot) and those that do not participate in the initial boot of the computer. The most striking example of a bootable USB-HID device is a keyboard, which begins working when the computer starts.

When designing an HID device, the following specification requirements must be met:

1. Full speed HID device can transfer 64000 bytes every second or 64 bytes every 1ms; A low-speed HID device can transfer up to 800 bytes per second, or 8 bytes every 10 ms.

2. The HID device can schedule its polling frequency to determine if it has fresh data to transmit.

3. Data exchange with the HID device is carried out through a special structure called a report. Each specific report can contain up to 65535 bytes of data. The report structure has a very flexible organization that allows you to describe any data transmission format. In order for a specific report format to become known to the host, the microcontroller must contain a special description - a report descriptor.

USB interaction is implemented directly on the microcontroller in several ways:

1. using a controller with hardware support, for example AT90USB*, from atmega;

2. using software emulation of the USB interface on any microcontroller.

For software implementation there are currently a number of ready-made solutions under various families microcontrollers. For AVR microcontrollers, for example, Atmega8 it is possible to use the following free libraries in the C language:

Both are quite easy to use, provide full emulation of USB 1.1 low-speed devices, with the exception of handling communication errors and electrical characteristics, and run on almost all AVR controllers with at least 2 kilobytes of flash memory, 128 bytes of RAM and a frequency of 12 to 20 MHz.

To write applications that support Windows USB HID devices require the hid* header files included in the WDK (Windows Driver Kit), or you can use the freely available hidlibrary library or another similar one.

Thus, in general, USB programming is a rather complex task, requiring a special microcontroller with hardware support and writing an operating system driver. However, in practice, when developing devices, you can use a much simpler HID device interface, support for which is implemented at the level of a standard system driver, and programming is simplified by using existing function libraries.

Control questions

  1. What is the difference between the D- and GND wires in USB? Why can't you use one common wire for power and signal?
  2. How many speed modes USB operation exists today (including version 3.0)?
  3. What is an HID device? Why do they not require writing drivers to work in modern operating systems?
  4. Is it possible to implement USB devices using a microprocessor that does not have built-in interface support?
  5. What are the main differences between USB 3.0 and previous versions?

But it’s not enough just to physically connect the device to the computer, you also need to establish data exchange between them. How to choose a port and organize a connection? A few years ago standard solution was using a COM port. By the way, various specialists are still installing 8, 16, or even 32 COM ports on industrial computers (there is a whole category of different PCI expansion cards for serial ports, controllers, etc.). Thus, if you need to connect several external devices with an RS-232 interface, you may need expensive adapters and exotic expansion cards, which, according to the old tradition, travel to Russia by ship for weeks. By the way, the name of a regular adapter “DB9m/DB25f adapter” can only cause irritation for a computer store manager.

What is an HID device

Nowadays, almost all devices are connected to a computer via a USB interface. Therefore, many new PCs do not have a COM port at all.

USB interface - a typical solution for connecting a new external device with a computer, more precisely, it is an HID interface based on the USB 1.1 protocol.

Although many people think that the HID (Human Interface Device) interface is intended solely for the keyboard, mouse and joystick, it is suitable for many solutions related to pairing external devices with a computer.

If the user needs to carry out low-speed data exchange (up to 64 kbit/s) and at the same time wants to reduce the time on tedious development of his own drivers, then HID is quite suitable for him. The end result will be a simple and completely modern solution based on a standard USB software interface with guaranteed support on all common software platforms.

HID Device Properties

From an organizational point of view software support HID devices, everything looks quite attractive: to work under Windows control you can quickly create understandable, compact code based on ready-made, proven algorithms. At the same time, the developer will have a lot of time to implement his own top-level data exchange protocol, since the necessary abstraction level is already organized through the HID protocol (see table). In addition, it is easy for a programmer to debug a written exchange protocol (of course, if there is a working HID device) - due to the relative rigidity of the protocol itself, it is enough to simply develop a computer support program for the device. Still would! The creator of the HID device has already taken on a lot of work.

Organization of data exchange between the HID device and the computer

To describe the interaction of an HID device with a computer, we will use the term “host”. In this case, it is understood as a control device in the general physical architecture of interaction via the USB protocol. So, all ports on a computer are hosts. You can connect various USB devices (flash drives, mice, webcams, cameras, etc.) that do not have a host to them. The host provides device discovery, connection, disconnection, configuration, as well as statistics collection and energy management.

The HID device can set its own polling frequency to determine if it contains any new data. This means that even at such a low level the programmer can trust the system, since the polling frequency and other communication parameters must be pre-set in the HID device controller program. This is how the HID protocol differs from general description USB 1.1 or USB 2.0, which does not have strict protocol requirements. However, for specific tasks that require an increased level of security, it can be quite difficult to get rid of cyclic polling, when almost the same blocks of data are constantly transmitted.

HID device programming features

HID devices have special descriptors. When the host determines that the device belongs to the HID class, it passes control of it to the appropriate driver. It is assumed that further data exchange is carried out under his leadership.

In Windows, it is responsible for accessing HID devices system service HidServ. More details about the functions of requests to HID devices and other features of working with the HID driver are described in the work of P. V. Agurov “USB Interface. Practice of use and programming" (St. Petersburg: BHV-Petersburg, 2005).

Programming HID devices at the “top level”

The hard life of “application” programmers working in Pascal is made easier by the proven HID module. PAS, shell software for hid. dll (Hid User Library - as specified in the file properties). The comments to the file indicate that it is based on the hidsdi.h and hidpi.h modules from Microsoft. And the HID file itself. PAS is part of the JEDI() package.

To work with an HID device in the Delphi for win32 environment, the TJvHidDeviceController component is used, which is a convenient global manager for accessing HID devices. And already on its basis you can get an object instance for working with a specific device.

Basic properties and events of the TJvHidDeviceController component

Let's look at the TJvHidDeviceController component in more detail. The OnArrival event is triggered when an HID device enters (connects) to the system; access to the device is provided in the handler of this event through an instance of the TJvHidDevice class. The simple OnDeviceChange event reacts to changes in the state of the device; it only signals changes in the system. The OnDeviceData event is triggered when data arrives from one of the HID devices and passes the following to the handler: HidDev: TJvHidDevice; - the device from which the data was received;

The OnDeviceDataError event notifies about a data transfer error by passing the HidDev parameters to the processing procedure: TJvHidDevice; - HID device and Error: DWORD; - error code. The OnDeviceUnplug event notifies that a device is removed from the list of installed ones on the system. The types of event handlers on Plug and Unplug are the same (in the source text: TJvHidUnplugEvent = TJvHidPlugEvent). An object of the TJvHidDevice class corresponding to the HID device is passed to the handler.

To sequentially enumerate the HID devices available in the system by calling the Enumerate method, the OnEnumerate event is intended, i.e., in the event handler, the found devices are sequentially transferred as objects. This event is forced by the Enumerate method, which is used to “pass” existing HID devices through a handler, for example, when revising the state of HID devices at the initiative of the host (computer).

The OnRemoval event is triggered when a device is physically removed from the system and has the same handler type TJvHidUnplugEvent as for OnDeviceUnplug. The CountByProductName function returns the number of devices that match the product name specified in the argument, and CountByVendorName returns the manufacturer name specified in the argument.

Main properties and events of the TJvHidDevice class

The TJvHidDevice class is a virtual representation of a single HID device. A new object of this class can be obtained, as already mentioned, from the OnArrival or OnEnumerate event. The functionality of the TJvHidDeviceController and TJvHidDevice classes is partially duplicated, since the first of them integrates common tools for working with a set of HID devices available in the system and a mechanism for accessing one of them. A device can be uniquely identified by its SerialNumber, ProductName, and VendorName properties. To obtain information about the arrival of data using such an object, you can use the OnData event. Data is sent through the WriteFile method (in the strict sense - through a function). WriteFile is a wrapper around the WriteFile (kernel32) system function.

To control whether the device has been removed, you should assign your own handler to the OnUnplug event. Before you start exchanging data with an HID device, you need to make sure that such exchange is possible using HasReadWriteAccess. This class even has a separate OnDataError event when a data exchange error occurs.

Now let’s look at code fragments from a “live” project that implements a test client application for organizing data exchange with a non-standard device - HID-based plastic chip cards. In the fight for realism, the author took it upon himself not to throw out “extra” technological code connections from the listings.

The ScanDevices method (Listing 1) is intended to initiate the process of searching the system for the required HID device. Most of the code, with the exception of the call to the Enumerate method, is optional and provides flexibility to the application, for example, so that the ability to work on a non-HID interface could be added to the same test program. The AddError method displays debugging information in the window while the program is running.

Listing 2 shows an OnEnumerate event handler to find the required external device. For simplicity, we will assume that the program can only work with one device of the type it needs.

Before considering the further implementation of the project, we should talk a little about the adopted top-level data exchange format, i.e., about the structure designed to be an intermediary between the methods of receiving and transmitting data and the specific application problem being solved. The fact is that here the developer is given the opportunity to realize his creative abilities. Or rather, developers, because the process of creating a new protocol is very often two-way, and the first fiddle is played by the one who finds it more difficult to implement the exchange algorithm. In general, no matter what the exchange protocol is, it is always nice to make each software entity as visual and self-sufficient as possible, even at the expense of some generally accepted traditions. For The best decision- something that will be implemented in a short time with minimal connection to the software environment and with great opportunities for further development. Based on these principles, a top-level exchange protocol was created, where the main concept is “command”. Listing 3 shows how much the author loves string data, which has saved him more than once when debugging program modules. How wonderful it is that we even have a String type! All protocol commands are divided into categories (classes), within which there is a command code that uniquely characterizes its purpose. The edParam parameter is used to send data to the device, and the edAnswerData parameter contains data received from the device. The string type of the described record members allows you to freely and clearly manipulate data in HEX string format. And the best part is that the format of the described record ideologically stands somewhere in the middle between its direct purpose and the various forms of its presentation (INI, HEX, XML, etc.)

Executing the command, i.e. sending data to the device, is implemented using sending data packets 8 bytes long (Listing 4). This length is not the only solution; this choice is dictated by the requirements of the upper-level protocol and may be different in each specific case. This is, as they say, a matter of taste. The strange IsUSBMode flag in the ExecuteCommand method (Listing 5 in PC World) is left as a reminder that we may need to use a COM port or some other interface instead of working with USB. At the beginning of the sent group of data, a sync series of a randomly selected format (for example, 3E3E3E2B) is transmitted to the device, informing the device that it has completely legal data at the input. Let me remind you that in this case we are talking not so much about HID, but about a specific top-level protocol, ideologically separated from the hardware and intended to solve special application problems.

The GetDataExecutor handler for data received from the device (a packet of 8 bytes) uses a specially created OnNewInputData event to transfer the initially processed data for further processing, indicating their old and new values ​​(Listing 6 on the “World of PC Disk”). In this way, raw data arrival events and indications for further processing are decoupled, allowing some specific algorithm to be added early on to warn against erroneous, duplicate, or unnecessary input information.

The examples of working with an HID device presented here illustrate the general idea of ​​the article - the relative ease of programming non-standard HID devices using Delphi.

But it’s not enough just to physically connect the device to the computer, you also need to establish data exchange between them. How to choose a port and organize a connection? A few years ago, the standard solution was to use a COM port. By the way, various specialists are still installing 8, 16, or even 32 COM ports on industrial computers (there is a whole category of different PCI expansion cards for serial ports, controllers, etc.). Thus, if you need to connect several external devices with an RS-232 interface, you may need expensive adapters and exotic expansion cards, which, according to the old tradition, travel to Russia by ship for weeks. By the way, the name of a regular adapter “DB9m/DB25f adapter” can only cause irritation for a computer store manager.

What is an HID device

Nowadays, almost all devices are connected to a computer via a USB interface. Therefore, many new PCs do not have a COM port at all.

The USB interface is a standard solution for pairing a new external device with a computer; more precisely, it is an HID interface based on the USB 1.1 protocol.

Although many people think that the HID (Human Interface Device) interface is intended solely for the keyboard, mouse and joystick, it is suitable for many solutions related to pairing external devices with a computer.

If the user needs to carry out low-speed data exchange (up to 64 kbit/s) and at the same time wants to reduce the time on tedious development of his own drivers, then HID is quite suitable for him. The end result will be a simple and completely modern solution based on a standard USB software interface with guaranteed support on all common software platforms.

HID Device Properties

From the point of view of organizing software support for an HID device, everything looks quite attractive: to work under Windows, you can quickly create understandable, compact code based on ready-made proven algorithms. At the same time, the developer will have a lot of time to implement his own top-level data exchange protocol, since the necessary abstraction level is already organized through the HID protocol (see table). In addition, it is easy for a programmer to debug a written exchange protocol (of course, if there is a working HID device) - due to the relative rigidity of the protocol itself, it is enough to simply develop a computer support program for the device. Still would! The creator of the HID device has already taken on a lot of work.

Organization of data exchange between the HID device and the computer

To describe the interaction of an HID device with a computer, we will use the term “host”. In this case, it is understood as a control device in the general physical architecture of interaction via the USB protocol. So, all ports on a computer are hosts. You can connect various USB devices (flash drives, mice, webcams, cameras, etc.) that do not have a host to them. The host provides device discovery, connection, disconnection, configuration, as well as statistics collection and energy management.

The HID device can set its own polling frequency to determine if it contains any new data. This means that even at such a low level the programmer can trust the system, since the polling frequency and other communication parameters must be pre-set in the HID device controller program. This is how the HID protocol differs from the general USB descriptions 1.1 or USB 2.0, which does not have strict requirements for the organization of the protocol. However, for specific tasks that require an increased level of security, it can be quite difficult to get rid of cyclic polling, when almost the same blocks of data are constantly transmitted.

HID device programming features

HID devices have special descriptors. When the host determines that the device belongs to the HID class, it passes control of it to the appropriate driver. It is assumed that further data exchange is carried out under his leadership.

In Windows, the HidServ system service is responsible for accessing HID devices. More details about the functions of requests to HID devices and other features of working with the HID driver are described in the work of P. V. Agurov “USB Interface. Practice of use and programming" (St. Petersburg: BHV-Petersburg, 2005).

Programming HID devices at the “top level”

The hard life of “application” programmers working in Pascal is made easier by the proven HID module. PAS, shell software for hid. dll (Hid User Library - as specified in the file properties). The comments to the file indicate that it is based on the hidsdi.h and hidpi.h modules from Microsoft. And the HID file itself. PAS is part of the JEDI() package.

To work with an HID device in the Delphi for win32 environment, the TJvHidDeviceController component is used, which is a convenient global manager for accessing HID devices. And already on its basis you can get an object instance for working with a specific device.

Basic properties and events of the TJvHidDeviceController component

Let's look at the TJvHidDeviceController component in more detail. The OnArrival event is triggered when an HID device enters (connects) to the system; access to the device is provided in the handler of this event through an instance of the TJvHidDevice class. The simple OnDeviceChange event reacts to changes in the state of the device; it only signals changes in the system. The OnDeviceData event is triggered when data arrives from one of the HID devices and passes the following to the handler: HidDev: TJvHidDevice; - the device from which the data was received;

The OnDeviceDataError event notifies about a data transfer error by passing the HidDev parameters to the processing procedure: TJvHidDevice; - HID device and Error: DWORD; - error code. The OnDeviceUnplug event notifies that a device is removed from the list of installed ones on the system. The types of event handlers on Plug and Unplug are the same (in the source text: TJvHidUnplugEvent = TJvHidPlugEvent). An object of the TJvHidDevice class corresponding to the HID device is passed to the handler.

To sequentially enumerate the HID devices available in the system by calling the Enumerate method, the OnEnumerate event is intended, i.e., in the event handler, the found devices are sequentially transferred as objects. This event is forced by the Enumerate method, which is used to “pass” existing HID devices through a handler, for example, when revising the state of HID devices at the initiative of the host (computer).

The OnRemoval event is triggered when a device is physically removed from the system and has the same handler type TJvHidUnplugEvent as for OnDeviceUnplug. The CountByProductName function returns the number of devices that match the product name specified in the argument, and CountByVendorName returns the manufacturer name specified in the argument.

Main properties and events of the TJvHidDevice class

The TJvHidDevice class is a virtual representation of a single HID device. A new object of this class can be obtained, as already mentioned, from the OnArrival or OnEnumerate event. The functionality of the TJvHidDeviceController and TJvHidDevice classes is partially duplicated, since the first of them integrates common tools for working with a set of HID devices available in the system and a mechanism for accessing one of them. A device can be uniquely identified by its SerialNumber, ProductName, and VendorName properties. To obtain information about the arrival of data using such an object, you can use the OnData event. Data is sent through the WriteFile method (in the strict sense - through a function). WriteFile is a wrapper around the WriteFile (kernel32) system function.

To control whether the device has been removed, you should assign your own handler to the OnUnplug event. Before you start exchanging data with an HID device, you need to make sure that such exchange is possible using HasReadWriteAccess. This class even has a separate OnDataError event when a data exchange error occurs.

Now let’s look at code fragments from a “live” project that implements a test client application for organizing data exchange with a non-standard device - HID-based plastic chip cards. In the fight for realism, the author took it upon himself not to throw out “extra” technological code connections from the listings.

The ScanDevices method (Listing 1) is intended to initiate the process of searching the system for the required HID device. Most of the code, with the exception of the call to the Enumerate method, is optional and provides flexibility to the application, for example, so that the ability to work on a non-HID interface could be added to the same test program. The AddError method displays debugging information in the window while the program is running.

Listing 2 shows an OnEnumerate event handler to find the required external device. For simplicity, we will assume that the program can only work with one device of the type it needs.

Before considering the further implementation of the project, we should talk a little about the adopted top-level data exchange format, i.e., about the structure designed to be an intermediary between the methods of receiving and transmitting data and the specific application problem being solved. The fact is that here the developer is given the opportunity to realize his creative abilities. Or rather, developers, because the process of creating a new protocol is very often two-way, and the first fiddle is played by the one who finds it more difficult to implement the exchange algorithm. In general, no matter what the exchange protocol is, it is always nice to make each software entity as visual and self-sufficient as possible, even at the expense of some generally accepted traditions. Because the best solution is the one that will be implemented in a short time with minimal connection to the software environment and with great opportunities for further development. Based on these principles, a top-level exchange protocol was created, where the main concept is “command”. Listing 3 shows how much the author loves string data, which has saved him more than once when debugging program modules. How wonderful it is that we even have a String type! All protocol commands are divided into categories (classes), within which there is a command code that uniquely characterizes its purpose. The edParam parameter is used to send data to the device, and the edAnswerData parameter contains data received from the device. The string type of the described record members allows you to freely and clearly manipulate data in HEX string format. And the best part is that the format of the described record ideologically stands somewhere in the middle between its direct purpose and the various forms of its presentation (INI, HEX, XML, etc.)

Executing the command, i.e. sending data to the device, is implemented using sending data packets 8 bytes long (Listing 4). This length is not the only solution; this choice is dictated by the requirements of the upper-level protocol and may be different in each specific case. This is, as they say, a matter of taste. The strange IsUSBMode flag in the ExecuteCommand method (Listing 5 in PC World) is left as a reminder that we may need to use a COM port or some other interface instead of working with USB. At the beginning of the sent group of data, a sync series of a randomly selected format (for example, 3E3E3E2B) is transmitted to the device, informing the device that it has completely legal data at the input. Let me remind you that in this case we are talking not so much about HID, but about a specific top-level protocol, ideologically separated from the hardware and intended to solve special application problems.

The GetDataExecutor handler for data received from the device (a packet of 8 bytes) uses a specially created OnNewInputData event to transfer the initially processed data for further processing, indicating their old and new values ​​(Listing 6 on the “World of PC Disk”). In this way, raw data arrival events and indications for further processing are decoupled, allowing some specific algorithm to be added early on to warn against erroneous, duplicate, or unnecessary input information.

The examples of working with an HID device presented here illustrate the general idea of ​​the article - the relative ease of programming non-standard HID devices using Delphi.


Fig. 1 Illustration of the operation of an Android device in USB Host and Accessory modes (picture from the site http://developer.android.com)

Note that using USB is not the only way to communicate with the same homemade device. Android also allows you to use NFC, Wi-Fi P2P, SIP, as well as standard network connection. So the developer has enough opportunities in his arsenal to realize his wildest ideas.

Another common communication option is various devices is still in use USB-COM adapter. There is material on the Internet on using a USB-COM adapter in Android - see, for example,. The popularity of this connection is due to the presence large quantities devices already developed using various microcontrollers, communication with which is carried out using a COM port (serial port), which 10 years ago was almost in a standard way transfer data from a computer to a homemade piece of hardware.

Compared to a COM port, using USB can significantly increase data transfer speeds and make this process more user-friendly. Transmission speed, which even in the case of low-speed devices (keyboards, mice, joysticks), is 10-1500 Kbps, simplicity and low cost of the cable system and connections, self-identification of devices with automatic configuration, hiding details electrical connection from the end user (plus the ability to disconnect the cable without turning off the devices), error control and error recovery at the protocol level - these are the undeniable advantages of this technology (see, p. 12).

In general, speaking about the use of USB for data transfer, it would be useful to mention P. Agurov’s book “USB Interface”. Although it is often criticized on the Internet and was last released in 2006, it has more than once helped to find the right solution when searching for information on various aspects of the application of this technology. The book covers issues from choosing a microcircuit and circuit design for the controller to writing a microcontroller program and examples of programming data transfer via the USB protocol from the computer. It is impossible not to indicate the “primary source” of data on this issue - the website of the non-profit organization USB IF (USB Implementers Forum), which is developing specifications for this interface -, Truth this material on English language. However, it is there that you will find comprehensive information about the USB interface device. There is a good translation of parts of the specification - . Those interested in software solutions from the microcontroller side can also see the link.

This article is addressed primarily to those who have any electronic device(developed by yourself or someone else), the data exchange protocol with which is well known (for example, there is already a program that works with this device in Windows/Linux) and I would like to have a program that works with it in Android.

A little about USB device classes

It should be noted that the development software to communicate with a specific device highly depends on its implementation at the microcontroller level. For obvious reasons, it is impossible to provide examples of communication programs for all types of USB devices in one article (initial information about programming various types devices can be found in). However, we will limit ourselves to presenting code that implements device search and access to its control points for information exchange. We will also analyze sending data using the example of one of the types of USB devices, namely, the HID (human interface device) class of devices. This class includes “slow” devices such as a keyboard, mouse, joystick, and there are plenty of examples of its implementation using various microcontrollers on the network (there are, for example, in).

Why is the HID class so popular among manufacturers of various home-made devices? To quote Wikipedia: “In addition to detailed specifications of classic input devices (such as keyboards and mice), the HID standard defines a special class of devices without detailed specifications. This class is called USB HID Consumer Control and is essentially an unregulated communication channel with a device. In this case, the device uses the same standard drivers for the operating system as a mouse and keyboard. So you can create USB device which does not require the creation and installation of special drivers in most common computer operating systems." It only remains to add that this specification also works in the Android OS (not excluding CyanogenMod firmware).

One of the options for exchanging data with an HID device is interrupt transfer, which is used when it is necessary to transfer small data packets (the maximum packet size depends on the transfer rate and ranges from 64 to 1024 bytes) after a specified time interval. The package for transmission is called a report (English - report, see pp. 71, 95). This length of a report is usually quite enough to exchange information with a homemade device; 64 bytes of information in one packet, for example, is quite a lot for a controller, because 1 bit of information is enough to transmit the states of an LED or a simple sensor.

Required Tools

So, we will need a tablet or phone with Android version no lower than 3.1. It should be noted here that the above USB Host API is not fully implemented on all mobile devices (this is also mentioned on the developer.android.com website, see link). On some tablets/phones, the USB connector is used only for charging and communication with personal computer. Once again I will refer the reader to the list of mobile devices suitable or unsuitable for our experiments (see).

You will also need some kind of USB device (for the first experiments, a regular USB flash drive will be enough), OTG adapter(On-The-Go - see Fig. 2) and/or a USB cable for connecting to the device. Wikipedia says about OTG: “When connecting via USB OTG, the rank of the device (master or slave) is determined by the presence or absence of a jumper between pins 4 and 5 in the connecting cable plug. In a USB OTG cable, such a jumper is installed only in one of the two connectors (see). Accordingly, we need such a jumper on the side of the mobile device.


Fig.2 Differences in the circuit of a regular USB cable and an OTG cable (picture from http://tech.firstpost.com)

You can solder such an OTG cable for your device yourself. To do this, you need to buy a suitable connector at a radio store, plus the author, for example, used an old cable from a portable hard drive:

It will also be a good help in your work USB program Device Info installed from Google storage Play Market. The program can detect devices connected to the USB connector of a tablet/phone using both the Java API and Linux kernels. That is, if your device is not detected using the Java USB Host API in USB Device Info, then, most likely, it will be in vain to use any (including your own) Android program written using Java for this mobile device and USB Host API.

Sometimes, the information output by the lsusb operating command is also very useful. Linux systems. With the -v and -d switches, lsusb displays everything, or almost everything, about a USB device that a software developer needs for devices of this class (see Fig. 3).


Fig.3 Example output of lsusb and lsusb -v -d commands

Next, you need a computer with installed Android SDK and Eclipse integrated development environment (IDE) with the ADT plugin (although you can get by with just the SDK). You can see how to create and install an application for Android, for example, in, or on the Internet.

And, of course, you need at least the desire to achieve results, without it you can’t! I note that to clarify some technical issues The author's use of USB in Android required weeks of painstaking search for information.

Java classes for working with USB in Android API

So, as they say on the website of the developers of the USB Host API for Android (see) - “before you start, it is important to understand what classes you will use in your work.” Table 1 provides a description of the most important classes for working with the USB Host API (an attempt to translate information from http://developer.android.com).

Table 1. Description of classes for working with USB in Android

Class name Description
USBManager Allows you to enumerate and communicate with connected USB devices.
Allows you to detect a connected USB device and exchange data with it.
USBDevice Represents a connected USB device and contains methods to access its identifying information, interfaces, and endpoints.
Represents a connected USB device and contains methods for accessing its identity, interfaces, and endpoints.
USBInterface Represents an interface of a USB device, which defines a set of functionality for the device. A device can have one or more interfaces on which to communicate on.
Represents the "interface" of a USB device, which defines the set of functions for that device. One device may have one or more interfaces for exchanging information.
USBEndpoint Represents an interface endpoint, which is a communication channel for this interface. An interface can have one or more endpoints, and usually has input and output endpoints for two-way communication with the device.
Represents the "endpoint" of an interface, which is the communication channel for that interface. An interface can have one or more endpoints, and usually has endpoints for receiving information and for transmitting it.
USBDeviceConnection Represents a connection to the device, which transfers data on endpoints. This class allows you to send data back and forth sychronously or asynchronously.
Represents "connection" to this device. Required to transfer data to the endpoint. This class allows you to receive or transmit data synchronously or asynchronously.
USBRequest Represents an asynchronous request to communicate with a device through a UsbDeviceConnection.
Represents an asynchronous request to communicate with a device via a UsbDeviceConnection.
USBConstants Defines USB constants that correspond to definitions in linux/usb/ch9.h of the Linux kernel..
Defines constants that correspond to the definitions in linux/usb/ch9.h of the Linux kernel.

In almost all cases of using the USB Host API, the programmer uses these classes in his work. The algorithm for their use looks something like this: we define devices (the goal is programmatic access to the UsbDevice class) connected to the host (mobile device) using UsbManager. When software access to a device is obtained, it is necessary to determine the appropriate UsbInterface and UsbEndpoint to communicate with it. Once you have the endpoint in your possession, open UsbDeviceConnection to communicate with the USB device. If the endpoint operates in asynchronous transfer mode, we use the UsbRequest class.

Let's try to figure it all out by creating a simple application that, using this API, will determine what is connected to the host with the OS Android device and will display some information about it on the screen of your phone or tablet.

Create a project

In Eclipse, a project is created using the File->New->Android Application Project menu items. Note also that the code below is borrowed from example applications supplied with the Android SDK (folder android sdk samples/android-N(API Level)/USB) we are talking about the Missile Launcher USB toy control program (see Fig. 4 ) Sample applications are downloaded via Android SDK Manager (check the box - Samples for SDK). In the listings below, the code examples are provided with comments that explain what is happening.


Fig.4 Fun toy "Rocket launcher"

When creating a project, do not forget to check the required API Level in the Minimum Requared SDK option (API Level 12, corresponding Android versions 3.1 /Honeycomb/, or higher). The project will have a very simple user interface - the main window (Activity) and TextView for displaying information. A similar project is discussed in detail in.

In the automatically created class for the Activity of our project, it is necessary to define the following instances of classes for working with USB:

private TextView lgView;
private UsbManager mUsbManager;
private UsbDevice mDevice;
private UsbDeviceConnection mConnection;
private UsbEndpoint mEndpointIntr;

LgView = (TextView) findViewById(R.id .logTextView ) ;

and get access to the UsbManager class

MUsbManager = (UsbManager) getSystemService(Context .USB_SERVICE ) ;

Let's also create an onResume() event handler. Let's achieve the goal - so that information about connected devices is updated when our application window is activated (see Listing 1).

Listing 1. OnResume() event handler

public void onResume() (
super.onResume();

//fill the container with a list of devices
HashMap< String , UsbDevice>deviceList = mUsbManager.getDeviceList();
Iterator< UsbDevice>deviceIterator = deviceList.values().iterator();

lgView.setText("Devices Count:" + deviceList.size());

while (deviceIterator.hasNext()) (
UsbDevice device = (UsbDevice) deviceIterator.next () ;

//example of determining the ProductID of a device
\n"+ "Device ProductID: " + device.getProductId());
}
//define the intent described in the filter
// intent AndroidManifest.xml
Intent intent = getIntent() ;
lgView.setText(lgView.getText()+" \n"+ "intent: " + intent);
String action = intent.getAction();

//if the device is connected, pass the link to
//to the setDevice() function
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) ;
if (UsbManager.ACTION_USB_DEVICE_ATTACHED .equals (action) ) (
setDevice(device) ;
lgView.setText(lgView.getText()+" \n" + "UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action) is TRUE") ;
) else if (UsbManager.ACTION_USB_DEVICE_DETACHED .equals (action) ) (
if (mDevice != null && mDevice.equals (device) ) (
setDevice(null) ;
lgView.setText(lgView.getText()+" \n" + "UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action) is TRUE") ;
}
}

Next, we will create the setDevice() function for the Activity, which is necessary to work with our device (see Listing 2). In the onResume() handler and in the setDevice() function, we exactly followed the algorithm for using the USB Host API described in the previous section.

Listing 2. setDevice() function

private void setDevice(UsbDevice device) (
lgView.setText(lgView.getText()+" \n"+ "setDevice " + device);

//determine available device interfaces
if (device.getInterfaceCount() != 1 ) (

LgView.setText (lgView.getText() + " \n"+ "could not find interface" ) ;
return ;
}
UsbInterface intf = device.getInterface(0);

//define device endpoints
if (intf.getEndpointCount() == 0 ) (

LgView.setText (lgView.getText() + " \n"+ "could not find endpoint" ) ;
return ;
) else (
lgView.setText(lgView.getText()+" \n"+ "Endpoints Count: " + intf.getEndpointCount () ) ;
}

UsbEndpoint epIN = null ;
UsbEndpoint epOUT = null ;

//look for endpoints to transmit via interrupts
for (int i = 0 ; i< intf.getEndpointCount () ; i++ ) {
if (intf.getEndpoint(i).getType() == UsbConstants.USB_ENDPOINT_XFER_INT) (
if (intf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN) (
epIN = intf.getEndpoint(i) ;
lgView.setText(lgView.getText()+" \n"+ "IN endpoint: " + intf.getEndpoint (i) ) ;
}
else(
epOUT = intf.getEndpoint(i) ;
lgView.setText(lgView.getText()+" \n"+ "OUT endpoint: " + intf.getEndpoint (i) ) ;
}
) else ( lgView.setText ( lgView.getText() + " \n" + "no endpoints for INTERRUPT_TRANSFER") ; }
}

MDevice = device;
mEndpointIntr = epOUT;

//open the device for data transfer
if (device != null ) (
UsbDeviceConnection connection = mUsbManager.openDevice (device) ;
if (connection != null && connection.claimInterface (intf, true ) ) (

LgView.setText (lgView.getText() + " \n"+ "open device SUCCESS!" ) ;
mConnection = connection;

) else (

LgView.setText (lgView.getText() + " \n"+ "open device FAIL!" ) ;
mConnection = null ;
}
}
}
}

In addition to the above code, which, as the attentive reader has probably guessed, opens the device for receiving and transmitting data, all that remains is to use the data exchange protocol, which, I repeat, should be well known to the developer. We will only present, as promised, the code that will send a certain message data packet to the HID device using interrupt transmission, the UsbRequest class and the corresponding endpoint - see Listing 3.

Listing 3. Example code for sending data to a device

//determining the size of the buffer to send
//based on the maximum packet size
int bufferDataLength = mEndpointIntr.getMaxPacketSize () ;

lgView.setText(lgView.getText()+" \n"+ mEndpointIntr.getMaxPacketSize());

ByteBuffer buffer = ByteBuffer.allocate (bufferDataLength + 1 ) ;

UsbRequest request = new UsbRequest() ;

buffer.put(message);

request.initialize(mConnection, mEndpointIntr) ;

request.queue(buffer, bufferDataLength) ;

if (request.equals(mConnection.requestWait()) )

//sending was successful
//lgView.setText(lgView.getText() + "\n" + "sending CLEAR!!!");

catch (Exception ex)

//Is there something wrong...
//lgView.setText(lgView.getText() + "\n" + "sending not clear...");

Device filtering in AndroidManifest.xml

Although there is no need to search in our application specific device with known VID (Vendor-ID) and PID (Product-ID), Google engineers do not provide examples of applications without an intent-filter section in the manifest file, and the author was unable to get the program to work without device filtering in AndroidManifest.xml.

Let me remind you that Vendor-ID and Product-ID are unique identifiers of USB devices. That is, using filtering, you can create an application that interacts only with specific device or some class of devices. Please note that device manufacturers must agree on these numbers with the USB IF organization.

An application whose manifest file is shown in Listing 4 and whose filter condition file is in Listing 5, for example, successfully recognizes USB flash drives connected to a mobile device, but does not recognize the keyboard and mouse that the author has. This application along with source code can be downloaded from the link.

Listing 4. AndroidManifest.xml file


" > http://schemas.android.com/apk/res/android"
> package="ru.learn2prog.usbhostexample"
android:versionCode="1"
android:versionName="1.0" >


android:minSdkVersion="12"
android:targetSdkVersion="14" />


android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >

android:name = "ru.learn2prog.usbhostexample.MainActivity"
android:label="@string/app_name" >
>

"android.intent.category.DEFAULT" />

"android.intent.category.LAUNCHER" />

>

>

>
"android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
>
>

>

Listing 5. Filter file device_filter.xml (/res/xml directory)

>

>

The operations for assembling and installing our application are no different from ordinary ones (see examples in,). I would like to draw your attention to the actions of the intent filter - when a device is connected to the host, the OS asks the user to launch our application.

Literature/References: 11.
12.
13. http://developer.android.com/guide/topics/connectivity/usb/host.html - overview of the classes required to work with USB in Android
14. link to application sources

Programming via USB port

Programming the device for setup satellite dishes SF-50 via USB differs from programming via RS-232 only in the way data is transferred from the instrument to the computer and from the computer to the instrument. When programming via USB, a portable USB drive(flash drive). This is convenient when, for example, your computer or, more often, a laptop (netbook) does not have a serial RS-232 port on its chassis.
To program the device using a USB drive you will need:
- USB drive (flash drive), formatted in file system FAT-32;
- AliEditor editor program, located in the Database_editor_new folder of the software section of the OPENBOX SF-50 device.

Before programming, you need to transfer the database from the device to your computer. To do this, turn on the device, connect to the port USB flash drive. Execute MENU – System – Save to USB,

Exit the menu by pressing the MENU button until the current channel appears, or until the main menu picture if there are no channels yet and remove the flash drive. Insert the flash drive into the computer.
Run the Editor.exe program from the Database_editor_new folder and open the image on the flash drive in it.

When prompted to select a database, select User Data Base.

Click OK. Select All Services, a list of all scanned and saved TV, radio and service channels available in the database will open.

Edit channels as you wish, for example, leaving only open channels.
On your computer keyboard, hold down the Shift button, press Down Arrow and highlight the channels you want to delete. Click Delete to delete the selected one.

To edit the satellite settings, select All Services – Satellite Information – EUTELSAT W4, W7, press the ENTER button.

If necessary, edit the values ​​in Antenna 1.
To remove a transponder, stand on the unnecessary one and press Delete button on the computer keyboard, confirm the selected action.

To add a transponder, go to the name of the satellite, press right button mouse and select Add Information (or highlight the satellite and press the Insert button on the keyboard).

Enter the data for the new transponder, taking it, for example, from the website lyngsat.com.

Click OK and make sure that the transponder is registered.

To add a satellite, go to the Satellite Information line, press the Insert key on the keyboard and enter the parameters of the new satellite.

close the editor program and remove the drive.
Insert the drive into the OPENBOX SF-50 device, follow the sequence MENU – System – Update from USB, select the “SAT&TP List” mode.

Select Start. Confirm your intentions.

The device will update the database and reboot itself. After the reboot, you will have to set the menu language to Russian in a new way. Reset the device to factory settings.
Exit the settings menu by pressing the MENU button twice. Press the OK button on the current channel and make sure that the channel list is edited.

You can also make sure that the list of transponders and satellites is edited.
Programming is complete.