Introduction to IIoT Gateways and Android Things
The Industrial Internet of Things (IIoT) is rapidly transforming manufacturing, logistics, and infrastructure by enabling data-driven decision-making. At the heart of many IIoT deployments are gateways, devices that bridge the operational technology (OT) world of industrial sensors and machinery with the information technology (IT) world of cloud platforms and data analytics. These gateways often require specialized interfaces and robust operating systems.
Android Things, Google’s embedded operating system built on Android, offers a compelling platform for IIoT gateway development due to its familiarity, extensive developer ecosystem, and built-in connectivity features. However, stock Android Things images are typically optimized for consumer IoT devices, lacking native support for the diverse range of industrial communication protocols like Modbus, CAN bus, RS-485, and EtherCAT. This guide will walk you through the process of customizing Android Things OS at the kernel level to integrate these crucial industrial sensor interfaces, transforming a standard Android Things device into a powerful IIoT gateway.
The Need for Customization: Bridging OT and IT
Industrial environments present unique challenges: extreme temperatures, electrical noise, legacy equipment, and stringent real-time requirements. While Android Things provides a solid foundation, direct interaction with industrial-grade sensors often necessitates low-level driver development and kernel modifications. For instance, a temperature sensor communicating via Modbus RTU over RS-485 needs a reliable serial driver and a userspace library to handle the Modbus protocol, or even better, kernel-level support for enhanced performance and stability.
Our goal is to create a custom Android Things build that can natively support these industrial protocols, allowing your application layer to seamlessly interact with a wide array of industrial hardware.
Setting Up Your Android Things Build Environment
Before diving into kernel modifications, you need a robust Linux development environment. Ubuntu 18.04 LTS or 20.04 LTS is highly recommended.
Prerequisites:
- A Linux machine (preferably Ubuntu) with at least 200GB free disk space and 16GB RAM.
- Java Development Kit (JDK) 8.
- Android SDK and Platform Tools.
- Repo tool and Git.
- Various build dependencies (e.g., `make`, `gcc`, `g++`, `python`, `flex`, `bison`, `libssl-dev`, `libz-dev`).
Install necessary packages:
sudo apt update && sudo apt upgrade -y
sudo apt install -y openjdk-8-jdk python git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev libgl1-mesa-dev libxml2-utils xsltproc unzip m4 bc ccache
mkdir ~/bin
PATH=~/bin:$PATH
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
Obtaining the Android Things AOSP Source
Android Things is built upon the Android Open Source Project (AOSP). You’ll need to download the source code for a compatible device, such as the Raspberry Pi 3 (for demonstration purposes).
mkdir android-things-iiot
cd android-things-iiot
repo init -u https://android.googlesource.com/platform/manifest -b android-things-1.0.2_r1 --depth=1
repo sync -j8
This will download a substantial amount of data. Replace `android-things-1.0.2_r1` with the desired Android Things branch if different.
Kernel Customization: Integrating Industrial Drivers
This is where we add support for industrial interfaces. For an IIoT gateway, common additions include RS-485, CAN bus, and potentially custom GPIO or SPI drivers.
Example: Adding RS-485 Support (via Device Tree Overlay)
Many modern industrial transceivers (e.g., MAX485) connect to a UART and require a GPIO pin for direction control (DE/RE pins). Instead of a full kernel module, we can often leverage existing serial drivers and use device tree overlays to configure the GPIO.
First, locate the kernel source for your device. For Raspberry Pi 3, it’s typically under `device/google/rpi3/kernel`. The main device tree source file is `arch/arm/boot/dts/bcm2710-rpi-3-b.dts` (or similar). You will likely create a new `.dts` overlay.
Let’s assume you’re connecting an RS-485 transceiver to UART1 and GPIO17 for direction control.
1. Create a new device tree overlay file, e.g., `device/google/rpi3/kernel/arch/arm/boot/dts/overlays/rpi-rs485-overlay.dts`:
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2710";
fragment@0 {
target = ;
__overlay__ {
pinctrl-names = "default";
pinctrl-0 = ;
status = "okay";
rs485 {
linux,rs485-enabled-at-boot-time;
tx-delay-rts-before-send = ;
rx-delay-rts-after-send = ;
rts-active-high;
rts-gpio = ; /* GPIO17, active high */
status = "okay";
};
};
};
};
2. Modify the build system to include this overlay. You’d typically add it to the `BOARD_KERNEL_DTS_OVERLAYS` variable in your device’s `BoardConfig.mk` or equivalent, or compile it manually and include it in the `boot.img`.
3. For more complex protocols like CAN bus, you might need to add specific kernel modules. You would place your new driver source (`.c` and `.h` files) in a suitable kernel directory (e.g., `drivers/net/can/`) and update the respective `Kconfig` and `Makefile` to compile it. Then, ensure your device tree includes the correct CAN controller nodes.
Compiling the Kernel:
cd device/google/rpi3/kernel
export ARCH=arm
export CROSS_COMPILE=/path/to/android-things-iiot/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-
make rpi_3_defconfig
make -j$(nproc)
This will compile your custom kernel. The resulting `zImage` and device tree blobs (`.dtb`) will be used in the next step.
Building the Custom Android Things Image
With the kernel changes in place, we now build the complete Android Things OS image.
cd /path/to/android-things-iiot
source build/envsetup.sh
lunch at_raspberry_pi3-userdebug # Or your target device
make -j$(nproc)
This process can take several hours depending on your system’s specifications. Upon successful completion, your custom images will be located in `out/target/product/rpi3/`.
Flashing the Custom Image to Your IIoT Gateway
You’ll get several `.img` files, including `boot.img`, `system.img`, `userdata.img`, etc. Use the Android Things `fastboot` utility to flash these images onto your hardware.
# Ensure your device is in fastboot mode
cd out/target/product/rpi3/
fastboot flash boot boot.img
fastboot flash system system.img
fastboot flash userdata userdata.img
fastboot reboot
Your device will now boot with your custom Android Things OS, including the new kernel modules and device tree configurations for industrial interfaces.
Developing the Application Layer: Interacting with Custom Drivers
With the custom kernel, your Android Things application can now interact with the industrial interfaces. For kernel modules, this typically involves opening device nodes (e.g., `/dev/ttyS1` for UART, `/dev/can0` for CAN bus) and using standard Linux system calls or an NDK wrapper.
Example: Accessing RS-485 from Android App (using NDK)
1. **C/C++ Native Library (JNI):** Create a C/C++ library that opens and configures the serial port (e.g., `/dev/ttyS1`) for RS-485 communication. You might use `termios` for serial port configuration and `read`/`write` for data transfer, or a Modbus library.
// jni/native-lib.cpp
#include
#include
#include
#include
#include
extern "C" JNIEXPORT jint JNICALL
Java_com_example_iiotgateway_SerialPortJNI_open(JNIEnv *env, jobject instance, jstring path, jint baudrate) {
const char *path_str = env->GetStringUTFChars(path, 0);
int fd = open(path_str, O_RDWR | O_NOCTTY | O_SYNC);
env->ReleaseStringUTFChars(path, path_str);
if (fd < 0) return -1;
struct termios tty;
if(tcgetattr(fd, &tty) != 0) return -1;
cfsetospeed(&tty, baudrate);
cfsetispeed(&tty, baudrate);
tty.c_cflag &= ~PARENB; // No parity
tty.c_cflag &= ~CSTOPB; // 1 stop bit
tty.c_cflag &= ~CSIZE; // Clear current size
tty.c_cflag |= CS8; // 8 data bits
tty.c_cflag &= ~CRTSCTS; // No flow control
tty.c_cflag |= CREAD | CLOCAL; // Enable receiver, ignore modem control lines
// Enable RS485 mode via ioctl (requires kernel support, specific to serial driver)
// struct serial_rs485 rs485conf;
// if (ioctl(fd, TIOCGRS485, &rs485conf) < 0) { /* handle error */ }
// rs485conf.flags |= SER_RS485_ENABLED;
// if (ioctl(fd, TIOCSRS485, &rs485conf) GetByteArrayElements(data, NULL);
jsize len = env->GetArrayLength(data);
int bytesWritten = write(fd, bufferPtr, len);
env->ReleaseByteArrayElements(data, bufferPtr, 0);
return bytesWritten;
}
// ... other methods for read, close, etc.
2. **Android Java Application:** Call the native methods to interact with your industrial hardware.
// Java/Kotlin code in your Android Things app
package com.example.iiotgateway;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends Activity {
static {
System.loadLibrary("native-lib");
}
public native int open(String path, int baudrate);
public native int write(int fd, byte[] data);
public native int read(int fd, byte[] buffer, int len);
public native void close(int fd);
private static final String TAG = "IIoTGateway";
private int rs485Fd = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "IIoT Gateway App Started");
// Example: Open RS-485 port /dev/ttyS1 at 9600 baud
rs485Fd = open("/dev/ttyS1", 9600);
if (rs485Fd >= 0) {
Log.i(TAG, "RS-485 port opened successfully: " + rs485Fd);
// Example Modbus RTU Read Holding Registers (Function Code 0x03)
// Address: 1, Starting Register: 0, Number of Registers: 1
byte[] modbusCommand = { (byte)0x01, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x84, (byte)0x0A };
int bytesWritten = write(rs485Fd, modbusCommand);
Log.d(TAG, "Modbus command written: " + bytesWritten + " bytes");
// Read response (in a separate thread/AsyncTask for real apps)
byte[] responseBuffer = new byte[256];
int bytesRead = read(rs485Fd, responseBuffer, responseBuffer.length);
if (bytesRead > 0) {
// Process Modbus response
Log.d(TAG, "Modbus response received: " + bytesRead + " bytes");
}
} else {
Log.e(TAG, "Failed to open RS-485 port.");
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (rs485Fd >= 0) {
close(rs485Fd);
Log.i(TAG, "RS-485 port closed.");
}
}
}
This application snippet demonstrates how to leverage your kernel modifications. Remember to handle permissions (e.g., adding `android.permission.SERIAL_PORT` or `android.permission.GPIO` to your manifest and ensuring the device node has appropriate permissions for your app).
Conclusion
Customizing Android Things OS for industrial sensor interfaces empowers you to build highly specialized and robust IIoT gateways. By modifying the kernel, adding device tree overlays, and developing corresponding application-level drivers, you can bridge the gap between consumer-oriented Android Things and the demanding world of industrial automation. This approach offers the flexibility of Android’s ecosystem combined with the low-level control required for true industrial-grade deployments, paving the way for innovative IIoT solutions.
Android Mobile Specs & Compare Directory
Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!
Compare Devices Specs →