I bought a Nordic nrf58240 USB Dongle
a few weeks ago to try to play around with the lowpan API but have had little to no success with integrating it with the LowPAN API on android things.
At first I tried plugging it in out of the box to see if it worked using the lowpan example and I could not get it to connect and would get a Provision Exception in the onProvisionException
callback when trying to create a network
So I thought let me buy the nrf58240-DK boards and see if that works, I flashed the prebuilt ncp image as described here and the DK board worked just fine on android things.
So I did a little more reading and read that I might have to build an image manually with the BOOTLOADER flag set so I did that.
Here are the commands I used with all the flags
make -f examples/Makefile-nrf52840 clean
make -f examples/Makefile-nrf52840 USB=1 BOOTLOADER=1 BORDER_AGENT=1 BORDER_ROUTER=1 COMMISSIONER=1 UDF_FORWARD=1 LINK_RAW=1
arm-none-eabi-objcopy output/nrf52840/bin/ot-cli-ftd -O ihex cli.hex
I took that .hex file and flashed it to the dongle with the nrf connect programmer tool
for windows. Plugged it back into my raspberry pi only to still get the same Provision exception when trying to create a network
Here is the exception I get
W/System.err: com.google.android.things.lowpan.LowpanException: android.net.lowpan.InterfaceDisabledException: android.os.ServiceSpecificException: InvalidWhenDisabled (code 3)
W/System.err: at com.google.android.things.lowpan.LowpanInterface$AsyncCallGlue.doInBackground(LowpanInterface.java:516)
W/System.err: at com.google.android.things.lowpan.LowpanInterface$AsyncCallGlue.doInBackground(LowpanInterface.java:508)
W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:333)
W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
W/System.err: at java.lang.Thread.run(Thread.java:764)
W/System.err: Caused by: android.net.lowpan.InterfaceDisabledException: android.os.ServiceSpecificException: InvalidWhenDisabled (code 3)
W/System.err: at android.net.lowpan.LowpanInterface.form(LowpanInterface.java:236)
W/System.err: at com.google.android.things.lowpan.LowpanInterface$1.run(LowpanInterface.java:587)
W/System.err: at com.google.android.things.lowpan.LowpanInterface$AsyncCallGlue.doInBackground(LowpanInterface.java:513)
W/System.err: ... 7 more
W/System.err: Caused by: android.os.ServiceSpecificException: InvalidWhenDisabled (code 3)
W/System.err: at android.os.Parcel.readException(Parcel.java:2027)
W/System.err: at android.os.Parcel.readException(Parcel.java:1959)
W/System.err: at android.net.lowpan.ILowpanInterface$Stub$Proxy.form(ILowpanInterface.java:810)
W/System.err: at android.net.lowpan.LowpanInterface.form(LowpanInterface.java:230)
W/System.err: ... 9 more
Here is my code
class MainActivity2: Activity(){
private var lowpanInterface: LowpanInterface? = null
private var lowpanScanner: LowpanScanner? = null
private var lowpanDriver: UartLowpanDriver? = null
private var lowpanManager:LowpanManager? = null
private val TAG = "MainActivity2"
private var connectivityManager: ConnectivityManager? = null
private var network: Network? = null
private var backgroundHandlerThread: HandlerThread? = null
private var handler: Handler? = null
private var uiThreadHandler: Handler? = null
private var socket: Socket? = null
private val UART_PORT = "USB1-1.2:1.1"
private val UART_BAUD = 115200
private val SERVER_ADDRESS = "192.168.1.208"
private val SERVER_PORT = 23456
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lowpanManager = LowpanManager.getInstance()
lowpanManager?.registerCallback(managerCallback)
try {
lowpanDriver = UartLowpanDriver(UART_PORT, UART_BAUD)
lowpanDriver?.register()
Log.d(TAG,"Lowpan Connected")
} catch (e: Exception) {
e.printStackTrace()
}
uiThreadHandler = Handler(Looper.getMainLooper())
}
override fun onDestroy() {
super.onDestroy()
stopNetworkScan()
// Detach from any network we might be attached to.
lowpanInterface?.unregisterCallback(callback)
lowpanInterface?.leave()
lowpanInterface = null
lowpanDriver?.unregister()
lowpanDriver?.close()
lowpanDriver = null
}
private fun scanForNetworks() {
val params = lowpanInterface?.getLowpanProvisioningParams(false)
if(params?.lowpanIdentity?.name == "MeshNetwork"){
return
}
lowpanScanner = lowpanInterface?.createScanner()?.apply {
setCallback(scanner)
startNetScan()
}
}
private fun stopNetworkScan() {
lowpanScanner?.stopNetScan()
}
private fun createNetwork(){
/* We are only specifying the network name here. By
* doing this we allow the interface to pick reasonable
* defaults for other required fields. If we specified
* our own values for those fields, they would be used
* instead.
*/
val identity = LowpanIdentity.Builder()
.setName("MeshNetwork")
.build()
/* Not specifying a LowpanCredential here tells “form()”
* that we want the interface to generate the master key
* for us.
*/
val provision = LowpanProvisioningParams.Builder().setLowpanIdentity(identity).build()
try{
lowpanInterface?.form(provision)
Log.d(TAG,"Network created")
}catch (e:LowpanException){
e.printStackTrace()
}catch (e:LowpanRuntimeException){
e.printStackTrace()
}
}
private fun resetNetwork() {
connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkRequest = NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_LOWPAN)
.build()
backgroundHandlerThread = HandlerThread("BackgroundThread")
backgroundHandlerThread!!.start()
handler = Handler(backgroundHandlerThread!!.looper)
connectivityManager!!.registerNetworkCallback(networkRequest,networkCallback, uiThreadHandler)
}
private val scanner = object : LowpanScanner.Callback(){
override fun onNetScanBeacon(beacon: LowpanBeaconInfo) {
val network = beacon.lowpanIdentity
if(network.name == "MeshNetwork"){
joinNetwork(beacon)
}
}
override fun onScanFinished() {
// Release a semaphore
Log.d(TAG,"Scan Finished")
}
}
private val managerCallback = object:LowpanManager.Callback(){
override fun onInterfaceAdded(lowpan_interface: LowpanInterface?) {
super.onInterfaceAdded(lowpan_interface)
lowpanInterface = lowpan_interface
lowpanManager?.let {
Log.d(TAG,"resetting network")
resetNetwork()
Log.d(TAG,"register callback")
lowpanInterface?.registerCallback(callback)
createNetwork()
}
}
override fun onInterfaceRemoved(lowpan_interface: LowpanInterface?) {
super.onInterfaceRemoved(lowpan_interface)
}
}
private val callback = object : LowpanInterface.Callback() {
override fun onStateChanged(state: Int) {
super.onStateChanged(state)
when (state){
LowpanInterface.STATE_ATTACHED -> Log.d(TAG,"Attached")
LowpanInterface.STATE_ATTACHING -> Log.d(TAG,"Attaching")
LowpanInterface.STATE_DISABLED -> Log.d(TAG,"Disabled")
LowpanInterface.STATE_FAULT -> Log.d(TAG,"Fault")
LowpanInterface.STATE_OFFLINE -> Log.d(TAG,"Offline")
}
/* Handle interface state changes. */
}
override fun onLowpanIdentityChanged(identity: LowpanIdentity?) {
super.onLowpanIdentityChanged(identity)
Log.d(TAG,"Identity changed")
Log.d(TAG,"Name: ${identity?.name}")
Log.d(TAG,"Channel: ${identity?.channel}")
Log.d(TAG,"Is Valid: ${identity?.isNameValid}")
Log.d(TAG,"Panid: ${identity?.panid}")
Log.d(TAG,"Raw Name: ${identity?.rawName}")
Log.d(TAG,"Xpanid: ${identity?.xpanid}")
/* Form, join, or leave completed successfully. */
}
override fun onProvisionException(exception: Exception?) {
super.onProvisionException(exception)
exception?.printStackTrace()
/* An error occurred during form or join. */
}
}
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
}
override fun onLost(network: Network) {
}
}
}
Do I need to flash the Dongle
differently?
Perhaps the Dongle
is not supported?
Not sure what the issue is at this point really