Uart / GPS 驱动程序样本缓冲区溢出

Uart / GPS driver sample buffer overflow

我正在尝试使用 raspberry pi 3 和 Ultimate GPS V3 分线板的 GPS 驱动程序示例。

这里是完整的源代码:https://github.com/androidthings/drivers-samples/tree/master/gps

GPS 板按照以下原理图连接:

启动示例应用程序时,出现以下错误:

com.example.androidthings.driversamples E/AndroidRuntime: FATAL EXCEPTION: main


Process: com.example.androidthings.driversamples, PID: 1299
   java.nio.BufferOverflowException
       at java.nio.Buffer.nextPutIndex(Buffer.java:508)
       at java.nio.HeapByteBuffer.put(HeapByteBuffer.java:142)
       at com.google.android.things.contrib.driver.gps.NmeaGpsModule.processBuffer(NmeaGpsModule.java:178)
       at com.google.android.things.contrib.driver.gps.NmeaGpsModule.readUartBuffer(NmeaGpsModule.java:160)
       at com.google.android.things.contrib.driver.gps.NmeaGpsModule.access[=10=]0(NmeaGpsModule.java:35)
       at com.google.android.things.contrib.driver.gps.NmeaGpsModule.onUartDeviceDataAvailable(NmeaGpsModule.java:139)
       at com.google.android.things.pio.UartDevice$UartDeviceCallbackDispatch.dispatchInterruptEvent(UartDevice.java:507)
       at com.google.android.things.pio.CallbackDispatch.onFileDescriptorEvents(CallbackDispatch.java:127)
       at android.os.MessageQueue.dispatchEvents(MessageQueue.java:282)
       at android.os.MessageQueue.nativePollOnce(Native Method)
       at android.os.MessageQueue.next(MessageQueue.java:323)
       at android.os.Looper.loop(Looper.java:136)
       at android.app.ActivityThread.main(ActivityThread.java:6077)
       at java.lang.reflect.Method.invoke(Native Method)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

更新 1

在 contrib-driver 项目中启用调试后,我看到一个新错误:W/NmeaParser: Invalid checksum (62), expected 108

12-28 17:53:28.638 1378-1378/com.example.androidthings.driversamples D/XXX: Debug version used
12-28 17:53:29.451 1378-1378/com.example.androidthings.driversamples I/Choreographer: Skipped 34 frames!  The application may be doing too much work on its main thread.
12-28 17:53:29.862 1378-1378/com.example.androidthings.driversamples W/NmeaParser: Invalid checksum (62), expected 108
12-28 17:53:29.862 1378-1378/com.example.androidthings.driversamples D/XXX: Buffer reset
12-28 17:53:30.427 1378-1378/com.example.androidthings.driversamples D/AndroidRuntime: Shutting down VM
12-28 17:53:30.428 1378-1378/com.example.androidthings.driversamples E/AndroidRuntime: FATAL EXCEPTION: main
   Process: com.example.androidthings.driversamples, PID: 1378
   java.nio.BufferOverflowException
       at java.nio.Buffer.nextPutIndex(Buffer.java:508)
       at java.nio.HeapByteBuffer.put(HeapByteBuffer.java:142)
       at com.google.android.things.contrib.driver.gps.NmeaGpsModule.processBuffer(NmeaGpsModule.java:179)
       at com.google.android.things.contrib.driver.gps.NmeaGpsModule.readUartBuffer(NmeaGpsModule.java:161)
       at com.google.android.things.contrib.driver.gps.NmeaGpsModule.access[=11=]0(NmeaGpsModule.java:35)
       at com.google.android.things.contrib.driver.gps.NmeaGpsModule.onUartDeviceDataAvailable(NmeaGpsModule.java:140)
       at com.google.android.things.pio.UartDevice$UartDeviceCallbackDispatch.dispatchInterruptEvent(UartDevice.java:507)
       at com.google.android.things.pio.CallbackDispatch.onFileDescriptorEvents(CallbackDispatch.java:127)
       at android.os.MessageQueue.dispatchEvents(MessageQueue.java:282)
       at android.os.MessageQueue.nativePollOnce(Native Method)
       at android.os.MessageQueue.next(MessageQueue.java:323)
       at android.os.Looper.loop(Looper.java:136)
       at android.app.ActivityThread.main(ActivityThread.java:6077)
       at java.lang.reflect.Method.invoke(Native Method)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
12-28 17:53:30.439 1378-1378/com.example.androidthings.driversamples I/Process: Sending signal. PID: 1378 SIG: 9

更新 2

将缓冲区大小增加 4 后,我能够接收到的消息很少。我看到一些消息有一些垃圾可以解释溢出:

12-28 23:38:17.393 2366-2366/? D/XXX: message: ��GPGGA,233817.000,3742.1931,N,12208.3976,W,1,04,1.96,164.3,M,-25.5,M,,*58
12-28 23:38:17.394 2366-2366/? D/XXX: Buffer reset
12-28 23:38:17.394 2366-2366/? D/XXX: message: GPGSA,A,3,23,03,26,22,,,,,,,,,2.20,1.96,1.00*0B
12-28 23:38:17.395 2366-2366/? D/XXX: Buffer reset
12-28 23:38:17.544 2366-2366/com.example.androidthings.driversamples D/XXX: message: GP��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������RMC,233817.000,A��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������,3742.1931,N,12208.3976,W,0.42,205.67,281216,,,A*71
12-28 23:38:17.545 2366-2366/com.example.androidthings.driversamples D/XXX: Buffer reset
12-28 23:38:17.545 2366-2366/com.example.androidthings.driversamples D/XXX: message: GPVTG,205.67,T,,M,0.42,N,0.78,K,A*32
12-28 23:38:17.546 2366-2366/com.example.androidthings.driversamples D/XXX: Buffer reset

我不知道这些垃圾是从哪里来的...

查看演示代码https://github.com/androidthings/drivers-samples/blob/master/gps/src/main/java/com/example/androidthings/driversamples/GpsActivity.java#L35 the Baud rate is set correctly as per the data sheet: https://cdn-learn.adafruit.com/downloads/pdf/adafruit-ultimate-gps.pdf

并查看 NmeaGpsModule 的 contrib 驱动程序,消息缓冲区长度是从驱动程序 https://github.com/androidthings/contrib-drivers/blob/master/gps/src/main/java/com/google/android/things/contrib/driver/gps/NmeaGpsModule.java#L169 读取的缓冲区大小的两倍,因此它不会仅一次读取就溢出。

该问题的理论可能是消息缓冲区在接收数据后未被清除 - 因此您在几个数据包后得到 BufferOverflowException

缓冲区在 2 个地方被重置:

新帧开始时:

https://github.com/androidthings/contrib-drivers/blob/master/gps/src/main/java/com/google/android/things/contrib/driver/gps/NmeaGpsModule.java#L187

或者当一帧结束时:

https://github.com/androidthings/contrib-drivers/blob/master/gps/src/main/java/com/google/android/things/contrib/driver/gps/NmeaGpsModule.java#L209


我没有硬件来调试你的问题,但我可以推荐你如何做:

这适用于任何想要调试 contrib-driver

的人

分叉/复制此 android 库:https://github.com/androidthings/contrib-drivers/tree/master/gps

编辑 build.gradle to add this dependency: https://github.com/novoda/bintray-release(按照自述文件获取说明)。

添加该依赖项后,build.gradle 将如下所示:

apply plugin: 'com.android.library'
apply plugin: 'com.novoda.bintray-release' // new code

android {
    compileSdkVersion 24
    buildToolsVersion '24.0.3'

    defaultConfig {
        minSdkVersion 24
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }
}

buildscript {
    repositories {
        jcenter()
   }
    dependencies {
        classpath 'com.novoda:bintray-release:0.4.0'  // new code
    }
}

dependencies {
    compile 'com.android.support:support-annotations:24.2.0'
    provided 'com.google.android.things:androidthings:0.1-devpreview'
}

publish {  // new code
    userOrg = 'google'
    groupId = 'com.google.android.things.contrib'
    artifactId = 'driver-gps'
    publishVersion = '0.1-DEBUG'
}

现在您可以发布自己的 GPS 驱动程序版本进行调试,但首先:

编辑 java 文件,添加日志记录。在 fork/copy 的 NmeaGpsModule.java 中,进行两项更改:

private void init(UartDevice device, int baudRate, Handler handler) throws IOException {
    Log.d("XXX", "MY VERSION BEING USED"); // new code
    mDevice = device;
    mDevice.setBaudrate(baudRate);
    mDevice.registerUartDeviceCallback(mCallback, handler);

    mParser = new NmeaParser();
}

private void resetBuffer() {
    Log.d("XXX", "BUFFER BEING RESET");  // new code
    mMessageBuffer.clear();
    mFrameFlag = false;
}

要发布此版本 运行 在与 build.gradle 相同的文件夹中的终端中执行此命令:

 ./gradlew clean build bintrayUpload -PdryRun=true

现在你已经释放了一个依赖! 返回您的应用程序(在本例中为 driver-sampleshttps://github.com/androidthings/drivers-samples/blob/master/gps/build.gradle#L39:

更改 build.gradle 以具有不同的依赖关系:

 compile 'com.google.android.things.contrib:driver-gps:0.1'

变成

 compile 'com.google.android.things.contrib:driver-gps:0.1-DEBUG'

并告诉它在本地查找此依赖项:

repositories {
    mavenLocal()
    jcenter()
}

现在重新运行 应用程序,您应该会看到您的日志!首先证明它有效的健全日志 "MY VERSION BEING USED" 然后重置缓冲区 "BUFFER BEING RESET" 如果缓冲区没有被重置..你需要检查你的硬接线或添加更多日志来找出原因。

在某些情况下,processBuffer() 将处理整个缓冲区(512 字节),而不管从 UART 读取了多少字节。如果它碰巧错过了开始或结束字符,您可能会在消息缓冲区中得到很多“0”。你可以把this修改成这样:

int count;
while ((count = uart.read(buffer, buffer.length)) > 0) {
  processBuffer(buffer, count);
}

然后将 this 修改为更像这样:

private void processBuffer(byte[] buffer, int length) {
    for (int i = 0; i < length; i++) {
        if (mParser.getFrameStart() == buffer[i]) {
            handleFrameStart();
        } else if (mParser.getFrameEnd() == buffer[i]) {
            handleFrameEnd();
        } else {
            //Insert all other characters into the buffer
            mMessageBuffer.put(buffer[i]);
        }
    }
}

这样一来,如果删除结束字符,您就不会用垃圾填满消息缓冲区。我注意到在我正在使用此源代码的项目中发生了这种情况。 readUartBuffer() 方法可以读取拆分消息,即消息的开头或结尾。如果是这样,坏事就会发生。