The Android Things LoWPAN APIs enable apps to interact with local devices connected over a wireless personal area network. Using LoWPAN user drivers, your apps can extend this framework and add new LoWPAN interfaces connected over Peripheral I/O.
Interface hardware connected through a LoWPAN user driver must implement a Network Control Processor (NCP) that supports the Spinel protocol. This is the standard communications protocol used by OpenThread devices.
Adding the required permission
Add the required permission for the user driver to your app's manifest file:
<uses-permission android:name="com.google.android.things.permission.MANAGE_LOWPAN_INTERFACES" />
Implementing the driver
To define a new LoWPAN interface, extend the LowpanDriver
class and override
the methods to manage the hardware connection:
Kotlin
import com.google.android.things.userdriver.lowpan.LowpanDriver import com.google.android.things.userdriver.lowpan.LowpanDriverCallback class NcpLowpanDriver : LowpanDriver() { ... override fun start(lowpanDriverCallback: LowpanDriverCallback?) { /* Open connection to interface hardware */ } override fun stop() { /* Close connection to interface hardware */ } override fun reset() { /* Send a reset command or power cycle the radio interface */ } override fun sendFrame(bytes: ByteArray?) { /* Transmit a data frame to the radio interface */ } }
Java
import com.google.android.things.userdriver.lowpan.LowpanDriver; import com.google.android.things.userdriver.lowpan.LowpanDriverCallback; ... public class NcpLowpanDriver extends LowpanDriver { ... @Override public void start(LowpanDriverCallback lowpanDriverCallback) { /* Open connection to interface hardware */ } @Override public void stop() { /* Close connection to interface hardware */ } @Override public void reset() { /* Send a reset command or power cycle the radio interface */ } @Override public void sendFrame(byte[] bytes) { /* Transmit a data frame to the radio interface */ } }
Managing the device connection
When the framework registers your new driver, it passes a LowpanDriverCallback
instance in the start()
method. Use this callback to report asynchronous
events from the hardware back to the framework service.
Once your driver has opened a connection to your interface hardware, report to
the framework that initialization is complete by calling onStarted()
callback
method. Report any errors that occur communicating with the interface hardware
via the onError()
callback method.
Kotlin
import com.google.android.things.userdriver.lowpan.LowpanDriver import com.google.android.things.userdriver.lowpan.LowpanDriverCallback ... class NcpLowpanDriver : LowpanDriver() { private var callback: LowpanDriverCallback? = null ... override fun start(lowpanDriverCallback: LowpanDriverCallback?) { callback = lowpanDriverCallback try { /* Open connection to interface hardware */ // Report completion to the framework callback?.onStarted() } catch (e: IOException) { // Report error to the framework callback?.onError(HAL_ERROR_IOFAIL) } } }
Java
import com.google.android.things.userdriver.lowpan.LowpanDriver; import com.google.android.things.userdriver.lowpan.LowpanDriverCallback; ... public class NcpLowpanDriver extends LowpanDriver { private LowpanDriverCallback callback; ... @Override public void start(LowpanDriverCallback lowpanDriverCallback) { callback = lowpanDriverCallback; try { /* Open connection to interface hardware */ // Report completion to the framework callback.onStarted(); } catch (IOException e) { // Report error to the framework callback.onError(HAL_ERROR_IOFAIL); } } }
Your driver should also monitor the interface hardware for reset events. If the
hardware is reset for any reason, report this to the framework via
LowpanDriverCallback.onReset()
.
Transferring data
The framework delivers data frames to the driver using the sendFrame()
method.
Pass each frame onto the interface hardware, and report any incoming frames from
the hardware via onReceiveFrame()
.
Kotlin
import com.google.android.things.userdriver.lowpan.LowpanDriver import com.google.android.things.userdriver.lowpan.LowpanDriverCallback ... class NcpLowpanDriver : LowpanDriver() { private var callback: LowpanDriverCallback? = null ... override fun sendFrame(bytes: ByteArray?) { try { /* Transmit a data frame to the radio interface */ } catch (e: IOException) { // Report error to the framework callback?.onError(HAL_ERROR_IOFAIL) } } /* Interface hardware generated a new data frame */ private fun onDataReceived(data: ByteArray) { // Report data to the framework callback?.onReceiveFrame(data) } }
Java
import com.google.android.things.userdriver.lowpan.LowpanDriver; import com.google.android.things.userdriver.lowpan.LowpanDriverCallback; ... public class NcpLowpanDriver extends LowpanDriver { private LowpanDriverCallback callback; ... @Override public void sendFrame(byte[] bytes) { try { /* Transmit a data frame to the radio interface */ } catch (IOException e) { // Report error to the framework callback.onError(HAL_ERROR_IOFAIL); } } /* Interface hardware generated a new data frame */ private void onDataReceived(byte[] data) { // Report data to the framework callback.onReceiveFrame(data); } }
Registering the interface
Connect your new radio interface to the framework by registering it with the
UserDriverManager
:
Kotlin
import com.google.android.things.userdriver.UserDriverManager class LowpanDriverService : Service() { lateinit var driver: NcpLowpanDriver override fun onCreate() { super.onCreate() ... val manager = UserDriverManager.getInstance() driver = NcpLowpanDriver() // Register the new driver with the framework manager.registerLowpanDriver(driver) } override fun onDestroy() { super.onDestroy() ... val manager = UserDriverManager.getInstance() // Unregister the driver when finished manager.unregisterLowpanDriver(driver) } }
Java
import com.google.android.things.userdriver.UserDriverManager; ... public class LowpanDriverService extends Service { NcpLowpanDriver driver; @Override public void onCreate() { super.onCreate(); ... UserDriverManager manager = UserDriverManager.getInstance(); driver = new NcpLowpanDriver(); // Register the new driver with the framework manager.registerLowpanDriver(driver); } @Override public void onDestroy() { super.onDestroy(); ... UserDriverManager manager = UserDriverManager.getInstance(); // Unregister the driver when finished manager.unregisterLowpanDriver(driver); } }
With the driver properly registered, apps can form or join local networks and communicate with connected devices using the Android LoWPAN API.