SoFunction
Updated on 2025-03-01

Detailed explanation of the basic process of Android USB to serial communication development

I haven't written an article for a long time. A new project was launched by the company a year ago, which is related to USB to serial communication. The requirement is to use an Android tablet to communicate with several peripherals after being transferred through USB. I was busy until recently and I slowly got idle. Taking advantage of the fact that I was not busy this weekend, I recorded the basic process of USB to serial communication development.

We developed the USB host mode, that is, the Android tablet is used as the host and the USB peripheral is used as the slave for data communication. The entire development process can be summarized as follows:

1. Discover the equipment

UsbManager usbManager = (UsbManager) (Context.USB_SERVICE);
Map<String, UsbDevice> usbList = ();

Through the classes provided by the UsbManager system, we can enumerate all the currently connected USB devices. What we mainly need is the UsbDevice object. Regarding the UsbDevice class, the official comment is as follows:

This class represents a USB device attached to the android device with the android device
acting as the USB host.

Yes, this class represents the USB device connected to Android.

2. Turn on the device

Next, we need to open the USB device we just searched for. We can imagine the connection between the tablet and the USB peripheral as a channel. Only after opening the channel door can the two sides communicate.

Generally speaking, when we first access the USB device on a custom Android device, we do not have access permissions by default. Therefore, we must first determine whether we have access permissions to the currently open USBDevice:

if (!(usbDevice)) {
    usbPermissionReceiver = new UsbPermissionReceiver();
    //Application permission    Intent intent = new Intent(ACTION_DEVICE_PERMISSION);
    PendingIntent mPermissionIntent = (context, 0, intent, 0);
    IntentFilter permissionFilter = new IntentFilter(ACTION_DEVICE_PERMISSION);
    (usbPermissionReceiver, permissionFilter);
    (usbDevice, mPermissionIntent);
    }

Here we declare a broadcast UsbPermissionReceiver, and do some other processing after receiving a authorized successful broadcast:

 private class UsbPermissionReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
      String action = ();
      if (ACTION_DEVICE_PERMISSION.equals(action)) {
        synchronized (this) {
          UsbDevice device = (UsbManager.EXTRA_DEVICE);
          if (().equals(()) {
            if ((UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
             //Authorization is successful, open the device here            } else {
             //Authorization failed            }
          }
        }
      }
    }
  }

Next, we need to find the interface UsbInterface with data transmission function, and find the data input and output port UsbEndpoint from it. Generally speaking, a usbDevice has multiple UsbInterfaces, and what we need is usually the first one, so:

usbInterface=(0);

Similarly, a usbInterface has multiple UsbEndpoints, which have control ports and data ports, etc. Therefore, we need to find the data input and output ports we need according to the type and data flow:

for (int index = 0; index < (); index++) {
        UsbEndpoint point = (index);
        if (() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
          if (() == UsbConstants.USB_DIR_IN) {
            usbEndpointIn = point;
          } else if (() == UsbConstants.USB_DIR_OUT) {
            usbEndpointOut = point;
          }
        }
      }

Finally, it is the real way to open the USB device. We need to create a UsbDeviceConnection with the USB peripheral. Its comments briefly illustrate its purpose:

This class is used for sending and receiving data and control messages to a USB device.

Its acquisition is also very simple, just one sentence of code:

usbDeviceConnection = (usbDevice);

At this point, theoretically, the connection between the tablet and the USB peripheral has been established, and data can be first released. However, in most cases, we also need to configure the USB serial port, such as baud rate, stop bit, data control, etc. Otherwise, the configurations on both sides are different, and the received data will be garbled. The specific configuration depends on what serial port chip you are using. Currently, the popular ones include pl2303, ch340, etc. Due to space issues, friends who need to configure the serial port code should check it out by themselves.

3. Data transmission

At this point, we can already conduct data transmission with the USB peripheral. First, let’s see how to send data to the USB device.

1. Send data to the USB peripheral

In the second step, we have obtained the output port of the data usbEndpointIn, and we send data to the peripherals through this port. Let's see how to use:

Copy the codeThe code is as follows:

int ret = (usbEndpointOut, data, , DEFAULT_TIMEOUT);

The bulkTransfer function is used to transmit data on a given port. The first parameter is the port for this transmission. Here we use the output port. The second parameter is the data to be sent, the type is a byte array, the third parameter represents the length of the data to be sent, and the last parameter is timeout. The return value represents the number of bytes successfully sent. If -1 is returned, it means that the sending failed.

2. Accept data sent by the USB peripheral

Similarly, we have found the data input port usbEndpointIn. Because the input of the data is irregular, we can open another thread to specifically accept the data. The code for accepting the data is as follows:

int inMax = (); 
ByteBuffer byteBuffer = (inMax); 
UsbRequest usbRequest = new UsbRequest(); 
(connection, inEndpoint); 
(byteBuffer, inMax); 
if(() == usbRequest){ 
  byte[] retData = (); 
  for(Byte byte1 : retData){ 
    (byte1); 
  } 
}

The above is the basic process of USB to serial communication. Some places are not written in a very comprehensive way, such as the method of receiving USB peripheral data, and you are welcome to correct any shortcomings. I also hope everyone supports me.