Android之USB转串口通信-基本流程
背景:近期公司一个项目对接第三方支付设备(类似平板的设备外接usb转串口设备),需要使用usb转串口,实现通信和交互,今天记下过程。有引用这个库 https://github.com/mik3y/usb-serial-for-android,感谢开源的大佬。这个库已经集合了一般的芯片协议,就不需要自己再配置了。我们设备是用的ProlificSerialDriver.唯一要注意的是配置设备的参数:波特率,数据位,体制位,奇偶校验等。其中我就在奇偶校验的参数配置上坑了一把。
只需要按照流程,注意些细节就能跑。贴下核心的几段代码:
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import com.hoho.android.usbserial.driver.UsbSerialPort
import com.hoho.android.usbserial.driver.UsbSerialProber
class ZYDataSource(){
var mUsbSeriaPortManager: USBSerialPortManager? = null
private var usbDeviceConnection: UsbDeviceConnection? = null
private var mDevice: UsbDevice? = null
private var mUsbSerialPort: UsbSerialPort? = null
private var usbPermissionReceiver: UsbPermissionReceiver? = null
private var mUsbManager: UsbManager? = null
/**
* 初始化
*/
override fun initCompletable(context: Context): Completable {
return Completable.create() {
mUsbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
//查找所有设备
val driversList = UsbSerialProber.getDefaultProber().findAllDrivers(mUsbManager)
if (driversList == null || driversList.size == 0) {
throw Exception("未找到设备")
}
//直接取第一个.
mDevice = driversList.first().device
if (!mUsbManager?.hasPermission(mDevice)!!) {
usbPermissionReceiver = UsbPermissionReceiver()
//申请权限
val intent = Intent(ACTION_DEVICE_PERMISSION)
val mPermissionIntent = PendingIntent.getBroadcast(context, 0, intent, 0)
val permissionFilter = IntentFilter(ACTION_DEVICE_PERMISSION)
context.registerReceiver(usbPermissionReceiver, permissionFilter)
mUsbManager?.requestPermission(mDevice, mPermissionIntent)
} else {
this.openDeviceConnection(device = mDevice!!)
}
it.onComplete()
}
}
inner class UsbPermissionReceiver : BroadcastReceiver() {
override fun onReceive(p0: Context?, intent: Intent?) {
val action = intent?.getAction()
if (ACTION_DEVICE_PERMISSION.equals(action)) {
synchronized(this) {
val device = intent.getParcelableExtra<UsbDevice>(UsbManager.EXTRA_DEVICE)
openDeviceConnection(device)
}
}
}
}
/**
* 打开连接
*/
fun openDeviceConnection(device: UsbDevice) {
synchronized(this) {
//授权成功,在这里进行打开设备操作
val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(mUsbManager)
if (availableDrivers.isEmpty()) {
return
}
// Open a connection to the first available driver.
val driver = availableDrivers[0]
// Read some data! Most have just one port (port 0).
mUsbSerialPort = driver.ports[0]
try {
mUsbSeriaPortManager = USBSerialPortManager(mUsbSerialPort!!)
usbDeviceConnection = mUsbManager?.openDevice(device)
mUsbSerialPort?.open(usbDeviceConnection)
mUsbSerialPort?.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_EVEN)
} catch (e: Exception) {
XLog.tag(TAG).e(e.message)
throw Exception("设备初始化失败")
}
}
}
/**
* 实际通信调用方法-找卡
*/
override fun searchCardSingle(requestData: ByteArray): Single<ByteArray> {
return Single.just(requestData)
.flatMap { data ->
val command = USBSerialPortManager.Command(data, data.size)
//通信
mUsbSeriaPortManager!!.execute(command)
}
.flatMap {
Single.just(it.rxBytes)
}
}
}
下面这个是USBSerialPortManager工具类
import com.hoho.android.usbserial.driver.UsbSerialPort
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
class USBSerialPortManager(private val usbSerialPort: UsbSerialPort,
private val writeTimeout: Int = 100,
private val readTimeout: Int = 50) {
open class Command(val hex: String, var rxLength: Int = 0, var rx: String = "") {
val bytes: ByteArray
get() = hex.hexStringToByteArray()
val rxBytes: ByteArray
get() = rx.hexStringToByteArray()
constructor(bytes: ByteArray, rxLength: Int) : this(bytes.toHex(), rxLength, "")
}
private fun runOnceSingle(command: Command, timeoutInMillis: Int = 2000): Single<Command> {
return Single.create {
XLog.tag(TAG).i("send data=${command.hex} to $usbSerialPort")
val txBytes = command.hex.hexStringToByteArray()
usbSerialPort.write(txBytes, writeTimeout)
if (command.rxLength <= 0) {
command.rx = ""
it.onSuccess(command)
return@create
}
var times = 0L
val interval = 2L
val bytes = ByteArray(command.rxLength)
var totalLength = 0
while (totalLength < command.rxLength) {
val bytesToRead = ByteArray(command.rxLength - totalLength)
val n = usbSerialPort.read(bytesToRead, readTimeout)
if (n > 0) {
for (i in 0 until n) {
bytes[totalLength + i] = bytesToRead[i]
}
totalLength += n
}
Thread.sleep(interval)
times += interval
if (times > timeoutInMillis) {
XLog.tag(TAG).e("read data from $usbSerialPort timeout, expect ${command.rxLength} bytes")
it.onError(Exception("read data from $usbSerialPort timeout, expect ${command.rxLength} bytes"))
return@create
}
}
command.rx = bytes.toHex()
XLog.tag(TAG).i("recv data=${command.rx} from $usbSerialPort")
it.onSuccess(command)
}
}
fun execute(command: Command, retryTimes: Long = 0L): Single<Command> {
return runOnceSingle(command).retry(retryTimes).subscribeOn(Schedulers.single())
}
companion object {
const val TAG = "USBSerialPortManager"
}
}
代码是kotlin语言,没有写注释,目前项目已上线。工具类基本可以通用。
本文由 创作,采用 知识共享署名4.0 国际许可协议进行许可。本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为: 2020/09/15 10:15