Android Usb (OTG) serial port communication, Service background service implementation method

The following are several open source Android serial communication libraries:
1. SerialPort: https://github.com/felHR85/SerialPort
This is a very popular Android serial communication library that supports a variety of devices and baud rates, and provides Very detailed documentation and sample code.
2. android-serialport-api: https://github.com/cepr/android-serialport-api
This is an easy-to-use Android serial port communication library that supports multiple devices and multiple baud rates, and provides examples code and documentation.
3. usb-serial-for-android: https://github.com/mik3y/usb-serial-for-android
This is an Android library that supports USB-to-serial communication, and can be connected to FTDI, PL2303 and other USB-to-serial chips , and provides very detailed documentation and sample code.
The above three libraries are all open source, and the source code and documentation can be obtained on GitHub.

There are examples of using the usb-serial-for-android library, but I found that there are two relatively big problems in it. The first one is to directly start the main interface when inserting, even if it is in the program, it needs to re-enter . The second is that the broadcast filter device_fitler.xml set in AndroidManifest.xml does not work at all. If you read this article and need to use my demo source code, you can move to the portal . But before that, it is strongly recommended to take a look at the routines on Github. If you have a strong understanding ability, you can directly move the Service source code.

Source code processed:

1. USB plugging and unplugging event when the App is running

2. App starts to check whether the USB exists

3. Whether the USB is a serial port device (because the plugging event can also be triggered when the USB storage device is inserted)

4. Start and stop processing

5. Sending and receiving processing

Gossip less! ! ! !

Service source code:

package com.apandserial.ConnectUtils.Manger;

import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

import com.apandserial.ConnectUtils.driver.UsbSerialDriver;
import com.apandserial.ConnectUtils.driver.UsbSerialPort;
import com.apandserial.ConnectUtils.driver.UsbSerialProber;
import com.apandserial.ConnectUtils.util.SerialInputOutputManager;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/***************************
 *Create By Jay_Song
 *Date:2023/5/17 Time:9:36
 ***************************/
public class ConnectService extends Service {

    private final static String TAG = "USB 插拔信息";
    private final static String USB_SERIALPORT_ATTCHED = "HR_USB_SERIALPORT_ATTCHED";
    private final static String USB_SERIALPORT_DETACHED = "HR_USB_SERIALPORT_DETACHED";
    private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";

    private UsbSerialPort mUsbPort;
    private UsbSerialDriver mUsbDriver;
    private UsbDeviceConnection musbDeviceConnection;
    private SerialInputOutputManager mSerialIoManager;
    public final ExecutorService mExecutor = Executors.newSingleThreadExecutor();


    @Override
    public void onCreate() {
        super.onCreate();
        IntentFilter filter = new IntentFilter();
        filter.addAction(USB_SERIALPORT_ATTCHED);
        filter.addAction(USB_SERIALPORT_DETACHED);
        registerReceiver(Br_UsbActionProc, filter);

        IntentFilter permissionintent = new IntentFilter();
        permissionintent.addAction(ACTION_USB_PERMISSION);
        registerReceiver(Br_UsbPermissionProc, permissionintent);

        CheckUsbDevice();

    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private final BroadcastReceiver Br_UsbPermissionProc = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action == null) {
                return;
            }
            switch (action) {
                case ACTION_USB_PERMISSION: {
                    UsbManager usbManager = (UsbManager) getBaseContext().getSystemService(Context.USB_SERVICE);
                    PendingIntent mPendingIntent = PendingIntent.getBroadcast(getBaseContext(), 0, new Intent(ACTION_USB_PERMISSION), 0);
                    for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
                        if (usbManager.hasPermission(usbDevice)) {
                            InitSerialPort(usbManager, usbDevice);
                        }
                    }
                }
            }
        }
    };

    /**
     * 初始化串口操作
     * @param usbManager
     * @param usbDevice
     */
    private void InitSerialPort(UsbManager usbManager, UsbDevice usbDevice) {

        Log.d(TAG, "Checkpermission: VID =" + usbDevice.getVendorId() + "  PID =" + usbDevice.getProductId());
        mUsbDriver = UsbSerialProber.getDefaultProber().probeDevice(usbDevice);
        mUsbPort = mUsbDriver.getPorts().get(0);
        musbDeviceConnection = usbManager.openDevice(usbDevice);
        try {

            mUsbPort.open(musbDeviceConnection);
            mUsbPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
            mSerialIoManager = new SerialInputOutputManager(mUsbPort, mSerialPortEventListener);
            mExecutor.execute(mSerialIoManager);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private final BroadcastReceiver Br_UsbActionProc = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent == null) {
                return;
            }
            switch (intent.getAction()) {
                case USB_SERIALPORT_ATTCHED:
                    Log.d(TAG, "onReceive: USB 插入处理");
                    CheckUsbDevice();
                    break;
                case USB_SERIALPORT_DETACHED:
                    Log.d(TAG, "onReceive: USB 拔出处理");
                    if(mUsbPort!=null)
                    {
                        try {
                            mUsbPort.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                    if (musbDeviceConnection!=null)
                    {
                        musbDeviceConnection.close();
                    }
                    mSerialIoManager.stop();
                    break;
            }
        }
    };

    private void CheckUsbDevice() {
        UsbManager usbManager = (UsbManager) getBaseContext().getSystemService(Context.USB_SERVICE);
        PendingIntent mPendingIntent = PendingIntent.getBroadcast(getBaseContext(), 0, new Intent(ACTION_USB_PERMISSION), 0);
        for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
            Log.d(TAG, "CheckUsbDevice: VID =" + usbDevice.getVendorId() + "  PID =" + usbDevice.getProductId());
            mUsbDriver = UsbSerialProber.getDefaultProber().probeDevice(usbDevice);
            if (mUsbDriver==null)
            {
                Log.d(TAG, "CheckUsbDevice:非法设备");
                return;
            }
            if (usbManager.hasPermission(usbDevice)) {
                InitSerialPort(usbManager,usbDevice); //具有权限 直接启动
            } else {
                /**先申请权限**/
                usbManager.requestPermission(usbDevice, mPendingIntent);
            }
        }

    }

    public static class Br_UsbAction extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent == null) {
                return;
            }
            switch (intent.getAction()) {
                case UsbManager.ACTION_USB_DEVICE_ATTACHED: {
                    Log.d(TAG, "onReceive: USB 插入");
                    Intent bintent = new Intent();
                    bintent.setAction(ConnectService.USB_SERIALPORT_ATTCHED);
                    context.sendBroadcast(bintent);
                }
                break;
                case UsbManager.ACTION_USB_DEVICE_DETACHED: {
                    Log.d(TAG, "onReceive: USB 拔出");
                    Intent bintent = new Intent();
                    bintent.setAction(ConnectService.USB_SERIALPORT_DETACHED);
                    context.sendBroadcast(bintent);
                }
                break;
            }
        }
    }

    private final SerialInputOutputManager.Listener mSerialPortEventListener =
            new SerialInputOutputManager.Listener() {
                @Override
                public void onNewData(byte[] data) {
                    String str = new String(data);
                    Log.d(TAG, "onNewData: " + str);
                    mSerialIoManager.writeAsync(data);
                }

                @Override
                public void onRunError(Exception e) {

                }
            };
}

Add in AndoridManifest.xml

   <receiver
            android:name=".ConnectUtils.Manger.ConnectService$Br_UsbAction"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
                <action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
            </intent-filter>
        </receiver>
        <service android:name="com.apandserial.ConnectUtils.Manger.ConnectService" />

Start ConnectService through Activity! ! ! ! !

Debug results:

 Automatically identify and open the serial port after insertion

Print the received information and send it back (the easiest way to debug the serial port):

 private final SerialInputOutputManager.Listener mSerialPortEventListener =
            new SerialInputOutputManager.Listener() {
                @Override
                public void onNewData(byte[] data) {
                    String str = new String(data);
                    Log.d(TAG, "onNewData: " + str);
                    mSerialIoManager.writeAsync(data);
                }

                @Override
                public void onRunError(Exception e) {

                }
            };

PC serial port assistant debugging results

 Unplug event:

When unplugging, you need to judge the status of the device and close the serial port:

case USB_SERIALPORT_DETACHED:
                    Log.d(TAG, "onReceive: USB 拔出处理");
                    if(mUsbPort!=null)
                    {
                        try {
                            mUsbPort.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                    if (musbDeviceConnection!=null)
                    {
                        musbDeviceConnection.close();
                    }
                    mSerialIoManager.stop();
                    break;
            }

Guess you like

Origin blog.csdn.net/MSONG93/article/details/130730467