xbee-android
xbee-android copied to clipboard
Listener Error While Receiving Data from Two Xbees at Once Via Bluetooth
Hi, I'm fairly new to Kotlin and Android so this might end up being a silly mistake.
I'm trying to design an app which will connect to two XBee3 modules at once via Bluetooth and continuously receive User Data Relay messages from them. I also use Kotlin coroutines to help with threading and preventing the app from being blocked.
I define both device variables and two IUserDataRelayReceiveListeners like this:
@Volatile var xBeeDevice1: XBeeBLEDevice? = null
@Volatile var xBeeDevice2: XBeeBLEDevice? = null
private val xBeeUserDataListener1 = IUserDataRelayReceiveListener {
GlobalScope.launch {
//receive and process User Data Relay string
}
}
private val xBeeUserDataListener2 = IUserDataRelayReceiveListener {
GlobalScope.launch {
//receive and process User Data Relay string
}
}
I then created two functions which connect to each XBee in the background (I'm just showing the connect function for xBeeDevice1):
private fun xBee1Connect() {
val device = XBeeBLEDevice(this, xBee1MacAddress, xBeePassword)
xBeeConnectJob = GlobalScope.launch(Dispatchers.IO){
//try connecting to the XBee
try {
// Open the connection with the device.
device.open()
// If the open method did not throw an exception, the connection is open.
runOnUiThread {
Toast.makeText(applicationContext, "XBEE connection successful!", Toast.LENGTH_SHORT).show()
xBeeDevice1 = device
//if thread finished successfully then send the connected device to the main UI
xBeeDevice1!!.addUserDataRelayListener(xBeeUserDataListener1)
}
} catch (e: BluetoothAuthenticationException) {
// There was a problem in the Bluetooth authentication process, so ask for the password again.
e.printStackTrace()
} catch (e: XBeeException) {
e.printStackTrace()
}
if (!device.isOpen) {
}
}
}
Everything works great, and both Listener functions receive and process the data concurrently. I also have a Broadcast Receiver which will detect when they disconnect, and it will run the disconnect() function on the proper XBee device.
I believe I have discovered a bug when I turn off one of the XBees while they are both actively connected. Sometimes (not all the time) the Listener for the other XBee will stop receiving data and not work, so then I'll have to reconnect to get it working again.
So, for example, if I shut power off of xBeeDevice1 then xBeeUserDataListener2 will sometimes stop receiving data, even though xBeeDevice2 is still active.
Do you have any idea how this might be happening? Are the two separate UserDataRelayListeners somehow linked together?
Hi @JesseG689,
We have not been able to reproduce the problem you mention. The listeners are independent each other, since they are registered in different XBeeBLEDevice objects.
Could you please paste the code referring to the broadcast receiver? Make sure you register the correct listener with the addUserDataRelayListener method and close the correct instance of the device when the Bluetooth disconnection event is received.
Best regards.
Hi @rubenmoral,
Thank you for your reply. That's good to know that my code is fine so far. The Listeners are each set to the correct device.
The bug occurs immediately when one of the XBee devices is turned off, way before the broadcast receiver even processes the ACTION_ACL_DISCONNECTED event - so I don't think the broadcast receiver could be causing this issue. The ACTION_ACL_DISCONNECTED signal is fired about 20 seconds after powering off one of the XBee devices.
My broadcast receiver is initialized within onCreate():
//initialize broadcast receiver
val filter = IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED)
registerReceiver(mBroadcastReceiver, filter)
And my broadcast receiver code is as follows:
private val mBroadcastReceiver = object : BroadcastReceiver(){
override fun onReceive(p0: Context?, p1: Intent?) {
when(p1?.action){
BluetoothDevice.ACTION_ACL_DISCONNECTED -> {
//disconnect the device which was determined to not be connected
if(!isSensor1Connected) {
xBeeDevice1?.removeUserDataRelayListener(xBeeUserDataListener1)
xBeeDevice1?.disconnect()
}
if(!isSensor2Connected) {
xBeeDevice2?.removeUserDataRelayListener(xBeeUserDataListener2)
xBeeDevice2?.disconnect()
}
}
}
}
}
In order to determine exactly which device was disconnected, I have two timers running on separate threads which check the data every 3 seconds to make sure the Listeners are still receiving data. They check to see if a volatile Boolean variable (receivedSensorxReading) is set to true at least once every 3 seconds while connected.
private fun checkConnection1Timer(){
connection1Handler = GlobalScope.launch{
while(isActive) {
if(receivedSensor1Reading) receivedSensor1Reading = false
else isSensor1Connected = false
delay(3000)
}
}
}
private fun checkConnection2Timer(){
connection2Handler = GlobalScope.launch{
while(isActive) {
if(receivedSensor2Reading) receivedSensor2Reading = false
else isSensor2Connected = false
delay(3000)
}
}
}
Every time the Listeners receive and process new data, they set the receivedSensor1Reading and receivedSensor2Reading flags to true
Let me know if any of this doesn't make sense and I can explain it better. Thanks for taking the time to look into my issue.
Just a quick update, I can also get this bug to happen while one Xbee is already connected and the other Xbee is in process of connecting. I'll explain the process...
-
Xbee1 is connected already, and Xbee2 is connecting.
-
As soon as Xbee2 gets the "I/XBeeBLEDevice: Authentication finished successfully" message, then I turn it off. After I do this, Xbee1's Listener stops working and no longer receives notifications.
I'm almost positive that the two Xbee device Listeners are linked together somehow. If anything goes wrong with one, then it shuts down the Listeners for both.
Here's the debug error log that I receive during this example process:
W/System.err: com.digi.xbee.api.exceptions.TimeoutException: There was a timeout while executing the requested operation. at com.digi.xbee.api.AbstractXBeeDevice.sendXBeePacket(AbstractXBeeDevice.java:1511) at com.digi.xbee.api.AbstractXBeeDevice.sendATCommand(AbstractXBeeDevice.java:1318) at com.digi.xbee.api.AbstractXBeeDevice.sendParameter(AbstractXBeeDevice.java:2685) at com.digi.xbee.api.AbstractXBeeDevice.getParameter(AbstractXBeeDevice.java:2624) at com.digi.xbee.api.AbstractXBeeDevice.readDeviceInfo(AbstractXBeeDevice.java:504) at com.digi.xbee.api.AbstractXBeeDevice.open(AbstractXBeeDevice.java:3159) at com.digi.xbee.api.android.XBeeBLEDevice.open(XBeeBLEDevice.java:100) at MainActivity$xBee1Connect$1.invokeSuspend(MainActivity.kt:1042) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:233) W/System.err: at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594) at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742) I/XBeeBLEDevice: [00:0D:6F:41:5D:14] Opening the connection interface... D/BluetoothGatt: connect() - device: 00:0D:6F:41:5D:14, auto: false registerApp() D/BluetoothGatt: registerApp() - UUID=3736013d-0b11-4d76-a9b4-b268ec914c29 D/BluetoothGatt: onClientRegistered() - status=0 clientIf=9 D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=9 device=00:0D:6F:41:5D:14 I/art: Enter while loop. D/ActivityThread: BDC-Calling finishReceiver: IIntentReceiver=2abceaf D/OpenGLRenderer: CacheTexture 7 upload: x, y, width height = 60, 61, 13, 19 D/BluetoothGatt: onCharacteristicWrite() - Device=00:0D:6F:41:5D:14 handle=13 Status=133 D/BluetoothGatt: onClientConnectionState() - status=8 clientIf=8 device=00:0D:6F:41:5D:14 close() unregisterApp() - mClientIf=8 D/BluetoothGatt: onClientConnectionState() - status=8 clientIf=9 device=00:0D:6F:41:5D:14 close() unregisterApp() - mClientIf=9
@JesseG689 unfortunately, we still cannot reproduce your issue. It makes no sense that the listeners are linked because they belong to different objects, and there is not any static class that handles them.
May I ask you to send us by email the app source code to take a deeper look and try to reproduce the issue? You can send it to [email protected].
Thanks.