FT8CN/ft8CN/app/src/main/java/com/bg7yoz/ft8cn/connector/CableSerialPort.java

375 wiersze
12 KiB
Java
Executable File
Czysty Wina Historia

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.bg7yoz.ft8cn.connector;
/**
* 用于USB串口操作的类。USB串口驱动在serialport目录中主要是CDC、CH34x、CP21xx、FTDI等。
*
* @author BGY70Z
* @date 2023-03-20
*/
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.PendingIntent;
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.Build;
import android.util.Log;
import com.bg7yoz.ft8cn.BuildConfig;
import com.bg7yoz.ft8cn.serialport.CdcAcmSerialDriver;
import com.bg7yoz.ft8cn.serialport.UsbSerialDriver;
import com.bg7yoz.ft8cn.serialport.UsbSerialPort;
import com.bg7yoz.ft8cn.serialport.UsbSerialProber;
import com.bg7yoz.ft8cn.serialport.util.SerialInputOutputManager;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
public class CableSerialPort {
private static final String TAG = "CableSerialPort";
private OnConnectorStateChanged onStateChanged;
public static final int SEND_TIMEOUT = 2000;
private static final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID;
public enum UsbPermission {Unknown, Requested, Granted, Denied}
private UsbPermission usbPermission = UsbPermission.Unknown;
private BroadcastReceiver broadcastReceiver;
private final Context context;
private int vendorId = 0x0c26;//设备号
private int portNum = 0;//端口号
private int baudRate = 19200;//波特率
private UsbSerialPort usbSerialPort;
private SerialInputOutputManager usbIoManager;
public SerialInputOutputManager.Listener ioListener = null;
private UsbManager usbManager;
private UsbDeviceConnection usbConnection;
private UsbSerialDriver driver;
private boolean connected = false;//是否处于连接状态
public CableSerialPort(Context mContext, SerialPort serialPort, int baud, OnConnectorStateChanged connectorStateChanged) {
vendorId = serialPort.vendorId;
portNum = serialPort.portNum;
baudRate = baud;
context = mContext;
this.onStateChanged=connectorStateChanged;
doBroadcast();
}
public CableSerialPort(Context mContext) {
context = mContext;
doBroadcast();
}
private void doBroadcast() {
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (INTENT_ACTION_GRANT_USB.equals(intent.getAction())) {
usbPermission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
? UsbPermission.Granted : UsbPermission.Denied;
connect();
}
}
};
}
private boolean prepare() {
registerRigSerialPort(context);
UsbDevice device = null;
usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
//此处把connection设成Null,这样在后面来通过是否null判断是否有权限。
usbConnection = null;
//此处是不是做个权限判断?
if (usbManager == null) {
return false;
}
for (UsbDevice v : usbManager.getDeviceList().values()) {
if (v.getVendorId() == vendorId) {
device = v;
}
}
if (device == null) {
Log.e(TAG, String.format("串口设备打开失败: 没有找到设备0x%04x", vendorId));
return false;
}
driver = UsbSerialProber.getDefaultProber().probeDevice(device);
if (driver == null) {
//试着把未知的设备加入到cdc驱动上
driver = new CdcAcmSerialDriver(device);
}
if (driver.getPorts().size() < portNum) {
Log.e(TAG, "串口号不存在,无法打开。");
return false;
}
Log.e(TAG, "connect: port size:" + String.valueOf(driver.getPorts().size()));
usbSerialPort = driver.getPorts().get(portNum);
usbConnection = usbManager.openDevice(driver.getDevice());
return true;
}
//@RequiresApi(api = Build.VERSION_CODES.S)
public boolean connect() {
connected = false;
if (!prepare()) {
//return false;
}
if (driver == null) {
if (onStateChanged!=null){
onStateChanged.onRunError("无法连接串口,没有驱动或串口不存在!");
}
return false;
}
if (usbConnection == null && usbPermission == UsbPermission.Unknown
&& !usbManager.hasPermission(driver.getDevice())) {
usbPermission = UsbPermission.Requested;
PendingIntent usbPermissionIntent;
//在android12 开始增加了PendingIntent.FLAG_MUTABLE保护机制所以要做版本判断
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
usbPermissionIntent = PendingIntent.getBroadcast(context, 0
, new Intent(INTENT_ACTION_GRANT_USB), PendingIntent.FLAG_MUTABLE);
} else {
usbPermissionIntent = PendingIntent.getBroadcast(context, 0
, new Intent(INTENT_ACTION_GRANT_USB), 0);
}
//PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(context, 0
// , new Intent(INTENT_ACTION_GRANT_USB), PendingIntent.FLAG_MUTABLE);
// , new Intent(INTENT_ACTION_GRANT_USB), 0);
usbManager.requestPermission(driver.getDevice(), usbPermissionIntent);
prepare();
}
if (usbConnection == null) {
if (onStateChanged!=null){
onStateChanged.onRunError("无法连接串口可能没有访问USB设备的权限");
}
return false;
}
try {
usbSerialPort.open(usbConnection);
//波特率、停止位
usbSerialPort.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
usbIoManager = new SerialInputOutputManager(usbSerialPort, new SerialInputOutputManager.Listener() {
@Override
public void onNewData(byte[] data) {
if (ioListener != null) {
ioListener.onNewData(data);
}
}
@Override
public void onRunError(Exception e) {
if (ioListener != null) {
ioListener.onRunError(e);
}
disconnect();
}
});
usbIoManager.start();
Log.d(TAG, "串口打开成功!");
connected = true;
if (onStateChanged!=null){
onStateChanged.onConnected();
}
} catch (Exception e) {
Log.e(TAG, "串口打开失败: " + e.getMessage());
if (onStateChanged!=null){
onStateChanged.onRunError("串口打开失败: " + e.getMessage());
}
disconnect();
return false;
}
return true;
}
public boolean sendData(final byte[] src) {
if (usbSerialPort != null) {
try {
usbSerialPort.write(src, SEND_TIMEOUT);
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "发送数据出错:" + e.getMessage());
return false;
}
return true;
} else {
Log.e(TAG, "无法发送数据,串口没有打开。");
return false;
}
}
public void disconnect() {
connected = false;
if (onStateChanged!=null){
onStateChanged.onDisconnected();
}
if (usbIoManager != null) {
usbIoManager.setListener(null);
usbIoManager.stop();
}
usbIoManager = null;
try {
if (usbSerialPort != null) {
usbSerialPort.close();
}
} catch (IOException ignored) {
}
usbSerialPort = null;
}
public void registerRigSerialPort(Context context) {
Log.d(TAG, "registerRigSerialPort: registered!");
context.registerReceiver(broadcastReceiver, new IntentFilter(INTENT_ACTION_GRANT_USB));
}
public void unregisterRigSerialPort(Activity activity) {
Log.d(TAG, "unregisterRigSerialPort: unregistered!");
activity.unregisterReceiver(broadcastReceiver);
}
/**
* 打开和关闭RTS
*
* @param rts_on true打开false关闭
*/
public void setRTS_On(boolean rts_on) {
try {
EnumSet<UsbSerialPort.ControlLine> controlLines = usbSerialPort.getSupportedControlLines();
if (controlLines.contains(UsbSerialPort.ControlLine.RTS)) {
usbSerialPort.setRTS(rts_on);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void setDTR_On(boolean dtr_on) {
try {
EnumSet<UsbSerialPort.ControlLine> controlLines = usbSerialPort.getSupportedControlLines();
if (controlLines.contains(UsbSerialPort.ControlLine.DTR)) {
usbSerialPort.setDTR(dtr_on);
}
} catch (IOException e) {
e.printStackTrace();
Log.d(TAG, "setDTR_On: " + e.getMessage());
}
}
public OnConnectorStateChanged getOnStateChanged() {
return onStateChanged;
}
public void setOnStateChanged(OnConnectorStateChanged onStateChanged) {
this.onStateChanged = onStateChanged;
}
public int getVendorId() {
return vendorId;
}
public void setVendorId(int deviceId) {
this.vendorId = deviceId;
}
public int getPortNum() {
return portNum;
}
public void setPortNum(int portNum) {
this.portNum = portNum;
}
public int getBaudRate() {
return baudRate;
}
public void setBaudRate(int baudRate) {
this.baudRate = baudRate;
}
/**
* 获取本机可用的串口设备串列表
*
* @param context context
* @return 串口设备列表
*/
public static ArrayList<SerialPort> listSerialPorts(Context context) {
ArrayList<SerialPort> serialPorts = new ArrayList<>();
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
for (UsbDevice device : usbManager.getDeviceList().values()) {
UsbSerialDriver driver = UsbSerialProber.getDefaultProber().probeDevice(device);
if (driver == null) {
continue;
//试着把未知的设备加入到cdc驱动上
//driver = new CdcAcmSerialDriver(device);
}
for (int i = 0; i < driver.getPorts().size(); i++) {
serialPorts.add(new SerialPort(device.getDeviceId(), device.getVendorId()
, device.getProductId(), i));
}
}
return serialPorts;
}
public boolean isConnected() {
return connected;
}
public static class SerialPort {
public int deviceId = 0;
public int vendorId = 0x0c26;//厂商号
public int productId = 0;//设备号
public int portNum = 0;//端口号
public SerialPort(int deviceId, int vendorId, int productId, int portNum) {
this.deviceId = deviceId;
this.vendorId = vendorId;
this.productId = productId;
this.portNum = portNum;
}
@SuppressLint("DefaultLocale")
@Override
public String toString() {
return String.format("SerialPort:deviceId=0x%04X, vendorId=0x%04X, portNum=%d"
, deviceId, vendorId, portNum);
}
@SuppressLint("DefaultLocale")
public String information() {
return String.format("\\0x%04X\\0x%04X\\0x%04X\\0x%d", deviceId, vendorId, productId, portNum);
}
}
}