Search code examples
androidraspberry-pi3uartnumberformatexceptionandroid-things

RPi 3 Android Things UART bidirectional communication crashes app


I am communicating via UART between an RPi 3 running Android Things and an Arduino.
Upon pressing a button on the RPi app a command is sent to the Arduino. There is no problem there. Every 2 seconds the Arduino sends a packet of information.

This works perfectly until I press a button that sends data to the Arduino. The Arduino receives the button command but the Android app crashes. I can even hit the button twice before the app crashes and the Arduino successfully receives both presses. The problem seems to be when the Arduino sends the next packet after the button press.

If I disconnect RPi UART RX the button does not cause a crash. In other words, as long as there is no incoming data the app works fine and vice versa. I can't make sense of the error:

E/AndroidRuntime: FATAL EXCEPTION: main
              Process: za.co.leafbox.boxcontrol, PID: 8817
              java.lang.NumberFormatException: For input string: "pump"
                  at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
                  at sun.misc.FloatingDecimal.parseFloat(FloatingDecimal.java:122)
                  at java.lang.Float.parseFloat(Float.java:452)
                  at za.co.leafbox.boxcontrol.MainActivity$2.readUartBuffer(MainActivity.java:284)
                  at za.co.leafbox.boxcontrol.MainActivity$2.onUartDeviceDataAvailable(MainActivity.java:234)
                  at com.google.android.things.pio.UartDeviceImpl$UartDeviceCallbackDispatch.dispatchInterruptEvent(UartDeviceImpl.java:250)
                  at com.google.android.things.pio.CallbackDispatch.onFileDescriptorEvents(CallbackDispatch.java:149)
                  at android.os.MessageQueue.dispatchEvents(MessageQueue.java:284)
                  at android.os.MessageQueue.nativePollOnce(Native Method)
                  at android.os.MessageQueue.next(MessageQueue.java:325)
                  at android.os.Looper.loop(Looper.java:142)
                  at android.app.ActivityThread.main(ActivityThread.java:6494)
                  at java.lang.reflect.Method.invoke(Native Method)
                  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

Example of the data received:

I/MainActivity: [45, 49, 46, 48, 48, 32, 49, 56, 46, 53, 48, 32, 54, 53, 46, 49, 48, 32, 45, 48, 46, 48, 56, 32, 48, 46, 48, 48, 32, 49, 54, 46, 51, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

OnClick function:

public void pumpToggle(View view){
    try{
        if (((ToggleButton) view).isChecked()) {
            byte[] buffer = {'g', 'g', '\n'};
            writeUartData(aNano, buffer);
        }
        else{
            byte[] buffer = {'g', 's', '\n'};
            writeUartData(aNano, buffer);
        }

    } catch (IOException e) {
        Log.e(TAG, "Data not Sent", e);
    }
}

UART callback:

private UartDeviceCallback mUartCallback = new UartDeviceCallback() {
    @Override
    public boolean onUartDeviceDataAvailable(UartDevice uart) {
        // Read available data from the UART device
        Log.i(TAG, "onUartDeviceDataAvailable");
        try {
            readUartBuffer(uart);
        } catch (IOException e) {
            Log.w(TAG, "Unable to access UART device", e);
        }
        // Continue listening for more interrupts
        return true;
    }

private void readUartBuffer(UartDevice uart) throws IOException {

    // Maximum amount of data to read at one time
    Log.i(TAG, "readUartBuffer");
    final int maxCount = 64;
    byte[] buffer = new byte[maxCount];
    byte[] convertBuf = new byte[20];
    boolean dataCompleteFlag = false;

    uart.read(buffer, maxCount);

    if (!dataCompleteFlag) {
        for (int i = 0; i < maxCount; i++) {
            if (buffer[i] == 36) {
                dataCompleteFlag = true;
                measureCount++;
                dataCount = 0;
            }
            else if(dataCount > maxCount) {
                dataCount = 0;
            }
            else if(buffer[i] != 0) {
                finalDataBuffer[dataCount] = buffer[i];
                dataCount++;
            }
        }
    }

    if (dataCompleteFlag) {
        Log.i(TAG, Arrays.toString(finalDataBuffer));
        int index = 0;
        int offSet;

        while (index < maxCount && finalDataBuffer[index] != 32) {
            convertBuf[index] = finalDataBuffer[index];
            index++;
        }
        index++;
        offSet = index;

        tankLevelString = new String(convertBuf);
        Float tankFloat = parseFloat(tankLevelString);
        tankLevelString += "cm";

        while (index < maxCount && finalDataBuffer[index] != 32) {
            convertBuf[index - offSet] = finalDataBuffer[index];
            index++;
        }
        index++;
        offSet = index;

        airTempString = new String(convertBuf);
        airTempString += "\u00b0C";

        while (index < maxCount && finalDataBuffer[index] != 32) {
            convertBuf[index - offSet] = finalDataBuffer[index];
            index++;
        }
        index++;
        offSet = index;

        humidityString = new String(convertBuf);
        humidityString += "%";

        while (index < maxCount && finalDataBuffer[index] != 32) {
            convertBuf[index - offSet] = finalDataBuffer[index];
            index++;
        }
        index++;
        offSet = index;

        ecString = new String(convertBuf);

        while (index < maxCount && finalDataBuffer[index] != 32) {
            convertBuf[index - offSet] = finalDataBuffer[index];
            index++;
        }
        index++;
        offSet = index;

        phString = new String(convertBuf);

        while (index < maxCount && finalDataBuffer[index] != 0) {
            convertBuf[index - offSet] = finalDataBuffer[index];
            index++;
        }

        waterTempString = new String(convertBuf);

        TextView airTemp = findViewById(R.id.airTemp);
        airTemp.setText(airTempString);

        TextView humidity = findViewById(R.id.humidity);
        humidity.setText(humidityString);

        TextView tankLevel1 = findViewById(R.id.tankLevel1);
        tankLevel1.setText(tankLevelString);

        TextView ec = findViewById(R.id.ec);
        ec.setText(ecString);

        TextView ph = findViewById(R.id.ph);
        ph.setText(phString);

        TextView wt = findViewById(R.id.waterTemp);
        wt.setText(waterTempString);

    }
}
@Override
public void onUartDeviceError(UartDevice uart, int error) {
    Log.w(TAG, uart + ": Error event " + error);
}
};

Solution

  • parseFloat (tankLevelString) is the line you get the NumberFormatException on. Apparently, tankLevelString, which is "pump", cannot be parsed into float. I recommend to investigate what causes it.