Skip to content

Commit

Permalink
修改串口数据接收逻辑,胜任高波特率,大数据量的连续发送的工作
Browse files Browse the repository at this point in the history
  • Loading branch information
swallowsonny committed Apr 29, 2020
1 parent 4e94ee4 commit cdda7c6
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 107 deletions.
32 changes: 17 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
## SerialHelper

> 一个基于[usb-serial-for-android](https://github.com/mik3y/usb-serial-for-android "usb-serial-for-android")封装的Android串口通讯框架, 搭配[ConvertExt](https://github.com/swallowsonny/ConvertExt)实现ByteArray与基本数据类型的快速高效解析转换
> 一个基于[usb-serial-for-android](https://github.com/mik3y/usb-serial-for-android "usb-serial-for-android")封装的Android串口通讯框架, 搭配[ConvertExt](https://github.com/swallowsonny/ConvertExt)实现ByteArray与基本数据类型的快速高效解析转换。该库配置简单,已用于某工业产品,波特率115200下稳定运行。
[![Download](https://api.bintray.com/packages/swallowsonny/ext/serialhelper/images/download.svg?version=1.0.4) ](https://bintray.com/swallowsonny/ext/serialhelper/1.0.3/link)
[![Download](https://api.bintray.com/packages/swallowsonny/ext/serialhelper/images/download.svg?version=2.0.0) ](https://bintray.com/swallowsonny/ext/serialhelper/1.0.3/link)
### 功能简介
- 框架处理权限请求问题
- 波特率设置
Expand All @@ -13,7 +13,7 @@
- 超时时长设置
- 串口连接状态监听
- 串口数据发送及数据监听
- 数据拼接,允许的最大的间隔
- 数据双缓冲,解决高波特率,大数据量下的混乱问题

### 快速开始
#### 基本配置
Expand All @@ -27,7 +27,7 @@ maven {

- 在app的build.gradle中添加
```
implementation 'com.swallowsonny:serialhelper:1.0.4'
implementation 'com.swallowsonny:serialhelper:2.0.0'
```

- 在res/xml目录中添加[device_filter.xml](https://github.com/swallowsonny/SerialHelper/blob/master/app/src/main/res/xml/device_filter.xml)
Expand All @@ -48,18 +48,19 @@ implementation 'com.swallowsonny:serialhelper:1.0.4'
#### 快速使用
- 在onCreate() 方法中初始化SerialHelper
```kotlin
serialHelper = object : SerialHelper(){
override fun isFullFrame(data: ArrayList<Byte>): Boolean {
// 判断是否是完整帧
return true
// 串口配置
val serialConfig = SerialConfig()
serialConfig.isAutoConnect = true // 默认连接第一个
serialConfig.baudRate = 9600 // 串口波特率
serialHelper =object : SerialHelper(serialConfig){
override fun isFullFrame(data: ByteArray): IntArray {
// 子线程 根据自己的完整帧判断方式 返回数据的起始索引和结束索引
// 示例中有ByteUtils工具类,查找帧头帧尾的索引号
// ByteUtils.getIndexRange(data, startBytes, endBytes)
return intArrayOf(0, data.size)
}
}
// 配置串口参数
val serialConfig = SerialConfig()
serialConfig.baudRate = 9600
serialConfig.isAutoConnect = true // 自动连接第一个设备
// 初始化
serialHelper.initConfig(serialConfig).onCreate(this)
serialHelper.onCreate(this)
```

- 在onDestory()中销毁SerialHelper
Expand Down Expand Up @@ -111,8 +112,9 @@ serialHelper.addOnUsbDataListener(object : OnUsbDataListener {
}

override fun onDataReceived(bytes: ByteArray) {
// 处理返回的数据, 当前线程为子线程
runOnUiThread {
// 处理返回的数据, 当前线程为子线程

}
}
})
Expand Down
4 changes: 4 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
Expand Down
49 changes: 49 additions & 0 deletions app/src/main/java/com/sjx/serialhelper/ByteUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.sjx.serialhelper

object ByteUtils {
/**
* ByteArray中查找数组索引
*/
fun getIndexRange(byteArray: ByteArray, startByteArray: ByteArray, endByteArray: ByteArray): IntArray{
// 查找头
var resultStartIndex = -1
var resultEndIndex = -1
var startI = 0
while (startI < byteArray.size - startByteArray.size){
// 查找
var findStart = true
for(i in startByteArray.indices){
findStart = true
if (byteArray[startI + i] != startByteArray[i]){
findStart = false
break
}
}
if(findStart){
resultStartIndex = startI
break
}
startI ++
}

var endI = startI + startByteArray.size
while (endI < byteArray.size - endByteArray.size){
// 查找
var findEnd = true
for(i in endByteArray.indices){
findEnd = true
if (byteArray[endI + i] != endByteArray[i]){
findEnd = false
break
}
}
if(findEnd){
resultEndIndex = endI + endByteArray.size
break
}
endI ++
}

return intArrayOf(resultStartIndex, resultEndIndex)
}
}
56 changes: 6 additions & 50 deletions app/src/main/java/com/sjx/serialhelper/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@ class MainActivity : AppCompatActivity() {
true
}

// 串口配置
val serialConfig = SerialConfig()
serialConfig.isAutoConnect = true
serialConfig.isAutoConnect = true // 默认连接第一个
serialConfig.baudRate = 9600 // 串口波特率
serialHelper =object : SerialHelper(serialConfig){
override fun isFullFrame(data: ByteArray): IntArray {
// 子线程 返回数据的起始索引和结束索引
return getIndexRange(data, startBytes, endBytes)
intArrayOf(0, data.size)
return ByteUtils.getIndexRange(data, startBytes, endBytes)
}
}
serialHelper.addOnUsbDataListener(object : OnUsbDataListener {
Expand Down Expand Up @@ -82,9 +85,7 @@ class MainActivity : AppCompatActivity() {

}
})

serialHelper.initConfig(serialConfig)
.onCreate(this)
serialHelper

btn_send.setOnClickListener {
val bst = et_send.text.toString()
Expand All @@ -105,49 +106,4 @@ class MainActivity : AppCompatActivity() {
serialHelper.onDestory()
}

/**
* ByteArray中查找数组索引
*/
fun getIndexRange(byteArray: ByteArray, startByteArray: ByteArray, endByteArray: ByteArray): IntArray{
// 查找头
var resultStartIndex = -1
var resultEndIndex = -1
var startI = 0
while (startI < byteArray.size - startByteArray.size){
// 查找
var findStart = true
for(i in startByteArray.indices){
findStart = true
if (byteArray[startI + i] != startByteArray[i]){
findStart = false
break
}
}
if(findStart){
resultStartIndex = startI
break
}
startI ++
}

var endI = startI + startByteArray.size
while (endI < byteArray.size - endByteArray.size){
// 查找
var findEnd = true
for(i in endByteArray.indices){
findEnd = true
if (byteArray[endI + i] != endByteArray[i]){
findEnd = false
break
}
}
if(findEnd){
resultEndIndex = endI + endByteArray.size
break
}
endI ++
}

return intArrayOf(resultStartIndex, resultEndIndex)
}
}
10 changes: 4 additions & 6 deletions serialhelperlibrary/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29


defaultConfig {
minSdkVersion 19
targetSdkVersion 29
versionCode 5
versionName "1.0.4"

versionCode 6
versionName "2.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
Expand All @@ -37,7 +35,7 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

implementation 'com.github.mik3y:usb-serial-for-android:2.1.0'
implementation 'com.github.mik3y:usb-serial-for-android:2.2.2'
}

//从这里开始配置
Expand All @@ -47,7 +45,7 @@ publish {
userOrg = 'swallowsonny' //bintray注册的用户名
groupId = 'com.swallowsonny' //compile引用时的第1部分groupId
artifactId = 'serialhelper' //compile引用时的第2部分项目名
publishVersion = '1.0.4' //compile引用时的第3部分版本号
publishVersion = '2.0.0' //compile引用时的第3部分版本号
desc = '一个简单易用的Android串口通讯框架'//项目描述
website = 'https://github.com/swallowsonny/SerialHelper' //github 托管地址
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.sjx.serialhelperlibrary

interface CheckFullFrame {
/**
* @param data 需要校验的数据
* @return 返回根据自己规则对应的起始索引与终止索引号, intArrayOf(0, data.size)
*/
fun isFullFrame(data: ByteArray): IntArray
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.sjx.serialhelperlibrary

interface OnUsbDataListener {
/**
* @param bytes 接收串口返回的数据,在子线程中
*/
fun onDataReceived(bytes: ByteArray)
fun onDataError(e: Exception?)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ public class SerialConfig {
private int dataBits = 8;
private int stopBits = UsbSerialPort.STOPBITS_1;
private int parity = UsbSerialPort.PARITY_NONE;
private int dataMaxSize = 30000;
private int doubleBufferSize = 30; // 30个大小
private Long readInterval = 10L; // 10ms

private long intervalFrame = 50L;
private int dataMaxSize = 30000; // 未满足要求的最大字节数,超过就清空
private int doubleBufferSize = 30; // 30个大小, 双缓冲的容器大小
private Long readInterval = 10L; // 读取休眠间隔,单位ms,这个值不能太大,读取速度要大于写入速度

private int timeout = 2000;

Expand Down Expand Up @@ -92,15 +90,6 @@ public SerialConfig setTimeout(int timeout) {
return this;
}

public long getIntervalFrame() {
return intervalFrame;
}

public SerialConfig setIntervalFrame(long intervalFrame) {
this.intervalFrame = intervalFrame;
return this;
}

public int getDataMaxSize() {
return dataMaxSize;
}
Expand All @@ -124,4 +113,4 @@ public Long getReadInterval() {
public void setReadInterval(Long readInterval) {
this.readInterval = readInterval;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import java.lang.IllegalArgumentException
import java.util.concurrent.Executors

abstract class SerialHelper(serialConfig: SerialConfig) : CheckFullFrame {
// private val WRITE_WAIT_MILLIS = 2000 // 0 blocked infinitely on unprogrammed arduino
private val ACTION_USB_PERMISSION = "com.sjx.serialhelperlibrary.USB_PERMISSION"
private val onUsbStatusChangeListeners = ArrayList<OnUsbStatusChangeListener>()
private val onUsbDataListeners = ArrayList<OnUsbDataListener>()
Expand Down Expand Up @@ -51,20 +50,26 @@ abstract class SerialHelper(serialConfig: SerialConfig) : CheckFullFrame {
var byteArray = byteArrayOf()
while (true) {
if (readPosition < writePosition) {
// 写入
mDoubleBuffer[(readPosition++ % mDoubleBufferSize).toInt()]?.copyInto(
byteArray,
byteArray.size
)
// // 写入
val indexBuffer =
mDoubleBuffer[(readPosition++ % mDoubleBufferSize).toInt()] ?: continue
val bytes = ByteArray(byteArray.size + indexBuffer.size)

// 组合数据
byteArray.copyInto(bytes)
indexBuffer.copyInto(bytes, byteArray.size)
byteArray = bytes
// 判断数据完整性, 返回结束和开始索引号
val result = isFullFrame(byteArray)
if (result.size == 2) {
if (result[0] == -1) {
// 头没找到,全部数据没用,不严谨,如果头分开了也删除了,几率很小
byteArray = byteArrayOf()
} else if(result[1] != -1) { // 找到头,也找到尾
} else if (result[1] != -1) { // 找到头,也找到尾
onUsbDataListeners.forEach {
it.onDataReceived(byteArray.copyOfRange(result[0], result[1]))
val temp = byteArray.copyOfRange(result[0], result[1])
// println("收到数据" + Utils.toHexString(temp))
it.onDataReceived(temp)
}
// 清空byteArray,清除
byteArray = byteArray.copyOfRange(result[1], byteArray.size)
Expand All @@ -80,7 +85,7 @@ abstract class SerialHelper(serialConfig: SerialConfig) : CheckFullFrame {
if (result[0] == -1) {
// 头没找到,全部数据没用,不严谨,如果头分开了也删除了,几率很小
byteArray = byteArrayOf()
} else if(result[1] != -1) { // 找到头,也找到尾
} else if (result[1] != -1) { // 找到头,也找到尾
onUsbDataListeners.forEach {
it.onDataReceived(byteArray.copyOfRange(result[0], result[1]))
}
Expand All @@ -98,7 +103,6 @@ abstract class SerialHelper(serialConfig: SerialConfig) : CheckFullFrame {
mThread.start()
}


private val mUsbPermissionActionReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
Expand Down Expand Up @@ -130,11 +134,6 @@ abstract class SerialHelper(serialConfig: SerialConfig) : CheckFullFrame {
}
}

fun initConfig(serialConfig: SerialConfig): SerialHelper {
this.serialConfig = serialConfig
return this
}

private fun requestPermission() {
val mPermissionIntent =
PendingIntent.getBroadcast(mContext, 0, Intent(ACTION_USB_PERMISSION), 0)
Expand Down Expand Up @@ -203,18 +202,14 @@ abstract class SerialHelper(serialConfig: SerialConfig) : CheckFullFrame {
}
}

// private var lastReceiveTime: Long = 0
// private val dataArray = ArrayList<Byte>()
private val serialManagerListener = object : SerialInputOutputManager.Listener {
override fun onRunError(e: Exception?) {
onUsbDataListeners.forEach { it.onDataError(e) }
}

override fun onNewData(data: ByteArray?) {
synchronized(this) {
if (data == null) return
mDoubleBuffer[(writePosition++ % mDoubleBufferSize).toInt()] = data
}
if (data == null) return
mDoubleBuffer[(writePosition++ % mDoubleBufferSize).toInt()] = data
}
}

Expand Down

0 comments on commit cdda7c6

Please sign in to comment.