Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Listener Error While Receiving Data from Two Xbees at Once Via Bluetooth #8

Open
JesseG689 opened this issue Aug 28, 2019 · 4 comments

Comments

@JesseG689
Copy link

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?

@JesseG689 JesseG689 changed the title Disconnect Error While Receiving Data from Two Xbees at Once Via Bluetooth Listener Error While Receiving Data from Two Xbees at Once Via Bluetooth Aug 28, 2019
@rubenmoral
Copy link
Member

rubenmoral commented Aug 29, 2019

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.

@JesseG689
Copy link
Author

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.

@JesseG689
Copy link
Author

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...

  1. Xbee1 is connected already, and Xbee2 is connecting.

  2. 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

@rubenmoral
Copy link
Member

@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 apps.feedback@digi.com.

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants