Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Android Serial Port Development with Google's Serial Port API

Tech May 17 2

Preparation

  • Android Studio
  • Google android-serialport-api

Background

There are many approaches to serial port development on Android using C-based methods such as JNI or CMake, but they are often complex. Google's API provides a simpler method for basic read/write operations (default setting: N81, no parity, 8 data bits, 1 stop bit). This is the easiest way to get started.

Java does not directly call C functions for serial communication; instead, it uses.so library files compiled from C with CMake or JNI. By using Google's API, you don't need to deal with the C files—just use the provided.so libraries and the Java classes that call them. The Google demo includes these classes, so you only need to import the necessary components and build upon them.

Getting Started

  1. Unzip the Google API demo and set it aside for reference.
  2. Create a new Android Studio project with the default settings.
  3. Open app/build.gradle and add the following inside android block to specify the location of.so files. Here we use a custom libs folder:
android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.hp.demo"
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    sourceSets.main {
        jniLibs.srcDirs = ['libs']
    }
}
  1. Navigate to android-serialport-api\android-serialport-api\project\libs in the unzipped demo. Copy all the folders (containing.so files for different CPU architectures) into your project's libs folder.

  2. Go to android-serialport-api\android-serialport-api\project\src and copy the android_serialport_api folder into your project's java directory (at the same level as com).

  3. Inside android_serialport_api, you'll find three items:

    • sample: Demo code from Google API. Delete this folder after copying, as it will cause XML-related errors.
    • SerialPort.java: The main class for serial port operations. This communicates with the.so library. You will build your code upon this.
    • SerialPortFinder.java: Usually not needed (I didn't use it). It helps find and list all available serial port names and paths, useful for batch operations.
  4. To reiterate: The standard approach is to write C and header files, compile them via JNI or CMake to produce.so files, then write a Java class that calls the.so library, and finally use that class. Our approach skips to the last step—using Google's pre-compiled.so and pre-written Java class, then buliding our own code on top.

  5. Now you can start coding. But first, verify:

    • Check that step 3 is correctly set up.

    • In SerialPort.java, ensure the following static block exists:

      static {
          System.loadLibrary("serial_port");
      }
      

      This loads the.so library. The library name must match: the.so file is libserial_port.so, so the name is serial_port. If step 3 is misconfigured, the library won't be found.

  6. Now for the actual work:

    a) Create a wrapper class around SerialPort.java. Although you can use SerialPort.java directly, its methods are low-level. When dealing with multiple serial ports needing different operations, a wrapper is essential to avoid code duplication. Your wrapper should provide:

    • Set serial port name and baud rate from outside
    • Pass serial port response data to external listeners
    • Open serial port, get input/output streams
    • Close serial port, close input/output streams
    • Write bytes to serial port
    • Write byte arrays
    • Write strings
    • Real-time listening for complete messages (See the demo for code details.)

    b) Use the wrapper: instantiate it, register a data receiver, call the send methods where needed, and handle message validation in the receiver.

Pitfall Warnings

  1. Incomplete serial port responses (missing a byte or two): This usually happens because you registered two listeners on the same serial port, and they are competing.

  2. Fragmented responses: The sending device may transmit byte by byte or in chunks, all arriving quickly. To safely assemble the complete message, sleep 10–100ms after receiving some data, then read again (reading from the input stream buffer). Concatenate the data and pass it to the external listener.

  3. Creating a new serial port is resource-intensive: The reading process runs in a loop. Insert a sleep of 10–100ms between reads to reduce CPU usage.

  4. Reading thread continues after closing serial port: Wrap the reading logic in a while loop with a boolean flag. Set the flag to false when closing the port, so the thread terminates naturally.

  5. The SerialPort constructor requires an int flags parameter besides file and baud rate: I haven't fully understood this. My senior always passed 0 without issues.

  6. The inputStream.read() method: It returns an int representing the number of bytes read. Store this value. When the buffer is empty, it returns -1. Always use an if condition to check if the returned int > 0 before further processing. This method has multiple overloads:

    • read(byte[] buffer): Reads bytes in to the buffer. Ensure no null pointer and that buffer capacity is sufficient.
    • read(byte[] buffer, int offset, int length): Reads length bytes and stores them starting at buffer[offset]. Useful for appending data when reading multiple times.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.