Files
2020-08-27 12:24:21 +08:00

368 lines
13 KiB
Java

package com.proxgrind.devices;
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.util.Log;
import com.felhr.usbserial.UsbSerialDevice;
import com.felhr.usbserial.UsbSerialInterface;
import com.proxgrind.chameleon.R;
import com.proxgrind.chameleon.callback.ConnectCallback;
import com.proxgrind.chameleon.utils.system.LogUtils;
import com.proxgrind.chameleon.utils.system.SystemUtils;
import com.proxgrind.chameleon.utils.tools.Commons;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/*
* Usb 2 uart Serial implements
*/
public class UsbSerialControl implements DriverInterface<String, UsbManager> {
//日志标签
private static final String LOG_TAG = UsbSerialControl.class.getSimpleName();
private final int UNIQUE_ID = 0x04;
//广播名称
private final String USB_PERMISSION_ACTION = "cn.rrg.nfctools.UsbSerialPer";
//设备名称!
private final String usbName = context.getString(R.string.usb_name);
//串口对象
private UsbSerialDevice mPort = null;
//单例模式
private static UsbSerialControl mThiz = null;
//回调接口
private DevCallback<String> mCallback = null;
//广播接收,由于是单例,因此实际上广播接收也可以设置为单例!
private BroadcastReceiver usbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//取到广播的意图
String action = intent.getAction();
//对比意图,根据意图做出回调选择
if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action) ||
UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action) ||
"cn.rrg.devices.usb_attach_uart".equals(action)) {
Log.d(LOG_TAG, "收到UsbSerial设备寻找的广播!");
if (mCallback != null) {
if (initUsbSerial(context)) {
//初始化成功则回调串口设备加入方法
mCallback.onAttach(usbName);
} else {
//不成则打印到LOG
Log.e(LOG_TAG, "no usb permission!");
}
}
}
//在申请权限的时候如果成功那么应当进行设备的初始化
if (USB_PERMISSION_ACTION.equals(action)) {
//get permission success
if (initUsbSerial(context)) {
//初始化成功则回调串口设备加入方法
mCallback.onAttach(usbName);
} else {
//不成则打印到LOG
Log.e(LOG_TAG, "no usb permission!");
}
}
//在设备移除时应当释放USB设备
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
//判断并且释放USB串口
if (mThiz != null) {
try {
mThiz.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//回调设备移除接口
if (mPort != null)
if (mCallback != null) {
try {
mCallback.onDetach(usbName);
} catch (Exception e) {
e.printStackTrace();
}
}
isConnected = false;
LogUtils.d("设备移除了。");
}
}
};
;
//注册状态
private static volatile boolean isRegister = false;
//轮询队列
private static final Queue<Byte> recvBufQueue = new ConcurrentLinkedQueue<>();
// 数据回调!
private static final UsbSerialInterface.UsbReadCallback readCallback = new UsbSerialInterface.UsbReadCallback() {
@Override
public void onReceivedData(byte[] bytes) {
//进行加锁,提高数据吞吐稳定性
for (byte b : bytes) {
recvBufQueue.add(b);
}
//LogUtils.d("USB自动接收到的数据: " + new String(bytes));
}
};
private volatile boolean isConnected = false;
/*私有化构造方法,懒汉单例模式*/
private UsbSerialControl() {
//you can't invoke this constructor
//beacause this class is single-instance!
}
public static UsbSerialControl get() {
synchronized (LOG_TAG) {
if (mThiz != null) {
return mThiz;
} else {
mThiz = new UsbSerialControl();
}
return mThiz;
}
}
//串口备初始化函数
private boolean initUsbSerial(Context context) {
//得到Usb管理器
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
if (usbManager == null) return false;
//尝试取出所有可用的列表
if (usbManager.getDeviceList() == null || usbManager.getDeviceList().size() <= 0) {
Log.d(LOG_TAG, "initUsbSerial() 未发现设备!");
return false;
}
//迭代集合里面的设备对象
List<UsbDevice> devList = new ArrayList<>(usbManager.getDeviceList().values());
//取出第一个USB对象
UsbDevice usbDevice = devList.get(0);
//判断设备是否支持
if (!UsbSerialDevice.isSupported(usbDevice)) {
Log.d(LOG_TAG, "UsbSerial支持检测结果: false");
return false;
}
//如果对于这个设备没有权限!
if (!usbManager.hasPermission(usbDevice)) {
//发送广播申请权限
PendingIntent intent =
PendingIntent.getBroadcast(context,
0, new Intent(USB_PERMISSION_ACTION), 0);
//Log.d(LOG_TAG, "尝试获得USB权限!");
usbManager.requestPermission(usbDevice, intent);
//当没有权限的时候应当直接返回
return false;
}
//一切正常返回true!
return connect();
}
@Override
public int write(byte[] buffer, int offset, int length, int timeout) throws IOException {
//TODO 注释防止外泄
if (mPort == null) {
//Log.e(LOG_TAG, "port is null");
return -1;
}
//构建一个可用字节的缓冲区
byte[] tmpBuf = new byte[length - offset];
//将可用字节灌装到定义的缓冲区
System.arraycopy(buffer, offset, tmpBuf, 0, tmpBuf.length);
//在同步块中进行提交操作!
mPort.write(tmpBuf);
//Log.d(LOG_TAG, "send: " + new String(buffer) + ", len" + buffer.length);
//Log.d(LOG_TAG, "发送的字节: " + HexUtil.toHexString(tmpBuf, 0, length - offset));
return length - offset;
}
@Override
public int read(byte[] buffer, int offset, int length, int timeout) throws IOException {
if (mPort == null) {
//Log.e(LOG_TAG, "port is null");
return -1;
}
long startTime = System.currentTimeMillis();
//Log.d(LOG_TAG, "数据缓冲区内长度正常,开始拷贝...");
while (recvBufQueue.size() < length) {
if (SystemUtils.isTimeout(startTime, timeout)) {
return -1;
}
}
int len = 0;
//从轮询缓冲队列中取出对应长度的数据
for (int i = offset; i < length; ++i) {
//判断轮询缓冲区的元素是否可用
if (recvBufQueue.peek() != null) {
Byte b = recvBufQueue.poll();
if (b != null) {
buffer[i] = b;
++len;
}
}
}
//Log.d(LOG_TAG, "接收到的数据: " + HexUtil.toHexString(buffer, offset, length));
//TODO 返回的是当前读取到的缓冲区的数据的长度(实际长度)!
return len;
}
@Override
public void flush() throws IOException {
//don't support flush
}
@Override
public void close() throws IOException {
isConnected = false;
if (mPort == null) {
Log.e(LOG_TAG, "port is null");
return;
}
mPort.close();
}
@Override
public void register(DevCallback<String> callback) {
mCallback = callback;
if (isRegister) {
LogUtils.d("USB驱动可能已经注册过了。");
return;
}
IntentFilter filter = new IntentFilter(USB_PERMISSION_ACTION);
filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction("cn.rrg.devices.usb_attach_uart");
try {
context.registerReceiver(usbReceiver, filter);
LogUtils.d("USB注册完成!");
} catch (Exception e) {
e.printStackTrace();
}
isRegister = true;
}
@Override
public void connect(String t, ConnectCallback callback) {
if (connect()) {
isConnected = true;
callback.onConnectSucces();
} else {
isConnected = false;
callback.onConnectFail();
}
}
@Override
public boolean isDeviceConnected() {
return mPort != null && isConnected;
}
public boolean connect() {
if (mPort != null) {
mPort.close();
mPort = null;
}
isConnected = false;
//得到Usb管理器
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
if (usbManager == null) {
return false;
}
//迭代集合里面的设备对象
List<UsbDevice> devList = new ArrayList<>(usbManager.getDeviceList().values());
if (devList.size() <= 0) {
return false;
}
//取出第一个USB对象
UsbDevice usbDevice = devList.get(0);
//USB链接!
UsbDeviceConnection connection = usbManager.openDevice(usbDevice);
//判断是否非空,为空证明没有权限
if (connection == null) {
//发送广播申请权限
PendingIntent intent = PendingIntent.getBroadcast(context, 0, new Intent(USB_PERMISSION_ACTION), 0);
//Log.d(LOG_TAG, "尝试获得USB权限!");
usbManager.requestPermission(usbDevice, intent);
//当没有权限的时候应当直接返回
return false;
}
Log.d(LOG_TAG, "开始尝试打开设备!");
//得到串口端口对象
mPort = UsbSerialDevice.createUsbSerialDevice(usbDevice, connection);
//尝试打开串口
if (mPort.open()) {
//设置波特率
mPort.setBaudRate(115200);
//设置数据位
mPort.setDataBits(UsbSerialDevice.DATA_BITS_8);
//设置停止位
mPort.setStopBits(UsbSerialDevice.STOP_BITS_1);
//奇偶校验值
mPort.setParity(UsbSerialDevice.PARITY_NONE);
//数据流控制
mPort.setFlowControl(UsbSerialDevice.FLOW_CONTROL_OFF);
//新数据回调
mPort.read(readCallback);
Log.d(LOG_TAG, "Usb链接成功,通信创建成功!!");
return true;
}
return false;
}
public boolean connectAndSetConnected() {
return isConnected = connect();
}
@Override
public UsbManager getAdapter() {
return (UsbManager) context.getSystemService(Context.USB_SERVICE);
}
@Override
public String getDevice() {
return mPort != null ? mPort.getClass().getSimpleName() : null;
}
@Override
public void disconnect() {
//TODO 暂时不做处理
try {
close();
} catch (IOException e) {
e.printStackTrace();
}
isConnected = false;
}
@Override
public int getUniqueId() {
return UNIQUE_ID;
}
@Override
public void unregister() {
//广播解注册
if (isRegister) {
try {
context.unregisterReceiver(usbReceiver);
isRegister = false;
LogUtils.d("解注册USB完成!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}